@vxnus/siduri 2.0.8 → 2.0.10

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.
@@ -22,24 +22,13 @@ async function configureBody(_context) {
22
22
  };
23
23
  }
24
24
  const companionSlug = _context.companionName.toLowerCase().replace(/[^a-z0-9_-]/g, '') || 'default';
25
- const { modelSource, initialExpression } = await inquirer_1.default.prompt([
25
+ const { modelSource } = await inquirer_1.default.prompt([
26
26
  {
27
27
  type: 'input',
28
28
  name: 'modelSource',
29
29
  message: 'Live2D Model path / URL (.model3.json):',
30
30
  default: `./assets/body/${companionSlug}/model.model3.json`,
31
31
  },
32
- {
33
- type: 'list',
34
- name: 'initialExpression',
35
- message: 'Initial avatar expression:',
36
- choices: [
37
- { name: 'Neutral', value: 'neutral' },
38
- { name: 'Happy / Cheerful', value: 'happy' },
39
- { name: 'Calm', value: 'calm' },
40
- ],
41
- default: 'neutral',
42
- },
43
32
  ]);
44
33
  const modelPath = modelSource.trim() || `./assets/body/${companionSlug}/model.model3.json`;
45
34
  const isHttpOrAbsolute = modelPath.startsWith('http://') || modelPath.startsWith('https://') || modelPath.startsWith('/');
@@ -49,12 +38,11 @@ async function configureBody(_context) {
49
38
  provider: 'live2d',
50
39
  modelPath,
51
40
  modelUrl: webModelUrl,
52
- initialExpression,
41
+ initialExpression: 'neutral',
53
42
  },
54
43
  summary: {
55
44
  Provider: 'Live2D',
56
45
  'Model Path': modelPath,
57
- Expression: initialExpression,
58
46
  },
59
47
  };
60
48
  }
@@ -6,18 +6,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.configureEar = configureEar;
7
7
  const inquirer_1 = __importDefault(require("inquirer"));
