@vxnus/siduri 2.0.0 → 2.0.1
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/README.md +7 -7
- package/dist/builtin-manifests.js +38 -32
- package/dist/clean-machine-e2e.test.js +16 -16
- package/dist/clean-machine-smoke.test.d.ts +1 -0
- package/dist/clean-machine-smoke.test.js +166 -0
- package/dist/configurators/knowledge.js +134 -46
- package/dist/configurators/memory.js +7 -25
- package/dist/configurators.test.js +11 -12
- package/dist/doctor.js +58 -14
- package/dist/generator.js +91 -15
- package/dist/generator.test.js +9 -7
- package/dist/index.d.ts +1 -1
- package/dist/index.js +37 -32
- package/dist/manifest.d.ts +1 -1
- package/dist/providers/openrouter.js +1 -1
- package/dist/release-check.js +1 -1
- package/dist/web-dist/404/index.html +1 -1
- package/dist/web-dist/404.html +1 -1
- package/dist/web-dist/__next.__PAGE__.txt +12 -12
- package/dist/web-dist/__next._full.txt +12 -12
- package/dist/web-dist/__next._tree.txt +1 -1
- package/dist/web-dist/_next/static/chunks/0jgw-jf26m0ui.js +22 -0
- package/dist/web-dist/_next/static/chunks/0tdcnq1-n6kof.js +31 -0
- package/dist/web-dist/_next/static/chunks/12vwhiuvdy_i7.js +1 -0
- package/dist/web-dist/_next/static/chunks/{2_duynll0m51m.js → 15zsrb5462n_-.js} +2 -2
- package/dist/web-dist/_next/static/chunks/2dsfgoa225hpl.js +1 -0
- package/dist/web-dist/_next/static/chunks/2mno6yfdoee0x.js +1 -0
- package/dist/web-dist/_next/static/chunks/30a48dk5bjyhj.js +1 -0
- package/dist/web-dist/_next/static/chunks/360luxuz2x8y_.js +1 -0
- package/dist/web-dist/_next/static/chunks/turbopack-2hpygfb68u21h.js +1 -0
- package/dist/web-dist/_not-found/__next._full.txt +8 -8
- package/dist/web-dist/_not-found/__next._not-found.__PAGE__.txt +7 -7
- package/dist/web-dist/_not-found/__next._tree.txt +1 -1
- package/dist/web-dist/_not-found/index.html +1 -1
- package/dist/web-dist/_not-found/index.txt +8 -8
- package/dist/web-dist/chat/__next._full.txt +9 -9
- package/dist/web-dist/chat/__next._tree.txt +1 -1
- package/dist/web-dist/chat/__next.chat.__PAGE__.txt +8 -8
- package/dist/web-dist/chat/index.html +1 -1
- package/dist/web-dist/chat/index.txt +9 -9
- package/dist/web-dist/index.html +1 -1
- package/dist/web-dist/index.txt +12 -12
- package/dist/web-dist/operator/__next._full.txt +9 -9
- package/dist/web-dist/operator/__next._tree.txt +1 -1
- package/dist/web-dist/operator/__next.operator.__PAGE__.txt +8 -8
- package/dist/web-dist/operator/index.html +1 -1
- package/dist/web-dist/operator/index.txt +9 -9
- package/dist/web-template.js +1 -1
- package/package.json +10 -10
- package/dist/web-dist/_next/static/chunks/09y7khbmco_v4.js +0 -1
- package/dist/web-dist/_next/static/chunks/0uwih7sydv413.js +0 -1
- package/dist/web-dist/_next/static/chunks/1_yae15ffa5f6.js +0 -1
- package/dist/web-dist/_next/static/chunks/2kcqevsmv6kh2.js +0 -31
- package/dist/web-dist/_next/static/chunks/2s3d1bfr0l4b0.js +0 -1
- package/dist/web-dist/_next/static/chunks/32z87id9k6i2z.js +0 -22
- package/dist/web-dist/_next/static/chunks/3bx2gs3idjmo1.js +0 -1
- package/dist/web-dist/_next/static/chunks/turbopack-3eipe4c-imn5l.js +0 -1
- /package/dist/web-dist/_next/static/{pWHUixFDDvANZeAf-shqT → lQfIAv021hLk8KVAElf2K}/_buildManifest.js +0 -0
- /package/dist/web-dist/_next/static/{pWHUixFDDvANZeAf-shqT → lQfIAv021hLk8KVAElf2K}/_clientMiddlewareManifest.js +0 -0
- /package/dist/web-dist/_next/static/{pWHUixFDDvANZeAf-shqT → lQfIAv021hLk8KVAElf2K}/_ssgManifest.js +0 -0
|
@@ -5,15 +5,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.configureKnowledge = configureKnowledge;
|
|
7
7
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
8
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
9
|
const knowledge_hub_1 = require("../providers/knowledge-hub");
|
|
9
10
|
async function configureKnowledge(_context, options = {}) {
|
|
10
11
|
const client = options.client || new knowledge_hub_1.KnowledgeHubClient();
|
|
12
|
+
// 1. Ask Knowledge source / mode
|
|
11
13
|
const { source } = await inquirer_1.default.prompt({
|
|
12
14
|
type: 'list',
|
|
13
15
|
name: 'source',
|
|
14
|
-
message: '
|
|
16
|
+
message: 'Select knowledge configuration:',
|
|
15
17
|
choices: [
|
|
16
|
-
{ name: 'E Knowledge Hub
|
|
18
|
+
{ name: 'E Knowledge Hub / Portable Pack (with Life Database)', value: 'e-hub' },
|
|
19
|
+
{ name: 'Life Database Only (SQLite personal state, schedule, preferences)', value: 'life-only' },
|
|
17
20
|
{ name: 'Do not use knowledge', value: 'none' },
|
|
18
21
|
],
|
|
19
22
|
});
|
|
@@ -21,80 +24,165 @@ async function configureKnowledge(_context, options = {}) {
|
|
|
21
24
|
return {
|
|
22
25
|
config: {
|
|
23
26
|
provider: 'none',
|
|
27
|
+
lifeDatabase: false,
|
|
24
28
|
},
|
|
25
29
|
summary: {
|
|
26
30
|
Source: 'Do not use knowledge',
|
|
31
|
+
Knowledge: 'Disabled',
|
|
27
32
|
},
|
|
28
33
|
};
|
|
29
34
|
}
|
|
30
|
-
|
|
35
|
+
const summary = {};
|
|
36
|
+
const config = {
|
|
37
|
+
dbPath: 'siduri.sqlite',
|
|
38
|
+
lifeDatabase: true,
|
|
39
|
+
};
|
|
40
|
+
if (source === 'life-only') {
|
|
41
|
+
config.provider = 'unified';
|
|
42
|
+
summary.Source = 'Life Database';
|
|
43
|
+
summary['Life Database'] = 'Enabled (siduri.sqlite)';
|
|
44
|
+
summary['E-Pack'] = 'None';
|
|
45
|
+
return { config, summary };
|
|
46
|
+
}
|
|
47
|
+
// 2. Discovery-First E-Knowledge Resolution Flow
|
|
31
48
|
while (true) {
|
|
32
|
-
const
|
|
49
|
+
const promptRes = await inquirer_1.default.prompt({
|
|
33
50
|
type: 'input',
|
|
34
51
|
name: 'packId',
|
|
35
|
-
message: '
|
|
52
|
+
message: 'Enter package ID (@publisher/name), local pack path, or remote URL:',
|
|
36
53
|
default: '@vxnus/e-teyvat',
|
|
37
|
-
validate: (val) => val.trim().length > 0 || 'Please enter a package ID.',
|
|
54
|
+
validate: (val) => val.trim().length > 0 || 'Please enter a package ID, path, or URL.',
|
|
38
55
|
});
|
|
39
|
-
const
|
|
56
|
+
const target = (promptRes.packId || promptRes.query || '').trim();
|
|
57
|
+
// Case A: Remote HTTP endpoint
|
|
58
|
+
if (target.startsWith('http://') || target.startsWith('https://')) {
|
|
59
|
+
console.log(`\n\x1b[36m── Knowledge Provider ────────────────────────\x1b[0m\n`);
|
|
60
|
+
console.log(` \x1b[2mType:\x1b[0m Remote E-Provider`);
|
|
61
|
+
console.log(` \x1b[2mEndpoint:\x1b[0m ${target}`);
|
|
62
|
+
console.log(` \x1b[2mConnectors:\x1b[0m Remote only (HTTP stream)\n`);
|
|
63
|
+
config.provider = 'e-remote';
|
|
64
|
+
config.baseUrl = target;
|
|
65
|
+
config.pack = {
|
|
66
|
+
mode: 'remote',
|
|
67
|
+
baseUrl: target,
|
|
68
|
+
};
|
|
69
|
+
summary.Source = 'Remote E-Provider';
|
|
70
|
+
summary.Provider = target;
|
|
71
|
+
summary['E-Pack'] = `Remote (${target})`;
|
|
72
|
+
return { config, summary };
|
|
73
|
+
}
|
|
74
|
+
// Case B: Local path / file
|
|
75
|
+
if (target.startsWith('./') || target.startsWith('/') || node_fs_1.default.existsSync(target)) {
|
|
76
|
+
console.log(`\n\x1b[36m── Knowledge Provider ────────────────────────\x1b[0m\n`);
|
|
77
|
+
console.log(` \x1b[2mType:\x1b[0m Local Knowledge Pack`);
|
|
78
|
+
console.log(` \x1b[2mPath:\x1b[0m ${target}`);
|
|
79
|
+
console.log(` \x1b[2mConnectors:\x1b[0m Local only (Filesystem)\n`);
|
|
80
|
+
config.provider = 'e-knowledge';
|
|
81
|
+
config.packPath = target;
|
|
82
|
+
config.pack = {
|
|
83
|
+
mode: 'local',
|
|
84
|
+
packPath: target,
|
|
85
|
+
};
|
|
86
|
+
summary.Source = 'Local Knowledge Pack';
|
|
87
|
+
summary.Provider = target;
|
|
88
|
+
summary['E-Pack'] = `Local (${target})`;
|
|
89
|
+
return { config, summary };
|
|
90
|
+
}
|
|
91
|
+
// Case C: E Knowledge Hub package ID (@publisher/name)
|
|
40
92
|
let manifest;
|
|
41
93
|
try {
|
|
42
|
-
process.stdout.write('\
|
|
43
|
-
manifest = await client.resolveProvider(
|
|
44
|
-
process.stdout.write('\r\
|
|
94
|
+
process.stdout.write('\x1b[2mResolving knowledge metadata...\x1b[0m');
|
|
95
|
+
manifest = await client.resolveProvider(target);
|
|
96
|
+
process.stdout.write('\r\x1b[32m✓\x1b[0m Knowledge metadata resolved\n');
|
|
45
97
|
}
|
|
46
98
|
catch (err) {
|
|
47
|
-
process.stdout.write('\r\
|
|
48
|
-
console.log(`\
|
|
99
|
+
process.stdout.write('\r\x1b[33m!\x1b[0m Knowledge resolution failed\n');
|
|
100
|
+
console.log(`\x1b[33mReason:\x1b[0m ${err.message}\n`);
|
|
49
101
|
const { failureAction } = await inquirer_1.default.prompt({
|
|
50
102
|
type: 'list',
|
|
51
103
|
name: 'failureAction',
|
|
52
104
|
message: 'What would you like to do?',
|
|
53
105
|
choices: [
|
|
54
|
-
{ name: 'Try again /
|
|
55
|
-
{ name: '
|
|
106
|
+
{ name: 'Try again / Enter another package ID or path', value: 'retry' },
|
|
107
|
+
{ name: 'Skip attaching E-pack (keep Life DB only)', value: 'skip' },
|
|
56
108
|
{ name: 'Cancel', value: 'cancel' },
|
|
57
109
|
],
|
|
58
110
|
});
|
|
59
|
-
if (failureAction === 'retry')
|
|
111
|
+
if (failureAction === 'retry')
|
|
60
112
|
continue;
|
|
61
|
-
}
|
|
62
113
|
if (failureAction === 'skip') {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
};
|
|
114
|
+
config.provider = 'unified';
|
|
115
|
+
summary.Source = 'Life Database';
|
|
116
|
+
summary['E-Pack'] = 'None';
|
|
117
|
+
return { config, summary };
|
|
67
118
|
}
|
|
68
119
|
throw new Error('Knowledge configuration cancelled.');
|
|
69
120
|
}
|
|
70
|
-
// Display
|
|
71
|
-
(0, knowledge_hub_1.displayKnowledgeProviderSummary)(manifest,
|
|
72
|
-
|
|
121
|
+
// Display metadata
|
|
122
|
+
(0, knowledge_hub_1.displayKnowledgeProviderSummary)(manifest, target);
|
|
123
|
+
// Inspect supported connectors
|
|
124
|
+
const hasRemoteUrl = Boolean(manifest.distribution?.url);
|
|
125
|
+
const connectorChoices = [];
|
|
126
|
+
if (hasRemoteUrl) {
|
|
127
|
+
connectorChoices.push({
|
|
128
|
+
name: `Remote (Stream directly from ${manifest.distribution?.url} without local storage)`,
|
|
129
|
+
value: 'remote',
|
|
130
|
+
});
|
|
131
|
+
connectorChoices.push({
|
|
132
|
+
name: 'Local (Download and run offline pack files on this machine)',
|
|
133
|
+
value: 'local',
|
|
134
|
+
});
|
|
135
|
+
connectorChoices.push({
|
|
136
|
+
name: 'Hybrid (Local pack cache with remote provider fallback/sync)',
|
|
137
|
+
value: 'hybrid',
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
connectorChoices.push({
|
|
142
|
+
name: 'Local (Offline pack files on this machine)',
|
|
143
|
+
value: 'local',
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
connectorChoices.push({
|
|
147
|
+
name: 'Choose another provider',
|
|
148
|
+
value: 'retry',
|
|
149
|
+
});
|
|
150
|
+
const choiceRes = await inquirer_1.default.prompt({
|
|
73
151
|
type: 'list',
|
|
74
|
-
name: '
|
|
75
|
-
message: '
|
|
76
|
-
choices:
|
|
77
|
-
{ name: 'Yes, use this provider', value: 'yes' },
|
|
78
|
-
{ name: 'Choose another provider', value: 'retry' },
|
|
79
|
-
],
|
|
152
|
+
name: 'connectorMode',
|
|
153
|
+
message: 'Choose connection type for this pack:',
|
|
154
|
+
choices: connectorChoices,
|
|
80
155
|
});
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
provider: 'e-hub',
|
|
85
|
-
registryUrl: 'https://e.vxnus.xyz/api/v1/knowledge',
|
|
86
|
-
packId: trimmedPackId,
|
|
87
|
-
},
|
|
88
|
-
summary: {
|
|
89
|
-
Source: 'E Knowledge Hub',
|
|
90
|
-
Provider: manifest.displayName || manifest.name,
|
|
91
|
-
Package: trimmedPackId,
|
|
92
|
-
Version: manifest.version,
|
|
93
|
-
},
|
|
94
|
-
metadata: {
|
|
95
|
-
manifest,
|
|
96
|
-
},
|
|
97
|
-
};
|
|
156
|
+
const rawChoice = choiceRes.connectorMode ?? choiceRes.confirmProvider;
|
|
157
|
+
if (rawChoice === 'retry') {
|
|
158
|
+
continue;
|
|
98
159
|
}
|
|
160
|
+
const connectorMode = (rawChoice === 'yes'
|
|
161
|
+
? (hasRemoteUrl ? 'remote' : 'local')
|
|
162
|
+
: (['remote', 'local', 'hybrid'].includes(rawChoice || '') ? rawChoice : 'local'));
|
|
163
|
+
config.provider = 'e-hub';
|
|
164
|
+
config.registryUrl = 'https://e.vxnus.xyz/api/v1/knowledge';
|
|
165
|
+
config.packId = target;
|
|
166
|
+
config.pack = {
|
|
167
|
+
mode: connectorMode,
|
|
168
|
+
packId: target,
|
|
169
|
+
registryUrl: 'https://e.vxnus.xyz/api/v1/knowledge',
|
|
170
|
+
baseUrl: manifest.distribution?.url,
|
|
171
|
+
preferredMode: 'lexical',
|
|
172
|
+
};
|
|
173
|
+
if (manifest.distribution?.url) {
|
|
174
|
+
config.baseUrl = manifest.distribution.url;
|
|
175
|
+
}
|
|
176
|
+
summary.Source = 'E Knowledge Hub';
|
|
177
|
+
summary.Provider = manifest.displayName || manifest.name;
|
|
178
|
+
summary.Package = target;
|
|
179
|
+
summary.Version = manifest.version;
|
|
180
|
+
summary['Life Database'] = 'Enabled (siduri.sqlite)';
|
|
181
|
+
summary['E-Pack'] = `${manifest.displayName || manifest.name} (${connectorMode})`;
|
|
182
|
+
return {
|
|
183
|
+
config,
|
|
184
|
+
summary,
|
|
185
|
+
metadata: { manifest },
|
|
186
|
+
};
|
|
99
187
|
}
|
|
100
188
|
}
|
|
@@ -6,39 +6,21 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.configureMemory = configureMemory;
|
|
7
7
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
8
8
|
async function configureMemory(_context) {
|
|
9
|
-
const {
|
|
9
|
+
const { provider } = await inquirer_1.default.prompt({
|
|
10
10
|
type: 'list',
|
|
11
|
-
name: '
|
|
12
|
-
message: 'Memory
|
|
11
|
+
name: 'provider',
|
|
12
|
+
message: 'Memory storage engine?',
|
|
13
13
|
choices: [
|
|
14
|
-
{ name: '
|
|
14
|
+
{ name: 'SQLite (Unified zero-config WAL + FTS5 full-text indexing)', value: 'sqlite' },
|
|
15
15
|
],
|
|
16
16
|
});
|
|
17
|
-
const { deployment } = await inquirer_1.default.prompt({
|
|
18
|
-
type: 'list',
|
|
19
|
-
name: 'deployment',
|
|
20
|
-
message: 'PostgreSQL deployment target?',
|
|
21
|
-
choices: [
|
|
22
|
-
{ name: 'Supabase (Hosted Postgres with connection pooling)', value: 'supabase' },
|
|
23
|
-
{ name: 'Neon (Serverless Postgres with branch-per-companion)', value: 'neon' },
|
|
24
|
-
{ name: 'Local PostgreSQL (System service or local installation)', value: 'local' },
|
|
25
|
-
{ name: 'Other PostgreSQL URL', value: 'other' },
|
|
26
|
-
],
|
|
27
|
-
});
|
|
28
|
-
const deploymentDisplayNames = {
|
|
29
|
-
supabase: 'Supabase',
|
|
30
|
-
neon: 'Neon',
|
|
31
|
-
local: 'Local PostgreSQL',
|
|
32
|
-
other: 'Other PostgreSQL',
|
|
33
|
-
};
|
|
34
17
|
return {
|
|
35
18
|
config: {
|
|
36
|
-
provider
|
|
37
|
-
deployment,
|
|
19
|
+
provider,
|
|
38
20
|
},
|
|
39
21
|
summary: {
|
|
40
|
-
Database: '
|
|
41
|
-
|
|
22
|
+
Database: 'SQLite (WAL + FTS5)',
|
|
23
|
+
Storage: 'siduri.sqlite',
|
|
42
24
|
},
|
|
43
25
|
};
|
|
44
26
|
}
|
|
@@ -179,14 +179,13 @@ describe('Guided Manifest-Driven Configuration UX Specification Tests', () => {
|
|
|
179
179
|
});
|
|
180
180
|
});
|
|
181
181
|
describe('Other Organ Configurators & Generic Router', () => {
|
|
182
|
-
test('Memory configurator configures
|
|
182
|
+
test('Memory configurator configures SQLite with WAL and FTS5', async () => {
|
|
183
183
|
inquirer_1.default.prompt
|
|
184
|
-
.mockResolvedValueOnce({
|
|
185
|
-
.mockResolvedValueOnce({ deployment: 'supabase' });
|
|
184
|
+
.mockResolvedValueOnce({ provider: 'sqlite' });
|
|
186
185
|
const result = await (0, memory_1.configureMemory)({ companionName: 'Sparkle', manifest: memoryManifest });
|
|
187
|
-
expect(result.config.provider).toBe('
|
|
188
|
-
expect(result.
|
|
189
|
-
expect(result.summary?.
|
|
186
|
+
expect(result.config.provider).toBe('sqlite');
|
|
187
|
+
expect(result.summary?.Database).toBe('SQLite (WAL + FTS5)');
|
|
188
|
+
expect(result.summary?.Storage).toBe('siduri.sqlite');
|
|
190
189
|
});
|
|
191
190
|
test('Voice configurator configures VOICEVOX engine and speaker ID', async () => {
|
|
192
191
|
inquirer_1.default.prompt
|
|
@@ -283,7 +282,7 @@ describe('Guided Manifest-Driven Configuration UX Specification Tests', () => {
|
|
|
283
282
|
test('formatReviewSummary displays actual configuration values and metadata', () => {
|
|
284
283
|
const summaryOutput = (0, index_1.formatReviewSummary)('Sparkle', [brainManifest, memoryManifest, knowledgeManifest, voiceManifest], {
|
|
285
284
|
brain: { Provider: 'OpenRouter', Model: 'openai/gpt-4o-mini' },
|
|
286
|
-
memory: { Database: '
|
|
285
|
+
memory: { Database: 'SQLite (WAL + FTS5)', Storage: 'siduri.sqlite' },
|
|
287
286
|
knowledge: { Source: 'E Knowledge Hub', Provider: 'E Teyvat', Package: '@vxnus/e-teyvat', Version: '1.2.0' },
|
|
288
287
|
voice: { Provider: 'VOICEVOX', 'Speaker ID': 1 },
|
|
289
288
|
});
|
|
@@ -292,8 +291,8 @@ describe('Guided Manifest-Driven Configuration UX Specification Tests', () => {
|
|
|
292
291
|
expect(summaryOutput).toContain('OpenRouter');
|
|
293
292
|
expect(summaryOutput).toContain('openai/gpt-4o-mini');
|
|
294
293
|
expect(summaryOutput).toContain('Memory');
|
|
295
|
-
expect(summaryOutput).toContain('
|
|
296
|
-
expect(summaryOutput).toContain('
|
|
294
|
+
expect(summaryOutput).toContain('SQLite');
|
|
295
|
+
expect(summaryOutput).toContain('siduri.sqlite');
|
|
297
296
|
expect(summaryOutput).toContain('Knowledge');
|
|
298
297
|
expect(summaryOutput).toContain('E Knowledge Hub');
|
|
299
298
|
expect(summaryOutput).toContain('E Teyvat');
|
|
@@ -304,7 +303,7 @@ describe('Guided Manifest-Driven Configuration UX Specification Tests', () => {
|
|
|
304
303
|
test('generateInstanceFiles accurately embeds configured organ values in siduri.config.json', () => {
|
|
305
304
|
const organConfigs = {
|
|
306
305
|
brain: { provider: 'openrouter', model: 'openai/gpt-4o-mini', apiKeyEnv: 'OPENROUTER_API_KEY' },
|
|
307
|
-
memory: { provider: '
|
|
306
|
+
memory: { provider: 'sqlite' },
|
|
308
307
|
knowledge: { provider: 'e-hub', registryUrl: 'https://e.vxnus.xyz/api/v1/knowledge', packId: '@vxnus/e-teyvat' },
|
|
309
308
|
voice: { provider: 'voicevox', speakerId: 2, baseUrl: 'http://localhost:50021' },
|
|
310
309
|
};
|
|
@@ -317,14 +316,14 @@ describe('Guided Manifest-Driven Configuration UX Specification Tests', () => {
|
|
|
317
316
|
expect(config.name).toBe('Sparkle');
|
|
318
317
|
expect(config.organs.brain.provider).toBe('openrouter');
|
|
319
318
|
expect(config.organs.brain.model).toBe('openai/gpt-4o-mini');
|
|
320
|
-
expect(config.organs.memory.
|
|
319
|
+
expect(config.organs.memory.provider).toBe('sqlite');
|
|
321
320
|
expect(config.organs.knowledge.provider).toBe('e-hub');
|
|
322
321
|
expect(config.organs.knowledge.packId).toBe('@vxnus/e-teyvat');
|
|
323
322
|
expect(config.organs.voice.speakerId).toBe(2);
|
|
324
323
|
// Verify explicit imports in src/index.js
|
|
325
324
|
expect(files['src/index.js']).toContain("import { OpenRouterBrain } from '@siduri-x/brain'");
|
|
326
325
|
expect(files['src/index.js']).toContain("import { SqliteMemoryStore } from '@siduri-x/memory'");
|
|
327
|
-
expect(files['src/index.js']).toContain("import {
|
|
326
|
+
expect(files['src/index.js']).toContain("import { UnifiedKnowledgeOrgan } from '@siduri-x/knowledge'");
|
|
328
327
|
expect(files['src/index.js']).toContain("import { VoiceAdapter } from '@siduri-x/voice'");
|
|
329
328
|
});
|
|
330
329
|
});
|
package/dist/doctor.js
CHANGED
|
@@ -129,25 +129,69 @@ async function runDoctor(options = {}) {
|
|
|
129
129
|
// 3. Check External Services
|
|
130
130
|
for (const m of selectedManifests) {
|
|
131
131
|
for (const service of m.services || []) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
132
|
+
const organConf = configuredOrgansMap[m.configKey] || configuredOrgansMap[m.organType];
|
|
133
|
+
const configuredUrl = organConf?.baseUrl || organConf?.url || effectiveEnv[`${service.name.toUpperCase()}_URL`];
|
|
134
|
+
if (configuredUrl && typeof configuredUrl === 'string' && configuredUrl.startsWith('http')) {
|
|
135
|
+
try {
|
|
136
|
+
const controller = new AbortController();
|
|
137
|
+
const timer = setTimeout(() => controller.abort(), 1000);
|
|
138
|
+
await fetch(configuredUrl, { signal: controller.signal }).catch(() => { });
|
|
139
|
+
clearTimeout(timer);
|
|
140
|
+
results.push({
|
|
141
|
+
category: 'Services',
|
|
142
|
+
name: `${service.name} (${m.organType})`,
|
|
143
|
+
status: 'PASS',
|
|
144
|
+
organName: m.name,
|
|
145
|
+
message: `Endpoint configured: ${configuredUrl}`,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
results.push({
|
|
150
|
+
category: 'Services',
|
|
151
|
+
name: `${service.name} (${m.organType})`,
|
|
152
|
+
status: 'OPTIONAL_MISSING',
|
|
153
|
+
organName: m.name,
|
|
154
|
+
message: `Service at ${configuredUrl} is not responding (optional local service)`,
|
|
155
|
+
remediation: `Start ${service.name} or allow auto-download if applicable.`,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
results.push({
|
|
161
|
+
category: 'Services',
|
|
162
|
+
name: `${service.name} (${m.organType})`,
|
|
163
|
+
status: 'PASS',
|
|
164
|
+
organName: m.name,
|
|
165
|
+
message: 'Service requirement declared (managed locally)',
|
|
166
|
+
});
|
|
167
|
+
}
|
|
139
168
|
}
|
|
140
169
|
}
|
|
141
170
|
// 4. Database Check (only if an organ declares database requirement)
|
|
142
171
|
const dbOrgan = selectedManifests.find((m) => m.database !== null && m.database !== undefined);
|
|
143
172
|
if (dbOrgan) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
173
|
+
try {
|
|
174
|
+
const testDbPath = node_path_1.default.join(projectDir, '.doctor-sqlite-test.tmp');
|
|
175
|
+
node_fs_1.default.writeFileSync(testDbPath, '');
|
|
176
|
+
node_fs_1.default.unlinkSync(testDbPath);
|
|
177
|
+
results.push({
|
|
178
|
+
category: 'Database',
|
|
179
|
+
name: 'SQLite Database',
|
|
180
|
+
status: 'PASS',
|
|
181
|
+
organName: dbOrgan.name,
|
|
182
|
+
message: 'Local storage directory writeable; SQLite operational',
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
results.push({
|
|
187
|
+
category: 'Database',
|
|
188
|
+
name: 'SQLite Database',
|
|
189
|
+
status: 'FAIL',
|
|
190
|
+
organName: dbOrgan.name,
|
|
191
|
+
message: `Storage directory write check failed: ${err.message}`,
|
|
192
|
+
remediation: 'Verify write permissions for the companion directory.',
|
|
193
|
+
});
|
|
194
|
+
}
|
|
151
195
|
}
|
|
152
196
|
else {
|
|
153
197
|
results.push({
|
package/dist/generator.js
CHANGED
|
@@ -36,7 +36,7 @@ function getDefaultConfigForManifest(manifest) {
|
|
|
36
36
|
config.apiKeyEnv = 'OPENROUTER_API_KEY';
|
|
37
37
|
}
|
|
38
38
|
else if (manifest.organType === 'memory') {
|
|
39
|
-
config.provider = config.provider || '
|
|
39
|
+
config.provider = config.provider || 'sqlite';
|
|
40
40
|
}
|
|
41
41
|
else if (manifest.organType === 'voice') {
|
|
42
42
|
config.provider = config.provider || 'voicevox';
|
|
@@ -72,7 +72,7 @@ function getDefaultConfigForManifest(manifest) {
|
|
|
72
72
|
function generateInstanceFiles(options) {
|
|
73
73
|
const instanceName = options.name || 'my-siduri';
|
|
74
74
|
const instanceId = options.id || 'default';
|
|
75
|
-
const coreVersion = options.coreVersion || '^
|
|
75
|
+
const coreVersion = options.coreVersion || '^2.0.1';
|
|
76
76
|
const manifests = options.selectedManifests;
|
|
77
77
|
const hasMemory = manifests.some((m) => m.organType === 'memory');
|
|
78
78
|
const hasVoice = manifests.some((m) => m.organType === 'voice');
|
|
@@ -80,14 +80,12 @@ function generateInstanceFiles(options) {
|
|
|
80
80
|
const hasMouth = manifests.some((m) => m.organType === 'mouth');
|
|
81
81
|
const voiceConfig = options.organConfigs?.voice || options.organConfigs?.['@siduri-x/voice'];
|
|
82
82
|
const isVoicevox = hasVoice && (!voiceConfig || voiceConfig.provider === 'voicevox');
|
|
83
|
-
const memoryConfig = options.organConfigs?.memory || options.organConfigs?.['@siduri-x/memory'];
|
|
84
|
-
const isPostgresLocal = hasMemory && (!memoryConfig || memoryConfig.deployment === 'local' || memoryConfig.provider === 'postgres');
|
|
85
83
|
// 1. package.json
|
|
86
84
|
const dependencies = {
|
|
87
85
|
'@siduri-x/core': coreVersion,
|
|
88
86
|
};
|
|
89
87
|
for (const m of manifests) {
|
|
90
|
-
dependencies[m.name] = `^${m.version || '
|
|
88
|
+
dependencies[m.name] = `^${m.version || '2.0.1'}`;
|
|
91
89
|
}
|
|
92
90
|
const scripts = {
|
|
93
91
|
start: 'node src/index.js',
|
|
@@ -95,12 +93,19 @@ function generateInstanceFiles(options) {
|
|
|
95
93
|
doctor: 'siduri doctor',
|
|
96
94
|
db: 'siduri db',
|
|
97
95
|
};
|
|
96
|
+
const devDependencies = {
|
|
97
|
+
'@vxnus/siduri': coreVersion,
|
|
98
|
+
};
|
|
98
99
|
const packageJsonObj = {
|
|
99
100
|
name: instanceName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') || 'my-siduri',
|
|
100
101
|
private: true,
|
|
101
102
|
type: 'module',
|
|
103
|
+
engines: {
|
|
104
|
+
node: '>=22.16.0',
|
|
105
|
+
},
|
|
102
106
|
scripts,
|
|
103
107
|
dependencies,
|
|
108
|
+
devDependencies,
|
|
104
109
|
};
|
|
105
110
|
const packageJson = JSON.stringify(packageJsonObj, null, 2) + '\n';
|
|
106
111
|
// 3. siduri.config.json
|
|
@@ -164,14 +169,35 @@ function generateInstanceFiles(options) {
|
|
|
164
169
|
`import { SiduriRuntime, dispatchCompanionChat, validateCompanionConfig } from '@siduri-x/core';`,
|
|
165
170
|
];
|
|
166
171
|
for (const m of manifests) {
|
|
167
|
-
|
|
172
|
+
if (m.name === '@siduri-x/self') {
|
|
173
|
+
importLines.push(`import { ActiveSelfCompiler, SqliteSelfRepository } from '@siduri-x/self';`);
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
importLines.push(`import { ${m.factory} } from '${m.name}';`);
|
|
177
|
+
}
|
|
168
178
|
}
|
|
169
179
|
const instantiationLines = [];
|
|
170
180
|
const organMapEntries = [];
|
|
171
181
|
for (const m of manifests) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
182
|
+
if (m.name === '@siduri-x/self') {
|
|
183
|
+
instantiationLines.push(`const self = new SqliteSelfRepository({ dbPath: path.resolve(rootDir, 'siduri.sqlite') });`);
|
|
184
|
+
instantiationLines.push(`const behavior = new ActiveSelfCompiler(config.organs.behavior);`);
|
|
185
|
+
organMapEntries.push(` behavior,`);
|
|
186
|
+
organMapEntries.push(` self,`);
|
|
187
|
+
}
|
|
188
|
+
else if (m.name === '@siduri-x/memory') {
|
|
189
|
+
instantiationLines.push(`const memory = new ${m.factory}({ ...config.organs.${m.configKey}, dbPath: path.resolve(rootDir, config.organs.${m.configKey}?.dbPath || 'siduri.sqlite') });`);
|
|
190
|
+
organMapEntries.push(` ${m.configKey},`);
|
|
191
|
+
}
|
|
192
|
+
else if (m.name === '@siduri-x/knowledge') {
|
|
193
|
+
instantiationLines.push(`const knowledge = new ${m.factory}({ ...config.organs.${m.configKey}, dbPath: path.resolve(rootDir, config.organs.${m.configKey}?.dbPath || 'siduri.sqlite') });`);
|
|
194
|
+
organMapEntries.push(` ${m.configKey},`);
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
const varName = m.configKey;
|
|
198
|
+
instantiationLines.push(`const ${varName} = new ${m.factory}(config.organs.${m.configKey});`);
|
|
199
|
+
organMapEntries.push(` ${varName},`);
|
|
200
|
+
}
|
|
175
201
|
}
|
|
176
202
|
if (hasMouth && hasVoice) {
|
|
177
203
|
instantiationLines.push(`if (typeof mouth?.setVoiceOrgan === 'function') mouth.setVoiceOrgan(voice);`);
|
|
@@ -184,6 +210,14 @@ function generateInstanceFiles(options) {
|
|
|
184
210
|
`const __dirname = path.dirname(__filename);`,
|
|
185
211
|
`const rootDir = path.resolve(__dirname, '..');`,
|
|
186
212
|
'',
|
|
213
|
+
`try {`,
|
|
214
|
+
` process.loadEnvFile(path.join(rootDir, '.env'));`,
|
|
215
|
+
`} catch (err) {`,
|
|
216
|
+
` if (err?.code !== 'ENOENT') {`,
|
|
217
|
+
` console.error('Failed to load .env file:', err.message);`,
|
|
218
|
+
` }`,
|
|
219
|
+
`}`,
|
|
220
|
+
'',
|
|
187
221
|
`const config = JSON.parse(`,
|
|
188
222
|
` await readFile(path.join(rootDir, 'siduri.config.json'), 'utf8')`,
|
|
189
223
|
`);`,
|
|
@@ -222,6 +256,51 @@ function generateInstanceFiles(options) {
|
|
|
222
256
|
` return;`,
|
|
223
257
|
` }`,
|
|
224
258
|
'',
|
|
259
|
+
` // API: Ready probe`,
|
|
260
|
+
` if (pathname === '/ready' && req.method === 'GET') {`,
|
|
261
|
+
` res.writeHead(200, { 'Content-Type': 'application/json' });`,
|
|
262
|
+
` res.end(JSON.stringify({ status: 'ready', companionId: config.id }));`,
|
|
263
|
+
` return;`,
|
|
264
|
+
` }`,
|
|
265
|
+
'',
|
|
266
|
+
` // API: Version info`,
|
|
267
|
+
` if (pathname === '/version' && req.method === 'GET') {`,
|
|
268
|
+
` res.writeHead(200, { 'Content-Type': 'application/json' });`,
|
|
269
|
+
` res.end(JSON.stringify({ version: '2.0.1', name: config.name, id: config.id }));`,
|
|
270
|
+
` return;`,
|
|
271
|
+
` }`,
|
|
272
|
+
'',
|
|
273
|
+
` // API: Identity info`,
|
|
274
|
+
` if (pathname === '/me' && req.method === 'GET') {`,
|
|
275
|
+
` res.writeHead(200, { 'Content-Type': 'application/json' });`,
|
|
276
|
+
` res.end(JSON.stringify({`,
|
|
277
|
+
` id: config.id,`,
|
|
278
|
+
` name: config.name,`,
|
|
279
|
+
` organs: Object.keys(config.organs || {}),`,
|
|
280
|
+
` }));`,
|
|
281
|
+
` return;`,
|
|
282
|
+
` }`,
|
|
283
|
+
'',
|
|
284
|
+
` // API: Voice & Observation health probes`,
|
|
285
|
+
` if (pathname === '/voice/health' && req.method === 'GET') {`,
|
|
286
|
+
` res.writeHead(200, { 'Content-Type': 'application/json' });`,
|
|
287
|
+
` res.end(JSON.stringify({ provider: config.organs?.voice?.provider || 'none', configured: Boolean(runtime.voice) }));`,
|
|
288
|
+
` return;`,
|
|
289
|
+
` }`,
|
|
290
|
+
'',
|
|
291
|
+
` if (pathname === '/obs/health' && req.method === 'GET') {`,
|
|
292
|
+
` res.writeHead(200, { 'Content-Type': 'application/json' });`,
|
|
293
|
+
` res.end(JSON.stringify({ provider: config.organs?.vision?.provider || 'none', configured: Boolean(runtime.vision) }));`,
|
|
294
|
+
` return;`,
|
|
295
|
+
` }`,
|
|
296
|
+
'',
|
|
297
|
+
` // API: Evidence & observations`,
|
|
298
|
+
` if ((pathname === '/evidence' || pathname === '/observations') && req.method === 'GET') {`,
|
|
299
|
+
` res.writeHead(200, { 'Content-Type': 'application/json' });`,
|
|
300
|
+
` res.end(JSON.stringify({ items: [] }));`,
|
|
301
|
+
` return;`,
|
|
302
|
+
` }`,
|
|
303
|
+
'',
|
|
225
304
|
` // API: Audio buffer retrieval for voice playback`,
|
|
226
305
|
` if (pathname.startsWith('/api/audio/') && req.method === 'GET') {`,
|
|
227
306
|
` const audioId = pathname.slice('/api/audio/'.length);`,
|
|
@@ -573,20 +652,17 @@ function generateInstanceFiles(options) {
|
|
|
573
652
|
'',
|
|
574
653
|
'## Prerequisites',
|
|
575
654
|
'',
|
|
576
|
-
'- **Node.js**: `
|
|
655
|
+
'- **Node.js**: `v22.16.0` or higher',
|
|
577
656
|
'- **Environment**: Valid `.env` file (configured from `.env.example`)',
|
|
578
657
|
];
|
|
579
658
|
if (hasMemory) {
|
|
580
|
-
readmeLines.push('- **
|
|
659
|
+
readmeLines.push('- **Database**: Embedded SQLite (`siduri.sqlite`). Automatically initialized with WAL mode and FTS5 full-text indexing with zero external setup.');
|
|
581
660
|
}
|
|
582
661
|
if (isVoicevox) {
|
|
583
662
|
readmeLines.push('- **VOICEVOX**: Note: The Voicevox engine executable will be securely auto-downloaded at runtime by Siduri if no local URL is provided.');
|
|
584
663
|
}
|
|
585
664
|
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`.');
|
|
586
|
-
|
|
587
|
-
readmeLines.push('', '### 3. Database Migrations', 'Ensure `DATABASE_URL` in `.env` is reachable, then push the memory organ PostgreSQL schema:', '```bash', 'npx @vxnus/siduri db push', '```');
|
|
588
|
-
}
|
|
589
|
-
readmeLines.push('', `### ${hasMemory ? '4' : '3'}. Diagnostics & Health Probe`, 'Verify all environment variables, schema conformance, services, and organ connections:', '```bash', 'npm run doctor', '```', '', `### ${hasMemory ? '5' : '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.');
|
|
665
|
+
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.');
|
|
590
666
|
const companionSlug = instanceName.toLowerCase().replace(/[^a-z0-9_-]/g, '') || 'default';
|
|
591
667
|
const createAssetsDirs = [];
|
|
592
668
|
if (hasBody) {
|