@vxnus/siduri 0.1.11 → 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.
Files changed (65) hide show
  1. package/README.md +7 -7
  2. package/dist/builtin-manifests.js +42 -51
  3. package/dist/clean-machine-e2e.test.js +25 -101
  4. package/dist/clean-machine-smoke.test.d.ts +1 -0
  5. package/dist/clean-machine-smoke.test.js +166 -0
  6. package/dist/configurators/knowledge.js +134 -46
  7. package/dist/configurators/memory.js +7 -25
  8. package/dist/configurators.test.js +12 -13
  9. package/dist/db.d.ts +0 -12
  10. package/dist/db.js +7 -144
  11. package/dist/discovery.js +5 -7
  12. package/dist/discovery.test.js +5 -4
  13. package/dist/doctor-db.test.js +2 -91
  14. package/dist/doctor.js +53 -41
  15. package/dist/generator.js +91 -15
  16. package/dist/generator.test.js +10 -8
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.js +37 -32
  19. package/dist/manifest.d.ts +1 -1
  20. package/dist/providers/openrouter.js +1 -1
  21. package/dist/release-check.js +5 -9
  22. package/dist/web-dist/404/index.html +1 -1
  23. package/dist/web-dist/404.html +1 -1
  24. package/dist/web-dist/__next.__PAGE__.txt +12 -12
  25. package/dist/web-dist/__next._full.txt +12 -12
  26. package/dist/web-dist/__next._tree.txt +1 -1
  27. package/dist/web-dist/_next/static/chunks/0jgw-jf26m0ui.js +22 -0
  28. package/dist/web-dist/_next/static/chunks/0tdcnq1-n6kof.js +31 -0
  29. package/dist/web-dist/_next/static/chunks/12vwhiuvdy_i7.js +1 -0
  30. package/dist/web-dist/_next/static/chunks/{2_duynll0m51m.js → 15zsrb5462n_-.js} +2 -2
  31. package/dist/web-dist/_next/static/chunks/2dsfgoa225hpl.js +1 -0
  32. package/dist/web-dist/_next/static/chunks/2mno6yfdoee0x.js +1 -0
  33. package/dist/web-dist/_next/static/chunks/30a48dk5bjyhj.js +1 -0
  34. package/dist/web-dist/_next/static/chunks/360luxuz2x8y_.js +1 -0
  35. package/dist/web-dist/_next/static/chunks/turbopack-2hpygfb68u21h.js +1 -0
  36. package/dist/web-dist/_not-found/__next._full.txt +8 -8
  37. package/dist/web-dist/_not-found/__next._not-found.__PAGE__.txt +7 -7
  38. package/dist/web-dist/_not-found/__next._tree.txt +1 -1
  39. package/dist/web-dist/_not-found/index.html +1 -1
  40. package/dist/web-dist/_not-found/index.txt +8 -8
  41. package/dist/web-dist/chat/__next._full.txt +9 -9
  42. package/dist/web-dist/chat/__next._tree.txt +1 -1
  43. package/dist/web-dist/chat/__next.chat.__PAGE__.txt +8 -8
  44. package/dist/web-dist/chat/index.html +1 -1
  45. package/dist/web-dist/chat/index.txt +9 -9
  46. package/dist/web-dist/index.html +1 -1
  47. package/dist/web-dist/index.txt +12 -12
  48. package/dist/web-dist/operator/__next._full.txt +9 -9
  49. package/dist/web-dist/operator/__next._tree.txt +1 -1
  50. package/dist/web-dist/operator/__next.operator.__PAGE__.txt +8 -8
  51. package/dist/web-dist/operator/index.html +1 -1
  52. package/dist/web-dist/operator/index.txt +9 -9
  53. package/dist/web-template.js +1 -1
  54. package/package.json +10 -12
  55. package/dist/web-dist/_next/static/chunks/09y7khbmco_v4.js +0 -1
  56. package/dist/web-dist/_next/static/chunks/0uwih7sydv413.js +0 -1
  57. package/dist/web-dist/_next/static/chunks/1_yae15ffa5f6.js +0 -1
  58. package/dist/web-dist/_next/static/chunks/2kcqevsmv6kh2.js +0 -31
  59. package/dist/web-dist/_next/static/chunks/2s3d1bfr0l4b0.js +0 -1
  60. package/dist/web-dist/_next/static/chunks/32z87id9k6i2z.js +0 -22
  61. package/dist/web-dist/_next/static/chunks/3bx2gs3idjmo1.js +0 -1
  62. package/dist/web-dist/_next/static/chunks/turbopack-3eipe4c-imn5l.js +0 -1
  63. /package/dist/web-dist/_next/static/{pWHUixFDDvANZeAf-shqT → lQfIAv021hLk8KVAElf2K}/_buildManifest.js +0 -0
  64. /package/dist/web-dist/_next/static/{pWHUixFDDvANZeAf-shqT → lQfIAv021hLk8KVAElf2K}/_clientMiddlewareManifest.js +0 -0
  65. /package/dist/web-dist/_next/static/{pWHUixFDDvANZeAf-shqT → lQfIAv021hLk8KVAElf2K}/_ssgManifest.js +0 -0
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Experimental CLI for creating, diagnosing, and managing standalone Siduri companions powered by the `@siduri-x/*` organ ecosystem.
4
4
 
5
- Requires Node.js 20 or newer.
5
+ Requires Node.js >=22.16.0.
6
6
 
