stage-ai 0.1.0 → 0.2.0
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/commands/exec.d.ts +1 -1
- package/dist/commands/exec.js +5 -32
- package/dist/commands/ls.js +12 -9
- package/dist/commands/new.js +25 -6
- package/dist/commands/push.js +7 -4
- package/dist/commands/read.js +5 -5
- package/dist/commands/render.js +4 -4
- package/dist/commands/write.js +4 -4
- package/dist/convex-client.d.ts +56 -0
- package/dist/convex-client.js +144 -0
- package/dist/main.js +34 -7
- package/package.json +16 -4
package/dist/commands/exec.d.ts
CHANGED
package/dist/commands/exec.js
CHANGED
|
@@ -1,34 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { error, output } from "../utils/output.js";
|
|
1
|
+
import { error } from "../utils/output.js";
|
|
3
2
|
import { EXIT_ERROR } from "../utils/exit-codes.js";
|
|
4
|
-
export async function exec(
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
output(options, {
|
|
9
|
-
json: () => ({
|
|
10
|
-
stdout: result.stdout,
|
|
11
|
-
stderr: result.stderr,
|
|
12
|
-
exitCode: result.exitCode,
|
|
13
|
-
session: sessionId,
|
|
14
|
-
}),
|
|
15
|
-
quiet: () => {
|
|
16
|
-
if (result.stdout)
|
|
17
|
-
process.stdout.write(result.stdout);
|
|
18
|
-
process.exit(result.exitCode);
|
|
19
|
-
},
|
|
20
|
-
human: () => {
|
|
21
|
-
if (result.stdout)
|
|
22
|
-
process.stdout.write(result.stdout);
|
|
23
|
-
if (result.stderr)
|
|
24
|
-
process.stderr.write(result.stderr);
|
|
25
|
-
if (result.exitCode !== 0)
|
|
26
|
-
process.exit(result.exitCode);
|
|
27
|
-
},
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
catch (e) {
|
|
31
|
-
error(e.message);
|
|
32
|
-
process.exit(EXIT_ERROR);
|
|
33
|
-
}
|
|
3
|
+
export async function exec(_command, _options) {
|
|
4
|
+
error("exec command is not supported with Convex backend");
|
|
5
|
+
error("Use 'stage ls' to list files, or write/read files directly");
|
|
6
|
+
process.exit(EXIT_ERROR);
|
|
34
7
|
}
|
package/dist/commands/ls.js
CHANGED
|
@@ -1,25 +1,28 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getAllFiles } from "../convex-client.js";
|
|
2
2
|
import { error, output } from "../utils/output.js";
|
|
3
3
|
import { EXIT_ERROR } from "../utils/exit-codes.js";
|
|
4
4
|
export async function ls(remotePath, options) {
|
|
5
5
|
const sessionId = options.session;
|
|
6
6
|
const dir = remotePath || "/app";
|
|
7
7
|
try {
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
const
|
|
8
|
+
const files = await getAllFiles(sessionId);
|
|
9
|
+
// Filter by directory if specified
|
|
10
|
+
const filtered = files
|
|
11
|
+
.filter(f => f.path.startsWith(dir))
|
|
12
|
+
.map(f => f.path)
|
|
13
|
+
.sort();
|
|
11
14
|
output(options, {
|
|
12
|
-
json: () => ({ path: dir, files:
|
|
15
|
+
json: () => ({ path: dir, files: filtered, count: filtered.length, session: sessionId }),
|
|
13
16
|
quiet: () => {
|
|
14
|
-
if (
|
|
15
|
-
process.stdout.write(
|
|
17
|
+
if (filtered.length)
|
|
18
|
+
process.stdout.write(filtered.join("\n") + "\n");
|
|
16
19
|
},
|
|
17
20
|
human: () => {
|
|
18
|
-
if (!
|
|
21
|
+
if (!filtered.length) {
|
|
19
22
|
console.log("(empty)");
|
|
20
23
|
return;
|
|
21
24
|
}
|
|
22
|
-
for (const f of
|
|
25
|
+
for (const f of filtered) {
|
|
23
26
|
console.log(f);
|
|
24
27
|
}
|
|
25
28
|
},
|
package/dist/commands/new.js
CHANGED
|
@@ -1,15 +1,34 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createSession, getConvexConfig } from "../convex-client.js";
|
|
2
2
|
import { error, output, success, hint } from "../utils/output.js";
|
|
3
3
|
import { EXIT_ERROR } from "../utils/exit-codes.js";
|
|
4
4
|
export async function newSession(options) {
|
|
5
5
|
try {
|
|
6
|
-
const
|
|
7
|
-
const
|
|
6
|
+
const sessionId = await createSession();
|
|
7
|
+
const config = getConvexConfig();
|
|
8
|
+
// Determine Stage UI URL
|
|
9
|
+
// For cloud: derive from Convex URL or use STAGE_URL
|
|
10
|
+
// For self-hosted: use STAGE_URL or default localhost
|
|
11
|
+
let stageUrl = process.env.STAGE_URL;
|
|
12
|
+
if (!stageUrl) {
|
|
13
|
+
if (config.isSelfHosted) {
|
|
14
|
+
stageUrl = "http://localhost:3000";
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
// For cloud, try to derive from Convex URL or use a default
|
|
18
|
+
stageUrl = process.env.NEXT_PUBLIC_STAGE_URL || "http://localhost:3000";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const url = `${stageUrl}/s/${sessionId}`;
|
|
8
22
|
output(options, {
|
|
9
|
-
json: () => ({
|
|
10
|
-
|
|
23
|
+
json: () => ({
|
|
24
|
+
id: sessionId,
|
|
25
|
+
url,
|
|
26
|
+
convexUrl: config.url,
|
|
27
|
+
mode: config.isSelfHosted ? "self-hosted" : "cloud",
|
|
28
|
+
}),
|
|
29
|
+
quiet: () => process.stdout.write(sessionId),
|
|
11
30
|
human: () => {
|
|
12
|
-
success(`Session created: ${
|
|
31
|
+
success(`Session created: ${sessionId}`);
|
|
13
32
|
hint(`URL: ${url}`);
|
|
14
33
|
},
|
|
15
34
|
});
|
package/dist/commands/push.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFileSync, readdirSync, statSync } from "node:fs";
|
|
2
2
|
import { join, relative, posix } from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { writeFile, triggerRender } from "../convex-client.js";
|
|
4
4
|
import { error, output, success, dim, bullet } from "../utils/output.js";
|
|
5
5
|
import { EXIT_ERROR, EXIT_USER_ERROR } from "../utils/exit-codes.js";
|
|
6
6
|
function walkDir(dir) {
|
|
@@ -47,14 +47,17 @@ export async function push(localDir, remoteDir, options) {
|
|
|
47
47
|
process.exit(EXIT_USER_ERROR);
|
|
48
48
|
}
|
|
49
49
|
try {
|
|
50
|
-
|
|
50
|
+
// Write all files to Convex
|
|
51
|
+
const paths = Object.keys(files);
|
|
52
|
+
for (const remotePath of paths) {
|
|
53
|
+
await writeFile(sessionId, remotePath, files[remotePath]);
|
|
54
|
+
}
|
|
51
55
|
let version;
|
|
52
56
|
if (options.render !== false) {
|
|
53
57
|
const entry = options.entry || `${targetDir}/App.tsx`;
|
|
54
|
-
const renderResult = await
|
|
58
|
+
const renderResult = await triggerRender(sessionId, entry);
|
|
55
59
|
version = renderResult.version;
|
|
56
60
|
}
|
|
57
|
-
const paths = Object.keys(files);
|
|
58
61
|
output(options, {
|
|
59
62
|
json: () => ({
|
|
60
63
|
success: true,
|
package/dist/commands/read.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readFile } from "../convex-client.js";
|
|
2
2
|
import { error, output } from "../utils/output.js";
|
|
3
3
|
import { EXIT_ERROR, EXIT_NOT_FOUND } from "../utils/exit-codes.js";
|
|
4
4
|
export async function read(remotePath, options) {
|
|
5
5
|
const sessionId = options.session;
|
|
6
6
|
try {
|
|
7
|
-
const result = await
|
|
8
|
-
if (result
|
|
9
|
-
error(
|
|
7
|
+
const result = await readFile(sessionId, remotePath);
|
|
8
|
+
if (!result) {
|
|
9
|
+
error(`File not found: ${remotePath}`);
|
|
10
10
|
process.exit(EXIT_NOT_FOUND);
|
|
11
11
|
}
|
|
12
12
|
output(options, {
|
|
13
|
-
json: () => ({ path: remotePath, content: result.content, session: sessionId }),
|
|
13
|
+
json: () => ({ path: remotePath, content: result.content, version: result.version, session: sessionId }),
|
|
14
14
|
quiet: () => process.stdout.write(result.content),
|
|
15
15
|
human: () => process.stdout.write(result.content),
|
|
16
16
|
});
|
package/dist/commands/render.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { triggerRender } from "../convex-client.js";
|
|
2
2
|
import { error, output, success, dim } from "../utils/output.js";
|
|
3
3
|
import { EXIT_ERROR } from "../utils/exit-codes.js";
|
|
4
4
|
export async function render(entry, options) {
|
|
5
5
|
const sessionId = options.session;
|
|
6
6
|
const entryPoint = entry || "/app/App.tsx";
|
|
7
7
|
try {
|
|
8
|
-
const result = await
|
|
8
|
+
const result = await triggerRender(sessionId, entryPoint);
|
|
9
9
|
output(options, {
|
|
10
10
|
json: () => ({
|
|
11
11
|
success: true,
|
|
12
|
-
entry:
|
|
12
|
+
entry: result.entry,
|
|
13
13
|
version: result.version,
|
|
14
14
|
session: sessionId,
|
|
15
15
|
}),
|
|
16
16
|
quiet: () => { },
|
|
17
|
-
human: () => success(`Rendered ${
|
|
17
|
+
human: () => success(`Rendered ${result.entry} ${dim(`(v${result.version})`)}`),
|
|
18
18
|
});
|
|
19
19
|
}
|
|
20
20
|
catch (e) {
|
package/dist/commands/write.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
|
-
import {
|
|
2
|
+
import { writeFile } from "../convex-client.js";
|
|
3
3
|
import { error, output, success } from "../utils/output.js";
|
|
4
4
|
import { EXIT_ERROR, EXIT_USER_ERROR } from "../utils/exit-codes.js";
|
|
5
5
|
export async function write(remotePath, localPath, options) {
|
|
@@ -26,11 +26,11 @@ export async function write(remotePath, localPath, options) {
|
|
|
26
26
|
process.exit(EXIT_USER_ERROR);
|
|
27
27
|
}
|
|
28
28
|
try {
|
|
29
|
-
await
|
|
29
|
+
const result = await writeFile(sessionId, remotePath, content);
|
|
30
30
|
output(options, {
|
|
31
|
-
json: () => ({ success: true, path: remotePath, bytes: content.length, session: sessionId }),
|
|
31
|
+
json: () => ({ success: true, path: remotePath, bytes: content.length, version: result.version, session: sessionId }),
|
|
32
32
|
quiet: () => { },
|
|
33
|
-
human: () => success(`${remotePath} (${content.length} bytes)`),
|
|
33
|
+
human: () => success(`${remotePath} (${content.length} bytes, v${result.version})`),
|
|
34
34
|
});
|
|
35
35
|
}
|
|
36
36
|
catch (e) {
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convex client for Stage CLI.
|
|
3
|
+
* Supports both Convex Cloud and self-hosted deployments.
|
|
4
|
+
*
|
|
5
|
+
* Environment variables:
|
|
6
|
+
* Convex Cloud:
|
|
7
|
+
* CONVEX_URL - Deployment URL (e.g., https://xxx.convex.cloud)
|
|
8
|
+
*
|
|
9
|
+
* Self-hosted:
|
|
10
|
+
* CONVEX_SELF_HOSTED_URL - Backend URL (e.g., http://127.0.0.1:3210)
|
|
11
|
+
* CONVEX_SELF_HOSTED_ADMIN_KEY - Admin key for auth
|
|
12
|
+
*/
|
|
13
|
+
interface ConvexConfig {
|
|
14
|
+
url: string;
|
|
15
|
+
adminKey?: string;
|
|
16
|
+
isSelfHosted: boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare function setConvexConfig(config: Partial<ConvexConfig>): void;
|
|
19
|
+
export declare function getConvexConfig(): ConvexConfig;
|
|
20
|
+
export declare function getConvexUrl(): string;
|
|
21
|
+
export declare function setConvexUrl(url: string): void;
|
|
22
|
+
export declare function createSession(): Promise<string>;
|
|
23
|
+
export declare function writeFile(sessionId: string, path: string, content: string): Promise<{
|
|
24
|
+
path: string;
|
|
25
|
+
version: number;
|
|
26
|
+
size: number;
|
|
27
|
+
}>;
|
|
28
|
+
export declare function readFile(sessionId: string, path: string): Promise<{
|
|
29
|
+
path: string;
|
|
30
|
+
content: string;
|
|
31
|
+
version?: number;
|
|
32
|
+
} | null>;
|
|
33
|
+
export declare function getAllFiles(sessionId: string): Promise<Array<{
|
|
34
|
+
path: string;
|
|
35
|
+
content: string;
|
|
36
|
+
version?: number;
|
|
37
|
+
}>>;
|
|
38
|
+
export declare function triggerRender(sessionId: string, entry?: string): Promise<{
|
|
39
|
+
entry: string;
|
|
40
|
+
version: number;
|
|
41
|
+
}>;
|
|
42
|
+
export declare function getRenderState(sessionId: string): Promise<{
|
|
43
|
+
entry: string;
|
|
44
|
+
version: number;
|
|
45
|
+
} | null>;
|
|
46
|
+
export declare function createSnapshot(sessionId: string, name?: string): Promise<string>;
|
|
47
|
+
export declare function getSnapshots(sessionId: string): Promise<Array<{
|
|
48
|
+
name?: string;
|
|
49
|
+
createdAt: number;
|
|
50
|
+
}>>;
|
|
51
|
+
export declare function getFileHistory(sessionId: string, path: string): Promise<Array<{
|
|
52
|
+
version?: number;
|
|
53
|
+
createdAt?: number;
|
|
54
|
+
}>>;
|
|
55
|
+
export declare function printConfig(): void;
|
|
56
|
+
export {};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convex client for Stage CLI.
|
|
3
|
+
* Supports both Convex Cloud and self-hosted deployments.
|
|
4
|
+
*
|
|
5
|
+
* Environment variables:
|
|
6
|
+
* Convex Cloud:
|
|
7
|
+
* CONVEX_URL - Deployment URL (e.g., https://xxx.convex.cloud)
|
|
8
|
+
*
|
|
9
|
+
* Self-hosted:
|
|
10
|
+
* CONVEX_SELF_HOSTED_URL - Backend URL (e.g., http://127.0.0.1:3210)
|
|
11
|
+
* CONVEX_SELF_HOSTED_ADMIN_KEY - Admin key for auth
|
|
12
|
+
*/
|
|
13
|
+
let _configOverride = null;
|
|
14
|
+
export function setConvexConfig(config) {
|
|
15
|
+
_configOverride = config;
|
|
16
|
+
}
|
|
17
|
+
export function getConvexConfig() {
|
|
18
|
+
// Check for overrides first
|
|
19
|
+
if (_configOverride?.url) {
|
|
20
|
+
return {
|
|
21
|
+
url: _configOverride.url,
|
|
22
|
+
adminKey: _configOverride.adminKey,
|
|
23
|
+
isSelfHosted: _configOverride.isSelfHosted ?? true,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
// Check for Convex Cloud
|
|
27
|
+
const cloudUrl = process.env.CONVEX_URL;
|
|
28
|
+
if (cloudUrl) {
|
|
29
|
+
return {
|
|
30
|
+
url: cloudUrl,
|
|
31
|
+
isSelfHosted: false,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// Check for self-hosted
|
|
35
|
+
const selfHostedUrl = process.env.CONVEX_SELF_HOSTED_URL;
|
|
36
|
+
const selfHostedKey = process.env.CONVEX_SELF_HOSTED_ADMIN_KEY;
|
|
37
|
+
if (selfHostedUrl) {
|
|
38
|
+
return {
|
|
39
|
+
url: selfHostedUrl,
|
|
40
|
+
adminKey: selfHostedKey,
|
|
41
|
+
isSelfHosted: true,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
// Default to local self-hosted
|
|
45
|
+
return {
|
|
46
|
+
url: "http://127.0.0.1:3210",
|
|
47
|
+
isSelfHosted: true,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export function getConvexUrl() {
|
|
51
|
+
return getConvexConfig().url;
|
|
52
|
+
}
|
|
53
|
+
// For backwards compatibility
|
|
54
|
+
export function setConvexUrl(url) {
|
|
55
|
+
setConvexConfig({ url, isSelfHosted: true });
|
|
56
|
+
}
|
|
57
|
+
// Generic mutation/query helpers
|
|
58
|
+
async function mutation(path, args) {
|
|
59
|
+
const config = getConvexConfig();
|
|
60
|
+
const url = `${config.url}/api/mutation`;
|
|
61
|
+
const headers = {
|
|
62
|
+
"Content-Type": "application/json"
|
|
63
|
+
};
|
|
64
|
+
// Add admin key for self-hosted
|
|
65
|
+
if (config.isSelfHosted && config.adminKey) {
|
|
66
|
+
headers["Authorization"] = `Convex ${config.adminKey}`;
|
|
67
|
+
}
|
|
68
|
+
const res = await fetch(url, {
|
|
69
|
+
method: "POST",
|
|
70
|
+
headers,
|
|
71
|
+
body: JSON.stringify({ path: `stage:${path}`, args }),
|
|
72
|
+
});
|
|
73
|
+
if (!res.ok) {
|
|
74
|
+
const text = await res.text();
|
|
75
|
+
throw new Error(`Convex error ${res.status}: ${text}`);
|
|
76
|
+
}
|
|
77
|
+
const data = await res.json();
|
|
78
|
+
if (data.status === "error") {
|
|
79
|
+
throw new Error(data.errorMessage || "Unknown error");
|
|
80
|
+
}
|
|
81
|
+
return data.value;
|
|
82
|
+
}
|
|
83
|
+
async function query(path, args) {
|
|
84
|
+
const config = getConvexConfig();
|
|
85
|
+
const url = `${config.url}/api/query`;
|
|
86
|
+
const headers = {
|
|
87
|
+
"Content-Type": "application/json"
|
|
88
|
+
};
|
|
89
|
+
// Add admin key for self-hosted
|
|
90
|
+
if (config.isSelfHosted && config.adminKey) {
|
|
91
|
+
headers["Authorization"] = `Convex ${config.adminKey}`;
|
|
92
|
+
}
|
|
93
|
+
const res = await fetch(url, {
|
|
94
|
+
method: "POST",
|
|
95
|
+
headers,
|
|
96
|
+
body: JSON.stringify({ path: `stage:${path}`, args }),
|
|
97
|
+
});
|
|
98
|
+
if (!res.ok) {
|
|
99
|
+
const text = await res.text();
|
|
100
|
+
throw new Error(`Convex error ${res.status}: ${text}`);
|
|
101
|
+
}
|
|
102
|
+
const data = await res.json();
|
|
103
|
+
if (data.status === "error") {
|
|
104
|
+
throw new Error(data.errorMessage || "Unknown error");
|
|
105
|
+
}
|
|
106
|
+
return data.value;
|
|
107
|
+
}
|
|
108
|
+
// Stage API
|
|
109
|
+
export async function createSession() {
|
|
110
|
+
return await mutation("createSession", {});
|
|
111
|
+
}
|
|
112
|
+
export async function writeFile(sessionId, path, content) {
|
|
113
|
+
return await mutation("writeFile", { sessionId, path, content });
|
|
114
|
+
}
|
|
115
|
+
export async function readFile(sessionId, path) {
|
|
116
|
+
return await query("readFile", { sessionId, path });
|
|
117
|
+
}
|
|
118
|
+
export async function getAllFiles(sessionId) {
|
|
119
|
+
return await query("getAllFiles", { sessionId });
|
|
120
|
+
}
|
|
121
|
+
export async function triggerRender(sessionId, entry) {
|
|
122
|
+
return await mutation("triggerRender", { sessionId, entry });
|
|
123
|
+
}
|
|
124
|
+
export async function getRenderState(sessionId) {
|
|
125
|
+
return await query("getRenderState", { sessionId });
|
|
126
|
+
}
|
|
127
|
+
export async function createSnapshot(sessionId, name) {
|
|
128
|
+
return await mutation("createSnapshot", { sessionId, name });
|
|
129
|
+
}
|
|
130
|
+
export async function getSnapshots(sessionId) {
|
|
131
|
+
return await query("getSnapshots", { sessionId });
|
|
132
|
+
}
|
|
133
|
+
export async function getFileHistory(sessionId, path) {
|
|
134
|
+
return await query("getFileHistory", { sessionId, path });
|
|
135
|
+
}
|
|
136
|
+
// Helper to show current config
|
|
137
|
+
export function printConfig() {
|
|
138
|
+
const config = getConvexConfig();
|
|
139
|
+
console.log(`Mode: ${config.isSelfHosted ? "self-hosted" : "cloud"}`);
|
|
140
|
+
console.log(`URL: ${config.url}`);
|
|
141
|
+
if (config.isSelfHosted && config.adminKey) {
|
|
142
|
+
console.log(`Admin key: ${config.adminKey.slice(0, 20)}...`);
|
|
143
|
+
}
|
|
144
|
+
}
|
package/dist/main.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { Command } from "commander";
|
|
4
|
-
import {
|
|
4
|
+
import { setConvexConfig, printConfig } from "./convex-client.js";
|
|
5
5
|
import { newSession } from "./commands/new.js";
|
|
6
6
|
import { write } from "./commands/write.js";
|
|
7
7
|
import { read } from "./commands/read.js";
|
|
@@ -15,11 +15,25 @@ const { version } = require("../package.json");
|
|
|
15
15
|
const program = new Command();
|
|
16
16
|
program
|
|
17
17
|
.name("stage")
|
|
18
|
-
.description(
|
|
18
|
+
.description(`CLI client for Stage — a sandboxed React runtime for AI agents
|
|
19
|
+
|
|
20
|
+
Environment variables:
|
|
21
|
+
CONVEX_URL Convex Cloud deployment URL
|
|
22
|
+
CONVEX_SELF_HOSTED_URL Self-hosted Convex URL
|
|
23
|
+
CONVEX_SELF_HOSTED_ADMIN_KEY Self-hosted admin key
|
|
24
|
+
STAGE_URL Stage frontend URL (for session links)`)
|
|
19
25
|
.version(`stage ${version}`, "-v, --version")
|
|
20
26
|
.option("--json", "Output as JSON")
|
|
21
27
|
.option("-q, --quiet", "Suppress output")
|
|
22
|
-
.option("-u, --url <url>", "
|
|
28
|
+
.option("-u, --url <url>", "Convex URL (overrides env vars)")
|
|
29
|
+
.option("--self-hosted", "Force self-hosted mode")
|
|
30
|
+
.option("--cloud", "Force cloud mode");
|
|
31
|
+
program
|
|
32
|
+
.command("config")
|
|
33
|
+
.description("Show current Convex configuration")
|
|
34
|
+
.action(() => {
|
|
35
|
+
printConfig();
|
|
36
|
+
});
|
|
23
37
|
program
|
|
24
38
|
.command("new")
|
|
25
39
|
.description("Create a new session")
|
|
@@ -45,7 +59,7 @@ program
|
|
|
45
59
|
});
|
|
46
60
|
program
|
|
47
61
|
.command("exec <command>")
|
|
48
|
-
.description("
|
|
62
|
+
.description("[DEPRECATED] Not supported with Convex backend")
|
|
49
63
|
.requiredOption("-s, --session <id>", "Session ID")
|
|
50
64
|
.action(async (command, opts, cmd) => {
|
|
51
65
|
const root = cmd.optsWithGlobals();
|
|
@@ -61,7 +75,7 @@ program
|
|
|
61
75
|
});
|
|
62
76
|
program
|
|
63
77
|
.command("ls [path]")
|
|
64
|
-
.description("List files in
|
|
78
|
+
.description("List files in session")
|
|
65
79
|
.requiredOption("-s, --session <id>", "Session ID")
|
|
66
80
|
.action(async (path, opts, cmd) => {
|
|
67
81
|
const root = cmd.optsWithGlobals();
|
|
@@ -92,8 +106,21 @@ program
|
|
|
92
106
|
});
|
|
93
107
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
94
108
|
const root = actionCommand.optsWithGlobals();
|
|
95
|
-
|
|
96
|
-
|
|
109
|
+
// Configure Convex client based on flags
|
|
110
|
+
if (root.url) {
|
|
111
|
+
const isSelfHosted = root.selfHosted || (!root.cloud && !root.url.includes("convex.cloud"));
|
|
112
|
+
setConvexConfig({
|
|
113
|
+
url: root.url,
|
|
114
|
+
isSelfHosted,
|
|
115
|
+
adminKey: process.env.CONVEX_SELF_HOSTED_ADMIN_KEY,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
else if (root.cloud) {
|
|
119
|
+
setConvexConfig({ isSelfHosted: false });
|
|
120
|
+
}
|
|
121
|
+
else if (root.selfHosted) {
|
|
122
|
+
setConvexConfig({ isSelfHosted: true });
|
|
123
|
+
}
|
|
97
124
|
});
|
|
98
125
|
program.parseAsync(process.argv).catch((err) => {
|
|
99
126
|
console.error("Fatal error:", err.message);
|
package/package.json
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stage-ai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "CLI client for Stage — a sandboxed React runtime for AI-generated applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/main.js",
|
|
7
7
|
"bin": {
|
|
8
8
|
"stage": "./dist/main.js"
|
|
9
9
|
},
|
|
10
|
-
"files": [
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
11
13
|
"scripts": {
|
|
12
14
|
"build": "tsc",
|
|
13
15
|
"prepublishOnly": "npm run build",
|
|
@@ -29,14 +31,24 @@
|
|
|
29
31
|
"bugs": {
|
|
30
32
|
"url": "https://github.com/the-shift-dev/stage-cli/issues"
|
|
31
33
|
},
|
|
32
|
-
"keywords": [
|
|
34
|
+
"keywords": [
|
|
35
|
+
"ai",
|
|
36
|
+
"agent",
|
|
37
|
+
"sandbox",
|
|
38
|
+
"react",
|
|
39
|
+
"runtime",
|
|
40
|
+
"cli",
|
|
41
|
+
"stage"
|
|
42
|
+
],
|
|
33
43
|
"license": "MIT",
|
|
34
44
|
"devDependencies": {
|
|
35
45
|
"@biomejs/biome": "^2.3.14",
|
|
46
|
+
"@types/node": "^25.3.3",
|
|
36
47
|
"typescript": "^5.8.0"
|
|
37
48
|
},
|
|
38
49
|
"dependencies": {
|
|
39
50
|
"chalk": "^5.6.2",
|
|
40
|
-
"commander": "^14.0.3"
|
|
51
|
+
"commander": "^14.0.3",
|
|
52
|
+
"convex": "^1.32.0"
|
|
41
53
|
}
|
|
42
54
|
}
|