@agimon-ai/po-runner 0.0.0-alpha.34 → 0.0.0-alpha.35

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.
@@ -1,12 +1,14 @@
1
1
  import { createApiClient, defineActivityGroup, defineChannelFile, defineFill, defineNativePlugin, defineSessionStore, nativeApiTransport, sessionApiAddress } from "@agimon-ai/po-core/native";
2
2
  import { ArrowRightIcon, Button, Dot, FolderIcon, Input, ListRow, PlayCircleIcon, SearchIcon, Sheet, SheetBody, SheetContent, SheetFooter, SheetHeader, SheetTitle, StatusBadge, fontOf } from "@agimon-ai/po-native-components";
3
- import { createElement, useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
3
+ import { createElement, memo, useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
4
4
  import { View } from "react-native-unistyles/components/native/View";
5
5
  import { Text } from "react-native-unistyles/components/native/Text";
6
6
  import { ScrollView } from "react-native-unistyles/components/native/ScrollView";
7
7
  import { Pressable } from "react-native-unistyles/components/native/Pressable";
8
8
  import { StyleSheet } from "react-native-unistyles";
9
9
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
+ import { AppState } from "react-native";
11
+ import { FlatList } from "react-native-unistyles/components/native/FlatList";
10
12
  //#region src/extensions/workspaces/sessions/(frontend)/_lib/format.ts
11
13
  /**
12
14
  * Local copy of the runtime's formatUptime (src/services/bashResult/index.ts):
@@ -168,11 +170,32 @@ function isRunnerActivityVisible(run, now = Date.now()) {
168
170
  /** The runner channel keeps the dock's busy state aligned with its rendered run list. */
169
171
  const runnerActivitySource = {
170
172
  subscribe(listener) {
171
- const subscription = runners.store.subscribe(listener);
172
- const timer = setInterval(listener, 1e3);
173
+ let timer;
174
+ const schedule = () => {
175
+ clearTimeout(timer);
176
+ const now = Date.now();
177
+ let deadline = Infinity;
178
+ for (const session of Object.values(runners.store.state)) {
179
+ if (!session) continue;
180
+ for (const run of session.runs) {
181
+ if (run.state !== "running") continue;
182
+ const revealAt = Date.parse(run.startedAt) + 3001;
183
+ if (revealAt > now) deadline = Math.min(deadline, revealAt);
184
+ }
185
+ }
186
+ if (Number.isFinite(deadline)) timer = setTimeout(() => {
187
+ listener();
188
+ schedule();
189
+ }, Math.min(deadline - now, 2147483647));
190
+ };
191
+ const subscription = runners.store.subscribe(() => {
192
+ listener();
193
+ schedule();
194
+ });
195
+ schedule();
173
196
  return () => {
174
197
  subscription.unsubscribe();
175
- clearInterval(timer);
198
+ clearTimeout(timer);
176
199
  };
177
200
  },
178
201
  isActive(sessionId) {
@@ -484,11 +507,40 @@ function useRunners(sessionId) {
484
507
  }, []);
485
508
  return useSyncExternalStore(subscribe, () => runners.select(runners.store.state, sessionId));
486
509
  }
510
+ /** Pause finite reads and clocks while native is not active; entering active refreshes immediately. */
511
+ function useRunnerForeground() {
512
+ const subscribe = useCallback((listener) => {
513
+ const subscription = AppState.addEventListener("change", listener);
514
+ return () => subscription.remove();
515
+ }, []);
516
+ return useSyncExternalStore(subscribe, () => AppState.currentState === "active");
517
+ }
518
+ function useRunnerClock(active, interval) {
519
+ const [now, setNow] = useState(() => Date.now());
520
+ useEffect(() => {
521
+ if (!active) return;
522
+ let timer;
523
+ const update = () => {
524
+ clearInterval(timer);
525
+ if (AppState.currentState !== "active") return;
526
+ setNow(Date.now());
527
+ timer = setInterval(() => setNow(Date.now()), interval);
528
+ };
529
+ const subscription = AppState.addEventListener("change", update);
530
+ update();
531
+ return () => {
532
+ clearInterval(timer);
533
+ subscription.remove();
534
+ };
535
+ }, [active, interval]);
536
+ return now;
537
+ }
487
538
  /** Native uses finite reads instead of browser SSE. Read a bounded tail through the host's sealed transport. */
488
539
  function useRunnerTail(sessionId, runId, running) {
540
+ const foreground = useRunnerForeground();
489
541
  const [tail, setTail] = useState();
490
542
  useEffect(() => {
491
- if (sessionId === null || !running) return;
543
+ if (sessionId === null || !running || !foreground) return;
492
544
  const controller = new AbortController();
493
545
  let timer;
494
546
  const read = async () => {
@@ -514,7 +566,8 @@ function useRunnerTail(sessionId, runId, running) {
514
566
  }, [
515
567
  sessionId,
516
568
  runId,
517
- running
569
+ running,
570
+ foreground
518
571
  ]);
519
572
  return running && tail?.id === `${sessionId}:${runId}` ? tail.text : void 0;
520
573
  }
@@ -577,6 +630,7 @@ function runnerLogTab(run) {
577
630
  }
578
631
  function RunnerLogPanel({ sessionId, runId, sendSessionFrame }) {
579
632
  const session = useRunners(sessionId);
633
+ const foreground = useRunnerForeground();
580
634
  const run = session.runs.find((candidate) => candidate.id === runId);
581
635
  const [typed, setTyped] = useState("");
582
636
  const [query, setQuery] = useState("");
@@ -592,7 +646,7 @@ function RunnerLogPanel({ sessionId, runId, sendSessionFrame }) {
592
646
  return () => clearTimeout(timer);
593
647
  }, [typed]);
594
648
  useEffect(() => {
595
- if (sessionId === null) return;
649
+ if (sessionId === null || !foreground) return;
596
650
  const controller = new AbortController();
597
651
  let timer;
598
652
  const read = async () => {
@@ -603,13 +657,21 @@ function RunnerLogPanel({ sessionId, runId, sendSessionFrame }) {
603
657
  contextLines: context
604
658
  }, controller.signal);
605
659
  if (controller.signal.aborted) return;
606
- setLoaded("error" in result ? {
607
- key: requestKey,
608
- error: result.error
609
- } : {
610
- key: requestKey,
611
- slice: result.slice,
612
- error: ""
660
+ setLoaded((previous) => {
661
+ const next = "error" in result ? {
662
+ key: requestKey,
663
+ error: result.error
664
+ } : {
665
+ key: requestKey,
666
+ slice: result.slice,
667
+ error: ""
668
+ };
669
+ if (previous?.key !== next.key || previous.error !== next.error) return next;
670
+ const before = previous.slice;
671
+ const after = next.slice;
672
+ if (before === after) return previous;
673
+ if (!before || !after) return next;
674
+ return before.text === after.text && before.totalLines === after.totalLines && before.lineCount === after.lineCount && before.fileSize === after.fileSize && before.completeBytes === after.completeBytes && before.path === after.path && before.exists === after.exists && before.truncated === after.truncated && before.runId === after.runId && before.running === after.running && before.lineNumbers?.length === after.lineNumbers?.length && (before.lineNumbers?.every((number, index) => number === after.lineNumbers?.[index]) ?? true) ? previous : next;
613
675
  });
614
676
  if (following && query === "" && ("error" in result || result.slice.running)) timer = setTimeout(() => void read(), 2e3);
615
677
  };
@@ -625,11 +687,9 @@ function RunnerLogPanel({ sessionId, runId, sendSessionFrame }) {
625
687
  ignoreCase,
626
688
  context,
627
689
  following,
628
- requestKey
690
+ requestKey,
691
+ foreground
629
692
  ]);
630
- const lines = logViewLines(slice?.text ?? "", [], 2e3).lines;
631
- const numbers = query === "" ? tailLineNumbers(slice?.totalLines ?? 0, lines.length) : slice?.lineNumbers ?? [];
632
- const gutter = String(numbers.at(-1) ?? 0).length;
633
693
  const stopping = session.stopRequested.includes(runId);
634
694
  const live = following && query === "" && slice?.running === true;
635
695
  return /* @__PURE__ */ jsxs(View, {
@@ -682,31 +742,11 @@ function RunnerLogPanel({ sessionId, runId, sendSessionFrame }) {
682
742
  }) : null
683
743
  ]
684
744
  }),
685
- /* @__PURE__ */ jsx(Text, {
686
- style: styles$2.meta,
687
- children: slice === void 0 ? error === "" ? "Reading…" : "" : query !== "" ? `${slice.lineCount} matching of ${slice.totalLines} lines` : `${live ? "Tailing" : "Showing"} last ${lines.length} of ${slice.totalLines} lines`
688
- }),
689
- /* @__PURE__ */ jsx(ScrollView, {
690
- style: styles$2.log,
691
- contentContainerStyle: styles$2.logBody,
692
- children: error !== "" ? /* @__PURE__ */ jsx(Text, {
693
- accessibilityRole: "alert",
694
- style: styles$2.error,
695
- children: error
696
- }) : slice?.exists === false ? /* @__PURE__ */ jsx(Text, {
697
- style: styles$2.meta,
698
- children: "This runner has not written a log yet."
699
- }) : slice && lines.length === 0 ? /* @__PURE__ */ jsx(Text, {
700
- style: styles$2.meta,
701
- children: query === "" ? "The log is empty." : "Nothing matched."
702
- }) : lines.map((line, index) => /* @__PURE__ */ jsxs(Text, {
703
- selectable: true,
704
- style: styles$2.line,
705
- children: [/* @__PURE__ */ jsx(Text, {
706
- style: styles$2.number,
707
- children: `${String(numbers[index] ?? "").padStart(gutter)} `
708
- }), line]
709
- }, `${numbers[index] ?? index}`))
745
+ /* @__PURE__ */ jsx(RunnerLogOutput, {
746
+ slice,
747
+ error,
748
+ query,
749
+ live
710
750
  }),
711
751
  /* @__PURE__ */ jsx(Text, {
712
752
  selectable: true,
@@ -718,6 +758,58 @@ function RunnerLogPanel({ sessionId, runId, sendSessionFrame }) {
718
758
  ]
719
759
  });
720
760
  }
761
+ const RunnerLogOutput = memo(function RunnerLogOutput({ slice, error, query, live }) {
762
+ const lines = useMemo(() => logViewLines(slice?.text ?? "", [], 2e3).lines, [slice?.text]);
763
+ const rows = useMemo(() => {
764
+ const numbers = query === "" ? tailLineNumbers(slice?.totalLines ?? 0, lines.length) : slice?.lineNumbers ?? [];
765
+ const gutter = String(numbers.at(-1) ?? 0).length;
766
+ return lines.map((text, index) => ({
767
+ key: String(numbers[index] ?? index),
768
+ number: `${String(numbers[index] ?? "").padStart(gutter)} `,
769
+ text
770
+ }));
771
+ }, [
772
+ lines,
773
+ query,
774
+ slice?.totalLines,
775
+ slice?.lineNumbers
776
+ ]);
777
+ const renderItem = useCallback(({ item }) => /* @__PURE__ */ jsxs(Text, {
778
+ selectable: true,
779
+ style: styles$2.line,
780
+ children: [/* @__PURE__ */ jsx(Text, {
781
+ style: styles$2.number,
782
+ children: item.number
783
+ }), item.text]
784
+ }), []);
785
+ const keyExtractor = useCallback((item) => item.key, []);
786
+ const empty = error !== "" ? /* @__PURE__ */ jsx(Text, {
787
+ accessibilityRole: "alert",
788
+ style: styles$2.error,
789
+ children: error
790
+ }) : slice?.exists === false ? /* @__PURE__ */ jsx(Text, {
791
+ style: styles$2.meta,
792
+ children: "This runner has not written a log yet."
793
+ }) : slice ? /* @__PURE__ */ jsx(Text, {
794
+ style: styles$2.meta,
795
+ children: query === "" ? "The log is empty." : "Nothing matched."
796
+ }) : null;
797
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Text, {
798
+ style: styles$2.meta,
799
+ children: slice === void 0 ? error === "" ? "Reading…" : "" : query !== "" ? `${slice.lineCount} matching of ${slice.totalLines} lines` : `${live ? "Tailing" : "Showing"} last ${lines.length} of ${slice.totalLines} lines`
800
+ }), /* @__PURE__ */ jsx(FlatList, {
801
+ style: styles$2.log,
802
+ contentContainerStyle: styles$2.logBody,
803
+ data: error !== "" || slice?.exists === false ? [] : rows,
804
+ renderItem,
805
+ keyExtractor,
806
+ ListEmptyComponent: empty,
807
+ initialNumToRender: 20,
808
+ maxToRenderPerBatch: 20,
809
+ windowSize: 5,
810
+ accessibilityLabel: "Runner log output"
811
+ })] });
812
+ });
721
813
  const styles$2 = StyleSheet.create((theme) => ({
722
814
  panel: {
723
815
  flex: 1,
@@ -984,12 +1076,9 @@ function RunnerRow({ run, props, stopping, now }) {
984
1076
  }
985
1077
  function RunnersActivitySection(props) {
986
1078
  const session = useRunners(props.sessionId);
1079
+ const active = useSyncExternalStore(runnerActivitySource.subscribe, () => runnerActivitySource.isActive(props.sessionId));
987
1080
  const running = session.runs.filter((run) => isRunnerActivityVisible(run));
988
- const [now, setNow] = useState(() => Date.now());
989
- useEffect(() => {
990
- const timer = setInterval(() => setNow(Date.now()), 1e3);
991
- return () => clearInterval(timer);
992
- }, []);
1081
+ const now = useRunnerClock(active, 1e3);
993
1082
  return running.length === 0 ? /* @__PURE__ */ jsxs(View, {
994
1083
  style: styles.idle,
995
1084
  children: [/* @__PURE__ */ jsx(Text, {
@@ -1028,15 +1117,11 @@ function RunnersPanel(props) {
1028
1117
  const running = session.runs.filter((run) => run.state === "running");
1029
1118
  const [command, setCommand] = useState("");
1030
1119
  const [cwd, setCwd] = useState("");
1031
- const [now, setNow] = useState(() => Date.now());
1120
+ const now = useRunnerClock(running.length > 0, 1e4);
1032
1121
  const baseline = useRef(null);
1033
1122
  /** What the pending launch ran, put back if the start fails. */
1034
1123
  const launched = useRef("");
1035
1124
  const timeout = useRef(void 0);
1036
- useEffect(() => {
1037
- const timer = setInterval(() => setNow(Date.now()), 1e4);
1038
- return () => clearInterval(timer);
1039
- }, []);
1040
1125
  useEffect(() => {
1041
1126
  if (baseline.current === null) return;
1042
1127
  const started = session.runs.find((run) => run.state === "running" && !baseline.current?.has(run.id));
@@ -1 +1 @@
1
- {"version":3,"file":"native.mjs","names":["isRecord","Button","FolderIcon","fontOf","Input","ListRow","Sheet","SheetBody","SheetContent","SheetFooter","SheetHeader","SheetTitle","PoNativeTheme","useState","StyleSheet","RunnerCommandBarProps","plainPunctuation","runnerFolderLabel","runnerFolders","RunnerCommandBar","command","onCommandChange","cwd","onCwdChange","sessionDirectory","folders","problem","onLaunch","defaultFolderOpen","folderOpen","setFolderOpen","path","setPath","pick","next","choices","styles","bar","line","grow","text","trim","undefined","meta","map","folder","create","theme","gap","spacing","uni__dependencies","flexDirection","alignItems","flex","color","colors","dim","fontFamily","sans","fontSize","sm","lineHeight","red","styles","WebPluginSlotProps","fontOf","Button","Input","StatusBadge","PoNativeTheme","ReactNode","useEffect","useState","StyleSheet","RunnerLogResponse","RunnerRunView","logViewLines","runnerBadge","runnerFolderLabel","tailLineNumbers","fetchRunnerLog","requestRunnerStop","useRunners","RunnerRunHeader","run","name","sessionDirectory","action","badge","commandOpen","setCommandOpen","styles","header","title","tone","label","grow","expanded","commandBox","open","undefined","command","prompt","folder","cwd","meta","runnerLogTab","id","panel","props","RunnerLogPanel","sessionId","runId","sendSessionFrame","session","runs","find","candidate","typed","setTyped","query","setQuery","ignoreCase","setIgnoreCase","context","setContext","following","setFollowing","requestKey","loaded","setLoaded","key","slice","error","timer","setTimeout","clearTimeout","controller","AbortController","ReturnType","read","result","lines","grep","contextLines","signal","aborted","running","abort","text","numbers","totalLines","length","lineNumbers","gutter","String","at","stopping","stopRequested","includes","live","state","actions","selected","value","lineCount","log","logBody","exists","map","line","index","number","padStart","path","logPath","create","theme","flex","gap","spacing","padding","backgroundColor","colors","bg","uni__dependencies","flexDirection","alignItems","minHeight","flexShrink","color","hi","fontWeight","fontFamily","sans","fontSize","base","paddingHorizontal","paddingVertical","borderRadius","md","deep","mono","sm","faint","dim","xs","lineHeight","red","flexWrap","styles","WebPluginSlotProps","fontOf","Button","SearchIcon","PoNativeTheme","useMemo","StyleSheet","RunnerRunView","requestRunnerStop","readRunnerScreen","sendRunnerInput","useRunners","RunnerRunHeader","runnerLogTab","runnerShellTab","run","id","label","name","panel","props","RunnerShellPanel","sessionId","runId","renderRunnerTerminal","sendSessionFrame","openTransientTab","session","runs","find","candidate","live","state","stopping","stopRequested","includes","request","undefined","key","read","from","generation","signal","AbortSignal","write","text","styles","sessionDirectory","terminal","meta","actions","action","create","theme","flex","gap","spacing","padding","backgroundColor","colors","bg","uni__dependencies","flexDirection","color","dim","fontFamily","sans","fontSize","sm","styles","WebPluginSlotProps","ArrowRightIcon","fontOf","Button","Dot","ListRow","PoNativeTheme","useEffect","useRef","useState","StyleSheet","RunnerRunView","formatRunnerUptime","runnerRunRequest","isRunnerActivityVisible","requestRunnerStart","requestRunnerStop","RunnerCommandBar","useRunners","useRunnerTail","runnerLogTab","runnerShellTab","runnerTab","run","interactive","runnersTab","id","label","panel","RunnersPanel","RunnerRow","props","stopping","now","tail","sessionId","state","name","openTransientTab","pressed","styles","row","line","meta","startedAt","sendSessionFrame","command","RunnersActivitySection","session","running","runs","filter","setNow","Date","timer","setInterval","clearInterval","length","idle","launch","launchText","map","stopRequested","includes","setCommand","cwd","setCwd","baseline","ReadonlySet","launched","timeout","ReturnType","setTimeout","undefined","current","started","find","has","clearTimeout","failureId","startFailure","Set","header","title","sessionDirectory","problem","message","create","theme","flex","gap","spacing","padding","backgroundColor","colors","bg","uni__dependencies","flexDirection","alignItems","paddingVertical","opacity","color","hi","fontFamily","sans","fontSize","base","lineHeight","fontWeight","medium","paddingLeft","dim","mono","sm","lg","flexWrap","green","activityGroupRunners","channelRunnerRuns","fillRunners"],"sources":["../../src/extensions/workspaces/sessions/(frontend)/_lib/format.ts","../../src/extensions/workspaces/sessions/(frontend)/_lib/launchLine.ts","../../src/constants/webRunners.ts","../../src/extensions/workspaces/sessions/(frontend)/_lib/runnersStore.native.ts","../../src/extensions/workspaces/sessions/(frontend)/_components/RunnerCommandBar.native.tsx","../../src/constants/webRunnerLog.ts","../../src/types/webRunnerLog.ts","../../src/types/apiRoutes.ts","../../generated/client.native.ts","../../src/extensions/workspaces/sessions/(frontend)/_lib/logApi.native.ts","../../src/extensions/workspaces/sessions/(frontend)/_components/runnerHooks.native.ts","../../src/extensions/workspaces/sessions/(frontend)/_components/RunnerLogPanel.native.tsx","../../src/extensions/workspaces/sessions/(frontend)/_lib/screenApi.native.ts","../../src/extensions/workspaces/sessions/(frontend)/_components/RunnerShellPanel.native.tsx","../../src/extensions/workspaces/sessions/(frontend)/_components/RunnersPanel.native.tsx","../../src/extensions/workspaces/sessions/(frontend)/activity-group/runners.native.ts","../../src/extensions/workspaces/sessions/(frontend)/channel/runner-runs.native.ts","../../src/extensions/workspaces/sessions/(frontend)/fill/Runners.activity.runners.native.tsx","../../generated/native.ts"],"sourcesContent":["import type { RunnerRunView } from '../../../../../types/webRunners';\n\n/**\n * Local copy of the runtime's formatUptime (src/services/bashResult/index.ts):\n * the web plugin may reach only src/types, so the one helper it needs lives here.\n */\nexport function formatRunnerUptime(startedAt: string, now: number): string {\n const started = Date.parse(startedAt);\n if (Number.isNaN(started)) return 'unknown';\n const seconds = Math.max(0, Math.floor((now - started) / 1000));\n if (seconds < 60) return `${seconds}s`;\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes}m`;\n const hours = Math.floor(minutes / 60);\n return hours < 24 ? `${hours}h` : `${Math.floor(hours / 24)}d`;\n}\n\n/** A bounded log view: what to render, and what the bound left out. */\nexport interface LogView {\n lines: string[];\n /** Lines dropped off the top to stay within the bound. */\n hidden: number;\n}\n\nexport interface LogViewOptions {\n /**\n * Drop the slice's last line because it is a fragment the follow stream will\n * deliver again, whole. Set only while following: a finished run's last line\n * may legitimately lack a newline, and dropping it would hide real output.\n */\n dropPartialTail?: boolean;\n}\n\n/**\n * The lines a log view shows: the slice's text, then whatever the follow\n * stream appended, bounded to the newest `max`.\n *\n * A log file ends with a newline, and the reader hands its text back with that\n * newline intact, so a naive split reports one blank line more than the file\n * has. Dropping exactly one trailing empty entry keeps the count the reader\n * sees equal to the count the server reported.\n */\nexport function logViewLines(\n text: string,\n appended: readonly string[],\n max: number,\n options: LogViewOptions = {},\n): LogView {\n const split = text.split('\\n');\n if (split.length > 0 && split[split.length - 1] === '') split.pop();\n if (options.dropPartialTail === true && split.length > 0) split.pop();\n const all = [...split, ...appended];\n const lines = all.slice(-max);\n return { lines, hidden: all.length - lines.length };\n}\n\n/**\n * Absolute 1-based numbers for a tail, counted back from the last line.\n *\n * A tail is contiguous, so only its end has to be known. Grep results are not\n * contiguous and carry their own numbers from the reader instead.\n */\nexport function tailLineNumbers(lastLineNumber: number, count: number): number[] {\n const first = Math.max(1, lastLineNumber - count + 1);\n return Array.from({ length: count }, (_, index) => first + index);\n}\n\n/**\n * Whether the view is actually following a growing log.\n *\n * Three things must hold: the reader asked to follow, no query is set (a\n * filtered view is a snapshot of the whole file, which a stream cannot\n * assemble a chunk at a time), and the runner is still writing. Without the\n * last one a finished run would claim to be tailing a file nothing will ever\n * append to.\n */\nexport function isFollowingLive(following: boolean, filtering: boolean, running: boolean): boolean {\n return following && !filtering && running;\n}\n\n/**\n * A folder as the command bar names it: the session directory by its last\n * segment, a folder inside it relative to it, anything else as written.\n */\nexport function runnerFolderLabel(folder: string, sessionDirectory: string | undefined): string {\n if (folder === '' || folder === sessionDirectory) {\n return sessionDirectory === undefined\n ? 'session directory'\n : (sessionDirectory.split('/').pop() ?? sessionDirectory);\n }\n if (sessionDirectory !== undefined && folder.startsWith(`${sessionDirectory}/`)) {\n return folder.slice(sessionDirectory.length + 1);\n }\n return folder;\n}\n\n/** The folders the picker offers past the session directory: those in use, then the one in effect. */\nexport function runnerFolders(\n inUse: readonly string[],\n current: string,\n sessionDirectory: string | undefined,\n): string[] {\n const folders = new Set([...inUse, current]);\n folders.delete('');\n if (sessionDirectory !== undefined) folders.delete(sessionDirectory);\n return [...folders];\n}\n\n/**\n * Undoes iOS smart punctuation, which React Native cannot switch off: a shell\n * reads ‘hi’ as literal quotes and a long dash before port as no flag at all.\n */\nexport function plainPunctuation(text: string): string {\n return text\n .replace(/[‘’]/g, \"'\")\n .replace(/[“”]/g, '\"')\n .replace(/\\u2014/g, '--');\n}\n\n/** The badge a run wears: its state while running, then how it ended. */\nexport function runnerBadge(run: RunnerRunView | undefined): {\n tone: 'neutral' | 'running' | 'ok' | 'error';\n label: string;\n} {\n if (run === undefined) return { tone: 'neutral', label: 'gone' };\n if (run.state === 'running') return { tone: 'running', label: 'running' };\n if (run.exit === undefined || run.exit.reason === 'stopped') return { tone: 'neutral', label: 'stopped' };\n const clean = run.exit.reason === 'completed' && (run.exit.code === 0 || run.exit.code === null);\n return clean ? { tone: 'ok', label: 'done' } : { tone: 'error', label: run.exit.reason.replace('_', ' ') };\n}\n","/**\n * The `/runners start` line the runners panel's command bar sends.\n *\n * WHY THE BUILDER LIVES HERE AND THE PARSER DOES NOT:\n * Cockpit code is compiled into the host bundle and may import only this\n * package's own web and type modules, so it cannot share the session's parser\n * in src/services. The two are pinned together by a test that parses what this\n * writes, which is the only guarantee that matters: the line has to survive\n * the trip.\n */\n\nexport const RUNNERS_START_LINE = '/runners start';\n/** A persistent login shell for the direct shell action in Runner Space. */\nexport const RUNNER_SHELL_COMMAND = 'exec \"${SHELL:-/bin/bash}\" -l';\n/** Ends the options and begins the command; the command may hold `=` and flags of its own. */\nexport const RUNNERS_COMMAND_SEPARATOR = '--';\n\nexport interface RunnerLaunchRequest {\n command: string;\n cwd?: string;\n name?: string;\n interactive?: boolean;\n /** A terminal when rmux or tmux is available, plain output otherwise. */\n preferInteractive?: boolean;\n}\n\n/** The no-form launch used when a reader asks for a shell rather than a command. */\nexport const RUNNER_SHELL_REQUEST: RunnerLaunchRequest = {\n command: RUNNER_SHELL_COMMAND,\n name: 'shell',\n interactive: true,\n};\n\n/**\n * What the runners panel's Run sends: the typed command on a terminal when\n * one is available, or a login shell when nothing was typed.\n */\nexport function runnerRunRequest(command: string, cwd: string): RunnerLaunchRequest {\n const where = cwd.trim() === '' ? {} : { cwd };\n return command.trim() === '' ? { ...RUNNER_SHELL_REQUEST, ...where } : { command, ...where, preferInteractive: true };\n}\n\n/** Quotes a value that carries whitespace, which is how a value survives tokenizing. */\nfunction quote(value: string): string {\n return /\\s/u.test(value) ? `\"${value}\"` : value;\n}\n\nexport function runnerLaunchLine(request: RunnerLaunchRequest): string {\n const cwd = request.cwd?.trim() ?? '';\n const name = request.name?.trim() ?? '';\n const pairs = [\n ...(name === '' ? [] : [`name=${quote(name)}`]),\n ...(cwd === '' ? [] : [`cwd=${quote(cwd)}`]),\n ...(request.interactive === true\n ? ['interactive=true']\n : request.preferInteractive === true\n ? ['interactive=prefer']\n : []),\n ];\n // The separator is always written, even with no options before it, so the\n // command is never re-read as a `key=value` pair.\n return [RUNNERS_START_LINE, ...pairs, RUNNERS_COMMAND_SEPARATOR, request.command.trim()].join(' ');\n}\n","export const RUNNER_RUNS_TYPE = 'runner_runs';\n","import { defineSessionStore, type SessionFrameSender } from '@agimon-ai/po-core/native';\n\nimport { RUNNER_RUNS_TYPE } from '../../../../../constants/webRunners';\nimport { type RunnerRunView, type RunnerStartFailureView } from '../../../../../types/webRunners';\nimport { type RunnerLaunchRequest, runnerLaunchLine } from './launchLine';\n\n/** The runtime's slash verb that stops one runner headlessly. */\nconst STOP_COMMAND = '/runners stop';\n\n/** One session's record: the hub's last report plus what this page asked for. */\nexport interface RunnersSession extends RunnerRunsPayload {\n /** Runners a stop was asked for and that have not yet reported an exit. */\n stopRequested: string[];\n}\n\nexport const runners = defineSessionStore<RunnersSession>({ runs: [], stopRequested: [] });\n\n/** Short commands stay out of the activity card, but remain in the runner feed. */\nexport function isRunnerActivityVisible(run: RunnerRunView, now = Date.now()): boolean {\n return run.state === 'running' && now - Date.parse(run.startedAt) > 3_000;\n}\n\n/** The runner channel keeps the dock's busy state aligned with its rendered run list. */\nexport const runnerActivitySource = {\n subscribe(listener: () => void) {\n const subscription = runners.store.subscribe(listener);\n const timer = setInterval(listener, 1_000);\n return () => {\n subscription.unsubscribe();\n clearInterval(timer);\n };\n },\n isActive(sessionId: string | null) {\n return runners.select(runners.store.state, sessionId).runs.some((run) => isRunnerActivityVisible(run));\n },\n};\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Asks the runtime to stop a runner through the same slash command the TUI's\n * Runner Space uses. The request is remembered until the runner's record\n * reports an exit; the runtime, not this click, decides when that is.\n */\nexport function requestRunnerStop(send: SessionFrameSender, sessionId: string, id: string): void {\n send(sessionId, { type: 'prompt', message: `${STOP_COMMAND} ${id}` });\n runners.update(sessionId, (current) => ({\n ...current,\n stopRequested: [...current.stopRequested.filter((known) => known !== id), id],\n }));\n}\n\n/**\n * Asks the runtime to start a runner, through the same prompt frame the stop\n * request uses and the same way agents and workflows launch their own work.\n *\n * Nothing is recorded as pending here. The runtime names the run, and it\n * arrives in the feed on its own; guessing at an id before it exists would\n * only have to be reconciled later.\n */\nexport function requestRunnerStart(send: SessionFrameSender, sessionId: string, request: RunnerLaunchRequest): void {\n send(sessionId, { type: 'prompt', message: runnerLaunchLine(request) });\n}\n\nexport interface RunnerRunsPayload {\n /** The runners the hub last reported; presented order preserved. */\n runs: RunnerRunView[];\n /** Where a runner starts when no folder is given. */\n sessionDirectory?: string;\n /** The last start that did not happen. */\n startFailure?: RunnerStartFailureView;\n}\n\n/** The plugin's session data channel: 'runner_runs' payloads into the store. */\nexport const runnerRunsChannel = runners.channel<RunnerRunsPayload>({\n channel: RUNNER_RUNS_TYPE,\n parse(input) {\n if (!isRecord(input) || !Array.isArray(input.runs)) return null;\n const failure = input.startFailure;\n return {\n runs: input.runs.filter(isRecord) as unknown as RunnerRunView[],\n ...(typeof input.sessionDirectory === 'string' ? { sessionDirectory: input.sessionDirectory } : {}),\n ...(isRecord(failure) && typeof failure.id === 'string' && typeof failure.message === 'string'\n ? { startFailure: { id: failure.id, message: failure.message } }\n : {}),\n };\n },\n reduce(current, payload) {\n // A stop request is spent once the runner reports an exit or leaves the feed.\n const stillRunning = new Set(payload.runs.filter((run) => run.state === 'running').map((run) => run.id));\n return { ...payload, stopRequested: current.stopRequested.filter((id) => stillRunning.has(id)) };\n },\n});\n","import {\n Button,\n FolderIcon,\n fontOf,\n Input,\n ListRow,\n Sheet,\n SheetBody,\n SheetContent,\n SheetFooter,\n SheetHeader,\n SheetTitle,\n} from '@agimon-ai/po-native-components';\nimport type { PoNativeTheme } from '@agimon-ai/po-web-components/nativeTheme';\nimport { useState } from 'react';\nimport { Text, View } from 'react-native';\nimport { StyleSheet } from 'react-native-unistyles';\n\nimport type { RunnerCommandBarProps } from '../../../../../types/webRunners';\nimport { plainPunctuation, runnerFolderLabel, runnerFolders } from '../_lib/format';\n\n/**\n * The phone's command bar: the command and Run on one line, the folder it runs\n * in on the row under it, chosen from a bottom sheet.\n */\nexport function RunnerCommandBar({\n command,\n onCommandChange,\n cwd,\n onCwdChange,\n sessionDirectory,\n folders,\n problem,\n onLaunch,\n defaultFolderOpen = false,\n}: RunnerCommandBarProps) {\n const [folderOpen, setFolderOpen] = useState(defaultFolderOpen);\n const [path, setPath] = useState('');\n const pick = (next: string): void => {\n onCwdChange(next);\n setPath('');\n setFolderOpen(false);\n };\n const choices = ['', ...runnerFolders(folders, cwd, sessionDirectory)];\n\n return (\n <View style={styles.bar}>\n <View style={styles.line}>\n <View style={styles.grow}>\n <Input\n testID=\"runners-panel-command\"\n accessibilityLabel=\"Command to run\"\n size=\"lg\"\n value={command}\n onChangeText={(text) => onCommandChange(plainPunctuation(text))}\n onSubmitEditing={onLaunch}\n placeholder=\"a command, like pnpm dev\"\n autoCapitalize=\"none\"\n autoCorrect={false}\n returnKeyType=\"go\"\n />\n </View>\n <Button testID=\"runners-panel-run\" variant=\"primary\" size=\"lg\" onPress={onLaunch}>\n {command.trim() === '' ? 'Open shell' : 'Run'}\n </Button>\n </View>\n <ListRow\n leading={<FolderIcon size={14} color={problem === undefined ? 'faint' : 'red'} />}\n title={runnerFolderLabel(cwd, sessionDirectory)}\n description=\"Runs in\"\n disclosure\n accessibilityLabel={`Runs in ${runnerFolderLabel(cwd, sessionDirectory)}`}\n onPress={() => setFolderOpen(true)}\n />\n {problem === undefined ? (\n <Text style={styles.meta}>Leave the command empty for a plain shell.</Text>\n ) : (\n <Text accessibilityRole=\"alert\" testID=\"runners-panel-problem\" style={styles.problem}>\n {problem}\n </Text>\n )}\n <Sheet open={folderOpen} onOpenChange={setFolderOpen}>\n <SheetContent>\n <SheetHeader closeLabel=\"Close folders\">\n <SheetTitle>Runs in</SheetTitle>\n </SheetHeader>\n <SheetBody>\n <View>\n {choices.map((folder) => (\n <ListRow\n key={folder}\n title={folder === '' ? 'Session directory' : runnerFolderLabel(folder, sessionDirectory)}\n description={folder === '' ? (sessionDirectory ?? 'Where this session started') : folder}\n selected={folder === cwd}\n onPress={() => pick(folder)}\n />\n ))}\n </View>\n <Input\n testID=\"runners-panel-cwd-path\"\n accessibilityLabel=\"Another folder\"\n value={path}\n onChangeText={(text) => setPath(plainPunctuation(text))}\n onSubmitEditing={() => {\n if (path.trim() !== '') pick(path.trim());\n }}\n placeholder=\"another folder, like packages/web\"\n autoCapitalize=\"none\"\n autoCorrect={false}\n returnKeyType=\"done\"\n />\n </SheetBody>\n <SheetFooter>A relative folder starts from the session directory.</SheetFooter>\n </SheetContent>\n </Sheet>\n </View>\n );\n}\n\nconst styles = StyleSheet.create((theme: PoNativeTheme) => ({\n bar: { gap: theme.spacing(1.5) },\n line: { flexDirection: 'row', alignItems: 'center', gap: theme.spacing(2) },\n grow: { flex: 1 },\n meta: {\n color: theme.colors.dim,\n fontFamily: fontOf(theme.fontFamily.sans),\n fontSize: theme.fontSize.sm,\n lineHeight: theme.lineHeight.sm,\n },\n problem: {\n color: theme.colors.red,\n fontFamily: fontOf(theme.fontFamily.sans),\n fontSize: theme.fontSize.sm,\n lineHeight: theme.lineHeight.sm,\n },\n}));\n","export const RUNNER_API_BASE_PATH = 'runner';\nexport const RUN_ID_PARAM = 'runId';\nexport const RUNNER_SCREEN_EVENT = 'screen';\nexport const RUNNER_LOG_STREAM_EVENT = 'append';\nexport const RUNNER_LOG_PING_EVENT = 'ping';\n","import type { LogSlice } from './logReader';\n\n/**\n * The runner log API, shared by this package's session-scoped routes and its\n * cockpit plugin. The two halves run in different processes, so the wire\n * vocabulary is declared here: the browser half may reach `src/types` and\n * nothing else on the server side.\n *\n * Where the routes live is not here. That is `src/types/apiRoutes`, which both\n * halves read, and the generated client turns into the URLs the page addresses.\n * The file a run writes to is still read from its metadata record by the server\n * alone.\n */\n\n/**\n * One chunk of an attached pane's output.\n *\n * Base64 because these are terminal bytes, escape sequences and all, and a\n * server-sent event is a line-oriented text frame that would mangle them.\n */\nexport interface RunnerScreenEvent {\n chunk: string;\n /** Byte offset just past this chunk, so a reconnect resumes rather than replays. */\n offset?: number;\n /** Set once the runner exits, so the page can stop watching. */\n ended?: boolean;\n}\n\n/** A finite byte slice for sealed HTTP followers. Decode chunks incrementally, not independently. */\nexport interface RunnerOutputResponse {\n /** Base64 bytes, preserving split UTF-8 characters and terminal escape sequences. */\n chunk: string;\n offset: number;\n /** The file was replaced or became shorter than the requested offset; discard the previous display/decoder state. */\n reset: boolean;\n /** Opaque raw file identity. Send back on screen/read to detect replacement, including regrowth. */\n generation?: string;\n exists: boolean;\n /** More bytes were present at read time; request the next slice before waiting. */\n hasMore: boolean;\n /** True only once the runner ended and all available bytes have been read. */\n ended: boolean;\n}\n\n/** The body of a keystroke POST. Text, not key codes: the pane wants bytes. */\nexport interface RunnerInputRequest {\n text: string;\n}\n\n/** The named SSE event carrying a RunnerScreenEvent payload. */\n\n/**\n * A log request as query parameters. `grep` is a literal substring, not a\n * regular expression, because that is what the reader matches; `lines` bounds\n * the answer to the last N lines of whatever survived the filter.\n */\nexport interface RunnerLogQueryParams {\n lines?: number;\n grep?: string;\n ignoreCase?: boolean;\n contextLines?: number;\n}\n\n/** The slice the log route answers with, plus which runner it came from. */\nexport interface RunnerLogResponse extends LogSlice {\n runId: string;\n /** True while the runner is still writing, so the page knows following is worth offering. */\n running: boolean;\n}\n\n/**\n * One server-sent event on the follow stream: the lines appended since the last\n * one. The stream never filters: a page that sets a query stops following and\n * reads a filtered slice instead, because grep with context is a whole-file\n * answer and cannot be assembled from a chunk at a time.\n */\nexport interface RunnerLogStreamEvent {\n /** Appended lines, in order; empty when the event only reports the runner ending. */\n lines: string[];\n /**\n * Byte offset just past the last line in this event.\n *\n * A follower that loses the stream resumes here. Without it the page could\n * only fall back to the offset its last slice reported, which every line\n * delivered since has already moved past, so a reconnect would replay them.\n */\n offset?: number;\n /** Set once the runner exits, so the page can stop following without polling the run list. */\n ended?: boolean;\n}\n\n/** The named SSE event carrying a RunnerLogStreamEvent payload. */\n\n/**\n * The named SSE event that carries nothing.\n *\n * A runner can be alive and silent for minutes, which on the wire is\n * indistinguishable from a connection that died. This is sent on a timer so\n * the socket keeps proving itself. Readers that only listen for `append`\n * ignore it, which is what makes it safe to add.\n */\n\n/** Query parameter names, shared so the page and the route cannot drift apart. */\nexport const RUNNER_LOG_PARAMS = {\n lines: 'lines',\n grep: 'grep',\n ignoreCase: 'ignoreCase',\n contextLines: 'contextLines',\n from: 'from',\n generation: 'generation',\n} as const;\n","import type { ApiResponseOf, ApiRoutes } from '@agimon-ai/po-core/web';\n\nimport { RUN_ID_PARAM } from '../constants/webRunnerLog';\nimport { RUNNER_LOG_PARAMS, type RunnerLogResponse, type RunnerOutputResponse } from './webRunnerLog';\n\n/**\n * This package's routes, as data.\n *\n * No scope and no base path: the build reads both off\n * `src/extensions/workspaces/sessions/(backend)/api/runner/`, so the mount is\n * stated once, by the folder that creates it. This package stated it four times\n * before, once per URL builder, each of them re-spelling `/plugins/` and the\n * session prefix by hand.\n *\n * The Hono app registers these paths verbatim and the browser addresses them,\n * so a path cannot move on one side alone. `:runId` is Hono's own parameter\n * syntax for that reason; a caller supplies the value as `params`, and the\n * client encodes the segment.\n */\nconst routes = {\n log: {\n method: 'GET',\n path: `/runners/:${RUN_ID_PARAM}/log`,\n query: [\n RUNNER_LOG_PARAMS.lines,\n RUNNER_LOG_PARAMS.grep,\n RUNNER_LOG_PARAMS.ignoreCase,\n RUNNER_LOG_PARAMS.contextLines,\n ],\n response: undefined as unknown as ApiResponseOf<RunnerLogResponse>,\n },\n /**\n * The live tail of that same log.\n *\n * `stream: true`, so the client exposes a URL and no call method: the\n * consumer is the browser’s own SSE reader, and a relayed call would\n * buffer a stream that never ends.\n */\n logStream: {\n method: 'GET',\n path: `/runners/:${RUN_ID_PARAM}/log/stream`,\n query: [RUNNER_LOG_PARAMS.from],\n stream: true,\n },\n /** The unscrubbed pane bytes, for a terminal emulator rather than a reader. */\n screenStream: {\n method: 'GET',\n path: `/runners/:${RUN_ID_PARAM}/screen/stream`,\n query: [RUNNER_LOG_PARAMS.from],\n stream: true,\n },\n /** Finite byte reads keep sealed HTTP exchanges bounded, unlike SSE. */\n logRead: {\n method: 'GET',\n path: `/runners/:${RUN_ID_PARAM}/log/read`,\n query: [RUNNER_LOG_PARAMS.from],\n response: undefined as unknown as ApiResponseOf<RunnerOutputResponse>,\n },\n screenRead: {\n method: 'GET',\n path: `/runners/:${RUN_ID_PARAM}/screen/read`,\n query: [RUNNER_LOG_PARAMS.from, RUNNER_LOG_PARAMS.generation],\n response: undefined as unknown as ApiResponseOf<RunnerOutputResponse>,\n },\n input: {\n method: 'POST',\n path: `/runners/:${RUN_ID_PARAM}/screen/input`,\n },\n} as const satisfies ApiRoutes;\n\nexport default routes;\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { createApiClient, nativeApiTransport, sessionApiAddress } from '@agimon-ai/po-core/native';\n\nimport routes from '../src/types/apiRoutes';\n\n/** Scopes the tree mounts 'runner' at. */\nexport const apiScopes = ['session'] as const;\n\nexport const api = createApiClient(routes, {\n scopes: apiScopes,\n basePath: 'runner',\n transport: nativeApiTransport,\n sessionAddress: sessionApiAddress,\n});\n","import { api } from '../../../../../../generated/client.native';\nimport { RUN_ID_PARAM } from '../../../../../constants/webRunnerLog';\nimport {\n RUNNER_LOG_PARAMS,\n type RunnerLogQueryParams,\n type RunnerLogResponse,\n} from '../../../../../types/webRunnerLog';\n\n/**\n * The page's half of this package's log API. The only place the cockpit talks\n * HTTP to the hub for a runner, so if the transport ever changes, it changes\n * here alone.\n *\n * The generated client owns every URL: a route is named, a session id selects\n * that session's own copy of the API, and the run id is a path parameter the\n * client substitutes and encodes. Nothing here spells a mount, a prefix or a\n * proxy parameter, which is what the four deleted URL builders each did by\n * hand.\n */\n\nexport type RunnerLogResult = { slice: RunnerLogResponse } | { error: string };\n\nconst UNREACHABLE = 'The cockpit hub is unreachable.';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/** Reads one runner's log: the last N lines, or the lines matching a substring with context. */\nexport async function fetchRunnerLog(\n sessionId: string,\n runId: string,\n params: RunnerLogQueryParams = {},\n signal?: AbortSignal,\n): Promise<RunnerLogResult> {\n const result = await api.session(sessionId).log({\n params: { [RUN_ID_PARAM]: runId },\n // An unset parameter is left out rather than sent empty: the route reads a\n // missing one as its own default, and an empty grep as no filter at all.\n query: {\n [RUNNER_LOG_PARAMS.lines]: params.lines,\n [RUNNER_LOG_PARAMS.grep]: params.grep === '' ? undefined : params.grep,\n [RUNNER_LOG_PARAMS.ignoreCase]: params.ignoreCase === true ? true : undefined,\n [RUNNER_LOG_PARAMS.contextLines]: params.contextLines,\n },\n ...(signal === undefined ? {} : { signal }),\n });\n if (!result.ok) {\n // Status 0 is the transport never answering, which covers both a dead hub\n // and the caller replacing this request. An abort is the caller's own doing\n // and is reported as no answer rather than as a failure to show.\n if (result.status === 0) return { error: signal?.aborted === true ? '' : UNREACHABLE };\n return { error: result.error === '' ? `The hub answered ${String(result.status)}.` : result.error };\n }\n if (!isRecord(result.data) || typeof result.data.text !== 'string') {\n return { error: `The hub answered ${String(result.status)}.` };\n }\n return { slice: result.data };\n}\n","import { useCallback, useEffect, useState, useSyncExternalStore } from 'react';\n\nimport { fetchRunnerLog } from '../_lib/logApi.native';\nimport { runners } from '../_lib/runnersStore.native';\n\nexport function useRunners(sessionId: string | null) {\n const subscribe = useCallback((listener: () => void) => {\n const subscription = runners.store.subscribe(listener);\n return () => subscription.unsubscribe();\n }, []);\n return useSyncExternalStore(subscribe, () => runners.select(runners.store.state, sessionId));\n}\n\n/** Native uses finite reads instead of browser SSE. Read a bounded tail through the host's sealed transport. */\nexport function useRunnerTail(sessionId: string | null, runId: string, running: boolean) {\n const [tail, setTail] = useState<{ id: string; text: string }>();\n useEffect(() => {\n if (sessionId === null || !running) return;\n const controller = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n const read = async () => {\n try {\n const result = await fetchRunnerLog(sessionId, runId, { lines: 5 }, controller.signal);\n if (controller.signal.aborted) return;\n if ('slice' in result) {\n const text = result.slice.text\n .split('\\n')\n .map((line) => line.trim())\n .filter(Boolean)\n .at(-1);\n if (text !== undefined) setTail({ id: `${sessionId}:${runId}`, text });\n if (!result.slice.running) return;\n }\n } catch {\n // A glance keeps the last known output when a read is unavailable.\n }\n if (!controller.signal.aborted) timer = setTimeout(() => void read(), 2_000);\n };\n void read();\n return () => {\n controller.abort();\n clearTimeout(timer);\n };\n }, [sessionId, runId, running]);\n return running && tail?.id === `${sessionId}:${runId}` ? tail.text : undefined;\n}\n","import type { WebPluginSlotProps } from '@agimon-ai/po-core/native';\nimport { fontOf, Button, Input, StatusBadge } from '@agimon-ai/po-native-components';\nimport type { PoNativeTheme } from '@agimon-ai/po-web-components/nativeTheme';\nimport { type ReactNode, useEffect, useState } from 'react';\nimport { Pressable, ScrollView, Text, View } from 'react-native';\nimport { StyleSheet } from 'react-native-unistyles';\n\nimport type { RunnerLogResponse } from '../../../../../types/webRunnerLog';\nimport type { RunnerRunView } from '../../../../../types/webRunners';\nimport { logViewLines, runnerBadge, runnerFolderLabel, tailLineNumbers } from '../_lib/format';\nimport { fetchRunnerLog } from '../_lib/logApi.native';\nimport { requestRunnerStop } from '../_lib/runnersStore.native';\nimport { useRunners } from './runnerHooks.native';\n\n/** The top of both runner screens: name, outcome, an action, and the command in its folder. */\nexport function RunnerRunHeader({\n run,\n name,\n sessionDirectory,\n action,\n}: {\n run: RunnerRunView | undefined;\n name: string;\n sessionDirectory: string | undefined;\n action?: ReactNode;\n}) {\n const badge = runnerBadge(run);\n /** A long command would eat a phone screen, so it starts as one truncated line. */\n const [commandOpen, setCommandOpen] = useState(false);\n return (\n <>\n <View style={styles.header}>\n <Text numberOfLines={1} style={styles.title}>\n {name}\n </Text>\n <StatusBadge tone={badge.tone}>{badge.label}</StatusBadge>\n <View style={styles.grow} />\n {action}\n </View>\n {run ? (\n <Pressable\n testID=\"runner-log-command-toggle\"\n accessibilityRole=\"button\"\n accessibilityState={{ expanded: commandOpen }}\n accessibilityHint={commandOpen ? 'Collapses the command' : 'Shows the full command'}\n style={styles.commandBox}\n onPress={() => setCommandOpen((open) => !open)}\n >\n <Text selectable={commandOpen} numberOfLines={commandOpen ? undefined : 1} style={styles.command}>\n <Text style={styles.prompt}>$ </Text>\n {run.command}\n </Text>\n {commandOpen ? (\n <Text numberOfLines={1} style={styles.folder}>\n in {runnerFolderLabel(run.cwd, sessionDirectory)}\n </Text>\n ) : null}\n </Pressable>\n ) : (\n <Text style={styles.meta}>No longer listed; its log stays readable.</Text>\n )}\n </>\n );\n}\n\nexport function runnerLogTab(run: RunnerRunView) {\n return {\n id: `runner-log-${run.id}`,\n label: `log · ${run.name}`,\n panel: (props: WebPluginSlotProps) => <RunnerLogPanel {...props} runId={run.id} />,\n };\n}\n\nexport function RunnerLogPanel({ sessionId, runId, sendSessionFrame }: WebPluginSlotProps & { runId: string }) {\n const session = useRunners(sessionId);\n const run = session.runs.find((candidate) => candidate.id === runId);\n const [typed, setTyped] = useState('');\n const [query, setQuery] = useState('');\n const [ignoreCase, setIgnoreCase] = useState(false);\n const [context, setContext] = useState(2);\n const [following, setFollowing] = useState(true);\n const requestKey = `${sessionId}:${runId}:${query}:${ignoreCase}:${context}:${following}`;\n const [loaded, setLoaded] = useState<{ key: string; slice?: RunnerLogResponse; error: string }>();\n const slice = loaded?.key === requestKey ? loaded.slice : undefined;\n const error = loaded?.key === requestKey ? loaded.error : '';\n useEffect(() => {\n const timer = setTimeout(() => setQuery(typed), 200);\n return () => clearTimeout(timer);\n }, [typed]);\n useEffect(() => {\n if (sessionId === null) return;\n const controller = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n const read = async () => {\n const result = await fetchRunnerLog(\n sessionId,\n runId,\n { lines: 2000, grep: query, ignoreCase, contextLines: context },\n controller.signal,\n );\n if (controller.signal.aborted) return;\n setLoaded(\n 'error' in result\n ? { key: requestKey, error: result.error }\n : { key: requestKey, slice: result.slice, error: '' },\n );\n if (following && query === '' && ('error' in result || result.slice.running))\n timer = setTimeout(() => void read(), 2_000);\n };\n void read();\n return () => {\n controller.abort();\n clearTimeout(timer);\n };\n }, [sessionId, runId, query, ignoreCase, context, following, requestKey]);\n const lines = logViewLines(slice?.text ?? '', [], 2000).lines;\n const numbers = query === '' ? tailLineNumbers(slice?.totalLines ?? 0, lines.length) : (slice?.lineNumbers ?? []);\n const gutter = String(numbers.at(-1) ?? 0).length;\n const stopping = session.stopRequested.includes(runId);\n const live = following && query === '' && slice?.running === true;\n return (\n <View testID=\"runner-log-panel\" style={styles.panel}>\n <RunnerRunHeader\n run={run}\n name={run?.name ?? runId}\n sessionDirectory={session.sessionDirectory}\n action={\n run?.state === 'running' && sessionId !== null ? (\n <Button\n variant={stopping ? 'outline' : 'danger-outline'}\n size=\"sm\"\n disabled={stopping}\n onPress={() => requestRunnerStop(sendSessionFrame, sessionId, runId)}\n >\n {stopping ? 'Stopping…' : 'Stop'}\n </Button>\n ) : null\n }\n />\n <Input\n testID=\"runner-log-search\"\n accessibilityLabel=\"Search this log\"\n placeholder=\"Search output\"\n value={typed}\n onChangeText={setTyped}\n autoCapitalize=\"none\"\n returnKeyType=\"search\"\n />\n <View style={styles.actions}>\n <Button\n variant={ignoreCase ? 'subtle' : 'outline'}\n size=\"sm\"\n accessibilityState={{ selected: ignoreCase }}\n onPress={() => setIgnoreCase((value) => !value)}\n >\n {ignoreCase ? 'Any case' : 'Match case'}\n </Button>\n {query === '' ? null : (\n <Button\n variant={context > 0 ? 'subtle' : 'outline'}\n size=\"sm\"\n onPress={() => setContext((value) => (value === 0 ? 2 : 0))}\n >\n {`± ${String(context)} lines`}\n </Button>\n )}\n {query === '' && slice?.running === true ? (\n <Button\n variant={live ? 'subtle' : 'outline'}\n size=\"sm\"\n accessibilityState={{ selected: live }}\n onPress={() => setFollowing((value) => !value)}\n >\n {live ? 'Following' : 'Follow'}\n </Button>\n ) : null}\n </View>\n <Text style={styles.meta}>\n {slice === undefined\n ? error === ''\n ? 'Reading…'\n : ''\n : query !== ''\n ? `${slice.lineCount} matching of ${slice.totalLines} lines`\n : `${live ? 'Tailing' : 'Showing'} last ${lines.length} of ${slice.totalLines} lines`}\n </Text>\n <ScrollView style={styles.log} contentContainerStyle={styles.logBody}>\n {error !== '' ? (\n <Text accessibilityRole=\"alert\" style={styles.error}>\n {error}\n </Text>\n ) : slice?.exists === false ? (\n <Text style={styles.meta}>This runner has not written a log yet.</Text>\n ) : slice && lines.length === 0 ? (\n <Text style={styles.meta}>{query === '' ? 'The log is empty.' : 'Nothing matched.'}</Text>\n ) : (\n lines.map((line, index) => (\n <Text selectable key={`${numbers[index] ?? index}`} style={styles.line}>\n <Text style={styles.number}>{`${String(numbers[index] ?? '').padStart(gutter)} `}</Text>\n {line}\n </Text>\n ))\n )}\n </ScrollView>\n <Text selectable numberOfLines={1} ellipsizeMode=\"middle\" style={styles.path}>\n {run?.logPath ?? slice?.path ?? ''}\n </Text>\n </View>\n );\n}\nconst styles = StyleSheet.create((theme: PoNativeTheme) => ({\n panel: { flex: 1, gap: theme.spacing(2), padding: theme.spacing(3), backgroundColor: theme.colors.bg },\n header: { flexDirection: 'row', alignItems: 'center', gap: theme.spacing(2), minHeight: 32 },\n grow: { flex: 1 },\n title: {\n flexShrink: 1,\n color: theme.colors.hi,\n fontWeight: '600',\n fontFamily: fontOf(theme.fontFamily.sans),\n fontSize: theme.fontSize.base,\n },\n commandBox: {\n gap: theme.spacing(1),\n paddingHorizontal: theme.spacing(3),\n paddingVertical: theme.spacing(2),\n borderRadius: theme.borderRadius.md,\n backgroundColor: theme.colors.deep,\n },\n command: { color: theme.colors.hi, fontFamily: fontOf(theme.fontFamily.mono), fontSize: theme.fontSize.sm },\n prompt: { color: theme.colors.faint },\n folder: { color: theme.colors.dim, fontFamily: fontOf(theme.fontFamily.mono), fontSize: theme.fontSize.xs },\n meta: {\n color: theme.colors.dim,\n fontFamily: fontOf(theme.fontFamily.sans),\n fontSize: theme.fontSize.sm,\n lineHeight: theme.lineHeight.sm,\n },\n error: { color: theme.colors.red, fontFamily: fontOf(theme.fontFamily.sans), fontSize: theme.fontSize.sm },\n actions: { flexDirection: 'row', gap: theme.spacing(2), flexWrap: 'wrap' },\n log: { flex: 1, borderRadius: theme.borderRadius.md, backgroundColor: theme.colors.deep },\n logBody: { padding: theme.spacing(3) },\n line: {\n color: theme.colors.text,\n fontFamily: fontOf(theme.fontFamily.mono),\n fontSize: theme.fontSize.xs,\n lineHeight: theme.lineHeight.sm,\n },\n number: { color: theme.colors.faint },\n path: { color: theme.colors.faint, fontFamily: fontOf(theme.fontFamily.mono), fontSize: theme.fontSize.xs },\n}));\n","import { api } from '../../../../../../generated/client.native';\nimport { RUN_ID_PARAM } from '../../../../../constants/webRunnerLog';\nimport { RUNNER_LOG_PARAMS, type RunnerOutputResponse } from '../../../../../types/webRunnerLog';\n\n/** Finite native reads preserve raw terminal bytes and generation-based replacement detection. */\nexport async function readRunnerScreen(\n sessionId: string,\n runId: string,\n from: number,\n generation: string | undefined,\n signal: AbortSignal,\n): Promise<RunnerOutputResponse> {\n const result = await api.session(sessionId).screenRead({\n params: { [RUN_ID_PARAM]: runId },\n query: { [RUNNER_LOG_PARAMS.from]: from, [RUNNER_LOG_PARAMS.generation]: generation },\n signal,\n });\n if (!result.ok) throw new Error(result.error || 'The connection to this pane dropped.');\n return result.data;\n}\nexport async function sendRunnerInput(sessionId: string, runId: string, text: string): Promise<void> {\n const result = await api.session(sessionId).input({ params: { [RUN_ID_PARAM]: runId }, body: { text } });\n if (!result.ok) throw new Error(result.error || 'This runner is no longer accepting input.');\n}\n","import type { WebPluginSlotProps } from '@agimon-ai/po-core/native';\nimport { fontOf, Button, SearchIcon } from '@agimon-ai/po-native-components';\nimport type { PoNativeTheme } from '@agimon-ai/po-web-components/nativeTheme';\nimport { useMemo } from 'react';\nimport { Text, View } from 'react-native';\nimport { StyleSheet } from 'react-native-unistyles';\n\nimport type { RunnerRunView } from '../../../../../types/webRunners';\nimport { requestRunnerStop } from '../_lib/runnersStore.native';\nimport { readRunnerScreen, sendRunnerInput } from '../_lib/screenApi.native';\nimport { useRunners } from './runnerHooks.native';\nimport { RunnerRunHeader, runnerLogTab } from './RunnerLogPanel.native';\n\n/** The host renders genuine terminal bytes; this package owns every scoped API call. */\nexport function runnerShellTab(run: RunnerRunView) {\n return {\n id: `runner-shell-${run.id}`,\n label: `shell · ${run.name}`,\n panel: (props: WebPluginSlotProps) => <RunnerShellPanel {...props} runId={run.id} />,\n };\n}\n\n/**\n * One terminal runner, full screen. A phone keyboard has no Ctrl key, so\n * Ctrl-C is a button; Search opens the runner's log, which the sink keeps\n * scrubbed beside the raw bytes for exactly that.\n */\nexport function RunnerShellPanel({\n sessionId,\n runId,\n renderRunnerTerminal,\n sendSessionFrame,\n openTransientTab,\n}: WebPluginSlotProps & { runId: string }) {\n const session = useRunners(sessionId);\n const run = session.runs.find((candidate) => candidate.id === runId);\n const live = run?.state === 'running';\n const stopping = session.stopRequested.includes(runId);\n const request = useMemo(\n () =>\n sessionId === null\n ? undefined\n : {\n key: `${sessionId}:${runId}`,\n read: (from: number, generation: string | undefined, signal: AbortSignal) =>\n readRunnerScreen(sessionId, runId, from, generation, signal),\n write: (text: string) => sendRunnerInput(sessionId, runId, text),\n },\n [sessionId, runId],\n );\n return (\n <View style={styles.panel}>\n <RunnerRunHeader\n run={run}\n name={run?.name ?? runId}\n sessionDirectory={session.sessionDirectory}\n action={\n live && sessionId !== null ? (\n <Button\n testID=\"runner-shell-stop\"\n variant={stopping ? 'outline' : 'danger-outline'}\n size=\"sm\"\n disabled={stopping}\n onPress={() => requestRunnerStop(sendSessionFrame, sessionId, runId)}\n >\n {stopping ? 'Stopping…' : 'Stop'}\n </Button>\n ) : null\n }\n />\n <View style={styles.terminal}>\n {request === undefined ? (\n <Text style={styles.meta}>Select a session to attach to this runner.</Text>\n ) : (\n renderRunnerTerminal?.(request)\n )}\n </View>\n <View style={styles.actions}>\n {run ? (\n <Button\n testID=\"runner-shell-search\"\n variant=\"outline\"\n onPress={() => openTransientTab(runnerLogTab(run))}\n style={styles.action}\n >\n <SearchIcon size={14} />\n Search output\n </Button>\n ) : null}\n {live && sessionId !== null ? (\n <Button\n testID=\"runner-shell-interrupt\"\n variant=\"outline\"\n onPress={() => void sendRunnerInput(sessionId, runId, '\\u0003')}\n style={styles.action}\n >\n Ctrl-C\n </Button>\n ) : null}\n </View>\n </View>\n );\n}\nconst styles = StyleSheet.create((theme: PoNativeTheme) => ({\n panel: { flex: 1, gap: theme.spacing(2), padding: theme.spacing(3), backgroundColor: theme.colors.bg },\n actions: { flexDirection: 'row', gap: theme.spacing(2) },\n action: { flex: 1 },\n terminal: { flex: 1 },\n meta: { color: theme.colors.dim, fontFamily: fontOf(theme.fontFamily.sans), fontSize: theme.fontSize.sm },\n}));\n","import type { WebPluginSlotProps } from '@agimon-ai/po-core/native';\nimport { ArrowRightIcon, fontOf, Button, Dot, ListRow } from '@agimon-ai/po-native-components';\nimport type { PoNativeTheme } from '@agimon-ai/po-web-components/nativeTheme';\nimport { useEffect, useRef, useState } from 'react';\nimport { Pressable, ScrollView, Text, View } from 'react-native';\nimport { StyleSheet } from 'react-native-unistyles';\n\nimport type { RunnerRunView } from '../../../../../types/webRunners';\nimport { formatRunnerUptime } from '../_lib/format';\nimport { runnerRunRequest } from '../_lib/launchLine';\nimport { isRunnerActivityVisible, requestRunnerStart, requestRunnerStop } from '../_lib/runnersStore.native';\nimport { RunnerCommandBar } from './RunnerCommandBar.native';\nimport { useRunners, useRunnerTail } from './runnerHooks.native';\nimport { runnerLogTab } from './RunnerLogPanel.native';\nimport { runnerShellTab } from './RunnerShellPanel.native';\n\n/** A runner's own screen: its terminal when it has one, its log when it does not. */\nfunction runnerTab(run: RunnerRunView) {\n return run.interactive ? runnerShellTab(run) : runnerLogTab(run);\n}\n\nexport function runnersTab() {\n return { id: 'runner-runs', label: 'runners', panel: RunnersPanel };\n}\n\nfunction RunnerRow({\n run,\n props,\n stopping,\n now,\n}: {\n run: RunnerRunView;\n props: WebPluginSlotProps;\n stopping: boolean;\n now: number;\n}) {\n const tail = useRunnerTail(props.sessionId, run.id, run.state === 'running');\n // One tap target for the row: the name, its uptime and Stop on one line, then\n // what it is doing, falling back to what it was asked to do.\n return (\n <Pressable\n testID={`activity-runner-${run.id}`}\n accessibilityRole=\"button\"\n accessibilityLabel={`Open ${run.name}`}\n onPress={() => props.openTransientTab(runnerTab(run))}\n style={({ pressed }) => [styles.row, pressed && styles.pressed]}\n >\n <View style={styles.line}>\n <Dot tone=\"yellow\" pulse />\n <Text numberOfLines={1} style={styles.name}>\n {run.name}\n </Text>\n <Text style={styles.meta}>{formatRunnerUptime(run.startedAt, now)}</Text>\n {props.sessionId !== null ? (\n <Button\n testID={`activity-runner-stop-${run.id}`}\n size=\"xs\"\n variant={stopping ? 'outline' : 'danger-outline'}\n disabled={stopping}\n onPress={() => {\n if (props.sessionId !== null) requestRunnerStop(props.sendSessionFrame, props.sessionId, run.id);\n }}\n >\n {stopping ? 'Stopping…' : 'Stop'}\n </Button>\n ) : null}\n </View>\n <Text numberOfLines={1} style={styles.tail}>\n {tail ?? `$ ${run.command}`}\n </Text>\n </Pressable>\n );\n}\n\nexport function RunnersActivitySection(props: WebPluginSlotProps) {\n const session = useRunners(props.sessionId);\n const running = session.runs.filter((run) => isRunnerActivityVisible(run));\n const [now, setNow] = useState(() => Date.now());\n useEffect(() => {\n const timer = setInterval(() => setNow(Date.now()), 1_000);\n return () => clearInterval(timer);\n }, []);\n return running.length === 0 ? (\n // The cockpit's idle line: the status, then the one jade action beside it.\n <View style={styles.idle}>\n <Text style={styles.meta}>Idle</Text>\n {props.sessionId !== null ? (\n <Pressable\n accessibilityRole=\"button\"\n testID=\"activity-runner-launch\"\n hitSlop={10}\n onPress={() => props.openTransientTab(runnersTab())}\n style={styles.launch}\n >\n <Text style={styles.launchText}>Launch a runner</Text>\n <ArrowRightIcon size={14} color=\"green\" />\n </Pressable>\n ) : null}\n </View>\n ) : (\n <View>\n {running.map((run) => (\n <RunnerRow key={run.id} run={run} props={props} now={now} stopping={session.stopRequested.includes(run.id)} />\n ))}\n </View>\n );\n}\n\n/**\n * Every running runner and the one place to start another: type a command\n * and Run hosts it on a terminal (plain output when the host has no rmux or\n * tmux), or leave it empty for a login shell. The started runner opens on\n * its own screen.\n */\nexport function RunnersPanel(props: WebPluginSlotProps) {\n const { openTransientTab } = props;\n const session = useRunners(props.sessionId);\n const running = session.runs.filter((run) => run.state === 'running');\n const [command, setCommand] = useState('');\n const [cwd, setCwd] = useState('');\n const [now, setNow] = useState(() => Date.now());\n const baseline = useRef<ReadonlySet<string> | null>(null);\n /** What the pending launch ran, put back if the start fails. */\n const launched = useRef('');\n const timeout = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n useEffect(() => {\n const timer = setInterval(() => setNow(Date.now()), 10_000);\n return () => clearInterval(timer);\n }, []);\n // ponytail: the first runner to appear after a launch is taken to be it, the\n // same guess the web panel makes.\n useEffect(() => {\n if (baseline.current === null) return;\n const started = session.runs.find((run) => run.state === 'running' && !baseline.current?.has(run.id));\n if (started === undefined) return;\n baseline.current = null;\n clearTimeout(timeout.current);\n openTransientTab(runnerTab(started));\n }, [session.runs, openTransientTab]);\n // A start that did not happen hands the command back beside its problem.\n const failureId = session.startFailure?.id;\n useEffect(() => {\n if (failureId === undefined || baseline.current === null) return;\n baseline.current = null;\n clearTimeout(timeout.current);\n setCommand(launched.current);\n }, [failureId]);\n useEffect(() => () => clearTimeout(timeout.current), []);\n const launch = () => {\n if (props.sessionId === null) return;\n baseline.current = new Set(session.runs.map((run) => run.id));\n clearTimeout(timeout.current);\n timeout.current = setTimeout(() => {\n baseline.current = null;\n }, 30_000);\n requestRunnerStart(props.sendSessionFrame, props.sessionId, runnerRunRequest(command, cwd));\n launched.current = command;\n setCommand('');\n };\n return (\n <View style={styles.panel}>\n <View style={styles.header}>\n <Text style={styles.title}>Runners</Text>\n <Text style={styles.meta}>{running.length === 0 ? 'Nothing running' : `${running.length} running`}</Text>\n </View>\n {props.sessionId !== null ? (\n <RunnerCommandBar\n command={command}\n onCommandChange={setCommand}\n cwd={cwd}\n onCwdChange={setCwd}\n folders={running.map((run) => run.cwd)}\n {...(session.sessionDirectory === undefined ? {} : { sessionDirectory: session.sessionDirectory })}\n {...(session.startFailure === undefined ? {} : { problem: session.startFailure.message })}\n onLaunch={launch}\n />\n ) : null}\n <ScrollView>\n {running.length === 0 ? (\n <Text style={styles.meta}>\n {props.sessionId === null\n ? 'Open a session to start a runner.'\n : 'Nothing running yet. Type a command above, like pnpm dev, and it opens as a live terminal.'}\n </Text>\n ) : (\n running.map((run) => (\n <ListRow\n key={run.id}\n leading={<Dot tone=\"yellow\" pulse />}\n title={run.name}\n description={`${run.command} · ${formatRunnerUptime(run.startedAt, now)}`}\n disclosure\n onPress={() => openTransientTab(runnerTab(run))}\n />\n ))\n )}\n </ScrollView>\n </View>\n );\n}\nconst styles = StyleSheet.create((theme: PoNativeTheme) => ({\n panel: { flex: 1, gap: theme.spacing(3), padding: theme.spacing(4), backgroundColor: theme.colors.bg },\n header: { flexDirection: 'row', alignItems: 'center', gap: theme.spacing(2) },\n row: { gap: theme.spacing(1), paddingVertical: theme.spacing(2) },\n pressed: { opacity: 0.6 },\n line: { flexDirection: 'row', alignItems: 'center', gap: theme.spacing(2) },\n name: {\n flex: 1,\n color: theme.colors.hi,\n fontFamily: fontOf(theme.fontFamily.sans),\n fontSize: theme.fontSize.base,\n lineHeight: theme.lineHeight.base,\n fontWeight: theme.fontWeight.medium,\n },\n tail: {\n // Under the name: the small dot plus the line's gap.\n paddingLeft: theme.spacing(3.5),\n color: theme.colors.dim,\n fontFamily: fontOf(theme.fontFamily.mono),\n fontSize: theme.fontSize.sm,\n lineHeight: theme.lineHeight.sm,\n },\n title: {\n color: theme.colors.hi,\n fontFamily: fontOf(theme.fontFamily.sans),\n fontSize: theme.fontSize.lg,\n fontWeight: '600',\n },\n meta: {\n color: theme.colors.dim,\n fontFamily: fontOf(theme.fontFamily.sans),\n fontSize: theme.fontSize.sm,\n lineHeight: theme.lineHeight.sm,\n },\n idle: { flexDirection: 'row', alignItems: 'center', flexWrap: 'wrap', gap: theme.spacing(4) },\n launch: { flexDirection: 'row', alignItems: 'center', gap: theme.spacing(1) },\n launchText: {\n color: theme.colors.green,\n fontFamily: fontOf(theme.fontFamily.sans),\n fontSize: theme.fontSize.base,\n lineHeight: theme.lineHeight.base,\n fontWeight: theme.fontWeight.medium,\n },\n}));\n","import { defineActivityGroup } from '@agimon-ai/po-core/native';\nimport { PlayCircleIcon } from '@agimon-ai/po-native-components';\nimport { createElement } from 'react';\n\nimport { runnersTab } from '../_components/RunnersPanel.native';\nimport { runnerActivitySource } from '../_lib/runnersStore.native';\n\nexport default defineActivityGroup({\n name: 'runners',\n keys: 'r l',\n icon: () => createElement(PlayCircleIcon),\n activeSource: runnerActivitySource,\n transientTab: runnersTab,\n order: 20,\n});\n","import { defineChannelFile } from '@agimon-ai/po-core/native';\n\nimport { runnerRunsChannel } from '../_lib/runnersStore.native';\nexport default defineChannelFile(runnerRunsChannel);\n","import { defineFill } from '@agimon-ai/po-core/native';\n\nimport { RunnersActivitySection } from '../_components/RunnersPanel.native';\n\nexport default defineFill({ slot: 'activity.runners', id: 'runners', component: RunnersActivitySection });\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineNativePlugin, type WebPluginContributions } from '@agimon-ai/po-core/native';\n\nimport activityGroupRunners from '../src/extensions/workspaces/sessions/(frontend)/activity-group/runners.native';\nimport channelRunnerRuns from '../src/extensions/workspaces/sessions/(frontend)/channel/runner-runs.native';\nimport fillRunners from '../src/extensions/workspaces/sessions/(frontend)/fill/Runners.activity.runners.native';\n\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const nativePlugin = defineNativePlugin({\n id: 'runner',\n session: {\n get activityGroups(): WebPluginContributions['activityGroups'] { return [via({ name: 'runners' }, activityGroupRunners)]; },\n get channels(): WebPluginContributions['channels'] { return [via({ channel: 'runner_runs' }, channelRunnerRuns)]; },\n get fills(): WebPluginContributions['fills'] { return [via({ slot: 'activity.runners', id: 'runners' }, fillRunners)]; },\n },\n});\n"],"mappings":";;;;;;;;;;;;;;AAMA,SAAgB,mBAAmB,WAAmB,KAAqB;CACzE,MAAM,UAAU,KAAK,MAAM,SAAS;CACpC,IAAI,OAAO,MAAM,OAAO,GAAG,OAAO;CAClC,MAAM,UAAU,KAAK,IAAI,GAAG,KAAK,OAAO,MAAM,WAAW,GAAI,CAAC;CAC9D,IAAI,UAAU,IAAI,OAAO,GAAG,QAAQ;CACpC,MAAM,UAAU,KAAK,MAAM,UAAU,EAAE;CACvC,IAAI,UAAU,IAAI,OAAO,GAAG,QAAQ;CACpC,MAAM,QAAQ,KAAK,MAAM,UAAU,EAAE;CACrC,OAAO,QAAQ,KAAK,GAAG,MAAM,KAAK,GAAG,KAAK,MAAM,QAAQ,EAAE,EAAE;AAC9D;;;;;;;;;;AA2BA,SAAgB,aACd,MACA,UACA,KACA,UAA0B,CAAC,GAClB;CACT,MAAM,QAAQ,KAAK,MAAM,IAAI;CAC7B,IAAI,MAAM,SAAS,KAAK,MAAM,MAAM,SAAS,OAAO,IAAI,MAAM,IAAI;CAClE,IAAI,QAAQ,oBAAoB,QAAQ,MAAM,SAAS,GAAG,MAAM,IAAI;CACpE,MAAM,MAAM,CAAC,GAAG,OAAO,GAAG,QAAQ;CAClC,MAAM,QAAQ,IAAI,MAAM,CAAC,GAAG;CAC5B,OAAO;EAAE;EAAO,QAAQ,IAAI,SAAS,MAAM;CAAO;AACpD;;;;;;;AAQA,SAAgB,gBAAgB,gBAAwB,OAAyB;CAC/E,MAAM,QAAQ,KAAK,IAAI,GAAG,iBAAiB,QAAQ,CAAC;CACpD,OAAO,MAAM,KAAK,EAAE,QAAQ,MAAM,IAAI,GAAG,UAAU,QAAQ,KAAK;AAClE;;;;;AAmBA,SAAgB,kBAAkB,QAAgB,kBAA8C;CAC9F,IAAI,WAAW,MAAM,WAAW,kBAC9B,OAAO,qBAAqB,KAAA,IACxB,sBACC,iBAAiB,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK;CAE5C,IAAI,qBAAqB,KAAA,KAAa,OAAO,WAAW,GAAG,iBAAiB,EAAE,GAC5E,OAAO,OAAO,MAAM,iBAAiB,SAAS,CAAC;CAEjD,OAAO;AACT;;AAGA,SAAgB,cACd,OACA,SACA,kBACU;CACV,MAAM,0BAAU,IAAI,IAAI,CAAC,GAAG,OAAO,OAAO,CAAC;CAC3C,QAAQ,OAAO,EAAE;CACjB,IAAI,qBAAqB,KAAA,GAAW,QAAQ,OAAO,gBAAgB;CACnE,OAAO,CAAC,GAAG,OAAO;AACpB;;;;;AAMA,SAAgB,iBAAiB,MAAsB;CACrD,OAAO,KACJ,QAAQ,SAAS,GAAG,CAAC,CACrB,QAAQ,SAAS,IAAG,CAAC,CACrB,QAAQ,WAAW,IAAI;AAC5B;;AAGA,SAAgB,YAAY,KAG1B;CACA,IAAI,QAAQ,KAAA,GAAW,OAAO;EAAE,MAAM;EAAW,OAAO;CAAO;CAC/D,IAAI,IAAI,UAAU,WAAW,OAAO;EAAE,MAAM;EAAW,OAAO;CAAU;CACxE,IAAI,IAAI,SAAS,KAAA,KAAa,IAAI,KAAK,WAAW,WAAW,OAAO;EAAE,MAAM;EAAW,OAAO;CAAU;CAExG,OADc,IAAI,KAAK,WAAW,gBAAgB,IAAI,KAAK,SAAS,KAAK,IAAI,KAAK,SAAS,QAC5E;EAAE,MAAM;EAAM,OAAO;CAAO,IAAI;EAAE,MAAM;EAAS,OAAO,IAAI,KAAK,OAAO,QAAQ,KAAK,GAAG;CAAE;AAC3G;;;;;;;;;;;;;ACtHA,MAAa,qBAAqB;;AAgBlC,MAAa,uBAA4C;CACvD,SAAS;CACT,MAAM;CACN,aAAa;AACf;;;;;AAMA,SAAgB,iBAAiB,SAAiB,KAAkC;CAClF,MAAM,QAAQ,IAAI,KAAK,MAAM,KAAK,CAAC,IAAI,EAAE,IAAI;CAC7C,OAAO,QAAQ,KAAK,MAAM,KAAK;EAAE,GAAG;EAAsB,GAAG;CAAM,IAAI;EAAE;EAAS,GAAG;EAAO,mBAAmB;CAAK;AACtH;;AAGA,SAAS,MAAM,OAAuB;CACpC,OAAO,MAAM,KAAK,KAAK,IAAI,IAAI,MAAM,KAAK;AAC5C;AAEA,SAAgB,iBAAiB,SAAsC;CACrE,MAAM,MAAM,QAAQ,KAAK,KAAK,KAAK;CACnC,MAAM,OAAO,QAAQ,MAAM,KAAK,KAAK;CACrC,MAAM,QAAQ;EACZ,GAAI,SAAS,KAAK,CAAC,IAAI,CAAC,QAAQ,MAAM,IAAI,GAAG;EAC7C,GAAI,QAAQ,KAAK,CAAC,IAAI,CAAC,OAAO,MAAM,GAAG,GAAG;EAC1C,GAAI,QAAQ,gBAAgB,OACxB,CAAC,kBAAkB,IACnB,QAAQ,sBAAsB,OAC5B,CAAC,oBAAoB,IACrB,CAAC;CACT;CAGA,OAAO;EAAC;EAAoB,GAAG;;EAAkC,QAAQ,QAAQ,KAAK;CAAC,CAAC,CAAC,KAAK,GAAG;AACnG;;;AC9DA,MAAa,mBAAmB;;;;ACOhC,MAAM,eAAe;AAQrB,MAAa,UAAU,mBAAmC;CAAE,MAAM,CAAC;CAAG,eAAe,CAAC;AAAE,CAAC;;AAGzF,SAAgB,wBAAwB,KAAoB,MAAM,KAAK,IAAI,GAAY;CACrF,OAAO,IAAI,UAAU,aAAa,MAAM,KAAK,MAAM,IAAI,SAAS,IAAI;AACtE;;AAGA,MAAa,uBAAuB;CAClC,UAAU,UAAsB;EAC9B,MAAM,eAAe,QAAQ,MAAM,UAAU,QAAQ;EACrD,MAAM,QAAQ,YAAY,UAAU,GAAK;EACzC,aAAa;GACX,aAAa,YAAY;GACzB,cAAc,KAAK;EACrB;CACF;CACA,SAAS,WAA0B;EACjC,OAAO,QAAQ,OAAO,QAAQ,MAAM,OAAO,SAAS,CAAC,CAAC,KAAK,MAAM,QAAQ,wBAAwB,GAAG,CAAC;CACvG;AACF;AAEA,SAASA,WAAS,OAAkD;CAClE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;;;;;;AAOA,SAAgB,kBAAkB,MAA0B,WAAmB,IAAkB;CAC/F,KAAK,WAAW;EAAE,MAAM;EAAU,SAAS,GAAG,aAAa,GAAG;CAAK,CAAC;CACpE,QAAQ,OAAO,YAAY,aAAa;EACtC,GAAG;EACH,eAAe,CAAC,GAAG,QAAQ,cAAc,QAAQ,UAAU,UAAU,EAAE,GAAG,EAAE;CAC9E,EAAE;AACJ;;;;;;;;;AAUA,SAAgB,mBAAmB,MAA0B,WAAmB,SAAoC;CAClH,KAAK,WAAW;EAAE,MAAM;EAAU,SAAS,iBAAiB,OAAO;CAAE,CAAC;AACxE;;AAYA,MAAa,oBAAoB,QAAQ,QAA2B;CAClE,SAAS;CACT,MAAM,OAAO;EACX,IAAI,CAACA,WAAS,KAAK,KAAK,CAAC,MAAM,QAAQ,MAAM,IAAI,GAAG,OAAO;EAC3D,MAAM,UAAU,MAAM;EACtB,OAAO;GACL,MAAM,MAAM,KAAK,OAAOA,UAAQ;GAChC,GAAI,OAAO,MAAM,qBAAqB,WAAW,EAAE,kBAAkB,MAAM,iBAAiB,IAAI,CAAC;GACjG,GAAIA,WAAS,OAAO,KAAK,OAAO,QAAQ,OAAO,YAAY,OAAO,QAAQ,YAAY,WAClF,EAAE,cAAc;IAAE,IAAI,QAAQ;IAAI,SAAS,QAAQ;GAAQ,EAAE,IAC7D,CAAC;EACP;CACF;CACA,OAAO,SAAS,SAAS;EAEvB,MAAM,eAAe,IAAI,IAAI,QAAQ,KAAK,QAAQ,QAAQ,IAAI,UAAU,SAAS,CAAC,CAAC,KAAK,QAAQ,IAAI,EAAE,CAAC;EACvG,OAAO;GAAE,GAAG;GAAS,eAAe,QAAQ,cAAc,QAAQ,OAAO,aAAa,IAAI,EAAE,CAAC;EAAE;CACjG;AACF,CAAC;;;;;;;ACrED,SAAgBmB,iBAAiB,EAC/BC,SACAC,iBACAC,KACAC,aACAC,kBACAC,SACAC,SACAC,UACAC,oBAAoB,SACI;CACxB,MAAM,CAACC,YAAYC,iBAAiBjB,SAASe,iBAAiB;CAC9D,MAAM,CAACG,MAAMC,WAAWnB,SAAS,EAAE;CACnC,MAAMoB,QAAQC,SAAuB;EACnCX,YAAYW,IAAI;EAChBF,QAAQ,EAAE;EACVF,cAAc,KAAK;CACrB;CACA,MAAMK,UAAU,CAAC,IAAI,GAAGjB,cAAcO,SAASH,KAAKE,gBAAgB,CAAC;CAErE,OACE,qBAAC,MAAD;EAAM,OAAOY,SAAOC;EAApB,UAAA;GACE,qBAAC,MAAD;IAAM,OAAOD,SAAOE;IAApB,UAAA,CACE,oBAAC,MAAD;KAAM,OAAOF,SAAOG;KAClB,UAAA,oBAAC,OAAD;MACE,QAAO;MACP,oBAAmB;MACnB,MAAK;MACL,OAAOnB;MACP,eAAeoB,SAASnB,gBAAgBL,iBAAiBwB,IAAI,CAAC;MAC9D,iBAAiBb;MACjB,aAAY;MACZ,gBAAe;MACf,aAAa;MACb,eAAc;KAAI,CAAA;IAEhB,CAAA,GACN,oBAAC,QAAD;KAAQ,QAAO;KAAoB,SAAQ;KAAU,MAAK;KAAK,SAASA;KACrEP,UAAAA,QAAQqB,KAAK,MAAM,KAAK,eAAe;IAClC,CAAA,CACJ;;GACN,oBAAC,SAAD;IACE,SAAS,oBAAC,YAAD;KAAY,MAAM;KAAI,OAAOf,YAAYgB,KAAAA,IAAY,UAAU;IAAM,CAAA;IAC9E,OAAOzB,kBAAkBK,KAAKE,gBAAgB;IAC9C,aAAY;IACZ,YAAA;IACA,oBAAoB,WAAWP,kBAAkBK,KAAKE,gBAAgB;IACtE,eAAeM,cAAc,IAAI;GAAE,CAAA;GAEpCJ,YAAYgB,KAAAA,IACX,oBAAC,MAAD;IAAM,OAAON,SAAOO;IAAM,UAAA;GAAgD,CAAA,IAE1E,oBAAC,MAAD;IAAM,mBAAkB;IAAQ,QAAO;IAAwB,OAAOP,SAAOV;IAC1EA,UAAAA;GACG,CAAA;GAER,oBAAC,OAAD;IAAO,MAAMG;IAAY,cAAcC;IACrC,UAAA,qBAAC,cAAD,EAAA,UAAA;KACE,oBAAC,aAAD;MAAa,YAAW;MACtB,UAAA,oBAAC,YAAD,EAAA,UAAY,UAAmB,CAAA;KACpB,CAAA;KACb,qBAAC,WAAD,EAAA,UAAA,CACE,oBAAC,MAAD,EAAA,UACGK,QAAQS,KAAKC,WACZ,oBAAC,SAAD;MAEE,OAAOA,WAAW,KAAK,sBAAsB5B,kBAAkB4B,QAAQrB,gBAAgB;MACvF,aAAaqB,WAAW,KAAMrB,oBAAoB,+BAAgCqB;MAClF,UAAUA,WAAWvB;MACrB,eAAeW,KAAKY,MAAM;KAAE,GAJvBA,MAIuB,CAE/B,EACG,CAAA,GACN,oBAAC,OAAD;MACE,QAAO;MACP,oBAAmB;MACnB,OAAOd;MACP,eAAeS,SAASR,QAAQhB,iBAAiBwB,IAAI,CAAC;MACtD,uBAAuB;OACrB,IAAIT,KAAKU,KAAK,MAAM,IAAIR,KAAKF,KAAKU,KAAK,CAAC;MAC1C;MACA,aAAY;MACZ,gBAAe;MACf,aAAa;MACb,eAAc;KAAM,CAAA,CAEb,EAAA,CAAA;KACX,oBAAC,aAAD,EAAA,UAAa,uDAAiE,CAAA;IAClE,EAAA,CAAA;GACT,CAAA;EACH;;AAEV;AAEA,MAAML,WAAStB,WAAWgC,QAAQC,WAA0B;CAC1DV,KAAK;EAAEW,KAAKD,MAAME,QAAQ,GAAG;EAACC,mBAAA,CAAA,CAAA;CAAC;CAC/BZ,MAAM;EAAEa,eAAe;EAAOC,YAAY;EAAUJ,KAAKD,MAAME,QAAQ,CAAC;EAACC,mBAAA,CAAA,CAAA;CAAC;CAC1EX,MAAM,EAAEc,MAAM,EAAE;CAChBV,MAAM;EACJW,OAAOP,MAAMQ,OAAOC;EACpBC,YAAYtD,OAAO4C,MAAMU,WAAWC,IAAI;EACxCC,UAAUZ,MAAMY,SAASC;EACzBC,YAAYd,MAAMc,WAAWD;EAAEV,mBAAA,CAAA,CAAA;CACjC;CACAxB,SAAS;EACP4B,OAAOP,MAAMQ,OAAOO;EACpBL,YAAYtD,OAAO4C,MAAMU,WAAWC,IAAI;EACxCC,UAAUZ,MAAMY,SAASC;EACzBC,YAAYd,MAAMc,WAAWD;EAAEV,mBAAA,CAAA,CAAA;CACjC;AACF,EAAE;;;ACtIF,MAAa,eAAe;;;;;;;;;;;;;ACsG5B,MAAa,oBAAoB;CAC/B,OAAO;CACP,MAAM;CACN,YAAY;CACZ,cAAc;CACd,MAAM;CACN,YAAY;AACd;;;;;;;;;;;;;;;;;AC3FA,MAAM,SAAS;CACb,KAAK;EACH,QAAQ;EACR,MAAM,aAAa,aAAa;EAChC,OAAO;GACL,kBAAkB;GAClB,kBAAkB;GAClB,kBAAkB;GAClB,kBAAkB;EACpB;EACA,UAAU,KAAA;CACZ;;;;;;;;CAQA,WAAW;EACT,QAAQ;EACR,MAAM,aAAa,aAAa;EAChC,OAAO,CAAC,kBAAkB,IAAI;EAC9B,QAAQ;CACV;;CAEA,cAAc;EACZ,QAAQ;EACR,MAAM,aAAa,aAAa;EAChC,OAAO,CAAC,kBAAkB,IAAI;EAC9B,QAAQ;CACV;;CAEA,SAAS;EACP,QAAQ;EACR,MAAM,aAAa,aAAa;EAChC,OAAO,CAAC,kBAAkB,IAAI;EAC9B,UAAU,KAAA;CACZ;CACA,YAAY;EACV,QAAQ;EACR,MAAM,aAAa,aAAa;EAChC,OAAO,CAAC,kBAAkB,MAAM,kBAAkB,UAAU;EAC5D,UAAU,KAAA;CACZ;CACA,OAAO;EACL,QAAQ;EACR,MAAM,aAAa,aAAa;CAClC;AACF;AC5DA,MAAa,MAAM,gBAAgB,QAAQ;CACzC,QAAQ,CAHgB,SAGhB;CACR,UAAU;CACV,WAAW;CACX,gBAAgB;AAClB,CAAC;;;ACSD,MAAM,cAAc;AAEpB,SAAS,SAAS,OAAkD;CAClE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;;AAGA,eAAsB,eACpB,WACA,OACA,SAA+B,CAAC,GAChC,QAC0B;CAC1B,MAAM,SAAS,MAAM,IAAI,QAAQ,SAAS,CAAC,CAAC,IAAI;EAC9C,QAAQ,GAAG,eAAe,MAAM;EAGhC,OAAO;IACJ,kBAAkB,QAAQ,OAAO;IACjC,kBAAkB,OAAO,OAAO,SAAS,KAAK,KAAA,IAAY,OAAO;IACjE,kBAAkB,aAAa,OAAO,eAAe,OAAO,OAAO,KAAA;IACnE,kBAAkB,eAAe,OAAO;EAC3C;EACA,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO;CAC3C,CAAC;CACD,IAAI,CAAC,OAAO,IAAI;EAId,IAAI,OAAO,WAAW,GAAG,OAAO,EAAE,OAAO,QAAQ,YAAY,OAAO,KAAK,YAAY;EACrF,OAAO,EAAE,OAAO,OAAO,UAAU,KAAK,oBAAoB,OAAO,OAAO,MAAM,EAAE,KAAK,OAAO,MAAM;CACpG;CACA,IAAI,CAAC,SAAS,OAAO,IAAI,KAAK,OAAO,OAAO,KAAK,SAAS,UACxD,OAAO,EAAE,OAAO,oBAAoB,OAAO,OAAO,MAAM,EAAE,GAAG;CAE/D,OAAO,EAAE,OAAO,OAAO,KAAK;AAC9B;;;ACrDA,SAAgB,WAAW,WAA0B;CACnD,MAAM,YAAY,aAAa,aAAyB;EACtD,MAAM,eAAe,QAAQ,MAAM,UAAU,QAAQ;EACrD,aAAa,aAAa,YAAY;CACxC,GAAG,CAAC,CAAC;CACL,OAAO,qBAAqB,iBAAiB,QAAQ,OAAO,QAAQ,MAAM,OAAO,SAAS,CAAC;AAC7F;;AAGA,SAAgB,cAAc,WAA0B,OAAe,SAAkB;CACvF,MAAM,CAAC,MAAM,WAAW,SAAuC;CAC/D,gBAAgB;EACd,IAAI,cAAc,QAAQ,CAAC,SAAS;EACpC,MAAM,aAAa,IAAI,gBAAgB;EACvC,IAAI;EACJ,MAAM,OAAO,YAAY;GACvB,IAAI;IACF,MAAM,SAAS,MAAM,eAAe,WAAW,OAAO,EAAE,OAAO,EAAE,GAAG,WAAW,MAAM;IACrF,IAAI,WAAW,OAAO,SAAS;IAC/B,IAAI,WAAW,QAAQ;KACrB,MAAM,OAAO,OAAO,MAAM,KACvB,MAAM,IAAI,CAAC,CACX,KAAK,SAAS,KAAK,KAAK,CAAC,CAAC,CAC1B,OAAO,OAAO,CAAC,CACf,GAAG,EAAE;KACR,IAAI,SAAS,KAAA,GAAW,QAAQ;MAAE,IAAI,GAAG,UAAU,GAAG;MAAS;KAAK,CAAC;KACrE,IAAI,CAAC,OAAO,MAAM,SAAS;IAC7B;GACF,QAAQ,CAER;GACA,IAAI,CAAC,WAAW,OAAO,SAAS,QAAQ,iBAAiB,KAAK,KAAK,GAAG,GAAK;EAC7E;EACA,KAAU;EACV,aAAa;GACX,WAAW,MAAM;GACjB,aAAa,KAAK;EACpB;CACF,GAAG;EAAC;EAAW;EAAO;CAAO,CAAC;CAC9B,OAAO,WAAW,MAAM,OAAO,GAAG,UAAU,GAAG,UAAU,KAAK,OAAO,KAAA;AACvE;;;;AC9BA,SAAgBiC,gBAAgB,EAC9BC,KACAC,MACAC,kBACAC,UAMC;CACD,MAAMC,QAAQX,YAAYO,GAAG;;CAE7B,MAAM,CAACK,aAAaC,kBAAkBlB,SAAS,KAAK;CACpD,OACE,qBAAA,UAAA,EAAA,UAAA,CACE,qBAAC,MAAD;EAAM,OAAOmB,SAAOC;EAApB,UAAA;GACE,oBAAC,MAAD;IAAM,eAAe;IAAG,OAAOD,SAAOE;IACnCR,UAAAA;GACG,CAAA;GACN,oBAAC,aAAD;IAAa,MAAMG,MAAMM;IAAON,UAAAA,MAAMO;GAAmB,CAAA;GACzD,oBAAC,MAAD,EAAM,OAAOJ,SAAOK,KAAK,CAAA;GACxBT;EACG;CACLH,CAAAA,GAAAA,MACC,qBAAC,WAAD;EACE,QAAO;EACP,mBAAkB;EAClB,oBAAoB,EAAEa,UAAUR,YAAY;EAC5C,mBAAmBA,cAAc,0BAA0B;EAC3D,OAAOE,SAAOO;EACd,eAAeR,gBAAgBS,SAAS,CAACA,IAAI;EAN/C,UAAA,CAQE,qBAAC,MAAD;GAAM,YAAYV;GAAa,eAAeA,cAAcW,KAAAA,IAAY;GAAG,OAAOT,SAAOU;GAAzF,UAAA,CACE,oBAAC,MAAD;IAAM,OAAOV,SAAOW;IAAQ,UAAA;GAAQ,CAAA,GACnClB,IAAIiB,OACD;EACLZ,CAAAA,GAAAA,cACC,qBAAC,MAAD;GAAM,eAAe;GAAG,OAAOE,SAAOY;GAAtC,UAAA,CAA6C,OACvCzB,kBAAkBM,IAAIoB,KAAKlB,gBAAgB,CAC3C;EACJ,CAAA,IAAA,IACK;CAEX,CAAA,IAAA,oBAAC,MAAD;EAAM,OAAOK,SAAOc;EAAM,UAAA;CAA+C,CAAA,CAE7E,EAAA,CAAA;AAEJ;AAEA,SAAgBC,aAAatB,KAAoB;CAC/C,OAAO;EACLuB,IAAI,cAAcvB,IAAIuB;EACtBZ,OAAO,SAASX,IAAIC;EACpBuB,QAAQC,UAA8B,oBAAC,gBAAD;GAAgB,GAAIA;GAAO,OAAOzB,IAAIuB;EAAG,CAAA;CACjF;AACF;AAEA,SAAgBG,eAAe,EAAEC,WAAWC,OAAOC,oBAA4D;CAC7G,MAAMC,UAAUhC,WAAW6B,SAAS;CACpC,MAAM3B,MAAM8B,QAAQC,KAAKC,MAAMC,cAAcA,UAAUV,OAAOK,KAAK;CACnE,MAAM,CAACM,OAAOC,YAAY/C,SAAS,EAAE;CACrC,MAAM,CAACgD,OAAOC,YAAYjD,SAAS,EAAE;CACrC,MAAM,CAACkD,YAAYC,iBAAiBnD,SAAS,KAAK;CAClD,MAAM,CAACoD,SAASC,cAAcrD,SAAS,CAAC;CACxC,MAAM,CAACsD,WAAWC,gBAAgBvD,SAAS,IAAI;CAC/C,MAAMwD,aAAa,GAAGjB,UAAS,GAAIC,MAAK,GAAIQ,MAAK,GAAIE,WAAU,GAAIE,QAAO,GAAIE;CAC9E,MAAM,CAACG,QAAQC,aAAa1D,SAAoE;CAChG,MAAM4D,QAAQH,QAAQE,QAAQH,aAAaC,OAAOG,QAAQhC,KAAAA;CAC1D,MAAMiC,QAAQJ,QAAQE,QAAQH,aAAaC,OAAOI,QAAQ;CAC1D9D,gBAAgB;EACd,MAAM+D,QAAQC,iBAAiBd,SAASH,KAAK,GAAG,GAAG;EACnD,aAAakB,aAAaF,KAAK;CACjC,GAAG,CAAChB,KAAK,CAAC;CACV/C,gBAAgB;EACd,IAAIwC,cAAc,MAAM;EACxB,MAAM0B,aAAa,IAAIC,gBAAgB;EACvC,IAAIJ;EACJ,MAAMM,OAAO,YAAY;GACvB,MAAMC,SAAS,MAAM7D,eACnB+B,WACAC,OACA;IAAE8B,OAAO;IAAMC,MAAMvB;IAAOE;IAAYsB,cAAcpB;GAAQ,GAC9Da,WAAWQ,MACb;GACA,IAAIR,WAAWQ,OAAOC,SAAS;GAC/BhB,UACE,WAAWW,SACP;IAAEV,KAAKH;IAAYK,OAAOQ,OAAOR;GAAM,IACvC;IAAEF,KAAKH;IAAYI,OAAOS,OAAOT;IAAOC,OAAO;GAAG,CACxD;GACA,IAAIP,aAAaN,UAAU,OAAO,WAAWqB,UAAUA,OAAOT,MAAMe,UAClEb,QAAQC,iBAAiB,KAAKK,KAAK,GAAG,GAAK;EAC/C;EACA,KAAU;EACV,aAAa;GACXH,WAAWW,MAAM;GACjBZ,aAAaF,KAAK;EACpB;CACF,GAAG;EAACvB;EAAWC;EAAOQ;EAAOE;EAAYE;EAASE;EAAWE;CAAU,CAAC;CACxE,MAAMc,QAAQlE,aAAawD,OAAOiB,QAAQ,IAAI,CAAA,GAAI,GAAI,CAAC,CAACP;CACxD,MAAMQ,UAAU9B,UAAU,KAAKzC,gBAAgBqD,OAAOmB,cAAc,GAAGT,MAAMU,MAAM,IAAKpB,OAAOqB,eAAe,CAAA;CAC9G,MAAMC,SAASC,OAAOL,QAAQM,GAAG,EAAE,KAAK,CAAC,CAAC,CAACJ;CAC3C,MAAMK,WAAW3C,QAAQ4C,cAAcC,SAAS/C,KAAK;CACrD,MAAMgD,OAAOlC,aAAaN,UAAU,MAAMY,OAAOe,YAAY;CAC7D,OACE,qBAAC,MAAD;EAAM,QAAO;EAAmB,OAAOxD,SAAOiB;EAA9C,UAAA;GACE,oBAAC,iBAAD;IACOxB;IACL,MAAMA,KAAKC,QAAQ2B;IACnB,kBAAkBE,QAAQ5B;IAC1B,QACEF,KAAK6E,UAAU,aAAalD,cAAc,OACxC,oBAAC,QAAD;KACE,SAAS8C,WAAW,YAAY;KAChC,MAAK;KACL,UAAUA;KACV,eAAe5E,kBAAkBgC,kBAAkBF,WAAWC,KAAK;KAElE6C,UAAAA,WAAW,cAAc;IACpB,CAAA,IACN;GACL,CAAA;GAEH,oBAAC,OAAD;IACE,QAAO;IACP,oBAAmB;IACnB,aAAY;IACZ,OAAOvC;IACP,cAAcC;IACd,gBAAe;IACf,eAAc;GAAQ,CAAA;GAExB,qBAAC,MAAD;IAAM,OAAO5B,SAAOuE;IAApB,UAAA;KACE,oBAAC,QAAD;MACE,SAASxC,aAAa,WAAW;MACjC,MAAK;MACL,oBAAoB,EAAEyC,UAAUzC,WAAW;MAC3C,eAAeC,eAAeyC,UAAU,CAACA,KAAK;MAE7C1C,UAAAA,aAAa,aAAa;KACrB,CAAA;KACPF,UAAU,KAAK,OACd,oBAAC,QAAD;MACE,SAASI,UAAU,IAAI,WAAW;MAClC,MAAK;MACL,eAAeC,YAAYuC,UAAWA,UAAU,IAAI,IAAI,CAAE;MAEzD,UAAA,KAAKT,OAAO/B,OAAO,EAAC;KACf,CAAA;KAETJ,UAAU,MAAMY,OAAOe,YAAY,OAClC,oBAAC,QAAD;MACE,SAASa,OAAO,WAAW;MAC3B,MAAK;MACL,oBAAoB,EAAEG,UAAUH,KAAK;MACrC,eAAejC,cAAcqC,UAAU,CAACA,KAAK;MAE5CJ,UAAAA,OAAO,cAAc;KAChB,CAAA,IACN;IACA;;GACN,oBAAC,MAAD;IAAM,OAAOrE,SAAOc;IACjB2B,UAAAA,UAAUhC,KAAAA,IACPiC,UAAU,KACR,aACA,KACFb,UAAU,KACR,GAAGY,MAAMiC,UAAS,eAAgBjC,MAAMmB,WAAU,UAClD,GAAGS,OAAO,YAAY,UAAS,QAASlB,MAAMU,OAAM,MAAOpB,MAAMmB,WAAU;GAC7E,CAAA;GACN,oBAAC,YAAD;IAAY,OAAO5D,SAAO2E;IAAK,uBAAuB3E,SAAO4E;IAC1DlC,UAAAA,UAAU,KACT,oBAAC,MAAD;KAAM,mBAAkB;KAAQ,OAAO1C,SAAO0C;KAC3CA,UAAAA;IACG,CAAA,IACJD,OAAOoC,WAAW,QACpB,oBAAC,MAAD;KAAM,OAAO7E,SAAOc;KAAM,UAAA;IAA4C,CAAA,IACpE2B,SAASU,MAAMU,WAAW,IAC5B,oBAAC,MAAD;KAAM,OAAO7D,SAAOc;KAAOe,UAAAA,UAAU,KAAK,sBAAsB;IAAyB,CAAA,IAEzFsB,MAAM2B,KAAKC,MAAMC,UACf,qBAAC,MAAD;KAAM,YAAA;KAA8C,OAAOhF,SAAO+E;KAAlE,UAAA,CACE,oBAAC,MAAD;MAAM,OAAO/E,SAAOiF;MAAS,UAAA,GAAGjB,OAAOL,QAAQqB,UAAU,EAAE,CAAC,CAACE,SAASnB,MAAM,EAAC;KAAW,CAAA,GACvFgB,IACG;IAHgB,GAAA,GAAGpB,QAAQqB,UAAUA,OAGrC,CACP;GAEO,CAAA;GACZ,oBAAC,MAAD;IAAM,YAAA;IAAW,eAAe;IAAG,eAAc;IAAS,OAAOhF,SAAOmF;IACrE1F,UAAAA,KAAK2F,WAAW3C,OAAO0C,QAAQ;GAC5B,CAAA;EACF;;AAEV;AACA,MAAMnF,WAASlB,WAAWuG,QAAQC,WAA0B;CAC1DrE,OAAO;EAAEsE,MAAM;EAAGC,KAAKF,MAAMG,QAAQ,CAAC;EAAGC,SAASJ,MAAMG,QAAQ,CAAC;EAAGE,iBAAiBL,MAAMM,OAAOC;EAAEC,mBAAA,CAAA,CAAA;CAAC;CACrG7F,QAAQ;EAAE8F,eAAe;EAAOC,YAAY;EAAUR,KAAKF,MAAMG,QAAQ,CAAC;EAAGQ,WAAW;EAAEH,mBAAA,CAAA,CAAA;CAAC;CAC3FzF,MAAM,EAAEkF,MAAM,EAAE;CAChBrF,OAAO;EACLgG,YAAY;EACZC,OAAOb,MAAMM,OAAOQ;EACpBC,YAAY;EACZC,YAAYhI,OAAOgH,MAAMgB,WAAWC,IAAI;EACxCC,UAAUlB,MAAMkB,SAASC;EAAIX,mBAAA,CAAA,CAAA;CAC/B;CACAvF,YAAY;EACViF,KAAKF,MAAMG,QAAQ,CAAC;EACpBiB,mBAAmBpB,MAAMG,QAAQ,CAAC;EAClCkB,iBAAiBrB,MAAMG,QAAQ,CAAC;EAChCmB,cAActB,MAAMsB,aAAaC;EACjClB,iBAAiBL,MAAMM,OAAOkB;EAAIhB,mBAAA,CAAA,CAAA;CACpC;CACApF,SAAS;EAAEyF,OAAOb,MAAMM,OAAOQ;EAAIE,YAAYhI,OAAOgH,MAAMgB,WAAWS,IAAI;EAAGP,UAAUlB,MAAMkB,SAASQ;EAAElB,mBAAA,CAAA,CAAA;CAAC;CAC1GnF,QAAQ;EAAEwF,OAAOb,MAAMM,OAAOqB;EAAKnB,mBAAA,CAAA,CAAA;CAAC;CACpClF,QAAQ;EAAEuF,OAAOb,MAAMM,OAAOsB;EAAKZ,YAAYhI,OAAOgH,MAAMgB,WAAWS,IAAI;EAAGP,UAAUlB,MAAMkB,SAASW;EAAErB,mBAAA,CAAA,CAAA;CAAC;CAC1GhF,MAAM;EACJqF,OAAOb,MAAMM,OAAOsB;EACpBZ,YAAYhI,OAAOgH,MAAMgB,WAAWC,IAAI;EACxCC,UAAUlB,MAAMkB,SAASQ;EACzBI,YAAY9B,MAAM8B,WAAWJ;EAAElB,mBAAA,CAAA,CAAA;CACjC;CACApD,OAAO;EAAEyD,OAAOb,MAAMM,OAAOyB;EAAKf,YAAYhI,OAAOgH,MAAMgB,WAAWC,IAAI;EAAGC,UAAUlB,MAAMkB,SAASQ;EAAElB,mBAAA,CAAA,CAAA;CAAC;CACzGvB,SAAS;EAAEwB,eAAe;EAAOP,KAAKF,MAAMG,QAAQ,CAAC;EAAG6B,UAAU;EAAMxB,mBAAA,CAAA,CAAA;CAAC;CACzEnB,KAAK;EAAEY,MAAM;EAAGqB,cAActB,MAAMsB,aAAaC;EAAIlB,iBAAiBL,MAAMM,OAAOkB;EAAIhB,mBAAA,CAAA,CAAA;CAAC;CACxFlB,SAAS;EAAEc,SAASJ,MAAMG,QAAQ,CAAC;EAACK,mBAAA,CAAA,CAAA;CAAC;CACrCf,MAAM;EACJoB,OAAOb,MAAMM,OAAOlC;EACpB4C,YAAYhI,OAAOgH,MAAMgB,WAAWS,IAAI;EACxCP,UAAUlB,MAAMkB,SAASW;EACzBC,YAAY9B,MAAM8B,WAAWJ;EAAElB,mBAAA,CAAA,CAAA;CACjC;CACAb,QAAQ;EAAEkB,OAAOb,MAAMM,OAAOqB;EAAKnB,mBAAA,CAAA,CAAA;CAAC;CACpCX,MAAM;EAAEgB,OAAOb,MAAMM,OAAOqB;EAAOX,YAAYhI,OAAOgH,MAAMgB,WAAWS,IAAI;EAAGP,UAAUlB,MAAMkB,SAASW;EAAErB,mBAAA,CAAA,CAAA;CAAC;AAC5G,EAAE;;;;ACpPF,eAAsB,iBACpB,WACA,OACA,MACA,YACA,QAC+B;CAC/B,MAAM,SAAS,MAAM,IAAI,QAAQ,SAAS,CAAC,CAAC,WAAW;EACrD,QAAQ,GAAG,eAAe,MAAM;EAChC,OAAO;IAAG,kBAAkB,OAAO;IAAO,kBAAkB,aAAa;EAAW;EACpF;CACF,CAAC;CACD,IAAI,CAAC,OAAO,IAAI,MAAM,IAAI,MAAM,OAAO,SAAS,sCAAsC;CACtF,OAAO,OAAO;AAChB;AACA,eAAsB,gBAAgB,WAAmB,OAAe,MAA6B;CACnG,MAAM,SAAS,MAAM,IAAI,QAAQ,SAAS,CAAC,CAAC,MAAM;EAAE,QAAQ,GAAG,eAAe,MAAM;EAAG,MAAM,EAAE,KAAK;CAAE,CAAC;CACvG,IAAI,CAAC,OAAO,IAAI,MAAM,IAAI,MAAM,OAAO,SAAS,2CAA2C;AAC7F;;;;ACTA,SAAgBwC,eAAeC,KAAoB;CACjD,OAAO;EACLC,IAAI,gBAAgBD,IAAIC;EACxBC,OAAO,WAAWF,IAAIG;EACtBC,QAAQC,UAA8B,oBAAC,kBAAD;GAAkB,GAAIA;GAAO,OAAOL,IAAIC;EAAG,CAAA;CACnF;AACF;;;;;;AAOA,SAAgBK,iBAAiB,EAC/BC,WACAC,OACAC,sBACAC,kBACAC,oBACyC;CACzC,MAAMC,UAAUhB,WAAWW,SAAS;CACpC,MAAMP,MAAMY,QAAQC,KAAKC,MAAMC,cAAcA,UAAUd,OAAOO,KAAK;CACnE,MAAMQ,OAAOhB,KAAKiB,UAAU;CAC5B,MAAMC,WAAWN,QAAQO,cAAcC,SAASZ,KAAK;CACrD,MAAMa,UAAU/B,cAEZiB,cAAc,OACVe,KAAAA,IACA;EACEC,KAAK,GAAGhB,UAAS,GAAIC;EACrBgB,OAAOC,MAAcC,YAAgCC,WACnDjC,iBAAiBa,WAAWC,OAAOiB,MAAMC,YAAYC,MAAM;EAC7DE,QAAQC,SAAiBnC,gBAAgBY,WAAWC,OAAOsB,IAAI;CACjE,GACN,CAACvB,WAAWC,KAAK,CACnB;CACA,OACE,qBAAC,MAAD;EAAM,OAAOuB,SAAO3B;EAApB,UAAA;GACE,oBAAC,iBAAD;IACOJ;IACL,MAAMA,KAAKG,QAAQK;IACnB,kBAAkBI,QAAQoB;IAC1B,QACEhB,QAAQT,cAAc,OACpB,oBAAC,QAAD;KACE,QAAO;KACP,SAASW,WAAW,YAAY;KAChC,MAAK;KACL,UAAUA;KACV,eAAezB,kBAAkBiB,kBAAkBH,WAAWC,KAAK;KAElEU,UAAAA,WAAW,cAAc;IACpB,CAAA,IACN;GACL,CAAA;GAEH,oBAAC,MAAD;IAAM,OAAOa,SAAOE;IACjBZ,UAAAA,YAAYC,KAAAA,IACX,oBAAC,MAAD;KAAM,OAAOS,SAAOG;KAAM,UAAA;IAAgD,CAAA,IAE1EzB,uBAAuBY,OAAO;GAE5B,CAAA;GACN,qBAAC,MAAD;IAAM,OAAOU,SAAOI;IAApB,UAAA,CACGnC,MACC,qBAAC,QAAD;KACE,QAAO;KACP,SAAQ;KACR,eAAeW,iBAAiBb,aAAaE,GAAG,CAAC;KACjD,OAAO+B,SAAOK;KAJhB,UAAA,CAME,oBAAC,YAAD,EAAY,MAAM,GAAG,CAAA,GAAA,eAEf;IACN,CAAA,IAAA,MACHpB,QAAQT,cAAc,OACrB,oBAAC,QAAD;KACE,QAAO;KACP,SAAQ;KACR,eAAe,KAAKZ,gBAAgBY,WAAWC,OAAO,GAAQ;KAC9D,OAAOuB,SAAOK;KAAO,UAAA;IAGf,CAAA,IACN,IACA;;EACF;;AAEV;AACA,MAAML,WAASxC,WAAW8C,QAAQC,WAA0B;CAC1DlC,OAAO;EAAEmC,MAAM;EAAGC,KAAKF,MAAMG,QAAQ,CAAC;EAAGC,SAASJ,MAAMG,QAAQ,CAAC;EAAGE,iBAAiBL,MAAMM,OAAOC;EAAEC,mBAAA,CAAA,CAAA;CAAC;CACrGX,SAAS;EAAEY,eAAe;EAAOP,KAAKF,MAAMG,QAAQ,CAAC;EAACK,mBAAA,CAAA,CAAA;CAAC;CACvDV,QAAQ,EAAEG,MAAM,EAAE;CAClBN,UAAU,EAAEM,MAAM,EAAE;CACpBL,MAAM;EAAEc,OAAOV,MAAMM,OAAOK;EAAKC,YAAYhE,OAAOoD,MAAMY,WAAWC,IAAI;EAAGC,UAAUd,MAAMc,SAASC;EAAEP,mBAAA,CAAA,CAAA;CAAC;AAC1G,EAAE;;;;AC5FF,SAAS+B,UAAUC,KAAoB;CACrC,OAAOA,IAAIC,cAAcH,eAAeE,GAAG,IAAIH,aAAaG,GAAG;AACjE;AAEA,SAAgBE,aAAa;CAC3B,OAAO;EAAEC,IAAI;EAAeC,OAAO;EAAWC,OAAOC;CAAa;AACpE;AAEA,SAASC,UAAU,EACjBP,KACAQ,OACAC,UACAC,OAMC;CACD,MAAMC,OAAOf,cAAcY,MAAMI,WAAWZ,IAAIG,IAAIH,IAAIa,UAAU,SAAS;CAG3E,OACE,qBAAC,WAAD;EACE,QAAQ,mBAAmBb,IAAIG;EAC/B,mBAAkB;EAClB,oBAAoB,QAAQH,IAAIc;EAChC,eAAeN,MAAMO,iBAAiBhB,UAAUC,GAAG,CAAC;EACpD,QAAQ,EAAEgB,cAAc,CAACC,OAAOC,KAAKF,WAAWC,OAAOD,OAAO;EALhE,UAAA,CAOE,qBAAC,MAAD;GAAM,OAAOC,OAAOE;GAApB,UAAA;IACE,oBAAC,KAAD;KAAK,MAAK;KAAS,OAAA;IAAK,CAAA;IACxB,oBAAC,MAAD;KAAM,eAAe;KAAG,OAAOF,OAAOH;KACnCd,UAAAA,IAAIc;IACD,CAAA;IACN,oBAAC,MAAD;KAAM,OAAOG,OAAOG;KAAO/B,UAAAA,mBAAmBW,IAAIqB,WAAWX,GAAG;IAAQ,CAAA;IACvEF,MAAMI,cAAc,OACnB,oBAAC,QAAD;KACE,QAAQ,wBAAwBZ,IAAIG;KACpC,MAAK;KACL,SAASM,WAAW,YAAY;KAChC,UAAUA;KACV,eAAe;MACb,IAAID,MAAMI,cAAc,MAAMnB,kBAAkBe,MAAMc,kBAAkBd,MAAMI,WAAWZ,IAAIG,EAAE;KACjG;KAECM,UAAAA,WAAW,cAAc;IACpB,CAAA,IACN;GACA;EACN,CAAA,GAAA,oBAAC,MAAD;GAAM,eAAe;GAAG,OAAOQ,OAAON;GACnCA,UAAAA,QAAQ,KAAKX,IAAIuB;EACd,CAAA,CACG;;AAEf;AAEA,SAAgBC,uBAAuBhB,OAA2B;CAChE,MAAMiB,UAAU9B,WAAWa,MAAMI,SAAS;CAC1C,MAAMc,UAAUD,QAAQE,KAAKC,QAAQ5B,QAAQT,wBAAwBS,GAAG,CAAC;CACzE,MAAM,CAACU,KAAKmB,UAAU3C,eAAe4C,KAAKpB,IAAI,CAAC;CAC/C1B,gBAAgB;EACd,MAAM+C,QAAQC,kBAAkBH,OAAOC,KAAKpB,IAAI,CAAC,GAAG,GAAK;EACzD,aAAauB,cAAcF,KAAK;CAClC,GAAG,CAAA,CAAE;CACL,OAAOL,QAAQQ,WAAW,IAExB,qBAAC,MAAD;EAAM,OAAOjB,OAAOkB;EAApB,UAAA,CACE,oBAAC,MAAD;GAAM,OAAOlB,OAAOG;GAAM,UAAA;EAAU,CAAA,GACnCZ,MAAMI,cAAc,OACnB,qBAAC,WAAD;GACE,mBAAkB;GAClB,QAAO;GACP,SAAS;GACT,eAAeJ,MAAMO,iBAAiBb,WAAW,CAAC;GAClD,OAAOe,OAAOmB;GALhB,UAAA,CAOE,oBAAC,MAAD;IAAM,OAAOnB,OAAOoB;IAAY,UAAA;GAAqB,CAAA,GACrD,oBAAC,gBAAD;IAAgB,MAAM;IAAI,OAAM;GAAO,CAAA,CAC9B;EACT,CAAA,IAAA,IACA;CAEN,CAAA,IAAA,oBAAC,MAAD,EAAA,UACGX,QAAQY,KAAKtC,QACZ,oBAAC,WAAD;EAA6BA;EAAYQ;EAAYE;EAAK,UAAUe,QAAQc,cAAcC,SAASxC,IAAIG,EAAE;CAAE,GAA3FH,IAAIG,EAAuF,CAC5G,EACG,CAAA;AAEV;;;;;;;AAQA,SAAgBG,aAAaE,OAA2B;CACtD,MAAM,EAAEO,qBAAqBP;CAC7B,MAAMiB,UAAU9B,WAAWa,MAAMI,SAAS;CAC1C,MAAMc,UAAUD,QAAQE,KAAKC,QAAQ5B,QAAQA,IAAIa,UAAU,SAAS;CACpE,MAAM,CAACU,SAASkB,cAAcvD,SAAS,EAAE;CACzC,MAAM,CAACwD,KAAKC,UAAUzD,SAAS,EAAE;CACjC,MAAM,CAACwB,KAAKmB,UAAU3C,eAAe4C,KAAKpB,IAAI,CAAC;CAC/C,MAAMkC,WAAW3D,OAAmC,IAAI;;CAExD,MAAM6D,WAAW7D,OAAO,EAAE;CAC1B,MAAM8D,UAAU9D,OAAkDiE,KAAAA,CAAS;CAC3ElE,gBAAgB;EACd,MAAM+C,QAAQC,kBAAkBH,OAAOC,KAAKpB,IAAI,CAAC,GAAG,GAAM;EAC1D,aAAauB,cAAcF,KAAK;CAClC,GAAG,CAAA,CAAE;CAGL/C,gBAAgB;EACd,IAAI4D,SAASO,YAAY,MAAM;EAC/B,MAAMC,UAAU3B,QAAQE,KAAK0B,MAAMrD,QAAQA,IAAIa,UAAU,aAAa,CAAC+B,SAASO,SAASG,IAAItD,IAAIG,EAAE,CAAC;EACpG,IAAIiD,YAAYF,KAAAA,GAAW;EAC3BN,SAASO,UAAU;EACnBI,aAAaR,QAAQI,OAAO;EAC5BpC,iBAAiBhB,UAAUqD,OAAO,CAAC;CACrC,GAAG,CAAC3B,QAAQE,MAAMZ,gBAAgB,CAAC;CAEnC,MAAMyC,YAAY/B,QAAQgC,cAActD;CACxCnB,gBAAgB;EACd,IAAIwE,cAAcN,KAAAA,KAAaN,SAASO,YAAY,MAAM;EAC1DP,SAASO,UAAU;EACnBI,aAAaR,QAAQI,OAAO;EAC5BV,WAAWK,SAASK,OAAO;CAC7B,GAAG,CAACK,SAAS,CAAC;CACdxE,sBAAsBuE,aAAaR,QAAQI,OAAO,GAAG,CAAA,CAAE;CACvD,MAAMf,eAAe;EACnB,IAAI5B,MAAMI,cAAc,MAAM;EAC9BgC,SAASO,UAAU,IAAIO,IAAIjC,QAAQE,KAAKW,KAAKtC,QAAQA,IAAIG,EAAE,CAAC;EAC5DoD,aAAaR,QAAQI,OAAO;EAC5BJ,QAAQI,UAAUF,iBAAiB;GACjCL,SAASO,UAAU;EACrB,GAAG,GAAM;EACT3D,mBAAmBgB,MAAMc,kBAAkBd,MAAMI,WAAWtB,iBAAiBiC,SAASmB,GAAG,CAAC;EAC1FI,SAASK,UAAU5B;EACnBkB,WAAW,EAAE;CACf;CACA,OACE,qBAAC,MAAD;EAAM,OAAOxB,OAAOZ;EAApB,UAAA;GACE,qBAAC,MAAD;IAAM,OAAOY,OAAO0C;IAApB,UAAA,CACE,oBAAC,MAAD;KAAM,OAAO1C,OAAO2C;KAAO,UAAA;IAAa,CAAA,GACxC,oBAAC,MAAD;KAAM,OAAO3C,OAAOG;KAAOM,UAAAA,QAAQQ,WAAW,IAAI,oBAAoB,GAAGR,QAAQQ,OAAM;IAAiB,CAAA,CACpG;;GACL1B,MAAMI,cAAc,OACnB,oBAAC,kBAAD;IACWW;IACT,iBAAiBkB;IACZC;IACL,aAAaC;IACb,SAASjB,QAAQY,KAAKtC,QAAQA,IAAI0C,GAAG;IACrC,GAAKjB,QAAQoC,qBAAqBX,KAAAA,IAAY,CAAC,IAAI,EAAEW,kBAAkBpC,QAAQoC,iBAAiB;IAChG,GAAKpC,QAAQgC,iBAAiBP,KAAAA,IAAY,CAAC,IAAI,EAAEY,SAASrC,QAAQgC,aAAaM,QAAQ;IACvF,UAAU3B;GAAO,CAAA,IAEjB;GACJ,oBAAC,YAAD,EAAA,UACGV,QAAQQ,WAAW,IAClB,oBAAC,MAAD;IAAM,OAAOjB,OAAOG;IACjBZ,UAAAA,MAAMI,cAAc,OACjB,sCACA;GACA,CAAA,IAENc,QAAQY,KAAKtC,QACX,oBAAC,SAAD;IAEE,SAAS,oBAAC,KAAD;KAAK,MAAK;KAAS,OAAA;IAAK,CAAA;IACjC,OAAOA,IAAIc;IACX,aAAa,GAAGd,IAAIuB,QAAO,KAAMlC,mBAAmBW,IAAIqB,WAAWX,GAAG;IACtE,YAAA;IACA,eAAeK,iBAAiBhB,UAAUC,GAAG,CAAC;GAAE,GAL3CA,IAAIG,EAKuC,CAEnD,EAEO,CAAA;EACR;;AAEV;AACA,MAAMc,SAAS9B,WAAW6E,QAAQC,WAA0B;CAC1D5D,OAAO;EAAE6D,MAAM;EAAGC,KAAKF,MAAMG,QAAQ,CAAC;EAAGC,SAASJ,MAAMG,QAAQ,CAAC;EAAGE,iBAAiBL,MAAMM,OAAOC;EAAEC,mBAAA,CAAA,CAAA;CAAC;CACrGd,QAAQ;EAAEe,eAAe;EAAOC,YAAY;EAAUR,KAAKF,MAAMG,QAAQ,CAAC;EAACK,mBAAA,CAAA,CAAA;CAAC;CAC5EvD,KAAK;EAAEiD,KAAKF,MAAMG,QAAQ,CAAC;EAAGQ,iBAAiBX,MAAMG,QAAQ,CAAC;EAACK,mBAAA,CAAA,CAAA;CAAC;CAChEzD,SAAS,EAAE6D,SAAS,GAAI;CACxB1D,MAAM;EAAEuD,eAAe;EAAOC,YAAY;EAAUR,KAAKF,MAAMG,QAAQ,CAAC;EAACK,mBAAA,CAAA,CAAA;CAAC;CAC1E3D,MAAM;EACJoD,MAAM;EACNY,OAAOb,MAAMM,OAAOQ;EACpBC,YAAYrG,OAAOsF,MAAMe,WAAWC,IAAI;EACxCC,UAAUjB,MAAMiB,SAASC;EACzBC,YAAYnB,MAAMmB,WAAWD;EAC7BE,YAAYpB,MAAMoB,WAAWC;EAAMb,mBAAA,CAAA,CAAA;CACrC;CACA9D,MAAM;EAEJ4E,aAAatB,MAAMG,QAAQ,GAAG;EAC9BU,OAAOb,MAAMM,OAAOiB;EACpBR,YAAYrG,OAAOsF,MAAMe,WAAWS,IAAI;EACxCP,UAAUjB,MAAMiB,SAASQ;EACzBN,YAAYnB,MAAMmB,WAAWM;EAAEjB,mBAAA,CAAA,CAAA;CACjC;CACAb,OAAO;EACLkB,OAAOb,MAAMM,OAAOQ;EACpBC,YAAYrG,OAAOsF,MAAMe,WAAWC,IAAI;EACxCC,UAAUjB,MAAMiB,SAASS;EACzBN,YAAY;EAAKZ,mBAAA,CAAA,CAAA;CACnB;CACArD,MAAM;EACJ0D,OAAOb,MAAMM,OAAOiB;EACpBR,YAAYrG,OAAOsF,MAAMe,WAAWC,IAAI;EACxCC,UAAUjB,MAAMiB,SAASQ;EACzBN,YAAYnB,MAAMmB,WAAWM;EAAEjB,mBAAA,CAAA,CAAA;CACjC;CACAtC,MAAM;EAAEuC,eAAe;EAAOC,YAAY;EAAUiB,UAAU;EAAQzB,KAAKF,MAAMG,QAAQ,CAAC;EAACK,mBAAA,CAAA,CAAA;CAAC;CAC5FrC,QAAQ;EAAEsC,eAAe;EAAOC,YAAY;EAAUR,KAAKF,MAAMG,QAAQ,CAAC;EAACK,mBAAA,CAAA,CAAA;CAAC;CAC5EpC,YAAY;EACVyC,OAAOb,MAAMM,OAAOsB;EACpBb,YAAYrG,OAAOsF,MAAMe,WAAWC,IAAI;EACxCC,UAAUjB,MAAMiB,SAASC;EACzBC,YAAYnB,MAAMmB,WAAWD;EAC7BE,YAAYpB,MAAMoB,WAAWC;EAAMb,mBAAA,CAAA,CAAA;CACrC;AACF,EAAE;;;AC5OF,IAAA,yBAAe,oBAAoB;CACjC,MAAM;CACN,MAAM;CACN,YAAY,cAAc,cAAc;CACxC,cAAc;CACd,cAAc;CACd,OAAO;AACT,CAAC;;;ACXD,IAAA,6BAAe,kBAAkB,iBAAiB;;;ACClD,IAAA,0CAAe,WAAW;CAAE,MAAM;CAAoB,IAAI;CAAW,WAAW;AAAuB,CAAC;;;ACGxG,MAAM,OAAU,UAAmC,UAChD,UAAU,KAAA,IAAY,KAAA,IAAY;CAAE,GAAG;CAAU,GAAI;AAAiB;AAEzE,MAAa,eAAe,mBAAmB;CAC7C,IAAI;CACJ,SAAS;EACP,IAAI,iBAA2D;GAAE,OAAO,CAAC,IAAI,EAAE,MAAM,UAAU,GAAGqB,sBAAoB,CAAC;EAAG;EAC1H,IAAI,WAA+C;GAAE,OAAO,CAAC,IAAI,EAAE,SAAS,cAAc,GAAGC,0BAAiB,CAAC;EAAG;EAClH,IAAI,QAAyC;GAAE,OAAO,CAAC,IAAI;IAAE,MAAM;IAAoB,IAAI;GAAU,GAAGC,uCAAW,CAAC;EAAG;CACzH;AACF,CAAC"}
1
+ {"version":3,"file":"native.mjs","names":["isRecord","Button","FolderIcon","fontOf","Input","ListRow","Sheet","SheetBody","SheetContent","SheetFooter","SheetHeader","SheetTitle","PoNativeTheme","useState","StyleSheet","RunnerCommandBarProps","plainPunctuation","runnerFolderLabel","runnerFolders","RunnerCommandBar","command","onCommandChange","cwd","onCwdChange","sessionDirectory","folders","problem","onLaunch","defaultFolderOpen","folderOpen","setFolderOpen","path","setPath","pick","next","choices","styles","bar","line","grow","text","trim","undefined","meta","map","folder","create","theme","gap","spacing","uni__dependencies","flexDirection","alignItems","flex","color","colors","dim","fontFamily","sans","fontSize","sm","lineHeight","red","styles","useCallback","useEffect","useState","useSyncExternalStore","AppState","fetchRunnerLog","runners","useRunners","sessionId","subscribe","listener","subscription","store","unsubscribe","select","state","useRunnerForeground","addEventListener","remove","currentState","useRunnerClock","active","interval","now","setNow","Date","timer","ReturnType","setInterval","update","clearInterval","useRunnerTail","runId","running","foreground","tail","setTail","id","text","controller","AbortController","setTimeout","read","result","lines","signal","aborted","slice","split","map","line","trim","filter","Boolean","at","undefined","abort","clearTimeout","WebPluginSlotProps","fontOf","Button","Input","StatusBadge","PoNativeTheme","memo","ReactNode","useCallback","useEffect","useMemo","useState","StyleSheet","RunnerLogResponse","RunnerRunView","logViewLines","runnerBadge","runnerFolderLabel","tailLineNumbers","fetchRunnerLog","requestRunnerStop","useRunners","useRunnerForeground","RunnerRunHeader","run","name","sessionDirectory","action","badge","commandOpen","setCommandOpen","styles","header","title","tone","label","grow","expanded","commandBox","open","undefined","command","prompt","folder","cwd","meta","runnerLogTab","id","panel","props","RunnerLogPanel","sessionId","runId","sendSessionFrame","session","foreground","runs","find","candidate","typed","setTyped","query","setQuery","ignoreCase","setIgnoreCase","context","setContext","following","setFollowing","requestKey","loaded","setLoaded","key","slice","error","timer","setTimeout","clearTimeout","controller","AbortController","ReturnType","read","result","lines","grep","contextLines","signal","aborted","previous","next","before","after","equal","text","totalLines","lineCount","fileSize","completeBytes","path","exists","truncated","running","lineNumbers","length","every","number","index","abort","stopping","stopRequested","includes","live","state","actions","selected","value","String","logPath","RunnerLogOutput","rows","numbers","gutter","at","map","padStart","renderItem","item","line","keyExtractor","empty","log","logBody","create","theme","flex","gap","spacing","padding","backgroundColor","colors","bg","uni__dependencies","flexDirection","alignItems","minHeight","flexShrink","color","hi","fontWeight","fontFamily","sans","fontSize","base","paddingHorizontal","paddingVertical","borderRadius","md","deep","mono","sm","faint","dim","xs","lineHeight","red","flexWrap","styles","WebPluginSlotProps","fontOf","Button","SearchIcon","PoNativeTheme","useMemo","StyleSheet","RunnerRunView","requestRunnerStop","readRunnerScreen","sendRunnerInput","useRunners","RunnerRunHeader","runnerLogTab","runnerShellTab","run","id","label","name","panel","props","RunnerShellPanel","sessionId","runId","renderRunnerTerminal","sendSessionFrame","openTransientTab","session","runs","find","candidate","live","state","stopping","stopRequested","includes","request","undefined","key","read","from","generation","signal","AbortSignal","write","text","styles","sessionDirectory","terminal","meta","actions","action","create","theme","flex","gap","spacing","padding","backgroundColor","colors","bg","uni__dependencies","flexDirection","color","dim","fontFamily","sans","fontSize","sm","styles","WebPluginSlotProps","ArrowRightIcon","fontOf","Button","Dot","ListRow","PoNativeTheme","useEffect","useRef","useState","useSyncExternalStore","StyleSheet","RunnerRunView","formatRunnerUptime","runnerRunRequest","isRunnerActivityVisible","requestRunnerStart","requestRunnerStop","runnerActivitySource","RunnerCommandBar","useRunners","useRunnerTail","useRunnerClock","runnerLogTab","runnerShellTab","runnerTab","run","interactive","runnersTab","id","label","panel","RunnersPanel","RunnerRow","props","stopping","now","tail","sessionId","state","name","openTransientTab","pressed","styles","row","line","meta","startedAt","sendSessionFrame","command","RunnersActivitySection","session","active","subscribe","isActive","running","runs","filter","length","idle","launch","launchText","map","stopRequested","includes","setCommand","cwd","setCwd","baseline","ReadonlySet","launched","timeout","ReturnType","setTimeout","undefined","current","started","find","has","clearTimeout","failureId","startFailure","Set","header","title","sessionDirectory","problem","message","create","theme","flex","gap","spacing","padding","backgroundColor","colors","bg","uni__dependencies","flexDirection","alignItems","paddingVertical","opacity","color","hi","fontFamily","sans","fontSize","base","lineHeight","fontWeight","medium","paddingLeft","dim","mono","sm","lg","flexWrap","green","activityGroupRunners","channelRunnerRuns","fillRunners"],"sources":["../../src/extensions/workspaces/sessions/(frontend)/_lib/format.ts","../../src/extensions/workspaces/sessions/(frontend)/_lib/launchLine.ts","../../src/constants/webRunners.ts","../../src/extensions/workspaces/sessions/(frontend)/_lib/runnersStore.native.ts","../../src/extensions/workspaces/sessions/(frontend)/_components/RunnerCommandBar.native.tsx","../../src/constants/webRunnerLog.ts","../../src/types/webRunnerLog.ts","../../src/types/apiRoutes.ts","../../generated/client.native.ts","../../src/extensions/workspaces/sessions/(frontend)/_lib/logApi.native.ts","../../src/extensions/workspaces/sessions/(frontend)/_components/runnerHooks.native.ts","../../src/extensions/workspaces/sessions/(frontend)/_components/RunnerLogPanel.native.tsx","../../src/extensions/workspaces/sessions/(frontend)/_lib/screenApi.native.ts","../../src/extensions/workspaces/sessions/(frontend)/_components/RunnerShellPanel.native.tsx","../../src/extensions/workspaces/sessions/(frontend)/_components/RunnersPanel.native.tsx","../../src/extensions/workspaces/sessions/(frontend)/activity-group/runners.native.ts","../../src/extensions/workspaces/sessions/(frontend)/channel/runner-runs.native.ts","../../src/extensions/workspaces/sessions/(frontend)/fill/Runners.activity.runners.native.tsx","../../generated/native.ts"],"sourcesContent":["import type { RunnerRunView } from '../../../../../types/webRunners';\n\n/**\n * Local copy of the runtime's formatUptime (src/services/bashResult/index.ts):\n * the web plugin may reach only src/types, so the one helper it needs lives here.\n */\nexport function formatRunnerUptime(startedAt: string, now: number): string {\n const started = Date.parse(startedAt);\n if (Number.isNaN(started)) return 'unknown';\n const seconds = Math.max(0, Math.floor((now - started) / 1000));\n if (seconds < 60) return `${seconds}s`;\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes}m`;\n const hours = Math.floor(minutes / 60);\n return hours < 24 ? `${hours}h` : `${Math.floor(hours / 24)}d`;\n}\n\n/** A bounded log view: what to render, and what the bound left out. */\nexport interface LogView {\n lines: string[];\n /** Lines dropped off the top to stay within the bound. */\n hidden: number;\n}\n\nexport interface LogViewOptions {\n /**\n * Drop the slice's last line because it is a fragment the follow stream will\n * deliver again, whole. Set only while following: a finished run's last line\n * may legitimately lack a newline, and dropping it would hide real output.\n */\n dropPartialTail?: boolean;\n}\n\n/**\n * The lines a log view shows: the slice's text, then whatever the follow\n * stream appended, bounded to the newest `max`.\n *\n * A log file ends with a newline, and the reader hands its text back with that\n * newline intact, so a naive split reports one blank line more than the file\n * has. Dropping exactly one trailing empty entry keeps the count the reader\n * sees equal to the count the server reported.\n */\nexport function logViewLines(\n text: string,\n appended: readonly string[],\n max: number,\n options: LogViewOptions = {},\n): LogView {\n const split = text.split('\\n');\n if (split.length > 0 && split[split.length - 1] === '') split.pop();\n if (options.dropPartialTail === true && split.length > 0) split.pop();\n const all = [...split, ...appended];\n const lines = all.slice(-max);\n return { lines, hidden: all.length - lines.length };\n}\n\n/**\n * Absolute 1-based numbers for a tail, counted back from the last line.\n *\n * A tail is contiguous, so only its end has to be known. Grep results are not\n * contiguous and carry their own numbers from the reader instead.\n */\nexport function tailLineNumbers(lastLineNumber: number, count: number): number[] {\n const first = Math.max(1, lastLineNumber - count + 1);\n return Array.from({ length: count }, (_, index) => first + index);\n}\n\n/**\n * Whether the view is actually following a growing log.\n *\n * Three things must hold: the reader asked to follow, no query is set (a\n * filtered view is a snapshot of the whole file, which a stream cannot\n * assemble a chunk at a time), and the runner is still writing. Without the\n * last one a finished run would claim to be tailing a file nothing will ever\n * append to.\n */\nexport function isFollowingLive(following: boolean, filtering: boolean, running: boolean): boolean {\n return following && !filtering && running;\n}\n\n/**\n * A folder as the command bar names it: the session directory by its last\n * segment, a folder inside it relative to it, anything else as written.\n */\nexport function runnerFolderLabel(folder: string, sessionDirectory: string | undefined): string {\n if (folder === '' || folder === sessionDirectory) {\n return sessionDirectory === undefined\n ? 'session directory'\n : (sessionDirectory.split('/').pop() ?? sessionDirectory);\n }\n if (sessionDirectory !== undefined && folder.startsWith(`${sessionDirectory}/`)) {\n return folder.slice(sessionDirectory.length + 1);\n }\n return folder;\n}\n\n/** The folders the picker offers past the session directory: those in use, then the one in effect. */\nexport function runnerFolders(\n inUse: readonly string[],\n current: string,\n sessionDirectory: string | undefined,\n): string[] {\n const folders = new Set([...inUse, current]);\n folders.delete('');\n if (sessionDirectory !== undefined) folders.delete(sessionDirectory);\n return [...folders];\n}\n\n/**\n * Undoes iOS smart punctuation, which React Native cannot switch off: a shell\n * reads ‘hi’ as literal quotes and a long dash before port as no flag at all.\n */\nexport function plainPunctuation(text: string): string {\n return text\n .replace(/[‘’]/g, \"'\")\n .replace(/[“”]/g, '\"')\n .replace(/\\u2014/g, '--');\n}\n\n/** The badge a run wears: its state while running, then how it ended. */\nexport function runnerBadge(run: RunnerRunView | undefined): {\n tone: 'neutral' | 'running' | 'ok' | 'error';\n label: string;\n} {\n if (run === undefined) return { tone: 'neutral', label: 'gone' };\n if (run.state === 'running') return { tone: 'running', label: 'running' };\n if (run.exit === undefined || run.exit.reason === 'stopped') return { tone: 'neutral', label: 'stopped' };\n const clean = run.exit.reason === 'completed' && (run.exit.code === 0 || run.exit.code === null);\n return clean ? { tone: 'ok', label: 'done' } : { tone: 'error', label: run.exit.reason.replace('_', ' ') };\n}\n","/**\n * The `/runners start` line the runners panel's command bar sends.\n *\n * WHY THE BUILDER LIVES HERE AND THE PARSER DOES NOT:\n * Cockpit code is compiled into the host bundle and may import only this\n * package's own web and type modules, so it cannot share the session's parser\n * in src/services. The two are pinned together by a test that parses what this\n * writes, which is the only guarantee that matters: the line has to survive\n * the trip.\n */\n\nexport const RUNNERS_START_LINE = '/runners start';\n/** A persistent login shell for the direct shell action in Runner Space. */\nexport const RUNNER_SHELL_COMMAND = 'exec \"${SHELL:-/bin/bash}\" -l';\n/** Ends the options and begins the command; the command may hold `=` and flags of its own. */\nexport const RUNNERS_COMMAND_SEPARATOR = '--';\n\nexport interface RunnerLaunchRequest {\n command: string;\n cwd?: string;\n name?: string;\n interactive?: boolean;\n /** A terminal when rmux or tmux is available, plain output otherwise. */\n preferInteractive?: boolean;\n}\n\n/** The no-form launch used when a reader asks for a shell rather than a command. */\nexport const RUNNER_SHELL_REQUEST: RunnerLaunchRequest = {\n command: RUNNER_SHELL_COMMAND,\n name: 'shell',\n interactive: true,\n};\n\n/**\n * What the runners panel's Run sends: the typed command on a terminal when\n * one is available, or a login shell when nothing was typed.\n */\nexport function runnerRunRequest(command: string, cwd: string): RunnerLaunchRequest {\n const where = cwd.trim() === '' ? {} : { cwd };\n return command.trim() === '' ? { ...RUNNER_SHELL_REQUEST, ...where } : { command, ...where, preferInteractive: true };\n}\n\n/** Quotes a value that carries whitespace, which is how a value survives tokenizing. */\nfunction quote(value: string): string {\n return /\\s/u.test(value) ? `\"${value}\"` : value;\n}\n\nexport function runnerLaunchLine(request: RunnerLaunchRequest): string {\n const cwd = request.cwd?.trim() ?? '';\n const name = request.name?.trim() ?? '';\n const pairs = [\n ...(name === '' ? [] : [`name=${quote(name)}`]),\n ...(cwd === '' ? [] : [`cwd=${quote(cwd)}`]),\n ...(request.interactive === true\n ? ['interactive=true']\n : request.preferInteractive === true\n ? ['interactive=prefer']\n : []),\n ];\n // The separator is always written, even with no options before it, so the\n // command is never re-read as a `key=value` pair.\n return [RUNNERS_START_LINE, ...pairs, RUNNERS_COMMAND_SEPARATOR, request.command.trim()].join(' ');\n}\n","export const RUNNER_RUNS_TYPE = 'runner_runs';\n","import { defineSessionStore, type SessionFrameSender } from '@agimon-ai/po-core/native';\n\nimport { RUNNER_RUNS_TYPE } from '../../../../../constants/webRunners';\nimport { type RunnerRunView, type RunnerStartFailureView } from '../../../../../types/webRunners';\nimport { type RunnerLaunchRequest, runnerLaunchLine } from './launchLine';\n\n/** The runtime's slash verb that stops one runner headlessly. */\nconst STOP_COMMAND = '/runners stop';\n\n/** One session's record: the hub's last report plus what this page asked for. */\nexport interface RunnersSession extends RunnerRunsPayload {\n /** Runners a stop was asked for and that have not yet reported an exit. */\n stopRequested: string[];\n}\n\nexport const runners = defineSessionStore<RunnersSession>({ runs: [], stopRequested: [] });\n\n/** Short commands stay out of the activity card, but remain in the runner feed. */\nexport function isRunnerActivityVisible(run: RunnerRunView, now = Date.now()): boolean {\n return run.state === 'running' && now - Date.parse(run.startedAt) > 3_000;\n}\n\n/** The runner channel keeps the dock's busy state aligned with its rendered run list. */\nexport const runnerActivitySource = {\n subscribe(this: void, listener: () => void) {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const schedule = () => {\n clearTimeout(timer);\n const now = Date.now();\n let deadline = Infinity;\n for (const session of Object.values(runners.store.state)) {\n if (!session) continue;\n for (const run of session.runs) {\n if (run.state !== 'running') continue;\n const revealAt = Date.parse(run.startedAt) + 3_001;\n if (revealAt > now) deadline = Math.min(deadline, revealAt);\n }\n }\n if (Number.isFinite(deadline))\n timer = setTimeout(\n () => {\n listener();\n schedule();\n },\n Math.min(deadline - now, 2_147_483_647),\n );\n };\n const subscription = runners.store.subscribe(() => {\n listener();\n schedule();\n });\n schedule();\n return () => {\n subscription.unsubscribe();\n clearTimeout(timer);\n };\n },\n isActive(sessionId: string | null) {\n return runners.select(runners.store.state, sessionId).runs.some((run) => isRunnerActivityVisible(run));\n },\n};\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Asks the runtime to stop a runner through the same slash command the TUI's\n * Runner Space uses. The request is remembered until the runner's record\n * reports an exit; the runtime, not this click, decides when that is.\n */\nexport function requestRunnerStop(send: SessionFrameSender, sessionId: string, id: string): void {\n send(sessionId, { type: 'prompt', message: `${STOP_COMMAND} ${id}` });\n runners.update(sessionId, (current) => ({\n ...current,\n stopRequested: [...current.stopRequested.filter((known) => known !== id), id],\n }));\n}\n\n/**\n * Asks the runtime to start a runner, through the same prompt frame the stop\n * request uses and the same way agents and workflows launch their own work.\n *\n * Nothing is recorded as pending here. The runtime names the run, and it\n * arrives in the feed on its own; guessing at an id before it exists would\n * only have to be reconciled later.\n */\nexport function requestRunnerStart(send: SessionFrameSender, sessionId: string, request: RunnerLaunchRequest): void {\n send(sessionId, { type: 'prompt', message: runnerLaunchLine(request) });\n}\n\nexport interface RunnerRunsPayload {\n /** The runners the hub last reported; presented order preserved. */\n runs: RunnerRunView[];\n /** Where a runner starts when no folder is given. */\n sessionDirectory?: string;\n /** The last start that did not happen. */\n startFailure?: RunnerStartFailureView;\n}\n\n/** The plugin's session data channel: 'runner_runs' payloads into the store. */\nexport const runnerRunsChannel = runners.channel<RunnerRunsPayload>({\n channel: RUNNER_RUNS_TYPE,\n parse(input) {\n if (!isRecord(input) || !Array.isArray(input.runs)) return null;\n const failure = input.startFailure;\n return {\n runs: input.runs.filter(isRecord) as unknown as RunnerRunView[],\n ...(typeof input.sessionDirectory === 'string' ? { sessionDirectory: input.sessionDirectory } : {}),\n ...(isRecord(failure) && typeof failure.id === 'string' && typeof failure.message === 'string'\n ? { startFailure: { id: failure.id, message: failure.message } }\n : {}),\n };\n },\n reduce(current, payload) {\n // A stop request is spent once the runner reports an exit or leaves the feed.\n const stillRunning = new Set(payload.runs.filter((run) => run.state === 'running').map((run) => run.id));\n return { ...payload, stopRequested: current.stopRequested.filter((id) => stillRunning.has(id)) };\n },\n});\n","import {\n Button,\n FolderIcon,\n fontOf,\n Input,\n ListRow,\n Sheet,\n SheetBody,\n SheetContent,\n SheetFooter,\n SheetHeader,\n SheetTitle,\n} from '@agimon-ai/po-native-components';\nimport type { PoNativeTheme } from '@agimon-ai/po-web-components/nativeTheme';\nimport { useState } from 'react';\nimport { Text, View } from 'react-native';\nimport { StyleSheet } from 'react-native-unistyles';\n\nimport type { RunnerCommandBarProps } from '../../../../../types/webRunners';\nimport { plainPunctuation, runnerFolderLabel, runnerFolders } from '../_lib/format';\n\n/**\n * The phone's command bar: the command and Run on one line, the folder it runs\n * in on the row under it, chosen from a bottom sheet.\n */\nexport function RunnerCommandBar({\n command,\n onCommandChange,\n cwd,\n onCwdChange,\n sessionDirectory,\n folders,\n problem,\n onLaunch,\n defaultFolderOpen = false,\n}: RunnerCommandBarProps) {\n const [folderOpen, setFolderOpen] = useState(defaultFolderOpen);\n const [path, setPath] = useState('');\n const pick = (next: string): void => {\n onCwdChange(next);\n setPath('');\n setFolderOpen(false);\n };\n const choices = ['', ...runnerFolders(folders, cwd, sessionDirectory)];\n\n return (\n <View style={styles.bar}>\n <View style={styles.line}>\n <View style={styles.grow}>\n <Input\n testID=\"runners-panel-command\"\n accessibilityLabel=\"Command to run\"\n size=\"lg\"\n value={command}\n onChangeText={(text) => onCommandChange(plainPunctuation(text))}\n onSubmitEditing={onLaunch}\n placeholder=\"a command, like pnpm dev\"\n autoCapitalize=\"none\"\n autoCorrect={false}\n returnKeyType=\"go\"\n />\n </View>\n <Button testID=\"runners-panel-run\" variant=\"primary\" size=\"lg\" onPress={onLaunch}>\n {command.trim() === '' ? 'Open shell' : 'Run'}\n </Button>\n </View>\n <ListRow\n leading={<FolderIcon size={14} color={problem === undefined ? 'faint' : 'red'} />}\n title={runnerFolderLabel(cwd, sessionDirectory)}\n description=\"Runs in\"\n disclosure\n accessibilityLabel={`Runs in ${runnerFolderLabel(cwd, sessionDirectory)}`}\n onPress={() => setFolderOpen(true)}\n />\n {problem === undefined ? (\n <Text style={styles.meta}>Leave the command empty for a plain shell.</Text>\n ) : (\n <Text accessibilityRole=\"alert\" testID=\"runners-panel-problem\" style={styles.problem}>\n {problem}\n </Text>\n )}\n <Sheet open={folderOpen} onOpenChange={setFolderOpen}>\n <SheetContent>\n <SheetHeader closeLabel=\"Close folders\">\n <SheetTitle>Runs in</SheetTitle>\n </SheetHeader>\n <SheetBody>\n <View>\n {choices.map((folder) => (\n <ListRow\n key={folder}\n title={folder === '' ? 'Session directory' : runnerFolderLabel(folder, sessionDirectory)}\n description={folder === '' ? (sessionDirectory ?? 'Where this session started') : folder}\n selected={folder === cwd}\n onPress={() => pick(folder)}\n />\n ))}\n </View>\n <Input\n testID=\"runners-panel-cwd-path\"\n accessibilityLabel=\"Another folder\"\n value={path}\n onChangeText={(text) => setPath(plainPunctuation(text))}\n onSubmitEditing={() => {\n if (path.trim() !== '') pick(path.trim());\n }}\n placeholder=\"another folder, like packages/web\"\n autoCapitalize=\"none\"\n autoCorrect={false}\n returnKeyType=\"done\"\n />\n </SheetBody>\n <SheetFooter>A relative folder starts from the session directory.</SheetFooter>\n </SheetContent>\n </Sheet>\n </View>\n );\n}\n\nconst styles = StyleSheet.create((theme: PoNativeTheme) => ({\n bar: { gap: theme.spacing(1.5) },\n line: { flexDirection: 'row', alignItems: 'center', gap: theme.spacing(2) },\n grow: { flex: 1 },\n meta: {\n color: theme.colors.dim,\n fontFamily: fontOf(theme.fontFamily.sans),\n fontSize: theme.fontSize.sm,\n lineHeight: theme.lineHeight.sm,\n },\n problem: {\n color: theme.colors.red,\n fontFamily: fontOf(theme.fontFamily.sans),\n fontSize: theme.fontSize.sm,\n lineHeight: theme.lineHeight.sm,\n },\n}));\n","export const RUNNER_API_BASE_PATH = 'runner';\nexport const RUN_ID_PARAM = 'runId';\nexport const RUNNER_SCREEN_EVENT = 'screen';\nexport const RUNNER_LOG_STREAM_EVENT = 'append';\nexport const RUNNER_LOG_PING_EVENT = 'ping';\n","import type { LogSlice } from './logReader';\n\n/**\n * The runner log API, shared by this package's session-scoped routes and its\n * cockpit plugin. The two halves run in different processes, so the wire\n * vocabulary is declared here: the browser half may reach `src/types` and\n * nothing else on the server side.\n *\n * Where the routes live is not here. That is `src/types/apiRoutes`, which both\n * halves read, and the generated client turns into the URLs the page addresses.\n * The file a run writes to is still read from its metadata record by the server\n * alone.\n */\n\n/**\n * One chunk of an attached pane's output.\n *\n * Base64 because these are terminal bytes, escape sequences and all, and a\n * server-sent event is a line-oriented text frame that would mangle them.\n */\nexport interface RunnerScreenEvent {\n chunk: string;\n /** Byte offset just past this chunk, so a reconnect resumes rather than replays. */\n offset?: number;\n /** Set once the runner exits, so the page can stop watching. */\n ended?: boolean;\n}\n\n/** A finite byte slice for sealed HTTP followers. Decode chunks incrementally, not independently. */\nexport interface RunnerOutputResponse {\n /** Base64 bytes, preserving split UTF-8 characters and terminal escape sequences. */\n chunk: string;\n offset: number;\n /** The file was replaced or became shorter than the requested offset; discard the previous display/decoder state. */\n reset: boolean;\n /** Opaque raw file identity. Send back on screen/read to detect replacement, including regrowth. */\n generation?: string;\n exists: boolean;\n /** More bytes were present at read time; request the next slice before waiting. */\n hasMore: boolean;\n /** True only once the runner ended and all available bytes have been read. */\n ended: boolean;\n}\n\n/** The body of a keystroke POST. Text, not key codes: the pane wants bytes. */\nexport interface RunnerInputRequest {\n text: string;\n}\n\n/** The named SSE event carrying a RunnerScreenEvent payload. */\n\n/**\n * A log request as query parameters. `grep` is a literal substring, not a\n * regular expression, because that is what the reader matches; `lines` bounds\n * the answer to the last N lines of whatever survived the filter.\n */\nexport interface RunnerLogQueryParams {\n lines?: number;\n grep?: string;\n ignoreCase?: boolean;\n contextLines?: number;\n}\n\n/** The slice the log route answers with, plus which runner it came from. */\nexport interface RunnerLogResponse extends LogSlice {\n runId: string;\n /** True while the runner is still writing, so the page knows following is worth offering. */\n running: boolean;\n}\n\n/**\n * One server-sent event on the follow stream: the lines appended since the last\n * one. The stream never filters: a page that sets a query stops following and\n * reads a filtered slice instead, because grep with context is a whole-file\n * answer and cannot be assembled from a chunk at a time.\n */\nexport interface RunnerLogStreamEvent {\n /** Appended lines, in order; empty when the event only reports the runner ending. */\n lines: string[];\n /**\n * Byte offset just past the last line in this event.\n *\n * A follower that loses the stream resumes here. Without it the page could\n * only fall back to the offset its last slice reported, which every line\n * delivered since has already moved past, so a reconnect would replay them.\n */\n offset?: number;\n /** Set once the runner exits, so the page can stop following without polling the run list. */\n ended?: boolean;\n}\n\n/** The named SSE event carrying a RunnerLogStreamEvent payload. */\n\n/**\n * The named SSE event that carries nothing.\n *\n * A runner can be alive and silent for minutes, which on the wire is\n * indistinguishable from a connection that died. This is sent on a timer so\n * the socket keeps proving itself. Readers that only listen for `append`\n * ignore it, which is what makes it safe to add.\n */\n\n/** Query parameter names, shared so the page and the route cannot drift apart. */\nexport const RUNNER_LOG_PARAMS = {\n lines: 'lines',\n grep: 'grep',\n ignoreCase: 'ignoreCase',\n contextLines: 'contextLines',\n from: 'from',\n generation: 'generation',\n} as const;\n","import type { ApiResponseOf, ApiRoutes } from '@agimon-ai/po-core/web';\n\nimport { RUN_ID_PARAM } from '../constants/webRunnerLog';\nimport { RUNNER_LOG_PARAMS, type RunnerLogResponse, type RunnerOutputResponse } from './webRunnerLog';\n\n/**\n * This package's routes, as data.\n *\n * No scope and no base path: the build reads both off\n * `src/extensions/workspaces/sessions/(backend)/api/runner/`, so the mount is\n * stated once, by the folder that creates it. This package stated it four times\n * before, once per URL builder, each of them re-spelling `/plugins/` and the\n * session prefix by hand.\n *\n * The Hono app registers these paths verbatim and the browser addresses them,\n * so a path cannot move on one side alone. `:runId` is Hono's own parameter\n * syntax for that reason; a caller supplies the value as `params`, and the\n * client encodes the segment.\n */\nconst routes = {\n log: {\n method: 'GET',\n path: `/runners/:${RUN_ID_PARAM}/log`,\n query: [\n RUNNER_LOG_PARAMS.lines,\n RUNNER_LOG_PARAMS.grep,\n RUNNER_LOG_PARAMS.ignoreCase,\n RUNNER_LOG_PARAMS.contextLines,\n ],\n response: undefined as unknown as ApiResponseOf<RunnerLogResponse>,\n },\n /**\n * The live tail of that same log.\n *\n * `stream: true`, so the client exposes a URL and no call method: the\n * consumer is the browser’s own SSE reader, and a relayed call would\n * buffer a stream that never ends.\n */\n logStream: {\n method: 'GET',\n path: `/runners/:${RUN_ID_PARAM}/log/stream`,\n query: [RUNNER_LOG_PARAMS.from],\n stream: true,\n },\n /** The unscrubbed pane bytes, for a terminal emulator rather than a reader. */\n screenStream: {\n method: 'GET',\n path: `/runners/:${RUN_ID_PARAM}/screen/stream`,\n query: [RUNNER_LOG_PARAMS.from],\n stream: true,\n },\n /** Finite byte reads keep sealed HTTP exchanges bounded, unlike SSE. */\n logRead: {\n method: 'GET',\n path: `/runners/:${RUN_ID_PARAM}/log/read`,\n query: [RUNNER_LOG_PARAMS.from],\n response: undefined as unknown as ApiResponseOf<RunnerOutputResponse>,\n },\n screenRead: {\n method: 'GET',\n path: `/runners/:${RUN_ID_PARAM}/screen/read`,\n query: [RUNNER_LOG_PARAMS.from, RUNNER_LOG_PARAMS.generation],\n response: undefined as unknown as ApiResponseOf<RunnerOutputResponse>,\n },\n input: {\n method: 'POST',\n path: `/runners/:${RUN_ID_PARAM}/screen/input`,\n },\n} as const satisfies ApiRoutes;\n\nexport default routes;\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { createApiClient, nativeApiTransport, sessionApiAddress } from '@agimon-ai/po-core/native';\n\nimport routes from '../src/types/apiRoutes';\n\n/** Scopes the tree mounts 'runner' at. */\nexport const apiScopes = ['session'] as const;\n\nexport const api = createApiClient(routes, {\n scopes: apiScopes,\n basePath: 'runner',\n transport: nativeApiTransport,\n sessionAddress: sessionApiAddress,\n});\n","import { api } from '../../../../../../generated/client.native';\nimport { RUN_ID_PARAM } from '../../../../../constants/webRunnerLog';\nimport {\n RUNNER_LOG_PARAMS,\n type RunnerLogQueryParams,\n type RunnerLogResponse,\n} from '../../../../../types/webRunnerLog';\n\n/**\n * The page's half of this package's log API. The only place the cockpit talks\n * HTTP to the hub for a runner, so if the transport ever changes, it changes\n * here alone.\n *\n * The generated client owns every URL: a route is named, a session id selects\n * that session's own copy of the API, and the run id is a path parameter the\n * client substitutes and encodes. Nothing here spells a mount, a prefix or a\n * proxy parameter, which is what the four deleted URL builders each did by\n * hand.\n */\n\nexport type RunnerLogResult = { slice: RunnerLogResponse } | { error: string };\n\nconst UNREACHABLE = 'The cockpit hub is unreachable.';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/** Reads one runner's log: the last N lines, or the lines matching a substring with context. */\nexport async function fetchRunnerLog(\n sessionId: string,\n runId: string,\n params: RunnerLogQueryParams = {},\n signal?: AbortSignal,\n): Promise<RunnerLogResult> {\n const result = await api.session(sessionId).log({\n params: { [RUN_ID_PARAM]: runId },\n // An unset parameter is left out rather than sent empty: the route reads a\n // missing one as its own default, and an empty grep as no filter at all.\n query: {\n [RUNNER_LOG_PARAMS.lines]: params.lines,\n [RUNNER_LOG_PARAMS.grep]: params.grep === '' ? undefined : params.grep,\n [RUNNER_LOG_PARAMS.ignoreCase]: params.ignoreCase === true ? true : undefined,\n [RUNNER_LOG_PARAMS.contextLines]: params.contextLines,\n },\n ...(signal === undefined ? {} : { signal }),\n });\n if (!result.ok) {\n // Status 0 is the transport never answering, which covers both a dead hub\n // and the caller replacing this request. An abort is the caller's own doing\n // and is reported as no answer rather than as a failure to show.\n if (result.status === 0) return { error: signal?.aborted === true ? '' : UNREACHABLE };\n return { error: result.error === '' ? `The hub answered ${String(result.status)}.` : result.error };\n }\n if (!isRecord(result.data) || typeof result.data.text !== 'string') {\n return { error: `The hub answered ${String(result.status)}.` };\n }\n return { slice: result.data };\n}\n","import { useCallback, useEffect, useState, useSyncExternalStore } from 'react';\nimport { AppState } from 'react-native';\n\nimport { fetchRunnerLog } from '../_lib/logApi.native';\nimport { runners } from '../_lib/runnersStore.native';\n\nexport function useRunners(sessionId: string | null) {\n const subscribe = useCallback((listener: () => void) => {\n const subscription = runners.store.subscribe(listener);\n return () => subscription.unsubscribe();\n }, []);\n return useSyncExternalStore(subscribe, () => runners.select(runners.store.state, sessionId));\n}\n\n/** Pause finite reads and clocks while native is not active; entering active refreshes immediately. */\nexport function useRunnerForeground() {\n const subscribe = useCallback((listener: () => void) => {\n const subscription = AppState.addEventListener('change', listener);\n return () => subscription.remove();\n }, []);\n return useSyncExternalStore(subscribe, () => AppState.currentState === 'active');\n}\n\nexport function useRunnerClock(active: boolean, interval: number) {\n const [now, setNow] = useState(() => Date.now());\n useEffect(() => {\n if (!active) return;\n let timer: ReturnType<typeof setInterval> | undefined;\n const update = () => {\n clearInterval(timer);\n if (AppState.currentState !== 'active') return;\n setNow(Date.now());\n timer = setInterval(() => setNow(Date.now()), interval);\n };\n const subscription = AppState.addEventListener('change', update);\n update();\n return () => {\n clearInterval(timer);\n subscription.remove();\n };\n }, [active, interval]);\n return now;\n}\n\n/** Native uses finite reads instead of browser SSE. Read a bounded tail through the host's sealed transport. */\nexport function useRunnerTail(sessionId: string | null, runId: string, running: boolean) {\n const foreground = useRunnerForeground();\n const [tail, setTail] = useState<{ id: string; text: string }>();\n useEffect(() => {\n if (sessionId === null || !running || !foreground) return;\n const controller = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n const read = async () => {\n try {\n const result = await fetchRunnerLog(sessionId, runId, { lines: 5 }, controller.signal);\n if (controller.signal.aborted) return;\n if ('slice' in result) {\n const text = result.slice.text\n .split('\\n')\n .map((line) => line.trim())\n .filter(Boolean)\n .at(-1);\n if (text !== undefined) setTail({ id: `${sessionId}:${runId}`, text });\n if (!result.slice.running) return;\n }\n } catch {\n // A glance keeps the last known output when a read is unavailable.\n }\n if (!controller.signal.aborted) timer = setTimeout(() => void read(), 2_000);\n };\n void read();\n return () => {\n controller.abort();\n clearTimeout(timer);\n };\n }, [sessionId, runId, running, foreground]);\n return running && tail?.id === `${sessionId}:${runId}` ? tail.text : undefined;\n}\n","import type { WebPluginSlotProps } from '@agimon-ai/po-core/native';\nimport { fontOf, Button, Input, StatusBadge } from '@agimon-ai/po-native-components';\nimport type { PoNativeTheme } from '@agimon-ai/po-web-components/nativeTheme';\nimport { memo, type ReactNode, useCallback, useEffect, useMemo, useState } from 'react';\nimport { FlatList, Pressable, Text, View } from 'react-native';\nimport { StyleSheet } from 'react-native-unistyles';\n\nimport type { RunnerLogResponse } from '../../../../../types/webRunnerLog';\nimport type { RunnerRunView } from '../../../../../types/webRunners';\nimport { logViewLines, runnerBadge, runnerFolderLabel, tailLineNumbers } from '../_lib/format';\nimport { fetchRunnerLog } from '../_lib/logApi.native';\nimport { requestRunnerStop } from '../_lib/runnersStore.native';\nimport { useRunners, useRunnerForeground } from './runnerHooks.native';\n\n/** The top of both runner screens: name, outcome, an action, and the command in its folder. */\nexport function RunnerRunHeader({\n run,\n name,\n sessionDirectory,\n action,\n}: {\n run: RunnerRunView | undefined;\n name: string;\n sessionDirectory: string | undefined;\n action?: ReactNode;\n}) {\n const badge = runnerBadge(run);\n /** A long command would eat a phone screen, so it starts as one truncated line. */\n const [commandOpen, setCommandOpen] = useState(false);\n return (\n <>\n <View style={styles.header}>\n <Text numberOfLines={1} style={styles.title}>\n {name}\n </Text>\n <StatusBadge tone={badge.tone}>{badge.label}</StatusBadge>\n <View style={styles.grow} />\n {action}\n </View>\n {run ? (\n <Pressable\n testID=\"runner-log-command-toggle\"\n accessibilityRole=\"button\"\n accessibilityState={{ expanded: commandOpen }}\n accessibilityHint={commandOpen ? 'Collapses the command' : 'Shows the full command'}\n style={styles.commandBox}\n onPress={() => setCommandOpen((open) => !open)}\n >\n <Text selectable={commandOpen} numberOfLines={commandOpen ? undefined : 1} style={styles.command}>\n <Text style={styles.prompt}>$ </Text>\n {run.command}\n </Text>\n {commandOpen ? (\n <Text numberOfLines={1} style={styles.folder}>\n in {runnerFolderLabel(run.cwd, sessionDirectory)}\n </Text>\n ) : null}\n </Pressable>\n ) : (\n <Text style={styles.meta}>No longer listed; its log stays readable.</Text>\n )}\n </>\n );\n}\n\nexport function runnerLogTab(run: RunnerRunView) {\n return {\n id: `runner-log-${run.id}`,\n label: `log · ${run.name}`,\n panel: (props: WebPluginSlotProps) => <RunnerLogPanel {...props} runId={run.id} />,\n };\n}\n\nexport function RunnerLogPanel({ sessionId, runId, sendSessionFrame }: WebPluginSlotProps & { runId: string }) {\n const session = useRunners(sessionId);\n const foreground = useRunnerForeground();\n const run = session.runs.find((candidate) => candidate.id === runId);\n const [typed, setTyped] = useState('');\n const [query, setQuery] = useState('');\n const [ignoreCase, setIgnoreCase] = useState(false);\n const [context, setContext] = useState(2);\n const [following, setFollowing] = useState(true);\n const requestKey = `${sessionId}:${runId}:${query}:${ignoreCase}:${context}:${following}`;\n const [loaded, setLoaded] = useState<{ key: string; slice?: RunnerLogResponse; error: string }>();\n const slice = loaded?.key === requestKey ? loaded.slice : undefined;\n const error = loaded?.key === requestKey ? loaded.error : '';\n useEffect(() => {\n const timer = setTimeout(() => setQuery(typed), 200);\n return () => clearTimeout(timer);\n }, [typed]);\n useEffect(() => {\n if (sessionId === null || !foreground) return;\n const controller = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n const read = async () => {\n const result = await fetchRunnerLog(\n sessionId,\n runId,\n { lines: 2000, grep: query, ignoreCase, contextLines: context },\n controller.signal,\n );\n if (controller.signal.aborted) return;\n setLoaded((previous) => {\n const next =\n 'error' in result\n ? { key: requestKey, error: result.error }\n : { key: requestKey, slice: result.slice, error: '' };\n if (previous?.key !== next.key || previous.error !== next.error) return next;\n const before = previous.slice;\n const after = next.slice;\n if (before === after) return previous;\n if (!before || !after) return next;\n const equal =\n before.text === after.text &&\n before.totalLines === after.totalLines &&\n before.lineCount === after.lineCount &&\n before.fileSize === after.fileSize &&\n before.completeBytes === after.completeBytes &&\n before.path === after.path &&\n before.exists === after.exists &&\n before.truncated === after.truncated &&\n before.runId === after.runId &&\n before.running === after.running &&\n before.lineNumbers?.length === after.lineNumbers?.length &&\n (before.lineNumbers?.every((number, index) => number === after.lineNumbers?.[index]) ?? true);\n return equal ? previous : next;\n });\n if (following && query === '' && ('error' in result || result.slice.running))\n timer = setTimeout(() => void read(), 2_000);\n };\n void read();\n return () => {\n controller.abort();\n clearTimeout(timer);\n };\n }, [sessionId, runId, query, ignoreCase, context, following, requestKey, foreground]);\n const stopping = session.stopRequested.includes(runId);\n const live = following && query === '' && slice?.running === true;\n return (\n <View testID=\"runner-log-panel\" style={styles.panel}>\n <RunnerRunHeader\n run={run}\n name={run?.name ?? runId}\n sessionDirectory={session.sessionDirectory}\n action={\n run?.state === 'running' && sessionId !== null ? (\n <Button\n variant={stopping ? 'outline' : 'danger-outline'}\n size=\"sm\"\n disabled={stopping}\n onPress={() => requestRunnerStop(sendSessionFrame, sessionId, runId)}\n >\n {stopping ? 'Stopping…' : 'Stop'}\n </Button>\n ) : null\n }\n />\n <Input\n testID=\"runner-log-search\"\n accessibilityLabel=\"Search this log\"\n placeholder=\"Search output\"\n value={typed}\n onChangeText={setTyped}\n autoCapitalize=\"none\"\n returnKeyType=\"search\"\n />\n <View style={styles.actions}>\n <Button\n variant={ignoreCase ? 'subtle' : 'outline'}\n size=\"sm\"\n accessibilityState={{ selected: ignoreCase }}\n onPress={() => setIgnoreCase((value) => !value)}\n >\n {ignoreCase ? 'Any case' : 'Match case'}\n </Button>\n {query === '' ? null : (\n <Button\n variant={context > 0 ? 'subtle' : 'outline'}\n size=\"sm\"\n onPress={() => setContext((value) => (value === 0 ? 2 : 0))}\n >\n {`± ${String(context)} lines`}\n </Button>\n )}\n {query === '' && slice?.running === true ? (\n <Button\n variant={live ? 'subtle' : 'outline'}\n size=\"sm\"\n accessibilityState={{ selected: live }}\n onPress={() => setFollowing((value) => !value)}\n >\n {live ? 'Following' : 'Follow'}\n </Button>\n ) : null}\n </View>\n <RunnerLogOutput slice={slice} error={error} query={query} live={live} />\n <Text selectable numberOfLines={1} ellipsizeMode=\"middle\" style={styles.path}>\n {run?.logPath ?? slice?.path ?? ''}\n </Text>\n </View>\n );\n}\nconst RunnerLogOutput = memo(function RunnerLogOutput({\n slice,\n error,\n query,\n live,\n}: {\n slice: RunnerLogResponse | undefined;\n error: string;\n query: string;\n live: boolean;\n}) {\n const lines = useMemo(() => logViewLines(slice?.text ?? '', [], 2000).lines, [slice?.text]);\n const rows = useMemo(() => {\n const numbers = query === '' ? tailLineNumbers(slice?.totalLines ?? 0, lines.length) : (slice?.lineNumbers ?? []);\n const gutter = String(numbers.at(-1) ?? 0).length;\n return lines.map((text, index) => ({\n key: String(numbers[index] ?? index),\n number: `${String(numbers[index] ?? '').padStart(gutter)} `,\n text,\n }));\n }, [lines, query, slice?.totalLines, slice?.lineNumbers]);\n const renderItem = useCallback(\n ({ item }: { item: (typeof rows)[number] }) => (\n <Text selectable style={styles.line}>\n <Text style={styles.number}>{item.number}</Text>\n {item.text}\n </Text>\n ),\n [],\n );\n const keyExtractor = useCallback((item: (typeof rows)[number]) => item.key, []);\n const empty =\n error !== '' ? (\n <Text accessibilityRole=\"alert\" style={styles.error}>\n {error}\n </Text>\n ) : slice?.exists === false ? (\n <Text style={styles.meta}>This runner has not written a log yet.</Text>\n ) : slice ? (\n <Text style={styles.meta}>{query === '' ? 'The log is empty.' : 'Nothing matched.'}</Text>\n ) : null;\n return (\n <>\n <Text style={styles.meta}>\n {slice === undefined\n ? error === ''\n ? 'Reading…'\n : ''\n : query !== ''\n ? `${slice.lineCount} matching of ${slice.totalLines} lines`\n : `${live ? 'Tailing' : 'Showing'} last ${lines.length} of ${slice.totalLines} lines`}\n </Text>\n <FlatList\n style={styles.log}\n contentContainerStyle={styles.logBody}\n data={error !== '' || slice?.exists === false ? [] : rows}\n renderItem={renderItem}\n keyExtractor={keyExtractor}\n ListEmptyComponent={empty}\n initialNumToRender={20}\n maxToRenderPerBatch={20}\n windowSize={5}\n accessibilityLabel=\"Runner log output\"\n />\n </>\n );\n});\n\nconst styles = StyleSheet.create((theme: PoNativeTheme) => ({\n panel: { flex: 1, gap: theme.spacing(2), padding: theme.spacing(3), backgroundColor: theme.colors.bg },\n header: { flexDirection: 'row', alignItems: 'center', gap: theme.spacing(2), minHeight: 32 },\n grow: { flex: 1 },\n title: {\n flexShrink: 1,\n color: theme.colors.hi,\n fontWeight: '600',\n fontFamily: fontOf(theme.fontFamily.sans),\n fontSize: theme.fontSize.base,\n },\n commandBox: {\n gap: theme.spacing(1),\n paddingHorizontal: theme.spacing(3),\n paddingVertical: theme.spacing(2),\n borderRadius: theme.borderRadius.md,\n backgroundColor: theme.colors.deep,\n },\n command: { color: theme.colors.hi, fontFamily: fontOf(theme.fontFamily.mono), fontSize: theme.fontSize.sm },\n prompt: { color: theme.colors.faint },\n folder: { color: theme.colors.dim, fontFamily: fontOf(theme.fontFamily.mono), fontSize: theme.fontSize.xs },\n meta: {\n color: theme.colors.dim,\n fontFamily: fontOf(theme.fontFamily.sans),\n fontSize: theme.fontSize.sm,\n lineHeight: theme.lineHeight.sm,\n },\n error: { color: theme.colors.red, fontFamily: fontOf(theme.fontFamily.sans), fontSize: theme.fontSize.sm },\n actions: { flexDirection: 'row', gap: theme.spacing(2), flexWrap: 'wrap' },\n log: { flex: 1, borderRadius: theme.borderRadius.md, backgroundColor: theme.colors.deep },\n logBody: { padding: theme.spacing(3) },\n line: {\n color: theme.colors.text,\n fontFamily: fontOf(theme.fontFamily.mono),\n fontSize: theme.fontSize.xs,\n lineHeight: theme.lineHeight.sm,\n },\n number: { color: theme.colors.faint },\n path: { color: theme.colors.faint, fontFamily: fontOf(theme.fontFamily.mono), fontSize: theme.fontSize.xs },\n}));\n","import { api } from '../../../../../../generated/client.native';\nimport { RUN_ID_PARAM } from '../../../../../constants/webRunnerLog';\nimport { RUNNER_LOG_PARAMS, type RunnerOutputResponse } from '../../../../../types/webRunnerLog';\n\n/** Finite native reads preserve raw terminal bytes and generation-based replacement detection. */\nexport async function readRunnerScreen(\n sessionId: string,\n runId: string,\n from: number,\n generation: string | undefined,\n signal: AbortSignal,\n): Promise<RunnerOutputResponse> {\n const result = await api.session(sessionId).screenRead({\n params: { [RUN_ID_PARAM]: runId },\n query: { [RUNNER_LOG_PARAMS.from]: from, [RUNNER_LOG_PARAMS.generation]: generation },\n signal,\n });\n if (!result.ok) throw new Error(result.error || 'The connection to this pane dropped.');\n return result.data;\n}\nexport async function sendRunnerInput(sessionId: string, runId: string, text: string): Promise<void> {\n const result = await api.session(sessionId).input({ params: { [RUN_ID_PARAM]: runId }, body: { text } });\n if (!result.ok) throw new Error(result.error || 'This runner is no longer accepting input.');\n}\n","import type { WebPluginSlotProps } from '@agimon-ai/po-core/native';\nimport { fontOf, Button, SearchIcon } from '@agimon-ai/po-native-components';\nimport type { PoNativeTheme } from '@agimon-ai/po-web-components/nativeTheme';\nimport { useMemo } from 'react';\nimport { Text, View } from 'react-native';\nimport { StyleSheet } from 'react-native-unistyles';\n\nimport type { RunnerRunView } from '../../../../../types/webRunners';\nimport { requestRunnerStop } from '../_lib/runnersStore.native';\nimport { readRunnerScreen, sendRunnerInput } from '../_lib/screenApi.native';\nimport { useRunners } from './runnerHooks.native';\nimport { RunnerRunHeader, runnerLogTab } from './RunnerLogPanel.native';\n\n/** The host renders genuine terminal bytes; this package owns every scoped API call. */\nexport function runnerShellTab(run: RunnerRunView) {\n return {\n id: `runner-shell-${run.id}`,\n label: `shell · ${run.name}`,\n panel: (props: WebPluginSlotProps) => <RunnerShellPanel {...props} runId={run.id} />,\n };\n}\n\n/**\n * One terminal runner, full screen. A phone keyboard has no Ctrl key, so\n * Ctrl-C is a button; Search opens the runner's log, which the sink keeps\n * scrubbed beside the raw bytes for exactly that.\n */\nexport function RunnerShellPanel({\n sessionId,\n runId,\n renderRunnerTerminal,\n sendSessionFrame,\n openTransientTab,\n}: WebPluginSlotProps & { runId: string }) {\n const session = useRunners(sessionId);\n const run = session.runs.find((candidate) => candidate.id === runId);\n const live = run?.state === 'running';\n const stopping = session.stopRequested.includes(runId);\n const request = useMemo(\n () =>\n sessionId === null\n ? undefined\n : {\n key: `${sessionId}:${runId}`,\n read: (from: number, generation: string | undefined, signal: AbortSignal) =>\n readRunnerScreen(sessionId, runId, from, generation, signal),\n write: (text: string) => sendRunnerInput(sessionId, runId, text),\n },\n [sessionId, runId],\n );\n return (\n <View style={styles.panel}>\n <RunnerRunHeader\n run={run}\n name={run?.name ?? runId}\n sessionDirectory={session.sessionDirectory}\n action={\n live && sessionId !== null ? (\n <Button\n testID=\"runner-shell-stop\"\n variant={stopping ? 'outline' : 'danger-outline'}\n size=\"sm\"\n disabled={stopping}\n onPress={() => requestRunnerStop(sendSessionFrame, sessionId, runId)}\n >\n {stopping ? 'Stopping…' : 'Stop'}\n </Button>\n ) : null\n }\n />\n <View style={styles.terminal}>\n {request === undefined ? (\n <Text style={styles.meta}>Select a session to attach to this runner.</Text>\n ) : (\n renderRunnerTerminal?.(request)\n )}\n </View>\n <View style={styles.actions}>\n {run ? (\n <Button\n testID=\"runner-shell-search\"\n variant=\"outline\"\n onPress={() => openTransientTab(runnerLogTab(run))}\n style={styles.action}\n >\n <SearchIcon size={14} />\n Search output\n </Button>\n ) : null}\n {live && sessionId !== null ? (\n <Button\n testID=\"runner-shell-interrupt\"\n variant=\"outline\"\n onPress={() => void sendRunnerInput(sessionId, runId, '\\u0003')}\n style={styles.action}\n >\n Ctrl-C\n </Button>\n ) : null}\n </View>\n </View>\n );\n}\nconst styles = StyleSheet.create((theme: PoNativeTheme) => ({\n panel: { flex: 1, gap: theme.spacing(2), padding: theme.spacing(3), backgroundColor: theme.colors.bg },\n actions: { flexDirection: 'row', gap: theme.spacing(2) },\n action: { flex: 1 },\n terminal: { flex: 1 },\n meta: { color: theme.colors.dim, fontFamily: fontOf(theme.fontFamily.sans), fontSize: theme.fontSize.sm },\n}));\n","import type { WebPluginSlotProps } from '@agimon-ai/po-core/native';\nimport { ArrowRightIcon, fontOf, Button, Dot, ListRow } from '@agimon-ai/po-native-components';\nimport type { PoNativeTheme } from '@agimon-ai/po-web-components/nativeTheme';\nimport { useEffect, useRef, useState, useSyncExternalStore } from 'react';\nimport { Pressable, ScrollView, Text, View } from 'react-native';\nimport { StyleSheet } from 'react-native-unistyles';\n\nimport type { RunnerRunView } from '../../../../../types/webRunners';\nimport { formatRunnerUptime } from '../_lib/format';\nimport { runnerRunRequest } from '../_lib/launchLine';\nimport {\n isRunnerActivityVisible,\n requestRunnerStart,\n requestRunnerStop,\n runnerActivitySource,\n} from '../_lib/runnersStore.native';\nimport { RunnerCommandBar } from './RunnerCommandBar.native';\nimport { useRunners, useRunnerTail, useRunnerClock } from './runnerHooks.native';\nimport { runnerLogTab } from './RunnerLogPanel.native';\nimport { runnerShellTab } from './RunnerShellPanel.native';\n\n/** A runner's own screen: its terminal when it has one, its log when it does not. */\nfunction runnerTab(run: RunnerRunView) {\n return run.interactive ? runnerShellTab(run) : runnerLogTab(run);\n}\n\nexport function runnersTab() {\n return { id: 'runner-runs', label: 'runners', panel: RunnersPanel };\n}\n\nfunction RunnerRow({\n run,\n props,\n stopping,\n now,\n}: {\n run: RunnerRunView;\n props: WebPluginSlotProps;\n stopping: boolean;\n now: number;\n}) {\n const tail = useRunnerTail(props.sessionId, run.id, run.state === 'running');\n // One tap target for the row: the name, its uptime and Stop on one line, then\n // what it is doing, falling back to what it was asked to do.\n return (\n <Pressable\n testID={`activity-runner-${run.id}`}\n accessibilityRole=\"button\"\n accessibilityLabel={`Open ${run.name}`}\n onPress={() => props.openTransientTab(runnerTab(run))}\n style={({ pressed }) => [styles.row, pressed && styles.pressed]}\n >\n <View style={styles.line}>\n <Dot tone=\"yellow\" pulse />\n <Text numberOfLines={1} style={styles.name}>\n {run.name}\n </Text>\n <Text style={styles.meta}>{formatRunnerUptime(run.startedAt, now)}</Text>\n {props.sessionId !== null ? (\n <Button\n testID={`activity-runner-stop-${run.id}`}\n size=\"xs\"\n variant={stopping ? 'outline' : 'danger-outline'}\n disabled={stopping}\n onPress={() => {\n if (props.sessionId !== null) requestRunnerStop(props.sendSessionFrame, props.sessionId, run.id);\n }}\n >\n {stopping ? 'Stopping…' : 'Stop'}\n </Button>\n ) : null}\n </View>\n <Text numberOfLines={1} style={styles.tail}>\n {tail ?? `$ ${run.command}`}\n </Text>\n </Pressable>\n );\n}\n\nexport function RunnersActivitySection(props: WebPluginSlotProps) {\n const session = useRunners(props.sessionId);\n // A mounted idle card also needs the reveal deadline, without a permanent clock.\n const active = useSyncExternalStore(runnerActivitySource.subscribe, () =>\n runnerActivitySource.isActive(props.sessionId),\n );\n const running = session.runs.filter((run) => isRunnerActivityVisible(run));\n const now = useRunnerClock(active, 1_000);\n return running.length === 0 ? (\n // The cockpit's idle line: the status, then the one jade action beside it.\n <View style={styles.idle}>\n <Text style={styles.meta}>Idle</Text>\n {props.sessionId !== null ? (\n <Pressable\n accessibilityRole=\"button\"\n testID=\"activity-runner-launch\"\n hitSlop={10}\n onPress={() => props.openTransientTab(runnersTab())}\n style={styles.launch}\n >\n <Text style={styles.launchText}>Launch a runner</Text>\n <ArrowRightIcon size={14} color=\"green\" />\n </Pressable>\n ) : null}\n </View>\n ) : (\n <View>\n {running.map((run) => (\n <RunnerRow key={run.id} run={run} props={props} now={now} stopping={session.stopRequested.includes(run.id)} />\n ))}\n </View>\n );\n}\n\n/**\n * Every running runner and the one place to start another: type a command\n * and Run hosts it on a terminal (plain output when the host has no rmux or\n * tmux), or leave it empty for a login shell. The started runner opens on\n * its own screen.\n */\nexport function RunnersPanel(props: WebPluginSlotProps) {\n const { openTransientTab } = props;\n const session = useRunners(props.sessionId);\n const running = session.runs.filter((run) => run.state === 'running');\n const [command, setCommand] = useState('');\n const [cwd, setCwd] = useState('');\n const now = useRunnerClock(running.length > 0, 10_000);\n const baseline = useRef<ReadonlySet<string> | null>(null);\n /** What the pending launch ran, put back if the start fails. */\n const launched = useRef('');\n const timeout = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n // ponytail: the first runner to appear after a launch is taken to be it, the\n // same guess the web panel makes.\n useEffect(() => {\n if (baseline.current === null) return;\n const started = session.runs.find((run) => run.state === 'running' && !baseline.current?.has(run.id));\n if (started === undefined) return;\n baseline.current = null;\n clearTimeout(timeout.current);\n openTransientTab(runnerTab(started));\n }, [session.runs, openTransientTab]);\n // A start that did not happen hands the command back beside its problem.\n const failureId = session.startFailure?.id;\n useEffect(() => {\n if (failureId === undefined || baseline.current === null) return;\n baseline.current = null;\n clearTimeout(timeout.current);\n setCommand(launched.current);\n }, [failureId]);\n useEffect(() => () => clearTimeout(timeout.current), []);\n const launch = () => {\n if (props.sessionId === null) return;\n baseline.current = new Set(session.runs.map((run) => run.id));\n clearTimeout(timeout.current);\n timeout.current = setTimeout(() => {\n baseline.current = null;\n }, 30_000);\n requestRunnerStart(props.sendSessionFrame, props.sessionId, runnerRunRequest(command, cwd));\n launched.current = command;\n setCommand('');\n };\n return (\n <View style={styles.panel}>\n <View style={styles.header}>\n <Text style={styles.title}>Runners</Text>\n <Text style={styles.meta}>{running.length === 0 ? 'Nothing running' : `${running.length} running`}</Text>\n </View>\n {props.sessionId !== null ? (\n <RunnerCommandBar\n command={command}\n onCommandChange={setCommand}\n cwd={cwd}\n onCwdChange={setCwd}\n folders={running.map((run) => run.cwd)}\n {...(session.sessionDirectory === undefined ? {} : { sessionDirectory: session.sessionDirectory })}\n {...(session.startFailure === undefined ? {} : { problem: session.startFailure.message })}\n onLaunch={launch}\n />\n ) : null}\n <ScrollView>\n {running.length === 0 ? (\n <Text style={styles.meta}>\n {props.sessionId === null\n ? 'Open a session to start a runner.'\n : 'Nothing running yet. Type a command above, like pnpm dev, and it opens as a live terminal.'}\n </Text>\n ) : (\n running.map((run) => (\n <ListRow\n key={run.id}\n leading={<Dot tone=\"yellow\" pulse />}\n title={run.name}\n description={`${run.command} · ${formatRunnerUptime(run.startedAt, now)}`}\n disclosure\n onPress={() => openTransientTab(runnerTab(run))}\n />\n ))\n )}\n </ScrollView>\n </View>\n );\n}\nconst styles = StyleSheet.create((theme: PoNativeTheme) => ({\n panel: { flex: 1, gap: theme.spacing(3), padding: theme.spacing(4), backgroundColor: theme.colors.bg },\n header: { flexDirection: 'row', alignItems: 'center', gap: theme.spacing(2) },\n row: { gap: theme.spacing(1), paddingVertical: theme.spacing(2) },\n pressed: { opacity: 0.6 },\n line: { flexDirection: 'row', alignItems: 'center', gap: theme.spacing(2) },\n name: {\n flex: 1,\n color: theme.colors.hi,\n fontFamily: fontOf(theme.fontFamily.sans),\n fontSize: theme.fontSize.base,\n lineHeight: theme.lineHeight.base,\n fontWeight: theme.fontWeight.medium,\n },\n tail: {\n // Under the name: the small dot plus the line's gap.\n paddingLeft: theme.spacing(3.5),\n color: theme.colors.dim,\n fontFamily: fontOf(theme.fontFamily.mono),\n fontSize: theme.fontSize.sm,\n lineHeight: theme.lineHeight.sm,\n },\n title: {\n color: theme.colors.hi,\n fontFamily: fontOf(theme.fontFamily.sans),\n fontSize: theme.fontSize.lg,\n fontWeight: '600',\n },\n meta: {\n color: theme.colors.dim,\n fontFamily: fontOf(theme.fontFamily.sans),\n fontSize: theme.fontSize.sm,\n lineHeight: theme.lineHeight.sm,\n },\n idle: { flexDirection: 'row', alignItems: 'center', flexWrap: 'wrap', gap: theme.spacing(4) },\n launch: { flexDirection: 'row', alignItems: 'center', gap: theme.spacing(1) },\n launchText: {\n color: theme.colors.green,\n fontFamily: fontOf(theme.fontFamily.sans),\n fontSize: theme.fontSize.base,\n lineHeight: theme.lineHeight.base,\n fontWeight: theme.fontWeight.medium,\n },\n}));\n","import { defineActivityGroup } from '@agimon-ai/po-core/native';\nimport { PlayCircleIcon } from '@agimon-ai/po-native-components';\nimport { createElement } from 'react';\n\nimport { runnersTab } from '../_components/RunnersPanel.native';\nimport { runnerActivitySource } from '../_lib/runnersStore.native';\n\nexport default defineActivityGroup({\n name: 'runners',\n keys: 'r l',\n icon: () => createElement(PlayCircleIcon),\n activeSource: runnerActivitySource,\n transientTab: runnersTab,\n order: 20,\n});\n","import { defineChannelFile } from '@agimon-ai/po-core/native';\n\nimport { runnerRunsChannel } from '../_lib/runnersStore.native';\nexport default defineChannelFile(runnerRunsChannel);\n","import { defineFill } from '@agimon-ai/po-core/native';\n\nimport { RunnersActivitySection } from '../_components/RunnersPanel.native';\n\nexport default defineFill({ slot: 'activity.runners', id: 'runners', component: RunnersActivitySection });\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineNativePlugin, type WebPluginContributions } from '@agimon-ai/po-core/native';\n\nimport activityGroupRunners from '../src/extensions/workspaces/sessions/(frontend)/activity-group/runners.native';\nimport channelRunnerRuns from '../src/extensions/workspaces/sessions/(frontend)/channel/runner-runs.native';\nimport fillRunners from '../src/extensions/workspaces/sessions/(frontend)/fill/Runners.activity.runners.native';\n\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const nativePlugin = defineNativePlugin({\n id: 'runner',\n session: {\n get activityGroups(): WebPluginContributions['activityGroups'] { return [via({ name: 'runners' }, activityGroupRunners)]; },\n get channels(): WebPluginContributions['channels'] { return [via({ channel: 'runner_runs' }, channelRunnerRuns)]; },\n get fills(): WebPluginContributions['fills'] { return [via({ slot: 'activity.runners', id: 'runners' }, fillRunners)]; },\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;;AAMA,SAAgB,mBAAmB,WAAmB,KAAqB;CACzE,MAAM,UAAU,KAAK,MAAM,SAAS;CACpC,IAAI,OAAO,MAAM,OAAO,GAAG,OAAO;CAClC,MAAM,UAAU,KAAK,IAAI,GAAG,KAAK,OAAO,MAAM,WAAW,GAAI,CAAC;CAC9D,IAAI,UAAU,IAAI,OAAO,GAAG,QAAQ;CACpC,MAAM,UAAU,KAAK,MAAM,UAAU,EAAE;CACvC,IAAI,UAAU,IAAI,OAAO,GAAG,QAAQ;CACpC,MAAM,QAAQ,KAAK,MAAM,UAAU,EAAE;CACrC,OAAO,QAAQ,KAAK,GAAG,MAAM,KAAK,GAAG,KAAK,MAAM,QAAQ,EAAE,EAAE;AAC9D;;;;;;;;;;AA2BA,SAAgB,aACd,MACA,UACA,KACA,UAA0B,CAAC,GAClB;CACT,MAAM,QAAQ,KAAK,MAAM,IAAI;CAC7B,IAAI,MAAM,SAAS,KAAK,MAAM,MAAM,SAAS,OAAO,IAAI,MAAM,IAAI;CAClE,IAAI,QAAQ,oBAAoB,QAAQ,MAAM,SAAS,GAAG,MAAM,IAAI;CACpE,MAAM,MAAM,CAAC,GAAG,OAAO,GAAG,QAAQ;CAClC,MAAM,QAAQ,IAAI,MAAM,CAAC,GAAG;CAC5B,OAAO;EAAE;EAAO,QAAQ,IAAI,SAAS,MAAM;CAAO;AACpD;;;;;;;AAQA,SAAgB,gBAAgB,gBAAwB,OAAyB;CAC/E,MAAM,QAAQ,KAAK,IAAI,GAAG,iBAAiB,QAAQ,CAAC;CACpD,OAAO,MAAM,KAAK,EAAE,QAAQ,MAAM,IAAI,GAAG,UAAU,QAAQ,KAAK;AAClE;;;;;AAmBA,SAAgB,kBAAkB,QAAgB,kBAA8C;CAC9F,IAAI,WAAW,MAAM,WAAW,kBAC9B,OAAO,qBAAqB,KAAA,IACxB,sBACC,iBAAiB,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK;CAE5C,IAAI,qBAAqB,KAAA,KAAa,OAAO,WAAW,GAAG,iBAAiB,EAAE,GAC5E,OAAO,OAAO,MAAM,iBAAiB,SAAS,CAAC;CAEjD,OAAO;AACT;;AAGA,SAAgB,cACd,OACA,SACA,kBACU;CACV,MAAM,0BAAU,IAAI,IAAI,CAAC,GAAG,OAAO,OAAO,CAAC;CAC3C,QAAQ,OAAO,EAAE;CACjB,IAAI,qBAAqB,KAAA,GAAW,QAAQ,OAAO,gBAAgB;CACnE,OAAO,CAAC,GAAG,OAAO;AACpB;;;;;AAMA,SAAgB,iBAAiB,MAAsB;CACrD,OAAO,KACJ,QAAQ,SAAS,GAAG,CAAC,CACrB,QAAQ,SAAS,IAAG,CAAC,CACrB,QAAQ,WAAW,IAAI;AAC5B;;AAGA,SAAgB,YAAY,KAG1B;CACA,IAAI,QAAQ,KAAA,GAAW,OAAO;EAAE,MAAM;EAAW,OAAO;CAAO;CAC/D,IAAI,IAAI,UAAU,WAAW,OAAO;EAAE,MAAM;EAAW,OAAO;CAAU;CACxE,IAAI,IAAI,SAAS,KAAA,KAAa,IAAI,KAAK,WAAW,WAAW,OAAO;EAAE,MAAM;EAAW,OAAO;CAAU;CAExG,OADc,IAAI,KAAK,WAAW,gBAAgB,IAAI,KAAK,SAAS,KAAK,IAAI,KAAK,SAAS,QAC5E;EAAE,MAAM;EAAM,OAAO;CAAO,IAAI;EAAE,MAAM;EAAS,OAAO,IAAI,KAAK,OAAO,QAAQ,KAAK,GAAG;CAAE;AAC3G;;;;;;;;;;;;;ACtHA,MAAa,qBAAqB;;AAgBlC,MAAa,uBAA4C;CACvD,SAAS;CACT,MAAM;CACN,aAAa;AACf;;;;;AAMA,SAAgB,iBAAiB,SAAiB,KAAkC;CAClF,MAAM,QAAQ,IAAI,KAAK,MAAM,KAAK,CAAC,IAAI,EAAE,IAAI;CAC7C,OAAO,QAAQ,KAAK,MAAM,KAAK;EAAE,GAAG;EAAsB,GAAG;CAAM,IAAI;EAAE;EAAS,GAAG;EAAO,mBAAmB;CAAK;AACtH;;AAGA,SAAS,MAAM,OAAuB;CACpC,OAAO,MAAM,KAAK,KAAK,IAAI,IAAI,MAAM,KAAK;AAC5C;AAEA,SAAgB,iBAAiB,SAAsC;CACrE,MAAM,MAAM,QAAQ,KAAK,KAAK,KAAK;CACnC,MAAM,OAAO,QAAQ,MAAM,KAAK,KAAK;CACrC,MAAM,QAAQ;EACZ,GAAI,SAAS,KAAK,CAAC,IAAI,CAAC,QAAQ,MAAM,IAAI,GAAG;EAC7C,GAAI,QAAQ,KAAK,CAAC,IAAI,CAAC,OAAO,MAAM,GAAG,GAAG;EAC1C,GAAI,QAAQ,gBAAgB,OACxB,CAAC,kBAAkB,IACnB,QAAQ,sBAAsB,OAC5B,CAAC,oBAAoB,IACrB,CAAC;CACT;CAGA,OAAO;EAAC;EAAoB,GAAG;;EAAkC,QAAQ,QAAQ,KAAK;CAAC,CAAC,CAAC,KAAK,GAAG;AACnG;;;AC9DA,MAAa,mBAAmB;;;;ACOhC,MAAM,eAAe;AAQrB,MAAa,UAAU,mBAAmC;CAAE,MAAM,CAAC;CAAG,eAAe,CAAC;AAAE,CAAC;;AAGzF,SAAgB,wBAAwB,KAAoB,MAAM,KAAK,IAAI,GAAY;CACrF,OAAO,IAAI,UAAU,aAAa,MAAM,KAAK,MAAM,IAAI,SAAS,IAAI;AACtE;;AAGA,MAAa,uBAAuB;CAClC,UAAsB,UAAsB;EAC1C,IAAI;EACJ,MAAM,iBAAiB;GACrB,aAAa,KAAK;GAClB,MAAM,MAAM,KAAK,IAAI;GACrB,IAAI,WAAW;GACf,KAAK,MAAM,WAAW,OAAO,OAAO,QAAQ,MAAM,KAAK,GAAG;IACxD,IAAI,CAAC,SAAS;IACd,KAAK,MAAM,OAAO,QAAQ,MAAM;KAC9B,IAAI,IAAI,UAAU,WAAW;KAC7B,MAAM,WAAW,KAAK,MAAM,IAAI,SAAS,IAAI;KAC7C,IAAI,WAAW,KAAK,WAAW,KAAK,IAAI,UAAU,QAAQ;IAC5D;GACF;GACA,IAAI,OAAO,SAAS,QAAQ,GAC1B,QAAQ,iBACA;IACJ,SAAS;IACT,SAAS;GACX,GACA,KAAK,IAAI,WAAW,KAAK,UAAa,CACxC;EACJ;EACA,MAAM,eAAe,QAAQ,MAAM,gBAAgB;GACjD,SAAS;GACT,SAAS;EACX,CAAC;EACD,SAAS;EACT,aAAa;GACX,aAAa,YAAY;GACzB,aAAa,KAAK;EACpB;CACF;CACA,SAAS,WAA0B;EACjC,OAAO,QAAQ,OAAO,QAAQ,MAAM,OAAO,SAAS,CAAC,CAAC,KAAK,MAAM,QAAQ,wBAAwB,GAAG,CAAC;CACvG;AACF;AAEA,SAASA,WAAS,OAAkD;CAClE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;;;;;;AAOA,SAAgB,kBAAkB,MAA0B,WAAmB,IAAkB;CAC/F,KAAK,WAAW;EAAE,MAAM;EAAU,SAAS,GAAG,aAAa,GAAG;CAAK,CAAC;CACpE,QAAQ,OAAO,YAAY,aAAa;EACtC,GAAG;EACH,eAAe,CAAC,GAAG,QAAQ,cAAc,QAAQ,UAAU,UAAU,EAAE,GAAG,EAAE;CAC9E,EAAE;AACJ;;;;;;;;;AAUA,SAAgB,mBAAmB,MAA0B,WAAmB,SAAoC;CAClH,KAAK,WAAW;EAAE,MAAM;EAAU,SAAS,iBAAiB,OAAO;CAAE,CAAC;AACxE;;AAYA,MAAa,oBAAoB,QAAQ,QAA2B;CAClE,SAAS;CACT,MAAM,OAAO;EACX,IAAI,CAACA,WAAS,KAAK,KAAK,CAAC,MAAM,QAAQ,MAAM,IAAI,GAAG,OAAO;EAC3D,MAAM,UAAU,MAAM;EACtB,OAAO;GACL,MAAM,MAAM,KAAK,OAAOA,UAAQ;GAChC,GAAI,OAAO,MAAM,qBAAqB,WAAW,EAAE,kBAAkB,MAAM,iBAAiB,IAAI,CAAC;GACjG,GAAIA,WAAS,OAAO,KAAK,OAAO,QAAQ,OAAO,YAAY,OAAO,QAAQ,YAAY,WAClF,EAAE,cAAc;IAAE,IAAI,QAAQ;IAAI,SAAS,QAAQ;GAAQ,EAAE,IAC7D,CAAC;EACP;CACF;CACA,OAAO,SAAS,SAAS;EAEvB,MAAM,eAAe,IAAI,IAAI,QAAQ,KAAK,QAAQ,QAAQ,IAAI,UAAU,SAAS,CAAC,CAAC,KAAK,QAAQ,IAAI,EAAE,CAAC;EACvG,OAAO;GAAE,GAAG;GAAS,eAAe,QAAQ,cAAc,QAAQ,OAAO,aAAa,IAAI,EAAE,CAAC;EAAE;CACjG;AACF,CAAC;;;;;;;AC9FD,SAAgBmB,iBAAiB,EAC/BC,SACAC,iBACAC,KACAC,aACAC,kBACAC,SACAC,SACAC,UACAC,oBAAoB,SACI;CACxB,MAAM,CAACC,YAAYC,iBAAiBjB,SAASe,iBAAiB;CAC9D,MAAM,CAACG,MAAMC,WAAWnB,SAAS,EAAE;CACnC,MAAMoB,QAAQC,SAAuB;EACnCX,YAAYW,IAAI;EAChBF,QAAQ,EAAE;EACVF,cAAc,KAAK;CACrB;CACA,MAAMK,UAAU,CAAC,IAAI,GAAGjB,cAAcO,SAASH,KAAKE,gBAAgB,CAAC;CAErE,OACE,qBAAC,MAAD;EAAM,OAAOY,SAAOC;EAApB,UAAA;GACE,qBAAC,MAAD;IAAM,OAAOD,SAAOE;IAApB,UAAA,CACE,oBAAC,MAAD;KAAM,OAAOF,SAAOG;KAClB,UAAA,oBAAC,OAAD;MACE,QAAO;MACP,oBAAmB;MACnB,MAAK;MACL,OAAOnB;MACP,eAAeoB,SAASnB,gBAAgBL,iBAAiBwB,IAAI,CAAC;MAC9D,iBAAiBb;MACjB,aAAY;MACZ,gBAAe;MACf,aAAa;MACb,eAAc;KAAI,CAAA;IAEhB,CAAA,GACN,oBAAC,QAAD;KAAQ,QAAO;KAAoB,SAAQ;KAAU,MAAK;KAAK,SAASA;KACrEP,UAAAA,QAAQqB,KAAK,MAAM,KAAK,eAAe;IAClC,CAAA,CACJ;;GACN,oBAAC,SAAD;IACE,SAAS,oBAAC,YAAD;KAAY,MAAM;KAAI,OAAOf,YAAYgB,KAAAA,IAAY,UAAU;IAAM,CAAA;IAC9E,OAAOzB,kBAAkBK,KAAKE,gBAAgB;IAC9C,aAAY;IACZ,YAAA;IACA,oBAAoB,WAAWP,kBAAkBK,KAAKE,gBAAgB;IACtE,eAAeM,cAAc,IAAI;GAAE,CAAA;GAEpCJ,YAAYgB,KAAAA,IACX,oBAAC,MAAD;IAAM,OAAON,SAAOO;IAAM,UAAA;GAAgD,CAAA,IAE1E,oBAAC,MAAD;IAAM,mBAAkB;IAAQ,QAAO;IAAwB,OAAOP,SAAOV;IAC1EA,UAAAA;GACG,CAAA;GAER,oBAAC,OAAD;IAAO,MAAMG;IAAY,cAAcC;IACrC,UAAA,qBAAC,cAAD,EAAA,UAAA;KACE,oBAAC,aAAD;MAAa,YAAW;MACtB,UAAA,oBAAC,YAAD,EAAA,UAAY,UAAmB,CAAA;KACpB,CAAA;KACb,qBAAC,WAAD,EAAA,UAAA,CACE,oBAAC,MAAD,EAAA,UACGK,QAAQS,KAAKC,WACZ,oBAAC,SAAD;MAEE,OAAOA,WAAW,KAAK,sBAAsB5B,kBAAkB4B,QAAQrB,gBAAgB;MACvF,aAAaqB,WAAW,KAAMrB,oBAAoB,+BAAgCqB;MAClF,UAAUA,WAAWvB;MACrB,eAAeW,KAAKY,MAAM;KAAE,GAJvBA,MAIuB,CAE/B,EACG,CAAA,GACN,oBAAC,OAAD;MACE,QAAO;MACP,oBAAmB;MACnB,OAAOd;MACP,eAAeS,SAASR,QAAQhB,iBAAiBwB,IAAI,CAAC;MACtD,uBAAuB;OACrB,IAAIT,KAAKU,KAAK,MAAM,IAAIR,KAAKF,KAAKU,KAAK,CAAC;MAC1C;MACA,aAAY;MACZ,gBAAe;MACf,aAAa;MACb,eAAc;KAAM,CAAA,CAEb,EAAA,CAAA;KACX,oBAAC,aAAD,EAAA,UAAa,uDAAiE,CAAA;IAClE,EAAA,CAAA;GACT,CAAA;EACH;;AAEV;AAEA,MAAML,WAAStB,WAAWgC,QAAQC,WAA0B;CAC1DV,KAAK;EAAEW,KAAKD,MAAME,QAAQ,GAAG;EAACC,mBAAA,CAAA,CAAA;CAAC;CAC/BZ,MAAM;EAAEa,eAAe;EAAOC,YAAY;EAAUJ,KAAKD,MAAME,QAAQ,CAAC;EAACC,mBAAA,CAAA,CAAA;CAAC;CAC1EX,MAAM,EAAEc,MAAM,EAAE;CAChBV,MAAM;EACJW,OAAOP,MAAMQ,OAAOC;EACpBC,YAAYtD,OAAO4C,MAAMU,WAAWC,IAAI;EACxCC,UAAUZ,MAAMY,SAASC;EACzBC,YAAYd,MAAMc,WAAWD;EAAEV,mBAAA,CAAA,CAAA;CACjC;CACAxB,SAAS;EACP4B,OAAOP,MAAMQ,OAAOO;EACpBL,YAAYtD,OAAO4C,MAAMU,WAAWC,IAAI;EACxCC,UAAUZ,MAAMY,SAASC;EACzBC,YAAYd,MAAMc,WAAWD;EAAEV,mBAAA,CAAA,CAAA;CACjC;AACF,EAAE;;;ACtIF,MAAa,eAAe;;;;;;;;;;;;;ACsG5B,MAAa,oBAAoB;CAC/B,OAAO;CACP,MAAM;CACN,YAAY;CACZ,cAAc;CACd,MAAM;CACN,YAAY;AACd;;;;;;;;;;;;;;;;;AC3FA,MAAM,SAAS;CACb,KAAK;EACH,QAAQ;EACR,MAAM,aAAa,aAAa;EAChC,OAAO;GACL,kBAAkB;GAClB,kBAAkB;GAClB,kBAAkB;GAClB,kBAAkB;EACpB;EACA,UAAU,KAAA;CACZ;;;;;;;;CAQA,WAAW;EACT,QAAQ;EACR,MAAM,aAAa,aAAa;EAChC,OAAO,CAAC,kBAAkB,IAAI;EAC9B,QAAQ;CACV;;CAEA,cAAc;EACZ,QAAQ;EACR,MAAM,aAAa,aAAa;EAChC,OAAO,CAAC,kBAAkB,IAAI;EAC9B,QAAQ;CACV;;CAEA,SAAS;EACP,QAAQ;EACR,MAAM,aAAa,aAAa;EAChC,OAAO,CAAC,kBAAkB,IAAI;EAC9B,UAAU,KAAA;CACZ;CACA,YAAY;EACV,QAAQ;EACR,MAAM,aAAa,aAAa;EAChC,OAAO,CAAC,kBAAkB,MAAM,kBAAkB,UAAU;EAC5D,UAAU,KAAA;CACZ;CACA,OAAO;EACL,QAAQ;EACR,MAAM,aAAa,aAAa;CAClC;AACF;AC5DA,MAAa,MAAM,gBAAgB,QAAQ;CACzC,QAAQ,CAHgB,SAGhB;CACR,UAAU;CACV,WAAW;CACX,gBAAgB;AAClB,CAAC;;;ACSD,MAAM,cAAc;AAEpB,SAAS,SAAS,OAAkD;CAClE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;;AAGA,eAAsB,eACpB,WACA,OACA,SAA+B,CAAC,GAChC,QAC0B;CAC1B,MAAM,SAAS,MAAM,IAAI,QAAQ,SAAS,CAAC,CAAC,IAAI;EAC9C,QAAQ,GAAG,eAAe,MAAM;EAGhC,OAAO;IACJ,kBAAkB,QAAQ,OAAO;IACjC,kBAAkB,OAAO,OAAO,SAAS,KAAK,KAAA,IAAY,OAAO;IACjE,kBAAkB,aAAa,OAAO,eAAe,OAAO,OAAO,KAAA;IACnE,kBAAkB,eAAe,OAAO;EAC3C;EACA,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO;CAC3C,CAAC;CACD,IAAI,CAAC,OAAO,IAAI;EAId,IAAI,OAAO,WAAW,GAAG,OAAO,EAAE,OAAO,QAAQ,YAAY,OAAO,KAAK,YAAY;EACrF,OAAO,EAAE,OAAO,OAAO,UAAU,KAAK,oBAAoB,OAAO,OAAO,MAAM,EAAE,KAAK,OAAO,MAAM;CACpG;CACA,IAAI,CAAC,SAAS,OAAO,IAAI,KAAK,OAAO,OAAO,KAAK,SAAS,UACxD,OAAO,EAAE,OAAO,oBAAoB,OAAO,OAAO,MAAM,EAAE,GAAG;CAE/D,OAAO,EAAE,OAAO,OAAO,KAAK;AAC9B;;;ACpDA,SAAgBqB,WAAWC,WAA0B;CACnD,MAAMC,YAAYT,aAAaU,aAAyB;EACtD,MAAMC,eAAeL,QAAQM,MAAMH,UAAUC,QAAQ;EACrD,aAAaC,aAAaE,YAAY;CACxC,GAAG,CAAA,CAAE;CACL,OAAOV,qBAAqBM,iBAAiBH,QAAQQ,OAAOR,QAAQM,MAAMG,OAAOP,SAAS,CAAC;AAC7F;;AAGA,SAAgBQ,sBAAsB;CACpC,MAAMP,YAAYT,aAAaU,aAAyB;EACtD,MAAMC,eAAeP,SAASa,iBAAiB,UAAUP,QAAQ;EACjE,aAAaC,aAAaO,OAAO;CACnC,GAAG,CAAA,CAAE;CACL,OAAOf,qBAAqBM,iBAAiBL,SAASe,iBAAiB,QAAQ;AACjF;AAEA,SAAgBC,eAAeC,QAAiBC,UAAkB;CAChE,MAAM,CAACC,KAAKC,UAAUtB,eAAeuB,KAAKF,IAAI,CAAC;CAC/CtB,gBAAgB;EACd,IAAI,CAACoB,QAAQ;EACb,IAAIK;EACJ,MAAMG,eAAe;GACnBC,cAAcJ,KAAK;GACnB,IAAItB,SAASe,iBAAiB,UAAU;GACxCK,OAAOC,KAAKF,IAAI,CAAC;GACjBG,QAAQE,kBAAkBJ,OAAOC,KAAKF,IAAI,CAAC,GAAGD,QAAQ;EACxD;EACA,MAAMX,eAAeP,SAASa,iBAAiB,UAAUY,MAAM;EAC/DA,OAAO;EACP,aAAa;GACXC,cAAcJ,KAAK;GACnBf,aAAaO,OAAO;EACtB;CACF,GAAG,CAACG,QAAQC,QAAQ,CAAC;CACrB,OAAOC;AACT;;AAGA,SAAgBQ,cAAcvB,WAA0BwB,OAAeC,SAAkB;CACvF,MAAMC,aAAalB,oBAAoB;CACvC,MAAM,CAACmB,MAAMC,WAAWlC,SAAuC;CAC/DD,gBAAgB;EACd,IAAIO,cAAc,QAAQ,CAACyB,WAAW,CAACC,YAAY;EACnD,MAAMK,aAAa,IAAIC,gBAAgB;EACvC,IAAId;EACJ,MAAMgB,OAAO,YAAY;GACvB,IAAI;IACF,MAAMC,SAAS,MAAMtC,eAAeG,WAAWwB,OAAO,EAAEY,OAAO,EAAE,GAAGL,WAAWM,MAAM;IACrF,IAAIN,WAAWM,OAAOC,SAAS;IAC/B,IAAI,WAAWH,QAAQ;KACrB,MAAML,OAAOK,OAAOI,MAAMT,KACvBU,MAAM,IAAI,CAAC,CACXC,KAAKC,SAASA,KAAKC,KAAK,CAAC,CAAC,CAC1BC,OAAOC,OAAO,CAAC,CACfC,GAAG,EAAE;KACR,IAAIhB,SAASiB,KAAAA,GAAWnB,QAAQ;MAAEC,IAAI,GAAG7B,UAAS,GAAIwB;MAASM;KAAK,CAAC;KACrE,IAAI,CAACK,OAAOI,MAAMd,SAAS;IAC7B;GACF,QAAQ,CACN;GAEF,IAAI,CAACM,WAAWM,OAAOC,SAASpB,QAAQe,iBAAiB,KAAKC,KAAK,GAAG,GAAK;EAC7E;EACA,KAAU;EACV,aAAa;GACXH,WAAWiB,MAAM;GACjBC,aAAa/B,KAAK;EACpB;CACF,GAAG;EAAClB;EAAWwB;EAAOC;EAASC;CAAU,CAAC;CAC1C,OAAOD,WAAWE,MAAME,OAAO,GAAG7B,UAAS,GAAIwB,UAAUG,KAAKG,OAAOiB,KAAAA;AACvE;;;;AC9DA,SAAgB0B,gBAAgB,EAC9BC,KACAC,MACAC,kBACAC,UAMC;CACD,MAAMC,QAAQZ,YAAYQ,GAAG;;CAE7B,MAAM,CAACK,aAAaC,kBAAkBnB,SAAS,KAAK;CACpD,OACE,qBAAA,UAAA,EAAA,UAAA,CACE,qBAAC,MAAD;EAAM,OAAOoB,SAAOC;EAApB,UAAA;GACE,oBAAC,MAAD;IAAM,eAAe;IAAG,OAAOD,SAAOE;IACnCR,UAAAA;GACG,CAAA;GACN,oBAAC,aAAD;IAAa,MAAMG,MAAMM;IAAON,UAAAA,MAAMO;GAAmB,CAAA;GACzD,oBAAC,MAAD,EAAM,OAAOJ,SAAOK,KAAK,CAAA;GACxBT;EACG;CACLH,CAAAA,GAAAA,MACC,qBAAC,WAAD;EACE,QAAO;EACP,mBAAkB;EAClB,oBAAoB,EAAEa,UAAUR,YAAY;EAC5C,mBAAmBA,cAAc,0BAA0B;EAC3D,OAAOE,SAAOO;EACd,eAAeR,gBAAgBS,SAAS,CAACA,IAAI;EAN/C,UAAA,CAQE,qBAAC,MAAD;GAAM,YAAYV;GAAa,eAAeA,cAAcW,KAAAA,IAAY;GAAG,OAAOT,SAAOU;GAAzF,UAAA,CACE,oBAAC,MAAD;IAAM,OAAOV,SAAOW;IAAQ,UAAA;GAAQ,CAAA,GACnClB,IAAIiB,OACD;EACLZ,CAAAA,GAAAA,cACC,qBAAC,MAAD;GAAM,eAAe;GAAG,OAAOE,SAAOY;GAAtC,UAAA,CAA6C,OACvC1B,kBAAkBO,IAAIoB,KAAKlB,gBAAgB,CAC3C;EACJ,CAAA,IAAA,IACK;CAEX,CAAA,IAAA,oBAAC,MAAD;EAAM,OAAOK,SAAOc;EAAM,UAAA;CAA+C,CAAA,CAE7E,EAAA,CAAA;AAEJ;AAEA,SAAgBC,aAAatB,KAAoB;CAC/C,OAAO;EACLuB,IAAI,cAAcvB,IAAIuB;EACtBZ,OAAO,SAASX,IAAIC;EACpBuB,QAAQC,UAA8B,oBAAC,gBAAD;GAAgB,GAAIA;GAAO,OAAOzB,IAAIuB;EAAG,CAAA;CACjF;AACF;AAEA,SAAgBG,eAAe,EAAEC,WAAWC,OAAOC,oBAA4D;CAC7G,MAAMC,UAAUjC,WAAW8B,SAAS;CACpC,MAAMI,aAAajC,oBAAoB;CACvC,MAAME,MAAM8B,QAAQE,KAAKC,MAAMC,cAAcA,UAAUX,OAAOK,KAAK;CACnE,MAAM,CAACO,OAAOC,YAAYjD,SAAS,EAAE;CACrC,MAAM,CAACkD,OAAOC,YAAYnD,SAAS,EAAE;CACrC,MAAM,CAACoD,YAAYC,iBAAiBrD,SAAS,KAAK;CAClD,MAAM,CAACsD,SAASC,cAAcvD,SAAS,CAAC;CACxC,MAAM,CAACwD,WAAWC,gBAAgBzD,SAAS,IAAI;CAC/C,MAAM0D,aAAa,GAAGlB,UAAS,GAAIC,MAAK,GAAIS,MAAK,GAAIE,WAAU,GAAIE,QAAO,GAAIE;CAC9E,MAAM,CAACG,QAAQC,aAAa5D,SAAoE;CAChG,MAAM8D,QAAQH,QAAQE,QAAQH,aAAaC,OAAOG,QAAQjC,KAAAA;CAC1D,MAAMkC,QAAQJ,QAAQE,QAAQH,aAAaC,OAAOI,QAAQ;CAC1DjE,gBAAgB;EACd,MAAMkE,QAAQC,iBAAiBd,SAASH,KAAK,GAAG,GAAG;EACnD,aAAakB,aAAaF,KAAK;CACjC,GAAG,CAAChB,KAAK,CAAC;CACVlD,gBAAgB;EACd,IAAI0C,cAAc,QAAQ,CAACI,YAAY;EACvC,MAAMuB,aAAa,IAAIC,gBAAgB;EACvC,IAAIJ;EACJ,MAAMM,OAAO,YAAY;GACvB,MAAMC,SAAS,MAAM/D,eACnBgC,WACAC,OACA;IAAE+B,OAAO;IAAMC,MAAMvB;IAAOE;IAAYsB,cAAcpB;GAAQ,GAC9Da,WAAWQ,MACb;GACA,IAAIR,WAAWQ,OAAOC,SAAS;GAC/BhB,WAAWiB,aAAa;IACtB,MAAMC,OACJ,WAAWP,SACP;KAAEV,KAAKH;KAAYK,OAAOQ,OAAOR;IAAM,IACvC;KAAEF,KAAKH;KAAYI,OAAOS,OAAOT;KAAOC,OAAO;IAAG;IACxD,IAAIc,UAAUhB,QAAQiB,KAAKjB,OAAOgB,SAASd,UAAUe,KAAKf,OAAO,OAAOe;IACxE,MAAMC,SAASF,SAASf;IACxB,MAAMkB,QAAQF,KAAKhB;IACnB,IAAIiB,WAAWC,OAAO,OAAOH;IAC7B,IAAI,CAACE,UAAU,CAACC,OAAO,OAAOF;IAc9B,OAZEC,OAAOG,SAASF,MAAME,QACtBH,OAAOI,eAAeH,MAAMG,cAC5BJ,OAAOK,cAAcJ,MAAMI,aAC3BL,OAAOM,aAAaL,MAAMK,YAC1BN,OAAOO,kBAAkBN,MAAMM,iBAC/BP,OAAOQ,SAASP,MAAMO,QACtBR,OAAOS,WAAWR,MAAMQ,UACxBT,OAAOU,cAAcT,MAAMS,aAC3BV,OAAOtC,UAAUuC,MAAMvC,SACvBsC,OAAOW,YAAYV,MAAMU,WACzBX,OAAOY,aAAaC,WAAWZ,MAAMW,aAAaC,WACjDb,OAAOY,aAAaE,OAAOC,QAAQC,UAAUD,WAAWd,MAAMW,cAAcI,MAAM,KAAK,QAC3ElB,WAAWC;GAC5B,CAAC;GACD,IAAItB,aAAaN,UAAU,OAAO,WAAWqB,UAAUA,OAAOT,MAAM4B,UAClE1B,QAAQC,iBAAiB,KAAKK,KAAK,GAAG,GAAK;EAC/C;EACA,KAAU;EACV,aAAa;GACXH,WAAW6B,MAAM;GACjB9B,aAAaF,KAAK;EACpB;CACF,GAAG;EAACxB;EAAWC;EAAOS;EAAOE;EAAYE;EAASE;EAAWE;EAAYd;CAAU,CAAC;CACpF,MAAMqD,WAAWtD,QAAQuD,cAAcC,SAAS1D,KAAK;CACrD,MAAM2D,OAAO5C,aAAaN,UAAU,MAAMY,OAAO4B,YAAY;CAC7D,OACE,qBAAC,MAAD;EAAM,QAAO;EAAmB,OAAOtE,SAAOiB;EAA9C,UAAA;GACE,oBAAC,iBAAD;IACOxB;IACL,MAAMA,KAAKC,QAAQ2B;IACnB,kBAAkBE,QAAQ5B;IAC1B,QACEF,KAAKwF,UAAU,aAAa7D,cAAc,OACxC,oBAAC,QAAD;KACE,SAASyD,WAAW,YAAY;KAChC,MAAK;KACL,UAAUA;KACV,eAAexF,kBAAkBiC,kBAAkBF,WAAWC,KAAK;KAElEwD,UAAAA,WAAW,cAAc;IACpB,CAAA,IACN;GACL,CAAA;GAEH,oBAAC,OAAD;IACE,QAAO;IACP,oBAAmB;IACnB,aAAY;IACZ,OAAOjD;IACP,cAAcC;IACd,gBAAe;IACf,eAAc;GAAQ,CAAA;GAExB,qBAAC,MAAD;IAAM,OAAO7B,SAAOkF;IAApB,UAAA;KACE,oBAAC,QAAD;MACE,SAASlD,aAAa,WAAW;MACjC,MAAK;MACL,oBAAoB,EAAEmD,UAAUnD,WAAW;MAC3C,eAAeC,eAAemD,UAAU,CAACA,KAAK;MAE7CpD,UAAAA,aAAa,aAAa;KACrB,CAAA;KACPF,UAAU,KAAK,OACd,oBAAC,QAAD;MACE,SAASI,UAAU,IAAI,WAAW;MAClC,MAAK;MACL,eAAeC,YAAYiD,UAAWA,UAAU,IAAI,IAAI,CAAE;MAEzD,UAAA,KAAKC,OAAOnD,OAAO,EAAC;KACf,CAAA;KAETJ,UAAU,MAAMY,OAAO4B,YAAY,OAClC,oBAAC,QAAD;MACE,SAASU,OAAO,WAAW;MAC3B,MAAK;MACL,oBAAoB,EAAEG,UAAUH,KAAK;MACrC,eAAe3C,cAAc+C,UAAU,CAACA,KAAK;MAE5CJ,UAAAA,OAAO,cAAc;KAChB,CAAA,IACN;IACA;;GACN,oBAAC,iBAAD;IAAwBtC;IAAcC;IAAcb;IAAakD;GAAK,CAAA;GACtE,oBAAC,MAAD;IAAM,YAAA;IAAW,eAAe;IAAG,eAAc;IAAS,OAAOhF,SAAOmE;IACrE1E,UAAAA,KAAK6F,WAAW5C,OAAOyB,QAAQ;GAC5B,CAAA;EACF;;AAEV;AACA,MAAMoB,kBAAkBhH,KAAK,SAASgH,gBAAgB,EACpD7C,OACAC,OACAb,OACAkD,QAMC;CACD,MAAM5B,QAAQzE,cAAcK,aAAa0D,OAAOoB,QAAQ,IAAI,CAAA,GAAI,GAAI,CAAC,CAACV,OAAO,CAACV,OAAOoB,IAAI,CAAC;CAC1F,MAAM0B,OAAO7G,cAAc;EACzB,MAAM8G,UAAU3D,UAAU,KAAK3C,gBAAgBuD,OAAOqB,cAAc,GAAGX,MAAMoB,MAAM,IAAK9B,OAAO6B,eAAe,CAAA;EAC9G,MAAMmB,SAASL,OAAOI,QAAQE,GAAG,EAAE,KAAK,CAAC,CAAC,CAACnB;EAC3C,OAAOpB,MAAMwC,KAAK9B,MAAMa,WAAW;GACjClC,KAAK4C,OAAOI,QAAQd,UAAUA,KAAK;GACnCD,QAAQ,GAAGW,OAAOI,QAAQd,UAAU,EAAE,CAAC,CAACkB,SAASH,MAAM,EAAC;GACxD5B;EACF,EAAE;CACJ,GAAG;EAACV;EAAOtB;EAAOY,OAAOqB;EAAYrB,OAAO6B;CAAW,CAAC;CACxD,MAAMuB,aAAarH,aAChB,EAAEsH,WACD,qBAAC,MAAD;EAAM,YAAA;EAAW,OAAO/F,SAAOgG;EAA/B,UAAA,CACE,oBAAC,MAAD;GAAM,OAAOhG,SAAO0E;GAASqB,UAAAA,KAAKrB;EAAa,CAAA,GAC9CqB,KAAKjC,IACF;CAER,CAAA,GAAA,CAAA,CACF;CACA,MAAMmC,eAAexH,aAAasH,SAAgCA,KAAKtD,KAAK,CAAA,CAAE;CAC9E,MAAMyD,QACJvD,UAAU,KACR,oBAAC,MAAD;EAAM,mBAAkB;EAAQ,OAAO3C,SAAO2C;EAC3CA,UAAAA;CACG,CAAA,IACJD,OAAO0B,WAAW,QACpB,oBAAC,MAAD;EAAM,OAAOpE,SAAOc;EAAM,UAAA;CAA4C,CAAA,IACpE4B,QACF,oBAAC,MAAD;EAAM,OAAO1C,SAAOc;EAAOgB,UAAAA,UAAU,KAAK,sBAAsB;CAAyB,CAAA,IACvF;CACN,OACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,MAAD;EAAM,OAAO9B,SAAOc;EACjB4B,UAAAA,UAAUjC,KAAAA,IACPkC,UAAU,KACR,aACA,KACFb,UAAU,KACR,GAAGY,MAAMsB,UAAS,eAAgBtB,MAAMqB,WAAU,UAClD,GAAGiB,OAAO,YAAY,UAAS,QAAS5B,MAAMoB,OAAM,MAAO9B,MAAMqB,WAAU;CAC7E,CAAA,GACN,oBAAC,UAAD;EACE,OAAO/D,SAAOmG;EACd,uBAAuBnG,SAAOoG;EAC9B,MAAMzD,UAAU,MAAMD,OAAO0B,WAAW,QAAQ,CAAA,IAAKoB;EACzCM;EACEG;EACd,oBAAoBC;EACpB,oBAAoB;EACpB,qBAAqB;EACrB,YAAY;EACZ,oBAAmB;CAAmB,CAAA,CAE1C,EAAA,CAAA;AAEJ,CAAC;AAED,MAAMlG,WAASnB,WAAWwH,QAAQC,WAA0B;CAC1DrF,OAAO;EAAEsF,MAAM;EAAGC,KAAKF,MAAMG,QAAQ,CAAC;EAAGC,SAASJ,MAAMG,QAAQ,CAAC;EAAGE,iBAAiBL,MAAMM,OAAOC;EAAEC,mBAAA,CAAA,CAAA;CAAC;CACrG7G,QAAQ;EAAE8G,eAAe;EAAOC,YAAY;EAAUR,KAAKF,MAAMG,QAAQ,CAAC;EAAGQ,WAAW;EAAEH,mBAAA,CAAA,CAAA;CAAC;CAC3FzG,MAAM,EAAEkG,MAAM,EAAE;CAChBrG,OAAO;EACLgH,YAAY;EACZC,OAAOb,MAAMM,OAAOQ;EACpBC,YAAY;EACZC,YAAYpJ,OAAOoI,MAAMgB,WAAWC,IAAI;EACxCC,UAAUlB,MAAMkB,SAASC;EAAIX,mBAAA,CAAA,CAAA;CAC/B;CACAvG,YAAY;EACViG,KAAKF,MAAMG,QAAQ,CAAC;EACpBiB,mBAAmBpB,MAAMG,QAAQ,CAAC;EAClCkB,iBAAiBrB,MAAMG,QAAQ,CAAC;EAChCmB,cAActB,MAAMsB,aAAaC;EACjClB,iBAAiBL,MAAMM,OAAOkB;EAAIhB,mBAAA,CAAA,CAAA;CACpC;CACApG,SAAS;EAAEyG,OAAOb,MAAMM,OAAOQ;EAAIE,YAAYpJ,OAAOoI,MAAMgB,WAAWS,IAAI;EAAGP,UAAUlB,MAAMkB,SAASQ;EAAElB,mBAAA,CAAA,CAAA;CAAC;CAC1GnG,QAAQ;EAAEwG,OAAOb,MAAMM,OAAOqB;EAAKnB,mBAAA,CAAA,CAAA;CAAC;CACpClG,QAAQ;EAAEuG,OAAOb,MAAMM,OAAOsB;EAAKZ,YAAYpJ,OAAOoI,MAAMgB,WAAWS,IAAI;EAAGP,UAAUlB,MAAMkB,SAASW;EAAErB,mBAAA,CAAA,CAAA;CAAC;CAC1GhG,MAAM;EACJqG,OAAOb,MAAMM,OAAOsB;EACpBZ,YAAYpJ,OAAOoI,MAAMgB,WAAWC,IAAI;EACxCC,UAAUlB,MAAMkB,SAASQ;EACzBI,YAAY9B,MAAM8B,WAAWJ;EAAElB,mBAAA,CAAA,CAAA;CACjC;CACAnE,OAAO;EAAEwE,OAAOb,MAAMM,OAAOyB;EAAKf,YAAYpJ,OAAOoI,MAAMgB,WAAWC,IAAI;EAAGC,UAAUlB,MAAMkB,SAASQ;EAAElB,mBAAA,CAAA,CAAA;CAAC;CACzG5B,SAAS;EAAE6B,eAAe;EAAOP,KAAKF,MAAMG,QAAQ,CAAC;EAAG6B,UAAU;EAAMxB,mBAAA,CAAA,CAAA;CAAC;CACzEX,KAAK;EAAEI,MAAM;EAAGqB,cAActB,MAAMsB,aAAaC;EAAIlB,iBAAiBL,MAAMM,OAAOkB;EAAIhB,mBAAA,CAAA,CAAA;CAAC;CACxFV,SAAS;EAAEM,SAASJ,MAAMG,QAAQ,CAAC;EAACK,mBAAA,CAAA,CAAA;CAAC;CACrCd,MAAM;EACJmB,OAAOb,MAAMM,OAAO9C;EACpBwD,YAAYpJ,OAAOoI,MAAMgB,WAAWS,IAAI;EACxCP,UAAUlB,MAAMkB,SAASW;EACzBC,YAAY9B,MAAM8B,WAAWJ;EAAElB,mBAAA,CAAA,CAAA;CACjC;CACApC,QAAQ;EAAEyC,OAAOb,MAAMM,OAAOqB;EAAKnB,mBAAA,CAAA,CAAA;CAAC;CACpC3C,MAAM;EAAEgD,OAAOb,MAAMM,OAAOqB;EAAOX,YAAYpJ,OAAOoI,MAAMgB,WAAWS,IAAI;EAAGP,UAAUlB,MAAMkB,SAASW;EAAErB,mBAAA,CAAA,CAAA;CAAC;AAC5G,EAAE;;;;AChTF,eAAsB,iBACpB,WACA,OACA,MACA,YACA,QAC+B;CAC/B,MAAM,SAAS,MAAM,IAAI,QAAQ,SAAS,CAAC,CAAC,WAAW;EACrD,QAAQ,GAAG,eAAe,MAAM;EAChC,OAAO;IAAG,kBAAkB,OAAO;IAAO,kBAAkB,aAAa;EAAW;EACpF;CACF,CAAC;CACD,IAAI,CAAC,OAAO,IAAI,MAAM,IAAI,MAAM,OAAO,SAAS,sCAAsC;CACtF,OAAO,OAAO;AAChB;AACA,eAAsB,gBAAgB,WAAmB,OAAe,MAA6B;CACnG,MAAM,SAAS,MAAM,IAAI,QAAQ,SAAS,CAAC,CAAC,MAAM;EAAE,QAAQ,GAAG,eAAe,MAAM;EAAG,MAAM,EAAE,KAAK;CAAE,CAAC;CACvG,IAAI,CAAC,OAAO,IAAI,MAAM,IAAI,MAAM,OAAO,SAAS,2CAA2C;AAC7F;;;;ACTA,SAAgBwC,eAAeC,KAAoB;CACjD,OAAO;EACLC,IAAI,gBAAgBD,IAAIC;EACxBC,OAAO,WAAWF,IAAIG;EACtBC,QAAQC,UAA8B,oBAAC,kBAAD;GAAkB,GAAIA;GAAO,OAAOL,IAAIC;EAAG,CAAA;CACnF;AACF;;;;;;AAOA,SAAgBK,iBAAiB,EAC/BC,WACAC,OACAC,sBACAC,kBACAC,oBACyC;CACzC,MAAMC,UAAUhB,WAAWW,SAAS;CACpC,MAAMP,MAAMY,QAAQC,KAAKC,MAAMC,cAAcA,UAAUd,OAAOO,KAAK;CACnE,MAAMQ,OAAOhB,KAAKiB,UAAU;CAC5B,MAAMC,WAAWN,QAAQO,cAAcC,SAASZ,KAAK;CACrD,MAAMa,UAAU/B,cAEZiB,cAAc,OACVe,KAAAA,IACA;EACEC,KAAK,GAAGhB,UAAS,GAAIC;EACrBgB,OAAOC,MAAcC,YAAgCC,WACnDjC,iBAAiBa,WAAWC,OAAOiB,MAAMC,YAAYC,MAAM;EAC7DE,QAAQC,SAAiBnC,gBAAgBY,WAAWC,OAAOsB,IAAI;CACjE,GACN,CAACvB,WAAWC,KAAK,CACnB;CACA,OACE,qBAAC,MAAD;EAAM,OAAOuB,SAAO3B;EAApB,UAAA;GACE,oBAAC,iBAAD;IACOJ;IACL,MAAMA,KAAKG,QAAQK;IACnB,kBAAkBI,QAAQoB;IAC1B,QACEhB,QAAQT,cAAc,OACpB,oBAAC,QAAD;KACE,QAAO;KACP,SAASW,WAAW,YAAY;KAChC,MAAK;KACL,UAAUA;KACV,eAAezB,kBAAkBiB,kBAAkBH,WAAWC,KAAK;KAElEU,UAAAA,WAAW,cAAc;IACpB,CAAA,IACN;GACL,CAAA;GAEH,oBAAC,MAAD;IAAM,OAAOa,SAAOE;IACjBZ,UAAAA,YAAYC,KAAAA,IACX,oBAAC,MAAD;KAAM,OAAOS,SAAOG;KAAM,UAAA;IAAgD,CAAA,IAE1EzB,uBAAuBY,OAAO;GAE5B,CAAA;GACN,qBAAC,MAAD;IAAM,OAAOU,SAAOI;IAApB,UAAA,CACGnC,MACC,qBAAC,QAAD;KACE,QAAO;KACP,SAAQ;KACR,eAAeW,iBAAiBb,aAAaE,GAAG,CAAC;KACjD,OAAO+B,SAAOK;KAJhB,UAAA,CAME,oBAAC,YAAD,EAAY,MAAM,GAAG,CAAA,GAAA,eAEf;IACN,CAAA,IAAA,MACHpB,QAAQT,cAAc,OACrB,oBAAC,QAAD;KACE,QAAO;KACP,SAAQ;KACR,eAAe,KAAKZ,gBAAgBY,WAAWC,OAAO,GAAQ;KAC9D,OAAOuB,SAAOK;KAAO,UAAA;IAGf,CAAA,IACN,IACA;;EACF;;AAEV;AACA,MAAML,WAASxC,WAAW8C,QAAQC,WAA0B;CAC1DlC,OAAO;EAAEmC,MAAM;EAAGC,KAAKF,MAAMG,QAAQ,CAAC;EAAGC,SAASJ,MAAMG,QAAQ,CAAC;EAAGE,iBAAiBL,MAAMM,OAAOC;EAAEC,mBAAA,CAAA,CAAA;CAAC;CACrGX,SAAS;EAAEY,eAAe;EAAOP,KAAKF,MAAMG,QAAQ,CAAC;EAACK,mBAAA,CAAA,CAAA;CAAC;CACvDV,QAAQ,EAAEG,MAAM,EAAE;CAClBN,UAAU,EAAEM,MAAM,EAAE;CACpBL,MAAM;EAAEc,OAAOV,MAAMM,OAAOK;EAAKC,YAAYhE,OAAOoD,MAAMY,WAAWC,IAAI;EAAGC,UAAUd,MAAMc,SAASC;EAAEP,mBAAA,CAAA,CAAA;CAAC;AAC1G,EAAE;;;;ACvFF,SAASkC,UAAUC,KAAoB;CACrC,OAAOA,IAAIC,cAAcH,eAAeE,GAAG,IAAIH,aAAaG,GAAG;AACjE;AAEA,SAAgBE,aAAa;CAC3B,OAAO;EAAEC,IAAI;EAAeC,OAAO;EAAWC,OAAOC;CAAa;AACpE;AAEA,SAASC,UAAU,EACjBP,KACAQ,OACAC,UACAC,OAMC;CACD,MAAMC,OAAOhB,cAAca,MAAMI,WAAWZ,IAAIG,IAAIH,IAAIa,UAAU,SAAS;CAG3E,OACE,qBAAC,WAAD;EACE,QAAQ,mBAAmBb,IAAIG;EAC/B,mBAAkB;EAClB,oBAAoB,QAAQH,IAAIc;EAChC,eAAeN,MAAMO,iBAAiBhB,UAAUC,GAAG,CAAC;EACpD,QAAQ,EAAEgB,cAAc,CAACC,OAAOC,KAAKF,WAAWC,OAAOD,OAAO;EALhE,UAAA,CAOE,qBAAC,MAAD;GAAM,OAAOC,OAAOE;GAApB,UAAA;IACE,oBAAC,KAAD;KAAK,MAAK;KAAS,OAAA;IAAK,CAAA;IACxB,oBAAC,MAAD;KAAM,eAAe;KAAG,OAAOF,OAAOH;KACnCd,UAAAA,IAAIc;IACD,CAAA;IACN,oBAAC,MAAD;KAAM,OAAOG,OAAOG;KAAOjC,UAAAA,mBAAmBa,IAAIqB,WAAWX,GAAG;IAAQ,CAAA;IACvEF,MAAMI,cAAc,OACnB,oBAAC,QAAD;KACE,QAAQ,wBAAwBZ,IAAIG;KACpC,MAAK;KACL,SAASM,WAAW,YAAY;KAChC,UAAUA;KACV,eAAe;MACb,IAAID,MAAMI,cAAc,MAAMrB,kBAAkBiB,MAAMc,kBAAkBd,MAAMI,WAAWZ,IAAIG,EAAE;KACjG;KAECM,UAAAA,WAAW,cAAc;IACpB,CAAA,IACN;GACA;EACN,CAAA,GAAA,oBAAC,MAAD;GAAM,eAAe;GAAG,OAAOQ,OAAON;GACnCA,UAAAA,QAAQ,KAAKX,IAAIuB;EACd,CAAA,CACG;;AAEf;AAEA,SAAgBC,uBAAuBhB,OAA2B;CAChE,MAAMiB,UAAU/B,WAAWc,MAAMI,SAAS;CAE1C,MAAMc,SAAS1C,qBAAqBQ,qBAAqBmC,iBACvDnC,qBAAqBoC,SAASpB,MAAMI,SAAS,CAC/C;CACA,MAAMiB,UAAUJ,QAAQK,KAAKC,QAAQ/B,QAAQX,wBAAwBW,GAAG,CAAC;CACzE,MAAMU,MAAMd,eAAe8B,QAAQ,GAAK;CACxC,OAAOG,QAAQG,WAAW,IAExB,qBAAC,MAAD;EAAM,OAAOf,OAAOgB;EAApB,UAAA,CACE,oBAAC,MAAD;GAAM,OAAOhB,OAAOG;GAAM,UAAA;EAAU,CAAA,GACnCZ,MAAMI,cAAc,OACnB,qBAAC,WAAD;GACE,mBAAkB;GAClB,QAAO;GACP,SAAS;GACT,eAAeJ,MAAMO,iBAAiBb,WAAW,CAAC;GAClD,OAAOe,OAAOiB;GALhB,UAAA,CAOE,oBAAC,MAAD;IAAM,OAAOjB,OAAOkB;IAAY,UAAA;GAAqB,CAAA,GACrD,oBAAC,gBAAD;IAAgB,MAAM;IAAI,OAAM;GAAO,CAAA,CAC9B;EACT,CAAA,IAAA,IACA;CAEN,CAAA,IAAA,oBAAC,MAAD,EAAA,UACGN,QAAQO,KAAKpC,QACZ,oBAAC,WAAD;EAA6BA;EAAYQ;EAAYE;EAAK,UAAUe,QAAQY,cAAcC,SAAStC,IAAIG,EAAE;CAAE,GAA3FH,IAAIG,EAAuF,CAC5G,EACG,CAAA;AAEV;;;;;;;AAQA,SAAgBG,aAAaE,OAA2B;CACtD,MAAM,EAAEO,qBAAqBP;CAC7B,MAAMiB,UAAU/B,WAAWc,MAAMI,SAAS;CAC1C,MAAMiB,UAAUJ,QAAQK,KAAKC,QAAQ/B,QAAQA,IAAIa,UAAU,SAAS;CACpE,MAAM,CAACU,SAASgB,cAAcxD,SAAS,EAAE;CACzC,MAAM,CAACyD,KAAKC,UAAU1D,SAAS,EAAE;CACjC,MAAM2B,MAAMd,eAAeiC,QAAQG,SAAS,GAAG,GAAM;CACrD,MAAMU,WAAW5D,OAAmC,IAAI;;CAExD,MAAM8D,WAAW9D,OAAO,EAAE;CAC1B,MAAM+D,UAAU/D,OAAkDkE,KAAAA,CAAS;CAG3EnE,gBAAgB;EACd,IAAI6D,SAASO,YAAY,MAAM;EAC/B,MAAMC,UAAUzB,QAAQK,KAAKqB,MAAMnD,QAAQA,IAAIa,UAAU,aAAa,CAAC6B,SAASO,SAASG,IAAIpD,IAAIG,EAAE,CAAC;EACpG,IAAI+C,YAAYF,KAAAA,GAAW;EAC3BN,SAASO,UAAU;EACnBI,aAAaR,QAAQI,OAAO;EAC5BlC,iBAAiBhB,UAAUmD,OAAO,CAAC;CACrC,GAAG,CAACzB,QAAQK,MAAMf,gBAAgB,CAAC;CAEnC,MAAMuC,YAAY7B,QAAQ8B,cAAcpD;CACxCtB,gBAAgB;EACd,IAAIyE,cAAcN,KAAAA,KAAaN,SAASO,YAAY,MAAM;EAC1DP,SAASO,UAAU;EACnBI,aAAaR,QAAQI,OAAO;EAC5BV,WAAWK,SAASK,OAAO;CAC7B,GAAG,CAACK,SAAS,CAAC;CACdzE,sBAAsBwE,aAAaR,QAAQI,OAAO,GAAG,CAAA,CAAE;CACvD,MAAMf,eAAe;EACnB,IAAI1B,MAAMI,cAAc,MAAM;EAC9B8B,SAASO,UAAU,IAAIO,IAAI/B,QAAQK,KAAKM,KAAKpC,QAAQA,IAAIG,EAAE,CAAC;EAC5DkD,aAAaR,QAAQI,OAAO;EAC5BJ,QAAQI,UAAUF,iBAAiB;GACjCL,SAASO,UAAU;EACrB,GAAG,GAAM;EACT3D,mBAAmBkB,MAAMc,kBAAkBd,MAAMI,WAAWxB,iBAAiBmC,SAASiB,GAAG,CAAC;EAC1FI,SAASK,UAAU1B;EACnBgB,WAAW,EAAE;CACf;CACA,OACE,qBAAC,MAAD;EAAM,OAAOtB,OAAOZ;EAApB,UAAA;GACE,qBAAC,MAAD;IAAM,OAAOY,OAAOwC;IAApB,UAAA,CACE,oBAAC,MAAD;KAAM,OAAOxC,OAAOyC;KAAO,UAAA;IAAa,CAAA,GACxC,oBAAC,MAAD;KAAM,OAAOzC,OAAOG;KAAOS,UAAAA,QAAQG,WAAW,IAAI,oBAAoB,GAAGH,QAAQG,OAAM;IAAiB,CAAA,CACpG;;GACLxB,MAAMI,cAAc,OACnB,oBAAC,kBAAD;IACWW;IACT,iBAAiBgB;IACZC;IACL,aAAaC;IACb,SAASZ,QAAQO,KAAKpC,QAAQA,IAAIwC,GAAG;IACrC,GAAKf,QAAQkC,qBAAqBX,KAAAA,IAAY,CAAC,IAAI,EAAEW,kBAAkBlC,QAAQkC,iBAAiB;IAChG,GAAKlC,QAAQ8B,iBAAiBP,KAAAA,IAAY,CAAC,IAAI,EAAEY,SAASnC,QAAQ8B,aAAaM,QAAQ;IACvF,UAAU3B;GAAO,CAAA,IAEjB;GACJ,oBAAC,YAAD,EAAA,UACGL,QAAQG,WAAW,IAClB,oBAAC,MAAD;IAAM,OAAOf,OAAOG;IACjBZ,UAAAA,MAAMI,cAAc,OACjB,sCACA;GACA,CAAA,IAENiB,QAAQO,KAAKpC,QACX,oBAAC,SAAD;IAEE,SAAS,oBAAC,KAAD;KAAK,MAAK;KAAS,OAAA;IAAK,CAAA;IACjC,OAAOA,IAAIc;IACX,aAAa,GAAGd,IAAIuB,QAAO,KAAMpC,mBAAmBa,IAAIqB,WAAWX,GAAG;IACtE,YAAA;IACA,eAAeK,iBAAiBhB,UAAUC,GAAG,CAAC;GAAE,GAL3CA,IAAIG,EAKuC,CAEnD,EAEO,CAAA;EACR;;AAEV;AACA,MAAMc,SAAShC,WAAW6E,QAAQC,WAA0B;CAC1D1D,OAAO;EAAE2D,MAAM;EAAGC,KAAKF,MAAMG,QAAQ,CAAC;EAAGC,SAASJ,MAAMG,QAAQ,CAAC;EAAGE,iBAAiBL,MAAMM,OAAOC;EAAEC,mBAAA,CAAA,CAAA;CAAC;CACrGd,QAAQ;EAAEe,eAAe;EAAOC,YAAY;EAAUR,KAAKF,MAAMG,QAAQ,CAAC;EAACK,mBAAA,CAAA,CAAA;CAAC;CAC5ErD,KAAK;EAAE+C,KAAKF,MAAMG,QAAQ,CAAC;EAAGQ,iBAAiBX,MAAMG,QAAQ,CAAC;EAACK,mBAAA,CAAA,CAAA;CAAC;CAChEvD,SAAS,EAAE2D,SAAS,GAAI;CACxBxD,MAAM;EAAEqD,eAAe;EAAOC,YAAY;EAAUR,KAAKF,MAAMG,QAAQ,CAAC;EAACK,mBAAA,CAAA,CAAA;CAAC;CAC1EzD,MAAM;EACJkD,MAAM;EACNY,OAAOb,MAAMM,OAAOQ;EACpBC,YAAYtG,OAAOuF,MAAMe,WAAWC,IAAI;EACxCC,UAAUjB,MAAMiB,SAASC;EACzBC,YAAYnB,MAAMmB,WAAWD;EAC7BE,YAAYpB,MAAMoB,WAAWC;EAAMb,mBAAA,CAAA,CAAA;CACrC;CACA5D,MAAM;EAEJ0E,aAAatB,MAAMG,QAAQ,GAAG;EAC9BU,OAAOb,MAAMM,OAAOiB;EACpBR,YAAYtG,OAAOuF,MAAMe,WAAWS,IAAI;EACxCP,UAAUjB,MAAMiB,SAASQ;EACzBN,YAAYnB,MAAMmB,WAAWM;EAAEjB,mBAAA,CAAA,CAAA;CACjC;CACAb,OAAO;EACLkB,OAAOb,MAAMM,OAAOQ;EACpBC,YAAYtG,OAAOuF,MAAMe,WAAWC,IAAI;EACxCC,UAAUjB,MAAMiB,SAASS;EACzBN,YAAY;EAAKZ,mBAAA,CAAA,CAAA;CACnB;CACAnD,MAAM;EACJwD,OAAOb,MAAMM,OAAOiB;EACpBR,YAAYtG,OAAOuF,MAAMe,WAAWC,IAAI;EACxCC,UAAUjB,MAAMiB,SAASQ;EACzBN,YAAYnB,MAAMmB,WAAWM;EAAEjB,mBAAA,CAAA,CAAA;CACjC;CACAtC,MAAM;EAAEuC,eAAe;EAAOC,YAAY;EAAUiB,UAAU;EAAQzB,KAAKF,MAAMG,QAAQ,CAAC;EAACK,mBAAA,CAAA,CAAA;CAAC;CAC5FrC,QAAQ;EAAEsC,eAAe;EAAOC,YAAY;EAAUR,KAAKF,MAAMG,QAAQ,CAAC;EAACK,mBAAA,CAAA,CAAA;CAAC;CAC5EpC,YAAY;EACVyC,OAAOb,MAAMM,OAAOsB;EACpBb,YAAYtG,OAAOuF,MAAMe,WAAWC,IAAI;EACxCC,UAAUjB,MAAMiB,SAASC;EACzBC,YAAYnB,MAAMmB,WAAWD;EAC7BE,YAAYpB,MAAMoB,WAAWC;EAAMb,mBAAA,CAAA,CAAA;CACrC;AACF,EAAE;;;AC7OF,IAAA,yBAAe,oBAAoB;CACjC,MAAM;CACN,MAAM;CACN,YAAY,cAAc,cAAc;CACxC,cAAc;CACd,cAAc;CACd,OAAO;AACT,CAAC;;;ACXD,IAAA,6BAAe,kBAAkB,iBAAiB;;;ACClD,IAAA,0CAAe,WAAW;CAAE,MAAM;CAAoB,IAAI;CAAW,WAAW;AAAuB,CAAC;;;ACGxG,MAAM,OAAU,UAAmC,UAChD,UAAU,KAAA,IAAY,KAAA,IAAY;CAAE,GAAG;CAAU,GAAI;AAAiB;AAEzE,MAAa,eAAe,mBAAmB;CAC7C,IAAI;CACJ,SAAS;EACP,IAAI,iBAA2D;GAAE,OAAO,CAAC,IAAI,EAAE,MAAM,UAAU,GAAGqB,sBAAoB,CAAC;EAAG;EAC1H,IAAI,WAA+C;GAAE,OAAO,CAAC,IAAI,EAAE,SAAS,cAAc,GAAGC,0BAAiB,CAAC;EAAG;EAClH,IAAI,QAAyC;GAAE,OAAO,CAAC,IAAI;IAAE,MAAM;IAAoB,IAAI;GAAU,GAAGC,uCAAW,CAAC;EAAG;CACzH;AACF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agimon-ai/po-runner",
3
- "version": "0.0.0-alpha.34",
3
+ "version": "0.0.0-alpha.35",
4
4
  "description": "Supervised shell execution, background process control, and run logs for Pi coding agents.",
5
5
  "keywords": [
6
6
  "ai",
@@ -209,10 +209,10 @@
209
209
  },
210
210
  "dependencies": {
211
211
  "@agimon-ai/foundation-process-registry": "0.30.13",
212
- "@agimon-ai/po-core": "0.0.0-alpha.34",
213
- "@agimon-ai/po-ui": "0.0.0-alpha.34",
214
- "@agimon-ai/po-web-components": "0.0.0-alpha.34",
215
- "@agimon-ai/po-web-security": "0.0.0-alpha.34",
212
+ "@agimon-ai/po-core": "0.0.0-alpha.35",
213
+ "@agimon-ai/po-ui": "0.0.0-alpha.35",
214
+ "@agimon-ai/po-web-components": "0.0.0-alpha.35",
215
+ "@agimon-ai/po-web-security": "0.0.0-alpha.35",
216
216
  "@deepseek-ai/cordis": "4.0.5",
217
217
  "@rmux/sdk": "0.6.5",
218
218
  "@xterm/headless": "6.0.0",
@@ -220,8 +220,8 @@
220
220
  "typebox": "1.3.37"
221
221
  },
222
222
  "devDependencies": {
223
- "@agimon-ai/po-build": "0.0.0-alpha.34",
224
- "@agimon-ai/po-native-components": "0.0.0-alpha.34",
223
+ "@agimon-ai/po-build": "0.0.0-alpha.35",
224
+ "@agimon-ai/po-native-components": "0.0.0-alpha.35",
225
225
  "@earendil-works/pi-coding-agent": "1.3.0",
226
226
  "@tanstack/react-store": "0.11.2",
227
227
  "@tanstack/store": "0.11.2",
@@ -237,7 +237,7 @@
237
237
  "vitest": "5.0.4"
238
238
  },
239
239
  "peerDependencies": {
240
- "@agimon-ai/po-native-components": "0.0.0-alpha.34",
240
+ "@agimon-ai/po-native-components": "0.0.0-alpha.35",
241
241
  "@earendil-works/pi-coding-agent": "1.3.0",
242
242
  "react-native": "0.86.3",
243
243
  "react-native-unistyles": "^3.5.3"
@@ -257,14 +257,14 @@
257
257
  }
258
258
  },
259
259
  "optionalDependencies": {
260
- "@agimon-ai/po-runner-rmux-darwin-arm64": "0.0.0-alpha.34",
261
- "@agimon-ai/po-runner-rmux-darwin-x64": "0.0.0-alpha.34",
262
- "@agimon-ai/po-runner-rmux-linux-arm64": "0.0.0-alpha.34",
263
- "@agimon-ai/po-runner-rmux-linux-x64": "0.0.0-alpha.34",
264
- "@agimon-ai/po-runner-rtk-darwin-arm64": "0.0.0-alpha.34",
265
- "@agimon-ai/po-runner-rtk-darwin-x64": "0.0.0-alpha.34",
266
- "@agimon-ai/po-runner-rtk-linux-arm64": "0.0.0-alpha.34",
267
- "@agimon-ai/po-runner-rtk-linux-x64": "0.0.0-alpha.34"
260
+ "@agimon-ai/po-runner-rmux-darwin-arm64": "0.0.0-alpha.35",
261
+ "@agimon-ai/po-runner-rmux-darwin-x64": "0.0.0-alpha.35",
262
+ "@agimon-ai/po-runner-rmux-linux-arm64": "0.0.0-alpha.35",
263
+ "@agimon-ai/po-runner-rmux-linux-x64": "0.0.0-alpha.35",
264
+ "@agimon-ai/po-runner-rtk-darwin-arm64": "0.0.0-alpha.35",
265
+ "@agimon-ai/po-runner-rtk-darwin-x64": "0.0.0-alpha.35",
266
+ "@agimon-ai/po-runner-rtk-linux-arm64": "0.0.0-alpha.35",
267
+ "@agimon-ai/po-runner-rtk-linux-x64": "0.0.0-alpha.35"
268
268
  },
269
269
  "engines": {
270
270
  "node": ">=24"