@kumologica/sdk 4.0.0-beta9 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/commands/open.js +29 -4
- package/cli/utils/license.js +9 -6
- package/package.json +7 -7
- package/src/app/lib/stores/settings-ai-store.js +107 -2
- package/src/app/lib/stores/settings-cloud-store.js +2 -1
- package/src/app/lib/utils/tools.min.js +1 -1
- package/src/app/ui/editor-client/public/red/red.js +224 -209
- package/src/app/ui/editor-client/public/red/red.min.js +1 -1
- package/src/app/ui/editor-client/public/red/style.min.css +1 -1
- package/src/app/ui/editor-client/src/js/ui/palette-aiassistant.js +200 -173
- package/src/app/ui/editor-client/src/js/ui/palette.js +24 -36
- package/src/app/ui/editor-client/src/sass/palette.scss +53 -8
- package/src/app/ui/editor-client/templates/index.mst +100 -95
- package/src/app/lib/ai/openai.js +0 -108
package/cli/commands/open.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const path = require("path");
|
|
2
2
|
const { spawn } = require("child_process");
|
|
3
|
-
const { Updater } = require("@kumologica/builder");
|
|
3
|
+
const { Updater, checkSDK } = require("@kumologica/builder");
|
|
4
|
+
|
|
4
5
|
const { confirm } = require("enquirer");
|
|
5
6
|
|
|
6
7
|
const { logError } = require("../utils/logger");
|
|
@@ -138,6 +139,26 @@ async function promptUpdates(updates) {
|
|
|
138
139
|
return false;
|
|
139
140
|
}
|
|
140
141
|
|
|
142
|
+
async function checkSDKVersion() {
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
const sdkVersion = await checkSDK.checkSDK();
|
|
146
|
+
|
|
147
|
+
if (!sdkVersion || sdkVersion === "") {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
console.log("");
|
|
152
|
+
console.log(`-----------------------------------------------------`);
|
|
153
|
+
console.log(`New version of Kumologica SDK is now available: ${sdkVersion}`);
|
|
154
|
+
console.log("To update, run: npm install -g @kumologica/sdk");
|
|
155
|
+
console.log(`-----------------------------------------------------`);
|
|
156
|
+
console.log("");
|
|
157
|
+
}catch (e) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
141
162
|
/*
|
|
142
163
|
check if upgrade in npmjs to the existing ones in package.json
|
|
143
164
|
check if upgrade or missing node_modules vs package.json
|
|
@@ -148,6 +169,7 @@ async function runUpdater(projectDir) {
|
|
|
148
169
|
console.debug("Project directory not provided, skipping upgrade check");
|
|
149
170
|
return;
|
|
150
171
|
}
|
|
172
|
+
|
|
151
173
|
const updater = new Updater(projectDir);
|
|
152
174
|
const updates = await updater.checkForUpdates();
|
|
153
175
|
|
|
@@ -166,9 +188,9 @@ async function runUpdater(projectDir) {
|
|
|
166
188
|
}
|
|
167
189
|
|
|
168
190
|
async function licenseCheck() {
|
|
169
|
-
|
|
170
191
|
const license = require("../utils/license.js");
|
|
171
|
-
|
|
192
|
+
const res = await license.licenseCheck();
|
|
193
|
+
return res;
|
|
172
194
|
}
|
|
173
195
|
|
|
174
196
|
exports.command = "open [project_directory]";
|
|
@@ -183,15 +205,18 @@ exports.desc = "Open Kumologica Designer";
|
|
|
183
205
|
|
|
184
206
|
exports.handler = async ({ project_directory }) => {
|
|
185
207
|
|
|
208
|
+
await checkSDKVersion();
|
|
209
|
+
|
|
186
210
|
const projectDir = project_directory
|
|
187
211
|
? path.resolve(project_directory)
|
|
188
212
|
: undefined;
|
|
189
213
|
|
|
190
|
-
if (!await licenseCheck(
|
|
214
|
+
if (!await licenseCheck()) {
|
|
191
215
|
process.exit(1);
|
|
192
216
|
}
|
|
193
217
|
|
|
194
218
|
await runUpdater(projectDir);
|
|
195
219
|
|
|
220
|
+
|
|
196
221
|
startElectron(projectDir);
|
|
197
222
|
};
|
package/cli/utils/license.js
CHANGED
|
@@ -70,8 +70,10 @@ async function promptForLicenseKey() {
|
|
|
70
70
|
|
|
71
71
|
console.log(`📧 Developer license will be requested for: ${email}`);
|
|
72
72
|
|
|
73
|
-
await tools.license.subscribe(email);
|
|
74
|
-
|
|
73
|
+
const res = await tools.license.subscribe(email);
|
|
74
|
+
if (res) {
|
|
75
|
+
console.log(`Follow the instructions in your email to complete the process.`);
|
|
76
|
+
}
|
|
75
77
|
|
|
76
78
|
return false;
|
|
77
79
|
} else {
|
|
@@ -92,15 +94,16 @@ async function licenseCheck() {
|
|
|
92
94
|
console.log("Reading license data...");
|
|
93
95
|
try {
|
|
94
96
|
const licenseData = tools.license.read(getHomeDir());
|
|
95
|
-
|
|
97
|
+
if (licenseData != null) {
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
|
|
96
101
|
} catch (e) {
|
|
97
102
|
console.error("Error reading license data:", e.message);
|
|
98
103
|
}
|
|
99
104
|
|
|
100
105
|
console.log("No license data...");
|
|
101
|
-
await promptForLicenseKey();
|
|
102
|
-
|
|
103
|
-
return false;
|
|
106
|
+
return await promptForLicenseKey();
|
|
104
107
|
}
|
|
105
108
|
|
|
106
109
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kumologica/sdk",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"productName": "Kumologica Designer",
|
|
5
5
|
"copyright": "Copyright 2020 Kumologica Pty Ltd, All Rights Reserved.",
|
|
6
6
|
"author": "Kumologica Pty Ltd <contact@kumologica.com>",
|
|
@@ -88,9 +88,9 @@
|
|
|
88
88
|
"@aws-sdk/signature-v4": "^3.370.0",
|
|
89
89
|
"@aws-sdk/types": "^3.936.0",
|
|
90
90
|
"@electron/remote": "^2.0.8",
|
|
91
|
-
"@kumologica/builder": "4.0.
|
|
92
|
-
"@kumologica/devkit": "4.0.
|
|
93
|
-
"@kumologica/runtime": "4.0.
|
|
91
|
+
"@kumologica/builder": "4.0.1",
|
|
92
|
+
"@kumologica/devkit": "4.0.1",
|
|
93
|
+
"@kumologica/runtime": "4.0.1",
|
|
94
94
|
"ajv": "8.10.0",
|
|
95
95
|
"archive-type": "^4.0.0",
|
|
96
96
|
"basic-auth": "2.0.1",
|
|
@@ -127,7 +127,7 @@
|
|
|
127
127
|
"js-yaml": "3.13.1",
|
|
128
128
|
"json-cycle": "^1.3.0",
|
|
129
129
|
"jsonata": "1.7.0",
|
|
130
|
-
"jsonpath": "1.0
|
|
130
|
+
"jsonpath": "1.3.0",
|
|
131
131
|
"make-dir": "^3.1.0",
|
|
132
132
|
"memorystore": "1.6.1",
|
|
133
133
|
"mime": "2.4.4",
|
|
@@ -179,8 +179,8 @@
|
|
|
179
179
|
"grunt-terser": "2.0.0",
|
|
180
180
|
"istanbul": "^0.4.5",
|
|
181
181
|
"license-checker": "^25.0.1",
|
|
182
|
-
"license-compatibility-checker": "^0.3.
|
|
183
|
-
"license-report": "^
|
|
182
|
+
"license-compatibility-checker": "^0.3.5",
|
|
183
|
+
"license-report": "^6.8.2",
|
|
184
184
|
"mocha": "10.2.0",
|
|
185
185
|
"node-sass": "9.0.0",
|
|
186
186
|
"tslint": "^5.18.0",
|
|
@@ -44,9 +44,19 @@ const got = require('got');
|
|
|
44
44
|
|
|
45
45
|
const PROMPT_URL = 'https://kumologica.com/ai/kumologica-prompt.md';
|
|
46
46
|
const FILENAME_PREFIX = 'kumologica-prompt';
|
|
47
|
+
const CHAT_HISTORY_FILENAME = 'kumologica-chat-history.json';
|
|
47
48
|
const FILE_EXTENSION = '.md';
|
|
48
49
|
const MAX_AGE_DAYS = 7;
|
|
49
50
|
|
|
51
|
+
const emptyHistory =
|
|
52
|
+
[
|
|
53
|
+
{
|
|
54
|
+
timestamp: 'latest',
|
|
55
|
+
title: 'Latest Chat',
|
|
56
|
+
messages: []
|
|
57
|
+
}
|
|
58
|
+
];
|
|
59
|
+
|
|
50
60
|
class AiConfigStore {
|
|
51
61
|
// aiConfigFileFullPath: a string representing the full path of the ai config file
|
|
52
62
|
|
|
@@ -56,6 +66,8 @@ class AiConfigStore {
|
|
|
56
66
|
const credsFile = `ai`;
|
|
57
67
|
|
|
58
68
|
this.aiConfigFileFullPath = path.join(homedir, credsDir, credsFile);
|
|
69
|
+
this.chatHistoryFileFullPath = path.join(homedir, credsDir, CHAT_HISTORY_FILENAME);
|
|
70
|
+
|
|
59
71
|
this.promptDirectory = path.join(homedir, credsDir);
|
|
60
72
|
|
|
61
73
|
// check whether the config file exist or not: ~/.kumologica/ai
|
|
@@ -66,6 +78,14 @@ class AiConfigStore {
|
|
|
66
78
|
fs.writeFileSync(this.aiConfigFileFullPath, defaultContent);
|
|
67
79
|
}
|
|
68
80
|
|
|
81
|
+
// check whether the chat history file exist or not: ~/.kumologica/ai
|
|
82
|
+
if (!fs.existsSync(this.chatHistoryFileFullPath)){
|
|
83
|
+
// create file and write default content on it
|
|
84
|
+
console.log(`Creating AI chat history file on: ${this.chatHistoryFileFullPath}...`)
|
|
85
|
+
fsx.ensureDirSync(path.join(homedir, credsDir));
|
|
86
|
+
fs.writeFileSync(this.chatHistoryFileFullPath, JSON.stringify(emptyHistory));
|
|
87
|
+
}
|
|
88
|
+
|
|
69
89
|
this.initFile = this.parseAiConfigFile();
|
|
70
90
|
this.syncPrompt();
|
|
71
91
|
}
|
|
@@ -116,7 +136,6 @@ class AiConfigStore {
|
|
|
116
136
|
}
|
|
117
137
|
}
|
|
118
138
|
|
|
119
|
-
|
|
120
139
|
async syncPrompt() {
|
|
121
140
|
const files = this.getPromptFiles();
|
|
122
141
|
const newest = files[0] || null;
|
|
@@ -152,7 +171,7 @@ class AiConfigStore {
|
|
|
152
171
|
}
|
|
153
172
|
|
|
154
173
|
parseAiConfigFile() {
|
|
155
|
-
this.initFile = ini.parse(this.readAiConfigFile());
|
|
174
|
+
this.initFile = this.unnestIni(ini.parse(this.readAiConfigFile()));
|
|
156
175
|
return this.initFile;
|
|
157
176
|
}
|
|
158
177
|
|
|
@@ -187,6 +206,92 @@ class AiConfigStore {
|
|
|
187
206
|
|
|
188
207
|
return lines.map(l => l.trim()).join('\n');
|
|
189
208
|
}
|
|
209
|
+
|
|
210
|
+
// history management methods
|
|
211
|
+
//
|
|
212
|
+
// the structure of chatHistory is an array of histories
|
|
213
|
+
// each history is an object of timestamp, title and array of messages
|
|
214
|
+
// the latest chat history is not timestamped but has a value of latest
|
|
215
|
+
//
|
|
216
|
+
readChatHistory() {
|
|
217
|
+
try {
|
|
218
|
+
const data = fs.readFileSync(this.chatHistoryFileFullPath, "utf-8");
|
|
219
|
+
const chatHistory = JSON.parse(data);
|
|
220
|
+
return chatHistory;
|
|
221
|
+
} catch (err) {
|
|
222
|
+
console.error('Failed to read chat history file:', err.message);
|
|
223
|
+
return emptyHistory;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
getChat(timestamp) {
|
|
228
|
+
const chatHistory = this.readChatHistory();
|
|
229
|
+
return chatHistory.find(h => h.timestamp === timestamp);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
writeChatHistoryFile(content) {
|
|
233
|
+
fs.writeFileSync(this.chatHistoryFileFullPath, content);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
updateChatHistory(timestamp, messages) {
|
|
237
|
+
let chatHistory = this.readChatHistory();
|
|
238
|
+
|
|
239
|
+
let chat = chatHistory.find(h => h.timestamp === timestamp);
|
|
240
|
+
if (chat) {
|
|
241
|
+
chat.messages = messages;
|
|
242
|
+
this.writeChatHistoryFile(JSON.stringify(chatHistory));
|
|
243
|
+
} else {
|
|
244
|
+
console.error(`Chat history with timestamp ${timestamp} not found.`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
newLatestChat() {
|
|
249
|
+
let chatHistory = this.readChatHistory() || [];
|
|
250
|
+
|
|
251
|
+
let chat = chatHistory.find(h => h.timestamp === "latest");
|
|
252
|
+
if (chat) {
|
|
253
|
+
chat.timestamp = new Date().toISOString();
|
|
254
|
+
}
|
|
255
|
+
chatHistory.push({
|
|
256
|
+
timestamp: 'latest',
|
|
257
|
+
title: 'Latest Chat',
|
|
258
|
+
messages: []
|
|
259
|
+
});
|
|
260
|
+
this.writeChatHistoryFile(JSON.stringify(chatHistory));
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
unnestIni(parsed) {
|
|
264
|
+
const result = {};
|
|
265
|
+
|
|
266
|
+
function recurse(obj, path = '') {
|
|
267
|
+
for (const key in obj) {
|
|
268
|
+
if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
|
|
269
|
+
|
|
270
|
+
const val = obj[key];
|
|
271
|
+
const fullPath = path ? `${path}.${key}` : key;
|
|
272
|
+
|
|
273
|
+
if (val && typeof val === 'object' && !Array.isArray(val)) {
|
|
274
|
+
// Check if this object contains only primitive values (i.e. it's a real section)
|
|
275
|
+
const isSectionContent = Object.values(val).every(
|
|
276
|
+
v => typeof v !== 'object' || v === null
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
if (isSectionContent) {
|
|
280
|
+
result[fullPath] = val; // ← this is what you want
|
|
281
|
+
} else {
|
|
282
|
+
recurse(val, fullPath); // deeper nesting in section name
|
|
283
|
+
}
|
|
284
|
+
} else {
|
|
285
|
+
// rare top-level key=value outside any section
|
|
286
|
+
result[fullPath] = val;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
recurse(parsed);
|
|
292
|
+
return result;
|
|
293
|
+
}
|
|
294
|
+
|
|
190
295
|
}
|
|
191
296
|
|
|
192
297
|
module.exports = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var e,o,n,
|
|
1
|
+
var e,o,n,r,s=require("crypto"),t=require("fs"),c=require("path");function l(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function i(){if(!o){o=1;let l="base64";e={subscribe:async function(e){console.log("Requesting license for email: "+e);try{var o=await fetch("https://api.infra.kumologica.com/p/signup?x-api-key=RjibYF3qZb2AzmTrPOnV35LfRV798e3Z87vp4izo",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:e})});if(o.ok)return!0;{let e=await o.text();return console.error(`License request failed: ${o.status} `+e),!1}}catch(e){return console.error("Fetch failed (network/socket level):",e.message),console.log("Node version:",process.version),console.log("Timeout being used (default 300s if not set):",fetch.Timeout||"not set"),e.cause&&(console.error("Underlying cause:",e.cause),console.error("Cause name:",e.cause.name),console.error("Cause message:",e.cause.message),console.error("Cause code (if any):",e.cause.code)),!1}},display:function(e){e?(console.log("-------- License Details ----------"),console.log("Subscriber: "+e.sub),console.log("Email: "+e.email),console.log("License Type: "+e.licenseType),console.log("Issued For: "+(e.name||e.email)),console.log("Issued By: "+e.iss),console.log("Issued At: "+new Date(e.iat).toLocaleString()),console.log("Expiry: "+("perpetual"===e.exp?"Perpetual":new Date(e.exp).toLocaleString())),console.log("-----------------------------------")):console.error("Invalid license data.")},verify:function(e){publicKeyPem=(()=>{var r=Buffer.from("XkI1bxBWOXhHBztkdXIuEXlKLBcSIWstZlEzOEADPyFCCVkUeQNIIxwWDU4QEiEyLHpfOjwHCVNlL3tTFiIvMGkcZCkOBnNgIjtybUckA3x7BRARDElXRxECPlB4OgF4aWIRDQAGLBI2Jns3eTINDkx+XSN9bAAFDHllInIdCEg8SzICC2JJJyl4CGk5JAB/EBQcLW4+dzcuMGxhLglhbHUZF2ZwFQMJEl08cAVfWGd5ADtje34SDUJCHxUlWh83aghXDnJXXwxxCFsUNANhCzJ0MHoiVyEvLlh2OC5gf2UwdGZhDxAvMllUcCgSWl1w",l).toString().split("").reverse().join("");let n="";for(let o=0;o<r.length;o++){let e="34jfd#d-cDFG23@W096ml".charCodeAt(o%21);n+=String.fromCharCode(r.charCodeAt(o)^e)}return Buffer.from(n,l).toString()})();var o=s,[e,r]=e.split(".");if(!e||!r)throw new Error("Invalid license format. License may have been tampered.");var e=Buffer.from(e,"base64url").toString("utf-8"),n=JSON.parse(e),e=Buffer.from(e,"utf-8"),r=Buffer.from(r,l),o=o.createVerify("SHA256");if(o.update(e),o.end(),!o.verify(publicKeyPem,r))throw new Error("Invalid license signature. License may have been tampered.");if(!(n&&n.sub&&n.email&&n.iss&&n.iat))throw new Error("Invalid license data. License may have been tampered.");if(n.exp&&("Perpetual"===n.exp||Date.now()>n.exp))throw new Error("License has expired. Please renew your license, contact Kumologica support at contact@kumologica.com.");return n},save:function(e,o){var r=t,n=c,n=(console.log("saving key to: "+e),n.join(e,"kumologica.license"));try{r.writeFileSync(n,o,"utf-8"),console.log("License saved successfully at: "+n)}catch(e){console.error("Failed to save license: "+e.message)}},read:function(e){var o=t,r=c.join(e,"kumologica.license");try{let e=o.readFileSync(r,"utf-8");return console.log("License read successfully from: "+r),e}catch(e){return null}}}}return e}var a=(()=>{if(r)return n;r=1;var e=i();return n={license:e}})(),u=l(a);module.exports=u;
|