@vxnus/siduri 0.0.2 → 0.0.4

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
@@ -5,11 +5,12 @@ Experimental CLI for creating and configuring Siduri companions.
5
5
  Requires Node.js 20 or newer.
6
6
 
7
7
  ```bash
8
- npx @vxnus/siduri@0.0.2 create
8
+ npx @vxnus/siduri@0.0.4 create
9
9
  ```
10
10
 
11
11
  The companion name becomes the project directory. For example, answering
12
- `Ganyu` creates `./ganyu/siduri.config.json` from the current directory.
12
+ `My Companion` creates `./my-companion/siduri.config.json` from the current
13
+ directory.
13
14
 
14
15
  The wizard configures the required Brain and Memory organs, then lets you
15
16
  enable or disable Voice, Knowledge, Behavior, Body, and Vision. Knowledge can
@@ -21,6 +22,10 @@ Brain providers:
21
22
  - **OpenAI-compatible API** — a custom `baseUrl`, model ID, and API-key
22
23
  environment variable.
23
24
 
25
+ Memory currently uses PostgreSQL. The wizard lets you choose Local PostgreSQL,
26
+ Neon, Supabase, or another PostgreSQL provider; all use `DATABASE_URL`. SQLite
27
+ is shown as a future option but is not selectable in this release.
28
+
24
29
  The wizard creates a project directory from the companion name, writes
25
30
  `siduri.config.json`, copies the Siduri runtime, and installs the runtime
26
31
  dependencies. API keys are never written to the configuration file. Optional
@@ -30,7 +35,7 @@ required.
30
35
  After setup, start the generated instance with:
31
36
 
32
37
  ```bash
33
- cd ganyu
38
+ cd my-companion
34
39
  npm run start
35
40
  ```
36
41
 
package/dist/index.js CHANGED
@@ -13,11 +13,11 @@ const node_util_1 = require("node:util");
13
13
  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
