@vxnus/siduri 0.1.8 → 0.1.10

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 (61) hide show
  1. package/dist/builtin-manifests.d.ts +2 -0
  2. package/dist/builtin-manifests.js +492 -0
  3. package/dist/clean-machine-e2e.test.d.ts +1 -0
  4. package/dist/clean-machine-e2e.test.js +236 -0
  5. package/dist/configurators/behavior.d.ts +2 -0
  6. package/dist/configurators/behavior.js +36 -0
  7. package/dist/configurators/body.d.ts +2 -0
  8. package/dist/configurators/body.js +60 -0
  9. package/dist/configurators/brain.d.ts +6 -0
  10. package/dist/configurators/brain.js +80 -0
  11. package/dist/configurators/ear.d.ts +2 -0
  12. package/dist/configurators/ear.js +28 -0
  13. package/dist/configurators/hands.d.ts +2 -0
  14. package/dist/configurators/hands.js +27 -0
  15. package/dist/configurators/index.d.ts +24 -0
  16. package/dist/configurators/index.js +78 -0
  17. package/dist/configurators/knowledge.d.ts +6 -0
  18. package/dist/configurators/knowledge.js +100 -0
  19. package/dist/configurators/memory.d.ts +2 -0
  20. package/dist/configurators/memory.js +44 -0
  21. package/dist/configurators/mouth.d.ts +2 -0
  22. package/dist/configurators/mouth.js +15 -0
  23. package/dist/configurators/observation.d.ts +2 -0
  24. package/dist/configurators/observation.js +12 -0
  25. package/dist/configurators/types.d.ts +12 -0
  26. package/dist/configurators/types.js +2 -0
  27. package/dist/configurators/vision.d.ts +2 -0
  28. package/dist/configurators/vision.js +39 -0
  29. package/dist/configurators/voice.d.ts +2 -0
  30. package/dist/configurators/voice.js +477 -0
  31. package/dist/configurators.test.d.ts +1 -0
  32. package/dist/configurators.test.js +331 -0
  33. package/dist/db.d.ts +25 -0
  34. package/dist/db.js +152 -0
  35. package/dist/discovery.d.ts +13 -0
  36. package/dist/discovery.js +87 -0
  37. package/dist/discovery.test.d.ts +1 -0
  38. package/dist/discovery.test.js +69 -0
  39. package/dist/doctor-db.test.d.ts +1 -0
  40. package/dist/doctor-db.test.js +141 -0
  41. package/dist/doctor.d.ts +19 -0
  42. package/dist/doctor.js +225 -0
  43. package/dist/generator.d.ts +21 -0
  44. package/dist/generator.js +666 -0
  45. package/dist/generator.test.d.ts +1 -0
  46. package/dist/generator.test.js +197 -0
  47. package/dist/index.d.ts +20 -0
  48. package/dist/index.js +401 -0
  49. package/dist/manifest.d.ts +33 -0
  50. package/dist/manifest.js +40 -0
  51. package/dist/providers/knowledge-hub.d.ts +37 -0
  52. package/dist/providers/knowledge-hub.js +141 -0
  53. package/dist/providers/openrouter.d.ts +32 -0
  54. package/dist/providers/openrouter.js +201 -0
  55. package/dist/release-check.d.ts +9 -0
  56. package/dist/release-check.js +133 -0
  57. package/dist/runtime-parity.test.d.ts +1 -0
  58. package/dist/runtime-parity.test.js +140 -0
  59. package/dist/web-template.d.ts +2 -0
  60. package/dist/web-template.js +557 -0
  61. package/package.json +1 -1
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateOrganManifest = validateOrganManifest;
4
+ function validateOrganManifest(manifest, sourcePath) {
5
+ if (!manifest || typeof manifest !== 'object') {
6
+ throw new Error(`Invalid manifest at ${sourcePath || 'unknown'}: expected an object`);
7
+ }
8
+ const m = manifest;
9
+ if (!m.name || typeof m.name !== 'string' || !m.name.startsWith('@siduri-x/')) {
10
+ throw new Error(`Invalid manifest name in ${sourcePath || 'unknown'}: expected package name starting with @siduri-x/`);
11
+ }
12
+ if (!m.organType || typeof m.organType !== 'string') {
13
+ throw new Error(`Invalid manifest organType in ${sourcePath || m.name}`);
14
+ }
15
+ if (!m.version || typeof m.version !== 'string') {
16
+ throw new Error(`Invalid manifest version in ${sourcePath || m.name}`);
17
+ }
18
+ if (!m.displayName || typeof m.displayName !== 'string') {
19
+ throw new Error(`Invalid manifest displayName in ${sourcePath || m.name}`);
20
+ }
21
+ if (!m.entrypoint || typeof m.entrypoint !== 'string') {
22
+ throw new Error(`Invalid manifest entrypoint in ${sourcePath || m.name}`);
23
+ }
24
+ if (!m.factory || typeof m.factory !== 'string') {
25
+ throw new Error(`Invalid manifest factory in ${sourcePath || m.name}`);
26
+ }
27
+ if (!m.configKey || typeof m.configKey !== 'string') {
28
+ throw new Error(`Invalid manifest configKey in ${sourcePath || m.name}`);
29
+ }
30
+ if (!m.configSchema || typeof m.configSchema !== 'object') {
31
+ throw new Error(`Invalid manifest configSchema in ${sourcePath || m.name}`);
32
+ }
33
+ if (!Array.isArray(m.environment)) {
34
+ throw new Error(`Invalid manifest environment in ${sourcePath || m.name}: expected array`);
35
+ }
36
+ if (!Array.isArray(m.services)) {
37
+ throw new Error(`Invalid manifest services in ${sourcePath || m.name}: expected array`);
38
+ }
39
+ return m;
40
+ }
@@ -0,0 +1,37 @@
1
+ export interface KnowledgeHubCapabilities {
2
+ search?: boolean;
3
+ retrieval?: boolean;
4
+ contextInjection?: boolean;
5
+ semanticSearch?: boolean;
6
+ lexicalSearch?: boolean;
7
+ [key: string]: unknown;
8
+ }
9
+ export interface KnowledgeHubManifest {
10
+ name: string;
11
+ displayName?: string;
12
+ publisher?: string;
13
+ package?: string;
14
+ version: string;
15
+ description?: string;
16
+ capabilities?: KnowledgeHubCapabilities | string[];
17
+ distribution?: {
18
+ kind?: string;
19
+ url?: string;
20
+ };
21
+ source?: string;
22
+ environment?: Array<{
23
+ name: string;
24
+ required?: boolean;
25
+ description?: string;
26
+ }>;
27
+ }
28
+ export declare const KNOWN_KNOWLEDGE_PACKS: Record<string, KnowledgeHubManifest>;
29
+ export declare function validateKnowledgeManifest(raw: unknown, packId?: string): KnowledgeHubManifest;
30
+ export declare function extractCapabilitiesList(capabilities?: KnowledgeHubCapabilities | string[]): string[];
31
+ export declare class KnowledgeHubClient {
32
+ private registryUrl;
33
+ private timeoutMs;
34
+ constructor(registryUrl?: string, timeoutMs?: number);
35
+ resolveProvider(packId: string): Promise<KnowledgeHubManifest>;
36
+ }
37
+ export declare function displayKnowledgeProviderSummary(manifest: KnowledgeHubManifest, packId: string): void;
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KnowledgeHubClient = exports.KNOWN_KNOWLEDGE_PACKS = void 0;
4
+ exports.validateKnowledgeManifest = validateKnowledgeManifest;
5
+ exports.extractCapabilitiesList = extractCapabilitiesList;
6
+ exports.displayKnowledgeProviderSummary = displayKnowledgeProviderSummary;
7
+ exports.KNOWN_KNOWLEDGE_PACKS = {
8
+ '@vxnus/e-teyvat': {
9
+ name: 'e-teyvat',
10
+ displayName: 'E Teyvat',
11
+ publisher: 'vxnus',
12
+ package: '@vxnus/e-teyvat',
13
+ version: '1.2.0',
14
+ description: 'Teyvat knowledge provider for Siduri.',
15
+ capabilities: ['Search', 'Retrieval', 'Context injection'],
16
+ distribution: {
17
+ kind: 'provider',
18
+ url: 'https://teyvat.e.vxnus.xyz',
19
+ },
20
+ source: 'E Knowledge Hub',
21
+ },
22
+ };
23
+ function validateKnowledgeManifest(raw, packId) {
24
+ if (!raw || typeof raw !== 'object') {
25
+ throw new Error(`Invalid knowledge manifest: expected object.`);
26
+ }
27
+ const m = raw;
28
+ if (!m.name || typeof m.name !== 'string') {
29
+ throw new Error(`Invalid knowledge manifest: missing 'name' field.`);
30
+ }
31
+ if (!m.version || typeof m.version !== 'string') {
32
+ throw new Error(`Invalid knowledge manifest: missing 'version' field.`);
33
+ }
34
+ return {
35
+ name: m.name,
36
+ displayName: m.displayName || m.name,
37
+ publisher: m.publisher,
38
+ package: m.package || packId || m.name,
39
+ version: m.version,
40
+ description: m.description || 'Knowledge pack provider',
41
+ capabilities: m.capabilities || ['Search', 'Retrieval'],
42
+ distribution: m.distribution,
43
+ source: m.source || 'E Knowledge Hub',
44
+ environment: m.environment || [],
45
+ };
46
+ }
47
+ function extractCapabilitiesList(capabilities) {
48
+ if (!capabilities) {
49
+ return ['Search', 'Retrieval'];
50
+ }
51
+ if (Array.isArray(capabilities)) {
52
+ return capabilities.map((c) => String(c));
53
+ }
54
+ const result = [];
55
+ if (capabilities.lexicalSearch || capabilities.search)
56
+ result.push('Search');
57
+ result.push('Retrieval');
58
+ if (capabilities.contextInjection)
59
+ result.push('Context injection');
60
+ if (capabilities.semanticSearch)
61
+ result.push('Semantic search');
62
+ if (capabilities.structuredEntities)
63
+ result.push('Structured entities');
64
+ if (capabilities.relations)
65
+ result.push('Entity relations');
66
+ if (capabilities.revisions)
67
+ result.push('Content revisions');
68
+ for (const [key, val] of Object.entries(capabilities)) {
69
+ if (val === true && !['search', 'retrieval', 'contextInjection', 'semanticSearch', 'lexicalSearch', 'structuredEntities', 'relations', 'revisions'].includes(key)) {
70
+ result.push(key);
71
+ }
72
+ }
73
+ return result.length > 0 ? result : ['Search', 'Retrieval'];
74
+ }
75
+ class KnowledgeHubClient {
76
+ registryUrl;
77
+ timeoutMs;
78
+ constructor(registryUrl = 'https://e.vxnus.xyz/api/v1/knowledge', timeoutMs = 5000) {
79
+ this.registryUrl = registryUrl.replace(/\/+$/, '');
80
+ this.timeoutMs = timeoutMs;
81
+ }
82
+ async resolveProvider(packId) {
83
+ const trimmed = packId.trim();
84
+ const match = trimmed.match(/^@([^/]+)\/([^/]+)$/);
85
+ if (!match) {
86
+ throw new Error(`Invalid package ID format "${packId}". Expected format: @publisher/name (e.g. @vxnus/e-teyvat)`);
87
+ }
88
+ const publisher = match[1];
89
+ const name = match[2];
90
+ const url = `${this.registryUrl}/${encodeURIComponent(publisher)}/${encodeURIComponent(name)}`;
91
+ const controller = new AbortController();
92
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
93
+ try {
94
+ const response = await fetch(url, {
95
+ method: 'GET',
96
+ headers: { Accept: 'application/json' },
97
+ signal: controller.signal,
98
+ });
99
+ if (!response.ok) {
100
+ // Check offline/built-in catalog fallback for known pack IDs
101
+ if (exports.KNOWN_KNOWLEDGE_PACKS[trimmed]) {
102
+ return exports.KNOWN_KNOWLEDGE_PACKS[trimmed];
103
+ }
104
+ throw new Error(`HTTP ${response.status}: ${response.statusText} for ${packId}`);
105
+ }
106
+ const body = await response.json();
107
+ return validateKnowledgeManifest(body, trimmed);
108
+ }
109
+ catch (err) {
110
+ // If network fails and known pack exists, use fallback
111
+ if (exports.KNOWN_KNOWLEDGE_PACKS[trimmed]) {
112
+ return exports.KNOWN_KNOWLEDGE_PACKS[trimmed];
113
+ }
114
+ throw new Error(`Failed to resolve package "${packId}" from E Knowledge Hub: ${err.message}`);
115
+ }
116
+ finally {
117
+ clearTimeout(timer);
118
+ }
119
+ }
120
+ }
121
+ exports.KnowledgeHubClient = KnowledgeHubClient;
122
+ function displayKnowledgeProviderSummary(manifest, packId) {
123
+ const cyan = '\u001b[36m';
124
+ const dim = '\u001b[2m';
125
+ const reset = '\u001b[0m';
126
+ console.log(`\n${cyan}── Knowledge Provider ────────────────────────${reset}\n`);
127
+ console.log(` ${dim}Name:${reset} ${manifest.displayName || manifest.name}`);
128
+ console.log(` ${dim}Package:${reset} ${packId}`);
129
+ console.log(` ${dim}Version:${reset} ${manifest.version}`);
130
+ if (manifest.description) {
131
+ console.log(`\n ${dim}Description:${reset}`);
132
+ console.log(` ${manifest.description}`);
133
+ }
134
+ const caps = extractCapabilitiesList(manifest.capabilities);
135
+ console.log(`\n ${dim}Capabilities:${reset}`);
136
+ for (const cap of caps) {
137
+ console.log(` • ${cap}`);
138
+ }
139
+ console.log(`\n ${dim}Source:${reset}`);
140
+ console.log(` ${manifest.source || 'E Knowledge Hub'}\n`);
141
+ }
@@ -0,0 +1,32 @@
1
+ export interface ModelOption {
2
+ id: string;
3
+ name: string;
4
+ description?: string;
5
+ contextLength?: number;
6
+ }
7
+ export interface ModelProvider {
8
+ listModels(): Promise<ModelOption[]>;
9
+ }
10
+ export declare const CURATED_OPENROUTER_MODELS: ModelOption[];
11
+ export declare class OpenRouterModelProvider implements ModelProvider {
12
+ private apiUrl;
13
+ private timeoutMs;
14
+ constructor(apiUrl?: string, timeoutMs?: number);
15
+ listModels(): Promise<ModelOption[]>;
16
+ }
17
+ export type ModelSelectionResult = {
18
+ type: 'selected';
19
+ modelId: string;
20
+ modelName: string;
21
+ } | {
22
+ type: 'manual';
23
+ modelId: string;
24
+ } | {
25
+ type: 'switch_provider';
26
+ } | {
27
+ type: 'cancel';
28
+ };
29
+ /**
30
+ * Interactive model selector with search, pagination, and robust error recovery.
31
+ */
32
+ export declare function promptOpenRouterModelSelection(provider?: ModelProvider): Promise<ModelSelectionResult>;
@@ -0,0 +1,201 @@
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
+ exports.OpenRouterModelProvider = exports.CURATED_OPENROUTER_MODELS = void 0;
7
+ exports.promptOpenRouterModelSelection = promptOpenRouterModelSelection;
8
+ const inquirer_1 = __importDefault(require("inquirer"));
9
+ exports.CURATED_OPENROUTER_MODELS = [
10
+ { id: 'openai/gpt-4o-mini', name: 'OpenAI: GPT-4o Mini', description: 'Fast, lightweight intelligence' },
11
+ { id: 'openai/gpt-4o', name: 'OpenAI: GPT-4o', description: 'Flagship multimodal intelligence' },
12
+ { id: 'anthropic/claude-3.5-sonnet', name: 'Anthropic: Claude 3.5 Sonnet', description: 'State-of-the-art reasoning and coding' },
13
+ { id: 'anthropic/claude-3-haiku', name: 'Anthropic: Claude 3 Haiku', description: 'Fast and compact' },
14
+ { id: 'google/gemini-2.0-flash-001', name: 'Google: Gemini 2.0 Flash', description: 'Next-gen speed and multimodal capabilities' },
15
+ { id: 'meta-llama/llama-3.3-70b-instruct', name: 'Meta: Llama 3.3 70B Instruct', description: 'High capability open weights model' },
16
+ { id: 'deepseek/deepseek-chat', name: 'DeepSeek: DeepSeek V3', description: 'Advanced conversational and coding model' },
17
+ { id: 'deepseek/deepseek-r1', name: 'DeepSeek: DeepSeek R1', description: 'Advanced reasoning model' },
18
+ { id: 'mistralai/mistral-large', name: 'Mistral: Mistral Large', description: 'Top-tier reasoning and multilingual model' },
19
+ ];
20
+ class OpenRouterModelProvider {
21
+ apiUrl;
22
+ timeoutMs;
23
+ constructor(apiUrl = 'https://openrouter.ai/api/v1/models', timeoutMs = 6000) {
24
+ this.apiUrl = apiUrl;
25
+ this.timeoutMs = timeoutMs;
26
+ }
27
+ async listModels() {
28
+ const controller = new AbortController();
29
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
30
+ try {
31
+ const response = await fetch(this.apiUrl, {
32
+ method: 'GET',
33
+ headers: {
34
+ Accept: 'application/json',
35
+ 'User-Agent': 'Siduri-CLI/1.0',
36
+ },
37
+ signal: controller.signal,
38
+ });
39
+ if (!response.ok) {
40
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
41
+ }
42
+ const body = (await response.json());
43
+ if (!body.data || !Array.isArray(body.data) || body.data.length === 0) {
44
+ throw new Error('Received empty or invalid model list from OpenRouter API.');
45
+ }
46
+ return body.data.map((m) => ({
47
+ id: m.id,
48
+ name: m.name || m.id,
49
+ description: m.description,
50
+ contextLength: m.context_length,
51
+ }));
52
+ }
53
+ finally {
54
+ clearTimeout(timer);
55
+ }
56
+ }
57
+ }
58
+ exports.OpenRouterModelProvider = OpenRouterModelProvider;
59
+ /**
60
+ * Interactive model selector with search, pagination, and robust error recovery.
61
+ */
62
+ async function promptOpenRouterModelSelection(provider = new OpenRouterModelProvider()) {
63
+ let models = [];
64
+ let fetchFailed = false;
65
+ let fetchError = '';
66
+ // 1. Fetch models dynamically
67
+ try {
68
+ process.stdout.write('\u001b[2mFetching OpenRouter models...\u001b[0m');
69
+ models = await provider.listModels();
70
+ process.stdout.write('\r\u001b[32m✓\u001b[0m Fetched OpenRouter models catalog\n');
71
+ }
72
+ catch (err) {
73
+ fetchFailed = true;
74
+ fetchError = err.message || String(err);
75
+ process.stdout.write('\r\u001b[33m!\u001b[0m Unable to fetch OpenRouter models.\n');
76
+ }
77
+ // 2. Handle failure if API is unreachable
78
+ if (fetchFailed || models.length === 0) {
79
+ console.log(`\u001b[33mReason:\u001b[0m ${fetchError || 'No models returned.'}\n`);
80
+ const { failureAction } = await inquirer_1.default.prompt({
81
+ type: 'list',
82
+ name: 'failureAction',
83
+ message: 'What would you like to do?',
84
+ choices: [
85
+ { name: 'Retry fetching models', value: 'retry' },
86
+ { name: 'Use curated standard models', value: 'curated' },
87
+ { name: 'Enter model ID manually', value: 'manual' },
88
+ { name: 'Choose another Brain provider', value: 'switch_provider' },
89
+ { name: 'Cancel', value: 'cancel' },
90
+ ],
91
+ });
92
+ if (failureAction === 'retry') {
93
+ return promptOpenRouterModelSelection(provider);
94
+ }
95
+ if (failureAction === 'curated') {
96
+ models = exports.CURATED_OPENROUTER_MODELS;
97
+ }
98
+ else if (failureAction === 'manual') {
99
+ const { manualId } = await inquirer_1.default.prompt({
100
+ type: 'input',
101
+ name: 'manualId',
102
+ message: 'Model ID (e.g. openai/gpt-4o-mini):',
103
+ default: 'openai/gpt-4o-mini',
104
+ validate: (val) => val.trim().length > 0 || 'Please enter a model ID.',
105
+ });
106
+ return { type: 'manual', modelId: manualId.trim() };
107
+ }
108
+ else if (failureAction === 'switch_provider') {
109
+ return { type: 'switch_provider' };
110
+ }
111
+ else {
112
+ return { type: 'cancel' };
113
+ }
114
+ }
115
+ // 3. Selection flow with filtering
116
+ let currentSearch = '';
117
+ while (true) {
118
+ let filtered = models;
119
+ if (currentSearch.trim()) {
120
+ const q = currentSearch.toLowerCase();
121
+ filtered = models.filter((m) => m.name.toLowerCase().includes(q) || m.id.toLowerCase().includes(q));
122
+ }
123
+ const choices = [];
124
+ // Search action at top
125
+ if (currentSearch) {
126
+ choices.push({
127
+ name: `\u001b[36m⌕ Clear filter (currently: "${currentSearch}") [${filtered.length} matches]\u001b[0m`,
128
+ value: '__CLEAR_FILTER__',
129
+ });
130
+ }
131
+ else {
132
+ choices.push({
133
+ name: `\u001b[36m⌕ Search / Filter models by keyword...\u001b[0m`,
134
+ value: '__FILTER__',
135
+ });
136
+ }
137
+ choices.push(new inquirer_1.default.Separator('── Models ──'));
138
+ if (filtered.length === 0) {
139
+ choices.push({
140
+ name: `\u001b[33mNo models matched "${currentSearch}". Search again or enter manually.\u001b[0m`,
141
+ value: '__FILTER__',
142
+ });
143
+ }
144
+ else {
145
+ // Limit to max 40 items displayed per page to prevent UI overload
146
+ const displayList = filtered.slice(0, 40);
147
+ for (const m of displayList) {
148
+ const idLabel = m.name !== m.id ? ` \u001b[2m(${m.id})\u001b[0m` : '';
149
+ choices.push({
150
+ name: `${m.name}${idLabel}`,
151
+ value: m.id,
152
+ });
153
+ }
154
+ if (filtered.length > 40) {
155
+ choices.push(new inquirer_1.default.Separator(`... and ${filtered.length - 40} more (use search to refine)`));
156
+ }
157
+ }
158
+ choices.push(new inquirer_1.default.Separator('── Other Options ──'));
159
+ choices.push({ name: 'Enter model ID manually', value: '__MANUAL__' });
160
+ choices.push({ name: 'Choose another Brain provider', value: '__SWITCH__' });
161
+ const { selectedValue } = await inquirer_1.default.prompt({
162
+ type: 'list',
163
+ name: 'selectedValue',
164
+ message: currentSearch ? `Select model (filtered by "${currentSearch}"):` : 'Select model:',
165
+ pageSize: 15,
166
+ choices,
167
+ });
168
+ if (selectedValue === '__FILTER__') {
169
+ const { query } = await inquirer_1.default.prompt({
170
+ type: 'input',
171
+ name: 'query',
172
+ message: 'Search models (e.g. claude, gpt, gemini, llama):',
173
+ });
174
+ currentSearch = query.trim();
175
+ continue;
176
+ }
177
+ if (selectedValue === '__CLEAR_FILTER__') {
178
+ currentSearch = '';
179
+ continue;
180
+ }
181
+ if (selectedValue === '__MANUAL__') {
182
+ const { manualId } = await inquirer_1.default.prompt({
183
+ type: 'input',
184
+ name: 'manualId',
185
+ message: 'Model ID (e.g. openai/gpt-4o-mini):',
186
+ default: 'openai/gpt-4o-mini',
187
+ validate: (val) => val.trim().length > 0 || 'Please enter a model ID.',
188
+ });
189
+ return { type: 'manual', modelId: manualId.trim() };
190
+ }
191
+ if (selectedValue === '__SWITCH__') {
192
+ return { type: 'switch_provider' };
193
+ }
194
+ const matchedModel = models.find((m) => m.id === selectedValue);
195
+ return {
196
+ type: 'selected',
197
+ modelId: selectedValue,
198
+ modelName: matchedModel?.name || selectedValue,
199
+ };
200
+ }
201
+ }
@@ -0,0 +1,9 @@
1
+ export interface ReleaseCheckReport {
2
+ packagesChecked: number;
3
+ tarballsInspected: number;
4
+ manifestsValidated: number;
5
+ cleanMachinePassed: boolean;
6
+ passed: boolean;
7
+ errors: string[];
8
+ }
9
+ export declare function runReleaseCheck(repoRoot?: string): ReleaseCheckReport;
@@ -0,0 +1,133 @@
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
+ exports.runReleaseCheck = runReleaseCheck;
7
+ const node_child_process_1 = require("node:child_process");
8
+ const node_fs_1 = __importDefault(require("node:fs"));
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ function run(cmd, cwd) {
11
+ return (0, node_child_process_1.execSync)(cmd, { cwd, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });
12
+ }
13
+ function runReleaseCheck(repoRoot = node_path_1.default.resolve(__dirname, '../..')) {
14
+ const errors = [];
15
+ const tempPackDir = node_path_1.default.resolve(repoRoot, 'cli/temp-release-check-packs');
16
+ if (node_fs_1.default.existsSync(tempPackDir))
17
+ node_fs_1.default.rmSync(tempPackDir, { recursive: true, force: true });
18
+ node_fs_1.default.mkdirSync(tempPackDir, { recursive: true });
19
+ const getPkgVer = (dir) => JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.resolve(repoRoot, dir, 'package.json'), 'utf8')).version;
20
+ const canonicalPackages = [
21
+ { name: '@siduri-x/core', dir: 'packages/core', isOrgan: false, tarName: `siduri-x-core-${getPkgVer('packages/core')}.tgz` },
22
+ { name: '@siduri-x/brain', dir: 'packages/organs/brain', isOrgan: true, tarName: `siduri-x-brain-${getPkgVer('packages/organs/brain')}.tgz` },
23
+ { name: '@siduri-x/memory', dir: 'packages/organs/memory', isOrgan: true, tarName: `siduri-x-memory-${getPkgVer('packages/organs/memory')}.tgz` },
24
+ { name: '@siduri-x/knowledge', dir: 'packages/organs/knowledge', isOrgan: true, tarName: `siduri-x-knowledge-${getPkgVer('packages/organs/knowledge')}.tgz` },
25
+ { name: '@siduri-x/behavior', dir: 'packages/organs/behavior', isOrgan: true, tarName: `siduri-x-behavior-${getPkgVer('packages/organs/behavior')}.tgz` },
26
+ { name: '@siduri-x/ear', dir: 'packages/organs/ear', isOrgan: true, tarName: `siduri-x-ear-${getPkgVer('packages/organs/ear')}.tgz` },
27
+ { name: '@siduri-x/vision', dir: 'packages/organs/vision', isOrgan: true, tarName: `siduri-x-vision-${getPkgVer('packages/organs/vision')}.tgz` },
28
+ { name: '@siduri-x/hands', dir: 'packages/organs/hands', isOrgan: true, tarName: `siduri-x-hands-${getPkgVer('packages/organs/hands')}.tgz` },
29
+ { name: '@siduri-x/body', dir: 'packages/organs/body', isOrgan: true, tarName: `siduri-x-body-${getPkgVer('packages/organs/body')}.tgz` },
30
+ { name: '@siduri-x/voice', dir: 'packages/organs/voice', isOrgan: true, tarName: `siduri-x-voice-${getPkgVer('packages/organs/voice')}.tgz` },
31
+ { name: '@siduri-x/mouth', dir: 'packages/organs/mouth', isOrgan: true, tarName: `siduri-x-mouth-${getPkgVer('packages/organs/mouth')}.tgz` },
32
+ { name: '@siduri-x/observation', dir: 'packages/organs/observation', isOrgan: true, tarName: `siduri-x-observation-${getPkgVer('packages/organs/observation')}.tgz` },
33
+ { name: '@vxnus/siduri', dir: 'cli', isOrgan: false, tarName: `vxnus-siduri-${getPkgVer('cli')}.tgz` },
34
+ ];
35
+ let packagesChecked = 0;
36
+ let tarballsInspected = 0;
37
+ let manifestsValidated = 0;
38
+ try {
39
+ // 1. Pack each package
40
+ for (const pkg of canonicalPackages) {
41
+ packagesChecked++;
42
+ try {
43
+ run(`pnpm --filter ${pkg.name} pack --pack-destination ${tempPackDir}`, repoRoot);
44
+ }
45
+ catch (err) {
46
+ errors.push(`Failed to pack ${pkg.name}: ${err.message}`);
47
+ continue;
48
+ }
49
+ const tarPath = node_path_1.default.join(tempPackDir, pkg.tarName);
50
+ if (!node_fs_1.default.existsSync(tarPath)) {
51
+ errors.push(`Tarball not found for ${pkg.name} at ${tarPath}`);
52
+ continue;
53
+ }
54
+ tarballsInspected++;
55
+ // Inspect tarball package.json
56
+ const pkgJsonRaw = run(`tar -xzf ${tarPath} -O package/package.json`, repoRoot);
57
+ const pkgJson = JSON.parse(pkgJsonRaw);
58
+ // Check package metadata
59
+ if (!pkgJson.name)
60
+ errors.push(`${pkg.name}: missing 'name'`);
61
+ if (!pkgJson.version)
62
+ errors.push(`${pkg.name}: missing 'version'`);
63
+ if (!pkgJson.description)
64
+ errors.push(`${pkg.name}: missing 'description'`);
65
+ if (!pkgJson.license)
66
+ errors.push(`${pkg.name}: missing 'license'`);
67
+ if (!pkgJson.engines || !pkgJson.engines.node)
68
+ errors.push(`${pkg.name}: missing 'engines.node'`);
69
+ // Check for zero workspace: or link: dependencies
70
+ const deps = { ...(pkgJson.dependencies || {}), ...(pkgJson.peerDependencies || {}) };
71
+ for (const [dep, ver] of Object.entries(deps)) {
72
+ if (typeof ver === 'string') {
73
+ if (ver.startsWith('workspace:'))
74
+ errors.push(`${pkg.name}: contains workspace dependency on ${dep}`);
75
+ if (ver.startsWith('link:'))
76
+ errors.push(`${pkg.name}: contains link: dependency on ${dep}`);
77
+ if (ver.includes('../'))
78
+ errors.push(`${pkg.name}: contains relative path on ${dep}`);
79
+ }
80
+ }
81
+ // Check tarball contents
82
+ const listing = run(`tar -tzf ${tarPath}`, repoRoot).split('\n');
83
+ if (pkg.isOrgan) {
84
+ if (!listing.some((l) => l.includes('package/organ-manifest.json'))) {
85
+ errors.push(`${pkg.name}: organ-manifest.json missing in tarball`);
86
+ }
87
+ else {
88
+ manifestsValidated++;
89
+ }
90
+ }
91
+ if (pkg.name === '@siduri-x/memory') {
92
+ if (!listing.some((l) => l.includes('package/migrations/001_initial_schema.sql'))) {
93
+ errors.push(`${pkg.name}: migrations/001_initial_schema.sql missing in tarball`);
94
+ }
95
+ }
96
+ if (pkg.name === '@vxnus/siduri') {
97
+ if (!pkgJson.bin || !pkgJson.bin.siduri) {
98
+ errors.push(`${pkg.name}: bin.siduri field missing in package.json`);
99
+ }
100
+ }
101
+ }
102
+ }
103
+ finally {
104
+ if (node_fs_1.default.existsSync(tempPackDir))
105
+ node_fs_1.default.rmSync(tempPackDir, { recursive: true, force: true });
106
+ }
107
+ return {
108
+ packagesChecked,
109
+ tarballsInspected,
110
+ manifestsValidated,
111
+ cleanMachinePassed: errors.length === 0,
112
+ passed: errors.length === 0,
113
+ errors,
114
+ };
115
+ }
116
+ if (require.main === module) {
117
+ console.log('Running release:check verification...');
118
+ const report = runReleaseCheck();
119
+ console.log(`Packages checked: ${report.packagesChecked}`);
120
+ console.log(`Tarballs inspected: ${report.tarballsInspected}`);
121
+ console.log(`Manifests validated: ${report.manifestsValidated}`);
122
+ if (report.passed) {
123
+ console.log('✓ release:check PASS: All packages meet canonical release invariants.');
124
+ process.exitCode = 0;
125
+ }
126
+ else {
127
+ console.error('✗ release:check FAIL:');
128
+ for (const err of report.errors) {
129
+ console.error(` - ${err}`);
130
+ }
131
+ process.exitCode = 1;
132
+ }
133
+ }
@@ -0,0 +1 @@
1
+ export {};