@skybridge/devtools 0.0.0-dev.6fb9fe8 → 0.0.0-dev.6fc0cc2

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.
@@ -0,0 +1,12 @@
1
+ import { Alpic } from "@alpic-ai/sdk";
2
+ import { type Router } from "express";
3
+ /**
4
+ * Dev-only router that drives the devtools Deploy button. Runs `@alpic-ai/sdk`
5
+ * in-process (no CLI spawning): `/status` is a plain request, deploy progress
6
+ * streams over SSE at `/events`.
7
+ *
8
+ * ponytail: deploy state + subscriber set are per-router-instance (closure
9
+ * scoped). The dev server mounts one router for one project, so a single
10
+ * in-flight deploy is fine; no change needed unless it ever hosts several.
11
+ */
12
+ export declare function createDeployRouter(alpicOverride?: Alpic): Router;
@@ -0,0 +1,279 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { Alpic, } from "@alpic-ai/sdk";
4
+ import express, {} from "express";
5
+ // `collecting`/`collected` share step 1, so there are 4 numbered steps.
6
+ const TOTAL_STEPS = 4;
7
+ const PHASE_STEPS = {
8
+ collecting: { step: 1, label: "Collecting files" },
9
+ collected: { step: 1, label: "Collecting files" },
10
+ uploading: { step: 2, label: "Uploading source" },
11
+ triggering: { step: 3, label: "Triggering deployment" },
12
+ deploying: { step: 4, label: "Deploying" },
13
+ };
14
+ const phaseText = (type) => {
15
+ const { step, label } = PHASE_STEPS[type];
16
+ return `${step}/${TOTAL_STEPS} ${label}`;
17
+ };
18
+ const errMessage = (err, fallback) => err instanceof Error ? err.message : fallback;
19
+ const configPath = () => join(process.cwd(), ".alpic", "project.json");
20
+ function loadConfig() {
21
+ const path = configPath();
22
+ if (!existsSync(path)) {
23
+ return null;
24
+ }
25
+ return JSON.parse(readFileSync(path, "utf8"));
26
+ }
27
+ function saveConfig(cfg) {
28
+ mkdirSync(join(process.cwd(), ".alpic"), { recursive: true });
29
+ writeFileSync(configPath(), JSON.stringify(cfg, null, 2));
30
+ }
31
+ /**
32
+ * Dev-only router that drives the devtools Deploy button. Runs `@alpic-ai/sdk`
33
+ * in-process (no CLI spawning): `/status` is a plain request, deploy progress
34
+ * streams over SSE at `/events`.
35
+ *
36
+ * ponytail: deploy state + subscriber set are per-router-instance (closure
37
+ * scoped). The dev server mounts one router for one project, so a single
38
+ * in-flight deploy is fine; no change needed unless it ever hosts several.
39
+ */
40
+ export function createDeployRouter(alpicOverride) {
41
+ const router = express.Router();
42
+ // Lazy: `new Alpic()` reads server-side env at construction, so defer it to
43
+ // the first request rather than mount time (keeps createApp test-safe).
44
+ let alpicInstance = alpicOverride;
45
+ const alpic = () => {
46
+ alpicInstance ??= new Alpic();
47
+ return alpicInstance;
48
+ };
49
+ let state = { status: "idle" };
50
+ const subscribers = new Set();
51
+ const write = (res, s) => {
52
+ res.write(`event: state\ndata: ${JSON.stringify(s)}\n\n`);
53
+ };
54
+ const setState = (s) => {
55
+ state = s;
56
+ for (const res of subscribers) {
57
+ write(res, s);
58
+ }
59
+ };
60
+ const runDeploy = async (environmentId, teamId) => {
61
+ const startedAt = Date.now();
62
+ setState({
63
+ status: "deploying",
64
+ phase: phaseText("collecting"),
65
+ startedAt,
66
+ deploymentPageUrl: null,
67
+ });
68
+ let pageUrl = null;
69
+ try {
70
+ const result = await alpic().deployments.deploy({
71
+ environmentId,
72
+ teamId,
73
+ onProgress: (event) => {
74
+ if (event.type === "deploying" && event.deploymentPageUrl) {
75
+ pageUrl = event.deploymentPageUrl;
76
+ }
77
+ setState({
78
+ status: "deploying",
79
+ phase: phaseText(event.type),
80
+ startedAt,
81
+ deploymentPageUrl: pageUrl,
82
+ });
83
+ },
84
+ });
85
+ if (result.status === "deployed") {
86
+ setState({
87
+ status: "deployed",
88
+ mcpServerUrl: result.mcpServerUrl,
89
+ deploymentPageUrl: result.deploymentPageUrl,
90
+ });
91
+ }
92
+ else {
93
+ setState({
94
+ status: "failed",
95
+ message: `Deployment ${result.status}.`,
96
+ deploymentPageUrl: result.deploymentPageUrl,
97
+ });
98
+ }
99
+ }
100
+ catch (err) {
101
+ setState({
102
+ status: "failed",
103
+ message: errMessage(err, "Deployment failed"),
104
+ deploymentPageUrl: pageUrl,
105
+ });
106
+ }
107
+ };
108
+ router.get("/__skybridge/deploy/status", async (_req, res) => {
109
+ try {
110
+ const whoami = await alpic().whoami();
111
+ if (whoami.method === "unauthenticated") {
112
+ res.json({ state: "signedOut" });
113
+ return;
114
+ }
115
+ const cfg = loadConfig();
116
+ let staleConfig = false;
117
+ if (cfg) {
118
+ try {
119
+ await alpic().api.projects.get.v1({ projectId: cfg.projectId });
120
+ }
121
+ catch {
122
+ // Stale config: linked project deleted/inaccessible — fall back to first deploy.
123
+ staleConfig = true;
124
+ }
125
+ }
126
+ if (!cfg || staleConfig) {
127
+ const teams = await alpic().api.teams.list.v1();
128
+ const team = teams[0];
129
+ if (!team) {
130
+ res.json({ state: "noTeam" });
131
+ return;
132
+ }
133
+ res.json({
134
+ state: "needsProject",
135
+ teams,
136
+ defaultTeamId: team.id,
137
+ staleConfig,
138
+ });
139
+ return;
140
+ }
141
+ // Surface the live URL + deployment page so the persistent "Deployed"
142
+ // view renders on load (not only after a fresh deploy). A git-driven
143
+ // latest deploy (commit/author set) means the last deploy came from a
144
+ // connected repo, not this local button — expose its details so the UI
145
+ // can inform + warn before redeploying over it.
146
+ // ponytail: git vs local is the only distinction the API exposes; CLI and
147
+ // devtools local deploys are indistinguishable.
148
+ let lastDeployGit = null;
149
+ let lastDeployStatus;
150
+ let lastDeployStartedAt;
151
+ let mcpServerUrl;
152
+ let deploymentPageUrl = null;
153
+ if (cfg.environmentId) {
154
+ try {
155
+ const latest = await alpic().deployments.getLatestForEnvironment(cfg.environmentId);
156
+ if (latest.sourceCommitId !== null) {
157
+ lastDeployGit = {
158
+ ref: latest.sourceRef,
159
+ commitMessage: latest.sourceCommitMessage,
160
+ author: latest.authorUsername,
161
+ };
162
+ }
163
+ lastDeployStatus = latest.status;
164
+ lastDeployStartedAt = latest.startedAt?.getTime();
165
+ deploymentPageUrl = latest.deploymentPageUrl;
166
+ if (latest.status === "deployed") {
167
+ const environment = await alpic().api.environments.get.v1({
168
+ environmentId: cfg.environmentId,
169
+ });
170
+ mcpServerUrl = environment.mcpServerUrl;
171
+ }
172
+ }
173
+ catch {
174
+ // no deployments yet — leave defaults
175
+ }
176
+ }
177
+ res.json({
178
+ state: "ready",
179
+ lastDeployGit,
180
+ lastDeployStatus,
181
+ lastDeployStartedAt,
182
+ mcpServerUrl,
183
+ deploymentPageUrl,
184
+ });
185
+ }
186
+ catch (err) {
187
+ res.status(502).json({
188
+ state: "error",
189
+ message: errMessage(err, "Alpic API unavailable"),
190
+ });
191
+ }
192
+ });
193
+ router.post("/__skybridge/deploy/project", async (req, res) => {
194
+ if (state.status === "deploying") {
195
+ res.status(409).json({ message: "A deployment is already in progress." });
196
+ return;
197
+ }
198
+ const name = typeof req.body?.name === "string" ? req.body.name.trim() : "";
199
+ const teamId = typeof req.body?.teamId === "string" ? req.body.teamId : "";
200
+ const teamName = typeof req.body?.teamName === "string" ? req.body.teamName : undefined;
201
+ if (!name || !teamId) {
202
+ res.status(400).json({ message: "name and teamId are required." });
203
+ return;
204
+ }
205
+ try {
206
+ const existing = await alpic().api.projects.list.v1({ teamId });
207
+ if (existing.some((p) => p.name === name)) {
208
+ res
209
+ .status(409)
210
+ .json({ message: `A project named "${name}" already exists.` });
211
+ return;
212
+ }
213
+ const created = await alpic().api.projects.create.v1({
214
+ name,
215
+ teamId,
216
+ runtime: "node24",
217
+ });
218
+ const productionEnv = created.productionEnvironment;
219
+ if (!productionEnv) {
220
+ res.status(500).json({
221
+ message: "Project created without a Production environment.",
222
+ });
223
+ return;
224
+ }
225
+ saveConfig({
226
+ projectId: created.id,
227
+ teamId: created.teamId,
228
+ teamName,
229
+ projectName: created.name,
230
+ environmentId: productionEnv.id,
231
+ environmentName: productionEnv.name,
232
+ });
233
+ res.status(202).json({ ok: true });
234
+ void runDeploy(productionEnv.id, created.teamId);
235
+ }
236
+ catch (err) {
237
+ res.status(502).json({
238
+ message: errMessage(err, "Failed to create project"),
239
+ });
240
+ }
241
+ });
242
+ router.post("/__skybridge/deploy/login", async (_req, res) => {
243
+ try {
244
+ await alpic().auth.login();
245
+ res.json({ ok: true });
246
+ }
247
+ catch (err) {
248
+ res.status(502).json({
249
+ message: errMessage(err, "Sign-in failed"),
250
+ });
251
+ }
252
+ });
253
+ router.post("/__skybridge/deploy", (_req, res) => {
254
+ if (state.status === "deploying") {
255
+ res.status(409).json({ message: "A deployment is already in progress." });
256
+ return;
257
+ }
258
+ const cfg = loadConfig();
259
+ if (!cfg?.environmentId) {
260
+ res.status(409).json({ message: "No linked project to redeploy." });
261
+ return;
262
+ }
263
+ res.status(202).json({ ok: true });
264
+ void runDeploy(cfg.environmentId, cfg.teamId);
265
+ });
266
+ router.get("/__skybridge/deploy/events", (req, res) => {
267
+ res.setHeader("Content-Type", "text/event-stream");
268
+ res.setHeader("Cache-Control", "no-cache, no-transform");
269
+ res.setHeader("Connection", "keep-alive");
270
+ res.flushHeaders?.();
271
+ write(res, state);
272
+ subscribers.add(res);
273
+ req.on("close", () => {
274
+ subscribers.delete(res);
275
+ });
276
+ });
277
+ return router;
278
+ }
279
+ //# sourceMappingURL=deploy-router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy-router.js","sourceRoot":"","sources":["../src/deploy-router.ts"],"names":[],"mappings":"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"}
@@ -9,8 +9,8 @@ import { type Router } from "express";
9
9
  *
