agent-stage 0.2.18 → 0.2.19
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 +46 -7
- package/dist/commands/page/add.js +4 -56
- package/dist/commands/prompt/index.d.ts +2 -0
- package/dist/commands/prompt/index.js +5 -0
- package/dist/commands/prompt/ui.d.ts +2 -0
- package/dist/commands/prompt/ui.js +60 -0
- package/dist/index.js +2 -0
- package/dist/lib/prompt/ui-prompt.d.ts +7 -0
- package/dist/lib/prompt/ui-prompt.js +49 -0
- package/package.json +1 -1
package/dist/commands/guide.js
CHANGED
|
@@ -4,7 +4,7 @@ import c from 'picocolors';
|
|
|
4
4
|
const guides = {
|
|
5
5
|
'quickstart': {
|
|
6
6
|
title: 'Quick Start for Agents',
|
|
7
|
-
description: 'Get started with agentstage in
|
|
7
|
+
description: 'Get started with agentstage in 4 steps',
|
|
8
8
|
examples: [
|
|
9
9
|
{
|
|
10
10
|
scenario: '1. Initialize project (first time only)',
|
|
@@ -13,11 +13,16 @@ const guides = {
|
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
scenario: '2. Create a page',
|
|
16
|
-
command: 'agentstage page add mypage
|
|
17
|
-
explanation: 'Creates
|
|
16
|
+
command: 'agentstage page add mypage',
|
|
17
|
+
explanation: 'Creates page files at pages/mypage/ui.json and pages/mypage/store.json'
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
|
-
scenario: '3.
|
|
20
|
+
scenario: '3. Generate prompt for AI UI JSON',
|
|
21
|
+
command: 'agentstage prompt ui --page mypage',
|
|
22
|
+
explanation: 'Prints a prompt you can send to AI to generate valid ui.json'
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
scenario: '4. Start page runtime',
|
|
21
26
|
command: 'agentstage serve mypage',
|
|
22
27
|
explanation: 'Starts the page runtime process'
|
|
23
28
|
}
|
|
@@ -40,9 +45,9 @@ const guides = {
|
|
|
40
45
|
explanation: 'Creates page with UI spec and initial state'
|
|
41
46
|
},
|
|
42
47
|
{
|
|
43
|
-
scenario: 'Create empty page
|
|
48
|
+
scenario: 'Create empty page then generate prompt',
|
|
44
49
|
command: 'agentstage page add todo',
|
|
45
|
-
explanation: 'Creates
|
|
50
|
+
explanation: 'Creates skeleton files. Then run: agentstage prompt ui --page todo'
|
|
46
51
|
},
|
|
47
52
|
{
|
|
48
53
|
scenario: 'Create page from stdin (for large JSON)',
|
|
@@ -68,6 +73,39 @@ const guides = {
|
|
|
68
73
|
}
|
|
69
74
|
]
|
|
70
75
|
},
|
|
76
|
+
'prompt-ui': {
|
|
77
|
+
title: 'Prompt for UI JSON',
|
|
78
|
+
description: 'Generate prompt text for AI to produce valid json-render ui.json',
|
|
79
|
+
examples: [
|
|
80
|
+
{
|
|
81
|
+
scenario: 'Generate a generic prompt',
|
|
82
|
+
command: 'agentstage prompt ui',
|
|
83
|
+
explanation: 'Outputs a reusable prompt with JSON shape and binding rules'
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
scenario: 'Generate with page context',
|
|
87
|
+
command: 'agentstage prompt ui --page todo',
|
|
88
|
+
explanation: 'Includes current ui.json/store.json context to guide refinement'
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
scenario: 'Pipe prompt into a file',
|
|
92
|
+
command: 'agentstage prompt ui --page todo > /tmp/todo.prompt.txt',
|
|
93
|
+
explanation: 'Useful for automation or LLM pipeline integration'
|
|
94
|
+
}
|
|
95
|
+
],
|
|
96
|
+
commonErrors: [
|
|
97
|
+
{
|
|
98
|
+
error: 'Project not initialized',
|
|
99
|
+
cause: 'Using --page without initialized workspace',
|
|
100
|
+
fix: 'Run: agentstage init'
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
error: 'Page "xxx" not found',
|
|
104
|
+
cause: 'The target page has no pages/<id>/ui.json yet',
|
|
105
|
+
fix: 'Run: agentstage page add <id> first'
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
},
|
|
71
109
|
'ui-json': {
|
|
72
110
|
title: 'UI JSON Format',
|
|
73
111
|
description: 'Complete guide to json-render UI specification',
|
|
@@ -201,7 +239,7 @@ push/pop: Navigate forward/back`
|
|
|
201
239
|
};
|
|
202
240
|
export const guideCommand = new Command('guide')
|
|
203
241
|
.description('Get guidance for using agentstage (for AI Agents)')
|
|
204
|
-
.argument('[topic]', 'Topic to get guidance on (quickstart, page-add, ui-json, state-management, validate)')
|
|
242
|
+
.argument('[topic]', 'Topic to get guidance on (quickstart, page-add, prompt-ui, ui-json, state-management, validate)')
|
|
205
243
|
.option('--list', 'List all available topics')
|
|
206
244
|
.action(async (topic, options) => {
|
|
207
245
|
if (options.list || !topic) {
|
|
@@ -216,6 +254,7 @@ export const guideCommand = new Command('guide')
|
|
|
216
254
|
console.log();
|
|
217
255
|
console.log(c.dim('Example:'));
|
|
218
256
|
console.log(` ${c.cyan('agentstage guide quickstart')}`);
|
|
257
|
+
console.log(` ${c.cyan('agentstage guide prompt-ui')}`);
|
|
219
258
|
console.log(` ${c.cyan('agentstage guide ui-json')}`);
|
|
220
259
|
console.log();
|
|
221
260
|
return;
|
|
@@ -39,6 +39,7 @@ export const pageAddCommand = new Command('add')
|
|
|
39
39
|
await mkdir(pagesDir, { recursive: true });
|
|
40
40
|
// 处理 UI
|
|
41
41
|
let uiContent;
|
|
42
|
+
const hasCustomUi = options.uiStdin || options.ui;
|
|
42
43
|
if (options.uiStdin) {
|
|
43
44
|
// 从 stdin 读取 UI
|
|
44
45
|
const input = await readStdin();
|
|
@@ -108,30 +109,20 @@ export const pageAddCommand = new Command('add')
|
|
|
108
109
|
}
|
|
109
110
|
// 输出结果
|
|
110
111
|
const port = config?.port || 3000;
|
|
111
|
-
if (
|
|
112
|
-
|
|
113
|
-
printAgentSuccess(`Page "${name}" created with custom UI and state`, [
|
|
112
|
+
if (hasCustomUi) {
|
|
113
|
+
printAgentSuccess(`Page "${name}" created with custom UI`, [
|
|
114
114
|
`Start runtime: agentstage serve ${name}`,
|
|
115
115
|
`Open http://localhost:${port} to see your page`,
|
|
116
116
|
`Update state: agentstage run set-state ${name} '{"key": "value"}'`
|
|
117
117
|
]);
|
|
118
118
|
}
|
|
119
119
|
else {
|
|
120
|
-
// 默认 UI,输出 prompts
|
|
121
120
|
consola.success(`Page "${name}" created`);
|
|
122
121
|
console.log(` UI: ${c.cyan(`pages/${name}/ui.json`)}`);
|
|
123
122
|
console.log(` Store: ${c.cyan(`pages/${name}/store.json`)}`);
|
|
124
123
|
console.log(` URL: ${c.cyan(`http://localhost:${port}/${name}`)}`);
|
|
125
124
|
console.log();
|
|
126
|
-
|
|
127
|
-
console.log(c.bold('🤖 AI Prompts'));
|
|
128
|
-
console.log(c.bold('─'.repeat(60)));
|
|
129
|
-
console.log();
|
|
130
|
-
console.log(c.dim('Send this to AI to generate UI:'));
|
|
131
|
-
console.log();
|
|
132
|
-
console.log(generatePromptContent(name));
|
|
133
|
-
console.log(c.bold('─'.repeat(60)));
|
|
134
|
-
console.log();
|
|
125
|
+
printAgentHint(`Generate prompt: agentstage prompt ui --page ${name}`);
|
|
135
126
|
printAgentHint(`Or provide UI directly: agentstage page add ${name} --ui '{...}' --state '{...}'`);
|
|
136
127
|
}
|
|
137
128
|
}
|
|
@@ -182,46 +173,3 @@ function generateDefaultState(name) {
|
|
|
182
173
|
function toTitleCase(str) {
|
|
183
174
|
return str.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
|
|
184
175
|
}
|
|
185
|
-
function generatePromptContent(name) {
|
|
186
|
-
const titleName = toTitleCase(name);
|
|
187
|
-
return `# Generate UI for "${titleName}" page
|
|
188
|
-
|
|
189
|
-
Output JSON format:
|
|
190
|
-
\`\`\`json
|
|
191
|
-
{
|
|
192
|
-
"root": "main",
|
|
193
|
-
"elements": {
|
|
194
|
-
"element-id": {
|
|
195
|
-
"type": "ComponentName",
|
|
196
|
-
"props": { ... },
|
|
197
|
-
"children": ["child-id-1"],
|
|
198
|
-
"on": { "press": { "action": "setState", "params": {...} } }
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
\`\`\`
|
|
203
|
-
|
|
204
|
-
## Components
|
|
205
|
-
|
|
206
|
-
**Layout**: Stack(direction, gap, align, justify), Card(title, description), Separator
|
|
207
|
-
**Typography**: Heading(text, level), Text(text, variant), Badge(text, variant)
|
|
208
|
-
**Inputs**: Input(label, name, type, placeholder), Button(label, variant)
|
|
209
|
-
**Data**: Table(columns, rows), Tabs(tabs), Dialog(title, openPath)
|
|
210
|
-
|
|
211
|
-
## State Bindings
|
|
212
|
-
- Read: \`{ "$state": "/path" }\`
|
|
213
|
-
- Write: \`{ "$bindState": "/path" }\`
|
|
214
|
-
- List item: \`{ "$item": "field" }\`
|
|
215
|
-
|
|
216
|
-
## Actions
|
|
217
|
-
- \`setState\`: { statePath: string, value: any }
|
|
218
|
-
- \`pushState\`: { statePath: string, value: any }
|
|
219
|
-
- \`removeState\`: { statePath: string, index: number }
|
|
220
|
-
|
|
221
|
-
## Usage
|
|
222
|
-
\`\`\`bash
|
|
223
|
-
agentstage page add ${name} --ui '{"root":"main",...}' --state '{"count":0}'
|
|
224
|
-
\`\`\`
|
|
225
|
-
|
|
226
|
-
Generate UI for: [describe your page here]`;
|
|
227
|
-
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import consola from "consola";
|
|
3
|
+
import { existsSync } from "fs";
|
|
4
|
+
import { readFile } from "fs/promises";
|
|
5
|
+
import { join } from "pathe";
|
|
6
|
+
import { buildUiPrompt } from "../../lib/prompt/ui-prompt.js";
|
|
7
|
+
import { getWorkspaceDir, isInitialized } from "../../utils/paths.js";
|
|
8
|
+
function parsePageId(pageId) {
|
|
9
|
+
if (!/^[a-z0-9-]+$/.test(pageId)) {
|
|
10
|
+
throw new Error("Invalid pageId. Allowed: lowercase letters, numbers, hyphen");
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
async function readJson(path) {
|
|
14
|
+
const content = await readFile(path, "utf8");
|
|
15
|
+
return JSON.parse(content);
|
|
16
|
+
}
|
|
17
|
+
export const promptUiCommand = new Command("ui")
|
|
18
|
+
.description("Print prompt text for generating json-render ui.json")
|
|
19
|
+
.option("--page <pageId>", "Use an existing page as context")
|
|
20
|
+
.option("--compact", "Hide verbose context sections", false)
|
|
21
|
+
.action(async (options) => {
|
|
22
|
+
const pageId = options.page;
|
|
23
|
+
const compact = options.compact === true;
|
|
24
|
+
try {
|
|
25
|
+
if (!pageId) {
|
|
26
|
+
process.stdout.write(`${buildUiPrompt({ compact })}\n`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
parsePageId(pageId);
|
|
30
|
+
if (!isInitialized()) {
|
|
31
|
+
throw new Error("Project not initialized. Please run `agentstage init` first.");
|
|
32
|
+
}
|
|
33
|
+
const workspaceDir = await getWorkspaceDir();
|
|
34
|
+
const pageDir = join(workspaceDir, "pages", pageId);
|
|
35
|
+
const uiPath = join(pageDir, "ui.json");
|
|
36
|
+
const storePath = join(pageDir, "store.json");
|
|
37
|
+
if (!existsSync(uiPath)) {
|
|
38
|
+
throw new Error(`Page "${pageId}" not found: ${uiPath}`);
|
|
39
|
+
}
|
|
40
|
+
const uiSpec = await readJson(uiPath);
|
|
41
|
+
let state = undefined;
|
|
42
|
+
if (existsSync(storePath)) {
|
|
43
|
+
const store = await readJson(storePath);
|
|
44
|
+
if (typeof store === "object" && store !== null && "state" in store) {
|
|
45
|
+
state = store.state;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
process.stdout.write(`${buildUiPrompt({
|
|
49
|
+
pageId,
|
|
50
|
+
uiSpec,
|
|
51
|
+
state,
|
|
52
|
+
compact,
|
|
53
|
+
})}\n`);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
const message = error instanceof Error ? error.message : "Failed to build ui prompt";
|
|
57
|
+
consola.error(message);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
});
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import { stopCommand } from './commands/stop.js';
|
|
|
12
12
|
import { statusCommand } from './commands/status.js';
|
|
13
13
|
import { pageCommand } from './commands/page/index.js';
|
|
14
14
|
import { runCommand } from './commands/run/index.js';
|
|
15
|
+
import { promptCommand } from './commands/prompt/index.js';
|
|
15
16
|
import { guideCommand } from './commands/guide.js';
|
|
16
17
|
import { cleanupCommand } from './commands/cleanup.js';
|
|
17
18
|
import { componentsCommand } from './commands/components.js';
|
|
@@ -30,6 +31,7 @@ program.addCommand(stopCommand); // stop
|
|
|
30
31
|
program.addCommand(statusCommand); // status
|
|
31
32
|
program.addCommand(pageCommand); // page add/rm/ls/manifest
|
|
32
33
|
program.addCommand(runCommand); // run get-state/set-state/exec/inspect/watch
|
|
34
|
+
program.addCommand(promptCommand); // prompt ui
|
|
33
35
|
program.addCommand(guideCommand); // guide
|
|
34
36
|
program.addCommand(cleanupCommand); // cleanup
|
|
35
37
|
program.addCommand(componentsCommand); // components
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
function toJson(value) {
|
|
2
|
+
return JSON.stringify(value, null, 2);
|
|
3
|
+
}
|
|
4
|
+
export function buildUiPrompt(input = {}) {
|
|
5
|
+
const sections = [];
|
|
6
|
+
const compact = input.compact === true;
|
|
7
|
+
const pageLabel = input.pageId ? ` for page "${input.pageId}"` : "";
|
|
8
|
+
sections.push(`Generate a json-render UI spec${pageLabel}.`);
|
|
9
|
+
sections.push("Return ONLY one valid JSON object.");
|
|
10
|
+
sections.push("Do not output markdown fences.");
|
|
11
|
+
sections.push("Do not output explanations.");
|
|
12
|
+
sections.push("");
|
|
13
|
+
sections.push("Required output shape:");
|
|
14
|
+
sections.push('{ "root": "element-id", "elements": { "element-id": { "type": "ComponentName", "props": {}, "children": [] } } }');
|
|
15
|
+
sections.push("");
|
|
16
|
+
sections.push("Rules:");
|
|
17
|
+
sections.push("1. root must reference an existing element key in elements.");
|
|
18
|
+
sections.push("2. Every children element id must exist in elements.");
|
|
19
|
+
sections.push("3. Use only registered component names.");
|
|
20
|
+
sections.push("4. Keep all props JSON-serializable.");
|
|
21
|
+
sections.push('5. State read binding: { "$state": "/path" }');
|
|
22
|
+
sections.push('6. Two-way binding: { "$bindState": "/path" }');
|
|
23
|
+
sections.push('7. List item binding: { "$item": "fieldName" }');
|
|
24
|
+
sections.push('8. List index binding: { "$index": true }');
|
|
25
|
+
sections.push("");
|
|
26
|
+
sections.push("Common components:");
|
|
27
|
+
sections.push("Layout: Stack, Card, Grid, Separator");
|
|
28
|
+
sections.push("Typography: Heading, Text, Badge");
|
|
29
|
+
sections.push("Input: Input, Button, Select, Checkbox, Switch");
|
|
30
|
+
sections.push("Data/Feedback: Table, Tabs, Dialog, Accordion, Alert, Progress, Skeleton, Spinner");
|
|
31
|
+
sections.push("");
|
|
32
|
+
sections.push("Actions:");
|
|
33
|
+
sections.push('Use event handlers like: "on": { "press": { "action": "setState", "params": { ... } } }');
|
|
34
|
+
sections.push("Common actions: setState, pushState, removeState");
|
|
35
|
+
if (input.state !== undefined) {
|
|
36
|
+
sections.push("");
|
|
37
|
+
sections.push("Current state context:");
|
|
38
|
+
sections.push(toJson(input.state));
|
|
39
|
+
}
|
|
40
|
+
if (input.uiSpec !== undefined && !compact) {
|
|
41
|
+
sections.push("");
|
|
42
|
+
sections.push("Existing ui.json context:");
|
|
43
|
+
sections.push(toJson(input.uiSpec));
|
|
44
|
+
sections.push("If you improve it, keep ids stable when possible.");
|
|
45
|
+
}
|
|
46
|
+
sections.push("");
|
|
47
|
+
sections.push("Now output the final JSON object only.");
|
|
48
|
+
return sections.join("\n");
|
|
49
|
+
}
|