@vxnus/siduri 0.0.1 → 0.0.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.
package/README.md CHANGED
@@ -2,12 +2,41 @@
2
2
 
3
3
  Experimental CLI for creating and configuring Siduri companions.
4
4
 
5
+ Requires Node.js 20 or newer.
6
+
5
7
  ```bash
6
- npx @vxnus/siduri@0.0.1 create
8
+ npx @vxnus/siduri@0.0.2 create
7
9
  ```
8
10
 
11
+ The companion name becomes the project directory. For example, answering
12
+ `Ganyu` creates `./ganyu/siduri.config.json` from the current directory.
13
+
9
14
  The wizard configures the required Brain and Memory organs, then lets you
10
15
  enable or disable Voice, Knowledge, Behavior, Body, and Vision. Knowledge can
11
16
  come from an installed E pack, an E Hub distribution, or a hosted provider.
12
17
 
18
+ Brain providers:
19
+
20
+ - **OpenRouter** — managed model routing using `OPENROUTER_API_KEY`.
21
+ - **OpenAI-compatible API** — a custom `baseUrl`, model ID, and API-key
22
+ environment variable.
23
+
24
+ The wizard creates a project directory from the companion name, writes
25
+ `siduri.config.json`, copies the Siduri runtime, and installs the runtime
26
+ dependencies. API keys are never written to the configuration file. Optional
27
+ organs can be configured as `{ "provider": "none" }`; Brain and Memory remain
28
+ required.
29
+
30
+ After setup, start the generated instance with:
31
+
32
+ ```bash
33
+ cd ganyu
34
+ npm run start
35
+ ```
36
+
37
+ For local development, build the CLI from the repository root with
38
+ `pnpm --filter @vxnus/siduri build`. For the full architecture, see the
39
+ [CLI documentation](../docs/cli.md) and
40
+ [configuration reference](../docs/configuration.md).
41
+
13
42
  This release is experimental and is not intended for production use.
package/dist/index.js CHANGED
@@ -14,7 +14,16 @@ const inquirer_1 = __importDefault(require("inquirer"));
14
14
  const e_knowledge_1 = require("@vxnus/e-knowledge");
15
15
  const execFile = (0, node_util_1.promisify)(node_child_process_1.execFile);
16
16
  const DEFAULT_REGISTRY_URL = 'https://e.vxnus.xyz/api/packs';
