@pinagent/react-native 0.1.0
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/README.md +201 -0
- package/dist/babel.cjs +130 -0
- package/dist/babel.cjs.map +1 -0
- package/dist/babel.d.cts +16 -0
- package/dist/babel.d.cts.map +1 -0
- package/dist/babel.d.ts +16 -0
- package/dist/babel.d.ts.map +1 -0
- package/dist/babel.js +130 -0
- package/dist/babel.js.map +1 -0
- package/dist/server.cjs +4684 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +109 -0
- package/dist/server.d.cts.map +1 -0
- package/dist/server.d.ts +110 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +4681 -0
- package/dist/server.js.map +1 -0
- package/package.json +83 -0
- package/src/native/Pinagent.tsx +703 -0
- package/src/native/StreamSheet.tsx +426 -0
- package/src/native/index.ts +9 -0
- package/src/native/inspector.ts +407 -0
- package/src/native/multi-pick.ts +74 -0
- package/src/native/restore.ts +91 -0
- package/src/native/screenshot.ts +34 -0
- package/src/native/submit-outcome.ts +70 -0
- package/src/native/transcript.ts +143 -0
- package/src/native/transport.ts +162 -0
- package/src/native/types.ts +95 -0
- package/src/native/ws-client.ts +173 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.cjs","names":["z","z","DatabaseSync","z","Buffer$1","WebSocketServer","WebSocket","ws","Buffer","delimiter"],"sources":["../../db/dist/schema.js","../../shared/dist/index.js","../../agent-runner/dist/host-branch-pr.js","../../agent-runner/dist/index.js","../src/server/ws-endpoint.ts","../src/server/metro-middleware.ts"],"sourcesContent":["import { sql } from \"drizzle-orm\";\nimport { integer, sqliteTable, text } from \"drizzle-orm/sqlite-core\";\n//#region src/schema.ts\n/**\n* Pinagent persistent state. Shared between the dev-side server\n* (Node's built-in `node:sqlite` via `@pinagent/agent-runner`'s\n* `src/db/client.ts`) and the browser cache (`@sqlite.org/sqlite-wasm` via\n* `@pinagent/widget/db/client`).\n*\n* Server-side is the source of truth: it owns the agent runs, log\n* files, and worktrees. The browser store mirrors only the\n* conversations the current page cares about and is rebuilt from\n* server state if it ever diverges.\n*\n* Naming follows the v2 plan (`pinagent-v2-plan.md` §4.2). When you\n* change a column here, run `pnpm --filter @pinagent/db drizzle:gen`\n* to produce a new migration; the server applies migrations on\n* connect.\n*/\n/**\n* One row per pinagent comment a developer submits. id is the nanoid\n* (matches the existing flat-file feedback id) so we can migrate\n* piecemeal without rewriting IDs.\n*\n* `status` mirrors what the MCP server writes today via `Storage.patch`\n* (`pending` / `fixed` / `wontfix` / `deferred`). `agentSessionId` is\n* the Claude Agent SDK session id we resume on follow-up turns.\n*/\nconst conversations = sqliteTable(\"conversations\", {\n\tid: text(\"id\").primaryKey(),\n\t/**\n\t* Comment text the developer wrote when submitting. Kept here in\n\t* addition to the original feedback JSON so SQLite-only readers\n\t* (browser cache) have it without a round-trip.\n\t*/\n\tcomment: text(\"comment\").notNull(),\n\t/** SDK session id, set after the first agent run. */\n\tagentSessionId: text(\"agent_session_id\"),\n\tstatus: text(\"status\", { enum: [\n\t\t\"pending\",\n\t\t\"fixed\",\n\t\t\"wontfix\",\n\t\t\"deferred\"\n\t] }).notNull().default(\"pending\"),\n\t/** Optional note left by the agent on resolve. */\n\tnote: text(\"note\"),\n\t/** Optional commit sha if the agent committed its fix. */\n\tcommitSha: text(\"commit_sha\"),\n\t/** When spawn mode is `worktree`, the git branch the agent ran in. */\n\tbranch: text(\"branch\"),\n\t/** When spawn mode is `worktree`, the absolute worktree path. */\n\tworktreePath: text(\"worktree_path\"),\n\t/**\n\t* Lifecycle of the worktree itself, orthogonal to `status` (which\n\t* tracks the developer's intent toward the feedback). `none` for\n\t* inline-mode rows that never created a worktree; `active` while the\n\t* worktree exists on disk; `landed` after a successful merge into\n\t* the project's HEAD branch; `discarded` after the developer threw\n\t* the work away. Once non-`active`, Land/Discard controls are hidden.\n\t*/\n\tworktreeState: text(\"worktree_state\", { enum: [\n\t\t\"none\",\n\t\t\"active\",\n\t\t\"landed\",\n\t\t\"discarded\"\n\t] }).notNull().default(\"none\"),\n\t/**\n\t* User-supplied title override. NULL means the dock falls back to a\n\t* title derived from `comment` (first non-empty line, ≤80 chars).\n\t* Renaming clears to NULL on empty input so the user can revert to\n\t* the agent-derived title without remembering what it was.\n\t*/\n\ttitle: text(\"title\"),\n\t/**\n\t* Soft-archive flag. Archived conversations are hidden from the\n\t* default Conversations list and excluded from the FAB pending count.\n\t* Orthogonal to status + worktreeState — you can archive an active\n\t* worktree (the worktree stays on disk) or a landed one (just hides\n\t* it from the active surface).\n\t*/\n\tarchived: integer(\"archived\", { mode: \"boolean\" }).notNull().default(false),\n\tcreatedAt: integer(\"created_at\", { mode: \"timestamp_ms\" }).notNull().default(sql`(unixepoch() * 1000)`),\n\tupdatedAt: integer(\"updated_at\", { mode: \"timestamp_ms\" }).notNull().default(sql`(unixepoch() * 1000)`),\n\tresolvedAt: integer(\"resolved_at\", { mode: \"timestamp_ms\" })\n});\n/**\n* DOM anchor metadata captured at pick time so the widget can\n* re-anchor itself across HMR / reloads (v2 plan Phase G). One row per\n* conversation.\n*\n* `clickX` / `clickY` are the cursor position relative to the target\n* element's top-left — preserved through scrolls and layout shifts the\n* same way the live widget does it.\n*/\nconst widgetAnchors = sqliteTable(\"widget_anchors\", {\n\tconversationId: text(\"conversation_id\").primaryKey().references(() => conversations.id, { onDelete: \"cascade\" }),\n\turl: text(\"url\").notNull(),\n\t/** From the `data-pa-loc` build-time attribute. */\n\tfile: text(\"file\"),\n\tline: integer(\"line\"),\n\tcol: integer(\"col\"),\n\t/** CSS-selector fallback for when `data-pa-loc` isn't available. */\n\tselector: text(\"selector\").notNull(),\n\tclickX: integer(\"click_x\"),\n\tclickY: integer(\"click_y\"),\n\tviewportW: integer(\"viewport_w\"),\n\tviewportH: integer(\"viewport_h\"),\n\t/** From `navigator.userAgent` at pick time. Mostly for debugging. */\n\tuserAgent: text(\"user_agent\"),\n\t/**\n\t* Enclosing component name, from the `data-pa-comp` attribute the\n\t* Babel plugin stamps next to `data-pa-loc`. Lets the agent prompt say\n\t* \"you clicked inside `<PriceCard>`\" rather than a bare file:line. Null\n\t* in uninstrumented apps or when the element sits outside any\n\t* PascalCase component.\n\t*/\n\tcomponent: text(\"component\"),\n\t/**\n\t* Outer→inner chain of distinct enclosing component names, e.g.\n\t* `[\"App\", \"PriceList\", \"PriceCard\"]`. Gives the agent structural\n\t* context about where in the component tree the target lives. Null\n\t* when nothing is instrumented.\n\t*/\n\tcomponentPath: text(\"component_path\", { mode: \"json\" }).$type(),\n\t/**\n\t* Loop-instance disambiguation. When the same JSX literal is rendered\n\t* more than once (a `.map()`), `data-pa-loc` is ambiguous: many DOM\n\t* nodes share one file:line. These capture *which* instance the user\n\t* clicked — `instanceIndex` is the 0-based position among siblings\n\t* sharing the loc and `instanceTotal` the count. Both null for the\n\t* common unique-loc case so single-pick rows are unchanged.\n\t*/\n\tinstanceIndex: integer(\"instance_index\"),\n\tinstanceTotal: integer(\"instance_total\"),\n\t/**\n\t* A short content fingerprint (text snippet + identity-ish attributes)\n\t* of the clicked instance, so the agent can locate the right `.map()`\n\t* item from the screenshot + source even though the file:line points\n\t* at the shared JSX literal. Null unless the loc was ambiguous.\n\t*/\n\tinstanceFingerprint: text(\"instance_fingerprint\"),\n\t/**\n\t* Secondary elements picked via Cmd/Ctrl-click before the committing\n\t* click. Same shape as the primary anchor's location columns, minus\n\t* the viewport/userAgent context (those are shared at the conversation\n\t* level). Null when the user picked exactly one element — the common\n\t* case — so the column adds no cost to single-pick conversations.\n\t*/\n\tadditionalAnchors: text(\"additional_anchors\", { mode: \"json\" }).$type()\n});\n/**\n* Append-only transcript of agent events. One row per AgentEvent\n* (init / text / tool_use / tool_result / ask_user / error / result)\n* plus user messages typed in the widget (`role: 'user'`).\n*\n* `turn` increments per agent turn so we can group events for replay\n* and for the \"Turn N\" sections in the markdown log file.\n*\n* This table IS the source of truth for the event stream. The bus\n* (`packages/agent-runner/src/bus.ts`) writes every publish straight\n* to this table and subscribers poll it — so cross-process delivery\n* works even when Vite-style dual-context module loading would\n* otherwise split an in-memory bus into separate instances. A `role`\n* of `__finished` is the bus's end-of-run sentinel (excluded from\n* external reads).\n*/\nconst messages = sqliteTable(\"messages\", {\n\tid: integer(\"id\").primaryKey({ autoIncrement: true }),\n\tconversationId: text(\"conversation_id\").notNull().references(() => conversations.id, { onDelete: \"cascade\" }),\n\tturn: integer(\"turn\").notNull(),\n\t/**\n\t* Discriminator. Matches AgentEvent.type plus `'user'` for typed\n\t* follow-ups. Keep as text (not an enum) so adding new event types\n\t* doesn't require a migration.\n\t*/\n\trole: text(\"role\").notNull(),\n\t/** Full event payload as JSON — kept opaque so schema evolves freely. */\n\tcontent: text(\"content\", { mode: \"json\" }).notNull(),\n\tcreatedAt: integer(\"created_at\", { mode: \"timestamp_ms\" }).notNull().default(sql`(unixepoch() * 1000)`)\n});\n/**\n* One row per in-flight SDK run. Server-only — the browser doesn't\n* need to know which runs are active, only their event stream.\n*\n* `awaitingAskId` is set whenever the `ask_user` tool is blocking on a\n* human response; lets the widget render the pending question\n* authoritatively even on a fresh page load.\n*/\nconst activeRuns = sqliteTable(\"active_runs\", {\n\tconversationId: text(\"conversation_id\").primaryKey().references(() => conversations.id, { onDelete: \"cascade\" }),\n\tstartedAt: integer(\"started_at\", { mode: \"timestamp_ms\" }).notNull(),\n\tcurrentTurn: integer(\"current_turn\").notNull(),\n\tawaitingAskId: text(\"awaiting_ask_id\"),\n\tlastError: text(\"last_error\")\n});\n/**\n* One row per GitHub PR the dock's compose flow has opened. Populated\n* by `composePullRequest` on the success path and read by the dock's\n* PRs route. The `state` column starts as `open` and is intended to be\n* reconciled against the GitHub API by a future refresh job — the\n* write path here only knows about creation.\n*\n* `conversationIds` is stored as a JSON array of the feedback ids the\n* compose flow bundled into the PR, mirroring what\n* `ComposeOpts.feedbackIds` carried in.\n*/\nconst pullRequests = sqliteTable(\"pull_requests\", {\n\tid: integer(\"id\").primaryKey({ autoIncrement: true }),\n\t/** GitHub PR number (unique within the repo). */\n\tnumber: integer(\"number\").notNull(),\n\t/** Octokit's `html_url` — what the dock links out to. */\n\turl: text(\"url\").notNull(),\n\t/** Compose branch name pushed for this PR. */\n\tbranch: text(\"branch\").notNull(),\n\t/** Target branch the PR merges into. */\n\tbaseBranch: text(\"base_branch\").notNull(),\n\ttitle: text(\"title\").notNull(),\n\t/**\n\t* PR body (markdown). Kept so the dock can show a preview without\n\t* round-tripping GitHub.\n\t*/\n\tbody: text(\"body\").notNull().default(\"\"),\n\tstate: text(\"state\", { enum: [\n\t\t\"open\",\n\t\t\"merged\",\n\t\t\"closed\",\n\t\t\"draft\"\n\t] }).notNull().default(\"open\"),\n\t/** Feedback/conversation ids bundled into this PR. */\n\tconversationIds: text(\"conversation_ids\", { mode: \"json\" }).$type().notNull().default(sql`('[]')`),\n\tcreatedAt: integer(\"created_at\", { mode: \"timestamp_ms\" }).notNull().default(sql`(unixepoch() * 1000)`),\n\tupdatedAt: integer(\"updated_at\", { mode: \"timestamp_ms\" }).notNull().default(sql`(unixepoch() * 1000)`)\n});\n/**\n* Append-only audit trail of meaningful project actions. Backs the\n* History route's Activity tab. Rows are derived from explicit emit\n* sites (Storage.create, mergeWorktree, discardWorktree,\n* composePullRequest); the table isn't a generic event sink and isn't\n* trying to mirror every WS event.\n*\n* `conversationId` is nullable so project-wide events (e.g. future\n* settings changes) can live here too, but every action emitted today\n* has one. `action` is kept as text — not an enum — so new actions can\n* land without a migration. `payload` is opaque JSON, shaped per-action\n* (e.g. `{ branch, commitSha }` for `conversation_landed`).\n*/\nconst auditEvents = sqliteTable(\"audit_events\", {\n\tid: integer(\"id\").primaryKey({ autoIncrement: true }),\n\tconversationId: text(\"conversation_id\"),\n\tactor: text(\"actor\", { enum: [\n\t\t\"agent\",\n\t\t\"user\",\n\t\t\"system\"\n\t] }).notNull(),\n\taction: text(\"action\").notNull(),\n\tpayload: text(\"payload\", { mode: \"json\" }).$type().notNull().default(sql`('{}')`),\n\tcreatedAt: integer(\"created_at\", { mode: \"timestamp_ms\" }).notNull().default(sql`(unixepoch() * 1000)`)\n});\n//#endregion\nexport { activeRuns, auditEvents, conversations, messages, pullRequests, widgetAnchors };\n\n//# sourceMappingURL=schema.js.map","import { z } from \"zod\";\n//#region src/cost.ts\n/**\n* Shared USD formatting for the running-cost displays. Both the in-page\n* widget tray and the dock's per-conversation cost chip render the same\n* dollar amounts, and used to carry byte-identical private copies of\n* this logic (each commented \"mirrors the other\"). Centralising it here\n* means the two surfaces can never drift on how a cost reads.\n*\n* Sub-cent amounts render at 4-decimal precision so a string of cheap\n* turns still surfaces a non-zero badge; >= $0.01 trims to two decimals.\n* Callers gate on `cost > 0`, so this never has to render \"$0\".\n*/\nfunction formatCompactUsd(usd) {\n\treturn usd < .01 ? `$${usd.toFixed(4)}` : `$${usd.toFixed(2)}`;\n}\n//#endregion\n//#region src/dock-api.ts\n/**\n* Zod schemas for the dock's HTTP boundary. The widget-dock package's\n* LocalTransport uses these to parse responses before handing them to\n* React; the server side (agent-runner via vite-plugin / next-plugin)\n* is free to use the same schemas to typecheck its return values.\n*\n* Phase 7b expanded the coverage to every read endpoint the dock hits.\n* Write endpoints (mutations) reuse the same response schemas.\n*\n* `.loose()` everywhere — unknown fields survive the parse so\n* additions to a payload don't break old dock builds.\n*/\n/** Dock-rendered status. Mirrors @pinagent/ui's StatusKey. */\nconst StatusKeySchema = z.enum([\n\t\"pending\",\n\t\"working\",\n\t\"awaitingClarification\",\n\t\"readyToLand\",\n\t\"landed\",\n\t\"discarded\",\n\t\"error\",\n\t\"anchorLost\"\n]);\nconst AnchorSchema = z.object({\n\tloc: z.string(),\n\tselector: z.string(),\n\tsnippet: z.string()\n}).loose();\nconst ConversationSchema = z.object({\n\tid: z.string(),\n\tshortId: z.string(),\n\ttitle: z.string(),\n\tstatus: StatusKeySchema,\n\tpage: z.string(),\n\tanchor: AnchorSchema,\n\tbranch: z.string(),\n\tupdatedAt: z.string(),\n\tlastMessage: z.string(),\n\tmessageCount: z.number().int().nonnegative()\n}).loose();\nconst ConversationDetailSchema = ConversationSchema.extend({\n\tcomment: z.string(),\n\tscreenshot: z.string().nullable()\n}).loose();\nconst ChangeSchema = z.object({\n\tid: z.string(),\n\tconversationId: z.string(),\n\tconversationTitle: z.string(),\n\tstatus: z.enum([\n\t\t\"readyToLand\",\n\t\t\"pending\",\n\t\t\"landed\",\n\t\t\"error\"\n\t]),\n\tbranch: z.string(),\n\tfilesChanged: z.number().int().nonnegative(),\n\tadditions: z.number().int().nonnegative(),\n\tdeletions: z.number().int().nonnegative(),\n\tpreview: z.string(),\n\tupdatedAt: z.string()\n}).loose();\nconst ChangeDiffSchema = z.object({\n\tdiff: z.string(),\n\ttruncated: z.boolean(),\n\t/**\n\t* Absolute path of the conversation's worktree, so the dock can open a\n\t* changed file at the agent's edited version. Optional for older servers.\n\t*/\n\tworktreePath: z.string().optional()\n}).loose();\nconst BranchSchema = z.object({\n\tid: z.string(),\n\tname: z.string(),\n\tconversationId: z.string().nullable(),\n\tconversationTitle: z.string().nullable(),\n\tcreatedAt: z.string(),\n\tlastActivity: z.string(),\n\tstate: z.enum([\n\t\t\"clean\",\n\t\t\"uncommitted\",\n\t\t\"behind-base\"\n\t]),\n\tdiskMb: z.number().nullable()\n}).loose();\nconst PullRequestSchema = z.object({\n\tid: z.string(),\n\tnumber: z.number().int(),\n\ttitle: z.string(),\n\tstate: z.enum([\n\t\t\"open\",\n\t\t\"merged\",\n\t\t\"closed\",\n\t\t\"draft\"\n\t]),\n\tbranch: z.string(),\n\tbaseBranch: z.string(),\n\turl: z.string(),\n\tupdatedAt: z.string(),\n\tconversationIds: z.array(z.string())\n}).loose();\nconst WorkingCopyFileSchema = z.object({\n\tpath: z.string(),\n\tadded: z.number().int().nonnegative(),\n\tdeleted: z.number().int().nonnegative(),\n\tstatus: z.enum([\n\t\t\"modified\",\n\t\t\"added\",\n\t\t\"deleted\",\n\t\t\"renamed\"\n\t])\n}).loose();\n/**\n* High-level git state of the branch the dev-server runs on — the data\n* behind the dock dashboard's working-changes hero. Mirrors\n* `@pinagent/agent-runner.WorkingCopyStatus`.\n*/\nconst WorkingCopyStatusSchema = z.object({\n\tbranch: z.string(),\n\tbaseBranch: z.string(),\n\tisDefaultBranch: z.boolean(),\n\tfilesChanged: z.number().int().nonnegative(),\n\tadditions: z.number().int().nonnegative(),\n\tdeletions: z.number().int().nonnegative(),\n\tfiles: z.array(WorkingCopyFileSchema),\n\tahead: z.number().int().nonnegative(),\n\tbehind: z.number().int().nonnegative(),\n\thasUpstream: z.boolean(),\n\tdirty: z.boolean(),\n\tpr: z.object({\n\t\tnumber: z.number().int(),\n\t\turl: z.string(),\n\t\tstate: z.enum([\n\t\t\t\"open\",\n\t\t\t\"merged\",\n\t\t\t\"closed\",\n\t\t\t\"draft\"\n\t\t])\n\t}).nullable()\n}).loose();\nconst PresentableConnectionsSchema = z.object({\n\tgithub: z.object({\n\t\tconnected: z.boolean(),\n\t\tlogin: z.string().nullable()\n\t}).loose(),\n\tanthropic: z.object({ keySet: z.boolean() }).loose()\n}).loose();\n/**\n* The three permission-mode options the dock's Settings picker exposes,\n* pinned alongside their SDK-mode equivalents and all human-facing\n* label text. Single source of truth — adding a fourth mode = one\n* append to this list, no scattered edits across the dock UI, the\n* detail-header chip, and the server-side translator.\n*\n* Consumers:\n* - `PermissionModeSchema` below (zod enum derived from `projectMode`)\n* - `agent-runner/settings-store` re-exports the schema/type\n* - `agent-runner/agent.toSdkPermissionMode` looks up `sdkMode`\n* - `widget-dock/routes/Settings.tsx` iterates this list for the\n* picker (uses `label` + `description`)\n* - `widget-dock/lib/permissionMode.ts` looks up the SDK→display\n* mapping for the detail-header chip (uses `shortLabel` + `tooltip`)\n*\n* `as const` so consumers can derive literal-string types.\n*/\nconst PROJECT_PERMISSION_MODES = [\n\t{\n\t\tprojectMode: \"auto\",\n\t\tsdkMode: \"acceptEdits\",\n\t\tlabel: \"Auto-accept edits\",\n\t\tshortLabel: \"Auto-accept\",\n\t\tdescription: \"Agent edits land in the worktree without confirmation.\",\n\t\ttooltip: \"Auto-accept edits — tool calls run without prompting.\"\n\t},\n\t{\n\t\tprojectMode: \"approve\",\n\t\tsdkMode: \"default\",\n\t\tlabel: \"Require approval\",\n\t\tshortLabel: \"Approval required\",\n\t\tdescription: \"Each edit pauses for your approval before applying.\",\n\t\ttooltip: \"Approval required — the agent prompts before each tool call.\"\n\t},\n\t{\n\t\tprojectMode: \"dry-run\",\n\t\tsdkMode: \"plan\",\n\t\tlabel: \"Dry-run only\",\n\t\tshortLabel: \"Dry-run\",\n\t\tdescription: \"Agents propose but never write. Useful for review-only setups.\",\n\t\ttooltip: \"Dry-run — plan mode: the agent reasons without running tools.\"\n\t}\n];\nconst PermissionModeSchema = z.enum(PROJECT_PERMISSION_MODES.map((m) => m.projectMode));\nconst DockProjectSettingsSchema = z.object({\n\tbaseBranch: z.string(),\n\tworktreeRetentionDays: z.number().int().nonnegative(),\n\tperConversationCapUsd: z.number(),\n\tmonthlyBudgetUsd: z.number().nullable(),\n\tpermissionMode: PermissionModeSchema,\n\t/**\n\t* If `PINAGENT_AGENT_PERMISSION_MODE` is set on the dev server, this\n\t* carries the resolved SDK mode that will *actually* be used at\n\t* spawn time — overriding the user's saved `permissionMode` above.\n\t* `null` when no env override is active. Read-only on the wire:\n\t* `ProjectSettingsPatchSchema.partial()` silently drops it on PATCH.\n\t*\n\t* Default is `null` so older servers without this field still parse\n\t* cleanly into the dock.\n\t*/\n\tpermissionModeOverride: z.string().nullable().default(null)\n}).loose();\nconst PruneStaleResultSchema = z.object({\n\tpruned: z.array(z.string()),\n\tfailed: z.array(z.object({\n\t\tfeedbackId: z.string(),\n\t\terror: z.string()\n\t}).loose()),\n\tretentionDays: z.number().int().nonnegative()\n}).loose();\nconst AuditActorSchema = z.enum([\n\t\"agent\",\n\t\"user\",\n\t\"system\"\n]);\nconst AuditEventSchema = z.object({\n\tid: z.string(),\n\tconversationId: z.string().nullable(),\n\tactor: AuditActorSchema,\n\taction: z.string(),\n\tpayload: z.record(z.string(), z.unknown()),\n\tcreatedAt: z.string()\n}).loose();\nconst HistoryMatchedFieldSchema = z.enum([\n\t\"comment\",\n\t\"note\",\n\t\"branch\",\n\t\"anchor\",\n\t\"selector\"\n]);\nconst HistorySearchHitSchema = z.object({\n\tid: z.string(),\n\tcomment: z.string(),\n\tstatus: z.enum([\n\t\t\"fixed\",\n\t\t\"wontfix\",\n\t\t\"pending\",\n\t\t\"deferred\"\n\t]),\n\tworktreeState: z.enum([\n\t\t\"none\",\n\t\t\"active\",\n\t\t\"landed\",\n\t\t\"discarded\"\n\t]),\n\tbranch: z.string().nullable(),\n\tfile: z.string().nullable(),\n\tline: z.number().nullable(),\n\tcol: z.number().nullable(),\n\tselector: z.string(),\n\turl: z.string(),\n\tcreatedAt: z.string(),\n\tupdatedAt: z.string(),\n\tresolvedAt: z.string().nullable(),\n\tmatchedFields: z.array(HistoryMatchedFieldSchema),\n\tsnippet: z.string()\n}).loose();\n//#endregion\n//#region src/dock-postmessage.ts\n/**\n* postMessage protocol between the embedded dock iframe and its host\n* page. Defines the wire contract; no runtime yet — the EmbeddedTransport\n* class that implements this protocol lands in a follow-up phase once\n* the dock has a real cross-origin context to talk to (the hosted\n* dashboard relay).\n*\n* Why the contract lives in @pinagent/shared today rather than in the\n* dock or host-script package:\n*\n* - Both sides of the boundary (the dock and the host's relay) need\n* the same schemas to validate inbound frames; pulling them from\n* a third package keeps either side independently swappable.\n*\n* - The hosted relay (apps/cloud) and the local dev relay\n* (packages/vite-plugin / packages/next-plugin) will both\n* implement the same host-side surface; one source of truth for\n* their input grammar makes the parity story explicit.\n*\n* Origin checking is strict in both directions and lives in the future\n* EmbeddedTransport class; the schemas here only validate shapes, not\n* provenance.\n*\n* Spec reference: pinpoint-dock-surface.md §5 (postMessage protocol).\n*/\n/**\n* RPC-style request. `id` is a UUID-ish correlation token the host\n* echoes back on the response so the dock can resolve the right\n* Promise. `path` mirrors the same-origin URL the LocalTransport hits\n* today (`/__pinagent/...`) so the host relay can forward without\n* its own routing table.\n*/\nconst DockToHostQuerySchema = z.object({\n\ttype: z.literal(\"query\"),\n\tid: z.string().min(1),\n\tpath: z.string().min(1),\n\tparams: z.record(z.string(), z.unknown()).optional()\n}).strict();\nconst DockToHostMutateSchema = z.object({\n\ttype: z.literal(\"mutate\"),\n\tid: z.string().min(1),\n\tpath: z.string().min(1),\n\tbody: z.unknown()\n}).strict();\n/**\n* Open a long-lived subscription to a server channel (project events,\n* per-conversation event stream, etc). The host relay keeps a map of\n* `subscriptionId → backend listener` and pushes back `event` frames.\n*/\nconst DockToHostSubscribeSchema = z.object({\n\ttype: z.literal(\"subscribe\"),\n\tchannel: z.string().min(1),\n\tsubscriptionId: z.string().min(1),\n\tparams: z.record(z.string(), z.unknown()).optional()\n}).strict();\nconst DockToHostUnsubscribeSchema = z.object({\n\ttype: z.literal(\"unsubscribe\"),\n\tsubscriptionId: z.string().min(1)\n}).strict();\n/**\n* Ask the host to open a popup window (OAuth flow, external link). The\n* host owns the window because the iframe sandbox bars\n* `allow-top-navigation`. Response comes back as `popup-closed` with\n* an optional result the popup posted to its opener pre-close.\n*/\nconst DockToHostOpenPopupSchema = z.object({\n\ttype: z.literal(\"open-popup\"),\n\turl: z.string().url(),\n\tsubscriptionId: z.string().min(1)\n}).strict();\n/**\n* Pure UI signals — open/close/resize — that the host might react to\n* (e.g. shifting the underlying page when the dock opens in panel\n* mode). The host doesn't have to handle these; the dock fires them\n* for observability.\n*/\nconst DockToHostUiEventSchema = z.object({\n\ttype: z.literal(\"ui-event\"),\n\tevent: z.enum([\n\t\t\"open\",\n\t\t\"close\",\n\t\t\"resize\"\n\t]),\n\tpayload: z.record(z.string(), z.unknown()).optional()\n}).strict();\nconst DockToHostSchema = z.discriminatedUnion(\"type\", [\n\tDockToHostQuerySchema,\n\tDockToHostMutateSchema,\n\tDockToHostSubscribeSchema,\n\tDockToHostUnsubscribeSchema,\n\tDockToHostOpenPopupSchema,\n\tDockToHostUiEventSchema\n]);\n/**\n* RPC response — `ok: true` carries the data, `ok: false` carries a\n* code + human-readable message so the dock can route into its\n* ErrorState components without re-deriving from string contents.\n*/\nconst HostToDockResponseSchema = z.discriminatedUnion(\"ok\", [z.object({\n\ttype: z.literal(\"response\"),\n\tid: z.string().min(1),\n\tok: z.literal(true),\n\tdata: z.unknown()\n}).strict(), z.object({\n\ttype: z.literal(\"response\"),\n\tid: z.string().min(1),\n\tok: z.literal(false),\n\terror: z.object({\n\t\tcode: z.string().min(1),\n\t\tmessage: z.string().min(1)\n\t}).strict()\n}).strict()]);\nconst HostToDockEventSchema = z.object({\n\ttype: z.literal(\"event\"),\n\tsubscriptionId: z.string().min(1),\n\tpayload: z.unknown()\n}).strict();\nconst HostToDockPopupClosedSchema = z.object({\n\ttype: z.literal(\"popup-closed\"),\n\tsubscriptionId: z.string().min(1),\n\tresult: z.record(z.string(), z.unknown()).optional()\n}).strict();\n/**\n* Once at iframe load (and on any host-side change worth re-broadcasting),\n* the host pushes its environment: which URL it's on, current viewport\n* dimensions, current theme. Lets the dock skip its own re-render\n* dance for context the host already knows.\n*/\nconst HostToDockContextSchema = z.object({\n\ttype: z.literal(\"host-context\"),\n\tpayload: z.object({\n\t\turl: z.string(),\n\t\tviewport: z.object({\n\t\t\tw: z.number().int().nonnegative(),\n\t\t\th: z.number().int().nonnegative()\n\t\t}).strict(),\n\t\ttheme: z.enum([\"light\", \"dark\"])\n\t}).strict()\n}).strict();\nconst HostToDockSchema = z.union([\n\tHostToDockResponseSchema,\n\tHostToDockEventSchema,\n\tHostToDockPopupClosedSchema,\n\tHostToDockContextSchema\n]);\n//#endregion\n//#region src/dock-status.ts\nfunction deriveDockStatus(status, worktreeState, isRunning = false) {\n\tif (isRunning) return \"working\";\n\tif (worktreeState === \"landed\") return \"landed\";\n\tif (worktreeState === \"discarded\") return \"discarded\";\n\tif (status === \"wontfix\") return \"discarded\";\n\tif (status === \"deferred\") return \"awaitingClarification\";\n\tif (status === \"fixed\") return \"readyToLand\";\n\tif (worktreeState === \"active\") return \"working\";\n\treturn \"pending\";\n}\n/**\n* Whether a derived status represents an agent the developer might still\n* want to act on — one mid-run, ready to land, or waiting on them. This\n* is the set the widget's running-agents tray surfaces; landed/discarded\n* (and the client-only error/anchorLost) are terminal or out of band.\n*/\nfunction isUnresolvedStatus(status) {\n\treturn status === \"working\" || status === \"readyToLand\" || status === \"awaitingClarification\";\n}\n//#endregion\n//#region src/event-bus.ts\n/**\n* Zod mirror of the AgentEvent union. Kept alongside the TS type so\n* the wire-boundary parse (ws-client on the dock) catches shape drift\n* the moment the server adds or renames a field — better than React\n* rendering `undefined` at runtime. Use `.loose()` on each\n* object so unknown fields survive the parse instead of being\n* stripped; future event-payload additions stay backwards compatible\n* for old clients.\n*/\nconst AgentEventSchema = z.discriminatedUnion(\"type\", [\n\tz.object({\n\t\ttype: z.literal(\"init\"),\n\t\tsessionId: z.string(),\n\t\tmodel: z.string(),\n\t\tpermissionMode: z.string(),\n\t\tapiKeySource: z.string()\n\t}).loose(),\n\tz.object({\n\t\ttype: z.literal(\"text\"),\n\t\ttext: z.string()\n\t}).loose(),\n\tz.object({\n\t\ttype: z.literal(\"tool_use\"),\n\t\tname: z.string(),\n\t\tsummary: z.string()\n\t}).loose(),\n\tz.object({\n\t\ttype: z.literal(\"tool_result\"),\n\t\tok: z.boolean()\n\t}).loose(),\n\tz.object({\n\t\ttype: z.literal(\"progress\"),\n\t\tturn: z.number()\n\t}).loose(),\n\tz.object({\n\t\ttype: z.literal(\"ask_user\"),\n\t\taskId: z.string(),\n\t\tquestion: z.string(),\n\t\tcontext: z.string().optional(),\n\t\toptions: z.array(z.string()).optional()\n\t}).loose(),\n\tz.object({\n\t\ttype: z.literal(\"error\"),\n\t\tmessage: z.string()\n\t}).loose(),\n\tz.object({\n\t\ttype: z.literal(\"result\"),\n\t\tsubtype: z.string(),\n\t\tnumTurns: z.number(),\n\t\ttotalCostUsd: z.number(),\n\t\tdurationMs: z.number(),\n\t\terrors: z.array(z.string()).optional()\n\t}).loose(),\n\tz.object({\n\t\ttype: z.literal(\"status_changed\"),\n\t\tstatus: z.enum([\n\t\t\t\"pending\",\n\t\t\t\"fixed\",\n\t\t\t\"wontfix\",\n\t\t\t\"deferred\"\n\t\t]),\n\t\tnote: z.string().nullable(),\n\t\tcommitSha: z.string().nullable(),\n\t\tresolvedAt: z.string().nullable()\n\t}).loose()\n]);\n/**\n* True when a run's reported `total_cost_usd` is notional rather than a\n* real charge — i.e. the SDK authenticated via a `claude login` session\n* (`apiKeySource === 'oauth'`) and the cost is billed against the Claude\n* subscription quota, not the developer's card. Both the in-page widget\n* footer and the dock's cost badge gate on this so the two surfaces can\n* never disagree on what counts as a billed run. If the SDK ever reports\n* a different string for subscription auth, change it here only.\n*/\nfunction isNotionalCost(apiKeySource) {\n\treturn apiKeySource === \"oauth\";\n}\n/**\n* True when a run's cost is unknown rather than genuinely zero — i.e. a\n* bring-your-own-model provider (`apiKeySource === 'cli'`) that wraps an\n* external agentic CLI which doesn't report cost, so we record\n* `totalCostUsd: 0` as a placeholder. Render surfaces use this to show\n* \"not tracked\" instead of a misleading \"$0.0000\" that reads as \"free\".\n* Single source of truth so the widget/dock/transcript stay consistent.\n*/\nfunction isUntrackedCost(apiKeySource) {\n\treturn apiKeySource === \"cli\";\n}\n//#endregion\n//#region src/render-transcript.ts\n/**\n* Plain-text renderer for an `AgentEvent[]` transcript.\n*\n* Shared so both `pinagent transcript` (CLI subcommand) and the MCP\n* server's `get_conversation_transcript` tool produce identical\n* output — agents and humans see the same string regardless of which\n* surface they read through, and there's exactly one place to evolve\n* the format.\n*\n* Output is terminal-friendly but deliberately ANSI-free. Pipe through\n* `bat` or `less -R` if you want highlights.\n*/\n/**\n* Render a transcript as plain text. One block per event, ordered by\n* the array. Returns \"(no events recorded)\\n\" for an empty input so\n* the caller can write the result unconditionally to stdout.\n*/\nfunction renderTranscript(events) {\n\tconst rendered = events.filter((e) => e.type !== \"progress\");\n\tif (rendered.length === 0) return \"(no events recorded)\\n\";\n\tconst init = rendered.find((e) => e.type === \"init\");\n\tconst apiKeySource = init?.type === \"init\" ? init.apiKeySource : null;\n\treturn `${rendered.map((event) => renderEvent(event, apiKeySource)).join(\"\\n\\n\")}\\n`;\n}\nfunction renderEvent(event, apiKeySource) {\n\tswitch (event.type) {\n\t\tcase \"init\": return `[init] ${event.sessionId} · ${event.model} · ${event.permissionMode} (${event.apiKeySource})`;\n\t\tcase \"text\": return event.text.split(\"\\n\").map((line) => `> ${line}`).join(\"\\n\");\n\t\tcase \"tool_use\": return `[tool_use] ${event.name}${event.summary ? ` · ${event.summary}` : \"\"}`;\n\t\tcase \"tool_result\": return `[tool_result] ${event.ok ? \"ok\" : \"error\"}`;\n\t\tcase \"progress\": return \"\";\n\t\tcase \"ask_user\": {\n\t\t\tconst opts = event.options?.length ? ` · options: ${event.options.join(\" | \")}` : \"\";\n\t\t\tconst ctx = event.context ? `\\n ${event.context}` : \"\";\n\t\t\treturn `[ask_user] ${event.question}${opts}${ctx}`;\n\t\t}\n\t\tcase \"error\": return `[error] ${event.message}`;\n\t\tcase \"result\": {\n\t\t\tconst cost = isUntrackedCost(apiKeySource) ? \"cost not tracked\" : isNotionalCost(apiKeySource) ? `≈$${event.totalCostUsd.toFixed(4)} API-equivalent (subscription)` : `$${event.totalCostUsd.toFixed(4)}`;\n\t\t\tconst dur = `${(event.durationMs / 1e3).toFixed(2)}s`;\n\t\t\tconst errs = event.errors?.length ? ` · errors: ${event.errors.join(\", \")}` : \"\";\n\t\t\treturn `[result] ${event.subtype} · ${event.numTurns} turn(s) · ${cost} · ${dur}${errs}`;\n\t\t}\n\t\tcase \"status_changed\": {\n\t\t\tconst note = event.note ? ` · ${event.note}` : \"\";\n\t\t\tconst sha = event.commitSha ? ` (${event.commitSha.slice(0, 8)})` : \"\";\n\t\t\treturn `[status_changed] ${event.status}${sha}${note}`;\n\t\t}\n\t}\n}\n//#endregion\n//#region src/ws-protocol.ts\n/**\n* Wire-format messages between the browser widget and the dev-side\n* WebSocket server.\n*\n* Validated on the server with the Zod schemas below. Client-side is\n* untyped at the wire boundary — the widget renders defensively.\n*\n* Reserved for the connection lifecycle:\n* - `ping` / `pong` — explicit liveness check (the `ws` library also\n* runs lower-level WS ping frames; this is\n* application-level and visible in protocol logs).\n*\n* Per-feedback subscribe/unsubscribe so one socket can multiplex\n* multiple in-flight agents — sets us up for the v2 \"multiple widgets\n* per page\" goal without changing the wire format.\n*/\nconst FeedbackId = z.string().min(8).max(16).regex(/^[A-Za-z0-9_-]+$/);\nconst ClientMessageSchema = z.discriminatedUnion(\"type\", [\n\tz.object({\n\t\ttype: z.literal(\"subscribe\"),\n\t\tfeedbackId: FeedbackId\n\t}),\n\tz.object({\n\t\ttype: z.literal(\"unsubscribe\"),\n\t\tfeedbackId: FeedbackId\n\t}),\n\tz.object({\n\t\ttype: z.literal(\"user_message\"),\n\t\tfeedbackId: FeedbackId,\n\t\tcontent: z.string().min(1).max(8e3)\n\t}),\n\tz.object({\n\t\ttype: z.literal(\"ask_response\"),\n\t\taskId: z.string().min(1).max(64),\n\t\tanswer: z.string().max(8e3)\n\t}),\n\tz.object({\n\t\ttype: z.literal(\"interrupt\"),\n\t\tfeedbackId: FeedbackId\n\t}),\n\tz.object({\n\t\ttype: z.literal(\"land_request\"),\n\t\tfeedbackId: FeedbackId\n\t}),\n\tz.object({\n\t\ttype: z.literal(\"discard_request\"),\n\t\tfeedbackId: FeedbackId\n\t}),\n\tz.object({\n\t\ttype: z.literal(\"reopen_request\"),\n\t\tfeedbackId: FeedbackId\n\t}),\n\tz.object({ type: z.literal(\"subscribe_project\") }),\n\tz.object({ type: z.literal(\"unsubscribe_project\") }),\n\tz.object({\n\t\ttype: z.literal(\"extension_hello\"),\n\t\tversion: z.string().max(32).optional()\n\t}),\n\tz.object({ type: z.literal(\"query_extension\") }),\n\tz.object({\n\t\ttype: z.literal(\"set_branch_routing\"),\n\t\tdefaultBaseBranch: z.string().min(1).max(128).nullable(),\n\t\tallowedBranchPatterns: z.array(z.string().min(1).max(128)).max(50)\n\t}),\n\tz.object({ type: z.literal(\"ping\") })\n]);\nconst ProjectEventSchema = z.discriminatedUnion(\"type\", [z.object({ type: z.literal(\"conversations_changed\") }).loose(), z.object({ type: z.literal(\"worktree_servers_changed\") }).loose()]);\n/**\n* Phase H lifecycle states the server can broadcast for a worktree.\n* Mirrors `Conversation.worktreeState` plus two transient states:\n* - `landing` / `discarding` — operation is in flight (optimistic UI hint)\n* - `conflict` — merge aborted because of conflicts; `conflicts` lists files\n* - `ttl_warning` — orphan-sweeper found this worktree past TTL\n*/\nconst WorktreeWireStateSchema = z.enum([\n\t\"none\",\n\t\"active\",\n\t\"landing\",\n\t\"landed\",\n\t\"discarding\",\n\t\"discarded\",\n\t\"conflict\",\n\t\"ttl_warning\"\n]);\n/**\n* Runtime guard at the wire boundary. The dock's ws-client `safeParse`s\n* every incoming frame so drift in the server's wire format surfaces\n* as a dropped frame, not as `undefined` rendered into React.\n*\n* Kept separate from the manual `ServerMessage` type union above: the\n* type union narrows cleanly under discriminated-union semantics, and\n* the schema's `.loose()` index signatures would block that\n* narrowing for spread-and-mutate constructions on the agent-runner\n* side. Both must stay in sync — when adding a variant, update both.\n*/\nconst ServerMessageSchema = z.discriminatedUnion(\"type\", [\n\tz.object({\n\t\ttype: z.literal(\"event\"),\n\t\tfeedbackId: z.string(),\n\t\tevent: AgentEventSchema\n\t}).loose(),\n\tz.object({\n\t\ttype: z.literal(\"done\"),\n\t\tfeedbackId: z.string()\n\t}).loose(),\n\tz.object({\n\t\ttype: z.literal(\"error\"),\n\t\tfeedbackId: z.string().optional(),\n\t\tmessage: z.string()\n\t}).loose(),\n\tz.object({\n\t\ttype: z.literal(\"worktree_state\"),\n\t\tfeedbackId: z.string(),\n\t\tstate: WorktreeWireStateSchema,\n\t\tcommitSha: z.string().optional(),\n\t\tconflicts: z.array(z.string()).optional(),\n\t\tmessage: z.string().optional(),\n\t\tchangesCount: z.number().optional()\n\t}).loose(),\n\tz.object({\n\t\ttype: z.literal(\"project_event\"),\n\t\tevent: ProjectEventSchema\n\t}).loose(),\n\tz.object({\n\t\ttype: z.literal(\"extension_status\"),\n\t\tpresent: z.boolean(),\n\t\tversion: z.string().optional()\n\t}).loose(),\n\tz.object({ type: z.literal(\"pong\") }).loose()\n]);\n//#endregion\n//#region src/index.ts\nconst PACKAGE_NAME = \"@pinagent/shared\";\n//#endregion\nexport { AgentEventSchema, AuditActorSchema, AuditEventSchema, BranchSchema, ChangeDiffSchema, ChangeSchema, ClientMessageSchema, ConversationDetailSchema, ConversationSchema, DockProjectSettingsSchema, DockToHostSchema, HistoryMatchedFieldSchema, HistorySearchHitSchema, HostToDockSchema, PACKAGE_NAME, PROJECT_PERMISSION_MODES, PermissionModeSchema, PresentableConnectionsSchema, ProjectEventSchema, PruneStaleResultSchema, PullRequestSchema, ServerMessageSchema, StatusKeySchema, WorkingCopyFileSchema, WorkingCopyStatusSchema, WorktreeWireStateSchema, deriveDockStatus, formatCompactUsd, isNotionalCost, isUnresolvedStatus, isUntrackedCost, renderTranscript };\n\n//# sourceMappingURL=index.js.map","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { access, copyFile, mkdir, open, readFile, rename, rm, writeFile } from \"node:fs/promises\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { auditEvents, desc, eq, pullRequests } from \"@pinagent/db\";\nimport { PROJECT_PERMISSION_MODES, PermissionModeSchema } from \"@pinagent/shared\";\nimport { z } from \"zod\";\nimport { nanoid } from \"nanoid\";\nimport { createHash } from \"node:crypto\";\nimport { DatabaseSync } from \"node:sqlite\";\nimport { fileURLToPath } from \"node:url\";\nimport * as schema from \"@pinagent/db/schema\";\nimport { drizzle } from \"drizzle-orm/sqlite-proxy\";\nimport { spawn } from \"node:child_process\";\nimport { Octokit } from \"@octokit/rest\";\n//#region src/atomic-file.ts\n/**\n* Small helpers for safe on-disk JSON stores (secrets, settings):\n*\n* - `withFileLock` serializes a read-modify-write critical section against a\n* path across all callers in this process, so two concurrent `patch()` calls\n* can't both read the same base and clobber each other's update.\n* - `atomicWriteFile` writes a sibling temp file (at the requested mode) then\n* renames it over the target, so a reader never sees a half-written file and\n* a sensitive file is never momentarily world-readable. A crash mid-write\n* leaves the previous file intact instead of truncating it.\n*/\nconst locks = /* @__PURE__ */ new Map();\nlet tmpCounter = 0;\n/** Run `fn` holding an exclusive in-process lock keyed by `key` (a file path). */\nfunction withFileLock(key, fn) {\n\tconst run = (locks.get(key) ?? Promise.resolve()).then(fn, fn);\n\tconst tail = run.then(() => {}, () => {});\n\tlocks.set(key, tail);\n\ttail.then(() => {\n\t\tif (locks.get(key) === tail) locks.delete(key);\n\t});\n\treturn run;\n}\n/**\n* Atomically write `data` to `path`: write a temp sibling (created with `mode`\n* when given, so it's never momentarily more permissive than intended) and\n* rename it over the target. Cleans up the temp on failure.\n*/\nasync function atomicWriteFile(path, data, mode) {\n\tawait mkdir(dirname(path), { recursive: true });\n\tconst tmp = `${path}.tmp-${process.pid}-${tmpCounter++}`;\n\ttry {\n\t\tawait writeFile(tmp, data, mode !== void 0 ? { mode } : void 0);\n\t\tawait rename(tmp, path);\n\t} catch (err) {\n\t\tawait rm(tmp, { force: true }).catch(() => {});\n\t\tthrow err;\n\t}\n}\nconst ProjectSettingsSchema = z.object({\n\tbaseBranch: z.string().min(1).max(128).regex(/^[A-Za-z0-9][A-Za-z0-9/_.-]*$/, \"invalid branch name\"),\n\tworktreeRetentionDays: z.number().int().min(1).max(60),\n\tperConversationCapUsd: z.number().min(.1).max(1e3),\n\tmonthlyBudgetUsd: z.number().min(0).max(1e5).nullable(),\n\tpermissionMode: PermissionModeSchema,\n\tallowedBranchPatterns: z.array(z.string().min(1).max(128)).max(50)\n});\nconst ProjectSettingsPatchSchema = ProjectSettingsSchema.partial();\nconst DEFAULT_SETTINGS = {\n\tbaseBranch: \"main\",\n\tworktreeRetentionDays: 7,\n\tperConversationCapUsd: 5,\n\tmonthlyBudgetUsd: null,\n\tpermissionMode: \"auto\",\n\tallowedBranchPatterns: []\n};\nvar SettingsStore = class {\n\tprojectRoot;\n\tconstructor(projectRoot) {\n\t\tthis.projectRoot = projectRoot;\n\t}\n\tpath() {\n\t\treturn join(this.projectRoot, \".pinagent\", \"config.json\");\n\t}\n\tasync read() {\n\t\tconst path = this.path();\n\t\tif (!existsSync(path)) return DEFAULT_SETTINGS;\n\t\ttry {\n\t\t\tconst raw = await readFile(path, \"utf8\");\n\t\t\tconst merged = {\n\t\t\t\t...DEFAULT_SETTINGS,\n\t\t\t\t...JSON.parse(raw)\n\t\t\t};\n\t\t\treturn ProjectSettingsSchema.parse(merged);\n\t\t} catch {\n\t\t\treturn DEFAULT_SETTINGS;\n\t\t}\n\t}\n\tasync patch(patch) {\n\t\tconst path = this.path();\n\t\treturn withFileLock(path, async () => {\n\t\t\tconst current = await this.read();\n\t\t\tconst next = ProjectSettingsSchema.parse({\n\t\t\t\t...current,\n\t\t\t\t...patch\n\t\t\t});\n\t\t\tawait atomicWriteFile(path, JSON.stringify(next, null, 2));\n\t\t\treturn next;\n\t\t});\n\t}\n};\n//#endregion\n//#region src/db/client.ts\n{\n\tconst proc = process;\n\tconst originalEmit = proc.emit.bind(proc);\n\tproc.emit = (event, ...args) => {\n\t\tif (event === \"warning\") {\n\t\t\tconst warning = args[0];\n\t\t\tif (warning instanceof Error && warning.name === \"ExperimentalWarning\" && warning.message.startsWith(\"SQLite is an experimental feature\")) return false;\n\t\t}\n\t\treturn originalEmit(event, ...args);\n\t};\n}\n/**\n* One Drizzle handle per dev process, keyed by project root so a\n* monorepo with multiple Pinagent-enabled apps gets distinct DBs.\n*\n* Storage is per-process and held on a globalThis Symbol so Next 16's\n* route module re-evaluations don't open the same DB file twice. The\n* underlying node:sqlite handle is cheap to keep open for the lifetime\n* of `next dev`.\n*\n* We use Node's built-in `node:sqlite` (stable since Node 22.13) rather\n* than `better-sqlite3` to avoid the native-build install step (pnpm\n* 10+ blocks postinstall by default; users were hitting\n* `Could not locate the bindings file` after fresh installs). Same\n* underlying SQLite engine, same on-disk format — no data migration.\n*\n* `drizzle-orm/sqlite-proxy` is the right adapter shape: it takes a\n* callback that executes SQL against any backend. We thread node:sqlite\n* synchronous calls through it. Drizzle exposes an async API to\n* consumers but our storage layer already `await`s everything, so call\n* sites are unchanged.\n*/\nconst SINGLETON_KEY = Symbol.for(\"pinagent.db\");\nconst moduleUrl = import.meta.url;\nconst MIGRATIONS_DIR = (() => {\n\tconst base = moduleUrl ? dirname(fileURLToPath(moduleUrl)) : __dirname;\n\tconst candidates = [\n\t\tresolve(base, \"..\", \"drizzle\"),\n\t\tresolve(base, \"..\", \"..\", \"db\", \"drizzle\"),\n\t\tresolve(base, \"..\", \"..\", \"..\", \"db\", \"drizzle\")\n\t];\n\treturn candidates.find((p) => existsSync(resolve(p, \"meta\", \"_journal.json\"))) ?? candidates[0];\n})();\n/**\n* Wrap a `node:sqlite` DatabaseSync in the drizzle-orm/sqlite-proxy\n* callback shape. `method` distinguishes 'run' (no rows expected,\n* returns changes / lastInsertRowid) from 'all' / 'get' / 'values'\n* (rows). The proxy callback is declared async; we just call the sync\n* primitives and return synchronously — Drizzle awaits the result.\n*/\nfunction makeDrizzle(raw) {\n\treturn drizzle(async (sql, params, method) => {\n\t\tconst stmt = raw.prepare(sql);\n\t\tif (method === \"run\") {\n\t\t\tconst info = stmt.run(...params);\n\t\t\treturn { rows: [{\n\t\t\t\tchanges: Number(info.changes),\n\t\t\t\tlastInsertRowid: info.lastInsertRowid\n\t\t\t}] };\n\t\t}\n\t\tconst rows = stmt.all(...params);\n\t\tconst columns = stmt.columns().map((c) => c.column ?? c.name);\n\t\tconst projected = rows.map((r) => columns.map((c) => r[c] ?? null));\n\t\tif (method === \"get\") return { rows: projected[0] ?? [] };\n\t\treturn { rows: projected };\n\t}, { schema });\n}\n/**\n* Apply every `.sql` migration in journal order. Replaces\n* `drizzle-orm/better-sqlite3/migrator` (which is bound to the\n* better-sqlite3 driver) with a tiny equivalent that drives node:sqlite\n* directly. Mirrors the browser-side migrator pattern in\n* `packages/widget/src/db/migrations.ts`.\n*/\nfunction runMigrations(raw, migrationsDir) {\n\tconst journalPath = join(migrationsDir, \"meta\", \"_journal.json\");\n\tif (!existsSync(journalPath)) {\n\t\tconsole.warn(`[pinagent:db] no migrations dir at ${migrationsDir}; skipping migrate(). Run \\`pnpm --filter @pinagent/db drizzle:gen\\` to generate.`);\n\t\treturn;\n\t}\n\traw.exec(`CREATE TABLE IF NOT EXISTS __drizzle_migrations (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n hash TEXT NOT NULL,\n created_at NUMERIC\n )`);\n\tconst sortedEntries = JSON.parse(readFileSync(journalPath, \"utf8\")).entries.slice().sort((a, b) => a.idx - b.idx);\n\tconst hashOf = (entry) => {\n\t\tconst sql = readFileSync(join(migrationsDir, `${entry.tag}.sql`), \"utf8\");\n\t\treturn createHash(\"sha256\").update(sql).digest(\"hex\");\n\t};\n\tconst insert = raw.prepare(\"INSERT INTO __drizzle_migrations (hash, created_at) VALUES (?, ?)\");\n\tconst lastRow = raw.prepare(\"SELECT created_at FROM __drizzle_migrations ORDER BY created_at DESC LIMIT 1\").get();\n\tlet lastWhen = lastRow?.created_at != null ? Number(lastRow.created_at) : null;\n\tif (lastWhen == null && sortedEntries.length > 0) {\n\t\tif (raw.prepare(\"SELECT 1 FROM sqlite_master WHERE type='table' AND name='conversations'\").get()) {\n\t\t\tfor (const entry of sortedEntries) insert.run(hashOf(entry), entry.when);\n\t\t\treturn;\n\t\t}\n\t}\n\tfor (const entry of sortedEntries) {\n\t\tif (lastWhen != null && lastWhen >= entry.when) continue;\n\t\tconst sql = readFileSync(join(migrationsDir, `${entry.tag}.sql`), \"utf8\");\n\t\tconst statements = sql.split(\"--> statement-breakpoint\").map((s) => s.trim()).filter(Boolean);\n\t\tfor (const stmt of statements) raw.exec(stmt);\n\t\tinsert.run(createHash(\"sha256\").update(sql).digest(\"hex\"), entry.when);\n\t\tlastWhen = entry.when;\n\t}\n}\nfunction getDb(projectRoot) {\n\tconst g = globalThis;\n\tif (!g[SINGLETON_KEY]) g[SINGLETON_KEY] = /* @__PURE__ */ new Map();\n\tconst cache = g[SINGLETON_KEY];\n\tconst root = resolve(projectRoot);\n\tconst existing = cache.get(root);\n\tif (existing) return existing.db;\n\tconst dbPath = join(root, \".pinagent\", \"db.sqlite\");\n\tconst pinagentDir = dirname(dbPath);\n\tmkdirSync(pinagentDir, { recursive: true });\n\tconst giPath = join(pinagentDir, \".gitignore\");\n\tif (!existsSync(giPath)) try {\n\t\twriteFileSync(giPath, \"*\\n\");\n\t} catch {}\n\tconst raw = new DatabaseSync(dbPath);\n\traw.exec(\"PRAGMA journal_mode = WAL\");\n\traw.exec(\"PRAGMA busy_timeout = 5000\");\n\traw.exec(\"PRAGMA foreign_keys = ON\");\n\trunMigrations(raw, MIGRATIONS_DIR);\n\traw.exec(\"DELETE FROM active_runs\");\n\tconst db = makeDrizzle(raw);\n\tcache.set(root, {\n\t\tdb,\n\t\traw\n\t});\n\treturn db;\n}\n//#endregion\n//#region src/git-utils.ts\n/**\n* Shared `git` runner. Lifted out of agent.ts so other modules\n* (changes.ts, future PR-composer code) can use the same spawn shape\n* without importing the whole agent module + its SDK pulls.\n*/\n/**\n* Spawn `git` with the given args in `cwd`, capturing stdout and stderr.\n* Never rejects on non-zero exit — callers inspect `code` themselves\n* because non-zero exits are meaningful for several git commands\n* (`git merge` returns 1 on conflict, `git rev-parse` returns non-zero\n* for missing refs, etc).\n*/\nfunction runGitCapture(cwd, args, opts = {}) {\n\treturn runCapture(\"git\", args, cwd, opts);\n}\n/**\n* Generic command-capture, same drain-safe shape as {@link runGitCapture}\n* (resolves on 'close', never rejects on non-zero exit). Used for `gh` (PR\n* creation fallback) as well as `git`. Rejects only if the binary can't be\n* spawned (e.g. `gh` not installed → ENOENT) — callers catch that to treat\n* the tool as unavailable.\n*/\nfunction runCapture(file, args, cwd, opts = {}) {\n\treturn new Promise((resolve, reject) => {\n\t\tconst child = spawn(file, args, {\n\t\t\tcwd,\n\t\t\tstdio: \"pipe\"\n\t\t});\n\t\tlet stdout = \"\";\n\t\tlet stderr = \"\";\n\t\tlet capped = false;\n\t\tconst max = opts.maxBytes;\n\t\tchild.stdout.on(\"data\", (d) => {\n\t\t\tif (capped) return;\n\t\t\tstdout += d.toString(\"utf8\");\n\t\t\tif (max !== void 0 && stdout.length >= max) {\n\t\t\t\tstdout = stdout.slice(0, max);\n\t\t\t\tcapped = true;\n\t\t\t\tchild.kill();\n\t\t\t}\n\t\t});\n\t\tchild.stderr.on(\"data\", (d) => {\n\t\t\tstderr += d.toString(\"utf8\");\n\t\t});\n\t\tchild.on(\"error\", reject);\n\t\tchild.on(\"close\", (code) => resolve({\n\t\t\tcode: code ?? -1,\n\t\t\tstdout,\n\t\t\tstderr,\n\t\t\tcapped\n\t\t}));\n\t});\n}\n/**\n* Spawn `git` and reject on non-zero exit, appending a diagnostic line to\n* the conversation log. Used for fire-and-forget mutations (`worktree add`)\n* where the caller wants an exception on failure rather than inspecting a\n* code — contrast with `runGitCapture`, which never rejects.\n*/\nfunction runGit(cwd, args, logPath) {\n\treturn new Promise((res, rej) => {\n\t\tconst child = spawn(\"git\", args, {\n\t\t\tcwd,\n\t\t\tstdio: \"pipe\"\n\t\t});\n\t\tlet stderr = \"\";\n\t\tchild.stderr.on(\"data\", (d) => {\n\t\t\tstderr += d.toString(\"utf8\");\n\t\t});\n\t\tchild.on(\"error\", rej);\n\t\tchild.on(\"close\", (code) => {\n\t\t\tif (code === 0) res();\n\t\t\telse {\n\t\t\t\tappendLog(logPath, `[pinagent:git] git ${args.join(\" \")} → exit ${code}\\n${stderr}\\n`).catch(() => {});\n\t\t\t\trej(/* @__PURE__ */ new Error(`git ${args.join(\" \")} exited ${code}: ${stderr.trim()}`));\n\t\t\t}\n\t\t});\n\t});\n}\n/**\n* Whether `cwd` is inside a git work tree. Use this instead of\n* `existsSync(join(cwd, '.git'))` — the dev server can run from a\n* subdirectory of the repo (e.g. an example app), where there's no `.git`\n* entry, or from a linked worktree, where `.git` is a *file* at the\n* worktree root and absent in subdirs. `git rev-parse` walks up like git\n* itself, so it's correct in all those cases. Never throws.\n*/\nasync function isInsideWorkTree(cwd) {\n\tconst res = await runGitCapture(cwd, [\"rev-parse\", \"--is-inside-work-tree\"]);\n\treturn res.code === 0 && res.stdout.trim() === \"true\";\n}\n/** Whether `cwd`'s working tree has uncommitted changes (`git status --porcelain`). */\nasync function isWorkingTreeDirty(cwd) {\n\tconst res = await runGitCapture(cwd, [\"status\", \"--porcelain\"]);\n\treturn res.code === 0 && res.stdout.trim().length > 0;\n}\n/** Append `text` to the file at `path`, creating it if needed. No-op on empty text. */\nasync function appendLog(path, text) {\n\tif (!text) return;\n\tconst h = await open(path, \"a\");\n\ttry {\n\t\tawait h.write(text);\n\t} finally {\n\t\tawait h.close();\n\t}\n}\n//#endregion\n//#region src/secrets-store.ts\n/**\n* Plaintext secrets at rest under `.pinagent/secrets.json`. The\n* dock's Connections route reads / writes via the HTTP endpoints\n* in `vite-plugin` / `next-plugin`, which call into this.\n*\n* For local dev: the secrets file lives on the same filesystem as\n* the user's git credentials, `.env` files, and shell history —\n* there's no real threat model improvement from encrypting at\n* rest. The hosted dashboard tier (spec §13 onwards) will need a\n* different storage backend; the API surface here is shaped so\n* that swap is local.\n*\n* Tokens never round-trip back out — readers either consume the\n* raw token inside the agent process (composer, SDK), or get the\n* presentable shape via `presentable()`.\n*/\nconst SecretsFileSchema = z.object({\n\tgithub: z.object({\n\t\ttoken: z.string().min(1),\n\t\t/** Cached from the validate-on-set GitHub `/user` call. */\n\t\tlogin: z.string().min(1)\n\t}).nullable().optional(),\n\tanthropic: z.object({ key: z.string().min(1) }).nullable().optional()\n}).default({});\nvar SecretsStore = class {\n\tprojectRoot;\n\tconstructor(projectRoot) {\n\t\tthis.projectRoot = projectRoot;\n\t}\n\tpath() {\n\t\treturn join(this.projectRoot, \".pinagent\", \"secrets.json\");\n\t}\n\t/** Read + parse. Returns `{}` for \"no file yet\" — that's expected on first run. */\n\tasync read() {\n\t\tconst path = this.path();\n\t\tif (!existsSync(path)) return SecretsFileSchema.parse({});\n\t\ttry {\n\t\t\tconst raw = await readFile(path, \"utf8\");\n\t\t\treturn SecretsFileSchema.parse(JSON.parse(raw));\n\t\t} catch {\n\t\t\treturn SecretsFileSchema.parse({});\n\t\t}\n\t}\n\tasync patch(patch) {\n\t\tconst path = this.path();\n\t\treturn withFileLock(path, async () => {\n\t\t\tconst next = {\n\t\t\t\t...await this.read(),\n\t\t\t\t...patch\n\t\t\t};\n\t\t\tawait atomicWriteFile(path, JSON.stringify(next, null, 2), 384);\n\t\t\treturn next;\n\t\t});\n\t}\n\tasync setGithub(token, login) {\n\t\tawait this.patch({ github: {\n\t\t\ttoken,\n\t\t\tlogin\n\t\t} });\n\t}\n\tasync clearGithub() {\n\t\tawait this.patch({ github: null });\n\t}\n\tasync setAnthropic(key) {\n\t\tawait this.patch({ anthropic: { key } });\n\t}\n\tasync clearAnthropic() {\n\t\tawait this.patch({ anthropic: null });\n\t}\n\tasync getGithubToken() {\n\t\treturn (await this.read()).github?.token ?? null;\n\t}\n\tasync getAnthropicKey() {\n\t\treturn (await this.read()).anthropic?.key ?? null;\n\t}\n\t/** Token-free view safe to ship over the wire. */\n\tasync presentable() {\n\t\tconst f = await this.read();\n\t\treturn {\n\t\t\tgithub: {\n\t\t\t\tconnected: Boolean(f.github),\n\t\t\t\tlogin: f.github?.login ?? null\n\t\t\t},\n\t\t\tanthropic: { keySet: Boolean(f.anthropic) }\n\t\t};\n\t}\n};\n//#endregion\n//#region src/audit-log.ts\n/**\n* Audit log — append-only record of meaningful project actions. Backs\n* the dock's History → Activity tab.\n*\n* Emitted at the action sites (Storage.create, mergeWorktree,\n* discardWorktree, composePullRequest) rather than tailing every event\n* the WS bus carries: the goal is a human-readable trail of what\n* happened to each conversation, not a transaction log.\n*\n* Writes are best-effort — `recordAuditEvent` swallows DB errors so a\n* failed audit insert can never mask a successful land/discard/PR. The\n* read side is exposed via `listAuditEvents` and surfaces a single\n* GET /__pinagent/audit-log endpoint to the dock.\n*/\nasync function recordAuditEvent(projectRoot, input) {\n\ttry {\n\t\tawait getDb(projectRoot).insert(auditEvents).values({\n\t\t\tconversationId: input.conversationId ?? null,\n\t\t\tactor: input.actor,\n\t\t\taction: input.action,\n\t\t\tpayload: input.payload ?? {}\n\t\t});\n\t} catch {}\n}\nasync function listAuditEvents(projectRoot, opts = {}) {\n\tconst limit = Math.min(Math.max(opts.limit ?? 100, 1), 500);\n\tconst offset = Math.max(opts.offset ?? 0, 0);\n\tconst db = getDb(projectRoot);\n\tconst where = opts.conversationId ? eq(auditEvents.conversationId, opts.conversationId) : void 0;\n\treturn (await (where ? db.select().from(auditEvents).where(where) : db.select().from(auditEvents)).orderBy(desc(auditEvents.createdAt), desc(auditEvents.id)).limit(limit).offset(offset)).map((r) => ({\n\t\tid: String(r.id),\n\t\tconversationId: r.conversationId,\n\t\tactor: r.actor,\n\t\taction: r.action,\n\t\tpayload: r.payload,\n\t\tcreatedAt: r.createdAt.toISOString()\n\t}));\n}\n//#endregion\n//#region src/git-remote.ts\n/**\n* Parse `git remote get-url origin` into { host, owner, repo } so the\n* PR composer can call the right API. Only GitHub is recognized for\n* v1 — other hosts return `null` and the composer falls back to a\n* \"push succeeded, open the PR yourself\" path.\n*\n* Handles the two URL shapes git uses:\n* - SSH: git@github.com:owner/repo.git\n* - HTTPS: https://github.com/owner/repo(.git)\n*\n* Trailing `.git` is stripped. Anything else (gitlab, self-hosted,\n* weird shapes) returns null without throwing — the caller treats that\n* as \"no API path available, push only.\"\n*/\nconst SSH_RE = /^git@github\\.com:([^/]+)\\/([^/]+?)(?:\\.git)?$/;\nconst HTTPS_RE = /^https:\\/\\/github\\.com\\/([^/]+)\\/([^/]+?)(?:\\.git)?\\/?$/;\nfunction parseGitHubRemote(url) {\n\tconst trimmed = url.trim();\n\tconst ssh = SSH_RE.exec(trimmed);\n\tif (ssh) return {\n\t\thost: \"github.com\",\n\t\towner: ssh[1],\n\t\trepo: ssh[2]\n\t};\n\tconst https = HTTPS_RE.exec(trimmed);\n\tif (https) return {\n\t\thost: \"github.com\",\n\t\towner: https[1],\n\t\trepo: https[2]\n\t};\n\treturn null;\n}\n/**\n* Look up the `origin` remote URL of `projectRoot` and parse it. Returns\n* null if there is no origin remote (or it isn't GitHub) — the composer\n* surfaces this as the manual-create path, not an error.\n*/\nasync function resolveOriginRemote(projectRoot) {\n\tconst result = await runGitCapture(projectRoot, [\n\t\t\"remote\",\n\t\t\"get-url\",\n\t\t\"origin\"\n\t]);\n\tif (result.code !== 0) return null;\n\treturn parseGitHubRemote(result.stdout);\n}\n//#endregion\n//#region src/github-auth.ts\n/**\n* Resolve a GitHub token for server-side API calls (opening PRs,\n* reconciling PR state). One place owns the precedence so the compose\n* and refresh paths can't drift:\n*\n* dock-stored secret (Connections route) → GITHUB_TOKEN → PINAGENT_GITHUB_TOKEN\n*\n* The Connections secret is the interactive path; the env vars stay for\n* CI / scripting. Returns `undefined` when nothing is configured — the\n* caller treats that as \"no API path available.\"\n*/\nasync function resolveGithubToken(projectRoot) {\n\treturn await new SecretsStore(projectRoot).getGithubToken() ?? process.env.GITHUB_TOKEN ?? process.env.PINAGENT_GITHUB_TOKEN;\n}\n//#endregion\n//#region src/pull-requests.ts\n/**\n* `listPullRequests` — read the dock's record of PRs the compose flow\n* has opened, newest activity first.\n*\n* Rows are written by `composePullRequest` on the success path. The read\n* side doesn't reach out to GitHub; `state` reflects whatever the last\n* `refreshPullRequests` (or the original insert, 'open') recorded. The\n* dock's \"Refresh\" action calls that reconcile path on demand.\n*/\nasync function listPullRequests(projectRoot) {\n\treturn (await getDb(projectRoot).select().from(pullRequests).orderBy(desc(pullRequests.updatedAt))).map((r) => ({\n\t\tid: String(r.id),\n\t\tnumber: r.number,\n\t\turl: r.url,\n\t\tbranch: r.branch,\n\t\tbaseBranch: r.baseBranch,\n\t\ttitle: r.title,\n\t\tbody: r.body,\n\t\tstate: r.state,\n\t\tconversationIds: r.conversationIds,\n\t\tcreatedAt: r.createdAt.toISOString(),\n\t\tupdatedAt: r.updatedAt.toISOString()\n\t}));\n}\n/**\n* Insert a row for a freshly-opened PR. Called by `composePullRequest`\n* after Octokit returns success; kept separate so the read path\n* (`listPullRequests`) and the write path don't share state beyond the\n* DB itself.\n*/\nasync function recordPullRequest(projectRoot, input) {\n\tawait getDb(projectRoot).insert(pullRequests).values({\n\t\tnumber: input.number,\n\t\turl: input.url,\n\t\tbranch: input.branch,\n\t\tbaseBranch: input.baseBranch,\n\t\ttitle: input.title,\n\t\tbody: input.body,\n\t\tconversationIds: input.conversationIds\n\t});\n}\n/**\n* Collapse GitHub's PR fields into our single `state` enum. GitHub\n* reports `state` as only 'open' | 'closed' and carries `merged` /\n* `draft` as separate flags — merged wins over closed, and draft only\n* applies while still open.\n*/\nfunction mapGithubPrState(pr) {\n\tif (pr.merged) return \"merged\";\n\tif (pr.state === \"closed\") return \"closed\";\n\tif (pr.draft) return \"draft\";\n\treturn \"open\";\n}\n/**\n* Update a recorded PR's `state` (and `updatedAt`, from GitHub's own\n* timestamp when supplied) by PR number — unique within the repo.\n*/\nasync function updatePullRequestState(projectRoot, number, state, updatedAtIso) {\n\tawait getDb(projectRoot).update(pullRequests).set({\n\t\tstate,\n\t\tupdatedAt: updatedAtIso ? new Date(updatedAtIso) : /* @__PURE__ */ new Date()\n\t}).where(eq(pullRequests.number, number));\n}\n/**\n* Update a recorded PR's `body` (and `updatedAt`) — written after the\n* dashboard refreshes the PR description on a push so the dock's PRs view\n* stays in sync with what's on GitHub.\n*/\nasync function updatePullRequestBody(projectRoot, number, body) {\n\tawait getDb(projectRoot).update(pullRequests).set({\n\t\tbody,\n\t\tupdatedAt: /* @__PURE__ */ new Date()\n\t}).where(eq(pullRequests.number, number));\n}\n/**\n* Map the JSON `gh pr view` reports into our `state` enum. gh uses uppercase\n* `state` (OPEN | CLOSED | MERGED) and a separate `isDraft` flag.\n*/\nfunction mapGhPrState(gh) {\n\tif (gh.state === \"MERGED\" || gh.mergedAt) return \"merged\";\n\tif (gh.state === \"CLOSED\") return \"closed\";\n\tif (gh.isDraft) return \"draft\";\n\treturn \"open\";\n}\n/** Read one PR's current state via the `gh` CLI. Null when gh is unavailable. */\nasync function fetchPrStateViaGh(projectRoot, number) {\n\ttry {\n\t\tconst res = await runCapture(\"gh\", [\n\t\t\t\"pr\",\n\t\t\t\"view\",\n\t\t\tString(number),\n\t\t\t\"--json\",\n\t\t\t\"state,isDraft,mergedAt,updatedAt\"\n\t\t], projectRoot);\n\t\tif (res.code !== 0) return null;\n\t\tconst j = JSON.parse(res.stdout);\n\t\treturn {\n\t\t\tstate: mapGhPrState(j),\n\t\t\tupdatedAt: j.updatedAt\n\t\t};\n\t} catch {\n\t\treturn null;\n\t}\n}\n/**\n* Reconcile every recorded PR's state against GitHub, then return the\n* refreshed list. Uses Octokit when a token is configured, otherwise the\n* `gh` CLI (so `gh`-only auth — no stored token — still reconciles; without\n* this the Refresh button did nothing for those users and a closed/merged PR\n* stayed \"open\" in the dock). Best-effort per PR: a deleted PR / network blip\n* keeps the prior state.\n*/\nasync function refreshPullRequests(projectRoot) {\n\tconst remote = await resolveOriginRemote(projectRoot);\n\tif (!remote) return listPullRequests(projectRoot);\n\tconst token = await resolveGithubToken(projectRoot);\n\tconst octokit = token ? new Octokit({ auth: token }) : null;\n\tconst current = await listPullRequests(projectRoot);\n\tfor (const pr of current) try {\n\t\tif (octokit) {\n\t\t\tconst { data } = await octokit.pulls.get({\n\t\t\t\towner: remote.owner,\n\t\t\t\trepo: remote.repo,\n\t\t\t\tpull_number: pr.number\n\t\t\t});\n\t\t\tawait updatePullRequestState(projectRoot, pr.number, mapGithubPrState(data), data.updated_at);\n\t\t} else {\n\t\t\tconst gh = await fetchPrStateViaGh(projectRoot, pr.number);\n\t\t\tif (gh) await updatePullRequestState(projectRoot, pr.number, gh.state, gh.updatedAt);\n\t\t}\n\t} catch {}\n\treturn listPullRequests(projectRoot);\n}\n//#endregion\n//#region src/github-pr.ts\n/**\n* The shared \"push a branch + open a PR on GitHub\" core.\n*\n* Lifted out of `pr-composer.ts` so two callers can share one\n* implementation of the push → Octokit-create → record → audit dance:\n* - `composePullRequest` (multi-conversation worktree merge), and\n* - `openHostBranchPr` (the dock dashboard's branch-centric \"Create PR\").\n*\n* Deliberately depends on `git` + `@octokit/rest` only — NOT the Claude\n* Agent SDK. That keeps it cheap enough for the `@pinagent/mcp` binary to\n* import without dragging the SDK into its bundle (the PR-description\n* summarization lives in the SDK-heavy `summarize-changes.ts`, used only\n* server-side by the dock endpoint).\n*/\n/**\n* Push `branchName` to `origin`, setting upstream. Uses the user's local\n* git credentials (SSH keys, credential manager) — pinagent never manages\n* them. Returns `{ ok }` plus the captured error on failure; never throws.\n*/\nasync function pushBranch(projectRoot, branchName) {\n\tconst push = await runGitCapture(projectRoot, [\n\t\t\"push\",\n\t\t\"-u\",\n\t\t\"origin\",\n\t\t`${branchName}:${branchName}`\n\t]);\n\tif (push.code !== 0) return {\n\t\tok: false,\n\t\terror: `git push failed: ${push.stderr.trim() || push.stdout.trim()}`\n\t};\n\treturn { ok: true };\n}\n/**\n* Open a PR on GitHub for an already-pushed branch, record it for the\n* dock's PRs view, and write a `pr_created` audit event. When no token /\n* non-GitHub remote is configured, returns the manual-compare fallback\n* with `branchPushed: true` so the caller can point the user at GitHub.\n*\n* Assumes `branchName` is already on the remote — call `pushBranch` first.\n*/\nasync function openPrOnGitHub(projectRoot, opts) {\n\tconst token = await resolveGithubToken(projectRoot);\n\tconst remote = await resolveOriginRemote(projectRoot);\n\tconst manualCompareUrl = remote ? `https://github.com/${remote.owner}/${remote.repo}/compare/${encodeURIComponent(opts.baseBranch)}...${encodeURIComponent(opts.branchName)}?expand=1` : void 0;\n\tif (!remote) return {\n\t\tok: true,\n\t\tbranchPushed: true\n\t};\n\tlet apiError;\n\tif (token) try {\n\t\tconst created = await new Octokit({ auth: token }).pulls.create({\n\t\t\towner: remote.owner,\n\t\t\trepo: remote.repo,\n\t\t\ttitle: opts.title,\n\t\t\tbody: opts.body,\n\t\t\thead: opts.branchName,\n\t\t\tbase: opts.baseBranch\n\t\t});\n\t\tawait recordOpenedPr(projectRoot, opts, created.data.number, created.data.html_url);\n\t\treturn {\n\t\t\tok: true,\n\t\t\tbranchPushed: true,\n\t\t\tprUrl: created.data.html_url\n\t\t};\n\t} catch (e) {\n\t\tapiError = `GitHub API call failed: ${e instanceof Error ? e.message : String(e)}`;\n\t}\n\tconst gh = await createPrViaGh(projectRoot, opts);\n\tif (gh.url) {\n\t\tconst number = parsePrNumberFromUrl(gh.url);\n\t\tif (number !== null) await recordOpenedPr(projectRoot, opts, number, gh.url);\n\t\treturn {\n\t\t\tok: true,\n\t\t\tbranchPushed: true,\n\t\t\tprUrl: gh.url\n\t\t};\n\t}\n\treturn {\n\t\tok: true,\n\t\tbranchPushed: true,\n\t\t...manualCompareUrl ? { manualCompareUrl } : {},\n\t\t...apiError || gh.error ? { error: apiError ?? `pushed ok, but couldn't open the PR: ${gh.error}` } : {}\n\t};\n}\n/**\n* Update an existing PR's description on GitHub (Octokit when a token is\n* set, else the `gh` CLI) and mirror it into the recorded row. Backs the\n* dashboard's \"refresh the PR body on push\" so the description reflects the\n* newly-pushed commits. Best-effort — never throws.\n*/\nasync function updatePrDescription(projectRoot, opts) {\n\tconst remote = await resolveOriginRemote(projectRoot);\n\tif (!remote) return {\n\t\tok: false,\n\t\terror: \"no GitHub remote\"\n\t};\n\tconst token = await resolveGithubToken(projectRoot);\n\tif (token) try {\n\t\tawait new Octokit({ auth: token }).pulls.update({\n\t\t\towner: remote.owner,\n\t\t\trepo: remote.repo,\n\t\t\tpull_number: opts.number,\n\t\t\tbody: opts.body\n\t\t});\n\t\tawait updatePullRequestBody(projectRoot, opts.number, opts.body).catch(() => {});\n\t\treturn { ok: true };\n\t} catch {}\n\ttry {\n\t\tconst res = await runCapture(\"gh\", [\n\t\t\t\"pr\",\n\t\t\t\"edit\",\n\t\t\tString(opts.number),\n\t\t\t\"--body\",\n\t\t\topts.body\n\t\t], projectRoot);\n\t\tif (res.code === 0) {\n\t\t\tawait updatePullRequestBody(projectRoot, opts.number, opts.body).catch(() => {});\n\t\t\treturn { ok: true };\n\t\t}\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: res.stderr.trim() || res.stdout.trim() || `gh exited ${res.code}`\n\t\t};\n\t} catch (e) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: e instanceof Error ? e.message : String(e)\n\t\t};\n\t}\n}\n/** Record an opened PR for the dock's PRs view + audit log. Best-effort. */\nasync function recordOpenedPr(projectRoot, opts, number, url) {\n\tawait recordPullRequest(projectRoot, {\n\t\tnumber,\n\t\turl,\n\t\tbranch: opts.branchName,\n\t\tbaseBranch: opts.baseBranch,\n\t\ttitle: opts.title,\n\t\tbody: opts.body,\n\t\tconversationIds: opts.conversationIds\n\t}).catch(() => {});\n\tawait recordAuditEvent(projectRoot, {\n\t\tconversationId: null,\n\t\tactor: \"user\",\n\t\taction: \"pr_created\",\n\t\tpayload: {\n\t\t\tnumber,\n\t\t\turl,\n\t\t\tbranch: opts.branchName,\n\t\t\tbaseBranch: opts.baseBranch,\n\t\t\ttitle: opts.title,\n\t\t\tconversationIds: opts.conversationIds\n\t\t}\n\t});\n}\n/**\n* Open a PR with the `gh` CLI (already-pushed branch). Returns the PR URL on\n* success. If the branch already has a PR, gh exits non-zero but prints the\n* existing URL — we surface that too so the dock can still flip to \"View PR\".\n* Returns `{ url: undefined }` when gh is missing/unauthed/errors.\n*/\nasync function createPrViaGh(projectRoot, opts) {\n\ttry {\n\t\tconst res = await runCapture(\"gh\", [\n\t\t\t\"pr\",\n\t\t\t\"create\",\n\t\t\t\"--head\",\n\t\t\topts.branchName,\n\t\t\t\"--base\",\n\t\t\topts.baseBranch,\n\t\t\t\"--title\",\n\t\t\topts.title,\n\t\t\t\"--body\",\n\t\t\topts.body\n\t\t], projectRoot);\n\t\tconst url = extractPrUrl(`${res.stdout}\\n${res.stderr}`);\n\t\tif (url) return { url };\n\t\treturn { error: res.stderr.trim() || res.stdout.trim() || `gh exited ${res.code}` };\n\t} catch (e) {\n\t\treturn { error: e instanceof Error ? e.message : String(e) };\n\t}\n}\n/** First `https://github.com/<owner>/<repo>/pull/<n>` URL in `text`, if any. */\nfunction extractPrUrl(text) {\n\treturn /https?:\\/\\/github\\.com\\/[^\\s/]+\\/[^\\s/]+\\/pull\\/\\d+/.exec(text)?.[0];\n}\n/** Parse the numeric PR id from a GitHub PR URL. Null when it doesn't match. */\nfunction parsePrNumberFromUrl(url) {\n\tconst m = /\\/pull\\/(\\d+)/.exec(url);\n\treturn m ? Number(m[1]) : null;\n}\n//#endregion\n//#region src/pr-screenshots.ts\n/**\n* Embed feedback screenshots into a GitHub PR body.\n*\n* GitHub does NOT render `data:` image URIs in PR/issue markdown, so a\n* base64-inlined screenshot would just show a broken image. The PNG has to\n* live at an http(s) URL GitHub can fetch. The cheapest way to host one from\n* a worktree (no external storage, no extra API) is to commit it onto the PR\n* branch itself and reference its `?raw=true` blob URL — once the branch is\n* pushed, the URL resolves.\n*\n* `.pinagent/` is gitignored (it holds the local DB + raw screenshots), so\n* the asset is force-added (`git add -f`) under `.pinagent/pr-assets/`. Only\n* the explicitly-added asset becomes tracked; the rest of `.pinagent/` stays\n* ignored.\n*\n* Which screenshots belong to a host-branch (\"working copy\") PR? Inline\n* feedback leaves no per-conversation git trail and is marked resolved the\n* moment the agent finishes — so a branch/commit can't be matched back to it.\n* Instead we use `commitSha` as a \"shipped\" marker: resolved feedback with a\n* screenshot and a null `commitSha` is sitting in the working copy unshipped;\n* the PR attaches it and the caller stamps the shipped commit onto it, so the\n* next PR won't re-attach it. (Worktree-mode feedback carries a `branch` and\n* its own merge commit, so it's excluded — its changes aren't in the host\n* working copy.)\n*\n* SDK-free and DB-free (git + fs only) so it can be imported from the\n* `@pinagent/agent-runner/pr` entry without bloating the `@pinagent/mcp` bin\n* — the caller supplies the records (and does the stamping) via its own\n* storage.\n*/\nconst ASSET_SUBDIR = \".pinagent/pr-assets\";\n/** First non-empty line of `comment`, trimmed and length-capped, for a caption. */\nfunction captionFor(comment) {\n\tconst line = comment.split(/\\r?\\n/).map((s) => s.trim()).find(Boolean);\n\tif (!line) return void 0;\n\treturn line.length > 100 ? `${line.slice(0, 99)}…` : line;\n}\n/** Strip markdown-significant chars from alt text and cap its length. */\nfunction altText(caption) {\n\tconst base = (caption ?? \"clicked element\").replace(/[[\\]]/g, \"\");\n\treturn base.length > 120 ? base.slice(0, 120) : base;\n}\n/** Encode a slash-separated path segment-by-segment (keeps `/` literal). */\nfunction encodePath(p) {\n\treturn p.split(\"/\").map((seg) => encodeURIComponent(seg)).join(\"/\");\n}\n/**\n* Pick the resolved, inline, not-yet-shipped feedback with a screenshot — the\n* conversations whose work is sitting in the current host working copy. These\n* are what a \"working copy\" / dock PR should show. The caller stamps the\n* shipped commit onto the returned `ids` after the PR succeeds, so a later PR\n* won't re-attach them.\n*\n* Excludes: unresolved feedback, worktree-mode feedback (carries a `branch`;\n* its changes live in a separate worktree, not the host working copy), and\n* already-shipped feedback (non-null `commitSha`).\n*/\nfunction selectUnshippedScreenshots(records) {\n\tconst shots = [];\n\tconst ids = [];\n\tfor (const r of records) {\n\t\tif (r.status !== \"fixed\") continue;\n\t\tif (r.branch) continue;\n\t\tif (r.commitSha) continue;\n\t\tif (!r.screenshot) continue;\n\t\tshots.push({\n\t\t\tid: r.id,\n\t\t\tscreenshot: r.screenshot,\n\t\t\tcaption: captionFor(r.comment)\n\t\t});\n\t\tids.push(r.id);\n\t}\n\treturn {\n\t\tshots,\n\t\tids\n\t};\n}\n/**\n* Copy each screenshot into `<commitCwd>/.pinagent/pr-assets/`, force-add +\n* commit them onto the current branch, and return a markdown block of\n* `?raw=true` blob URLs (referencing `branch`) to append to the PR body, plus\n* the ids that were actually committed (so the caller can mark them shipped).\n*\n* Returns empty markdown and commits nothing when there are no usable\n* screenshots or the origin isn't GitHub (the blob URL only resolves on\n* GitHub). Best-effort throughout: a missing screenshot file is skipped and\n* a git failure leaves the body un-augmented rather than failing the PR.\n*\n* Call BEFORE pushing `branch` so the committed asset reaches the remote.\n*/\nasync function stageScreenshotAssets(projectRoot, commitCwd, branch, shots) {\n\tconst empty = {\n\t\tmarkdown: \"\",\n\t\tcommitted: 0,\n\t\tids: []\n\t};\n\tif (shots.length === 0) return empty;\n\tconst remote = await resolveOriginRemote(projectRoot);\n\tif (!remote) return empty;\n\tawait mkdir(join(commitCwd, \".pinagent\", \"pr-assets\"), { recursive: true });\n\tconst staged = [];\n\tfor (const shot of shots) {\n\t\tconst src = join(projectRoot, \".pinagent\", shot.screenshot);\n\t\ttry {\n\t\t\tawait access(src);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tconst rel = `${ASSET_SUBDIR}/${shot.id}.png`;\n\t\tawait copyFile(src, join(commitCwd, \".pinagent\", \"pr-assets\", `${shot.id}.png`));\n\t\tif ((await runGitCapture(commitCwd, [\n\t\t\t\"add\",\n\t\t\t\"-f\",\n\t\t\t\"--\",\n\t\t\trel\n\t\t])).code !== 0) continue;\n\t\tstaged.push(shot);\n\t}\n\tif (staged.length === 0) return empty;\n\tconst commit = await runGitCapture(commitCwd, [\n\t\t\"commit\",\n\t\t\"-m\",\n\t\t\"pinagent: attach feedback screenshots\"\n\t]);\n\tif (commit.code !== 0 && !/nothing to commit/.test(`${commit.stdout}\\n${commit.stderr}`)) return empty;\n\treturn {\n\t\tmarkdown: `\\n\\n---\\n\\n### Screenshots\\n\\n${staged.map((s) => {\n\t\t\tconst rel = `${ASSET_SUBDIR}/${s.id}.png`;\n\t\t\tconst url = `https://github.com/${remote.owner}/${remote.repo}/blob/${encodePath(branch)}/${encodePath(rel)}?raw=true`;\n\t\t\tconst img = ``;\n\t\t\treturn s.caption ? `**${s.caption}**\\n\\n${img}` : img;\n\t\t}).join(\"\\n\\n\")}\\n`,\n\t\tcommitted: staged.length,\n\t\tids: staged.map((s) => s.id)\n\t};\n}\n//#endregion\n//#region src/host-branch-pr.ts\n/**\n* Branch-centric PR actions for the dock dashboard — push / open a PR for\n* the branch the dev-server is *already on*, rather than merging a set of\n* per-conversation worktrees (that's `pr-composer.ts`).\n*\n* The PR title/body are supplied by the caller: the dock endpoint runs the\n* inline summarizer (`summarize-changes.ts`) first; the `@pinagent/mcp`\n* `create_pull_request` tool has the connected agent summarize and pass\n* them in. Both then land here.\n*\n* Imports only git + `github-pr` (Octokit) — NOT the Claude Agent SDK — so\n* the MCP binary can import `openHostBranchPr` without bundling the SDK.\n*/\nconst BRANCH_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9/_.-]{0,127}$/;\n/**\n* Stage everything (`git add -A`) and commit with `message`. No-op (ok,\n* committed: false) when the tree is clean. SDK-free, so the dashboard's\n* Create PR / Push flows (and the MCP tool) can fold the developer's\n* uncommitted edits into the branch before pushing — otherwise the push\n* would silently omit them.\n*/\nasync function commitWorkingChanges(projectRoot, message) {\n\tif (!await isWorkingTreeDirty(projectRoot)) return {\n\t\tok: true,\n\t\tcommitted: false\n\t};\n\tconst add = await runGitCapture(projectRoot, [\"add\", \"-A\"]);\n\tif (add.code !== 0) return {\n\t\tok: false,\n\t\tcommitted: false,\n\t\terror: `git add failed: ${add.stderr.trim()}`\n\t};\n\tawait unstageAddedGitlinks(projectRoot);\n\tconst commit = await runGitCapture(projectRoot, [\n\t\t\"commit\",\n\t\t\"-m\",\n\t\tmessage\n\t]);\n\tconst nothingToCommit = /nothing to commit/.test(`${commit.stdout}\\n${commit.stderr}`);\n\tif (commit.code !== 0 && !nothingToCommit) return {\n\t\tok: false,\n\t\tcommitted: false,\n\t\terror: `git commit failed: ${commit.stderr.trim() || commit.stdout.trim()}`\n\t};\n\treturn {\n\t\tok: true,\n\t\tcommitted: commit.code === 0\n\t};\n}\n/**\n* Unstage entries that `git add -A` recorded as gitlinks (mode 160000) —\n* embedded git repositories it picked up. Only newly-added ones (status A),\n* so an intentionally-tracked submodule's pointer update is left alone.\n*/\nasync function unstageAddedGitlinks(projectRoot) {\n\tconst raw = await runGitCapture(projectRoot, [\n\t\t\"diff\",\n\t\t\"--cached\",\n\t\t\"--raw\"\n\t]);\n\tif (raw.code !== 0) return;\n\tfor (const line of raw.stdout.split(\"\\n\")) {\n\t\tif (!line.startsWith(\":\")) continue;\n\t\tconst tab = line.indexOf(\"\t\");\n\t\tif (tab === -1) continue;\n\t\tconst fields = line.slice(1, tab).split(\" \");\n\t\tconst newMode = fields[1];\n\t\tconst status = fields[4] ?? \"\";\n\t\tconst path = line.slice(tab + 1);\n\t\tif (newMode === \"160000\" && status.startsWith(\"A\") && path) await runGitCapture(projectRoot, [\n\t\t\t\"reset\",\n\t\t\t\"-q\",\n\t\t\t\"--\",\n\t\t\tpath\n\t\t]);\n\t}\n}\nasync function resolveCurrentBranch(projectRoot) {\n\tconst sym = await runGitCapture(projectRoot, [\n\t\t\"symbolic-ref\",\n\t\t\"--short\",\n\t\t\"HEAD\"\n\t]);\n\tif (sym.code !== 0) return null;\n\tconst branch = sym.stdout.trim();\n\treturn branch.length > 0 ? branch : null;\n}\n/**\n* Push the current branch and open a PR targeting the configured base\n* branch. Guards against PR-ing the base branch onto itself (nothing to\n* compare) and detached HEAD.\n*/\nasync function openHostBranchPr(projectRoot, opts) {\n\tif (!await isInsideWorkTree(projectRoot)) return {\n\t\tok: false,\n\t\tbranchPushed: false,\n\t\terror: \"project root is not a git repository\"\n\t};\n\tconst branch = await resolveCurrentBranch(projectRoot);\n\tif (!branch) return {\n\t\tok: false,\n\t\tbranchPushed: false,\n\t\terror: \"cannot open a PR from a detached HEAD\"\n\t};\n\tconst { baseBranch } = await new SettingsStore(projectRoot).read();\n\tif (branch === baseBranch) return {\n\t\tok: false,\n\t\tbranchPushed: false,\n\t\terror: `current branch \"${branch}\" is the base branch — switch to a feature branch first`\n\t};\n\tif (await isWorkingTreeDirty(projectRoot)) {\n\t\tif (!opts.commitMessage) return {\n\t\t\tok: false,\n\t\t\tbranchPushed: false,\n\t\t\terror: \"uncommitted changes present — provide a commit message\"\n\t\t};\n\t\tconst committed = await commitWorkingChanges(projectRoot, opts.commitMessage);\n\t\tif (!committed.ok) return {\n\t\t\tok: false,\n\t\t\tbranchPushed: false,\n\t\t\terror: committed.error\n\t\t};\n\t}\n\tconst headSha = await runGitCapture(projectRoot, [\"rev-parse\", \"HEAD\"]);\n\tconst shippedCommit = headSha.code === 0 ? headSha.stdout.trim() : void 0;\n\tconst { markdown: screenshotMd, ids: shippedScreenshotIds } = await stageScreenshotAssets(projectRoot, projectRoot, branch, opts.screenshots ?? []);\n\tconst push = await pushBranch(projectRoot, branch);\n\tif (!push.ok) return {\n\t\tok: false,\n\t\tbranchPushed: false,\n\t\terror: push.error ?? \"git push failed\"\n\t};\n\treturn {\n\t\t...await openPrOnGitHub(projectRoot, {\n\t\t\tbranchName: branch,\n\t\t\tbaseBranch,\n\t\t\ttitle: opts.title,\n\t\t\tbody: opts.body + screenshotMd,\n\t\t\tconversationIds: []\n\t\t}),\n\t\tshippedCommit,\n\t\tshippedScreenshotIds\n\t};\n}\n/**\n* Push the current branch to its upstream — backs the dashboard's \"Push\n* changes\" action when local commits are ahead of the remote (e.g. agents\n* landed more work after the PR was opened).\n*/\nasync function pushHostBranch(projectRoot, opts = {}) {\n\tif (!await isInsideWorkTree(projectRoot)) return {\n\t\tok: false,\n\t\tpushed: false,\n\t\terror: \"project root is not a git repository\"\n\t};\n\tconst branch = await resolveCurrentBranch(projectRoot);\n\tif (!branch) return {\n\t\tok: false,\n\t\tpushed: false,\n\t\terror: \"cannot push a detached HEAD\"\n\t};\n\tif (await isWorkingTreeDirty(projectRoot)) {\n\t\tif (!opts.commitMessage) return {\n\t\t\tok: false,\n\t\t\tpushed: false,\n\t\t\terror: \"uncommitted changes present — provide a commit message\"\n\t\t};\n\t\tconst committed = await commitWorkingChanges(projectRoot, opts.commitMessage);\n\t\tif (!committed.ok) return {\n\t\t\tok: false,\n\t\t\tpushed: false,\n\t\t\terror: committed.error\n\t\t};\n\t}\n\tconst push = await pushBranch(projectRoot, branch);\n\tif (!push.ok) return {\n\t\tok: false,\n\t\tpushed: false,\n\t\terror: push.error\n\t};\n\treturn {\n\t\tok: true,\n\t\tpushed: true\n\t};\n}\n/**\n* Create a new branch from the current HEAD and switch to it, carrying any\n* uncommitted working changes over (leaving the base branch clean). Backs\n* the dashboard's \"Start a branch\" action — the helpful next step when the\n* dev server is on the base branch, where a PR can't be opened (main→main).\n* The auto-generated `pinagent/<id>` name is fine; the eventual Create PR\n* supplies the real, agent-summarized title.\n*/\nasync function startHostBranch(projectRoot, opts = {}) {\n\tif (!await isInsideWorkTree(projectRoot)) return {\n\t\tok: false,\n\t\terror: \"project root is not a git repository\"\n\t};\n\tlet name = opts.name?.trim() || `pinagent/${nanoid(8)}`;\n\tif (!BRANCH_NAME_RE.test(name)) return {\n\t\tok: false,\n\t\terror: \"invalid branch name (alphanumeric + ./_- only)\"\n\t};\n\tif (await branchExists(projectRoot, name)) name = `${name}-${nanoid(4)}`;\n\tconst res = await runGitCapture(projectRoot, [\n\t\t\"switch\",\n\t\t\"-c\",\n\t\tname\n\t]);\n\tif (res.code !== 0) return {\n\t\tok: false,\n\t\terror: `git switch failed: ${res.stderr.trim() || res.stdout.trim()}`\n\t};\n\treturn {\n\t\tok: true,\n\t\tbranch: name\n\t};\n}\nasync function branchExists(projectRoot, name) {\n\treturn (await runGitCapture(projectRoot, [\n\t\t\"rev-parse\",\n\t\t\"--verify\",\n\t\t\"--quiet\",\n\t\t`refs/heads/${name}`\n\t])).code === 0;\n}\n/**\n* Turn a change summary (e.g. an agent-written commit subject like\n* `feat(dock): add pricing tiers`) into a readable branch name —\n* `pinagent/add-pricing-tiers`. Drops any Conventional-Commits prefix,\n* lowercases, and dash-joins. Returns undefined when nothing usable remains\n* (caller then falls back to the auto-generated id).\n*/\nfunction slugifyBranchName(summary) {\n\tconst slug = (summary.replace(/^\\s*[a-z]+(\\([^)]*\\))?!?:\\s*/i, \"\").split(\"\\n\")[0] ?? \"\").trim().toLowerCase().replace(/[^a-z0-9]+/g, \"-\").replace(/^-+|-+$/g, \"\").slice(0, 40).replace(/-+$/, \"\");\n\treturn slug ? `pinagent/${slug}` : void 0;\n}\n//#endregion\nexport { DEFAULT_SETTINGS as C, ProjectSettingsSchema as D, ProjectSettingsPatchSchema as E, SettingsStore as O, getDb as S, PermissionModeSchema as T, appendLog as _, startHostBranch as a, runGit as b, openPrOnGitHub as c, listPullRequests as d, refreshPullRequests as f, SecretsStore as g, SecretsFileSchema as h, slugifyBranchName as i, pushBranch as l, recordAuditEvent as m, openHostBranchPr as n, selectUnshippedScreenshots as o, listAuditEvents as p, pushHostBranch as r, stageScreenshotAssets as s, commitWorkingChanges as t, updatePrDescription as u, isInsideWorkTree as v, PROJECT_PERMISSION_MODES as w, runGitCapture as x, isWorkingTreeDirty as y };\n\n//# sourceMappingURL=host-branch-pr.js.map","import { C as DEFAULT_SETTINGS, D as ProjectSettingsSchema, E as ProjectSettingsPatchSchema, O as SettingsStore, S as getDb, T as PermissionModeSchema, _ as appendLog, a as startHostBranch, b as runGit, c as openPrOnGitHub, d as listPullRequests, f as refreshPullRequests, g as SecretsStore, h as SecretsFileSchema, i as slugifyBranchName, l as pushBranch, m as recordAuditEvent, n as openHostBranchPr, o as selectUnshippedScreenshots, p as listAuditEvents, r as pushHostBranch, s as stageScreenshotAssets, t as commitWorkingChanges, u as updatePrDescription, v as isInsideWorkTree, w as PROJECT_PERMISSION_MODES, x as runGitCapture, y as isWorkingTreeDirty } from \"./host-branch-pr.js\";\nimport { createWriteStream, existsSync, readFileSync } from \"node:fs\";\nimport { mkdir, readFile, readdir, rename, rm, writeFile } from \"node:fs/promises\";\nimport { basename, dirname, isAbsolute, join, relative, resolve, sep } from \"node:path\";\nimport { activeRuns, and, asc, conversations, count, eq, gte, inArray, like, lt, messages, notInArray, or, widgetAnchors } from \"@pinagent/db\";\nimport { ClientMessageSchema, isNotionalCost } from \"@pinagent/shared\";\nimport { and as and$1, asc as asc$1, eq as eq$1, gt, sql } from \"drizzle-orm\";\nimport { z } from \"zod\";\nimport { createSdkMcpServer, query, tool } from \"@anthropic-ai/claude-agent-sdk\";\nimport { nanoid } from \"nanoid\";\nimport { createHash } from \"node:crypto\";\nimport { spawn } from \"node:child_process\";\nimport { createInterface } from \"node:readline\";\nimport { Buffer as Buffer$1 } from \"node:buffer\";\nimport { createConnection, createServer } from \"node:net\";\nimport { Octokit } from \"@octokit/rest\";\nimport { homedir } from \"node:os\";\nimport { WebSocket, WebSocketServer } from \"ws\";\n//#region src/agent-permission.ts\n/**\n* Resolve the spawn mode from env. The new default (V2) is `'inline'` —\n* SDK-backed per-submit agent with streaming back to the widget. Worktree\n* mode is opt-in; `'off'` (or the legacy `'false'`) disables spawning so\n* channel-mode / pull-mode setups don't get a redundant agent per submit.\n*/\nfunction resolveAgentMode(env) {\n\tconst v = env.PINAGENT_SPAWN_AGENT;\n\tif (v === \"worktree\") return \"worktree\";\n\tif (v === \"off\" || v === \"false\") return false;\n\treturn \"inline\";\n}\n/**\n* Resolve the SDK permission mode for a run. Precedence:\n* `PINAGENT_AGENT_PERMISSION_MODE` env override > project settings\n* (`.pinagent/config.json` permissionMode) > default.\n* The env override is kept so CI / power users can bypass the dock UI\n* without editing the settings file.\n*/\nasync function resolveRunPermissionMode(projectRoot) {\n\tconst override = resolvePermissionModeOverride(process.env);\n\tif (override) return override;\n\treturn toSdkPermissionMode((await new SettingsStore(projectRoot).read()).permissionMode);\n}\nfunction resolvePermissionMode(env) {\n\tconst v = env.PINAGENT_AGENT_PERMISSION_MODE;\n\tif (v === \"default\" || v === \"acceptEdits\" || v === \"bypassPermissions\" || v === \"plan\" || v === \"dontAsk\" || v === \"auto\") return v;\n\treturn \"acceptEdits\";\n}\n/**\n* The active env override for permission mode, or `null` when no\n* override is set. Different shape from `resolvePermissionMode`, which\n* falls back to `'acceptEdits'` whether the env was unset or invalid —\n* callers that need to distinguish \"no override\" from \"override → some\n* mode\" (e.g. the dock's Settings UI banner) want this signal.\n*/\nfunction resolvePermissionModeOverride(env) {\n\tif (!env.PINAGENT_AGENT_PERMISSION_MODE) return null;\n\treturn resolvePermissionMode(env);\n}\n/**\n* Map the user-facing project setting to the SDK's permission-mode\n* value-space. Looks up the shared `PROJECT_PERMISSION_MODES` table so\n* the mapping stays in sync with the dock's Settings labels and the\n* detail-header chip.\n*/\nfunction toSdkPermissionMode(mode) {\n\treturn PROJECT_PERMISSION_MODES.find((m) => m.projectMode === mode)?.sdkMode ?? \"acceptEdits\";\n}\n//#endregion\n//#region src/bus.ts\nconst POLL_INTERVAL_MS = 100;\nconst FINISHED_ROLE = \"__finished\";\nvar SqliteEventBus = class {\n\tfeedbackId;\n\tprojectRoot;\n\tconstructor(feedbackId, projectRoot) {\n\t\tthis.feedbackId = feedbackId;\n\t\tthis.projectRoot = projectRoot;\n\t}\n\t/**\n\t* Append an event to the bus. INSERTs one row into `messages` keyed\n\t* by the conversation id. Idempotent failures (e.g. the conversation\n\t* row doesn't exist yet because POST handler hasn't finished writing\n\t* it) are silently swallowed — the caller's event ordering is\n\t* preserved by the autoincrement id, and a missing row would only\n\t* happen during a narrow startup race we already tolerate.\n\t*/\n\tasync publish(event) {\n\t\ttry {\n\t\t\tawait getDb(this.projectRoot).insert(messages).values({\n\t\t\t\tconversationId: this.feedbackId,\n\t\t\t\tturn: 1,\n\t\t\t\trole: event.type,\n\t\t\t\tcontent: event\n\t\t\t});\n\t\t} catch {}\n\t}\n\t/**\n\t* Start delivering events to `sub`. Replays everything written so\n\t* far for this feedback id (via the first poll), then delivers new\n\t* events as they arrive. Calling the returned function stops\n\t* polling.\n\t*\n\t* Polling is per-subscriber. For our actual subscriber load (1–3\n\t* widget connections per feedback) this is cheaper than maintaining\n\t* a shared poll loop with a fan-out Set.\n\t*/\n\tsubscribe(sub) {\n\t\tlet lastSeenId = 0;\n\t\tlet stopped = false;\n\t\tlet polling = false;\n\t\tconst poll = async () => {\n\t\t\tif (stopped || polling) return;\n\t\t\tpolling = true;\n\t\t\ttry {\n\t\t\t\tconst rows = await getDb(this.projectRoot).select().from(messages).where(and$1(eq$1(messages.conversationId, this.feedbackId), gt(messages.id, lastSeenId))).orderBy(asc$1(messages.id));\n\t\t\t\tfor (const row of rows) {\n\t\t\t\t\tif (stopped) return;\n\t\t\t\t\tlastSeenId = row.id;\n\t\t\t\t\tif (row.role === FINISHED_ROLE) {\n\t\t\t\t\t\tstopped = true;\n\t\t\t\t\t\tclearInterval(interval);\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tsub.onClose();\n\t\t\t\t\t\t} catch {}\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\ttry {\n\t\t\t\t\t\tsub.onEvent(row.content);\n\t\t\t\t\t} catch {}\n\t\t\t\t}\n\t\t\t} catch {} finally {\n\t\t\t\tpolling = false;\n\t\t\t}\n\t\t};\n\t\tpoll();\n\t\tconst interval = setInterval(() => {\n\t\t\tpoll();\n\t\t}, POLL_INTERVAL_MS);\n\t\treturn () => {\n\t\t\tstopped = true;\n\t\t\tclearInterval(interval);\n\t\t};\n\t}\n\t/**\n\t* Signal that no more events will be published for this feedback.\n\t* Writes a sentinel row that subscribers pick up on their next poll\n\t* and translate into `onClose`. The DB rows themselves stay until\n\t* the parent `conversations` row is deleted (FK cascade).\n\t*/\n\tasync markFinished() {\n\t\ttry {\n\t\t\tawait getDb(this.projectRoot).insert(messages).values({\n\t\t\t\tconversationId: this.feedbackId,\n\t\t\t\tturn: 1,\n\t\t\t\trole: FINISHED_ROLE,\n\t\t\t\tcontent: {}\n\t\t\t});\n\t\t} catch {}\n\t}\n};\n/**\n* Per-context cache of bus instances. Cross-context publish/subscribe\n* still works because the instances all hit the same SQLite file —\n* the cache here just avoids re-allocating the bus object on every\n* lookup within one context.\n*/\nconst BUSES_SYMBOL = Symbol.for(\"pinagent.agent-runner.bus\");\nconst buses = globalThis[BUSES_SYMBOL] ?? /* @__PURE__ */ new Map();\nglobalThis[BUSES_SYMBOL] = buses;\nfunction getOrCreateBus(feedbackId, projectRoot) {\n\tconst root = projectRoot ?? process.env.PINAGENT_PROJECT_ROOT ?? process.cwd();\n\tlet bus = buses.get(feedbackId);\n\tif (!bus) {\n\t\tbus = new SqliteEventBus(feedbackId, root);\n\t\tbuses.set(feedbackId, bus);\n\t}\n\treturn bus;\n}\n//#endregion\n//#region src/ask-user.ts\n/**\n* `ask_user` custom SDK tool — the agent's only blessed way to pause and\n* wait for a typed human answer mid-run.\n*\n* Flow:\n* 1. Model calls `ask_user({ question, ... })`.\n* 2. Handler generates an askId, publishes an `ask_user` AgentEvent to\n* the feedback's bus (so subscribed WS clients render a form), and\n* returns a Promise.\n* 3. User types an answer in the widget; the widget sends\n* `ask_response { askId, answer }` over WS.\n* 4. The WS server calls `resolveAsk(askId, answer)`; the Promise\n* resolves with a `CallToolResult` carrying the answer text; the\n* agent receives it as the tool result and continues.\n*\n* If the run ends, the dev server restarts, or a TTL elapses with no\n* answer, the Promise rejects so the agent gets a clear failure rather\n* than hanging on a dead UI.\n*/\nconst ASK_TTL_MS = 600 * 1e3;\n/**\n* Pending asks LOCAL TO THIS CONTEXT. The resolve/reject closures are\n* tied to the agent's Promise — process-bound, not serialisable. The\n* WS server can land in a different context than the one running the\n* agent (Next 16 Turbopack, Vite 8), so we route cross-context responses\n* via `process.emit(ASK_RESPONSE_EVENT, ...)` — see `resolveAsk`.\n*/\nconst pending = /* @__PURE__ */ new Map();\nconst ASK_RESPONSE_EVENT = \"pinagent:ask-response\";\nconst inputSchema = {\n\tquestion: z.string().min(1).max(2e3).describe(\"The question to ask the user. Be specific and concise.\"),\n\tcontext: z.string().max(2e3).optional().describe(\"Optional: what you are trying to do and why you need this clarification. Helps the user answer with the right context.\"),\n\toptions: z.array(z.string().min(1).max(200)).max(6).optional().describe(\"Optional: suggested answers. Rendered as one-click buttons. Use sparingly — only when the answer is genuinely closed-ended.\")\n};\n/**\n* Build an SDK MCP server that exposes a single `ask_user` tool scoped to\n* one feedback id. The handler closes over `feedbackId` so the published\n* event lands on the correct bus.\n*/\nfunction createAskUserMcpServer(feedbackId) {\n\treturn createSdkMcpServer({\n\t\tname: \"pinagent-ask-user\",\n\t\tversion: \"0.1.0\",\n\t\ttools: [tool(\"ask_user\", [\n\t\t\t\"Ask the human developer a question and wait for their typed answer.\",\n\t\t\t\"Use this when you cannot proceed without clarification — preferred over\",\n\t\t\t\"guessing or making an assumption. The user sees the question in their\",\n\t\t\t\"browser widget and types a response.\"\n\t\t].join(\" \"), inputSchema, async (args) => {\n\t\t\tconst askId = nanoid(10);\n\t\t\tconst bus = getOrCreateBus(feedbackId);\n\t\t\treturn { content: [{\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: await new Promise((resolve, reject) => {\n\t\t\t\t\tconst timeout = setTimeout(() => {\n\t\t\t\t\t\tpending.delete(askId);\n\t\t\t\t\t\tprocess.off(ASK_RESPONSE_EVENT, onResponse);\n\t\t\t\t\t\treject(/* @__PURE__ */ new Error(`ask_user timed out after ${ASK_TTL_MS / 1e3}s with no response`));\n\t\t\t\t\t}, ASK_TTL_MS);\n\t\t\t\t\tconst onResponse = (payload) => {\n\t\t\t\t\t\tif (payload.askId !== askId) return;\n\t\t\t\t\t\tconst entry = pending.get(askId);\n\t\t\t\t\t\tif (entry) entry.resolve(payload.answer);\n\t\t\t\t\t};\n\t\t\t\t\tprocess.on(ASK_RESPONSE_EVENT, onResponse);\n\t\t\t\t\tpending.set(askId, {\n\t\t\t\t\t\tfeedbackId,\n\t\t\t\t\t\tresolve: (a) => {\n\t\t\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\t\t\tpending.delete(askId);\n\t\t\t\t\t\t\tprocess.off(ASK_RESPONSE_EVENT, onResponse);\n\t\t\t\t\t\t\tresolve(a);\n\t\t\t\t\t\t},\n\t\t\t\t\t\treject: (reason) => {\n\t\t\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\t\t\tpending.delete(askId);\n\t\t\t\t\t\t\tprocess.off(ASK_RESPONSE_EVENT, onResponse);\n\t\t\t\t\t\t\treject(new Error(reason));\n\t\t\t\t\t\t},\n\t\t\t\t\t\ttimeout\n\t\t\t\t\t});\n\t\t\t\t\tbus.publish({\n\t\t\t\t\t\ttype: \"ask_user\",\n\t\t\t\t\t\taskId,\n\t\t\t\t\t\tquestion: args.question,\n\t\t\t\t\t\tcontext: args.context,\n\t\t\t\t\t\toptions: args.options\n\t\t\t\t\t});\n\t\t\t\t})\n\t\t\t}] };\n\t\t})]\n\t});\n}\n/**\n* Resolve the matching pending ask. Tries the local-context Map first\n* for the same-context case; otherwise broadcasts via `process.emit`\n* so the context running the agent (and holding the resolve closure)\n* can settle the Promise. Returns true optimistically when emitting\n* cross-context — we can't know synchronously whether another context\n* had a matching pending entry, but stale UI / double-submits are rare\n* enough that swallowing the \"no pending ask\" error is acceptable.\n*/\nfunction resolveAsk(askId, answer) {\n\tconst entry = pending.get(askId);\n\tif (entry) {\n\t\tentry.resolve(answer);\n\t\treturn true;\n\t}\n\tconst payload = {\n\t\taskId,\n\t\tanswer\n\t};\n\tprocess.emit(ASK_RESPONSE_EVENT, payload);\n\treturn true;\n}\n/**\n* Reject every pending ask tied to this feedback id. Called when the\n* agent stream ends so the SDK Promise unblocks rather than hanging\n* until TTL.\n*/\nfunction rejectAsk(feedbackId, reason) {\n\tfor (const [askId, entry] of pending.entries()) if (entry.feedbackId === feedbackId) {\n\t\tentry.reject(reason);\n\t\tpending.delete(askId);\n\t}\n}\n/**\n* MCP namespaces tools as `mcp__<server-name>__<tool-name>`. Pass this in\n* the SDK's `allowedTools` so the model can actually call it without a\n* permission prompt — otherwise `acceptEdits` mode wouldn't auto-allow a\n* non-Edit tool call.\n*/\nconst ASK_USER_TOOL_NAME = \"mcp__pinagent-ask-user__ask_user\";\n//#endregion\n//#region src/project-events.ts\nconst LISTENERS_SYMBOL = Symbol.for(\"pinagent.project-event.listeners\");\nconst listeners = globalThis[LISTENERS_SYMBOL] ?? /* @__PURE__ */ new Set();\nglobalThis[LISTENERS_SYMBOL] = listeners;\nfunction emitProjectChange(event) {\n\tfor (const listener of listeners) try {\n\t\tlistener(event);\n\t} catch {}\n}\nfunction onProjectChange(listener) {\n\tlisteners.add(listener);\n\treturn () => {\n\t\tlisteners.delete(listener);\n\t};\n}\n//#endregion\n//#region src/agent-auth.ts\n/**\n* Auth for agent runs — the explicit-key contract.\n*\n* Pinagent must never authenticate a run with an API key it merely *found* in\n* the environment. The Claude Agent SDK (and agentic CLIs like Codex) read a\n* raw `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` straight from `process.env`, so a\n* stale, scoped, or third-party key a developer exported for some unrelated\n* tool would otherwise be picked up silently — billing their key and, worse,\n* shadowing the Claude Code / Codex subscription they actually meant to use, so\n* the run dies with `authentication_failed` (\"Invalid API key\").\n*\n* A key is therefore used ONLY when the developer hands one to pinagent\n* explicitly, through one of two channels:\n*\n* 1. the `apiKey` option in the consuming app's plugin config\n* (`pinagent({ apiKey })` in vite.config / next.config), bridged to the\n* runner as `PINAGENT_AGENT_API_KEY`; or\n* 2. a key saved at runtime via the dock's Connections route (`SecretsStore`).\n*\n* With neither set, the implicit key is stripped from the run's environment and\n* the provider falls back to the agentic subscription — the behaviour a\n* developer running Pinagent locally expects.\n*/\n/**\n* pinagent-namespaced bridge var the plugins set from the explicit `apiKey`\n* option. This is the ONLY env channel pinagent treats as an opt-in to use a\n* raw key — never the ambient `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` a\n* developer may have exported for other tools.\n*/\nconst EXPLICIT_API_KEY_ENV = \"PINAGENT_AGENT_API_KEY\";\n/**\n* Credentials provider SDKs / agentic CLIs read straight from the environment.\n* Stripped from any env pinagent hands to a run so a stray shell key can't\n* authenticate by accident; an explicitly-configured key is re-supplied on top.\n*/\nconst ANTHROPIC_KEY_VAR = \"ANTHROPIC_API_KEY\";\nconst PROVIDER_KEY_VARS = [ANTHROPIC_KEY_VAR, \"OPENAI_API_KEY\"];\n/** The key the developer configured for `pinagent({ apiKey })`, if any. */\nfunction configuredKey() {\n\treturn process.env[\"PINAGENT_AGENT_API_KEY\"]?.trim() || null;\n}\n/**\n* Resolve the explicitly-configured Anthropic key for a Claude Agent SDK run,\n* or null when the developer configured neither channel (→ subscription).\n* A dock-saved key is the runtime override and wins, so a user can swap auth\n* without editing config or restarting the dev server; otherwise the\n* plugin-config key applies.\n*/\nasync function resolveAnthropicKey(projectRoot) {\n\treturn await new SecretsStore(projectRoot).getAnthropicKey() ?? configuredKey();\n}\n/**\n* Build the environment handed to a Claude Agent SDK `query()`: the inherited\n* environment with the implicit `ANTHROPIC_API_KEY` (and the internal bridge\n* var) removed, plus the explicitly-configured key re-added when one exists.\n* Entries in `extra` are applied last so callers can still pin run-scoped vars\n* (e.g. `PINAGENT_PROJECT_ROOT`).\n*/\nasync function buildSdkAuthEnv(projectRoot, extra = {}) {\n\tconst env = { ...process.env };\n\tdelete env[ANTHROPIC_KEY_VAR];\n\tdelete env[EXPLICIT_API_KEY_ENV];\n\tconst key = await resolveAnthropicKey(projectRoot);\n\tif (key) env[ANTHROPIC_KEY_VAR] = key;\n\treturn {\n\t\t...env,\n\t\t...extra\n\t};\n}\n/**\n* Build the environment for a wrapped agent CLI (Codex, aider, …): the\n* inherited environment with the implicit provider keys (and the internal\n* bridge var) stripped, plus the explicitly-configured key re-supplied under\n* both provider names so whichever the CLI reads picks it up. Absent an\n* explicit key, the CLI sees none and falls back to its own login (e.g. Codex →\n* the ChatGPT subscription). `extra` overrides win last.\n*\n* Only the plugin-config key feeds the CLI: the dock's saved key is\n* Claude-provider-specific, so it isn't reinterpreted as an arbitrary CLI's\n* credential.\n*/\nfunction buildCliAuthEnv(extra = {}) {\n\tconst env = { ...process.env };\n\tconst key = configuredKey();\n\tfor (const v of PROVIDER_KEY_VARS) delete env[v];\n\tdelete env[EXPLICIT_API_KEY_ENV];\n\tif (key) for (const v of PROVIDER_KEY_VARS) env[v] = key;\n\treturn {\n\t\t...env,\n\t\t...extra\n\t};\n}\n//#endregion\n//#region src/agent-guide.ts\n/**\n* Surfacing the project guidance nearest to the element the developer\n* clicked. When feedback lands with a `file:line`, walk up the directory\n* tree from that file toward the project root and pull in the closest\n* `CLAUDE.md` / `AGENTS.md` so the agent starts with the conventions that\n* actually govern the code it's about to touch.\n*\n* The Claude Agent SDK (and Codex) already discover guide files by walking\n* UP from the agent's working directory — but that misses a nested guide\n* sitting *below* the worktree/project root, right next to the clicked\n* file. That nested guide is exactly the one most relevant to the edit, so\n* we resolve it explicitly here and inject it into the system prompt.\n*/\n/**\n* Guide filenames we recognise. `CLAUDE.md` is Claude's convention and\n* `AGENTS.md` is the cross-agent (Codex, etc.) one; both are checked at\n* each directory so whichever a project uses is found.\n*/\nconst GUIDE_FILENAMES = [\"CLAUDE.md\", \"AGENTS.md\"];\n/**\n* Hard cap on injected guide bytes. A sprawling guide shouldn't crowd out\n* the actual task in the prompt; past this we truncate with a marker.\n*/\nconst MAX_GUIDE_BYTES = 16e3;\n/**\n* Find the guide file nearest to `file`, searching its own directory first\n* and walking up to (and including) `projectRoot`. Returns `null` when the\n* feedback has no file, the path escapes the project, or no guide exists\n* anywhere on the path.\n*/\nfunction findNearestAgentGuide(file, projectRoot, opts = {}) {\n\tif (!file) return null;\n\tconst root = resolve(projectRoot);\n\tconst absFile = isAbsolute(file) ? resolve(file) : resolve(root, file);\n\tif (!isWithin(root, absFile)) return null;\n\tconst order = guideOrder(opts.prefer);\n\tlet dir = dirname(absFile);\n\twhile (true) {\n\t\tfor (const filename of order) {\n\t\t\tconst guidePath = resolve(dir, filename);\n\t\t\tconst content = tryRead(guidePath);\n\t\t\tif (content !== null) {\n\t\t\t\tconst clipped = clip(content);\n\t\t\t\treturn {\n\t\t\t\t\tfilename,\n\t\t\t\t\trelativePath: toPosix(relative(root, guidePath)),\n\t\t\t\t\tcontent: clipped.content,\n\t\t\t\t\ttruncated: clipped.truncated\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\tif (dir === root) break;\n\t\tconst parent = dirname(dir);\n\t\tif (parent === dir) break;\n\t\tdir = parent;\n\t}\n\treturn null;\n}\n/**\n* Render a found guide as a block to append to the agent's system prompt\n* (or, for a wrapped CLI with no system prompt, its task prompt). Framed so\n* the agent knows the guidance is scoped to the file it's editing.\n*/\nfunction renderAgentGuide(guide) {\n\treturn [\n\t\t\"\",\n\t\t`Project guidance applies to the code you're editing. The nearest guide to`,\n\t\t`the clicked element is \\`${guide.relativePath}\\` — follow it${guide.truncated ? \" (truncated below; read the full file if you need more)\" : \"\"}:`,\n\t\t\"\",\n\t\t`<project-guidance path=\"${guide.relativePath}\">`,\n\t\tguide.content,\n\t\t\"</project-guidance>\"\n\t].join(\"\\n\");\n}\n/** Order the filenames so the preferred one is checked first at each dir. */\nfunction guideOrder(prefer) {\n\tif (!prefer || prefer === GUIDE_FILENAMES[0]) return GUIDE_FILENAMES;\n\treturn [prefer, ...GUIDE_FILENAMES.filter((f) => f !== prefer)];\n}\n/** Read a file as UTF-8, returning null for any read error (missing, dir, …). */\nfunction tryRead(path) {\n\ttry {\n\t\treturn readFileSync(path, \"utf8\");\n\t} catch {\n\t\treturn null;\n\t}\n}\n/** True when `child` is `parent` or sits inside it. */\nfunction isWithin(parent, child) {\n\tif (child === parent) return true;\n\tconst rel = relative(parent, child);\n\treturn rel !== \"\" && !rel.startsWith(\"..\") && !isAbsolute(rel);\n}\n/** Clip content to the byte cap on a line boundary, with a marker. */\nfunction clip(content) {\n\tif (Buffer.byteLength(content, \"utf8\") <= MAX_GUIDE_BYTES) return {\n\t\tcontent,\n\t\ttruncated: false\n\t};\n\tlet sliced = content.slice(0, MAX_GUIDE_BYTES);\n\twhile (Buffer.byteLength(sliced, \"utf8\") > MAX_GUIDE_BYTES - 32) sliced = sliced.slice(0, -32);\n\tconst lastNl = sliced.lastIndexOf(\"\\n\");\n\tif (lastNl > 0) sliced = sliced.slice(0, lastNl);\n\treturn {\n\t\tcontent: `${sliced}\\n\\n… [truncated]`,\n\t\ttruncated: true\n\t};\n}\n/** Normalise path separators to POSIX for stable prompt/display output. */\nfunction toPosix(path) {\n\treturn path.split(/[\\\\/]/).join(\"/\");\n}\n//#endregion\n//#region src/agent-render.ts\n/**\n* Render a single SDK message as a markdown fragment to append to the log.\n*\n* Returns '' for messages we don't surface (status pings, partial deltas,\n* etc.) so the caller can no-op cheaply.\n*\n* The aim is a readable transcript, not a raw event dump — text comes\n* through as plain markdown, tool calls collapse to a single-line chip,\n* errors stand out. If a new SDK message type arrives we don't recognise,\n* we drop it silently rather than serialising a JSON blob into the log.\n*/\nfunction renderMessage(message) {\n\tswitch (message.type) {\n\t\tcase \"assistant\": return renderAssistant(message);\n\t\tcase \"result\": return \"\\n---\\n\";\n\t\tcase \"user\": return renderUser(message);\n\t\tdefault: return \"\";\n\t}\n}\nfunction renderInitFooter(message) {\n\tconst mcp = message.mcp_servers.map((s) => `${s.name}=${s.status}`).join(\", \");\n\tconst lines = [`> _session_ \\`${message.session_id}\\` · model \\`${message.model}\\` · ${message.permissionMode}`];\n\tif (mcp) lines.push(`> _mcp_ ${mcp}`);\n\tlines.push(\"\");\n\treturn `${lines.join(\"\\n\")}\\n`;\n}\nfunction renderResultFooter(result, apiKeySource) {\n\tconst lines = [];\n\tif (result.subtype === \"success\") lines.push(`**Outcome:** success (${result.num_turns} turn${result.num_turns === 1 ? \"\" : \"s\"})`);\n\telse {\n\t\tlines.push(`**Outcome:** \\`${result.subtype}\\``);\n\t\tif (result.errors?.length) {\n\t\t\tlines.push(\"\");\n\t\t\tfor (const e of result.errors) lines.push(`> ${e}`);\n\t\t}\n\t}\n\tlines.push(`**Tokens:** in=${result.usage.input_tokens} · out=${result.usage.output_tokens}${result.usage.cache_read_input_tokens ? ` · cache_read=${result.usage.cache_read_input_tokens}` : \"\"}${result.usage.cache_creation_input_tokens ? ` · cache_write=${result.usage.cache_creation_input_tokens}` : \"\"}`);\n\tlines.push(isNotionalCost(apiKeySource) ? `**Cost:** ≈$${result.total_cost_usd.toFixed(4)} API-equivalent (subscription — not billed)` : `**Cost:** $${result.total_cost_usd.toFixed(4)}`);\n\tlines.push(`**Duration:** ${(result.duration_ms / 1e3).toFixed(1)}s`);\n\treturn lines.join(\" \\n\");\n}\nfunction renderAssistant(message) {\n\tconst blocks = message.message.content;\n\tif (!Array.isArray(blocks)) return \"\";\n\tconst out = [];\n\tfor (const block of blocks) if (block.type === \"text\" && block.text.trim()) out.push(`${block.text}\\n`);\n\telse if (block.type === \"tool_use\") out.push(renderToolUse(block.name, block.input));\n\telse if (block.type === \"thinking\") out.push(\"<!-- thinking -->\\n\");\n\tif (message.error) out.push(`\\n> ⚠️ assistant error: \\`${message.error}\\`\\n`);\n\tif (out.length === 0) return \"\";\n\treturn `${out.join(\"\\n\")}\\n`;\n}\nfunction renderUser(message) {\n\tconst content = message.message?.content;\n\tif (!Array.isArray(content)) return \"\";\n\tconst chips = [];\n\tfor (const block of content) if (block.type === \"tool_result\") chips.push(renderToolResult(block));\n\tif (chips.length === 0) return \"\";\n\treturn `${chips.join(\"\\n\")}\\n`;\n}\nfunction renderToolUse(name, input) {\n\tconst summary = summariseToolInput(name, input);\n\treturn `\\`[${name}]\\`${summary ? ` ${summary}` : \"\"}\\n`;\n}\nfunction renderToolResult(block) {\n\treturn `${block.is_error ? \"✗\" : \"✓\"} _tool result_`;\n}\nfunction summariseToolInput(name, input) {\n\tif (input == null || typeof input !== \"object\") return \"\";\n\tconst obj = input;\n\tfor (const f of [\n\t\t\"file_path\",\n\t\t\"path\",\n\t\t\"filePath\",\n\t\t\"notebook_path\"\n\t]) if (typeof obj[f] === \"string\") return `\\`${obj[f]}\\``;\n\tif (typeof obj.command === \"string\") return `\\`${truncate(obj.command, 80)}\\``;\n\tif (typeof obj.pattern === \"string\") return `pattern=\\`${truncate(obj.pattern, 60)}\\``;\n\tif (typeof obj.url === \"string\") return obj.url;\n\tif (typeof obj.prompt === \"string\") return `\\`${truncate(obj.prompt, 60)}\\``;\n\tif (name.startsWith(\"mcp__\")) {\n\t\tconst keys = Object.keys(obj);\n\t\tconst first = keys[0];\n\t\tif (keys.length === 1 && first != null && typeof obj[first] !== \"object\") return `${first}=\\`${String(obj[first])}\\``;\n\t}\n\treturn \"\";\n}\nfunction truncate(s, n) {\n\tif (s.length <= n) return s;\n\treturn `${s.slice(0, n - 1)}…`;\n}\n//#endregion\n//#region src/providers/claude-code.ts\n/**\n* @pinagent/mcp tool names the spawned agent needs to do its job:\n*\n* - `get_feedback` — fetch the full feedback record incl. screenshot\n* - `resolve_feedback` — mark fixed/wontfix/deferred when done\n* - `get_source_context` — read a window of source around file:line\n* - `list_pending_feedback`— rarely needed by a spawned agent (it knows its\n* own id), included for parity with pull mode\n*\n* They are surfaced to the SDK via the user's `.mcp.json` (loaded by\n* `settingSources: ['user', 'project', 'local']`). Allowlisting them\n* makes the spawned agent auto-accept the calls instead of timing out\n* waiting for a non-existent permission prompt.\n*/\nconst PINAGENT_MCP_TOOLS = [\n\t\"mcp__pinagent__get_feedback\",\n\t\"mcp__pinagent__resolve_feedback\",\n\t\"mcp__pinagent__get_source_context\",\n\t\"mcp__pinagent__list_pending_feedback\"\n];\n/**\n* Tools a dry-run must never be allowed to call: anything that writes to\n* the workspace, runs a command, or transitions the agent out of plan\n* mode. See `buildSdkOptions` for why denying `ExitPlanMode` is the load-\n* bearing entry — without it a headless `plan`-mode run silently writes.\n*/\nconst DRY_RUN_DENIED_TOOLS = new Set([\n\t\"ExitPlanMode\",\n\t\"Edit\",\n\t\"MultiEdit\",\n\t\"Write\",\n\t\"NotebookEdit\",\n\t\"Bash\"\n]);\n/**\n* The default, most capable provider: the Claude Agent SDK. Runs the full\n* agentic loop (tool calls, edits, permission gating, session resume) and\n* streams its `SDKMessage`s, which we normalize into Pinagent's\n* `AgentEvent` union here so nothing downstream has to know it was Claude.\n*/\nvar ClaudeCodeProvider = class {\n\tid = \"claude-code\";\n\tasync *run(req) {\n\t\tconst sdkOptions = await buildSdkOptions(req);\n\t\tconst startedAt = Date.now();\n\t\tlet apiKeySource = null;\n\t\tlet turn = 0;\n\t\tlet sawResult = false;\n\t\ttry {\n\t\t\tfor await (const message of query({\n\t\t\t\tprompt: req.prompt,\n\t\t\t\toptions: sdkOptions\n\t\t\t})) {\n\t\t\t\tconst sessionId = \"session_id\" in message && typeof message.session_id === \"string\" ? message.session_id : void 0;\n\t\t\t\tif (message.type === \"system\" && message.subtype === \"init\") {\n\t\t\t\t\tapiKeySource = message.apiKeySource ?? null;\n\t\t\t\t\tyield {\n\t\t\t\t\t\tevents: toAgentEvents(message),\n\t\t\t\t\t\tlog: renderInitFooter(message),\n\t\t\t\t\t\tsessionId\n\t\t\t\t\t};\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (message.type === \"result\") {\n\t\t\t\t\tsawResult = true;\n\t\t\t\t\tyield {\n\t\t\t\t\t\tevents: toAgentEvents(message),\n\t\t\t\t\t\tlog: renderMessage(message),\n\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\tisResult: true,\n\t\t\t\t\t\tresultFooter: renderResultFooter(message, apiKeySource)\n\t\t\t\t\t};\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst events = toAgentEvents(message);\n\t\t\t\tif (message.type === \"assistant\") {\n\t\t\t\t\tturn += 1;\n\t\t\t\t\tevents.push({\n\t\t\t\t\t\ttype: \"progress\",\n\t\t\t\t\t\tturn\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tyield {\n\t\t\t\t\tevents,\n\t\t\t\t\tlog: renderMessage(message),\n\t\t\t\t\tsessionId\n\t\t\t\t};\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tif (sawResult) return;\n\t\t\tconst aborted = req.abortSignal.aborted;\n\t\t\tconst detail = err instanceof Error ? err.message : String(err);\n\t\t\tconst durationMs = Date.now() - startedAt;\n\t\t\tconst resultEvent = {\n\t\t\t\ttype: \"result\",\n\t\t\t\tsubtype: aborted ? \"aborted\" : \"error\",\n\t\t\t\tnumTurns: turn,\n\t\t\t\ttotalCostUsd: 0,\n\t\t\t\tdurationMs\n\t\t\t};\n\t\t\tconst events = [];\n\t\t\tconst seconds = `${(durationMs / 1e3).toFixed(1)}s`;\n\t\t\tlet footer;\n\t\t\tif (aborted) footer = `**Outcome:** \\`aborted\\` \\n**Duration:** ${seconds}`;\n\t\t\telse {\n\t\t\t\tresultEvent.errors = [detail];\n\t\t\t\tevents.push({\n\t\t\t\t\ttype: \"error\",\n\t\t\t\t\tmessage: detail\n\t\t\t\t});\n\t\t\t\tfooter = `**Outcome:** \\`error\\` \\n> ${detail} \\n**Duration:** ${seconds}`;\n\t\t\t}\n\t\t\tevents.push(resultEvent);\n\t\t\tyield {\n\t\t\t\tevents,\n\t\t\t\tlog: `\\n> [pinagent] ${aborted ? \"run aborted by user\" : `agent stream errored: ${detail}`}\\n`,\n\t\t\t\tisResult: true,\n\t\t\t\tresultFooter: footer\n\t\t\t};\n\t\t}\n\t}\n};\n/**\n* Build the Claude Agent SDK options for a run. Kept byte-for-byte\n* equivalent to the original inline construction in `agent.ts` so the\n* SDK-mocking tests (which assert on the params handed to `query()`)\n* continue to pass unchanged.\n*/\nasync function buildSdkOptions(req) {\n\tconst env = await buildSdkAuthEnv(req.projectRoot, {\n\t\tPINAGENT_PROJECT_ROOT: req.projectRoot,\n\t\tCLAUDE_CODE_STREAM_CLOSE_TIMEOUT: \"720000\"\n\t});\n\tconst guide = findNearestAgentGuide(req.targetFile, req.projectRoot, { prefer: \"CLAUDE.md\" });\n\tconst options = {\n\t\tcwd: req.cwd,\n\t\tpermissionMode: req.permissionMode,\n\t\tenv,\n\t\tsettingSources: [\n\t\t\t\"user\",\n\t\t\t\"project\",\n\t\t\t\"local\"\n\t\t],\n\t\tabortController: toAbortController(req.abortSignal),\n\t\tmcpServers: { \"pinagent-ask-user\": createAskUserMcpServer(req.feedbackId) },\n\t\tallowedTools: [ASK_USER_TOOL_NAME, ...PINAGENT_MCP_TOOLS],\n\t\tsystemPrompt: {\n\t\t\ttype: \"preset\",\n\t\t\tpreset: \"claude_code\",\n\t\t\tappend: [\n\t\t\t\t\"\",\n\t\t\t\t\"You are running inside Pinagent, a tool that lets developers click a UI\",\n\t\t\t\t\"element in the browser and leave a comment for you to act on. The user\",\n\t\t\t\t\"is watching your output stream into a small widget pane next to the\",\n\t\t\t\t\"element they clicked.\",\n\t\t\t\t\"\",\n\t\t\t\t`If you need clarification mid-task, call the \\`${ASK_USER_TOOL_NAME}\\``,\n\t\t\t\t\"tool with a clear question (and optional `options` for closed-ended\",\n\t\t\t\t\"answers). Prefer asking over guessing on ambiguous requirements.\",\n\t\t\t\t...guide ? [renderAgentGuide(guide)] : []\n\t\t\t].join(\"\\n\")\n\t\t}\n\t};\n\tif (req.permissionMode === \"plan\") options.canUseTool = async (toolName) => DRY_RUN_DENIED_TOOLS.has(toolName) ? {\n\t\tbehavior: \"deny\",\n\t\tmessage: `Dry-run mode: \\`${toolName}\\` is blocked. Pinagent is in dry-run (plan) mode — describe the change you would make, but do not edit files, run commands, or exit plan mode.`\n\t} : { behavior: \"allow\" };\n\tif (req.resume) options.resume = req.resume;\n\treturn options;\n}\n/**\n* The SDK wants an `AbortController`, but the provider contract hands us a\n* bare `AbortSignal` (so non-SDK providers aren't forced to fabricate a\n* controller). Bridge the two by forwarding the signal's abort to a fresh\n* controller the SDK can own.\n*/\nfunction toAbortController(signal) {\n\tconst controller = new AbortController();\n\tif (signal.aborted) controller.abort();\n\telse signal.addEventListener(\"abort\", () => controller.abort(), { once: true });\n\treturn controller;\n}\n/** Translate one SDK message into zero or more Pinagent bus events. */\nfunction toAgentEvents(message) {\n\tswitch (message.type) {\n\t\tcase \"system\":\n\t\t\tif (message.subtype === \"init\") return [{\n\t\t\t\ttype: \"init\",\n\t\t\t\tsessionId: message.session_id,\n\t\t\t\tmodel: message.model,\n\t\t\t\tpermissionMode: message.permissionMode,\n\t\t\t\tapiKeySource: message.apiKeySource\n\t\t\t}];\n\t\t\treturn [];\n\t\tcase \"assistant\": {\n\t\t\tconst out = [];\n\t\t\tconst blocks = message.message?.content;\n\t\t\tif (!Array.isArray(blocks)) return out;\n\t\t\tfor (const block of blocks) if (block.type === \"text\" && block.text.trim()) out.push({\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: block.text\n\t\t\t});\n\t\t\telse if (block.type === \"tool_use\") {\n\t\t\t\tif (block.name === \"mcp__pinagent-ask-user__ask_user\") continue;\n\t\t\t\tout.push({\n\t\t\t\t\ttype: \"tool_use\",\n\t\t\t\t\tname: block.name,\n\t\t\t\t\tsummary: summariseToolInput(block.name, block.input)\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (message.error) out.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\tmessage: `assistant error: ${message.error}`\n\t\t\t});\n\t\t\treturn out;\n\t\t}\n\t\tcase \"user\": {\n\t\t\tconst out = [];\n\t\t\tconst blocks = message.message?.content;\n\t\t\tif (!Array.isArray(blocks)) return out;\n\t\t\tfor (const block of blocks) if (typeof block === \"object\" && block !== null && block.type === \"tool_result\") out.push({\n\t\t\t\ttype: \"tool_result\",\n\t\t\t\tok: !block.is_error\n\t\t\t});\n\t\t\treturn out;\n\t\t}\n\t\tcase \"result\": {\n\t\t\tconst event = {\n\t\t\t\ttype: \"result\",\n\t\t\t\tsubtype: message.subtype,\n\t\t\t\tnumTurns: message.num_turns,\n\t\t\t\ttotalCostUsd: message.total_cost_usd,\n\t\t\t\tdurationMs: message.duration_ms\n\t\t\t};\n\t\t\tif (message.subtype !== \"success\" && Array.isArray(message.errors)) event.errors = message.errors;\n\t\t\treturn [event];\n\t\t}\n\t\tdefault: return [];\n\t}\n}\n//#endregion\n//#region src/providers/cli.ts\n/**\n* Bring-your-own-model provider: wrap an arbitrary agentic CLI (Codex,\n* aider, opencode, Cline headless, a shell script, …) and translate its\n* stdout into Pinagent's `AgentEvent` stream.\n*\n* The wrapped CLI owns its own agentic loop and edits files directly in\n* `req.cwd`. We don't intercept its tool calls — we surface its narration\n* to the widget and let its on-disk edits land in the project (or\n* worktree) exactly as the Claude provider's edits do.\n*\n* Configuration (env, read per-run so a dev-server restart isn't needed):\n*\n* - `PINAGENT_AGENT_CLI_COMMAND` (required) the command to run. Either a\n* JSON array (`[\"aider\",\"--yes-always\"]`) or a space-separated string\n* (`aider --yes-always`). The first element is the executable.\n* - `PINAGENT_AGENT_CLI_PROMPT` `arg` (default) appends the prompt as the\n* final argv; `stdin` writes it to the child's stdin and closes it.\n* - `PINAGENT_AGENT_CLI_FORMAT` `text` (default) treats each stdout line\n* as assistant text; `stream-json` parses each line as JSON and maps a\n* pragmatic subset of common agent event shapes.\n* - `PINAGENT_AGENT_CLI_MODEL` label for the `init` event (defaults to\n* the executable name). Cosmetic — drives the widget's model chip.\n*\n* The child inherits the parent env plus `PINAGENT_PROJECT_ROOT`,\n* `PINAGENT_FEEDBACK_ID`, and `PINAGENT_RESUME_SESSION` so an MCP-aware\n* CLI (or a wrapper script) can connect to the pinagent MCP server, fetch\n* the feedback, and call `resolve_feedback` itself.\n*\n* Auth is explicit-only (see agent-auth.ts): `buildCliAuthEnv` strips any\n* ambient `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` from the child's env so a\n* stray shell key can't bill against a wrapped CLI by accident, and re-supplies\n* a key only when the consuming app passed one via the `apiKey` plugin option.\n* Absent that, the CLI falls back to its own login (e.g. Codex → the ChatGPT\n* subscription).\n*/\nvar CliAgentProvider = class {\n\tid = \"cli\";\n\tasync *run(req) {\n\t\tconst config = resolveCliConfig(process.env);\n\t\tconst sessionId = req.resume ?? nanoid(12);\n\t\tconst startedAt = Date.now();\n\t\tyield {\n\t\t\tevents: [{\n\t\t\t\ttype: \"init\",\n\t\t\t\tsessionId,\n\t\t\t\tmodel: config.model,\n\t\t\t\tpermissionMode: req.permissionMode,\n\t\t\t\tapiKeySource: \"cli\"\n\t\t\t}],\n\t\t\tlog: `> _cli_ \\`${config.argv.join(\" \")}\\` · session \\`${sessionId}\\`\\n\\n`,\n\t\t\tsessionId\n\t\t};\n\t\tconst guide = findNearestAgentGuide(req.targetFile, req.projectRoot, { prefer: \"AGENTS.md\" });\n\t\tconst prompt = guide ? `${req.prompt}\\n${renderAgentGuide(guide)}` : req.prompt;\n\t\tconst args = [...config.argv.slice(1)];\n\t\tif (config.promptMode === \"arg\") args.push(prompt);\n\t\tconst child = spawn(config.argv[0], args, {\n\t\t\tcwd: req.cwd,\n\t\t\tenv: buildCliAuthEnv({\n\t\t\t\tPINAGENT_PROJECT_ROOT: req.projectRoot,\n\t\t\t\tPINAGENT_FEEDBACK_ID: req.feedbackId,\n\t\t\t\tPINAGENT_RESUME_SESSION: req.resume ?? \"\"\n\t\t\t}),\n\t\t\tstdio: [\n\t\t\t\t\"pipe\",\n\t\t\t\t\"pipe\",\n\t\t\t\t\"pipe\"\n\t\t\t]\n\t\t});\n\t\tconst onAbort = () => child.kill(\"SIGTERM\");\n\t\tif (req.abortSignal.aborted) onAbort();\n\t\telse req.abortSignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\tchild.stdin.on(\"error\", () => {});\n\t\ttry {\n\t\t\tif (config.promptMode === \"stdin\") child.stdin.write(prompt);\n\t\t\tchild.stdin.end();\n\t\t} catch {}\n\t\tconst queue = new AsyncLineQueue();\n\t\tconst stdout = createInterface({ input: child.stdout });\n\t\tconst stderr = createInterface({ input: child.stderr });\n\t\tstdout.on(\"line\", (line) => queue.push({\n\t\t\tline,\n\t\t\tstream: \"stdout\"\n\t\t}));\n\t\tstderr.on(\"line\", (line) => queue.push({\n\t\t\tline,\n\t\t\tstream: \"stderr\"\n\t\t}));\n\t\tlet openStreams = 2;\n\t\tconst onClose = () => {\n\t\t\topenStreams -= 1;\n\t\t\tif (openStreams === 0) queue.close();\n\t\t};\n\t\tstdout.on(\"close\", onClose);\n\t\tstderr.on(\"close\", onClose);\n\t\tconst exit = new Promise((resolve) => {\n\t\t\tchild.on(\"exit\", (code, signal) => resolve({\n\t\t\t\tcode,\n\t\t\t\tsignal,\n\t\t\t\tspawnError: null\n\t\t\t}));\n\t\t\tchild.on(\"error\", (err) => resolve({\n\t\t\t\tcode: null,\n\t\t\t\tsignal: null,\n\t\t\t\tspawnError: err instanceof Error ? err : new Error(String(err))\n\t\t\t}));\n\t\t});\n\t\tlet turn = 0;\n\t\tfor await (const { line, stream } of queue) {\n\t\t\tconst events = stream === \"stderr\" ? parseTextLine(line, stream) : config.format === \"stream-json\" ? parseStreamJsonLine(line) : parseTextLine(line, stream);\n\t\t\tif (events.length === 0) continue;\n\t\t\tif (stream === \"stdout\" && events.some((e) => e.type === \"text\")) {\n\t\t\t\tturn += 1;\n\t\t\t\tevents.push({\n\t\t\t\t\ttype: \"progress\",\n\t\t\t\t\tturn\n\t\t\t\t});\n\t\t\t}\n\t\t\tyield {\n\t\t\t\tevents,\n\t\t\t\tlog: renderCliLine(line, stream)\n\t\t\t};\n\t\t}\n\t\treq.abortSignal.removeEventListener(\"abort\", onAbort);\n\t\tconst { code, signal, spawnError } = await exit;\n\t\tconst aborted = req.abortSignal.aborted;\n\t\tconst subtype = aborted ? \"aborted\" : spawnError || signal || code !== 0 ? \"error\" : \"success\";\n\t\tconst resultEvent = {\n\t\t\ttype: \"result\",\n\t\t\tsubtype,\n\t\t\tnumTurns: turn,\n\t\t\ttotalCostUsd: 0,\n\t\t\tdurationMs: Date.now() - startedAt\n\t\t};\n\t\tif (subtype !== \"success\") {\n\t\t\tlet reason;\n\t\t\tif (aborted) reason = \"run aborted\";\n\t\t\telse if (spawnError) reason = `failed to start ${config.argv[0]}: ${spawnError.message}`;\n\t\t\telse if (signal) reason = `${config.argv[0]} terminated by signal ${signal}`;\n\t\t\telse reason = `${config.argv[0]} exited with code ${code}`;\n\t\t\tresultEvent.errors = [reason];\n\t\t}\n\t\tyield {\n\t\t\tevents: [resultEvent],\n\t\t\tlog: \"\\n---\\n\",\n\t\t\tisResult: true,\n\t\t\tresultFooter: renderCliFooter(subtype, turn, Date.now() - startedAt)\n\t\t};\n\t}\n};\n/** Parse the CLI provider config out of the environment, validating it. */\nfunction resolveCliConfig(env) {\n\tconst raw = env.PINAGENT_AGENT_CLI_COMMAND?.trim();\n\tif (!raw) throw new Error(\"PINAGENT_AGENT_CLI_COMMAND is required when PINAGENT_AGENT_PROVIDER=cli. Set it to the agent CLI to run, e.g. PINAGENT_AGENT_CLI_COMMAND='[\\\"aider\\\",\\\"--yes-always\\\"]'.\");\n\tlet argv;\n\tif (raw.startsWith(\"[\")) try {\n\t\tconst parsed = JSON.parse(raw);\n\t\tif (!Array.isArray(parsed) || parsed.some((a) => typeof a !== \"string\")) throw new Error(\"not a string array\");\n\t\targv = parsed;\n\t} catch (err) {\n\t\tthrow new Error(`PINAGENT_AGENT_CLI_COMMAND looked like JSON but failed to parse as a string array: ${err instanceof Error ? err.message : String(err)}`);\n\t}\n\telse argv = raw.split(/\\s+/).filter(Boolean);\n\tif (argv.length === 0) throw new Error(\"PINAGENT_AGENT_CLI_COMMAND resolved to an empty command\");\n\tconst promptMode = env.PINAGENT_AGENT_CLI_PROMPT === \"stdin\" ? \"stdin\" : \"arg\";\n\tconst format = env.PINAGENT_AGENT_CLI_FORMAT === \"stream-json\" ? \"stream-json\" : \"text\";\n\tconst model = env.PINAGENT_AGENT_CLI_MODEL?.trim() || argv[0];\n\treturn {\n\t\targv,\n\t\tpromptMode,\n\t\tformat,\n\t\tmodel\n\t};\n}\n/** Plain-text mode: every non-blank line is assistant narration. */\nfunction parseTextLine(line, stream) {\n\tif (!line.trim()) return [];\n\treturn [{\n\t\ttype: \"text\",\n\t\ttext: stream === \"stderr\" ? `[stderr] ${line}` : line\n\t}];\n}\n/**\n* stream-json mode: best-effort mapping of the common shapes emitted by\n* agentic CLIs. Unknown/unparseable lines fall back to raw text so output\n* is never silently dropped.\n*/\nfunction parseStreamJsonLine(line) {\n\tconst trimmed = line.trim();\n\tif (!trimmed) return [];\n\tlet obj;\n\ttry {\n\t\tobj = JSON.parse(trimmed);\n\t} catch {\n\t\treturn [{\n\t\t\ttype: \"text\",\n\t\t\ttext: line\n\t\t}];\n\t}\n\tif (obj == null || typeof obj !== \"object\") return [{\n\t\ttype: \"text\",\n\t\ttext: line\n\t}];\n\tconst o = obj;\n\tconst direct = pickString(o.text) ?? pickString(o.content) ?? pickString(o.delta) ?? deltaText(o.delta);\n\tif (direct) return [{\n\t\ttype: \"text\",\n\t\ttext: direct\n\t}];\n\tconst message = o.message;\n\tif (message && typeof message === \"object\") {\n\t\tconst blocks = message.content;\n\t\tif (Array.isArray(blocks)) return blocksToEvents(blocks);\n\t}\n\tif (Array.isArray(o.content)) return blocksToEvents(o.content);\n\tconst type = pickString(o.type);\n\tif ((type === \"tool_use\" || type === \"tool_call\") && typeof o.name === \"string\") return [{\n\t\ttype: \"tool_use\",\n\t\tname: o.name,\n\t\tsummary: summariseToolInput(o.name, o.input)\n\t}];\n\treturn [{\n\t\ttype: \"text\",\n\t\ttext: line\n\t}];\n}\nfunction blocksToEvents(blocks) {\n\tconst out = [];\n\tfor (const block of blocks) {\n\t\tif (block == null || typeof block !== \"object\") continue;\n\t\tconst b = block;\n\t\tif (b.type === \"text\" && typeof b.text === \"string\" && b.text.trim()) out.push({\n\t\t\ttype: \"text\",\n\t\t\ttext: b.text\n\t\t});\n\t\telse if ((b.type === \"tool_use\" || b.type === \"tool_call\") && typeof b.name === \"string\") out.push({\n\t\t\ttype: \"tool_use\",\n\t\t\tname: b.name,\n\t\t\tsummary: summariseToolInput(b.name, b.input)\n\t\t});\n\t\telse if (b.type === \"tool_result\") out.push({\n\t\t\ttype: \"tool_result\",\n\t\t\tok: !b.is_error\n\t\t});\n\t}\n\treturn out;\n}\nfunction pickString(v) {\n\treturn typeof v === \"string\" && v.trim() ? v : null;\n}\nfunction deltaText(v) {\n\tif (v && typeof v === \"object\") return pickString(v.text);\n\treturn null;\n}\nfunction renderCliLine(line, stream) {\n\tif (!line.trim()) return \"\";\n\treturn stream === \"stderr\" ? `> \\`${line}\\`\\n` : `${line}\\n`;\n}\nfunction renderCliFooter(subtype, turns, durationMs) {\n\treturn [\n\t\tsubtype === \"success\" ? `**Outcome:** success (${turns} chunk${turns === 1 ? \"\" : \"s\"})` : `**Outcome:** \\`${subtype}\\``,\n\t\t\"**Cost:** n/a (external CLI)\",\n\t\t`**Duration:** ${(durationMs / 1e3).toFixed(1)}s`\n\t].join(\" \\n\");\n}\n/**\n* Minimal async iterable backed by a push queue. `readline` is push-based\n* (`'line'` events) but our provider is pull-based (`for await`), so this\n* buffers lines until the consumer asks for them and resolves cleanly when\n* the underlying streams close.\n*/\nvar AsyncLineQueue = class {\n\tbuffer = [];\n\tresolvers = [];\n\tdone = false;\n\tpush(item) {\n\t\tif (this.done) return;\n\t\tconst resolve = this.resolvers.shift();\n\t\tif (resolve) resolve({\n\t\t\tvalue: item,\n\t\t\tdone: false\n\t\t});\n\t\telse this.buffer.push(item);\n\t}\n\tclose() {\n\t\tthis.done = true;\n\t\tfor (const resolve of this.resolvers.splice(0)) resolve({\n\t\t\tvalue: void 0,\n\t\t\tdone: true\n\t\t});\n\t}\n\t[Symbol.asyncIterator]() {\n\t\treturn { next: () => {\n\t\t\tconst item = this.buffer.shift();\n\t\t\tif (item) return Promise.resolve({\n\t\t\t\tvalue: item,\n\t\t\t\tdone: false\n\t\t\t});\n\t\t\tif (this.done) return Promise.resolve({\n\t\t\t\tvalue: void 0,\n\t\t\t\tdone: true\n\t\t\t});\n\t\t\treturn new Promise((resolve) => this.resolvers.push(resolve));\n\t\t} };\n\t}\n};\n//#endregion\n//#region src/providers/index.ts\n/**\n* Resolve which agent backend a run should use. Precedence:\n* `PINAGENT_AGENT_PROVIDER` env > default (`claude-code`).\n*\n* Defaulting to `claude-code` keeps every existing setup working with no\n* config; \"bring your own model\" is opt-in via the env var.\n*/\nfunction resolveProviderId(env) {\n\tif (env.PINAGENT_AGENT_PROVIDER?.trim().toLowerCase() === \"cli\") return \"cli\";\n\treturn \"claude-code\";\n}\n/** Instantiate the provider for an id. */\nfunction createProvider(id) {\n\tswitch (id) {\n\t\tcase \"cli\": return new CliAgentProvider();\n\t\tdefault: return new ClaudeCodeProvider();\n\t}\n}\n/** Convenience: resolve the provider straight from the environment. */\nfunction resolveProvider(env = process.env) {\n\treturn createProvider(resolveProviderId(env));\n}\n//#endregion\n//#region src/storage.ts\n/**\n* Bus event roles that shouldn't count toward \"transcript depth\". The\n* `__finished` sentinel comes from `bus.ts` and isn't a real event;\n* `init` and `result` are agent-run bookkeeping the user-facing badge\n* shouldn't include. Anything else (text / tool_use / tool_result /\n* ask_user / error / user / ask_response) counts.\n*/\nconst NON_MESSAGE_ROLES = [\n\t\"__finished\",\n\t\"init\",\n\t\"result\"\n];\nconst ID_RE = /^[A-Za-z0-9_-]{8,16}$/;\n/** Per-extra anchor in the multi-pick payload — flat fields mirroring\n* the primary widget_anchors columns, minus viewport/userAgent (those\n* are conversation-level). */\nconst AdditionalAnchorSchema = z.object({\n\tfile: z.string().max(512).nullable(),\n\tline: z.number().int().min(1).max(1e6).nullable(),\n\tcol: z.number().int().min(0).max(1e6).nullable(),\n\tselector: z.string().max(2e3),\n\tclickX: z.number().int().min(-1e6).max(1e6),\n\tclickY: z.number().int().min(-1e6).max(1e6),\n\t/** Enclosing component name for this extra pick, when instrumented. */\n\tcomponent: z.string().max(256).nullable().optional()\n});\n/**\n* Loop-instance disambiguation captured at pick time. Present only when\n* the target's `data-pa-loc` is shared by more than one live element (a\n* `.map()`), so the agent can tell which item was clicked.\n*/\nconst InstanceInfoSchema = z.object({\n\tindex: z.number().int().min(0).max(1e6),\n\ttotal: z.number().int().min(1).max(1e6),\n\tfingerprint: z.string().max(512)\n});\nconst FeedbackInputSchema = z.object({\n\tcomment: z.string().min(1).max(8e3),\n\tloc: z.object({\n\t\tfile: z.string().min(1).max(512),\n\t\tline: z.number().int().min(1).max(1e6),\n\t\tcol: z.number().int().min(0).max(1e6)\n\t}).nullable(),\n\tselector: z.string().max(2e3),\n\turl: z.string().max(2048),\n\tviewport: z.object({\n\t\tw: z.number().int().min(1),\n\t\th: z.number().int().min(1)\n\t}),\n\tuserAgent: z.string().max(1024),\n\tscreenshot: z.string().min(1),\n\tcreatedAt: z.string().min(1),\n\t/**\n\t* Cmd/Ctrl-click extras queued before the committing click. Optional\n\t* for backward compatibility with single-pick clients; capped at 32\n\t* to keep a runaway client from blowing up the JSON column.\n\t*/\n\tadditionalAnchors: z.array(AdditionalAnchorSchema).max(32).optional(),\n\t/**\n\t* Enclosing-component context from `data-pa-comp`. All optional for\n\t* backward compatibility with clients that predate the attribute.\n\t*/\n\tcomponent: z.string().max(256).nullable().optional(),\n\tcomponentPath: z.array(z.string().max(256)).max(16).optional(),\n\tinstance: InstanceInfoSchema.nullable().optional()\n});\nconst StatusSchema = z.enum([\n\t\"pending\",\n\t\"fixed\",\n\t\"wontfix\",\n\t\"deferred\"\n]);\nconst WorktreeStateSchema = z.enum([\n\t\"none\",\n\t\"active\",\n\t\"landed\",\n\t\"discarded\"\n]);\nconst PatchSchema = z.object({\n\tstatus: StatusSchema.optional(),\n\tnote: z.string().max(8e3).nullable().optional(),\n\tcommitSha: z.string().max(64).nullable().optional(),\n\tagentSessionId: z.string().max(128).nullable().optional(),\n\tbranch: z.string().max(256).nullable().optional(),\n\tworktreePath: z.string().max(1024).nullable().optional(),\n\tworktreeState: WorktreeStateSchema.optional(),\n\t/**\n\t* Title override. Pass an empty string or `null` to clear back to the\n\t* comment-derived title. Capped at 200 chars so the list rows don't\n\t* blow up.\n\t*/\n\ttitle: z.string().max(200).nullable().optional(),\n\tarchived: z.boolean().optional()\n});\n/**\n* Server-side feedback storage. Backed by SQLite via Drizzle on the\n* shared `@pinagent/db` schema; screenshots stay on disk as PNG files\n* under `.pinagent/screenshots/` because they're large binary blobs.\n*\n* The class deliberately preserves the v1 `FeedbackRecord` shape and\n* method names so the MCP server, route handler, and agent code don't\n* need to change. Internally it joins `conversations` and\n* `widget_anchors` on every read.\n*\n* On first open, any legacy `.pinagent/feedback/<id>.json` files are\n* imported into SQLite (and left on disk as a backup). Once they're in\n* the DB, subsequent reads come from SQLite.\n*/\nvar Storage = class {\n\troot;\n\tfeedbackDir;\n\tscreenshotsDir;\n\tlegacyImportDone = false;\n\tconstructor(root) {\n\t\tthis.root = root;\n\t\tthis.feedbackDir = join(root, \".pinagent\", \"feedback\");\n\t\tthis.screenshotsDir = join(root, \".pinagent\", \"screenshots\");\n\t}\n\tdb() {\n\t\treturn getDb(this.root);\n\t}\n\tasync ensureDirs() {\n\t\tawait mkdir(this.screenshotsDir, { recursive: true });\n\t}\n\t/**\n\t* One-shot import of legacy JSON feedback records into SQLite.\n\t* Safe to call multiple times — uses ON CONFLICT DO NOTHING so\n\t* already-imported rows aren't overwritten.\n\t*/\n\tasync maybeImportLegacy() {\n\t\tif (this.legacyImportDone) return;\n\t\tthis.legacyImportDone = true;\n\t\tif (!existsSync(this.feedbackDir)) return;\n\t\ttry {\n\t\t\tconst names = await readdir(this.feedbackDir);\n\t\t\tfor (const n of names) {\n\t\t\t\tif (!n.endsWith(\".json\") || n.endsWith(\".tmp\")) continue;\n\t\t\t\tconst id = n.slice(0, -5);\n\t\t\t\tif (!ID_RE.test(id)) continue;\n\t\t\t\ttry {\n\t\t\t\t\tconst raw = await readFile(join(this.feedbackDir, n), \"utf8\");\n\t\t\t\t\tconst rec = JSON.parse(raw);\n\t\t\t\t\tif (!rec.id || !rec.comment) continue;\n\t\t\t\t\tawait this.insertRecord(rec);\n\t\t\t\t} catch {}\n\t\t\t}\n\t\t} catch {}\n\t}\n\tasync insertRecord(rec) {\n\t\tconst db = this.db();\n\t\tawait db.insert(conversations).values({\n\t\t\tid: rec.id,\n\t\t\tcomment: rec.comment,\n\t\t\tagentSessionId: rec.agentSessionId ?? null,\n\t\t\tstatus: rec.status,\n\t\t\tnote: rec.note ?? null,\n\t\t\tcommitSha: rec.commitSha ?? null,\n\t\t\tcreatedAt: parseDate(rec.createdAt),\n\t\t\tupdatedAt: parseDate(rec.createdAt),\n\t\t\tresolvedAt: rec.resolvedAt ? parseDate(rec.resolvedAt) : null\n\t\t}).onConflictDoNothing();\n\t\tawait db.insert(widgetAnchors).values({\n\t\t\tconversationId: rec.id,\n\t\t\turl: rec.url,\n\t\t\tfile: rec.file,\n\t\t\tline: rec.line,\n\t\t\tcol: rec.col,\n\t\t\tselector: rec.selector,\n\t\t\tviewportW: rec.viewport.w,\n\t\t\tviewportH: rec.viewport.h,\n\t\t\tuserAgent: rec.userAgent,\n\t\t\tcomponent: rec.component,\n\t\t\tcomponentPath: rec.componentPath,\n\t\t\tinstanceIndex: rec.instanceIndex,\n\t\t\tinstanceTotal: rec.instanceTotal,\n\t\t\tinstanceFingerprint: rec.instanceFingerprint,\n\t\t\tadditionalAnchors: rec.additionalAnchors\n\t\t}).onConflictDoNothing();\n\t}\n\tasync create(id, input) {\n\t\tawait this.ensureDirs();\n\t\tconst pngBuf = Buffer$1.from(input.screenshot, \"base64\");\n\t\tconst pngRel = join(\"screenshots\", `${id}.png`);\n\t\tconst pngAbs = join(this.root, \".pinagent\", pngRel);\n\t\tawait this.atomicWriteBytes(pngAbs, pngBuf);\n\t\tconst db = this.db();\n\t\tconst createdAt = parseDate(input.createdAt);\n\t\tawait db.insert(conversations).values({\n\t\t\tid,\n\t\t\tcomment: input.comment,\n\t\t\tstatus: \"pending\",\n\t\t\tcreatedAt,\n\t\t\tupdatedAt: createdAt\n\t\t});\n\t\tconst componentPath = input.componentPath && input.componentPath.length > 0 ? input.componentPath : null;\n\t\tawait db.insert(widgetAnchors).values({\n\t\t\tconversationId: id,\n\t\t\turl: input.url,\n\t\t\tfile: input.loc?.file ?? null,\n\t\t\tline: input.loc?.line ?? null,\n\t\t\tcol: input.loc?.col ?? null,\n\t\t\tselector: input.selector,\n\t\t\tviewportW: input.viewport.w,\n\t\t\tviewportH: input.viewport.h,\n\t\t\tuserAgent: input.userAgent,\n\t\t\tcomponent: input.component ?? null,\n\t\t\tcomponentPath,\n\t\t\tinstanceIndex: input.instance?.index ?? null,\n\t\t\tinstanceTotal: input.instance?.total ?? null,\n\t\t\tinstanceFingerprint: input.instance?.fingerprint ?? null,\n\t\t\tadditionalAnchors: input.additionalAnchors && input.additionalAnchors.length > 0 ? input.additionalAnchors : null\n\t\t});\n\t\tconst record = {\n\t\t\tid,\n\t\t\tcomment: input.comment,\n\t\t\tfile: input.loc?.file ?? null,\n\t\t\tline: input.loc?.line ?? null,\n\t\t\tcol: input.loc?.col ?? null,\n\t\t\tselector: input.selector,\n\t\t\turl: input.url,\n\t\t\tviewport: input.viewport,\n\t\t\tuserAgent: input.userAgent,\n\t\t\tadditionalAnchors: input.additionalAnchors && input.additionalAnchors.length > 0 ? input.additionalAnchors : null,\n\t\t\tcomponent: input.component ?? null,\n\t\t\tcomponentPath,\n\t\t\tinstanceIndex: input.instance?.index ?? null,\n\t\t\tinstanceTotal: input.instance?.total ?? null,\n\t\t\tinstanceFingerprint: input.instance?.fingerprint ?? null,\n\t\t\tscreenshot: pngRel,\n\t\t\tstatus: \"pending\",\n\t\t\tnote: null,\n\t\t\tcommitSha: null,\n\t\t\tagentSessionId: null,\n\t\t\tbranch: null,\n\t\t\tworktreePath: null,\n\t\t\tworktreeState: \"none\",\n\t\t\ttitle: null,\n\t\t\tarchived: false,\n\t\t\tcreatedAt: input.createdAt,\n\t\t\tupdatedAt: input.createdAt,\n\t\t\tresolvedAt: null,\n\t\t\tmessageCount: 0,\n\t\t\ttotalCostUsd: 0,\n\t\t\tapiKeySource: null,\n\t\t\tisRunning: false\n\t\t};\n\t\temitProjectChange({ type: \"conversations_changed\" });\n\t\tawait recordAuditEvent(this.root, {\n\t\t\tconversationId: id,\n\t\t\tactor: \"user\",\n\t\t\taction: \"conversation_created\",\n\t\t\tpayload: {\n\t\t\t\tpage: input.url,\n\t\t\t\t...input.loc?.file ? { file: input.loc.file } : {}\n\t\t\t}\n\t\t});\n\t\treturn record;\n\t}\n\tasync list() {\n\t\tawait this.maybeImportLegacy();\n\t\tconst db = this.db();\n\t\tconst rows = await db.select().from(conversations).leftJoin(widgetAnchors, eq(conversations.id, widgetAnchors.conversationId)).orderBy(asc(conversations.createdAt));\n\t\tconst counts = await db.select({\n\t\t\tid: messages.conversationId,\n\t\t\tn: count()\n\t\t}).from(messages).where(notInArray(messages.role, NON_MESSAGE_ROLES)).groupBy(messages.conversationId);\n\t\tconst countByConvId = new Map(counts.map((c) => [c.id, c.n]));\n\t\tconst costRows = await db.select({\n\t\t\tid: messages.conversationId,\n\t\t\tcontent: messages.content\n\t\t}).from(messages).where(eq(messages.role, \"result\"));\n\t\tconst costByConvId = /* @__PURE__ */ new Map();\n\t\tfor (const r of costRows) {\n\t\t\tconst c = extractResultCost(r.content);\n\t\t\tif (c > 0) costByConvId.set(r.id, (costByConvId.get(r.id) ?? 0) + c);\n\t\t}\n\t\tconst initRows = await db.select({\n\t\t\tid: messages.conversationId,\n\t\t\tcontent: messages.content\n\t\t}).from(messages).where(eq(messages.role, \"init\"));\n\t\tconst apiKeySourceByConvId = /* @__PURE__ */ new Map();\n\t\tfor (const r of initRows) {\n\t\t\tif (apiKeySourceByConvId.has(r.id)) continue;\n\t\t\tconst src = extractApiKeySource(r.content);\n\t\t\tif (src) apiKeySourceByConvId.set(r.id, src);\n\t\t}\n\t\tconst runningRows = await db.select({ id: activeRuns.conversationId }).from(activeRuns);\n\t\tconst runningIds = new Set(runningRows.map((r) => r.id));\n\t\treturn rows.map((r) => rowToRecord(r, countByConvId.get(r.conversations.id) ?? 0, costByConvId.get(r.conversations.id) ?? 0, apiKeySourceByConvId.get(r.conversations.id) ?? null, runningIds.has(r.conversations.id)));\n\t}\n\tasync read(id) {\n\t\tif (!ID_RE.test(id)) return null;\n\t\tawait this.maybeImportLegacy();\n\t\tconst db = this.db();\n\t\tconst row = (await db.select().from(conversations).leftJoin(widgetAnchors, eq(conversations.id, widgetAnchors.conversationId)).where(eq(conversations.id, id)).limit(1))[0];\n\t\tif (!row) return null;\n\t\tconst countRows = await db.select({ n: count() }).from(messages).where(and(eq(messages.conversationId, id), notInArray(messages.role, NON_MESSAGE_ROLES)));\n\t\tconst totalCostUsd = await this.computeConversationCost(id);\n\t\tconst apiKeySource = await this.readApiKeySource(id);\n\t\tconst runningRows = await db.select({ id: activeRuns.conversationId }).from(activeRuns).where(eq(activeRuns.conversationId, id)).limit(1);\n\t\treturn rowToRecord(row, countRows[0]?.n ?? 0, totalCostUsd, apiKeySource, runningRows.length > 0);\n\t}\n\t/**\n\t* Read `apiKeySource` off the conversation's `init` event. Drives the\n\t* dock's notional-cost relabeling (see `isNotionalCost`). Null when no\n\t* `init` has been recorded yet (created but never run).\n\t*/\n\tasync readApiKeySource(id) {\n\t\tif (!ID_RE.test(id)) return null;\n\t\tconst rows = await this.db().select({ content: messages.content }).from(messages).where(and(eq(messages.conversationId, id), eq(messages.role, \"init\"))).orderBy(asc(messages.id)).limit(1);\n\t\treturn rows[0] ? extractApiKeySource(rows[0].content) : null;\n\t}\n\t/**\n\t* Sum the SDK-reported `totalCostUsd` across every `result` event\n\t* recorded for one conversation. Used both for the per-row display\n\t* value and for the per-conversation cap check at spawn time.\n\t*/\n\tasync computeConversationCost(id) {\n\t\tif (!ID_RE.test(id)) return 0;\n\t\tconst rows = await this.db().select({ content: messages.content }).from(messages).where(and(eq(messages.conversationId, id), eq(messages.role, \"result\")));\n\t\tlet total = 0;\n\t\tfor (const r of rows) total += extractResultCost(r.content);\n\t\treturn total;\n\t}\n\t/**\n\t* Sum the SDK-reported `totalCostUsd` across every `result` event\n\t* recorded in the given UTC calendar month, across all conversations.\n\t* Drives the `monthlyBudgetUsd` cap check. The `month` argument's\n\t* day-of-month is ignored — we always span the calendar month it\n\t* falls in. Callers pass `new Date()` for \"current month\".\n\t*/\n\tasync computeMonthlySpend(month) {\n\t\tconst db = this.db();\n\t\tconst start = new Date(Date.UTC(month.getUTCFullYear(), month.getUTCMonth(), 1));\n\t\tconst end = new Date(Date.UTC(month.getUTCFullYear(), month.getUTCMonth() + 1, 1));\n\t\tconst rows = await db.select({ content: messages.content }).from(messages).where(and(eq(messages.role, \"result\"), gte(messages.createdAt, start), lt(messages.createdAt, end)));\n\t\tlet total = 0;\n\t\tfor (const r of rows) total += extractResultCost(r.content);\n\t\treturn total;\n\t}\n\t/**\n\t* Full transcript for one conversation, in insertion order. Returns\n\t* the raw `AgentEvent` payloads as they were appended to the bus,\n\t* skipping the `__finished` sentinel (which is internal bookkeeping,\n\t* not an event subscribers should see). Backs the HTTP transcript\n\t* endpoint that external clients (CLI, hosted dock) read.\n\t*\n\t* Returns [] for unknown ids — matches `read()`'s \"no error on\n\t* missing row\" contract; the route handler distinguishes via `read`.\n\t*/\n\tasync listMessages(id) {\n\t\tif (!ID_RE.test(id)) return [];\n\t\tawait this.maybeImportLegacy();\n\t\treturn (await this.db().select().from(messages).where(and(eq(messages.conversationId, id), notInArray(messages.role, [\"__finished\"]))).orderBy(asc(messages.id))).map((r) => r.content);\n\t}\n\tasync readScreenshotBase64(rec) {\n\t\tconst abs = join(this.root, \".pinagent\", rec.screenshot);\n\t\tif (!existsSync(abs)) return null;\n\t\treturn (await readFile(abs)).toString(\"base64\");\n\t}\n\t/**\n\t* Returns the patched record + the previous status (so callers can\n\t* tell whether a terminal-status transition just happened and fire a\n\t* `status_changed` event without re-reading).\n\t*/\n\tasync patchWithDiff(id, patch) {\n\t\tif (!ID_RE.test(id)) return null;\n\t\tconst current = await this.read(id);\n\t\tif (!current) return null;\n\t\tconst previousStatus = current.status;\n\t\tconst update = { updatedAt: /* @__PURE__ */ new Date() };\n\t\tif (patch.status !== void 0) {\n\t\t\tupdate.status = patch.status;\n\t\t\tif (patch.status !== \"pending\") update.resolvedAt = /* @__PURE__ */ new Date();\n\t\t\telse update.resolvedAt = null;\n\t\t}\n\t\tif (patch.note !== void 0) update.note = patch.note;\n\t\tif (patch.commitSha !== void 0) update.commitSha = patch.commitSha;\n\t\tif (patch.agentSessionId !== void 0) update.agentSessionId = patch.agentSessionId;\n\t\tif (patch.branch !== void 0) update.branch = patch.branch;\n\t\tif (patch.worktreePath !== void 0) update.worktreePath = patch.worktreePath;\n\t\tif (patch.worktreeState !== void 0) update.worktreeState = patch.worktreeState;\n\t\tif (patch.title !== void 0) update.title = patch.title && patch.title.trim().length > 0 ? patch.title.trim() : null;\n\t\tif (patch.archived !== void 0) update.archived = patch.archived;\n\t\tawait this.db().update(conversations).set(update).where(eq(conversations.id, id));\n\t\tconst next = await this.read(id);\n\t\tif (!next) return null;\n\t\temitProjectChange({ type: \"conversations_changed\" });\n\t\treturn {\n\t\t\trecord: next,\n\t\t\tpreviousStatus\n\t\t};\n\t}\n\tasync patch(id, patch) {\n\t\tconst result = await this.patchWithDiff(id, patch);\n\t\treturn result ? result.record : null;\n\t}\n\tasync atomicWriteBytes(p, data) {\n\t\tconst tmp = `${p}.tmp`;\n\t\tawait writeFile(tmp, data);\n\t\tawait rename(tmp, p);\n\t}\n};\nfunction parseDate(iso) {\n\tconst d = new Date(iso);\n\tif (Number.isNaN(d.getTime())) return /* @__PURE__ */ new Date();\n\treturn d;\n}\nfunction rowToRecord(row, messageCount, totalCostUsd, apiKeySource, isRunning) {\n\tconst c = row.conversations;\n\tconst a = row.widget_anchors;\n\treturn {\n\t\tid: c.id,\n\t\tcomment: c.comment,\n\t\tfile: a?.file ?? null,\n\t\tline: a?.line ?? null,\n\t\tcol: a?.col ?? null,\n\t\tselector: a?.selector ?? \"\",\n\t\turl: a?.url ?? \"\",\n\t\tviewport: {\n\t\t\tw: a?.viewportW ?? 0,\n\t\t\th: a?.viewportH ?? 0\n\t\t},\n\t\tuserAgent: a?.userAgent ?? \"\",\n\t\tadditionalAnchors: a?.additionalAnchors ?? null,\n\t\tcomponent: a?.component ?? null,\n\t\tcomponentPath: a?.componentPath ?? null,\n\t\tinstanceIndex: a?.instanceIndex ?? null,\n\t\tinstanceTotal: a?.instanceTotal ?? null,\n\t\tinstanceFingerprint: a?.instanceFingerprint ?? null,\n\t\tscreenshot: join(\"screenshots\", `${c.id}.png`),\n\t\tstatus: c.status,\n\t\tnote: c.note,\n\t\tcommitSha: c.commitSha,\n\t\tagentSessionId: c.agentSessionId,\n\t\tbranch: c.branch,\n\t\tworktreePath: c.worktreePath,\n\t\tworktreeState: c.worktreeState,\n\t\ttitle: c.title,\n\t\tarchived: c.archived,\n\t\tcreatedAt: c.createdAt.toISOString(),\n\t\tupdatedAt: c.updatedAt.toISOString(),\n\t\tresolvedAt: c.resolvedAt ? c.resolvedAt.toISOString() : null,\n\t\tmessageCount,\n\t\ttotalCostUsd,\n\t\tapiKeySource,\n\t\tisRunning\n\t};\n}\n/**\n* Pull the `totalCostUsd` out of a stored `result` event's JSON content.\n* Tolerant of missing/non-numeric values so a malformed historical row\n* (or a future event shape) doesn't poison the aggregate — those just\n* count as 0.\n*/\nfunction extractResultCost(content) {\n\tif (content && typeof content === \"object\" && \"totalCostUsd\" in content) {\n\t\tconst v = content.totalCostUsd;\n\t\tif (typeof v === \"number\" && Number.isFinite(v) && v >= 0) return v;\n\t}\n\treturn 0;\n}\n/**\n* Pull `apiKeySource` out of a stored `init` event's JSON content. Mirrors\n* `extractResultCost`'s tolerance: missing/non-string values yield null so\n* the dock simply falls back to showing the raw cost (the pre-existing\n* behavior) rather than mis-labeling it.\n*/\nfunction extractApiKeySource(content) {\n\tif (content && typeof content === \"object\" && \"apiKeySource\" in content) {\n\t\tconst v = content.apiKeySource;\n\t\tif (typeof v === \"string\" && v) return v;\n\t}\n\treturn null;\n}\nasync function isInGitignore(root) {\n\tconst gi = resolve(root, \".gitignore\");\n\tif (!existsSync(gi)) return false;\n\ttry {\n\t\treturn (await readFile(gi, \"utf8\")).split(/\\r?\\n/).map((s) => s.trim()).some((s) => s === \".pinagent\" || s === \".pinagent/\" || s === \"/.pinagent\" || s === \"/.pinagent/\");\n\t} catch {\n\t\treturn false;\n\t}\n}\nfunction isInsideRoot(root, target) {\n\tconst rel = relative(resolve(root), resolve(target));\n\treturn !rel.startsWith(\"..\") && !rel.startsWith(`../`) && rel !== \"..\";\n}\n//#endregion\n//#region src/branch-routing.ts\n/**\n* Branch-routing enforcement primitives (OSS / dev-side).\n*\n* The cloud control plane owns the *policy* (an org's default base branch +\n* allowed land-target patterns); this module is the on-machine enforcement of\n* it. The matching logic is re-implemented here rather than imported from the\n* Elastic `@pinagent/ee-team-features` package so the OSS agent-runner stays\n* free of any source-available dependency — the policy crosses the boundary\n* as plain data (today via local project settings; later pushed over the relay\n* channel) and is enforced with this code.\n*\n* Keep this behaviourally in sync with ee-team-features' `branch-routing.ts`:\n* patterns are anchored full-string globs where `*` matches any run of\n* characters, and an empty pattern list allows any branch.\n*/\nfunction escapeRegExp(literal) {\n\treturn literal.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n/** Match a branch name against a single `*`-glob pattern (anchored). */\nfunction matchBranchPattern(pattern, branch) {\n\treturn new RegExp(`^${pattern.split(\"*\").map(escapeRegExp).join(\".*\")}$`).test(branch);\n}\n/**\n* Whether `branch` may be landed on under `allowedPatterns`. An empty list\n* (the default) allows any branch — branch routing is opt-in.\n*/\nfunction isBranchAllowed(allowedPatterns, branch) {\n\tif (allowedPatterns.length === 0) return true;\n\treturn allowedPatterns.some((pattern) => matchBranchPattern(pattern, branch));\n}\n//#endregion\n//#region src/worktree.ts\nasync function createWorktree(projectRoot, feedbackId, logPath) {\n\tif (!existsSync(join(projectRoot, \".git\"))) throw new Error(\"project root is not a git repository\");\n\tconst worktreeDir = join(projectRoot, \".pinagent\", \"worktrees\");\n\tawait mkdir(worktreeDir, { recursive: true });\n\tconst worktreePath = join(worktreeDir, feedbackId);\n\tconst branch = `pinagent/${feedbackId}`;\n\tconst { baseBranch } = await new SettingsStore(projectRoot).read();\n\tconst baseResolves = (await runGitCapture(projectRoot, [\n\t\t\"rev-parse\",\n\t\t\"--verify\",\n\t\t\"--quiet\",\n\t\tbaseBranch\n\t])).code === 0;\n\tconst addArgs = baseResolves ? [\n\t\t\"worktree\",\n\t\t\"add\",\n\t\t\"-b\",\n\t\tbranch,\n\t\tworktreePath,\n\t\tbaseBranch\n\t] : [\n\t\t\"worktree\",\n\t\t\"add\",\n\t\t\"-b\",\n\t\tbranch,\n\t\tworktreePath\n\t];\n\tif (!baseResolves) await appendLog(logPath, `> [pinagent] base branch \\`${baseBranch}\\` not found; forking worktree from HEAD\\n`);\n\tawait runGit(projectRoot, addArgs, logPath);\n\ttry {\n\t\tawait new Storage(projectRoot).patch(feedbackId, {\n\t\t\tbranch,\n\t\t\tworktreePath,\n\t\t\tworktreeState: \"active\"\n\t\t});\n\t} catch {}\n\treturn worktreePath;\n}\n/**\n* Land the agent's worktree onto the project's HEAD branch — but only when HEAD\n* still matches the base the worktree forked from (`settings.baseBranch`). If\n* the developer switched the main checkout to another branch, landing is\n* refused rather than silently merging the work into the wrong branch.\n*\n* The agent intentionally does not commit (see `buildInitialPrompt`) so the\n* developer can review the diff before landing; we stage and commit on its\n* behalf as a single squash here. On merge conflict the merge is aborted —\n* the worktree is left intact so the user can resolve manually and retry.\n*\n* Should be called via `merge-queue.ts` so concurrent landings on the same\n* project serialize cleanly.\n*/\nasync function mergeWorktree(projectRoot, feedbackId, logPath) {\n\tconst storage = new Storage(projectRoot);\n\tconst rec = await storage.read(feedbackId);\n\tif (!rec) return {\n\t\tok: false,\n\t\terror: `feedback not found: ${feedbackId}`\n\t};\n\tif (!rec.worktreePath || !rec.branch) return {\n\t\tok: false,\n\t\terror: \"this conversation has no worktree (inline-mode submission)\"\n\t};\n\tif (rec.worktreeState !== \"active\") return {\n\t\tok: false,\n\t\terror: `cannot land: worktree state is ${rec.worktreeState}`\n\t};\n\tif (!existsSync(rec.worktreePath)) return {\n\t\tok: false,\n\t\terror: `worktree no longer exists at ${rec.worktreePath}`\n\t};\n\tif (!existsSync(join(projectRoot, \".git\"))) return {\n\t\tok: false,\n\t\terror: \"project root is not a git repository\"\n\t};\n\tawait appendLog(logPath, `\\n## Land · ${(/* @__PURE__ */ new Date()).toISOString()}\\n\\n`);\n\tconst head = await runGitCapture(projectRoot, [\n\t\t\"symbolic-ref\",\n\t\t\"--short\",\n\t\t\"HEAD\"\n\t]);\n\tif (head.code !== 0) return {\n\t\tok: false,\n\t\terror: `cannot resolve project HEAD branch (detached?): ${head.stderr.trim()}`\n\t};\n\tconst targetBranch = head.stdout.trim();\n\tif (targetBranch === rec.branch) return {\n\t\tok: false,\n\t\terror: `project HEAD is already on ${rec.branch}; nothing to land`\n\t};\n\tconst settings = await new SettingsStore(projectRoot).read();\n\tif ((await runGitCapture(projectRoot, [\n\t\t\"rev-parse\",\n\t\t\"--verify\",\n\t\t\"--quiet\",\n\t\tsettings.baseBranch\n\t])).code === 0 && targetBranch !== settings.baseBranch) return {\n\t\tok: false,\n\t\terror: `cannot land: the project is on \"${targetBranch}\" but this worktree was based on \"${settings.baseBranch}\". Check out \"${settings.baseBranch}\" to land, or discard.`\n\t};\n\tconst { allowedBranchPatterns } = settings;\n\tif (!isBranchAllowed(allowedBranchPatterns, targetBranch)) {\n\t\tconst allowed = allowedBranchPatterns.join(\", \");\n\t\tawait appendLog(logPath, `> [pinagent] branch routing blocked landing onto \\`${targetBranch}\\` (allowed: ${allowed})\\n`);\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: `branch routing policy does not allow landing onto \"${targetBranch}\" (allowed: ${allowed})`\n\t\t};\n\t}\n\tconst status = await runGitCapture(rec.worktreePath, [\"status\", \"--porcelain\"]);\n\tif (status.code !== 0) return {\n\t\tok: false,\n\t\terror: `git status failed in worktree: ${status.stderr.trim()}`\n\t};\n\tif (status.stdout.trim()) {\n\t\tconst add = await runGitCapture(rec.worktreePath, [\"add\", \"-A\"]);\n\t\tif (add.code !== 0) return {\n\t\t\tok: false,\n\t\t\terror: `git add failed: ${add.stderr.trim()}`\n\t\t};\n\t\tconst commit = await runGitCapture(rec.worktreePath, [\n\t\t\t\"commit\",\n\t\t\t\"-m\",\n\t\t\tformatLandCommitMessage(rec)\n\t\t]);\n\t\tif (commit.code !== 0) {\n\t\t\tconst combined = `${commit.stdout}\\n${commit.stderr}`;\n\t\t\tif (!/nothing to commit/.test(combined)) return {\n\t\t\t\tok: false,\n\t\t\t\terror: `git commit failed: ${commit.stderr.trim() || commit.stdout.trim()}`\n\t\t\t};\n\t\t}\n\t}\n\tconst ahead = await runGitCapture(projectRoot, [\n\t\t\"rev-list\",\n\t\t\"--count\",\n\t\t`${targetBranch}..${rec.branch}`\n\t]);\n\tif (ahead.code !== 0) return {\n\t\tok: false,\n\t\terror: `cannot compare branches: ${ahead.stderr.trim()}`\n\t};\n\tif (Number(ahead.stdout.trim()) === 0) {\n\t\tawait appendLog(logPath, \"> [pinagent] no changes to land\\n\");\n\t\tawait cleanupWorktreeFiles(rec.worktreePath, rec.branch, projectRoot, logPath);\n\t\tawait storage.patch(feedbackId, { worktreeState: \"landed\" });\n\t\tawait recordAuditEvent(projectRoot, {\n\t\t\tconversationId: feedbackId,\n\t\t\tactor: \"user\",\n\t\t\taction: \"conversation_landed\",\n\t\t\tpayload: {\n\t\t\t\tbranch: rec.branch,\n\t\t\t\ttarget: targetBranch,\n\t\t\t\tnoop: true\n\t\t\t}\n\t\t});\n\t\treturn { ok: true };\n\t}\n\tif ((await runGitCapture(projectRoot, [\n\t\t\"merge\",\n\t\t\"--no-ff\",\n\t\t\"--no-edit\",\n\t\trec.branch\n\t])).code !== 0) {\n\t\tconst conflicts = (await runGitCapture(projectRoot, [\n\t\t\t\"diff\",\n\t\t\t\"--name-only\",\n\t\t\t\"--diff-filter=U\"\n\t\t])).stdout.split(\"\\n\").map((s) => s.trim()).filter(Boolean);\n\t\tconst abort = await runGitCapture(projectRoot, [\"merge\", \"--abort\"]);\n\t\tawait appendLog(logPath, `> [pinagent] merge into \\`${targetBranch}\\` failed: ${conflicts.length} conflicted file(s)\\n${conflicts.map((c) => `> - \\`${c}\\`\\n`).join(\"\")}\\n`);\n\t\tif (abort.code !== 0) {\n\t\t\tawait appendLog(logPath, `> [pinagent] WARNING: \\`git merge --abort\\` failed; the project working tree may be left mid-merge: ${abort.stderr.trim()}\\n`);\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: `merge conflicted and \\`git merge --abort\\` failed; the project working tree may be left mid-merge — resolve manually: ${abort.stderr.trim()}`,\n\t\t\t\tconflicts\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tok: false,\n\t\t\tconflicts\n\t\t};\n\t}\n\tconst sha = await runGitCapture(projectRoot, [\"rev-parse\", \"HEAD\"]);\n\tconst commitSha = sha.code === 0 ? sha.stdout.trim() : void 0;\n\tawait cleanupWorktreeFiles(rec.worktreePath, rec.branch, projectRoot, logPath);\n\tawait storage.patch(feedbackId, {\n\t\tworktreeState: \"landed\",\n\t\t...commitSha ? { commitSha } : {}\n\t});\n\tawait recordAuditEvent(projectRoot, {\n\t\tconversationId: feedbackId,\n\t\tactor: \"user\",\n\t\taction: \"conversation_landed\",\n\t\tpayload: {\n\t\t\tbranch: rec.branch,\n\t\t\ttarget: targetBranch,\n\t\t\t...commitSha ? { commitSha } : {}\n\t\t}\n\t});\n\tawait appendLog(logPath, `> [pinagent] landed onto \\`${targetBranch}\\`${commitSha ? ` as \\`${commitSha.slice(0, 12)}\\`` : \"\"}\\n`);\n\treturn {\n\t\tok: true,\n\t\t...commitSha ? { commitSha } : {}\n\t};\n}\n/**\n* Reverse a landed/discarded conversation: put it back in the active\n* list so the user can follow up with the agent. We reset\n* `worktreeState` to `'none'` and `status` to `'pending'`; we do NOT\n* recreate the worktree (it was cleaned up at land/discard time and\n* the developer's actual changes have either already merged or were\n* thrown away). For inline-mode runs that's all that's needed — the\n* user can immediately send a follow-up. For ex-worktree runs the\n* conversation is conceptually inline-mode from this point forward.\n*\n* Refuses on conversations that aren't already resolved so a stray\n* client click can't reset a still-active worktree.\n*/\nasync function reopenConversation(projectRoot, feedbackId, logPath) {\n\tconst storage = new Storage(projectRoot);\n\tconst rec = await storage.read(feedbackId);\n\tif (!rec) return {\n\t\tok: false,\n\t\terror: `feedback not found: ${feedbackId}`\n\t};\n\tif (rec.worktreeState !== \"landed\" && rec.worktreeState !== \"discarded\") return {\n\t\tok: false,\n\t\terror: `cannot reopen: worktree state is ${rec.worktreeState} (expected landed or discarded)`\n\t};\n\tawait appendLog(logPath, `\\n## Reopen · ${(/* @__PURE__ */ new Date()).toISOString()}\\n\\n`);\n\tawait storage.patch(feedbackId, {\n\t\tworktreeState: \"none\",\n\t\tstatus: \"pending\"\n\t});\n\tawait recordAuditEvent(projectRoot, {\n\t\tconversationId: feedbackId,\n\t\tactor: \"user\",\n\t\taction: \"conversation_reopened\",\n\t\tpayload: {\n\t\t\tpreviousWorktreeState: rec.worktreeState,\n\t\t\tpreviousStatus: rec.status\n\t\t}\n\t});\n\treturn { ok: true };\n}\n/**\n* Bulk re-open a batch of resolved conversations from the History\n* view's multi-select. Each id goes through the existing per-row\n* `reopenConversation` so the worktree-state flip + per-row\n* `conversation_reopened` audit emission stay intact; this function\n* adds ONE summary `conversations_bulk_reopened` event covering the\n* batch.\n*/\nasync function reopenConversations(projectRoot, feedbackIds) {\n\tconst reopened = [];\n\tconst failed = [];\n\tfor (const id of feedbackIds) {\n\t\tconst logPath = join(projectRoot, \".pinagent\", \"logs\", `${id}.md`);\n\t\tawait mkdir(join(projectRoot, \".pinagent\", \"logs\"), { recursive: true });\n\t\ttry {\n\t\t\tconst result = await reopenConversation(projectRoot, id, logPath);\n\t\t\tif (result.ok) reopened.push(id);\n\t\t\telse failed.push({\n\t\t\t\tfeedbackId: id,\n\t\t\t\terror: result.error\n\t\t\t});\n\t\t} catch (e) {\n\t\t\tfailed.push({\n\t\t\t\tfeedbackId: id,\n\t\t\t\terror: e instanceof Error ? e.message : String(e)\n\t\t\t});\n\t\t}\n\t}\n\tif (reopened.length > 0) await recordAuditEvent(projectRoot, {\n\t\tconversationId: null,\n\t\tactor: \"user\",\n\t\taction: \"conversations_bulk_reopened\",\n\t\tpayload: {\n\t\t\tids: reopened,\n\t\t\tcount: reopened.length\n\t\t}\n\t});\n\treturn {\n\t\treopened,\n\t\tfailed\n\t};\n}\n/**\n* Throw away the worktree and its branch without merging. Idempotent —\n* tolerates a missing worktree or branch (the user may have cleaned\n* them up manually).\n*/\nasync function discardWorktree(projectRoot, feedbackId, logPath) {\n\tconst storage = new Storage(projectRoot);\n\tconst rec = await storage.read(feedbackId);\n\tif (!rec) return { ok: true };\n\tawait appendLog(logPath, `\\n## Discard · ${(/* @__PURE__ */ new Date()).toISOString()}\\n\\n`);\n\tif (rec.worktreePath && rec.branch) await cleanupWorktreeFiles(rec.worktreePath, rec.branch, projectRoot, logPath);\n\tawait storage.patch(feedbackId, { worktreeState: \"discarded\" });\n\tawait recordAuditEvent(projectRoot, {\n\t\tconversationId: feedbackId,\n\t\tactor: \"user\",\n\t\taction: \"conversation_discarded\",\n\t\tpayload: rec.branch ? { branch: rec.branch } : {}\n\t});\n\treturn { ok: true };\n}\nasync function cleanupWorktreeFiles(worktreePath, branch, projectRoot, logPath) {\n\tif (existsSync(worktreePath)) {\n\t\tconst rm = await runGitCapture(projectRoot, [\n\t\t\t\"worktree\",\n\t\t\t\"remove\",\n\t\t\t\"--force\",\n\t\t\tworktreePath\n\t\t]);\n\t\tif (rm.code !== 0) await appendLog(logPath, `> [pinagent:git] worktree remove → exit ${rm.code}\\n${rm.stderr}\\n`);\n\t}\n\tawait runGitCapture(projectRoot, [\"worktree\", \"prune\"]);\n\tconst br = await runGitCapture(projectRoot, [\n\t\t\"branch\",\n\t\t\"-D\",\n\t\tbranch\n\t]);\n\tif (br.code !== 0 && !/not found|did not match/i.test(br.stderr)) await appendLog(logPath, `> [pinagent:git] branch -D ${branch} → exit ${br.code}\\n${br.stderr}\\n`);\n}\nfunction formatLandCommitMessage(rec) {\n\tconst firstLine = rec.comment.split(/\\r?\\n/)[0]?.trim() ?? \"\";\n\tconst subject = firstLine.length > 70 ? `${firstLine.slice(0, 67)}…` : firstLine;\n\tconst where = rec.file ? `${rec.file}:${rec.line ?? \"?\"}${rec.col != null ? `:${rec.col}` : \"\"}` : rec.selector;\n\treturn [\n\t\t`pinagent: ${subject || \"agent edit\"}`,\n\t\t\"\",\n\t\t\"Landed via pinagent.\",\n\t\t\"\",\n\t\t`Feedback: ${rec.id}`,\n\t\t`Target: ${where}`,\n\t\t\"\"\n\t].join(\"\\n\");\n}\n//#endregion\n//#region src/worktree-stats.ts\nasync function computeWorktreeStats(worktreePath, baseRef) {\n\tif (!existsSync(worktreePath)) return null;\n\tconst mb = await runGitCapture(worktreePath, [\n\t\t\"merge-base\",\n\t\tbaseRef,\n\t\t\"HEAD\"\n\t]);\n\tconst diff = await runGitCapture(worktreePath, [\n\t\t\"diff\",\n\t\t\"--shortstat\",\n\t\tmb.code === 0 ? mb.stdout.trim() : baseRef\n\t]);\n\tif (diff.code !== 0) return null;\n\tconst line = diff.stdout.trim();\n\tif (!line) return {\n\t\tfilesChanged: 0,\n\t\tadditions: 0,\n\t\tdeletions: 0\n\t};\n\treturn parseShortStat(line);\n}\n/**\n* One-line preview of the first changed hunk for a worktree. Drives\n* the dock's Changes list row, which renders this as a truncated\n* monospace line under the stats. Returns '' for worktrees with no\n* changes (or only binary/rename-only diffs that don't have a\n* `+`/`-` content line to surface).\n*/\nconst PREVIEW_MAX_CHARS = 140;\n/** Stop reading the preview diff after this many bytes — the first changed line. */\nconst PREVIEW_CAP_BYTES = 64 * 1024;\nasync function computeWorktreePreview(worktreePath, baseRef) {\n\tif (!existsSync(worktreePath)) return \"\";\n\tconst mb = await runGitCapture(worktreePath, [\n\t\t\"merge-base\",\n\t\tbaseRef,\n\t\t\"HEAD\"\n\t]);\n\tconst result = await runGitCapture(worktreePath, [\n\t\t\"diff\",\n\t\t\"--no-color\",\n\t\t\"--unified=0\",\n\t\tmb.code === 0 ? mb.stdout.trim() : baseRef\n\t], { maxBytes: PREVIEW_CAP_BYTES });\n\tif (result.code !== 0 && !result.capped) return \"\";\n\tfor (const line of result.stdout.split(\"\\n\")) {\n\t\tif (line.startsWith(\"+++\") || line.startsWith(\"---\")) continue;\n\t\tif (!line.startsWith(\"+\") && !line.startsWith(\"-\")) continue;\n\t\treturn line.length > PREVIEW_MAX_CHARS ? `${line.slice(0, PREVIEW_MAX_CHARS - 1)}…` : line;\n\t}\n\treturn \"\";\n}\n/**\n* Capture the full unified diff of a worktree against its base ref —\n* the data the Changes view's expand-to-diff UI renders. Capped at a\n* generous-but-bounded size so an accidental megabyte of churn doesn't\n* lock up the dock when the user expands a row.\n*\n* Mirrors `computeWorktreeStats`'s base-resolution shape so the diff\n* and the stats line up for any given conversation.\n*/\nconst DIFF_CAP_BYTES$1 = 512 * 1024;\nasync function computeWorktreeDiff(worktreePath, baseRef) {\n\tif (!existsSync(worktreePath)) return null;\n\tconst mb = await runGitCapture(worktreePath, [\n\t\t\"merge-base\",\n\t\tbaseRef,\n\t\t\"HEAD\"\n\t]);\n\tconst result = await runGitCapture(worktreePath, [\n\t\t\"diff\",\n\t\t\"--no-color\",\n\t\tmb.code === 0 ? mb.stdout.trim() : baseRef\n\t], { maxBytes: DIFF_CAP_BYTES$1 });\n\tif (result.code !== 0 && !result.capped) return null;\n\tif (!result.capped) return {\n\t\tdiff: result.stdout,\n\t\ttruncated: false\n\t};\n\tconst cut = result.stdout.lastIndexOf(\"\\n\");\n\treturn {\n\t\tdiff: cut >= 0 ? result.stdout.slice(0, cut) : result.stdout,\n\t\ttruncated: true\n\t};\n}\nfunction parseShortStat(line) {\n\tconst files = /(\\d+)\\s+files?\\s+changed/.exec(line);\n\tconst ins = /(\\d+)\\s+insertions?\\(\\+\\)/.exec(line);\n\tconst del = /(\\d+)\\s+deletions?\\(-\\)/.exec(line);\n\treturn {\n\t\tfilesChanged: files ? Number(files[1]) : 0,\n\t\tadditions: ins ? Number(ins[1]) : 0,\n\t\tdeletions: del ? Number(del[1]) : 0\n\t};\n}\n/**\n* Count files with uncommitted changes in a worktree (`git status --porcelain`\n* line count). Returns `null` if the worktree path doesn't exist or `git`\n* fails — the caller treats that as \"unknown\" rather than zero, so the widget\n* can omit the count from its label instead of showing a misleading \"0 changes\".\n*/\nasync function countWorktreeChanges(worktreePath) {\n\tif (!existsSync(worktreePath)) return null;\n\tconst status = await runGitCapture(worktreePath, [\"status\", \"--porcelain\"]);\n\tif (status.code !== 0) return null;\n\tconst trimmed = status.stdout.trim();\n\tif (!trimmed) return 0;\n\treturn trimmed.split(\"\\n\").length;\n}\n//#endregion\n//#region src/agent.ts\n/**\n* In-flight runs LOCAL TO THIS CONTEXT. The AbortController is a\n* process-bound object — there's no way to serialise it across\n* contexts/processes, so we keep the per-context Map. Cross-context\n* `interruptRun` calls reach the owning context via `process.emit`\n* (see INTERRUPT_EVENT below), which all contexts in the same Node\n* process share.\n*\n* Cross-context \"is a run in flight?\" visibility is handled separately\n* by the `active_runs` SQLite table — see `hasActiveRun` below.\n*/\nconst activeRuns$1 = /* @__PURE__ */ new Map();\n/**\n* Cross-context signalling channel for interrupts. The WS server can\n* land in a different context than the one running the SDK loop (Next 16\n* Turbopack, Vite 8 environments), so the in-memory `activeRuns` Map in\n* the WS server's context wouldn't see the entry. Node's `process`\n* EventEmitter is shared across all contexts in one process, so emit-ing\n* here reliably reaches the owning context's listener (registered in\n* `runQuery`). Same idea as the SQLite-backed bus, but for a transient\n* signal rather than a stream — no persistence needed.\n*/\nconst INTERRUPT_EVENT = \"pinagent:interrupt\";\nasync function recordActiveRun(projectRoot, feedbackId) {\n\ttry {\n\t\tawait getDb(projectRoot).insert(activeRuns).values({\n\t\t\tconversationId: feedbackId,\n\t\t\tstartedAt: /* @__PURE__ */ new Date(),\n\t\t\tcurrentTurn: 1\n\t\t}).onConflictDoUpdate({\n\t\t\ttarget: activeRuns.conversationId,\n\t\t\tset: { startedAt: /* @__PURE__ */ new Date() }\n\t\t});\n\t\temitProjectChange({ type: \"conversations_changed\" });\n\t} catch {}\n}\nasync function clearActiveRun(projectRoot, feedbackId) {\n\ttry {\n\t\tawait getDb(projectRoot).delete(activeRuns).where(eq$1(activeRuns.conversationId, feedbackId));\n\t\temitProjectChange({ type: \"conversations_changed\" });\n\t} catch {}\n}\n/**\n* Run an isolated Claude Agent SDK query for a single freshly-submitted\n* feedback record. Kicks off in the background; the route handler resolves\n* its POST as soon as this returns \"started\", not when the agent finishes.\n*\n* Log file at `.pinagent/logs/<id>.md` accumulates the transcript across\n* the initial run plus any follow-up turns the user sends over WS.\n*/\nasync function spawnAgent(ctx) {\n\tif (ctx.mode === false) return;\n\tconst logsDir = join(ctx.projectRoot, \".pinagent\", \"logs\");\n\tawait mkdir(logsDir, { recursive: true });\n\tconst logPath = join(logsDir, `${ctx.feedback.id}.md`);\n\tconst capCheck = await checkCostCaps(ctx.projectRoot, ctx.feedback.id);\n\tif (!capCheck.ok) {\n\t\tawait getOrCreateBus(ctx.feedback.id, ctx.projectRoot).publish({\n\t\t\ttype: \"error\",\n\t\t\tmessage: capCheck.reason\n\t\t});\n\t\tawait appendLog(logPath, `\\n> [pinagent] spawn refused: ${capCheck.reason}\\n`);\n\t\treturn;\n\t}\n\tlet cwd = ctx.projectRoot;\n\tconst startedAt = (/* @__PURE__ */ new Date()).toISOString();\n\tif (ctx.mode === \"worktree\") try {\n\t\tcwd = await createWorktree(ctx.projectRoot, ctx.feedback.id, logPath);\n\t} catch (err) {\n\t\tawait appendLog(logPath, `${renderHeader(ctx, cwd, startedAt, false)}\\n> [pinagent] worktree creation failed: ${stringifyErr(err)}\\n`);\n\t\treturn;\n\t}\n\tawait appendLog(logPath, renderHeader(ctx, cwd, startedAt, true));\n\tconst prompt = buildInitialPrompt(ctx.feedback, ctx.mode, cwd);\n\tconst permissionMode = await resolveRunPermissionMode(ctx.projectRoot);\n\trunQuery({\n\t\tprojectRoot: ctx.projectRoot,\n\t\tfeedbackId: ctx.feedback.id,\n\t\tcwd,\n\t\tlogPath,\n\t\tprompt,\n\t\tisInitial: true,\n\t\tpermissionMode,\n\t\ttargetFile: ctx.feedback.file\n\t});\n}\n/**\n* Send a follow-up message into the existing conversation for `feedbackId`.\n* Resumes the prior SDK session so the agent keeps full context. Resolves\n* once the new turn has been started, not when it finishes.\n*\n* Refuses if there's no prior session (the feedback was never spawn-mode).\n*\n* The widget queues follow-ups client-side and flushes the next one the\n* instant it sees the prior turn's `result` event. That flush can reach us\n* a few ms BEFORE the just-finished run has torn down its `active_runs`\n* row (the teardown's `clearActiveRun` runs in `runQuery`'s finally, after\n* the `result` was already published). The widget only ever has one turn\n* in flight, so a lingering active run here is that finishing turn — not a\n* parallel one — so we briefly wait for it to clear rather than bouncing\n* the follow-up back. A bounced follow-up is effectively dropped: the\n* widget re-queues it but has no further turn-end event to re-flush it on,\n* so the agent appears to \"just end\" without addressing the follow-up.\n*/\nasync function runFollowUpTurn(feedbackId, content) {\n\tconst projectRoot = process.env.PINAGENT_PROJECT_ROOT ?? process.cwd();\n\tif (!await waitForRunToClear(feedbackId, projectRoot)) throw new Error(\"a turn is already in progress for this feedback\");\n\tconst rec = await new Storage(projectRoot).read(feedbackId);\n\tif (!rec) throw new Error(`feedback not found: ${feedbackId}`);\n\tif (!rec.agentSessionId) throw new Error(\"no prior agent session — only spawn-mode submissions support follow-ups\");\n\tconst capCheck = await checkCostCaps(projectRoot, feedbackId);\n\tif (!capCheck.ok) {\n\t\tawait getOrCreateBus(feedbackId, projectRoot).publish({\n\t\t\ttype: \"error\",\n\t\t\tmessage: capCheck.reason\n\t\t});\n\t\tthrow new Error(capCheck.reason);\n\t}\n\tconst worktreePath = join(projectRoot, \".pinagent\", \"worktrees\", feedbackId);\n\tconst cwd = existsSync(worktreePath) ? worktreePath : projectRoot;\n\tconst logsDir = join(projectRoot, \".pinagent\", \"logs\");\n\tawait mkdir(logsDir, { recursive: true });\n\tconst logPath = join(logsDir, `${feedbackId}.md`);\n\tawait appendLog(logPath, `\\n## Follow-up turn · ${(/* @__PURE__ */ new Date()).toISOString()}\\n\\n> **User**\\n> \\n> ${content.split(\"\\n\").join(\"\\n> \")}\\n\\n`);\n\trunQuery({\n\t\tprojectRoot,\n\t\tfeedbackId,\n\t\tcwd,\n\t\tlogPath,\n\t\tprompt: content,\n\t\tisInitial: false,\n\t\tpermissionMode: await resolveRunPermissionMode(projectRoot),\n\t\tresume: rec.agentSessionId,\n\t\ttargetFile: rec.file\n\t});\n}\n/**\n* True iff an SDK run is currently in flight for this feedback id, in\n* ANY context. Reads the `active_runs` SQLite row inserted by\n* `runQuery`. Local-Map check is cheap and short-circuits the common\n* case where the run was started in the same context.\n*/\nasync function hasActiveRun(feedbackId, projectRoot) {\n\tif (activeRuns$1.has(feedbackId)) return true;\n\tconst root = projectRoot ?? process.env.PINAGENT_PROJECT_ROOT ?? process.cwd();\n\ttry {\n\t\treturn (await getDb(root).select().from(activeRuns).where(eq$1(activeRuns.conversationId, feedbackId)).limit(1)).length > 0;\n\t} catch {\n\t\treturn false;\n\t}\n}\n/** Longest a follow-up waits for the prior turn's cleanup to land. */\nconst FOLLOWUP_RUN_CLEAR_TIMEOUT_MS = 3e3;\n/** How often `waitForRunToClear` re-checks the `active_runs` row. */\nconst FOLLOWUP_RUN_CLEAR_POLL_MS = 25;\n/**\n* Wait (bounded) for any in-flight run for `feedbackId` to finish, polling\n* `hasActiveRun`. Returns true once it's clear, or false if the timeout\n* elapses with a run still active. Returns true immediately when nothing is\n* in flight — the common case — so this is cheap. See `runFollowUpTurn` for\n* why a follow-up tolerates a briefly-lingering run rather than bouncing it.\n*/\nasync function waitForRunToClear(feedbackId, projectRoot) {\n\tconst deadline = Date.now() + FOLLOWUP_RUN_CLEAR_TIMEOUT_MS;\n\twhile (await hasActiveRun(feedbackId, projectRoot)) {\n\t\tif (Date.now() >= deadline) return false;\n\t\tawait new Promise((resolve) => setTimeout(resolve, FOLLOWUP_RUN_CLEAR_POLL_MS));\n\t}\n\treturn true;\n}\n/**\n* Abort an in-flight run for `feedbackId`. Returns true if the run\n* either lives in this context (local abort) OR lives in some other\n* context in this process (cross-context signal sent via `process.emit`\n* — the owning context's listener will call `abort` on its\n* AbortController). Returns false if no SQLite row exists for an\n* active run, i.e. nothing was actually in flight.\n*\n* The SDK propagates the abort through its tool loop and exits the\n* iterator; `consumeStream` catches the abort error and writes a\n* minimal footer.\n*/\nasync function interruptRun(feedbackId, projectRoot) {\n\tconst local = activeRuns$1.get(feedbackId);\n\tif (local) {\n\t\tlocal.abort.abort();\n\t\treturn true;\n\t}\n\tconst root = projectRoot ?? process.env.PINAGENT_PROJECT_ROOT ?? process.cwd();\n\tlet exists = false;\n\ttry {\n\t\texists = (await getDb(root).select().from(activeRuns).where(eq$1(activeRuns.conversationId, feedbackId)).limit(1)).length > 0;\n\t} catch {\n\t\texists = false;\n\t}\n\tif (!exists) return false;\n\tprocess.emit(INTERRUPT_EVENT, feedbackId);\n\treturn true;\n}\n/**\n* Gate every new turn (initial spawn + follow-ups) on the cost caps in\n* the project's settings. The cap is breached when the *running total*\n* is already at or above the cap — that lets the first-ever turn run\n* freely (totalCostUsd starts at 0) but blocks the next turn once\n* spending has caught up.\n*\n* Returns `{ ok: true }` when within both caps, or `{ ok: false, reason }`\n* with a user-facing message. Callers emit the message on the bus so\n* every subscriber sees it, and refuse to actually start the turn.\n*/\nasync function checkCostCaps(projectRoot, feedbackId) {\n\tconst settings = await new SettingsStore(projectRoot).read();\n\tconst storage = new Storage(projectRoot);\n\tconst notional = isNotionalCost(await storage.readApiKeySource(feedbackId));\n\tconst conversationCost = await storage.computeConversationCost(feedbackId);\n\tif (conversationCost >= settings.perConversationCapUsd) return {\n\t\tok: false,\n\t\treason: `per-conversation cost cap reached: ${formatCapSpend(conversationCost, settings.perConversationCapUsd, notional)}. Raise the cap in Settings or resolve this conversation.`\n\t};\n\tif (settings.monthlyBudgetUsd !== null) {\n\t\tconst monthlySpend = await storage.computeMonthlySpend(/* @__PURE__ */ new Date());\n\t\tif (monthlySpend >= settings.monthlyBudgetUsd) return {\n\t\t\tok: false,\n\t\t\treason: `monthly budget reached: ${formatCapSpend(monthlySpend, settings.monthlyBudgetUsd, notional)} this month. Raise the budget in Settings.`\n\t\t};\n\t}\n\treturn { ok: true };\n}\n/**\n* Format the `<used> of <cap>` fragment of a cap-breach message. For\n* notional (subscription) runs the amount is API-equivalent and was never\n* billed, so we say so rather than \"spent\".\n*/\nfunction formatCapSpend(used, cap, notional) {\n\tconst usedUsd = `$${used.toFixed(2)}`;\n\tconst capUsd = `$${cap.toFixed(2)}`;\n\treturn notional ? `≈${usedUsd} of ${capUsd} API-equivalent (subscription — not billed)` : `${usedUsd} of ${capUsd} spent`;\n}\nasync function runQuery(opts) {\n\tconst { permissionMode } = opts;\n\tconst abort = new AbortController();\n\tactiveRuns$1.set(opts.feedbackId, { abort });\n\tconst onInterrupt = (id) => {\n\t\tif (id === opts.feedbackId) abort.abort();\n\t};\n\tprocess.on(INTERRUPT_EVENT, onInterrupt);\n\trecordActiveRun(opts.projectRoot, opts.feedbackId);\n\tconst provider = resolveProvider(process.env);\n\tconst request = {\n\t\tprojectRoot: opts.projectRoot,\n\t\tfeedbackId: opts.feedbackId,\n\t\tcwd: opts.cwd,\n\t\ttargetFile: opts.targetFile,\n\t\tprompt: opts.prompt,\n\t\tisInitial: opts.isInitial,\n\t\tpermissionMode,\n\t\tresume: opts.resume,\n\t\tabortSignal: abort.signal\n\t};\n\ttry {\n\t\tawait consumeStream(opts, provider.run(request));\n\t} finally {\n\t\tactiveRuns$1.delete(opts.feedbackId);\n\t\tprocess.off(INTERRUPT_EVENT, onInterrupt);\n\t\tawait clearActiveRun(opts.projectRoot, opts.feedbackId);\n\t\trejectAsk(opts.feedbackId, \"agent run ended\");\n\t}\n}\n/**\n* Drive one provider run: publish its events to the bus, append its log\n* chunks to the transcript, persist the session id, and finalize the\n* resolution block. Provider-neutral — every backend funnels through the\n* same `ProviderRunItem` stream, so cost/session/status handling is shared.\n*/\nasync function consumeStream(opts, stream) {\n\tlet sessionRecorded = false;\n\tlet resultRendered = false;\n\tconst bus = getOrCreateBus(opts.feedbackId);\n\ttry {\n\t\tfor await (const item of stream) {\n\t\t\tif (!sessionRecorded && item.sessionId) {\n\t\t\t\tsessionRecorded = true;\n\t\t\t\tawait persistSessionId(opts.projectRoot, opts.feedbackId, item.sessionId);\n\t\t\t}\n\t\t\tfor (const ev of item.events ?? []) await bus.publish(ev);\n\t\t\tif (item.isResult) {\n\t\t\t\tresultRendered = true;\n\t\t\t\tif (item.log) await appendLog(opts.logPath, item.log);\n\t\t\t\tif (opts.isInitial) await appendResolution(opts.projectRoot, opts.feedbackId, opts.logPath, item.resultFooter ?? null);\n\t\t\t\telse if (item.resultFooter) await appendLog(opts.logPath, `\\n${item.resultFooter}\\n`);\n\t\t\t\ttry {\n\t\t\t\t\tconst rec = await new Storage(opts.projectRoot).read(opts.feedbackId);\n\t\t\t\t\tif (rec && rec.status !== \"pending\") {\n\t\t\t\t\t\tawait bus.publish({\n\t\t\t\t\t\t\ttype: \"status_changed\",\n\t\t\t\t\t\t\tstatus: rec.status,\n\t\t\t\t\t\t\tnote: rec.note,\n\t\t\t\t\t\t\tcommitSha: rec.commitSha,\n\t\t\t\t\t\t\tresolvedAt: rec.resolvedAt\n\t\t\t\t\t\t});\n\t\t\t\t\t\temitProjectChange({ type: \"conversations_changed\" });\n\t\t\t\t\t}\n\t\t\t\t} catch {}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (item.log) await appendLog(opts.logPath, item.log);\n\t\t}\n\t} catch (err) {\n\t\tconst msg = stringifyErr(err);\n\t\tawait bus.publish({\n\t\t\ttype: \"error\",\n\t\t\tmessage: msg\n\t\t});\n\t\tawait appendLog(opts.logPath, `\\n> [pinagent] agent stream errored: ${msg}\\n`);\n\t} finally {\n\t\tif (!resultRendered && opts.isInitial) await appendResolution(opts.projectRoot, opts.feedbackId, opts.logPath, null);\n\t}\n}\nasync function persistSessionId(projectRoot, feedbackId, sessionId) {\n\ttry {\n\t\tawait new Storage(projectRoot).patch(feedbackId, { agentSessionId: sessionId });\n\t} catch {}\n}\nfunction stringifyErr(e) {\n\treturn e instanceof Error ? e.message : String(e);\n}\nfunction renderHeader(ctx, cwd, startedAt, worktreeReady) {\n\tconst rec = ctx.feedback;\n\tconst where = rec.file ? `${rec.file}:${rec.line ?? \"?\"}${rec.col != null ? `:${rec.col}` : \"\"}` : rec.selector;\n\tconst branchLine = ctx.mode === \"worktree\" && worktreeReady ? `branch: pinagent/${rec.id}\\n` : \"\";\n\treturn [\n\t\t\"---\",\n\t\t`id: ${rec.id}`,\n\t\t`mode: ${ctx.mode}`,\n\t\t`target: ${where}`,\n\t\t`url: ${rec.url}`,\n\t\t`started: ${startedAt}`,\n\t\t`cwd: ${cwd}`,\n\t\tbranchLine.trimEnd(),\n\t\t\"---\",\n\t\t\"\",\n\t\t`# Pinagent feedback \\`${rec.id}\\``,\n\t\t\"\",\n\t\t`**Target:** \\`${where}\\` `,\n\t\t`**URL:** ${rec.url} `,\n\t\t`**Mode:** ${ctx.mode}${ctx.mode === \"worktree\" && worktreeReady ? ` · **Branch:** \\`pinagent/${rec.id}\\`` : \"\"}`,\n\t\t\"\",\n\t\t\"> **Comment**\",\n\t\t\"> \",\n\t\t`> ${rec.comment.split(\"\\n\").join(\"\\n> \")}`,\n\t\t\"\",\n\t\t\"## Agent output\",\n\t\t\"\",\n\t\t\"\"\n\t].filter((l) => l !== null).join(\"\\n\");\n}\nasync function appendResolution(projectRoot, feedbackId, logPath, footer) {\n\tconst updated = await new Storage(projectRoot).read(feedbackId);\n\tconst finishedAt = (/* @__PURE__ */ new Date()).toISOString();\n\tconst lines = [];\n\tlines.push(\"\");\n\tlines.push(\"## Resolution\");\n\tlines.push(\"\");\n\tlines.push(`**Finished:** ${finishedAt} `);\n\tif (footer) lines.push(footer);\n\telse lines.push(\"> Stream ended without a `result` message.\");\n\tif (!updated) {\n\t\tlines.push(\"\");\n\t\tlines.push(\"> Feedback record disappeared between spawn and exit.\");\n\t} else {\n\t\tlines.push(`**Status:** \\`${updated.status}\\``);\n\t\tif (updated.resolvedAt) lines.push(`**Resolved at:** ${updated.resolvedAt}`);\n\t\tif (updated.commitSha) lines.push(`**Commit:** \\`${updated.commitSha}\\``);\n\t\tif (updated.agentSessionId) lines.push(`**Session:** \\`${updated.agentSessionId}\\``);\n\t\tif (updated.note) {\n\t\t\tlines.push(\"\");\n\t\t\tlines.push(\"### Note from agent\");\n\t\t\tlines.push(\"\");\n\t\t\tlines.push(updated.note);\n\t\t}\n\t\tif (updated.status === \"pending\") {\n\t\t\tlines.push(\"\");\n\t\t\tlines.push(\"> ⚠️ Agent exited without calling `resolve_feedback`. The record is still pending.\");\n\t\t}\n\t}\n\tlines.push(\"\");\n\tawait appendLog(logPath, lines.join(\"\\n\"));\n}\nfunction buildInitialPrompt(rec, mode, cwd) {\n\tconst where = rec.file ? `${rec.file}:${rec.line ?? \"?\"}${rec.col != null ? `:${rec.col}` : \"\"}` : rec.selector;\n\tconst worktreeContext = mode === \"worktree\" ? [\n\t\t\"\",\n\t\t\"You are working in a FRESH git worktree at:\",\n\t\t` ${cwd}`,\n\t\t`on branch pinagent/${rec.id} (forked from current HEAD).`,\n\t\t\"\",\n\t\t\"Make edits freely. DO NOT commit — the developer will review your\",\n\t\t\"changes by diffing this branch against main.\"\n\t].join(\"\\n\") : \"\";\n\tconst componentLine = rec.component ? `Component: <${rec.component}>` : \"\";\n\tconst componentPathLine = rec.componentPath && rec.componentPath.length > 1 ? `Component path: ${rec.componentPath.join(\" › \")}` : \"\";\n\tconst instanceNote = rec.instanceTotal && rec.instanceTotal > 1 ? [\n\t\t\"\",\n\t\t`Heads up: this target's source location is rendered ${rec.instanceTotal} times`,\n\t\t`(likely a list/.map()). The developer clicked instance #${(rec.instanceIndex ?? 0) + 1} of ${rec.instanceTotal}.`,\n\t\trec.instanceFingerprint ? `That instance's content: ${rec.instanceFingerprint}` : \"\",\n\t\t`The file:line points at the *shared* JSX literal — edit there, but use the`,\n\t\t`screenshot and the content above to act on the correct item if the change is`,\n\t\t`instance-specific (e.g. its data source) rather than the markup itself.`\n\t].filter((l) => l !== \"\").join(\"\\n\") : \"\";\n\tconst additional = rec.additionalAnchors ?? [];\n\tconst additionalTargets = additional.length > 0 ? [\n\t\t\"\",\n\t\t`The developer multi-selected ${additional.length + 1} elements and left a single`,\n\t\t`comment that applies to ALL of them. Besides the primary Target above, also`,\n\t\t`address these (apply the same change to each unless the comment says otherwise):`,\n\t\t...additional.map((a, i) => {\n\t\t\tconst aloc = a.file ? `${a.file}:${a.line ?? \"?\"}${a.col != null ? `:${a.col}` : \"\"}` : a.selector;\n\t\t\tconst comp = a.component ? ` (<${a.component}>)` : \"\";\n\t\t\treturn ` ${i + 2}. ${aloc}${comp}`;\n\t\t})\n\t].join(\"\\n\") : \"\";\n\treturn [\n\t\t\"A developer submitted Pinagent feedback. Address it autonomously.\",\n\t\t\"\",\n\t\t`Feedback id: ${rec.id}`,\n\t\t`Target: ${where}`,\n\t\tcomponentLine,\n\t\tcomponentPathLine,\n\t\t`Comment: \"${rec.comment.replace(/\\s+/g, \" \").slice(0, 200)}\"`,\n\t\tinstanceNote,\n\t\tadditionalTargets,\n\t\tworktreeContext,\n\t\t\"\",\n\t\t\"Workflow:\",\n\t\t\" 1. Call the pinagent MCP tool `get_feedback` with the id above —\",\n\t\t\" it returns the full comment plus a screenshot of what the user\",\n\t\t\" selected.\",\n\t\t\" 2. Optionally call `get_source_context` to see code around the target.\",\n\t\t\" 3. Edit the file(s) to address the request. Be conservative: only\",\n\t\t\" change what the comment asks for.\",\n\t\t\" 4. Call `resolve_feedback` with status=\\\"fixed\\\" and a one-sentence\",\n\t\t\" note describing what you changed. Use status=\\\"wontfix\\\" with a\",\n\t\t\" reason if you cannot apply the change.\"\n\t].filter((l) => l !== \"\").join(\"\\n\");\n}\n//#endregion\n//#region src/concurrency.ts\n/**\n* Bounded-concurrency `map`. A dock refresh fans out per-worktree git work\n* (status, merge-base, rev-list, diff, du …) — several child processes per row.\n* With an unbounded `Promise.all` over many retained worktrees that's hundreds\n* of concurrent processes in one tick, enough to exhaust file descriptors / PIDs\n* and stall the dev box. `mapLimit` keeps at most `limit` running at once while\n* preserving input order in the result.\n*/\nasync function mapLimit(items, limit, fn) {\n\tconst results = new Array(items.length);\n\tlet next = 0;\n\tconst workerCount = Math.max(1, Math.min(limit, items.length));\n\tconst worker = async () => {\n\t\tfor (let i = next++; i < items.length; i = next++) results[i] = await fn(items[i], i);\n\t};\n\tawait Promise.all(Array.from({ length: workerCount }, worker));\n\treturn results;\n}\n//#endregion\n//#region src/merge-queue.ts\n/**\n* Per-project FIFO queue for landing/discarding pinagent worktrees.\n*\n* v2 plan §6 calls for serialised merges so two widgets racing to land\n* onto the same target branch can't interleave. We do that by chaining\n* each enqueued job onto the project's current tail Promise. Failures\n* are isolated — a rejected job's error is returned to its caller, but\n* the queue continues from the same logical point so the next job\n* isn't poisoned.\n*\n* In-memory only. On an agent-runner restart, in-flight queue entries are\n* dropped along with the WS connections that initiated them; the DB\n* still shows `worktreeState='active'` for any conversation that\n* hadn't reached `landed`/`discarded`, so the user can re-click Land\n* from the widget after the server comes back.\n*/\nconst QUEUES_SYMBOL = Symbol.for(\"pinagent.merge-queue.tails\");\nconst tails = globalThis[QUEUES_SYMBOL] ?? /* @__PURE__ */ new Map();\nglobalThis[QUEUES_SYMBOL] = tails;\n/**\n* Enqueue `fn` onto the FIFO for `projectRoot`. The returned Promise\n* resolves/rejects with whatever `fn` does once every previously\n* enqueued job for this project has settled. A throwing `fn` does not\n* poison the queue: subsequent enqueues still run.\n*/\nfunction enqueue(projectRoot, fn) {\n\tconst result = (tails.get(projectRoot) ?? Promise.resolve()).then(fn, fn);\n\tconst next = result.then(() => void 0, () => void 0);\n\ttails.set(projectRoot, next);\n\tnext.then(() => {\n\t\tif (tails.get(projectRoot) === next) tails.delete(projectRoot);\n\t});\n\treturn result;\n}\n//#endregion\n//#region src/worktree-serve.ts\n/**\n* On-demand dev servers for worktrees — the \"Open app\" affordance in the\n* dock's Branches view.\n*\n* A pinagent worktree (`spawnAgent: 'worktree'`) is just a git branch + a\n* directory on disk; nothing serves it. The project's single Vite/Next dev\n* server stays bound to the project root, so the only way to *see* what an\n* agent did in a worktree is the diff view. This module lets the dock stand\n* up a throwaway dev server rooted at the worktree directory on its own\n* port, so the developer can open the worktree's running app in a browser\n* tab.\n*\n* Lifecycle:\n* - `serveWorktree` lazily spawns (or reuses) one server per feedbackId,\n* tracked in a globalThis-pinned registry that survives Next/Vite HMR\n* module re-eval (same pattern as the WS subscriber sets in ws-server.ts).\n* - `stopWorktreeServer` kills one; called from every worktree-teardown\n* path (prune / land / discard) so a served server doesn't outlive the\n* directory it's rooted in.\n* - A process-exit hook tears them all down so a SIGINT on the main dev\n* server doesn't leak orphaned child servers.\n*\n* The command to run is resolved by `resolveServeCommand`: the configured\n* `worktreeServeCommand` override (plugin option → PINAGENT_WORKTREE_SERVE_COMMAND\n* env) wins; otherwise we infer it from the worktree's package.json.\n*/\n/** Tell project subscribers (the dock's switcher) the running-server set changed. */\nfunction emitServersChanged() {\n\temitProjectChange({ type: \"worktree_servers_changed\" });\n}\n/** Base port for the per-worktree dev-server probe. Steps upward to find a\n* free port. Kept clear of the WS server's 53636..53645 fallback window. */\nconst DEFAULT_BASE_PORT = 53700;\nconst PORT_PROBE_RANGE = 50;\n/** How long to wait for a freshly-spawned dev server to accept connections\n* before we report failure. Cold Vite/Next starts can be slow. */\nconst READY_TIMEOUT_MS = 3e4;\nconst READY_POLL_MS = 250;\n/**\n* Snapshot the currently-tracked dev servers — backs the dock's worktree\n* switcher. Dead children (the exit handler usually evicts them, but a\n* race is possible) are filtered out so the dock never points an iframe\n* at a corpse.\n*/\nfunction listWorktreeServers() {\n\tconst out = [];\n\tfor (const [feedbackId, entry] of registry) {\n\t\tif (!isAlive(entry.child)) continue;\n\t\tout.push({\n\t\t\tfeedbackId,\n\t\t\tport: entry.port,\n\t\t\turl: `http://localhost:${entry.port}`,\n\t\t\tstatus: entry.status\n\t\t});\n\t}\n\treturn out;\n}\nconst REGISTRY_SYMBOL = Symbol.for(\"pinagent.worktreeServers\");\nconst registry = globalThis[REGISTRY_SYMBOL] ?? /* @__PURE__ */ new Map();\nglobalThis[REGISTRY_SYMBOL] = registry;\nconst CLEANUP_SYMBOL = Symbol.for(\"pinagent.worktreeServersCleanup\");\nif (!globalThis[CLEANUP_SYMBOL]) {\n\tglobalThis[CLEANUP_SYMBOL] = true;\n\tconst killAll = () => {\n\t\tfor (const id of [...registry.keys()]) killEntry(id);\n\t};\n\tprocess.once(\"exit\", killAll);\n\tprocess.once(\"SIGINT\", killAll);\n\tprocess.once(\"SIGTERM\", killAll);\n}\n/**\n* Resolve the shell command that starts a dev server for a worktree.\n*\n* Resolution order:\n* 1. `override` (the `worktreeServeCommand` plugin option): trusted\n* verbatim. A `{port}` placeholder is substituted with the chosen port;\n* if absent, ` --port <port>` is appended so the server still binds\n* where we expect.\n* 2. Inference from the worktree's package.json — detects the package\n* manager from the lockfile and the framework (next vs vite) from\n* dependencies, then runs the `dev` (or `start`) script with the\n* framework's port flag.\n*\n* Returns null when no override is given and no runnable script is found —\n* the caller surfaces a \"set worktreeServeCommand\" hint.\n*/\nfunction resolveServeCommand(args) {\n\tconst { worktreePath, port, override } = args;\n\tif (override && override.trim().length > 0) return override.includes(\"{port}\") ? override.replaceAll(\"{port}\", String(port)) : `${override} --port ${port}`;\n\tconst pkg = readPackageJson(worktreePath);\n\tif (!pkg) return null;\n\tconst scripts = pkg.scripts ?? {};\n\tconst script = scripts.dev !== void 0 ? \"dev\" : scripts.start !== void 0 ? \"start\" : null;\n\tif (!script) return null;\n\tconst pm = detectPackageManager(worktreePath);\n\tconst portFlag = {\n\t\t...pkg.dependencies,\n\t\t...pkg.devDependencies\n\t}.next !== void 0 ? `-p ${port}` : `--port ${port}`;\n\treturn pm === \"yarn\" ? `yarn ${script} ${portFlag}` : `${pm} run ${script} -- ${portFlag}`;\n}\nfunction readPackageJson(dir) {\n\ttry {\n\t\treturn JSON.parse(readFileSync(join(dir, \"package.json\"), \"utf8\"));\n\t} catch {\n\t\treturn null;\n\t}\n}\nfunction detectPackageManager(dir) {\n\tif (existsSync(join(dir, \"pnpm-lock.yaml\"))) return \"pnpm\";\n\tif (existsSync(join(dir, \"yarn.lock\"))) return \"yarn\";\n\tif (existsSync(join(dir, \"bun.lockb\"))) return \"bun\";\n\treturn \"npm\";\n}\n/**\n* Start (or reuse) a dev server for the given worktree and return its URL.\n*\n* Throws when the conversation has no worktree, the worktree directory is\n* gone, no command can be resolved, or the server doesn't accept\n* connections within the readiness timeout.\n*/\nasync function serveWorktree(projectRoot, feedbackId, env = process.env) {\n\tconst existing = registry.get(feedbackId);\n\tif (existing && isAlive(existing.child)) {\n\t\tawait existing.ready;\n\t\treturn {\n\t\t\turl: `http://localhost:${existing.port}`,\n\t\t\tport: existing.port,\n\t\t\treused: true\n\t\t};\n\t}\n\tif (existing) registry.delete(feedbackId);\n\tconst rec = await new Storage(projectRoot).read(feedbackId);\n\tif (!rec) throw new Error(\"conversation not found\");\n\tif (!rec.worktreePath) throw new Error(\"conversation has no worktree to serve\");\n\tif (!existsSync(rec.worktreePath)) throw new Error(`worktree no longer exists at ${rec.worktreePath}`);\n\tconst port = await findFreePort(Number(env.PINAGENT_WORKTREE_SERVE_BASE_PORT) || DEFAULT_BASE_PORT);\n\tconst command = resolveServeCommand({\n\t\tworktreePath: rec.worktreePath,\n\t\tport,\n\t\toverride: env.PINAGENT_WORKTREE_SERVE_COMMAND\n\t});\n\tif (!command) throw new Error(\"couldn't infer a dev command for this worktree — set `worktreeServeCommand` in the pinagent plugin options\");\n\tconst logDir = join(projectRoot, \".pinagent\", \"logs\");\n\tawait mkdir(logDir, { recursive: true });\n\tconst logPath = join(logDir, `${feedbackId}-serve.log`);\n\tconst logStream = createWriteStream(logPath, { flags: \"a\" });\n\tconst child = spawn(command, {\n\t\tcwd: rec.worktreePath,\n\t\tenv,\n\t\tshell: true,\n\t\tdetached: true,\n\t\tstdio: [\n\t\t\t\"ignore\",\n\t\t\t\"pipe\",\n\t\t\t\"pipe\"\n\t\t]\n\t});\n\tchild.stdout?.pipe(logStream);\n\tchild.stderr?.pipe(logStream);\n\tconst ready = waitForPort(port, child, logPath);\n\tconst entry = {\n\t\tport,\n\t\tchild,\n\t\tready,\n\t\tstatus: \"starting\"\n\t};\n\tregistry.set(feedbackId, entry);\n\tready.then(() => {\n\t\tentry.status = \"running\";\n\t\temitServersChanged();\n\t}, () => {});\n\tchild.once(\"exit\", () => {\n\t\tif (registry.get(feedbackId)?.child === child) {\n\t\t\tregistry.delete(feedbackId);\n\t\t\temitServersChanged();\n\t\t}\n\t});\n\ttry {\n\t\tawait ready;\n\t} catch (err) {\n\t\tkillEntry(feedbackId);\n\t\temitServersChanged();\n\t\tthrow err;\n\t}\n\treturn {\n\t\turl: `http://localhost:${port}`,\n\t\tport,\n\t\treused: false\n\t};\n}\n/** Stop the dev server for one worktree, if any. No-op when none is running. */\nfunction stopWorktreeServer(feedbackId) {\n\tconst existed = registry.has(feedbackId);\n\tkillEntry(feedbackId);\n\tif (existed) emitServersChanged();\n}\nfunction killEntry(feedbackId) {\n\tconst entry = registry.get(feedbackId);\n\tif (!entry) return;\n\tregistry.delete(feedbackId);\n\tconst pid = entry.child.pid;\n\tif (pid === void 0) return;\n\ttry {\n\t\tprocess.kill(-pid, \"SIGTERM\");\n\t} catch {\n\t\ttry {\n\t\t\tentry.child.kill(\"SIGTERM\");\n\t\t} catch {}\n\t}\n}\nfunction isAlive(child) {\n\treturn child.exitCode === null && child.signalCode === null && !child.killed;\n}\n/**\n* Find a free TCP port at or above `start`, walking upward. Throws if the\n* whole probe range is occupied.\n*/\nasync function findFreePort(start) {\n\tfor (let port = start; port < start + PORT_PROBE_RANGE; port++) if (await isPortFree(port)) return port;\n\tthrow new Error(`no free port in range ${start}..${start + PORT_PROBE_RANGE - 1}`);\n}\nfunction isPortFree(port) {\n\treturn new Promise((resolve) => {\n\t\tconst server = createServer();\n\t\tserver.once(\"error\", () => resolve(false));\n\t\tserver.once(\"listening\", () => server.close(() => resolve(true)));\n\t\tserver.listen(port, \"127.0.0.1\");\n\t});\n}\n/**\n* Resolve once `port` accepts a TCP connection (the dev server is up), or\n* reject if the child exits first or the readiness timeout elapses.\n*/\nfunction waitForPort(port, child, logPath) {\n\treturn new Promise((resolve, reject) => {\n\t\tconst deadline = Date.now() + READY_TIMEOUT_MS;\n\t\tlet settled = false;\n\t\tconst finish = (err) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tif (err) reject(err);\n\t\t\telse resolve();\n\t\t};\n\t\tchild.once(\"exit\", (code) => finish(/* @__PURE__ */ new Error(`dev server exited before becoming ready (code ${code ?? \"unknown\"}). The worktree may be missing dependencies — try installing them there. See ${logPath} for the dev-server output.`)));\n\t\tconst attempt = () => {\n\t\t\tif (settled) return;\n\t\t\tconst socket = createConnection({\n\t\t\t\tport,\n\t\t\t\thost: \"127.0.0.1\"\n\t\t\t});\n\t\t\tsocket.once(\"connect\", () => {\n\t\t\t\tsocket.destroy();\n\t\t\t\tfinish();\n\t\t\t});\n\t\t\tsocket.once(\"error\", () => {\n\t\t\t\tsocket.destroy();\n\t\t\t\tif (Date.now() > deadline) {\n\t\t\t\t\tfinish(/* @__PURE__ */ new Error(`dev server didn't start within ${READY_TIMEOUT_MS / 1e3}s. See ${logPath} for its output.`));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsetTimeout(attempt, READY_POLL_MS);\n\t\t\t});\n\t\t};\n\t\tattempt();\n\t});\n}\n//#endregion\n//#region src/branches.ts\n/**\n* `listBranches` — assemble the data the dock's Branches view needs.\n*\n* Walks every conversation with a worktree (`worktreePath !== null`,\n* worktreeState in 'active' | 'landed'). For each: shells out to git\n* for cleanliness + ahead/behind state, stats the directory for disk\n* usage, and returns a flat array shaped for the existing dock\n* Branch row layout.\n*\n* Disk usage uses `du -sk` because traversing the worktree in Node\n* for every refetch is slow on large projects and `du` is universally\n* available on every platform pinagent supports. We accept its small\n* overcount on tools like cp-on-write filesystems — the dock surfaces\n* the number as informational, not load-bearing.\n*/\n/** Max worktrees whose git/disk stats are computed in parallel per refresh. */\nconst GIT_FANOUT_LIMIT$1 = 8;\nasync function listBranches(projectRoot) {\n\tconst candidates = (await new Storage(projectRoot).list()).filter((r) => r.worktreePath !== null && r.branch !== null && (r.worktreeState === \"active\" || r.worktreeState === \"landed\"));\n\tif (candidates.length === 0) return [];\n\tconst baseRef = await resolveBaseRef$1(projectRoot);\n\treturn (await mapLimit(candidates, GIT_FANOUT_LIMIT$1, async (rec) => {\n\t\tif (!rec.worktreePath || !rec.branch) return null;\n\t\tif (!existsSync(rec.worktreePath)) return null;\n\t\tconst [state, diskMb] = await Promise.all([computeBranchState(projectRoot, rec.worktreePath, rec.branch, baseRef), computeDiskMb(rec.worktreePath)]);\n\t\treturn {\n\t\t\tid: rec.id,\n\t\t\tname: rec.branch,\n\t\t\tconversationId: rec.id,\n\t\t\tconversationTitle: titleOf$1(rec.comment),\n\t\t\tcreatedAt: rec.createdAt,\n\t\t\tlastActivity: rec.updatedAt,\n\t\t\tstate,\n\t\t\tdiskMb\n\t\t};\n\t})).filter((r) => r !== null).sort((a, b) => Date.parse(b.lastActivity) - Date.parse(a.lastActivity));\n}\nasync function resolveBaseRef$1(projectRoot) {\n\tconst sym = await runGitCapture(projectRoot, [\n\t\t\"symbolic-ref\",\n\t\t\"--short\",\n\t\t\"HEAD\"\n\t]);\n\tconst baseName = sym.code === 0 ? sym.stdout.trim() : \"HEAD\";\n\tconst sha = await runGitCapture(projectRoot, [\"rev-parse\", baseName]);\n\treturn sha.code === 0 ? sha.stdout.trim() : baseName;\n}\nasync function computeBranchState(projectRoot, worktreePath, branch, baseRef) {\n\tconst status = await runGitCapture(worktreePath, [\"status\", \"--porcelain\"]);\n\tif (status.code === 0 && status.stdout.trim().length > 0) return \"uncommitted\";\n\tconst behindCount = await runGitCapture(projectRoot, [\n\t\t\"rev-list\",\n\t\t\"--count\",\n\t\t`${branch}..${baseRef}`\n\t]);\n\tif (behindCount.code === 0 && Number(behindCount.stdout.trim()) > 0) return \"behind-base\";\n\treturn \"clean\";\n}\n/**\n* Run `du -sk <path>` and return MiB rounded to the nearest int. Returns\n* null on any failure (Windows, permission denied, `du` not on PATH).\n*/\nfunction computeDiskMb(worktreePath) {\n\treturn new Promise((resolve) => {\n\t\tconst child = spawn(\"du\", [\"-sk\", worktreePath], { stdio: [\n\t\t\t\"ignore\",\n\t\t\t\"pipe\",\n\t\t\t\"ignore\"\n\t\t] });\n\t\tlet out = \"\";\n\t\tchild.stdout.on(\"data\", (d) => {\n\t\t\tout += d.toString(\"utf8\");\n\t\t});\n\t\tchild.on(\"error\", () => resolve(null));\n\t\tchild.on(\"exit\", (code) => {\n\t\t\tif (code !== 0) return resolve(null);\n\t\t\tconst k = Number(out.split(/\\s+/, 1)[0]);\n\t\t\tif (!Number.isFinite(k)) return resolve(null);\n\t\t\tresolve(Math.max(1, Math.round(k / 1024)));\n\t\t});\n\t});\n}\nfunction titleOf$1(comment) {\n\tconst first = comment.split(\"\\n\").find((l) => l.trim().length > 0);\n\tif (!first) return null;\n\tconst t = first.trim();\n\treturn t.length > 80 ? `${t.slice(0, 77)}…` : t;\n}\n/**\n* Tear down one conversation's worktree + branch by name. Same lifecycle\n* as `discardConversation` from the Conversations detail view — the\n* Branches view just calls into the same path so \"discard\" / \"prune\"\n* stay one verb at the storage layer.\n*\n* Goes through the merge queue so it serializes with any concurrent\n* land/discard on the same project.\n*/\nasync function pruneBranch(projectRoot, feedbackId) {\n\tif (!await new Storage(projectRoot).read(feedbackId)) return {\n\t\tok: false,\n\t\tfeedbackId,\n\t\terror: \"conversation not found\"\n\t};\n\tconst logPath = join(projectRoot, \".pinagent\", \"logs\", `${feedbackId}.md`);\n\tawait mkdir(join(projectRoot, \".pinagent\", \"logs\"), { recursive: true });\n\tstopWorktreeServer(feedbackId);\n\ttry {\n\t\tawait enqueue(projectRoot, () => discardWorktree(projectRoot, feedbackId, logPath));\n\t\treturn {\n\t\t\tok: true,\n\t\t\tfeedbackId\n\t\t};\n\t} catch (e) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tfeedbackId,\n\t\t\terror: e instanceof Error ? e.message : String(e)\n\t\t};\n\t}\n}\n/**\n* Stand up (or reuse) an on-demand dev server for one conversation's\n* worktree, so the dock's \"Open app\" action can point a browser tab at the\n* worktree's running app. Delegates to `serveWorktree`; wraps failures in a\n* structured result so the HTTP layer can return a 422 with a message\n* instead of a 500.\n*/\nasync function serveBranch(projectRoot, feedbackId) {\n\ttry {\n\t\tconst result = await serveWorktree(projectRoot, feedbackId);\n\t\treturn {\n\t\t\tok: true,\n\t\t\turl: result.url,\n\t\t\tport: result.port,\n\t\t\treused: result.reused\n\t\t};\n\t} catch (e) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: e instanceof Error ? e.message : String(e)\n\t\t};\n\t}\n}\n/**\n* Wire body for `POST /__pinagent/branches/bulk-prune`. Capped at 200\n* ids — well past the manual-select pain threshold and bounds the\n* worst-case request.\n*/\nconst BulkPruneBodySchema = z.object({ feedbackIds: z.array(z.string().regex(ID_RE)).min(1).max(200) });\n/**\n* Prune a hand-picked batch of worktrees. Each id goes through the\n* existing per-row `pruneBranch` so the worktree teardown + per-row\n* `conversation_discarded` audit emission stay intact; this function\n* adds ONE summary `worktrees_bulk_pruned` event covering the batch.\n*\n* Serial loop matches `pruneStaleBranches`: each prune already\n* serializes via the merge queue, so parallel calls wouldn't gain\n* anything and a linear loop keeps the result order predictable for\n* the dock's success toast.\n*/\nasync function pruneBranches(projectRoot, feedbackIds) {\n\tconst pruned = [];\n\tconst failed = [];\n\tfor (const id of feedbackIds) {\n\t\tconst result = await pruneBranch(projectRoot, id);\n\t\tif (result.ok) pruned.push(result.feedbackId);\n\t\telse failed.push({\n\t\t\tfeedbackId: result.feedbackId,\n\t\t\terror: result.error ?? \"unknown\"\n\t\t});\n\t}\n\tif (pruned.length > 0) await recordAuditEvent(projectRoot, {\n\t\tconversationId: null,\n\t\tactor: \"user\",\n\t\taction: \"worktrees_bulk_pruned\",\n\t\tpayload: {\n\t\t\tids: pruned,\n\t\t\tcount: pruned.length\n\t\t}\n\t});\n\treturn {\n\t\tpruned,\n\t\tfailed\n\t};\n}\n/**\n* Bulk-prune every branch whose `lastActivity` is older than the\n* project's configured `worktreeRetentionDays`. Reads the retention\n* from SettingsStore so the threshold matches what the dock displays\n* — no risk of \"the dock said 9 stale, the server only pruned 7.\"\n*/\nasync function pruneStaleBranches(projectRoot) {\n\tconst settings = await new SettingsStore(projectRoot).read();\n\tconst thresholdMs = settings.worktreeRetentionDays * 24 * 60 * 60 * 1e3;\n\tconst cutoff = Date.now() - thresholdMs;\n\tconst stale = (await listBranches(projectRoot)).filter((b) => Date.parse(b.lastActivity) < cutoff);\n\tconst pruned = [];\n\tconst failed = [];\n\tfor (const b of stale) {\n\t\tconst result = await pruneBranch(projectRoot, b.conversationId);\n\t\tif (result.ok) pruned.push(result.feedbackId);\n\t\telse failed.push({\n\t\t\tfeedbackId: result.feedbackId,\n\t\t\terror: result.error ?? \"unknown\"\n\t\t});\n\t}\n\treturn {\n\t\tpruned,\n\t\tfailed,\n\t\tretentionDays: settings.worktreeRetentionDays\n\t};\n}\n//#endregion\n//#region src/changes.ts\n/**\n* `listChanges` — assemble the data the dock's Changes view needs.\n*\n* Walks every conversation with a worktree (`worktreeState` in\n* 'active' | 'landed'), computes its diff stats against the project's\n* current HEAD branch, and returns a flat array shaped for the dock's\n* existing Change row layout.\n*\n* Lives in agent-runner (not in middleware.ts / route.ts) so both the\n* vite-plugin and next-plugin call into the same logic — they only\n* differ in how the returned data is serialized to the wire.\n*/\n/** Max worktrees whose git stats are computed in parallel per dock refresh. */\nconst GIT_FANOUT_LIMIT = 8;\n/**\n* Best-effort resolution of the project's current HEAD branch — used\n* as the diff base. Falls back to the literal string `HEAD` if `git\n* symbolic-ref` fails (detached HEAD, no .git at root), which still\n* gives a usable diff.\n*/\nasync function resolveBaseRef(projectRoot) {\n\tconst sym = await runGitCapture(projectRoot, [\n\t\t\"symbolic-ref\",\n\t\t\"--short\",\n\t\t\"HEAD\"\n\t]);\n\tif (sym.code === 0) return sym.stdout.trim();\n\treturn \"HEAD\";\n}\n/**\n* Count commits on the worktree's branch that aren't on the base. The\n* agent never commits (the Land step does it on the user's behalf, see\n* agent.ts `mergeWorktree`), so any commit here came from the user\n* reaching into the worktree manually. Returns 0 on git failures —\n* the warning is best-effort, never worth blocking the Changes view.\n*/\nasync function countExternalCommits(worktreePath, baseRef) {\n\tconst ahead = await runGitCapture(worktreePath, [\n\t\t\"rev-list\",\n\t\t\"--count\",\n\t\t`${baseRef}..HEAD`\n\t]);\n\tif (ahead.code !== 0) return 0;\n\tconst n = Number(ahead.stdout.trim());\n\treturn Number.isFinite(n) && n > 0 ? n : 0;\n}\nasync function listChanges(projectRoot) {\n\tconst candidates = (await new Storage(projectRoot).list()).filter((r) => r.worktreeState === \"active\" || r.worktreeState === \"landed\");\n\tif (candidates.length === 0) return [];\n\tconst baseRef = await resolveBaseRef(projectRoot);\n\treturn (await mapLimit(candidates, GIT_FANOUT_LIMIT, async (rec) => {\n\t\tif (!rec.worktreePath) return null;\n\t\tconst isActive = rec.worktreeState === \"active\";\n\t\tconst stats = isActive ? await computeWorktreeStats(rec.worktreePath, baseRef) : {\n\t\t\tfilesChanged: 0,\n\t\t\tadditions: 0,\n\t\t\tdeletions: 0\n\t\t};\n\t\tif (!stats) return null;\n\t\tconst externallyModified = isActive ? await countExternalCommits(rec.worktreePath, baseRef) > 0 : false;\n\t\tconst preview = isActive ? await computeWorktreePreview(rec.worktreePath, baseRef) : \"\";\n\t\treturn {\n\t\t\tid: rec.id,\n\t\t\tconversationId: rec.id,\n\t\t\tconversationTitle: titleOf(rec.comment),\n\t\t\tstatus: rec.worktreeState === \"landed\" ? \"landed\" : stats.filesChanged > 0 ? \"readyToLand\" : \"pending\",\n\t\t\tbranch: rec.branch ?? \"\",\n\t\t\tfilesChanged: stats.filesChanged,\n\t\t\tadditions: stats.additions,\n\t\t\tdeletions: stats.deletions,\n\t\t\texternallyModified,\n\t\t\tpreview,\n\t\t\tupdatedAt: rec.updatedAt\n\t\t};\n\t})).filter((r) => r !== null).sort((a, b) => Date.parse(b.updatedAt) - Date.parse(a.updatedAt));\n}\nfunction titleOf(comment) {\n\tconst t = (comment.split(\"\\n\").find((l) => l.trim().length > 0) ?? comment).trim();\n\treturn t.length > 80 ? `${t.slice(0, 77)}…` : t;\n}\n/**\n* Fetch the full unified diff for one conversation's worktree. Returns\n* null when the conversation isn't found, isn't in a worktree state we\n* can diff, or the worktree is gone from disk.\n*\n* PR-D3 lazy-loads diffs per row via this — the list endpoint stays\n* lightweight (stats only), only expanded rows pay the diff cost.\n*/\nasync function getChangeDiff(projectRoot, feedbackId) {\n\tconst rec = await new Storage(projectRoot).read(feedbackId);\n\tif (!rec) return null;\n\tif (rec.worktreeState !== \"active\") return null;\n\tif (!rec.worktreePath) return null;\n\tconst baseRef = await resolveBaseRef(projectRoot);\n\tconst diff = await computeWorktreeDiff(rec.worktreePath, baseRef);\n\tif (!diff) return null;\n\treturn {\n\t\t...diff,\n\t\tworktreePath: rec.worktreePath\n\t};\n}\n//#endregion\n//#region src/connection-validators.ts\n/**\n* Verify-on-set helpers for the Connections route. Each function makes\n* a single trivial upstream call to confirm the credential works before\n* we persist it — surfacing \"this token is wrong\" at form-submit time\n* rather than at first composer / agent run.\n*\n* Pinned to native `fetch` so we don't pull `@octokit/rest` into this\n* lightweight path; the composer already depends on Octokit for the PR\n* API call where the richer client matters.\n*/\nasync function validateGithubToken(token) {\n\ttry {\n\t\tconst { data } = await new Octokit({ auth: token }).users.getAuthenticated();\n\t\treturn {\n\t\t\tok: true,\n\t\t\tlogin: data.login\n\t\t};\n\t} catch (e) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: e instanceof Error ? e.message : \"GitHub rejected the token\"\n\t\t};\n\t}\n}\n/**\n* Minimum-cost validation call: `POST /v1/messages` with `max_tokens: 1`\n* against Haiku. Returns 200 for any working key; surfaces upstream\n* error bodies on failure.\n*/\nasync function validateAnthropicKey(key) {\n\ttry {\n\t\tconst res = await fetch(\"https://api.anthropic.com/v1/messages\", {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"content-type\": \"application/json\",\n\t\t\t\t\"x-api-key\": key,\n\t\t\t\t\"anthropic-version\": \"2023-06-01\"\n\t\t\t},\n\t\t\tbody: JSON.stringify({\n\t\t\t\tmodel: \"claude-haiku-4-5-20251001\",\n\t\t\t\tmax_tokens: 1,\n\t\t\t\tmessages: [{\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tcontent: \"hi\"\n\t\t\t\t}]\n\t\t\t})\n\t\t});\n\t\tif (res.ok) return { ok: true };\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: (await res.json().catch(() => ({}))).error?.message ?? `Anthropic API returned ${res.status}`\n\t\t};\n\t} catch (e) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: e instanceof Error ? e.message : \"unreachable\"\n\t\t};\n\t}\n}\n//#endregion\n//#region src/conversation-patch.ts\n/**\n* Conversation patch helpers — single entry points both plugins call\n* when the dock PATCHes one or many conversations.\n*\n* - `applyConversationPatch` wraps Storage.patch for a single id and\n* emits the human-facing audit events (rename, archive, unarchive).\n* - `applyBulkArchive` does N storage.patch calls then emits ONE\n* bulk audit event with the full id list. Bulk avoids papering the\n* History → Activity feed with N individual archive entries when a\n* user sweeps 50 stale rows.\n*\n* Other fields (status, worktreeState, etc.) flow through Storage.patch\n* unaudited because they have their own emit sites elsewhere\n* (mergeWorktree, discardWorktree, MCP resolve).\n*/\n/**\n* Wire body for `POST /__pinagent/feedback/bulk-update`. v1 only carries\n* the archived flip; rename + lifecycle stay on the per-row PATCH.\n* Cap on the id list keeps the worst-case request bounded — a 200-row\n* batch is already well past the manual-select pain threshold.\n*/\nconst BulkUpdateBodySchema = z.object({\n\tids: z.array(z.string().regex(ID_RE)).min(1).max(200),\n\tpatch: z.object({ archived: z.boolean() })\n});\n/**\n* Wire body for `POST /__pinagent/feedback/bulk-reopen`. Same id cap\n* as bulk-update — the bulk reopen iterates per-row and is bounded by\n* the same back-pressure considerations.\n*/\nconst BulkReopenBodySchema = z.object({ feedbackIds: z.array(z.string().regex(ID_RE)).min(1).max(200) });\nasync function applyConversationPatch(projectRoot, id, patch) {\n\tconst storage = new Storage(projectRoot);\n\tconst previous = await storage.read(id);\n\tif (!previous) return { record: null };\n\tconst updated = await storage.patch(id, patch);\n\tif (!updated) return { record: null };\n\tif (patch.title !== void 0 && previous.title !== updated.title) await recordAuditEvent(projectRoot, {\n\t\tconversationId: id,\n\t\tactor: \"user\",\n\t\taction: \"conversation_renamed\",\n\t\tpayload: {\n\t\t\tfrom: previous.title,\n\t\t\tto: updated.title\n\t\t}\n\t});\n\tif (patch.archived !== void 0 && previous.archived !== updated.archived) await recordAuditEvent(projectRoot, {\n\t\tconversationId: id,\n\t\tactor: \"user\",\n\t\taction: updated.archived ? \"conversation_archived\" : \"conversation_unarchived\",\n\t\tpayload: {}\n\t});\n\treturn { record: updated };\n}\n/**\n* Archive or unarchive a batch of conversations. The dock's bulk-archive\n* action calls through this; the audit log gets a single\n* `conversations_bulk_archived` / `conversations_bulk_unarchived` row\n* naming every affected id, regardless of batch size.\n*\n* Storage.patch already emits a `conversations_changed` project event\n* per row — the dock invalidates `['conversations']` once per render\n* frame thanks to TanStack Query's coalescing, so N emits collapses to\n* one refetch downstream.\n*/\nasync function applyBulkArchive(projectRoot, ids, archived) {\n\tconst storage = new Storage(projectRoot);\n\tconst updated = [];\n\tconst skipped = [];\n\tfor (const id of ids) {\n\t\tconst previous = await storage.read(id);\n\t\tif (!previous || previous.archived === archived) {\n\t\t\tskipped.push(id);\n\t\t\tcontinue;\n\t\t}\n\t\tif (await storage.patch(id, { archived })) updated.push(id);\n\t\telse skipped.push(id);\n\t}\n\tif (updated.length > 0) await recordAuditEvent(projectRoot, {\n\t\tconversationId: null,\n\t\tactor: \"user\",\n\t\taction: archived ? \"conversations_bulk_archived\" : \"conversations_bulk_unarchived\",\n\t\tpayload: {\n\t\t\tids: updated,\n\t\t\tcount: updated.length\n\t\t}\n\t});\n\treturn {\n\t\tupdated,\n\t\tskipped\n\t};\n}\n//#endregion\n//#region src/editor.ts\n/**\n* Resolve the editor command. Honors (in order):\n* 1. PINAGENT_EDITOR — pinagent-specific override\n* 2. EDITOR / VISUAL — standard *nix env vars\n* 3. 'code' — VSCode CLI, the most common default\n*/\nfunction detectEditor(env) {\n\treturn env.PINAGENT_EDITOR || env.EDITOR || env.VISUAL || \"code\";\n}\n/**\n* Build the right CLI invocation for the chosen editor.\n*\n* Most modern code editors accept `-g file:line:col` (VSCode lineage).\n* JetBrains tools use `--line` and `--column` flags. Sublime takes\n* `file:line:col` without a flag. Fallback: pass just the file path.\n*/\nfunction buildCommand(editor, file, line, col) {\n\tconst name = editor.split(/[\\\\/]/).pop()?.toLowerCase() ?? editor.toLowerCase();\n\tconst locator = line != null && col != null ? `${file}:${line}:${col}` : line != null ? `${file}:${line}` : file;\n\tif ([\n\t\t\"code\",\n\t\t\"code-insiders\",\n\t\t\"cursor\",\n\t\t\"windsurf\",\n\t\t\"codium\",\n\t\t\"vscodium\"\n\t].includes(name)) return {\n\t\tcmd: editor,\n\t\targs: [\"-g\", locator]\n\t};\n\tif (name === \"zed\") return {\n\t\tcmd: editor,\n\t\targs: [locator]\n\t};\n\tif (name === \"subl\" || name === \"sublime_text\") return {\n\t\tcmd: editor,\n\t\targs: [locator]\n\t};\n\tif ([\n\t\t\"idea\",\n\t\t\"webstorm\",\n\t\t\"pycharm\",\n\t\t\"rubymine\",\n\t\t\"phpstorm\",\n\t\t\"goland\",\n\t\t\"rider\",\n\t\t\"clion\"\n\t].includes(name)) {\n\t\tconst args = [file];\n\t\tif (line != null) args.push(\"--line\", String(line));\n\t\tif (col != null) args.push(\"--column\", String(col));\n\t\treturn {\n\t\t\tcmd: editor,\n\t\t\targs\n\t\t};\n\t}\n\tif (name === \"atom\" || name === \"mate\") return {\n\t\tcmd: editor,\n\t\targs: [locator]\n\t};\n\treturn {\n\t\tcmd: editor,\n\t\targs: [file]\n\t};\n}\nasync function openInEditor(projectRoot, file, line, col) {\n\tif (file.includes(\"..\")) throw new Error(\"path traversal not allowed\");\n\tconst abs = isAbsolute(file) ? file : resolve(projectRoot, file);\n\tconst rootAbs = resolve(projectRoot);\n\tif (!abs.startsWith(rootAbs + sep) && abs !== rootAbs) throw new Error(\"path outside project root\");\n\tif (!existsSync(abs)) throw new Error(`file not found: ${file}`);\n\tconst editor = detectEditor(process.env);\n\tconst { cmd, args } = buildCommand(editor, abs, line, col);\n\tawait new Promise((resolveP, reject) => {\n\t\tlet settled = false;\n\t\tconst child = spawn(cmd, args, {\n\t\t\tdetached: true,\n\t\t\tstdio: \"ignore\"\n\t\t});\n\t\tchild.on(\"error\", (err) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\treject(err);\n\t\t});\n\t\tsetTimeout(() => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tchild.unref();\n\t\t\tresolveP();\n\t\t}, 200);\n\t});\n\treturn {\n\t\tok: true,\n\t\teditor,\n\t\tcommand: `${cmd} ${args.join(\" \")}`\n\t};\n}\n//#endregion\n//#region src/files.ts\n/**\n* File source for the browser composer's `@`-mention picker. Two modes,\n* mirroring how Claude Code's own `@` behaves:\n*\n* - **project** (default) — fuzzy-match over the project's files. Uses\n* `git ls-files` (tracked + untracked-but-not-ignored) so the list\n* respects `.gitignore` and skips `node_modules`/build noise. Falls\n* back to a bounded filesystem walk when the project isn't a git repo.\n* - **path** — when the query starts with `/` or `~`, browse the real\n* filesystem directory at that prefix. This is the \"reach anywhere on\n* the machine\" mode (e.g. an absolute path into `~/Pictures`). It's\n* safe here because the whole tool is localhost-only and the trust\n* boundary is the developer's own machine (see Invariants in CLAUDE.md).\n*\n* Both modes return the same {@link FileEntry} shape and cap their output\n* so a huge tree can't blow up the response.\n*/\nconst MAX_ENTRIES = 50;\n/** Directories never worth walking in the fs-walk fallback. */\nconst WALK_SKIP = new Set([\n\t\"node_modules\",\n\t\".git\",\n\t\".next\",\n\t\".turbo\",\n\t\"dist\",\n\t\"build\",\n\t\"coverage\",\n\t\".pinagent\"\n]);\nconst WALK_FILE_CAP = 2e4;\n/**\n* Resolve a `@`-mention query into a ranked list of files/dirs. `query`\n* is the text the user typed after `@` (may be empty for the initial\n* \"show me everything\" menu).\n*/\nasync function listProjectFiles(root, query) {\n\tconst q = query ?? \"\";\n\tif (q.startsWith(\"/\") || q.startsWith(\"~\")) return browsePath(q);\n\treturn browseProject(root, q);\n}\nasync function browseProject(root, query) {\n\tconst ranked = rankFuzzy(await gitFiles(root) ?? await walkFiles(root), query);\n\tconst truncated = ranked.length > MAX_ENTRIES;\n\treturn {\n\t\tmode: \"project\",\n\t\tentries: ranked.slice(0, MAX_ENTRIES).map((path) => toEntry(path, false)),\n\t\ttruncated\n\t};\n}\n/**\n* Project file list via git: tracked files plus untracked-but-not-ignored\n* ones (so a freshly-created file shows up). Returns null when this isn't\n* a git repo or git isn't available, so the caller can fall back.\n*/\nasync function gitFiles(root) {\n\ttry {\n\t\tconst res = await runGitCapture(root, [\n\t\t\t\"ls-files\",\n\t\t\t\"--cached\",\n\t\t\t\"--others\",\n\t\t\t\"--exclude-standard\",\n\t\t\t\"--deduplicate\"\n\t\t]);\n\t\tif (res.code !== 0) return null;\n\t\treturn res.stdout.split(\"\\n\").filter((l) => l.length > 0);\n\t} catch {\n\t\treturn null;\n\t}\n}\n/** Bounded recursive walk used when the project isn't a git repo. */\nasync function walkFiles(root) {\n\tconst out = [];\n\tconst stack = [root];\n\twhile (stack.length > 0 && out.length < WALK_FILE_CAP) {\n\t\tconst dir = stack.pop();\n\t\tif (!dir) break;\n\t\tlet entries;\n\t\ttry {\n\t\t\tentries = await readdir(dir, { withFileTypes: true });\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const ent of entries) {\n\t\t\tif (ent.name.startsWith(\".git\")) continue;\n\t\t\tif (ent.isDirectory()) {\n\t\t\t\tif (WALK_SKIP.has(ent.name)) continue;\n\t\t\t\tstack.push(join(dir, ent.name));\n\t\t\t} else if (ent.isFile()) {\n\t\t\t\tconst rel = relPosix(root, join(dir, ent.name));\n\t\t\t\tout.push(rel);\n\t\t\t\tif (out.length >= WALK_FILE_CAP) break;\n\t\t\t}\n\t\t}\n\t}\n\treturn out;\n}\nasync function browsePath(query) {\n\tconst expanded = query.startsWith(\"~\") ? join(homedir(), query.slice(1)) : query;\n\tconst endsWithSep = expanded.endsWith(\"/\") || expanded.endsWith(sep);\n\tconst dir = endsWithSep ? expanded : dirname(expanded);\n\tconst partial = endsWithSep ? \"\" : basename(expanded);\n\tif (!isAbsolute(dir) || !existsSync(dir)) return {\n\t\tmode: \"path\",\n\t\tentries: [],\n\t\ttruncated: false\n\t};\n\tlet dirents;\n\ttry {\n\t\tdirents = await readdir(dir, { withFileTypes: true });\n\t} catch {\n\t\treturn {\n\t\t\tmode: \"path\",\n\t\t\tentries: [],\n\t\t\ttruncated: false\n\t\t};\n\t}\n\tconst lower = partial.toLowerCase();\n\tconst matched = dirents.filter((d) => lower ? d.name.toLowerCase().startsWith(lower) : !d.name.startsWith(\".\")).filter((d) => d.isDirectory() || d.isFile());\n\tmatched.sort((a, b) => {\n\t\tconst ad = a.isDirectory() ? 0 : 1;\n\t\tconst bd = b.isDirectory() ? 0 : 1;\n\t\tif (ad !== bd) return ad - bd;\n\t\treturn a.name.localeCompare(b.name);\n\t});\n\tconst truncated = matched.length > MAX_ENTRIES;\n\treturn {\n\t\tmode: \"path\",\n\t\tentries: matched.slice(0, MAX_ENTRIES).map((d) => {\n\t\t\treturn {\n\t\t\t\tpath: join(dir, d.name),\n\t\t\t\tname: d.name,\n\t\t\t\tdir,\n\t\t\t\tisDir: d.isDirectory()\n\t\t\t};\n\t\t}),\n\t\ttruncated\n\t};\n}\nfunction toEntry(path, isDir) {\n\treturn {\n\t\tpath,\n\t\tname: basename(path),\n\t\tdir: dirname(path),\n\t\tisDir\n\t};\n}\nfunction relPosix(root, target) {\n\tconst rel = resolve(target).slice(resolve(root).length + 1);\n\treturn sep === \"/\" ? rel : rel.split(sep).join(\"/\");\n}\n/**\n* Subsequence fuzzy match + score, newest-friendly ordering. Empty query\n* returns the list as-is (capped by the caller). Scoring favours: matches\n* in the basename, contiguous runs, and matches right after a path\n* separator — the things that make a path \"feel\" like the right one.\n*/\nfunction rankFuzzy(paths, query) {\n\tif (!query) return paths;\n\tconst q = query.toLowerCase();\n\tconst scored = [];\n\tfor (const path of paths) {\n\t\tconst score = fuzzyScore(path.toLowerCase(), q, path);\n\t\tif (score > 0) scored.push({\n\t\t\tpath,\n\t\t\tscore\n\t\t});\n\t}\n\tscored.sort((a, b) => b.score - a.score || a.path.length - b.path.length);\n\treturn scored.map((s) => s.path);\n}\nfunction fuzzyScore(haystack, needle, original) {\n\tlet hi = 0;\n\tlet score = 0;\n\tlet prevMatch = -2;\n\tconst baseStart = original.length - basename(original).length;\n\tfor (let ni = 0; ni < needle.length; ni++) {\n\t\tconst ch = needle[ni] ?? \"\";\n\t\tconst found = haystack.indexOf(ch, hi);\n\t\tif (found === -1) return 0;\n\t\tscore += 1;\n\t\tif (found === prevMatch + 1) score += 2;\n\t\tif (found === 0 || haystack[found - 1] === \"/\") score += 3;\n\t\tif (found >= baseStart) score += 2;\n\t\tprevMatch = found;\n\t\thi = found + 1;\n\t}\n\treturn score;\n}\n//#endregion\n//#region src/git-branches.ts\n/**\n* List the repo's real git branches — base-branch candidates for the PR\n* composer. Distinct from `branches.ts`, which lists pinagent's own\n* *worktree* branches (one per conversation); this is the project's\n* actual heads + origin remotes, normalized into a flat name list.\n*\n* The composer's base-branch field stays free-text (you can target a\n* branch git doesn't know about yet); this just feeds the dropdown so\n* the common case is a pick, not a type.\n*/\n/**\n* Normalize `git for-each-ref --format=%(refname:short)` output over\n* `refs/heads refs/remotes/origin`: strip the `origin/` prefix off\n* remote branches, drop the `origin/HEAD` symref, dedupe local vs remote\n* copies of the same branch, and sort. Pure so it's unit-testable\n* without a git repo.\n*/\nfunction parseGitBranches(stdout) {\n\tconst out = /* @__PURE__ */ new Set();\n\tfor (const raw of stdout.split(\"\\n\")) {\n\t\tconst line = raw.trim();\n\t\tif (!line) continue;\n\t\tconst name = line.startsWith(\"origin/\") ? line.slice(7) : line;\n\t\tif (!name || name === \"HEAD\") continue;\n\t\tout.add(name);\n\t}\n\treturn [...out].sort();\n}\n/**\n* Local heads + origin remotes for `projectRoot`, as a flat, sorted,\n* de-duplicated name list. Returns `[]` when the git call fails (not a\n* repo, no branches) — the composer falls back to plain free-text.\n*/\nasync function listGitBranches(projectRoot) {\n\tconst result = await runGitCapture(projectRoot, [\n\t\t\"for-each-ref\",\n\t\t\"--format=%(refname:short)\",\n\t\t\"refs/heads\",\n\t\t\"refs/remotes/origin\"\n\t]);\n\tif (result.code !== 0) return [];\n\treturn parseGitBranches(result.stdout);\n}\n//#endregion\n//#region src/history.ts\n/**\n* `searchHistory` — server-side full-text search over resolved\n* conversations. Backs the dock's History route once the user types in\n* the search input.\n*\n* v1 uses SQLite LIKE with `%query%` against five columns: comment,\n* note, branch, anchor file, anchor selector. Good enough for a typical\n* project (<10k conversations); FTS5 is the natural next step once a\n* project starts feeling the LIKE scan, and the query shape here is\n* compatible with swapping in `match` against an FTS5 virtual table.\n*\n* Status filter: 'all' means any resolved conversation (worktreeState\n* landed | discarded, OR status wontfix — see status-derive in the\n* dock for the full mapping). 'landed' / 'discarded' narrow further.\n*/\nconst MAX_QUERY_LEN = 200;\nconst SNIPPET_RADIUS = 40;\nasync function searchHistory(projectRoot, opts) {\n\tconst trimmed = opts.query.trim();\n\tif (trimmed.length === 0) return [];\n\tconst query = trimmed.slice(0, MAX_QUERY_LEN);\n\tconst limit = Math.min(opts.limit ?? 50, 200);\n\tconst pattern = `%${query}%`;\n\tconst statusFilter = opts.status ?? \"all\";\n\tconst resolvedPredicates = [];\n\tif (statusFilter === \"landed\") resolvedPredicates.push(eq(conversations.worktreeState, \"landed\"));\n\telse if (statusFilter === \"discarded\") {\n\t\tconst orExpr = or(eq(conversations.worktreeState, \"discarded\"), eq(conversations.status, \"wontfix\"));\n\t\tif (orExpr) resolvedPredicates.push(orExpr);\n\t} else {\n\t\tconst orExpr = or(inArray(conversations.worktreeState, [\"landed\", \"discarded\"]), eq(conversations.status, \"wontfix\"));\n\t\tif (orExpr) resolvedPredicates.push(orExpr);\n\t}\n\tconst matchPredicate = or(like(conversations.comment, pattern), like(conversations.note, pattern), like(conversations.branch, pattern), like(widgetAnchors.file, pattern), like(widgetAnchors.selector, pattern));\n\tif (!matchPredicate) return [];\n\tconst where = and(...resolvedPredicates, matchPredicate);\n\tconst rows = await getDb(projectRoot).select().from(conversations).leftJoin(widgetAnchors, eq(conversations.id, widgetAnchors.conversationId)).where(where).limit(limit);\n\tconst lowerQuery = query.toLowerCase();\n\treturn rows.map((row) => {\n\t\tconst c = row.conversations;\n\t\tconst a = row.widget_anchors;\n\t\tconst matched = [];\n\t\tif (c.comment.toLowerCase().includes(lowerQuery)) matched.push(\"comment\");\n\t\tif (c.note?.toLowerCase().includes(lowerQuery)) matched.push(\"note\");\n\t\tif (c.branch?.toLowerCase().includes(lowerQuery)) matched.push(\"branch\");\n\t\tif (a?.file?.toLowerCase().includes(lowerQuery)) matched.push(\"anchor\");\n\t\tif (a?.selector?.toLowerCase().includes(lowerQuery)) matched.push(\"selector\");\n\t\treturn {\n\t\t\tid: c.id,\n\t\t\tcomment: c.comment,\n\t\t\tstatus: c.status,\n\t\t\tworktreeState: c.worktreeState,\n\t\t\tbranch: c.branch,\n\t\t\tfile: a?.file ?? null,\n\t\t\tline: a?.line ?? null,\n\t\t\tcol: a?.col ?? null,\n\t\t\tselector: a?.selector ?? \"\",\n\t\t\turl: a?.url ?? \"\",\n\t\t\tcreatedAt: c.createdAt.toISOString(),\n\t\t\tupdatedAt: c.updatedAt.toISOString(),\n\t\t\tresolvedAt: c.resolvedAt?.toISOString() ?? null,\n\t\t\tmatchedFields: matched,\n\t\t\tsnippet: matched.includes(\"comment\") ? snippetAround(c.comment, lowerQuery) : \"\"\n\t\t};\n\t});\n}\n/**\n* Take a comment and return ~80 chars of context around the first\n* match, with ellipses for trimmed sides. Lets the History row show\n* \"…leading text [match] trailing…\" without dumping the whole comment.\n*/\nfunction snippetAround(text, lowerNeedle) {\n\tconst idx = text.toLowerCase().indexOf(lowerNeedle);\n\tif (idx < 0) return text.slice(0, SNIPPET_RADIUS * 2);\n\tconst start = Math.max(0, idx - SNIPPET_RADIUS);\n\tconst end = Math.min(text.length, idx + lowerNeedle.length + SNIPPET_RADIUS);\n\tconst prefix = start > 0 ? \"…\" : \"\";\n\tconst suffix = end < text.length ? \"…\" : \"\";\n\treturn `${prefix}${text.slice(start, end).replace(/\\s+/g, \" \").trim()}${suffix}`;\n}\n//#endregion\n//#region src/pr-composer.ts\n/**\n* `composePullRequest` — orchestrate the multi-conversation PR flow.\n*\n* Takes a set of conversation ids the user multi-selected in the dock's\n* Changes view, bundles their commits onto a fresh compose branch,\n* pushes it, and (if a GitHub token is available) opens the PR.\n*\n* Done in an isolated temporary worktree so the developer's main\n* checkout stays untouched — the user can keep editing on their\n* working branch while the compose runs.\n*\n* On any failure during merge or push, the temp worktree + compose\n* branch are removed so the project doesn't accumulate half-built state.\n* Individual conversation worktrees are only cleaned up + marked landed\n* after the push succeeds — the PR being merged is the user's\n* responsibility, but at this point their changes are safely on the\n* remote.\n*/\nconst ComposeOptsSchema = z.object({\n\tfeedbackIds: z.array(z.string().min(1)).min(1).max(50),\n\tbranchName: z.string().min(1).max(128).regex(/^[A-Za-z0-9][A-Za-z0-9/_.-]*$/, \"invalid branch name\"),\n\ttitle: z.string().min(1).max(200),\n\tdescription: z.string().max(2e4),\n\tbaseBranch: z.string().min(1).max(128).regex(/^[A-Za-z0-9][A-Za-z0-9/_.-]*$/, \"invalid base branch\")\n});\nconst BRANCH_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9/_.-]{0,127}$/;\nasync function composePullRequest(projectRoot, opts) {\n\tif (opts.feedbackIds.length === 0) return {\n\t\tok: false,\n\t\tbranchPushed: false,\n\t\terror: \"no conversations selected\"\n\t};\n\tif (!BRANCH_NAME_RE.test(opts.branchName)) return {\n\t\tok: false,\n\t\tbranchPushed: false,\n\t\terror: \"invalid branch name (alphanumeric + ./_- only)\"\n\t};\n\tif (!await isInsideWorkTree(projectRoot)) return {\n\t\tok: false,\n\t\tbranchPushed: false,\n\t\terror: \"project root is not a git repository\"\n\t};\n\tconst storage = new Storage(projectRoot);\n\tconst recs = [];\n\tfor (const id of opts.feedbackIds) {\n\t\tconst rec = await storage.read(id);\n\t\tif (!rec) return {\n\t\t\tok: false,\n\t\t\tbranchPushed: false,\n\t\t\terror: `conversation not found: ${id}`\n\t\t};\n\t\tif (rec.worktreeState !== \"active\") return {\n\t\t\tok: false,\n\t\t\tbranchPushed: false,\n\t\t\terror: `conversation ${id} is ${rec.worktreeState}; only active conversations can be composed`\n\t\t};\n\t\tif (!rec.worktreePath || !rec.branch) return {\n\t\t\tok: false,\n\t\t\tbranchPushed: false,\n\t\t\terror: `conversation ${id} has no worktree (inline-mode submission)`\n\t\t};\n\t\tif (!existsSync(rec.worktreePath)) return {\n\t\t\tok: false,\n\t\t\tbranchPushed: false,\n\t\t\terror: `conversation ${id} worktree no longer exists at ${rec.worktreePath}`\n\t\t};\n\t\trecs.push(rec);\n\t}\n\tfor (const rec of recs) {\n\t\tconst wt = rec.worktreePath;\n\t\tconst status = await runGitCapture(wt, [\"status\", \"--porcelain\"]);\n\t\tif (status.code !== 0) return {\n\t\t\tok: false,\n\t\t\tbranchPushed: false,\n\t\t\terror: `git status failed in ${rec.id} worktree: ${status.stderr.trim()}`\n\t\t};\n\t\tif (!status.stdout.trim()) continue;\n\t\tconst add = await runGitCapture(wt, [\"add\", \"-A\"]);\n\t\tif (add.code !== 0) return {\n\t\t\tok: false,\n\t\t\tbranchPushed: false,\n\t\t\terror: `git add failed in ${rec.id}: ${add.stderr.trim()}`\n\t\t};\n\t\tconst subject = (rec.comment.split(/\\r?\\n/)[0] ?? \"\").trim();\n\t\tconst commit = await runGitCapture(wt, [\n\t\t\t\"commit\",\n\t\t\t\"-m\",\n\t\t\t[\n\t\t\t\t`pinagent: ${subject.length > 70 ? `${subject.slice(0, 67)}…` : subject || \"agent edit\"}`,\n\t\t\t\t\"\",\n\t\t\t\t`Feedback: ${rec.id}`,\n\t\t\t\t\"\"\n\t\t\t].join(\"\\n\")\n\t\t]);\n\t\tif (commit.code !== 0 && !/nothing to commit/.test(`${commit.stdout}\\n${commit.stderr}`)) return {\n\t\t\tok: false,\n\t\t\tbranchPushed: false,\n\t\t\terror: `git commit failed in ${rec.id}: ${commit.stderr.trim() || commit.stdout.trim()}`\n\t\t};\n\t}\n\tconst safeName = opts.branchName.replace(/[^A-Za-z0-9_.-]+/g, \"_\");\n\tconst composeDir = join(projectRoot, \".pinagent\", \"compose\");\n\tawait mkdir(composeDir, { recursive: true });\n\tconst composePath = join(composeDir, safeName);\n\tawait rm(composePath, {\n\t\trecursive: true,\n\t\tforce: true\n\t}).catch(() => {});\n\tawait runGitCapture(projectRoot, [\"worktree\", \"prune\"]);\n\tawait runGitCapture(projectRoot, [\n\t\t\"branch\",\n\t\t\"-D\",\n\t\topts.branchName\n\t]).catch(() => {});\n\tconst wtAdd = await runGitCapture(projectRoot, [\n\t\t\"worktree\",\n\t\t\"add\",\n\t\t\"-b\",\n\t\topts.branchName,\n\t\tcomposePath,\n\t\topts.baseBranch\n\t]);\n\tif (wtAdd.code !== 0) return {\n\t\tok: false,\n\t\tbranchPushed: false,\n\t\terror: `worktree add failed (base=${opts.baseBranch}): ${wtAdd.stderr.trim()}`\n\t};\n\tconst cleanupCompose = async () => {\n\t\tawait runGitCapture(projectRoot, [\n\t\t\t\"worktree\",\n\t\t\t\"remove\",\n\t\t\t\"--force\",\n\t\t\tcomposePath\n\t\t]);\n\t\tawait runGitCapture(projectRoot, [\"worktree\", \"prune\"]);\n\t\tawait runGitCapture(projectRoot, [\n\t\t\t\"branch\",\n\t\t\t\"-D\",\n\t\t\topts.branchName\n\t\t]);\n\t};\n\tfor (const rec of recs) if ((await runGitCapture(composePath, [\n\t\t\"merge\",\n\t\t\"--no-ff\",\n\t\t\"--no-edit\",\n\t\trec.branch\n\t])).code !== 0) {\n\t\tconst files = (await runGitCapture(composePath, [\n\t\t\t\"diff\",\n\t\t\t\"--name-only\",\n\t\t\t\"--diff-filter=U\"\n\t\t])).stdout.split(\"\\n\").map((s) => s.trim()).filter(Boolean);\n\t\tawait runGitCapture(composePath, [\"merge\", \"--abort\"]);\n\t\tawait cleanupCompose();\n\t\treturn {\n\t\t\tok: false,\n\t\t\tbranchPushed: false,\n\t\t\terror: `merge conflict integrating ${rec.id} (${rec.branch})`,\n\t\t\tconflicts: {\n\t\t\t\tfeedbackId: rec.id,\n\t\t\t\tfiles\n\t\t\t}\n\t\t};\n\t}\n\tconst shots = recs.map((rec) => ({\n\t\tid: rec.id,\n\t\tscreenshot: rec.screenshot,\n\t\tcaption: (rec.comment.split(/\\r?\\n/).find((l) => l.trim())?.trim() ?? \"\") || void 0\n\t}));\n\tconst { markdown: screenshotMd } = await stageScreenshotAssets(projectRoot, composePath, opts.branchName, shots);\n\tconst push = await pushBranch(projectRoot, opts.branchName);\n\tif (!push.ok) {\n\t\tawait cleanupCompose();\n\t\treturn {\n\t\t\tok: false,\n\t\t\tbranchPushed: false,\n\t\t\terror: push.error ?? \"git push failed\"\n\t\t};\n\t}\n\tfor (const rec of recs) {\n\t\tif (rec.worktreePath && rec.branch) {\n\t\t\tawait runGitCapture(projectRoot, [\n\t\t\t\t\"worktree\",\n\t\t\t\t\"remove\",\n\t\t\t\t\"--force\",\n\t\t\t\trec.worktreePath\n\t\t\t]);\n\t\t\tawait runGitCapture(projectRoot, [\"worktree\", \"prune\"]);\n\t\t\tawait runGitCapture(projectRoot, [\n\t\t\t\t\"branch\",\n\t\t\t\t\"-D\",\n\t\t\t\trec.branch\n\t\t\t]);\n\t\t}\n\t\tawait storage.patch(rec.id, { worktreeState: \"landed\" }).catch(() => {});\n\t\tawait recordAuditEvent(projectRoot, {\n\t\t\tconversationId: rec.id,\n\t\t\tactor: \"user\",\n\t\t\taction: \"conversation_landed\",\n\t\t\tpayload: {\n\t\t\t\tvia: \"pr\",\n\t\t\t\tbranch: rec.branch ?? opts.branchName,\n\t\t\t\tcomposeBranch: opts.branchName\n\t\t\t}\n\t\t});\n\t}\n\tawait rm(composePath, {\n\t\trecursive: true,\n\t\tforce: true\n\t}).catch(() => {});\n\tawait runGitCapture(projectRoot, [\"worktree\", \"prune\"]);\n\treturn openPrOnGitHub(projectRoot, {\n\t\tbranchName: opts.branchName,\n\t\tbaseBranch: opts.baseBranch,\n\t\ttitle: opts.title,\n\t\tbody: opts.description + screenshotMd,\n\t\tconversationIds: opts.feedbackIds\n\t});\n}\n//#endregion\n//#region src/worktree-ttl.ts\n/**\n* Phase H — orphan-worktree TTL sweep.\n*\n* On agent-runner boot, scan SQLite for conversations whose worktree has been\n* sitting in `worktreeState='active'` past the configured TTL. Add each one\n* to an in-memory set; next time the widget subscribes to that feedback,\n* the WS server overrides the initial `worktree_state` emission from\n* `active` to `ttl_warning` so the UI nudges the user to land or discard.\n*\n* We do NOT auto-discard: the user might genuinely want a multi-week\n* worktree, and silent data loss is the worst failure mode for a tool\n* whose pitch is \"trust what the agents did\". TTL is advisory only.\n*\n* Env:\n* PINAGENT_WORKTREE_TTL_DAYS (default 7) — days since last update\n* before a worktree is flagged. Set to 0 to disable the sweep.\n*/\nconst DEFAULT_TTL_DAYS = 7;\nconst TTL_SYMBOL = Symbol.for(\"pinagent.worktree-ttl.flagged\");\nconst flagged = globalThis[TTL_SYMBOL] ?? /* @__PURE__ */ new Set();\nglobalThis[TTL_SYMBOL] = flagged;\nfunction ttlDays(env) {\n\tconst raw = env.PINAGENT_WORKTREE_TTL_DAYS;\n\tif (raw === void 0 || raw === \"\") return DEFAULT_TTL_DAYS;\n\tconst n = Number(raw);\n\tif (!Number.isFinite(n) || n < 0) return DEFAULT_TTL_DAYS;\n\treturn n;\n}\n/**\n* One-shot scan at startup. Idempotent — re-running just refreshes the\n* flag set. Best-effort; swallows DB errors so an agent-runner boot is\n* never blocked by a TTL sweep failure.\n*/\nasync function sweepStaleWorktrees(projectRoot) {\n\tconst days = ttlDays(process.env);\n\tif (days === 0) {\n\t\tflagged.clear();\n\t\treturn;\n\t}\n\ttry {\n\t\tconst cutoff = /* @__PURE__ */ new Date(Date.now() - days * 24 * 60 * 60 * 1e3);\n\t\tconst rows = await getDb(projectRoot).select({ id: conversations.id }).from(conversations).where(and(eq(conversations.worktreeState, \"active\"), lt(conversations.updatedAt, cutoff)));\n\t\tflagged.clear();\n\t\tfor (const r of rows) flagged.add(r.id);\n\t} catch {}\n}\n/**\n* True iff the most recent sweep flagged this conversation. Returns false\n* after the user has taken an action (land/discard) and `clearWarning`\n* was called.\n*/\nfunction isStale(feedbackId) {\n\treturn flagged.has(feedbackId);\n}\n/**\n* Drop a feedback from the flagged set. Called from the WS server's\n* `land_request` / `discard_request` handlers so the warning doesn't\n* reappear for repeat subscribes after the user has acted.\n*/\nfunction clearWarning(feedbackId) {\n\tflagged.delete(feedbackId);\n}\n//#endregion\n//#region src/ws-server.ts\nconst DEFAULT_PORT = 53636;\nconst WS_PATH = \"/__pinagent/ws\";\nconst PORT_FALLBACK_RANGE = 10;\nconst SINGLETON_KEY = Symbol.for(\"pinagent.ws-server\");\n/**\n* Attempt to bind a WebSocketServer on `port`. Resolves to the bound\n* server, or `null` if the port is in use. Other errors propagate.\n*/\nfunction tryBind(port) {\n\treturn new Promise((resolve, reject) => {\n\t\tconst wss = new WebSocketServer({\n\t\t\tport,\n\t\t\tpath: WS_PATH\n\t\t});\n\t\tconst onListening = () => {\n\t\t\twss.off(\"error\", onError);\n\t\t\tresolve(wss);\n\t\t};\n\t\tconst onError = (err) => {\n\t\t\twss.off(\"listening\", onListening);\n\t\t\tif (err.code === \"EADDRINUSE\") {\n\t\t\t\twss.close();\n\t\t\t\tresolve(null);\n\t\t\t} else reject(err);\n\t\t};\n\t\twss.once(\"listening\", onListening);\n\t\twss.once(\"error\", onError);\n\t});\n}\n/**\n* Start (or return the existing) WebSocket server for this dev process.\n*\n* Next 16 / Vite HMR can load the config more than once (workers, HMR) — the\n* singleton keyed off a global Symbol prevents us from binding the same port\n* twice. The cached entry is a Promise during in-flight bind so concurrent\n* callers (parallel Turbopack re-evaluations) share one bind attempt.\n*\n* If `PINAGENT_WS_PORT` is already taken — typically by a stale dev server\n* from another pinagent project on this machine — we walk up to\n* `PORT_FALLBACK_RANGE` ports forward to find a free one. We then mutate\n* `process.env.PINAGENT_WS_PORT` so the route handler's widget-bundle\n* prelude (next-plugin/route.ts) reports the actually-bound port, not the\n* requested one. Without this, the widget would connect to the stale\n* stranger and silently see no events.\n*\n* We run on a dedicated port rather than hijacking Next's underlying http\n* server because Next App Router routes can't perform an upgrade. The widget\n* learns the port from a prelude injected into /__pinagent/widget.js by the\n* route handler (see `widget-config.ts`).\n*/\nasync function startWsServer() {\n\tconst g = globalThis;\n\tconst existing = g[SINGLETON_KEY];\n\tif (existing) return existing;\n\tconst pending = (async () => {\n\t\tconst envPort = process.env.PINAGENT_WS_PORT;\n\t\tconst requested = envPort ? Number(envPort) : DEFAULT_PORT;\n\t\tif (!Number.isFinite(requested) || requested <= 0 || requested > 65535) throw new Error(`[pinagent] invalid PINAGENT_WS_PORT: ${envPort}`);\n\t\tlet wss = null;\n\t\tlet boundPort = requested;\n\t\tfor (let i = 0; i < PORT_FALLBACK_RANGE; i++) {\n\t\t\tconst candidate = requested + i;\n\t\t\twss = await tryBind(candidate);\n\t\t\tif (wss) {\n\t\t\t\tboundPort = candidate;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconsole.log(`[pinagent] port ${candidate} in use (likely a stale dev server from another project); trying ${candidate + 1}`);\n\t\t}\n\t\tif (!wss) throw new Error(`[pinagent] no free WS port in range ${requested}..${requested + PORT_FALLBACK_RANGE - 1}`);\n\t\tprocess.env.PINAGENT_WS_PORT = String(boundPort);\n\t\tconsole.log(`[pinagent] WebSocket server listening on ws://127.0.0.1:${boundPort}${WS_PATH}`);\n\t\twss.on(\"connection\", (socket) => {\n\t\t\tattachConnection(socket);\n\t\t});\n\t\twss.on(\"error\", (err) => {\n\t\t\tconsole.error(\"[pinagent] WebSocket server error:\", err);\n\t\t});\n\t\tconst handle = {\n\t\t\tport: boundPort,\n\t\t\twss,\n\t\t\thttpServer: null\n\t\t};\n\t\tg[SINGLETON_KEY] = handle;\n\t\tprocess.once(\"SIGINT\", () => wss.close());\n\t\tprocess.once(\"SIGTERM\", () => wss.close());\n\t\tsweepStaleWorktrees(projectRoot());\n\t\tensureProjectListener();\n\t\tensureCrossProcessProjectPoller();\n\t\tmaybeStartRelayClient();\n\t\treturn handle;\n\t})();\n\tg[SINGLETON_KEY] = pending;\n\ttry {\n\t\treturn await pending;\n\t} catch (err) {\n\t\tif (g[SINGLETON_KEY] === pending) delete g[SINGLETON_KEY];\n\t\tthrow err;\n\t}\n}\n/**\n* Build a `noServer` WebSocket endpoint to hand to a host that owns its own\n* HTTP server and routes the `upgrade` event by pathname — notably Metro's\n* `config.server.websocketEndpoints` (React Native / Expo).\n*\n* Unlike {@link startWsServer}, this binds no port: the caller's dev server\n* (Metro) already listens, performs the HTTP upgrade, and dispatches matching\n* requests here via `handleUpgrade`. That means RN streaming rides the *same*\n* host:port the widget already talks to for `POST /__pinagent/feedback`, so a\n* physical device needs no second port and no port discovery.\n*\n* Each accepted socket is wired to the same {@link attachConnection} the web\n* path uses — identical wire protocol, bus subscription, and worktree\n* controls. We also start the project-event fan-out and relay (idempotent,\n* singleton-guarded) so worktree Land/Discard and cloud mode behave the same.\n*/\nfunction createPinagentWsEndpoint() {\n\tconst wss = new WebSocketServer({ noServer: true });\n\twss.on(\"connection\", (socket) => {\n\t\tattachConnection(socket);\n\t});\n\tsweepStaleWorktrees(projectRoot());\n\tensureProjectListener();\n\tensureCrossProcessProjectPoller();\n\tmaybeStartRelayClient();\n\treturn wss;\n}\n/**\n* Worktree-state fan-out: keyed by feedbackId, value is the set of\n* sockets currently subscribed. Lives separately from the\n* `event-bus` because worktree state is a property of the conversation\n* row (durable in SQLite) rather than an agent-run event — and changes\n* to it can happen long after the agent run's bus has been finished\n* and evicted. Survives module re-eval via globalThis pinning.\n*/\nconst WT_SUBS_SYMBOL = Symbol.for(\"pinagent.ws.worktreeSubs\");\nconst worktreeSubs = globalThis[WT_SUBS_SYMBOL] ?? /* @__PURE__ */ new Map();\nglobalThis[WT_SUBS_SYMBOL] = worktreeSubs;\nfunction addWorktreeSub(feedbackId, socket) {\n\tlet set = worktreeSubs.get(feedbackId);\n\tif (!set) {\n\t\tset = /* @__PURE__ */ new Set();\n\t\tworktreeSubs.set(feedbackId, set);\n\t}\n\tset.add(socket);\n}\nfunction removeWorktreeSub(feedbackId, socket) {\n\tconst set = worktreeSubs.get(feedbackId);\n\tif (!set) return;\n\tset.delete(socket);\n\tif (set.size === 0) worktreeSubs.delete(feedbackId);\n}\nfunction broadcastWorktreeState(feedbackId, payload) {\n\tconst set = worktreeSubs.get(feedbackId);\n\tif (!set) return;\n\tconst msg = {\n\t\ttype: \"worktree_state\",\n\t\tfeedbackId,\n\t\t...payload\n\t};\n\tfor (const sock of set) send(sock, msg);\n}\n/**\n* Project-wide subscribers. Sockets self-register via `subscribe_project`\n* and receive `project_event` messages whenever Storage emits a change\n* (see project-events.ts). Lives separately from `worktreeSubs` because\n* it's not keyed by feedbackId — every project subscriber gets every\n* project event.\n*\n* Pinned via globalThis so Next 16 / HMR re-evaluation doesn't lose\n* subscribers across module reloads — same approach as worktreeSubs.\n*/\nconst PROJECT_SUBS_SYMBOL = Symbol.for(\"pinagent.ws.projectSubs\");\nconst projectSubs = globalThis[PROJECT_SUBS_SYMBOL] ?? /* @__PURE__ */ new Set();\nglobalThis[PROJECT_SUBS_SYMBOL] = projectSubs;\n/**\n* Singleton-guarded listener registration. `onProjectChange` returns an\n* unsubscribe handle; we keep the handle around the same global slot so\n* a duplicate `startWsServer` call doesn't stack listeners (which would\n* cause each event to fan out twice, then three times, etc).\n*/\nconst PROJECT_LISTENER_SYMBOL = Symbol.for(\"pinagent.ws.projectListener\");\nfunction ensureProjectListener() {\n\tconst slot = globalThis;\n\tif (slot[PROJECT_LISTENER_SYMBOL]) return;\n\tslot[PROJECT_LISTENER_SYMBOL] = onProjectChange((event) => fanoutProjectEvent(event));\n}\n/**\n* Watches `conversations.updatedAt` so writes from OTHER processes\n* (notably the MCP server's `resolve_feedback`, which runs as a child\n* Node process under the SDK and never touches our in-process\n* `emitProjectChange`) still trigger a dock refresh.\n*\n* Mirrors the polling pattern in `bus.ts` (per-conversation events).\n* Latency upper bound is one poll interval; the dock's TanStack Query\n* invalidation is idempotent, so the worst case if an in-process event\n* also fires is one extra refetch ~`POLL_MS` later — harmless.\n*\n* The initial watermark is seeded asynchronously; until the seed\n* resolves, the very first poll might fire a redundant\n* `conversations_changed`. That's acceptable: project subscribers\n* connect AFTER startWsServer, so they normally won't see it; if they\n* do, it's one wasted refetch on first connect.\n*/\nconst PROJECT_POLLER_SYMBOL = Symbol.for(\"pinagent.ws.projectPoller\");\nconst PROJECT_POLL_MS = 250;\nfunction ensureCrossProcessProjectPoller() {\n\tconst slot = globalThis;\n\tif (slot[PROJECT_POLLER_SYMBOL]) return;\n\tlet lastSeenMs = 0;\n\tlet polling = false;\n\t(async () => {\n\t\ttry {\n\t\t\tconst ms = (await getDb(projectRoot()).select({ max: sql`MAX(${conversations.updatedAt})` }).from(conversations))[0]?.max ?? null;\n\t\t\tif (ms !== null) lastSeenMs = Number(ms);\n\t\t} catch {}\n\t})();\n\tconst interval = setInterval(() => {\n\t\tif (polling) return;\n\t\tpolling = true;\n\t\t(async () => {\n\t\t\ttry {\n\t\t\t\tconst ms = (await getDb(projectRoot()).select({ max: sql`MAX(${conversations.updatedAt})` }).from(conversations))[0]?.max ?? null;\n\t\t\t\tif (ms !== null && Number(ms) > lastSeenMs) {\n\t\t\t\t\tlastSeenMs = Number(ms);\n\t\t\t\t\tfanoutProjectEvent({ type: \"conversations_changed\" });\n\t\t\t\t}\n\t\t\t} catch {} finally {\n\t\t\t\tpolling = false;\n\t\t\t}\n\t\t})();\n\t}, PROJECT_POLL_MS);\n\tslot[PROJECT_POLLER_SYMBOL] = () => clearInterval(interval);\n}\nfunction fanoutProjectEvent(event) {\n\tconst msg = {\n\t\ttype: \"project_event\",\n\t\tevent\n\t};\n\tfor (const sock of projectSubs) send(sock, msg);\n}\n/**\n* Connected VSCode-extension sockets, mapped to their reported version.\n* An entry exists for every socket that sent `extension_hello`. The dock\n* consults presence (size > 0) to decide whether to nudge the user to\n* install the editor bridge.\n*\n* Pinned to globalThis for the same Next-16 / HMR-survival reason as the\n* subscriber sets above — a module re-eval mustn't forget that an\n* extension is live and start telling docks it's missing.\n*/\nconst EXTENSION_SOCKETS_SYMBOL = Symbol.for(\"pinagent.ws.extensionSockets\");\nconst extensionSockets = globalThis[EXTENSION_SOCKETS_SYMBOL] ?? /* @__PURE__ */ new Map();\nglobalThis[EXTENSION_SOCKETS_SYMBOL] = extensionSockets;\n/**\n* Snapshot the current presence state. `version` is the last-registered\n* extension's version (newest connection wins) — good enough for the\n* single-editor common case; multi-window users just see one of them.\n*/\nfunction extensionStatusMessage() {\n\tlet version;\n\tfor (const v of extensionSockets.values()) if (v) version = v;\n\tconst msg = {\n\t\ttype: \"extension_status\",\n\t\tpresent: extensionSockets.size > 0\n\t};\n\tif (version) msg.version = version;\n\treturn msg;\n}\n/** Push the current presence snapshot to every project subscriber. */\nfunction broadcastExtensionStatus() {\n\tconst msg = extensionStatusMessage();\n\tfor (const sock of projectSubs) send(sock, msg);\n}\nfunction projectRoot() {\n\treturn process.env.PINAGENT_PROJECT_ROOT ?? process.cwd();\n}\nfunction logPathFor(root, feedbackId) {\n\treturn join(root, \".pinagent\", \"logs\", `${feedbackId}.md`);\n}\nconst PING_INTERVAL_MS = 3e4;\nfunction attachConnection(socket) {\n\tconst state = {\n\t\tsubscriptions: /* @__PURE__ */ new Map(),\n\t\tprojectSubscribed: false,\n\t\talive: true\n\t};\n\tconst ping = setInterval(() => {\n\t\tif (!state.alive) {\n\t\t\tsocket.terminate();\n\t\t\treturn;\n\t\t}\n\t\tstate.alive = false;\n\t\ttry {\n\t\t\tsocket.ping();\n\t\t} catch {}\n\t}, PING_INTERVAL_MS);\n\tsocket.on(\"pong\", () => {\n\t\tstate.alive = true;\n\t});\n\tsocket.on(\"message\", (raw) => {\n\t\tlet parsed;\n\t\ttry {\n\t\t\tparsed = JSON.parse(raw.toString(\"utf8\"));\n\t\t} catch {\n\t\t\tsendError(socket, void 0, \"invalid JSON\");\n\t\t\treturn;\n\t\t}\n\t\tconst validated = ClientMessageSchema.safeParse(parsed);\n\t\tif (!validated.success) {\n\t\t\tsendError(socket, void 0, `invalid message: ${validated.error.message}`);\n\t\t\treturn;\n\t\t}\n\t\thandleClientMessage(socket, state, validated.data);\n\t});\n\tsocket.on(\"close\", () => {\n\t\tclearInterval(ping);\n\t\tfor (const [feedbackId, unsub] of state.subscriptions.entries()) {\n\t\t\tunsub();\n\t\t\tremoveWorktreeSub(feedbackId, socket);\n\t\t}\n\t\tstate.subscriptions.clear();\n\t\tif (state.projectSubscribed) {\n\t\t\tprojectSubs.delete(socket);\n\t\t\tstate.projectSubscribed = false;\n\t\t}\n\t\tif (extensionSockets.delete(socket)) broadcastExtensionStatus();\n\t});\n\tsocket.on(\"error\", () => {});\n}\nasync function handleClientMessage(socket, state, msg) {\n\tswitch (msg.type) {\n\t\tcase \"subscribe\": {\n\t\t\tif (state.subscriptions.has(msg.feedbackId)) return;\n\t\t\tconst unsub = getOrCreateBus(msg.feedbackId).subscribe({\n\t\t\t\tonEvent(event) {\n\t\t\t\t\tsend(socket, {\n\t\t\t\t\t\ttype: \"event\",\n\t\t\t\t\t\tfeedbackId: msg.feedbackId,\n\t\t\t\t\t\tevent\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tonClose() {\n\t\t\t\t\tsend(socket, {\n\t\t\t\t\t\ttype: \"done\",\n\t\t\t\t\t\tfeedbackId: msg.feedbackId\n\t\t\t\t\t});\n\t\t\t\t\tstate.subscriptions.delete(msg.feedbackId);\n\t\t\t\t\tremoveWorktreeSub(msg.feedbackId, socket);\n\t\t\t\t}\n\t\t\t});\n\t\t\tstate.subscriptions.set(msg.feedbackId, unsub);\n\t\t\taddWorktreeSub(msg.feedbackId, socket);\n\t\t\temitCurrentWorktreeState(socket, msg.feedbackId);\n\t\t\treturn;\n\t\t}\n\t\tcase \"unsubscribe\": {\n\t\t\tconst unsub = state.subscriptions.get(msg.feedbackId);\n\t\t\tif (unsub) {\n\t\t\t\tunsub();\n\t\t\t\tstate.subscriptions.delete(msg.feedbackId);\n\t\t\t}\n\t\t\tremoveWorktreeSub(msg.feedbackId, socket);\n\t\t\treturn;\n\t\t}\n\t\tcase \"ask_response\":\n\t\t\tif (!resolveAsk(msg.askId, msg.answer)) sendError(socket, void 0, `no pending ask ${msg.askId}`);\n\t\t\treturn;\n\t\tcase \"user_message\":\n\t\t\ttry {\n\t\t\t\tawait runFollowUpTurn(msg.feedbackId, msg.content);\n\t\t\t} catch (err) {\n\t\t\t\tsendError(socket, msg.feedbackId, err instanceof Error ? err.message : String(err));\n\t\t\t}\n\t\t\treturn;\n\t\tcase \"interrupt\":\n\t\t\tif (!await interruptRun(msg.feedbackId)) sendError(socket, msg.feedbackId, \"no in-flight run to interrupt\");\n\t\t\treturn;\n\t\tcase \"land_request\": {\n\t\t\tconst root = projectRoot();\n\t\t\tconst logPath = logPathFor(root, msg.feedbackId);\n\t\t\tclearWarning(msg.feedbackId);\n\t\t\tbroadcastWorktreeState(msg.feedbackId, { state: \"landing\" });\n\t\t\tconst result = await enqueue(root, () => mergeWorktree(root, msg.feedbackId, logPath));\n\t\t\tif (result.ok) broadcastWorktreeState(msg.feedbackId, {\n\t\t\t\tstate: \"landed\",\n\t\t\t\t...result.commitSha ? { commitSha: result.commitSha } : {}\n\t\t\t});\n\t\t\telse if (result.conflicts && result.conflicts.length > 0) broadcastWorktreeState(msg.feedbackId, {\n\t\t\t\tstate: \"conflict\",\n\t\t\t\tconflicts: result.conflicts\n\t\t\t});\n\t\t\telse broadcastWorktreeState(msg.feedbackId, {\n\t\t\t\tstate: \"active\",\n\t\t\t\t...result.error ? { message: result.error } : {}\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tcase \"discard_request\": {\n\t\t\tconst root = projectRoot();\n\t\t\tconst logPath = logPathFor(root, msg.feedbackId);\n\t\t\tclearWarning(msg.feedbackId);\n\t\t\tbroadcastWorktreeState(msg.feedbackId, { state: \"discarding\" });\n\t\t\ttry {\n\t\t\t\tawait enqueue(root, () => discardWorktree(root, msg.feedbackId, logPath));\n\t\t\t\tbroadcastWorktreeState(msg.feedbackId, { state: \"discarded\" });\n\t\t\t} catch (err) {\n\t\t\t\tbroadcastWorktreeState(msg.feedbackId, {\n\t\t\t\t\tstate: \"active\",\n\t\t\t\t\tmessage: err instanceof Error ? err.message : String(err)\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tcase \"reopen_request\": {\n\t\t\tconst root = projectRoot();\n\t\t\tconst logPath = logPathFor(root, msg.feedbackId);\n\t\t\tconst result = await enqueue(root, () => reopenConversation(root, msg.feedbackId, logPath));\n\t\t\tif (result.ok) broadcastWorktreeState(msg.feedbackId, { state: \"none\" });\n\t\t\telse sendError(socket, msg.feedbackId, result.error);\n\t\t\treturn;\n\t\t}\n\t\tcase \"subscribe_project\":\n\t\t\tif (state.projectSubscribed) return;\n\t\t\tprojectSubs.add(socket);\n\t\t\tstate.projectSubscribed = true;\n\t\t\tsend(socket, extensionStatusMessage());\n\t\t\treturn;\n\t\tcase \"unsubscribe_project\":\n\t\t\tif (!state.projectSubscribed) return;\n\t\t\tprojectSubs.delete(socket);\n\t\t\tstate.projectSubscribed = false;\n\t\t\treturn;\n\t\tcase \"extension_hello\":\n\t\t\textensionSockets.set(socket, msg.version);\n\t\t\tbroadcastExtensionStatus();\n\t\t\treturn;\n\t\tcase \"set_branch_routing\": {\n\t\t\tconst patch = { allowedBranchPatterns: msg.allowedBranchPatterns };\n\t\t\tif (msg.defaultBaseBranch !== null) patch.baseBranch = msg.defaultBaseBranch;\n\t\t\ttry {\n\t\t\t\tawait new SettingsStore(projectRoot()).patch(patch);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[pinagent] failed to apply pushed branch-routing policy:\", err);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tcase \"query_extension\":\n\t\t\tsend(socket, extensionStatusMessage());\n\t\t\treturn;\n\t\tcase \"ping\":\n\t\t\tsend(socket, { type: \"pong\" });\n\t\t\treturn;\n\t}\n}\nasync function emitCurrentWorktreeState(socket, feedbackId) {\n\ttry {\n\t\tconst rec = await new Storage(projectRoot()).read(feedbackId);\n\t\tif (!rec) return;\n\t\tconst state = rec.worktreeState === \"active\" && isStale(feedbackId) ? \"ttl_warning\" : rec.worktreeState;\n\t\tconst payload = {\n\t\t\ttype: \"worktree_state\",\n\t\t\tfeedbackId,\n\t\t\tstate\n\t\t};\n\t\tif (rec.commitSha) payload.commitSha = rec.commitSha;\n\t\tif (rec.worktreePath && (state === \"active\" || state === \"ttl_warning\")) {\n\t\t\tconst n = await countWorktreeChanges(rec.worktreePath);\n\t\t\tif (n !== null) payload.changesCount = n;\n\t\t}\n\t\tsend(socket, payload);\n\t} catch {}\n}\nfunction send(socket, message) {\n\tif (socket.readyState !== socket.OPEN) return;\n\ttry {\n\t\tsocket.send(JSON.stringify(message));\n\t} catch {}\n}\nfunction sendError(socket, feedbackId, message) {\n\tsend(socket, feedbackId ? {\n\t\ttype: \"error\",\n\t\tfeedbackId,\n\t\tmessage\n\t} : {\n\t\ttype: \"error\",\n\t\tmessage\n\t});\n}\n//#endregion\n//#region src/relay-client.ts\nconst DEFAULT_MIN_BACKOFF_MS = 1e3;\nconst DEFAULT_MAX_BACKOFF_MS = 3e4;\nconst DEVICE_PATH = \"/__pinagent/device\";\n/** Build the relay's device-endpoint URL for a session. */\nfunction buildDeviceUrl(origin, sessionId) {\n\treturn `${origin.replace(/\\/+$/, \"\")}${DEVICE_PATH}?session=${encodeURIComponent(sessionId)}`;\n}\n/**\n* Full-jitter exponential backoff: a random delay in `[exp/2, exp]` where\n* `exp = min(max, min * 2^attempt)`. Jitter avoids a thundering herd of\n* dev machines all reconnecting in lockstep after a relay blip.\n*/\nfunction nextBackoff(attempt, opts) {\n\tconst exp = Math.min(opts.max, opts.min * 2 ** attempt);\n\treturn Math.round(exp / 2 + Math.random() * (exp / 2));\n}\nfunction defaultConnect(url, token) {\n\treturn new WebSocket(url, { headers: { Authorization: `Bearer ${token}` } });\n}\n/**\n* Open and maintain the outbound device connection, reconnecting with\n* backoff on any drop. Returns a handle whose `close()` stops reconnecting\n* and tears down the current socket.\n*/\nfunction startRelayClient(opts) {\n\tconst min = opts.minBackoffMs ?? DEFAULT_MIN_BACKOFF_MS;\n\tconst max = opts.maxBackoffMs ?? DEFAULT_MAX_BACKOFF_MS;\n\tconst connect = opts.connect ?? defaultConnect;\n\tconst attach = opts.attach ?? attachConnection;\n\tconst schedule = opts.schedule ?? ((fn, ms) => void setTimeout(fn, ms));\n\tconst log = opts.log ?? ((msg) => console.log(`[pinagent] ${msg}`));\n\tconst deviceUrl = buildDeviceUrl(opts.url, opts.sessionId);\n\tlet stopped = false;\n\tlet attempt = 0;\n\tlet socket = null;\n\tconst open = () => {\n\t\tif (stopped) return;\n\t\tconst ws = connect(deviceUrl, opts.token);\n\t\tsocket = ws;\n\t\tws.on(\"open\", () => {\n\t\t\tattempt = 0;\n\t\t\tlog(`relay connected (${deviceUrl})`);\n\t\t\tattach(ws);\n\t\t});\n\t\tws.on(\"close\", () => {\n\t\t\tif (stopped) return;\n\t\t\tconst delay = nextBackoff(attempt++, {\n\t\t\t\tmin,\n\t\t\t\tmax\n\t\t\t});\n\t\t\tlog(`relay disconnected; reconnecting in ${delay}ms`);\n\t\t\tschedule(open, delay);\n\t\t});\n\t\tws.on(\"error\", () => {});\n\t};\n\topen();\n\treturn { close() {\n\t\tstopped = true;\n\t\ttry {\n\t\t\tsocket?.close();\n\t\t} catch {}\n\t} };\n}\n/**\n* Derive a stable session id from the project root when one isn't supplied\n* via env. Stable across restarts (so a machine reconnects to its own\n* Durable Object) and opaque (doesn't leak the filesystem path).\n*/\nfunction defaultSessionId() {\n\tconst root = process.env.PINAGENT_PROJECT_ROOT ?? process.cwd();\n\treturn createHash(\"sha256\").update(root).digest(\"hex\").slice(0, 16);\n}\nconst RELAY_CLIENT_SYMBOL = Symbol.for(\"pinagent.relayClient\");\n/**\n* Start the dial-out client iff cloud mode is configured. Reads:\n* - `PINAGENT_RELAY_URL` (required to enable; e.g. wss://relay.pinagent.dev)\n* - `PINAGENT_RELAY_TOKEN` (required; bearer token for the relay — must be a\n* `device`-scoped session token; the relay rejects a `client` token on the\n* device endpoint)\n* - `PINAGENT_RELAY_SESSION` (optional; defaults to a hash of the project root)\n*\n* Singleton-guarded via globalThis for the same Next-16 / HMR re-eval\n* reason the ws-server subscriber sets are pinned — a module reload mustn't\n* open a second device connection.\n*/\nfunction maybeStartRelayClient() {\n\tconst url = process.env.PINAGENT_RELAY_URL;\n\tconst token = process.env.PINAGENT_RELAY_TOKEN;\n\tif (!url || !token) return null;\n\tconst g = globalThis;\n\tconst existing = g[RELAY_CLIENT_SYMBOL];\n\tif (existing) return existing;\n\tconst handle = startRelayClient({\n\t\turl,\n\t\ttoken,\n\t\tsessionId: process.env.PINAGENT_RELAY_SESSION ?? defaultSessionId()\n\t});\n\tg[RELAY_CLIENT_SYMBOL] = handle;\n\treturn handle;\n}\n//#endregion\n//#region src/summarize-changes.ts\n/**\n* `summarizeChangesForPr` — run a one-shot Claude Agent SDK query that turns\n* the current branch's diff into a PR title + markdown body. Used by the\n* dock dashboard's \"Create PR\" button, where there's no connected agent to\n* write the description (the MCP `create_pull_request` path instead has the\n* caller supply title/body, so it never needs this).\n*\n* This is the ONLY PR module that imports `@anthropic-ai/claude-agent-sdk`.\n* Keeping it separate from `host-branch-pr.ts` / `github-pr.ts` is what lets\n* the `@pinagent/mcp` binary import the PR-open core without the SDK.\n*/\n/** Cap the diff we feed the model so a huge churn doesn't blow the prompt. */\nconst DIFF_CAP_BYTES = 60 * 1024;\nconst CONVENTIONAL_SPEC = [\n\t\"Format the subject as a Conventional Commit: `type(scope): summary`.\",\n\t\"- type is one of: feat, fix, chore, docs, refactor, test, perf, build, ci.\",\n\t\"- scope is the main area changed, inferred from the file paths in the diff\",\n\t\" (e.g. dock, widget, agent-runner, mcp, vite-plugin, next-plugin, ui, db).\",\n\t\" Omit the parentheses only if the change is genuinely repo-wide.\",\n\t\"- summary is concise, imperative, lowercase, no trailing period, <70 chars.\",\n\t\"Examples: \\\"fix(dock): commit working changes before opening the PR\\\",\",\n\t\"\\\"feat(widget): add multi-element selection\\\".\"\n].join(\"\\n\");\nconst SYSTEM_PROMPT = [\n\t\"You write pull-request descriptions for Pinagent, a click-to-fix dev tool.\",\n\t\"You are given a git diff and commit log for a feature branch.\",\n\t\"Respond with ONLY a single JSON object, no prose, no code fences:\",\n\t\"{ \\\"title\\\": \\\"<Conventional Commits PR title>\\\", \\\"body\\\": \\\"<markdown body>\\\" }\",\n\t\"\",\n\tCONVENTIONAL_SPEC,\n\t\"\",\n\t\"The body should open with a one-paragraph summary, then a \\\"## Changes\\\"\",\n\t\"section with bullet points of what changed and why. Keep it factual and\",\n\t\"grounded in the diff. End the body with this exact line (keep the link):\",\n\t\"🤖 Generated with [Pinagent](https://pinagent.dev)\"\n].join(\"\\n\");\n/**\n* Extract `{ title, body }` from the model's response. Prefers a JSON object\n* anywhere in the text; falls back to first-line-as-title / rest-as-body so\n* a non-JSON answer still produces a usable PR. Exported for unit testing.\n*/\nfunction parsePrSummary(text) {\n\tconst trimmed = text.trim();\n\tconst start = trimmed.indexOf(\"{\");\n\tconst end = trimmed.lastIndexOf(\"}\");\n\tif (start !== -1 && end > start) {\n\t\tconst candidate = trimmed.slice(start, end + 1);\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(candidate);\n\t\t\tconst title = typeof parsed.title === \"string\" ? parsed.title.trim() : \"\";\n\t\t\tconst body = typeof parsed.body === \"string\" ? parsed.body.trim() : \"\";\n\t\t\tif (title) return {\n\t\t\t\ttitle,\n\t\t\t\tbody: body || title\n\t\t\t};\n\t\t} catch {}\n\t}\n\tconst lines = trimmed.split(\"\\n\");\n\tconst title = (lines[0] ?? \"\").replace(/^#+\\s*/, \"\").trim() || \"Update\";\n\treturn {\n\t\ttitle,\n\t\tbody: lines.slice(1).join(\"\\n\").trim() || title\n\t};\n}\n/** Gather the diff + commit context the summarizer reasons over. */\nasync function gatherContext(projectRoot) {\n\tconst { baseBranch } = await new SettingsStore(projectRoot).read();\n\tconst mb = await runGitCapture(projectRoot, [\n\t\t\"merge-base\",\n\t\tbaseBranch,\n\t\t\"HEAD\"\n\t]);\n\tconst compareTo = mb.code === 0 ? mb.stdout.trim() : baseBranch;\n\tconst stat = await runGitCapture(projectRoot, [\n\t\t\"diff\",\n\t\t\"--stat\",\n\t\tcompareTo\n\t]);\n\tconst log = await runGitCapture(projectRoot, [\n\t\t\"log\",\n\t\t\"--oneline\",\n\t\t`${compareTo}..HEAD`\n\t]);\n\tconst diff = await runGitCapture(projectRoot, [\n\t\t\"diff\",\n\t\t\"--no-color\",\n\t\tcompareTo\n\t]);\n\tlet diffText = diff.code === 0 ? diff.stdout : \"\";\n\tlet truncatedNote = \"\";\n\tif (diffText.length > DIFF_CAP_BYTES) {\n\t\tconst cut = diffText.lastIndexOf(\"\\n\", DIFF_CAP_BYTES);\n\t\tdiffText = diffText.slice(0, cut >= 0 ? cut : DIFF_CAP_BYTES);\n\t\ttruncatedNote = \"\\n\\n[diff truncated — summarize from the portion shown plus the stat]\";\n\t}\n\treturn [\n\t\t`Base branch: ${baseBranch}`,\n\t\t\"\",\n\t\t\"## Commits\",\n\t\tlog.code === 0 && log.stdout.trim() ? log.stdout.trim() : \"(no commits ahead of base)\",\n\t\t\"\",\n\t\t\"## Diffstat\",\n\t\tstat.stdout.trim() || \"(no changes)\",\n\t\t\"\",\n\t\t\"## Diff\",\n\t\tdiffText || \"(empty)\",\n\t\ttruncatedNote\n\t].join(\"\\n\");\n}\n/**\n* Produce a PR title + body for the current branch. Throws if the SDK run\n* yields no text (caller surfaces that as a failed Create-PR).\n*/\nasync function summarizeChangesForPr(projectRoot) {\n\tconst text = await runOneShot(projectRoot, `Write a PR description for these changes.\\n\\n${await gatherContext(projectRoot)}`, SYSTEM_PROMPT);\n\tif (!text.trim()) throw new Error(\"summarizer returned no text — check the Anthropic API key in Connections\");\n\treturn parsePrSummary(text);\n}\nconst COMMIT_SYSTEM_PROMPT = [\n\t\"You write git commit messages. You are given a diff of uncommitted changes.\",\n\t\"Respond with ONLY the commit message: a subject line, then optionally a\",\n\t\"blank line and a short body. No prose, no code fences, no quotes.\",\n\t\"\",\n\tCONVENTIONAL_SPEC\n].join(\"\\n\");\n/**\n* Generate a commit message for the *uncommitted* working changes (diff vs\n* HEAD). Used by the dashboard's \"Push changes\" action to commit the latest\n* batch before pushing. Falls back to a generic message if the model is\n* unavailable, since a missing key shouldn't block shipping the work.\n*/\nasync function summarizeCommitMessage(projectRoot) {\n\tconst diff = await runGitCapture(projectRoot, [\n\t\t\"diff\",\n\t\t\"--no-color\",\n\t\t\"HEAD\"\n\t]);\n\tlet diffText = diff.code === 0 ? diff.stdout : \"\";\n\tif (diffText.length > DIFF_CAP_BYTES) {\n\t\tconst cut = diffText.lastIndexOf(\"\\n\", DIFF_CAP_BYTES);\n\t\tdiffText = diffText.slice(0, cut >= 0 ? cut : DIFF_CAP_BYTES);\n\t}\n\ttry {\n\t\tconst msg = (await runOneShot(projectRoot, `Write a commit message for these uncommitted changes.\\n\\n${diffText || \"(no diff)\"}`, COMMIT_SYSTEM_PROMPT)).trim().replace(/^[\"'`]|[\"'`]$/g, \"\").trim();\n\t\tif (msg) return msg;\n\t} catch {}\n\treturn \"pinagent: update working changes\";\n}\n/**\n* Run a single read-only Claude Agent SDK query and return the concatenated\n* assistant text. No tools / settings / MCP — a focused one-shot over the\n* context we already gathered.\n*/\nasync function runOneShot(projectRoot, prompt, systemPrompt) {\n\tconst env = await buildSdkAuthEnv(projectRoot);\n\tlet text = \"\";\n\tfor await (const message of query({\n\t\tprompt,\n\t\toptions: {\n\t\t\tcwd: projectRoot,\n\t\t\tenv,\n\t\t\tsettingSources: [],\n\t\t\tallowedTools: [],\n\t\t\tsystemPrompt\n\t\t}\n\t})) if (message.type === \"assistant\") {\n\t\tconst blocks = message.message?.content;\n\t\tif (Array.isArray(blocks)) {\n\t\t\tfor (const block of blocks) if (block.type === \"text\" && block.text) text += block.text;\n\t\t}\n\t}\n\treturn text;\n}\n//#endregion\n//#region src/working-copy.ts\n/**\n* `getWorkingCopyStatus` — a high-level git summary of the branch the\n* dev-server is running on (the developer's own working copy), diffed\n* against the project's configured base branch.\n*\n* Powers the dock's redesigned dashboard: \"what have I changed on this\n* branch, and what's the next action?\" Distinct from `changes.ts`, which\n* summarizes pinagent's per-conversation agent worktrees — this is the\n* host checkout itself.\n*\n* All ref comparisons run from `projectRoot` (the host checkout), which\n* is the reliable place to resolve refs — see the \"git ref resolution\n* from worktrees\" note in branches.ts / changes.ts.\n*/\n/** Resolve the current checkout branch. Falls back to 'HEAD' when detached. */\nasync function resolveCurrentBranch(projectRoot) {\n\tconst sym = await runGitCapture(projectRoot, [\n\t\t\"symbolic-ref\",\n\t\t\"--short\",\n\t\t\"HEAD\"\n\t]);\n\treturn sym.code === 0 ? sym.stdout.trim() : \"HEAD\";\n}\n/**\n* Map `git diff --name-status` letters to our coarse status enum. We only\n* surface the common four; anything exotic (copy, type-change) reads as\n* 'modified' so the row still renders.\n*/\nfunction mapStatusLetter(letter) {\n\tswitch (letter[0]) {\n\t\tcase \"A\": return \"added\";\n\t\tcase \"D\": return \"deleted\";\n\t\tcase \"R\": return \"renamed\";\n\t\tdefault: return \"modified\";\n\t}\n}\n/**\n* Per-file change rows vs `compareTo`. Joins `--numstat` (added/deleted\n* counts) with `--name-status` (status letter) keyed by path. Binary files\n* report '-' counts in numstat → surfaced as 0/0.\n*/\nasync function listFiles(projectRoot, compareTo) {\n\tconst numstat = await runGitCapture(projectRoot, [\n\t\t\"diff\",\n\t\t\"--numstat\",\n\t\tcompareTo\n\t]);\n\tif (numstat.code !== 0) return [];\n\tconst status = await runGitCapture(projectRoot, [\n\t\t\"diff\",\n\t\t\"--name-status\",\n\t\tcompareTo\n\t]);\n\tconst statusByPath = /* @__PURE__ */ new Map();\n\tif (status.code === 0) for (const line of status.stdout.split(\"\\n\")) {\n\t\tconst parts = line.split(\"\t\");\n\t\tif (parts.length < 2) continue;\n\t\tconst letter = parts[0]?.trim() ?? \"\";\n\t\tconst path = parts[parts.length - 1]?.trim() ?? \"\";\n\t\tif (path) statusByPath.set(path, mapStatusLetter(letter));\n\t}\n\tconst files = [];\n\tfor (const line of numstat.stdout.split(\"\\n\")) {\n\t\tconst parts = line.split(\"\t\");\n\t\tif (parts.length < 3) continue;\n\t\tconst [addedRaw, deletedRaw] = parts;\n\t\tconst rawPath = parts.slice(2).join(\"\t\").trim();\n\t\tconst path = rawPath.includes(\" => \") ? rawPath.split(\" => \").pop()?.replace(/}$/, \"\").trim() ?? rawPath : rawPath;\n\t\tif (!path) continue;\n\t\tfiles.push({\n\t\t\tpath,\n\t\t\tadded: addedRaw === \"-\" ? 0 : Number(addedRaw) || 0,\n\t\t\tdeleted: deletedRaw === \"-\" ? 0 : Number(deletedRaw) || 0,\n\t\t\tstatus: statusByPath.get(path) ?? \"modified\"\n\t\t});\n\t}\n\treturn files;\n}\n/** Cap on untracked rows we count + list, so a stray huge dir can't stall the GET. */\nconst UNTRACKED_CAP = 200;\n/**\n* New (untracked) files, which `git diff` doesn't report. `--exclude-standard`\n* honors .gitignore (so node_modules / .pinagent / .claude/worktrees are\n* skipped). Added-line counts come from `git diff --no-index` against\n* /dev/null — which reads the file without staging it (no index mutation).\n*/\nasync function listUntrackedFiles(projectRoot) {\n\tconst res = await runGitCapture(projectRoot, [\n\t\t\"ls-files\",\n\t\t\"--others\",\n\t\t\"--exclude-standard\"\n\t]);\n\tif (res.code !== 0) return [];\n\tconst paths = res.stdout.split(\"\\n\").map((s) => s.trim()).filter(Boolean).filter((p) => p !== \".pinagent\" && !p.startsWith(\".pinagent/\")).slice(0, UNTRACKED_CAP);\n\treturn Promise.all(paths.map(async (path) => {\n\t\tconst firstField = (await runGitCapture(projectRoot, [\n\t\t\t\"diff\",\n\t\t\t\"--no-index\",\n\t\t\t\"--numstat\",\n\t\t\t\"--\",\n\t\t\t\"/dev/null\",\n\t\t\tpath\n\t\t])).stdout.split(\"\\n\").find((l) => l.includes(\"\t\"))?.split(\"\t\")[0] ?? \"-\";\n\t\treturn {\n\t\t\tpath,\n\t\t\tadded: firstField === \"-\" ? 0 : Number(firstField) || 0,\n\t\t\tdeleted: 0,\n\t\t\tstatus: \"added\"\n\t\t};\n\t}));\n}\n/**\n* Ahead/behind the remote tracking branch. Returns `hasUpstream: false`\n* with zero counts when the branch has no `@{upstream}` configured (never\n* pushed) — the caller treats that as \"Create PR will push for you.\"\n*/\nasync function resolveRemoteDivergence(projectRoot) {\n\tif ((await runGitCapture(projectRoot, [\n\t\t\"rev-parse\",\n\t\t\"--abbrev-ref\",\n\t\t\"--symbolic-full-name\",\n\t\t\"@{upstream}\"\n\t])).code !== 0) return {\n\t\tahead: 0,\n\t\tbehind: 0,\n\t\thasUpstream: false\n\t};\n\tconst aheadRes = await runGitCapture(projectRoot, [\n\t\t\"rev-list\",\n\t\t\"--count\",\n\t\t\"@{upstream}..HEAD\"\n\t]);\n\tconst behindRes = await runGitCapture(projectRoot, [\n\t\t\"rev-list\",\n\t\t\"--count\",\n\t\t\"HEAD..@{upstream}\"\n\t]);\n\tconst toCount = (s) => {\n\t\tconst n = Number(s.trim());\n\t\treturn Number.isFinite(n) && n > 0 ? n : 0;\n\t};\n\treturn {\n\t\tahead: aheadRes.code === 0 ? toCount(aheadRes.stdout) : 0,\n\t\tbehind: behindRes.code === 0 ? toCount(behindRes.stdout) : 0,\n\t\thasUpstream: true\n\t};\n}\n/** Pick the most relevant recorded PR for `branch`: open/draft win over merged/closed. */\nfunction pickPrForBranch(prs, branch) {\n\tconst mine = prs.filter((p) => p.branch === branch);\n\tif (mine.length === 0) return null;\n\tconst chosen = mine.find((p) => p.state === \"open\" || p.state === \"draft\") ?? mine[0];\n\tif (!chosen) return null;\n\treturn {\n\t\tnumber: chosen.number,\n\t\turl: chosen.url,\n\t\tstate: chosen.state\n\t};\n}\nasync function getWorkingCopyStatus(projectRoot) {\n\tconst { baseBranch } = await new SettingsStore(projectRoot).read();\n\tconst branch = await resolveCurrentBranch(projectRoot);\n\tconst isDefaultBranch = branch === baseBranch;\n\tconst mb = await runGitCapture(projectRoot, [\n\t\t\"merge-base\",\n\t\tbaseBranch,\n\t\t\"HEAD\"\n\t]);\n\tconst compareTo = mb.code === 0 ? mb.stdout.trim() : baseBranch;\n\tconst notGitRepo = !await isInsideWorkTree(projectRoot);\n\tconst [stats, trackedFiles, untrackedFiles, divergence, dirtyStatus, prs] = await Promise.all([\n\t\tnotGitRepo ? Promise.resolve(null) : computeWorktreeStats(projectRoot, baseBranch),\n\t\tnotGitRepo ? Promise.resolve([]) : listFiles(projectRoot, compareTo),\n\t\tnotGitRepo ? Promise.resolve([]) : listUntrackedFiles(projectRoot),\n\t\tnotGitRepo ? Promise.resolve({\n\t\t\tahead: 0,\n\t\t\tbehind: 0,\n\t\t\thasUpstream: false\n\t\t}) : resolveRemoteDivergence(projectRoot),\n\t\tnotGitRepo ? Promise.resolve({\n\t\t\tcode: -1,\n\t\t\tstdout: \"\",\n\t\t\tstderr: \"\"\n\t\t}) : runGitCapture(projectRoot, [\"status\", \"--porcelain\"]),\n\t\tlistPullRequests(projectRoot).catch(() => [])\n\t]);\n\tconst files = [...trackedFiles, ...untrackedFiles];\n\tconst untrackedAdditions = untrackedFiles.reduce((sum, f) => sum + f.added, 0);\n\treturn {\n\t\tbranch,\n\t\tbaseBranch,\n\t\tisDefaultBranch,\n\t\tfilesChanged: (stats?.filesChanged ?? trackedFiles.length) + untrackedFiles.length,\n\t\tadditions: (stats?.additions ?? 0) + untrackedAdditions,\n\t\tdeletions: stats?.deletions ?? 0,\n\t\tfiles,\n\t\tahead: divergence.ahead,\n\t\tbehind: divergence.behind,\n\t\thasUpstream: divergence.hasUpstream,\n\t\tdirty: dirtyStatus.code === 0 && dirtyStatus.stdout.trim().length > 0,\n\t\tpr: pickPrForBranch(prs, branch)\n\t};\n}\n//#endregion\n//#region src/index.ts\nconst PACKAGE_NAME = \"@pinagent/agent-runner\";\n//#endregion\nexport { ASK_USER_TOOL_NAME, BulkPruneBodySchema, BulkReopenBodySchema, BulkUpdateBodySchema, ClaudeCodeProvider, CliAgentProvider, ComposeOptsSchema, DEFAULT_SETTINGS, FeedbackInputSchema, ID_RE, PACKAGE_NAME, PatchSchema, PermissionModeSchema, ProjectSettingsPatchSchema, ProjectSettingsSchema, SecretsFileSchema, SecretsStore, SettingsStore, StatusSchema, Storage, WorktreeStateSchema, applyBulkArchive, applyConversationPatch, attachConnection, buildDeviceUrl, commitWorkingChanges, composePullRequest, computeWorktreeDiff, computeWorktreeStats, countWorktreeChanges, createAskUserMcpServer, createPinagentWsEndpoint, createProvider, discardWorktree, getChangeDiff, getOrCreateBus, getWorkingCopyStatus, hasActiveRun, interruptRun, isInGitignore, isInsideRoot, isWorkingTreeDirty, listAuditEvents, listBranches, listChanges, listGitBranches, listProjectFiles, listPullRequests, listWorktreeServers, maybeStartRelayClient, mergeWorktree, nextBackoff, openHostBranchPr, openInEditor, openPrOnGitHub, parseGitBranches, parsePrSummary, pruneBranch, pruneBranches, pruneStaleBranches, pushBranch, pushHostBranch, recordAuditEvent, refreshPullRequests, rejectAsk, reopenConversation, reopenConversations, resolveAgentMode, resolveAsk, resolvePermissionMode, resolvePermissionModeOverride, resolveProvider, resolveProviderId, resolveServeCommand, runFollowUpTurn, searchHistory, selectUnshippedScreenshots, serveBranch, serveWorktree, slugifyBranchName, spawnAgent, startHostBranch, startRelayClient, startWsServer, stopWorktreeServer, summarizeChangesForPr, summarizeCommitMessage, toSdkPermissionMode, updatePrDescription, validateAnthropicKey, validateGithubToken };\n\n//# sourceMappingURL=index.js.map","// SPDX-License-Identifier: Apache-2.0\n/**\n * Metro WebSocket endpoint for Pinagent — live agent streaming on RN.\n *\n * The web plugins run a dedicated WS server on a separate port (53636) and\n * tell the browser widget that port via an injected config. A phone can't\n * discover a second port, so RN streams over the *same* host:port the widget\n * already uses for `POST /__pinagent/feedback` — no second port, no discovery.\n *\n * There are two ways the Metro-family dev servers expose a custom WS path, and\n * they are NOT interchangeable:\n *\n * - **Bare Metro** (`metro/src/index` `runServer`) honors\n * `config.server.websocketEndpoints` — a `{ [path]: ws.Server }` map it\n * folds into its own `upgrade` dispatch. `pinagentWebsocketEndpoints`\n * produces that map.\n * - **Expo** (`@expo/cli`'s forked `runServer`) does NOT. It builds its own\n * endpoint map (`/hot`, devtools, debugger) and `socket.destroy()`s any\n * upgrade path it doesn't recognise, so a user `websocketEndpoints` entry\n * is silently dropped and `/__pinagent/ws` connections reconnect forever\n * (\"Connecting…\" in the stream sheet). Expo *does* honor `enhanceMiddleware`\n * though — which is why the feedback POST and the agent run still work.\n *\n * To cover both, `pinagentMiddleware` self-installs the `/__pinagent/ws` handler\n * on the live HTTP server (via {@link ensurePinagentUpgrade}) the first time a\n * request flows through it — see `metro-middleware.ts`. That path works under\n * Expo and bare Metro alike, so `websocketEndpoints` wiring is now optional and\n * kept only for explicit bare-Metro setups.\n *\n * Wire it in `metro.config.js` alongside the feedback middleware:\n *\n * const { pinagentMiddleware } = require('@pinagent/react-native/server');\n *\n * config.server = {\n * ...config.server,\n * enhanceMiddleware: (mw, server) =>\n * pinagentMiddleware({ projectRoot: __dirname }).chain(mw),\n * };\n *\n * The accepted socket is wired to the exact `attachConnection` the web widget\n * talks to, so the wire protocol (subscribe / event / done / user_message /\n * ask_response / interrupt / worktree controls) is identical.\n */\nimport type { IncomingMessage, Server } from 'node:http';\nimport type { Duplex } from 'node:stream';\nimport { createPinagentWsEndpoint } from '@pinagent/agent-runner';\n\nexport interface PinagentWsEndpointsOpts {\n /**\n * Project root — where `.pinagent/` lives. Pass `__dirname`, the same value\n * given to `pinagentMiddleware`. The agent run records events keyed on this\n * root; the WS server's bus subscription otherwise resolves the root from\n * `PINAGENT_PROJECT_ROOT` (falling back to `process.cwd()`). Metro's cwd is\n * usually the project dir, but we pin the env var so streaming always reads\n * the same `.pinagent/db.sqlite` the feedback middleware writes to.\n */\n projectRoot: string;\n}\n\n/**\n * Returns the `{ [path]: ws.Server }` map to spread into Metro's\n * `config.server.websocketEndpoints`. Mounts the Pinagent stream at\n * `/__pinagent/ws`.\n */\nexport function pinagentWebsocketEndpoints(\n opts: PinagentWsEndpointsOpts,\n): Record<string, ReturnType<typeof createPinagentWsEndpoint>> {\n if (!process.env.PINAGENT_PROJECT_ROOT) {\n process.env.PINAGENT_PROJECT_ROOT = opts.projectRoot;\n }\n return { '/__pinagent/ws': createPinagentWsEndpoint() };\n}\n\n/** Per-server guard so we only take over the `upgrade` event once. */\nconst UPGRADE_HOOKED = Symbol.for('pinagent.rn.upgradeHooked');\n\ntype UpgradeListener = (req: IncomingMessage, socket: Duplex, head: Buffer) => void;\n\n/**\n * Idempotently mount `/__pinagent/ws` on a live HTTP server, regardless of\n * whether the host honors `config.server.websocketEndpoints`.\n *\n * Expo's dev server registers a single `upgrade` listener that destroys any\n * path it doesn't know, so simply *adding* a second listener races with that\n * destroy. Instead we take the listener over: capture whatever `upgrade`\n * listeners are already attached (Metro's `/hot`, Expo's devtools/debugger\n * sockets, …), remove them, and install one router that handles\n * `/__pinagent/ws` itself and delegates every other path back to the captured\n * listeners untouched. HMR and the rest keep working; our path no longer gets\n * destroyed out from under us.\n *\n * Called lazily from `pinagentMiddleware` with `req.socket.server` — by the\n * time any HTTP request reaches the middleware the dev server is listening and\n * its own `upgrade` listener is already registered, so the capture is complete.\n */\nexport function ensurePinagentUpgrade(server: Server): void {\n const flagged = server as Server & { [UPGRADE_HOOKED]?: boolean };\n if (flagged[UPGRADE_HOOKED]) return;\n flagged[UPGRADE_HOOKED] = true;\n\n const wss = createPinagentWsEndpoint();\n const prior = server.listeners('upgrade') as UpgradeListener[];\n server.removeAllListeners('upgrade');\n\n server.on('upgrade', (req, socket: Duplex, head: Buffer) => {\n let pathname = '';\n try {\n pathname = new URL(req.url ?? '', 'http://localhost').pathname;\n } catch {\n pathname = (req.url ?? '').split('?')[0] ?? '';\n }\n if (pathname === '/__pinagent/ws') {\n wss.handleUpgrade(req, socket, head, (ws) => wss.emit('connection', ws, req));\n return;\n }\n for (const fn of prior) fn.call(server, req, socket, head);\n });\n}\n","// SPDX-License-Identifier: Apache-2.0\n/**\n * Metro dev-server adapter for Pinagent.\n *\n * This is a near-copy of the `POST /__pinagent/feedback` arm of\n * `packages/vite-plugin/src/middleware.ts`. It reuses the existing\n * backend verbatim — `Storage` (writes to `.pinagent/db.sqlite` +\n * screenshots), `FeedbackInputSchema` (the wire contract), and\n * `spawnAgent` (inline / worktree agent runs). Nothing about agent\n * pickup is RN-specific; only the route mounting differs.\n *\n * Wire it in `metro.config.js`:\n *\n * const { pinagentMiddleware } = require('@pinagent/react-native/server');\n * module.exports = {\n * server: {\n * enhanceMiddleware: (metroMiddleware, server) =>\n * pinagentMiddleware({ projectRoot: __dirname }).chain(metroMiddleware),\n * },\n * };\n *\n * `.chain(next)` returns a single connect handler that runs our routes\n * first and defers everything else to Metro's own middleware.\n */\nimport { Buffer } from 'node:buffer';\nimport { spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport type { IncomingMessage, Server, ServerResponse } from 'node:http';\nimport { delimiter, isAbsolute, join, relative, resolve as resolvePath } from 'node:path';\nimport {\n FeedbackInputSchema,\n type SpawnAgentMode,\n Storage,\n spawnAgent,\n} from '@pinagent/agent-runner';\nimport { nanoid } from 'nanoid';\nimport { ensurePinagentUpgrade } from './ws-endpoint';\n\nconst MAX_BODY_BYTES = 8 * 1024 * 1024; // 8MB raw JSON (screenshot dominates)\n\ntype Handler = (req: IncomingMessage, res: ServerResponse, next: () => void) => void;\n\nexport interface PinagentMiddlewareOpts {\n /** Project root — where `.pinagent/` lives. Pass `__dirname`. */\n projectRoot: string;\n /**\n * Agent spawn mode, same semantics as the Vite plugin:\n * `false` (file only), `'inline'`, or `'worktree'`. Defaults to\n * `'inline'`.\n */\n spawnMode?: SpawnAgentMode;\n /**\n * Optional explicit API key for spawned agent runs, same semantics as the\n * Vite plugin's `apiKey`.\n *\n * Pinagent never reads `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` from the\n * environment on its own — a key exported in your shell for other tools must\n * not get billed (or, if stale, fail the run with \"Invalid API key\") just\n * because pinagent happened to inherit it. When you leave this unset, runs\n * authenticate against your agentic subscription (Claude Code, or Codex's\n * ChatGPT login when using the CLI provider).\n *\n * Set it only when you deliberately want a raw key used, e.g.\n * `pinagentMiddleware({ projectRoot: __dirname, apiKey: process.env.MY_KEY })`.\n * For the default Claude provider it's passed as the Anthropic key; for the\n * bring-your-own CLI provider it's supplied to the wrapped CLI as both\n * `ANTHROPIC_API_KEY` and `OPENAI_API_KEY`. Bridged to the runner via the\n * `PINAGENT_AGENT_API_KEY` env var (RN has no dock, so the option/env is the\n * whole story — there's no runtime Connections store to take precedence).\n */\n apiKey?: string;\n}\n\nexport interface PinagentMiddleware {\n (req: IncomingMessage, res: ServerResponse, next: () => void): void;\n /** Compose: run pinagent routes first, then `next` for everything else. */\n chain(next: Handler): Handler;\n}\n\nexport function pinagentMiddleware(opts: PinagentMiddlewareOpts): PinagentMiddleware {\n const storage = new Storage(opts.projectRoot);\n const spawnMode: SpawnAgentMode = opts.spawnMode ?? 'inline';\n\n // Pin the project root so the agent run (which resolves its bus root from\n // PINAGENT_PROJECT_ROOT, falling back to cwd) writes the same\n // `.pinagent/db.sqlite` the WS subscription reads. Metro's cwd is usually the\n // project dir, but don't rely on it.\n if (!process.env.PINAGENT_PROJECT_ROOT) {\n process.env.PINAGENT_PROJECT_ROOT = opts.projectRoot;\n }\n\n // Bridge an explicitly-configured agent API key to the runner — identical to\n // vite-plugin (`packages/vite-plugin/src/index.ts`). Pinagent only ever uses\n // a key handed to it on purpose; absent this (and any env the user set), runs\n // fall back to subscription auth. The authority is agent-auth.ts in\n // @pinagent/agent-runner. No-op when the consumer omits it.\n if (opts.apiKey) {\n process.env.PINAGENT_AGENT_API_KEY = opts.apiKey;\n }\n\n const handler = (async (req: IncomingMessage, res: ServerResponse, next: () => void) => {\n // Self-install the `/__pinagent/ws` upgrade handler on the live HTTP\n // server. Expo's dev server ignores `config.server.websocketEndpoints`\n // (see ws-endpoint.ts), so routing streaming through the middleware — which\n // Expo *does* honor via `enhanceMiddleware` — is the only path that works\n // under both Expo and bare Metro. Idempotent + cheap, so running it on\n // every request (the bundle fetch arrives long before any WS) is fine.\n const server = (req.socket as { server?: Server } | undefined)?.server;\n if (server) ensurePinagentUpgrade(server);\n\n const url = req.url ?? '';\n if (!url.startsWith('/__pinagent')) return next();\n\n try {\n // POST /__pinagent/feedback — identical contract to the web plugins.\n if (req.method === 'POST' && url === '/__pinagent/feedback') {\n const raw = await readJsonBody(req);\n const parsed = FeedbackInputSchema.safeParse(raw);\n if (!parsed.success) return badRequest(res, parsed.error.message);\n\n const decoded = Buffer.from(parsed.data.screenshot, 'base64');\n if (decoded.length > 5 * 1024 * 1024) {\n return badRequest(res, 'screenshot exceeds 5MB');\n }\n\n const id = nanoid(10);\n const rec = await storage.create(id, parsed.data);\n\n const agentSpawned = spawnMode !== false;\n if (agentSpawned) {\n try {\n await spawnAgent({ projectRoot: storage.root, feedback: rec, mode: spawnMode });\n } catch {\n // Surfaces in the per-feedback log; don't fail the POST.\n }\n }\n return json(res, 200, { id: rec.id, agentSpawned });\n }\n\n // GET /__pinagent/feedback — list (handy for a future RN inbox view).\n if (req.method === 'GET' && url === '/__pinagent/feedback') {\n const items = await storage.list();\n return json(res, 200, items);\n }\n\n // POST /__pinagent/open — open a tapped component's source file in the\n // developer's editor on the machine running Metro. The RN analog of\n // the web composer's \"navigate to file\": the phone can't open your\n // editor, but the dev server can.\n if (req.method === 'POST' && url === '/__pinagent/open') {\n const raw = (await readJsonBody(req)) as {\n file?: unknown;\n line?: unknown;\n col?: unknown;\n } | null;\n const file = typeof raw?.file === 'string' ? raw.file : '';\n if (!file) return badRequest(res, 'missing file');\n const abs = resolvePath(opts.projectRoot, file);\n // Confine to the project root — never let a crafted path escape it.\n const rel = relative(opts.projectRoot, abs);\n if (rel.startsWith('..') || isAbsolute(rel)) {\n return badRequest(res, 'path outside project root');\n }\n const line = Number.isFinite(Number(raw?.line)) ? Number(raw?.line) : 1;\n const col = Number.isFinite(Number(raw?.col)) ? Number(raw?.col) : 1;\n const opened = openInEditor(abs, line, col);\n return json(res, 200, { ok: opened });\n }\n\n return json(res, 404, { error: 'not found' });\n } catch (err) {\n return json(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n }) as unknown as PinagentMiddleware;\n\n handler.chain = (nextMw: Handler): Handler => {\n return (req, res, next) => {\n if ((req.url ?? '').startsWith('/__pinagent')) {\n handler(req, res, () => nextMw(req, res, next));\n } else {\n nextMw(req, res, next);\n }\n };\n };\n\n return handler;\n}\n\nfunction readJsonBody(req: IncomingMessage): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n let total = 0;\n req.on('data', (chunk: Buffer) => {\n total += chunk.length;\n if (total > MAX_BODY_BYTES) {\n reject(new Error('payload too large'));\n req.destroy();\n return;\n }\n chunks.push(chunk);\n });\n req.on('end', () => {\n if (chunks.length === 0) return resolve(null);\n try {\n resolve(JSON.parse(Buffer.concat(chunks).toString('utf8')));\n } catch (e) {\n reject(e);\n }\n });\n req.on('error', reject);\n });\n}\n\nfunction json(res: ServerResponse, status: number, body: unknown): void {\n res.statusCode = status;\n res.setHeader('Content-Type', 'application/json; charset=utf-8');\n res.setHeader('Cache-Control', 'no-store');\n res.end(JSON.stringify(body));\n}\n\nfunction badRequest(res: ServerResponse, msg: string): void {\n json(res, 400, { error: msg });\n}\n\n/** Find an executable on `PATH`. Returns the full path, or null. */\nfunction findOnPath(bin: string): string | null {\n for (const dir of (process.env.PATH ?? '').split(delimiter)) {\n if (dir && existsSync(join(dir, bin))) return join(dir, bin);\n }\n return null;\n}\n\ninterface Opener {\n cmd: string;\n /** Flags that precede the `file:line:col` target. */\n prefixArgs: string[];\n}\n\n// Editors that accept a `file:line:col` target. `-g` makes the VS Code family\n// jump to the line; `subl`/`zed` take the suffix directly.\nconst CLI_EDITORS: Array<{ bin: string; args: string[] }> = [\n { bin: 'code', args: ['-g'] },\n { bin: 'cursor', args: ['-g'] },\n { bin: 'windsurf', args: ['-g'] },\n { bin: 'code-insiders', args: ['-g'] },\n { bin: 'codium', args: ['-g'] },\n { bin: 'zed', args: [] },\n { bin: 'subl', args: [] },\n];\n\n// macOS app names (under /Applications) for when the CLI shim isn't on PATH —\n// `open -a <App> --args …` hands the same flags to the app on launch.\nconst MAC_APPS: Array<{ app: string; args: string[] }> = [\n { app: 'Cursor', args: ['-g'] },\n { app: 'Visual Studio Code', args: ['-g'] },\n { app: 'Windsurf', args: ['-g'] },\n { app: 'VSCodium', args: ['-g'] },\n { app: 'Zed', args: [] },\n { app: 'Sublime Text', args: [] },\n];\n\n/**\n * Pick a command that can open a `file:line:col` target. Order:\n * `PINAGENT_EDITOR` (explicit) → a known editor CLI on `PATH` → a known macOS\n * editor app. Returns null if nothing suitable is found.\n */\nfunction resolveOpener(): Opener | null {\n const override = process.env.PINAGENT_EDITOR?.trim();\n if (override) {\n const [cmd, ...prefixArgs] = override.split(/\\s+/);\n if (cmd) return { cmd, prefixArgs };\n }\n for (const e of CLI_EDITORS) {\n if (findOnPath(e.bin)) return { cmd: e.bin, prefixArgs: e.args };\n }\n if (process.platform === 'darwin') {\n for (const a of MAC_APPS) {\n if (existsSync(`/Applications/${a.app}.app`)) {\n return { cmd: 'open', prefixArgs: ['-a', a.app, '--args', ...a.args] };\n }\n }\n }\n return null;\n}\n\n/**\n * Open `<file>:<line>:<col>` in the developer's editor (see\n * {@link resolveOpener} for selection). Best-effort and fully detached — a\n * missing editor must never crash Metro. Returns whether a launch was\n * attempted, so the device can tell the developer when no editor was found.\n */\nfunction openInEditor(abs: string, line: number, col: number): boolean {\n const opener = resolveOpener();\n if (!opener) return false;\n const target = `${abs}:${line}:${col}`;\n try {\n const child = spawn(opener.cmd, [...opener.prefixArgs, target], {\n stdio: 'ignore',\n detached: true,\n });\n child.on('error', () => {\n // Editor binary not actually launchable — swallow; comment still files.\n });\n child.unref();\n return true;\n } catch {\n return false;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,MAAM,iBAAA,GAAA,wBAAA,aAA4B,iBAAiB;CAClD,KAAA,GAAA,wBAAA,MAAS,IAAI,EAAE,WAAW;;;;;;CAM1B,UAAA,GAAA,wBAAA,MAAc,SAAS,EAAE,QAAQ;;CAEjC,iBAAA,GAAA,wBAAA,MAAqB,kBAAkB;CACvC,SAAA,GAAA,wBAAA,MAAa,UAAU,EAAE,MAAM;EAC9B;EACA;EACA;EACA;CACD,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,SAAS;;CAEhC,OAAA,GAAA,wBAAA,MAAW,MAAM;;CAEjB,YAAA,GAAA,wBAAA,MAAgB,YAAY;;CAE5B,SAAA,GAAA,wBAAA,MAAa,QAAQ;;CAErB,eAAA,GAAA,wBAAA,MAAmB,eAAe;;;;;;;;;CASlC,gBAAA,GAAA,wBAAA,MAAoB,kBAAkB,EAAE,MAAM;EAC7C;EACA;EACA;EACA;CACD,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,MAAM;;;;;;;CAO7B,QAAA,GAAA,wBAAA,MAAY,OAAO;;;;;;;;CAQnB,WAAA,GAAA,wBAAA,SAAkB,YAAY,EAAE,MAAM,UAAU,CAAC,EAAE,QAAQ,EAAE,QAAQ,KAAK;CAC1E,YAAA,GAAA,wBAAA,SAAmB,cAAc,EAAE,MAAM,eAAe,CAAC,EAAE,QAAQ,EAAE,QAAQ,YAAA,GAAG,sBAAsB;CACtG,YAAA,GAAA,wBAAA,SAAmB,cAAc,EAAE,MAAM,eAAe,CAAC,EAAE,QAAQ,EAAE,QAAQ,YAAA,GAAG,sBAAsB;CACtG,aAAA,GAAA,wBAAA,SAAoB,eAAe,EAAE,MAAM,eAAe,CAAC;AAC5D,CAAC;;;;;;;;;;AAUD,MAAM,iBAAA,GAAA,wBAAA,aAA4B,kBAAkB;CACnD,iBAAA,GAAA,wBAAA,MAAqB,iBAAiB,EAAE,WAAW,EAAE,iBAAiB,cAAc,IAAI,EAAE,UAAU,UAAU,CAAC;CAC/G,MAAA,GAAA,wBAAA,MAAU,KAAK,EAAE,QAAQ;;CAEzB,OAAA,GAAA,wBAAA,MAAW,MAAM;CACjB,OAAA,GAAA,wBAAA,SAAc,MAAM;CACpB,MAAA,GAAA,wBAAA,SAAa,KAAK;;CAElB,WAAA,GAAA,wBAAA,MAAe,UAAU,EAAE,QAAQ;CACnC,SAAA,GAAA,wBAAA,SAAgB,SAAS;CACzB,SAAA,GAAA,wBAAA,SAAgB,SAAS;CACzB,YAAA,GAAA,wBAAA,SAAmB,YAAY;CAC/B,YAAA,GAAA,wBAAA,SAAmB,YAAY;;CAE/B,YAAA,GAAA,wBAAA,MAAgB,YAAY;;;;;;;;CAQ5B,YAAA,GAAA,wBAAA,MAAgB,WAAW;;;;;;;CAO3B,gBAAA,GAAA,wBAAA,MAAoB,kBAAkB,EAAE,MAAM,OAAO,CAAC,EAAE,MAAM;;;;;;;;;CAS9D,gBAAA,GAAA,wBAAA,SAAuB,gBAAgB;CACvC,gBAAA,GAAA,wBAAA,SAAuB,gBAAgB;;;;;;;CAOvC,sBAAA,GAAA,wBAAA,MAA0B,sBAAsB;;;;;;;;CAQhD,oBAAA,GAAA,wBAAA,MAAwB,sBAAsB,EAAE,MAAM,OAAO,CAAC,EAAE,MAAM;AACvE,CAAC;;;;;;;;;;;;;;;;;AAiBD,MAAM,YAAA,GAAA,wBAAA,aAAuB,YAAY;CACxC,KAAA,GAAA,wBAAA,SAAY,IAAI,EAAE,WAAW,EAAE,eAAe,KAAK,CAAC;CACpD,iBAAA,GAAA,wBAAA,MAAqB,iBAAiB,EAAE,QAAQ,EAAE,iBAAiB,cAAc,IAAI,EAAE,UAAU,UAAU,CAAC;CAC5G,OAAA,GAAA,wBAAA,SAAc,MAAM,EAAE,QAAQ;;;;;;CAM9B,OAAA,GAAA,wBAAA,MAAW,MAAM,EAAE,QAAQ;;CAE3B,UAAA,GAAA,wBAAA,MAAc,WAAW,EAAE,MAAM,OAAO,CAAC,EAAE,QAAQ;CACnD,YAAA,GAAA,wBAAA,SAAmB,cAAc,EAAE,MAAM,eAAe,CAAC,EAAE,QAAQ,EAAE,QAAQ,YAAA,GAAG,sBAAsB;AACvG,CAAC;;;;;;;;;AASD,MAAM,cAAA,GAAA,wBAAA,aAAyB,eAAe;CAC7C,iBAAA,GAAA,wBAAA,MAAqB,iBAAiB,EAAE,WAAW,EAAE,iBAAiB,cAAc,IAAI,EAAE,UAAU,UAAU,CAAC;CAC/G,YAAA,GAAA,wBAAA,SAAmB,cAAc,EAAE,MAAM,eAAe,CAAC,EAAE,QAAQ;CACnE,cAAA,GAAA,wBAAA,SAAqB,cAAc,EAAE,QAAQ;CAC7C,gBAAA,GAAA,wBAAA,MAAoB,iBAAiB;CACrC,YAAA,GAAA,wBAAA,MAAgB,YAAY;AAC7B,CAAC;;;;;;;;;;;;AAYD,MAAM,gBAAA,GAAA,wBAAA,aAA2B,iBAAiB;CACjD,KAAA,GAAA,wBAAA,SAAY,IAAI,EAAE,WAAW,EAAE,eAAe,KAAK,CAAC;;CAEpD,SAAA,GAAA,wBAAA,SAAgB,QAAQ,EAAE,QAAQ;;CAElC,MAAA,GAAA,wBAAA,MAAU,KAAK,EAAE,QAAQ;;CAEzB,SAAA,GAAA,wBAAA,MAAa,QAAQ,EAAE,QAAQ;;CAE/B,aAAA,GAAA,wBAAA,MAAiB,aAAa,EAAE,QAAQ;CACxC,QAAA,GAAA,wBAAA,MAAY,OAAO,EAAE,QAAQ;;;;;CAK7B,OAAA,GAAA,wBAAA,MAAW,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE;CACvC,QAAA,GAAA,wBAAA,MAAY,SAAS,EAAE,MAAM;EAC5B;EACA;EACA;EACA;CACD,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,MAAM;;CAE7B,kBAAA,GAAA,wBAAA,MAAsB,oBAAoB,EAAE,MAAM,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,YAAA,GAAG,QAAQ;CACjG,YAAA,GAAA,wBAAA,SAAmB,cAAc,EAAE,MAAM,eAAe,CAAC,EAAE,QAAQ,EAAE,QAAQ,YAAA,GAAG,sBAAsB;CACtG,YAAA,GAAA,wBAAA,SAAmB,cAAc,EAAE,MAAM,eAAe,CAAC,EAAE,QAAQ,EAAE,QAAQ,YAAA,GAAG,sBAAsB;AACvG,CAAC;;;;;;;;;;;;;;AAcD,MAAM,eAAA,GAAA,wBAAA,aAA0B,gBAAgB;CAC/C,KAAA,GAAA,wBAAA,SAAY,IAAI,EAAE,WAAW,EAAE,eAAe,KAAK,CAAC;CACpD,iBAAA,GAAA,wBAAA,MAAqB,iBAAiB;CACtC,QAAA,GAAA,wBAAA,MAAY,SAAS,EAAE,MAAM;EAC5B;EACA;EACA;CACD,EAAE,CAAC,EAAE,QAAQ;CACb,SAAA,GAAA,wBAAA,MAAa,QAAQ,EAAE,QAAQ;CAC/B,UAAA,GAAA,wBAAA,MAAc,WAAW,EAAE,MAAM,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,YAAA,GAAG,QAAQ;CAChF,YAAA,GAAA,wBAAA,SAAmB,cAAc,EAAE,MAAM,eAAe,CAAC,EAAE,QAAQ,EAAE,QAAQ,YAAA,GAAG,sBAAsB;AACvG,CAAC;;;;;;;;;;;;;;;;AClOD,MAAM,kBAAkBA,IAAAA,EAAE,KAAK;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD,CAAC;AACD,MAAM,eAAeA,IAAAA,EAAE,OAAO;CAC7B,KAAKA,IAAAA,EAAE,OAAO;CACd,UAAUA,IAAAA,EAAE,OAAO;CACnB,SAASA,IAAAA,EAAE,OAAO;AACnB,CAAC,EAAE,MAAM;AACkBA,IAAAA,EAAE,OAAO;CACnC,IAAIA,IAAAA,EAAE,OAAO;CACb,SAASA,IAAAA,EAAE,OAAO;CAClB,OAAOA,IAAAA,EAAE,OAAO;CAChB,QAAQ;CACR,MAAMA,IAAAA,EAAE,OAAO;CACf,QAAQ;CACR,QAAQA,IAAAA,EAAE,OAAO;CACjB,WAAWA,IAAAA,EAAE,OAAO;CACpB,aAAaA,IAAAA,EAAE,OAAO;CACtB,cAAcA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAC5C,CAAC,EAAE,MAC8B,EAAmB,OAAO;CAC1D,SAASA,IAAAA,EAAE,OAAO;CAClB,YAAYA,IAAAA,EAAE,OAAO,EAAE,SAAS;AACjC,CAAC,EAAE,MAAM;AACYA,IAAAA,EAAE,OAAO;CAC7B,IAAIA,IAAAA,EAAE,OAAO;CACb,gBAAgBA,IAAAA,EAAE,OAAO;CACzB,mBAAmBA,IAAAA,EAAE,OAAO;CAC5B,QAAQA,IAAAA,EAAE,KAAK;EACd;EACA;EACA;EACA;CACD,CAAC;CACD,QAAQA,IAAAA,EAAE,OAAO;CACjB,cAAcA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;CAC3C,WAAWA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;CACxC,WAAWA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;CACxC,SAASA,IAAAA,EAAE,OAAO;CAClB,WAAWA,IAAAA,EAAE,OAAO;AACrB,CAAC,EAAE,MAAM;AACgBA,IAAAA,EAAE,OAAO;CACjC,MAAMA,IAAAA,EAAE,OAAO;CACf,WAAWA,IAAAA,EAAE,QAAQ;;;;;CAKrB,cAAcA,IAAAA,EAAE,OAAO,EAAE,SAAS;AACnC,CAAC,EAAE,MAAM;AACYA,IAAAA,EAAE,OAAO;CAC7B,IAAIA,IAAAA,EAAE,OAAO;CACb,MAAMA,IAAAA,EAAE,OAAO;CACf,gBAAgBA,IAAAA,EAAE,OAAO,EAAE,SAAS;CACpC,mBAAmBA,IAAAA,EAAE,OAAO,EAAE,SAAS;CACvC,WAAWA,IAAAA,EAAE,OAAO;CACpB,cAAcA,IAAAA,EAAE,OAAO;CACvB,OAAOA,IAAAA,EAAE,KAAK;EACb;EACA;EACA;CACD,CAAC;CACD,QAAQA,IAAAA,EAAE,OAAO,EAAE,SAAS;AAC7B,CAAC,EAAE,MAAM;AACiBA,IAAAA,EAAE,OAAO;CAClC,IAAIA,IAAAA,EAAE,OAAO;CACb,QAAQA,IAAAA,EAAE,OAAO,EAAE,IAAI;CACvB,OAAOA,IAAAA,EAAE,OAAO;CAChB,OAAOA,IAAAA,EAAE,KAAK;EACb;EACA;EACA;EACA;CACD,CAAC;CACD,QAAQA,IAAAA,EAAE,OAAO;CACjB,YAAYA,IAAAA,EAAE,OAAO;CACrB,KAAKA,IAAAA,EAAE,OAAO;CACd,WAAWA,IAAAA,EAAE,OAAO;CACpB,iBAAiBA,IAAAA,EAAE,MAAMA,IAAAA,EAAE,OAAO,CAAC;AACpC,CAAC,EAAE,MAAM;AACT,MAAM,wBAAwBA,IAAAA,EAAE,OAAO;CACtC,MAAMA,IAAAA,EAAE,OAAO;CACf,OAAOA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;CACpC,SAASA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;CACtC,QAAQA,IAAAA,EAAE,KAAK;EACd;EACA;EACA;EACA;CACD,CAAC;AACF,CAAC,EAAE,MAAM;AAMuBA,IAAAA,EAAE,OAAO;CACxC,QAAQA,IAAAA,EAAE,OAAO;CACjB,YAAYA,IAAAA,EAAE,OAAO;CACrB,iBAAiBA,IAAAA,EAAE,QAAQ;CAC3B,cAAcA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;CAC3C,WAAWA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;CACxC,WAAWA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;CACxC,OAAOA,IAAAA,EAAE,MAAM,qBAAqB;CACpC,OAAOA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;CACpC,QAAQA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;CACrC,aAAaA,IAAAA,EAAE,QAAQ;CACvB,OAAOA,IAAAA,EAAE,QAAQ;CACjB,IAAIA,IAAAA,EAAE,OAAO;EACZ,QAAQA,IAAAA,EAAE,OAAO,EAAE,IAAI;EACvB,KAAKA,IAAAA,EAAE,OAAO;EACd,OAAOA,IAAAA,EAAE,KAAK;GACb;GACA;GACA;GACA;EACD,CAAC;CACF,CAAC,EAAE,SAAS;AACb,CAAC,EAAE,MAAM;AAC4BA,IAAAA,EAAE,OAAO;CAC7C,QAAQA,IAAAA,EAAE,OAAO;EAChB,WAAWA,IAAAA,EAAE,QAAQ;EACrB,OAAOA,IAAAA,EAAE,OAAO,EAAE,SAAS;CAC5B,CAAC,EAAE,MAAM;CACT,WAAWA,IAAAA,EAAE,OAAO,EAAE,QAAQA,IAAAA,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM;AACpD,CAAC,EAAE,MAAM;;;;;;;;;;;;;;;;;;;AAmBT,MAAM,2BAA2B;CAChC;EACC,aAAa;EACb,SAAS;EACT,OAAO;EACP,YAAY;EACZ,aAAa;EACb,SAAS;CACV;CACA;EACC,aAAa;EACb,SAAS;EACT,OAAO;EACP,YAAY;EACZ,aAAa;EACb,SAAS;CACV;CACA;EACC,aAAa;EACb,SAAS;EACT,OAAO;EACP,YAAY;EACZ,aAAa;EACb,SAAS;CACV;AACD;AACA,MAAM,uBAAuBA,IAAAA,EAAE,KAAK,yBAAyB,KAAK,MAAM,EAAE,WAAW,CAAC;AACpDA,IAAAA,EAAE,OAAO;CAC1C,YAAYA,IAAAA,EAAE,OAAO;CACrB,uBAAuBA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;CACpD,uBAAuBA,IAAAA,EAAE,OAAO;CAChC,kBAAkBA,IAAAA,EAAE,OAAO,EAAE,SAAS;CACtC,gBAAgB;;;;;;;;;;;CAWhB,wBAAwBA,IAAAA,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,IAAI;AAC3D,CAAC,EAAE,MAAM;AACsBA,IAAAA,EAAE,OAAO;CACvC,QAAQA,IAAAA,EAAE,MAAMA,IAAAA,EAAE,OAAO,CAAC;CAC1B,QAAQA,IAAAA,EAAE,MAAMA,IAAAA,EAAE,OAAO;EACxB,YAAYA,IAAAA,EAAE,OAAO;EACrB,OAAOA,IAAAA,EAAE,OAAO;CACjB,CAAC,EAAE,MAAM,CAAC;CACV,eAAeA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAC7C,CAAC,EAAE,MAAM;AACT,MAAM,mBAAmBA,IAAAA,EAAE,KAAK;CAC/B;CACA;CACA;AACD,CAAC;AACwBA,IAAAA,EAAE,OAAO;CACjC,IAAIA,IAAAA,EAAE,OAAO;CACb,gBAAgBA,IAAAA,EAAE,OAAO,EAAE,SAAS;CACpC,OAAO;CACP,QAAQA,IAAAA,EAAE,OAAO;CACjB,SAASA,IAAAA,EAAE,OAAOA,IAAAA,EAAE,OAAO,GAAGA,IAAAA,EAAE,QAAQ,CAAC;CACzC,WAAWA,IAAAA,EAAE,OAAO;AACrB,CAAC,EAAE,MAAM;AACT,MAAM,4BAA4BA,IAAAA,EAAE,KAAK;CACxC;CACA;CACA;CACA;CACA;AACD,CAAC;AAC8BA,IAAAA,EAAE,OAAO;CACvC,IAAIA,IAAAA,EAAE,OAAO;CACb,SAASA,IAAAA,EAAE,OAAO;CAClB,QAAQA,IAAAA,EAAE,KAAK;EACd;EACA;EACA;EACA;CACD,CAAC;CACD,eAAeA,IAAAA,EAAE,KAAK;EACrB;EACA;EACA;EACA;CACD,CAAC;CACD,QAAQA,IAAAA,EAAE,OAAO,EAAE,SAAS;CAC5B,MAAMA,IAAAA,EAAE,OAAO,EAAE,SAAS;CAC1B,MAAMA,IAAAA,EAAE,OAAO,EAAE,SAAS;CAC1B,KAAKA,IAAAA,EAAE,OAAO,EAAE,SAAS;CACzB,UAAUA,IAAAA,EAAE,OAAO;CACnB,KAAKA,IAAAA,EAAE,OAAO;CACd,WAAWA,IAAAA,EAAE,OAAO;CACpB,WAAWA,IAAAA,EAAE,OAAO;CACpB,YAAYA,IAAAA,EAAE,OAAO,EAAE,SAAS;CAChC,eAAeA,IAAAA,EAAE,MAAM,yBAAyB;CAChD,SAASA,IAAAA,EAAE,OAAO;AACnB,CAAC,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCT,MAAM,wBAAwBA,IAAAA,EAAE,OAAO;CACtC,MAAMA,IAAAA,EAAE,QAAQ,OAAO;CACvB,IAAIA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC;CACpB,MAAMA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC;CACtB,QAAQA,IAAAA,EAAE,OAAOA,IAAAA,EAAE,OAAO,GAAGA,IAAAA,EAAE,QAAQ,CAAC,EAAE,SAAS;AACpD,CAAC,EAAE,OAAO;AACV,MAAM,yBAAyBA,IAAAA,EAAE,OAAO;CACvC,MAAMA,IAAAA,EAAE,QAAQ,QAAQ;CACxB,IAAIA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC;CACpB,MAAMA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC;CACtB,MAAMA,IAAAA,EAAE,QAAQ;AACjB,CAAC,EAAE,OAAO;;;;;;AAMV,MAAM,4BAA4BA,IAAAA,EAAE,OAAO;CAC1C,MAAMA,IAAAA,EAAE,QAAQ,WAAW;CAC3B,SAASA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC;CACzB,gBAAgBA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC;CAChC,QAAQA,IAAAA,EAAE,OAAOA,IAAAA,EAAE,OAAO,GAAGA,IAAAA,EAAE,QAAQ,CAAC,EAAE,SAAS;AACpD,CAAC,EAAE,OAAO;AACV,MAAM,8BAA8BA,IAAAA,EAAE,OAAO;CAC5C,MAAMA,IAAAA,EAAE,QAAQ,aAAa;CAC7B,gBAAgBA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC;AACjC,CAAC,EAAE,OAAO;;;;;;;AAOV,MAAM,4BAA4BA,IAAAA,EAAE,OAAO;CAC1C,MAAMA,IAAAA,EAAE,QAAQ,YAAY;CAC5B,KAAKA,IAAAA,EAAE,OAAO,EAAE,IAAI;CACpB,gBAAgBA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC;AACjC,CAAC,EAAE,OAAO;;;;;;;AAOV,MAAM,0BAA0BA,IAAAA,EAAE,OAAO;CACxC,MAAMA,IAAAA,EAAE,QAAQ,UAAU;CAC1B,OAAOA,IAAAA,EAAE,KAAK;EACb;EACA;EACA;CACD,CAAC;CACD,SAASA,IAAAA,EAAE,OAAOA,IAAAA,EAAE,OAAO,GAAGA,IAAAA,EAAE,QAAQ,CAAC,EAAE,SAAS;AACrD,CAAC,EAAE,OAAO;AACeA,IAAAA,EAAE,mBAAmB,QAAQ;CACrD;CACA;CACA;CACA;CACA;CACA;AACD,CAAC;;;;;;AAMD,MAAM,2BAA2BA,IAAAA,EAAE,mBAAmB,MAAM,CAACA,IAAAA,EAAE,OAAO;CACrE,MAAMA,IAAAA,EAAE,QAAQ,UAAU;CAC1B,IAAIA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC;CACpB,IAAIA,IAAAA,EAAE,QAAQ,IAAI;CAClB,MAAMA,IAAAA,EAAE,QAAQ;AACjB,CAAC,EAAE,OAAO,GAAGA,IAAAA,EAAE,OAAO;CACrB,MAAMA,IAAAA,EAAE,QAAQ,UAAU;CAC1B,IAAIA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC;CACpB,IAAIA,IAAAA,EAAE,QAAQ,KAAK;CACnB,OAAOA,IAAAA,EAAE,OAAO;EACf,MAAMA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC;EACtB,SAASA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC;CAC1B,CAAC,EAAE,OAAO;AACX,CAAC,EAAE,OAAO,CAAC,CAAC;AACZ,MAAM,wBAAwBA,IAAAA,EAAE,OAAO;CACtC,MAAMA,IAAAA,EAAE,QAAQ,OAAO;CACvB,gBAAgBA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC;CAChC,SAASA,IAAAA,EAAE,QAAQ;AACpB,CAAC,EAAE,OAAO;AACV,MAAM,8BAA8BA,IAAAA,EAAE,OAAO;CAC5C,MAAMA,IAAAA,EAAE,QAAQ,cAAc;CAC9B,gBAAgBA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC;CAChC,QAAQA,IAAAA,EAAE,OAAOA,IAAAA,EAAE,OAAO,GAAGA,IAAAA,EAAE,QAAQ,CAAC,EAAE,SAAS;AACpD,CAAC,EAAE,OAAO;;;;;;;AAOV,MAAM,0BAA0BA,IAAAA,EAAE,OAAO;CACxC,MAAMA,IAAAA,EAAE,QAAQ,cAAc;CAC9B,SAASA,IAAAA,EAAE,OAAO;EACjB,KAAKA,IAAAA,EAAE,OAAO;EACd,UAAUA,IAAAA,EAAE,OAAO;GAClB,GAAGA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;GAChC,GAAGA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;EACjC,CAAC,EAAE,OAAO;EACV,OAAOA,IAAAA,EAAE,KAAK,CAAC,SAAS,MAAM,CAAC;CAChC,CAAC,EAAE,OAAO;AACX,CAAC,EAAE,OAAO;AACeA,IAAAA,EAAE,MAAM;CAChC;CACA;CACA;CACA;AACD,CAAC;;;;;;;;;;AAiCD,MAAM,mBAAmBA,IAAAA,EAAE,mBAAmB,QAAQ;CACrDA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,MAAM;EACtB,WAAWA,IAAAA,EAAE,OAAO;EACpB,OAAOA,IAAAA,EAAE,OAAO;EAChB,gBAAgBA,IAAAA,EAAE,OAAO;EACzB,cAAcA,IAAAA,EAAE,OAAO;CACxB,CAAC,EAAE,MAAM;CACTA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,MAAM;EACtB,MAAMA,IAAAA,EAAE,OAAO;CAChB,CAAC,EAAE,MAAM;CACTA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,UAAU;EAC1B,MAAMA,IAAAA,EAAE,OAAO;EACf,SAASA,IAAAA,EAAE,OAAO;CACnB,CAAC,EAAE,MAAM;CACTA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,aAAa;EAC7B,IAAIA,IAAAA,EAAE,QAAQ;CACf,CAAC,EAAE,MAAM;CACTA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,UAAU;EAC1B,MAAMA,IAAAA,EAAE,OAAO;CAChB,CAAC,EAAE,MAAM;CACTA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,UAAU;EAC1B,OAAOA,IAAAA,EAAE,OAAO;EAChB,UAAUA,IAAAA,EAAE,OAAO;EACnB,SAASA,IAAAA,EAAE,OAAO,EAAE,SAAS;EAC7B,SAASA,IAAAA,EAAE,MAAMA,IAAAA,EAAE,OAAO,CAAC,EAAE,SAAS;CACvC,CAAC,EAAE,MAAM;CACTA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,OAAO;EACvB,SAASA,IAAAA,EAAE,OAAO;CACnB,CAAC,EAAE,MAAM;CACTA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,QAAQ;EACxB,SAASA,IAAAA,EAAE,OAAO;EAClB,UAAUA,IAAAA,EAAE,OAAO;EACnB,cAAcA,IAAAA,EAAE,OAAO;EACvB,YAAYA,IAAAA,EAAE,OAAO;EACrB,QAAQA,IAAAA,EAAE,MAAMA,IAAAA,EAAE,OAAO,CAAC,EAAE,SAAS;CACtC,CAAC,EAAE,MAAM;CACTA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,gBAAgB;EAChC,QAAQA,IAAAA,EAAE,KAAK;GACd;GACA;GACA;GACA;EACD,CAAC;EACD,MAAMA,IAAAA,EAAE,OAAO,EAAE,SAAS;EAC1B,WAAWA,IAAAA,EAAE,OAAO,EAAE,SAAS;EAC/B,YAAYA,IAAAA,EAAE,OAAO,EAAE,SAAS;CACjC,CAAC,EAAE,MAAM;AACV,CAAC;;;;;;;;;;AAUD,SAAS,eAAe,cAAc;CACrC,OAAO,iBAAiB;AACzB;;;;;;;;;;;;;;;;;AAkFA,MAAM,aAAaA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,kBAAkB;AACrE,MAAM,sBAAsBA,IAAAA,EAAE,mBAAmB,QAAQ;CACxDA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,WAAW;EAC3B,YAAY;CACb,CAAC;CACDA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,aAAa;EAC7B,YAAY;CACb,CAAC;CACDA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,cAAc;EAC9B,YAAY;EACZ,SAASA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;CACnC,CAAC;CACDA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,cAAc;EAC9B,OAAOA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;EAC/B,QAAQA,IAAAA,EAAE,OAAO,EAAE,IAAI,GAAG;CAC3B,CAAC;CACDA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,WAAW;EAC3B,YAAY;CACb,CAAC;CACDA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,cAAc;EAC9B,YAAY;CACb,CAAC;CACDA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,iBAAiB;EACjC,YAAY;CACb,CAAC;CACDA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,gBAAgB;EAChC,YAAY;CACb,CAAC;CACDA,IAAAA,EAAE,OAAO,EAAE,MAAMA,IAAAA,EAAE,QAAQ,mBAAmB,EAAE,CAAC;CACjDA,IAAAA,EAAE,OAAO,EAAE,MAAMA,IAAAA,EAAE,QAAQ,qBAAqB,EAAE,CAAC;CACnDA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,iBAAiB;EACjC,SAASA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,SAAS;CACtC,CAAC;CACDA,IAAAA,EAAE,OAAO,EAAE,MAAMA,IAAAA,EAAE,QAAQ,iBAAiB,EAAE,CAAC;CAC/CA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,oBAAoB;EACpC,mBAAmBA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS;EACvD,uBAAuBA,IAAAA,EAAE,MAAMA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,CAAC,EAAE,IAAI,EAAE;CAClE,CAAC;CACDA,IAAAA,EAAE,OAAO,EAAE,MAAMA,IAAAA,EAAE,QAAQ,MAAM,EAAE,CAAC;AACrC,CAAC;AACD,MAAM,qBAAqBA,IAAAA,EAAE,mBAAmB,QAAQ,CAACA,IAAAA,EAAE,OAAO,EAAE,MAAMA,IAAAA,EAAE,QAAQ,uBAAuB,EAAE,CAAC,EAAE,MAAM,GAAGA,IAAAA,EAAE,OAAO,EAAE,MAAMA,IAAAA,EAAE,QAAQ,0BAA0B,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;;;;;;;;AAQ3L,MAAM,0BAA0BA,IAAAA,EAAE,KAAK;CACtC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD,CAAC;AAY2BA,IAAAA,EAAE,mBAAmB,QAAQ;CACxDA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,OAAO;EACvB,YAAYA,IAAAA,EAAE,OAAO;EACrB,OAAO;CACR,CAAC,EAAE,MAAM;CACTA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,MAAM;EACtB,YAAYA,IAAAA,EAAE,OAAO;CACtB,CAAC,EAAE,MAAM;CACTA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,OAAO;EACvB,YAAYA,IAAAA,EAAE,OAAO,EAAE,SAAS;EAChC,SAASA,IAAAA,EAAE,OAAO;CACnB,CAAC,EAAE,MAAM;CACTA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,gBAAgB;EAChC,YAAYA,IAAAA,EAAE,OAAO;EACrB,OAAO;EACP,WAAWA,IAAAA,EAAE,OAAO,EAAE,SAAS;EAC/B,WAAWA,IAAAA,EAAE,MAAMA,IAAAA,EAAE,OAAO,CAAC,EAAE,SAAS;EACxC,SAASA,IAAAA,EAAE,OAAO,EAAE,SAAS;EAC7B,cAAcA,IAAAA,EAAE,OAAO,EAAE,SAAS;CACnC,CAAC,EAAE,MAAM;CACTA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,eAAe;EAC/B,OAAO;CACR,CAAC,EAAE,MAAM;CACTA,IAAAA,EAAE,OAAO;EACR,MAAMA,IAAAA,EAAE,QAAQ,kBAAkB;EAClC,SAASA,IAAAA,EAAE,QAAQ;EACnB,SAASA,IAAAA,EAAE,OAAO,EAAE,SAAS;CAC9B,CAAC,EAAE,MAAM;CACTA,IAAAA,EAAE,OAAO,EAAE,MAAMA,IAAAA,EAAE,QAAQ,MAAM,EAAE,CAAC,EAAE,MAAM;AAC7C,CAAC;;;;;;;;;;;;;;AC1rBD,MAAM,wBAAwB,IAAI,IAAI;AACtC,IAAI,aAAa;;AAEjB,SAAS,aAAa,KAAK,IAAI;CAC9B,MAAM,OAAO,MAAM,IAAI,GAAG,KAAK,QAAQ,QAAQ,GAAG,KAAK,IAAI,EAAE;CAC7D,MAAM,OAAO,IAAI,WAAW,CAAC,SAAS,CAAC,CAAC;CACxC,MAAM,IAAI,KAAK,IAAI;CACnB,KAAK,WAAW;EACf,IAAI,MAAM,IAAI,GAAG,MAAM,MAAM,MAAM,OAAO,GAAG;CAC9C,CAAC;CACD,OAAO;AACR;;;;;;AAMA,eAAe,gBAAgB,MAAM,MAAM,MAAM;CAChD,OAAA,GAAA,iBAAA,QAAA,GAAA,UAAA,SAAoB,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;CAC9C,MAAM,MAAM,GAAG,KAAK,OAAO,QAAQ,IAAI,GAAG;CAC1C,IAAI;EACH,OAAA,GAAA,iBAAA,WAAgB,KAAK,MAAM,SAAS,KAAK,IAAI,EAAE,KAAK,IAAI,KAAK,CAAC;EAC9D,OAAA,GAAA,iBAAA,QAAa,KAAK,IAAI;CACvB,SAAS,KAAK;EACb,OAAA,GAAA,iBAAA,IAAS,KAAK,EAAE,OAAO,KAAK,CAAC,EAAE,YAAY,CAAC,CAAC;EAC7C,MAAM;CACP;AACD;AACA,MAAM,wBAAwBC,IAAAA,EAAE,OAAO;CACtC,YAAYA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,MAAM,iCAAiC,qBAAqB;CACnG,uBAAuBA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;CACrD,uBAAuBA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,GAAG;CACjD,kBAAkBA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS;CACtD,gBAAgB;CAChB,uBAAuBA,IAAAA,EAAE,MAAMA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,CAAC,EAAE,IAAI,EAAE;AAClE,CAAC;AACkC,sBAAsB,QAAQ;AACjE,MAAM,mBAAmB;CACxB,YAAY;CACZ,uBAAuB;CACvB,uBAAuB;CACvB,kBAAkB;CAClB,gBAAgB;CAChB,uBAAuB,CAAC;AACzB;AACA,IAAI,gBAAgB,MAAM;CACzB;CACA,YAAY,aAAa;EACxB,KAAK,cAAc;CACpB;CACA,OAAO;EACN,QAAA,GAAA,UAAA,MAAY,KAAK,aAAa,aAAa,aAAa;CACzD;CACA,MAAM,OAAO;EACZ,MAAM,OAAO,KAAK,KAAK;EACvB,IAAI,EAAA,GAAA,QAAA,YAAY,IAAI,GAAG,OAAO;EAC9B,IAAI;GACH,MAAM,MAAM,OAAA,GAAA,iBAAA,UAAe,MAAM,MAAM;GACvC,MAAM,SAAS;IACd,GAAG;IACH,GAAG,KAAK,MAAM,GAAG;GAClB;GACA,OAAO,sBAAsB,MAAM,MAAM;EAC1C,QAAQ;GACP,OAAO;EACR;CACD;CACA,MAAM,MAAM,OAAO;EAClB,MAAM,OAAO,KAAK,KAAK;EACvB,OAAO,aAAa,MAAM,YAAY;GACrC,MAAM,UAAU,MAAM,KAAK,KAAK;GAChC,MAAM,OAAO,sBAAsB,MAAM;IACxC,GAAG;IACH,GAAG;GACJ,CAAC;GACD,MAAM,gBAAgB,MAAM,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;GACzD,OAAO;EACR,CAAC;CACF;AACD;AAGA;CACC,MAAM,OAAO;CACb,MAAM,eAAe,KAAK,KAAK,KAAK,IAAI;CACxC,KAAK,QAAQ,OAAO,GAAG,SAAS;EAC/B,IAAI,UAAU,WAAW;GACxB,MAAM,UAAU,KAAK;GACrB,IAAI,mBAAmB,SAAS,QAAQ,SAAS,yBAAyB,QAAQ,QAAQ,WAAW,mCAAmC,GAAG,OAAO;EACnJ;EACA,OAAO,aAAa,OAAO,GAAG,IAAI;CACnC;AACD;;;;;;;;;;;;;;;;;;;;;;AAsBA,MAAM,gBAAgB,OAAO,IAAI,aAAa;AAC9C,MAAM,YAAA,QAAA,KAAA,EAAA,cAAA,UAAA,EAAA;AACN,MAAM,wBAAwB;CAC7B,MAAM,OAAO,aAAA,GAAA,UAAA,UAAA,GAAA,SAAA,eAAkC,SAAS,CAAC,IAAI;CAC7D,MAAM,aAAa;yBACV,MAAM,MAAM,SAAS;yBACrB,MAAM,MAAM,MAAM,MAAM,SAAS;yBACjC,MAAM,MAAM,MAAM,MAAM,MAAM,SAAS;CAChD;CACA,OAAO,WAAW,MAAM,OAAA,GAAA,QAAA,aAAA,GAAA,UAAA,SAAyB,GAAG,QAAQ,eAAe,CAAC,CAAC,KAAK,WAAW;AAC9F,GAAG;;;;;;;;AAQH,SAAS,YAAY,KAAK;CACzB,QAAA,GAAA,yBAAA,SAAe,OAAO,KAAK,QAAQ,WAAW;EAC7C,MAAM,OAAO,IAAI,QAAQ,GAAG;EAC5B,IAAI,WAAW,OAAO;GACrB,MAAM,OAAO,KAAK,IAAI,GAAG,MAAM;GAC/B,OAAO,EAAE,MAAM,CAAC;IACf,SAAS,OAAO,KAAK,OAAO;IAC5B,iBAAiB,KAAK;GACvB,CAAC,EAAE;EACJ;EACA,MAAM,OAAO,KAAK,IAAI,GAAG,MAAM;EAC/B,MAAM,UAAU,KAAK,QAAQ,EAAE,KAAK,MAAM,EAAE,UAAU,EAAE,IAAI;EAC5D,MAAM,YAAY,KAAK,KAAK,MAAM,QAAQ,KAAK,MAAM,EAAE,MAAM,IAAI,CAAC;EAClE,IAAI,WAAW,OAAO,OAAO,EAAE,MAAM,UAAU,MAAM,CAAC,EAAE;EACxD,OAAO,EAAE,MAAM,UAAU;CAC1B,GAAG,EAAE,QAAA,eAAO,CAAC;AACd;;;;;;;;AAQA,SAAS,cAAc,KAAK,eAAe;CAC1C,MAAM,eAAA,GAAA,UAAA,MAAmB,eAAe,QAAQ,eAAe;CAC/D,IAAI,EAAA,GAAA,QAAA,YAAY,WAAW,GAAG;EAC7B,QAAQ,KAAK,sCAAsC,cAAc,kFAAkF;EACnJ;CACD;CACA,IAAI,KAAK;;;;OAIH;CACN,MAAM,gBAAgB,KAAK,OAAA,GAAA,QAAA,cAAmB,aAAa,MAAM,CAAC,EAAE,QAAQ,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG;CAChH,MAAM,UAAU,UAAU;EACzB,MAAM,OAAA,GAAA,QAAA,eAAA,GAAA,UAAA,MAAwB,eAAe,GAAG,MAAM,IAAI,KAAK,GAAG,MAAM;EACxE,QAAA,GAAA,YAAA,YAAkB,QAAQ,EAAE,OAAO,GAAG,EAAE,OAAO,KAAK;CACrD;CACA,MAAM,SAAS,IAAI,QAAQ,mEAAmE;CAC9F,MAAM,UAAU,IAAI,QAAQ,8EAA8E,EAAE,IAAI;CAChH,IAAI,WAAW,SAAS,cAAc,OAAO,OAAO,QAAQ,UAAU,IAAI;CAC1E,IAAI,YAAY,QAAQ,cAAc,SAAS;MAC1C,IAAI,QAAQ,yEAAyE,EAAE,IAAI,GAAG;GACjG,KAAK,MAAM,SAAS,eAAe,OAAO,IAAI,OAAO,KAAK,GAAG,MAAM,IAAI;GACvE;EACD;;CAED,KAAK,MAAM,SAAS,eAAe;EAClC,IAAI,YAAY,QAAQ,YAAY,MAAM,MAAM;EAChD,MAAM,OAAA,GAAA,QAAA,eAAA,GAAA,UAAA,MAAwB,eAAe,GAAG,MAAM,IAAI,KAAK,GAAG,MAAM;EACxE,MAAM,aAAa,IAAI,MAAM,0BAA0B,EAAE,KAAK,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,OAAO;EAC5F,KAAK,MAAM,QAAQ,YAAY,IAAI,KAAK,IAAI;EAC5C,OAAO,KAAA,GAAA,YAAA,YAAe,QAAQ,EAAE,OAAO,GAAG,EAAE,OAAO,KAAK,GAAG,MAAM,IAAI;EACrE,WAAW,MAAM;CAClB;AACD;AACA,SAAS,MAAM,aAAa;CAC3B,MAAM,IAAI;CACV,IAAI,CAAC,EAAE,gBAAgB,EAAE,iCAAiC,IAAI,IAAI;CAClE,MAAM,QAAQ,EAAE;CAChB,MAAM,QAAA,GAAA,UAAA,SAAe,WAAW;CAChC,MAAM,WAAW,MAAM,IAAI,IAAI;CAC/B,IAAI,UAAU,OAAO,SAAS;CAC9B,MAAM,UAAA,GAAA,UAAA,MAAc,MAAM,aAAa,WAAW;CAClD,MAAM,eAAA,GAAA,UAAA,SAAsB,MAAM;CAClC,CAAA,GAAA,QAAA,WAAU,aAAa,EAAE,WAAW,KAAK,CAAC;CAC1C,MAAM,UAAA,GAAA,UAAA,MAAc,aAAa,YAAY;CAC7C,IAAI,EAAA,GAAA,QAAA,YAAY,MAAM,GAAG,IAAI;EAC5B,CAAA,GAAA,QAAA,eAAc,QAAQ,KAAK;CAC5B,QAAQ,CAAC;CACT,MAAM,MAAM,IAAIC,YAAAA,aAAa,MAAM;CACnC,IAAI,KAAK,2BAA2B;CACpC,IAAI,KAAK,4BAA4B;CACrC,IAAI,KAAK,0BAA0B;CACnC,cAAc,KAAK,cAAc;CACjC,IAAI,KAAK,yBAAyB;CAClC,MAAM,KAAK,YAAY,GAAG;CAC1B,MAAM,IAAI,MAAM;EACf;EACA;CACD,CAAC;CACD,OAAO;AACR;;;;;;;;;;;;;AAeA,SAAS,cAAc,KAAK,MAAM,OAAO,CAAC,GAAG;CAC5C,OAAO,WAAW,OAAO,MAAM,KAAK,IAAI;AACzC;;;;;;;;AAQA,SAAS,WAAW,MAAM,MAAM,KAAK,OAAO,CAAC,GAAG;CAC/C,OAAO,IAAI,SAAS,SAAS,WAAW;EACvC,MAAM,SAAA,GAAA,mBAAA,OAAc,MAAM,MAAM;GAC/B;GACA,OAAO;EACR,CAAC;EACD,IAAI,SAAS;EACb,IAAI,SAAS;EACb,IAAI,SAAS;EACb,MAAM,MAAM,KAAK;EACjB,MAAM,OAAO,GAAG,SAAS,MAAM;GAC9B,IAAI,QAAQ;GACZ,UAAU,EAAE,SAAS,MAAM;GAC3B,IAAI,QAAQ,KAAK,KAAK,OAAO,UAAU,KAAK;IAC3C,SAAS,OAAO,MAAM,GAAG,GAAG;IAC5B,SAAS;IACT,MAAM,KAAK;GACZ;EACD,CAAC;EACD,MAAM,OAAO,GAAG,SAAS,MAAM;GAC9B,UAAU,EAAE,SAAS,MAAM;EAC5B,CAAC;EACD,MAAM,GAAG,SAAS,MAAM;EACxB,MAAM,GAAG,UAAU,SAAS,QAAQ;GACnC,MAAM,QAAQ;GACd;GACA;GACA;EACD,CAAC,CAAC;CACH,CAAC;AACF;;;;;;;AAOA,SAAS,OAAO,KAAK,MAAM,SAAS;CACnC,OAAO,IAAI,SAAS,KAAK,QAAQ;EAChC,MAAM,SAAA,GAAA,mBAAA,OAAc,OAAO,MAAM;GAChC;GACA,OAAO;EACR,CAAC;EACD,IAAI,SAAS;EACb,MAAM,OAAO,GAAG,SAAS,MAAM;GAC9B,UAAU,EAAE,SAAS,MAAM;EAC5B,CAAC;EACD,MAAM,GAAG,SAAS,GAAG;EACrB,MAAM,GAAG,UAAU,SAAS;GAC3B,IAAI,SAAS,GAAG,IAAI;QACf;IACJ,UAAU,SAAS,sBAAsB,KAAK,KAAK,GAAG,EAAE,UAAU,KAAK,IAAI,OAAO,GAAG,EAAE,YAAY,CAAC,CAAC;IACrG,oBAAoB,IAAI,MAAM,OAAO,KAAK,KAAK,GAAG,EAAE,UAAU,KAAK,IAAI,OAAO,KAAK,GAAG,CAAC;GACxF;EACD,CAAC;CACF,CAAC;AACF;;AAmBA,eAAe,UAAU,MAAM,MAAM;CACpC,IAAI,CAAC,MAAM;CACX,MAAM,IAAI,OAAA,GAAA,iBAAA,MAAW,MAAM,GAAG;CAC9B,IAAI;EACH,MAAM,EAAE,MAAM,IAAI;CACnB,UAAU;EACT,MAAM,EAAE,MAAM;CACf;AACD;;;;;;;;;;;;;;;;;AAmBA,MAAM,oBAAoBD,IAAAA,EAAE,OAAO;CAClC,QAAQA,IAAAA,EAAE,OAAO;EAChB,OAAOA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC;;EAEvB,OAAOA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC;CACxB,CAAC,EAAE,SAAS,EAAE,SAAS;CACvB,WAAWA,IAAAA,EAAE,OAAO,EAAE,KAAKA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,SAAS;AACrE,CAAC,EAAE,QAAQ,CAAC,CAAC;AACb,IAAI,eAAe,MAAM;CACxB;CACA,YAAY,aAAa;EACxB,KAAK,cAAc;CACpB;CACA,OAAO;EACN,QAAA,GAAA,UAAA,MAAY,KAAK,aAAa,aAAa,cAAc;CAC1D;;CAEA,MAAM,OAAO;EACZ,MAAM,OAAO,KAAK,KAAK;EACvB,IAAI,EAAA,GAAA,QAAA,YAAY,IAAI,GAAG,OAAO,kBAAkB,MAAM,CAAC,CAAC;EACxD,IAAI;GACH,MAAM,MAAM,OAAA,GAAA,iBAAA,UAAe,MAAM,MAAM;GACvC,OAAO,kBAAkB,MAAM,KAAK,MAAM,GAAG,CAAC;EAC/C,QAAQ;GACP,OAAO,kBAAkB,MAAM,CAAC,CAAC;EAClC;CACD;CACA,MAAM,MAAM,OAAO;EAClB,MAAM,OAAO,KAAK,KAAK;EACvB,OAAO,aAAa,MAAM,YAAY;GACrC,MAAM,OAAO;IACZ,GAAG,MAAM,KAAK,KAAK;IACnB,GAAG;GACJ;GACA,MAAM,gBAAgB,MAAM,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG,GAAG;GAC9D,OAAO;EACR,CAAC;CACF;CACA,MAAM,UAAU,OAAO,OAAO;EAC7B,MAAM,KAAK,MAAM,EAAE,QAAQ;GAC1B;GACA;EACD,EAAE,CAAC;CACJ;CACA,MAAM,cAAc;EACnB,MAAM,KAAK,MAAM,EAAE,QAAQ,KAAK,CAAC;CAClC;CACA,MAAM,aAAa,KAAK;EACvB,MAAM,KAAK,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;CACxC;CACA,MAAM,iBAAiB;EACtB,MAAM,KAAK,MAAM,EAAE,WAAW,KAAK,CAAC;CACrC;CACA,MAAM,iBAAiB;EACtB,QAAQ,MAAM,KAAK,KAAK,GAAG,QAAQ,SAAS;CAC7C;CACA,MAAM,kBAAkB;EACvB,QAAQ,MAAM,KAAK,KAAK,GAAG,WAAW,OAAO;CAC9C;;CAEA,MAAM,cAAc;EACnB,MAAM,IAAI,MAAM,KAAK,KAAK;EAC1B,OAAO;GACN,QAAQ;IACP,WAAW,QAAQ,EAAE,MAAM;IAC3B,OAAO,EAAE,QAAQ,SAAS;GAC3B;GACA,WAAW,EAAE,QAAQ,QAAQ,EAAE,SAAS,EAAE;EAC3C;CACD;AACD;;;;;;;;;;;;;;;AAiBA,eAAe,iBAAiB,aAAa,OAAO;CACnD,IAAI;EACH,MAAM,MAAM,WAAW,EAAE,OAAO,WAAW,EAAE,OAAO;GACnD,gBAAgB,MAAM,kBAAkB;GACxC,OAAO,MAAM;GACb,QAAQ,MAAM;GACd,SAAS,MAAM,WAAW,CAAC;EAC5B,CAAC;CACF,QAAQ,CAAC;AACV;;;;;;;;;;AC3aA,eAAe,yBAAyB,aAAa;CACpD,MAAM,WAAW,8BAA8B,QAAQ,GAAG;CAC1D,IAAI,UAAU,OAAO;CACrB,OAAO,qBAAqB,MAAM,IAAI,cAAc,WAAW,EAAE,KAAK,GAAG,cAAc;AACxF;AACA,SAAS,sBAAsB,KAAK;CACnC,MAAM,IAAI,IAAI;CACd,IAAI,MAAM,aAAa,MAAM,iBAAiB,MAAM,uBAAuB,MAAM,UAAU,MAAM,aAAa,MAAM,QAAQ,OAAO;CACnI,OAAO;AACR;;;;;;;;AAQA,SAAS,8BAA8B,KAAK;CAC3C,IAAI,CAAC,IAAI,gCAAgC,OAAO;CAChD,OAAO,sBAAsB,GAAG;AACjC;;;;;;;AAOA,SAAS,oBAAoB,MAAM;CAClC,OAAO,yBAAyB,MAAM,MAAM,EAAE,gBAAgB,IAAI,GAAG,WAAW;AACjF;AAGA,MAAM,mBAAmB;AACzB,MAAM,gBAAgB;AACtB,IAAI,iBAAiB,MAAM;CAC1B;CACA;CACA,YAAY,YAAY,aAAa;EACpC,KAAK,aAAa;EAClB,KAAK,cAAc;CACpB;;;;;;;;;CASA,MAAM,QAAQ,OAAO;EACpB,IAAI;GACH,MAAM,MAAM,KAAK,WAAW,EAAE,OAAO,QAAQ,EAAE,OAAO;IACrD,gBAAgB,KAAK;IACrB,MAAM;IACN,MAAM,MAAM;IACZ,SAAS;GACV,CAAC;EACF,QAAQ,CAAC;CACV;;;;;;;;;;;CAWA,UAAU,KAAK;EACd,IAAI,aAAa;EACjB,IAAI,UAAU;EACd,IAAI,UAAU;EACd,MAAM,OAAO,YAAY;GACxB,IAAI,WAAW,SAAS;GACxB,UAAU;GACV,IAAI;IACH,MAAM,OAAO,MAAM,MAAM,KAAK,WAAW,EAAE,OAAO,EAAE,KAAK,QAAQ,EAAE,OAAA,GAAA,YAAA,MAAA,GAAA,YAAA,IAAiB,SAAS,gBAAgB,KAAK,UAAU,IAAA,GAAA,YAAA,IAAM,SAAS,IAAI,UAAU,CAAC,CAAC,EAAE,SAAA,GAAA,YAAA,KAAc,SAAS,EAAE,CAAC;IACvL,KAAK,MAAM,OAAO,MAAM;KACvB,IAAI,SAAS;KACb,aAAa,IAAI;KACjB,IAAI,IAAI,SAAS,eAAe;MAC/B,UAAU;MACV,cAAc,QAAQ;MACtB,IAAI;OACH,IAAI,QAAQ;MACb,QAAQ,CAAC;MACT;KACD;KACA,IAAI;MACH,IAAI,QAAQ,IAAI,OAAO;KACxB,QAAQ,CAAC;IACV;GACD,QAAQ,CAAC,UAAU;IAClB,UAAU;GACX;EACD;EACA,KAAK;EACL,MAAM,WAAW,kBAAkB;GAClC,KAAK;EACN,GAAG,gBAAgB;EACnB,aAAa;GACZ,UAAU;GACV,cAAc,QAAQ;EACvB;CACD;;;;;;;CAOA,MAAM,eAAe;EACpB,IAAI;GACH,MAAM,MAAM,KAAK,WAAW,EAAE,OAAO,QAAQ,EAAE,OAAO;IACrD,gBAAgB,KAAK;IACrB,MAAM;IACN,MAAM;IACN,SAAS,CAAC;GACX,CAAC;EACF,QAAQ,CAAC;CACV;AACD;;;;;;;AAOA,MAAM,eAAe,OAAO,IAAI,2BAA2B;AAC3D,MAAM,QAAQ,WAAW,iCAAiC,IAAI,IAAI;AAClE,WAAW,gBAAgB;AAC3B,SAAS,eAAe,YAAY,aAAa;CAChD,MAAM,OAAO,eAAe,QAAQ,IAAI,yBAAyB,QAAQ,IAAI;CAC7E,IAAI,MAAM,MAAM,IAAI,UAAU;CAC9B,IAAI,CAAC,KAAK;EACT,MAAM,IAAI,eAAe,YAAY,IAAI;EACzC,MAAM,IAAI,YAAY,GAAG;CAC1B;CACA,OAAO;AACR;;;;;;;;;;;;;;;;;;;;AAsBA,MAAM,aAAa,MAAM;;;;;;;;AAQzB,MAAM,0BAA0B,IAAI,IAAI;AACxC,MAAM,qBAAqB;AAC3B,MAAM,cAAc;CACnB,UAAUE,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS,wDAAwD;CACtG,SAASA,IAAAA,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,SAAS,EAAE,SAAS,wHAAwH;CACzK,SAASA,IAAAA,EAAE,MAAMA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS,EAAE,SAAS,6HAA6H;AACtM;;;;;;AAMA,SAAS,uBAAuB,YAAY;CAC3C,QAAA,GAAA,+BAAA,oBAA0B;EACzB,MAAM;EACN,SAAS;EACT,OAAO,EAAA,GAAA,+BAAA,MAAM,YAAY;GACxB;GACA;GACA;GACA;EACD,EAAE,KAAK,GAAG,GAAG,aAAa,OAAO,SAAS;GACzC,MAAM,SAAA,GAAA,OAAA,QAAe,EAAE;GACvB,MAAM,MAAM,eAAe,UAAU;GACrC,OAAO,EAAE,SAAS,CAAC;IAClB,MAAM;IACN,MAAM,MAAM,IAAI,SAAS,SAAS,WAAW;KAC5C,MAAM,UAAU,iBAAiB;MAChC,QAAQ,OAAO,KAAK;MACpB,QAAQ,IAAI,oBAAoB,UAAU;MAC1C,uBAAuB,IAAI,MAAM,4BAA4B,aAAa,IAAI,mBAAmB,CAAC;KACnG,GAAG,UAAU;KACb,MAAM,cAAc,YAAY;MAC/B,IAAI,QAAQ,UAAU,OAAO;MAC7B,MAAM,QAAQ,QAAQ,IAAI,KAAK;MAC/B,IAAI,OAAO,MAAM,QAAQ,QAAQ,MAAM;KACxC;KACA,QAAQ,GAAG,oBAAoB,UAAU;KACzC,QAAQ,IAAI,OAAO;MAClB;MACA,UAAU,MAAM;OACf,aAAa,OAAO;OACpB,QAAQ,OAAO,KAAK;OACpB,QAAQ,IAAI,oBAAoB,UAAU;OAC1C,QAAQ,CAAC;MACV;MACA,SAAS,WAAW;OACnB,aAAa,OAAO;OACpB,QAAQ,OAAO,KAAK;OACpB,QAAQ,IAAI,oBAAoB,UAAU;OAC1C,OAAO,IAAI,MAAM,MAAM,CAAC;MACzB;MACA;KACD,CAAC;KACD,IAAI,QAAQ;MACX,MAAM;MACN;MACA,UAAU,KAAK;MACf,SAAS,KAAK;MACd,SAAS,KAAK;KACf,CAAC;IACF,CAAC;GACF,CAAC,EAAE;EACJ,CAAC,CAAC;CACH,CAAC;AACF;;;;;;;;;;AAUA,SAAS,WAAW,OAAO,QAAQ;CAClC,MAAM,QAAQ,QAAQ,IAAI,KAAK;CAC/B,IAAI,OAAO;EACV,MAAM,QAAQ,MAAM;EACpB,OAAO;CACR;CACA,MAAM,UAAU;EACf;EACA;CACD;CACA,QAAQ,KAAK,oBAAoB,OAAO;CACxC,OAAO;AACR;;;;;;AAMA,SAAS,UAAU,YAAY,QAAQ;CACtC,KAAK,MAAM,CAAC,OAAO,UAAU,QAAQ,QAAQ,GAAG,IAAI,MAAM,eAAe,YAAY;EACpF,MAAM,OAAO,MAAM;EACnB,QAAQ,OAAO,KAAK;CACrB;AACD;;;;;;;AAOA,MAAM,qBAAqB;AAG3B,MAAM,mBAAmB,OAAO,IAAI,kCAAkC;AACtE,MAAM,YAAY,WAAW,qCAAqC,IAAI,IAAI;AAC1E,WAAW,oBAAoB;AAC/B,SAAS,kBAAkB,OAAO;CACjC,KAAK,MAAM,YAAY,WAAW,IAAI;EACrC,SAAS,KAAK;CACf,QAAQ,CAAC;AACV;AACA,SAAS,gBAAgB,UAAU;CAClC,UAAU,IAAI,QAAQ;CACtB,aAAa;EACZ,UAAU,OAAO,QAAQ;CAC1B;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,MAAM,uBAAuB;;;;;;AAM7B,MAAM,oBAAoB;AAC1B,MAAM,oBAAoB,CAAC,mBAAmB,gBAAgB;;AAE9D,SAAS,gBAAgB;CACxB,OAAO,QAAQ,IAAI,2BAA2B,KAAK,KAAK;AACzD;;;;;;;;AAQA,eAAe,oBAAoB,aAAa;CAC/C,OAAO,MAAM,IAAI,aAAa,WAAW,EAAE,gBAAgB,KAAK,cAAc;AAC/E;;;;;;;;AAQA,eAAe,gBAAgB,aAAa,QAAQ,CAAC,GAAG;CACvD,MAAM,MAAM,EAAE,GAAG,QAAQ,IAAI;CAC7B,OAAO,IAAI;CACX,OAAO,IAAI;CACX,MAAM,MAAM,MAAM,oBAAoB,WAAW;CACjD,IAAI,KAAK,IAAI,qBAAqB;CAClC,OAAO;EACN,GAAG;EACH,GAAG;CACJ;AACD;;;;;;;;;;;;;AAaA,SAAS,gBAAgB,QAAQ,CAAC,GAAG;CACpC,MAAM,MAAM,EAAE,GAAG,QAAQ,IAAI;CAC7B,MAAM,MAAM,cAAc;CAC1B,KAAK,MAAM,KAAK,mBAAmB,OAAO,IAAI;CAC9C,OAAO,IAAI;CACX,IAAI,KAAK,KAAK,MAAM,KAAK,mBAAmB,IAAI,KAAK;CACrD,OAAO;EACN,GAAG;EACH,GAAG;CACJ;AACD;;;;;;;;;;;;;;;;;;;AAqBA,MAAM,kBAAkB,CAAC,aAAa,WAAW;;;;;AAKjD,MAAM,kBAAkB;;;;;;;AAOxB,SAAS,sBAAsB,MAAM,aAAa,OAAO,CAAC,GAAG;CAC5D,IAAI,CAAC,MAAM,OAAO;CAClB,MAAM,QAAA,GAAA,UAAA,SAAe,WAAW;CAChC,MAAM,WAAA,GAAA,UAAA,YAAqB,IAAI,KAAA,GAAA,UAAA,SAAY,IAAI,KAAA,GAAA,UAAA,SAAY,MAAM,IAAI;CACrE,IAAI,CAAC,SAAS,MAAM,OAAO,GAAG,OAAO;CACrC,MAAM,QAAQ,WAAW,KAAK,MAAM;CACpC,IAAI,OAAA,GAAA,UAAA,SAAc,OAAO;CACzB,OAAO,MAAM;EACZ,KAAK,MAAM,YAAY,OAAO;GAC7B,MAAM,aAAA,GAAA,UAAA,SAAoB,KAAK,QAAQ;GACvC,MAAM,UAAU,QAAQ,SAAS;GACjC,IAAI,YAAY,MAAM;IACrB,MAAM,UAAU,KAAK,OAAO;IAC5B,OAAO;KACN;KACA,cAAc,SAAA,GAAA,UAAA,UAAiB,MAAM,SAAS,CAAC;KAC/C,SAAS,QAAQ;KACjB,WAAW,QAAQ;IACpB;GACD;EACD;EACA,IAAI,QAAQ,MAAM;EAClB,MAAM,UAAA,GAAA,UAAA,SAAiB,GAAG;EAC1B,IAAI,WAAW,KAAK;EACpB,MAAM;CACP;CACA,OAAO;AACR;;;;;;AAMA,SAAS,iBAAiB,OAAO;CAChC,OAAO;EACN;EACA;EACA,4BAA4B,MAAM,aAAa,gBAAgB,MAAM,YAAY,4DAA4D,GAAG;EAChJ;EACA,2BAA2B,MAAM,aAAa;EAC9C,MAAM;EACN;CACD,EAAE,KAAK,IAAI;AACZ;;AAEA,SAAS,WAAW,QAAQ;CAC3B,IAAI,CAAC,UAAU,WAAW,gBAAgB,IAAI,OAAO;CACrD,OAAO,CAAC,QAAQ,GAAG,gBAAgB,QAAQ,MAAM,MAAM,MAAM,CAAC;AAC/D;;AAEA,SAAS,QAAQ,MAAM;CACtB,IAAI;EACH,QAAA,GAAA,QAAA,cAAoB,MAAM,MAAM;CACjC,QAAQ;EACP,OAAO;CACR;AACD;;AAEA,SAAS,SAAS,QAAQ,OAAO;CAChC,IAAI,UAAU,QAAQ,OAAO;CAC7B,MAAM,OAAA,GAAA,UAAA,UAAe,QAAQ,KAAK;CAClC,OAAO,QAAQ,MAAM,CAAC,IAAI,WAAW,IAAI,KAAK,EAAA,GAAA,UAAA,YAAY,GAAG;AAC9D;;AAEA,SAAS,KAAK,SAAS;CACtB,IAAI,OAAO,WAAW,SAAS,MAAM,KAAK,iBAAiB,OAAO;EACjE;EACA,WAAW;CACZ;CACA,IAAI,SAAS,QAAQ,MAAM,GAAG,eAAe;CAC7C,OAAO,OAAO,WAAW,QAAQ,MAAM,IAAI,kBAAkB,IAAI,SAAS,OAAO,MAAM,GAAG,GAAG;CAC7F,MAAM,SAAS,OAAO,YAAY,IAAI;CACtC,IAAI,SAAS,GAAG,SAAS,OAAO,MAAM,GAAG,MAAM;CAC/C,OAAO;EACN,SAAS,GAAG,OAAO;EACnB,WAAW;CACZ;AACD;;AAEA,SAAS,QAAQ,MAAM;CACtB,OAAO,KAAK,MAAM,OAAO,EAAE,KAAK,GAAG;AACpC;;;;;;;;;;;;AAcA,SAAS,cAAc,SAAS;CAC/B,QAAQ,QAAQ,MAAhB;EACC,KAAK,aAAa,OAAO,gBAAgB,OAAO;EAChD,KAAK,UAAU,OAAO;EACtB,KAAK,QAAQ,OAAO,WAAW,OAAO;EACtC,SAAS,OAAO;CACjB;AACD;AACA,SAAS,iBAAiB,SAAS;CAClC,MAAM,MAAM,QAAQ,YAAY,KAAK,MAAM,GAAG,EAAE,KAAK,GAAG,EAAE,QAAQ,EAAE,KAAK,IAAI;CAC7E,MAAM,QAAQ,CAAC,iBAAiB,QAAQ,WAAW,eAAe,QAAQ,MAAM,OAAO,QAAQ,gBAAgB;CAC/G,IAAI,KAAK,MAAM,KAAK,WAAW,KAAK;CACpC,MAAM,KAAK,EAAE;CACb,OAAO,GAAG,MAAM,KAAK,IAAI,EAAE;AAC5B;AACA,SAAS,mBAAmB,QAAQ,cAAc;CACjD,MAAM,QAAQ,CAAC;CACf,IAAI,OAAO,YAAY,WAAW,MAAM,KAAK,yBAAyB,OAAO,UAAU,OAAO,OAAO,cAAc,IAAI,KAAK,IAAI,EAAE;MAC7H;EACJ,MAAM,KAAK,kBAAkB,OAAO,QAAQ,GAAG;EAC/C,IAAI,OAAO,QAAQ,QAAQ;GAC1B,MAAM,KAAK,EAAE;GACb,KAAK,MAAM,KAAK,OAAO,QAAQ,MAAM,KAAK,KAAK,GAAG;EACnD;CACD;CACA,MAAM,KAAK,kBAAkB,OAAO,MAAM,aAAa,SAAS,OAAO,MAAM,gBAAgB,OAAO,MAAM,0BAA0B,iBAAiB,OAAO,MAAM,4BAA4B,KAAK,OAAO,MAAM,8BAA8B,kBAAkB,OAAO,MAAM,gCAAgC,IAAI;CACjT,MAAM,KAAK,eAAe,YAAY,IAAI,eAAe,OAAO,eAAe,QAAQ,CAAC,EAAE,+CAA+C,cAAc,OAAO,eAAe,QAAQ,CAAC,GAAG;CACzL,MAAM,KAAK,kBAAkB,OAAO,cAAc,KAAK,QAAQ,CAAC,EAAE,EAAE;CACpE,OAAO,MAAM,KAAK,MAAM;AACzB;AACA,SAAS,gBAAgB,SAAS;CACjC,MAAM,SAAS,QAAQ,QAAQ;CAC/B,IAAI,CAAC,MAAM,QAAQ,MAAM,GAAG,OAAO;CACnC,MAAM,MAAM,CAAC;CACb,KAAK,MAAM,SAAS,QAAQ,IAAI,MAAM,SAAS,UAAU,MAAM,KAAK,KAAK,GAAG,IAAI,KAAK,GAAG,MAAM,KAAK,GAAG;MACjG,IAAI,MAAM,SAAS,YAAY,IAAI,KAAK,cAAc,MAAM,MAAM,MAAM,KAAK,CAAC;MAC9E,IAAI,MAAM,SAAS,YAAY,IAAI,KAAK,qBAAqB;CAClE,IAAI,QAAQ,OAAO,IAAI,KAAK,8BAA8B,QAAQ,MAAM,KAAK;CAC7E,IAAI,IAAI,WAAW,GAAG,OAAO;CAC7B,OAAO,GAAG,IAAI,KAAK,IAAI,EAAE;AAC1B;AACA,SAAS,WAAW,SAAS;CAC5B,MAAM,UAAU,QAAQ,SAAS;CACjC,IAAI,CAAC,MAAM,QAAQ,OAAO,GAAG,OAAO;CACpC,MAAM,QAAQ,CAAC;CACf,KAAK,MAAM,SAAS,SAAS,IAAI,MAAM,SAAS,eAAe,MAAM,KAAK,iBAAiB,KAAK,CAAC;CACjG,IAAI,MAAM,WAAW,GAAG,OAAO;CAC/B,OAAO,GAAG,MAAM,KAAK,IAAI,EAAE;AAC5B;AACA,SAAS,cAAc,MAAM,OAAO;CACnC,MAAM,UAAU,mBAAmB,MAAM,KAAK;CAC9C,OAAO,MAAM,KAAK,KAAK,UAAU,IAAI,YAAY,GAAG;AACrD;AACA,SAAS,iBAAiB,OAAO;CAChC,OAAO,GAAG,MAAM,WAAW,MAAM,IAAI;AACtC;AACA,SAAS,mBAAmB,MAAM,OAAO;CACxC,IAAI,SAAS,QAAQ,OAAO,UAAU,UAAU,OAAO;CACvD,MAAM,MAAM;CACZ,KAAK,MAAM,KAAK;EACf;EACA;EACA;EACA;CACD,GAAG,IAAI,OAAO,IAAI,OAAO,UAAU,OAAO,KAAK,IAAI,GAAG;CACtD,IAAI,OAAO,IAAI,YAAY,UAAU,OAAO,KAAK,SAAS,IAAI,SAAS,EAAE,EAAE;CAC3E,IAAI,OAAO,IAAI,YAAY,UAAU,OAAO,aAAa,SAAS,IAAI,SAAS,EAAE,EAAE;CACnF,IAAI,OAAO,IAAI,QAAQ,UAAU,OAAO,IAAI;CAC5C,IAAI,OAAO,IAAI,WAAW,UAAU,OAAO,KAAK,SAAS,IAAI,QAAQ,EAAE,EAAE;CACzE,IAAI,KAAK,WAAW,OAAO,GAAG;EAC7B,MAAM,OAAO,OAAO,KAAK,GAAG;EAC5B,MAAM,QAAQ,KAAK;EACnB,IAAI,KAAK,WAAW,KAAK,SAAS,QAAQ,OAAO,IAAI,WAAW,UAAU,OAAO,GAAG,MAAM,KAAK,OAAO,IAAI,MAAM,EAAE;CACnH;CACA,OAAO;AACR;AACA,SAAS,SAAS,GAAG,GAAG;CACvB,IAAI,EAAE,UAAU,GAAG,OAAO;CAC1B,OAAO,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC,EAAE;AAC7B;;;;;;;;;;;;;;;AAiBA,MAAM,qBAAqB;CAC1B;CACA;CACA;CACA;AACD;;;;;;;AAOA,MAAM,uBAAuB,IAAI,IAAI;CACpC;CACA;CACA;CACA;CACA;CACA;AACD,CAAC;;;;;;;AAOD,IAAI,qBAAqB,MAAM;CAC9B,KAAK;CACL,OAAO,IAAI,KAAK;EACf,MAAM,aAAa,MAAM,gBAAgB,GAAG;EAC5C,MAAM,YAAY,KAAK,IAAI;EAC3B,IAAI,eAAe;EACnB,IAAI,OAAO;EACX,IAAI,YAAY;EAChB,IAAI;GACH,WAAW,MAAM,YAAA,GAAA,+BAAA,OAAiB;IACjC,QAAQ,IAAI;IACZ,SAAS;GACV,CAAC,GAAG;IACH,MAAM,YAAY,gBAAgB,WAAW,OAAO,QAAQ,eAAe,WAAW,QAAQ,aAAa,KAAK;IAChH,IAAI,QAAQ,SAAS,YAAY,QAAQ,YAAY,QAAQ;KAC5D,eAAe,QAAQ,gBAAgB;KACvC,MAAM;MACL,QAAQ,cAAc,OAAO;MAC7B,KAAK,iBAAiB,OAAO;MAC7B;KACD;KACA;IACD;IACA,IAAI,QAAQ,SAAS,UAAU;KAC9B,YAAY;KACZ,MAAM;MACL,QAAQ,cAAc,OAAO;MAC7B,KAAK,cAAc,OAAO;MAC1B;MACA,UAAU;MACV,cAAc,mBAAmB,SAAS,YAAY;KACvD;KACA;IACD;IACA,MAAM,SAAS,cAAc,OAAO;IACpC,IAAI,QAAQ,SAAS,aAAa;KACjC,QAAQ;KACR,OAAO,KAAK;MACX,MAAM;MACN;KACD,CAAC;IACF;IACA,MAAM;KACL;KACA,KAAK,cAAc,OAAO;KAC1B;IACD;GACD;EACD,SAAS,KAAK;GACb,IAAI,WAAW;GACf,MAAM,UAAU,IAAI,YAAY;GAChC,MAAM,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;GAC9D,MAAM,aAAa,KAAK,IAAI,IAAI;GAChC,MAAM,cAAc;IACnB,MAAM;IACN,SAAS,UAAU,YAAY;IAC/B,UAAU;IACV,cAAc;IACd;GACD;GACA,MAAM,SAAS,CAAC;GAChB,MAAM,UAAU,IAAI,aAAa,KAAK,QAAQ,CAAC,EAAE;GACjD,IAAI;GACJ,IAAI,SAAS,SAAS,6CAA6C;QAC9D;IACJ,YAAY,SAAS,CAAC,MAAM;IAC5B,OAAO,KAAK;KACX,MAAM;KACN,SAAS;IACV,CAAC;IACD,SAAS,+BAA+B,OAAO,oBAAoB;GACpE;GACA,OAAO,KAAK,WAAW;GACvB,MAAM;IACL;IACA,KAAK,kBAAkB,UAAU,wBAAwB,yBAAyB,SAAS;IAC3F,UAAU;IACV,cAAc;GACf;EACD;CACD;AACD;;;;;;;AAOA,eAAe,gBAAgB,KAAK;CACnC,MAAM,MAAM,MAAM,gBAAgB,IAAI,aAAa;EAClD,uBAAuB,IAAI;EAC3B,kCAAkC;CACnC,CAAC;CACD,MAAM,QAAQ,sBAAsB,IAAI,YAAY,IAAI,aAAa,EAAE,QAAQ,YAAY,CAAC;CAC5F,MAAM,UAAU;EACf,KAAK,IAAI;EACT,gBAAgB,IAAI;EACpB;EACA,gBAAgB;GACf;GACA;GACA;EACD;EACA,iBAAiB,kBAAkB,IAAI,WAAW;EAClD,YAAY,EAAE,qBAAqB,uBAAuB,IAAI,UAAU,EAAE;EAC1E,cAAc,CAAC,oBAAoB,GAAG,kBAAkB;EACxD,cAAc;GACb,MAAM;GACN,QAAQ;GACR,QAAQ;IACP;IACA;IACA;IACA;IACA;IACA;IACA,kDAAkD,mBAAmB;IACrE;IACA;IACA,GAAG,QAAQ,CAAC,iBAAiB,KAAK,CAAC,IAAI,CAAC;GACzC,EAAE,KAAK,IAAI;EACZ;CACD;CACA,IAAI,IAAI,mBAAmB,QAAQ,QAAQ,aAAa,OAAO,aAAa,qBAAqB,IAAI,QAAQ,IAAI;EAChH,UAAU;EACV,SAAS,mBAAmB,SAAS;CACtC,IAAI,EAAE,UAAU,QAAQ;CACxB,IAAI,IAAI,QAAQ,QAAQ,SAAS,IAAI;CACrC,OAAO;AACR;;;;;;;AAOA,SAAS,kBAAkB,QAAQ;CAClC,MAAM,aAAa,IAAI,gBAAgB;CACvC,IAAI,OAAO,SAAS,WAAW,MAAM;MAChC,OAAO,iBAAiB,eAAe,WAAW,MAAM,GAAG,EAAE,MAAM,KAAK,CAAC;CAC9E,OAAO;AACR;;AAEA,SAAS,cAAc,SAAS;CAC/B,QAAQ,QAAQ,MAAhB;EACC,KAAK;GACJ,IAAI,QAAQ,YAAY,QAAQ,OAAO,CAAC;IACvC,MAAM;IACN,WAAW,QAAQ;IACnB,OAAO,QAAQ;IACf,gBAAgB,QAAQ;IACxB,cAAc,QAAQ;GACvB,CAAC;GACD,OAAO,CAAC;EACT,KAAK,aAAa;GACjB,MAAM,MAAM,CAAC;GACb,MAAM,SAAS,QAAQ,SAAS;GAChC,IAAI,CAAC,MAAM,QAAQ,MAAM,GAAG,OAAO;GACnC,KAAK,MAAM,SAAS,QAAQ,IAAI,MAAM,SAAS,UAAU,MAAM,KAAK,KAAK,GAAG,IAAI,KAAK;IACpF,MAAM;IACN,MAAM,MAAM;GACb,CAAC;QACI,IAAI,MAAM,SAAS,YAAY;IACnC,IAAI,MAAM,SAAS,oCAAoC;IACvD,IAAI,KAAK;KACR,MAAM;KACN,MAAM,MAAM;KACZ,SAAS,mBAAmB,MAAM,MAAM,MAAM,KAAK;IACpD,CAAC;GACF;GACA,IAAI,QAAQ,OAAO,IAAI,KAAK;IAC3B,MAAM;IACN,SAAS,oBAAoB,QAAQ;GACtC,CAAC;GACD,OAAO;EACR;EACA,KAAK,QAAQ;GACZ,MAAM,MAAM,CAAC;GACb,MAAM,SAAS,QAAQ,SAAS;GAChC,IAAI,CAAC,MAAM,QAAQ,MAAM,GAAG,OAAO;GACnC,KAAK,MAAM,SAAS,QAAQ,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,SAAS,eAAe,IAAI,KAAK;IACrH,MAAM;IACN,IAAI,CAAC,MAAM;GACZ,CAAC;GACD,OAAO;EACR;EACA,KAAK,UAAU;GACd,MAAM,QAAQ;IACb,MAAM;IACN,SAAS,QAAQ;IACjB,UAAU,QAAQ;IAClB,cAAc,QAAQ;IACtB,YAAY,QAAQ;GACrB;GACA,IAAI,QAAQ,YAAY,aAAa,MAAM,QAAQ,QAAQ,MAAM,GAAG,MAAM,SAAS,QAAQ;GAC3F,OAAO,CAAC,KAAK;EACd;EACA,SAAS,OAAO,CAAC;CAClB;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCA,IAAI,mBAAmB,MAAM;CAC5B,KAAK;CACL,OAAO,IAAI,KAAK;EACf,MAAM,SAAS,iBAAiB,QAAQ,GAAG;EAC3C,MAAM,YAAY,IAAI,WAAA,GAAA,OAAA,QAAiB,EAAE;EACzC,MAAM,YAAY,KAAK,IAAI;EAC3B,MAAM;GACL,QAAQ,CAAC;IACR,MAAM;IACN;IACA,OAAO,OAAO;IACd,gBAAgB,IAAI;IACpB,cAAc;GACf,CAAC;GACD,KAAK,aAAa,OAAO,KAAK,KAAK,GAAG,EAAE,iBAAiB,UAAU;GACnE;EACD;EACA,MAAM,QAAQ,sBAAsB,IAAI,YAAY,IAAI,aAAa,EAAE,QAAQ,YAAY,CAAC;EAC5F,MAAM,SAAS,QAAQ,GAAG,IAAI,OAAO,IAAI,iBAAiB,KAAK,MAAM,IAAI;EACzE,MAAM,OAAO,CAAC,GAAG,OAAO,KAAK,MAAM,CAAC,CAAC;EACrC,IAAI,OAAO,eAAe,OAAO,KAAK,KAAK,MAAM;EACjD,MAAM,SAAA,GAAA,mBAAA,OAAc,OAAO,KAAK,IAAI,MAAM;GACzC,KAAK,IAAI;GACT,KAAK,gBAAgB;IACpB,uBAAuB,IAAI;IAC3B,sBAAsB,IAAI;IAC1B,yBAAyB,IAAI,UAAU;GACxC,CAAC;GACD,OAAO;IACN;IACA;IACA;GACD;EACD,CAAC;EACD,MAAM,gBAAgB,MAAM,KAAK,SAAS;EAC1C,IAAI,IAAI,YAAY,SAAS,QAAQ;OAChC,IAAI,YAAY,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;EACtE,MAAM,MAAM,GAAG,eAAe,CAAC,CAAC;EAChC,IAAI;GACH,IAAI,OAAO,eAAe,SAAS,MAAM,MAAM,MAAM,MAAM;GAC3D,MAAM,MAAM,IAAI;EACjB,QAAQ,CAAC;EACT,MAAM,QAAQ,IAAI,eAAe;EACjC,MAAM,UAAA,GAAA,cAAA,iBAAyB,EAAE,OAAO,MAAM,OAAO,CAAC;EACtD,MAAM,UAAA,GAAA,cAAA,iBAAyB,EAAE,OAAO,MAAM,OAAO,CAAC;EACtD,OAAO,GAAG,SAAS,SAAS,MAAM,KAAK;GACtC;GACA,QAAQ;EACT,CAAC,CAAC;EACF,OAAO,GAAG,SAAS,SAAS,MAAM,KAAK;GACtC;GACA,QAAQ;EACT,CAAC,CAAC;EACF,IAAI,cAAc;EAClB,MAAM,gBAAgB;GACrB,eAAe;GACf,IAAI,gBAAgB,GAAG,MAAM,MAAM;EACpC;EACA,OAAO,GAAG,SAAS,OAAO;EAC1B,OAAO,GAAG,SAAS,OAAO;EAC1B,MAAM,OAAO,IAAI,SAAS,YAAY;GACrC,MAAM,GAAG,SAAS,MAAM,WAAW,QAAQ;IAC1C;IACA;IACA,YAAY;GACb,CAAC,CAAC;GACF,MAAM,GAAG,UAAU,QAAQ,QAAQ;IAClC,MAAM;IACN,QAAQ;IACR,YAAY,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;GAC/D,CAAC,CAAC;EACH,CAAC;EACD,IAAI,OAAO;EACX,WAAW,MAAM,EAAE,MAAM,YAAY,OAAO;GAC3C,MAAM,SAAS,WAAW,WAAW,cAAc,MAAM,MAAM,IAAI,OAAO,WAAW,gBAAgB,oBAAoB,IAAI,IAAI,cAAc,MAAM,MAAM;GAC3J,IAAI,OAAO,WAAW,GAAG;GACzB,IAAI,WAAW,YAAY,OAAO,MAAM,MAAM,EAAE,SAAS,MAAM,GAAG;IACjE,QAAQ;IACR,OAAO,KAAK;KACX,MAAM;KACN;IACD,CAAC;GACF;GACA,MAAM;IACL;IACA,KAAK,cAAc,MAAM,MAAM;GAChC;EACD;EACA,IAAI,YAAY,oBAAoB,SAAS,OAAO;EACpD,MAAM,EAAE,MAAM,QAAQ,eAAe,MAAM;EAC3C,MAAM,UAAU,IAAI,YAAY;EAChC,MAAM,UAAU,UAAU,YAAY,cAAc,UAAU,SAAS,IAAI,UAAU;EACrF,MAAM,cAAc;GACnB,MAAM;GACN;GACA,UAAU;GACV,cAAc;GACd,YAAY,KAAK,IAAI,IAAI;EAC1B;EACA,IAAI,YAAY,WAAW;GAC1B,IAAI;GACJ,IAAI,SAAS,SAAS;QACjB,IAAI,YAAY,SAAS,mBAAmB,OAAO,KAAK,GAAG,IAAI,WAAW;QAC1E,IAAI,QAAQ,SAAS,GAAG,OAAO,KAAK,GAAG,wBAAwB;QAC/D,SAAS,GAAG,OAAO,KAAK,GAAG,oBAAoB;GACpD,YAAY,SAAS,CAAC,MAAM;EAC7B;EACA,MAAM;GACL,QAAQ,CAAC,WAAW;GACpB,KAAK;GACL,UAAU;GACV,cAAc,gBAAgB,SAAS,MAAM,KAAK,IAAI,IAAI,SAAS;EACpE;CACD;AACD;;AAEA,SAAS,iBAAiB,KAAK;CAC9B,MAAM,MAAM,IAAI,4BAA4B,KAAK;CACjD,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,0KAA0K;CACpM,IAAI;CACJ,IAAI,IAAI,WAAW,GAAG,GAAG,IAAI;EAC5B,MAAM,SAAS,KAAK,MAAM,GAAG;EAC7B,IAAI,CAAC,MAAM,QAAQ,MAAM,KAAK,OAAO,MAAM,MAAM,OAAO,MAAM,QAAQ,GAAG,MAAM,IAAI,MAAM,oBAAoB;EAC7G,OAAO;CACR,SAAS,KAAK;EACb,MAAM,IAAI,MAAM,sFAAsF,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GAAG;CACzJ;MACK,OAAO,IAAI,MAAM,KAAK,EAAE,OAAO,OAAO;CAC3C,IAAI,KAAK,WAAW,GAAG,MAAM,IAAI,MAAM,yDAAyD;CAChG,MAAM,aAAa,IAAI,8BAA8B,UAAU,UAAU;CACzE,MAAM,SAAS,IAAI,8BAA8B,gBAAgB,gBAAgB;CACjF,MAAM,QAAQ,IAAI,0BAA0B,KAAK,KAAK,KAAK;CAC3D,OAAO;EACN;EACA;EACA;EACA;CACD;AACD;;AAEA,SAAS,cAAc,MAAM,QAAQ;CACpC,IAAI,CAAC,KAAK,KAAK,GAAG,OAAO,CAAC;CAC1B,OAAO,CAAC;EACP,MAAM;EACN,MAAM,WAAW,WAAW,YAAY,SAAS;CAClD,CAAC;AACF;;;;;;AAMA,SAAS,oBAAoB,MAAM;CAClC,MAAM,UAAU,KAAK,KAAK;CAC1B,IAAI,CAAC,SAAS,OAAO,CAAC;CACtB,IAAI;CACJ,IAAI;EACH,MAAM,KAAK,MAAM,OAAO;CACzB,QAAQ;EACP,OAAO,CAAC;GACP,MAAM;GACN,MAAM;EACP,CAAC;CACF;CACA,IAAI,OAAO,QAAQ,OAAO,QAAQ,UAAU,OAAO,CAAC;EACnD,MAAM;EACN,MAAM;CACP,CAAC;CACD,MAAM,IAAI;CACV,MAAM,SAAS,WAAW,EAAE,IAAI,KAAK,WAAW,EAAE,OAAO,KAAK,WAAW,EAAE,KAAK,KAAK,UAAU,EAAE,KAAK;CACtG,IAAI,QAAQ,OAAO,CAAC;EACnB,MAAM;EACN,MAAM;CACP,CAAC;CACD,MAAM,UAAU,EAAE;CAClB,IAAI,WAAW,OAAO,YAAY,UAAU;EAC3C,MAAM,SAAS,QAAQ;EACvB,IAAI,MAAM,QAAQ,MAAM,GAAG,OAAO,eAAe,MAAM;CACxD;CACA,IAAI,MAAM,QAAQ,EAAE,OAAO,GAAG,OAAO,eAAe,EAAE,OAAO;CAC7D,MAAM,OAAO,WAAW,EAAE,IAAI;CAC9B,KAAK,SAAS,cAAc,SAAS,gBAAgB,OAAO,EAAE,SAAS,UAAU,OAAO,CAAC;EACxF,MAAM;EACN,MAAM,EAAE;EACR,SAAS,mBAAmB,EAAE,MAAM,EAAE,KAAK;CAC5C,CAAC;CACD,OAAO,CAAC;EACP,MAAM;EACN,MAAM;CACP,CAAC;AACF;AACA,SAAS,eAAe,QAAQ;CAC/B,MAAM,MAAM,CAAC;CACb,KAAK,MAAM,SAAS,QAAQ;EAC3B,IAAI,SAAS,QAAQ,OAAO,UAAU,UAAU;EAChD,MAAM,IAAI;EACV,IAAI,EAAE,SAAS,UAAU,OAAO,EAAE,SAAS,YAAY,EAAE,KAAK,KAAK,GAAG,IAAI,KAAK;GAC9E,MAAM;GACN,MAAM,EAAE;EACT,CAAC;OACI,KAAK,EAAE,SAAS,cAAc,EAAE,SAAS,gBAAgB,OAAO,EAAE,SAAS,UAAU,IAAI,KAAK;GAClG,MAAM;GACN,MAAM,EAAE;GACR,SAAS,mBAAmB,EAAE,MAAM,EAAE,KAAK;EAC5C,CAAC;OACI,IAAI,EAAE,SAAS,eAAe,IAAI,KAAK;GAC3C,MAAM;GACN,IAAI,CAAC,EAAE;EACR,CAAC;CACF;CACA,OAAO;AACR;AACA,SAAS,WAAW,GAAG;CACtB,OAAO,OAAO,MAAM,YAAY,EAAE,KAAK,IAAI,IAAI;AAChD;AACA,SAAS,UAAU,GAAG;CACrB,IAAI,KAAK,OAAO,MAAM,UAAU,OAAO,WAAW,EAAE,IAAI;CACxD,OAAO;AACR;AACA,SAAS,cAAc,MAAM,QAAQ;CACpC,IAAI,CAAC,KAAK,KAAK,GAAG,OAAO;CACzB,OAAO,WAAW,WAAW,OAAO,KAAK,QAAQ,GAAG,KAAK;AAC1D;AACA,SAAS,gBAAgB,SAAS,OAAO,YAAY;CACpD,OAAO;EACN,YAAY,YAAY,yBAAyB,MAAM,QAAQ,UAAU,IAAI,KAAK,IAAI,KAAK,kBAAkB,QAAQ;EACrH;EACA,kBAAkB,aAAa,KAAK,QAAQ,CAAC,EAAE;CAChD,EAAE,KAAK,MAAM;AACd;;;;;;;AAOA,IAAI,iBAAiB,MAAM;CAC1B,SAAS,CAAC;CACV,YAAY,CAAC;CACb,OAAO;CACP,KAAK,MAAM;EACV,IAAI,KAAK,MAAM;EACf,MAAM,UAAU,KAAK,UAAU,MAAM;EACrC,IAAI,SAAS,QAAQ;GACpB,OAAO;GACP,MAAM;EACP,CAAC;OACI,KAAK,OAAO,KAAK,IAAI;CAC3B;CACA,QAAQ;EACP,KAAK,OAAO;EACZ,KAAK,MAAM,WAAW,KAAK,UAAU,OAAO,CAAC,GAAG,QAAQ;GACvD,OAAO,KAAK;GACZ,MAAM;EACP,CAAC;CACF;CACA,CAAC,OAAO,iBAAiB;EACxB,OAAO,EAAE,YAAY;GACpB,MAAM,OAAO,KAAK,OAAO,MAAM;GAC/B,IAAI,MAAM,OAAO,QAAQ,QAAQ;IAChC,OAAO;IACP,MAAM;GACP,CAAC;GACD,IAAI,KAAK,MAAM,OAAO,QAAQ,QAAQ;IACrC,OAAO,KAAK;IACZ,MAAM;GACP,CAAC;GACD,OAAO,IAAI,SAAS,YAAY,KAAK,UAAU,KAAK,OAAO,CAAC;EAC7D,EAAE;CACH;AACD;;;;;;;;AAUA,SAAS,kBAAkB,KAAK;CAC/B,IAAI,IAAI,yBAAyB,KAAK,EAAE,YAAY,MAAM,OAAO,OAAO;CACxE,OAAO;AACR;;AAEA,SAAS,eAAe,IAAI;CAC3B,QAAQ,IAAR;EACC,KAAK,OAAO,OAAO,IAAI,iBAAiB;EACxC,SAAS,OAAO,IAAI,mBAAmB;CACxC;AACD;;AAEA,SAAS,gBAAgB,MAAM,QAAQ,KAAK;CAC3C,OAAO,eAAe,kBAAkB,GAAG,CAAC;AAC7C;;;;;;;;AAUA,MAAM,oBAAoB;CACzB;CACA;CACA;AACD;AACA,MAAM,QAAQ;;;;AAId,MAAM,yBAAyBA,IAAAA,EAAE,OAAO;CACvC,MAAMA,IAAAA,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,SAAS;CACnC,MAAMA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS;CAChD,KAAKA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS;CAC/C,UAAUA,IAAAA,EAAE,OAAO,EAAE,IAAI,GAAG;CAC5B,QAAQA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,IAAI,GAAG;CAC1C,QAAQA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,IAAI,GAAG;;CAE1C,WAAWA,IAAAA,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,SAAS,EAAE,SAAS;AACpD,CAAC;;;;;;AAMD,MAAM,qBAAqBA,IAAAA,EAAE,OAAO;CACnC,OAAOA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;CACtC,OAAOA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;CACtC,aAAaA,IAAAA,EAAE,OAAO,EAAE,IAAI,GAAG;AAChC,CAAC;AACD,MAAM,sBAAsBA,IAAAA,EAAE,OAAO;CACpC,SAASA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;CAClC,KAAKA,IAAAA,EAAE,OAAO;EACb,MAAMA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;EAC/B,MAAMA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;EACrC,KAAKA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;CACrC,CAAC,EAAE,SAAS;CACZ,UAAUA,IAAAA,EAAE,OAAO,EAAE,IAAI,GAAG;CAC5B,KAAKA,IAAAA,EAAE,OAAO,EAAE,IAAI,IAAI;CACxB,UAAUA,IAAAA,EAAE,OAAO;EAClB,GAAGA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC;EACzB,GAAGA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC;CAC1B,CAAC;CACD,WAAWA,IAAAA,EAAE,OAAO,EAAE,IAAI,IAAI;CAC9B,YAAYA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC;CAC5B,WAAWA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC;;;;;;CAM3B,mBAAmBA,IAAAA,EAAE,MAAM,sBAAsB,EAAE,IAAI,EAAE,EAAE,SAAS;;;;;CAKpE,WAAWA,IAAAA,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,SAAS,EAAE,SAAS;CACnD,eAAeA,IAAAA,EAAE,MAAMA,IAAAA,EAAE,OAAO,EAAE,IAAI,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS;CAC7D,UAAU,mBAAmB,SAAS,EAAE,SAAS;AAClD,CAAC;AACD,MAAM,eAAeA,IAAAA,EAAE,KAAK;CAC3B;CACA;CACA;CACA;AACD,CAAC;AACD,MAAM,sBAAsBA,IAAAA,EAAE,KAAK;CAClC;CACA;CACA;CACA;AACD,CAAC;AACmBA,IAAAA,EAAE,OAAO;CAC5B,QAAQ,aAAa,SAAS;CAC9B,MAAMA,IAAAA,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,SAAS,EAAE,SAAS;CAC9C,WAAWA,IAAAA,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,SAAS;CAClD,gBAAgBA,IAAAA,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,SAAS,EAAE,SAAS;CACxD,QAAQA,IAAAA,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,SAAS,EAAE,SAAS;CAChD,cAAcA,IAAAA,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE,SAAS,EAAE,SAAS;CACvD,eAAe,oBAAoB,SAAS;;;;;;CAM5C,OAAOA,IAAAA,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,SAAS,EAAE,SAAS;CAC/C,UAAUA,IAAAA,EAAE,QAAQ,EAAE,SAAS;AAChC,CAAC;;;;;;;;;;;;;;;AAeD,IAAI,UAAU,MAAM;CACnB;CACA;CACA;CACA,mBAAmB;CACnB,YAAY,MAAM;EACjB,KAAK,OAAO;EACZ,KAAK,eAAA,GAAA,UAAA,MAAmB,MAAM,aAAa,UAAU;EACrD,KAAK,kBAAA,GAAA,UAAA,MAAsB,MAAM,aAAa,aAAa;CAC5D;CACA,KAAK;EACJ,OAAO,MAAM,KAAK,IAAI;CACvB;CACA,MAAM,aAAa;EAClB,OAAA,GAAA,iBAAA,OAAY,KAAK,gBAAgB,EAAE,WAAW,KAAK,CAAC;CACrD;;;;;;CAMA,MAAM,oBAAoB;EACzB,IAAI,KAAK,kBAAkB;EAC3B,KAAK,mBAAmB;EACxB,IAAI,EAAA,GAAA,QAAA,YAAY,KAAK,WAAW,GAAG;EACnC,IAAI;GACH,MAAM,QAAQ,OAAA,GAAA,iBAAA,SAAc,KAAK,WAAW;GAC5C,KAAK,MAAM,KAAK,OAAO;IACtB,IAAI,CAAC,EAAE,SAAS,OAAO,KAAK,EAAE,SAAS,MAAM,GAAG;IAChD,MAAM,KAAK,EAAE,MAAM,GAAG,EAAE;IACxB,IAAI,CAAC,MAAM,KAAK,EAAE,GAAG;IACrB,IAAI;KACH,MAAM,MAAM,OAAA,GAAA,iBAAA,WAAA,GAAA,UAAA,MAAoB,KAAK,aAAa,CAAC,GAAG,MAAM;KAC5D,MAAM,MAAM,KAAK,MAAM,GAAG;KAC1B,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,SAAS;KAC7B,MAAM,KAAK,aAAa,GAAG;IAC5B,QAAQ,CAAC;GACV;EACD,QAAQ,CAAC;CACV;CACA,MAAM,aAAa,KAAK;EACvB,MAAM,KAAK,KAAK,GAAG;EACnB,MAAM,GAAG,OAAO,aAAa,EAAE,OAAO;GACrC,IAAI,IAAI;GACR,SAAS,IAAI;GACb,gBAAgB,IAAI,kBAAkB;GACtC,QAAQ,IAAI;GACZ,MAAM,IAAI,QAAQ;GAClB,WAAW,IAAI,aAAa;GAC5B,WAAW,UAAU,IAAI,SAAS;GAClC,WAAW,UAAU,IAAI,SAAS;GAClC,YAAY,IAAI,aAAa,UAAU,IAAI,UAAU,IAAI;EAC1D,CAAC,EAAE,oBAAoB;EACvB,MAAM,GAAG,OAAO,aAAa,EAAE,OAAO;GACrC,gBAAgB,IAAI;GACpB,KAAK,IAAI;GACT,MAAM,IAAI;GACV,MAAM,IAAI;GACV,KAAK,IAAI;GACT,UAAU,IAAI;GACd,WAAW,IAAI,SAAS;GACxB,WAAW,IAAI,SAAS;GACxB,WAAW,IAAI;GACf,WAAW,IAAI;GACf,eAAe,IAAI;GACnB,eAAe,IAAI;GACnB,eAAe,IAAI;GACnB,qBAAqB,IAAI;GACzB,mBAAmB,IAAI;EACxB,CAAC,EAAE,oBAAoB;CACxB;CACA,MAAM,OAAO,IAAI,OAAO;EACvB,MAAM,KAAK,WAAW;EACtB,MAAM,SAASC,YAAAA,OAAS,KAAK,MAAM,YAAY,QAAQ;EACvD,MAAM,UAAA,GAAA,UAAA,MAAc,eAAe,GAAG,GAAG,KAAK;EAC9C,MAAM,UAAA,GAAA,UAAA,MAAc,KAAK,MAAM,aAAa,MAAM;EAClD,MAAM,KAAK,iBAAiB,QAAQ,MAAM;EAC1C,MAAM,KAAK,KAAK,GAAG;EACnB,MAAM,YAAY,UAAU,MAAM,SAAS;EAC3C,MAAM,GAAG,OAAO,aAAa,EAAE,OAAO;GACrC;GACA,SAAS,MAAM;GACf,QAAQ;GACR;GACA,WAAW;EACZ,CAAC;EACD,MAAM,gBAAgB,MAAM,iBAAiB,MAAM,cAAc,SAAS,IAAI,MAAM,gBAAgB;EACpG,MAAM,GAAG,OAAO,aAAa,EAAE,OAAO;GACrC,gBAAgB;GAChB,KAAK,MAAM;GACX,MAAM,MAAM,KAAK,QAAQ;GACzB,MAAM,MAAM,KAAK,QAAQ;GACzB,KAAK,MAAM,KAAK,OAAO;GACvB,UAAU,MAAM;GAChB,WAAW,MAAM,SAAS;GAC1B,WAAW,MAAM,SAAS;GAC1B,WAAW,MAAM;GACjB,WAAW,MAAM,aAAa;GAC9B;GACA,eAAe,MAAM,UAAU,SAAS;GACxC,eAAe,MAAM,UAAU,SAAS;GACxC,qBAAqB,MAAM,UAAU,eAAe;GACpD,mBAAmB,MAAM,qBAAqB,MAAM,kBAAkB,SAAS,IAAI,MAAM,oBAAoB;EAC9G,CAAC;EACD,MAAM,SAAS;GACd;GACA,SAAS,MAAM;GACf,MAAM,MAAM,KAAK,QAAQ;GACzB,MAAM,MAAM,KAAK,QAAQ;GACzB,KAAK,MAAM,KAAK,OAAO;GACvB,UAAU,MAAM;GAChB,KAAK,MAAM;GACX,UAAU,MAAM;GAChB,WAAW,MAAM;GACjB,mBAAmB,MAAM,qBAAqB,MAAM,kBAAkB,SAAS,IAAI,MAAM,oBAAoB;GAC7G,WAAW,MAAM,aAAa;GAC9B;GACA,eAAe,MAAM,UAAU,SAAS;GACxC,eAAe,MAAM,UAAU,SAAS;GACxC,qBAAqB,MAAM,UAAU,eAAe;GACpD,YAAY;GACZ,QAAQ;GACR,MAAM;GACN,WAAW;GACX,gBAAgB;GAChB,QAAQ;GACR,cAAc;GACd,eAAe;GACf,OAAO;GACP,UAAU;GACV,WAAW,MAAM;GACjB,WAAW,MAAM;GACjB,YAAY;GACZ,cAAc;GACd,cAAc;GACd,cAAc;GACd,WAAW;EACZ;EACA,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;EACnD,MAAM,iBAAiB,KAAK,MAAM;GACjC,gBAAgB;GAChB,OAAO;GACP,QAAQ;GACR,SAAS;IACR,MAAM,MAAM;IACZ,GAAG,MAAM,KAAK,OAAO,EAAE,MAAM,MAAM,IAAI,KAAK,IAAI,CAAC;GAClD;EACD,CAAC;EACD,OAAO;CACR;CACA,MAAM,OAAO;EACZ,MAAM,KAAK,kBAAkB;EAC7B,MAAM,KAAK,KAAK,GAAG;EACnB,MAAM,OAAO,MAAM,GAAG,OAAO,EAAE,KAAK,aAAa,EAAE,SAAS,gBAAA,GAAA,YAAA,IAAkB,cAAc,IAAI,cAAc,cAAc,CAAC,EAAE,SAAA,GAAA,YAAA,KAAY,cAAc,SAAS,CAAC;EACnK,MAAM,SAAS,MAAM,GAAG,OAAO;GAC9B,IAAI,SAAS;GACb,IAAA,GAAA,YAAA,OAAS;EACV,CAAC,EAAE,KAAK,QAAQ,EAAE,OAAA,GAAA,YAAA,YAAiB,SAAS,MAAM,iBAAiB,CAAC,EAAE,QAAQ,SAAS,cAAc;EACrG,MAAM,gBAAgB,IAAI,IAAI,OAAO,KAAK,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;EAC5D,MAAM,WAAW,MAAM,GAAG,OAAO;GAChC,IAAI,SAAS;GACb,SAAS,SAAS;EACnB,CAAC,EAAE,KAAK,QAAQ,EAAE,OAAA,GAAA,YAAA,IAAS,SAAS,MAAM,QAAQ,CAAC;EACnD,MAAM,+BAA+B,IAAI,IAAI;EAC7C,KAAK,MAAM,KAAK,UAAU;GACzB,MAAM,IAAI,kBAAkB,EAAE,OAAO;GACrC,IAAI,IAAI,GAAG,aAAa,IAAI,EAAE,KAAK,aAAa,IAAI,EAAE,EAAE,KAAK,KAAK,CAAC;EACpE;EACA,MAAM,WAAW,MAAM,GAAG,OAAO;GAChC,IAAI,SAAS;GACb,SAAS,SAAS;EACnB,CAAC,EAAE,KAAK,QAAQ,EAAE,OAAA,GAAA,YAAA,IAAS,SAAS,MAAM,MAAM,CAAC;EACjD,MAAM,uCAAuC,IAAI,IAAI;EACrD,KAAK,MAAM,KAAK,UAAU;GACzB,IAAI,qBAAqB,IAAI,EAAE,EAAE,GAAG;GACpC,MAAM,MAAM,oBAAoB,EAAE,OAAO;GACzC,IAAI,KAAK,qBAAqB,IAAI,EAAE,IAAI,GAAG;EAC5C;EACA,MAAM,cAAc,MAAM,GAAG,OAAO,EAAE,IAAI,WAAW,eAAe,CAAC,EAAE,KAAK,UAAU;EACtF,MAAM,aAAa,IAAI,IAAI,YAAY,KAAK,MAAM,EAAE,EAAE,CAAC;EACvD,OAAO,KAAK,KAAK,MAAM,YAAY,GAAG,cAAc,IAAI,EAAE,cAAc,EAAE,KAAK,GAAG,aAAa,IAAI,EAAE,cAAc,EAAE,KAAK,GAAG,qBAAqB,IAAI,EAAE,cAAc,EAAE,KAAK,MAAM,WAAW,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC;CACvN;CACA,MAAM,KAAK,IAAI;EACd,IAAI,CAAC,MAAM,KAAK,EAAE,GAAG,OAAO;EAC5B,MAAM,KAAK,kBAAkB;EAC7B,MAAM,KAAK,KAAK,GAAG;EACnB,MAAM,OAAO,MAAM,GAAG,OAAO,EAAE,KAAK,aAAa,EAAE,SAAS,gBAAA,GAAA,YAAA,IAAkB,cAAc,IAAI,cAAc,cAAc,CAAC,EAAE,OAAA,GAAA,YAAA,IAAS,cAAc,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC,GAAG;EACzK,IAAI,CAAC,KAAK,OAAO;EACjB,MAAM,YAAY,MAAM,GAAG,OAAO,EAAE,IAAA,GAAA,YAAA,OAAS,EAAE,CAAC,EAAE,KAAK,QAAQ,EAAE,OAAA,GAAA,YAAA,MAAA,GAAA,YAAA,IAAa,SAAS,gBAAgB,EAAE,IAAA,GAAA,YAAA,YAAc,SAAS,MAAM,iBAAiB,CAAC,CAAC;EACzJ,MAAM,eAAe,MAAM,KAAK,wBAAwB,EAAE;EAC1D,MAAM,eAAe,MAAM,KAAK,iBAAiB,EAAE;EACnD,MAAM,cAAc,MAAM,GAAG,OAAO,EAAE,IAAI,WAAW,eAAe,CAAC,EAAE,KAAK,UAAU,EAAE,OAAA,GAAA,YAAA,IAAS,WAAW,gBAAgB,EAAE,CAAC,EAAE,MAAM,CAAC;EACxI,OAAO,YAAY,KAAK,UAAU,IAAI,KAAK,GAAG,cAAc,cAAc,YAAY,SAAS,CAAC;CACjG;;;;;;CAMA,MAAM,iBAAiB,IAAI;EAC1B,IAAI,CAAC,MAAM,KAAK,EAAE,GAAG,OAAO;EAC5B,MAAM,OAAO,MAAM,KAAK,GAAG,EAAE,OAAO,EAAE,SAAS,SAAS,QAAQ,CAAC,EAAE,KAAK,QAAQ,EAAE,OAAA,GAAA,YAAA,MAAA,GAAA,YAAA,IAAa,SAAS,gBAAgB,EAAE,IAAA,GAAA,YAAA,IAAM,SAAS,MAAM,MAAM,CAAC,CAAC,EAAE,SAAA,GAAA,YAAA,KAAY,SAAS,EAAE,CAAC,EAAE,MAAM,CAAC;EAC1L,OAAO,KAAK,KAAK,oBAAoB,KAAK,GAAG,OAAO,IAAI;CACzD;;;;;;CAMA,MAAM,wBAAwB,IAAI;EACjC,IAAI,CAAC,MAAM,KAAK,EAAE,GAAG,OAAO;EAC5B,MAAM,OAAO,MAAM,KAAK,GAAG,EAAE,OAAO,EAAE,SAAS,SAAS,QAAQ,CAAC,EAAE,KAAK,QAAQ,EAAE,OAAA,GAAA,YAAA,MAAA,GAAA,YAAA,IAAa,SAAS,gBAAgB,EAAE,IAAA,GAAA,YAAA,IAAM,SAAS,MAAM,QAAQ,CAAC,CAAC;EACzJ,IAAI,QAAQ;EACZ,KAAK,MAAM,KAAK,MAAM,SAAS,kBAAkB,EAAE,OAAO;EAC1D,OAAO;CACR;;;;;;;;CAQA,MAAM,oBAAoB,OAAO;EAChC,MAAM,KAAK,KAAK,GAAG;EACnB,MAAM,QAAQ,IAAI,KAAK,KAAK,IAAI,MAAM,eAAe,GAAG,MAAM,YAAY,GAAG,CAAC,CAAC;EAC/E,MAAM,MAAM,IAAI,KAAK,KAAK,IAAI,MAAM,eAAe,GAAG,MAAM,YAAY,IAAI,GAAG,CAAC,CAAC;EACjF,MAAM,OAAO,MAAM,GAAG,OAAO,EAAE,SAAS,SAAS,QAAQ,CAAC,EAAE,KAAK,QAAQ,EAAE,OAAA,GAAA,YAAA,MAAA,GAAA,YAAA,IAAa,SAAS,MAAM,QAAQ,IAAA,GAAA,YAAA,KAAO,SAAS,WAAW,KAAK,IAAA,GAAA,YAAA,IAAM,SAAS,WAAW,GAAG,CAAC,CAAC;EAC9K,IAAI,QAAQ;EACZ,KAAK,MAAM,KAAK,MAAM,SAAS,kBAAkB,EAAE,OAAO;EAC1D,OAAO;CACR;;;;;;;;;;;CAWA,MAAM,aAAa,IAAI;EACtB,IAAI,CAAC,MAAM,KAAK,EAAE,GAAG,OAAO,CAAC;EAC7B,MAAM,KAAK,kBAAkB;EAC7B,QAAQ,MAAM,KAAK,GAAG,EAAE,OAAO,EAAE,KAAK,QAAQ,EAAE,OAAA,GAAA,YAAA,MAAA,GAAA,YAAA,IAAa,SAAS,gBAAgB,EAAE,IAAA,GAAA,YAAA,YAAc,SAAS,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,SAAA,GAAA,YAAA,KAAY,SAAS,EAAE,CAAC,GAAG,KAAK,MAAM,EAAE,OAAO;CACvL;CACA,MAAM,qBAAqB,KAAK;EAC/B,MAAM,OAAA,GAAA,UAAA,MAAW,KAAK,MAAM,aAAa,IAAI,UAAU;EACvD,IAAI,EAAA,GAAA,QAAA,YAAY,GAAG,GAAG,OAAO;EAC7B,QAAQ,OAAA,GAAA,iBAAA,UAAe,GAAG,GAAG,SAAS,QAAQ;CAC/C;;;;;;CAMA,MAAM,cAAc,IAAI,OAAO;EAC9B,IAAI,CAAC,MAAM,KAAK,EAAE,GAAG,OAAO;EAC5B,MAAM,UAAU,MAAM,KAAK,KAAK,EAAE;EAClC,IAAI,CAAC,SAAS,OAAO;EACrB,MAAM,iBAAiB,QAAQ;EAC/B,MAAM,SAAS,EAAE,2BAA2B,IAAI,KAAK,EAAE;EACvD,IAAI,MAAM,WAAW,KAAK,GAAG;GAC5B,OAAO,SAAS,MAAM;GACtB,IAAI,MAAM,WAAW,WAAW,OAAO,6BAA6B,IAAI,KAAK;QACxE,OAAO,aAAa;EAC1B;EACA,IAAI,MAAM,SAAS,KAAK,GAAG,OAAO,OAAO,MAAM;EAC/C,IAAI,MAAM,cAAc,KAAK,GAAG,OAAO,YAAY,MAAM;EACzD,IAAI,MAAM,mBAAmB,KAAK,GAAG,OAAO,iBAAiB,MAAM;EACnE,IAAI,MAAM,WAAW,KAAK,GAAG,OAAO,SAAS,MAAM;EACnD,IAAI,MAAM,iBAAiB,KAAK,GAAG,OAAO,eAAe,MAAM;EAC/D,IAAI,MAAM,kBAAkB,KAAK,GAAG,OAAO,gBAAgB,MAAM;EACjE,IAAI,MAAM,UAAU,KAAK,GAAG,OAAO,QAAQ,MAAM,SAAS,MAAM,MAAM,KAAK,EAAE,SAAS,IAAI,MAAM,MAAM,KAAK,IAAI;EAC/G,IAAI,MAAM,aAAa,KAAK,GAAG,OAAO,WAAW,MAAM;EACvD,MAAM,KAAK,GAAG,EAAE,OAAO,aAAa,EAAE,IAAI,MAAM,EAAE,OAAA,GAAA,YAAA,IAAS,cAAc,IAAI,EAAE,CAAC;EAChF,MAAM,OAAO,MAAM,KAAK,KAAK,EAAE;EAC/B,IAAI,CAAC,MAAM,OAAO;EAClB,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;EACnD,OAAO;GACN,QAAQ;GACR;EACD;CACD;CACA,MAAM,MAAM,IAAI,OAAO;EACtB,MAAM,SAAS,MAAM,KAAK,cAAc,IAAI,KAAK;EACjD,OAAO,SAAS,OAAO,SAAS;CACjC;CACA,MAAM,iBAAiB,GAAG,MAAM;EAC/B,MAAM,MAAM,GAAG,EAAE;EACjB,OAAA,GAAA,iBAAA,WAAgB,KAAK,IAAI;EACzB,OAAA,GAAA,iBAAA,QAAa,KAAK,CAAC;CACpB;AACD;AACA,SAAS,UAAU,KAAK;CACvB,MAAM,IAAI,IAAI,KAAK,GAAG;CACtB,IAAI,OAAO,MAAM,EAAE,QAAQ,CAAC,GAAG,uBAAuB,IAAI,KAAK;CAC/D,OAAO;AACR;AACA,SAAS,YAAY,KAAK,cAAc,cAAc,cAAc,WAAW;CAC9E,MAAM,IAAI,IAAI;CACd,MAAM,IAAI,IAAI;CACd,OAAO;EACN,IAAI,EAAE;EACN,SAAS,EAAE;EACX,MAAM,GAAG,QAAQ;EACjB,MAAM,GAAG,QAAQ;EACjB,KAAK,GAAG,OAAO;EACf,UAAU,GAAG,YAAY;EACzB,KAAK,GAAG,OAAO;EACf,UAAU;GACT,GAAG,GAAG,aAAa;GACnB,GAAG,GAAG,aAAa;EACpB;EACA,WAAW,GAAG,aAAa;EAC3B,mBAAmB,GAAG,qBAAqB;EAC3C,WAAW,GAAG,aAAa;EAC3B,eAAe,GAAG,iBAAiB;EACnC,eAAe,GAAG,iBAAiB;EACnC,eAAe,GAAG,iBAAiB;EACnC,qBAAqB,GAAG,uBAAuB;EAC/C,aAAA,GAAA,UAAA,MAAiB,eAAe,GAAG,EAAE,GAAG,KAAK;EAC7C,QAAQ,EAAE;EACV,MAAM,EAAE;EACR,WAAW,EAAE;EACb,gBAAgB,EAAE;EAClB,QAAQ,EAAE;EACV,cAAc,EAAE;EAChB,eAAe,EAAE;EACjB,OAAO,EAAE;EACT,UAAU,EAAE;EACZ,WAAW,EAAE,UAAU,YAAY;EACnC,WAAW,EAAE,UAAU,YAAY;EACnC,YAAY,EAAE,aAAa,EAAE,WAAW,YAAY,IAAI;EACxD;EACA;EACA;EACA;CACD;AACD;;;;;;;AAOA,SAAS,kBAAkB,SAAS;CACnC,IAAI,WAAW,OAAO,YAAY,YAAY,kBAAkB,SAAS;EACxE,MAAM,IAAI,QAAQ;EAClB,IAAI,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,KAAK,KAAK,GAAG,OAAO;CACnE;CACA,OAAO;AACR;;;;;;;AAOA,SAAS,oBAAoB,SAAS;CACrC,IAAI,WAAW,OAAO,YAAY,YAAY,kBAAkB,SAAS;EACxE,MAAM,IAAI,QAAQ;EAClB,IAAI,OAAO,MAAM,YAAY,GAAG,OAAO;CACxC;CACA,OAAO;AACR;;;;;;;;;;;;;;;;AA+BA,SAAS,aAAa,SAAS;CAC9B,OAAO,QAAQ,QAAQ,uBAAuB,MAAM;AACrD;;AAEA,SAAS,mBAAmB,SAAS,QAAQ;CAC5C,OAAO,IAAI,OAAO,IAAI,QAAQ,MAAM,GAAG,EAAE,IAAI,YAAY,EAAE,KAAK,IAAI,EAAE,EAAE,EAAE,KAAK,MAAM;AACtF;;;;;AAKA,SAAS,gBAAgB,iBAAiB,QAAQ;CACjD,IAAI,gBAAgB,WAAW,GAAG,OAAO;CACzC,OAAO,gBAAgB,MAAM,YAAY,mBAAmB,SAAS,MAAM,CAAC;AAC7E;AAGA,eAAe,eAAe,aAAa,YAAY,SAAS;CAC/D,IAAI,EAAA,GAAA,QAAA,aAAA,GAAA,UAAA,MAAiB,aAAa,MAAM,CAAC,GAAG,MAAM,IAAI,MAAM,sCAAsC;CAClG,MAAM,eAAA,GAAA,UAAA,MAAmB,aAAa,aAAa,WAAW;CAC9D,OAAA,GAAA,iBAAA,OAAY,aAAa,EAAE,WAAW,KAAK,CAAC;CAC5C,MAAM,gBAAA,GAAA,UAAA,MAAoB,aAAa,UAAU;CACjD,MAAM,SAAS,YAAY;CAC3B,MAAM,EAAE,eAAe,MAAM,IAAI,cAAc,WAAW,EAAE,KAAK;CACjE,MAAM,gBAAgB,MAAM,cAAc,aAAa;EACtD;EACA;EACA;EACA;CACD,CAAC,GAAG,SAAS;CACb,MAAM,UAAU,eAAe;EAC9B;EACA;EACA;EACA;EACA;EACA;CACD,IAAI;EACH;EACA;EACA;EACA;EACA;CACD;CACA,IAAI,CAAC,cAAc,MAAM,UAAU,SAAS,8BAA8B,WAAW,2CAA2C;CAChI,MAAM,OAAO,aAAa,SAAS,OAAO;CAC1C,IAAI;EACH,MAAM,IAAI,QAAQ,WAAW,EAAE,MAAM,YAAY;GAChD;GACA;GACA,eAAe;EAChB,CAAC;CACF,QAAQ,CAAC;CACT,OAAO;AACR;;;;;;;;;;;;;;;AAeA,eAAe,cAAc,aAAa,YAAY,SAAS;CAC9D,MAAM,UAAU,IAAI,QAAQ,WAAW;CACvC,MAAM,MAAM,MAAM,QAAQ,KAAK,UAAU;CACzC,IAAI,CAAC,KAAK,OAAO;EAChB,IAAI;EACJ,OAAO,uBAAuB;CAC/B;CACA,IAAI,CAAC,IAAI,gBAAgB,CAAC,IAAI,QAAQ,OAAO;EAC5C,IAAI;EACJ,OAAO;CACR;CACA,IAAI,IAAI,kBAAkB,UAAU,OAAO;EAC1C,IAAI;EACJ,OAAO,kCAAkC,IAAI;CAC9C;CACA,IAAI,EAAA,GAAA,QAAA,YAAY,IAAI,YAAY,GAAG,OAAO;EACzC,IAAI;EACJ,OAAO,gCAAgC,IAAI;CAC5C;CACA,IAAI,EAAA,GAAA,QAAA,aAAA,GAAA,UAAA,MAAiB,aAAa,MAAM,CAAC,GAAG,OAAO;EAClD,IAAI;EACJ,OAAO;CACR;CACA,MAAM,UAAU,SAAS,gCAAgC,IAAI,KAAK,GAAG,YAAY,EAAE,KAAK;CACxF,MAAM,OAAO,MAAM,cAAc,aAAa;EAC7C;EACA;EACA;CACD,CAAC;CACD,IAAI,KAAK,SAAS,GAAG,OAAO;EAC3B,IAAI;EACJ,OAAO,mDAAmD,KAAK,OAAO,KAAK;CAC5E;CACA,MAAM,eAAe,KAAK,OAAO,KAAK;CACtC,IAAI,iBAAiB,IAAI,QAAQ,OAAO;EACvC,IAAI;EACJ,OAAO,8BAA8B,IAAI,OAAO;CACjD;CACA,MAAM,WAAW,MAAM,IAAI,cAAc,WAAW,EAAE,KAAK;CAC3D,KAAK,MAAM,cAAc,aAAa;EACrC;EACA;EACA;EACA,SAAS;CACV,CAAC,GAAG,SAAS,KAAK,iBAAiB,SAAS,YAAY,OAAO;EAC9D,IAAI;EACJ,OAAO,mCAAmC,aAAa,oCAAoC,SAAS,WAAW,gBAAgB,SAAS,WAAW;CACpJ;CACA,MAAM,EAAE,0BAA0B;CAClC,IAAI,CAAC,gBAAgB,uBAAuB,YAAY,GAAG;EAC1D,MAAM,UAAU,sBAAsB,KAAK,IAAI;EAC/C,MAAM,UAAU,SAAS,sDAAsD,aAAa,eAAe,QAAQ,IAAI;EACvH,OAAO;GACN,IAAI;GACJ,OAAO,sDAAsD,aAAa,cAAc,QAAQ;EACjG;CACD;CACA,MAAM,SAAS,MAAM,cAAc,IAAI,cAAc,CAAC,UAAU,aAAa,CAAC;CAC9E,IAAI,OAAO,SAAS,GAAG,OAAO;EAC7B,IAAI;EACJ,OAAO,kCAAkC,OAAO,OAAO,KAAK;CAC7D;CACA,IAAI,OAAO,OAAO,KAAK,GAAG;EACzB,MAAM,MAAM,MAAM,cAAc,IAAI,cAAc,CAAC,OAAO,IAAI,CAAC;EAC/D,IAAI,IAAI,SAAS,GAAG,OAAO;GAC1B,IAAI;GACJ,OAAO,mBAAmB,IAAI,OAAO,KAAK;EAC3C;EACA,MAAM,SAAS,MAAM,cAAc,IAAI,cAAc;GACpD;GACA;GACA,wBAAwB,GAAG;EAC5B,CAAC;EACD,IAAI,OAAO,SAAS,GAAG;GACtB,MAAM,WAAW,GAAG,OAAO,OAAO,IAAI,OAAO;GAC7C,IAAI,CAAC,oBAAoB,KAAK,QAAQ,GAAG,OAAO;IAC/C,IAAI;IACJ,OAAO,sBAAsB,OAAO,OAAO,KAAK,KAAK,OAAO,OAAO,KAAK;GACzE;EACD;CACD;CACA,MAAM,QAAQ,MAAM,cAAc,aAAa;EAC9C;EACA;EACA,GAAG,aAAa,IAAI,IAAI;CACzB,CAAC;CACD,IAAI,MAAM,SAAS,GAAG,OAAO;EAC5B,IAAI;EACJ,OAAO,4BAA4B,MAAM,OAAO,KAAK;CACtD;CACA,IAAI,OAAO,MAAM,OAAO,KAAK,CAAC,MAAM,GAAG;EACtC,MAAM,UAAU,SAAS,mCAAmC;EAC5D,MAAM,qBAAqB,IAAI,cAAc,IAAI,QAAQ,aAAa,OAAO;EAC7E,MAAM,QAAQ,MAAM,YAAY,EAAE,eAAe,SAAS,CAAC;EAC3D,MAAM,iBAAiB,aAAa;GACnC,gBAAgB;GAChB,OAAO;GACP,QAAQ;GACR,SAAS;IACR,QAAQ,IAAI;IACZ,QAAQ;IACR,MAAM;GACP;EACD,CAAC;EACD,OAAO,EAAE,IAAI,KAAK;CACnB;CACA,KAAK,MAAM,cAAc,aAAa;EACrC;EACA;EACA;EACA,IAAI;CACL,CAAC,GAAG,SAAS,GAAG;EACf,MAAM,aAAa,MAAM,cAAc,aAAa;GACnD;GACA;GACA;EACD,CAAC,GAAG,OAAO,MAAM,IAAI,EAAE,KAAK,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,OAAO;EAC1D,MAAM,QAAQ,MAAM,cAAc,aAAa,CAAC,SAAS,SAAS,CAAC;EACnE,MAAM,UAAU,SAAS,6BAA6B,aAAa,aAAa,UAAU,OAAO,uBAAuB,UAAU,KAAK,MAAM,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,GAAG;EAC7K,IAAI,MAAM,SAAS,GAAG;GACrB,MAAM,UAAU,SAAS,uGAAuG,MAAM,OAAO,KAAK,EAAE,GAAG;GACvJ,OAAO;IACN,IAAI;IACJ,OAAO,yHAAyH,MAAM,OAAO,KAAK;IAClJ;GACD;EACD;EACA,OAAO;GACN,IAAI;GACJ;EACD;CACD;CACA,MAAM,MAAM,MAAM,cAAc,aAAa,CAAC,aAAa,MAAM,CAAC;CAClE,MAAM,YAAY,IAAI,SAAS,IAAI,IAAI,OAAO,KAAK,IAAI,KAAK;CAC5D,MAAM,qBAAqB,IAAI,cAAc,IAAI,QAAQ,aAAa,OAAO;CAC7E,MAAM,QAAQ,MAAM,YAAY;EAC/B,eAAe;EACf,GAAG,YAAY,EAAE,UAAU,IAAI,CAAC;CACjC,CAAC;CACD,MAAM,iBAAiB,aAAa;EACnC,gBAAgB;EAChB,OAAO;EACP,QAAQ;EACR,SAAS;GACR,QAAQ,IAAI;GACZ,QAAQ;GACR,GAAG,YAAY,EAAE,UAAU,IAAI,CAAC;EACjC;CACD,CAAC;CACD,MAAM,UAAU,SAAS,8BAA8B,aAAa,IAAI,YAAY,SAAS,UAAU,MAAM,GAAG,EAAE,EAAE,MAAM,GAAG,GAAG;CAChI,OAAO;EACN,IAAI;EACJ,GAAG,YAAY,EAAE,UAAU,IAAI,CAAC;CACjC;AACD;;;;;;;;;;;;;;AAcA,eAAe,mBAAmB,aAAa,YAAY,SAAS;CACnE,MAAM,UAAU,IAAI,QAAQ,WAAW;CACvC,MAAM,MAAM,MAAM,QAAQ,KAAK,UAAU;CACzC,IAAI,CAAC,KAAK,OAAO;EAChB,IAAI;EACJ,OAAO,uBAAuB;CAC/B;CACA,IAAI,IAAI,kBAAkB,YAAY,IAAI,kBAAkB,aAAa,OAAO;EAC/E,IAAI;EACJ,OAAO,oCAAoC,IAAI,cAAc;CAC9D;CACA,MAAM,UAAU,SAAS,kCAAkC,IAAI,KAAK,GAAG,YAAY,EAAE,KAAK;CAC1F,MAAM,QAAQ,MAAM,YAAY;EAC/B,eAAe;EACf,QAAQ;CACT,CAAC;CACD,MAAM,iBAAiB,aAAa;EACnC,gBAAgB;EAChB,OAAO;EACP,QAAQ;EACR,SAAS;GACR,uBAAuB,IAAI;GAC3B,gBAAgB,IAAI;EACrB;CACD,CAAC;CACD,OAAO,EAAE,IAAI,KAAK;AACnB;;;;;;AAgDA,eAAe,gBAAgB,aAAa,YAAY,SAAS;CAChE,MAAM,UAAU,IAAI,QAAQ,WAAW;CACvC,MAAM,MAAM,MAAM,QAAQ,KAAK,UAAU;CACzC,IAAI,CAAC,KAAK,OAAO,EAAE,IAAI,KAAK;CAC5B,MAAM,UAAU,SAAS,mCAAmC,IAAI,KAAK,GAAG,YAAY,EAAE,KAAK;CAC3F,IAAI,IAAI,gBAAgB,IAAI,QAAQ,MAAM,qBAAqB,IAAI,cAAc,IAAI,QAAQ,aAAa,OAAO;CACjH,MAAM,QAAQ,MAAM,YAAY,EAAE,eAAe,YAAY,CAAC;CAC9D,MAAM,iBAAiB,aAAa;EACnC,gBAAgB;EAChB,OAAO;EACP,QAAQ;EACR,SAAS,IAAI,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;CACjD,CAAC;CACD,OAAO,EAAE,IAAI,KAAK;AACnB;AACA,eAAe,qBAAqB,cAAc,QAAQ,aAAa,SAAS;CAC/E,KAAA,GAAA,QAAA,YAAe,YAAY,GAAG;EAC7B,MAAM,KAAK,MAAM,cAAc,aAAa;GAC3C;GACA;GACA;GACA;EACD,CAAC;EACD,IAAI,GAAG,SAAS,GAAG,MAAM,UAAU,SAAS,2CAA2C,GAAG,KAAK,IAAI,GAAG,OAAO,GAAG;CACjH;CACA,MAAM,cAAc,aAAa,CAAC,YAAY,OAAO,CAAC;CACtD,MAAM,KAAK,MAAM,cAAc,aAAa;EAC3C;EACA;EACA;CACD,CAAC;CACD,IAAI,GAAG,SAAS,KAAK,CAAC,2BAA2B,KAAK,GAAG,MAAM,GAAG,MAAM,UAAU,SAAS,8BAA8B,OAAO,UAAU,GAAG,KAAK,IAAI,GAAG,OAAO,GAAG;AACpK;AACA,SAAS,wBAAwB,KAAK;CACrC,MAAM,YAAY,IAAI,QAAQ,MAAM,OAAO,EAAE,IAAI,KAAK,KAAK;CAC3D,MAAM,UAAU,UAAU,SAAS,KAAK,GAAG,UAAU,MAAM,GAAG,EAAE,EAAE,KAAK;CACvE,MAAM,QAAQ,IAAI,OAAO,GAAG,IAAI,KAAK,GAAG,IAAI,QAAQ,MAAM,IAAI,OAAO,OAAO,IAAI,IAAI,QAAQ,OAAO,IAAI;CACvG,OAAO;EACN,aAAa,WAAW;EACxB;EACA;EACA;EACA,aAAa,IAAI;EACjB,aAAa;EACb;CACD,EAAE,KAAK,IAAI;AACZ;;;;;;;AAwGA,eAAe,qBAAqB,cAAc;CACjD,IAAI,EAAA,GAAA,QAAA,YAAY,YAAY,GAAG,OAAO;CACtC,MAAM,SAAS,MAAM,cAAc,cAAc,CAAC,UAAU,aAAa,CAAC;CAC1E,IAAI,OAAO,SAAS,GAAG,OAAO;CAC9B,MAAM,UAAU,OAAO,OAAO,KAAK;CACnC,IAAI,CAAC,SAAS,OAAO;CACrB,OAAO,QAAQ,MAAM,IAAI,EAAE;AAC5B;;;;;;;;;;;;AAcA,MAAM,+BAA+B,IAAI,IAAI;;;;;;;;;;;AAW7C,MAAM,kBAAkB;AACxB,eAAe,gBAAgB,aAAa,YAAY;CACvD,IAAI;EACH,MAAM,MAAM,WAAW,EAAE,OAAO,UAAU,EAAE,OAAO;GAClD,gBAAgB;GAChB,2BAA2B,IAAI,KAAK;GACpC,aAAa;EACd,CAAC,EAAE,mBAAmB;GACrB,QAAQ,WAAW;GACnB,KAAK,EAAE,2BAA2B,IAAI,KAAK,EAAE;EAC9C,CAAC;EACD,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;CACpD,QAAQ,CAAC;AACV;AACA,eAAe,eAAe,aAAa,YAAY;CACtD,IAAI;EACH,MAAM,MAAM,WAAW,EAAE,OAAO,UAAU,EAAE,OAAA,GAAA,YAAA,IAAW,WAAW,gBAAgB,UAAU,CAAC;EAC7F,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;CACpD,QAAQ,CAAC;AACV;;;;;;;;;AASA,eAAe,WAAW,KAAK;CAC9B,IAAI,IAAI,SAAS,OAAO;CACxB,MAAM,WAAA,GAAA,UAAA,MAAe,IAAI,aAAa,aAAa,MAAM;CACzD,OAAA,GAAA,iBAAA,OAAY,SAAS,EAAE,WAAW,KAAK,CAAC;CACxC,MAAM,WAAA,GAAA,UAAA,MAAe,SAAS,GAAG,IAAI,SAAS,GAAG,IAAI;CACrD,MAAM,WAAW,MAAM,cAAc,IAAI,aAAa,IAAI,SAAS,EAAE;CACrE,IAAI,CAAC,SAAS,IAAI;EACjB,MAAM,eAAe,IAAI,SAAS,IAAI,IAAI,WAAW,EAAE,QAAQ;GAC9D,MAAM;GACN,SAAS,SAAS;EACnB,CAAC;EACD,MAAM,UAAU,SAAS,iCAAiC,SAAS,OAAO,GAAG;EAC7E;CACD;CACA,IAAI,MAAM,IAAI;CACd,MAAM,6BAA6B,IAAI,KAAK,GAAG,YAAY;CAC3D,IAAI,IAAI,SAAS,YAAY,IAAI;EAChC,MAAM,MAAM,eAAe,IAAI,aAAa,IAAI,SAAS,IAAI,OAAO;CACrE,SAAS,KAAK;EACb,MAAM,UAAU,SAAS,GAAG,aAAa,KAAK,KAAK,WAAW,KAAK,EAAE,2CAA2C,aAAa,GAAG,EAAE,GAAG;EACrI;CACD;CACA,MAAM,UAAU,SAAS,aAAa,KAAK,KAAK,WAAW,IAAI,CAAC;CAChE,MAAM,SAAS,mBAAmB,IAAI,UAAU,IAAI,MAAM,GAAG;CAC7D,MAAM,iBAAiB,MAAM,yBAAyB,IAAI,WAAW;CACrE,SAAS;EACR,aAAa,IAAI;EACjB,YAAY,IAAI,SAAS;EACzB;EACA;EACA;EACA,WAAW;EACX;EACA,YAAY,IAAI,SAAS;CAC1B,CAAC;AACF;;;;;;;;;;;;;;;;;;;AAmBA,eAAe,gBAAgB,YAAY,SAAS;CACnD,MAAM,cAAc,QAAQ,IAAI,yBAAyB,QAAQ,IAAI;CACrE,IAAI,CAAC,MAAM,kBAAkB,YAAY,WAAW,GAAG,MAAM,IAAI,MAAM,iDAAiD;CACxH,MAAM,MAAM,MAAM,IAAI,QAAQ,WAAW,EAAE,KAAK,UAAU;CAC1D,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,uBAAuB,YAAY;CAC7D,IAAI,CAAC,IAAI,gBAAgB,MAAM,IAAI,MAAM,yEAAyE;CAClH,MAAM,WAAW,MAAM,cAAc,aAAa,UAAU;CAC5D,IAAI,CAAC,SAAS,IAAI;EACjB,MAAM,eAAe,YAAY,WAAW,EAAE,QAAQ;GACrD,MAAM;GACN,SAAS,SAAS;EACnB,CAAC;EACD,MAAM,IAAI,MAAM,SAAS,MAAM;CAChC;CACA,MAAM,gBAAA,GAAA,UAAA,MAAoB,aAAa,aAAa,aAAa,UAAU;CAC3E,MAAM,OAAA,GAAA,QAAA,YAAiB,YAAY,IAAI,eAAe;CACtD,MAAM,WAAA,GAAA,UAAA,MAAe,aAAa,aAAa,MAAM;CACrD,OAAA,GAAA,iBAAA,OAAY,SAAS,EAAE,WAAW,KAAK,CAAC;CACxC,MAAM,WAAA,GAAA,UAAA,MAAe,SAAS,GAAG,WAAW,IAAI;CAChD,MAAM,UAAU,SAAS,0CAA0C,IAAI,KAAK,GAAG,YAAY,EAAE,wBAAwB,QAAQ,MAAM,IAAI,EAAE,KAAK,MAAM,EAAE,KAAK;CAC3J,SAAS;EACR;EACA;EACA;EACA;EACA,QAAQ;EACR,WAAW;EACX,gBAAgB,MAAM,yBAAyB,WAAW;EAC1D,QAAQ,IAAI;EACZ,YAAY,IAAI;CACjB,CAAC;AACF;;;;;;;AAOA,eAAe,aAAa,YAAY,aAAa;CACpD,IAAI,aAAa,IAAI,UAAU,GAAG,OAAO;CACzC,MAAM,OAAO,eAAe,QAAQ,IAAI,yBAAyB,QAAQ,IAAI;CAC7E,IAAI;EACH,QAAQ,MAAM,MAAM,IAAI,EAAE,OAAO,EAAE,KAAK,UAAU,EAAE,OAAA,GAAA,YAAA,IAAW,WAAW,gBAAgB,UAAU,CAAC,EAAE,MAAM,CAAC,GAAG,SAAS;CAC3H,QAAQ;EACP,OAAO;CACR;AACD;;AAEA,MAAM,gCAAgC;;AAEtC,MAAM,6BAA6B;;;;;;;;AAQnC,eAAe,kBAAkB,YAAY,aAAa;CACzD,MAAM,WAAW,KAAK,IAAI,IAAI;CAC9B,OAAO,MAAM,aAAa,YAAY,WAAW,GAAG;EACnD,IAAI,KAAK,IAAI,KAAK,UAAU,OAAO;EACnC,MAAM,IAAI,SAAS,YAAY,WAAW,SAAS,0BAA0B,CAAC;CAC/E;CACA,OAAO;AACR;;;;;;;;;;;;;AAaA,eAAe,aAAa,YAAY,aAAa;CACpD,MAAM,QAAQ,aAAa,IAAI,UAAU;CACzC,IAAI,OAAO;EACV,MAAM,MAAM,MAAM;EAClB,OAAO;CACR;CACA,MAAM,OAAO,eAAe,QAAQ,IAAI,yBAAyB,QAAQ,IAAI;CAC7E,IAAI,SAAS;CACb,IAAI;EACH,UAAU,MAAM,MAAM,IAAI,EAAE,OAAO,EAAE,KAAK,UAAU,EAAE,OAAA,GAAA,YAAA,IAAW,WAAW,gBAAgB,UAAU,CAAC,EAAE,MAAM,CAAC,GAAG,SAAS;CAC7H,QAAQ;EACP,SAAS;CACV;CACA,IAAI,CAAC,QAAQ,OAAO;CACpB,QAAQ,KAAK,iBAAiB,UAAU;CACxC,OAAO;AACR;;;;;;;;;;;;AAYA,eAAe,cAAc,aAAa,YAAY;CACrD,MAAM,WAAW,MAAM,IAAI,cAAc,WAAW,EAAE,KAAK;CAC3D,MAAM,UAAU,IAAI,QAAQ,WAAW;CACvC,MAAM,WAAW,eAAe,MAAM,QAAQ,iBAAiB,UAAU,CAAC;CAC1E,MAAM,mBAAmB,MAAM,QAAQ,wBAAwB,UAAU;CACzE,IAAI,oBAAoB,SAAS,uBAAuB,OAAO;EAC9D,IAAI;EACJ,QAAQ,sCAAsC,eAAe,kBAAkB,SAAS,uBAAuB,QAAQ,EAAE;CAC1H;CACA,IAAI,SAAS,qBAAqB,MAAM;EACvC,MAAM,eAAe,MAAM,QAAQ,oCAAoC,IAAI,KAAK,CAAC;EACjF,IAAI,gBAAgB,SAAS,kBAAkB,OAAO;GACrD,IAAI;GACJ,QAAQ,2BAA2B,eAAe,cAAc,SAAS,kBAAkB,QAAQ,EAAE;EACtG;CACD;CACA,OAAO,EAAE,IAAI,KAAK;AACnB;;;;;;AAMA,SAAS,eAAe,MAAM,KAAK,UAAU;CAC5C,MAAM,UAAU,IAAI,KAAK,QAAQ,CAAC;CAClC,MAAM,SAAS,IAAI,IAAI,QAAQ,CAAC;CAChC,OAAO,WAAW,IAAI,QAAQ,MAAM,OAAO,+CAA+C,GAAG,QAAQ,MAAM,OAAO;AACnH;AACA,eAAe,SAAS,MAAM;CAC7B,MAAM,EAAE,mBAAmB;CAC3B,MAAM,QAAQ,IAAI,gBAAgB;CAClC,aAAa,IAAI,KAAK,YAAY,EAAE,MAAM,CAAC;CAC3C,MAAM,eAAe,OAAO;EAC3B,IAAI,OAAO,KAAK,YAAY,MAAM,MAAM;CACzC;CACA,QAAQ,GAAG,iBAAiB,WAAW;CACvC,gBAAgB,KAAK,aAAa,KAAK,UAAU;CACjD,MAAM,WAAW,gBAAgB,QAAQ,GAAG;CAC5C,MAAM,UAAU;EACf,aAAa,KAAK;EAClB,YAAY,KAAK;EACjB,KAAK,KAAK;EACV,YAAY,KAAK;EACjB,QAAQ,KAAK;EACb,WAAW,KAAK;EAChB;EACA,QAAQ,KAAK;EACb,aAAa,MAAM;CACpB;CACA,IAAI;EACH,MAAM,cAAc,MAAM,SAAS,IAAI,OAAO,CAAC;CAChD,UAAU;EACT,aAAa,OAAO,KAAK,UAAU;EACnC,QAAQ,IAAI,iBAAiB,WAAW;EACxC,MAAM,eAAe,KAAK,aAAa,KAAK,UAAU;EACtD,UAAU,KAAK,YAAY,iBAAiB;CAC7C;AACD;;;;;;;AAOA,eAAe,cAAc,MAAM,QAAQ;CAC1C,IAAI,kBAAkB;CACtB,IAAI,iBAAiB;CACrB,MAAM,MAAM,eAAe,KAAK,UAAU;CAC1C,IAAI;EACH,WAAW,MAAM,QAAQ,QAAQ;GAChC,IAAI,CAAC,mBAAmB,KAAK,WAAW;IACvC,kBAAkB;IAClB,MAAM,iBAAiB,KAAK,aAAa,KAAK,YAAY,KAAK,SAAS;GACzE;GACA,KAAK,MAAM,MAAM,KAAK,UAAU,CAAC,GAAG,MAAM,IAAI,QAAQ,EAAE;GACxD,IAAI,KAAK,UAAU;IAClB,iBAAiB;IACjB,IAAI,KAAK,KAAK,MAAM,UAAU,KAAK,SAAS,KAAK,GAAG;IACpD,IAAI,KAAK,WAAW,MAAM,iBAAiB,KAAK,aAAa,KAAK,YAAY,KAAK,SAAS,KAAK,gBAAgB,IAAI;SAChH,IAAI,KAAK,cAAc,MAAM,UAAU,KAAK,SAAS,KAAK,KAAK,aAAa,GAAG;IACpF,IAAI;KACH,MAAM,MAAM,MAAM,IAAI,QAAQ,KAAK,WAAW,EAAE,KAAK,KAAK,UAAU;KACpE,IAAI,OAAO,IAAI,WAAW,WAAW;MACpC,MAAM,IAAI,QAAQ;OACjB,MAAM;OACN,QAAQ,IAAI;OACZ,MAAM,IAAI;OACV,WAAW,IAAI;OACf,YAAY,IAAI;MACjB,CAAC;MACD,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;KACpD;IACD,QAAQ,CAAC;IACT;GACD;GACA,IAAI,KAAK,KAAK,MAAM,UAAU,KAAK,SAAS,KAAK,GAAG;EACrD;CACD,SAAS,KAAK;EACb,MAAM,MAAM,aAAa,GAAG;EAC5B,MAAM,IAAI,QAAQ;GACjB,MAAM;GACN,SAAS;EACV,CAAC;EACD,MAAM,UAAU,KAAK,SAAS,wCAAwC,IAAI,GAAG;CAC9E,UAAU;EACT,IAAI,CAAC,kBAAkB,KAAK,WAAW,MAAM,iBAAiB,KAAK,aAAa,KAAK,YAAY,KAAK,SAAS,IAAI;CACpH;AACD;AACA,eAAe,iBAAiB,aAAa,YAAY,WAAW;CACnE,IAAI;EACH,MAAM,IAAI,QAAQ,WAAW,EAAE,MAAM,YAAY,EAAE,gBAAgB,UAAU,CAAC;CAC/E,QAAQ,CAAC;AACV;AACA,SAAS,aAAa,GAAG;CACxB,OAAO,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACjD;AACA,SAAS,aAAa,KAAK,KAAK,WAAW,eAAe;CACzD,MAAM,MAAM,IAAI;CAChB,MAAM,QAAQ,IAAI,OAAO,GAAG,IAAI,KAAK,GAAG,IAAI,QAAQ,MAAM,IAAI,OAAO,OAAO,IAAI,IAAI,QAAQ,OAAO,IAAI;CACvG,MAAM,aAAa,IAAI,SAAS,cAAc,gBAAgB,oBAAoB,IAAI,GAAG,MAAM;CAC/F,OAAO;EACN;EACA,OAAO,IAAI;EACX,SAAS,IAAI;EACb,WAAW;EACX,QAAQ,IAAI;EACZ,YAAY;EACZ,QAAQ;EACR,WAAW,QAAQ;EACnB;EACA;EACA,yBAAyB,IAAI,GAAG;EAChC;EACA,iBAAiB,MAAM;EACvB,YAAY,IAAI,IAAI;EACpB,aAAa,IAAI,OAAO,IAAI,SAAS,cAAc,gBAAgB,+BAA+B,IAAI,GAAG,MAAM;EAC/G;EACA;EACA;EACA,KAAK,IAAI,QAAQ,MAAM,IAAI,EAAE,KAAK,MAAM;EACxC;EACA;EACA;EACA;CACD,EAAE,QAAQ,MAAM,MAAM,IAAI,EAAE,KAAK,IAAI;AACtC;AACA,eAAe,iBAAiB,aAAa,YAAY,SAAS,QAAQ;CACzE,MAAM,UAAU,MAAM,IAAI,QAAQ,WAAW,EAAE,KAAK,UAAU;CAC9D,MAAM,8BAA8B,IAAI,KAAK,GAAG,YAAY;CAC5D,MAAM,QAAQ,CAAC;CACf,MAAM,KAAK,EAAE;CACb,MAAM,KAAK,eAAe;CAC1B,MAAM,KAAK,EAAE;CACb,MAAM,KAAK,iBAAiB,WAAW,GAAG;CAC1C,IAAI,QAAQ,MAAM,KAAK,MAAM;MACxB,MAAM,KAAK,4CAA4C;CAC5D,IAAI,CAAC,SAAS;EACb,MAAM,KAAK,EAAE;EACb,MAAM,KAAK,uDAAuD;CACnE,OAAO;EACN,MAAM,KAAK,iBAAiB,QAAQ,OAAO,GAAG;EAC9C,IAAI,QAAQ,YAAY,MAAM,KAAK,oBAAoB,QAAQ,YAAY;EAC3E,IAAI,QAAQ,WAAW,MAAM,KAAK,iBAAiB,QAAQ,UAAU,GAAG;EACxE,IAAI,QAAQ,gBAAgB,MAAM,KAAK,kBAAkB,QAAQ,eAAe,GAAG;EACnF,IAAI,QAAQ,MAAM;GACjB,MAAM,KAAK,EAAE;GACb,MAAM,KAAK,qBAAqB;GAChC,MAAM,KAAK,EAAE;GACb,MAAM,KAAK,QAAQ,IAAI;EACxB;EACA,IAAI,QAAQ,WAAW,WAAW;GACjC,MAAM,KAAK,EAAE;GACb,MAAM,KAAK,qFAAqF;EACjG;CACD;CACA,MAAM,KAAK,EAAE;CACb,MAAM,UAAU,SAAS,MAAM,KAAK,IAAI,CAAC;AAC1C;AACA,SAAS,mBAAmB,KAAK,MAAM,KAAK;CAC3C,MAAM,QAAQ,IAAI,OAAO,GAAG,IAAI,KAAK,GAAG,IAAI,QAAQ,MAAM,IAAI,OAAO,OAAO,IAAI,IAAI,QAAQ,OAAO,IAAI;CACvG,MAAM,kBAAkB,SAAS,aAAa;EAC7C;EACA;EACA,KAAK;EACL,sBAAsB,IAAI,GAAG;EAC7B;EACA;EACA;CACD,EAAE,KAAK,IAAI,IAAI;CACf,MAAM,gBAAgB,IAAI,YAAY,eAAe,IAAI,UAAU,KAAK;CACxE,MAAM,oBAAoB,IAAI,iBAAiB,IAAI,cAAc,SAAS,IAAI,mBAAmB,IAAI,cAAc,KAAK,KAAK,MAAM;CACnI,MAAM,eAAe,IAAI,iBAAiB,IAAI,gBAAgB,IAAI;EACjE;EACA,uDAAuD,IAAI,cAAc;EACzE,4DAA4D,IAAI,iBAAiB,KAAK,EAAE,MAAM,IAAI,cAAc;EAChH,IAAI,sBAAsB,4BAA4B,IAAI,wBAAwB;EAClF;EACA;EACA;CACD,EAAE,QAAQ,MAAM,MAAM,EAAE,EAAE,KAAK,IAAI,IAAI;CACvC,MAAM,aAAa,IAAI,qBAAqB,CAAC;CAC7C,MAAM,oBAAoB,WAAW,SAAS,IAAI;EACjD;EACA,gCAAgC,WAAW,SAAS,EAAE;EACtD;EACA;EACA,GAAG,WAAW,KAAK,GAAG,MAAM;GAC3B,MAAM,OAAO,EAAE,OAAO,GAAG,EAAE,KAAK,GAAG,EAAE,QAAQ,MAAM,EAAE,OAAO,OAAO,IAAI,EAAE,QAAQ,OAAO,EAAE;GAC1F,MAAM,OAAO,EAAE,YAAY,MAAM,EAAE,UAAU,MAAM;GACnD,OAAO,KAAK,IAAI,EAAE,IAAI,OAAO;EAC9B,CAAC;CACF,EAAE,KAAK,IAAI,IAAI;CACf,OAAO;EACN;EACA;EACA,gBAAgB,IAAI;EACpB,WAAW;EACX;EACA;EACA,aAAa,IAAI,QAAQ,QAAQ,QAAQ,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE;EAC5D;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACD,EAAE,QAAQ,MAAM,MAAM,EAAE,EAAE,KAAK,IAAI;AACpC;;;;;;;;;;;;;;;;;AAuCA,MAAM,gBAAgB,OAAO,IAAI,4BAA4B;AAC7D,MAAM,QAAQ,WAAW,kCAAkC,IAAI,IAAI;AACnE,WAAW,iBAAiB;;;;;;;AAO5B,SAAS,QAAQ,aAAa,IAAI;CACjC,MAAM,UAAU,MAAM,IAAI,WAAW,KAAK,QAAQ,QAAQ,GAAG,KAAK,IAAI,EAAE;CACxE,MAAM,OAAO,OAAO,WAAW,KAAK,SAAS,KAAK,CAAC;CACnD,MAAM,IAAI,aAAa,IAAI;CAC3B,KAAK,WAAW;EACf,IAAI,MAAM,IAAI,WAAW,MAAM,MAAM,MAAM,OAAO,WAAW;CAC9D,CAAC;CACD,OAAO;AACR;AA4DA,MAAM,kBAAkB,OAAO,IAAI,0BAA0B;AAC7D,MAAM,WAAW,WAAW,oCAAoC,IAAI,IAAI;AACxE,WAAW,mBAAmB;AAC9B,MAAM,iBAAiB,OAAO,IAAI,iCAAiC;AACnE,IAAI,CAAC,WAAW,iBAAiB;CAChC,WAAW,kBAAkB;CAC7B,MAAM,gBAAgB;EACrB,KAAK,MAAM,MAAM,CAAC,GAAG,SAAS,KAAK,CAAC,GAAG,UAAU,EAAE;CACpD;CACA,QAAQ,KAAK,QAAQ,OAAO;CAC5B,QAAQ,KAAK,UAAU,OAAO;CAC9B,QAAQ,KAAK,WAAW,OAAO;AAChC;AAgIA,SAAS,UAAU,YAAY;CAC9B,MAAM,QAAQ,SAAS,IAAI,UAAU;CACrC,IAAI,CAAC,OAAO;CACZ,SAAS,OAAO,UAAU;CAC1B,MAAM,MAAM,MAAM,MAAM;CACxB,IAAI,QAAQ,KAAK,GAAG;CACpB,IAAI;EACH,QAAQ,KAAK,CAAC,KAAK,SAAS;CAC7B,QAAQ;EACP,IAAI;GACH,MAAM,MAAM,KAAK,SAAS;EAC3B,QAAQ,CAAC;CACV;AACD;AA+M4BD,IAAAA,EAAE,OAAO,EAAE,aAAaA,IAAAA,EAAE,MAAMA,IAAAA,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,CAAC;AA2PzEA,IAAAA,EAAE,OAAO;CACrC,KAAKA,IAAAA,EAAE,MAAMA,IAAAA,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;CACpD,OAAOA,IAAAA,EAAE,OAAO,EAAE,UAAUA,IAAAA,EAAE,QAAQ,EAAE,CAAC;AAC1C,CAAC;AAM4BA,IAAAA,EAAE,OAAO,EAAE,aAAaA,IAAAA,EAAE,MAAMA,IAAAA,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,CAAC;AAkf7EA,IAAAA,EAAE,OAAO;CAClC,aAAaA,IAAAA,EAAE,MAAMA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;CACrD,YAAYA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,MAAM,iCAAiC,qBAAqB;CACnG,OAAOA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;CAChC,aAAaA,IAAAA,EAAE,OAAO,EAAE,IAAI,GAAG;CAC/B,YAAYA,IAAAA,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,MAAM,iCAAiC,qBAAqB;AACpG,CAAC;;;;;;;;;;;;;;;;;;AAsND,MAAM,mBAAmB;AACzB,MAAM,aAAa,OAAO,IAAI,+BAA+B;AAC7D,MAAM,UAAU,WAAW,+BAA+B,IAAI,IAAI;AAClE,WAAW,cAAc;AACzB,SAAS,QAAQ,KAAK;CACrB,MAAM,MAAM,IAAI;CAChB,IAAI,QAAQ,KAAK,KAAK,QAAQ,IAAI,OAAO;CACzC,MAAM,IAAI,OAAO,GAAG;CACpB,IAAI,CAAC,OAAO,SAAS,CAAC,KAAK,IAAI,GAAG,OAAO;CACzC,OAAO;AACR;;;;;;AAMA,eAAe,oBAAoB,aAAa;CAC/C,MAAM,OAAO,QAAQ,QAAQ,GAAG;CAChC,IAAI,SAAS,GAAG;EACf,QAAQ,MAAM;EACd;CACD;CACA,IAAI;EACH,MAAM,yBAAyB,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,KAAK,GAAG;EAC9E,MAAM,OAAO,MAAM,MAAM,WAAW,EAAE,OAAO,EAAE,IAAI,cAAc,GAAG,CAAC,EAAE,KAAK,aAAa,EAAE,OAAA,GAAA,YAAA,MAAA,GAAA,YAAA,IAAa,cAAc,eAAe,QAAQ,IAAA,GAAA,YAAA,IAAM,cAAc,WAAW,MAAM,CAAC,CAAC;EACpL,QAAQ,MAAM;EACd,KAAK,MAAM,KAAK,MAAM,QAAQ,IAAI,EAAE,EAAE;CACvC,QAAQ,CAAC;AACV;;;;;;AAMA,SAAS,QAAQ,YAAY;CAC5B,OAAO,QAAQ,IAAI,UAAU;AAC9B;;;;;;AAMA,SAAS,aAAa,YAAY;CACjC,QAAQ,OAAO,UAAU;AAC1B;;;;;;;;;;;;;;;;;AAuHA,SAAS,2BAA2B;CACnC,MAAM,MAAM,IAAIE,GAAAA,gBAAgB,EAAE,UAAU,KAAK,CAAC;CAClD,IAAI,GAAG,eAAe,WAAW;EAChC,iBAAiB,MAAM;CACxB,CAAC;CACD,oBAAoB,YAAY,CAAC;CACjC,sBAAsB;CACtB,gCAAgC;CAChC,sBAAsB;CACtB,OAAO;AACR;;;;;;;;;AASA,MAAM,iBAAiB,OAAO,IAAI,0BAA0B;AAC5D,MAAM,eAAe,WAAW,mCAAmC,IAAI,IAAI;AAC3E,WAAW,kBAAkB;AAC7B,SAAS,eAAe,YAAY,QAAQ;CAC3C,IAAI,MAAM,aAAa,IAAI,UAAU;CACrC,IAAI,CAAC,KAAK;EACT,sBAAsB,IAAI,IAAI;EAC9B,aAAa,IAAI,YAAY,GAAG;CACjC;CACA,IAAI,IAAI,MAAM;AACf;AACA,SAAS,kBAAkB,YAAY,QAAQ;CAC9C,MAAM,MAAM,aAAa,IAAI,UAAU;CACvC,IAAI,CAAC,KAAK;CACV,IAAI,OAAO,MAAM;CACjB,IAAI,IAAI,SAAS,GAAG,aAAa,OAAO,UAAU;AACnD;AACA,SAAS,uBAAuB,YAAY,SAAS;CACpD,MAAM,MAAM,aAAa,IAAI,UAAU;CACvC,IAAI,CAAC,KAAK;CACV,MAAM,MAAM;EACX,MAAM;EACN;EACA,GAAG;CACJ;CACA,KAAK,MAAM,QAAQ,KAAK,KAAK,MAAM,GAAG;AACvC;;;;;;;;;;;AAWA,MAAM,sBAAsB,OAAO,IAAI,yBAAyB;AAChE,MAAM,cAAc,WAAW,wCAAwC,IAAI,IAAI;AAC/E,WAAW,uBAAuB;;;;;;;AAOlC,MAAM,0BAA0B,OAAO,IAAI,6BAA6B;AACxE,SAAS,wBAAwB;CAChC,MAAM,OAAO;CACb,IAAI,KAAK,0BAA0B;CACnC,KAAK,2BAA2B,iBAAiB,UAAU,mBAAmB,KAAK,CAAC;AACrF;;;;;;;;;;;;;;;;;;AAkBA,MAAM,wBAAwB,OAAO,IAAI,2BAA2B;AACpE,MAAM,kBAAkB;AACxB,SAAS,kCAAkC;CAC1C,MAAM,OAAO;CACb,IAAI,KAAK,wBAAwB;CACjC,IAAI,aAAa;CACjB,IAAI,UAAU;CACd,CAAC,YAAY;EACZ,IAAI;GACH,MAAM,MAAM,MAAM,MAAM,YAAY,CAAC,EAAE,OAAO,EAAE,KAAK,YAAA,GAAG,OAAO,cAAc,UAAU,GAAG,CAAC,EAAE,KAAK,aAAa,GAAG,IAAI,OAAO;GAC7H,IAAI,OAAO,MAAM,aAAa,OAAO,EAAE;EACxC,QAAQ,CAAC;CACV,GAAG;CACH,MAAM,WAAW,kBAAkB;EAClC,IAAI,SAAS;EACb,UAAU;EACV,CAAC,YAAY;GACZ,IAAI;IACH,MAAM,MAAM,MAAM,MAAM,YAAY,CAAC,EAAE,OAAO,EAAE,KAAK,YAAA,GAAG,OAAO,cAAc,UAAU,GAAG,CAAC,EAAE,KAAK,aAAa,GAAG,IAAI,OAAO;IAC7H,IAAI,OAAO,QAAQ,OAAO,EAAE,IAAI,YAAY;KAC3C,aAAa,OAAO,EAAE;KACtB,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;IACrD;GACD,QAAQ,CAAC,UAAU;IAClB,UAAU;GACX;EACD,GAAG;CACJ,GAAG,eAAe;CAClB,KAAK,+BAA+B,cAAc,QAAQ;AAC3D;AACA,SAAS,mBAAmB,OAAO;CAClC,MAAM,MAAM;EACX,MAAM;EACN;CACD;CACA,KAAK,MAAM,QAAQ,aAAa,KAAK,MAAM,GAAG;AAC/C;;;;;;;;;;;AAWA,MAAM,2BAA2B,OAAO,IAAI,8BAA8B;AAC1E,MAAM,mBAAmB,WAAW,6CAA6C,IAAI,IAAI;AACzF,WAAW,4BAA4B;;;;;;AAMvC,SAAS,yBAAyB;CACjC,IAAI;CACJ,KAAK,MAAM,KAAK,iBAAiB,OAAO,GAAG,IAAI,GAAG,UAAU;CAC5D,MAAM,MAAM;EACX,MAAM;EACN,SAAS,iBAAiB,OAAO;CAClC;CACA,IAAI,SAAS,IAAI,UAAU;CAC3B,OAAO;AACR;;AAEA,SAAS,2BAA2B;CACnC,MAAM,MAAM,uBAAuB;CACnC,KAAK,MAAM,QAAQ,aAAa,KAAK,MAAM,GAAG;AAC/C;AACA,SAAS,cAAc;CACtB,OAAO,QAAQ,IAAI,yBAAyB,QAAQ,IAAI;AACzD;AACA,SAAS,WAAW,MAAM,YAAY;CACrC,QAAA,GAAA,UAAA,MAAY,MAAM,aAAa,QAAQ,GAAG,WAAW,IAAI;AAC1D;AACA,MAAM,mBAAmB;AACzB,SAAS,iBAAiB,QAAQ;CACjC,MAAM,QAAQ;EACb,+BAA+B,IAAI,IAAI;EACvC,mBAAmB;EACnB,OAAO;CACR;CACA,MAAM,OAAO,kBAAkB;EAC9B,IAAI,CAAC,MAAM,OAAO;GACjB,OAAO,UAAU;GACjB;EACD;EACA,MAAM,QAAQ;EACd,IAAI;GACH,OAAO,KAAK;EACb,QAAQ,CAAC;CACV,GAAG,gBAAgB;CACnB,OAAO,GAAG,cAAc;EACvB,MAAM,QAAQ;CACf,CAAC;CACD,OAAO,GAAG,YAAY,QAAQ;EAC7B,IAAI;EACJ,IAAI;GACH,SAAS,KAAK,MAAM,IAAI,SAAS,MAAM,CAAC;EACzC,QAAQ;GACP,UAAU,QAAQ,KAAK,GAAG,cAAc;GACxC;EACD;EACA,MAAM,YAAY,oBAAoB,UAAU,MAAM;EACtD,IAAI,CAAC,UAAU,SAAS;GACvB,UAAU,QAAQ,KAAK,GAAG,oBAAoB,UAAU,MAAM,SAAS;GACvE;EACD;EACA,oBAAoB,QAAQ,OAAO,UAAU,IAAI;CAClD,CAAC;CACD,OAAO,GAAG,eAAe;EACxB,cAAc,IAAI;EAClB,KAAK,MAAM,CAAC,YAAY,UAAU,MAAM,cAAc,QAAQ,GAAG;GAChE,MAAM;GACN,kBAAkB,YAAY,MAAM;EACrC;EACA,MAAM,cAAc,MAAM;EAC1B,IAAI,MAAM,mBAAmB;GAC5B,YAAY,OAAO,MAAM;GACzB,MAAM,oBAAoB;EAC3B;EACA,IAAI,iBAAiB,OAAO,MAAM,GAAG,yBAAyB;CAC/D,CAAC;CACD,OAAO,GAAG,eAAe,CAAC,CAAC;AAC5B;AACA,eAAe,oBAAoB,QAAQ,OAAO,KAAK;CACtD,QAAQ,IAAI,MAAZ;EACC,KAAK,aAAa;GACjB,IAAI,MAAM,cAAc,IAAI,IAAI,UAAU,GAAG;GAC7C,MAAM,QAAQ,eAAe,IAAI,UAAU,EAAE,UAAU;IACtD,QAAQ,OAAO;KACd,KAAK,QAAQ;MACZ,MAAM;MACN,YAAY,IAAI;MAChB;KACD,CAAC;IACF;IACA,UAAU;KACT,KAAK,QAAQ;MACZ,MAAM;MACN,YAAY,IAAI;KACjB,CAAC;KACD,MAAM,cAAc,OAAO,IAAI,UAAU;KACzC,kBAAkB,IAAI,YAAY,MAAM;IACzC;GACD,CAAC;GACD,MAAM,cAAc,IAAI,IAAI,YAAY,KAAK;GAC7C,eAAe,IAAI,YAAY,MAAM;GACrC,yBAAyB,QAAQ,IAAI,UAAU;GAC/C;EACD;EACA,KAAK,eAAe;GACnB,MAAM,QAAQ,MAAM,cAAc,IAAI,IAAI,UAAU;GACpD,IAAI,OAAO;IACV,MAAM;IACN,MAAM,cAAc,OAAO,IAAI,UAAU;GAC1C;GACA,kBAAkB,IAAI,YAAY,MAAM;GACxC;EACD;EACA,KAAK;GACJ,IAAI,CAAC,WAAW,IAAI,OAAO,IAAI,MAAM,GAAG,UAAU,QAAQ,KAAK,GAAG,kBAAkB,IAAI,OAAO;GAC/F;EACD,KAAK;GACJ,IAAI;IACH,MAAM,gBAAgB,IAAI,YAAY,IAAI,OAAO;GAClD,SAAS,KAAK;IACb,UAAU,QAAQ,IAAI,YAAY,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;GACnF;GACA;EACD,KAAK;GACJ,IAAI,CAAC,MAAM,aAAa,IAAI,UAAU,GAAG,UAAU,QAAQ,IAAI,YAAY,+BAA+B;GAC1G;EACD,KAAK,gBAAgB;GACpB,MAAM,OAAO,YAAY;GACzB,MAAM,UAAU,WAAW,MAAM,IAAI,UAAU;GAC/C,aAAa,IAAI,UAAU;GAC3B,uBAAuB,IAAI,YAAY,EAAE,OAAO,UAAU,CAAC;GAC3D,MAAM,SAAS,MAAM,QAAQ,YAAY,cAAc,MAAM,IAAI,YAAY,OAAO,CAAC;GACrF,IAAI,OAAO,IAAI,uBAAuB,IAAI,YAAY;IACrD,OAAO;IACP,GAAG,OAAO,YAAY,EAAE,WAAW,OAAO,UAAU,IAAI,CAAC;GAC1D,CAAC;QACI,IAAI,OAAO,aAAa,OAAO,UAAU,SAAS,GAAG,uBAAuB,IAAI,YAAY;IAChG,OAAO;IACP,WAAW,OAAO;GACnB,CAAC;QACI,uBAAuB,IAAI,YAAY;IAC3C,OAAO;IACP,GAAG,OAAO,QAAQ,EAAE,SAAS,OAAO,MAAM,IAAI,CAAC;GAChD,CAAC;GACD;EACD;EACA,KAAK,mBAAmB;GACvB,MAAM,OAAO,YAAY;GACzB,MAAM,UAAU,WAAW,MAAM,IAAI,UAAU;GAC/C,aAAa,IAAI,UAAU;GAC3B,uBAAuB,IAAI,YAAY,EAAE,OAAO,aAAa,CAAC;GAC9D,IAAI;IACH,MAAM,QAAQ,YAAY,gBAAgB,MAAM,IAAI,YAAY,OAAO,CAAC;IACxE,uBAAuB,IAAI,YAAY,EAAE,OAAO,YAAY,CAAC;GAC9D,SAAS,KAAK;IACb,uBAAuB,IAAI,YAAY;KACtC,OAAO;KACP,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;IACzD,CAAC;GACF;GACA;EACD;EACA,KAAK,kBAAkB;GACtB,MAAM,OAAO,YAAY;GACzB,MAAM,UAAU,WAAW,MAAM,IAAI,UAAU;GAC/C,MAAM,SAAS,MAAM,QAAQ,YAAY,mBAAmB,MAAM,IAAI,YAAY,OAAO,CAAC;GAC1F,IAAI,OAAO,IAAI,uBAAuB,IAAI,YAAY,EAAE,OAAO,OAAO,CAAC;QAClE,UAAU,QAAQ,IAAI,YAAY,OAAO,KAAK;GACnD;EACD;EACA,KAAK;GACJ,IAAI,MAAM,mBAAmB;GAC7B,YAAY,IAAI,MAAM;GACtB,MAAM,oBAAoB;GAC1B,KAAK,QAAQ,uBAAuB,CAAC;GACrC;EACD,KAAK;GACJ,IAAI,CAAC,MAAM,mBAAmB;GAC9B,YAAY,OAAO,MAAM;GACzB,MAAM,oBAAoB;GAC1B;EACD,KAAK;GACJ,iBAAiB,IAAI,QAAQ,IAAI,OAAO;GACxC,yBAAyB;GACzB;EACD,KAAK,sBAAsB;GAC1B,MAAM,QAAQ,EAAE,uBAAuB,IAAI,sBAAsB;GACjE,IAAI,IAAI,sBAAsB,MAAM,MAAM,aAAa,IAAI;GAC3D,IAAI;IACH,MAAM,IAAI,cAAc,YAAY,CAAC,EAAE,MAAM,KAAK;GACnD,SAAS,KAAK;IACb,QAAQ,MAAM,4DAA4D,GAAG;GAC9E;GACA;EACD;EACA,KAAK;GACJ,KAAK,QAAQ,uBAAuB,CAAC;GACrC;EACD,KAAK;GACJ,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAC;GAC7B;CACF;AACD;AACA,eAAe,yBAAyB,QAAQ,YAAY;CAC3D,IAAI;EACH,MAAM,MAAM,MAAM,IAAI,QAAQ,YAAY,CAAC,EAAE,KAAK,UAAU;EAC5D,IAAI,CAAC,KAAK;EACV,MAAM,QAAQ,IAAI,kBAAkB,YAAY,QAAQ,UAAU,IAAI,gBAAgB,IAAI;EAC1F,MAAM,UAAU;GACf,MAAM;GACN;GACA;EACD;EACA,IAAI,IAAI,WAAW,QAAQ,YAAY,IAAI;EAC3C,IAAI,IAAI,iBAAiB,UAAU,YAAY,UAAU,gBAAgB;GACxE,MAAM,IAAI,MAAM,qBAAqB,IAAI,YAAY;GACrD,IAAI,MAAM,MAAM,QAAQ,eAAe;EACxC;EACA,KAAK,QAAQ,OAAO;CACrB,QAAQ,CAAC;AACV;AACA,SAAS,KAAK,QAAQ,SAAS;CAC9B,IAAI,OAAO,eAAe,OAAO,MAAM;CACvC,IAAI;EACH,OAAO,KAAK,KAAK,UAAU,OAAO,CAAC;CACpC,QAAQ,CAAC;AACV;AACA,SAAS,UAAU,QAAQ,YAAY,SAAS;CAC/C,KAAK,QAAQ,aAAa;EACzB,MAAM;EACN;EACA;CACD,IAAI;EACH,MAAM;EACN;CACD,CAAC;AACF;AAGA,MAAM,yBAAyB;AAC/B,MAAM,yBAAyB;AAC/B,MAAM,cAAc;;AAEpB,SAAS,eAAe,QAAQ,WAAW;CAC1C,OAAO,GAAG,OAAO,QAAQ,QAAQ,EAAE,IAAI,YAAY,WAAW,mBAAmB,SAAS;AAC3F;;;;;;AAMA,SAAS,YAAY,SAAS,MAAM;CACnC,MAAM,MAAM,KAAK,IAAI,KAAK,KAAK,KAAK,MAAM,KAAK,OAAO;CACtD,OAAO,KAAK,MAAM,MAAM,IAAI,KAAK,OAAO,KAAK,MAAM,EAAE;AACtD;AACA,SAAS,eAAe,KAAK,OAAO;CACnC,OAAO,IAAIC,GAAAA,UAAU,KAAK,EAAE,SAAS,EAAE,eAAe,UAAU,QAAQ,EAAE,CAAC;AAC5E;;;;;;AAMA,SAAS,iBAAiB,MAAM;CAC/B,MAAM,MAAM,KAAK,gBAAgB;CACjC,MAAM,MAAM,KAAK,gBAAgB;CACjC,MAAM,UAAU,KAAK,WAAW;CAChC,MAAM,SAAS,KAAK,UAAU;CAC9B,MAAM,WAAW,KAAK,cAAc,IAAI,OAAO,KAAK,WAAW,IAAI,EAAE;CACrE,MAAM,MAAM,KAAK,SAAS,QAAQ,QAAQ,IAAI,cAAc,KAAK;CACjE,MAAM,YAAY,eAAe,KAAK,KAAK,KAAK,SAAS;CACzD,IAAI,UAAU;CACd,IAAI,UAAU;CACd,IAAI,SAAS;CACb,MAAM,aAAa;EAClB,IAAI,SAAS;EACb,MAAMC,OAAK,QAAQ,WAAW,KAAK,KAAK;EACxC,SAASA;EACT,KAAG,GAAG,cAAc;GACnB,UAAU;GACV,IAAI,oBAAoB,UAAU,EAAE;GACpC,OAAOA,IAAE;EACV,CAAC;EACD,KAAG,GAAG,eAAe;GACpB,IAAI,SAAS;GACb,MAAM,QAAQ,YAAY,WAAW;IACpC;IACA;GACD,CAAC;GACD,IAAI,uCAAuC,MAAM,GAAG;GACpD,SAAS,MAAM,KAAK;EACrB,CAAC;EACD,KAAG,GAAG,eAAe,CAAC,CAAC;CACxB;CACA,KAAK;CACL,OAAO,EAAE,QAAQ;EAChB,UAAU;EACV,IAAI;GACH,QAAQ,MAAM;EACf,QAAQ,CAAC;CACV,EAAE;AACH;;;;;;AAMA,SAAS,mBAAmB;CAC3B,MAAM,OAAO,QAAQ,IAAI,yBAAyB,QAAQ,IAAI;CAC9D,QAAA,GAAA,YAAA,YAAkB,QAAQ,EAAE,OAAO,IAAI,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AACnE;AACA,MAAM,sBAAsB,OAAO,IAAI,sBAAsB;;;;;;;;;;;;;AAa7D,SAAS,wBAAwB;CAChC,MAAM,MAAM,QAAQ,IAAI;CACxB,MAAM,QAAQ,QAAQ,IAAI;CAC1B,IAAI,CAAC,OAAO,CAAC,OAAO,OAAO;CAC3B,MAAM,IAAI;CACV,MAAM,WAAW,EAAE;CACnB,IAAI,UAAU,OAAO;CACrB,MAAM,SAAS,iBAAiB;EAC/B;EACA;EACA,WAAW,QAAQ,IAAI,0BAA0B,iBAAiB;CACnE,CAAC;CACD,EAAE,uBAAuB;CACzB,OAAO;AACR;AAgBA,MAAM,oBAAoB;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD,EAAE,KAAK,IAAI;AACW;CACrB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD,EAAE,KAAK,IAAI;AAmFkB;CAC5B;CACA;CACA;CACA;CACA;AACD,EAAE,KAAK,IAAI;;;;;;;;AC9qJX,SAAgB,2BACd,MAC6D;CAC7D,IAAI,CAAC,QAAQ,IAAI,uBACf,QAAQ,IAAI,wBAAwB,KAAK;CAE3C,OAAO,EAAE,kBAAkB,yBAAyB,EAAE;AACxD;;AAGA,MAAM,iBAAiB,OAAO,IAAI,2BAA2B;;;;;;;;;;;;;;;;;;AAqB7D,SAAgB,sBAAsB,QAAsB;CAC1D,MAAM,UAAU;CAChB,IAAI,QAAQ,iBAAiB;CAC7B,QAAQ,kBAAkB;CAE1B,MAAM,MAAM,yBAAyB;CACrC,MAAM,QAAQ,OAAO,UAAU,SAAS;CACxC,OAAO,mBAAmB,SAAS;CAEnC,OAAO,GAAG,YAAY,KAAK,QAAgB,SAAiB;EAC1D,IAAI,WAAW;EACf,IAAI;GACF,WAAW,IAAI,IAAI,IAAI,OAAO,IAAI,kBAAkB,EAAE;EACxD,QAAQ;GACN,YAAY,IAAI,OAAO,IAAI,MAAM,GAAG,EAAE,MAAM;EAC9C;EACA,IAAI,aAAa,kBAAkB;GACjC,IAAI,cAAc,KAAK,QAAQ,OAAO,OAAO,IAAI,KAAK,cAAc,IAAI,GAAG,CAAC;GAC5E;EACF;EACA,KAAK,MAAM,MAAM,OAAO,GAAG,KAAK,QAAQ,KAAK,QAAQ,IAAI;CAC3D,CAAC;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;AC/EA,MAAM,iBAAiB,IAAI,OAAO;AAyClC,SAAgB,mBAAmB,MAAkD;CACnF,MAAM,UAAU,IAAI,QAAQ,KAAK,WAAW;CAC5C,MAAM,YAA4B,KAAK,aAAa;CAMpD,IAAI,CAAC,QAAQ,IAAI,uBACf,QAAQ,IAAI,wBAAwB,KAAK;CAQ3C,IAAI,KAAK,QACP,QAAQ,IAAI,yBAAyB,KAAK;CAG5C,MAAM,WAAW,OAAO,KAAsB,KAAqB,SAAqB;EAOtF,MAAM,SAAU,IAAI,QAA4C;EAChE,IAAI,QAAQ,sBAAsB,MAAM;EAExC,MAAM,MAAM,IAAI,OAAO;EACvB,IAAI,CAAC,IAAI,WAAW,aAAa,GAAG,OAAO,KAAK;EAEhD,IAAI;GAEF,IAAI,IAAI,WAAW,UAAU,QAAQ,wBAAwB;IAC3D,MAAM,MAAM,MAAM,aAAa,GAAG;IAClC,MAAM,SAAS,oBAAoB,UAAU,GAAG;IAChD,IAAI,CAAC,OAAO,SAAS,OAAO,WAAW,KAAK,OAAO,MAAM,OAAO;IAGhE,IADgBC,YAAAA,OAAO,KAAK,OAAO,KAAK,YAAY,QAC1C,EAAE,SAAS,IAAI,OAAO,MAC9B,OAAO,WAAW,KAAK,wBAAwB;IAGjD,MAAM,MAAA,GAAA,OAAA,QAAY,EAAE;IACpB,MAAM,MAAM,MAAM,QAAQ,OAAO,IAAI,OAAO,IAAI;IAEhD,MAAM,eAAe,cAAc;IACnC,IAAI,cACF,IAAI;KACF,MAAM,WAAW;MAAE,aAAa,QAAQ;MAAM,UAAU;MAAK,MAAM;KAAU,CAAC;IAChF,QAAQ,CAER;IAEF,OAAO,KAAK,KAAK,KAAK;KAAE,IAAI,IAAI;KAAI;IAAa,CAAC;GACpD;GAGA,IAAI,IAAI,WAAW,SAAS,QAAQ,wBAElC,OAAO,KAAK,KAAK,KAAK,MADF,QAAQ,KAAK,CACN;GAO7B,IAAI,IAAI,WAAW,UAAU,QAAQ,oBAAoB;IACvD,MAAM,MAAO,MAAM,aAAa,GAAG;IAKnC,MAAM,OAAO,OAAO,KAAK,SAAS,WAAW,IAAI,OAAO;IACxD,IAAI,CAAC,MAAM,OAAO,WAAW,KAAK,cAAc;IAChD,MAAM,OAAA,GAAA,UAAA,SAAkB,KAAK,aAAa,IAAI;IAE9C,MAAM,OAAA,GAAA,UAAA,UAAe,KAAK,aAAa,GAAG;IAC1C,IAAI,IAAI,WAAW,IAAI,MAAA,GAAA,UAAA,YAAgB,GAAG,GACxC,OAAO,WAAW,KAAK,2BAA2B;IAKpD,OAAO,KAAK,KAAK,KAAK,EAAE,IADT,aAAa,KAFf,OAAO,SAAS,OAAO,KAAK,IAAI,CAAC,IAAI,OAAO,KAAK,IAAI,IAAI,GAC1D,OAAO,SAAS,OAAO,KAAK,GAAG,CAAC,IAAI,OAAO,KAAK,GAAG,IAAI,CAElC,EAAE,CAAC;GACtC;GAEA,OAAO,KAAK,KAAK,KAAK,EAAE,OAAO,YAAY,CAAC;EAC9C,SAAS,KAAK;GACZ,OAAO,KAAK,KAAK,KAAK,EAAE,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,EAAE,CAAC;EACnF;CACF;CAEA,QAAQ,SAAS,WAA6B;EAC5C,QAAQ,KAAK,KAAK,SAAS;GACzB,KAAK,IAAI,OAAO,IAAI,WAAW,aAAa,GAC1C,QAAQ,KAAK,WAAW,OAAO,KAAK,KAAK,IAAI,CAAC;QAE9C,OAAO,KAAK,KAAK,IAAI;EAEzB;CACF;CAEA,OAAO;AACT;AAEA,SAAS,aAAa,KAAwC;CAC5D,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,SAAmB,CAAC;EAC1B,IAAI,QAAQ;EACZ,IAAI,GAAG,SAAS,UAAkB;GAChC,SAAS,MAAM;GACf,IAAI,QAAQ,gBAAgB;IAC1B,uBAAO,IAAI,MAAM,mBAAmB,CAAC;IACrC,IAAI,QAAQ;IACZ;GACF;GACA,OAAO,KAAK,KAAK;EACnB,CAAC;EACD,IAAI,GAAG,aAAa;GAClB,IAAI,OAAO,WAAW,GAAG,OAAO,QAAQ,IAAI;GAC5C,IAAI;IACF,QAAQ,KAAK,MAAMA,YAAAA,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM,CAAC,CAAC;GAC5D,SAAS,GAAG;IACV,OAAO,CAAC;GACV;EACF,CAAC;EACD,IAAI,GAAG,SAAS,MAAM;CACxB,CAAC;AACH;AAEA,SAAS,KAAK,KAAqB,QAAgB,MAAqB;CACtE,IAAI,aAAa;CACjB,IAAI,UAAU,gBAAgB,iCAAiC;CAC/D,IAAI,UAAU,iBAAiB,UAAU;CACzC,IAAI,IAAI,KAAK,UAAU,IAAI,CAAC;AAC9B;AAEA,SAAS,WAAW,KAAqB,KAAmB;CAC1D,KAAK,KAAK,KAAK,EAAE,OAAO,IAAI,CAAC;AAC/B;;AAGA,SAAS,WAAW,KAA4B;CAC9C,KAAK,MAAM,QAAQ,QAAQ,IAAI,QAAQ,IAAI,MAAMC,UAAAA,SAAS,GACxD,IAAI,QAAA,GAAA,QAAA,aAAA,GAAA,UAAA,MAAuB,KAAK,GAAG,CAAC,GAAG,QAAA,GAAA,UAAA,MAAY,KAAK,GAAG;CAE7D,OAAO;AACT;AAUA,MAAM,cAAsD;CAC1D;EAAE,KAAK;EAAQ,MAAM,CAAC,IAAI;CAAE;CAC5B;EAAE,KAAK;EAAU,MAAM,CAAC,IAAI;CAAE;CAC9B;EAAE,KAAK;EAAY,MAAM,CAAC,IAAI;CAAE;CAChC;EAAE,KAAK;EAAiB,MAAM,CAAC,IAAI;CAAE;CACrC;EAAE,KAAK;EAAU,MAAM,CAAC,IAAI;CAAE;CAC9B;EAAE,KAAK;EAAO,MAAM,CAAC;CAAE;CACvB;EAAE,KAAK;EAAQ,MAAM,CAAC;CAAE;AAC1B;AAIA,MAAM,WAAmD;CACvD;EAAE,KAAK;EAAU,MAAM,CAAC,IAAI;CAAE;CAC9B;EAAE,KAAK;EAAsB,MAAM,CAAC,IAAI;CAAE;CAC1C;EAAE,KAAK;EAAY,MAAM,CAAC,IAAI;CAAE;CAChC;EAAE,KAAK;EAAY,MAAM,CAAC,IAAI;CAAE;CAChC;EAAE,KAAK;EAAO,MAAM,CAAC;CAAE;CACvB;EAAE,KAAK;EAAgB,MAAM,CAAC;CAAE;AAClC;;;;;;AAOA,SAAS,gBAA+B;CACtC,MAAM,WAAW,QAAQ,IAAI,iBAAiB,KAAK;CACnD,IAAI,UAAU;EACZ,MAAM,CAAC,KAAK,GAAG,cAAc,SAAS,MAAM,KAAK;EACjD,IAAI,KAAK,OAAO;GAAE;GAAK;EAAW;CACpC;CACA,KAAK,MAAM,KAAK,aACd,IAAI,WAAW,EAAE,GAAG,GAAG,OAAO;EAAE,KAAK,EAAE;EAAK,YAAY,EAAE;CAAK;CAEjE,IAAI,QAAQ,aAAa;OAClB,MAAM,KAAK,UACd,KAAA,GAAA,QAAA,YAAe,iBAAiB,EAAE,IAAI,KAAK,GACzC,OAAO;GAAE,KAAK;GAAQ,YAAY;IAAC;IAAM,EAAE;IAAK;IAAU,GAAG,EAAE;GAAI;EAAE;CAAA;CAI3E,OAAO;AACT;;;;;;;AAQA,SAAS,aAAa,KAAa,MAAc,KAAsB;CACrE,MAAM,SAAS,cAAc;CAC7B,IAAI,CAAC,QAAQ,OAAO;CACpB,MAAM,SAAS,GAAG,IAAI,GAAG,KAAK,GAAG;CACjC,IAAI;EACF,MAAM,SAAA,GAAA,mBAAA,OAAc,OAAO,KAAK,CAAC,GAAG,OAAO,YAAY,MAAM,GAAG;GAC9D,OAAO;GACP,UAAU;EACZ,CAAC;EACD,MAAM,GAAG,eAAe,CAExB,CAAC;EACD,MAAM,MAAM;EACZ,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF"}
|