- const DEFAULT_REGISTRY_URL = 'https://e.vxnus.xyz/api/packs';
17
- const CLI_VERSION = '0.0.2';
16
+ const DEFAULT_REGISTRY_URL = 'https://e.vxnus.xyz/api/v1/knowledge';
17
+ const CLI_VERSION = '0.0.4';
18
18
  const RUNTIME_DEPENDENCIES = {
19
- '@vxnus/e': '^0.1.3',
20
- '@vxnus/e-knowledge': '^0.1.2',
19
+ '@vxnus/e': '^0.1.4',
20
+ '@vxnus/e-knowledge': '^0.1.4',
21
21
  cors: '^2.8.5',
22
22
  express: '^4.18.2',
23
23
  pg: '^8.23.0',
@@ -33,7 +33,7 @@ const colors = {
33
33
  };
34
34
  function printHeader() {
35
35
  console.log(`\n${colors.cyan}◈ SIDURI${colors.reset} ${colors.dim}companion setup${colors.reset}`);
36
- console.log(`${colors.yellow}Experimental release 0.0.2${colors.reset} · configuration may change\n`);
36
+ console.log(`${colors.yellow}Experimental release 0.0.4${colors.reset} · configuration may change\n`);
37
37
  }
38
38
  function printSection(title) {
39
39
  console.log(`\n${colors.cyan}── ${title} ${'─'.repeat(Math.max(2, 42 - title.length))}${colors.reset}`);
@@ -185,13 +185,13 @@ async function chooseHubPack(registryUrl) {
185
185
  const { query } = await inquirer_1.default.prompt({
186
186
  type: 'input',
187
187
  name: 'query',
188
- message: 'Search the Knowledge Hub or enter a package ID:',
188
+ message: 'Search E Knowledge Hub or enter package ID (e.g. @vxnus/e-teyvat):',
189
189
  });
190
190
  const normalized = query.trim().replace(/^@/, '');
191
191
  const [publisher, name] = normalized.split('/');
192
192
  const result = publisher && name && !query.includes(' ')
193
- ? await withTask('Searching Knowledge Hub', () => getJson(`${registryUrl}/${encodeURIComponent(publisher)}/${encodeURIComponent(name)}`))
194
- : await withTask('Searching Knowledge Hub', () => getJson(`${registryUrl}?q=${encodeURIComponent(query)}&limit=20`));
193
+ ? await withTask('Searching E Knowledge Hub', () => getJson(`${registryUrl}/${encodeURIComponent(publisher)}/${encodeURIComponent(name)}`))
194
+ : await withTask('Searching E Knowledge Hub', () => getJson(`${registryUrl}?q=${encodeURIComponent(query)}&limit=20`));
195
195
  const packs = 'packs' in result ? result.packs : [result];
196
196
  if (packs.length === 0)
197
197
  throw new Error(`No knowledge packs found for '${query}'`);
@@ -211,7 +211,7 @@ async function configureKnowledge() {
211
211
  name: 'mode',
212
212
  message: 'Knowledge source?',
213
213
  choices: [
214
- { name: 'Knowledge Hub', value: 'hub' },
214
+ { name: 'E Knowledge Hub', value: 'hub' },
215
215
  { name: 'Installed local pack', value: 'local' },
216
216
  { name: 'Hosted provider URL', value: 'remote' },
217
217
  { name: 'Do not use knowledge', value: 'none' },
@@ -238,18 +238,16 @@ async function configureKnowledge() {
238
238
  message: 'Remote knowledge provider URL:',
239
239
  });
240
240
  const provider = (0, e_knowledge_1.createRemoteProvider)({ baseUrl, timeoutMs: 5000 });
241
- const manifest = await withTask('Checking provider manifest', async () => provider.manifest());
241
+ const manifest = await withTask('Checking provider manifest', async () => {
242
+ if (!provider.manifest) {
243
+ throw new Error('Remote knowledge provider does not support manifest inspection');
244
+ }
245
+ return provider.manifest();
246
+ });
242
247
  printSuccess(`Provider ready · ${manifest.id}`);
243
248
  return { provider: 'e-remote', baseUrl: baseUrl.replace(/\/+$/, ''), timeoutMs: 5000 };
244
249
  }
245
- const { registryUrl: enteredRegistryUrl } = await inquirer_1.default.prompt({
246
- type: 'input',
247
- name: 'registryUrl',
248
- message: 'Knowledge Hub registry URL:',
249
- default: process.env.SIDURI_KNOWLEDGE_REGISTRY_URL || DEFAULT_REGISTRY_URL,
250
- validate: urlValue,
251
- });
252
- const registryUrl = enteredRegistryUrl.replace(/\/+$/, '');
250
+ const registryUrl = (process.env.E_REGISTRY_URL || process.env.SIDURI_KNOWLEDGE_REGISTRY_URL || DEFAULT_REGISTRY_URL).replace(/\/+$/, '');
253
251
  const pack = await chooseHubPack(registryUrl);
254
252
  if (pack.distribution.kind === 'archive') {
255
253
  const { install } = await inquirer_1.default.prompt({
@@ -269,7 +267,12 @@ async function configureKnowledge() {
269
267
  throw new Error('Archive installation was declined and no hosted provider is available');
270
268
  }
271
269
  const provider = (0, e_knowledge_1.createRemoteProvider)({ baseUrl: pack.distribution.url, timeoutMs: 5000 });
272
- await withTask('Checking provider manifest', async () => provider.manifest());
270
+ await withTask('Checking provider manifest', async () => {
271
+ if (!provider.manifest) {
272
+ throw new Error('Remote knowledge provider does not support manifest inspection');
273
+ }
274
+ return provider.manifest();
275
+ });
273
276
  printSuccess(`Provider ready · ${pack.id}`);
274
277
  return { provider: 'e-hub', registryUrl, packId: pack.id, timeoutMs: 5000 };
275
278
  }
@@ -294,11 +297,30 @@ async function main() {
294
297
  printSection('Companion');
295
298
  const answers = await inquirer_1.default.prompt([
296
299
  { type: 'input', name: 'name', message: 'Companion name:', default: 'Siduri', validate: nonEmpty },
297
- { type: 'list', name: 'memory', message: 'Memory provider?', choices: [{ name: 'PostgreSQL', value: 'postgres' }] },
300
+ {
301
+ type: 'list',
302
+ name: 'memoryEngine',
303
+ message: 'Memory database?',
304
+ choices: [
305
+ { name: 'PostgreSQL', value: 'postgres' },
306
+ { name: 'SQLite (future)', value: 'sqlite', disabled: 'Coming soon' },
307
+ ],
308
+ },
298
309
  ]);
310
+ const { memoryDeployment } = await inquirer_1.default.prompt({
311
+ type: 'list',
312
+ name: 'memoryDeployment',
313
+ message: 'PostgreSQL deployment?',
314
+ choices: [
315
+ { name: 'Local PostgreSQL', value: 'local' },
316
+ { name: 'Neon', value: 'neon' },
317
+ { name: 'Supabase', value: 'supabase' },
318
+ { name: 'Other PostgreSQL provider', value: 'other' },
319
+ ],
320
+ });
299
321
  const projectPath = node_path_1.default.resolve(process.cwd(), projectDirectoryName(answers.name));
300
322
  await (0, promises_1.mkdir)(projectPath, { recursive: true });
301
- printSuccess(`${answers.name} · PostgreSQL memory · ${projectPath}`);
323
+ printSuccess(`${answers.name} · PostgreSQL / ${memoryDeployment} · ${projectPath}`);
302
324
  printSection('Brain · required');
303
325
  const { brainProvider } = await inquirer_1.default.prompt({
304
326
  type: 'list',
@@ -337,7 +359,7 @@ async function main() {
337
359
  const knowledge = await configureKnowledge();
338
360
  const remaining = await inquirer_1.default.prompt([
339
361
  { type: 'list', name: 'behavior', message: 'Behavior preset?', choices: [{ name: 'Calm', value: 'Calm' }, { name: 'Cheerful, Encouraging', value: 'Cheerful, Encouraging' }, { name: 'Do not use custom behavior', value: 'none' }] },
340
- { type: 'list', name: 'body', message: 'Body provider?', choices: [{ name: 'VTube Studio / Live2D', value: 'live2d' }, { name: 'Do not use body', value: 'none' }] },
362
+ { type: 'list', name: 'body', message: 'Body provider?', choices: [{ name: 'Live2D Body (Renderer-agnostic)', value: 'live2d' }, { name: 'Do not use body', value: 'none' }] },
341
363
  { type: 'list', name: 'vision', message: 'Vision provider?', choices: [{ name: 'OpenRouter vision', value: 'openrouter' }, { name: 'Do not use vision', value: 'none' }] },
342
364
  ]);
343
365
  const config = {
@@ -345,10 +367,10 @@ async function main() {
345
367
  name: answers.name,
346
368
  brain,
347
369
  voice: { provider: voice, speakerId: 1 },
348
- memory: { provider: answers.memory },
370
+ memory: { provider: answers.memoryEngine, deployment: memoryDeployment },
349
371
  knowledge,
350
372
  behavior: { provider: remaining.behavior === 'none' ? 'none' : 'active_self', preset: remaining.behavior },
351
- body: { provider: remaining.body, vtsUrl: process.env.VTS_URL || 'ws://127.0.0.1:8001' },
373
+ body: { provider: remaining.body },
352
374
  vision: { provider: remaining.vision, model: 'gpt-4-vision' },
353
375
  };
354
376
  const configPath = node_path_1.default.join(projectPath, 'siduri.config.json');
@@ -401,8 +423,6 @@ async function main() {
401
423
  await (0, promises_1.writeFile)(node_path_1.default.join(projectPath, '.env.example'), [
402
424
  `${keyEnv}=`,
403
425
  'DATABASE_URL=postgresql://postgres:postgres@localhost:5432/siduri',
404
- 'VTS_URL=ws://127.0.0.1:8001',
405
- 'VTS_AUTH_TOKEN=',
406
426
  '',
407
427
  ].join('\n'), { mode: 0o600 });
408
428
  await withTask('Installing Siduri runtime dependencies', () => execFile('npm', ['install', '--no-audit', '--no-fund'], { cwd: projectPath }).then(() => undefined));