viagen 0.0.2 → 0.0.3
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/README.md +30 -1
- package/dist/cli.js +345 -0
- package/dist/index.d.ts +39 -1
- package/dist/index.js +640 -342
- package/package.json +17 -10
- package/site/.viagen/server.log +1 -0
- package/site/index.html +247 -0
- package/site/vite.config.ts +7 -0
- package/dist/index.cjs +0 -803
- package/dist/index.d.cts +0 -17
package/README.md
CHANGED
|
@@ -36,6 +36,35 @@ viagen({
|
|
|
36
36
|
|
|
37
37
|
All options are optional. Defaults shown above.
|
|
38
38
|
|
|
39
|
+
## Sandbox
|
|
40
|
+
|
|
41
|
+
Deploy your dev server to a remote Vercel Sandbox:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx viagen sandbox
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
This creates an isolated microVM, uploads your project, installs dependencies, and starts the dev server. All endpoints are protected with token-based auth.
|
|
48
|
+
|
|
49
|
+
**Prerequisites:** `ANTHROPIC_API_KEY` in `.env` + Vercel auth (`vercel link && vercel env pull` or set `VERCEL_TOKEN`, `VERCEL_TEAM_ID`, `VERCEL_PROJECT_ID`).
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npx viagen sandbox stop <sandboxId> # Stop a running sandbox
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## CLI (coming soon)
|
|
56
|
+
|
|
57
|
+
`npx viagen setup` — interactive setup that uses the Vercel CLI under the hood to log in, pick a team, link a project, and write all the credentials to `.env` so `npx viagen sandbox` just works.
|
|
58
|
+
|
|
59
|
+
## Auth
|
|
60
|
+
|
|
61
|
+
Set `VIAGEN_AUTH_TOKEN` in `.env` to protect all endpoints. When set:
|
|
62
|
+
|
|
63
|
+
- Browser: visit `?token=<token>` to set a session cookie
|
|
64
|
+
- API: use `Authorization: Bearer <token>` header
|
|
65
|
+
|
|
66
|
+
Auth is automatic when deploying via `npx viagen sandbox`.
|
|
67
|
+
|
|
39
68
|
## Endpoints
|
|
40
69
|
|
|
41
70
|
**`POST /via/chat`** — Send a message, get a streamed response.
|
|
@@ -72,6 +101,6 @@ You can also open the chat UI directly at `http://localhost:5173/via/ui`.
|
|
|
72
101
|
|
|
73
102
|
```bash
|
|
74
103
|
npm install
|
|
75
|
-
npm run dev #
|
|
104
|
+
npm run dev # Dev server
|
|
76
105
|
npm run build # Build with tsup
|
|
77
106
|
```
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import { readFileSync as readFileSync2, existsSync } from "fs";
|
|
5
|
+
import { join as join2 } from "path";
|
|
6
|
+
import { execSync } from "child_process";
|
|
7
|
+
import { createInterface } from "readline";
|
|
8
|
+
|
|
9
|
+
// src/sandbox.ts
|
|
10
|
+
import { randomUUID } from "crypto";
|
|
11
|
+
import { readFileSync, readdirSync } from "fs";
|
|
12
|
+
import { join, relative } from "path";
|
|
13
|
+
import { Sandbox } from "@vercel/sandbox";
|
|
14
|
+
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
15
|
+
"node_modules",
|
|
16
|
+
".git",
|
|
17
|
+
"dist",
|
|
18
|
+
".viagen",
|
|
19
|
+
".next",
|
|
20
|
+
".nuxt"
|
|
21
|
+
]);
|
|
22
|
+
var SKIP_FILES = /* @__PURE__ */ new Set([".env", ".env.local"]);
|
|
23
|
+
function collectFiles(dir, base) {
|
|
24
|
+
const files = [];
|
|
25
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
26
|
+
if (entry.name.startsWith(".") && SKIP_DIRS.has(entry.name)) continue;
|
|
27
|
+
if (SKIP_DIRS.has(entry.name)) continue;
|
|
28
|
+
const fullPath = join(dir, entry.name);
|
|
29
|
+
const relPath = relative(base, fullPath);
|
|
30
|
+
if (entry.isDirectory()) {
|
|
31
|
+
files.push(...collectFiles(fullPath, base));
|
|
32
|
+
} else if (entry.isFile()) {
|
|
33
|
+
if (SKIP_FILES.has(entry.name)) continue;
|
|
34
|
+
files.push({ path: relPath, content: readFileSync(fullPath) });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return files;
|
|
38
|
+
}
|
|
39
|
+
function extractHost(httpsUrl) {
|
|
40
|
+
try {
|
|
41
|
+
return new URL(httpsUrl).host;
|
|
42
|
+
} catch {
|
|
43
|
+
return "github.com";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async function deploySandbox(opts) {
|
|
47
|
+
const token = randomUUID();
|
|
48
|
+
const useGit = !!opts.git;
|
|
49
|
+
const sandbox = await Sandbox.create({
|
|
50
|
+
runtime: "node22",
|
|
51
|
+
ports: [5173],
|
|
52
|
+
...opts.git ? {
|
|
53
|
+
source: {
|
|
54
|
+
type: "git",
|
|
55
|
+
url: opts.git.remoteUrl,
|
|
56
|
+
username: "x-access-token",
|
|
57
|
+
password: opts.git.token,
|
|
58
|
+
revision: opts.git.branch
|
|
59
|
+
}
|
|
60
|
+
} : {}
|
|
61
|
+
});
|
|
62
|
+
try {
|
|
63
|
+
if (useGit && opts.git) {
|
|
64
|
+
await sandbox.runCommand("git", [
|
|
65
|
+
"config",
|
|
66
|
+
"--global",
|
|
67
|
+
"user.name",
|
|
68
|
+
opts.git.userName
|
|
69
|
+
]);
|
|
70
|
+
await sandbox.runCommand("git", [
|
|
71
|
+
"config",
|
|
72
|
+
"--global",
|
|
73
|
+
"user.email",
|
|
74
|
+
opts.git.userEmail
|
|
75
|
+
]);
|
|
76
|
+
await sandbox.runCommand("bash", [
|
|
77
|
+
"-c",
|
|
78
|
+
`echo 'https://x-access-token:${opts.git.token}@${extractHost(opts.git.remoteUrl)}' > ~/.git-credentials`
|
|
79
|
+
]);
|
|
80
|
+
await sandbox.runCommand("git", [
|
|
81
|
+
"config",
|
|
82
|
+
"--global",
|
|
83
|
+
"credential.helper",
|
|
84
|
+
"store"
|
|
85
|
+
]);
|
|
86
|
+
if (opts.overlayFiles && opts.overlayFiles.length > 0) {
|
|
87
|
+
await sandbox.writeFiles(opts.overlayFiles);
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
const files = collectFiles(opts.cwd, opts.cwd);
|
|
91
|
+
if (files.length > 0) {
|
|
92
|
+
await sandbox.writeFiles(files);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const envLines = [
|
|
96
|
+
`ANTHROPIC_API_KEY=${opts.apiKey}`,
|
|
97
|
+
`VIAGEN_AUTH_TOKEN=${token}`
|
|
98
|
+
];
|
|
99
|
+
if (opts.git) {
|
|
100
|
+
envLines.push(`GITHUB_TOKEN=${opts.git.token}`);
|
|
101
|
+
}
|
|
102
|
+
await sandbox.writeFiles([
|
|
103
|
+
{
|
|
104
|
+
path: ".env",
|
|
105
|
+
content: Buffer.from(envLines.join("\n"))
|
|
106
|
+
}
|
|
107
|
+
]);
|
|
108
|
+
const install = await sandbox.runCommand("npm", ["install"]);
|
|
109
|
+
if (install.exitCode !== 0) {
|
|
110
|
+
const stderr = await install.stderr();
|
|
111
|
+
throw new Error(
|
|
112
|
+
`npm install failed (exit ${install.exitCode}): ${stderr}`
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
await sandbox.runCommand({
|
|
116
|
+
cmd: "npm",
|
|
117
|
+
args: ["run", "dev", "--", "--host", "0.0.0.0"],
|
|
118
|
+
detached: true
|
|
119
|
+
});
|
|
120
|
+
const baseUrl = sandbox.domain(5173);
|
|
121
|
+
const url = `${baseUrl}?token=${token}`;
|
|
122
|
+
return {
|
|
123
|
+
url,
|
|
124
|
+
token,
|
|
125
|
+
sandboxId: sandbox.sandboxId,
|
|
126
|
+
mode: useGit ? "git" : "upload"
|
|
127
|
+
};
|
|
128
|
+
} catch (err) {
|
|
129
|
+
await sandbox.stop().catch(() => {
|
|
130
|
+
});
|
|
131
|
+
throw err;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async function stopSandbox(sandboxId) {
|
|
135
|
+
const sandbox = await Sandbox.get({ sandboxId });
|
|
136
|
+
await sandbox.stop();
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// src/cli.ts
|
|
140
|
+
function loadDotenv(dir) {
|
|
141
|
+
const envPath = join2(dir, ".env");
|
|
142
|
+
if (!existsSync(envPath)) return {};
|
|
143
|
+
const vars = {};
|
|
144
|
+
const content = readFileSync2(envPath, "utf-8");
|
|
145
|
+
for (const line of content.split("\n")) {
|
|
146
|
+
const trimmed = line.trim();
|
|
147
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
148
|
+
const idx = trimmed.indexOf("=");
|
|
149
|
+
if (idx === -1) continue;
|
|
150
|
+
const key = trimmed.slice(0, idx).trim();
|
|
151
|
+
const val = trimmed.slice(idx + 1).trim();
|
|
152
|
+
vars[key] = val;
|
|
153
|
+
}
|
|
154
|
+
return vars;
|
|
155
|
+
}
|
|
156
|
+
function openBrowser(url) {
|
|
157
|
+
try {
|
|
158
|
+
const platform = process.platform;
|
|
159
|
+
if (platform === "darwin") {
|
|
160
|
+
execSync(`open "${url}"`);
|
|
161
|
+
} else if (platform === "linux") {
|
|
162
|
+
execSync(`xdg-open "${url}"`);
|
|
163
|
+
} else if (platform === "win32") {
|
|
164
|
+
execSync(`start "${url}"`);
|
|
165
|
+
}
|
|
166
|
+
} catch {
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function git(cwd, args) {
|
|
170
|
+
return execSync(`git ${args}`, { cwd, stdio: "pipe", encoding: "utf-8" }).trim();
|
|
171
|
+
}
|
|
172
|
+
function sshToHttps(url) {
|
|
173
|
+
if (url.startsWith("https://")) return url;
|
|
174
|
+
if (url.startsWith("http://")) return url.replace(/^http:\/\//, "https://");
|
|
175
|
+
const shorthand = url.match(/^[\w.-]+@([\w.-]+):([\w./_-]+)$/);
|
|
176
|
+
if (shorthand) return `https://${shorthand[1]}/${shorthand[2]}`;
|
|
177
|
+
const sshUrl = url.match(/^ssh:\/\/[\w.-]+@([\w.-]+)\/([\w./_-]+)$/);
|
|
178
|
+
if (sshUrl) return `https://${sshUrl[1]}/${sshUrl[2]}`;
|
|
179
|
+
return url;
|
|
180
|
+
}
|
|
181
|
+
function getGitInfo(cwd) {
|
|
182
|
+
try {
|
|
183
|
+
git(cwd, "rev-parse --is-inside-work-tree");
|
|
184
|
+
} catch {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
const remoteUrlRaw = git(cwd, "remote get-url origin");
|
|
189
|
+
const branch = git(cwd, "branch --show-current");
|
|
190
|
+
const userName = git(cwd, "config user.name");
|
|
191
|
+
const userEmail = git(cwd, "config user.email");
|
|
192
|
+
const status = git(cwd, "status --porcelain");
|
|
193
|
+
const remoteUrl = sshToHttps(remoteUrlRaw);
|
|
194
|
+
if (!remoteUrl || !branch) return null;
|
|
195
|
+
return { remoteUrl, branch, userName, userEmail, isDirty: status.length > 0 };
|
|
196
|
+
} catch {
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function promptUser(question) {
|
|
201
|
+
if (!process.stdin.isTTY) return Promise.resolve("");
|
|
202
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
203
|
+
return new Promise((resolve) => {
|
|
204
|
+
rl.question(question, (answer) => {
|
|
205
|
+
rl.close();
|
|
206
|
+
resolve(answer.trim().toLowerCase());
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
async function main() {
|
|
211
|
+
const args = process.argv.slice(2);
|
|
212
|
+
const command = args[0];
|
|
213
|
+
if (command === "sandbox") {
|
|
214
|
+
const subcommand = args[1];
|
|
215
|
+
if (subcommand === "stop") {
|
|
216
|
+
const sandboxId = args[2];
|
|
217
|
+
if (!sandboxId) {
|
|
218
|
+
console.error("Usage: viagen sandbox stop <sandboxId>");
|
|
219
|
+
process.exit(1);
|
|
220
|
+
}
|
|
221
|
+
console.log(`Stopping sandbox ${sandboxId}...`);
|
|
222
|
+
await stopSandbox(sandboxId);
|
|
223
|
+
console.log("Sandbox stopped.");
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const cwd = process.cwd();
|
|
227
|
+
const dotenv = loadDotenv(cwd);
|
|
228
|
+
for (const [key, val] of Object.entries(dotenv)) {
|
|
229
|
+
if (!process.env[key]) process.env[key] = val;
|
|
230
|
+
}
|
|
231
|
+
const env = { ...dotenv, ...process.env };
|
|
232
|
+
const apiKey = env["ANTHROPIC_API_KEY"];
|
|
233
|
+
if (!apiKey) {
|
|
234
|
+
console.error("Error: ANTHROPIC_API_KEY not found.");
|
|
235
|
+
console.error("Set it in .env or as an environment variable.");
|
|
236
|
+
process.exit(1);
|
|
237
|
+
}
|
|
238
|
+
const hasOidc = !!env["VERCEL_OIDC_TOKEN"];
|
|
239
|
+
const hasToken = !!env["VERCEL_TOKEN"] && !!env["VERCEL_TEAM_ID"] && !!env["VERCEL_PROJECT_ID"];
|
|
240
|
+
if (!hasOidc && !hasToken) {
|
|
241
|
+
console.error("Error: Vercel authentication not configured.");
|
|
242
|
+
console.error("");
|
|
243
|
+
console.error("Option 1: Run `vercel link && vercel env pull`");
|
|
244
|
+
console.error(
|
|
245
|
+
"Option 2: Set VERCEL_TOKEN, VERCEL_TEAM_ID, and VERCEL_PROJECT_ID"
|
|
246
|
+
);
|
|
247
|
+
process.exit(1);
|
|
248
|
+
}
|
|
249
|
+
const githubToken = env["GITHUB_TOKEN"];
|
|
250
|
+
const gitInfo = getGitInfo(cwd);
|
|
251
|
+
let deployGit;
|
|
252
|
+
let overlayFiles;
|
|
253
|
+
if (gitInfo && githubToken) {
|
|
254
|
+
if (gitInfo.isDirty) {
|
|
255
|
+
console.log("");
|
|
256
|
+
console.log("Your working tree has uncommitted changes.");
|
|
257
|
+
console.log("");
|
|
258
|
+
console.log(" 1) Clone from remote (clean) \u2014 full git, can push");
|
|
259
|
+
console.log(" 2) Upload local files \u2014 includes changes, no git");
|
|
260
|
+
console.log(" 3) Clone + overlay \u2014 git history + your local changes (default)");
|
|
261
|
+
console.log("");
|
|
262
|
+
let answer = await promptUser("Choose mode [1/2/3]: ");
|
|
263
|
+
if (!answer || answer === "3") {
|
|
264
|
+
deployGit = {
|
|
265
|
+
remoteUrl: gitInfo.remoteUrl,
|
|
266
|
+
branch: gitInfo.branch,
|
|
267
|
+
userName: gitInfo.userName,
|
|
268
|
+
userEmail: gitInfo.userEmail,
|
|
269
|
+
token: githubToken
|
|
270
|
+
};
|
|
271
|
+
overlayFiles = collectFiles(cwd, cwd);
|
|
272
|
+
} else if (answer === "1") {
|
|
273
|
+
deployGit = {
|
|
274
|
+
remoteUrl: gitInfo.remoteUrl,
|
|
275
|
+
branch: gitInfo.branch,
|
|
276
|
+
userName: gitInfo.userName,
|
|
277
|
+
userEmail: gitInfo.userEmail,
|
|
278
|
+
token: githubToken
|
|
279
|
+
};
|
|
280
|
+
} else {
|
|
281
|
+
console.log("Note: Sandbox is ephemeral \u2014 changes can't be pushed.");
|
|
282
|
+
}
|
|
283
|
+
} else {
|
|
284
|
+
deployGit = {
|
|
285
|
+
remoteUrl: gitInfo.remoteUrl,
|
|
286
|
+
branch: gitInfo.branch,
|
|
287
|
+
userName: gitInfo.userName,
|
|
288
|
+
userEmail: gitInfo.userEmail,
|
|
289
|
+
token: githubToken
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
} else if (gitInfo && !githubToken) {
|
|
293
|
+
console.log("Note: No GITHUB_TOKEN set \u2014 changes from the sandbox can't be saved.");
|
|
294
|
+
} else {
|
|
295
|
+
console.log("Note: Not a git repo \u2014 sandbox will use file upload (ephemeral).");
|
|
296
|
+
}
|
|
297
|
+
console.log("");
|
|
298
|
+
console.log("Creating sandbox...");
|
|
299
|
+
if (deployGit) {
|
|
300
|
+
console.log(` Repo: ${deployGit.remoteUrl}`);
|
|
301
|
+
console.log(` Branch: ${deployGit.branch}`);
|
|
302
|
+
}
|
|
303
|
+
const result = await deploySandbox({ cwd, apiKey, git: deployGit, overlayFiles });
|
|
304
|
+
console.log("");
|
|
305
|
+
console.log("Sandbox deployed!");
|
|
306
|
+
console.log("");
|
|
307
|
+
console.log(` URL: ${result.url}`);
|
|
308
|
+
console.log(` Sandbox ID: ${result.sandboxId}`);
|
|
309
|
+
console.log(` Mode: ${result.mode === "git" ? "git clone (can push)" : "file upload (ephemeral)"}`);
|
|
310
|
+
console.log(` Token: ${result.token}`);
|
|
311
|
+
console.log("");
|
|
312
|
+
console.log(`Stop with: npx viagen sandbox stop ${result.sandboxId}`);
|
|
313
|
+
openBrowser(result.url);
|
|
314
|
+
} else {
|
|
315
|
+
console.log("viagen \u2014 Claude Code in your Vite dev server");
|
|
316
|
+
console.log("");
|
|
317
|
+
console.log("Usage:");
|
|
318
|
+
console.log(" viagen <command>");
|
|
319
|
+
console.log("");
|
|
320
|
+
console.log("Commands:");
|
|
321
|
+
console.log(" sandbox Deploy your project to a Vercel Sandbox");
|
|
322
|
+
console.log(" sandbox stop <id> Stop a running sandbox");
|
|
323
|
+
console.log(" help Show this help message");
|
|
324
|
+
console.log("");
|
|
325
|
+
console.log("Getting started:");
|
|
326
|
+
console.log(" 1. npm install viagen");
|
|
327
|
+
console.log(" 2. Add viagen() to your vite.config.ts plugins");
|
|
328
|
+
console.log(" 3. Set ANTHROPIC_API_KEY in .env");
|
|
329
|
+
console.log(" 4. npm run dev");
|
|
330
|
+
console.log("");
|
|
331
|
+
console.log("Environment variables (.env):");
|
|
332
|
+
console.log(" ANTHROPIC_API_KEY Required. Your Anthropic API key.");
|
|
333
|
+
console.log(" GITHUB_TOKEN Optional. Enables git commit+push from sandbox.");
|
|
334
|
+
console.log(" VIAGEN_AUTH_TOKEN Optional. Protects all endpoints with token auth.");
|
|
335
|
+
console.log(" VERCEL_TOKEN Required for sandbox. Vercel access token.");
|
|
336
|
+
console.log(" VERCEL_TEAM_ID Required for sandbox. From .vercel/project.json (orgId).");
|
|
337
|
+
console.log(" VERCEL_PROJECT_ID Required for sandbox. From .vercel/project.json (projectId).");
|
|
338
|
+
console.log("");
|
|
339
|
+
console.log("Docs: http://localhost:5173/via/docs (when dev server is running)");
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
main().catch((err) => {
|
|
343
|
+
console.error(err.message || err);
|
|
344
|
+
process.exit(1);
|
|
345
|
+
});
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
import { Plugin } from 'vite';
|
|
2
2
|
|
|
3
|
+
interface GitInfo {
|
|
4
|
+
/** HTTPS remote URL (transformed from SSH if needed). */
|
|
5
|
+
remoteUrl: string;
|
|
6
|
+
/** Branch to check out. */
|
|
7
|
+
branch: string;
|
|
8
|
+
/** Git user name for commits. */
|
|
9
|
+
userName: string;
|
|
10
|
+
/** Git user email for commits. */
|
|
11
|
+
userEmail: string;
|
|
12
|
+
/** GitHub PAT (or other host token) for auth. */
|
|
13
|
+
token: string;
|
|
14
|
+
}
|
|
15
|
+
interface DeploySandboxOptions {
|
|
16
|
+
/** Project directory to upload (used in file-upload mode). */
|
|
17
|
+
cwd: string;
|
|
18
|
+
/** Anthropic API key to inject into sandbox .env. */
|
|
19
|
+
apiKey: string;
|
|
20
|
+
/** If provided, clone the repo instead of uploading files. */
|
|
21
|
+
git?: GitInfo;
|
|
22
|
+
/** Dirty files to overlay on top of a git clone. */
|
|
23
|
+
overlayFiles?: {
|
|
24
|
+
path: string;
|
|
25
|
+
content: Buffer;
|
|
26
|
+
}[];
|
|
27
|
+
}
|
|
28
|
+
interface DeploySandboxResult {
|
|
29
|
+
/** Full URL with auth token in query string. */
|
|
30
|
+
url: string;
|
|
31
|
+
/** Auth token for API access. */
|
|
32
|
+
token: string;
|
|
33
|
+
/** Sandbox ID for later management. */
|
|
34
|
+
sandboxId: string;
|
|
35
|
+
/** Deployment mode used. */
|
|
36
|
+
mode: "git" | "upload";
|
|
37
|
+
}
|
|
38
|
+
declare function deploySandbox(opts: DeploySandboxOptions): Promise<DeploySandboxResult>;
|
|
39
|
+
|
|
3
40
|
interface ViagenOptions {
|
|
4
41
|
/** Toggle button placement. Default: 'bottom-right' */
|
|
5
42
|
position?: "bottom-right" | "bottom-left" | "top-right" | "top-left";
|
|
@@ -12,6 +49,7 @@ interface ViagenOptions {
|
|
|
12
49
|
/** Inject the toggle button + chat panel into pages. Default: true */
|
|
13
50
|
ui?: boolean;
|
|
14
51
|
}
|
|
52
|
+
|
|
15
53
|
declare function viagen(options?: ViagenOptions): Plugin;
|
|
16
54
|
|
|
17
|
-
export { type ViagenOptions, viagen as default, viagen };
|
|
55
|
+
export { type GitInfo, type ViagenOptions, viagen as default, deploySandbox, viagen };
|