@kumologica/sdk 4.0.0-beta8 → 4.0.0-beta9
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/LICENSE +170 -0
- package/cli/commands/export-commands/cloudformation.js +1 -1
- package/cli/commands/run.js +68 -29
- package/cli/commands/test.js +1 -1
- package/package.json +12 -9
- package/src/app/lib/ai/chatai.js +179 -0
- package/src/app/lib/stores/settings-ai-store.js +194 -0
- package/src/app/preload.js +12 -4
- package/src/app/ui/editor-client/public/red/red.js +836 -216
- package/src/app/ui/editor-client/public/red/red.min.js +2 -2
- package/src/app/ui/editor-client/public/red/style.min.css +1 -1
- package/src/app/ui/editor-client/src/js/red.js +1 -0
- package/src/app/ui/editor-client/src/js/ui/aitab.js +90 -0
- package/src/app/ui/editor-client/src/js/ui/editor.js +115 -1
- package/src/app/ui/editor-client/src/js/ui/palette-aiassistant.js +527 -0
- package/src/app/ui/editor-client/src/js/ui/palette.js +132 -0
- package/src/app/ui/editor-client/src/js/ui/tray.js +10 -0
- package/src/app/ui/editor-client/src/js/ui/ui-settings.js +50 -5
- package/src/app/ui/editor-client/src/sass/palette.scss +41 -1
- package/src/app/ui/editor-client/src/sass/ui-settings.scss +11 -0
- package/src/app/ui/editor-client/templates/index.mst +45 -3
- package/src/server/TaskServer.js +68 -0
- package/cli/utils/fs/create-zip-file.js +0 -39
- package/src/app/ui/editor-client/src/js/ui/tab-ai.js +0 -210
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
// properties: ~/.kumologica/credentials
|
|
2
|
+
|
|
3
|
+
const defaultContent = `; This file contains all your sensitive credential information
|
|
4
|
+
; about your ai configuration used by Kumologica Designer.
|
|
5
|
+
; For more information visit https://docs.kumologica.com/settings
|
|
6
|
+
;
|
|
7
|
+
; supported providers: openai, anthropic, deepseek, xai, gemini, aws bedrock
|
|
8
|
+
;
|
|
9
|
+
; Examples:
|
|
10
|
+
;
|
|
11
|
+
; =============== Anthropic =======================
|
|
12
|
+
; [anthropic-haiku]
|
|
13
|
+
; provider = anthropic
|
|
14
|
+
; model = claude-haiku-4-5
|
|
15
|
+
; api_key = your-anthropic-api-key
|
|
16
|
+
; max_tokens = 4096
|
|
17
|
+
; temperature = 0.7
|
|
18
|
+
|
|
19
|
+
; ============= OpenAI =======================
|
|
20
|
+
; [openai-gpt4o]
|
|
21
|
+
; provider = openai
|
|
22
|
+
; model = gpt-4o
|
|
23
|
+
; api_key = your-openai-api-key
|
|
24
|
+
; max_tokens = 8192
|
|
25
|
+
; temperature = 0.7
|
|
26
|
+
|
|
27
|
+
; ============= AWS Bedrock =======================
|
|
28
|
+
; [aws bedrock claude 3.5 sonnet]
|
|
29
|
+
; provider = bedrock
|
|
30
|
+
; model=anthropic.claude-3-5-sonnet-20241022-v2:0
|
|
31
|
+
; region=ap-southeast-2
|
|
32
|
+
; ; your local AWS profile name, if not provided the default profile will be used
|
|
33
|
+
; profile=bedrock
|
|
34
|
+
; max_tokens = 8192
|
|
35
|
+
; temperature = 0.7
|
|
36
|
+
`
|
|
37
|
+
|
|
38
|
+
const os = require('os');
|
|
39
|
+
const fs = require('fs');
|
|
40
|
+
const fsx = require('fs-extra')
|
|
41
|
+
const ini = require('ini');
|
|
42
|
+
const path = require('path');
|
|
43
|
+
const got = require('got');
|
|
44
|
+
|
|
45
|
+
const PROMPT_URL = 'https://kumologica.com/ai/kumologica-prompt.md';
|
|
46
|
+
const FILENAME_PREFIX = 'kumologica-prompt';
|
|
47
|
+
const FILE_EXTENSION = '.md';
|
|
48
|
+
const MAX_AGE_DAYS = 7;
|
|
49
|
+
|
|
50
|
+
class AiConfigStore {
|
|
51
|
+
// aiConfigFileFullPath: a string representing the full path of the ai config file
|
|
52
|
+
|
|
53
|
+
constructor() {
|
|
54
|
+
let homedir = os.homedir();
|
|
55
|
+
const credsDir = '.kumologica';
|
|
56
|
+
const credsFile = `ai`;
|
|
57
|
+
|
|
58
|
+
this.aiConfigFileFullPath = path.join(homedir, credsDir, credsFile);
|
|
59
|
+
this.promptDirectory = path.join(homedir, credsDir);
|
|
60
|
+
|
|
61
|
+
// check whether the config file exist or not: ~/.kumologica/ai
|
|
62
|
+
if (!fs.existsSync(this.aiConfigFileFullPath)){
|
|
63
|
+
// create file and write default content on it
|
|
64
|
+
console.log(`Creating AI config file on: ${this.aiConfigFileFullPath}...`)
|
|
65
|
+
fsx.ensureDirSync(path.join(homedir, credsDir));
|
|
66
|
+
fs.writeFileSync(this.aiConfigFileFullPath, defaultContent);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
this.initFile = this.parseAiConfigFile();
|
|
70
|
+
this.syncPrompt();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
deleteOldFiles(files) {
|
|
74
|
+
for (const f of files) {
|
|
75
|
+
try {
|
|
76
|
+
fs.unlinkSync(f.fullPath);
|
|
77
|
+
console.debug(`Deleted old: ${f.name}`);
|
|
78
|
+
} catch {}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
getPromptFiles() {
|
|
83
|
+
try {
|
|
84
|
+
return fs.readdirSync(this.promptDirectory)
|
|
85
|
+
.filter(f => f.startsWith(FILENAME_PREFIX) && f.endsWith(FILE_EXTENSION))
|
|
86
|
+
.map(f => {
|
|
87
|
+
const fullPath = path.join(this.promptDirectory, f);
|
|
88
|
+
try {
|
|
89
|
+
const stat = fs.statSync(fullPath);
|
|
90
|
+
return { name: f, fullPath, mtime: stat.mtime.getTime() };
|
|
91
|
+
} catch {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
})
|
|
95
|
+
.filter(Boolean)
|
|
96
|
+
.sort((a, b) => b.mtime - a.mtime); // newest first
|
|
97
|
+
} catch {
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
getPrompt() {
|
|
103
|
+
if (this.prompt) {
|
|
104
|
+
return this.prompt;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const newest = this.getPromptFiles()[0];
|
|
108
|
+
if (!newest) return null;
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
this.prompt = fs.readFileSync(newest.fullPath, 'utf-8').trim();
|
|
112
|
+
return this.prompt;
|
|
113
|
+
} catch (err) {
|
|
114
|
+
console.error('Failed to read prompt file:', err.message);
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
async syncPrompt() {
|
|
121
|
+
const files = this.getPromptFiles();
|
|
122
|
+
const newest = files[0] || null;
|
|
123
|
+
|
|
124
|
+
const isRecent = newest && (Date.now() - newest.mtime) <= MAX_AGE_DAYS * 24 * 60 * 60 * 1000;
|
|
125
|
+
|
|
126
|
+
if (isRecent) {
|
|
127
|
+
// Still fresh → just clean up any old junk and exit
|
|
128
|
+
this.deleteOldFiles(files.slice(1));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Need fresh copy
|
|
133
|
+
const filename = `${FILENAME_PREFIX}-${new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19)}${FILE_EXTENSION}`;
|
|
134
|
+
const filepath = path.join(this.promptDirectory, filename);
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
console.log('Downloading latest prompt...');
|
|
138
|
+
const { body } = await got(PROMPT_URL);
|
|
139
|
+
fs.writeFileSync(filepath, body, 'utf-8');
|
|
140
|
+
console.log(`Saved: ${filename}`);
|
|
141
|
+
|
|
142
|
+
// Delete everything except the new file
|
|
143
|
+
this.deleteOldFiles(files);
|
|
144
|
+
} catch (err) {
|
|
145
|
+
try { fs.unlinkSync(filepath); } catch {}
|
|
146
|
+
throw new Error(`Download failed: ${err.message}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
getSections() {
|
|
151
|
+
return Object.keys(this.initFile).filter(key => key !== '');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
parseAiConfigFile() {
|
|
155
|
+
this.initFile = ini.parse(this.readAiConfigFile());
|
|
156
|
+
return this.initFile;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
getAliases(section){
|
|
160
|
+
if (this.initFile && this.initFile[section]){
|
|
161
|
+
return Object.keys(this.initFile[section]);
|
|
162
|
+
}else{
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
getAliasInfo(section, alias) {
|
|
168
|
+
if (this.initFile && this.initFile[section]){
|
|
169
|
+
return this.initFile[section][alias];
|
|
170
|
+
}else{
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
getAiConfigFileFullPath() {
|
|
176
|
+
return this.aiConfigFileFullPath;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
writeAiConfigFile(content) {
|
|
180
|
+
this.initFile = ini.parse(content);
|
|
181
|
+
fs.writeFileSync(this.aiConfigFileFullPath, content);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
readAiConfigFile() {
|
|
185
|
+
const data = fs.readFileSync(this.aiConfigFileFullPath, "utf-8");
|
|
186
|
+
const lines = data.split(/\r\n|\n/);
|
|
187
|
+
|
|
188
|
+
return lines.map(l => l.trim()).join('\n');
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
module.exports = {
|
|
193
|
+
AiConfigStore
|
|
194
|
+
};
|
package/src/app/preload.js
CHANGED
|
@@ -35,8 +35,9 @@ const KumohubConfig = require("./lib/stores/kumohub-config-store");
|
|
|
35
35
|
const AzureConfig = require("./lib/stores/azure-config-store");
|
|
36
36
|
const ProjectInfoConfig = require("./lib/stores/project-info-config-store");
|
|
37
37
|
const { CloudConfigStore } = require("./lib/stores/settings-cloud-store");
|
|
38
|
+
const { AiConfigStore } = require("./lib/stores/settings-ai-store");
|
|
38
39
|
const { NetworkConfigStore } = require("./lib/stores/settings-network-store");
|
|
39
|
-
const {
|
|
40
|
+
const { chatAi } = require("./lib/ai/chatai");
|
|
40
41
|
|
|
41
42
|
const AWSProfile = require("./lib/aws/aws-profile");
|
|
42
43
|
const AWSDeployer = require("./lib/aws");
|
|
@@ -69,10 +70,9 @@ const KUMOLOGICA_NODE_LIB_BASEURL = "https://library.kumohub.io";
|
|
|
69
70
|
const KUMOLOGICA_NODE_LIB_URL = `${KUMOLOGICA_NODE_LIB_BASEURL}/library.json`;
|
|
70
71
|
|
|
71
72
|
const cloudConfigStore = new CloudConfigStore();
|
|
73
|
+
const aiConfigStore = new AiConfigStore();
|
|
72
74
|
const networkConfigStore = new NetworkConfigStore();
|
|
73
75
|
|
|
74
|
-
const openAIClient = new OpenAIClient({ version: "gpt-3.5-turbo" }); //'gpt-4'
|
|
75
|
-
|
|
76
76
|
// function to be called each time
|
|
77
77
|
// project changes - either new project created or old project opened.
|
|
78
78
|
// header.js is the component handling project changes.
|
|
@@ -82,6 +82,7 @@ function loadConfigs() {
|
|
|
82
82
|
window.__kumologica.settings.cloudConfig = new CloudConfig.CloudConfigStore({
|
|
83
83
|
dataPath: window.__kumologica.settings.projectDir,
|
|
84
84
|
});
|
|
85
|
+
window.__kumologica.settings.aiConfig = new AiConfigStore();
|
|
85
86
|
|
|
86
87
|
window.__kumologica.settings.kumohubConfig =
|
|
87
88
|
new KumohubConfig.KumohubConfigStore({
|
|
@@ -580,6 +581,11 @@ function includeNodePathIntoPath() {
|
|
|
580
581
|
}
|
|
581
582
|
}
|
|
582
583
|
|
|
584
|
+
|
|
585
|
+
async function chatWithAi(params) {
|
|
586
|
+
return await chatAi(params );
|
|
587
|
+
}
|
|
588
|
+
|
|
583
589
|
async function npmInstall(dependency) {
|
|
584
590
|
return new Promise((resolve, reject) => {
|
|
585
591
|
window.__kumologica.editor.terminal.eventEmitter.emit(
|
|
@@ -679,6 +685,7 @@ window.__kumologica.settings = {};
|
|
|
679
685
|
window.__kumologica.settings.loadConfigs = loadConfigs;
|
|
680
686
|
|
|
681
687
|
window.__kumologica.settings.cloudConfigStore = cloudConfigStore;
|
|
688
|
+
window.__kumologica.settings.aiConfigStore = aiConfigStore;
|
|
682
689
|
window.__kumologica.settings.networkConfigStore = networkConfigStore;
|
|
683
690
|
window.__kumologica.settings.workspacePreferenceStore =
|
|
684
691
|
new WorkspacePreferenceStore();
|
|
@@ -737,7 +744,8 @@ window.__kumologica.libs.dagre = dagre;
|
|
|
737
744
|
window.__kumologica.libs.simpleGit = simpleGit;
|
|
738
745
|
|
|
739
746
|
// AI utilities
|
|
740
|
-
window.__kumologica.libs.
|
|
747
|
+
window.__kumologica.libs.chatAi = chatWithAi;
|
|
748
|
+
|
|
741
749
|
|
|
742
750
|
/**
|
|
743
751
|
* Return the name of the valid kumologica flow or undefined otherwise.
|