@rimori/client 1.1.9 → 1.2.0

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 (151) hide show
  1. package/README.md +128 -45
  2. package/dist/cli/scripts/init/dev-registration.d.ts +35 -0
  3. package/dist/cli/scripts/init/dev-registration.js +175 -0
  4. package/dist/cli/scripts/init/env-setup.d.ts +9 -0
  5. package/dist/cli/scripts/init/env-setup.js +43 -0
  6. package/dist/cli/scripts/init/file-operations.d.ts +4 -0
  7. package/dist/cli/scripts/init/file-operations.js +51 -0
  8. package/dist/cli/scripts/init/html-cleaner.d.ts +4 -0
  9. package/dist/cli/scripts/init/html-cleaner.js +38 -0
  10. package/dist/cli/scripts/init/main.d.ts +2 -0
  11. package/dist/cli/scripts/init/main.js +159 -0
  12. package/dist/cli/scripts/init/package-setup.d.ts +32 -0
  13. package/dist/cli/scripts/init/package-setup.js +75 -0
  14. package/dist/cli/scripts/init/router-transformer.d.ts +6 -0
  15. package/dist/cli/scripts/init/router-transformer.js +254 -0
  16. package/dist/cli/scripts/init/tailwind-config.d.ts +4 -0
  17. package/dist/cli/scripts/init/tailwind-config.js +56 -0
  18. package/dist/cli/scripts/init/vite-config.d.ts +20 -0
  19. package/dist/cli/scripts/init/vite-config.js +54 -0
  20. package/dist/cli/scripts/release/release-config-upload.d.ts +7 -0
  21. package/dist/cli/scripts/release/release-config-upload.js +116 -0
  22. package/dist/cli/scripts/release/release-db-update.d.ts +6 -0
  23. package/dist/cli/scripts/release/release-db-update.js +100 -0
  24. package/dist/cli/scripts/release/release-file-upload.d.ts +6 -0
  25. package/dist/cli/scripts/release/release-file-upload.js +136 -0
  26. package/dist/cli/scripts/release/release.d.ts +23 -0
  27. package/dist/cli/scripts/release/release.js +70 -0
  28. package/dist/cli/types/DatabaseTypes.d.ts +103 -0
  29. package/dist/cli/types/DatabaseTypes.js +2 -0
  30. package/dist/components/ai/Assistant.js +4 -4
  31. package/dist/components/ai/Avatar.d.ts +3 -2
  32. package/dist/components/ai/Avatar.js +10 -5
  33. package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.js +1 -1
  34. package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.d.ts +1 -0
  35. package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.js +12 -6
  36. package/dist/components/ai/utils.js +0 -1
  37. package/dist/components/audio/Playbutton.js +3 -3
  38. package/dist/{core → components}/components/ContextMenu.js +2 -2
  39. package/dist/components.d.ts +5 -5
  40. package/dist/components.js +5 -5
  41. package/dist/core/controller/AIController.d.ts +15 -0
  42. package/dist/core/controller/AIController.js +120 -0
  43. package/dist/{controller → core/controller}/ObjectController.d.ts +8 -0
  44. package/dist/{controller → core/controller}/SettingsController.d.ts +12 -4
  45. package/dist/{controller → core/controller}/SettingsController.js +0 -25
  46. package/dist/{controller → core/controller}/SharedContentController.d.ts +10 -19
  47. package/dist/{controller → core/controller}/SharedContentController.js +11 -11
  48. package/dist/core/core.d.ts +13 -0
  49. package/dist/core/core.js +8 -0
  50. package/dist/{plugin/fromRimori → fromRimori}/EventBus.d.ts +3 -3
  51. package/dist/{plugin/fromRimori → fromRimori}/EventBus.js +25 -8
  52. package/dist/fromRimori/PluginTypes.d.ts +171 -0
  53. package/dist/hooks/UseChatHook.d.ts +2 -1
  54. package/dist/hooks/UseChatHook.js +3 -3
  55. package/dist/index.d.ts +5 -3
  56. package/dist/index.js +4 -3
  57. package/dist/plugin/AccomplishmentHandler.d.ts +1 -1
  58. package/dist/plugin/AccomplishmentHandler.js +1 -1
  59. package/dist/plugin/PluginController.d.ts +16 -3
  60. package/dist/plugin/PluginController.js +24 -18
  61. package/dist/plugin/RimoriClient.d.ts +22 -17
  62. package/dist/plugin/RimoriClient.js +35 -25
  63. package/dist/plugin/StandaloneClient.js +11 -8
  64. package/dist/plugin/ThemeSetter.d.ts +1 -0
  65. package/dist/plugin/ThemeSetter.js +9 -6
  66. package/dist/providers/PluginProvider.d.ts +3 -0
  67. package/dist/providers/PluginProvider.js +4 -4
  68. package/dist/utils/Language.d.ts +2 -1
  69. package/dist/utils/Language.js +4 -2
  70. package/dist/utils/difficultyConverter.js +1 -1
  71. package/dist/utils/endpoint.d.ts +2 -0
  72. package/dist/utils/endpoint.js +2 -0
  73. package/dist/worker/WorkerSetup.js +3 -1
  74. package/example/docs/devdocs.md +231 -0
  75. package/example/docs/overview.md +29 -0
  76. package/example/docs/userdocs.md +123 -0
  77. package/example/rimori.config.ts +89 -0
  78. package/example/worker/vite.config.ts +23 -0
  79. package/example/worker/worker.ts +11 -0
  80. package/package.json +15 -9
  81. package/src/cli/scripts/init/dev-registration.ts +193 -0
  82. package/src/cli/scripts/init/env-setup.ts +44 -0
  83. package/src/cli/scripts/init/file-operations.ts +58 -0
  84. package/src/cli/scripts/init/html-cleaner.ts +48 -0
  85. package/src/cli/scripts/init/main.ts +171 -0
  86. package/src/cli/scripts/init/package-setup.ts +117 -0
  87. package/src/cli/scripts/init/router-transformer.ts +329 -0
  88. package/src/cli/scripts/init/tailwind-config.ts +75 -0
  89. package/src/cli/scripts/init/vite-config.ts +73 -0
  90. package/src/cli/scripts/release/release-config-upload.ts +114 -0
  91. package/src/cli/scripts/release/release-db-update.ts +97 -0
  92. package/src/cli/scripts/release/release-file-upload.ts +138 -0
  93. package/src/cli/scripts/release/release.ts +69 -0
  94. package/src/cli/types/DatabaseTypes.ts +117 -0
  95. package/src/components/ai/Assistant.tsx +4 -4
  96. package/src/components/ai/Avatar.tsx +24 -7
  97. package/src/components/ai/EmbeddedAssistent/CircleAudioAvatar.tsx +1 -1
  98. package/src/components/ai/EmbeddedAssistent/VoiceRecoder.tsx +16 -8
  99. package/src/components/ai/utils.ts +0 -2
  100. package/src/components/audio/Playbutton.tsx +3 -3
  101. package/src/{core → components}/components/ContextMenu.tsx +3 -3
  102. package/src/components.ts +6 -6
  103. package/src/core/controller/AIController.ts +122 -0
  104. package/src/core/controller/ObjectController.ts +115 -0
  105. package/src/{controller → core/controller}/SettingsController.ts +13 -29
  106. package/src/{controller → core/controller}/SharedContentController.ts +18 -28
  107. package/src/core/core.ts +15 -0
  108. package/src/{plugin/fromRimori → fromRimori}/EventBus.ts +28 -10
  109. package/src/fromRimori/PluginTypes.ts +203 -0
  110. package/src/hooks/UseChatHook.ts +5 -4
  111. package/src/index.ts +5 -3
  112. package/src/plugin/AccomplishmentHandler.ts +1 -1
  113. package/src/plugin/PluginController.ts +35 -23
  114. package/src/plugin/RimoriClient.ts +48 -41
  115. package/src/plugin/StandaloneClient.ts +11 -8
  116. package/src/plugin/ThemeSetter.ts +12 -8
  117. package/src/providers/PluginProvider.tsx +7 -4
  118. package/src/utils/Language.ts +4 -2
  119. package/src/utils/difficultyConverter.ts +3 -3
  120. package/src/utils/endpoint.ts +2 -0
  121. package/src/worker/WorkerSetup.ts +4 -2
  122. package/dist/components/PluginController.d.ts +0 -21
  123. package/dist/components/PluginController.js +0 -116
  124. package/dist/controller/AIController.d.ts +0 -23
  125. package/dist/controller/AIController.js +0 -93
  126. package/dist/controller/SidePluginController.d.ts +0 -3
  127. package/dist/controller/SidePluginController.js +0 -31
  128. package/dist/core.d.ts +0 -7
  129. package/dist/core.js +0 -7
  130. package/dist/plugin/ContextMenu.d.ts +0 -17
  131. package/dist/plugin/ContextMenu.js +0 -45
  132. package/dist/plugin/fromRimori/PluginTypes.d.ts +0 -48
  133. package/dist/plugin/fromRimori/SupabaseHandler.d.ts +0 -13
  134. package/dist/plugin/fromRimori/SupabaseHandler.js +0 -55
  135. package/dist/providers/PluginController.d.ts +0 -21
  136. package/dist/providers/PluginController.js +0 -116
  137. package/dist/types/Actions.d.ts +0 -4
  138. package/dist/types/Actions.js +0 -1
  139. package/src/controller/AIController.ts +0 -112
  140. package/src/controller/ObjectController.ts +0 -107
  141. package/src/controller/SidePluginController.ts +0 -25
  142. package/src/core.ts +0 -8
  143. package/src/plugin/fromRimori/PluginTypes.ts +0 -64
  144. package/src/types/Actions.ts +0 -6
  145. /package/dist/{core → components}/components/ContextMenu.d.ts +0 -0
  146. /package/dist/{controller → core/controller}/ObjectController.js +0 -0
  147. /package/dist/{controller → core/controller}/VoiceController.d.ts +0 -0
  148. /package/dist/{controller → core/controller}/VoiceController.js +0 -0
  149. /package/dist/{plugin/fromRimori → fromRimori}/PluginTypes.js +0 -0
  150. /package/src/{controller → core/controller}/VoiceController.ts +0 -0
  151. /package/src/{plugin/fromRimori → fromRimori}/readme.md +0 -0
