@agent-creator/cli 0.4.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.
Files changed (66) hide show
  1. package/README.md +9 -0
  2. package/dist/package.json +36 -0
  3. package/dist/src/capabilities/agent-core/capability.config.d.ts +2 -0
  4. package/dist/src/capabilities/agent-core/capability.config.js +6 -0
  5. package/dist/src/capabilities/agent-core/fileLoader.d.ts +3 -0
  6. package/dist/src/capabilities/agent-core/fileLoader.js +40 -0
  7. package/dist/src/capabilities/agent-core/files/base/.env.example +4 -0
  8. package/dist/src/capabilities/agent-core/files/base/README.md +69 -0
  9. package/dist/src/capabilities/agent-core/files/base/agent.config.ts +31 -0
  10. package/dist/src/capabilities/agent-core/files/base/package.json +33 -0
  11. package/dist/src/capabilities/agent-core/files/base/src/cli.ts +46 -0
  12. package/dist/src/capabilities/agent-core/files/base/src/dev.ts +1 -0
  13. package/dist/src/capabilities/agent-core/files/base/src/env.ts +23 -0
  14. package/dist/src/capabilities/agent-core/files/base/src/index.ts +31 -0
  15. package/dist/src/capabilities/agent-core/files/base/src/skills/index.ts +9 -0
  16. package/dist/src/capabilities/agent-core/files/base/tests/agent.test.ts +25 -0
  17. package/dist/src/capabilities/agent-core/files/base/tsconfig.json +17 -0
  18. package/dist/src/capabilities/agent-core/files/service/next.config.ts +15 -0
  19. package/dist/src/capabilities/agent-core/files/service/package.json +30 -0
  20. package/dist/src/capabilities/agent-core/files/service/src/app/api/agent/route.ts +10 -0
  21. package/dist/src/capabilities/agent-core/files/service/src/app/api/agent/stream/route.ts +53 -0
  22. package/dist/src/capabilities/agent-core/files/service/src/app/globals.css +34 -0
  23. package/dist/src/capabilities/agent-core/files/service/src/app/layout.tsx +19 -0
  24. package/dist/src/capabilities/agent-core/files/service/src/app/page.tsx +7 -0
  25. package/dist/src/capabilities/agent-core/files/service/src/components/AgentChat.tsx +146 -0
  26. package/dist/src/capabilities/capabilityRegistry.d.ts +3 -0
  27. package/dist/src/capabilities/capabilityRegistry.js +16 -0
  28. package/dist/src/capabilities/index.d.ts +1 -0
  29. package/dist/src/capabilities/index.js +1 -0
  30. package/dist/src/cli/cli.d.ts +3 -0
  31. package/dist/src/cli/cli.js +63 -0
  32. package/dist/src/commands/addSkill.d.ts +2 -0
  33. package/dist/src/commands/addSkill.js +58 -0
  34. package/dist/src/commands/addTool.d.ts +3 -0
  35. package/dist/src/commands/addTool.js +7 -0
  36. package/dist/src/commands/create.d.ts +2 -0
  37. package/dist/src/commands/create.js +32 -0
  38. package/dist/src/commands/dev.d.ts +1 -0
  39. package/dist/src/commands/dev.js +11 -0
  40. package/dist/src/commands/trace.d.ts +7 -0
  41. package/dist/src/commands/trace.js +35 -0
  42. package/dist/src/commands/validate.d.ts +1 -0
  43. package/dist/src/commands/validate.js +166 -0
  44. package/dist/src/index.d.ts +2 -0
  45. package/dist/src/index.js +3 -0
  46. package/dist/src/schemas/agentConfig.schema.d.ts +103 -0
  47. package/dist/src/schemas/agentConfig.schema.js +26 -0
  48. package/dist/src/schemas/capability.schema.d.ts +25 -0
  49. package/dist/src/schemas/capability.schema.js +11 -0
  50. package/dist/src/types/capability.d.ts +11 -0
  51. package/dist/src/types/capability.js +1 -0
  52. package/dist/src/types/cli.d.ts +10 -0
  53. package/dist/src/types/cli.js +1 -0
  54. package/dist/src/utils/fs.d.ts +4 -0
  55. package/dist/src/utils/fs.js +21 -0
  56. package/dist/src/utils/logger.d.ts +6 -0
  57. package/dist/src/utils/logger.js +14 -0
  58. package/dist/src/utils/packageManager.d.ts +1 -0
  59. package/dist/src/utils/packageManager.js +5 -0
  60. package/dist/src/utils/path.d.ts +2 -0
  61. package/dist/src/utils/path.js +7 -0
  62. package/dist/src/utils/string.d.ts +4 -0
  63. package/dist/src/utils/string.js +21 -0
  64. package/dist/src/version.d.ts +4 -0
  65. package/dist/src/version.js +5 -0
  66. package/package.json +36 -0
@@ -0,0 +1,146 @@
1
+ 'use client';
2
+
3
+ import { Alert, Button, Card, Input, Layout, Space, Tag, Typography } from 'antd';
4
+ import { useMemo, useState } from 'react';
5
+ import type { AgentOutput, AgentProgressEvent } from '@agent-creator/core';
6
+
7
+ interface Message {
8
+ role: 'user' | 'agent';
9
+ content: string;
10
+ output?: AgentOutput;
11
+ progress?: AgentProgressEvent[];
12
+ }
13
+
14
+ export function AgentChat() {
15
+ const [input, setInput] = useState('');
16
+ const [loading, setLoading] = useState(false);
17
+ const [messages, setMessages] = useState<Message[]>([]);
18
+ const sessionId = useMemo(() => `web_${Date.now()}`, []);
19
+
20
+ async function send() {
21
+ const text = input.trim();
22
+ if (!text) return;
23
+ setInput('');
24
+ setLoading(true);
25
+ setMessages((current) => [...current, { role: 'user', content: text }]);
26
+ const agentMessageIndex = messages.length + 1;
27
+ setMessages((current) => [...current, { role: 'agent', content: 'Agent is working...', progress: [] }]);
28
+ try {
29
+ const response = await fetch('/api/agent/stream', {
30
+ method: 'POST',
31
+ headers: { 'Content-Type': 'application/json' },
32
+ body: JSON.stringify({ input: text, sessionId }),
33
+ });
34
+ if (!response.body) throw new Error('Streaming response is unavailable.');
35
+ await readStream(response.body, {
36
+ onProgress(event) {
37
+ setMessages((current) => current.map((message, index) => index === agentMessageIndex
38
+ ? { ...message, content: event.message, progress: [...(message.progress ?? []), event] }
39
+ : message));
40
+ },
41
+ onFinal(output) {
42
+ setMessages((current) => current.map((message, index) => index === agentMessageIndex
43
+ ? { ...message, content: output.message, output }
44
+ : message));
45
+ },
46
+ });
47
+ } catch (error) {
48
+ setMessages((current) => current.map((message, index) => index === agentMessageIndex
49
+ ? { ...message, content: error instanceof Error ? error.message : String(error) }
50
+ : message));
51
+ } finally {
52
+ setLoading(false);
53
+ }
54
+ }
55
+
56
+ return (
57
+ <Layout className="appShell">
58
+ <div className="content">
59
+ <Space direction="vertical" size={16} style={{ width: '100%' }}>
60
+ <Space align="center" style={{ justifyContent: 'space-between', width: '100%' }}>
61
+ <div>
62
+ <Typography.Title level={2} style={{ marginBottom: 0 }}>{{projectName}}</Typography.Title>
63
+ <Typography.Text type="secondary">Agent service example shell</Typography.Text>
64
+ </div>
65
+ </Space>
66
+ <Card>
67
+ <Space direction="vertical" size={12} style={{ width: '100%' }}>
68
+ {messages.length === 0 && (
69
+ <Alert
70
+ type="info"
71
+ showIcon
72
+ message="Configure the model environment variables, then ask the Agent a question."
73
+ />
74
+ )}
75
+ {messages.map((message, index) => (
76
+ <Card key={index} size="small" title={message.role === 'user' ? 'You' : 'Agent'}>
77
+ <Space direction="vertical" style={{ width: '100%' }}>
78
+ <Typography.Text>{message.content}</Typography.Text>
79
+ {message.output && (
80
+ <Space wrap>
81
+ <Tag color={message.output.success ? 'green' : 'red'}>{message.output.success ? 'success' : 'failed'}</Tag>
82
+ <Tag>{message.output.intent}</Tag>
83
+ {message.output.traceId && <Tag>{message.output.traceId}</Tag>}
84
+ </Space>
85
+ )}
86
+ {message.output?.data !== undefined && (
87
+ <pre className="jsonBlock">{JSON.stringify(message.output.data, null, 2)}</pre>
88
+ )}
89
+ {message.progress && message.progress.length > 0 && (
90
+ <pre className="jsonBlock">{message.progress.map((event) => `${event.type}: ${event.message}`).join('\n')}</pre>
91
+ )}
92
+ </Space>
93
+ </Card>
94
+ ))}
95
+ <Input.Search
96
+ value={input}
97
+ enterButton={<Button type="primary" loading={loading}>Send</Button>}
98
+ placeholder="Ask the agent..."
99
+ onChange={(event) => setInput((event.target as unknown as { value: string }).value)}
100
+ onSearch={send}
101
+ disabled={loading}
102
+ />
103
+ </Space>
104
+ </Card>
105
+ </Space>
106
+ </div>
107
+ </Layout>
108
+ );
109
+ }
110
+
111
+ async function readStream(
112
+ body: ReadableStream<Uint8Array>,
113
+ handlers: {
114
+ onProgress(event: AgentProgressEvent): void;
115
+ onFinal(output: AgentOutput): void;
116
+ },
117
+ ) {
118
+ const reader = body.getReader();
119
+ const decoder = new TextDecoder();
120
+ let buffer = '';
121
+
122
+ while (true) {
123
+ const { done, value } = await reader.read();
124
+ if (done) break;
125
+ buffer += decoder.decode(value, { stream: true });
126
+ const lines = buffer.split('\n');
127
+ buffer = lines.pop() ?? '';
128
+ for (const line of lines) handleLine(line, handlers);
129
+ }
130
+ if (buffer.trim()) handleLine(buffer, handlers);
131
+ }
132
+
133
+ function handleLine(
134
+ line: string,
135
+ handlers: {
136
+ onProgress(event: AgentProgressEvent): void;
137
+ onFinal(output: AgentOutput): void;
138
+ },
139
+ ) {
140
+ if (!line.trim()) return;
141
+ const event = JSON.parse(line) as
142
+ | { type: 'progress'; event: AgentProgressEvent }
143
+ | { type: 'final'; output: AgentOutput };
144
+ if (event.type === 'progress') handlers.onProgress(event.event);
145
+ else handlers.onFinal(event.output);
146
+ }
@@ -0,0 +1,3 @@
1
+ import type { AgentCapabilityDefinition } from '../types/capability.js';
2
+ export declare function getCapability(name: string): AgentCapabilityDefinition;
3
+ export declare function listCapabilities(): AgentCapabilityDefinition[];
@@ -0,0 +1,16 @@
1
+ import { agentCoreCapability } from './agent-core/capability.config.js';
2
+ const capabilities = new Map([
3
+ [agentCoreCapability.name, agentCoreCapability],
4
+ ]);
5
+ export function getCapability(name) {
6
+ if (name !== 'agent-core') {
7
+ throw new Error('当前版本只支持 agent-core。RAG、workflow、guard 等能力会以 add 命令或模块形式扩展。');
8
+ }
9
+ const capability = capabilities.get(name);
10
+ if (!capability)
11
+ throw new Error(`Capability not found: ${name}`);
12
+ return capability;
13
+ }
14
+ export function listCapabilities() {
15
+ return [...capabilities.values()];
16
+ }
@@ -0,0 +1 @@
1
+ export { getCapability, listCapabilities } from './capabilityRegistry.js';
@@ -0,0 +1 @@
1
+ export { getCapability, listCapabilities } from './capabilityRegistry.js';
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function buildCli(): Command;
3
+ export declare function runCli(argv: string[]): void;
@@ -0,0 +1,63 @@
1
+ import { Command } from 'commander';
2
+ import { addSkillCommand } from '../commands/addSkill.js';
3
+ import { addToolCommand } from '../commands/addTool.js';
4
+ import { createCommand } from '../commands/create.js';
5
+ import { devCommand } from '../commands/dev.js';
6
+ import { traceCommand } from '../commands/trace.js';
7
+ import { validateCommand } from '../commands/validate.js';
8
+ import { CLI_VERSION } from '../version.js';
9
+ export function buildCli() {
10
+ const program = new Command();
11
+ program
12
+ .name('agent')
13
+ .description('Create and maintain runnable Agent projects.')
14
+ .version(CLI_VERSION);
15
+ program
16
+ .command('create')
17
+ .argument('<name>', 'project name')
18
+ .option('--capability <capability>', 'agent capability name', 'agent-core')
19
+ .option('--mode <mode>', 'generation mode: package | service', 'service')
20
+ .option('--package-manager <packageManager>', 'package manager', 'npm')
21
+ .option('--force', 'overwrite an existing directory', false)
22
+ .action(createCommand);
23
+ program
24
+ .command('validate')
25
+ .description('Validate the current generated Agent project.')
26
+ .action(validateCommand);
27
+ program
28
+ .command('version')
29
+ .description('Print the Agent Creator CLI version.')
30
+ .action(() => {
31
+ console.log(program.version());
32
+ });
33
+ program
34
+ .command('help')
35
+ .description('Print Agent Creator CLI help.')
36
+ .action(() => {
37
+ program.outputHelp();
38
+ });
39
+ program
40
+ .command('dev')
41
+ .description('Run the generated Agent interactive console.')
42
+ .action(devCommand);
43
+ program
44
+ .command('trace')
45
+ .option('--latest', 'show the latest trace', false)
46
+ .option('--list', 'list traces', false)
47
+ .option('--id <traceId>', 'show a trace by id')
48
+ .action(traceCommand);
49
+ const add = program.command('add').description('Add generated project modules.');
50
+ add
51
+ .command('skill')
52
+ .argument('<skillName>', 'skill name')
53
+ .action(addSkillCommand);
54
+ add
55
+ .command('tool')
56
+ .argument('<toolName>', 'tool name')
57
+ .description('Deprecated alias for agent add skill.')
58
+ .action(addToolCommand);
59
+ return program;
60
+ }
61
+ export function runCli(argv) {
62
+ buildCli().parse(argv);
63
+ }
@@ -0,0 +1,2 @@
1
+ import type { AddToolOptions } from '../types/cli.js';
2
+ export declare function addSkillCommand(skillName: string, _options?: AddToolOptions): Promise<void>;
@@ -0,0 +1,58 @@
1
+ import path from 'node:path';
2
+ import { pathExists, readText, writeFileEnsured } from '../utils/fs.js';
3
+ import { assertSafeName, toCamelCase, toKebabCase, toToolName } from '../utils/string.js';
4
+ import { logger } from '../utils/logger.js';
5
+ export async function addSkillCommand(skillName, _options = {}) {
6
+ assertSafeName(skillName);
7
+ if (!(await pathExists('agent.config.ts')) || !(await pathExists('src/skills/index.ts'))) {
8
+ throw new Error('agent add skill must be run from a generated Agent project root.');
9
+ }
10
+ const fileName = toKebabCase(skillName);
11
+ const symbolName = `${toCamelCase(skillName)}Skill`;
12
+ const dottedName = toToolName(skillName);
13
+ const target = path.join(process.cwd(), 'src/skills', `${fileName}.ts`);
14
+ if (await pathExists(target))
15
+ throw new Error(`Skill already exists: src/skills/${fileName}.ts`);
16
+ await writeFileEnsured(target, skillFile(symbolName, dottedName));
17
+ await updateSkillsIndex(fileName, symbolName, dottedName);
18
+ await updateAgentConfig(dottedName);
19
+ logger.success(`Added skill ${dottedName}.`);
20
+ }
21
+ function skillFile(symbolName, dottedName) {
22
+ return `import { z } from 'zod';
23
+ import type { Skill } from '@agent-creator/core';
24
+
25
+ const inputSchema = z.object({
26
+ query: z.string().min(1),
27
+ });
28
+
29
+ const outputSchema = z.object({
30
+ ok: z.boolean(),
31
+ result: z.string(),
32
+ });
33
+
34
+ export const ${symbolName}: Skill<z.infer<typeof inputSchema>, z.infer<typeof outputSchema>> = {
35
+ name: '${dottedName}',
36
+ description: 'Generated skill skeleton.',
37
+ inputSchema,
38
+ outputSchema,
39
+ async execute(input) {
40
+ return { ok: true, result: \`Handled \${input.query}\` };
41
+ },
42
+ };
43
+ `;
44
+ }
45
+ async function updateSkillsIndex(fileName, symbolName, dottedName) {
46
+ const indexPath = path.join(process.cwd(), 'src/skills/index.ts');
47
+ let text = await readText(indexPath);
48
+ text = `import { ${symbolName} } from './${fileName}.js';\n${text}`;
49
+ text = text.replace('// agent-creator:skill-imports', `// agent-creator:skill-imports\n ${symbolName},`);
50
+ text = text.replace('// agent-creator:skill-exports', `// agent-creator:skill-exports\n '${dottedName}',`);
51
+ await writeFileEnsured(indexPath, text);
52
+ }
53
+ async function updateAgentConfig(dottedName) {
54
+ const configPath = path.join(process.cwd(), 'agent.config.ts');
55
+ let text = await readText(configPath);
56
+ text = text.replace('// agent-creator:skills', `// agent-creator:skills\n '${dottedName}',`);
57
+ await writeFileEnsured(configPath, text);
58
+ }
@@ -0,0 +1,3 @@
1
+ import type { AddToolOptions } from '../types/cli.js';
2
+ /** @deprecated Use agent add skill. */
3
+ export declare function addToolCommand(toolName: string, options: AddToolOptions): Promise<void>;
@@ -0,0 +1,7 @@
1
+ import { logger } from '../utils/logger.js';
2
+ import { addSkillCommand } from './addSkill.js';
3
+ /** @deprecated Use agent add skill. */
4
+ export async function addToolCommand(toolName, options) {
5
+ logger.warn('agent add tool is deprecated; use agent add skill.');
6
+ await addSkillCommand(toolName, options);
7
+ }
@@ -0,0 +1,2 @@
1
+ import type { CreateOptions } from '../types/cli.js';
2
+ export declare function createCommand(name: string, options: CreateOptions): Promise<void>;
@@ -0,0 +1,32 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { getCapability } from '../capabilities/index.js';
4
+ import { pathExists, writeFileEnsured } from '../utils/fs.js';
5
+ import { resolveProjectPath } from '../utils/path.js';
6
+ import { logger } from '../utils/logger.js';
7
+ import { installCommand } from '../utils/packageManager.js';
8
+ export async function createCommand(name, options) {
9
+ const capabilityName = options.capability ?? 'agent-core';
10
+ const mode = options.mode ?? 'service';
11
+ if (!['package', 'service'].includes(mode)) {
12
+ throw new Error(`Unsupported create mode "${mode}". Use "package" or "service".`);
13
+ }
14
+ const capability = getCapability(capabilityName);
15
+ const targetDir = resolveProjectPath(name);
16
+ if (await pathExists(targetDir)) {
17
+ if (!options.force) {
18
+ throw new Error(`Directory already exists: ${targetDir}. Use --force to overwrite.`);
19
+ }
20
+ await fs.rm(targetDir, { recursive: true, force: true });
21
+ }
22
+ for (const file of await capability.files(name, { ...options, mode })) {
23
+ await writeFileEnsured(path.join(targetDir, file.path), file.content);
24
+ }
25
+ const packageManager = options.packageManager ?? 'npm';
26
+ logger.success(`Created ${name} with ${capability.name}.`);
27
+ logger.info('');
28
+ logger.info(`cd ${name}`);
29
+ logger.info(installCommand(packageManager));
30
+ logger.info('npm run dev');
31
+ logger.info('npm test');
32
+ }
@@ -0,0 +1 @@
1
+ export declare function devCommand(): Promise<void>;
@@ -0,0 +1,11 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { pathExists } from '../utils/fs.js';
3
+ export async function devCommand() {
4
+ if (!(await pathExists('src/dev.ts'))) {
5
+ throw new Error('agent dev must be run from a generated Agent project root.');
6
+ }
7
+ const child = spawn('npm', ['run', 'dev'], { stdio: 'inherit', shell: process.platform === 'win32' });
8
+ child.on('exit', (code) => {
9
+ process.exitCode = code ?? 0;
10
+ });
11
+ }
@@ -0,0 +1,7 @@
1
+ interface TraceOptions {
2
+ latest?: boolean;
3
+ list?: boolean;
4
+ id?: string;
5
+ }
6
+ export declare function traceCommand(options: TraceOptions): Promise<void>;
7
+ export {};
@@ -0,0 +1,35 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { pathExists, readText } from '../utils/fs.js';
4
+ import { logger } from '../utils/logger.js';
5
+ export async function traceCommand(options) {
6
+ const directory = path.resolve(process.cwd(), '.agent-traces');
7
+ if (!(await pathExists(directory))) {
8
+ throw new Error('No .agent-traces directory found. Run this in a generated Agent project.');
9
+ }
10
+ const files = (await fs.readdir(directory))
11
+ .filter((file) => file.endsWith('.json'))
12
+ .sort();
13
+ if (options.list) {
14
+ if (files.length === 0) {
15
+ logger.info('No traces found.');
16
+ return;
17
+ }
18
+ for (const file of files)
19
+ logger.info(file.replace(/\.json$/, ''));
20
+ return;
21
+ }
22
+ const selected = options.id ? `${options.id}.json` : files.at(-1);
23
+ if (!selected) {
24
+ logger.info('No traces found.');
25
+ return;
26
+ }
27
+ const content = await readText(path.join(directory, selected));
28
+ const trace = JSON.parse(content);
29
+ if (options.latest || !options.id) {
30
+ logger.info(`${trace.traceId} ${trace.finalOutput?.intent ?? 'unknown'} ${trace.finalOutput?.success ? 'success' : 'failed'} ${trace.latencyMs ?? 0}ms`);
31
+ logger.info(content);
32
+ return;
33
+ }
34
+ logger.info(content);
35
+ }
@@ -0,0 +1 @@
1
+ export declare function validateCommand(): Promise<void>;
@@ -0,0 +1,166 @@
1
+ import path from 'node:path';
2
+ import fs from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import { pathToFileURL } from 'node:url';
5
+ import ts from 'typescript';
6
+ import { agentConfigSchema } from '../schemas/agentConfig.schema.js';
7
+ import { pathExists, readText } from '../utils/fs.js';
8
+ import { logger } from '../utils/logger.js';
9
+ import { SUPPORTED_CONFIG_VERSIONS } from '../version.js';
10
+ export async function validateCommand() {
11
+ const cwd = process.cwd();
12
+ const issues = [];
13
+ const required = [
14
+ 'agent.config.ts',
15
+ 'package.json',
16
+ 'src/index.ts',
17
+ 'src/skills/index.ts',
18
+ ];
19
+ for (const file of required) {
20
+ if (!(await pathExists(path.join(cwd, file)))) {
21
+ issues.push({ location: file, reason: 'Required file is missing.', fix: `Restore or regenerate ${file}.` });
22
+ }
23
+ }
24
+ const configPath = path.join(cwd, 'agent.config.ts');
25
+ if (await pathExists(configPath)) {
26
+ const configResult = await loadAndValidateConfig(configPath);
27
+ if (!configResult.config) {
28
+ issues.push(...configResult.issues);
29
+ }
30
+ else if (!SUPPORTED_CONFIG_VERSIONS.includes(configResult.config.configVersion)) {
31
+ issues.push({
32
+ location: 'agent.config.ts:configVersion',
33
+ reason: `Unsupported configVersion "${configResult.config.configVersion}".`,
34
+ fix: `Use one of: ${SUPPORTED_CONFIG_VERSIONS.join(', ')}. Future versions may provide agent migrate.`,
35
+ });
36
+ }
37
+ else {
38
+ if (configResult.config.service.enabled && configResult.config.service.framework !== 'next') {
39
+ issues.push({
40
+ location: 'agent.config.ts:service',
41
+ reason: 'Generated service-enabled projects must use Next.js.',
42
+ fix: "Set service.framework to 'next' or set service.enabled to false for package mode.",
43
+ });
44
+ }
45
+ if (configResult.config.service.enabled) {
46
+ await validateServiceProject(cwd, issues);
47
+ }
48
+ }
49
+ const enabledSkills = configResult.config?.skills.enabled ?? extractEnabledSkills(await readText(configPath));
50
+ const skillsIndex = await pathExists(path.join(cwd, 'src/skills/index.ts'))
51
+ ? await readText(path.join(cwd, 'src/skills/index.ts'))
52
+ : '';
53
+ for (const skill of enabledSkills) {
54
+ if (!skillsIndex.includes(`'${skill}'`)) {
55
+ issues.push({
56
+ location: 'agent.config.ts',
57
+ reason: `Enabled skill "${skill}" is not registered in src/skills/index.ts.`,
58
+ fix: 'Register the skill with agent add skill or remove it from skills.enabled.',
59
+ });
60
+ }
61
+ }
62
+ await validateCoreDependency(cwd, issues);
63
+ }
64
+ if (issues.length > 0) {
65
+ logger.error('Agent project validation failed:');
66
+ for (const issue of issues) {
67
+ logger.error(`- ${issue.location}: ${issue.reason} Fix: ${issue.fix}`);
68
+ }
69
+ process.exitCode = 1;
70
+ return;
71
+ }
72
+ logger.success('Agent project validation passed.');
73
+ }
74
+ async function validateServiceProject(cwd, issues) {
75
+ const required = [
76
+ 'src/app/page.tsx',
77
+ 'src/app/api/agent/route.ts',
78
+ 'src/components/AgentChat.tsx',
79
+ ];
80
+ for (const file of required) {
81
+ if (!(await pathExists(path.join(cwd, file)))) {
82
+ issues.push({ location: file, reason: 'Required service file is missing.', fix: `Restore ${file} from the agent-core capability.` });
83
+ }
84
+ }
85
+ const packagePath = path.join(cwd, 'package.json');
86
+ if (!(await pathExists(packagePath)))
87
+ return;
88
+ const packageJson = JSON.parse(await readText(packagePath));
89
+ const dependencies = packageJson.dependencies ?? {};
90
+ for (const dependency of ['next', 'react', 'react-dom', 'antd', '@ant-design/nextjs-registry']) {
91
+ if (!dependencies[dependency]) {
92
+ issues.push({
93
+ location: 'package.json',
94
+ reason: `Generated service Agent requires dependency "${dependency}".`,
95
+ fix: `Add ${dependency} to dependencies.`,
96
+ });
97
+ }
98
+ }
99
+ }
100
+ async function validateCoreDependency(cwd, issues) {
101
+ const packagePath = path.join(cwd, 'package.json');
102
+ if (!(await pathExists(packagePath)))
103
+ return;
104
+ const packageJson = JSON.parse(await readText(packagePath));
105
+ if (!packageJson.dependencies?.['@agent-creator/core']) {
106
+ issues.push({
107
+ location: 'package.json',
108
+ reason: 'Generated Agent requires @agent-creator/core.',
109
+ fix: 'Add @agent-creator/core to dependencies.',
110
+ });
111
+ }
112
+ }
113
+ function extractEnabledSkills(configText) {
114
+ const match = configText.match(/enabled:\s*\[([\s\S]*?)\]/m);
115
+ if (!match)
116
+ return [];
117
+ return [...match[1].matchAll(/'([^']+)'/g)].map((item) => item[1]);
118
+ }
119
+ async function loadAndValidateConfig(configPath) {
120
+ try {
121
+ const loaded = await loadConfig(configPath);
122
+ const parsed = agentConfigSchema.safeParse(loaded);
123
+ if (parsed.success)
124
+ return { config: parsed.data, issues: [] };
125
+ return {
126
+ issues: parsed.error.issues.map((issue) => ({
127
+ location: `agent.config.ts:${issue.path.join('.') || 'default'}`,
128
+ reason: issue.message,
129
+ fix: 'Update agent.config.ts to match the AgentConfig schema documented in docs/generated-agent-runtime.md.',
130
+ })),
131
+ };
132
+ }
133
+ catch (error) {
134
+ return {
135
+ issues: [
136
+ {
137
+ location: 'agent.config.ts',
138
+ reason: `Could not load config: ${error instanceof Error ? error.message : String(error)}`,
139
+ fix: 'Run npm install in the generated project and make sure agent.config.ts has a valid default export.',
140
+ },
141
+ ],
142
+ };
143
+ }
144
+ }
145
+ async function loadConfig(configPath) {
146
+ const source = await readText(configPath);
147
+ const transpiled = ts.transpileModule(source, {
148
+ compilerOptions: {
149
+ target: ts.ScriptTarget.ES2022,
150
+ module: ts.ModuleKind.ES2022,
151
+ moduleResolution: ts.ModuleResolutionKind.NodeNext,
152
+ importsNotUsedAsValues: ts.ImportsNotUsedAsValues.Remove,
153
+ },
154
+ fileName: configPath,
155
+ });
156
+ const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'agent-config-'));
157
+ const tempFile = path.join(tempDir, 'agent.config.mjs');
158
+ await fs.writeFile(tempFile, transpiled.outputText, 'utf8');
159
+ try {
160
+ const imported = await import(`${pathToFileURL(tempFile).href}?t=${Date.now()}`);
161
+ return imported.default;
162
+ }
163
+ finally {
164
+ await fs.rm(tempDir, { recursive: true, force: true });
165
+ }
166
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { runCli } from './cli/cli.js';
3
+ runCli(process.argv);