@vxnus/siduri 2.0.35 → 2.0.37
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/configurators/behavior.js +1 -3
- package/dist/configurators/body.js +7 -4
- package/dist/configurators/voice.js +5 -6
- package/dist/configurators.test.js +13 -1
- package/dist/generator.js +12 -13
- package/dist/generator.test.js +4 -4
- package/dist/index.d.ts +3 -2
- package/dist/index.js +61 -29
- package/dist/project-dir.test.d.ts +1 -0
- package/dist/project-dir.test.js +37 -0
- package/dist/web-template.js +3 -3
- package/package.json +7 -7
|
@@ -6,8 +6,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.configureBehavior = configureBehavior;
|
|
7
7
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
8
8
|
async function configureBehavior(_context) {
|
|
9
|
-
const companionName = _context.companionName || 'Companion';
|
|
10
|
-
const companionSlug = companionName.toLowerCase().replace(/[^a-z0-9_-]/g, '') || 'default';
|
|
11
9
|
const { personaMode } = await inquirer_1.default.prompt({
|
|
12
10
|
type: 'list',
|
|
13
11
|
name: 'personaMode',
|
|
@@ -59,7 +57,7 @@ async function configureBehavior(_context) {
|
|
|
59
57
|
const archetype = personaAnswers.archetype.trim() || 'Knowledge Assistant & Research Partner';
|
|
60
58
|
const ethos = personaAnswers.ethos.trim() || 'Direct technical candor, thoughtful, concise, and loyal';
|
|
61
59
|
const directive = personaAnswers.directive.trim() || 'Speak concisely and stay in character without sycophantic filler';
|
|
62
|
-
const selfPath =
|
|
60
|
+
const selfPath = './assets/self/default.self';
|
|
63
61
|
return {
|
|
64
62
|
config: {
|
|
65
63
|
provider: 'active_self',
|
|
@@ -21,18 +21,21 @@ async function configureBody(_context) {
|
|
|
21
21
|
summary: { Provider: 'None (Headless)' },
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
|
-
const companionSlug = _context.companionName.toLowerCase().replace(/[^a-z0-9_-]/g, '') || 'default';
|
|
25
24
|
const { modelSource } = await inquirer_1.default.prompt([
|
|
26
25
|
{
|
|
27
26
|
type: 'input',
|
|
28
27
|
name: 'modelSource',
|
|
29
28
|
message: 'Live2D Model path / URL (.model3.json):',
|
|
30
|
-
default:
|
|
29
|
+
default: './assets/body/default/model.model3.json',
|
|
31
30
|
},
|
|
32
31
|
]);
|
|
33
|
-
const modelPath = modelSource.trim() ||
|
|
32
|
+
const modelPath = modelSource.trim() || './assets/body/default/model.model3.json';
|
|
34
33
|
const isHttpOrAbsolute = modelPath.startsWith('http://') || modelPath.startsWith('https://') || modelPath.startsWith('/');
|
|
35
|
-
const webModelUrl = isHttpOrAbsolute
|
|
34
|
+
const webModelUrl = isHttpOrAbsolute
|
|
35
|
+
? modelPath
|
|
36
|
+
: modelPath.startsWith('./')
|
|
37
|
+
? modelPath.slice(1)
|
|
38
|
+
: `/${modelPath}`;
|
|
36
39
|
return {
|
|
37
40
|
config: {
|
|
38
41
|
provider: 'live2d',
|
|
@@ -7,7 +7,6 @@ exports.configureVoice = configureVoice;
|
|
|
7
7
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
8
8
|
const colors_1 = require("../colors");
|
|
9
9
|
async function configureVoice(_context) {
|
|
10
|
-
const companionSlug = _context.companionName.toLowerCase().replace(/[^a-z0-9_-]/g, '') || 'default';
|
|
11
10
|
const { provider } = await inquirer_1.default.prompt({
|
|
12
11
|
type: 'list',
|
|
13
12
|
name: 'provider',
|
|
@@ -35,21 +34,21 @@ async function configureVoice(_context) {
|
|
|
35
34
|
}
|
|
36
35
|
if (provider === 'rvc') {
|
|
37
36
|
console.log(`\n ${colors_1.colors.cyan}ℹ RVC Voice Model Setup:${colors_1.colors.reset}`);
|
|
38
|
-
console.log(` • ${colors_1.colors.dim}Voice Weights:${colors_1.colors.reset} Place your trained weights (.pth) in: ${colors_1.colors.green}./assets/voice
|
|
39
|
-
console.log(` • ${colors_1.colors.dim}Feature Index:${colors_1.colors.reset} Place optional .index in: ${colors_1.colors.green}./assets/voice
|
|
37
|
+
console.log(` • ${colors_1.colors.dim}Voice Weights:${colors_1.colors.reset} Place your trained weights (.pth) in: ${colors_1.colors.green}./assets/voice/default/default.pth${colors_1.colors.reset}`);
|
|
38
|
+
console.log(` • ${colors_1.colors.dim}Feature Index:${colors_1.colors.reset} Place optional .index in: ${colors_1.colors.green}./assets/voice/default/default.index${colors_1.colors.reset}`);
|
|
40
39
|
console.log(` • ${colors_1.colors.dim}RVC Service:${colors_1.colors.reset} Ensure your headless RVC microservice is running before voice inference.\n`);
|
|
41
40
|
const rvcAnswers = await inquirer_1.default.prompt([
|
|
42
41
|
{
|
|
43
42
|
type: 'input',
|
|
44
43
|
name: 'modelPath',
|
|
45
44
|
message: 'RVC Model Path (.pth weights):',
|
|
46
|
-
default:
|
|
45
|
+
default: './assets/voice/default/default.pth',
|
|
47
46
|
},
|
|
48
47
|
{
|
|
49
48
|
type: 'input',
|
|
50
49
|
name: 'indexPath',
|
|
51
50
|
message: 'RVC Feature Index Path (.index, optional):',
|
|
52
|
-
default:
|
|
51
|
+
default: './assets/voice/default/default.index',
|
|
53
52
|
},
|
|
54
53
|
{
|
|
55
54
|
type: 'input',
|
|
@@ -90,7 +89,7 @@ async function configureVoice(_context) {
|
|
|
90
89
|
rvc: {
|
|
91
90
|
enabled: true,
|
|
92
91
|
serviceUrl: rvcAnswers.serviceUrl.trim(),
|
|
93
|
-
modelName:
|
|
92
|
+
modelName: 'default',
|
|
94
93
|
modelPath: rvcAnswers.modelPath.trim(),
|
|
95
94
|
indexPath: rvcAnswers.indexPath.trim() || undefined,
|
|
96
95
|
pitchShift,
|
|
@@ -304,6 +304,18 @@ describe('Guided Manifest-Driven Configuration UX Specification Tests', () => {
|
|
|
304
304
|
expect(result.config.initialExpression).toBe('neutral');
|
|
305
305
|
expect(result.summary?.['Model Path']).toBe('./assets/body/sparkle/model.model3.json');
|
|
306
306
|
});
|
|
307
|
+
test('Body configurator defaults model path to assets/body/default', async () => {
|
|
308
|
+
inquirer_1.default.prompt
|
|
309
|
+
.mockResolvedValueOnce({ provider: 'live2d' })
|
|
310
|
+
.mockResolvedValueOnce({
|
|
311
|
+
modelSource: '',
|
|
312
|
+
});
|
|
313
|
+
const result = await (0, body_1.configureBody)({ companionName: 'MyCompanion', manifest: bodyManifest });
|
|
314
|
+
expect(result.config.provider).toBe('live2d');
|
|
315
|
+
expect(result.config.modelPath).toBe('./assets/body/default/model.model3.json');
|
|
316
|
+
expect(result.config.modelUrl).toBe('/assets/body/default/model.model3.json');
|
|
317
|
+
expect(result.summary?.['Model Path']).toBe('./assets/body/default/model.model3.json');
|
|
318
|
+
});
|
|
307
319
|
test('Hands configurator configures MCP tool execution timeout', async () => {
|
|
308
320
|
inquirer_1.default.prompt
|
|
309
321
|
.mockResolvedValueOnce({ provider: 'mcp' })
|
|
@@ -337,7 +349,7 @@ describe('Guided Manifest-Driven Configuration UX Specification Tests', () => {
|
|
|
337
349
|
expect(result.config.provider).toBe('active_self');
|
|
338
350
|
expect(result.config.mode).toBe('custom');
|
|
339
351
|
expect(result.config.archetype).toBe('System Sentinel');
|
|
340
|
-
expect(result.config.selfPath).toBe('./assets/self/
|
|
352
|
+
expect(result.config.selfPath).toBe('./assets/self/default.self');
|
|
341
353
|
});
|
|
342
354
|
test('Vision configurator configures OpenRouter vision model', async () => {
|
|
343
355
|
inquirer_1.default.prompt.mockResolvedValueOnce({ model: 'gpt-4-vision' });
|
package/dist/generator.js
CHANGED
|
@@ -73,10 +73,9 @@ function getDefaultConfigForManifest(manifest) {
|
|
|
73
73
|
}
|
|
74
74
|
function generateInstanceFiles(options) {
|
|
75
75
|
const instanceName = options.name || 'my-siduri';
|
|
76
|
-
const companionSlug = instanceName.toLowerCase().replace(/[^a-z0-9_-]/g, '') || 'default';
|
|
77
76
|
const instanceId = options.id || 'default';
|
|
78
77
|
const coreVersion = options.coreVersion || '^2.0.15';
|
|
79
|
-
const cliVersion = options.cliVersion || '^2.0.
|
|
78
|
+
const cliVersion = options.cliVersion || '^2.0.37';
|
|
80
79
|
const canonicalOrder = ['brain', 'memory', 'knowledge', 'behavior', 'voice', 'body', 'mouth', 'hands', 'vision', 'ear', 'observation'];
|
|
81
80
|
const manifests = [...options.selectedManifests].sort((a, b) => {
|
|
82
81
|
const idxA = canonicalOrder.indexOf(a.organType);
|
|
@@ -204,13 +203,13 @@ function generateInstanceFiles(options) {
|
|
|
204
203
|
if (m.name === '@siduri-x/self') {
|
|
205
204
|
instantiationLines.push(`const self = new SqliteSelfRepository({ dbPath: path.resolve(rootDir, 'siduri.sqlite') });`);
|
|
206
205
|
instantiationLines.push(`const behavior = new ActiveSelfCompiler(config.organs.behavior);`);
|
|
207
|
-
instantiationLines.push(`const selfFile = path.resolve(rootDir, config.organs.behavior?.selfPath || 'assets/self
|
|
206
|
+
instantiationLines.push(`const selfFile = path.resolve(rootDir, config.organs.behavior?.selfPath || 'assets/self/default.self');`);
|
|
208
207
|
instantiationLines.push(`try {`);
|
|
209
208
|
instantiationLines.push(` const selfRaw = await readFile(selfFile, 'utf8').catch(() => null);`);
|
|
210
209
|
instantiationLines.push(` if (selfRaw) {`);
|
|
211
210
|
instantiationLines.push(` const parsedSelf = SelfPackageParser.parse(selfRaw);`);
|
|
212
211
|
instantiationLines.push(` if (parsedSelf.isValid && parsedSelf.manifest) {`);
|
|
213
|
-
instantiationLines.push(` await self.setIdentity({ companionId: config.id || 'default', name: parsedSelf.manifest.identity?.name ||
|
|
212
|
+
instantiationLines.push(` await self.setIdentity({ companionId: config.id || 'default', name: parsedSelf.manifest.identity?.name || '', archetype: parsedSelf.manifest.identity?.archetype, version: parsedSelf.manifest.version || '1.0.0', updatedAt: new Date().toISOString() });`);
|
|
214
213
|
instantiationLines.push(` if (parsedSelf.manifest.directives) {`);
|
|
215
214
|
instantiationLines.push(` await self.commitDirectives(config.id || 'default', parsedSelf.manifest.directives.map((d) => ({ id: d.id, companionId: config.id || 'default', directive: d.directive, category: (d.category || 'behavioral'), status: 'active', priority: d.priority || 50, createdAt: new Date().toISOString() })));`);
|
|
216
215
|
instantiationLines.push(` }`);
|
|
@@ -337,7 +336,7 @@ function generateInstanceFiles(options) {
|
|
|
337
336
|
` res.end(JSON.stringify({`,
|
|
338
337
|
` id: config.id,`,
|
|
339
338
|
` companionId: config.id,`,
|
|
340
|
-
` name: identity?.name ||
|
|
339
|
+
` name: identity?.name || undefined,`,
|
|
341
340
|
` archetype: identity?.archetype || identity?.role,`,
|
|
342
341
|
` origin: identity?.origin,`,
|
|
343
342
|
` ethos: identity?.ethos,`,
|
|
@@ -849,12 +848,12 @@ function generateInstanceFiles(options) {
|
|
|
849
848
|
readmeLines.push('', '### 3. Diagnostics & Health Probe', 'Verify all environment variables, schema conformance, services, and organ connections:', '```bash', 'npm run doctor', '```', '', '### 4. Start Companion & Web Console', 'Launch your companion runtime and Web UI / Memory Control Panel:', '```bash', 'npm start', '```', 'Then open `http://localhost:3000` in your browser.');
|
|
850
849
|
const createAssetsDirs = [];
|
|
851
850
|
if (hasBody) {
|
|
852
|
-
createAssetsDirs.push(
|
|
853
|
-
readmeLines.push('', '### Body & Avatar Models',
|
|
851
|
+
createAssetsDirs.push('assets/body/default');
|
|
852
|
+
readmeLines.push('', '### Body & Avatar Models', 'Place your Live2D Cubism model assets into `./assets/body/default/`:', '- `model.model3.json`', '- `model.moc3`', '- textures directory');
|
|
854
853
|
}
|
|
855
854
|
if (hasVoice) {
|
|
856
|
-
createAssetsDirs.push(
|
|
857
|
-
readmeLines.push('', '### Voice & RVC Models',
|
|
855
|
+
createAssetsDirs.push('assets/voice/default');
|
|
856
|
+
readmeLines.push('', '### Voice & RVC Models', 'Place your character RVC voice models into `./assets/voice/default/`:', '- `default.pth` (Target voice weights)', '- `default.index` (Feature index file)');
|
|
858
857
|
}
|
|
859
858
|
const knowledgeConfig = options.organConfigs?.knowledge || options.organConfigs?.['@siduri-x/knowledge'];
|
|
860
859
|
if (manifests.some((m) => m.organType === 'knowledge') && knowledgeConfig?.packPath) {
|
|
@@ -867,19 +866,19 @@ function generateInstanceFiles(options) {
|
|
|
867
866
|
if (manifests.some((m) => m.organType === 'behavior')) {
|
|
868
867
|
createAssetsDirs.push('assets/self');
|
|
869
868
|
if (behaviorConfig?.mode === 'custom' || behaviorConfig?.archetype) {
|
|
870
|
-
const selfRelPath =
|
|
869
|
+
const selfRelPath = 'assets/self/default.self';
|
|
871
870
|
const selfContent = [
|
|
872
871
|
`specVersion: "2.0.0"`,
|
|
873
872
|
`kind: "self"`,
|
|
874
|
-
`id: "
|
|
875
|
-
`name: "
|
|
873
|
+
`id: "default-self"`,
|
|
874
|
+
`name: "Default Persona"`,
|
|
876
875
|
`version: "1.0.0"`,
|
|
877
876
|
`author:`,
|
|
878
877
|
` name: "Operator"`,
|
|
879
878
|
`license: "MIT"`,
|
|
880
879
|
``,
|
|
881
880
|
`identity:`,
|
|
882
|
-
` name: "${
|
|
881
|
+
` name: "${(behaviorConfig.name || behaviorConfig.companionName || '').replace(/"/g, '\\"')}"`,
|
|
883
882
|
` archetype: "${(behaviorConfig.archetype || 'Knowledge Assistant & Research Partner').replace(/"/g, '\\"')}"`,
|
|
884
883
|
` origin: "Constructed companion"`,
|
|
885
884
|
` ethos: "${(behaviorConfig.ethos || 'Direct technical candor, thoughtful, concise, and loyal').replace(/"/g, '\\"')}"`,
|
package/dist/generator.test.js
CHANGED
|
@@ -154,11 +154,11 @@ describe('Instance Generator Composition Invariants (Phase 3)', () => {
|
|
|
154
154
|
expect(pkg.dependencies['@siduri-x/voice']).toBeDefined();
|
|
155
155
|
// Body & voice asset directories requested
|
|
156
156
|
expect(files.createAssetsBodyDir).toBe(true);
|
|
157
|
-
expect(files.createAssetsDirs).toContain('assets/body/
|
|
158
|
-
expect(files.createAssetsDirs).toContain('assets/voice/
|
|
157
|
+
expect(files.createAssetsDirs).toContain('assets/body/default');
|
|
158
|
+
expect(files.createAssetsDirs).toContain('assets/voice/default');
|
|
159
159
|
// README mentions Live2D model assets & prerequisites
|
|
160
|
-
expect(files['README.md']).toContain('assets/body/
|
|
161
|
-
expect(files['README.md']).toContain('assets/voice/
|
|
160
|
+
expect(files['README.md']).toContain('assets/body/default');
|
|
161
|
+
expect(files['README.md']).toContain('assets/voice/default');
|
|
162
162
|
expect(files['README.md']).toContain('Prerequisites');
|
|
163
163
|
// No docker compose generated (Docker completely removed, host-native runtime)
|
|
164
164
|
expect(files['docker-compose.yml']).toBeUndefined();
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { OrganManifest } from './manifest';
|
|
3
|
-
export declare const CLI_VERSION = "2.0.
|
|
3
|
+
export declare const CLI_VERSION = "2.0.37";
|
|
4
4
|
import { colors } from './colors';
|
|
5
5
|
export { colors };
|
|
6
6
|
export declare function printHeader(): void;
|
|
7
7
|
export declare function printSection(title: string): void;
|
|
8
8
|
export declare function printSuccess(message: string): void;
|
|
9
9
|
export declare function projectDirectoryName(value: string): string;
|
|
10
|
-
export declare function
|
|
10
|
+
export declare function validateProjectDirectory(value: string): true | string;
|
|
11
|
+
export declare function formatReviewSummary(projectDirName: string, selectedManifests: OrganManifest[], organSummaries: Record<string, Record<string, unknown>>): string;
|
|
11
12
|
export declare function withTask<T>(label: string, task: () => Promise<T>): Promise<T>;
|
|
12
13
|
export declare function runCreateWizard(targetDir?: string, options?: {
|
|
13
14
|
localPath?: string;
|
package/dist/index.js
CHANGED
|
@@ -42,6 +42,7 @@ exports.printHeader = printHeader;
|
|
|
42
42
|
exports.printSection = printSection;
|
|
43
43
|
exports.printSuccess = printSuccess;
|
|
44
44
|
exports.projectDirectoryName = projectDirectoryName;
|
|
45
|
+
exports.validateProjectDirectory = validateProjectDirectory;
|
|
45
46
|
exports.formatReviewSummary = formatReviewSummary;
|
|
46
47
|
exports.withTask = withTask;
|
|
47
48
|
exports.runCreateWizard = runCreateWizard;
|
|
@@ -60,7 +61,7 @@ const doctor_1 = require("./doctor");
|
|
|
60
61
|
const db_1 = require("./db");
|
|
61
62
|
const configurators_1 = require("./configurators");
|
|
62
63
|
const execFile = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
63
|
-
exports.CLI_VERSION = '2.0.
|
|
64
|
+
exports.CLI_VERSION = '2.0.37';
|
|
64
65
|
const colors_1 = require("./colors");
|
|
65
66
|
Object.defineProperty(exports, "colors", { enumerable: true, get: function () { return colors_1.colors; } });
|
|
66
67
|
function printHeader() {
|
|
@@ -74,18 +75,27 @@ function printSuccess(message) {
|
|
|
74
75
|
console.log(`${colors_1.colors.green}✓${colors_1.colors.reset} ${message}`);
|
|
75
76
|
}
|
|
76
77
|
function projectDirectoryName(value) {
|
|
77
|
-
|
|
78
|
-
.trim()
|
|
79
|
-
.toLowerCase()
|
|
80
|
-
.replace(/[^a-z0-9]+/g, '-')
|
|
81
|
-
.replace(/^-+|-+$/g, '');
|
|
82
|
-
return slug || 'siduri';
|
|
78
|
+
return (value || '').trim() || 'Companion';
|
|
83
79
|
}
|
|
84
|
-
function
|
|
80
|
+
function validateProjectDirectory(value) {
|
|
81
|
+
const trimmed = (value || '').trim();
|
|
82
|
+
if (!trimmed) {
|
|
83
|
+
return 'Please enter a project directory.';
|
|
84
|
+
}
|
|
85
|
+
if (/^\d+$/.test(trimmed) || !isNaN(Number(trimmed))) {
|
|
86
|
+
return 'Project directory cannot be a number.';
|
|
87
|
+
}
|
|
88
|
+
const resolved = node_path_1.default.resolve(process.cwd(), trimmed);
|
|
89
|
+
if (node_fs_1.default.existsSync(resolved)) {
|
|
90
|
+
return `Directory "${trimmed}" already exists in the current directory.`;
|
|
91
|
+
}
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
function formatReviewSummary(projectDirName, selectedManifests, organSummaries) {
|
|
85
95
|
const lines = [];
|
|
86
|
-
lines.push(`\n${colors_1.colors.cyan}── Review ${
|
|
87
|
-
lines.push(` ${colors_1.colors.bold}
|
|
88
|
-
lines.push(` ${colors_1.colors.dim}
|
|
96
|
+
lines.push(`\n${colors_1.colors.cyan}── Review ${projectDirName} ${'─'.repeat(Math.max(2, 42 - (projectDirName.length + 9)))}${colors_1.colors.reset}\n`);
|
|
97
|
+
lines.push(` ${colors_1.colors.bold}Project${colors_1.colors.reset}`);
|
|
98
|
+
lines.push(` ${colors_1.colors.dim}Directory:${colors_1.colors.reset} ${projectDirName}\n`);
|
|
89
99
|
for (const m of selectedManifests) {
|
|
90
100
|
const isRequired = m.organType === 'brain';
|
|
91
101
|
const tag = isRequired ? ` ${colors_1.colors.dim}· required${colors_1.colors.reset}` : '';
|
|
@@ -136,20 +146,42 @@ async function runCreateWizard(targetDir, options) {
|
|
|
136
146
|
if (availableManifests.length === 0) {
|
|
137
147
|
throw new Error('No @siduri-x/* organ packages found. Please ensure organs are installed or in workspace.');
|
|
138
148
|
}
|
|
139
|
-
printSection('
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
default
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
149
|
+
printSection('Project Details');
|
|
150
|
+
let projectDirName;
|
|
151
|
+
if (targetDir) {
|
|
152
|
+
const check = validateProjectDirectory(targetDir);
|
|
153
|
+
if (check !== true) {
|
|
154
|
+
console.warn(`${colors_1.colors.yellow}!${colors_1.colors.reset} Provided directory "${targetDir}" is invalid: ${check}\n`);
|
|
155
|
+
const dirAnswers = await inquirer_1.default.prompt([
|
|
156
|
+
{
|
|
157
|
+
type: 'input',
|
|
158
|
+
name: 'directory',
|
|
159
|
+
message: 'Project directory:',
|
|
160
|
+
default: 'Companion',
|
|
161
|
+
validate: validateProjectDirectory,
|
|
162
|
+
},
|
|
163
|
+
]);
|
|
164
|
+
projectDirName = dirAnswers.directory.trim();
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
projectDirName = targetDir.trim();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
const dirAnswers = await inquirer_1.default.prompt([
|
|
172
|
+
{
|
|
173
|
+
type: 'input',
|
|
174
|
+
name: 'directory',
|
|
175
|
+
message: 'Project directory:',
|
|
176
|
+
default: 'Companion',
|
|
177
|
+
validate: validateProjectDirectory,
|
|
178
|
+
},
|
|
179
|
+
]);
|
|
180
|
+
projectDirName = dirAnswers.directory.trim();
|
|
181
|
+
}
|
|
182
|
+
const projectDir = node_path_1.default.resolve(process.cwd(), projectDirName);
|
|
151
183
|
printSection('Organ Configuration');
|
|
152
|
-
console.log(`${colors_1.colors.dim}Configuring capability organs for ${
|
|
184
|
+
console.log(`${colors_1.colors.dim}Configuring capability organs for ${projectDirName} sequentially from cognition to physical embodiment.${colors_1.colors.reset}\n`);
|
|
153
185
|
// Canonical organ presentation order: Cognition -> Memory/State -> Identity -> Embodiment & Peripheral
|
|
154
186
|
const canonicalOrder = ['brain', 'memory', 'knowledge', 'behavior', 'voice', 'body', 'mouth', 'hands', 'vision', 'ear', 'observation'];
|
|
155
187
|
const orderedManifests = [...availableManifests].sort((a, b) => {
|
|
@@ -167,7 +199,7 @@ async function runCreateWizard(targetDir, options) {
|
|
|
167
199
|
const sectionTitle = isRequired ? `${m.displayName.split(' ')[0] || m.organType} · required` : m.displayName.split(' ')[0] || m.organType;
|
|
168
200
|
printSection(sectionTitle);
|
|
169
201
|
const res = await (0, configurators_1.configureOrgan)(m, {
|
|
170
|
-
companionName,
|
|
202
|
+
companionName: projectDirName,
|
|
171
203
|
existingConfig: organConfigs[m.configKey],
|
|
172
204
|
});
|
|
173
205
|
if (res.config?.provider === 'none') {
|
|
@@ -179,11 +211,11 @@ async function runCreateWizard(targetDir, options) {
|
|
|
179
211
|
}
|
|
180
212
|
// 2. Final Review and Edit Loop
|
|
181
213
|
while (true) {
|
|
182
|
-
console.log(formatReviewSummary(
|
|
214
|
+
console.log(formatReviewSummary(projectDirName, selectedManifests, organSummaries));
|
|
183
215
|
const { reviewAction } = await inquirer_1.default.prompt({
|
|
184
216
|
type: 'list',
|
|
185
217
|
name: 'reviewAction',
|
|
186
|
-
message: `Create ${
|
|
218
|
+
message: `Create ${projectDirName} with this configuration?`,
|
|
187
219
|
choices: [
|
|
188
220
|
{ name: 'Yes, create', value: 'create' },
|
|
189
221
|
{ name: 'Go back and edit', value: 'edit' },
|
|
@@ -224,7 +256,7 @@ async function runCreateWizard(targetDir, options) {
|
|
|
224
256
|
const sectionTitle = isRequired ? `${m.displayName.split(' ')[0] || m.organType} · required` : m.displayName.split(' ')[0] || m.organType;
|
|
225
257
|
printSection(sectionTitle);
|
|
226
258
|
const res = await (0, configurators_1.configureOrgan)(m, {
|
|
227
|
-
companionName,
|
|
259
|
+
companionName: projectDirName,
|
|
228
260
|
existingConfig: organConfigs[m.configKey],
|
|
229
261
|
});
|
|
230
262
|
if (res.config?.provider === 'none') {
|
|
@@ -251,7 +283,7 @@ async function runCreateWizard(targetDir, options) {
|
|
|
251
283
|
}
|
|
252
284
|
// 4. Generate Instance Files
|
|
253
285
|
const files = (0, generator_1.generateInstanceFiles)({
|
|
254
|
-
name:
|
|
286
|
+
name: projectDirName,
|
|
255
287
|
selectedManifests,
|
|
256
288
|
organConfigs,
|
|
257
289
|
localPath: options?.localPath,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
jest.mock('inquirer', () => ({
|
|
4
|
+
prompt: jest.fn(),
|
|
5
|
+
Separator: jest.fn((label) => ({ type: 'separator', line: label })),
|
|
6
|
+
}));
|
|
7
|
+
const index_1 = require("./index");
|
|
8
|
+
describe('Project Directory Validation & Handling', () => {
|
|
9
|
+
test('rejects empty or whitespace-only directory names', () => {
|
|
10
|
+
expect((0, index_1.validateProjectDirectory)('')).toBe('Please enter a project directory.');
|
|
11
|
+
expect((0, index_1.validateProjectDirectory)(' ')).toBe('Please enter a project directory.');
|
|
12
|
+
});
|
|
13
|
+
test('rejects purely numeric directory names', () => {
|
|
14
|
+
expect((0, index_1.validateProjectDirectory)('123')).toBe('Project directory cannot be a number.');
|
|
15
|
+
expect((0, index_1.validateProjectDirectory)('0')).toBe('Project directory cannot be a number.');
|
|
16
|
+
expect((0, index_1.validateProjectDirectory)('42')).toBe('Project directory cannot be a number.');
|
|
17
|
+
expect((0, index_1.validateProjectDirectory)('999999')).toBe('Project directory cannot be a number.');
|
|
18
|
+
});
|
|
19
|
+
test('rejects directory names that already exist in cwd', () => {
|
|
20
|
+
// 'src' definitely exists in cli working directory
|
|
21
|
+
const result = (0, index_1.validateProjectDirectory)('src');
|
|
22
|
+
expect(result).toBe('Directory "src" already exists in the current directory.');
|
|
23
|
+
});
|
|
24
|
+
test('accepts valid non-kebab-case directory names', () => {
|
|
25
|
+
const nonExistentDir = 'CompanionTestDir_' + Date.now();
|
|
26
|
+
expect((0, index_1.validateProjectDirectory)(nonExistentDir)).toBe(true);
|
|
27
|
+
const privateCompanion = 'PrivateCompanion_' + Date.now();
|
|
28
|
+
expect((0, index_1.validateProjectDirectory)(privateCompanion)).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
test('projectDirectoryName preserves casing without forcing kebab-case', () => {
|
|
31
|
+
expect((0, index_1.projectDirectoryName)('Companion')).toBe('Companion');
|
|
32
|
+
expect((0, index_1.projectDirectoryName)('PrivateCompanion')).toBe('PrivateCompanion');
|
|
33
|
+
expect((0, index_1.projectDirectoryName)('MySpecialCompanion')).toBe('MySpecialCompanion');
|
|
34
|
+
expect((0, index_1.projectDirectoryName)(' TrimmedCompanion ')).toBe('TrimmedCompanion');
|
|
35
|
+
expect((0, index_1.projectDirectoryName)('')).toBe('Companion');
|
|
36
|
+
});
|
|
37
|
+
});
|
package/dist/web-template.js
CHANGED
|
@@ -324,7 +324,7 @@ function generateWebHtml(instanceName, manifests) {
|
|
|
324
324
|
<header>
|
|
325
325
|
<div class="brand">
|
|
326
326
|
<h1>◈ SIDURI</h1>
|
|
327
|
-
<span id="companion-display-name" style="font-weight: 600; color: #fff;"
|
|
327
|
+
<span id="companion-display-name" style="font-weight: 600; color: #fff;">Companion</span>
|
|
328
328
|
<div class="badges">
|
|
329
329
|
${organBadges}
|
|
330
330
|
</div>
|
|
@@ -350,7 +350,7 @@ function generateWebHtml(instanceName, manifests) {
|
|
|
350
350
|
<div class="chat-pane">
|
|
351
351
|
<div id="messages" class="messages-container">
|
|
352
352
|
<div class="message companion">
|
|
353
|
-
<div class="meta companion-meta"
|
|
353
|
+
<div class="meta companion-meta">Companion</div>
|
|
354
354
|
Hello! I am your Siduri companion. How can I help you today?
|
|
355
355
|
</div>
|
|
356
356
|
</div>
|
|
@@ -415,7 +415,7 @@ function generateWebHtml(instanceName, manifests) {
|
|
|
415
415
|
|
|
416
416
|
<script>
|
|
417
417
|
let currentClaims = [];
|
|
418
|
-
let companionName = '
|
|
418
|
+
let companionName = 'Companion';
|
|
419
419
|
|
|
420
420
|
function updateCompanionName(newName) {
|
|
421
421
|
if (!newName || typeof newName !== 'string' || !newName.trim()) return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vxnus/siduri",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.37",
|
|
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
|
+
}
|