@@ -0,0 +1,7 @@
1
+ import { Config } from './release.js';
2
+ /**
3
+ * Read and send the rimori configuration to the release endpoint
4
+ * @param config - Configuration object
5
+ */
6
+ export declare function sendConfiguration(config: Config): Promise<string>;
7
+ export declare function releasePlugin(config: Config, release_id: string): Promise<void>;
@@ -0,0 +1,116 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import fs from 'fs';
11
+ import path from 'path';
12
+ import ts from 'typescript';
13
+ /**
14
+ * Read and send the rimori configuration to the release endpoint
15
+ * @param config - Configuration object
16
+ */
17
+ export function sendConfiguration(config) {
18
+ return __awaiter(this, void 0, void 0, function* () {
19
+ const configPath = path.resolve('./rimori/rimori.config.ts');
20
+ // Check if config file exists
21
+ try {
22
+ yield fs.promises.access(configPath);
23
+ }
24
+ catch (e) {
25
+ throw new Error('Could not find rimori.config.ts in ./rimori/ directory');
26
+ }
27
+ try {
28
+ let configObject;
29
+ // Use TypeScript compiler to transpile and load
30
+ const configContent = yield fs.promises.readFile(configPath, 'utf8');
31
+ // Transpile TypeScript to JavaScript
32
+ const result = ts.transpile(configContent, {
33
+ target: ts.ScriptTarget.ES2020,
34
+ module: ts.ModuleKind.ES2020
35
+ });
36
+ // Create a temporary file to import the transpiled code
37
+ const tempFile = path.join(process.cwd(), 'temp_config.js');
38
+ yield fs.promises.writeFile(tempFile, result);
39
+ try {
40
+ // Use dynamic import to load the config
41
+ const config = yield import(`file://${tempFile}`);
42
+ configObject = config.default || config;
43
+ // Clean up temp file
44
+ yield fs.promises.unlink(tempFile);
45
+ }
46
+ catch (error) {
47
+ // Clean up temp file even on error
48
+ try {
49
+ yield fs.promises.unlink(tempFile);
50
+ }
51
+ catch (e) { }
52
+ throw error;
53
+ }
54
+ if (!configObject) {
55
+ throw new Error('Configuration object is empty or undefined');
56
+ }
57
+ console.log(`🚀 Sending configuration...`);
58
+ const requestBody = {
59
+ config: configObject,
60
+ version: config.version,
61
+ plugin_id: config.plugin_id,
62
+ release_channel: config.release_channel,
63
+ rimori_client_version: config.rimori_client_version,
64
+ };
65
+ try {
66
+ const response = yield fetch(`${config.domain}/release`, {
67
+ method: 'POST',
68
+ headers: {
69
+ 'Content-Type': 'application/json',
70
+ 'Authorization': `Bearer ${config.token}`
71
+ },
72
+ body: JSON.stringify(requestBody),
73
+ });
74
+ const responseText = yield response.text();
75
+ console.log('Configuration response status:', response.status);
76
+ console.log('Configuration response text:', responseText);
77
+ const responseData = JSON.parse(responseText);
78
+ if (response.ok) {
79
+ console.log('✅ Configuration deployed successfully!');
80
+ return responseData.release_id;
81
+ }
82
+ else {
83
+ console.log('❌ Configuration failed!');
84
+ console.log('Error:', responseData.error || 'Unknown error');
85
+ console.log('Response data:', JSON.stringify(responseData, null, 2));
86
+ throw new Error('Configuration upload failed');
87
+ }
88
+ }
89
+ catch (e) {
90
+ console.log("error", e);
91
+ throw new Error("Error sending configuration");
92
+ }
93
+ }
94
+ catch (error) {
95
+ console.error('❌ Error sending configuration:', error.message);
96
+ throw error;
97
+ }
98
+ });
99
+ }
100
+ export function releasePlugin(config, release_id) {
101
+ return __awaiter(this, void 0, void 0, function* () {
102
+ const response = yield fetch(`${config.domain}/release/${release_id}/release`, {
103
+ method: 'POST',
104
+ headers: {
105
+ 'Content-Type': 'application/json',
106
+ 'Authorization': `Bearer ${config.token}`
107
+ },
108
+ body: JSON.stringify({ plugin_id: config.plugin_id })
109
+ });
110
+ if (!response.ok) {
111
+ console.log("Response:", yield response.text());
112
+ throw new Error("Failed to release plugin");
113
+ }
114
+ console.log("✅ Plugin released successfully");
115
+ });
116
+ }
@@ -0,0 +1,6 @@
1
+ import { Config } from "./release";
2
+ /**
3
+ * Read and send the database configuration to the release endpoint
4
+ * @param config - Configuration object
5
+ */
6
+ export default function dbUpdate(config: Config, release_id: string): Promise<void>;
@@ -0,0 +1,100 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import fs from 'fs';
11
+ import path from 'path';
12
+ import ts from 'typescript';
13
+ /**
14
+ * Read and send the database configuration to the release endpoint
15
+ * @param config - Configuration object
16
+ */
17
+ export default function dbUpdate(config, release_id) {
18
+ return __awaiter(this, void 0, void 0, function* () {
19
+ const dbConfigPath = path.resolve('./rimori/db.config.ts');
20
+ // Check if db config file exists
21
+ try {
22
+ yield fs.promises.access(dbConfigPath);
23
+ }
24
+ catch (e) {
25
+ console.warn('Could not find db.config.ts in ./rimori/ directory. Skipping database configuration upload.');
26
+ return;
27
+ }
28
+ try {
29
+ let dbConfigObject;
30
+ // Use TypeScript compiler to transpile and load
31
+ const dbConfigContent = yield fs.promises.readFile(dbConfigPath, 'utf8');
32
+ // Transpile TypeScript to JavaScript
33
+ const result = ts.transpile(dbConfigContent, {
34
+ target: ts.ScriptTarget.ES2020,
35
+ module: ts.ModuleKind.ES2020
36
+ });
37
+ // Create a temporary file to import the transpiled code
38
+ const tempFile = path.join(process.cwd(), 'temp_db_config.js');
39
+ yield fs.promises.writeFile(tempFile, result);
40
+ try {
41
+ // Use dynamic import to load the db config
42
+ const dbConfig = yield import(`file://${tempFile}`);
43
+ dbConfigObject = Object.values(dbConfig);
44
+ // Clean up temp file
45
+ yield fs.promises.unlink(tempFile);
46
+ }
47
+ catch (error) {
48
+ // Clean up temp file even on error
49
+ try {
50
+ yield fs.promises.unlink(tempFile);
51
+ }
52
+ catch (e) { }
53
+ throw error;
54
+ }
55
+ if (!dbConfigObject) {
56
+ throw new Error('Database configuration object is empty or undefined');
57
+ }
58
+ console.log(`🗄️ Sending database configuration...`);
59
+ const requestBody = {
60
+ db_config: dbConfigObject,
61
+ version: config.version,
62
+ release_channel: config.release_channel,
63
+ plugin_id: config.plugin_id,
64
+ };
65
+ const response = yield fetch(`${config.domain}/release/${release_id}/db`, {
66
+ method: 'POST',
67
+ headers: {
68
+ 'Content-Type': 'application/json',
69
+ 'Authorization': `Bearer ${config.token}`
70
+ },
71
+ body: JSON.stringify(requestBody),
72
+ }).catch((e) => {
73
+ console.log("error", e);
74
+ throw new Error("Error sending database configuration");
75
+ });
76
+ try {
77
+ const responseText = yield response.text().catch((e) => {
78
+ console.log("error", e);
79
+ throw new Error("Error sending database configuration");
80
+ });
81
+ const responseData = JSON.parse(responseText);
82
+ if (response.ok) {
83
+ console.log('✅ Database configuration deployed successfully!');
84
+ }
85
+ else {
86
+ console.log("responseData", responseData);
87
+ throw new Error(responseData.message);
88
+ }
89
+ }
90
+ catch (e) {
91
+ console.log("error", e);
92
+ throw new Error("Error sending database configuration");
93
+ }
94
+ }
95
+ catch (error) {
96
+ console.error('❌ Error sending database configuration:', error.message);
97
+ throw error;
98
+ }
99
+ });
100
+ }
@@ -0,0 +1,6 @@
1
+ import { Config } from './release.js';
2
+ /**
3
+ * Upload all files from a directory and its subdirectories to the release function
4
+ * @param config - Configuration object
5
+ */
6
+ export declare function uploadDirectory(config: Config, release_id: string): Promise<void>;
@@ -0,0 +1,136 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import fs from 'fs';
11
+ import path from 'path';
12
+ /**
13
+ * Upload all files from a directory and its subdirectories to the release function
14
+ * @param config - Configuration object
15
+ */
16
+ export function uploadDirectory(config, release_id) {
17
+ return __awaiter(this, void 0, void 0, function* () {
18
+ const relativePath = './dist';
19
+ console.log(`📁 Preparing to upload files from ${relativePath}...`);
20
+ // Check if dist directory exists
21
+ try {
22
+ yield fs.promises.access(relativePath);
23
+ }
24
+ catch (e) {
25
+ throw new Error(`Directory ${relativePath} does not exist. Make sure to build your plugin first.`);
26
+ }
27
+ // Get all files recursively
28
+ const files = yield getAllFiles(relativePath);
29
+ if (files.length === 0) {
30
+ console.log('⚠️ No files found to upload');
31
+ return;
32
+ }
33
+ console.log(`🚀 Uploading ${files.length} files...`);
34
+ // Create FormData
35
+ const formData = new FormData();
36
+ // Add version and release channel data
37
+ formData.append('version', config.version);
38
+ formData.append('release_channel', config.release_channel);
39
+ formData.append('plugin_id', config.plugin_id);
40
+ // Create path mapping with IDs as keys
41
+ const pathMapping = {};
42
+ for (let i = 0; i < files.length; i++) {
43
+ const filePath = files[i];
44
+ try {
45
+ const fileContent = yield fs.promises.readFile(filePath);
46
+ const relativePath = path.relative('./dist', filePath);
47
+ const contentType = getContentType(filePath);
48
+ // Generate unique ID for this file
49
+ const fileId = `file_${i}`;
50
+ // Add to path mapping using ID as key
51
+ pathMapping[fileId] = relativePath;
52
+ // Create a Blob with the file content and content type
53
+ const blob = new Blob([fileContent], { type: contentType });
54
+ // Add file to FormData with ID_filename format
55
+ const fileName = `${fileId}_${path.basename(filePath)}`;
56
+ formData.append('files', blob, fileName);
57
+ }
58
+ catch (error) {
59
+ console.error(`❌ Error reading file ${filePath}:`, error.message);
60
+ throw error;
61
+ }
62
+ }
63
+ // Add path mapping to FormData
64
+ formData.append('path_mapping', JSON.stringify(pathMapping));
65
+ // Upload to the release endpoint
66
+ const response = yield fetch(`${config.domain}/release/${release_id}/files`, {
67
+ method: 'POST',
68
+ headers: { 'Authorization': `Bearer ${config.token}` },
69
+ body: formData,
70
+ });
71
+ if (response.ok) {
72
+ console.log('✅ Files uploaded successfully!');
73
+ }
74
+ else {
75
+ const errorText = yield response.text();
76
+ console.log('❌ File upload failed!');
77
+ console.log('Response:', errorText);
78
+ throw new Error(`File upload failed with status ${response.status}`);
79
+ }
80
+ });
81
+ }
82
+ /**
83
+ * Recursively get all files from a directory
84
+ */
85
+ function getAllFiles(dirPath) {
86
+ return __awaiter(this, void 0, void 0, function* () {
87
+ const files = [];
88
+ function traverse(currentPath) {
89
+ return __awaiter(this, void 0, void 0, function* () {
90
+ const entries = yield fs.promises.readdir(currentPath, { withFileTypes: true });
91
+ for (const entry of entries) {
92
+ const fullPath = path.join(currentPath, entry.name);
93
+ if (entry.isDirectory()) {
94
+ yield traverse(fullPath);
95
+ }
96
+ else if (entry.isFile()) {
97
+ files.push(fullPath);
98
+ }
99
+ }
100
+ });
101
+ }
102
+ yield traverse(dirPath);
103
+ return files;
104
+ });
105
+ }
106
+ /**
107
+ * Get content type based on file extension
108
+ */
109
+ function getContentType(filePath) {
110
+ var _a;
111
+ const ext = (_a = filePath.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase();
112
+ const contentTypes = {
113
+ html: 'text/html',
114
+ css: 'text/css',
115
+ js: 'application/javascript',
116
+ json: 'application/json',
117
+ md: 'text/markdown',
118
+ txt: 'text/plain',
119
+ png: 'image/png',
120
+ jpg: 'image/jpeg',
121
+ jpeg: 'image/jpeg',
122
+ gif: 'image/gif',
123
+ svg: 'image/svg+xml',
124
+ pdf: 'application/pdf',
125
+ ico: 'image/x-icon',
126
+ mp3: 'audio/mpeg',
127
+ wav: 'audio/wav',
128
+ ogg: 'audio/ogg',
129
+ m4a: 'audio/mp4',
130
+ webp: 'image/webp',
131
+ };
132
+ const contentType = contentTypes[ext || ''];
133
+ if (!contentType)
134
+ throw new Error(`Unsupported file type: ${ext}`);
135
+ return contentType;
136
+ }
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Usage:
4
+ * rimori-release <release_channel>
5
+ *
6
+ * Environment variables required:
7
+ * RIMORI_TOKEN - Your Rimori token
8
+ * RIMORI_PLUGIN - Your plugin ID
9
+ *
10
+ * Make sure to install dependencies:
11
+ * npm install node-fetch form-data ts-node typescript
12
+ */
13
+ import 'dotenv/config';
14
+ declare const config: {
15
+ version: any;
16
+ release_channel: string;
17
+ plugin_id: any;
18
+ token: string;
19
+ domain: string;
20
+ rimori_client_version: any;
21
+ };
22
+ export type Config = typeof config;
23
+ export {};
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Usage:
4
+ * rimori-release <release_channel>
5
+ *
6
+ * Environment variables required:
7
+ * RIMORI_TOKEN - Your Rimori token
8
+ * RIMORI_PLUGIN - Your plugin ID
9
+ *
10
+ * Make sure to install dependencies:
11
+ * npm install node-fetch form-data ts-node typescript
12
+ */
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ import 'dotenv/config';
23
+ import fs from 'fs';
24
+ import path from 'path';
25
+ import dbUpdate from './release-db-update.js';
26
+ import { uploadDirectory } from './release-file-upload.js';
27
+ import { releasePlugin, sendConfiguration } from './release-config-upload.js';
28
+ // Read version from package.json
29
+ const packageJson = JSON.parse(fs.readFileSync(path.resolve('./package.json'), 'utf8'));
30
+ const { version, r_id: pluginId } = packageJson;
31
+ const RIMORI_TOKEN = process.env.RIMORI_TOKEN;
32
+ if (!RIMORI_TOKEN)
33
+ throw new Error('RIMORI_TOKEN is not set');
34
+ if (!pluginId)
35
+ throw new Error('The plugin id (r_id) is not set in package.json');
36
+ const [releaseChannel] = process.argv.slice(2);
37
+ if (!releaseChannel) {
38
+ console.error('Usage: rimori-release <release_channel>');
39
+ process.exit(1);
40
+ }
41
+ const config = {
42
+ version,
43
+ release_channel: releaseChannel,
44
+ plugin_id: pluginId,
45
+ token: RIMORI_TOKEN,
46
+ domain: process.env.RIMORI_BACKEND_URL || "https://api.rimori.se",
47
+ rimori_client_version: packageJson.dependencies['@rimori/client'].replace('^', ''),
48
+ };
49
+ /**
50
+ * Main release process
51
+ */
52
+ function releaseProcess() {
53
+ return __awaiter(this, void 0, void 0, function* () {
54
+ try {
55
+ console.log(`🚀 Releasing ${config.plugin_id} to ${config.release_channel}...`);
56
+ // First send the configuration
57
+ const release_id = yield sendConfiguration(config);
58
+ yield dbUpdate(config, release_id);
59
+ // Then upload the files
60
+ yield uploadDirectory(config, release_id);
61
+ // Then release the plugin
62
+ yield releasePlugin(config, release_id);
63
+ }
64
+ catch (error) {
65
+ console.log("❌ Error:", error.message);
66
+ process.exit(1);
67
+ }
68
+ });
69
+ }
70
+ releaseProcess();
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Supported database column data types for table schema definitions.
3
+ */
4
+ type DbColumnType = 'decimal' | 'integer' | 'text' | 'boolean' | 'json' | 'timestamp' | 'uuid';
5
+ /**
6
+ * Foreign key relationship configuration with cascade delete support.
7
+ * Defines a relationship where the source record is deleted when the destination record is deleted.
8
+ */
9
+ interface ForeignKeyRelation {
10
+ /** The target table that this column references */
11
+ references_table: string;
12
+ /** The target column in the referenced table (defaults to 'id') */
13
+ references_column?: string;
14
+ /** Whether to cascade delete when the referenced record is deleted */
15
+ on_delete_cascade: boolean;
16
+ }
17
+ /**
18
+ * Database column definition with support for types, constraints, and relationships.
19
+ */
20
+ export interface DbColumnDefinition {
21
+ /** The data type of the column */
22
+ type: DbColumnType;
23
+ /** Human-readable description of the column's purpose */
24
+ description: string;
25
+ /** Whether the column can contain null values */
26
+ nullable?: boolean;
27
+ /** Whether the column has a unique constraint */
28
+ unique?: boolean;
29
+ /** Default value for the column. can also use sql functions like now(), auth.uid() or gen_random_uuid() */
30
+ default_value?: string | number | boolean;
31
+ /** Array of allowed values for enumerated columns */
32
+ /** Foreign key relationship configuration */
33
+ foreign_key?: ForeignKeyRelation;
34
+ /** The name of the column before it was renamed. */
35
+ old_name?: string;
36
+ /** Whether the column is deprecated. The column gets renamed to column_name_old. To fully remove the column, first set deprecated to true and then after a release, remove the column from the table definition. */
37
+ deprecated?: boolean;
38
+ /** Whether the column is a primary key */
39
+ /** Restrictions for the column. If the column is restricted, the permission is further restricted. E.g. if the column is restricted to user, then the user can only read the column if they have the right permission.
40
+ * Example: Denying users to update the column, but allowing the moderator to update the column.
41
+ */
42
+ restrict?: {
43
+ /** Restrictions for the user */
44
+ user: Partial<Omit<DbPermissionDefinition, 'delete'>>;
45
+ /** Restrictions for the moderator */
46
+ moderator?: Partial<Omit<DbPermissionDefinition, 'delete'>>;
47
+ };
48
+ }
49
+ /**
50
+ * Base table structure that all database tables inherit.
51
+ * Includes standard audit fields for tracking creation and ownership.
52
+ */
53
+ interface BaseTableStructure {
54
+ /** Unique identifier for the record */
55
+ id: DbColumnDefinition;
56
+ /** Timestamp when the record was created */
57
+ created_at: DbColumnDefinition;
58
+ /** ID of the user who created the record */
59
+ created_by: DbColumnDefinition;
60
+ }
61
+ /**
62
+ * Complete database table schema definition.
63
+ * Defines the structure, constraints, and relationships for a database table.
64
+ */
65
+ export interface DbTableDefinition {
66
+ /** Name of the database table */
67
+ table_name: string;
68
+ /** Description of the table's purpose and usage */
69
+ description: string;
70
+ /** Permissions for the table */
71
+ permissions: {
72
+ user: DbPermissionDefinition;
73
+ moderator?: DbPermissionDefinition;
74
+ };
75
+ /** Column definitions for the table */
76
+ columns: {
77
+ [column_name: string]: DbColumnDefinition;
78
+ };
79
+ }
80
+ /**
81
+ * Permission definition for a database table.
82
+ * NONE means the action is not allowed.
83
+ * OWN means only do the action on your own records.
84
+ * ALL means do the action on all records.
85
+ *
86
+ * Defines the permissions for a database table.
87
+ */
88
+ export type DbPermission = "NONE" | "OWN" | "ALL";
89
+ /**
90
+ * Permission definition for a database table.
91
+ * Defines the permissions for a database table.
92
+ */
93
+ export interface DbPermissionDefinition {
94
+ read: DbPermission;
95
+ insert: DbPermission;
96
+ update: DbPermission;
97
+ delete: DbPermission;
98
+ }
99
+ /**
100
+ * Full table definition that includes automatically generated fields.
101
+ */
102
+ export type FullTable<T extends Record<string, DbColumnDefinition>> = T & BaseTableStructure;
103
+ export {};
@@ -0,0 +1,2 @@
1
+ // Database table structure definitions
2
+ export {};
@@ -10,7 +10,7 @@ import { getFirstMessages } from './utils';
10
10
  export function AssistantChat({ avatarImageUrl, voiceId, onComplete, autoStartConversation }) {
11
11
  var _a;
12
12
  const [oralCommunication, setOralCommunication] = React.useState(true);
13
- const { llm, event } = usePlugin();
13
+ const { ai: llm, event } = usePlugin();
14
14
  const sender = useMemo(() => new MessageSender(llm.getVoice, voiceId), []);
15
15
  const { messages, append, isLoading, setMessages } = useChat();
16
16
  const lastAssistantMessage = (_a = [...messages].filter((m) => m.role === 'assistant').pop()) === null || _a === void 0 ? void 0 : _a.content;
@@ -37,15 +37,15 @@ export function AssistantChat({ avatarImageUrl, voiceId, onComplete, autoStartCo
37
37
  const lastMessage = messages[messages.length - 1];
38
38
  useEffect(() => {
39
39
  console.log("lastMessage", lastMessage);
40
- const toolInvocations = lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.toolInvocations;
40
+ const toolInvocations = lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.toolCalls;
41
41
  if (toolInvocations && toolInvocations.length > 0) {
42
42
  console.log("toolInvocations", toolInvocations);
43
43
  onComplete(toolInvocations[0].args);
44
44
  }
45
45
  }, [lastMessage]);
46
- if ((lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.toolInvocations) && lastMessage.toolInvocations.length > 0) {
46
+ if ((lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.toolCalls) && lastMessage.toolCalls.length > 0) {
47
47
  console.log("lastMessage test2", lastMessage);
48
- const args = lastMessage.toolInvocations[0].args;
48
+ const args = lastMessage.toolCalls[0].args;
49
49
  const success = args.explanationUnderstood === "TRUE" || args.studentKnowsTopic === "TRUE";
50
50
  return _jsxs("div", { className: "px-5 pt-5 overflow-y-auto text-center", style: { height: "478px" }, children: [_jsx("h1", { className: 'text-center mt-5 mb-5', children: success ? "Great job!" : "You failed" }), _jsx("p", { children: args.improvementHints })] });
51
51
  }
@@ -1,4 +1,4 @@
1
- import { Tool } from '../../controller/AIController';
1
+ import { Tool } from '../../fromRimori/PluginTypes';
2
2
  import { FirstMessages } from './utils';
3
3
  interface Props {
4
4
  voiceId: any;
@@ -8,6 +8,7 @@ interface Props {
8
8
  isDarkTheme?: boolean;
9
9
  children?: React.ReactNode;
10
10
  autoStartConversation?: FirstMessages;
11
+ className?: string;
11
12
  }
12
- export declare function Avatar({ avatarImageUrl, voiceId, agentTools, autoStartConversation, children, isDarkTheme, circleSize }: Props): import("react/jsx-runtime").JSX.Element;
13
+ export declare function Avatar({ avatarImageUrl, voiceId, agentTools, autoStartConversation, children, isDarkTheme, circleSize, className }: Props): import("react/jsx-runtime").JSX.Element;
13
14
  export {};
@@ -6,11 +6,11 @@ import { CircleAudioAvatar } from './EmbeddedAssistent/CircleAudioAvatar';
6
6
  import { useChat } from '../../hooks/UseChatHook';
7
7
  import { usePlugin } from '../../components';
8
8
  import { getFirstMessages } from './utils';
9
- export function Avatar({ avatarImageUrl, voiceId, agentTools, autoStartConversation, children, isDarkTheme = false, circleSize = "300px" }) {
10
- const { llm, event } = usePlugin();
9
+ export function Avatar({ avatarImageUrl, voiceId, agentTools, autoStartConversation, children, isDarkTheme = false, circleSize = "300px", className }) {
10
+ const { ai, event } = usePlugin();
11
11
  const [agentReplying, setAgentReplying] = useState(false);
12
12
  const [isProcessingMessage, setIsProcessingMessage] = useState(false);
13
- const sender = useMemo(() => new MessageSender(llm.getVoice, voiceId), []);
13
+ const sender = useMemo(() => new MessageSender(ai.getVoice, voiceId), [voiceId]);
14
14
  const { messages, append, isLoading, lastMessage, setMessages } = useChat(agentTools);
15
15
  useEffect(() => {
16
16
  console.log("messages", messages);
@@ -33,13 +33,18 @@ export function Avatar({ avatarImageUrl, voiceId, agentTools, autoStartConversat
33
33
  else if (autoStartConversation.userMessage) {
34
34
  append([{ role: 'user', content: autoStartConversation.userMessage, id: messages.length.toString() }]);
35
35
  }
36
- }, []);
36
+ }, [autoStartConversation]);
37
37
  useEffect(() => {
38
38
  if ((lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.role) === 'assistant') {
39
39
  sender.handleNewText(lastMessage.content, isLoading);
40
+ if (lastMessage.toolCalls) {
41
+ console.log("unlocking mic", lastMessage);
42
+ setAgentReplying(false);
43
+ setIsProcessingMessage(false);
44
+ }
40
45
  }
41
46
  }, [lastMessage, isLoading]);
42
- return (_jsxs("div", { className: 'pb-8', children: [_jsx(CircleAudioAvatar, { width: circleSize, className: 'mx-auto', imageUrl: avatarImageUrl, isDarkTheme: isDarkTheme }), children, _jsx(VoiceRecorder, { iconSize: '300', disabled: agentReplying, loading: isProcessingMessage, onVoiceRecorded: (message) => {
47
+ return (_jsxs("div", { className: `md:pb-8 ${className || ''}`, children: [_jsx(CircleAudioAvatar, { width: circleSize, className: 'mx-auto', imageUrl: avatarImageUrl, isDarkTheme: isDarkTheme }), children, _jsx(VoiceRecorder, { iconSize: '30', className: 'w-16 h-16 shadow-lg rounded-full bg-gray-400 dark:bg-gray-800', disabled: agentReplying, loading: isProcessingMessage, enablePushToTalk: true, onVoiceRecorded: (message) => {
43
48
  setAgentReplying(true);
44
49
  append([{ role: 'user', content: "Message(" + Math.floor((messages.length + 1) / 2) + "): " + message, id: messages.length.toString() }]);
45
50
  }, onRecordingStatusChange: (running) => !running && setIsProcessingMessage(true) })] }));
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useEffect, useRef } from 'react';
3
- import { EventBus } from '../../../plugin/fromRimori/EventBus';
3
+ import { EventBus } from '../../../fromRimori/EventBus';
4
4
  export function CircleAudioAvatar({ imageUrl, className, isDarkTheme = false, width = "150px" }) {
5
5
  const canvasRef = useRef(null);
6
6
  const currentLoudnessRef = useRef(0);