10
10
  * if (env.NODE_ENV !== "production") {
11
11
  * app.use(await devtoolsStaticServer(server));
12
- * app.use(await widgetsDevServer());
13
- * ^^^^^^^^ Make sure to install the devtoolsStaticServer before the widgetsDevServer
12
+ * app.use(await viewsDevServer());
13
+ * ^^^^^^^^ Make sure to install the devtoolsStaticServer before the viewsDevServer
14
14
  * }
15
15
  */
16
16
  export declare const devtoolsStaticServer: () => Promise<Router>;
@@ -2,6 +2,20 @@ import path from "node:path";
2
2
  import { fileURLToPath } from "node:url";
3
3
  import cors from "cors";
4
4
  import express, {} from "express";
5
+ import { createDeployRouter } from "./deploy-router.js";
6
+ const detectPackageManager = () => {
7
+ const userAgent = process.env.npm_config_user_agent ?? "";
8
+ if (userAgent.startsWith("pnpm")) {
9
+ return "pnpm";
10
+ }
11
+ if (userAgent.startsWith("yarn")) {
12
+ return "yarn";
13
+ }
14
+ if (userAgent.startsWith("bun")) {
15
+ return "bun";
16
+ }
17
+ return "npm";
18
+ };
5
19
  /**
6
20
  * Serve the built devtools React app
7
21
  * This router serves static files from the devtools's dist directory.
@@ -12,14 +26,18 @@ import express, {} from "express";
12
26
  *
13
27
  * if (env.NODE_ENV !== "production") {
14
28
  * app.use(await devtoolsStaticServer(server));
15
- * app.use(await widgetsDevServer());
16
- * ^^^^^^^^ Make sure to install the devtoolsStaticServer before the widgetsDevServer
29
+ * app.use(await viewsDevServer());
30
+ * ^^^^^^^^ Make sure to install the devtoolsStaticServer before the viewsDevServer
17
31
  * }
18
32
  */