8
8
  async function configureEar(_context) {
9
- const { defaultSource } = await inquirer_1.default.prompt({
9
+ const { choice } = await inquirer_1.default.prompt({
10
10
  type: 'list',
11
- name: 'defaultSource',
12
- message: 'Perception ingress channel:',
11
+ name: 'choice',
12
+ message: 'Ear (Sensory Input & Perception Ingress):',
13
13
  choices: [
14
- { name: 'Text Chat (Standard multimodal chat ingress)', value: 'text_chat' },
15
- { name: 'Audio Streaming Ingress', value: 'audio_stream' },
16
- { name: 'None (Skip / Disable sensory ingress)', value: 'none' },
14
+ {
15
+ name: 'Enabled (Recommended: Active sensory bounds & audio/text ingress validation)',
16
+ value: 'enabled',
17
+ },
18
+ {
19
+ name: 'None (Skip / Disable sensory ingress)',
20
+ value: 'none',
21
+ },
17
22
  ],
18
- default: 'none',
23
+ default: 'enabled',
19
24
  });
20
- if (defaultSource === 'none') {
25
+ if (choice === 'none') {
21
26
  return {
22
27
  config: { provider: 'none' },
23
28
  summary: { Provider: 'None (Ear disabled)' },
@@ -25,12 +30,14 @@ async function configureEar(_context) {
25
30
  }
26
31
  return {
27
32
  config: {
28
- defaultSource,
33
+ defaultSource: 'text_chat',
29
34
  maxTextLength: 4000,
30
35
  maxAudioBytes: 10485760,
31
36
  },
32
37
  summary: {
33
- 'Default Ingress': defaultSource === 'text_chat' ? 'Text Chat' : 'Audio Stream',
38
+ Status: 'Enabled (Active sensory guard & audio/text ingress)',
39
+ 'Max Text': '4,000 characters',
40
+ 'Max Audio': '10 MB',
34
41
  },
35
42
  };
36
43
  }
@@ -9,23 +9,29 @@ async function configureObservation(_context) {
9
9
  const { provider } = await inquirer_1.default.prompt({
10
10
  type: 'list',
11
11
  name: 'provider',
12
- message: 'Screen observation & frame capture?',
12
+ message: 'Screen observation & continuous frame ingest:',
13
13
  choices: [
14
- { name: 'Frame Ingest (SHA-256 deduplicated visual grounding for vision)', value: 'fixture' },
15
- { name: 'None (Skip / Disable screen observation)', value: 'none' },
14
+ {
15
+ name: 'None (Disabled as default - Work in progress)',
16
+ value: 'none',
17
+ },
18
+ {
19
+ name: 'Experimental Frame Ingest (Prototype - requires active vision)',
20
+ value: 'fixture',
21
+ },
16
22
  ],
17
23
  default: 'none',
18
24
  });
19
25
  if (provider === 'none') {
20
26
  return {
21
27
  config: { provider: 'none' },
22
- summary: { Provider: 'None (Observation disabled)' },
28
+ summary: { Provider: 'Disabled (Work in progress)' },
23
29
  };
24
30
  }
25
31
  return {
26
32
  config: {},
27
33
  summary: {
28
- Provider: 'Grounded Observation Ingest',
34
+ Provider: 'Experimental Frame Ingest (Work in progress)',
29
35
  Deduplication: 'Cryptographic SHA-256 Hashing',
30
36
  },
31
37
  };
@@ -17,6 +17,8 @@ const body_1 = require("./configurators/body");
17
17
  const hands_1 = require("./configurators/hands");
18
18
  const behavior_1 = require("./configurators/behavior");
19
19
  const vision_1 = require("./configurators/vision");
20
+ const ear_1 = require("./configurators/ear");
21
+ const observation_1 = require("./configurators/observation");
20
22
  // Mock inquirer.prompt
21
23
  jest.mock('inquirer', () => ({
22
24
  prompt: jest.fn(),
@@ -32,6 +34,8 @@ describe('Guided Manifest-Driven Configuration UX Specification Tests', () => {
32
34
  const handsManifest = registry.get('hands');
33
35
  const behaviorManifest = registry.get('behavior');
34
36
  const visionManifest = registry.get('vision');
37
+ const earManifest = registry.get('ear');
38
+ const observationManifest = registry.get('observation');
35
39
  beforeEach(() => {
36
40
  jest.clearAllMocks();
37
41
  });
@@ -287,18 +291,17 @@ describe('Guided Manifest-Driven Configuration UX Specification Tests', () => {
287
291
  expect(result.config.rvc.pitchShift).toBe(-6);
288
292
  expect(result.summary?.['Base TTS']).toBe('piper');
289
293
  });
290
- test('Body configurator configures Live2D, custom model path, and expression', async () => {
294
+ test('Body configurator configures Live2D and custom model path', async () => {
291
295
  inquirer_1.default.prompt
292
296
  .mockResolvedValueOnce({ provider: 'live2d' })
293
297
  .mockResolvedValueOnce({
294
298
  modelSource: './assets/body/sparkle/model.model3.json',
295
- initialExpression: 'happy',
296
299
  });
297
300
  const result = await (0, body_1.configureBody)({ companionName: 'Sparkle', manifest: bodyManifest });
298
301
  expect(result.config.provider).toBe('live2d');
299
302
  expect(result.config.modelPath).toBe('./assets/body/sparkle/model.model3.json');
300
303
  expect(result.config.modelUrl).toBe('/assets/body/sparkle/model.model3.json');
301
- expect(result.config.initialExpression).toBe('happy');
304
+ expect(result.config.initialExpression).toBe('neutral');
302
305
  expect(result.summary?.['Model Path']).toBe('./assets/body/sparkle/model.model3.json');
303
306
  });
304
307
  test('Hands configurator configures MCP tool execution timeout', async () => {
@@ -348,6 +351,31 @@ describe('Guided Manifest-Driven Configuration UX Specification Tests', () => {
348
351
  expect(result.config.provider).toBe('none');
349
352
  expect(result.summary?.Provider).toBe('None (Vision disabled)');
350
353
  });
354
+ test('Ear configurator enables sensory bounds by default', async () => {
355
+ inquirer_1.default.prompt.mockResolvedValueOnce({ choice: 'enabled' });
356
+ const result = await (0, ear_1.configureEar)({ companionName: 'Sparkle', manifest: earManifest });
357
+ expect(result.config.defaultSource).toBe('text_chat');
358
+ expect(result.config.maxTextLength).toBe(4000);
359
+ expect(result.config.maxAudioBytes).toBe(10485760);
360
+ expect(result.summary?.Status).toContain('Enabled');
361
+ });
362
+ test('Ear configurator disables sensory ingress when none is selected', async () => {
363
+ inquirer_1.default.prompt.mockResolvedValueOnce({ choice: 'none' });
364
+ const result = await (0, ear_1.configureEar)({ companionName: 'Sparkle', manifest: earManifest });
365
+ expect(result.config.provider).toBe('none');
366
+ expect(result.summary?.Provider).toBe('None (Ear disabled)');
367
+ });
368
+ test('Observation configurator disables observation by default as work in progress', async () => {
369
+ inquirer_1.default.prompt.mockResolvedValueOnce({ provider: 'none' });
370
+ const result = await (0, observation_1.configureObservation)({ companionName: 'Sparkle', manifest: observationManifest });
371
+ expect(result.config.provider).toBe('none');
372
+ expect(result.summary?.Provider).toContain('Disabled (Work in progress)');
373
+ });
374
+ test('Observation configurator configures experimental fixture ingest when chosen', async () => {
375
+ inquirer_1.default.prompt.mockResolvedValueOnce({ provider: 'fixture' });
376
+ const result = await (0, observation_1.configureObservation)({ companionName: 'Sparkle', manifest: observationManifest });
377
+ expect(result.summary?.Provider).toContain('Work in progress');
378
+ });
351
379
  });
352
380
  describe('Review Summary Formatting & Generator Integration', () => {
353
381
  test('formatReviewSummary displays actual configuration values and metadata', () => {
package/dist/generator.js CHANGED
@@ -81,6 +81,7 @@ function generateInstanceFiles(options) {
81
81
  const hasVoice = manifests.some((m) => m.organType === 'voice');
82
82
  const hasBody = manifests.some((m) => m.organType === 'body');
83
83
  const hasMouth = manifests.some((m) => m.organType === 'mouth');
84
+ const hasVision = manifests.some((m) => m.organType === 'vision');
84
85
  const voiceConfig = options.organConfigs?.voice || options.organConfigs?.['@siduri-x/voice'];
85
86
  const isVoicevox = hasVoice && (!voiceConfig || voiceConfig.provider === 'voicevox');
86
87
  // 1. package.json
@@ -209,6 +210,11 @@ function generateInstanceFiles(options) {
209
210
  instantiationLines.push(`const knowledge = new ${m.factory}({ ...config.organs.${m.configKey}, dbPath: path.resolve(rootDir, config.organs.${m.configKey}?.dbPath || 'siduri.sqlite') });`);
210
211
  organMapEntries.push(` ${m.configKey},`);
211
212
  }
213
+ else if (m.name === '@siduri-x/observation') {
214
+ const visionArg = hasVision ? 'vision' : '{ analyze: async () => JSON.stringify({ readings: [] }) }';
215
+ instantiationLines.push(`const observation = new ${m.factory}(${visionArg});`);
216
+ organMapEntries.push(` ${m.configKey},`);
217
+ }
212
218
  else {
213
219
  const varName = m.configKey;
214
220
  instantiationLines.push(`const ${varName} = new ${m.factory}(config.organs.${m.configKey});`);
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { OrganManifest } from './manifest';
3
- export declare const CLI_VERSION = "2.0.8";
3
+ export declare const CLI_VERSION = "2.0.10";
4
4
  import { colors } from './colors';
5
5
  export { colors };
6
6
  export declare function printHeader(): void;
package/dist/index.js CHANGED
@@ -26,7 +26,7 @@ const doctor_1 = require("./doctor");
26
26
  const db_1 = require("./db");
27
27
  const configurators_1 = require("./configurators");
28
28
  const execFile = (0, node_util_1.promisify)(node_child_process_1.execFile);
29
- exports.CLI_VERSION = '2.0.8';
29
+ exports.CLI_VERSION = '2.0.10';
30
30
  const colors_1 = require("./colors");
31
31
  Object.defineProperty(exports, "colors", { enumerable: true, get: function () { return colors_1.colors; } });
32
32
  function printHeader() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vxnus/siduri",
3
- "version": "2.0.8",
3
+ "version": "2.0.10",
4
4
  "description": "Experimental CLI for installing and configuring Siduri companions",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {