diff --git a/api/openapi.yaml b/api/openapi.yaml index 7b90a24..b958f10 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -1352,9 +1352,9 @@ components: event_seq: { type: integer, format: int64, description: "The task's latest event when the snapshot was started: the tree holds at least the work up to it." } trigger: type: string - enum: [message, turn_end, tool_call, ask_human, timer] - x-enum-varnames: [SnapshotTriggerMessage, SnapshotTriggerTurnEnd, SnapshotTriggerToolCall, SnapshotTriggerAskHuman, SnapshotTriggerTimer] - description: "turn_end: after byre's end-of-turn commit. message (the agent wrote text after one or more tool calls), tool_call, ask_human and timer appear only on snapshots taken by earlier builds." + enum: [message, turn_end, tool_call, ask_human, timer, requested] + x-enum-varnames: [SnapshotTriggerMessage, SnapshotTriggerTurnEnd, SnapshotTriggerToolCall, SnapshotTriggerAskHuman, SnapshotTriggerTimer, SnapshotTriggerRequested] + description: "turn_end: after byre's end-of-turn commit. requested: a task's agent or the lead asked for it with take_snapshot. message (the agent wrote text after one or more tool calls), tool_call, ask_human and timer appear only on snapshots taken by earlier builds." created_at: { type: string, format: date-time } Preview: diff --git a/docs/operations.md b/docs/operations.md index fbf6dc3..01cf1d6 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -200,7 +200,7 @@ Each user has one long-running lead agent, shown in the left pane. It is not tie - **Messages.** `POST /api/me/lead/messages` sends the caller's message to their lead, starting a lead session when there is none. While the lead is mid-turn the message is held in `lead_inputs`; the lead's PostToolUse hook (Codex: `turn/steer` after each completed tool item) hands held messages over after its next tool call, like a task's queued messages (see "Agent sessions"), and any still held become its next turn. Signals are never handed over mid-turn. The composer stays enabled. `GET /api/me/lead/sessions` lists the caller's lead sessions; interrupt and compact use the usual session endpoints. - **Scrollback.** `GET /api/me/lead/events` returns a page of the caller's lead events in whole turns, `turns` of them (default 50): those after the `turns`+1'th `turn.ended` before `before` (or before the latest event, so the page also holds a turn still running), with `more` saying whether earlier events exist. The lead pane loads only the last page (see "Events"); when its top comes within 400px of view (an `IntersectionObserver` on an empty element kept as the transcript's first child), it fetches the page before its first event, draws it with fresh render state into a fragment (`prependEvents` in `web/src/task.ts`), inserts it at the top and keeps the scroll position. A page starts just after a `turn.ended`, so rendering it from scratch matches how it drew as part of the whole history. Live events still append without limit until the page is reloaded. - **Signals.** Every published event goes through `Manager.Observe`. These become signals in `lead_inputs` for every user who has a lead session: `inbox.created` (a question with its choices and recommendation, an error or rate limit), `inbox.updated` when a human answered a question or error (a question's signal also carries its text and the agent's recommendation, so the lead sees where the human departed from it), `task.created` (naming the TODO item it was started from, or a subtask's parent, if any), `task.merge_started` (" is merging, started by ."), `task.merged`, `task.discarded`, `turn.ended` with `summary: true` (" finished a turn:" with its `result` cut to 1500 characters), `task.workflow_stage` (" started stage "" of workflow "".") and `task.workflow_finished` (" finished workflow "":" with its output cut to 1500 characters), `review.started` (" started a review of snapshot ."), `review.finished` (" review of snapshot :" with the review's summary, `change` and findings, or why it failed or was skipped; `reviewLine` in `internal/agents/review.go`), `user.message` on a task from a human (see "Pane lock"), and `task.state` (" state: → .", or " state: ." for a new task; see "Task state in the store"). The store hands `Observe` all of one transaction's events together, and they become one signal, its `task.state` lines first, so a turn's summary always arrives with the state its turn end left the task in. The human switching the right pane is not a signal. A signal caused by the lead itself (actor ` (lead)`) is skipped, as is the update from an answer it gave. A task's `task.created` event carries the actor that created it, separately from its `created_by` login: tasks the lead creates with `create_task` or `start_todo` keep the human's login as `created_by` but have actor ` (lead)`. Whenever the lead is idle, byre sends the oldest held message from the human as its own turn, or else every held signal as one `byre` message headed "Signals since your last turn (n)", followed by "Tasks now:" with the `list_tasks` text and a line saying what the lead's right pane shows (task or project, and selected tab) and whether the human is working in it (`leadStateText` in `internal/agents/lead.go`). If collecting that fails, for example because a project's repository is gone, the batch is still sent, ending instead with "The task list and right pane state are unavailable:" and the error, which is also logged as `lead state`. Its guidance tells it not to respond to the human's own actions, and to make its final message exactly `NO_REPLY` when a batch needs nothing from it. A transcript (`quietReply` in `web/src/task.ts`) never draws an `agent.message` whose last line is `NO_REPLY` (the model sometimes writes a sentence before it), and hides the live partial message while its text is still a prefix of it; the partial message starts hidden and is first shown by its 100ms render, so an empty one never takes up space. A lead turn that byre starts without a handoff (a signal batch or a handoff continuation) is held (`ctx.held`): its `byre` message is never drawn, the turn isn't opened, so the scanner stays off, its partial message stays hidden, and its tool calls, subagents and thinking are rendered into an off-screen fragment instead of the transcript. The turn is released, inserting that fragment where the turn belongs, when it draws anything else: a real message, a note, or its own `turn.ended` when it ends without `NO_REPLY`. When it ends in `NO_REPLY` while still held, the fragment is dropped, so nothing of the turn ever appears; a turn that draws a real message anywhere in it keeps all of it, even when a later message is `NO_REPLY`. -- **Tools.** `list_tasks` (each project's active tasks with their state, each subtask noting its parent, then a line listing the titles of its `TODO.md` items on the default branch that no active task was started from), `read_transcript` (a task's events in brief, the last `limit` or those after `after_seq`; closed tasks too), `search_closed_tasks` (see "Closing a task"), `read_inbox`, `answer_question` (an `option`, `other` or `dismiss` response recorded as the user, through the same checks as `POST /api/inbox/responses`), `send_message` (starts the task's agent if it has none; refused while it is mid-turn), `create_task` and `start_todo` (each with an optional `workflow` to freeze and run), `interrupt`, `compact_task`, `merge_task` (optional `target`: `main`, or `parent` for a subtask, see "Subtasks"), `discard_task`, `show`, `compact_self`, the note tools (see "Notes") and the workflow tools (see "Workflows"). The lead also has Claude Code's own tools and reads worktrees by path. Messages it sends task agents have actor ` (lead)`, so they don't make the user a participant; tasks, merges, discards and answers are done as the user. Its guidance says to answer a question only when the answer is clear or the human gave it, and to merge or discard only when the human asks. +- **Tools.** `list_tasks` (each project's active tasks with their state, each subtask noting its parent, then a line listing the titles of its `TODO.md` items on the default branch that no active task was started from), `read_transcript` (a task's events in brief, the last `limit` or those after `after_seq`; closed tasks too), `search_closed_tasks` (see "Closing a task"), `read_inbox`, `answer_question` (an `option`, `other` or `dismiss` response recorded as the user, through the same checks as `POST /api/inbox/responses`), `send_message` (starts the task's agent if it has none; refused while it is mid-turn), `create_task` and `start_todo` (each with an optional `workflow` to freeze and run), `interrupt`, `compact_task`, `take_snapshot` (see "Snapshots"), `merge_task` (optional `target`: `main`, or `parent` for a subtask, see "Subtasks"), `discard_task`, `show`, `compact_self`, the note tools (see "Notes") and the workflow tools (see "Workflows"). The lead also has Claude Code's own tools and reads worktrees by path. Messages it sends task agents have actor ` (lead)`, so they don't make the user a participant; tasks, merges, discards and answers are done as the user. Its guidance says to answer a question only when the answer is clear or the human gave it, and to merge or discard only when the human asks. - **Focus.** `users.focus` holds what the user's right pane shows: `project_id`, `task_id`, `tabs` (the tabs put first, in order) and `tab` (the selected one). With a `task_id`, `project_id` is always that task's project, filled in by the server; with only a `project_id`, the pane shows that project with no task, which only the Project tab has anything for. `GET /api/me/focus` reads it; `PUT /api/me/focus` and the lead's `show` set it, refusing an unknown tab, a task that isn't active or an unknown project, and record a `focus.updated` event owned by the user. The page applies the focus on load and on every `focus.updated` it didn't cause itself; the human's own changes (⌘K, the right pane's task picker, clicking a tab, a task link, a notification) are sent with `PUT /api/me/focus`. The URL follows the focus: `#/task/`, `#/project/`, or `#/` for neither. - **Pane lock.** A `show` of what the pane already shows (the same task, or the same project with no task, on the same selected tab; `sameView`) tells the lead so and applies only its `tabs` order, whether or not the human is in the pane, so the human's selected tab stays selected. Otherwise, while the human is working in the right pane, the lead's `show` is refused with an error telling it to say in chat what it would have shown, unless its selected tab is `project` (the fallback the lead shows when nothing needs the human, so the human being there doesn't hold it) or the pane is finished (`Manager.paneFinished`): its task is merged, discarded or merging (`merging_by` or `finalizing` set), or its selected tab is `inbox` and the task has no open items, or the human is waiting on the task's agent (`Manager.paneWaiting`): the selected tab is `transcript`, the task's implementer session is running, the page reports no unsent text in the pane, and either the `user.message` that started the running turn came from the user after the pane last moved, or the pane last moved 10 seconds ago or more (`watchHold`). The pane's last move is the last `PUT /api/me/focus` or `show` that set it (`Manager.paneMoved`, in memory, so a restart counts as long ago). For the user's own message, unsent text reported before the turn started doesn't count, since the page's report of the composer emptying on send can arrive after the message does. A `user.message` on a task from a human (not `byre`, an agent or a lead) signals every lead " sent a message; its agent is working on it.", and the sender's own lead, when its pane shows that task and is waiting that way, also gets "Your right pane is free: the human is waiting on 's agent." Each `PUT /api/me/focus` from the user starts a 10-second timer (`endWatchHold`); when it fires, if the pane hasn't moved since, the page still reports the human in it, the user hasn't messaged the task since the move (that already freed it, above), and the pane is waiting that way, the lead gets the signal "Your right pane is free: the human has watched 's agent work for 10 seconds without typing." The lead's own `show` starts no timer. When an `inbox.updated`, `task.merge_started`, `task.merged` or `task.discarded` event leaves a user's focused task finished that way, that user's signal for it gets a line "Your right pane is free: has nothing left in its inbox." (or "is merging."/"is merged."/"is discarded."), even when the event itself makes no signal, such as a dismissed error; `inbox.updated` on a task that is no longer active adds none. The lead's guidance tells it to show the next thing that needs the human on that line, or, when nothing does, the project's Project tab with a short status in chat: one line per active task, then up to three TODO items it would start next, each with a reason, starting one only when the human picks it. It writes each item as a link to `#/todo//`; Markdown views draw that (`web/src/todolink.ts`) as the title followed by small `start` and `discuss` buttons, styled like a snapshot row's, that call `POST /api/projects/{id}/todo/tasks` with the first model, as the Project tab's do, or, once an active task was started from that item, the task's colour, dot and state, linking to it. A chat view refills them whenever its transcript grows or tasks or sessions change. When that status says nothing new since its last one, it replies `NO_REPLY` instead. The page sends `PUT /api/me/pane-focus` with `focused` and `drafting` whenever either changes: `focused` is true while the browser window has focus and the focused element is inside the right pane, and `drafting` while any textarea in the right pane (other than xterm's helper) holds non-blank text, checked on focus changes, `input` and `submit`. The pane itself is focusable (`tabIndex` -1), so a click anywhere in it counts, not only on inputs and buttons; a re-render that removes the focused element hands focus back to the pane rather than counting as leaving. The page sends false on `pagehide` (with `keepalive`) and resends true when its event stream reconnects. byre keeps both flags and the time of the last report in memory per user (`Manager.paneFocus`, `Manager.paneReported`), so they start false after a restart until the page resends them. - **Move hold.** Each `PUT /api/me/focus` from the user (switching task or tab, by any means: the switcher, a tab, a link, a notification, or the page's own switch to Inbox when a question arrives) records the time in `Manager.humanMoved`, and for 10 seconds after it (`moveHold`) every `show` that would change the view is refused, whatever the pane lock above would allow, with an error giving how long ago the move was. A `show` of what the pane already shows still applies its tab order. When the 10 seconds pass without another move by the user (`endMoveHold`, on a timer), byre clears it and sends the lead the signal "The move hold is over: …", every time, whether or not a `show` was refused; its guidance tells it to show what it held back if the pane's other rules allow, or reply `NO_REPLY`. It is in memory, so a restart clears it. @@ -287,6 +287,8 @@ byre snapshots each task's worktree at the end of every turn (`internal/agents/s The trigger is `turn_end`: the snapshot starts after byre's end-of-turn commit and the `turn.ended` event. Snapshots taken by earlier builds also carry `message` (mid-turn, when the agent wrote text after tool calls), `tool_call`, `ask_human` and `timer`. A snapshot whose tree equals the task's latest snapshot's tree is skipped, so a turn that changed no files leaves none. Snapshots run one at a time per task: a trigger that arrives while one is running replaces any already waiting one, and the waiting one runs when the current one finishes. Failures are logged and dropped. +The `take_snapshot` MCP tool asks for a snapshot now (`RequestSnapshot` and `takeSnapshotTool` in `internal/agents/snapshots.go`): a task's agent calls it with no arguments for its own task, and the lead with a `task_id`. The snapshot has trigger `requested`, is taken even when its tree equals the latest snapshot's (so it retries a failed review of unchanged work), and is reviewed like any other (see "Reviews"); it counts as a review request (`BeginReviewRequest`) from the call until the reviewer starts. It is attributed to the task's latest implementer session, authored as that session's creator, and can be taken mid-turn, uncommitted work included. A requested snapshot that is replaced while waiting passes its trigger and its taken-even-when-unchanged to the one that replaces it. Refused for a closed task, while the task is merging or being discarded, and for a task with no agent session. + Merging or discarding a task stops new snapshots for it, waits for one in progress, and deletes its `refs/byre/tasks//` refs; the rows stay. `GET /api/tasks/{taskId}/snapshots` lists a task's rows, oldest first. `git for-each-ref refs/byre/` in the project's repo lists the live refs. `GET /api/tasks/{taskId}/changes?snapshot=` reports a snapshot instead of the live worktree: its `tree` is the snapshot's tree, and `base` is the merge-base of the snapshot's commit and the default branch, or with `step=true` the previous snapshot's tree (for snapshot 1, the same merge-base: the snapshot commit's parent is the worktree's `HEAD`, which already holds whatever byre committed at the end of the turn). It reads the stored shas, so it works only while the task is active and its refs keep the objects; `since` with `snapshot` is a 400. `GET /api/tasks/{taskId}/diff` takes that `base` and `tree` as usual. @@ -305,14 +307,14 @@ The fork's session guidance gets one more line (`forkGuidance` in `internal/agen ## Reviews -Every new snapshot of a task gets a review: a separate agent session on the vendor the task's agent doesn't use reads the change and reports on it (`internal/agents/review.go`, `internal/store/review.go`). A turn that changes no files makes no snapshot and so no review, and a snapshot whose change (the diff below) has no files runs no reviewer: it gets a `reviews` row in state `skipped`, with no session, vendor or model. The snapshot at the end of a Merge turn that finishes into the squash (the turn ended cleanly with `merging_by` still set, read by `turnEnded` before it asks for the snapshot) gets no review and no `reviews` row at all, since the task closes a moment later; a Merge turn that errors, is interrupted, or calls `stop_merge` is reviewed as usual. Nothing else starts a review, and nothing waits for one: reviews ride along for the human to look at when they want. +Every new snapshot of a task gets a review: a separate agent session on the vendor the task's agent doesn't use reads the change and reports on it (`internal/agents/review.go`, `internal/store/review.go`). A turn that changes no files makes no snapshot and so no review, and a snapshot whose change (the diff below) has no files runs no reviewer: it gets a `reviews` row in state `skipped`, with no session, vendor or model. The snapshot at the end of a Merge turn that finishes into the squash (the turn ended cleanly with `merging_by` still set, read by `turnEnded` before it asks for the snapshot) gets no review and no `reviews` row at all, since the task closes a moment later; a Merge turn that errors, is interrupted, or calls `stop_merge` is reviewed as usual. Besides `take_snapshot` (see "Snapshots"), nothing else starts a review, and nothing waits for one: reviews ride along for the human to look at when they want. -- **Starting.** After `takeSnapshot` creates a snapshot, `afterSnapshot` runs `startReviewer`: it picks the vendor opposite the task's latest implementer session (`reviewVendor`) and that vendor's model in `reviewModels`, checks the snapshot's commit out detached at `worktrees//review-`, creates an `agent_sessions` row with `role` `reviewer` on the task (created by the task's creator), a `reviews` row (`running`, one per snapshot), and sends `reviewPrompt` as its first turn (actor `byre`): the change as `git diff` from the previous snapshot (the merge-base with the default branch for the first) with its changed files, the merge-base diff of all the task's work for context, and the task's first message to its agent. +- **Starting.** After `takeSnapshot` creates a snapshot, `afterSnapshot` runs `startReviewer`: it picks the vendor opposite the task's latest implementer session (`reviewVendor`) and that vendor's model in `reviewModels`, checks the snapshot's commit out detached at `worktrees//review-`, creates an `agent_sessions` row with `role` `reviewer` on the task (created by the task's creator), a `reviews` row (`running`, one per snapshot), and sends `reviewPrompt` as its first turn (actor `byre`): all of the task's work as `git diff` from the merge-base of the snapshot and the default branch, with its changed files, and the task's first message to its agent. Every review covers the whole task against the default branch, not only what changed since the previous snapshot, and a snapshot with no changes against it is `skipped`. - **Running.** Reviewer sessions get `reviewGuidance` and only the `submit_review` tool, whose arguments (`reviewSchema`: `change`, a few sentences of Markdown on what the change does, required and non-empty; a Markdown `summary`, which the guidance and schema require to be exactly "No significant findings." when there are no findings and otherwise a bulleted list with one line per finding; `findings`, each with `severity`, `category`, `title`, `detail`, `path`, `line`, `end_line` and `images`; and top-level `images`) become the review's `result` and mark it `done`. The guidance encourages, without requiring, Mermaid blocks for a data flow, call graph, state machine or schema the change alters, and screenshots when the change alters something visible. - **Forwarding.** When a submitted review has findings, byre sends them to the task's live agent as a `byre` message (`forwardFindings` and `findingsMessage` in `internal/agents/review.go`): each finding's severity, title, location and detail, under a preamble asking the agent to check each one against the code and its brief, act on those that hold up, and say in its final message which it acted on and which it left and why. It goes through `Manager.Message`, so it is queued like any message while the agent is mid-turn. A task with no live agent session gets nothing, and the log says `review findings not forwarded`. Forwarding doesn't set any finding's state; **fix** and **ignore** stay available. - **Screenshots.** Reviewer sessions also get the Playwright MCP server (`playwrightMCP` in `internal/agents/review.go`: `npx @playwright/mcp` at a pinned version, headless Chrome, isolated profile, absolute file paths), passed to Claude as a `stdio` entry in `--mcp-config` and to Codex as `mcp_servers` in the thread's `config`. Its automatically named files go to `worktrees//review--media`, removed with the checkout. Each `images` entry is `{path, caption}`, the path absolute or relative to the checkout; at `submit_review` byre reads every one, refuses the whole submission (nothing recorded) for a missing file or one that isn't one of `store.ImageTypes` within `store.MaxBlobBytes`, then stores each as a blob and replaces its `path` with `blob`, since the files are deleted with the checkout. They run without the Stop-hook bounce, mid-turn delivery, end-of-turn commit, snapshots or turn summaries, and their `user.message` events carry no `head`. When the reviewer's turn ends byre completes its session, kills its process and removes the worktree; a review still `running` then fails with why (no submission, with the final message; an error; an interrupt). A process that exits mid-turn fails the review the same way. `StopReview` (`POST /api/reviews/{reviewId}/stop`, the Stop button on a running review's card) ends the reviewer the same way and fails the review ("the reviewer was stopped"), and `Watch` calls it for a reviewer whose process the health check finds `stuck` (no stream event for `StuckAfter`), which is how a reviewer whose connection died while the machine slept gets cleared. Merging or discarding the task fails its running reviews ("the task was closed") and ends their reviewers. On startup, a running reviewer resumes like any session, and a running review whose reviewer isn't `running` fails. - **Events.** `review.started`, `review.finished` (state `done`, `failed` or `skipped`; a skipped review emits only `review.finished`) and `review.finding` (a finding's state set, with the user as actor) carry the whole review, with the task's ids and no `agent_session_id`. A reviewer's own events carry its session id and the task's ids: the transcript skips every event of a session whose `session.created` has `role` `reviewer`, and draws each `review.finished` as a note with its outcome; the lead's `read_transcript` leaves the reviewer's events out and shows each `review.finished` with its summary and findings (`reviewLine`). `GET /api/tasks/{taskId}/sessions` and everything that looks for the task's agent (`ListSessions`) see only implementer sessions. -- **UI.** The **Reviews** tab (`web/src/reviews.ts`) shows one review at a time, picked by snapshot (see "Snapshots" for the picker): its snapshot, state or severity counts, error, summary, screenshots and findings, and, while it runs, a **Stop** button (`POST /api/reviews/{reviewId}/stop`). The `change` field is not shown; it goes to the lead and into notes. A finding with `path` and `line` shows, under its title, the lines `line` to `end_line` plus 3 either side from that file's diff for the snapshot's step (`changes?snapshot=&step=true`, the diff the reviewer was given), with new-file line numbers and the finding's own lines marked; it shows nothing when those lines aren't in the diff, and "diff not available" with the error once the task is closed. Screenshots link to the full image. Each open finding has **fix** and **ignore** buttons (also on review cards in the inbox). **fix** sends the finding's severity, title, location and detail to the task's agent as a message from the user: through `POST /api/sessions/{id}/messages` to its latest live session (queued like any message while the agent is mid-turn, see "Agent sessions"), or starting a session when it has none; the view stays where it is, so several findings can be sent in a row. Then it, or **ignore** on its own, records the finding's state (`fixed` or `ignored`) with `PUT /api/reviews/{reviewId}/findings/{index}`, the index being the finding's position in `result.findings`; the review's `finding_states` (the `reviews.finding_states` column, a JSON object from index to state) holds them, and the buttons give way to "fix sent" or "ignored". Only a `done` review's findings take a state, and there is no way to clear one. The tab loads when it opens, when the task changes, and on each `review.*` event in the task's stream. The tab follows the latest `review.*` event of the highest-numbered snapshot: while that review runs, the tab label (and its entry in the More menu) carries a spinner in place of any earlier review's count; once it finishes with open findings (those with no state), the tab (or the More menu holding it) is highlighted with a badge of their count. Each snapshot row's **review** button carries a mark over its top-right corner from that snapshot's latest `review.*` event: a spinner while the review runs, a grey ● when it was skipped, a green ✓ when it finished with no open findings, and, when it has open findings, the button highlighted with their count in a badge. A failed review leaves the button unmarked. While any of a task's reviews is `running` and its agent is idle, the task's state is `reviewing` (see "Task state in the store"), which the task switcher and the Project tab show as **Working** (see "Task state"). `GET /api/tasks/{taskId}/reviews` lists a task's reviews oldest first. `sqlite3 byre.db "SELECT id, task_id, snapshot_n, vendor, state, error FROM reviews ORDER BY created_at DESC LIMIT 20"` shows recent ones. +- **UI.** The **Reviews** tab (`web/src/reviews.ts`) shows one review at a time, picked by snapshot (see "Snapshots" for the picker): its snapshot, state or severity counts, error, summary, screenshots and findings, and, while it runs, a **Stop** button (`POST /api/reviews/{reviewId}/stop`). The `change` field is not shown; it goes to the lead and into notes. A finding with `path` and `line` shows, under its title, the lines `line` to `end_line` plus 3 either side from that file's diff for the snapshot against the default branch (`changes?snapshot=`, the diff the reviewer was given), with new-file line numbers and the finding's own lines marked; it shows nothing when those lines aren't in the diff, and "diff not available" with the error once the task is closed. Screenshots link to the full image. Each open finding has **fix** and **ignore** buttons (also on review cards in the inbox). **fix** sends the finding's severity, title, location and detail to the task's agent as a message from the user: through `POST /api/sessions/{id}/messages` to its latest live session (queued like any message while the agent is mid-turn, see "Agent sessions"), or starting a session when it has none; the view stays where it is, so several findings can be sent in a row. Then it, or **ignore** on its own, records the finding's state (`fixed` or `ignored`) with `PUT /api/reviews/{reviewId}/findings/{index}`, the index being the finding's position in `result.findings`; the review's `finding_states` (the `reviews.finding_states` column, a JSON object from index to state) holds them, and the buttons give way to "fix sent" or "ignored". Only a `done` review's findings take a state, and there is no way to clear one. The tab loads when it opens, when the task changes, and on each `review.*` event in the task's stream. The tab follows the latest `review.*` event of the highest-numbered snapshot: while that review runs, the tab label (and its entry in the More menu) carries a spinner in place of any earlier review's count; once it finishes with open findings (those with no state), the tab (or the More menu holding it) is highlighted with a badge of their count. Each snapshot row's **review** button carries a mark over its top-right corner from that snapshot's latest `review.*` event: a spinner while the review runs, a grey ● when it was skipped, a green ✓ when it finished with no open findings, and, when it has open findings, the button highlighted with their count in a badge. A failed review leaves the button unmarked. While any of a task's reviews is `running` and its agent is idle, the task's state is `reviewing` (see "Task state in the store"), which the task switcher and the Project tab show as **Working** (see "Task state"). `GET /api/tasks/{taskId}/reviews` lists a task's reviews oldest first. `sqlite3 byre.db "SELECT id, task_id, snapshot_n, vendor, state, error FROM reviews ORDER BY created_at DESC LIMIT 20"` shows recent ones. ## Workflows diff --git a/internal/agents/leadtools.go b/internal/agents/leadtools.go index dfdf35e..830b830 100644 --- a/internal/agents/leadtools.go +++ b/internal/agents/leadtools.go @@ -341,6 +341,19 @@ func (m *Manager) leadTools(l *live) []mcp.Tool { return fmt.Sprintf("Merge of %s started.", task.Id), nil }), + tool("take_snapshot", takeSnapshotDescription+" Refused while the task is merging or being discarded.", taskOnly, + func(ctx context.Context, user api.User, raw json.RawMessage) (string, error) { + task, _, err := m.taskArg(ctx, raw) + if err != nil { + return "", err + } + err = m.RequestSnapshot(ctx, task.Id) + if err != nil { + return "", err + } + return fmt.Sprintf("Snapshot of %s requested; its review shows in the task's transcript and Reviews tab, and findings go to its agent.", task.Id), nil + }), + tool("discard_task", "Discard a task: its agent gets one turn to write the task summary, then byre stops it and deletes its worktree and branch without merging. This destroys its unmerged work. Refused for a task with active subtasks. Only when the human asks. "+ "If the agent is mid-turn, the summary turn starts when that turn ends; no other turn runs in between.", diff --git a/internal/agents/manager.go b/internal/agents/manager.go index 1c6bc51..ab048c2 100644 --- a/internal/agents/manager.go +++ b/internal/agents/manager.go @@ -688,7 +688,7 @@ func (m *Manager) startLive(ctx context.Context, sess api.AgentSession, task api if err != nil { return nil, err } - tools := append([]mcp.Tool{m.askTool(l), m.cancelQuestionTool(l), m.setMergeTitleTool(l), m.stopMergeTool(l), m.setTaskSummaryTool(l), m.searchClosedTool(l), m.exposePortTool(l)}, m.subtaskTools(l)...) + tools := append([]mcp.Tool{m.askTool(l), m.cancelQuestionTool(l), m.setMergeTitleTool(l), m.stopMergeTool(l), m.setTaskSummaryTool(l), m.searchClosedTool(l), m.exposePortTool(l), m.takeSnapshotTool(l)}, m.subtaskTools(l)...) if sess.Role == api.Implementer { g += longTitleGuidance(task) notes, err := m.notesText(ctx, task.CreatedBy, task.ProjectId) @@ -1028,7 +1028,7 @@ func (m *Manager) turnEnded(ctx context.Context, l *live, res endResult) error { return err } if snapshot { - m.snapshotSoon(l, api.SnapshotTriggerTurnEnd, 0, review) + m.snapshotSoon(liveTarget(l), api.SnapshotTriggerTurnEnd, 0, review, false) } switch next { diff --git a/internal/agents/review.go b/internal/agents/review.go index c08c8ff..7abb592 100644 --- a/internal/agents/review.go +++ b/internal/agents/review.go @@ -24,7 +24,7 @@ var reviewModels = map[api.AgentSessionVendor]string{api.Claude: "claude-opus-5- var severities = []string{"critical", "high", "medium", "low", "info"} -const reviewGuidance = `You are a reviewer running inside byre. Another agent is doing a task; you review the change it just made, and a human may read your review in byre's web UI. +const reviewGuidance = `You are a reviewer running inside byre. Another agent is doing a task; you review all of its work so far, and a human may read your review in byre's web UI. - Your working directory is a detached checkout of the snapshot under review. Read, build and run whatever you need there, but don't edit, commit or push: the checkout is discarded when you finish, and the task's own worktree belongs to its agent. - Report with byre's submit_review tool, exactly once, then end your turn with one line. A review that isn't submitted is lost. - Start the review with ` + "`change`" + `: what the change does, in a few sentences, for someone who hasn't read it. @@ -213,35 +213,22 @@ func (m *Manager) startReviewer(ctx context.Context, task api.Task, snap api.Sna } func (m *Manager) reviewPrompt(ctx context.Context, task api.Task, project api.Project, snap api.Snapshot) (string, error) { - previous := "" - if snap.N > 1 { - prev, err := m.store.GetSnapshot(ctx, task.Id, snap.N-1) - if err != nil { - return "", err - } - previous = prev.CommitSha - } - changes, err := git.Compare(project.RepoPath, project.DefaultBranch, snap.CommitSha, snap.TreeSha, previous) + changes, err := git.Compare(project.RepoPath, project.DefaultBranch, snap.CommitSha, snap.TreeSha, "") if err != nil { return "", err } - previous = changes.Base if len(changes.Files) == 0 { return "", nil } - whole, err := git.Compare(project.RepoPath, project.DefaultBranch, snap.CommitSha, snap.TreeSha, "") - if err != nil { - return "", err - } brief, err := m.store.FirstTaskMessage(ctx, task.Id) if err != nil { return "", err } b := &strings.Builder{} - fmt.Fprintf(b, "Review the change the agent working on the byre task %q just made: look for bugs, security problems, missing or wrong tests, and anything that doesn't do what the task asked.\n\n", task.Title) - fmt.Fprintf(b, "It is snapshot %d of the task, commit %s, checked out in your working directory. The change is `git diff %s %s`; %d files changed:\n", - snap.N, snap.CommitSha, previous, snap.CommitSha, len(changes.Files)) + fmt.Fprintf(b, "Review the work of the agent on the byre task %q: look for bugs, security problems, missing or wrong tests, and anything that doesn't do what the task asked.\n\n", task.Title) + fmt.Fprintf(b, "It is snapshot %d of the task, commit %s, checked out in your working directory. The change is all of the task's work, `git diff %s %s` (from the merge-base with %s); %d files changed:\n", + snap.N, snap.CommitSha, changes.Base, snap.CommitSha, project.DefaultBranch, len(changes.Files)) for i, f := range changes.Files { if i == maxReviewFiles { fmt.Fprintf(b, "- … and %d more\n", len(changes.Files)-maxReviewFiles) @@ -249,7 +236,6 @@ func (m *Manager) reviewPrompt(ctx context.Context, task api.Task, project api.P } fmt.Fprintf(b, "- %s %s (+%d −%d)\n", f.Status, f.Path, f.Additions, f.Deletions) } - fmt.Fprintf(b, "\nFor context, all of the task's work so far is `git diff %s %s` (from the merge-base with %s, %d files).\n", whole.Base, snap.CommitSha, project.DefaultBranch, len(whole.Files)) if brief != "" { fmt.Fprintf(b, "\nThe task's brief, the first message its agent got:\n\n%s\n", quote(clip(brief, 4000))) } diff --git a/internal/agents/snapshots.go b/internal/agents/snapshots.go index 9a31f96..4de91e5 100644 --- a/internal/agents/snapshots.go +++ b/internal/agents/snapshots.go @@ -12,6 +12,7 @@ import ( "g.fc.run/misc/byre/internal/api" "g.fc.run/misc/byre/internal/claude" "g.fc.run/misc/byre/internal/git" + "g.fc.run/misc/byre/internal/mcp" "g.fc.run/misc/byre/internal/store" ) @@ -19,6 +20,20 @@ type snapRequest struct { trigger api.SnapshotTrigger seq int64 review bool + force bool +} + +type snapTarget struct { + taskID string + projectID string + sessionID string + dir string + gitName string + gitEmail string +} + +func liveTarget(l *live) snapTarget { + return snapTarget{taskID: l.taskID, projectID: l.projectID, sessionID: l.id, dir: l.dir, gitName: l.gitName, gitEmail: l.gitEmail} } type snapState struct { @@ -37,44 +52,48 @@ func (m *Manager) snapStateLocked(taskID string) *snapState { return st } -func (m *Manager) snapshotSoon(l *live, trigger api.SnapshotTrigger, seq int64, review bool) { +func (m *Manager) snapshotSoon(t snapTarget, trigger api.SnapshotTrigger, seq int64, review, force bool) { m.snapMu.Lock() defer m.snapMu.Unlock() - st := m.snapStateLocked(l.taskID) + st := m.snapStateLocked(t.taskID) if st.closed { - m.dropRequest(l.taskID, &snapRequest{review: review}) + m.dropRequest(t.taskID, &snapRequest{review: review}) return } - req := &snapRequest{trigger: trigger, seq: seq, review: review} + req := &snapRequest{trigger: trigger, seq: seq, review: review, force: force} if st.running { - m.dropRequest(l.taskID, st.pending) + if p := st.pending; p != nil && p.force { + req.force = true + req.trigger = p.trigger + } + m.dropRequest(t.taskID, st.pending) st.pending = req return } st.running = true - go m.runSnapshots(l, st, req) + go m.runSnapshots(t, st, req) } -func (m *Manager) runSnapshots(l *live, st *snapState, req *snapRequest) { +func (m *Manager) runSnapshots(t snapTarget, st *snapState, req *snapRequest) { for { st.mu.Lock() m.snapMu.Lock() closed := st.closed m.snapMu.Unlock() if !closed { - snap, err := m.takeSnapshot(context.Background(), l, req.trigger, req.seq) + snap, err := m.takeSnapshot(context.Background(), t, req.trigger, req.seq, req.force) if err != nil { - slog.Error("take snapshot", "task", l.taskID, "trigger", req.trigger, "err", err) + slog.Error("take snapshot", "task", t.taskID, "trigger", req.trigger, "err", err) } if req.review { go func() { m.afterSnapshot(snap) - m.endReviewRequest(l.taskID) + m.endReviewRequest(t.taskID) }() } } else { - m.dropRequest(l.taskID, req) + m.dropRequest(t.taskID, req) } st.mu.Unlock() @@ -82,7 +101,7 @@ func (m *Manager) runSnapshots(l *live, st *snapState, req *snapRequest) { req = st.pending st.pending = nil if req == nil || st.closed { - m.dropRequest(l.taskID, req) + m.dropRequest(t.taskID, req) st.running = false m.snapMu.Unlock() return @@ -104,34 +123,34 @@ func (m *Manager) endReviewRequest(taskID string) { } } -func (m *Manager) takeSnapshot(ctx context.Context, l *live, trigger api.SnapshotTrigger, seq int64) (*api.Snapshot, error) { +func (m *Manager) takeSnapshot(ctx context.Context, t snapTarget, trigger api.SnapshotTrigger, seq int64, force bool) (*api.Snapshot, error) { if seq == 0 { var err error - seq, err = m.store.LastTaskSeq(ctx, l.taskID) + seq, err = m.store.LastTaskSeq(ctx, t.taskID) if err != nil { return nil, err } } - tree, err := git.Snapshot(l.dir) + tree, err := git.Snapshot(t.dir) if err != nil { return nil, err } - last, err := m.store.LastSnapshot(ctx, l.taskID) + last, err := m.store.LastSnapshot(ctx, t.taskID) if err != nil && !errors.Is(err, store.ErrNotFound) { return nil, err } - if err == nil && last.TreeSha == tree { + if err == nil && last.TreeSha == tree && !force { return nil, nil } n := last.N + 1 - commit, err := git.CommitSnapshot(l.dir, tree, git.SnapshotRef(l.taskID, n), fmt.Sprintf("byre snapshot %d (%s)", n, trigger), []string{ - "GIT_AUTHOR_NAME=" + l.gitName, - "GIT_AUTHOR_EMAIL=" + l.gitEmail, - "GIT_COMMITTER_NAME=" + l.gitName, - "GIT_COMMITTER_EMAIL=" + l.gitEmail, + commit, err := git.CommitSnapshot(t.dir, tree, git.SnapshotRef(t.taskID, n), fmt.Sprintf("byre snapshot %d (%s)", n, trigger), []string{ + "GIT_AUTHOR_NAME=" + t.gitName, + "GIT_AUTHOR_EMAIL=" + t.gitEmail, + "GIT_COMMITTER_NAME=" + t.gitName, + "GIT_COMMITTER_EMAIL=" + t.gitEmail, }) if err != nil { return nil, err @@ -139,8 +158,8 @@ func (m *Manager) takeSnapshot(ctx context.Context, l *live, trigger api.Snapsho snap := api.Snapshot{ Id: store.NewID(), - TaskId: l.taskID, - AgentSessionId: l.id, + TaskId: t.taskID, + AgentSessionId: t.sessionID, N: n, CommitSha: commit, TreeSha: tree, @@ -148,13 +167,71 @@ func (m *Manager) takeSnapshot(ctx context.Context, l *live, trigger api.Snapsho Trigger: trigger, CreatedAt: time.Now().UTC(), } - err = m.store.CreateSnapshot(ctx, snap, l.projectID) + err = m.store.CreateSnapshot(ctx, snap, t.projectID) if err != nil { return nil, err } return &snap, nil } +func (m *Manager) RequestSnapshot(ctx context.Context, taskID string) error { + task, project, err := m.activeTask(ctx, taskID) + if err != nil { + return err + } + discard, err := m.store.GetDiscard(ctx, task.Id) + if err != nil { + return err + } + if discard.State != store.DiscardNone { + return fmt.Errorf("%w: task %s is being discarded", ErrConflict, task.Id) + } + mergingBy, err := m.store.MergingBy(ctx, task.Id) + if err != nil { + return err + } + if mergingBy != "" { + return fmt.Errorf("%w: task %s is merging", ErrConflict, task.Id) + } + sessions, err := m.store.ListSessions(ctx, task.Id) + if err != nil { + return err + } + if len(sessions) == 0 { + return fmt.Errorf("%w: task %s has no agent session to attribute a snapshot to", ErrConflict, task.Id) + } + sess := sessions[len(sessions)-1] + creator, err := m.store.GetUser(ctx, sess.CreatedBy) + if err != nil { + return err + } + err = m.store.BeginReviewRequest(ctx, task.Id) + if err != nil { + return err + } + t := snapTarget{taskID: task.Id, projectID: project.Id, sessionID: sess.Id, dir: task.WorktreePath, gitName: creator.GitName, gitEmail: creator.GitEmail} + m.snapshotSoon(t, api.SnapshotTriggerRequested, 0, true, true) + return nil +} + +func (m *Manager) takeSnapshotTool(l *live) mcp.Tool { + return mcp.Tool{ + Name: "take_snapshot", + Description: takeSnapshotDescription + " It snapshots your own task's worktree.", + InputSchema: json.RawMessage(`{"type": "object", "properties": {}}`), + Handler: func(ctx context.Context, args json.RawMessage) (string, error) { + err := m.RequestSnapshot(ctx, l.taskID) + if err != nil { + return "", err + } + return "Snapshot requested. A reviewer reviews it against the default branch, and any findings come to you as a message from byre.", nil + }, + } +} + +const takeSnapshotDescription = "Snapshot a task's worktree now, uncommitted work included, and start a review of it: a reviewer on the other vendor reviews all of the task's work against the default branch. " + + "byre already does this at the end of every turn that changes files; call this to review work mid-turn, or to retry a review that failed (it snapshots even when nothing changed since the last snapshot)." + func (m *Manager) dropSnapshots(repo, taskID string) error { m.snapMu.Lock() st := m.snapStateLocked(taskID) diff --git a/internal/api/api.gen.go b/internal/api/api.gen.go index 7e79615..a95c153 100644 --- a/internal/api/api.gen.go +++ b/internal/api/api.gen.go @@ -293,11 +293,12 @@ func (e ReviewState) Valid() bool { // Defines values for SnapshotTrigger. const ( - SnapshotTriggerAskHuman SnapshotTrigger = "ask_human" - SnapshotTriggerMessage SnapshotTrigger = "message" - SnapshotTriggerTimer SnapshotTrigger = "timer" - SnapshotTriggerToolCall SnapshotTrigger = "tool_call" - SnapshotTriggerTurnEnd SnapshotTrigger = "turn_end" + SnapshotTriggerAskHuman SnapshotTrigger = "ask_human" + SnapshotTriggerMessage SnapshotTrigger = "message" + SnapshotTriggerRequested SnapshotTrigger = "requested" + SnapshotTriggerTimer SnapshotTrigger = "timer" + SnapshotTriggerToolCall SnapshotTrigger = "tool_call" + SnapshotTriggerTurnEnd SnapshotTrigger = "turn_end" ) // Valid indicates whether the value is a known member of the SnapshotTrigger enum. @@ -307,6 +308,8 @@ func (e SnapshotTrigger) Valid() bool { return true case SnapshotTriggerMessage: return true + case SnapshotTriggerRequested: + return true case SnapshotTriggerTimer: return true case SnapshotTriggerToolCall: @@ -964,11 +967,11 @@ type Snapshot struct { TaskId string `json:"task_id"` TreeSha string `json:"tree_sha"` - // Trigger turn_end: after byre's end-of-turn commit. message (the agent wrote text after one or more tool calls), tool_call, ask_human and timer appear only on snapshots taken by earlier builds. + // Trigger turn_end: after byre's end-of-turn commit. requested: a task's agent or the lead asked for it with take_snapshot. message (the agent wrote text after one or more tool calls), tool_call, ask_human and timer appear only on snapshots taken by earlier builds. Trigger SnapshotTrigger `json:"trigger"` } -// SnapshotTrigger turn_end: after byre's end-of-turn commit. message (the agent wrote text after one or more tool calls), tool_call, ask_human and timer appear only on snapshots taken by earlier builds. +// SnapshotTrigger turn_end: after byre's end-of-turn commit. requested: a task's agent or the lead asked for it with take_snapshot. message (the agent wrote text after one or more tool calls), tool_call, ask_human and timer appear only on snapshots taken by earlier builds. type SnapshotTrigger string // Stage defines model for Stage. @@ -3542,157 +3545,158 @@ var swaggerSpec = []string{ "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", } // decodeSpec returns the embedded OpenAPI spec as raw JSON bytes, diff --git a/internal/store/store.go b/internal/store/store.go index 69d10a2..544898a 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -1801,6 +1801,16 @@ const taskStateExpr = `CASE ), 'no_agent') END` +func (s *Store) BeginReviewRequest(ctx context.Context, taskID string) error { + return s.write(ctx, func(tx *sql.Tx, emit emitFunc) error { + _, err := tx.ExecContext(ctx, `UPDATE tasks SET review_requests = review_requests + 1 WHERE id = ?`, taskID) + if err != nil { + return err + } + return settleTaskState(ctx, tx, emit, taskID, "byre") + }) +} + func (s *Store) EndReviewRequest(ctx context.Context, taskID string) error { return s.write(ctx, func(tx *sql.Tx, emit emitFunc) error { _, err := tx.ExecContext(ctx, `UPDATE tasks SET review_requests = max(review_requests - 1, 0) WHERE id = ?`, taskID) diff --git a/mac/Sources/Byre/Reviews.swift b/mac/Sources/Byre/Reviews.swift index db24685..6d00369 100644 --- a/mac/Sources/Byre/Reviews.swift +++ b/mac/Sources/Byre/Reviews.swift @@ -14,7 +14,7 @@ private func stateText(_ r: Review) -> String { } @MainActor -private enum StepPatches { +private enum SnapshotPatches { static var changes: [String: Task] = [:] static var patches: [String: Task] = [:] @@ -26,7 +26,7 @@ private enum StepPatches { let fetched = Task { let ck = "\(taskId)/\(n)" let pending = changes[ck] ?? Task { - try await api.client.getTaskChanges(path: .init(taskId: taskId), query: .init(snapshot: n, step: true)).ok.body.json + try await api.client.getTaskChanges(path: .init(taskId: taskId), query: .init(snapshot: n)).ok.body.json } changes[ck] = pending let c: TaskChanges @@ -338,7 +338,7 @@ private struct FindingDiff: View { } .task(id: "\(taskId)/\(n)/\(path)/\(line)/\(end)") { do { - let patch = try await StepPatches.patch(store.api, taskId, n, path) + let patch = try await SnapshotPatches.patch(store.api, taskId, n, path) let lines = patch.map { linesAround($0, line, end) } ?? [] var out: [DiffRow] = [] for (i, d) in lines.enumerated() { diff --git a/web/dist/reviews.js b/web/dist/reviews.js index c7d0949..80a70de 100644 --- a/web/dist/reviews.js +++ b/web/dist/reviews.js @@ -81,23 +81,23 @@ function reviewImages(v) { return h("figure", {}, h("a", { href: src, target: "_blank", rel: "noopener" }, h("img", { src, alt: caption || "screenshot", loading: "lazy" })), caption ? h("figcaption", {}, caption) : null); })); } -const stepChanges = new Map(); -const stepPatches = new Map(); +const snapChanges = new Map(); +const snapPatches = new Map(); function snapshotPatch(taskId, n, path) { const key = `${taskId}/${n}/${path}`; - const cached = stepPatches.get(key); + const cached = snapPatches.get(key); if (cached) { return cached; } const fetched = (async () => { const ck = `${taskId}/${n}`; - let pending = stepChanges.get(ck); + let pending = snapChanges.get(ck); if (!pending) { - pending = get("/api/tasks/{taskId}/changes", { path: { taskId }, query: { snapshot: n, step: true } }); - stepChanges.set(ck, pending); + pending = get("/api/tasks/{taskId}/changes", { path: { taskId }, query: { snapshot: n } }); + snapChanges.set(ck, pending); } const changes = await pending.catch((err) => { - stepChanges.delete(ck); + snapChanges.delete(ck); throw err; }); const f = changes.files.find((c) => c.path === path); @@ -107,8 +107,8 @@ function snapshotPatch(taskId, n, path) { const d = await get("/api/tasks/{taskId}/diff", { path: { taskId }, query: { base: changes.base, tree: changes.tree, path: f.path, old_path: f.old_path } }); return d.patch; })(); - stepPatches.set(key, fetched); - fetched.catch(() => stepPatches.delete(key)); + snapPatches.set(key, fetched); + fetched.catch(() => snapPatches.delete(key)); return fetched; } function linesAround(patch, line, end) { diff --git a/web/dist/reviews.js.map b/web/dist/reviews.js.map index 22ae3f4..9a84583 100644 --- a/web/dist/reviews.js.map +++ b/web/dist/reviews.js.map @@ -1 +1 @@ -{"version":3,"file":"reviews.js","sourceRoot":"","sources":["../src/reviews.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAgC,MAAM,UAAU,CAAC;AACxE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAKvD,MAAM,UAAU,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AAEjE,MAAM,UAAU,aAAa,CAAC,EAAa;IACzC,OAAO,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAA4B,CAAC;IACxD,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,UAAU,CAA+B,CAAC,CAAC,CAAC,EAAE,CAAC;AAC9F,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,CAAS;IACpC,OAAO,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AACtG,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,CAAS;IACzC,OAAO,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC7G,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAmB;IAC9C,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,OAA4B,CAAC,CAAC;IACtF,OAAO,GAAG,CAAC,MAAM,CAAqB,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC;AACvH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,CAAS;IACpC,OAAO,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAmC;IAChE,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/H,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;AAC1F,CAAC;AAED,SAAS,SAAS,CAAC,CAAS;IAC1B,QAAQ,CAAC,CAAC,KAAK,EAAE,CAAC;QAChB,KAAK,SAAS;YACZ,OAAO,gBAAgB,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,KAAK,IAAI,CAAC;QAClD,KAAK,MAAM;YACT,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC;QACzB,KAAK,QAAQ;YACX,OAAO,QAAQ,CAAC;QAClB,KAAK,SAAS;YACZ,OAAO,qBAAqB,CAAC;IACjC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,CAAS,EAAE,MAA0B;IAC9D,OAAO,CAAC,CACN,SAAS,EACT,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,KAAK,EAAE,EAAE,EAC9B,CAAC,CACC,QAAQ,EACR,EAAE,EACF,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,iBAAiB,EAAE,EAAE,aAAa,CAAC,CAAC,UAAU,EAAE,CAAC,EACpE,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,gBAAgB,CAAC,CAAC,KAAK,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,EAC7D,CAAC,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC,UAAU,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,EAC7E,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAC7C,EACD,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EACtE,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CACpD,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,oBAAoB,EAAE,KAAK,EAAE,mDAAmD,EAAE,EAAE,MAAM,CAAC,CAAC;IAC3I,CAAC,CAAC,OAAO,GAAG,KAAK,IAAI,EAAE;QACrB,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,8BAA8B,EAAE,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC3E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,CAAC,CAAC,QAAQ,GAAG,KAAK,CAAC;YACnB,KAAK,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;QACjC,CAAC;IACH,CAAC,CAAC;IACF,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,YAAY,CAAC,CAAS,EAAE,MAA0B;IACzD,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAA4B,CAAC;IACxD,MAAM,QAAQ,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,CAAC,CACN,KAAK,EACL,EAAE,KAAK,EAAE,eAAe,EAAE,EAC1B,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,EAAE,mBAAmB,EAAE,EAAE,CAAC,EAC/D,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAC3B,QAAQ,CAAC,MAAM,GAAG,CAAC;QACjB,CAAC,CAAC,CAAC,CACC,IAAI,EACJ,EAAE,KAAK,EAAE,UAAU,EAAE,EACrB,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACvB,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;YAC7C,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5D,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5E,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,UAAU,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAC7F,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3F,OAAO,CAAC,CACN,IAAI,EACJ,EAAE,KAAK,EAAE,WAAW,QAAQ,EAAE,EAAE,EAChC,CAAC,CACC,KAAK,EACL,EAAE,KAAK,EAAE,cAAc,EAAE,EACzB,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,YAAY,QAAQ,EAAE,EAAE,EAAE,QAAQ,CAAC,EACtD,OAAO,CAAC,CAAC,UAAU,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EACnH,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,EAC/D,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAC3D,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CACvD,EACD,MAAM,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAClF,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,mBAAmB,EAAE,EAAE,CAAC,EAC5D,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAC1B,CAAC;QACJ,CAAC,CAAC,CACH;QACH,CAAC,CAAC,IAAI,CACT,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,CAAU;IAC9B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,CAAC,CACN,KAAK,EACL,EAAE,KAAK,EAAE,eAAe,EAAE,EAC1B,GAAI,CAA+B,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QAC9C,MAAM,GAAG,GAAG,cAAc,kBAAkB,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;QAC1E,MAAM,OAAO,GAAG,OAAO,GAAG,CAAC,SAAS,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACzE,OAAO,CAAC,CACN,QAAQ,EACR,EAAE,EACF,CAAC,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,IAAI,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,EAC1H,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAC9C,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;AACJ,CAAC;AAED,MAAM,WAAW,GAAG,IAAI,GAAG,EAA2C,CAAC;AACvE,MAAM,WAAW,GAAG,IAAI,GAAG,EAAuC,CAAC;AAEnE,SAAS,aAAa,CAAC,MAAc,EAAE,CAAS,EAAE,IAAY;IAC5D,MAAM,GAAG,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;IACrC,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,MAAM,OAAO,GAAG,CAAC,KAAK,IAAI,EAAE;QAC1B,MAAM,EAAE,GAAG,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC;QAC5B,IAAI,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,GAAG,GAAG,CAAC,6BAA6B,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;YACvG,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC/B,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;YACnD,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACvB,MAAM,GAAG,CAAC;QACZ,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QACrD,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;YACnB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,CAAC,GAAG,MAAM,GAAG,CAAC,0BAA0B,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC7J,OAAO,CAAC,CAAC,KAAK,CAAC;IACjB,CAAC,CAAC,EAAE,CAAC;IACL,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7C,OAAO,OAAO,CAAC;AACjB,CAAC;AAID,SAAS,WAAW,CAAC,KAAa,EAAE,IAAY,EAAE,GAAW;IAC3D,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,MAAM,CAAC,GAAG,uCAAuC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1D,IAAI,CAAC,EAAE,CAAC;YACN,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACjB,MAAM,GAAG,IAAI,CAAC;YACd,SAAS;QACX,CAAC;QACD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,SAAS;QACX,CAAC;QACD,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACtB,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QAChD,CAAC;aAAM,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;QAC9C,CAAC;aAAM,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,SAAS,WAAW,CAAC,MAAc,EAAE,CAAS,EAAE,IAAY,EAAE,IAAY,EAAE,GAAW;IACrF,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;IAChD,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CACjC,CAAC,KAAK,EAAE,EAAE;QACR,MAAM,KAAK,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;QACvE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,GAAG,CAAC,MAAM,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QACD,MAAM,IAAI,GAAkB,EAAE,CAAC;QAC/B,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACrB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1B,IAAI,IAAI,IAAI,CAAC,CAAC,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;gBAC1E,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;YACpD,CAAC;YACD,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,EAAE,IAAI,IAAI,IAAI,CAAC,CAAC,EAAE,IAAI,GAAG,CAAC;YAC7D,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC;QAC/J,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;IACrD,CAAC,EACD,CAAC,GAAY,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,uBAAuB,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CACrG,CAAC;IACF,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,cAAc,CAAC,MAAc,EAAE,CAAS,EAAE,KAAa,EAAE,CAA0B,EAAE,KAAa;IACzG,MAAM,GAAG,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC,CAAC;IACpD,MAAM,IAAI,GAAG,CAAC,CAAe,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IAC7H,MAAM,OAAO,GAAG,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAChD,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,CAAC,OAAO,CAAC,CAAC;QACd,OAAO,GAAG,CAAC;IACb,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,CAAe,EAAE,EAAE,CAAC,GAAG,CAAC,0CAA0C,EAAE,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAC3I,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,8CAA8C,EAAE,EAAE,KAAK,CAAC,CAAC;IAChI,MAAM,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,qEAAqE,EAAE,EAAE,QAAQ,CAAC,CAAC;IAChK,GAAG,CAAC,OAAO,GAAG,KAAK,IAAI,EAAE;QACvB,MAAM,IAAI,GAAG,iDAAiD,CAAC,CAAC,UAAU,WAAW,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;QACnN,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC;QACpB,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,8BAA8B,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;YACjF,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,WAAW,CAAC,CAAC;YAC/D,IAAI,IAAI,EAAE,CAAC;gBACT,MAAM,IAAI,CAAC,oCAAoC,EAAE,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;YACrG,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,CAAC,8BAA8B,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;YAC3F,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,QAAQ,GAAG,KAAK,CAAC;YACrB,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC;YACxB,KAAK,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;YAC/B,OAAO;QACT,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,CAAC;QACd,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE,CAAC,SAAS,CAAC,+BAA+B,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1G,CAAC,CAAC;IACF,MAAM,CAAC,OAAO,GAAG,KAAK,IAAI,EAAE;QAC1B,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC;QACpB,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC;YACtB,IAAI,CAAC,SAAS,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,QAAQ,GAAG,KAAK,CAAC;YACrB,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC;YACxB,KAAK,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;QACjC,CAAC;IACH,CAAC,CAAC;IACF,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IAC1B,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAiB;IAC5C,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,CAAC;IACtD,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC;IAChD,IAAI,OAA6B,CAAC;IAClC,IAAI,KAAK,GAAG,EAAE,CAAC;IACf,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE;QACtB,MAAM,MAAM,GAAG,KAAK,CAAC,cAAc,CAAC;QACpC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,EAAE,CAAC;YACT,OAAO;QACT,CAAC;QACD,MAAM,OAAO,GAAG,EAAE,MAAM,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,6BAA6B,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;YAC7E,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;gBACvB,OAAO,GAAG,KAAK,CAAC;gBAChB,KAAK,GAAG,EAAE,CAAC;YACb,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;gBACvB,OAAO,GAAG,SAAS,CAAC;gBACpB,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QACD,IAAI,CAAC,QAAQ,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;YACpC,MAAM,EAAE,CAAC;QACX,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,MAAM,GAAG,GAAG,EAAE;QAClB,MAAM,MAAM,GAAG,KAAK,CAAC,cAAc,CAAC;QACpC,OAAO,CAAC,IAAI,CAAC,CAAC;QACd,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,mBAAmB,CAAC,CAAC,CAAC;YACjE,OAAO;QACT,CAAC;QACD,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC;YAC9D,OAAO;QACT,CAAC;QACD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC;YACxD,OAAO;QACT,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,8FAA8F,CAAC,CAAC,CAAC;YAC5I,OAAO;QACT,CAAC;QACD,MAAM,CAAC,GAAG,KAAK,CAAC,QAAQ,IAAI,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC,UAAU,CAAC;QACvD,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,CAAC;QAC1D,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACxF,MAAM,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,+BAA+B,EAAE,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9I,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,CAAC,QAAQ,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACzD,MAAM,IAAI,GAAG,CAAC,EAAU,EAAE,KAAa,EAAE,EAAE;YACzC,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YACjG,CAAC,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YACjC,OAAO,CAAC,CAAC;QACX,CAAC,CAAC;QACF,MAAM,IAAI,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5C,MAAM,IAAI,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACnC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QAC9G,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,0BAA0B,CAAC,OAAO,CAAC,CAAC,CAAC;IACtH,CAAC,CAAC;IAEF,MAAM,IAAI,GAAG;QACX,MAAM,CAAC,CAAC,WAAW,CAAC,EAAE,GAAG,EAAE;YACzB,MAAM,EAAE,CAAC;YACT,OAAO,GAAG,SAAS,CAAC;YACpB,KAAK,GAAG,EAAE,CAAC;YACX,MAAM,EAAE,CAAC;YACT,KAAK,IAAI,EAAE,CAAC;QACd,CAAC,CAAC;QACF,MAAM,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE;YAC/B,IAAK,KAAqB,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;gBAC/C,KAAK,IAAI,EAAE,CAAC;YACd,CAAC;QACH,CAAC,CAAC;QACF,MAAM,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;IAEF,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IAC/D,MAAM,EAAE,CAAC;IACT,KAAK,IAAI,EAAE,CAAC;IACZ,OAAO,GAAG,EAAE;QACV,QAAQ,GAAG,IAAI,CAAC;QAChB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,GAAG,EAAE,CAAC;QACR,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"} \ No newline at end of file +{"version":3,"file":"reviews.js","sourceRoot":"","sources":["../src/reviews.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAgC,MAAM,UAAU,CAAC;AACxE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAKvD,MAAM,UAAU,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AAEjE,MAAM,UAAU,aAAa,CAAC,EAAa;IACzC,OAAO,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAA4B,CAAC;IACxD,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,UAAU,CAA+B,CAAC,CAAC,CAAC,EAAE,CAAC;AAC9F,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,CAAS;IACpC,OAAO,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AACtG,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,CAAS;IACzC,OAAO,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC7G,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAmB;IAC9C,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,OAA4B,CAAC,CAAC;IACtF,OAAO,GAAG,CAAC,MAAM,CAAqB,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC;AACvH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,CAAS;IACpC,OAAO,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAmC;IAChE,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/H,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;AAC1F,CAAC;AAED,SAAS,SAAS,CAAC,CAAS;IAC1B,QAAQ,CAAC,CAAC,KAAK,EAAE,CAAC;QAChB,KAAK,SAAS;YACZ,OAAO,gBAAgB,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,KAAK,IAAI,CAAC;QAClD,KAAK,MAAM;YACT,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC;QACzB,KAAK,QAAQ;YACX,OAAO,QAAQ,CAAC;QAClB,KAAK,SAAS;YACZ,OAAO,qBAAqB,CAAC;IACjC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,CAAS,EAAE,MAA0B;IAC9D,OAAO,CAAC,CACN,SAAS,EACT,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,KAAK,EAAE,EAAE,EAC9B,CAAC,CACC,QAAQ,EACR,EAAE,EACF,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,iBAAiB,EAAE,EAAE,aAAa,CAAC,CAAC,UAAU,EAAE,CAAC,EACpE,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,gBAAgB,CAAC,CAAC,KAAK,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,EAC7D,CAAC,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC,UAAU,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,EAC7E,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAC7C,EACD,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EACtE,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CACpD,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,oBAAoB,EAAE,KAAK,EAAE,mDAAmD,EAAE,EAAE,MAAM,CAAC,CAAC;IAC3I,CAAC,CAAC,OAAO,GAAG,KAAK,IAAI,EAAE;QACrB,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,8BAA8B,EAAE,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC3E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,CAAC,CAAC,QAAQ,GAAG,KAAK,CAAC;YACnB,KAAK,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;QACjC,CAAC;IACH,CAAC,CAAC;IACF,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,YAAY,CAAC,CAAS,EAAE,MAA0B;IACzD,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAA4B,CAAC;IACxD,MAAM,QAAQ,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,CAAC,CACN,KAAK,EACL,EAAE,KAAK,EAAE,eAAe,EAAE,EAC1B,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,EAAE,mBAAmB,EAAE,EAAE,CAAC,EAC/D,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAC3B,QAAQ,CAAC,MAAM,GAAG,CAAC;QACjB,CAAC,CAAC,CAAC,CACC,IAAI,EACJ,EAAE,KAAK,EAAE,UAAU,EAAE,EACrB,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACvB,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;YAC7C,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5D,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5E,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,UAAU,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAC7F,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3F,OAAO,CAAC,CACN,IAAI,EACJ,EAAE,KAAK,EAAE,WAAW,QAAQ,EAAE,EAAE,EAChC,CAAC,CACC,KAAK,EACL,EAAE,KAAK,EAAE,cAAc,EAAE,EACzB,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,YAAY,QAAQ,EAAE,EAAE,EAAE,QAAQ,CAAC,EACtD,OAAO,CAAC,CAAC,UAAU,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EACnH,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,EAC/D,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAC3D,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CACvD,EACD,MAAM,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAClF,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,mBAAmB,EAAE,EAAE,CAAC,EAC5D,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAC1B,CAAC;QACJ,CAAC,CAAC,CACH;QACH,CAAC,CAAC,IAAI,CACT,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,CAAU;IAC9B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,CAAC,CACN,KAAK,EACL,EAAE,KAAK,EAAE,eAAe,EAAE,EAC1B,GAAI,CAA+B,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QAC9C,MAAM,GAAG,GAAG,cAAc,kBAAkB,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;QAC1E,MAAM,OAAO,GAAG,OAAO,GAAG,CAAC,SAAS,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACzE,OAAO,CAAC,CACN,QAAQ,EACR,EAAE,EACF,CAAC,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,IAAI,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,EAC1H,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAC9C,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;AACJ,CAAC;AAED,MAAM,WAAW,GAAG,IAAI,GAAG,EAA2C,CAAC;AACvE,MAAM,WAAW,GAAG,IAAI,GAAG,EAAuC,CAAC;AAEnE,SAAS,aAAa,CAAC,MAAc,EAAE,CAAS,EAAE,IAAY;IAC5D,MAAM,GAAG,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;IACrC,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,MAAM,OAAO,GAAG,CAAC,KAAK,IAAI,EAAE;QAC1B,MAAM,EAAE,GAAG,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC;QAC5B,IAAI,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,GAAG,GAAG,CAAC,6BAA6B,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;YAC3F,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC/B,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;YACnD,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACvB,MAAM,GAAG,CAAC;QACZ,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QACrD,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;YACnB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,CAAC,GAAG,MAAM,GAAG,CAAC,0BAA0B,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC7J,OAAO,CAAC,CAAC,KAAK,CAAC;IACjB,CAAC,CAAC,EAAE,CAAC;IACL,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7C,OAAO,OAAO,CAAC;AACjB,CAAC;AAID,SAAS,WAAW,CAAC,KAAa,EAAE,IAAY,EAAE,GAAW;IAC3D,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,MAAM,CAAC,GAAG,uCAAuC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1D,IAAI,CAAC,EAAE,CAAC;YACN,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACjB,MAAM,GAAG,IAAI,CAAC;YACd,SAAS;QACX,CAAC;QACD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,SAAS;QACX,CAAC;QACD,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACtB,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QAChD,CAAC;aAAM,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;QAC9C,CAAC;aAAM,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,SAAS,WAAW,CAAC,MAAc,EAAE,CAAS,EAAE,IAAY,EAAE,IAAY,EAAE,GAAW;IACrF,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;IAChD,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CACjC,CAAC,KAAK,EAAE,EAAE;QACR,MAAM,KAAK,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;QACvE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,GAAG,CAAC,MAAM,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QACD,MAAM,IAAI,GAAkB,EAAE,CAAC;QAC/B,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACrB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1B,IAAI,IAAI,IAAI,CAAC,CAAC,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;gBAC1E,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;YACpD,CAAC;YACD,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,EAAE,IAAI,IAAI,IAAI,CAAC,CAAC,EAAE,IAAI,GAAG,CAAC;YAC7D,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC;QAC/J,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;IACrD,CAAC,EACD,CAAC,GAAY,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,uBAAuB,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CACrG,CAAC;IACF,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,cAAc,CAAC,MAAc,EAAE,CAAS,EAAE,KAAa,EAAE,CAA0B,EAAE,KAAa;IACzG,MAAM,GAAG,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC,CAAC;IACpD,MAAM,IAAI,GAAG,CAAC,CAAe,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IAC7H,MAAM,OAAO,GAAG,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAChD,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,CAAC,OAAO,CAAC,CAAC;QACd,OAAO,GAAG,CAAC;IACb,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,CAAe,EAAE,EAAE,CAAC,GAAG,CAAC,0CAA0C,EAAE,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAC3I,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,8CAA8C,EAAE,EAAE,KAAK,CAAC,CAAC;IAChI,MAAM,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,qEAAqE,EAAE,EAAE,QAAQ,CAAC,CAAC;IAChK,GAAG,CAAC,OAAO,GAAG,KAAK,IAAI,EAAE;QACvB,MAAM,IAAI,GAAG,iDAAiD,CAAC,CAAC,UAAU,WAAW,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;QACnN,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC;QACpB,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,8BAA8B,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;YACjF,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,WAAW,CAAC,CAAC;YAC/D,IAAI,IAAI,EAAE,CAAC;gBACT,MAAM,IAAI,CAAC,oCAAoC,EAAE,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;YACrG,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,CAAC,8BAA8B,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;YAC3F,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,QAAQ,GAAG,KAAK,CAAC;YACrB,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC;YACxB,KAAK,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;YAC/B,OAAO;QACT,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,CAAC;QACd,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE,CAAC,SAAS,CAAC,+BAA+B,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1G,CAAC,CAAC;IACF,MAAM,CAAC,OAAO,GAAG,KAAK,IAAI,EAAE;QAC1B,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC;QACpB,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC;YACtB,IAAI,CAAC,SAAS,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,QAAQ,GAAG,KAAK,CAAC;YACrB,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC;YACxB,KAAK,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;QACjC,CAAC;IACH,CAAC,CAAC;IACF,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IAC1B,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAiB;IAC5C,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,CAAC;IACtD,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC;IAChD,IAAI,OAA6B,CAAC;IAClC,IAAI,KAAK,GAAG,EAAE,CAAC;IACf,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE;QACtB,MAAM,MAAM,GAAG,KAAK,CAAC,cAAc,CAAC;QACpC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,EAAE,CAAC;YACT,OAAO;QACT,CAAC;QACD,MAAM,OAAO,GAAG,EAAE,MAAM,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,6BAA6B,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;YAC7E,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;gBACvB,OAAO,GAAG,KAAK,CAAC;gBAChB,KAAK,GAAG,EAAE,CAAC;YACb,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;gBACvB,OAAO,GAAG,SAAS,CAAC;gBACpB,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QACD,IAAI,CAAC,QAAQ,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;YACpC,MAAM,EAAE,CAAC;QACX,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,MAAM,GAAG,GAAG,EAAE;QAClB,MAAM,MAAM,GAAG,KAAK,CAAC,cAAc,CAAC;QACpC,OAAO,CAAC,IAAI,CAAC,CAAC;QACd,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,mBAAmB,CAAC,CAAC,CAAC;YACjE,OAAO;QACT,CAAC;QACD,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC;YAC9D,OAAO;QACT,CAAC;QACD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC;YACxD,OAAO;QACT,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,8FAA8F,CAAC,CAAC,CAAC;YAC5I,OAAO;QACT,CAAC;QACD,MAAM,CAAC,GAAG,KAAK,CAAC,QAAQ,IAAI,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC,UAAU,CAAC;QACvD,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,CAAC;QAC1D,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACxF,MAAM,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,+BAA+B,EAAE,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9I,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,CAAC,QAAQ,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACzD,MAAM,IAAI,GAAG,CAAC,EAAU,EAAE,KAAa,EAAE,EAAE;YACzC,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YACjG,CAAC,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YACjC,OAAO,CAAC,CAAC;QACX,CAAC,CAAC;QACF,MAAM,IAAI,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5C,MAAM,IAAI,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACnC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QAC9G,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,0BAA0B,CAAC,OAAO,CAAC,CAAC,CAAC;IACtH,CAAC,CAAC;IAEF,MAAM,IAAI,GAAG;QACX,MAAM,CAAC,CAAC,WAAW,CAAC,EAAE,GAAG,EAAE;YACzB,MAAM,EAAE,CAAC;YACT,OAAO,GAAG,SAAS,CAAC;YACpB,KAAK,GAAG,EAAE,CAAC;YACX,MAAM,EAAE,CAAC;YACT,KAAK,IAAI,EAAE,CAAC;QACd,CAAC,CAAC;QACF,MAAM,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE;YAC/B,IAAK,KAAqB,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;gBAC/C,KAAK,IAAI,EAAE,CAAC;YACd,CAAC;QACH,CAAC,CAAC;QACF,MAAM,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;IAEF,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IAC/D,MAAM,EAAE,CAAC;IACT,KAAK,IAAI,EAAE,CAAC;IACZ,OAAO,GAAG,EAAE;QACV,QAAQ,GAAG,IAAI,CAAC;QAChB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,GAAG,EAAE,CAAC;QACR,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"} \ No newline at end of file diff --git a/web/src/api.gen.ts b/web/src/api.gen.ts index ea5ff65..c974cd6 100644 --- a/web/src/api.gen.ts +++ b/web/src/api.gen.ts @@ -1249,10 +1249,10 @@ export interface components { */ event_seq: number; /** - * @description turn_end: after byre's end-of-turn commit. message (the agent wrote text after one or more tool calls), tool_call, ask_human and timer appear only on snapshots taken by earlier builds. + * @description turn_end: after byre's end-of-turn commit. requested: a task's agent or the lead asked for it with take_snapshot. message (the agent wrote text after one or more tool calls), tool_call, ask_human and timer appear only on snapshots taken by earlier builds. * @enum {string} */ - trigger: "message" | "turn_end" | "tool_call" | "ask_human" | "timer"; + trigger: "message" | "turn_end" | "tool_call" | "ask_human" | "timer" | "requested"; /** Format: date-time */ created_at: string; }; diff --git a/web/src/reviews.ts b/web/src/reviews.ts index ab4fdbe..f48a74e 100644 --- a/web/src/reviews.ts +++ b/web/src/reviews.ts @@ -144,24 +144,24 @@ function reviewImages(v: unknown): HTMLElement | null { ); } -const stepChanges = new Map>(); -const stepPatches = new Map>(); +const snapChanges = new Map>(); +const snapPatches = new Map>(); function snapshotPatch(taskId: string, n: number, path: string): Promise { const key = `${taskId}/${n}/${path}`; - const cached = stepPatches.get(key); + const cached = snapPatches.get(key); if (cached) { return cached; } const fetched = (async () => { const ck = `${taskId}/${n}`; - let pending = stepChanges.get(ck); + let pending = snapChanges.get(ck); if (!pending) { - pending = get("/api/tasks/{taskId}/changes", { path: { taskId }, query: { snapshot: n, step: true } }); - stepChanges.set(ck, pending); + pending = get("/api/tasks/{taskId}/changes", { path: { taskId }, query: { snapshot: n } }); + snapChanges.set(ck, pending); } const changes = await pending.catch((err: unknown) => { - stepChanges.delete(ck); + snapChanges.delete(ck); throw err; }); const f = changes.files.find((c) => c.path === path); @@ -171,8 +171,8 @@ function snapshotPatch(taskId: string, n: number, path: string): Promise stepPatches.delete(key)); + snapPatches.set(key, fetched); + fetched.catch(() => snapPatches.delete(key)); return fetched; }