agent-stage 0.2.14 → 0.2.17
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/guide.js +5 -5
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.js +94 -138
- package/dist/commands/page/add.js +5 -40
- package/dist/commands/run/exec.js +1 -1
- package/dist/commands/run/inspect.js +1 -1
- package/dist/commands/run/watch.js +1 -1
- package/dist/commands/serve.d.ts +2 -0
- package/dist/commands/serve.js +238 -0
- package/dist/commands/status.d.ts +1 -1
- package/dist/commands/status.js +41 -40
- package/dist/commands/stop.d.ts +1 -1
- package/dist/commands/stop.js +26 -44
- package/dist/index.js +16 -30
- package/dist/utils/agent-helper.js +5 -5
- package/dist/utils/paths.js +5 -5
- package/dist/utils/tunnel.d.ts +1 -1
- package/dist/utils/tunnel.js +1 -1
- package/package.json +8 -5
- package/dist/commands/dev/index.d.ts +0 -2
- package/dist/commands/dev/index.js +0 -11
- package/dist/commands/dev/init.d.ts +0 -2
- package/dist/commands/dev/init.js +0 -215
- package/dist/commands/dev/start.d.ts +0 -2
- package/dist/commands/dev/start.js +0 -145
- package/dist/commands/dev/status.d.ts +0 -2
- package/dist/commands/dev/status.js +0 -55
- package/dist/commands/dev/stop.d.ts +0 -2
- package/dist/commands/dev/stop.js +0 -45
- package/dist/commands/exec.d.ts +0 -2
- package/dist/commands/exec.js +0 -75
- package/dist/commands/inspect.d.ts +0 -2
- package/dist/commands/inspect.js +0 -62
- package/dist/commands/ls.d.ts +0 -2
- package/dist/commands/ls.js +0 -132
- package/dist/commands/restart.d.ts +0 -2
- package/dist/commands/restart.js +0 -90
- package/dist/commands/rm-page.d.ts +0 -2
- package/dist/commands/rm-page.js +0 -32
- package/dist/commands/start.d.ts +0 -2
- package/dist/commands/start.js +0 -82
- package/dist/commands/watch.d.ts +0 -2
- package/dist/commands/watch.js +0 -54
- package/template/components.json +0 -17
- package/template/index.html +0 -13
- package/template/package.json +0 -41
- package/template/postcss.config.js +0 -6
- package/template/src/components/PageRenderer.tsx +0 -108
- package/template/src/components/bridge-state-provider.tsx +0 -87
- package/template/src/components/ui/button.tsx +0 -55
- package/template/src/components/ui/card.tsx +0 -78
- package/template/src/components/ui/input.tsx +0 -24
- package/template/src/index.css +0 -59
- package/template/src/lib/bridge.ts +0 -53
- package/template/src/lib/utils.ts +0 -6
- package/template/src/main.tsx +0 -23
- package/template/src/pages/counter/store.json +0 -8
- package/template/src/pages/counter/ui.json +0 -108
- package/template/src/pages/test-page/store.json +0 -8
- package/template/src/routeTree.gen.ts +0 -77
- package/template/src/routes/__root.tsx +0 -11
- package/template/src/routes/counter.tsx +0 -19
- package/template/src/routes/index.tsx +0 -46
- package/template/src/vite-env.d.ts +0 -1
- package/template/tailwind.config.js +0 -53
- package/template/tsconfig.json +0 -25
- package/template/tsconfig.node.json +0 -11
- package/template/vite.config.ts +0 -22
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import * as p from "@clack/prompts";
|
|
3
|
+
import consola from "consola";
|
|
4
|
+
import c from "picocolors";
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
|
+
import { createRequire } from "node:module";
|
|
7
|
+
import { createServer } from "node:net";
|
|
8
|
+
import { execa } from "execa";
|
|
9
|
+
import { existsSync } from "fs";
|
|
10
|
+
import { dirname, join } from "pathe";
|
|
11
|
+
import { getWorkspaceDir, isInitialized, readRuntimeConfig, saveRuntimeConfig, } from "../utils/paths.js";
|
|
12
|
+
import { canStartTunnel, startTunnel, printTunnelInfo } from "../utils/tunnel.js";
|
|
13
|
+
import { checkCloudflared, printInstallInstructions } from "../utils/cloudflared.js";
|
|
14
|
+
const require = createRequire(import.meta.url);
|
|
15
|
+
async function ensurePortAvailable(port, host) {
|
|
16
|
+
await new Promise((resolve, reject) => {
|
|
17
|
+
const probe = createServer();
|
|
18
|
+
probe.once("error", (error) => {
|
|
19
|
+
probe.close();
|
|
20
|
+
if (error.code === "EADDRINUSE") {
|
|
21
|
+
reject(new Error(`Port ${port} is already in use`));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
reject(error);
|
|
25
|
+
});
|
|
26
|
+
probe.listen(port, host, () => {
|
|
27
|
+
probe.close((error) => {
|
|
28
|
+
if (error) {
|
|
29
|
+
reject(error);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
resolve();
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
async function waitForRuntimeReady(port, pageId, timeoutMs = 5000) {
|
|
38
|
+
const start = Date.now();
|
|
39
|
+
let lastError = null;
|
|
40
|
+
while (Date.now() - start < timeoutMs) {
|
|
41
|
+
try {
|
|
42
|
+
const response = await fetch(`http://127.0.0.1:${port}/health`, {
|
|
43
|
+
signal: AbortSignal.timeout(500),
|
|
44
|
+
});
|
|
45
|
+
if (response.ok) {
|
|
46
|
+
const health = (await response.json());
|
|
47
|
+
if (health.ok === true && health.pageId === pageId) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
lastError = new Error("runtime health mismatch");
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
lastError = new Error(`health returned ${response.status}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
lastError = error;
|
|
58
|
+
}
|
|
59
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
60
|
+
}
|
|
61
|
+
throw lastError instanceof Error
|
|
62
|
+
? lastError
|
|
63
|
+
: new Error("Runtime health check timed out");
|
|
64
|
+
}
|
|
65
|
+
function resolveRenderServeBin() {
|
|
66
|
+
const override = process.env.AGENTSTAGE_RENDER_SERVE_BIN;
|
|
67
|
+
if (override) {
|
|
68
|
+
return override;
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
const serveModulePath = require.resolve("@agentstage/render/serve");
|
|
72
|
+
const candidate = join(dirname(serveModulePath), "serve-cli.js");
|
|
73
|
+
if (existsSync(candidate)) {
|
|
74
|
+
return candidate;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// ignore resolution failure
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
async function waitForRuntimeProcessOrReady(subprocess, ready) {
|
|
83
|
+
let onError = null;
|
|
84
|
+
let onExit = null;
|
|
85
|
+
const exited = new Promise((_, reject) => {
|
|
86
|
+
onError = (error) => {
|
|
87
|
+
reject(error);
|
|
88
|
+
};
|
|
89
|
+
onExit = (code, signal) => {
|
|
90
|
+
const detail = code !== null ? `code ${code}` : `signal ${signal ?? "unknown"}`;
|
|
91
|
+
reject(new Error(`Runtime process exited before becoming ready (${detail})`));
|
|
92
|
+
};
|
|
93
|
+
subprocess.once("error", onError);
|
|
94
|
+
subprocess.once("exit", onExit);
|
|
95
|
+
});
|
|
96
|
+
try {
|
|
97
|
+
await Promise.race([ready, exited]);
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
if (onError) {
|
|
101
|
+
subprocess.off("error", onError);
|
|
102
|
+
}
|
|
103
|
+
if (onExit) {
|
|
104
|
+
subprocess.off("exit", onExit);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
export const serveCommand = new Command("serve")
|
|
109
|
+
.description("Serve a single page runtime (Bun required)")
|
|
110
|
+
.argument("<pageId>", "Page id to serve")
|
|
111
|
+
.option("-p, --port <port>", "Port to run the server on", "3000")
|
|
112
|
+
.option("--host <host>", "Host to bind", "0.0.0.0")
|
|
113
|
+
.option("-t, --tunnel", "Expose server to internet via Cloudflare Tunnel", false)
|
|
114
|
+
.option("--open", "Open browser automatically", false)
|
|
115
|
+
.action(async (pageId, options) => {
|
|
116
|
+
if (!isInitialized()) {
|
|
117
|
+
consola.error("Project not initialized. Please run `agentstage init` first.");
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
if (!/^[a-z0-9-]+$/.test(pageId)) {
|
|
121
|
+
consola.error("Invalid pageId. Allowed: lowercase letters, numbers, hyphen");
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
const workspaceDir = await getWorkspaceDir();
|
|
125
|
+
const port = Number.parseInt(String(options.port), 10);
|
|
126
|
+
const host = String(options.host || "0.0.0.0");
|
|
127
|
+
if (!Number.isFinite(port) || port <= 0 || port > 65535) {
|
|
128
|
+
consola.error(`Invalid port: ${options.port}`);
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
const pageUiPath = join(workspaceDir, "pages", pageId, "ui.json");
|
|
132
|
+
if (!existsSync(pageUiPath)) {
|
|
133
|
+
consola.error(`Page "${pageId}" not found: ${pageUiPath}`);
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
try {
|
|
137
|
+
await execa("bun", ["--version"], { stdio: "pipe" });
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
consola.error("Bun is required but not found.");
|
|
141
|
+
consola.info("Install Bun: https://bun.sh/docs/installation");
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
const serveBin = resolveRenderServeBin();
|
|
145
|
+
if (!serveBin) {
|
|
146
|
+
consola.error("Cannot resolve @agentstage/render serve runtime entry.");
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
const existingConfig = await readRuntimeConfig();
|
|
150
|
+
if (existingConfig) {
|
|
151
|
+
try {
|
|
152
|
+
process.kill(existingConfig.pid, 0);
|
|
153
|
+
consola.warn(`Runtime is already running (PID: ${existingConfig.pid}, Port: ${existingConfig.port})`);
|
|
154
|
+
console.log(` Web: ${c.cyan(`http://localhost:${existingConfig.port}`)}`);
|
|
155
|
+
if (existingConfig.tunnelUrl) {
|
|
156
|
+
console.log(` Public: ${c.cyan(c.underline(existingConfig.tunnelUrl))}`);
|
|
157
|
+
}
|
|
158
|
+
console.log(` Bridge: ${c.cyan(`ws://localhost:${existingConfig.port}/_bridge`)}`);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
// stale runtime config
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
await ensurePortAvailable(port, host);
|
|
166
|
+
let tunnelUrl;
|
|
167
|
+
if (options.tunnel) {
|
|
168
|
+
const canTunnel = await canStartTunnel();
|
|
169
|
+
if (!canTunnel) {
|
|
170
|
+
const info = await checkCloudflared();
|
|
171
|
+
printInstallInstructions(info);
|
|
172
|
+
consola.error("Cannot start with --tunnel: cloudflared not installed");
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
const s = p.spinner();
|
|
177
|
+
s.start(`Starting page runtime (${pageId})...`);
|
|
178
|
+
try {
|
|
179
|
+
const subprocess = spawn("bun", [
|
|
180
|
+
serveBin,
|
|
181
|
+
"--workspace",
|
|
182
|
+
workspaceDir,
|
|
183
|
+
"--page",
|
|
184
|
+
pageId,
|
|
185
|
+
"--port",
|
|
186
|
+
String(port),
|
|
187
|
+
"--host",
|
|
188
|
+
host,
|
|
189
|
+
], {
|
|
190
|
+
cwd: workspaceDir,
|
|
191
|
+
detached: true,
|
|
192
|
+
stdio: "ignore",
|
|
193
|
+
});
|
|
194
|
+
if (!subprocess.pid) {
|
|
195
|
+
throw new Error("Failed to start runtime process");
|
|
196
|
+
}
|
|
197
|
+
subprocess.unref();
|
|
198
|
+
if (options.tunnel) {
|
|
199
|
+
s.message("Starting Cloudflare Tunnel...");
|
|
200
|
+
const tunnel = await startTunnel(port);
|
|
201
|
+
tunnelUrl = tunnel.url;
|
|
202
|
+
}
|
|
203
|
+
await waitForRuntimeProcessOrReady(subprocess, waitForRuntimeReady(port, pageId));
|
|
204
|
+
const config = {
|
|
205
|
+
pid: subprocess.pid,
|
|
206
|
+
port,
|
|
207
|
+
startedAt: new Date().toISOString(),
|
|
208
|
+
tunnelUrl,
|
|
209
|
+
};
|
|
210
|
+
await saveRuntimeConfig(config);
|
|
211
|
+
s.stop(`Runtime started (${pageId})`);
|
|
212
|
+
console.log();
|
|
213
|
+
consola.success("Agentstage runtime is running");
|
|
214
|
+
console.log(` Page: ${c.cyan(pageId)}`);
|
|
215
|
+
console.log(` Web: ${c.cyan(`http://localhost:${port}`)}`);
|
|
216
|
+
if (tunnelUrl) {
|
|
217
|
+
printTunnelInfo(tunnelUrl);
|
|
218
|
+
}
|
|
219
|
+
console.log(` Bridge: ${c.cyan(`ws://localhost:${port}/_bridge`)}`);
|
|
220
|
+
console.log(` Workspace: ${c.gray(workspaceDir)}`);
|
|
221
|
+
console.log();
|
|
222
|
+
if (options.open) {
|
|
223
|
+
const openUrl = tunnelUrl || `http://localhost:${port}`;
|
|
224
|
+
try {
|
|
225
|
+
await execa("open", [openUrl]);
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
// ignore open errors
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
catch (error) {
|
|
233
|
+
s.stop("Failed to start runtime");
|
|
234
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
235
|
+
consola.error(message);
|
|
236
|
+
process.exit(1);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Command } from
|
|
1
|
+
import { Command } from "commander";
|
|
2
2
|
export declare const statusCommand: Command;
|
package/dist/commands/status.js
CHANGED
|
@@ -1,52 +1,53 @@
|
|
|
1
|
-
import { Command } from
|
|
2
|
-
import consola from
|
|
3
|
-
import c from
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
return true;
|
|
9
|
-
}
|
|
10
|
-
catch {
|
|
11
|
-
return false;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
export const statusCommand = new Command('status')
|
|
15
|
-
.description('Show the Agentstage Runtime status')
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import consola from "consola";
|
|
3
|
+
import c from "picocolors";
|
|
4
|
+
import { readRuntimeConfig, isInitialized, getWorkspaceDir, } from "../utils/paths.js";
|
|
5
|
+
import { checkCloudflared } from "../utils/cloudflared.js";
|
|
6
|
+
export const statusCommand = new Command("status")
|
|
7
|
+
.description("Check the Agentstage Runtime status")
|
|
16
8
|
.action(async () => {
|
|
17
|
-
// 1. 检查是否已初始化
|
|
18
9
|
if (!isInitialized()) {
|
|
19
|
-
consola.error(
|
|
10
|
+
consola.error("Project not initialized. Please run `agentstage init` first.");
|
|
20
11
|
process.exit(1);
|
|
21
12
|
}
|
|
22
13
|
const workspaceDir = await getWorkspaceDir();
|
|
23
|
-
console.log();
|
|
24
|
-
console.log(c.bold('Agentstage Runtime'));
|
|
25
|
-
console.log(c.gray('─'.repeat(40)));
|
|
26
|
-
console.log(`Workspace: ${c.cyan(workspaceDir)}`);
|
|
27
|
-
// 2. 读取运行时配置
|
|
28
14
|
const config = await readRuntimeConfig();
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
15
|
+
console.log();
|
|
16
|
+
console.log(c.bold("Workspace:"), c.cyan(workspaceDir));
|
|
17
|
+
console.log();
|
|
18
|
+
const cloudflared = await checkCloudflared();
|
|
19
|
+
console.log(c.bold("Cloudflare Tunnel:"));
|
|
20
|
+
if (cloudflared.installed) {
|
|
21
|
+
console.log(` Status: ${c.green("✓ installed")}`);
|
|
22
|
+
console.log(` Version: ${c.gray(cloudflared.version || "unknown")}`);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
console.log(` Status: ${c.yellow("✗ not installed")}`);
|
|
26
|
+
console.log(` Install: ${c.gray(cloudflared.installCommand)}`);
|
|
35
27
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (
|
|
39
|
-
console.log(`Status:
|
|
40
|
-
console.log(`PID: ${config.pid}`);
|
|
41
|
-
console.log(`Port: ${config.port}`);
|
|
42
|
-
console.log(`Started: ${new Date(config.startedAt).toLocaleString()}`);
|
|
43
|
-
console.log(`Web: ${c.cyan(`http://localhost:${config.port}`)}`);
|
|
44
|
-
console.log(`Bridge: ${c.cyan(`ws://localhost:${config.port}/_bridge`)}`);
|
|
28
|
+
console.log();
|
|
29
|
+
console.log(c.bold("Runtime:"));
|
|
30
|
+
if (!config) {
|
|
31
|
+
console.log(` Status: ${c.gray("stopped")}`);
|
|
45
32
|
}
|
|
46
33
|
else {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
34
|
+
try {
|
|
35
|
+
process.kill(config.pid, 0);
|
|
36
|
+
console.log(` Status: ${c.green("running")}`);
|
|
37
|
+
console.log(` PID: ${c.gray(config.pid)}`);
|
|
38
|
+
console.log(` Port: ${c.cyan(config.port)}`);
|
|
39
|
+
console.log(` Local: ${c.cyan(`http://localhost:${config.port}`)}`);
|
|
40
|
+
if (config.tunnelUrl) {
|
|
41
|
+
console.log(` Public: ${c.cyan(c.underline(config.tunnelUrl))}`);
|
|
42
|
+
}
|
|
43
|
+
console.log(` Bridge: ${c.cyan(`ws://localhost:${config.port}/_bridge`)}`);
|
|
44
|
+
console.log(` Started: ${c.gray(new Date(config.startedAt).toLocaleString())}`);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
console.log(` Status: ${c.yellow("stale (process not found)")}`);
|
|
48
|
+
console.log(` Last PID: ${c.gray(config.pid)}`);
|
|
49
|
+
console.log(` Last Port: ${c.gray(config.port)}`);
|
|
50
|
+
}
|
|
50
51
|
}
|
|
51
52
|
console.log();
|
|
52
53
|
});
|
package/dist/commands/stop.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Command } from
|
|
1
|
+
import { Command } from "commander";
|
|
2
2
|
export declare const stopCommand: Command;
|
package/dist/commands/stop.js
CHANGED
|
@@ -1,58 +1,40 @@
|
|
|
1
|
-
import { Command } from
|
|
2
|
-
import consola from
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
try {
|
|
8
|
-
process.kill(pid, 'SIGTERM');
|
|
9
|
-
let attempts = 0;
|
|
10
|
-
while (attempts < 10) {
|
|
11
|
-
await new Promise(r => setTimeout(r, 500));
|
|
12
|
-
try {
|
|
13
|
-
process.kill(pid, 0);
|
|
14
|
-
attempts++;
|
|
15
|
-
}
|
|
16
|
-
catch {
|
|
17
|
-
break;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
if (attempts >= 10) {
|
|
21
|
-
process.kill(pid, 'SIGKILL');
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
catch (error) {
|
|
25
|
-
if (error.code !== 'ESRCH')
|
|
26
|
-
throw error;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
export const stopCommand = new Command('stop')
|
|
30
|
-
.description('Stop the Agentstage Runtime')
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import consola from "consola";
|
|
3
|
+
import c from "picocolors";
|
|
4
|
+
import { readRuntimeConfig, removeRuntimeConfig, isInitialized, } from "../utils/paths.js";
|
|
5
|
+
export const stopCommand = new Command("stop")
|
|
6
|
+
.description("Stop the Agentstage Runtime")
|
|
31
7
|
.action(async () => {
|
|
32
|
-
// 1. 检查是否已初始化
|
|
33
8
|
if (!isInitialized()) {
|
|
34
|
-
consola.error(
|
|
9
|
+
consola.error("Project not initialized. Please run `agentstage init` first.");
|
|
35
10
|
process.exit(1);
|
|
36
11
|
}
|
|
37
|
-
// 2. 读取运行时配置
|
|
38
12
|
const config = await readRuntimeConfig();
|
|
39
13
|
if (!config) {
|
|
40
|
-
consola.
|
|
14
|
+
consola.warn("Runtime is not running");
|
|
41
15
|
return;
|
|
42
16
|
}
|
|
43
|
-
// 3. 停止进程
|
|
44
17
|
try {
|
|
45
|
-
|
|
18
|
+
process.kill(config.pid, 0);
|
|
19
|
+
process.kill(config.pid, "SIGTERM");
|
|
20
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
21
|
+
try {
|
|
22
|
+
process.kill(config.pid, 0);
|
|
23
|
+
process.kill(config.pid, "SIGKILL");
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// process already stopped
|
|
27
|
+
}
|
|
46
28
|
await removeRuntimeConfig();
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
29
|
+
consola.success("Runtime stopped");
|
|
30
|
+
console.log(` PID: ${c.gray(config.pid)}`);
|
|
31
|
+
console.log(` Port: ${c.gray(config.port)}`);
|
|
32
|
+
if (config.tunnelUrl) {
|
|
33
|
+
console.log(` Tunnel: ${c.gray(config.tunnelUrl)}`);
|
|
51
34
|
}
|
|
52
|
-
consola.success('Runtime stopped');
|
|
53
35
|
}
|
|
54
|
-
catch
|
|
55
|
-
|
|
56
|
-
|
|
36
|
+
catch {
|
|
37
|
+
await removeRuntimeConfig();
|
|
38
|
+
consola.info("Runtime was not running (stale config cleaned up)");
|
|
57
39
|
}
|
|
58
40
|
});
|
package/dist/index.js
CHANGED
|
@@ -7,48 +7,34 @@ import { dirname, join } from 'pathe';
|
|
|
7
7
|
// Read version from package.json
|
|
8
8
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
9
|
const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8'));
|
|
10
|
-
import {
|
|
10
|
+
import { initCommand } from './commands/init.js';
|
|
11
|
+
import { stopCommand } from './commands/stop.js';
|
|
12
|
+
import { statusCommand } from './commands/status.js';
|
|
11
13
|
import { pageCommand } from './commands/page/index.js';
|
|
12
14
|
import { runCommand } from './commands/run/index.js';
|
|
13
15
|
import { guideCommand } from './commands/guide.js';
|
|
14
16
|
import { cleanupCommand } from './commands/cleanup.js';
|
|
15
17
|
import { componentsCommand } from './commands/components.js';
|
|
16
18
|
import { doctorCommand } from './commands/doctor.js';
|
|
17
|
-
import { execCommand } from './commands/exec.js';
|
|
18
|
-
import { initCommand } from './commands/init.js';
|
|
19
|
-
import { inspectCommand } from './commands/inspect.js';
|
|
20
|
-
import { lsCommand } from './commands/ls.js';
|
|
21
|
-
import { restartCommand } from './commands/restart.js';
|
|
22
|
-
import { rmPageCommand } from './commands/rm-page.js';
|
|
23
|
-
import { startCommand } from './commands/start.js';
|
|
24
|
-
import { statusCommand } from './commands/status.js';
|
|
25
|
-
import { stopCommand } from './commands/stop.js';
|
|
26
19
|
import { verifyCommand } from './commands/verify.js';
|
|
27
|
-
import {
|
|
20
|
+
import { serveCommand } from './commands/serve.js';
|
|
28
21
|
const program = new Command();
|
|
29
22
|
program
|
|
30
23
|
.name('agentstage')
|
|
31
24
|
.description('Agent UI Stage CLI - Create interactive UI for AI agents')
|
|
32
25
|
.version(pkg.version);
|
|
33
|
-
// Register
|
|
34
|
-
program.addCommand(
|
|
35
|
-
program.addCommand(
|
|
36
|
-
program.addCommand(
|
|
37
|
-
program.addCommand(
|
|
38
|
-
program.addCommand(
|
|
39
|
-
program.addCommand(
|
|
40
|
-
program.addCommand(
|
|
41
|
-
program.addCommand(
|
|
42
|
-
program.addCommand(
|
|
43
|
-
program.addCommand(
|
|
44
|
-
program.addCommand(
|
|
45
|
-
program.addCommand(restartCommand);
|
|
46
|
-
program.addCommand(rmPageCommand);
|
|
47
|
-
program.addCommand(startCommand);
|
|
48
|
-
program.addCommand(statusCommand);
|
|
49
|
-
program.addCommand(stopCommand);
|
|
50
|
-
program.addCommand(verifyCommand);
|
|
51
|
-
program.addCommand(watchCommand);
|
|
26
|
+
// Register commands
|
|
27
|
+
program.addCommand(initCommand); // init
|
|
28
|
+
program.addCommand(serveCommand); // serve <pageId>
|
|
29
|
+
program.addCommand(stopCommand); // stop
|
|
30
|
+
program.addCommand(statusCommand); // status
|
|
31
|
+
program.addCommand(pageCommand); // page add/rm/ls/manifest
|
|
32
|
+
program.addCommand(runCommand); // run get-state/set-state/exec/inspect/watch
|
|
33
|
+
program.addCommand(guideCommand); // guide
|
|
34
|
+
program.addCommand(cleanupCommand); // cleanup
|
|
35
|
+
program.addCommand(componentsCommand); // components
|
|
36
|
+
program.addCommand(doctorCommand); // doctor
|
|
37
|
+
program.addCommand(verifyCommand); // verify
|
|
52
38
|
// Error handling
|
|
53
39
|
program.exitOverride();
|
|
54
40
|
try {
|
|
@@ -53,17 +53,17 @@ const errorGuides = {
|
|
|
53
53
|
// 运行时相关
|
|
54
54
|
'runtime_not_running': {
|
|
55
55
|
message: 'Runtime is not running',
|
|
56
|
-
cause: 'The
|
|
57
|
-
fix: 'Start
|
|
58
|
-
example: 'agentstage
|
|
59
|
-
relatedCommands: ['
|
|
56
|
+
cause: 'The runtime process is not started',
|
|
57
|
+
fix: 'Start a page runtime in another terminal',
|
|
58
|
+
example: 'agentstage serve <pageId>',
|
|
59
|
+
relatedCommands: ['serve', 'status']
|
|
60
60
|
},
|
|
61
61
|
'page_not_connected': {
|
|
62
62
|
message: 'Page is not connected',
|
|
63
63
|
cause: 'Using --live flag but page is not open in browser',
|
|
64
64
|
fix: 'Either remove --live, or open the page in browser first',
|
|
65
65
|
example: '# Option 1: File-only update\nagentstage run set-state mypage \'{...}\'\n\n# Option 2: Open page first\n# Then use --live',
|
|
66
|
-
relatedCommands: ['run set-state', '
|
|
66
|
+
relatedCommands: ['run set-state', 'serve']
|
|
67
67
|
},
|
|
68
68
|
// 路径遍历(安全)
|
|
69
69
|
'path_traversal_detected': {
|
package/dist/utils/paths.js
CHANGED
|
@@ -52,15 +52,15 @@ export async function getPidFile() {
|
|
|
52
52
|
*/
|
|
53
53
|
export async function getPagesDir() {
|
|
54
54
|
const workspace = await getWorkspaceDir();
|
|
55
|
-
// New
|
|
56
|
-
if (existsSync(join(workspace, '
|
|
57
|
-
return join(workspace, '
|
|
55
|
+
// New runtime data structure
|
|
56
|
+
if (existsSync(join(workspace, 'pages'))) {
|
|
57
|
+
return join(workspace, 'pages');
|
|
58
58
|
}
|
|
59
|
-
// Legacy
|
|
59
|
+
// Legacy template structure fallback
|
|
60
60
|
if (existsSync(join(workspace, 'src', 'pages'))) {
|
|
61
61
|
return join(workspace, 'src', 'pages');
|
|
62
62
|
}
|
|
63
|
-
throw new Error('
|
|
63
|
+
throw new Error('Pages directory not found at pages/');
|
|
64
64
|
}
|
|
65
65
|
// 运行时配置文件路径
|
|
66
66
|
export async function getRuntimeConfigFile() {
|
package/dist/utils/tunnel.d.ts
CHANGED
package/dist/utils/tunnel.js
CHANGED
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-stage",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.17",
|
|
4
4
|
"files": [
|
|
5
|
-
"dist"
|
|
6
|
-
"template"
|
|
5
|
+
"dist"
|
|
7
6
|
],
|
|
8
7
|
"type": "module",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/parkgogogo/agent-stage"
|
|
11
|
+
},
|
|
9
12
|
"bin": {
|
|
10
13
|
"agent-stage": "./dist/index.js"
|
|
11
14
|
},
|
|
@@ -16,8 +19,8 @@
|
|
|
16
19
|
"execa": "^9.3.1",
|
|
17
20
|
"pathe": "^1.1.2",
|
|
18
21
|
"picocolors": "^1.1.1",
|
|
19
|
-
"@agentstage/
|
|
20
|
-
"@agentstage/
|
|
22
|
+
"@agentstage/render": "0.2.5",
|
|
23
|
+
"@agentstage/bridge": "0.1.3"
|
|
21
24
|
},
|
|
22
25
|
"devDependencies": {
|
|
23
26
|
"@types/node": "^22.13.5",
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { devInitCommand } from './init.js';
|
|
3
|
-
import { devStartCommand } from './start.js';
|
|
4
|
-
import { devStopCommand } from './stop.js';
|
|
5
|
-
import { devStatusCommand } from './status.js';
|
|
6
|
-
export const devCommand = new Command('dev')
|
|
7
|
-
.description('Development commands for Agentstage')
|
|
8
|
-
.addCommand(devInitCommand)
|
|
9
|
-
.addCommand(devStartCommand)
|
|
10
|
-
.addCommand(devStopCommand)
|
|
11
|
-
.addCommand(devStatusCommand);
|