@otomus/nerva-cli 0.1.1

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 (45) hide show
  1. package/dist/commands/dev.d.ts +42 -0
  2. package/dist/commands/dev.d.ts.map +1 -0
  3. package/dist/commands/dev.js +257 -0
  4. package/dist/commands/dev.js.map +1 -0
  5. package/dist/commands/generate.d.ts +24 -0
  6. package/dist/commands/generate.d.ts.map +1 -0
  7. package/dist/commands/generate.js +162 -0
  8. package/dist/commands/generate.js.map +1 -0
  9. package/dist/commands/list.d.ts +19 -0
  10. package/dist/commands/list.d.ts.map +1 -0
  11. package/dist/commands/list.js +96 -0
  12. package/dist/commands/list.js.map +1 -0
  13. package/dist/commands/new.d.ts +23 -0
  14. package/dist/commands/new.d.ts.map +1 -0
  15. package/dist/commands/new.js +138 -0
  16. package/dist/commands/new.js.map +1 -0
  17. package/dist/commands/plugin.d.ts +79 -0
  18. package/dist/commands/plugin.d.ts.map +1 -0
  19. package/dist/commands/plugin.js +319 -0
  20. package/dist/commands/plugin.js.map +1 -0
  21. package/dist/commands/test.d.ts +52 -0
  22. package/dist/commands/test.d.ts.map +1 -0
  23. package/dist/commands/test.js +110 -0
  24. package/dist/commands/test.js.map +1 -0
  25. package/dist/commands/trace-ui.d.ts +16 -0
  26. package/dist/commands/trace-ui.d.ts.map +1 -0
  27. package/dist/commands/trace-ui.js +117 -0
  28. package/dist/commands/trace-ui.js.map +1 -0
  29. package/dist/config/nerva-yaml.d.ts +70 -0
  30. package/dist/config/nerva-yaml.d.ts.map +1 -0
  31. package/dist/config/nerva-yaml.js +185 -0
  32. package/dist/config/nerva-yaml.js.map +1 -0
  33. package/dist/index.d.ts +14 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +36 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/registry/plugin-registry.d.ts +30 -0
  38. package/dist/registry/plugin-registry.d.ts.map +1 -0
  39. package/dist/registry/plugin-registry.js +134 -0
  40. package/dist/registry/plugin-registry.js.map +1 -0
  41. package/dist/templates/render.d.ts +36 -0
  42. package/dist/templates/render.d.ts.map +1 -0
  43. package/dist/templates/render.js +52 -0
  44. package/dist/templates/render.js.map +1 -0
  45. package/package.json +32 -0
