@vxnus/siduri 0.0.1 → 0.0.3

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,45 @@
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.3 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
+ Memory currently uses PostgreSQL. The wizard lets you choose Local PostgreSQL,
25
+ Neon, Supabase, or another PostgreSQL provider; all use `DATABASE_URL`. SQLite
26
+ is shown as a future option but is not selectable in this release.
27
+
28
+ The wizard creates a project directory from the companion name, writes
29
+ `siduri.config.json`, copies the Siduri runtime, and installs the runtime
30
+ dependencies. API keys are never written to the configuration file. Optional
31
+ organs can be configured as `{ "provider": "none" }`; Brain and Memory remain
32
+ required.
33
+
34
+ After setup, start the generated instance with:
35
+
36
+ ```bash
37
+ cd ganyu
38
+ npm run start
39
+ ```
40
+
41
+ For local development, build the CLI from the repository root with
42
+ `pnpm --filter @vxnus/siduri build`. For the full architecture, see the
43
+ [CLI documentation](../docs/cli.md) and
44
+ [configuration reference](../docs/configuration.md).
45
+
13
46
  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.3';
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.3${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
  }
@@ -242,9 +294,30 @@ async function main() {
242
294
  printSection('Companion');
243
295
  const answers = await inquirer_1.default.prompt([
244
296
  { type: 'input', name: 'name', message: 'Companion name:', default: 'Siduri', validate: nonEmpty },
245
- { type: 'list', name: 'memory', message: 'Memory provider?', choices: [{ name: 'PostgreSQL', value: 'postgres' }] },
297
+ {
298
+ type: 'list',
299
+ name: 'memoryEngine',
300
+ message: 'Memory database?',
301
+ choices: [
302
+ { name: 'PostgreSQL', value: 'postgres' },
303
+ { name: 'SQLite (future)', value: 'sqlite', disabled: 'Coming soon' },
304
+ ],
305
+ },
246
306
  ]);
247
- printSuccess(`${answers.name} · PostgreSQL memory`);
307
+ const { memoryDeployment } = await inquirer_1.default.prompt({
308
+ type: 'list',
309
+ name: 'memoryDeployment',
310
+ message: 'PostgreSQL deployment?',
311
+ choices: [
312
+ { name: 'Local PostgreSQL', value: 'local' },
313
+ { name: 'Neon', value: 'neon' },
314
+ { name: 'Supabase', value: 'supabase' },
315
+ { name: 'Other PostgreSQL provider', value: 'other' },
316
+ ],
317
+ });
318
+ const projectPath = node_path_1.default.resolve(process.cwd(), projectDirectoryName(answers.name));
319
+ await (0, promises_1.mkdir)(projectPath, { recursive: true });
320
+ printSuccess(`${answers.name} · PostgreSQL / ${memoryDeployment} · ${projectPath}`);
248
321
  printSection('Brain · required');
249
322
  const { brainProvider } = await inquirer_1.default.prompt({
250
323
  type: 'list',
@@ -291,13 +364,13 @@ async function main() {
291
364
  name: answers.name,
292
365
  brain,
293
366
  voice: { provider: voice, speakerId: 1 },
294
- memory: { provider: answers.memory },
367
+ memory: { provider: answers.memoryEngine, deployment: memoryDeployment },
295
368
  knowledge,
296
369
  behavior: { provider: remaining.behavior === 'none' ? 'none' : 'active_self', preset: remaining.behavior },
297
370
  body: { provider: remaining.body, vtsUrl: process.env.VTS_URL || 'ws://127.0.0.1:8001' },
298
371
  vision: { provider: remaining.vision, model: 'gpt-4-vision' },
299
372
  };
300
- const configPath = node_path_1.default.join(process.cwd(), 'siduri.config.json');
373
+ const configPath = node_path_1.default.join(projectPath, 'siduri.config.json');
301
374
  try {
302
375
  await (0, promises_1.readFile)(configPath, 'utf8');
303
376
  const { overwrite } = await inquirer_1.default.prompt({
@@ -335,7 +408,25 @@ async function main() {
335
408
  }
336
409
  await (0, promises_1.writeFile)(configPath, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
337
410
  printSuccess(`Configuration written · ${configPath}`);
338
- console.log(`${colors.dim}Next: start Siduri with pnpm --filter @siduri-y/api dev${colors.reset}\n`);
411
+ await (0, promises_1.cp)(node_path_1.default.join(__dirname, 'runtime.js'), node_path_1.default.join(projectPath, 'siduri-runtime.js'));
412
+ await (0, promises_1.writeFile)(node_path_1.default.join(projectPath, 'package.json'), JSON.stringify({
413
+ name: projectDirectoryName(answers.name),
414
+ private: true,
415
+ version: '0.0.0',
416
+ scripts: { start: 'node siduri-runtime.js', dev: 'node siduri-runtime.js' },
417
+ dependencies: RUNTIME_DEPENDENCIES,
418
+ }, null, 2) + '\n', { mode: 0o600 });
419
+ const keyEnv = config.brain.apiKeyEnv || 'OPENROUTER_API_KEY';
420
+ await (0, promises_1.writeFile)(node_path_1.default.join(projectPath, '.env.example'), [
421
+ `${keyEnv}=`,
422
+ 'DATABASE_URL=postgresql://postgres:postgres@localhost:5432/siduri',
423
+ 'VTS_URL=ws://127.0.0.1:8001',
424
+ 'VTS_AUTH_TOKEN=',
425
+ '',
426
+ ].join('\n'), { mode: 0o600 });
427
+ await withTask('Installing Siduri runtime dependencies', () => execFile('npm', ['install', '--no-audit', '--no-fund'], { cwd: projectPath }).then(() => undefined));
428
+ printSuccess(`Siduri instance ready · ${projectPath}`);
429
+ console.log(`${colors.dim}Next: cd ${projectDirectoryName(answers.name)} && npm run start${colors.reset}\n`);
339
430
  }
340
431
  main().catch((error) => {
341
432
  if (error && typeof error === 'object' && 'name' in error && error.name === 'ExitPromptError') {