viagen 0.0.57 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -252,7 +252,9 @@ async function deploySandbox(opts) {
252
252
  sandboxId: sandbox2.sandboxId,
253
253
  mode: useGit ? "git" : "upload",
254
254
  streamLogs: (opts2) => devServer.logs(opts2),
255
- stop: () => sandbox2.stop()
255
+ stop: async () => {
256
+ await sandbox2.stop();
257
+ }
256
258
  };
257
259
  } catch (err) {
258
260
  await sandbox2.stop().catch(() => {
package/dist/index.js CHANGED
@@ -101,16 +101,17 @@ function registerHealthRoutes(server, env, errorRef) {
101
101
  const prompt = env["VIAGEN_PROMPT"] || null;
102
102
  const taskId = env["VIAGEN_TASK_ID"] || null;
103
103
  const environmentId = env["VIAGEN_ENVIRONMENT_ID"] || null;
104
+ const projectId = env["VIAGEN_PROJECT_ID"] || null;
104
105
  res.setHeader("Content-Type", "application/json");
105
106
  if (configured) {
106
- res.end(JSON.stringify({ status: "ok", configured: true, git, vercel, branch, session, prompt, taskId, environmentId, missing }));
107
+ res.end(JSON.stringify({ status: "ok", configured: true, git, vercel, branch, session, prompt, taskId, environmentId, projectId, missing }));
107
108
  } else {
108
109
  res.end(
109
- JSON.stringify({ status: "error", configured: false, git, vercel, branch, session, prompt, taskId, environmentId, missing })
110
+ JSON.stringify({ status: "error", configured: false, git, vercel, branch, session, prompt, taskId, environmentId, projectId, missing })
110
111
  );
111
112
  }
112
113
  });
113
- const currentVersion = true ? "0.0.57" : "0.0.0";
114
+ const currentVersion = true ? "0.1.2" : "0.0.0";
114
115
  debug("health", `version resolved: ${currentVersion}`);
115
116
  let versionCache = null;
116
117
  server.middlewares.use("/via/version", (_req, res) => {
@@ -770,10 +771,10 @@ data: ${JSON.stringify(doneData)}
770
771
  `);
771
772
  res.end();
772
773
  }
773
- if (opts.viagenClient && opts.environmentId) {
774
+ if (opts.viagenClient && opts.projectId) {
774
775
  const taskId = opts.env["VIAGEN_TASK_ID"];
775
776
  if (taskId && (event.inputTokens || event.outputTokens)) {
776
- opts.viagenClient.tasks.update(opts.environmentId, taskId, {
777
+ opts.viagenClient.tasks.update(opts.projectId, taskId, {
777
778
  ...event.inputTokens != null && { inputTokens: event.inputTokens },
778
779
  ...event.outputTokens != null && { outputTokens: event.outputTokens }
779
780
  }).catch((err) => {
@@ -3798,7 +3799,7 @@ function buildUiHtml(opts) {
3798
3799
 
3799
3800
  // Store task context for history rendering
3800
3801
  healthTaskId = data.taskId || null;
3801
- healthProjectId = data.environmentId || null;
3802
+ healthProjectId = data.projectId || data.environmentId || null;
3802
3803
 
3803
3804
  // Load chat history from server (source of truth)
3804
3805
  await loadHistory();
@@ -3892,7 +3893,7 @@ function buildUiHtml(opts) {
3892
3893
  if (data.prompt && data.configured && chatLog.length === 0) {
3893
3894
  if (data.taskId) {
3894
3895
  // Task mode: show link instead of raw prompt
3895
- var taskUrl = 'https://app.viagen.dev/environments/' + data.environmentId + '/tasks/' + data.taskId;
3896
+ var taskUrl = 'https://app.viagen.dev/projects/' + (data.projectId || data.environmentId) + '/tasks/' + data.taskId;
3896
3897
  var div = document.createElement('div');
3897
3898
  div.className = 'msg msg-user';
3898
3899
  div.innerHTML = '<span class="label">Task</span><span class="text">Working on <a href="' + escapeHtml(taskUrl) + '" target="_blank" style="color:#2563eb;text-decoration:underline;">Via Task</a></span>';
@@ -4287,6 +4288,34 @@ function parseCookies(header) {
4287
4288
  }
4288
4289
  return cookies;
4289
4290
  }
4291
+ function buildWaitPage(targetUrl) {
4292
+ return `<!DOCTYPE html>
4293
+ <html><head><meta charset="utf-8"><title>Loading\u2026</title>
4294
+ <style>
4295
+ body { margin: 0; display: flex; align-items: center; justify-content: center;
4296
+ height: 100vh; background: #0a0a0a; color: #888; font-family: system-ui; }
4297
+ .spinner { width: 20px; height: 20px; border: 2px solid #333; border-top-color: #f97316;
4298
+ border-radius: 50%; animation: spin .6s linear infinite; margin-right: 12px; }
4299
+ @keyframes spin { to { transform: rotate(360deg); } }
4300
+ </style></head>
4301
+ <body><div class="spinner"></div><span>Starting dev server\u2026</span>
4302
+ <script>
4303
+ (async () => {
4304
+ const target = ${JSON.stringify(targetUrl)};
4305
+ for (let i = 0; i < 60; i++) {
4306
+ try {
4307
+ const r = await fetch(target, { credentials: 'same-origin' });
4308
+ const text = await r.text();
4309
+ // Vite is ready when we get a non-empty HTML response
4310
+ if (r.ok && text.length > 0) { window.location.replace(target); return; }
4311
+ } catch {}
4312
+ await new Promise(r => setTimeout(r, 500));
4313
+ }
4314
+ // After 30s, navigate anyway \u2014 let the user see whatever error there is
4315
+ window.location.replace(target);
4316
+ })();
4317
+ </script></body></html>`;
4318
+ }
4290
4319
  function createAuthMiddleware(token) {
4291
4320
  return function authMiddleware(req, res, next) {
4292
4321
  const url2 = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
@@ -4294,26 +4323,26 @@ function createAuthMiddleware(token) {
4294
4323
  if (pathMatch && pathMatch[2] === token) {
4295
4324
  const cleanPath = pathMatch[1] || "/";
4296
4325
  const cleanUrl = cleanPath + (url2.search || "");
4297
- debug("auth", `token URL match (/t/:token) \u2192 redirect to ${cleanUrl}`);
4326
+ debug("auth", `token URL match (/t/:token) \u2192 wait-page redirect to ${cleanUrl}`);
4298
4327
  res.setHeader(
4299
4328
  "Set-Cookie",
4300
4329
  `viagen_session=${token}; HttpOnly; SameSite=Lax; Path=/`
4301
4330
  );
4302
- res.writeHead(302, { Location: cleanUrl });
4303
- res.end();
4331
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
4332
+ res.end(buildWaitPage(cleanUrl));
4304
4333
  return;
4305
4334
  }
4306
4335
  const queryToken = url2.searchParams.get("token");
4307
4336
  if (queryToken === token) {
4308
4337
  url2.searchParams.delete("token");
4309
4338
  const cleanUrl = url2.pathname + (url2.search || "");
4310
- debug("auth", `query token match (?token=) \u2192 redirect to ${cleanUrl}`);
4339
+ debug("auth", `query token match (?token=) \u2192 wait-page redirect to ${cleanUrl}`);
4311
4340
  res.setHeader(
4312
4341
  "Set-Cookie",
4313
4342
  `viagen_session=${token}; HttpOnly; SameSite=Lax; Path=/`
4314
4343
  );
4315
- res.writeHead(302, { Location: cleanUrl });
4316
- res.end();
4344
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
4345
+ res.end(buildWaitPage(cleanUrl));
4317
4346
  return;
4318
4347
  }
4319
4348
  if (req.headers.cookie) {
@@ -18657,7 +18686,7 @@ import {
18657
18686
  tool
18658
18687
  } from "@anthropic-ai/claude-agent-sdk";
18659
18688
  function createViagenTools(config2) {
18660
- const { client, environmentId } = config2;
18689
+ const { client, projectId } = config2;
18661
18690
  const taskId = process.env["VIAGEN_TASK_ID"];
18662
18691
  const tools = [
18663
18692
  tool(
@@ -18682,7 +18711,7 @@ function createViagenTools(config2) {
18682
18711
  }
18683
18712
  const internalStatus = args.status === "review" ? "validating" : args.status === "completed" ? "completed" : args.status;
18684
18713
  try {
18685
- await client.tasks.update(environmentId, id, {
18714
+ await client.tasks.update(projectId, id, {
18686
18715
  ...internalStatus && { status: internalStatus },
18687
18716
  ...args.prUrl && { prUrl: args.prUrl },
18688
18717
  result: args.result,
@@ -18703,12 +18732,12 @@ function createViagenTools(config2) {
18703
18732
  ),
18704
18733
  tool(
18705
18734
  "viagen_list_tasks",
18706
- "List tasks in the current environment. Optionally filter by status.",
18735
+ "List tasks in the current project. Optionally filter by status.",
18707
18736
  {
18708
18737
  status: external_exports.enum(["ready", "running", "validating", "completed", "timed_out"]).optional().describe("Filter tasks by status.")
18709
18738
  },
18710
18739
  async (args) => {
18711
- const tasks = await client.tasks.list(environmentId, args.status);
18740
+ const tasks = await client.tasks.list(projectId, args.status);
18712
18741
  return {
18713
18742
  content: [
18714
18743
  {
@@ -18726,7 +18755,7 @@ function createViagenTools(config2) {
18726
18755
  taskId: external_exports.string().describe("The task ID to retrieve.")
18727
18756
  },
18728
18757
  async (args) => {
18729
- const task = await client.tasks.get(environmentId, args.taskId);
18758
+ const task = await client.tasks.get(projectId, args.taskId);
18730
18759
  return {
18731
18760
  content: [
18732
18761
  {
@@ -18739,14 +18768,14 @@ function createViagenTools(config2) {
18739
18768
  ),
18740
18769
  tool(
18741
18770
  "viagen_create_task",
18742
- "Create a new task in the current environment. Use this to create follow-up work.",
18771
+ "Create a new task in the current project. Use this to create follow-up work.",
18743
18772
  {
18744
18773
  prompt: external_exports.string().describe("The task prompt / instructions."),
18745
18774
  branch: external_exports.string().optional().describe("Git branch name for the task."),
18746
18775
  type: external_exports.enum(["task", "plan"]).optional().describe("Task type: 'task' for code changes, 'plan' for implementation plans.")
18747
18776
  },
18748
18777
  async (args) => {
18749
- const task = await client.tasks.create(environmentId, {
18778
+ const task = await client.tasks.create(projectId, {
18750
18779
  prompt: args.prompt,
18751
18780
  branch: args.branch,
18752
18781
  type: args.type
@@ -18793,12 +18822,12 @@ Constraints:
18793
18822
  `;
18794
18823
  var TASK_TOOLS_PROMPT = `
18795
18824
  You have access to viagen platform tools for task management:
18796
- - viagen_list_tasks: List tasks in this environment (optionally filter by status)
18825
+ - viagen_list_tasks: List tasks in this project (optionally filter by status)
18797
18826
  - viagen_get_task: Get full details of a specific task
18798
18827
  - viagen_create_task: Create follow-up tasks for work you identify
18799
18828
  - viagen_update_task: Update a task's status ('review' or 'completed'). Accepts an optional taskId \u2014 defaults to the current task if one is set.
18800
18829
 
18801
- Use these to understand environment context and create follow-up work when appropriate.
18830
+ Use these to understand project context and create follow-up work when appropriate.
18802
18831
  `;
18803
18832
 
18804
18833
  // src/index.ts
@@ -19049,7 +19078,9 @@ async function deploySandbox(opts) {
19049
19078
  sandboxId: sandbox.sandboxId,
19050
19079
  mode: useGit ? "git" : "upload",
19051
19080
  streamLogs: (opts2) => devServer.logs(opts2),
19052
- stop: () => sandbox.stop()
19081
+ stop: async () => {
19082
+ await sandbox.stop();
19083
+ }
19053
19084
  };
19054
19085
  } catch (err) {
19055
19086
  await sandbox.stop().catch(() => {
@@ -19182,7 +19213,7 @@ ${payload.err.frame || ""}`
19182
19213
  }
19183
19214
  const platformToken = env["VIAGEN_USER_TOKEN"] || env["VIAGEN_AUTH_TOKEN"];
19184
19215
  const platformUrl = env["VIAGEN_PLATFORM_URL"] || "https://app.viagen.dev";
19185
- const environmentId = env["VIAGEN_ENVIRONMENT_ID"];
19216
+ const projectId = env["VIAGEN_PROJECT_ID"];
19186
19217
  let viagenClient = null;
19187
19218
  if (platformToken) {
19188
19219
  viagenClient = createViagen({ token: platformToken, baseUrl: platformUrl });
@@ -19222,9 +19253,9 @@ ${payload.err.frame || ""}`
19222
19253
  res.end(JSON.stringify({ error: "Method not allowed" }));
19223
19254
  return;
19224
19255
  }
19225
- if (!viagenClient || !environmentId) {
19256
+ if (!viagenClient || !projectId) {
19226
19257
  res.writeHead(503, { "Content-Type": "application/json" });
19227
- res.end(JSON.stringify({ error: "Task creation not configured: missing platform credentials or VIAGEN_ENVIRONMENT_ID" }));
19258
+ res.end(JSON.stringify({ error: "Task creation not configured: missing platform credentials or VIAGEN_PROJECT_ID" }));
19228
19259
  return;
19229
19260
  }
19230
19261
  let body = "";
@@ -19246,7 +19277,7 @@ Page URL: ${pageUrl}`);
19246
19277
  if (screenshot) parts.push("\n[Screenshot attached]");
19247
19278
  parts.push("\n\n[Submitted via viagen preview feedback]");
19248
19279
  const fullPrompt = parts.join("");
19249
- const task = await viagenClient.tasks.create(environmentId, { prompt: fullPrompt, type: "task" });
19280
+ const task = await viagenClient.tasks.create(projectId, { prompt: fullPrompt, type: "task" });
19250
19281
  if (screenshot && task.id) {
19251
19282
  try {
19252
19283
  const [header, b64] = screenshot.split(",");
@@ -19254,7 +19285,7 @@ Page URL: ${pageUrl}`);
19254
19285
  const binary = Buffer.from(b64, "base64");
19255
19286
  const blob = new Blob([binary], { type: mime });
19256
19287
  const ext = mime === "image/png" ? "png" : "jpeg";
19257
- await viagenClient.tasks.addAttachment(environmentId, task.id, blob, `screenshot.${ext}`);
19288
+ await viagenClient.tasks.addAttachment(projectId, task.id, blob, `screenshot.${ext}`);
19258
19289
  debug("preview", `screenshot attached to task ${task.id}`);
19259
19290
  } catch (attachErr) {
19260
19291
  debug("preview", `screenshot attachment failed (non-fatal): ${attachErr}`);
@@ -19277,12 +19308,12 @@ Page URL: ${pageUrl}`);
19277
19308
  const resolvedModel = env["VIAGEN_MODEL"] || opts.model;
19278
19309
  debug("server", `creating ChatSession (model: ${resolvedModel})`);
19279
19310
  let mcpServers;
19280
- const hasPlatformContext = !!(viagenClient && environmentId);
19311
+ const hasPlatformContext = !!(viagenClient && projectId);
19281
19312
  if (hasPlatformContext) {
19282
19313
  debug("server", "creating viagen MCP tools (platform connected)");
19283
19314
  const viagenMcp = createViagenTools({
19284
19315
  client: viagenClient,
19285
- environmentId
19316
+ projectId
19286
19317
  });
19287
19318
  mcpServers = { [viagenMcp.name]: viagenMcp };
19288
19319
  }
@@ -19314,7 +19345,7 @@ Page URL: ${pageUrl}`);
19314
19345
  registerChatRoutes(server, chatSession, {
19315
19346
  env,
19316
19347
  viagenClient: viagenClient ?? void 0,
19317
- environmentId
19348
+ projectId
19318
19349
  });
19319
19350
  if (hasEditor) {
19320
19351
  registerFileRoutes(server, {
@@ -19334,8 +19365,8 @@ Page URL: ${pageUrl}`);
19334
19365
  debug("server", "auto-prompt completed");
19335
19366
  logBuffer.push("info", `[viagen] Prompt completed`);
19336
19367
  const currentTaskId = env["VIAGEN_TASK_ID"];
19337
- if (viagenClient && environmentId && currentTaskId && (event.inputTokens || event.outputTokens)) {
19338
- viagenClient.tasks.update(environmentId, currentTaskId, {
19368
+ if (viagenClient && projectId && currentTaskId && (event.inputTokens || event.outputTokens)) {
19369
+ viagenClient.tasks.update(projectId, currentTaskId, {
19339
19370
  ...event.inputTokens != null && { inputTokens: event.inputTokens },
19340
19371
  ...event.outputTokens != null && { outputTokens: event.outputTokens }
19341
19372
  }).catch((err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "viagen",
3
- "version": "0.0.57",
3
+ "version": "0.1.2",
4
4
  "description": "Vite dev server plugin that exposes endpoints for chatting with Claude Code SDK",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -50,6 +50,6 @@
50
50
  "license": "MIT",
51
51
  "repository": {
52
52
  "type": "git",
53
- "url": "https://github.com/viagen-dev/viagen"
53
+ "url": "https://github.com/viagen-dev/viagen-sdk"
54
54
  }
55
55
  }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 Ben Ipsen
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
package/README.md DELETED
@@ -1,189 +0,0 @@
1
- # viagen
2
-
3
- A Vite dev server plugin and CLI tool that enables you to use Claude Code in a sandbox — instantly.
4
-
5
- ## Prerequisites
6
-
7
- - [Claude](https://claude.ai/signup) — Max, Pro, or API plan. The setup wizard handles auth.
8
- - [Vercel](https://vercel.com/signup) — Free plan works. Sandboxes last 45 min on Hobby, 5 hours on Pro.
9
- - [GitHub CLI](https://cli.github.com) — Enables git clone and push from sandboxes.
10
-
11
- ## Quick Setup (Claude Code Plugin)
12
-
13
- ```
14
- /plugin marketplace add viagen-dev/viagen-claude-plugin
15
- /plugin install viagen@viagen-marketplace
16
- ```
17
-
18
- **Restart Claude Code to load the plugin.**
19
-
20
- ```
21
- /viagen-install
22
- ```
23
-
24
- The plugin will handle npm installation, vite config updates, and run the setup wizard for you.
25
-
26
- ## Manual Setup
27
-
28
- ### Step 1 — Add viagen to your app
29
-
30
- ```bash
31
- npm install --save-dev viagen
32
- ```
33
-
34
- ```ts
35
- // vite.config.ts
36
- import { defineConfig } from 'vite'
37
- import { viagen } from 'viagen'
38
-
39
- export default defineConfig({
40
- plugins: [viagen()],
41
- })
42
- ```
43
-
44
- ### Step 2 — Setup
45
-
46
- ```bash
47
- npx viagen setup
48
- ```
49
-
50
- The setup wizard authenticates with Claude, detects your GitHub and Vercel credentials, and captures your git remote info — all written to your local `.env`. This ensures sandboxes clone the correct repo instead of inferring it at runtime.
51
-
52
- You can now run `npm run dev` to start the local dev server. At this point you can launch viagen and chat with Claude to make changes to your app.
53
-
54
- ### Step 3 — Sandbox
55
-
56
- ```bash
57
- npx viagen sandbox
58
- ```
59
-
60
- Deploys your dev server to a remote Vercel Sandbox — an isolated VM-like environment where Claude can read, write, and push code.
61
-
62
- ```bash
63
- # Deploy on a specific branch
64
- npx viagen sandbox --branch feature/my-thing
65
-
66
- # Set a longer timeout (default: 30 min)
67
- npx viagen sandbox --timeout 60
68
-
69
- # Auto-send a prompt on load
70
- npx viagen sandbox --prompt "build me a landing page"
71
-
72
- # Stop a running sandbox
73
- npx viagen sandbox stop <sandboxId>
74
- ```
75
-
76
-
77
- ## Plugin Options
78
-
79
- ```ts
80
- viagen({
81
- position: 'bottom-right', // toggle button position
82
- model: 'sonnet', // claude model
83
- panelWidth: 375, // chat panel width in px
84
- overlay: true, // fix button on error overlay
85
- ui: true, // inject chat panel into pages
86
- sandboxFiles: [...], // copy files manually into sandbox
87
- systemPrompt: '...', // custom system prompt (see below)
88
- editable: ['src','conf'], // files/dirs editable in the UI
89
- mcpServers: { ... }, // additional MCP servers for Claude
90
- })
91
- ```
92
-
93
-
94
- ### Custom MCP Servers
95
-
96
- Pass additional [MCP server](https://modelcontextprotocol.io) configurations to give Claude access to custom tools:
97
-
98
- ```ts
99
- viagen({
100
- mcpServers: {
101
- 'my-db': {
102
- command: 'npx',
103
- args: ['-y', '@my-org/db-mcp-server'],
104
- env: { DATABASE_URL: process.env.DATABASE_URL },
105
- },
106
- },
107
- })
108
- ```
109
-
110
- These are merged with viagen's built-in platform tools (when connected). User-provided servers take precedence if names collide.
111
-
112
- ### Editable Files
113
-
114
- Add a file editor panel to the chat UI:
115
-
116
- ```ts
117
- viagen({
118
- editable: ['src/components', 'vite.config.ts']
119
- })
120
- ```
121
-
122
- Paths can be files or directories (directories include all files within). The editor appears as a "Files" tab in the chat panel with a collapsible directory tree, syntax highlighting (TypeScript, JavaScript, CSS, HTML, JSON, Markdown), and image preview.
123
-
124
- The default system prompt tells Claude it's embedded in a Vite dev server, that file edits trigger HMR, and how to check server logs. Recent build errors are automatically appended to give Claude context about what went wrong.
125
-
126
- To customize the prompt, you can replace it entirely or extend the default:
127
-
128
- ```ts
129
- import { viagen, DEFAULT_SYSTEM_PROMPT } from 'viagen'
130
-
131
- viagen({
132
- // Replace entirely
133
- systemPrompt: 'You are a React expert. Only use TypeScript.',
134
-
135
- // Or extend the default
136
- systemPrompt: DEFAULT_SYSTEM_PROMPT + '\nAlways use Tailwind for styling.',
137
- })
138
- ```
139
-
140
- ## API
141
-
142
- Every viagen endpoint is available as an API. Build your own UI, integrate with CI, or script Claude from the command line.
143
-
144
- ```
145
- POST /via/chat — send a message, streamed SSE response
146
- POST /via/chat/reset — clear conversation history
147
- GET /via/health — check API key status
148
- GET /via/error — latest build error (if any)
149
- GET /via/ui — standalone chat interface
150
- GET /via/iframe — split view (app + chat side by side)
151
- GET /via/files — list editable files (when configured)
152
- GET /via/file?path= — read file content
153
- POST /via/file — write file content { path, content }
154
- GET /via/file/raw — serve raw file (images, etc.) with correct MIME type
155
- GET /via/git/status — list changed files (git status)
156
- GET /via/git/diff — full diff, or single file with ?path=
157
- GET /via/git/branch — current branch, remote URL, open PR info
158
- GET /via/logs — dev server log entries, optional ?since=<timestamp>
159
- ```
160
-
161
- When `VIAGEN_AUTH_TOKEN` is set (always on in sandboxes), pass the token as a `Bearer` header, a `/t/:token` path segment, or a `?token=` query param.
162
-
163
- ```bash
164
- # With curl
165
- curl -X POST http://localhost:5173/via/chat \
166
- -H "Authorization: Bearer $VIAGEN_AUTH_TOKEN" \
167
- -H "Content-Type: application/json" \
168
- -d '{"message": "add a hello world route"}'
169
-
170
- # Or pass the token in the URL path (sets a session cookie)
171
- open "http://localhost:5173/via/ui/t/$VIAGEN_AUTH_TOKEN"
172
-
173
- # ?token= query param also works (fallback for backwards compat)
174
- open "http://localhost:5173/via/ui?token=$VIAGEN_AUTH_TOKEN"
175
- ```
176
-
177
- ## Development
178
-
179
- ```bash
180
- npm install
181
- npm run dev # Dev server (site)
182
- npm run build # Build with tsup
183
- npm run test # Run tests
184
- npm run typecheck # Type check
185
- ```
186
-
187
- ## License
188
-
189
- [MIT](LICENSE)