19
33
  export const devtoolsStaticServer = async () => {
20
34
  const router = express.Router();
21
35
  const distDir = path.dirname(fileURLToPath(import.meta.url));
22
36
  router.use(cors());
37
+ router.get("/__skybridge/devtools/project", (_req, res) => {
38
+ res.json({ packageManager: detectPackageManager() });
39
+ });
40
+ router.use(createDeployRouter());
23
41
  router.use(express.static(distDir));
24
42
  router.get("/", (_req, res, next) => {
25
43
  const indexHtmlPath = path.join(distDir, "index.html");
@@ -1 +1 @@
1
- {"version":3,"file":"devtoolsStaticServer.js","sourceRoot":"","sources":["../src/devtoolsStaticServer.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,OAAO,EAAE,EAAe,MAAM,SAAS,CAAC;AAE/C;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,IAAqB,EAAE;IAC9D,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAEhC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAE7D,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IACnB,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IACpC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAClC,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;QACvD,GAAG,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE;YACpC,IAAI,KAAK,EAAE,CAAC;gBACV,IAAI,CAAC,KAAK,CAAC,CAAC;YACd,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC"}
1
+ {"version":3,"file":"devtoolsStaticServer.js","sourceRoot":"","sources":["../src/devtoolsStaticServer.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,OAAO,EAAE,EAAe,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAIxD,MAAM,oBAAoB,GAAG,GAAmB,EAAE;IAChD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,EAAE,CAAC;IAC1D,IAAI,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACjC,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACjC,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,IAAqB,EAAE;IAC9D,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAEhC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAE7D,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IACnB,MAAM,CAAC,GAAG,CAAC,+BAA+B,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;QACxD,GAAG,CAAC,IAAI,CAAC,EAAE,cAAc,EAAE,oBAAoB,EAAE,EAAE,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC,CAAC;IACjC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IACpC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAClC,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;QACvD,GAAG,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE;YACpC,IAAI,KAAK,EAAE,CAAC;gBACV,IAAI,CAAC,KAAK,CAAC,CAAC;YACd,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC"}
package/dist/favicon.ico CHANGED
Binary file
package/dist/index.html CHANGED
@@ -5,8 +5,8 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/favicon.ico" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>Skybridge MCP devtools</title>
8
- <script type="module" crossorigin src="/assets/index-OU90cWzh.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-BS8tKQug.css">
8
+ <script type="module" crossorigin src="/assets/index-e5cYSkNO.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-Cf7N7CBv.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="root"></div>
@@ -0,0 +1,15 @@
1
+ <svg width="90" height="90" viewBox="0 0 90 90" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <g clip-path="url(#clip0_3933_970)">
3
+ <mask id="mask0_3933_970" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="90" height="90">
4
+ <path d="M90 0H0V90H90V0Z" fill="white"/>
5
+ </mask>
6
+ <g mask="url(#mask0_3933_970)">
7
+ <path d="M17.2704 89.9987C37.5976 24.3967 65.182 12.9084 89.9996 35.3807V84.1606C89.9996 87.3849 87.3858 89.9987 84.1615 89.9987H17.2704ZM84.1615 0C87.3858 0 89.9996 2.6139 89.9996 5.83819V30.9146C52.0566 -5.26767 14.9006 31.2366 0.000976562 57.6768V5.83819C0.00104114 2.6139 2.61486 2.23904e-08 5.83917 0H84.1615Z" fill="black"/>
8
+ </g>
9
+ </g>
10
+ <defs>
11
+ <clipPath id="clip0_3933_970">
12
+ <rect width="90" height="90" fill="white"/>
13
+ </clipPath>
14
+ </defs>
15
+ </svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skybridge/devtools",
3
- "version": "0.0.0-dev.6fb9fe8",
3
+ "version": "0.0.0-dev.6fc0cc2",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -16,59 +16,74 @@
16
16
  }
17
17
  },
18
18
  "dependencies": {
19
+ "@alpic-ai/sdk": "^1.145.0",
20
+ "@t3-oss/env-core": "^0.13.11",
19
21
  "cors": "^2.8.6",
20
- "express": "^5.2.1"
22
+ "express": "^5.2.1",
23
+ "zod": "^4.3.5"
21
24
  },
22
25
  "devDependencies": {
23
- "@base-ui/react": "^1.2.0",
26
+ "@alpic-ai/ui": "^1.116.0",
27
+ "@base-ui/react": "^1.3.0",
24
28
  "@fontsource-variable/jetbrains-mono": "^5.2.8",
25
- "@microlink/react-json-view": "^1.27.1",
26
- "@modelcontextprotocol/sdk": "^1.26.0",
27
- "@rjsf/core": "^6.3.1",
28
- "@rjsf/shadcn": "^6.3.1",
29
- "@rjsf/utils": "^6.3.1",
30
- "@rjsf/validator-ajv8": "^6.3.1",
31
- "@tailwindcss/vite": "^4.1.18",
32
- "@tanstack/react-query": "^5.90.21",
29
+ "@modelcontextprotocol/sdk": "^1.29.0",
30
+ "@playwright/test": "^1.49.0",
31
+ "@radix-ui/react-accordion": "^1.2.12",
32
+ "@radix-ui/react-tooltip": "^1.2.8",
33
+ "@rjsf/core": "^6.4.2",
34
+ "@rjsf/shadcn": "^6.4.2",
35
+ "@rjsf/utils": "^6.4.2",
36
+ "@rjsf/validator-ajv8": "^6.4.2",
37
+ "@tailwindcss/vite": "^4.2.2",
38
+ "@tanstack/react-query": "^5.95.2",
33
39
  "@total-typescript/tsconfig": "^1.0.4",
34
40
  "@types/cors": "^2.8.19",
35
41
  "@types/express": "^5.0.6",
36
42
  "@types/lodash-es": "^4.17.12",
37
43
  "@types/react": "^19.2.14",
38
44
  "@types/react-dom": "^19.2.3",
39
- "@vitejs/plugin-react": "^5.1.4",
40
- "ahooks": "^3.9.6",
41
- "autoprefixer": "^10.4.24",
45
+ "@types/react-syntax-highlighter": "^15.5.13",
46
+ "@vitejs/plugin-react": "^6.0.1",
47
+ "ahooks": "^3.9.7",
48
+ "autoprefixer": "^10.4.27",
42
49
  "class-variance-authority": "^0.7.1",
43
50
  "clsx": "^2.1.1",
44
51
  "cmdk": "^1.1.1",
45
- "framer-motion": "^12.34.1",
52
+ "framer-motion": "^12.38.0",
46
53
  "lodash-es": "^4.17.23",
47
- "lucide-react": "^0.574.0",
48
- "motion": "^12.34.1",
49
- "nuqs": "^2.8.8",
50
- "postcss": "^8.5.6",
54
+ "lucide-react": "^1.7.0",
55
+ "motion": "^12.38.0",
56
+ "nuqs": "^2.8.9",
57
+ "postcss": "^8.5.8",
51
58
  "react": "^19.2.4",
52
59
  "react-dom": "^19.2.4",
53
- "react-resizable-panels": "^4.6.4",
54
- "shadcn": "^3.8.5",
55
- "shiki": "^3.22.0",
56
- "tailwind-merge": "^3.4.1",
57
- "tailwindcss": "^4.1.18",
60
+ "react-resizable-panels": "^4.11.0",
61
+ "react-syntax-highlighter": "^16.1.1",
62
+ "shadcn": "^4.1.1",
63
+ "shiki": "^4.0.2",
64
+ "tailwind-merge": "^3.5.0",
65
+ "tailwindcss": "^4.2.2",
58
66
  "tailwindcss-animate": "^1.0.7",
67
+ "tsx": "^4.21.0",
59
68
  "tw-animate-css": "^1.4.0",
60
- "typescript": "~5.9.3",
61
- "vite": "^7.3.1",
62
- "zustand": "^5.0.11",
63
- "skybridge": "0.0.0-dev.6fb9fe8"
69
+ "typescript": "~6.0.2",
70
+ "vite": "^8.0.3",
71
+ "vitest": "^4.1.4",
72
+ "zustand": "^5.0.12",
73
+ "skybridge": "0.0.0-dev.6fc0cc2"
64
74
  },
65
75
  "scripts": {
66
76
  "dev": "vite",
67
77
  "build": "tsc -b && vite build && pnpm run build:server",
68
78
  "build:server": "tsc -p tsconfig.server.json",
69
- "test": "pnpm run test:type && pnpm run test:format",
70
- "test:type": "tsc --noEmit",
79
+ "test": "pnpm run test:format && pnpm run test:types && pnpm run test:unit",
80
+ "format": "biome check --write --error-on-warnings",
71
81
  "test:format": "biome ci",
72
- "preview": "vite preview"
82
+ "test:types": "tsc --noEmit -p e2e/tsconfig.json",
83
+ "test:unit": "vitest run",
84
+ "preview": "vite preview",
85
+ "e2e:fixture": "tsx ./e2e/fixtures/server.ts",
86
+ "test:e2e": "playwright test --config e2e/playwright.config.ts",
87
+ "test:e2e:install": "playwright install --with-deps chromium"
73
88
  }
74
89
  }