@vxnus/siduri 2.0.4 → 2.0.6
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/dist/builtin-manifests.js +2 -2
- package/dist/configurators/ear.js +8 -0
- package/dist/configurators/hands.js +16 -0
- package/dist/configurators/mouth.js +21 -1
- package/dist/configurators/observation.js +20 -0
- package/dist/configurators/vision.js +8 -0
- package/dist/configurators/voice.js +3 -117
- package/dist/configurators.test.js +45 -22
- package/dist/index.d.ts +1 -1
- package/dist/index.js +40 -45
- package/package.json +7 -7
|
@@ -382,7 +382,7 @@ exports.BUILTIN_ORGAN_MANIFESTS = [
|
|
|
382
382
|
organType: 'voice',
|
|
383
383
|
version: '2.0.2',
|
|
384
384
|
displayName: 'Voice (Speech Synthesis & Voice Conversion)',
|
|
385
|
-
description: 'Queued speech synthesis and audio rendering lifecycle adapter (
|
|
385
|
+
description: 'Queued speech synthesis and audio rendering lifecycle adapter (VOICEVOX, RVC)',
|
|
386
386
|
entrypoint: './dist/index.js',
|
|
387
387
|
factory: 'VoicevoxAdapter',
|
|
388
388
|
configKey: 'voice',
|
|
@@ -392,7 +392,7 @@ exports.BUILTIN_ORGAN_MANIFESTS = [
|
|
|
392
392
|
properties: {
|
|
393
393
|
provider: {
|
|
394
394
|
type: 'string',
|
|
395
|
-
enum: ['voicevox', 'none']
|
|
395
|
+
enum: ['voicevox', 'edge-tts', 'kokoro', 'piper', 'none']
|
|
396
396
|
},
|
|
397
397
|
speakerId: {
|
|
398
398
|
type: 'number',
|
|
@@ -13,8 +13,16 @@ async function configureEar(_context) {
|
|
|
13
13
|
choices: [
|
|
14
14
|
{ name: 'Text Chat (Standard multimodal chat ingress)', value: 'text_chat' },
|
|
15
15
|
{ name: 'Audio Streaming Ingress', value: 'audio_stream' },
|
|
16
|
+
{ name: 'None (Skip / Disable sensory ingress)', value: 'none' },
|
|
16
17
|
],
|
|
18
|
+
default: 'none',
|
|
17
19
|
});
|
|
20
|
+
if (defaultSource === 'none') {
|
|
21
|
+
return {
|
|
22
|
+
config: { provider: 'none' },
|
|
23
|
+
summary: { Provider: 'None (Ear disabled)' },
|
|
24
|
+
};
|
|
25
|
+
}
|
|
18
26
|
return {
|
|
19
27
|
config: {
|
|
20
28
|
defaultSource,
|
|
@@ -6,6 +6,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.configureHands = configureHands;
|
|
7
7
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
8
8
|
async function configureHands(_context) {
|
|
9
|
+
const { provider } = await inquirer_1.default.prompt({
|
|
10
|
+
type: 'list',
|
|
11
|
+
name: 'provider',
|
|
12
|
+
message: 'Hands tool execution engine?',
|
|
13
|
+
choices: [
|
|
14
|
+
{ name: 'MCP Client (Model Context Protocol & signed capability tokens)', value: 'mcp' },
|
|
15
|
+
{ name: 'None (Skip / No external tool execution)', value: 'none' },
|
|
16
|
+
],
|
|
17
|
+
default: 'none',
|
|
18
|
+
});
|
|
19
|
+
if (provider === 'none') {
|
|
20
|
+
return {
|
|
21
|
+
config: { provider: 'none' },
|
|
22
|
+
summary: { Provider: 'None (Hands disabled)' },
|
|
23
|
+
};
|
|
24
|
+
}
|
|
9
25
|
const { timeoutSeconds } = await inquirer_1.default.prompt({
|
|
10
26
|
type: 'input',
|
|
11
27
|
name: 'timeoutSeconds',
|
|
@@ -1,14 +1,34 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.configureMouth = configureMouth;
|
|
7
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
4
8
|
async function configureMouth(_context) {
|
|
9
|
+
const { provider } = await inquirer_1.default.prompt({
|
|
10
|
+
type: 'list',
|
|
11
|
+
name: 'provider',
|
|
12
|
+
message: 'Mouth output delivery channel?',
|
|
13
|
+
choices: [
|
|
14
|
+
{ name: 'Web Streaming (Server-Sent Events, Live2D visemes & SSML)', value: 'web' },
|
|
15
|
+
{ name: 'None (Silent / Disable speech streaming output)', value: 'none' },
|
|
16
|
+
],
|
|
17
|
+
default: 'web',
|
|
18
|
+
});
|
|
19
|
+
if (provider === 'none') {
|
|
20
|
+
return {
|
|
21
|
+
config: { provider: 'none' },
|
|
22
|
+
summary: { Provider: 'None (Mouth disabled)' },
|
|
23
|
+
};
|
|
24
|
+
}
|
|
5
25
|
return {
|
|
6
26
|
config: {
|
|
7
27
|
defaultMedium: 'web',
|
|
8
28
|
maxTextLength: 8000,
|
|
9
29
|
},
|
|
10
30
|
summary: {
|
|
11
|
-
'
|
|
31
|
+
'Delivery Medium': 'Web SSE Streaming',
|
|
12
32
|
'Max Text Length': '8000 chars',
|
|
13
33
|
},
|
|
14
34
|
};
|
|
@@ -1,7 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.configureObservation = configureObservation;
|
|
7
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
4
8
|
async function configureObservation(_context) {
|
|
9
|
+
const { provider } = await inquirer_1.default.prompt({
|
|
10
|
+
type: 'list',
|
|
11
|
+
name: 'provider',
|
|
12
|
+
message: 'Screen observation & frame capture?',
|
|
13
|
+
choices: [
|
|
14
|
+
{ name: 'Frame Ingest (SHA-256 deduplicated visual grounding for vision)', value: 'fixture' },
|
|
15
|
+
{ name: 'None (Skip / Disable screen observation)', value: 'none' },
|
|
16
|
+
],
|
|
17
|
+
default: 'none',
|
|
18
|
+
});
|
|
19
|
+
if (provider === 'none') {
|
|
20
|
+
return {
|
|
21
|
+
config: { provider: 'none' },
|
|
22
|
+
summary: { Provider: 'None (Observation disabled)' },
|
|
23
|
+
};
|
|
24
|
+
}
|
|
5
25
|
return {
|
|
6
26
|
config: {},
|
|
7
27
|
summary: {
|
|
@@ -14,8 +14,16 @@ async function configureVision(_context) {
|
|
|
14
14
|
{ name: 'GPT-4 Vision / GPT-4o (Multimodal OCR & Object Inspection)', value: 'gpt-4-vision' },
|
|
15
15
|
{ name: 'Claude 3.5 Sonnet Vision', value: 'anthropic/claude-3.5-sonnet' },
|
|
16
16
|
{ name: 'Custom Vision Model', value: 'custom' },
|
|
17
|
+
{ name: 'None (Skip / Disable visual perception)', value: 'none' },
|
|
17
18
|
],
|
|
19
|
+
default: 'none',
|
|
18
20
|
});
|
|
21
|
+
if (model === 'none') {
|
|
22
|
+
return {
|
|
23
|
+
config: { provider: 'none' },
|
|
24
|
+
summary: { Provider: 'None (Vision disabled)' },
|
|
25
|
+
};
|
|
26
|
+
}
|
|
19
27
|
let selectedModel = model;
|
|
20
28
|
if (model === 'custom') {
|
|
21
29
|
const { customModel } = await inquirer_1.default.prompt({
|
|
@@ -10,26 +10,14 @@ async function configureVoice(_context) {
|
|
|
10
10
|
const { provider } = await inquirer_1.default.prompt({
|
|
11
11
|
type: 'list',
|
|
12
12
|
name: 'provider',
|
|
13
|
-
message: 'Voice
|
|
13
|
+
message: 'Voice engine?',
|
|
14
14
|
choices: [
|
|
15
15
|
{
|
|
16
|
-
name: '
|
|
17
|
-
value: 'edge-tts',
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
name: 'VOICEVOX (Standard VOICEVOX stock character voice banks)',
|
|
16
|
+
name: 'VOICEVOX (Pre-trained character voice banks: Zundamon, Shikoku Metan, etc.)',
|
|
21
17
|
value: 'voicevox',
|
|
22
18
|
},
|
|
23
19
|
{
|
|
24
|
-
name: '
|
|
25
|
-
value: 'kokoro',
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
name: 'Piper TTS (Fast local neural TTS via HTTP/CLI)',
|
|
29
|
-
value: 'piper',
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
name: 'RVC (Custom user-owned voice model via .pth / .index weights)',
|
|
20
|
+
name: 'RVC (Custom character voice model via .pth / .index weights + Base TTS)',
|
|
33
21
|
value: 'rvc',
|
|
34
22
|
},
|
|
35
23
|
{
|
|
@@ -44,108 +32,6 @@ async function configureVoice(_context) {
|
|
|
44
32
|
summary: { Provider: 'None (Voice disabled)' },
|
|
45
33
|
};
|
|
46
34
|
}
|
|
47
|
-
if (provider === 'edge-tts') {
|
|
48
|
-
const edgeAnswers = await inquirer_1.default.prompt([
|
|
49
|
-
{
|
|
50
|
-
type: 'input',
|
|
51
|
-
name: 'voice',
|
|
52
|
-
message: 'Edge-TTS Voice Identifier (e.g. ja-JP-NanamiNeural, en-US-AriaNeural):',
|
|
53
|
-
default: 'ja-JP-NanamiNeural',
|
|
54
|
-
},
|
|
55
|
-
]);
|
|
56
|
-
const voice = edgeAnswers.voice.trim() || 'ja-JP-NanamiNeural';
|
|
57
|
-
return {
|
|
58
|
-
config: {
|
|
59
|
-
provider: 'edge-tts',
|
|
60
|
-
voice,
|
|
61
|
-
maxQueueDepth: 50,
|
|
62
|
-
},
|
|
63
|
-
summary: {
|
|
64
|
-
Provider: 'Edge-TTS (Cloud Neural)',
|
|
65
|
-
Voice: voice,
|
|
66
|
-
},
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
if (provider === 'kokoro') {
|
|
70
|
-
const kokoroAnswers = await inquirer_1.default.prompt([
|
|
71
|
-
{
|
|
72
|
-
type: 'input',
|
|
73
|
-
name: 'baseUrl',
|
|
74
|
-
message: 'Kokoro HTTP Base URL (leave empty if using local kokoro-tts CLI):',
|
|
75
|
-
default: 'http://localhost:8880',
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
type: 'input',
|
|
79
|
-
name: 'voice',
|
|
80
|
-
message: 'Kokoro Voice Name (e.g. af_bella, af_heart):',
|
|
81
|
-
default: 'af_bella',
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
type: 'input',
|
|
85
|
-
name: 'speed',
|
|
86
|
-
message: 'Speech Speed multiplier (e.g. 1.0):',
|
|
87
|
-
default: '1.0',
|
|
88
|
-
},
|
|
89
|
-
]);
|
|
90
|
-
const baseUrl = kokoroAnswers.baseUrl.trim() || undefined;
|
|
91
|
-
const voice = kokoroAnswers.voice.trim() || 'af_bella';
|
|
92
|
-
const speed = parseFloat(kokoroAnswers.speed) || 1.0;
|
|
93
|
-
return {
|
|
94
|
-
config: {
|
|
95
|
-
provider: 'kokoro',
|
|
96
|
-
baseUrl,
|
|
97
|
-
voice,
|
|
98
|
-
speed,
|
|
99
|
-
maxQueueDepth: 50,
|
|
100
|
-
},
|
|
101
|
-
summary: {
|
|
102
|
-
Provider: 'Kokoro TTS (Local / Server)',
|
|
103
|
-
Mode: baseUrl ? `HTTP (${baseUrl})` : 'CLI (kokoro-tts)',
|
|
104
|
-
Voice: voice,
|
|
105
|
-
Speed: speed,
|
|
106
|
-
},
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
if (provider === 'piper') {
|
|
110
|
-
const piperAnswers = await inquirer_1.default.prompt([
|
|
111
|
-
{
|
|
112
|
-
type: 'input',
|
|
113
|
-
name: 'baseUrl',
|
|
114
|
-
message: 'Piper HTTP Base URL (leave empty if using local piper CLI):',
|
|
115
|
-
default: 'http://localhost:5000',
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
type: 'input',
|
|
119
|
-
name: 'model',
|
|
120
|
-
message: 'Piper Model Path or Name (.onnx, optional):',
|
|
121
|
-
default: '',
|
|
122
|
-
},
|
|
123
|
-
{
|
|
124
|
-
type: 'input',
|
|
125
|
-
name: 'speakerId',
|
|
126
|
-
message: 'Piper Speaker ID (optional):',
|
|
127
|
-
default: '',
|
|
128
|
-
},
|
|
129
|
-
]);
|
|
130
|
-
const baseUrl = piperAnswers.baseUrl.trim() || undefined;
|
|
131
|
-
const model = piperAnswers.model.trim() || undefined;
|
|
132
|
-
const speakerId = piperAnswers.speakerId.trim() ? parseInt(piperAnswers.speakerId.trim(), 10) : undefined;
|
|
133
|
-
return {
|
|
134
|
-
config: {
|
|
135
|
-
provider: 'piper',
|
|
136
|
-
baseUrl,
|
|
137
|
-
model,
|
|
138
|
-
speakerId,
|
|
139
|
-
maxQueueDepth: 50,
|
|
140
|
-
},
|
|
141
|
-
summary: {
|
|
142
|
-
Provider: 'Piper TTS (Local / Server)',
|
|
143
|
-
Mode: baseUrl ? `HTTP (${baseUrl})` : 'CLI (piper)',
|
|
144
|
-
Model: model || 'default',
|
|
145
|
-
'Speaker ID': speakerId !== undefined ? speakerId : 'default',
|
|
146
|
-
},
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
35
|
if (provider === 'rvc') {
|
|
150
36
|
const rvcAnswers = await inquirer_1.default.prompt([
|
|
151
37
|
{
|
|
@@ -247,37 +247,45 @@ describe('Guided Manifest-Driven Configuration UX Specification Tests', () => {
|
|
|
247
247
|
expect(result.config.rvc.pitchShift).toBe(12);
|
|
248
248
|
expect(result.summary?.['Base TTS']).toBe('edge-tts');
|
|
249
249
|
});
|
|
250
|
-
test('Voice configurator
|
|
250
|
+
test('Voice configurator disables voice when none is selected', async () => {
|
|
251
251
|
inquirer_1.default.prompt
|
|
252
|
-
.mockResolvedValueOnce({ provider: '
|
|
253
|
-
.mockResolvedValueOnce({ voice: 'en-US-AriaNeural' });
|
|
252
|
+
.mockResolvedValueOnce({ provider: 'none' });
|
|
254
253
|
const result = await (0, voice_1.configureVoice)({ companionName: 'Sparkle', manifest: voiceManifest });
|
|
255
|
-
expect(result.config.provider).toBe('
|
|
256
|
-
expect(result.
|
|
257
|
-
expect(result.summary?.Provider).toBe('Edge-TTS (Cloud Neural)');
|
|
258
|
-
expect(result.summary?.Voice).toBe('en-US-AriaNeural');
|
|
254
|
+
expect(result.config.provider).toBe('none');
|
|
255
|
+
expect(result.summary?.Provider).toBe('None (Voice disabled)');
|
|
259
256
|
});
|
|
260
|
-
test('Voice configurator configures
|
|
257
|
+
test('Voice configurator configures RVC with Kokoro as Base TTS Engine', async () => {
|
|
261
258
|
inquirer_1.default.prompt
|
|
262
|
-
.mockResolvedValueOnce({ provider: '
|
|
263
|
-
.mockResolvedValueOnce({
|
|
259
|
+
.mockResolvedValueOnce({ provider: 'rvc' })
|
|
260
|
+
.mockResolvedValueOnce({
|
|
261
|
+
modelPath: './assets/voice/sparkle/sparkle.pth',
|
|
262
|
+
indexPath: './assets/voice/sparkle/sparkle.index',
|
|
263
|
+
pitchShift: '0',
|
|
264
|
+
f0Method: 'pm',
|
|
265
|
+
baseTts: 'kokoro',
|
|
266
|
+
serviceUrl: 'http://localhost:50055',
|
|
267
|
+
});
|
|
264
268
|
const result = await (0, voice_1.configureVoice)({ companionName: 'Sparkle', manifest: voiceManifest });
|
|
265
269
|
expect(result.config.provider).toBe('kokoro');
|
|
266
|
-
expect(result.config.
|
|
267
|
-
expect(result.
|
|
268
|
-
expect(result.config.speed).toBe(1.2);
|
|
269
|
-
expect(result.summary?.Provider).toBe('Kokoro TTS (Local / Server)');
|
|
270
|
+
expect(result.config.rvc.enabled).toBe(true);
|
|
271
|
+
expect(result.summary?.['Base TTS']).toBe('kokoro');
|
|
270
272
|
});
|
|
271
|
-
test('Voice configurator configures
|
|
273
|
+
test('Voice configurator configures RVC with Piper as Base TTS Engine', async () => {
|
|
272
274
|
inquirer_1.default.prompt
|
|
273
|
-
.mockResolvedValueOnce({ provider: '
|
|
274
|
-
.mockResolvedValueOnce({
|
|
275
|
+
.mockResolvedValueOnce({ provider: 'rvc' })
|
|
276
|
+
.mockResolvedValueOnce({
|
|
277
|
+
modelPath: './assets/voice/sparkle/sparkle.pth',
|
|
278
|
+
indexPath: '',
|
|
279
|
+
pitchShift: '-6',
|
|
280
|
+
f0Method: 'harvest',
|
|
281
|
+
baseTts: 'piper',
|
|
282
|
+
serviceUrl: 'http://localhost:50055',
|
|
283
|
+
});
|
|
275
284
|
const result = await (0, voice_1.configureVoice)({ companionName: 'Sparkle', manifest: voiceManifest });
|
|
276
285
|
expect(result.config.provider).toBe('piper');
|
|
277
|
-
expect(result.config.
|
|
278
|
-
expect(result.config.
|
|
279
|
-
expect(result.
|
|
280
|
-
expect(result.summary?.Provider).toBe('Piper TTS (Local / Server)');
|
|
286
|
+
expect(result.config.rvc.enabled).toBe(true);
|
|
287
|
+
expect(result.config.rvc.pitchShift).toBe(-6);
|
|
288
|
+
expect(result.summary?.['Base TTS']).toBe('piper');
|
|
281
289
|
});
|
|
282
290
|
test('Body configurator configures Live2D, custom model path, and expression', async () => {
|
|
283
291
|
inquirer_1.default.prompt
|
|
@@ -294,9 +302,18 @@ describe('Guided Manifest-Driven Configuration UX Specification Tests', () => {
|
|
|
294
302
|
expect(result.summary?.['Model Path']).toBe('./assets/body/sparkle/model.model3.json');
|
|
295
303
|
});
|
|
296
304
|
test('Hands configurator configures MCP tool execution timeout', async () => {
|
|
297
|
-
inquirer_1.default.prompt
|
|
305
|
+
inquirer_1.default.prompt
|
|
306
|
+
.mockResolvedValueOnce({ provider: 'mcp' })
|
|
307
|
+
.mockResolvedValueOnce({ timeoutSeconds: '15' });
|
|
298
308
|
const result = await (0, hands_1.configureHands)({ companionName: 'Sparkle', manifest: handsManifest });
|
|
299
309
|
expect(result.config.defaultTimeoutMs).toBe(15000);
|
|
310
|
+
expect(result.summary?.Provider).toBeUndefined();
|
|
311
|
+
});
|
|
312
|
+
test('Hands configurator disables tool execution when none is selected', async () => {
|
|
313
|
+
inquirer_1.default.prompt.mockResolvedValueOnce({ provider: 'none' });
|
|
314
|
+
const result = await (0, hands_1.configureHands)({ companionName: 'Sparkle', manifest: handsManifest });
|
|
315
|
+
expect(result.config.provider).toBe('none');
|
|
316
|
+
expect(result.summary?.Provider).toBe('None (Hands disabled)');
|
|
300
317
|
});
|
|
301
318
|
test('Behavior configurator configures active self personality preset', async () => {
|
|
302
319
|
inquirer_1.default.prompt.mockResolvedValueOnce({ preset: 'cheerful' });
|
|
@@ -310,6 +327,12 @@ describe('Guided Manifest-Driven Configuration UX Specification Tests', () => {
|
|
|
310
327
|
expect(result.config.provider).toBe('openrouter');
|
|
311
328
|
expect(result.config.model).toBe('gpt-4-vision');
|
|
312
329
|
});
|
|
330
|
+
test('Vision configurator disables vision when none is selected', async () => {
|
|
331
|
+
inquirer_1.default.prompt.mockResolvedValueOnce({ model: 'none' });
|
|
332
|
+
const result = await (0, vision_1.configureVision)({ companionName: 'Sparkle', manifest: visionManifest });
|
|
333
|
+
expect(result.config.provider).toBe('none');
|
|
334
|
+
expect(result.summary?.Provider).toBe('None (Vision disabled)');
|
|
335
|
+
});
|
|
313
336
|
});
|
|
314
337
|
describe('Review Summary Formatting & Generator Integration', () => {
|
|
315
338
|
test('formatReviewSummary displays actual configuration values and metadata', () => {
|
package/dist/index.d.ts
CHANGED
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.
|
|
29
|
+
exports.CLI_VERSION = '2.0.6';
|
|
30
30
|
exports.colors = {
|
|
31
31
|
cyan: '\u001b[36m',
|
|
32
32
|
dim: '\u001b[2m',
|
|
@@ -120,50 +120,21 @@ async function runCreateWizard(targetDir) {
|
|
|
120
120
|
]);
|
|
121
121
|
const companionName = basicAnswers.name;
|
|
122
122
|
const projectDir = targetDir ? node_path_1.default.resolve(process.cwd(), targetDir) : node_path_1.default.resolve(process.cwd(), projectDirectoryName(companionName));
|
|
123
|
-
printSection('Organ
|
|
124
|
-
console.log(`${exports.colors.dim}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const canonicalOrder = ['memory', 'knowledge', 'behavior', 'voice', 'body', 'mouth', 'hands', 'vision', 'ear', 'observation'];
|
|
129
|
-
const nonBrainManifests = availableManifests
|
|
130
|
-
.filter((m) => m.organType !== 'brain')
|
|
131
|
-
.sort((a, b) => {
|
|
123
|
+
printSection('Organ Configuration');
|
|
124
|
+
console.log(`${exports.colors.dim}Configuring capability organs for ${companionName} sequentially from cognition to physical embodiment.${exports.colors.reset}\n`);
|
|
125
|
+
// Canonical organ presentation order: Cognition -> Memory/State -> Identity -> Embodiment & Peripheral
|
|
126
|
+
const canonicalOrder = ['brain', 'memory', 'knowledge', 'behavior', 'voice', 'body', 'mouth', 'hands', 'vision', 'ear', 'observation'];
|
|
127
|
+
const orderedManifests = [...availableManifests].sort((a, b) => {
|
|
132
128
|
const idxA = canonicalOrder.indexOf(a.organType);
|
|
133
129
|
const idxB = canonicalOrder.indexOf(b.organType);
|
|
134
130
|
const valA = idxA === -1 ? 99 : idxA;
|
|
135
131
|
const valB = idxB === -1 ? 99 : idxB;
|
|
136
132
|
return valA - valB;
|
|
137
133
|
});
|
|
138
|
-
const isRecommendedType = (type) => ['memory', 'knowledge', 'behavior', 'voice', 'body', 'mouth'].includes(type);
|
|
139
|
-
const organChoices = nonBrainManifests.map((m) => ({
|
|
140
|
-
name: `${m.displayName} ${exports.colors.dim}— ${m.description}${exports.colors.reset}`,
|
|
141
|
-
value: m.organType,
|
|
142
|
-
checked: isRecommendedType(m.organType),
|
|
143
|
-
}));
|
|
144
|
-
const { selectedOrganTypes } = await inquirer_1.default.prompt({
|
|
145
|
-
type: 'checkbox',
|
|
146
|
-
name: 'selectedOrganTypes',
|
|
147
|
-
message: 'Select capability organs to enable:',
|
|
148
|
-
choices: organChoices,
|
|
149
|
-
});
|
|
150
134
|
const selectedManifests = [];
|
|
151
135
|
const organConfigs = {};
|
|
152
136
|
const organSummaries = {};
|
|
153
|
-
|
|
154
|
-
const brainManifest = registry.get('brain') || availableManifests.find((m) => m.organType === 'brain');
|
|
155
|
-
if (brainManifest) {
|
|
156
|
-
selectedManifests.push(brainManifest);
|
|
157
|
-
}
|
|
158
|
-
for (const organType of selectedOrganTypes) {
|
|
159
|
-
const m = registry.get(organType) || availableManifests.find((item) => item.organType === organType);
|
|
160
|
-
if (m)
|
|
161
|
-
selectedManifests.push(m);
|
|
162
|
-
}
|
|
163
|
-
// 2. Interactive Organ Configuration Stage
|
|
164
|
-
printSection('Organ Configuration');
|
|
165
|
-
console.log(`${exports.colors.dim}Configure each enabled organ for ${companionName}.${exports.colors.reset}\n`);
|
|
166
|
-
for (const m of selectedManifests) {
|
|
137
|
+
for (const m of orderedManifests) {
|
|
167
138
|
const isRequired = m.organType === 'brain';
|
|
168
139
|
const sectionTitle = isRequired ? `${m.displayName.split(' ')[0] || m.organType} · required` : m.displayName.split(' ')[0] || m.organType;
|
|
169
140
|
printSection(sectionTitle);
|
|
@@ -171,10 +142,14 @@ async function runCreateWizard(targetDir) {
|
|
|
171
142
|
companionName,
|
|
172
143
|
existingConfig: organConfigs[m.configKey],
|
|
173
144
|
});
|
|
145
|
+
if (res.config?.provider === 'none') {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
selectedManifests.push(m);
|
|
174
149
|
organConfigs[m.configKey] = res.config;
|
|
175
150
|
organSummaries[m.configKey] = res.summary || {};
|
|
176
151
|
}
|
|
177
|
-
//
|
|
152
|
+
// 2. Final Review and Edit Loop
|
|
178
153
|
while (true) {
|
|
179
154
|
console.log(formatReviewSummary(companionName, selectedManifests, organSummaries));
|
|
180
155
|
const { reviewAction } = await inquirer_1.default.prompt({
|
|
@@ -195,10 +170,13 @@ async function runCreateWizard(targetDir) {
|
|
|
195
170
|
break;
|
|
196
171
|
}
|
|
197
172
|
if (reviewAction === 'edit') {
|
|
198
|
-
const editChoices =
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
173
|
+
const editChoices = orderedManifests.map((m) => {
|
|
174
|
+
const isSelected = selectedManifests.some((sm) => sm.organType === m.organType);
|
|
175
|
+
return {
|
|
176
|
+
name: `${m.displayName} (${isSelected ? 'Enabled' : 'Disabled / Skipped'})`,
|
|
177
|
+
value: m.configKey,
|
|
178
|
+
};
|
|
179
|
+
});
|
|
202
180
|
editChoices.push({ name: 'Edit all organs in sequence', value: '__ALL__' });
|
|
203
181
|
editChoices.push({ name: 'Back to review', value: '__BACK__' });
|
|
204
182
|
const { organToEdit } = await inquirer_1.default.prompt({
|
|
@@ -211,8 +189,8 @@ async function runCreateWizard(targetDir) {
|
|
|
211
189
|
continue;
|
|
212
190
|
}
|
|
213
191
|
const organsToReconfigure = organToEdit === '__ALL__'
|
|
214
|
-
?
|
|
215
|
-
:
|
|
192
|
+
? orderedManifests
|
|
193
|
+
: orderedManifests.filter((m) => m.configKey === organToEdit);
|
|
216
194
|
for (const m of organsToReconfigure) {
|
|
217
195
|
const isRequired = m.organType === 'brain';
|
|
218
196
|
const sectionTitle = isRequired ? `${m.displayName.split(' ')[0] || m.organType} · required` : m.displayName.split(' ')[0] || m.organType;
|
|
@@ -221,8 +199,25 @@ async function runCreateWizard(targetDir) {
|
|
|
221
199
|
companionName,
|
|
222
200
|
existingConfig: organConfigs[m.configKey],
|
|
223
201
|
});
|
|
224
|
-
|
|
225
|
-
|
|
202
|
+
if (res.config?.provider === 'none') {
|
|
203
|
+
const idx = selectedManifests.findIndex((sm) => sm.organType === m.organType);
|
|
204
|
+
if (idx !== -1)
|
|
205
|
+
selectedManifests.splice(idx, 1);
|
|
206
|
+
delete organConfigs[m.configKey];
|
|
207
|
+
delete organSummaries[m.configKey];
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
if (!selectedManifests.some((sm) => sm.organType === m.organType)) {
|
|
211
|
+
selectedManifests.push(m);
|
|
212
|
+
selectedManifests.sort((a, b) => {
|
|
213
|
+
const idxA = canonicalOrder.indexOf(a.organType);
|
|
214
|
+
const idxB = canonicalOrder.indexOf(b.organType);
|
|
215
|
+
return (idxA === -1 ? 99 : idxA) - (idxB === -1 ? 99 : idxB);
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
organConfigs[m.configKey] = res.config;
|
|
219
|
+
organSummaries[m.configKey] = res.summary || {};
|
|
220
|
+
}
|
|
226
221
|
}
|
|
227
222
|
}
|
|
228
223
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vxnus/siduri",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.6",
|
|
4
4
|
"description": "Experimental CLI for installing and configuring Siduri companions",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -23,6 +23,11 @@
|
|
|
23
23
|
"siduri": "./dist/index.js"
|
|
24
24
|
},
|
|
25
25
|
"main": "dist/index.js",
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsc && node ./scripts/copy-web-dist.cjs",
|
|
28
|
+
"dev": "tsc -w",
|
|
29
|
+
"test": "jest --config jest.config.json"
|
|
30
|
+
},
|
|
26
31
|
"dependencies": {
|
|
27
32
|
"@vxnus/e": "^0.1.5",
|
|
28
33
|
"@vxnus/e-knowledge": "^0.1.5",
|
|
@@ -35,10 +40,5 @@
|
|
|
35
40
|
"ts-jest": "^29.4.12",
|
|
36
41
|
"typescript": "^5.9.3",
|
|
37
42
|
"@types/inquirer": "^9.0.10"
|
|
38
|
-
},
|
|
39
|
-
"scripts": {
|
|
40
|
-
"build": "tsc && node ./scripts/copy-web-dist.cjs",
|
|
41
|
-
"dev": "tsc -w",
|
|
42
|
-
"test": "jest --config jest.config.json"
|
|
43
43
|
}
|
|
44
|
-
}
|
|
44
|
+
}
|