@@ -0,0 +1,110 @@
1
+ /**
2
+ * `nerva test` command.
3
+ *
4
+ * Detects the project language from nerva.yaml and runs the appropriate
5
+ * test runner (pytest for Python, vitest for TypeScript).
6
+ */
7
+ import { spawn } from 'node:child_process';
8
+ import { readNervaConfig } from '../config/nerva-yaml.js';
9
+ /** Test runner command and arguments for each supported language. */
10
+ const RUNNER_CONFIG = {
11
+ python: { cmd: 'python', args: ['-m', 'pytest'] },
12
+ typescript: { cmd: 'npx', args: ['vitest', 'run'] },
13
+ };
14
+ /**
15
+ * Builds the full argument list for the test runner, including optional coverage flag.
16
+ *
17
+ * @param lang - Project language
18
+ * @param coverage - Whether to enable coverage reporting
19
+ * @returns Tuple of [command, args]
20
+ */
21
+ export function buildTestCommand(lang, coverage) {
22
+ const config = RUNNER_CONFIG[lang];
23
+ if (!config) {
24
+ throw new Error(`Unsupported language for testing: "${lang}"`);
25
+ }
26
+ const args = [...config.args];
27
+ if (coverage) {
28
+ args.push('--coverage');
29
+ }
30
+ return { cmd: config.cmd, args };
31
+ }
32
+ /**
33
+ * Detects the project language from nerva.yaml in the given directory.
34
+ *
35
+ * @param projectDir - Absolute path to project root
36
+ * @returns Detected project language
37
+ * @throws {Error} If nerva.yaml is missing or invalid
38
+ */
39
+ export async function detectLanguage(projectDir) {
40
+ const config = await readNervaConfig(projectDir);
41
+ return config.lang;
42
+ }
43
+ /**
44
+ * Runs the test command as a child process and returns its exit code.
45
+ *
46
+ * @param projectDir - Working directory for the test runner
47
+ * @param cmd - Command to execute
48
+ * @param args - Arguments to pass
49
+ * @returns Exit code from the test runner (0 = success)
50
+ */
51
+ export function runTestProcess(projectDir, cmd, args) {
52
+ return new Promise((resolve) => {
53
+ const child = spawn(cmd, args, {
54
+ cwd: projectDir,
55
+ stdio: 'inherit',
56
+ shell: true,
57
+ });
58
+ child.on('close', (code) => {
59
+ resolve(code ?? 1);
60
+ });
61
+ child.on('error', (err) => {
62
+ console.error(`[nerva test] Failed to start test runner: ${err.message}`);
63
+ resolve(1);
64
+ });
65
+ });
66
+ }
67
+ /**
68
+ * Executes the test command: detects language, runs the appropriate test runner,
69
+ * and prints a trace summary.
70
+ *
71
+ * @param projectDir - Absolute path to project root
72
+ * @param coverage - Whether to enable coverage
73
+ * @returns Exit code from the test runner
74
+ */
75
+ export async function executeTest(projectDir, coverage) {
76
+ const lang = await detectLanguage(projectDir);
77
+ const { cmd, args } = buildTestCommand(lang, coverage);
78
+ console.log(`[nerva test] Detected language: ${lang}`);
79
+ console.log(`[nerva test] Running: ${cmd} ${args.join(' ')}`);
80
+ console.log('');
81
+ const startTime = Date.now();
82
+ const exitCode = await runTestProcess(projectDir, cmd, args);
83
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(2);
84
+ console.log('');
85
+ console.log(' Nerva Test Summary');
86
+ console.log(' ==================');
87
+ console.log(` Language: ${lang}`);
88
+ console.log(` Runner: ${cmd} ${args.join(' ')}`);
89
+ console.log(` Duration: ${elapsed}s`);
90
+ console.log(` Exit: ${exitCode === 0 ? 'PASS' : 'FAIL'} (code ${exitCode})`);
91
+ console.log('');
92
+ return exitCode;
93
+ }
94
+ /**
95
+ * Registers the `nerva test` command with the CLI program.
96
+ *
97
+ * @param program - The root commander program
98
+ */
99
+ export function registerTestCommand(program) {
100
+ program
101
+ .command('test')
102
+ .description('Run tests using the language-appropriate test runner')
103
+ .option('--coverage', 'Enable coverage reporting', false)
104
+ .action(async (options) => {
105
+ const projectDir = process.cwd();
106
+ const exitCode = await executeTest(projectDir, options.coverage);
107
+ process.exitCode = exitCode;
108
+ });
109
+ }
110
+ //# sourceMappingURL=test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.js","sourceRoot":"","sources":["../../src/commands/test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Trace UI HTML page served by the dev server.
3
+ *
4
+ * Returns a self-contained HTML page that displays trace events as a tree,
5
+ * auto-refreshing every 2 seconds from the `/traces` endpoint.
6
+ */
7
+ /**
8
+ * Builds the trace UI HTML page as a string.
9
+ *
10
+ * The page fetches `/traces` every 2 seconds and renders spans
11
+ * as an indented, color-coded tree in a monospace font.
12
+ *
13
+ * @returns Complete HTML document string
14
+ */
15
+ export declare function buildTraceHtml(): string;
16
+ //# sourceMappingURL=trace-ui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-ui.d.ts","sourceRoot":"","sources":["../../src/commands/trace-ui.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;GAOG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAqGvC"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Trace UI HTML page served by the dev server.
3
+ *
4
+ * Returns a self-contained HTML page that displays trace events as a tree,
5
+ * auto-refreshing every 2 seconds from the `/traces` endpoint.
6
+ */
7
+ /**
8
+ * Builds the trace UI HTML page as a string.
9
+ *
10
+ * The page fetches `/traces` every 2 seconds and renders spans
11
+ * as an indented, color-coded tree in a monospace font.
12
+ *
13
+ * @returns Complete HTML document string
14
+ */
15
+ export function buildTraceHtml() {
16
+ return `<!DOCTYPE html>
17
+ <html lang="en">
18
+ <head>
19
+ <meta charset="UTF-8">
20
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
21
+ <title>Nerva Trace UI</title>
22
+ <style>
23
+ * { margin: 0; padding: 0; box-sizing: border-box; }
24
+ body {
25
+ font-family: "SF Mono", "Menlo", "Consolas", monospace;
26
+ font-size: 13px;
27
+ background: #1a1a2e;
28
+ color: #e0e0e0;
29
+ padding: 24px;
30
+ }
31
+ h1 { color: #7fdbca; margin-bottom: 16px; font-size: 18px; }
32
+ .status { color: #888; margin-bottom: 16px; font-size: 11px; }
33
+ .trace-list { list-style: none; }
34
+ .trace-item { margin-bottom: 2px; white-space: pre; }
35
+ .channel-agent { color: #c792ea; }
36
+ .channel-tool { color: #82aaff; }
37
+ .channel-middleware { color: #ffcb6b; }
38
+ .channel-router { color: #f78c6c; }
39
+ .channel-system { color: #89ddff; }
40
+ .channel-unknown { color: #a0a0a0; }
41
+ .timestamp { color: #666; }
42
+ .empty { color: #555; font-style: italic; margin-top: 12px; }
43
+ </style>
44
+ </head>
45
+ <body>
46
+ <h1>Nerva Trace UI</h1>
47
+ <div class="status" id="status">Connecting...</div>
48
+ <ul class="trace-list" id="traces"></ul>
49
+
50
+ <script>
51
+ const CHANNEL_COLORS = {
52
+ agent: 'channel-agent',
53
+ tool: 'channel-tool',
54
+ middleware: 'channel-middleware',
55
+ router: 'channel-router',
56
+ system: 'channel-system',
57
+ };
58
+
59
+ function channelClass(channel) {
60
+ return CHANNEL_COLORS[channel] || 'channel-unknown';
61
+ }
62
+
63
+ function escapeHtml(text) {
64
+ const div = document.createElement('div');
65
+ div.textContent = text;
66
+ return div.innerHTML;
67
+ }
68
+
69
+ function renderTrace(trace, depth) {
70
+ const indent = ' '.repeat(depth);
71
+ const ch = trace.channel || 'unknown';
72
+ const ts = trace.timestamp ? new Date(trace.timestamp).toISOString().slice(11, 23) : '';
73
+ const msg = escapeHtml(trace.message || trace.event || JSON.stringify(trace));
74
+
75
+ let html = '<li class="trace-item">';
76
+ html += '<span class="timestamp">' + escapeHtml(ts) + '</span> ';
77
+ html += indent;
78
+ html += '<span class="' + channelClass(ch) + '">[' + escapeHtml(ch) + ']</span> ';
79
+ html += msg;
80
+ html += '</li>';
81
+
82
+ if (Array.isArray(trace.children)) {
83
+ for (const child of trace.children) {
84
+ html += renderTrace(child, depth + 1);
85
+ }
86
+ }
87
+
88
+ return html;
89
+ }
90
+
91
+ async function refresh() {
92
+ try {
93
+ const res = await fetch('/traces');
94
+ const data = await res.json();
95
+ const list = document.getElementById('traces');
96
+ const status = document.getElementById('status');
97
+
98
+ if (!Array.isArray(data) || data.length === 0) {
99
+ list.innerHTML = '<li class="empty">No traces yet.</li>';
100
+ } else {
101
+ list.innerHTML = data.map(function(t) { return renderTrace(t, 0); }).join('');
102
+ }
103
+
104
+ status.textContent = 'Last updated: ' + new Date().toLocaleTimeString() +
105
+ ' (' + (data.length || 0) + ' traces)';
106
+ } catch (err) {
107
+ document.getElementById('status').textContent = 'Error: ' + err.message;
108
+ }
109
+ }
110
+
111
+ refresh();
112
+ setInterval(refresh, 2000);
113
+ </script>
114
+ </body>
115
+ </html>`;
116
+ }
117
+ //# sourceMappingURL=trace-ui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-ui.js","sourceRoot":"","sources":["../../src/commands/trace-ui.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAmGD,CAAC;AACT,CAAC"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * nerva.yaml configuration parser and validator.
3
+ *
4
+ * Handles reading, writing, and validating the project-level nerva.yaml
5
+ * that declares agents, tools, middleware, and routers.
6
+ */
7
+ /** A single registered component (agent, tool, middleware, or router). */
8
+ export interface ComponentEntry {
9
+ name: string;
10
+ path: string;
11
+ description?: string;
12
+ }
13
+ /** Supported project languages. */
14
+ export type ProjectLang = 'python' | 'typescript';
15
+ /** Top-level nerva.yaml schema. */
16
+ export interface NervaConfig {
17
+ name: string;
18
+ version: string;
19
+ lang: ProjectLang;
20
+ agents: ComponentEntry[];
21
+ tools: ComponentEntry[];
22
+ middleware: ComponentEntry[];
23
+ routers: ComponentEntry[];
24
+ policy?: Record<string, unknown>;
25
+ }
26
+ /** Component types that can be registered in nerva.yaml. */
27
+ export type ComponentType = 'agent' | 'tool' | 'middleware' | 'router';
28
+ /** Keys used in nerva.yaml for each component type's list section. */
29
+ export type ConfigListKey = 'agents' | 'tools' | 'middleware' | 'routers';
30
+ /**
31
+ * Returns the config key used in nerva.yaml for a given component type.
32
+ *
33
+ * @param type - The singular component type
34
+ * @returns The yaml section key (e.g. 'agent' -> 'agents', 'middleware' -> 'middleware')
35
+ */
36
+ export declare function pluralizeType(type: ComponentType): ConfigListKey;
37
+ /**
38
+ * Parses raw YAML-like text into a NervaConfig object.
39
+ *
40
+ * Uses a simple line-based parser for the flat nerva.yaml format.
41
+ * This avoids pulling in a full YAML library for a predictable schema.
42
+ *
43
+ * @param content - Raw file content
44
+ * @returns Parsed configuration
45
+ * @throws {Error} If required fields are missing or lang is invalid
46
+ */
47
+ export declare function parseNervaConfig(content: string): NervaConfig;
48
+ /**
49
+ * Reads and parses nerva.yaml from the given project directory.
50
+ *
51
+ * @param projectDir - Absolute path to project root
52
+ * @returns Parsed NervaConfig
53
+ * @throws {Error} If the file cannot be read or parsed
54
+ */
55
+ export declare function readNervaConfig(projectDir: string): Promise<NervaConfig>;
56
+ /**
57
+ * Serializes a NervaConfig to YAML-formatted text.
58
+ *
59
+ * @param config - The configuration to serialize
60
+ * @returns YAML string
61
+ */
62
+ export declare function serializeNervaConfig(config: NervaConfig): string;
63
+ /**
64
+ * Writes a NervaConfig back to nerva.yaml in the given directory.
65
+ *
66
+ * @param projectDir - Absolute path to project root
67
+ * @param config - Configuration to write
68
+ */
69
+ export declare function writeNervaConfig(projectDir: string, config: NervaConfig): Promise<void>;
70
+ //# sourceMappingURL=nerva-yaml.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nerva-yaml.d.ts","sourceRoot":"","sources":["../../src/config/nerva-yaml.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,mCAAmC;AACnC,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,YAAY,CAAC;AAElD,mCAAmC;AACnC,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,4DAA4D;AAC5D,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,GAAG,YAAY,GAAG,QAAQ,CAAC;AAEvE,sEAAsE;AACtE,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,OAAO,GAAG,YAAY,GAAG,SAAS,CAAC;AAc1E;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,aAAa,GAAG,aAAa,CAEhE;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CA+D7D;AAmDD;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAI9E;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAuBhE;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7F"}
@@ -0,0 +1,185 @@
1
+ /**
2
+ * nerva.yaml configuration parser and validator.
3
+ *
4
+ * Handles reading, writing, and validating the project-level nerva.yaml
5
+ * that declares agents, tools, middleware, and routers.
6
+ */
7
+ import { readFile, writeFile } from 'node:fs/promises';
8
+ import { join } from 'node:path';
9
+ const VALID_LANGS = new Set(['python', 'typescript']);
10
+ const REQUIRED_FIELDS = ['name', 'version', 'lang'];
11
+ const COMPONENT_LISTS = ['agent', 'tool', 'middleware', 'router'];
12
+ /** Maps singular component type to the nerva.yaml section key. */
13
+ const TYPE_TO_KEY = {
14
+ agent: 'agents',
15
+ tool: 'tools',
16
+ middleware: 'middleware',
17
+ router: 'routers',
18
+ };
19
+ /**
20
+ * Returns the config key used in nerva.yaml for a given component type.
21
+ *
22
+ * @param type - The singular component type
23
+ * @returns The yaml section key (e.g. 'agent' -> 'agents', 'middleware' -> 'middleware')
24
+ */
25
+ export function pluralizeType(type) {
26
+ return TYPE_TO_KEY[type];
27
+ }
28
+ /**
29
+ * Parses raw YAML-like text into a NervaConfig object.
30
+ *
31
+ * Uses a simple line-based parser for the flat nerva.yaml format.
32
+ * This avoids pulling in a full YAML library for a predictable schema.
33
+ *
34
+ * @param content - Raw file content
35
+ * @returns Parsed configuration
36
+ * @throws {Error} If required fields are missing or lang is invalid
37
+ */
38
+ export function parseNervaConfig(content) {
39
+ const lines = content.split('\n');
40
+ const config = {};
41
+ const listSections = {
42
+ agents: [],
43
+ tools: [],
44
+ middleware: [],
45
+ routers: [],
46
+ };
47
+ let currentSection = null;
48
+ let currentEntry = null;
49
+ for (const rawLine of lines) {
50
+ const line = rawLine.trimEnd();
51
+ if (line.trim() === '' || line.trim().startsWith('#')) {
52
+ continue;
53
+ }
54
+ // Top-level section header (e.g. "agents:")
55
+ const sectionMatch = line.match(/^(\w+):$/);
56
+ if (sectionMatch) {
57
+ flushEntry(currentSection, currentEntry, listSections);
58
+ currentEntry = null;
59
+ const key = sectionMatch[1];
60
+ if (key in listSections) {
61
+ currentSection = key;
62
+ }
63
+ else {
64
+ currentSection = null;
65
+ }
66
+ continue;
67
+ }
68
+ // Top-level key: value pair (e.g. "name: my-project")
69
+ const kvMatch = line.match(/^(\w+):\s+(.+)$/);
70
+ if (kvMatch && !currentSection) {
71
+ config[kvMatch[1]] = kvMatch[2].trim();
72
+ continue;
73
+ }
74
+ // List item start (e.g. " - name: my-agent")
75
+ const listItemMatch = line.match(/^\s+-\s+(\w+):\s+(.+)$/);
76
+ if (listItemMatch && currentSection) {
77
+ flushEntry(currentSection, currentEntry, listSections);
78
+ currentEntry = { [listItemMatch[1]]: listItemMatch[2].trim() };
79
+ continue;
80
+ }
81
+ // Continuation of list item (e.g. " path: agents/my-agent.py")
82
+ const continuationMatch = line.match(/^\s+(\w+):\s+(.+)$/);
83
+ if (continuationMatch && currentSection && currentEntry) {
84
+ currentEntry[continuationMatch[1]] = continuationMatch[2].trim();
85
+ continue;
86
+ }
87
+ }
88
+ flushEntry(currentSection, currentEntry, listSections);
89
+ return validateConfig({
90
+ ...config,
91
+ ...listSections,
92
+ });
93
+ }
94
+ /**
95
+ * Flushes a partially-built component entry into the appropriate list.
96
+ *
97
+ * @param section - Current yaml section name
98
+ * @param entry - Partial entry to flush
99
+ * @param lists - Map of section name to component entries
100
+ */
101
+ function flushEntry(section, entry, lists) {
102
+ if (!section || !entry || !entry.name || !entry.path) {
103
+ return;
104
+ }
105
+ lists[section].push({ name: entry.name, path: entry.path, description: entry.description });
106
+ }
107
+ /**
108
+ * Validates a raw parsed object against the NervaConfig schema.
109
+ *
110
+ * @param raw - Unvalidated config object
111
+ * @returns Validated NervaConfig
112
+ * @throws {Error} If validation fails
113
+ */
114
+ function validateConfig(raw) {
115
+ for (const field of REQUIRED_FIELDS) {
116
+ if (!raw[field] || typeof raw[field] !== 'string') {
117
+ throw new Error(`nerva.yaml: missing or invalid required field "${field}"`);
118
+ }
119
+ }
120
+ const lang = raw['lang'];
121
+ if (!VALID_LANGS.has(lang)) {
122
+ throw new Error(`nerva.yaml: lang must be "python" or "typescript", got "${lang}"`);
123
+ }
124
+ return {
125
+ name: raw['name'],
126
+ version: raw['version'],
127
+ lang: lang,
128
+ agents: raw['agents'] ?? [],
129
+ tools: raw['tools'] ?? [],
130
+ middleware: raw['middleware'] ?? [],
131
+ routers: raw['routers'] ?? [],
132
+ policy: raw['policy'] ?? undefined,
133
+ };
134
+ }
135
+ /**
136
+ * Reads and parses nerva.yaml from the given project directory.
137
+ *
138
+ * @param projectDir - Absolute path to project root
139
+ * @returns Parsed NervaConfig
140
+ * @throws {Error} If the file cannot be read or parsed
141
+ */
142
+ export async function readNervaConfig(projectDir) {
143
+ const filePath = join(projectDir, 'nerva.yaml');
144
+ const content = await readFile(filePath, 'utf-8');
145
+ return parseNervaConfig(content);
146
+ }
147
+ /**
148
+ * Serializes a NervaConfig to YAML-formatted text.
149
+ *
150
+ * @param config - The configuration to serialize
151
+ * @returns YAML string
152
+ */
153
+ export function serializeNervaConfig(config) {
154
+ const lines = [];
155
+ lines.push(`name: ${config.name}`);
156
+ lines.push(`version: ${config.version}`);
157
+ lines.push(`lang: ${config.lang}`);
158
+ for (const type of COMPONENT_LISTS) {
159
+ const plural = pluralizeType(type);
160
+ const entries = config[plural];
161
+ lines.push('');
162
+ lines.push(`${plural}:`);
163
+ for (const entry of entries) {
164
+ lines.push(` - name: ${entry.name}`);
165
+ lines.push(` path: ${entry.path}`);
166
+ if (entry.description) {
167
+ lines.push(` description: ${entry.description}`);
168
+ }
169
+ }
170
+ }
171
+ lines.push('');
172
+ return lines.join('\n');
173
+ }
174
+ /**
175
+ * Writes a NervaConfig back to nerva.yaml in the given directory.
176
+ *
177
+ * @param projectDir - Absolute path to project root
178
+ * @param config - Configuration to write
179
+ */
180
+ export async function writeNervaConfig(projectDir, config) {
181
+ const filePath = join(projectDir, 'nerva.yaml');
182
+ const content = serializeNervaConfig(config);
183
+ await writeFile(filePath, content, 'utf-8');
184
+ }
185
+ //# sourceMappingURL=nerva-yaml.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nerva-yaml.js","sourceRoot":"","sources":["../../src/config/nerva-yaml.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Nerva CLI entry point.
4
+ *
5
+ * Registers all sub-commands and runs the CLI program.
6
+ */
7
+ import { Command } from 'commander';
8
+ /**
9
+ * Creates and configures the root CLI program with all commands.
10
+ *
11
+ * @returns Configured Commander program
12
+ */
13
+ export declare function createProgram(): Command;
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAgBvC"}
package/dist/index.js ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Nerva CLI entry point.
4
+ *
5
+ * Registers all sub-commands and runs the CLI program.
6
+ */
7
+ import { Command } from 'commander';
8
+ import { registerNewCommand } from './commands/new.js';
9
+ import { registerGenerateCommand } from './commands/generate.js';
10
+ import { registerListCommand } from './commands/list.js';
11
+ import { registerDevCommand } from './commands/dev.js';
12
+ import { registerTestCommand } from './commands/test.js';
13
+ import { registerPluginCommand } from './commands/plugin.js';
14
+ const VERSION = '0.1.0';
15
+ /**
16
+ * Creates and configures the root CLI program with all commands.
17
+ *
18
+ * @returns Configured Commander program
19
+ */
20
+ export function createProgram() {
21
+ const program = new Command();
22
+ program
23
+ .name('nerva')
24
+ .description('CLI for the Nerva agent runtime')
25
+ .version(VERSION);
26
+ registerNewCommand(program);
27
+ registerGenerateCommand(program);
28
+ registerListCommand(program);
29
+ registerDevCommand(program);
30
+ registerTestCommand(program);
31
+ registerPluginCommand(program);
32
+ return program;
33
+ }
34
+ const program = createProgram();
35
+ program.parse(process.argv);
36
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,MAAM,OAAO,GAAG,OAAO,CAAC;AAExB;;;;GAIG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,OAAO,CAAC;SACb,WAAW,CAAC,iCAAiC,CAAC;SAC9C,OAAO,CAAC,OAAO,CAAC,CAAC;IAEpB,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC5B,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACjC,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC7B,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC5B,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC7B,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAE/B,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;AAChC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Community plugin registry client.
3
+ *
4
+ * Searches the npm registry for packages with the `nerva-plugin` keyword
5
+ * and fetches package metadata. Uses `https.get` with no external dependencies.
6
+ */
7
+ /** Summary of a plugin found in the npm registry. */
8
+ export interface RegistryPluginInfo {
9
+ name: string;
10
+ description: string;
11
+ version: string;
12
+ downloads: number;
13
+ }
14
+ /**
15
+ * Searches the npm registry for packages matching a query and the `nerva-plugin` keyword.
16
+ *
17
+ * @param query - Free-text search query
18
+ * @returns Array of matching plugin summaries, sorted by relevance
19
+ * @throws {Error} If the npm registry is unreachable or returns invalid data
20
+ */
21
+ export declare function searchPlugins(query: string): Promise<RegistryPluginInfo[]>;
22
+ /**
23
+ * Fetches detailed package info from the npm registry for a specific package.
24
+ *
25
+ * @param name - Exact npm package name
26
+ * @returns Plugin info with name, description, latest version, and monthly downloads
27
+ * @throws {Error} If the package is not found or the registry is unreachable
28
+ */
29
+ export declare function fetchPluginInfo(name: string): Promise<RegistryPluginInfo>;
30
+ //# sourceMappingURL=plugin-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-registry.d.ts","sourceRoot":"","sources":["../../src/registry/plugin-registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,qDAAqD;AACrD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AA4ED;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAiBhF;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAsB/E"}