@vxnus/siduri 2.0.37 → 2.0.38
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 +1 -1
- package/dist/generator.js +188 -3
- package/dist/generator.test.js +42 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +20 -1
- package/package.json +1 -1
|
@@ -5,7 +5,7 @@ exports.BUILTIN_ORGAN_MANIFESTS = [
|
|
|
5
5
|
{
|
|
6
6
|
name: '@siduri-x/self',
|
|
7
7
|
organType: 'behavior',
|
|
8
|
-
version: '2.0.
|
|
8
|
+
version: '2.0.11',
|
|
9
9
|
displayName: 'Self & Persona (Identity & Directives)',
|
|
10
10
|
description: 'Autonomous persona compiler, relational stances, and .self asset loader',
|
|
11
11
|
entrypoint: './dist/index.js',
|
package/dist/generator.js
CHANGED
|
@@ -75,7 +75,7 @@ function generateInstanceFiles(options) {
|
|
|
75
75
|
const instanceName = options.name || 'my-siduri';
|
|
76
76
|
const instanceId = options.id || 'default';
|
|
77
77
|
const coreVersion = options.coreVersion || '^2.0.15';
|
|
78
|
-
const cliVersion = options.cliVersion || '^2.0.
|
|
78
|
+
const cliVersion = options.cliVersion || '^2.0.38';
|
|
79
79
|
const canonicalOrder = ['brain', 'memory', 'knowledge', 'behavior', 'voice', 'body', 'mouth', 'hands', 'vision', 'ear', 'observation'];
|
|
80
80
|
const manifests = [...options.selectedManifests].sort((a, b) => {
|
|
81
81
|
const idxA = canonicalOrder.indexOf(a.organType);
|
|
@@ -191,7 +191,7 @@ function generateInstanceFiles(options) {
|
|
|
191
191
|
];
|
|
192
192
|
for (const m of manifests) {
|
|
193
193
|
if (m.name === '@siduri-x/self') {
|
|
194
|
-
importLines.push(`import { ActiveSelfCompiler, SqliteSelfRepository, SelfPackageParser } from '@siduri-x/self';`);
|
|
194
|
+
importLines.push(`import { ActiveSelfCompiler, SqliteSelfRepository, SelfPackageParser, scanDirective } from '@siduri-x/self';`);
|
|
195
195
|
}
|
|
196
196
|
else {
|
|
197
197
|
importLines.push(`import { ${m.factory} } from '${m.name}';`);
|
|
@@ -346,6 +346,191 @@ function generateInstanceFiles(options) {
|
|
|
346
346
|
` return;`,
|
|
347
347
|
` }`,
|
|
348
348
|
'',
|
|
349
|
+
` // API: Teach Mode detected-self`,
|
|
350
|
+
` if (pathname === '/teach/detected-self' && req.method === 'GET') {`,
|
|
351
|
+
` res.writeHead(200, { 'Content-Type': 'application/json' });`,
|
|
352
|
+
` if (typeof SelfPackageParser === 'undefined') {`,
|
|
353
|
+
` res.end(JSON.stringify({ detected: false }));`,
|
|
354
|
+
` return;`,
|
|
355
|
+
` }`,
|
|
356
|
+
` try {`,
|
|
357
|
+
` const companionId = parsedUrl.searchParams.get('companionId') || config.id || 'default';`,
|
|
358
|
+
` const explicitPath = parsedUrl.searchParams.get('path');`,
|
|
359
|
+
` const envPath = process.env.SIDURI_SELF_PATH || process.env.SELF_PATH;`,
|
|
360
|
+
` const configPath = config.organs?.behavior?.selfPath;`,
|
|
361
|
+
` const candidates = [];`,
|
|
362
|
+
` if (explicitPath) candidates.push(path.resolve(rootDir, explicitPath));`,
|
|
363
|
+
` if (envPath) candidates.push(path.resolve(rootDir, envPath));`,
|
|
364
|
+
` if (configPath) candidates.push(path.resolve(rootDir, configPath));`,
|
|
365
|
+
` candidates.push(path.resolve(rootDir, 'assets', 'self', companionId + '.self'));`,
|
|
366
|
+
` candidates.push(path.resolve(rootDir, 'assets', 'self', 'default.self'));`,
|
|
367
|
+
` candidates.push(path.resolve(rootDir, companionId + '.self'));`,
|
|
368
|
+
'',
|
|
369
|
+
` const searchDirs = [`,
|
|
370
|
+
` path.resolve(rootDir, 'assets', 'self'),`,
|
|
371
|
+
` path.resolve(rootDir, 'assets'),`,
|
|
372
|
+
` path.resolve(rootDir),`,
|
|
373
|
+
` ];`,
|
|
374
|
+
'',
|
|
375
|
+
` let matchedFilePath = null;`,
|
|
376
|
+
` for (const candidate of candidates) {`,
|
|
377
|
+
` try {`,
|
|
378
|
+
` const s = await stat(candidate);`,
|
|
379
|
+
` if (s.isFile()) {`,
|
|
380
|
+
` matchedFilePath = candidate;`,
|
|
381
|
+
` break;`,
|
|
382
|
+
` }`,
|
|
383
|
+
` } catch {}`,
|
|
384
|
+
` }`,
|
|
385
|
+
'',
|
|
386
|
+
` if (!matchedFilePath) {`,
|
|
387
|
+
` for (const dir of searchDirs) {`,
|
|
388
|
+
` try {`,
|
|
389
|
+
` const entries = await readdir(dir);`,
|
|
390
|
+
` const selfFiles = entries.filter((f) => f.endsWith('.self'));`,
|
|
391
|
+
` if (selfFiles.length > 0) {`,
|
|
392
|
+
` const companionSelf = selfFiles.find((f) => f === companionId + '.self');`,
|
|
393
|
+
` matchedFilePath = path.join(dir, companionSelf || selfFiles[0]);`,
|
|
394
|
+
` break;`,
|
|
395
|
+
` }`,
|
|
396
|
+
` } catch {}`,
|
|
397
|
+
` }`,
|
|
398
|
+
` }`,
|
|
399
|
+
'',
|
|
400
|
+
` if (!matchedFilePath) {`,
|
|
401
|
+
` res.end(JSON.stringify({ detected: false }));`,
|
|
402
|
+
` return;`,
|
|
403
|
+
` }`,
|
|
404
|
+
'',
|
|
405
|
+
` const content = await readFile(matchedFilePath, 'utf8');`,
|
|
406
|
+
` const parsed = SelfPackageParser.parse(content);`,
|
|
407
|
+
` let alreadyInstalled = false;`,
|
|
408
|
+
` if (typeof self?.getIdentity === 'function') {`,
|
|
409
|
+
` try {`,
|
|
410
|
+
` const existingIdentity = await self.getIdentity(companionId);`,
|
|
411
|
+
` const existingDirectives = await self.getActiveDirectives(companionId);`,
|
|
412
|
+
` if (`,
|
|
413
|
+
` existingIdentity &&`,
|
|
414
|
+
` parsed.manifest?.identity?.name &&`,
|
|
415
|
+
` existingIdentity.name.toLowerCase() === parsed.manifest.identity.name.toLowerCase() &&`,
|
|
416
|
+
` existingDirectives.length > 0`,
|
|
417
|
+
` ) {`,
|
|
418
|
+
` alreadyInstalled = true;`,
|
|
419
|
+
` }`,
|
|
420
|
+
` } catch {}`,
|
|
421
|
+
` }`,
|
|
422
|
+
'',
|
|
423
|
+
` res.end(JSON.stringify({`,
|
|
424
|
+
` detected: true,`,
|
|
425
|
+
` filename: path.basename(matchedFilePath),`,
|
|
426
|
+
` path: path.relative(rootDir, matchedFilePath),`,
|
|
427
|
+
` content,`,
|
|
428
|
+
` parsed,`,
|
|
429
|
+
` alreadyInstalled,`,
|
|
430
|
+
` }));`,
|
|
431
|
+
` } catch (err) {`,
|
|
432
|
+
` res.end(JSON.stringify({ detected: false, error: err.message }));`,
|
|
433
|
+
` }`,
|
|
434
|
+
` return;`,
|
|
435
|
+
` }`,
|
|
436
|
+
'',
|
|
437
|
+
` // API: Teach Mode upload-self`,
|
|
438
|
+
` if (pathname === '/teach/upload-self' && req.method === 'POST') {`,
|
|
439
|
+
` let body = '';`,
|
|
440
|
+
` req.on('data', (chunk) => { body += chunk; });`,
|
|
441
|
+
` req.on('end', async () => {`,
|
|
442
|
+
` if (typeof SelfPackageParser === 'undefined') {`,
|
|
443
|
+
` res.writeHead(400, { 'Content-Type': 'application/json' });`,
|
|
444
|
+
` res.end(JSON.stringify({ error: 'Self organ is not configured' }));`,
|
|
445
|
+
` return;`,
|
|
446
|
+
` }`,
|
|
447
|
+
` try {`,
|
|
448
|
+
` const { content } = JSON.parse(body || '{}');`,
|
|
449
|
+
` if (!content) {`,
|
|
450
|
+
` res.writeHead(400, { 'Content-Type': 'application/json' });`,
|
|
451
|
+
` res.end(JSON.stringify({ error: 'Missing content' }));`,
|
|
452
|
+
` return;`,
|
|
453
|
+
` }`,
|
|
454
|
+
` const parsed = SelfPackageParser.parse(content);`,
|
|
455
|
+
` res.writeHead(200, { 'Content-Type': 'application/json' });`,
|
|
456
|
+
` res.end(JSON.stringify(parsed));`,
|
|
457
|
+
` } catch (err) {`,
|
|
458
|
+
` res.writeHead(500, { 'Content-Type': 'application/json' });`,
|
|
459
|
+
` res.end(JSON.stringify({ error: err.message }));`,
|
|
460
|
+
` }`,
|
|
461
|
+
` });`,
|
|
462
|
+
` return;`,
|
|
463
|
+
` }`,
|
|
464
|
+
'',
|
|
465
|
+
` // API: Teach Mode install-self`,
|
|
466
|
+
` if (pathname === '/teach/install-self' && req.method === 'POST') {`,
|
|
467
|
+
` let body = '';`,
|
|
468
|
+
` req.on('data', (chunk) => { body += chunk; });`,
|
|
469
|
+
` req.on('end', async () => {`,
|
|
470
|
+
` if (typeof self === 'undefined' || typeof self?.setIdentity !== 'function') {`,
|
|
471
|
+
` res.writeHead(400, { 'Content-Type': 'application/json' });`,
|
|
472
|
+
` res.end(JSON.stringify({ error: 'Self organ is not configured' }));`,
|
|
473
|
+
` return;`,
|
|
474
|
+
` }`,
|
|
475
|
+
` try {`,
|
|
476
|
+
` const { companionId, manifest, approvedDirectiveIds } = JSON.parse(body || '{}');`,
|
|
477
|
+
` const cid = companionId || config.id || 'default';`,
|
|
478
|
+
` if (!manifest || !Array.isArray(approvedDirectiveIds)) {`,
|
|
479
|
+
` res.writeHead(400, { 'Content-Type': 'application/json' });`,
|
|
480
|
+
` res.end(JSON.stringify({ error: 'Missing required fields' }));`,
|
|
481
|
+
` return;`,
|
|
482
|
+
` }`,
|
|
483
|
+
` if (!manifest.identity || !manifest.identity.name) {`,
|
|
484
|
+
` res.writeHead(400, { 'Content-Type': 'application/json' });`,
|
|
485
|
+
` res.end(JSON.stringify({ error: 'Invalid manifest: missing identity.name' }));`,
|
|
486
|
+
` return;`,
|
|
487
|
+
` }`,
|
|
488
|
+
` const directivesToCommit = manifest.directives?.filter((d) => approvedDirectiveIds.includes(d.id)) || [];`,
|
|
489
|
+
` for (const d of directivesToCommit) {`,
|
|
490
|
+
` if (!d || typeof d.directive !== 'string') {`,
|
|
491
|
+
` res.writeHead(400, { 'Content-Type': 'application/json' });`,
|
|
492
|
+
` res.end(JSON.stringify({ error: 'Invalid directive entry: missing directive string' }));`,
|
|
493
|
+
` return;`,
|
|
494
|
+
` }`,
|
|
495
|
+
` const scan = typeof scanDirective === 'function' ? scanDirective(d.directive) : { safe: true };`,
|
|
496
|
+
` if (!scan.safe) {`,
|
|
497
|
+
` res.writeHead(400, { 'Content-Type': 'application/json' });`,
|
|
498
|
+
` res.end(JSON.stringify({ error: 'Safety check failed for directive: ' + scan.reason, directiveId: d.id, reason: scan.reason }));`,
|
|
499
|
+
` return;`,
|
|
500
|
+
` }`,
|
|
501
|
+
` }`,
|
|
502
|
+
'',
|
|
503
|
+
` await self.setIdentity({`,
|
|
504
|
+
` companionId: cid,`,
|
|
505
|
+
` name: manifest.identity.name,`,
|
|
506
|
+
` archetype: manifest.identity.archetype,`,
|
|
507
|
+
` origin: manifest.identity.origin,`,
|
|
508
|
+
` ethos: manifest.identity.ethos,`,
|
|
509
|
+
` version: manifest.version || '1.0.0',`,
|
|
510
|
+
` updatedAt: new Date().toISOString(),`,
|
|
511
|
+
` });`,
|
|
512
|
+
` if (directivesToCommit.length > 0 && typeof self.commitDirectives === 'function') {`,
|
|
513
|
+
` await self.commitDirectives(cid, directivesToCommit.map((d) => ({`,
|
|
514
|
+
` id: d.id,`,
|
|
515
|
+
` companionId: cid,`,
|
|
516
|
+
` directive: d.directive,`,
|
|
517
|
+
` category: d.category || 'behavioral',`,
|
|
518
|
+
` status: 'active',`,
|
|
519
|
+
` priority: d.priority || 50,`,
|
|
520
|
+
` createdAt: new Date().toISOString(),`,
|
|
521
|
+
` })));`,
|
|
522
|
+
` }`,
|
|
523
|
+
'',
|
|
524
|
+
` res.writeHead(200, { 'Content-Type': 'application/json' });`,
|
|
525
|
+
` res.end(JSON.stringify({ success: true, companionId: cid, installedDirectives: directivesToCommit.length }));`,
|
|
526
|
+
` } catch (err) {`,
|
|
527
|
+
` res.writeHead(500, { 'Content-Type': 'application/json' });`,
|
|
528
|
+
` res.end(JSON.stringify({ error: err.message }));`,
|
|
529
|
+
` }`,
|
|
530
|
+
` });`,
|
|
531
|
+
` return;`,
|
|
532
|
+
` }`,
|
|
533
|
+
'',
|
|
349
534
|
` // API: Voice & Observation health probes`,
|
|
350
535
|
` if (pathname === '/voice/health' && req.method === 'GET') {`,
|
|
351
536
|
` res.writeHead(200, { 'Content-Type': 'application/json' });`,
|
|
@@ -878,7 +1063,7 @@ function generateInstanceFiles(options) {
|
|
|
878
1063
|
`license: "MIT"`,
|
|
879
1064
|
``,
|
|
880
1065
|
`identity:`,
|
|
881
|
-
` name: "${(behaviorConfig.name || behaviorConfig.companionName || '').replace(/"/g, '\\"')}"`,
|
|
1066
|
+
` name: "${(behaviorConfig.name || behaviorConfig.companionName || options.name || '').replace(/"/g, '\\"')}"`,
|
|
882
1067
|
` archetype: "${(behaviorConfig.archetype || 'Knowledge Assistant & Research Partner').replace(/"/g, '\\"')}"`,
|
|
883
1068
|
` origin: "Constructed companion"`,
|
|
884
1069
|
` ethos: "${(behaviorConfig.ethos || 'Direct technical candor, thoughtful, concise, and loyal').replace(/"/g, '\\"')}"`,
|
package/dist/generator.test.js
CHANGED
|
@@ -64,6 +64,18 @@ describe('Instance Generator Composition Invariants (Phase 3)', () => {
|
|
|
64
64
|
environment: [{ name: 'VOICEVOX_URL', default: 'http://localhost:50021' }],
|
|
65
65
|
services: [{ name: 'VOICEVOX', kind: 'http_service' }],
|
|
66
66
|
},
|
|
67
|
+
self: {
|
|
68
|
+
name: '@siduri-x/self',
|
|
69
|
+
organType: 'behavior',
|
|
70
|
+
version: '1.0.0',
|
|
71
|
+
displayName: 'Self (Active Persona & Directives)',
|
|
72
|
+
entrypoint: './dist/index.js',
|
|
73
|
+
factory: 'ActiveSelfCompiler',
|
|
74
|
+
configKey: 'behavior',
|
|
75
|
+
configSchema: { type: 'object', properties: { provider: { type: 'string' } } },
|
|
76
|
+
environment: [],
|
|
77
|
+
services: [],
|
|
78
|
+
},
|
|
67
79
|
};
|
|
68
80
|
test('Composition A: Brain only', () => {
|
|
69
81
|
const files = (0, generator_1.generateInstanceFiles)({
|
|
@@ -207,4 +219,34 @@ describe('Instance Generator Composition Invariants (Phase 3)', () => {
|
|
|
207
219
|
expect(chatSlice).toContain("channel: 'direct'");
|
|
208
220
|
expect(chatStreamSlice).toContain("channel: 'direct'");
|
|
209
221
|
});
|
|
222
|
+
test('Composition F: Brain + Self persona manifest & Teach Mode endpoints', () => {
|
|
223
|
+
const files = (0, generator_1.generateInstanceFiles)({
|
|
224
|
+
name: 'BrattyCompanion',
|
|
225
|
+
selectedManifests: [MOCK_MANIFESTS.brain, MOCK_MANIFESTS.self],
|
|
226
|
+
organConfigs: {
|
|
227
|
+
behavior: {
|
|
228
|
+
provider: 'active_self',
|
|
229
|
+
mode: 'custom',
|
|
230
|
+
archetype: 'Bratty little sister',
|
|
231
|
+
ethos: 'bratty, warmth, smug',
|
|
232
|
+
directive: 'Speak as bratty little sister, calling me onii-chan',
|
|
233
|
+
selfPath: './assets/self/default.self',
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
// 1. Assets directory and .self file created in memory
|
|
238
|
+
expect(files.createAssetsDirs).toContain('assets/self');
|
|
239
|
+
expect(files['assets/self/default.self']).toBeDefined();
|
|
240
|
+
expect(files['assets/self/default.self']).toContain('archetype: "Bratty little sister"');
|
|
241
|
+
expect(files['assets/self/default.self']).toContain('ethos: "bratty, warmth, smug"');
|
|
242
|
+
expect(files['assets/self/default.self']).toContain('Speak as bratty little sister, calling me onii-chan');
|
|
243
|
+
expect(files['assets/self/default.self']).toContain('name: "BrattyCompanion"');
|
|
244
|
+
// 2. src/index.js imports scanDirective
|
|
245
|
+
const srcIndexJs = files['src/index.js'];
|
|
246
|
+
expect(srcIndexJs).toContain("import { ActiveSelfCompiler, SqliteSelfRepository, SelfPackageParser, scanDirective } from '@siduri-x/self';");
|
|
247
|
+
// 3. Teach Mode endpoints are generated
|
|
248
|
+
expect(srcIndexJs).toContain("pathname === '/teach/detected-self'");
|
|
249
|
+
expect(srcIndexJs).toContain("pathname === '/teach/upload-self'");
|
|
250
|
+
expect(srcIndexJs).toContain("pathname === '/teach/install-self'");
|
|
251
|
+
});
|
|
210
252
|
});
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -61,7 +61,7 @@ const doctor_1 = require("./doctor");
|
|
|
61
61
|
const db_1 = require("./db");
|
|
62
62
|
const configurators_1 = require("./configurators");
|
|
63
63
|
const execFile = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
64
|
-
exports.CLI_VERSION = '2.0.
|
|
64
|
+
exports.CLI_VERSION = '2.0.38';
|
|
65
65
|
const colors_1 = require("./colors");
|
|
66
66
|
Object.defineProperty(exports, "colors", { enumerable: true, get: function () { return colors_1.colors; } });
|
|
67
67
|
function printHeader() {
|
|
@@ -320,6 +320,25 @@ async function runCreateWizard(targetDir, options) {
|
|
|
320
320
|
else if (files.createAssetsBodyDir) {
|
|
321
321
|
await (0, promises_1.mkdir)(node_path_1.default.join(projectDir, 'assets/body'), { recursive: true });
|
|
322
322
|
}
|
|
323
|
+
// Write all additional generated files (such as assets/self/default.self or other assets)
|
|
324
|
+
const handledKeys = new Set([
|
|
325
|
+
'package.json',
|
|
326
|
+
'siduri.config.json',
|
|
327
|
+
'siduri.schema.json',
|
|
328
|
+
'.env.example',
|
|
329
|
+
'README.md',
|
|
330
|
+
'src/index.js',
|
|
331
|
+
'public/index.html',
|
|
332
|
+
'createAssetsDirs',
|
|
333
|
+
'createAssetsBodyDir',
|
|
334
|
+
]);
|
|
335
|
+
for (const [relPath, content] of Object.entries(files)) {
|
|
336
|
+
if (handledKeys.has(relPath) || typeof content !== 'string')
|
|
337
|
+
continue;
|
|
338
|
+
const destPath = node_path_1.default.join(projectDir, relPath);
|
|
339
|
+
await (0, promises_1.mkdir)(node_path_1.default.dirname(destPath), { recursive: true });
|
|
340
|
+
await (0, promises_1.writeFile)(destPath, content, 'utf8');
|
|
341
|
+
}
|
|
323
342
|
// If local knowledge archive is configured with a download URL, automatically fetch and unpack it
|
|
324
343
|
const knowledgeConfig = organConfigs.knowledge || organConfigs['@siduri-x/knowledge'];
|
|
325
344
|
if (knowledgeConfig?.pack?.mode === 'local' && knowledgeConfig?.pack?.archiveUrl) {
|