@fengye404/termpilot 0.1.2 → 0.1.4

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.
@@ -5,8 +5,8 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
6
6
  <meta name="theme-color" content="#0f172a" />
7
7
  <title>TermPilot</title>
8
- <script type="module" crossorigin src="/assets/index-ChAARFV0.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-L-E4Jdut.css">
8
+ <script type="module" crossorigin src="/assets/index-CyNBuXm-.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-CCXqowYd.css">
10
10
  <link rel="manifest" href="/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js"></script></head>
11
11
  <body class="bg-slate-950">
12
12
  <div id="root"></div>
package/app/dist/sw.js CHANGED
@@ -1 +1 @@
1
- if(!self.define){let e,s={};const i=(i,n)=>(i=new URL(i+".js",n).href,s[i]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=s,document.head.appendChild(e)}else e=i,importScripts(i),s()}).then(()=>{let e=s[i];if(!e)throw new Error(`Module ${i} didn’t register its module`);return e}));self.define=(n,t)=>{const r=e||("document"in self?document.currentScript.src:"")||location.href;if(s[r])return;let o={};const c=e=>i(e,r),l={module:{uri:r},exports:o,require:c};s[r]=Promise.all(n.map(e=>l[e]||c(e))).then(e=>(t(...e),o))}}define(["./workbox-1d3d89e3"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"registerSW.js",revision:"1872c500de691dce40960bb85481de07"},{url:"index.html",revision:"1c311ba4a7b4b145a3f355013d6f3347"},{url:"assets/index-L-E4Jdut.css",revision:null},{url:"assets/index-ChAARFV0.js",revision:null},{url:"manifest.webmanifest",revision:"97cf47c913710ef5ce3dc79cf9c7c245"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html")))});
1
+ if(!self.define){let e,s={};const i=(i,n)=>(i=new URL(i+".js",n).href,s[i]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=s,document.head.appendChild(e)}else e=i,importScripts(i),s()}).then(()=>{let e=s[i];if(!e)throw new Error(`Module ${i} didn’t register its module`);return e}));self.define=(n,r)=>{const t=e||("document"in self?document.currentScript.src:"")||location.href;if(s[t])return;let o={};const c=e=>i(e,t),d={module:{uri:t},exports:o,require:c};s[t]=Promise.all(n.map(e=>d[e]||c(e))).then(e=>(r(...e),o))}}define(["./workbox-1d3d89e3"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"registerSW.js",revision:"1872c500de691dce40960bb85481de07"},{url:"index.html",revision:"62d1459fd4ff940e1a94025c3dc4d076"},{url:"assets/index-CyNBuXm-.js",revision:null},{url:"assets/index-CCXqowYd.css",revision:null},{url:"manifest.webmanifest",revision:"97cf47c913710ef5ce3dc79cf9c7c245"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html")))});
package/dist/cli.js CHANGED
@@ -5,7 +5,10 @@ import path3 from "path";
5
5
  import { fileURLToPath as fileURLToPath2 } from "url";
6
6
 
7
7
  // agent/src/cli.ts
8
+ import { spawn as spawn2 } from "child_process";
9
+ import { openSync as openSync2 } from "fs";
8
10
  import { cwd as processCwd2 } from "process";
11
+ import { setTimeout as delay2 } from "timers/promises";
9
12
 
10
13
  // agent/src/daemon.ts
11
14
  import { setTimeout as delay } from "timers/promises";
@@ -44,6 +47,12 @@ function getAgentHome() {
44
47
  function getStateFilePath() {
45
48
  return path.join(getAgentHome(), "state.json");
46
49
  }
50
+ function getAgentRuntimeFilePath() {
51
+ return path.join(getAgentHome(), "agent-runtime.json");
52
+ }
53
+ function getAgentLogFilePath() {
54
+ return path.join(getAgentHome(), "agent.log");
55
+ }
47
56
  function getStateLockPath() {
48
57
  return `${getStateFilePath()}.lock`;
49
58
  }
@@ -136,6 +145,36 @@ function updateSession(sid, updater) {
136
145
  return nextState;
137
146
  });
138
147
  }
148
+ function loadAgentRuntime() {
149
+ ensureAgentHome();
150
+ try {
151
+ const raw = readFileSync(getAgentRuntimeFilePath(), "utf8");
152
+ const parsed = JSON.parse(raw);
153
+ if (typeof parsed.pid !== "number" || typeof parsed.relayUrl !== "string" || typeof parsed.deviceId !== "string" || typeof parsed.startedAt !== "string") {
154
+ return null;
155
+ }
156
+ return {
157
+ pid: parsed.pid,
158
+ relayUrl: parsed.relayUrl,
159
+ deviceId: parsed.deviceId,
160
+ startedAt: parsed.startedAt
161
+ };
162
+ } catch {
163
+ return null;
164
+ }
165
+ }
166
+ function saveAgentRuntime(runtime) {
167
+ ensureAgentHome();
168
+ writeFileSync(getAgentRuntimeFilePath(), `${JSON.stringify(runtime, null, 2)}
169
+ `, "utf8");
170
+ }
171
+ function clearAgentRuntime(expectedPid) {
172
+ const current = loadAgentRuntime();
173
+ if (expectedPid !== void 0 && current?.pid !== expectedPid) {
174
+ return;
175
+ }
176
+ rmSync(getAgentRuntimeFilePath(), { force: true });
177
+ }
139
178
 
140
179
  // agent/src/tmux-backend.ts
141
180
  import { randomUUID as randomUUID2 } from "crypto";
@@ -182,7 +221,7 @@ async function createSession(input = {}) {
182
221
  const name = input.name?.trim() || `session-${sid.slice(0, 6)}`;
183
222
  const shell = input.shell?.trim() || process.env.SHELL || "/bin/zsh";
184
223
  const workingDirectory = input.cwd?.trim() || processCwd();
185
- const deviceId = input.deviceId || DEFAULT_DEVICE_ID;
224
+ const deviceId = input.deviceId?.trim() || process.env.TERMPILOT_DEVICE_ID || DEFAULT_DEVICE_ID;
186
225
  const startedAt = now();
187
226
  const tmuxSessionName = buildTmuxSessionName(sid, name);
188
227
  await runTmux(["new-session", "-d", "-s", tmuxSessionName, "-c", workingDirectory, shell]);
@@ -677,6 +716,11 @@ function printHelp() {
677
716
  console.log(`TermPilot agent \u7528\u6CD5\uFF1A
678
717
 
679
718
  termpilot agent
719
+ termpilot agent --foreground
720
+ termpilot agent status
721
+ termpilot agent stop
722
+ termpilot claude code
723
+ termpilot run -- claude code
680
724
  termpilot create --name claude-main --cwd /path/to/project
681
725
  termpilot list
682
726
  termpilot kill --sid <sid>
@@ -771,6 +815,175 @@ function getDeviceId(argv) {
771
815
  const args = parseArgs(argv);
772
816
  return resolveDeviceId(typeof args.deviceId === "string" ? args.deviceId : void 0);
773
817
  }
818
+ function getRelayUrl() {
819
+ return process.env.TERMPILOT_RELAY_URL ?? "ws://127.0.0.1:8787/ws";
820
+ }
821
+ function isProcessAlive(pid) {
822
+ try {
823
+ process.kill(pid, 0);
824
+ return true;
825
+ } catch {
826
+ return false;
827
+ }
828
+ }
829
+ function readRuntimeStatus() {
830
+ const runtime = loadAgentRuntime();
831
+ if (!runtime) {
832
+ return { runtime: null, alive: false };
833
+ }
834
+ const alive = isProcessAlive(runtime.pid);
835
+ if (!alive) {
836
+ clearAgentRuntime(runtime.pid);
837
+ return { runtime: null, alive: false };
838
+ }
839
+ return { runtime, alive };
840
+ }
841
+ async function waitForPairingCode(deviceId) {
842
+ let lastError = null;
843
+ for (let attempt = 0; attempt < 12; attempt += 1) {
844
+ try {
845
+ return await createPairingCode(deviceId);
846
+ } catch (error) {
847
+ lastError = error;
848
+ await delay2(500);
849
+ }
850
+ }
851
+ if (lastError instanceof Error) {
852
+ console.warn(`\u540E\u53F0 agent \u5DF2\u542F\u52A8\uFF0C\u4F46\u6682\u65F6\u8FD8\u6CA1\u62FF\u5230\u914D\u5BF9\u7801\uFF1A${lastError.message}`);
853
+ }
854
+ return null;
855
+ }
856
+ async function runStart(argv) {
857
+ const args = parseArgs(argv);
858
+ if (args.foreground) {
859
+ await runDaemon();
860
+ return;
861
+ }
862
+ const deviceId = getDeviceId(argv);
863
+ const relayUrl = getRelayUrl();
864
+ const existing = readRuntimeStatus();
865
+ if (existing.runtime && existing.alive) {
866
+ console.log(`\u540E\u53F0 agent \u5DF2\u5728\u8FD0\u884C\uFF0CPID: ${existing.runtime.pid}`);
867
+ console.log(`\u8BBE\u5907: ${existing.runtime.deviceId}`);
868
+ console.log(`relay: ${existing.runtime.relayUrl}`);
869
+ const pairing2 = await waitForPairingCode(deviceId);
870
+ if (pairing2) {
871
+ console.log(`\u914D\u5BF9\u7801: ${pairing2.pairingCode}`);
872
+ console.log(`\u6709\u6548\u671F\u81F3: ${pairing2.expiresAt}`);
873
+ }
874
+ return;
875
+ }
876
+ clearAgentRuntime();
877
+ const logFilePath = getAgentLogFilePath();
878
+ const logFd = openSync2(logFilePath, "a");
879
+ const child = spawn2(process.execPath, [process.argv[1], "agent-daemon"], {
880
+ detached: true,
881
+ stdio: ["ignore", logFd, logFd],
882
+ env: process.env
883
+ });
884
+ child.unref();
885
+ if (!child.pid) {
886
+ throw new Error("\u540E\u53F0 agent \u542F\u52A8\u5931\u8D25\uFF0C\u672A\u83B7\u53D6\u5230\u5B50\u8FDB\u7A0B PID\u3002");
887
+ }
888
+ saveAgentRuntime({
889
+ pid: child.pid,
890
+ relayUrl,
891
+ deviceId,
892
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
893
+ });
894
+ console.log(`\u540E\u53F0 agent \u5DF2\u542F\u52A8\uFF0CPID: ${child.pid}`);
895
+ console.log(`\u8BBE\u5907: ${deviceId}`);
896
+ console.log(`relay: ${relayUrl}`);
897
+ console.log(`\u65E5\u5FD7: ${logFilePath}`);
898
+ const pairing = await waitForPairingCode(deviceId);
899
+ if (pairing) {
900
+ console.log(`\u914D\u5BF9\u7801: ${pairing.pairingCode}`);
901
+ console.log(`\u6709\u6548\u671F\u81F3: ${pairing.expiresAt}`);
902
+ console.log("\u624B\u673A\u7AEF\u76F4\u63A5\u6253\u5F00 relay \u9875\u9762\u5E76\u8F93\u5165\u8FD9\u4E2A\u914D\u5BF9\u7801\u5373\u53EF\u3002");
903
+ }
904
+ }
905
+ function runStatus() {
906
+ const { runtime, alive } = readRuntimeStatus();
907
+ if (!runtime || !alive) {
908
+ console.log("\u540E\u53F0 agent \u5F53\u524D\u672A\u8FD0\u884C\u3002");
909
+ console.log(`\u72B6\u6001\u76EE\u5F55: ${getAgentHome()}`);
910
+ console.log(`\u65E5\u5FD7: ${getAgentLogFilePath()}`);
911
+ return;
912
+ }
913
+ const sessions = loadState().sessions.filter((session) => session.deviceId === runtime.deviceId);
914
+ const runningSessions = sessions.filter((session) => session.status === "running").length;
915
+ console.log("\u540E\u53F0 agent \u6B63\u5728\u8FD0\u884C\u3002");
916
+ console.log(`PID: ${runtime.pid}`);
917
+ console.log(`\u8BBE\u5907: ${runtime.deviceId}`);
918
+ console.log(`relay: ${runtime.relayUrl}`);
919
+ console.log(`\u542F\u52A8\u65F6\u95F4: ${runtime.startedAt}`);
920
+ console.log(`\u65E5\u5FD7: ${getAgentLogFilePath()}`);
921
+ console.log(`\u4F1A\u8BDD: ${runningSessions} \u4E2A\u8FD0\u884C\u4E2D / ${sessions.length} \u4E2A\u603B\u8BA1`);
922
+ }
923
+ async function runStop() {
924
+ const { runtime, alive } = readRuntimeStatus();
925
+ if (!runtime || !alive) {
926
+ console.log("\u540E\u53F0 agent \u5F53\u524D\u672A\u8FD0\u884C\u3002");
927
+ clearAgentRuntime();
928
+ return;
929
+ }
930
+ process.kill(runtime.pid, "SIGTERM");
931
+ for (let attempt = 0; attempt < 20; attempt += 1) {
932
+ if (!isProcessAlive(runtime.pid)) {
933
+ clearAgentRuntime(runtime.pid);
934
+ console.log(`\u540E\u53F0 agent \u5DF2\u505C\u6B62\uFF0CPID: ${runtime.pid}`);
935
+ return;
936
+ }
937
+ await delay2(100);
938
+ }
939
+ process.kill(runtime.pid, "SIGKILL");
940
+ clearAgentRuntime(runtime.pid);
941
+ console.log(`\u540E\u53F0 agent \u5DF2\u5F3A\u5236\u505C\u6B62\uFF0CPID: ${runtime.pid}`);
942
+ }
943
+ function buildQuickSessionName(commandArgs) {
944
+ const raw = commandArgs.join("-").trim().toLowerCase();
945
+ const normalized = raw.replace(/[^a-z0-9_-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
946
+ return normalized.slice(0, 32) || "task";
947
+ }
948
+ async function runManagedCommand(argv) {
949
+ const commandArgs = argv[0] === "--" ? argv.slice(1) : argv;
950
+ if (commandArgs.length === 0) {
951
+ throw new Error("\u8BF7\u5728 termpilot \u540E\u9762\u63D0\u4F9B\u8981\u8FD0\u884C\u7684\u547D\u4EE4\uFF0C\u4F8B\u5982\uFF1Atermpilot claude code");
952
+ }
953
+ const session = await createSession({
954
+ name: buildQuickSessionName(commandArgs),
955
+ cwd: processCwd2(),
956
+ deviceId: resolveDeviceId()
957
+ });
958
+ console.log(`\u5DF2\u521B\u5EFA\u4F1A\u8BDD ${session.sid} (${session.name})`);
959
+ await sendInput(session, `${commandArgs.join(" ")}
960
+ `);
961
+ await attachSession(session);
962
+ }
963
+ async function runDaemon() {
964
+ await ensureTmuxAvailable();
965
+ const relayUrl = getRelayUrl();
966
+ const deviceId = resolveDeviceId();
967
+ saveAgentRuntime({
968
+ pid: process.pid,
969
+ relayUrl,
970
+ deviceId,
971
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
972
+ });
973
+ const daemon = createDaemonFromEnv();
974
+ const stop = () => {
975
+ void daemon.stop().finally(() => {
976
+ clearAgentRuntime(process.pid);
977
+ process.exit(0);
978
+ });
979
+ };
980
+ process.on("SIGINT", stop);
981
+ process.on("SIGTERM", stop);
982
+ process.on("exit", () => {
983
+ clearAgentRuntime(process.pid);
984
+ });
985
+ await daemon.start();
986
+ }
774
987
  async function runPair(argv) {
775
988
  const deviceId = getDeviceId(argv);
776
989
  const payload = await createPairingCode(deviceId);
@@ -833,16 +1046,17 @@ async function runAgentCli(argv = process.argv.slice(2)) {
833
1046
  return;
834
1047
  }
835
1048
  switch (command) {
1049
+ case "start":
1050
+ await runStart(rest);
1051
+ return;
1052
+ case "status":
1053
+ runStatus();
1054
+ return;
1055
+ case "stop":
1056
+ await runStop();
1057
+ return;
836
1058
  case "daemon": {
837
- await ensureTmuxAvailable();
838
- const daemon = createDaemonFromEnv();
839
- process.on("SIGINT", () => {
840
- void daemon.stop().finally(() => process.exit(0));
841
- });
842
- process.on("SIGTERM", () => {
843
- void daemon.stop().finally(() => process.exit(0));
844
- });
845
- await daemon.start();
1059
+ await runDaemon();
846
1060
  return;
847
1061
  }
848
1062
  case "create":
@@ -875,9 +1089,13 @@ async function runAgentCli(argv = process.argv.slice(2)) {
875
1089
  case "revoke":
876
1090
  await runRevoke(rest);
877
1091
  return;
1092
+ case "run":
1093
+ await ensureTmuxAvailable();
1094
+ await runManagedCommand(rest);
1095
+ return;
878
1096
  default:
879
- printHelp();
880
- process.exitCode = 1;
1097
+ await ensureTmuxAvailable();
1098
+ await runManagedCommand(argv);
881
1099
  }
882
1100
  }
883
1101
 
@@ -1883,6 +2101,10 @@ function printHelp2() {
1883
2101
 
1884
2102
  termpilot relay [--host 0.0.0.0] [--port 8787]
1885
2103
  termpilot agent [--relay ws://127.0.0.1:8787/ws] [--device-id pc-main]
2104
+ termpilot agent status
2105
+ termpilot agent stop
2106
+ termpilot claude code
2107
+ termpilot run -- claude code
1886
2108
 
1887
2109
  termpilot pair [--device-id pc-main]
1888
2110
  termpilot create --name claude-main [--cwd /path/to/project]
@@ -1935,7 +2157,15 @@ async function main(argv = process.argv.slice(2)) {
1935
2157
  }
1936
2158
  case "agent": {
1937
2159
  const agentArgs = applyEnvFlags(rest, AGENT_ENV_FLAGS);
1938
- await runAgentCli(agentArgs.length > 0 ? agentArgs : ["daemon"]);
2160
+ if (agentArgs[0] === "status" || agentArgs[0] === "stop" || agentArgs[0] === "daemon") {
2161
+ await runAgentCli(agentArgs);
2162
+ } else {
2163
+ await runAgentCli(["start", ...agentArgs]);
2164
+ }
2165
+ return;
2166
+ }
2167
+ case "agent-daemon": {
2168
+ await runAgentCli(["daemon", ...rest]);
1939
2169
  return;
1940
2170
  }
1941
2171
  case "pair":
@@ -1952,8 +2182,7 @@ async function main(argv = process.argv.slice(2)) {
1952
2182
  return;
1953
2183
  }
1954
2184
  default:
1955
- printHelp2();
1956
- process.exitCode = 1;
2185
+ await runAgentCli([command, ...rest]);
1957
2186
  }
1958
2187
  }
1959
2188
  void main().catch((error) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fengye404/termpilot",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "packageManager": "pnpm@10.31.0",
6
6
  "description": "一个基于 tmux 的终端会话跨端查看与控制原型。",
@@ -1 +0,0 @@
1
- .xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;inset:0}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm .xterm-accessibility,.xterm .xterm-message{position:absolute;inset:0;z-index:10;color:transparent;pointer-events:none}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-amber-200:oklch(92.4% .12 95.746);--color-amber-400:oklch(82.8% .189 84.429);--color-emerald-100:oklch(95% .052 163.051);--color-emerald-200:oklch(90.5% .093 164.15);--color-emerald-300:oklch(84.5% .143 164.978);--color-emerald-400:oklch(76.5% .177 163.223);--color-emerald-500:oklch(69.6% .17 162.48);--color-sky-100:oklch(95.1% .026 236.824);--color-sky-300:oklch(82.8% .111 230.318);--color-sky-400:oklch(74.6% .16 232.661);--color-sky-500:oklch(68.5% .169 237.323);--color-rose-100:oklch(94.1% .03 12.58);--color-rose-200:oklch(89.2% .058 10.001);--color-rose-500:oklch(64.5% .246 16.439);--color-slate-100:oklch(96.8% .007 247.896);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-300:oklch(86.9% .022 252.894);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-700:oklch(37.2% .044 257.287);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--color-slate-950:oklch(12.9% .042 264.695);--color-white:#fff;--spacing:.25rem;--container-md:28rem;--container-2xl:42rem;--container-7xl:80rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-3xl:1.875rem;--text-3xl--line-height: 1.2 ;--font-weight-medium:500;--font-weight-semibold:600;--radius-2xl:1rem;--radius-3xl:1.5rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.start{inset-inline-start:var(--spacing)}.mx-auto{margin-inline:auto}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.block{display:block}.flex{display:flex}.grid{display:grid}.inline{display:inline}.h-full{height:100%}.min-h-11{min-height:calc(var(--spacing) * 11)}.min-h-32{min-height:calc(var(--spacing) * 32)}.min-h-\[56vh\]{min-height:56vh}.min-h-\[68vh\]{min-height:68vh}.min-h-\[440px\]{min-height:440px}.min-h-screen{min-height:100vh}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-7xl{max-width:var(--container-7xl)}.max-w-md{max-width:var(--container-md)}.flex-1{flex:1}.resize{resize:both}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-5{gap:calc(var(--spacing) * 5)}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 5) * calc(1 - var(--tw-space-y-reverse)))}.overflow-hidden{overflow:hidden}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-3xl{border-radius:var(--radius-3xl)}.rounded-full{border-radius:3.40282e38px}.border{border-style:var(--tw-border-style);border-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-amber-400\/50{border-color:#fcbb0080}@supports (color:color-mix(in lab,red,red)){.border-amber-400\/50{border-color:color-mix(in oklab,var(--color-amber-400) 50%,transparent)}}.border-current\/30{border-color:currentColor}@supports (color:color-mix(in lab,red,red)){.border-current\/30{border-color:color-mix(in oklab,currentcolor 30%,transparent)}}.border-emerald-500\/40{border-color:#00bb7f66}@supports (color:color-mix(in lab,red,red)){.border-emerald-500\/40{border-color:color-mix(in oklab,var(--color-emerald-500) 40%,transparent)}}.border-emerald-500\/50{border-color:#00bb7f80}@supports (color:color-mix(in lab,red,red)){.border-emerald-500\/50{border-color:color-mix(in oklab,var(--color-emerald-500) 50%,transparent)}}.border-rose-500\/40{border-color:#ff235766}@supports (color:color-mix(in lab,red,red)){.border-rose-500\/40{border-color:color-mix(in oklab,var(--color-rose-500) 40%,transparent)}}.border-sky-400\/70{border-color:#00bcfeb3}@supports (color:color-mix(in lab,red,red)){.border-sky-400\/70{border-color:color-mix(in oklab,var(--color-sky-400) 70%,transparent)}}.border-sky-500\/40{border-color:#00a5ef66}@supports (color:color-mix(in lab,red,red)){.border-sky-500\/40{border-color:color-mix(in oklab,var(--color-sky-500) 40%,transparent)}}.border-slate-700{border-color:var(--color-slate-700)}.border-slate-800{border-color:var(--color-slate-800)}.border-slate-800\/80{border-color:#1d293dcc}@supports (color:color-mix(in lab,red,red)){.border-slate-800\/80{border-color:color-mix(in oklab,var(--color-slate-800) 80%,transparent)}}.bg-emerald-400{background-color:var(--color-emerald-400)}.bg-emerald-500\/10{background-color:#00bb7f1a}@supports (color:color-mix(in lab,red,red)){.bg-emerald-500\/10{background-color:color-mix(in oklab,var(--color-emerald-500) 10%,transparent)}}.bg-emerald-500\/15{background-color:#00bb7f26}@supports (color:color-mix(in lab,red,red)){.bg-emerald-500\/15{background-color:color-mix(in oklab,var(--color-emerald-500) 15%,transparent)}}.bg-rose-500\/10{background-color:#ff23571a}@supports (color:color-mix(in lab,red,red)){.bg-rose-500\/10{background-color:color-mix(in oklab,var(--color-rose-500) 10%,transparent)}}.bg-sky-500{background-color:var(--color-sky-500)}.bg-sky-500\/10{background-color:#00a5ef1a}@supports (color:color-mix(in lab,red,red)){.bg-sky-500\/10{background-color:color-mix(in oklab,var(--color-sky-500) 10%,transparent)}}.bg-slate-700{background-color:var(--color-slate-700)}.bg-slate-900\/70{background-color:#0f172bb3}@supports (color:color-mix(in lab,red,red)){.bg-slate-900\/70{background-color:color-mix(in oklab,var(--color-slate-900) 70%,transparent)}}.bg-slate-900\/72{background-color:#0f172bb8}@supports (color:color-mix(in lab,red,red)){.bg-slate-900\/72{background-color:color-mix(in oklab,var(--color-slate-900) 72%,transparent)}}.bg-slate-950{background-color:var(--color-slate-950)}.bg-slate-950\/35{background-color:#02061859}@supports (color:color-mix(in lab,red,red)){.bg-slate-950\/35{background-color:color-mix(in oklab,var(--color-slate-950) 35%,transparent)}}.bg-slate-950\/40{background-color:#02061866}@supports (color:color-mix(in lab,red,red)){.bg-slate-950\/40{background-color:color-mix(in oklab,var(--color-slate-950) 40%,transparent)}}.bg-slate-950\/60{background-color:#02061899}@supports (color:color-mix(in lab,red,red)){.bg-slate-950\/60{background-color:color-mix(in oklab,var(--color-slate-950) 60%,transparent)}}.bg-slate-950\/95{background-color:#020618f2}@supports (color:color-mix(in lab,red,red)){.bg-slate-950\/95{background-color:color-mix(in oklab,var(--color-slate-950) 95%,transparent)}}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-12{padding-block:calc(var(--spacing) * 12)}.text-center{text-align:center}.text-left{text-align:left}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[11px\]{font-size:11px}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.25em\]{--tw-tracking:.25em;letter-spacing:.25em}.text-amber-200{color:var(--color-amber-200)}.text-emerald-100{color:var(--color-emerald-100)}.text-emerald-200{color:var(--color-emerald-200)}.text-emerald-300{color:var(--color-emerald-300)}.text-rose-100{color:var(--color-rose-100)}.text-rose-200{color:var(--color-rose-200)}.text-sky-100{color:var(--color-sky-100)}.text-sky-300{color:var(--color-sky-300)}.text-slate-100{color:var(--color-slate-100)}.text-slate-200{color:var(--color-slate-200)}.text-slate-300{color:var(--color-slate-300)}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-slate-950{color:var(--color-slate-950)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-0{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-slate-950\/30{--tw-shadow-color:#0206184d}@supports (color:color-mix(in lab,red,red)){.shadow-slate-950\/30{--tw-shadow-color:color-mix(in oklab, color-mix(in oklab, var(--color-slate-950) 30%, transparent) var(--tw-shadow-alpha), transparent)}}.shadow-slate-950\/40{--tw-shadow-color:#02061866}@supports (color:color-mix(in lab,red,red)){.shadow-slate-950\/40{--tw-shadow-color:color-mix(in oklab, color-mix(in oklab, var(--color-slate-950) 40%, transparent) var(--tw-shadow-alpha), transparent)}}.backdrop-blur{--tw-backdrop-blur:blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.outline-none{--tw-outline-style:none;outline-style:none}.placeholder\:text-slate-500::placeholder{color:var(--color-slate-500)}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-60:disabled{opacity:.6}@media(min-width:40rem){.sm\:grid-cols-\[minmax\(0\,1fr\)_auto_auto\]{grid-template-columns:minmax(0,1fr) auto auto}.sm\:flex-row{flex-direction:row}.sm\:px-6{padding-inline:calc(var(--spacing) * 6)}}@media(min-width:48rem){.md\:sticky{position:sticky}.md\:top-0{top:calc(var(--spacing) * 0)}.md\:z-10{z-index:10}.md\:flex-row{flex-direction:row}.md\:items-end{align-items:flex-end}.md\:justify-between{justify-content:space-between}.md\:bg-slate-900\/72{background-color:#0f172bb8}@supports (color:color-mix(in lab,red,red)){.md\:bg-slate-900\/72{background-color:color-mix(in oklab,var(--color-slate-900) 72%,transparent)}}.md\:pb-2{padding-bottom:calc(var(--spacing) * 2)}}@media(min-width:64rem){.lg\:grid-cols-\[360px_minmax\(0\,1fr\)\]{grid-template-columns:360px minmax(0,1fr)}.lg\:px-8{padding-inline:calc(var(--spacing) * 8)}}}.xterm{cursor:text;-webkit-user-select:none;user-select:none;position:relative}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{z-index:5;position:absolute;top:0}.xterm .xterm-helper-textarea{opacity:0;z-index:-5;white-space:nowrap;resize:none;border:0;width:0;height:0;margin:0;padding:0;position:absolute;top:0;left:-9999em;overflow:hidden}.xterm .composition-view{color:#fff;white-space:nowrap;z-index:1;background:#000;display:none;position:absolute}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{cursor:default;background-color:#000;position:absolute;inset:0;overflow-y:scroll}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;top:0;left:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{visibility:hidden;line-height:normal;display:inline-block;position:absolute;top:0;left:-9999em}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility,.xterm .xterm-message{z-index:10;color:#0000;pointer-events:none;position:absolute;inset:0}.xterm .live-region{width:1px;height:1px;position:absolute;left:-9999px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{-webkit-text-decoration:underline double;text-decoration:underline double}.xterm-underline-3{-webkit-text-decoration:underline wavy;text-decoration:underline wavy}.xterm-underline-4{-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.xterm-underline-5{-webkit-text-decoration:underline dashed;text-decoration:underline dashed}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:underline overline}.xterm-overline.xterm-underline-2{-webkit-text-decoration:overline double underline;text-decoration:overline double underline}.xterm-overline.xterm-underline-3{-webkit-text-decoration:overline wavy underline;text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{-webkit-text-decoration:overline dotted underline;text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{-webkit-text-decoration:overline dashed underline;text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;pointer-events:none;position:absolute;top:0;right:0}.xterm-decoration-top{z-index:2;position:relative}:root{color-scheme:dark}body{color:#e2e8f0;background:radial-gradient(circle at 0 0,#38bdf824,#0000 32%),linear-gradient(#020617,#0f172a 48%,#020617);min-height:100vh;margin:0;font-family:SF Pro Display,PingFang SC,Helvetica Neue,sans-serif}#root{min-height:100vh}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}