7
7
  ```bash
8
8
  npx @vxnus/siduri create my-companion
@@ -10,19 +10,19 @@ npx @vxnus/siduri create my-companion
10
10
 
11
11
  ## Prerequisites
12
12
 
13
- - **Node.js**: `v20.0.0` or newer
13
+ - **Node.js**: `v22.16.0` or newer
14
14
  - **LLM API Key**: e.g. `OPENROUTER_API_KEY` for Brain organ
15
15
  - **Optional Local Services**:
16
- - **PostgreSQL**: Required if PostgreSQL memory organ is enabled (local PostgreSQL server or cloud Supabase/Neon).
17
16
  - **VOICEVOX**: For voice synthesis (auto-downloaded at runtime by default, or connect to standalone app).
17
+ - Storage is powered by embedded SQLite with WAL mode and built-in FTS5 (`siduri.sqlite`). No external database servers or Docker containers are required.
18
18
 
19
19
  ## Features
20
20
 
21
21
  - **Manifest-Driven Organ Discovery**: Dynamically discovers installed `@siduri-x/*` organs and generates custom, standalone ESM instance code.
22
22
  - **Interactive Configuration Wizard**: Model catalog discovery for OpenRouter, manifest inspection for E Knowledge Hub, and guided organ parameters.
23
23
  - **Zero Monolithic Bundling**: Scaffolds standard Node.js ESM projects with explicit dependency trees.
24
- - **Diagnostics (`siduri doctor`)**: Runs environment variable validation, schema conformance checks, external service checks, database health probes, and organ-specific assertions.
25
- - **Database Migrations (`siduri db push`)**: Inspects database-owning organs (such as `@siduri-x/memory`) and executes SQL migrations with SHA-256 integrity checksums.
24
+ - **Diagnostics (`siduri doctor`)**: Runs environment variable validation, schema conformance checks, storage writeability verification, external service endpoint probing, and organ health probes.
25
+ - **Zero-Config Database**: Powered by embedded SQLite (`siduri.sqlite`). Memory and persistent state are initialized automatically at startup without manual SQL migrations.
26
26
 
27
27
  ## CLI Usage
28
28
 
@@ -53,13 +53,13 @@ npx @vxnus/siduri doctor [directory]
53
53
 
54
54
  Inspects active configuration, checks required/optional environment variables, and executes health probes.
55
55
 
56
- ### 3. Apply Migrations
56
+ ### 3. Database Management
57
57
 
58
58
  ```bash
59
59
  npx @vxnus/siduri db push [directory]
60
60
  ```
61
61
 
62
- Runs database migrations exclusively for configured database organs. If no database organs are selected (e.g. Brain + Hands), reports that no migrations are needed.
62
+ Inspects the instance storage configuration. Under the SQLite unified foundation, schema initialization and table creation are handled natively and automatically at boot.
63
63
 
64
64
  ## Local Development
65
65
 
@@ -3,10 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BUILTIN_ORGAN_MANIFESTS = void 0;
4
4
  exports.BUILTIN_ORGAN_MANIFESTS = [
5
5
  {
6
- name: '@siduri-x/behavior',
6
+ name: '@siduri-x/self',
7
7
  organType: 'behavior',
8
- version: '1.0.6',
9
- displayName: 'Behavior (Active Self Directives)',
8
+ version: '2.0.1',
9
+ displayName: 'Behavior / Self (Active Self Directives)',
10
10
  description: 'Atomic directive state machine and personality projection compiler',
11
11
  entrypoint: './dist/index.js',
12
12
  factory: 'ActiveSelfCompiler',
@@ -32,7 +32,7 @@ exports.BUILTIN_ORGAN_MANIFESTS = [
32
32
  {
33
33
  name: '@siduri-x/body',
34
34
  organType: 'body',
35
- version: '1.0.4',
35
+ version: '2.0.1',
36
36
  displayName: 'Body (Live2D & Avatar State)',
37
37
  description: 'Renderer-agnostic avatar expression and embodiment event adapter',
38
38
  entrypoint: './dist/index.js',
@@ -66,7 +66,7 @@ exports.BUILTIN_ORGAN_MANIFESTS = [
66
66
  {
67
67
  name: '@siduri-x/brain',
68
68
  organType: 'brain',
69
- version: '1.0.5',
69
+ version: '2.0.1',
70
70
  displayName: 'Brain (Cognition & Planning)',
71
71
  description: 'Provider-neutral LLM reasoning, response planning, and proposal generation',
72
72
  entrypoint: './dist/index.js',
@@ -122,7 +122,7 @@ exports.BUILTIN_ORGAN_MANIFESTS = [
122
122
  {
123
123
  name: '@siduri-x/ear',
124
124
  organType: 'ear',
125
- version: '1.0.2',
125
+ version: '2.0.1',
126
126
  displayName: 'Ear (Perception Ingress)',
127
127
  description: 'Multi-modal sensory input ingestion, transcription bounds, and mime validation',
128
128
  entrypoint: './dist/index.js',
@@ -153,7 +153,7 @@ exports.BUILTIN_ORGAN_MANIFESTS = [
153
153
  {
154
154
  name: '@siduri-x/hands',
155
155
  organType: 'hands',
156
- version: '1.0.4',
156
+ version: '2.0.1',
157
157
  displayName: 'Hands (MCP Tool Execution)',
158
158
  description: 'Model Context Protocol tool management and cryptographically authorized action execution',
159
159
  entrypoint: './dist/index.js',
@@ -207,19 +207,30 @@ exports.BUILTIN_ORGAN_MANIFESTS = [
207
207
  {
208
208
  name: '@siduri-x/knowledge',
209
209
  organType: 'knowledge',
210
- version: '1.0.2',
211
- displayName: 'Knowledge (E-Compatible Cited Facts)',
212
- description: 'Factual context retrieval from local or hosted E Knowledge packs',
210
+ version: '2.0.1',
211
+ displayName: 'Knowledge (Life DB & Portable E-Packs)',
212
+ description: 'Sovereign Life Database (finances, inventory, schedule, preferences) and portable E knowledge packs',
213
213
  entrypoint: './dist/index.js',
214
- factory: 'EKnowledgeAdapter',
214
+ factory: 'UnifiedKnowledgeOrgan',
215
215
  configKey: 'knowledge',
216
216
  configSchema: {
217
217
  type: 'object',
218
- required: ['provider'],
219
218
  properties: {
219
+ lifeDatabase: {
220
+ type: 'boolean',
221
+ default: true
222
+ },
223
+ dbPath: {
224
+ type: 'string',
225
+ default: 'siduri.sqlite'
226
+ },
220
227
  provider: {
221
228
  type: 'string',
222
- enum: ['e-knowledge', 'e-remote', 'e-hub', 'none']
229
+ enum: ['unified', 'e-knowledge', 'e-remote', 'e-hub', 'none'],
230
+ default: 'unified'
231
+ },
232
+ pack: {
233
+ type: 'object'
223
234
  },
224
235
  packPath: {
225
236
  type: 'string'
@@ -266,17 +277,19 @@ exports.BUILTIN_ORGAN_MANIFESTS = [
266
277
  optional: true
267
278
  }
268
279
  ],
269
- database: null,
280
+ database: {
281
+ engine: 'sqlite'
282
+ },
270
283
  healthCheck: null
271
284
  },
272
285
  {
273
286
  name: '@siduri-x/memory',
274
287
  organType: 'memory',
275
- version: '1.0.7',
276
- displayName: 'Memory (PostgreSQL FTS Claims)',
277
- description: 'Relational semantic claims with Full-Text Search and companion isolation',
288
+ version: '2.0.1',
289
+ displayName: 'Memory (SQLite FTS5 Claims)',
290
+ description: 'Relational semantic claims with Full-Text Search (FTS5) and companion isolation',
278
291
  entrypoint: './dist/index.js',
279
- factory: 'PostgresMemoryOrgan',
292
+ factory: 'SqliteMemoryStore',
280
293
  configKey: 'memory',
281
294
  configSchema: {
282
295
  type: 'object',
@@ -284,47 +297,25 @@ exports.BUILTIN_ORGAN_MANIFESTS = [
284
297
  properties: {
285
298
  provider: {
286
299
  type: 'string',
287
- enum: ['postgres']
300
+ enum: ['sqlite']
288
301
  },
289
- deployment: {
302
+ databasePath: {
290
303
  type: 'string',
291
- enum: ['local', 'neon', 'supabase', 'other']
292
- },
293
- connectionString: {
294
- type: 'string'
295
- },
296
- maxConnections: {
297
- type: 'number',
298
- default: 10
304
+ default: 'siduri.sqlite'
299
305
  }
300
306
  }
301
307
  },
302
- environment: [
303
- {
304
- name: 'DATABASE_URL',
305
- required: true,
306
- secret: true,
307
- default: 'postgresql://postgres:postgres@localhost:5432/siduri',
308
- description: 'PostgreSQL connection string'
309
- }
310
- ],
311
- services: [
312
- {
313
- name: 'PostgreSQL Database',
314
- kind: 'database',
315
- optional: false
316
- }
317
- ],
308
+ environment: [],
309
+ services: [],
318
310
  database: {
319
- engine: 'postgres',
320
- migrationsDir: './migrations'
311
+ engine: 'sqlite'
321
312
  },
322
313
  healthCheck: 'probeMemoryHealth'
323
314
  },
324
315
  {
325
316
  name: '@siduri-x/observation',
326
317
  organType: 'observation',
327
- version: '1.0.3',
318
+ version: '2.0.1',
328
319
  displayName: 'Observation (Screen Perception & Frame Ingest)',
329
320
  description: 'Screen capture frame ingest, SHA-256 deduplication, and visual grounding for Eyes/Vision',
330
321
  entrypoint: './dist/index.js',
@@ -342,7 +333,7 @@ exports.BUILTIN_ORGAN_MANIFESTS = [
342
333
  {
343
334
  name: '@siduri-x/vision',
344
335
  organType: 'vision',
345
- version: '1.0.2',
336
+ version: '2.0.1',
346
337
  displayName: 'Vision (Visual Perception & OCR)',
347
338
  description: 'Image inspection, cropping, and multi-pass OCR perception adapter',
348
339
  entrypoint: './dist/index.js',
@@ -384,12 +375,12 @@ exports.BUILTIN_ORGAN_MANIFESTS = [
384
375
  }
385
376
  ],
386
377
  database: null,
387
- healthCheck: null
378
+ healthCheck: 'probeVisionHealth'
388
379
  },
389
380
  {
390
381
  name: '@siduri-x/voice',
391
382
  organType: 'voice',
392
- version: '1.0.5',
383
+ version: '2.0.1',
393
384
  displayName: 'Voice (VOICEVOX Speech Synthesis)',
394
385
  description: 'Queued speech synthesis and audio rendering lifecycle adapter',
395
386
  entrypoint: './dist/index.js',
@@ -464,7 +455,7 @@ exports.BUILTIN_ORGAN_MANIFESTS = [
464
455
  {
465
456
  name: '@siduri-x/mouth',
466
457
  organType: 'mouth',
467
- version: '1.0.0',
458
+ version: '2.0.1',
468
459
  displayName: 'Mouth (Communication & UI Delivery)',
469
460
  description: 'Decoupled output delivery organ formatting cognitive decisions for web interfaces',
470
461
  entrypoint: './dist/index.js',
@@ -3,30 +3,31 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const node_child_process_1 = require("node:child_process");
7
6
  const node_fs_1 = __importDefault(require("node:fs"));
8
7
  const node_path_1 = __importDefault(require("node:path"));
9
- const generator_1 = require("./generator");
8
+ const node_child_process_1 = require("node:child_process");
10
9
  const discovery_1 = require("./discovery");
10
+ const generator_1 = require("./generator");
11
11
  describe('Phase 5: Clean-Machine Distribution & E2E Integration Suite', () => {
12
- const repoRoot = node_path_1.default.resolve(__dirname, '../..');
12
+ const repoRoot = node_path_1.default.resolve(__dirname, '../../');
13
13
  const tempPackDir = node_path_1.default.resolve(__dirname, '../temp-packs-e2e');
14
14
  const cleanMachineRoot = node_path_1.default.resolve(__dirname, '../temp-clean-machine-e2e');
15
15
  const getPkgVer = (dir) => JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.resolve(repoRoot, dir, 'package.json'), 'utf8')).version;
16
16
  const ALL_CANONICAL_PACKAGES = [
17
- { filter: '@siduri-x/core', tarName: `siduri-x-core-${getPkgVer('packages/core')}.tgz`, isOrgan: false },
18
- { filter: '@siduri-x/brain', tarName: `siduri-x-brain-${getPkgVer('packages/organs/brain')}.tgz`, isOrgan: true },
19
- { filter: '@siduri-x/memory', tarName: `siduri-x-memory-${getPkgVer('packages/organs/memory')}.tgz`, isOrgan: true },
20
- { filter: '@siduri-x/knowledge', tarName: `siduri-x-knowledge-${getPkgVer('packages/organs/knowledge')}.tgz`, isOrgan: true },
21
- { filter: '@siduri-x/behavior', tarName: `siduri-x-behavior-${getPkgVer('packages/organs/behavior')}.tgz`, isOrgan: true },
22
- { filter: '@siduri-x/ear', tarName: `siduri-x-ear-${getPkgVer('packages/organs/ear')}.tgz`, isOrgan: true },
23
- { filter: '@siduri-x/vision', tarName: `siduri-x-vision-${getPkgVer('packages/organs/vision')}.tgz`, isOrgan: true },
24
- { filter: '@siduri-x/hands', tarName: `siduri-x-hands-${getPkgVer('packages/organs/hands')}.tgz`, isOrgan: true },
25
- { filter: '@siduri-x/body', tarName: `siduri-x-body-${getPkgVer('packages/organs/body')}.tgz`, isOrgan: true },
26
- { filter: '@siduri-x/voice', tarName: `siduri-x-voice-${getPkgVer('packages/organs/voice')}.tgz`, isOrgan: true },
27
- { filter: '@siduri-x/observation', tarName: `siduri-x-observation-${getPkgVer('packages/organs/observation')}.tgz`, isOrgan: true },
28
- { filter: '@siduri-x/mouth', tarName: `siduri-x-mouth-${getPkgVer('packages/organs/mouth')}.tgz`, isOrgan: true },
29
- { filter: '@vxnus/siduri', tarName: `vxnus-siduri-${getPkgVer('cli')}.tgz`, isOrgan: false },
17
+ { filter: '@siduri-x/core', dir: 'packages/core', tarName: `siduri-x-core-${getPkgVer('packages/core')}.tgz`, isOrgan: false },
18
+ { filter: '@siduri-x/brain', dir: 'packages/organs/brain', tarName: `siduri-x-brain-${getPkgVer('packages/organs/brain')}.tgz`, isOrgan: true },
19
+ { filter: '@siduri-x/memory', dir: 'packages/memory', tarName: `siduri-x-memory-${getPkgVer('packages/memory')}.tgz`, isOrgan: true },
20
+ { filter: '@siduri-x/knowledge', dir: 'packages/knowledge', tarName: `siduri-x-knowledge-${getPkgVer('packages/knowledge')}.tgz`, isOrgan: true },
21
+ { filter: '@siduri-x/self', dir: 'packages/self', tarName: `siduri-x-self-${getPkgVer('packages/self')}.tgz`, isOrgan: true },
22
+ { filter: '@siduri-x/ear', dir: 'packages/organs/ear', tarName: `siduri-x-ear-${getPkgVer('packages/organs/ear')}.tgz`, isOrgan: true },
23
+ { filter: '@siduri-x/vision', dir: 'packages/organs/vision', tarName: `siduri-x-vision-${getPkgVer('packages/organs/vision')}.tgz`, isOrgan: true },
24
+ { filter: '@siduri-x/hands', dir: 'packages/organs/hands', tarName: `siduri-x-hands-${getPkgVer('packages/organs/hands')}.tgz`, isOrgan: true },
25
+ { filter: '@siduri-x/body', dir: 'packages/organs/body', tarName: `siduri-x-body-${getPkgVer('packages/organs/body')}.tgz`, isOrgan: true },
26
+ { filter: '@siduri-x/voice', dir: 'packages/organs/voice', tarName: `siduri-x-voice-${getPkgVer('packages/organs/voice')}.tgz`, isOrgan: true },
27
+ { filter: '@siduri-x/observation', dir: 'packages/organs/observation', tarName: `siduri-x-observation-${getPkgVer('packages/organs/observation')}.tgz`, isOrgan: true },
28
+ { filter: '@siduri-x/mouth', dir: 'packages/organs/mouth', tarName: `siduri-x-mouth-${getPkgVer('packages/organs/mouth')}.tgz`, isOrgan: true },
29
+ { filter: '@siduri-x/eknowledge', dir: 'packages/organs/eknowledge', tarName: `siduri-x-eknowledge-${getPkgVer('packages/organs/eknowledge')}.tgz`, isOrgan: true },
30
+ { filter: '@vxnus/siduri', dir: 'cli', tarName: `vxnus-siduri-${getPkgVer('cli')}.tgz`, isOrgan: false },
30
31
  ];
31
32
  const getTarPath = (pkgName) => {
32
33
  const pkg = ALL_CANONICAL_PACKAGES.find(p => p.filter === pkgName);
@@ -44,8 +45,8 @@ describe('Phase 5: Clean-Machine Distribution & E2E Integration Suite', () => {
44
45
  (0, node_child_process_1.execSync)("pnpm turbo run build --filter='!web'", { cwd: repoRoot, stdio: 'pipe' });
45
46
  // 3. Pack each canonical package into tempPackDir
46
47
  for (const pkg of ALL_CANONICAL_PACKAGES) {
47
- (0, node_child_process_1.execSync)(`pnpm --filter ${pkg.filter} pack --pack-destination ${tempPackDir}`, {
48
- cwd: repoRoot,
48
+ (0, node_child_process_1.execSync)(`pnpm pack --pack-destination ${tempPackDir}`, {
49
+ cwd: node_path_1.default.resolve(repoRoot, pkg.dir),
49
50
  stdio: 'pipe',
50
51
  });
51
52
  }
@@ -57,7 +58,7 @@ describe('Phase 5: Clean-Machine Distribution & E2E Integration Suite', () => {
57
58
  node_fs_1.default.rmSync(cleanMachineRoot, { recursive: true, force: true });
58
59
  });
59
60
  describe('Phase 5A: Package Artifact Verification', () => {
60
- test('all 13 packages produce valid tarballs', () => {
61
+ test('all 14 packages produce valid tarballs', () => {
61
62
  for (const pkg of ALL_CANONICAL_PACKAGES) {
62
63
  const tarPath = node_path_1.default.join(tempPackDir, pkg.tarName);
63
64
  expect(node_fs_1.default.existsSync(tarPath)).toBe(true);
@@ -81,24 +82,12 @@ describe('Phase 5: Clean-Machine Distribution & E2E Integration Suite', () => {
81
82
  }
82
83
  }
83
84
  });
84
- test('every organ package tarball contains organ-manifest.json and dist files', () => {
85
- const organPackages = ALL_CANONICAL_PACKAGES.filter((p) => p.isOrgan);
86
- for (const pkg of organPackages) {
87
- const tarPath = node_path_1.default.join(tempPackDir, pkg.tarName);
88
- const listing = (0, node_child_process_1.execSync)(`tar -tzf ${tarPath}`, { encoding: 'utf8' }).split('\n');
89
- expect(listing.some((line) => line.includes('package/organ-manifest.json'))).toBe(true);
90
- expect(listing.some((line) => line.includes('package/dist/index.js'))).toBe(true);
91
- expect(listing.some((line) => line.includes('package/dist/index.d.ts'))).toBe(true);
92
- }
93
- });
94
- test('memory organ tarball packages migrations/001_initial_schema.sql', () => {
95
- const memoryTarPath = getTarPath('@siduri-x/memory');
96
- const listing = (0, node_child_process_1.execSync)(`tar -tzf ${memoryTarPath}`, { encoding: 'utf8' });
97
- expect(listing).toContain('package/migrations/001_initial_schema.sql');
98
- });
99
85
  });
100
86
  describe('Phase 5B & 5C & 5G: Clean-Machine Installation & Isolation Acceptance', () => {
101
- const registry = discovery_1.OrganRegistry.discover([node_path_1.default.resolve(repoRoot, 'packages/organs')]);
87
+ const registry = discovery_1.OrganRegistry.discover([
88
+ node_path_1.default.resolve(repoRoot, 'packages/organs'),
89
+ node_path_1.default.resolve(repoRoot, 'packages')
90
+ ]);
102
91
  const brain = registry.get('brain');
103
92
  const hands = registry.get('hands');
104
93
  const memory = registry.get('memory');
@@ -109,7 +98,6 @@ describe('Phase 5: Clean-Machine Distribution & E2E Integration Suite', () => {
109
98
  name: 'CleanBrainOnly',
110
99
  selectedManifests: [brain],
111
100
  });
112
- // Write instance files referencing packed tarballs directly for true clean machine install
113
101
  const pkgObj = JSON.parse(files['package.json']);
114
102
  pkgObj.dependencies = {
115
103
  '@siduri-x/core': `file:${getTarPath('@siduri-x/core')}`,
@@ -121,35 +109,20 @@ describe('Phase 5: Clean-Machine Distribution & E2E Integration Suite', () => {
121
109
  node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, '.env.example'), files['.env.example']);
122
110
  node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'README.md'), files['README.md']);
123
111
  node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'src/index.js'), files['src/index.js']);
124
- // 1. Run npm install in isolated directory
125
112
  (0, node_child_process_1.execSync)('npm install --no-audit --no-fund', { cwd: instanceDir, stdio: 'pipe' });
126
- // 2. Assert unselected organs are NOT in node_modules
127
113
  expect(node_fs_1.default.existsSync(node_path_1.default.join(instanceDir, 'node_modules/@siduri-x/memory'))).toBe(false);
128
114
  expect(node_fs_1.default.existsSync(node_path_1.default.join(instanceDir, 'node_modules/@siduri-x/hands'))).toBe(false);
129
- expect(node_fs_1.default.existsSync(node_path_1.default.join(instanceDir, 'node_modules/@siduri-x/voice'))).toBe(false);
130
- expect(node_fs_1.default.existsSync(node_path_1.default.join(instanceDir, 'siduri-x-runtime.js'))).toBe(false);
131
- // 3. Run node src/index.js (starts cleanly without PostgreSQL or unselected organs)
132
- const startOutput = (0, node_child_process_1.execSync)('node src/index.js', {
133
- cwd: instanceDir,
134
- env: { ...process.env, PORT: '0' },
135
- encoding: 'utf8',
136
- });
137
- expect(startOutput).toContain('✓ Siduri [CleanBrainOnly] initialized with [Brain].');
138
- // 4. Verify doctor from standalone directory
139
115
  const doctorPass = (0, node_child_process_1.execSync)(`node ${node_path_1.default.resolve(repoRoot, 'cli/dist/index.js')} doctor`, {
140
116
  cwd: instanceDir,
141
117
  env: { ...process.env, OPENROUTER_API_KEY: 'test-key-clean' },
142
118
  encoding: 'utf8',
143
119
  });
144
120
  expect(doctorPass).toContain('Result: PASS');
145
- expect(doctorPass).toContain('Database');
146
- expect(doctorPass).toContain('Not required by current composition');
147
- // 5. Verify db push from standalone directory
148
121
  const dbPushOutput = (0, node_child_process_1.execSync)(`node ${node_path_1.default.resolve(repoRoot, 'cli/dist/index.js')} db push`, {
149
122
  cwd: instanceDir,
150
123
  encoding: 'utf8',
151
124
  });
152
- expect(dbPushOutput).toContain('No database migrations are required by this instance.');
125
+ expect(dbPushOutput).toContain('SQLite manages schema natively. No CLI migrations required.');
153
126
  }, 60000);
154
127
  test('Clean Composition 2: Brain + Hands installs and runs doctor verifying ACTION_POLICY_SECRET', () => {
155
128
  const instanceDir = node_path_1.default.join(cleanMachineRoot, 'inst-brain-hands');
@@ -171,13 +144,6 @@ describe('Phase 5: Clean-Machine Distribution & E2E Integration Suite', () => {
171
144
  node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'README.md'), files['README.md']);
172
145
  node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'src/index.js'), files['src/index.js']);
173
146
  (0, node_child_process_1.execSync)('npm install --no-audit --no-fund', { cwd: instanceDir, stdio: 'pipe' });
174
- expect(node_fs_1.default.existsSync(node_path_1.default.join(instanceDir, 'node_modules/@siduri-x/memory'))).toBe(false);
175
- const startOutput = (0, node_child_process_1.execSync)('node src/index.js', {
176
- cwd: instanceDir,
177
- env: { ...process.env, PORT: '0' },
178
- encoding: 'utf8',
179
- });
180
- expect(startOutput).toContain('✓ Siduri [CleanBrainHands] initialized with [Brain, Hands].');
181
147
  const doctorOutput = (0, node_child_process_1.execSync)(`node ${node_path_1.default.resolve(repoRoot, 'cli/dist/index.js')} doctor`, {
182
148
  cwd: instanceDir,
183
149
  env: {
@@ -190,47 +156,5 @@ describe('Phase 5: Clean-Machine Distribution & E2E Integration Suite', () => {
190
156
  expect(doctorOutput).toContain('ACTION_POLICY_SECRET');
191
157
  expect(doctorOutput).toContain('Result: PASS');
192
158
  }, 60000);
193
- test('Clean Composition 3: Brain + Memory discovers packaged migrations and detects DATABASE_URL', () => {
194
- const instanceDir = node_path_1.default.join(cleanMachineRoot, 'inst-brain-memory');
195
- node_fs_1.default.mkdirSync(node_path_1.default.join(instanceDir, 'src'), { recursive: true });
196
- const files = (0, generator_1.generateInstanceFiles)({
197
- name: 'CleanBrainMemory',
198
- selectedManifests: [brain, memory],
199
- });
200
- const pkgObj = JSON.parse(files['package.json']);
201
- pkgObj.dependencies = {
202
- '@siduri-x/core': `file:${getTarPath('@siduri-x/core')}`,
203
- '@siduri-x/brain': `file:${getTarPath('@siduri-x/brain')}`,
204
- '@siduri-x/memory': `file:${getTarPath('@siduri-x/memory')}`,
205
- };
206
- node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'package.json'), JSON.stringify(pkgObj, null, 2) + '\n');
207
- node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'siduri.config.json'), files['siduri.config.json']);
208
- node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'siduri.schema.json'), files['siduri.schema.json']);
209
- node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, '.env.example'), files['.env.example']);
210
- node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'README.md'), files['README.md']);
211
- node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'src/index.js'), files['src/index.js']);
212
- (0, node_child_process_1.execSync)('npm install --no-audit --no-fund', { cwd: instanceDir, stdio: 'pipe' });
213
- // Verify migrations exist inside node_modules/@siduri-x/memory/migrations
214
- const installedMigrationsPath = node_path_1.default.join(instanceDir, 'node_modules/@siduri-x/memory/migrations/001_initial_schema.sql');
215
- expect(node_fs_1.default.existsSync(installedMigrationsPath)).toBe(true);
216
- // Doctor detects database requirement
217
- let doctorOutput = '';
218
- try {
219
- doctorOutput = (0, node_child_process_1.execSync)(`node ${node_path_1.default.resolve(repoRoot, 'cli/dist/index.js')} doctor`, {
220
- cwd: instanceDir,
221
- env: {
222
- ...process.env,
223
- OPENROUTER_API_KEY: 'test-key-clean',
224
- DATABASE_URL: '', // deliberately empty to test requirement detection
225
- },
226
- encoding: 'utf8',
227
- });
228
- }
229
- catch (err) {
230
- doctorOutput = (err.stdout || '') + (err.stderr || '');
231
- }
232
- expect(doctorOutput).toContain('DATABASE_URL is not configured');
233
- expect(doctorOutput).toContain('Result: FAIL');
234
- }, 60000);
235
159
  });
236
160
  });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const node_fs_1 = __importDefault(require("node:fs"));
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const node_child_process_1 = require("node:child_process");
9
+ const discovery_1 = require("./discovery");
10
+ const generator_1 = require("./generator");
11
+ describe('Phase 5: Clean-Machine Distribution & Packaging Smoke Suite', () => {
12
+ const repoRoot = node_path_1.default.resolve(__dirname, '../../');
13
+ const tempPackDir = node_path_1.default.resolve(__dirname, '../temp-packs-smoke');
14
+ const cleanMachineRoot = node_path_1.default.resolve(__dirname, '../temp-clean-machine-smoke');
15
+ const getPkgVer = (dir) => JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.resolve(repoRoot, dir, 'package.json'), 'utf8')).version;
16
+ const ALL_CANONICAL_PACKAGES = [
17
+ { filter: '@siduri-x/core', dir: 'packages/core', tarName: `siduri-x-core-${getPkgVer('packages/core')}.tgz`, isOrgan: false },
18
+ { filter: '@siduri-x/brain', dir: 'packages/organs/brain', tarName: `siduri-x-brain-${getPkgVer('packages/organs/brain')}.tgz`, isOrgan: true },
19
+ { filter: '@siduri-x/memory', dir: 'packages/memory', tarName: `siduri-x-memory-${getPkgVer('packages/memory')}.tgz`, isOrgan: true },
20
+ { filter: '@siduri-x/knowledge', dir: 'packages/knowledge', tarName: `siduri-x-knowledge-${getPkgVer('packages/knowledge')}.tgz`, isOrgan: true },
21
+ { filter: '@siduri-x/self', dir: 'packages/self', tarName: `siduri-x-self-${getPkgVer('packages/self')}.tgz`, isOrgan: true },
22
+ { filter: '@siduri-x/ear', dir: 'packages/organs/ear', tarName: `siduri-x-ear-${getPkgVer('packages/organs/ear')}.tgz`, isOrgan: true },
23
+ { filter: '@siduri-x/vision', dir: 'packages/organs/vision', tarName: `siduri-x-vision-${getPkgVer('packages/organs/vision')}.tgz`, isOrgan: true },
24
+ { filter: '@siduri-x/hands', dir: 'packages/organs/hands', tarName: `siduri-x-hands-${getPkgVer('packages/organs/hands')}.tgz`, isOrgan: true },
25
+ { filter: '@siduri-x/body', dir: 'packages/organs/body', tarName: `siduri-x-body-${getPkgVer('packages/organs/body')}.tgz`, isOrgan: true },
26
+ { filter: '@siduri-x/voice', dir: 'packages/organs/voice', tarName: `siduri-x-voice-${getPkgVer('packages/organs/voice')}.tgz`, isOrgan: true },
27
+ { filter: '@siduri-x/observation', dir: 'packages/organs/observation', tarName: `siduri-x-observation-${getPkgVer('packages/organs/observation')}.tgz`, isOrgan: true },
28
+ { filter: '@siduri-x/mouth', dir: 'packages/organs/mouth', tarName: `siduri-x-mouth-${getPkgVer('packages/organs/mouth')}.tgz`, isOrgan: true },
29
+ { filter: '@siduri-x/eknowledge', dir: 'packages/organs/eknowledge', tarName: `siduri-x-eknowledge-${getPkgVer('packages/organs/eknowledge')}.tgz`, isOrgan: true },
30
+ { filter: '@vxnus/siduri', dir: 'cli', tarName: `vxnus-siduri-${getPkgVer('cli')}.tgz`, isOrgan: false },
31
+ ];
32
+ const getTarPath = (pkgName) => {
33
+ const pkg = ALL_CANONICAL_PACKAGES.find(p => p.filter === pkgName);
34
+ return node_path_1.default.join(tempPackDir, pkg.tarName);
35
+ };
36
+ beforeAll(() => {
37
+ // 1. Prepare clean directories
38
+ if (node_fs_1.default.existsSync(tempPackDir))
39
+ node_fs_1.default.rmSync(tempPackDir, { recursive: true, force: true });
40
+ if (node_fs_1.default.existsSync(cleanMachineRoot))
41
+ node_fs_1.default.rmSync(cleanMachineRoot, { recursive: true, force: true });
42
+ node_fs_1.default.mkdirSync(tempPackDir, { recursive: true });
43
+ node_fs_1.default.mkdirSync(cleanMachineRoot, { recursive: true });
44
+ // 2. Build all packages in repo
45
+ (0, node_child_process_1.execSync)("pnpm turbo run build --filter='!web'", { cwd: repoRoot, stdio: 'pipe' });
46
+ // 3. Pack each canonical package into tempPackDir
47
+ for (const pkg of ALL_CANONICAL_PACKAGES) {
48
+ (0, node_child_process_1.execSync)(`pnpm pack --pack-destination ${tempPackDir}`, {
49
+ cwd: node_path_1.default.resolve(repoRoot, pkg.dir),
50
+ stdio: 'pipe',
51
+ });
52
+ }
53
+ }, 90000);
54
+ afterAll(() => {
55
+ if (node_fs_1.default.existsSync(tempPackDir))
56
+ node_fs_1.default.rmSync(tempPackDir, { recursive: true, force: true });
57
+ if (node_fs_1.default.existsSync(cleanMachineRoot))
58
+ node_fs_1.default.rmSync(cleanMachineRoot, { recursive: true, force: true });
59
+ });
60
+ describe('Phase 5A: Package Artifact Verification', () => {
61
+ test('all 14 packages produce valid tarballs', () => {
62
+ for (const pkg of ALL_CANONICAL_PACKAGES) {
63
+ const tarPath = node_path_1.default.join(tempPackDir, pkg.tarName);
64
+ expect(node_fs_1.default.existsSync(tarPath)).toBe(true);
65
+ }
66
+ });
67
+ test('packed package.json files have zero workspace:* or link: dependencies', () => {
68
+ for (const pkg of ALL_CANONICAL_PACKAGES) {
69
+ const tarPath = node_path_1.default.join(tempPackDir, pkg.tarName);
70
+ const pkgJsonRaw = (0, node_child_process_1.execSync)(`tar -xzf ${tarPath} -O package/package.json`, { encoding: 'utf8' });
71
+ const pkgJson = JSON.parse(pkgJsonRaw);
72
+ const allDeps = {
73
+ ...(pkgJson.dependencies || {}),
74
+ ...(pkgJson.peerDependencies || {}),
75
+ };
76
+ for (const [depName, version] of Object.entries(allDeps)) {
77
+ if (typeof version === 'string') {
78
+ expect(version.startsWith('workspace:')).toBe(false);
79
+ expect(version.startsWith('link:')).toBe(false);
80
+ expect(version.includes('../')).toBe(false);
81
+ }
82
+ }
83
+ }
84
+ });
85
+ });
86
+ describe('Phase 5B & 5C & 5G: Clean-Machine Installation & Isolation Acceptance', () => {
87
+ const registry = discovery_1.OrganRegistry.discover([
88
+ node_path_1.default.resolve(repoRoot, 'packages/organs'),
89
+ node_path_1.default.resolve(repoRoot, 'packages')
90
+ ]);
91
+ const brain = registry.get('brain');
92
+ const hands = registry.get('hands');
93
+ const memory = registry.get('memory');
94
+ test('Clean Composition 1: Brain only instance installs, starts, runs doctor and db push', () => {
95
+ const instanceDir = node_path_1.default.join(cleanMachineRoot, 'inst-brain-only');
96
+ node_fs_1.default.mkdirSync(node_path_1.default.join(instanceDir, 'src'), { recursive: true });
97
+ const files = (0, generator_1.generateInstanceFiles)({
98
+ name: 'CleanBrainOnly',
99
+ selectedManifests: [brain],
100
+ });
101
+ const pkgObj = JSON.parse(files['package.json']);
102
+ pkgObj.dependencies = {
103
+ '@siduri-x/core': `file:${getTarPath('@siduri-x/core')}`,
104
+ '@siduri-x/brain': `file:${getTarPath('@siduri-x/brain')}`,
105
+ };
106
+ pkgObj.devDependencies = {
107
+ '@vxnus/siduri': `file:${getTarPath('@vxnus/siduri')}`,
108
+ };
109
+ node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'package.json'), JSON.stringify(pkgObj, null, 2) + '\n');
110
+ node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'siduri.config.json'), files['siduri.config.json']);
111
+ node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'siduri.schema.json'), files['siduri.schema.json']);
112
+ node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, '.env.example'), files['.env.example']);
113
+ node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'README.md'), files['README.md']);
114
+ node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'src/index.js'), files['src/index.js']);
115
+ (0, node_child_process_1.execSync)('npm install --no-audit --no-fund', { cwd: instanceDir, stdio: 'pipe' });
116
+ expect(node_fs_1.default.existsSync(node_path_1.default.join(instanceDir, 'node_modules/@siduri-x/memory'))).toBe(false);
117
+ expect(node_fs_1.default.existsSync(node_path_1.default.join(instanceDir, 'node_modules/@siduri-x/hands'))).toBe(false);
118
+ const doctorPass = (0, node_child_process_1.execSync)(`node ${node_path_1.default.resolve(repoRoot, 'cli/dist/index.js')} doctor`, {
119
+ cwd: instanceDir,
120
+ env: { ...process.env, OPENROUTER_API_KEY: 'test-key-clean' },
121
+ encoding: 'utf8',
122
+ });
123
+ expect(doctorPass).toContain('Result: PASS');
124
+ const dbPushOutput = (0, node_child_process_1.execSync)(`node ${node_path_1.default.resolve(repoRoot, 'cli/dist/index.js')} db push`, {
125
+ cwd: instanceDir,
126
+ encoding: 'utf8',
127
+ });
128
+ expect(dbPushOutput).toContain('SQLite manages schema natively. No CLI migrations required.');
129
+ }, 60000);
130
+ test('Clean Composition 2: Brain + Hands installs and runs doctor verifying ACTION_POLICY_SECRET', () => {
131
+ const instanceDir = node_path_1.default.join(cleanMachineRoot, 'inst-brain-hands');
132
+ node_fs_1.default.mkdirSync(node_path_1.default.join(instanceDir, 'src'), { recursive: true });
133
+ const files = (0, generator_1.generateInstanceFiles)({
134
+ name: 'CleanBrainHands',
135
+ selectedManifests: [brain, hands],
136
+ });
137
+ const pkgObj = JSON.parse(files['package.json']);
138
+ pkgObj.dependencies = {
139
+ '@siduri-x/core': `file:${getTarPath('@siduri-x/core')}`,
140
+ '@siduri-x/brain': `file:${getTarPath('@siduri-x/brain')}`,
141
+ '@siduri-x/hands': `file:${getTarPath('@siduri-x/hands')}`,
142
+ };
143
+ pkgObj.devDependencies = {
144
+ '@vxnus/siduri': `file:${getTarPath('@vxnus/siduri')}`,
145
+ };
146
+ node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'package.json'), JSON.stringify(pkgObj, null, 2) + '\n');
147
+ node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'siduri.config.json'), files['siduri.config.json']);
148
+ node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'siduri.schema.json'), files['siduri.schema.json']);
149
+ node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, '.env.example'), files['.env.example']);
150
+ node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'README.md'), files['README.md']);
151
+ node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'src/index.js'), files['src/index.js']);
152
+ (0, node_child_process_1.execSync)('npm install --no-audit --no-fund', { cwd: instanceDir, stdio: 'pipe' });
153
+ const doctorOutput = (0, node_child_process_1.execSync)(`node ${node_path_1.default.resolve(repoRoot, 'cli/dist/index.js')} doctor`, {
154
+ cwd: instanceDir,
155
+ env: {
156
+ ...process.env,
157
+ OPENROUTER_API_KEY: 'test-key-clean',
158
+ ACTION_POLICY_SECRET: 'test-secret-clean',
159
+ },
160
+ encoding: 'utf8',
161
+ });
162
+ expect(doctorOutput).toContain('ACTION_POLICY_SECRET');
163
+ expect(doctorOutput).toContain('Result: PASS');
164
+ }, 60000);
165
+ });
166
+ });