17
- const CLI_VERSION = '0.0.1';
17
+ const CLI_VERSION = '0.0.2';
18
+ const RUNTIME_DEPENDENCIES = {
19
+ '@vxnus/e': '^0.1.3',
20
+ '@vxnus/e-knowledge': '^0.1.2',
21
+ cors: '^2.8.5',
22
+ express: '^4.18.2',
23
+ pg: '^8.23.0',
24
+ ws: '^8.21.3',
25
+ zod: '^4.4.3',
26
+ };
18
27
  const colors = {
19
28
  cyan: '\u001b[36m',
20
29
  dim: '\u001b[2m',
@@ -24,7 +33,7 @@ const colors = {
24
33
  };
25
34
  function printHeader() {
26
35
  console.log(`\n${colors.cyan}◈ SIDURI${colors.reset} ${colors.dim}companion setup${colors.reset}`);
27
- console.log(`${colors.yellow}Experimental release 0.0.1${colors.reset} · configuration may change\n`);
36
+ console.log(`${colors.yellow}Experimental release 0.0.2${colors.reset} · configuration may change\n`);
28
37
  }
29
38
  function printSection(title) {
30
39
  console.log(`\n${colors.cyan}── ${title} ${'─'.repeat(Math.max(2, 42 - title.length))}${colors.reset}`);
@@ -32,6 +41,36 @@ function printSection(title) {
32
41
  function printSuccess(message) {
33
42
  console.log(`${colors.green}✓${colors.reset} ${message}`);
34
43
  }
44
+ function runtimePath() {
45
+ const projectRuntime = node_path_1.default.join(process.cwd(), 'siduri-runtime.js');
46
+ return node_path_1.default.resolve(pathExists(projectRuntime) ? projectRuntime : node_path_1.default.join(__dirname, 'runtime.js'));
47
+ }
48
+ function pathExists(filePath) {
49
+ try {
50
+ require('node:fs').accessSync(filePath);
51
+ return true;
52
+ }
53
+ catch {
54
+ return false;
55
+ }
56
+ }
57
+ async function startRuntime() {
58
+ const filePath = runtimePath();
59
+ if (!pathExists(filePath)) {
60
+ throw new Error('Siduri runtime bundle is missing. Reinstall the CLI or rebuild the package.');
61
+ }
62
+ await new Promise((resolve, reject) => {
63
+ const child = (0, node_child_process_1.spawn)(process.execPath, [filePath], { stdio: 'inherit', env: process.env });
64
+ child.once('error', reject);
65
+ child.once('exit', (code, signal) => {
66
+ if (signal)
67
+ process.exitCode = 1;
68
+ else if (code !== null)
69
+ process.exitCode = code;
70
+ resolve();
71
+ });
72
+ });
73
+ }
35
74
  async function withTask(label, task) {
36
75
  process.stdout.write(`${colors.dim}${label}${colors.reset}`);
37
76
  const frames = ['·', '•', '●', '•'];
@@ -66,6 +105,14 @@ function urlValue(value) {
66
105
  function safePart(value) {
67
106
  return value.replace(/[^a-zA-Z0-9._-]/g, '_');
68
107
  }
108
+ function projectDirectoryName(value) {
109
+ const slug = value
110
+ .trim()
111
+ .toLowerCase()
112
+ .replace(/[^a-z0-9]+/g, '-')
113
+ .replace(/^-+|-+$/g, '');
114
+ return slug || 'siduri';
115
+ }
69
116
  async function getJson(url) {
70
117
  const controller = new AbortController();
71
118
  const timeout = setTimeout(() => controller.abort(), 15000);
@@ -232,9 +279,14 @@ async function main() {
232
279
  console.log(CLI_VERSION);
233
280
  return;
234
281
  }
282
+ if (command === 'start') {
283
+ await startRuntime();
284
+ return;
285
+ }
235
286
  if (command !== 'create') {
236
287
  printHeader();
237
288
  console.log('Usage: npx @vxnus/siduri create');
289
+ console.log(' npx @vxnus/siduri start');
238
290
  console.log(' npx @vxnus/siduri --version');
239
291
  return;
240
292
  }
@@ -244,7 +296,9 @@ async function main() {
244
296
  { type: 'input', name: 'name', message: 'Companion name:', default: 'Siduri', validate: nonEmpty },
245
297
  { type: 'list', name: 'memory', message: 'Memory provider?', choices: [{ name: 'PostgreSQL', value: 'postgres' }] },
246
298
  ]);
247
- printSuccess(`${answers.name} · PostgreSQL memory`);
299
+ const projectPath = node_path_1.default.resolve(process.cwd(), projectDirectoryName(answers.name));
300
+ await (0, promises_1.mkdir)(projectPath, { recursive: true });
301
+ printSuccess(`${answers.name} · PostgreSQL memory · ${projectPath}`);
248
302
  printSection('Brain · required');
249
303
  const { brainProvider } = await inquirer_1.default.prompt({
250
304
  type: 'list',
@@ -297,7 +351,7 @@ async function main() {
297
351
  body: { provider: remaining.body, vtsUrl: process.env.VTS_URL || 'ws://127.0.0.1:8001' },
298
352
  vision: { provider: remaining.vision, model: 'gpt-4-vision' },
299
353
  };
300
- const configPath = node_path_1.default.join(process.cwd(), 'siduri.config.json');
354
+ const configPath = node_path_1.default.join(projectPath, 'siduri.config.json');
301
355
  try {
302
356
  await (0, promises_1.readFile)(configPath, 'utf8');
303
357
  const { overwrite } = await inquirer_1.default.prompt({
@@ -335,7 +389,25 @@ async function main() {
335
389
  }
336
390
  await (0, promises_1.writeFile)(configPath, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
337
391
  printSuccess(`Configuration written · ${configPath}`);
338
- console.log(`${colors.dim}Next: start Siduri with pnpm --filter @siduri-y/api dev${colors.reset}\n`);
392
+ await (0, promises_1.cp)(node_path_1.default.join(__dirname, 'runtime.js'), node_path_1.default.join(projectPath, 'siduri-runtime.js'));
393
+ await (0, promises_1.writeFile)(node_path_1.default.join(projectPath, 'package.json'), JSON.stringify({
394
+ name: projectDirectoryName(answers.name),
395
+ private: true,
396
+ version: '0.0.0',
397
+ scripts: { start: 'node siduri-runtime.js', dev: 'node siduri-runtime.js' },
398
+ dependencies: RUNTIME_DEPENDENCIES,
399
+ }, null, 2) + '\n', { mode: 0o600 });
400
+ const keyEnv = config.brain.apiKeyEnv || 'OPENROUTER_API_KEY';
401
+ await (0, promises_1.writeFile)(node_path_1.default.join(projectPath, '.env.example'), [
402
+ `${keyEnv}=`,
403
+ 'DATABASE_URL=postgresql://postgres:postgres@localhost:5432/siduri',
404
+ 'VTS_URL=ws://127.0.0.1:8001',
405
+ 'VTS_AUTH_TOKEN=',
406
+ '',
407
+ ].join('\n'), { mode: 0o600 });
408
+ await withTask('Installing Siduri runtime dependencies', () => execFile('npm', ['install', '--no-audit', '--no-fund'], { cwd: projectPath }).then(() => undefined));
409
+ printSuccess(`Siduri instance ready · ${projectPath}`);
410
+ console.log(`${colors.dim}Next: cd ${projectDirectoryName(answers.name)} && npm run start${colors.reset}\n`);
339
411
  }
340
412
  main().catch((error) => {
341
413
  if (error && typeof error === 'object' && 'name' in error && error.name === 'ExitPromptError') {