@vxnus/siduri 2.0.5 → 2.0.7
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 +16 -3
- package/dist/configurators/behavior.js +59 -16
- 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.test.js +34 -4
- package/dist/generator.d.ts +1 -0
- package/dist/generator.js +50 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +40 -45
- package/package.json +1 -1
|
@@ -6,8 +6,8 @@ exports.BUILTIN_ORGAN_MANIFESTS = [
|
|
|
6
6
|
name: '@siduri-x/self',
|
|
7
7
|
organType: 'behavior',
|
|
8
8
|
version: '2.0.2',
|
|
9
|
-
displayName: '
|
|
10
|
-
description: '
|
|
9
|
+
displayName: 'Self & Persona (Identity & Directives)',
|
|
10
|
+
description: 'Autonomous persona compiler, relational stances, and .self asset loader',
|
|
11
11
|
entrypoint: './dist/index.js',
|
|
12
12
|
factory: 'ActiveSelfCompiler',
|
|
13
13
|
configKey: 'behavior',
|
|
@@ -19,7 +19,20 @@ exports.BUILTIN_ORGAN_MANIFESTS = [
|
|
|
19
19
|
type: 'string',
|
|
20
20
|
enum: ['active_self', 'none']
|
|
21
21
|
},
|
|
22
|
-
|
|
22
|
+
mode: {
|
|
23
|
+
type: 'string',
|
|
24
|
+
enum: ['blank_slate', 'custom']
|
|
25
|
+
},
|
|
26
|
+
archetype: {
|
|
27
|
+
type: 'string'
|
|
28
|
+
},
|
|
29
|
+
ethos: {
|
|
30
|
+
type: 'string'
|
|
31
|
+
},
|
|
32
|
+
directive: {
|
|
33
|
+
type: 'string'
|
|
34
|
+
},
|
|
35
|
+
selfPath: {
|
|
23
36
|
type: 'string'
|
|
24
37
|
}
|
|
25
38
|
}
|
|
@@ -6,31 +6,74 @@ 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
|
|
9
|
+
const companionName = _context.companionName || 'Companion';
|
|
10
|
+
const companionSlug = companionName.toLowerCase().replace(/[^a-z0-9_-]/g, '') || 'default';
|
|
11
|
+
const { personaMode } = await inquirer_1.default.prompt({
|
|
10
12
|
type: 'list',
|
|
11
|
-
name: '
|
|
12
|
-
message: '
|
|
13
|
+
name: 'personaMode',
|
|
14
|
+
message: 'Define base persona now or later?',
|
|
13
15
|
choices: [
|
|
14
|
-
{
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
{
|
|
17
|
+
name: 'Later (Start as a pure blank slate; evolve via interaction or add .self later)',
|
|
18
|
+
value: 'later',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: 'Now (Define archetype, ethos, and generate base .self persona asset)',
|
|
22
|
+
value: 'now',
|
|
23
|
+
},
|
|
18
24
|
],
|
|
25
|
+
default: 'later',
|
|
19
26
|
});
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
if (personaMode === 'later') {
|
|
28
|
+
return {
|
|
29
|
+
config: {
|
|
30
|
+
provider: 'active_self',
|
|
31
|
+
mode: 'blank_slate',
|
|
32
|
+
},
|
|
33
|
+
summary: {
|
|
34
|
+
Persona: 'Blank Slate (Evolve via interaction)',
|
|
35
|
+
Directives: 'Zero predeclared biases',
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const personaAnswers = await inquirer_1.default.prompt([
|
|
40
|
+
{
|
|
41
|
+
type: 'input',
|
|
42
|
+
name: 'archetype',
|
|
43
|
+
message: 'Companion archetype or role:',
|
|
44
|
+
default: 'Knowledge Assistant & Research Partner',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
type: 'input',
|
|
48
|
+
name: 'ethos',
|
|
49
|
+
message: 'Core ethos & speaking demeanor:',
|
|
50
|
+
default: 'Direct technical candor, thoughtful, concise, and loyal',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
type: 'input',
|
|
54
|
+
name: 'directive',
|
|
55
|
+
message: 'Primary behavioral directive or rule:',
|
|
56
|
+
default: 'Speak concisely and stay in character without sycophantic filler',
|
|
57
|
+
},
|
|
58
|
+
]);
|
|
59
|
+
const archetype = personaAnswers.archetype.trim() || 'Knowledge Assistant & Research Partner';
|
|
60
|
+
const ethos = personaAnswers.ethos.trim() || 'Direct technical candor, thoughtful, concise, and loyal';
|
|
61
|
+
const directive = personaAnswers.directive.trim() || 'Speak concisely and stay in character without sycophantic filler';
|
|
62
|
+
const selfPath = `./assets/self/${companionSlug}.self`;
|
|
26
63
|
return {
|
|
27
64
|
config: {
|
|
28
65
|
provider: 'active_self',
|
|
29
|
-
|
|
66
|
+
mode: 'custom',
|
|
67
|
+
archetype,
|
|
68
|
+
ethos,
|
|
69
|
+
directive,
|
|
70
|
+
selfPath,
|
|
30
71
|
},
|
|
31
72
|
summary: {
|
|
32
|
-
|
|
33
|
-
|
|
73
|
+
Persona: 'Configured (.self asset)',
|
|
74
|
+
Archetype: archetype,
|
|
75
|
+
Ethos: ethos,
|
|
76
|
+
'Self Asset': selfPath,
|
|
34
77
|
},
|
|
35
78
|
};
|
|
36
79
|
}
|
|
@@ -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({
|
|
@@ -302,15 +302,39 @@ describe('Guided Manifest-Driven Configuration UX Specification Tests', () => {
|
|
|
302
302
|
expect(result.summary?.['Model Path']).toBe('./assets/body/sparkle/model.model3.json');
|
|
303
303
|
});
|
|
304
304
|
test('Hands configurator configures MCP tool execution timeout', async () => {
|
|
305
|
-
inquirer_1.default.prompt
|
|
305
|
+
inquirer_1.default.prompt
|
|
306
|
+
.mockResolvedValueOnce({ provider: 'mcp' })
|
|
307
|
+
.mockResolvedValueOnce({ timeoutSeconds: '15' });
|
|
306
308
|
const result = await (0, hands_1.configureHands)({ companionName: 'Sparkle', manifest: handsManifest });
|
|
307
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)');
|
|
308
317
|
});
|
|
309
|
-
test('Behavior configurator configures
|
|
310
|
-
inquirer_1.default.prompt.mockResolvedValueOnce({
|
|
318
|
+
test('Behavior configurator configures blank slate mode when later is chosen', async () => {
|
|
319
|
+
inquirer_1.default.prompt.mockResolvedValueOnce({ personaMode: 'later' });
|
|
311
320
|
const result = await (0, behavior_1.configureBehavior)({ companionName: 'Sparkle', manifest: behaviorManifest });
|
|
312
321
|
expect(result.config.provider).toBe('active_self');
|
|
313
|
-
expect(result.config.
|
|
322
|
+
expect(result.config.mode).toBe('blank_slate');
|
|
323
|
+
expect(result.summary?.Persona).toBe('Blank Slate (Evolve via interaction)');
|
|
324
|
+
});
|
|
325
|
+
test('Behavior configurator configures custom persona asset when now is chosen', async () => {
|
|
326
|
+
inquirer_1.default.prompt
|
|
327
|
+
.mockResolvedValueOnce({ personaMode: 'now' })
|
|
328
|
+
.mockResolvedValueOnce({
|
|
329
|
+
archetype: 'System Sentinel',
|
|
330
|
+
ethos: 'Snarky and loyal',
|
|
331
|
+
directive: 'No sycophantic greetings',
|
|
332
|
+
});
|
|
333
|
+
const result = await (0, behavior_1.configureBehavior)({ companionName: 'Sparkle', manifest: behaviorManifest });
|
|
334
|
+
expect(result.config.provider).toBe('active_self');
|
|
335
|
+
expect(result.config.mode).toBe('custom');
|
|
336
|
+
expect(result.config.archetype).toBe('System Sentinel');
|
|
337
|
+
expect(result.config.selfPath).toBe('./assets/self/sparkle.self');
|
|
314
338
|
});
|
|
315
339
|
test('Vision configurator configures OpenRouter vision model', async () => {
|
|
316
340
|
inquirer_1.default.prompt.mockResolvedValueOnce({ model: 'gpt-4-vision' });
|
|
@@ -318,6 +342,12 @@ describe('Guided Manifest-Driven Configuration UX Specification Tests', () => {
|
|
|
318
342
|
expect(result.config.provider).toBe('openrouter');
|
|
319
343
|
expect(result.config.model).toBe('gpt-4-vision');
|
|
320
344
|
});
|
|
345
|
+
test('Vision configurator disables vision when none is selected', async () => {
|
|
346
|
+
inquirer_1.default.prompt.mockResolvedValueOnce({ model: 'none' });
|
|
347
|
+
const result = await (0, vision_1.configureVision)({ companionName: 'Sparkle', manifest: visionManifest });
|
|
348
|
+
expect(result.config.provider).toBe('none');
|
|
349
|
+
expect(result.summary?.Provider).toBe('None (Vision disabled)');
|
|
350
|
+
});
|
|
321
351
|
});
|
|
322
352
|
describe('Review Summary Formatting & Generator Integration', () => {
|
|
323
353
|
test('formatReviewSummary displays actual configuration values and metadata', () => {
|
package/dist/generator.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export interface GeneratedInstanceFiles {
|
|
|
9
9
|
'public/index.html': string;
|
|
10
10
|
createAssetsBodyDir?: boolean;
|
|
11
11
|
createAssetsDirs?: string[];
|
|
12
|
+
[key: string]: string | boolean | string[] | undefined;
|
|
12
13
|
}
|
|
13
14
|
export interface InstanceGeneratorOptions {
|
|
14
15
|
name: string;
|
package/dist/generator.js
CHANGED
|
@@ -73,6 +73,7 @@ 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';
|
|
76
77
|
const instanceId = options.id || 'default';
|
|
77
78
|
const coreVersion = options.coreVersion || '^2.0.3';
|
|
78
79
|
const manifests = options.selectedManifests;
|
|
@@ -172,7 +173,7 @@ function generateInstanceFiles(options) {
|
|
|
172
173
|
];
|
|
173
174
|
for (const m of manifests) {
|
|
174
175
|
if (m.name === '@siduri-x/self') {
|
|
175
|
-
importLines.push(`import { ActiveSelfCompiler, SqliteSelfRepository } from '@siduri-x/self';`);
|
|
176
|
+
importLines.push(`import { ActiveSelfCompiler, SqliteSelfRepository, SelfPackageParser } from '@siduri-x/self';`);
|
|
176
177
|
}
|
|
177
178
|
else {
|
|
178
179
|
importLines.push(`import { ${m.factory} } from '${m.name}';`);
|
|
@@ -184,6 +185,19 @@ function generateInstanceFiles(options) {
|
|
|
184
185
|
if (m.name === '@siduri-x/self') {
|
|
185
186
|
instantiationLines.push(`const self = new SqliteSelfRepository({ dbPath: path.resolve(rootDir, 'siduri.sqlite') });`);
|
|
186
187
|
instantiationLines.push(`const behavior = new ActiveSelfCompiler(config.organs.behavior);`);
|
|
188
|
+
instantiationLines.push(`const selfFile = path.resolve(rootDir, config.organs.behavior?.selfPath || 'assets/self/${companionSlug}.self');`);
|
|
189
|
+
instantiationLines.push(`try {`);
|
|
190
|
+
instantiationLines.push(` const selfRaw = await readFile(selfFile, 'utf8').catch(() => null);`);
|
|
191
|
+
instantiationLines.push(` if (selfRaw) {`);
|
|
192
|
+
instantiationLines.push(` const parsedSelf = SelfPackageParser.parse(selfRaw);`);
|
|
193
|
+
instantiationLines.push(` if (parsedSelf.isValid && parsedSelf.manifest) {`);
|
|
194
|
+
instantiationLines.push(` await self.setIdentity({ companionId: config.id || 'default', name: parsedSelf.manifest.identity?.name || config.name, archetype: parsedSelf.manifest.identity?.archetype, version: parsedSelf.manifest.version || '1.0.0', updatedAt: new Date().toISOString() });`);
|
|
195
|
+
instantiationLines.push(` if (parsedSelf.manifest.directives) {`);
|
|
196
|
+
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() })));`);
|
|
197
|
+
instantiationLines.push(` }`);
|
|
198
|
+
instantiationLines.push(` }`);
|
|
199
|
+
instantiationLines.push(` }`);
|
|
200
|
+
instantiationLines.push(`} catch {}`);
|
|
187
201
|
organMapEntries.push(` behavior,`);
|
|
188
202
|
organMapEntries.push(` self,`);
|
|
189
203
|
}
|
|
@@ -665,7 +679,6 @@ function generateInstanceFiles(options) {
|
|
|
665
679
|
}
|
|
666
680
|
readmeLines.push('', '## Getting Started', '', '### 1. Install Dependencies', '```bash', 'npm install', '```', '', '### 2. Configure Environment', '```bash', 'cp .env.example .env', '```', 'Fill in your LLM API key (e.g. `OPENROUTER_API_KEY`) and any other service credentials in `.env`.');
|
|
667
681
|
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.');
|
|
668
|
-
const companionSlug = instanceName.toLowerCase().replace(/[^a-z0-9_-]/g, '') || 'default';
|
|
669
682
|
const createAssetsDirs = [];
|
|
670
683
|
if (hasBody) {
|
|
671
684
|
createAssetsDirs.push(`assets/body/${companionSlug}`);
|
|
@@ -681,6 +694,38 @@ function generateInstanceFiles(options) {
|
|
|
681
694
|
createAssetsDirs.push(cleanPackDir);
|
|
682
695
|
readmeLines.push('', '### Knowledge Pack Assets', `Local knowledge pack files reside in \`./${cleanPackDir}/\`.`);
|
|
683
696
|
}
|
|
697
|
+
const behaviorConfig = options.organConfigs?.behavior || options.organConfigs?.['@siduri-x/self'];
|
|
698
|
+
let selfPersonaFile = null;
|
|
699
|
+
if (manifests.some((m) => m.organType === 'behavior')) {
|
|
700
|
+
createAssetsDirs.push('assets/self');
|
|
701
|
+
if (behaviorConfig?.mode === 'custom' || behaviorConfig?.archetype) {
|
|
702
|
+
const selfRelPath = `assets/self/${companionSlug}.self`;
|
|
703
|
+
const selfContent = [
|
|
704
|
+
`specVersion: "2.0.0"`,
|
|
705
|
+
`kind: "self"`,
|
|
706
|
+
`id: "${companionSlug}-self"`,
|
|
707
|
+
`name: "${instanceName} Persona"`,
|
|
708
|
+
`version: "1.0.0"`,
|
|
709
|
+
`author:`,
|
|
710
|
+
` name: "Operator"`,
|
|
711
|
+
`license: "MIT"`,
|
|
712
|
+
``,
|
|
713
|
+
`identity:`,
|
|
714
|
+
` name: "${instanceName}"`,
|
|
715
|
+
` archetype: "${(behaviorConfig.archetype || 'Knowledge Assistant & Research Partner').replace(/"/g, '\\"')}"`,
|
|
716
|
+
` origin: "Constructed companion"`,
|
|
717
|
+
` ethos: "${(behaviorConfig.ethos || 'Direct technical candor, thoughtful, concise, and loyal').replace(/"/g, '\\"')}"`,
|
|
718
|
+
``,
|
|
719
|
+
`directives:`,
|
|
720
|
+
` - id: "dir-01"`,
|
|
721
|
+
` category: "behavioral"`,
|
|
722
|
+
` directive: "${(behaviorConfig.directive || 'Speak concisely and stay in character without sycophantic filler').replace(/"/g, '\\"')}"`,
|
|
723
|
+
``,
|
|
724
|
+
].join('\n');
|
|
725
|
+
selfPersonaFile = { path: selfRelPath, content: selfContent };
|
|
726
|
+
readmeLines.push('', '### Self & Persona Assets', `Companion persona manifest resides in \`./${selfRelPath}\`.`);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
684
729
|
readmeLines.push('');
|
|
685
730
|
const readmeMd = readmeLines.join('\n');
|
|
686
731
|
const webHtml = (0, web_template_1.generateWebHtml)(instanceName, manifests);
|
|
@@ -695,5 +740,8 @@ function generateInstanceFiles(options) {
|
|
|
695
740
|
createAssetsBodyDir: hasBody,
|
|
696
741
|
createAssetsDirs,
|
|
697
742
|
};
|
|
743
|
+
if (selfPersonaFile) {
|
|
744
|
+
result[selfPersonaFile.path] = selfPersonaFile.content;
|
|
745
|
+
}
|
|
698
746
|
return result;
|
|
699
747
|
}
|
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.7';
|
|
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
|
}
|