@akanjs/cli 2.2.1 → 2.2.2-rc.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.
- package/incrementalBuilder.proc.js +56 -40
- package/index.js +74 -60
- package/package.json +2 -2
|
@@ -17,18 +17,6 @@ import { ChatOpenAI } from "@langchain/openai";
|
|
|
17
17
|
import { Logger as Logger2 } from "akanjs/common";
|
|
18
18
|
import chalk from "chalk";
|
|
19
19
|
|
|
20
|
-
// pkgs/@akanjs/devkit/cloud/constants.ts
|
|
21
|
-
var basePath = `${Bun.env.HOME ?? Bun.env.USERPROFILE}/.akan`;
|
|
22
|
-
var configPath = `${basePath}/config.json`;
|
|
23
|
-
var akanCloudHost = process.env.USE_AKANJS_PKGS === "true" ? "http://localhost" : "https://cloud.akanjs.com";
|
|
24
|
-
var akanCloudUrl = `${akanCloudHost}${process.env.USE_AKANJS_PKGS === "true" ? ":8282" : ""}/api`;
|
|
25
|
-
var defaultHostConfig = {};
|
|
26
|
-
var defaultAkanGlobalConfig = {
|
|
27
|
-
cloudHost: {},
|
|
28
|
-
remoteEnvServers: {},
|
|
29
|
-
llm: null
|
|
30
|
-
};
|
|
31
|
-
|
|
32
20
|
// pkgs/@akanjs/devkit/cloud/globalConfig.ts
|
|
33
21
|
import { mkdir } from "fs/promises";
|
|
34
22
|
import dayjs from "dayjs";
|
|
@@ -71,8 +59,19 @@ class FileSys {
|
|
|
71
59
|
}
|
|
72
60
|
}
|
|
73
61
|
|
|
62
|
+
// pkgs/@akanjs/devkit/cloud/constants.ts
|
|
63
|
+
var basePath = `${Bun.env.HOME ?? Bun.env.USERPROFILE}/.akan`;
|
|
64
|
+
var configPath = `${basePath}/config.json`;
|
|
65
|
+
var getDefaultHostConfig = (host = GlobalConfig.akanCloudHost) => ({ host });
|
|
66
|
+
var defaultAkanGlobalConfig = {
|
|
67
|
+
cloudHost: {},
|
|
68
|
+
remoteEnvServers: {},
|
|
69
|
+
llm: null
|
|
70
|
+
};
|
|
71
|
+
|
|
74
72
|
// pkgs/@akanjs/devkit/cloud/globalConfig.ts
|
|
75
73
|
class GlobalConfig {
|
|
74
|
+
static akanCloudHost = process.env.USE_AKANJS_PKGS === "true" ? `http://localhost:${process.env.CLOUD_HOST_PORT ?? 8283}` : "https://cloud.akanjs.com";
|
|
76
75
|
static async#getAkanGlobalConfig() {
|
|
77
76
|
const exists = await FileSys.fileExists(configPath);
|
|
78
77
|
const akanConfig = exists ? await FileSys.readJson(configPath) : {};
|
|
@@ -87,13 +86,13 @@ class GlobalConfig {
|
|
|
87
86
|
await mkdir(basePath, { recursive: true });
|
|
88
87
|
await Bun.write(configPath, JSON.stringify(akanConfig, null, 2));
|
|
89
88
|
}
|
|
90
|
-
static async getHostConfig(host = akanCloudHost) {
|
|
89
|
+
static async getHostConfig(host = GlobalConfig.akanCloudHost) {
|
|
91
90
|
const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
|
|
92
|
-
return GlobalConfig.toHostConfig(akanConfig.cloudHost[host] ??
|
|
91
|
+
return GlobalConfig.toHostConfig(akanConfig.cloudHost[host] ?? getDefaultHostConfig(host));
|
|
93
92
|
}
|
|
94
|
-
static async setHostConfig(
|
|
93
|
+
static async setHostConfig(config = getDefaultHostConfig()) {
|
|
95
94
|
const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
|
|
96
|
-
akanConfig.cloudHost[host] = GlobalConfig.toHostConfigDto(config);
|
|
95
|
+
akanConfig.cloudHost[config.host] = GlobalConfig.toHostConfigDto(config);
|
|
97
96
|
await GlobalConfig.#setAkanGlobalConfig(akanConfig);
|
|
98
97
|
}
|
|
99
98
|
static async getLlmConfig() {
|
|
@@ -145,6 +144,7 @@ class GlobalConfig {
|
|
|
145
144
|
}
|
|
146
145
|
static toHostConfigDto(hostConfig) {
|
|
147
146
|
return {
|
|
147
|
+
host: hostConfig.host,
|
|
148
148
|
auth: {
|
|
149
149
|
accessToken: hostConfig.auth?.accessToken ? GlobalConfig.toAccessTokenDto(hostConfig.auth.accessToken) : undefined,
|
|
150
150
|
self: hostConfig.auth?.self
|
|
@@ -153,6 +153,7 @@ class GlobalConfig {
|
|
|
153
153
|
}
|
|
154
154
|
static toHostConfig(hostConfigDto) {
|
|
155
155
|
return {
|
|
156
|
+
host: hostConfigDto.host,
|
|
156
157
|
auth: {
|
|
157
158
|
accessToken: hostConfigDto.auth?.accessToken ? GlobalConfig.toAccessToken(hostConfigDto.auth.accessToken) : undefined,
|
|
158
159
|
self: hostConfigDto.auth?.self
|
|
@@ -177,7 +178,7 @@ class HttpClient {
|
|
|
177
178
|
...headers
|
|
178
179
|
}
|
|
179
180
|
});
|
|
180
|
-
return response.json();
|
|
181
|
+
return await response.json();
|
|
181
182
|
}
|
|
182
183
|
async getFile(url, localPath, headers) {
|
|
183
184
|
const response = await fetch(`${this.baseUrl}${url}`, {
|
|
@@ -194,7 +195,7 @@ class HttpClient {
|
|
|
194
195
|
body: isFormData ? data : JSON.stringify(data),
|
|
195
196
|
headers: isFormData ? { ...this.headers, ...headers } : { "Content-Type": "application/json", ...this.headers, ...headers }
|
|
196
197
|
});
|
|
197
|
-
return response.json();
|
|
198
|
+
return await response.json();
|
|
198
199
|
}
|
|
199
200
|
setHeaders(headers) {
|
|
200
201
|
Object.assign(this.headers, headers);
|
|
@@ -206,21 +207,25 @@ class CloudApi {
|
|
|
206
207
|
#api;
|
|
207
208
|
#accessToken = null;
|
|
208
209
|
#workspace;
|
|
210
|
+
host;
|
|
211
|
+
url;
|
|
209
212
|
static async fromHost(workspace, host) {
|
|
210
213
|
const hostConfig = await GlobalConfig.getHostConfig(host);
|
|
211
214
|
return new CloudApi(workspace, hostConfig);
|
|
212
215
|
}
|
|
213
216
|
constructor(workspace, hostConfig) {
|
|
214
217
|
this.#workspace = workspace;
|
|
215
|
-
const host = akanCloudHost;
|
|
216
|
-
this.#api = new HttpClient(`${host}/api`);
|
|
217
218
|
this.#accessToken = hostConfig.auth?.accessToken ?? null;
|
|
219
|
+
this.host = hostConfig.host;
|
|
220
|
+
this.url = `${this.host}/api`;
|
|
221
|
+
this.#api = new HttpClient(this.url);
|
|
218
222
|
if (this.#accessToken && !GlobalConfig.needRefreshToken(this.#accessToken))
|
|
219
223
|
this.#api.setHeaders({
|
|
220
224
|
Authorization: `Bearer ${this.#accessToken.jwt}`
|
|
221
225
|
});
|
|
222
226
|
}
|
|
223
227
|
async uploadEnv(devProjectId, file) {
|
|
228
|
+
await this.#ensureAccessTokenLive();
|
|
224
229
|
const formData = new FormData;
|
|
225
230
|
formData.append("devProjectId", devProjectId);
|
|
226
231
|
formData.append("file", file);
|
|
@@ -228,18 +233,13 @@ class CloudApi {
|
|
|
228
233
|
return data;
|
|
229
234
|
}
|
|
230
235
|
async downloadEnv(devProjectId) {
|
|
236
|
+
await this.#ensureAccessTokenLive();
|
|
231
237
|
const localPath = `${this.#workspace.workspaceRoot}/local/env.tar`;
|
|
232
238
|
await this.#api.getFile(`/downloadEnv/${devProjectId}`, localPath);
|
|
233
239
|
return localPath;
|
|
234
240
|
}
|
|
235
241
|
async getRemoteAuthToken(remoteId) {
|
|
236
242
|
try {
|
|
237
|
-
if (this.#accessToken) {
|
|
238
|
-
if (GlobalConfig.needRefreshToken(this.#accessToken))
|
|
239
|
-
return await this.#refreshAuthToken();
|
|
240
|
-
else
|
|
241
|
-
return await this.#refreshAuthToken();
|
|
242
|
-
}
|
|
243
243
|
const accessToken = await this.#api.get(`/getRemoteAuthToken/${remoteId}`);
|
|
244
244
|
this.#accessToken = GlobalConfig.toAccessToken(accessToken);
|
|
245
245
|
this.#api.setHeaders({
|
|
@@ -250,14 +250,21 @@ class CloudApi {
|
|
|
250
250
|
return null;
|
|
251
251
|
}
|
|
252
252
|
}
|
|
253
|
-
async#
|
|
253
|
+
async#ensureAccessTokenLive({
|
|
254
|
+
allowUnauthorized = false
|
|
255
|
+
} = {}) {
|
|
256
|
+
if (!this.#accessToken)
|
|
257
|
+
throw new Error("No access token");
|
|
258
|
+
const needRefresh = GlobalConfig.needRefreshToken(this.#accessToken);
|
|
259
|
+
if (!needRefresh)
|
|
260
|
+
return this.#accessToken;
|
|
254
261
|
const refreshToken = this.#accessToken?.refreshToken;
|
|
255
262
|
if (!refreshToken)
|
|
256
263
|
throw new Error("No refresh token");
|
|
257
264
|
return await this.refreshAuthToken(refreshToken);
|
|
258
265
|
}
|
|
259
266
|
async refreshAuthToken(refreshToken) {
|
|
260
|
-
const response = await this.#api.post(`/
|
|
267
|
+
const response = await this.#api.post(`/refreshAuthToken`, { refreshToken });
|
|
261
268
|
this.#accessToken = GlobalConfig.toAccessToken(response);
|
|
262
269
|
this.#api.setHeaders({ Authorization: `Bearer ${this.#accessToken.jwt}` });
|
|
263
270
|
return this.#accessToken;
|
|
@@ -333,10 +340,10 @@ class Spinner {
|
|
|
333
340
|
|
|
334
341
|
// pkgs/@akanjs/devkit/aiEditor.ts
|
|
335
342
|
var MAX_ASK_TRY = 300;
|
|
336
|
-
var
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
343
|
+
var deepSeekLlmModels = ["deepseek-chat", "deepseek-reasoner"];
|
|
344
|
+
var openAiLlmModels = ["gpt-5.5", "gpt-4.1", "gpt-4.1-mini", "gpt-4o", "gpt-4o-mini"];
|
|
345
|
+
var supportedLlmModels = [...deepSeekLlmModels, ...openAiLlmModels];
|
|
346
|
+
var isOpenAiLlmModel = (model) => openAiLlmModels.includes(model);
|
|
340
347
|
var parseTypescriptFileBlocks = (text) => {
|
|
341
348
|
const fileBlocks = [];
|
|
342
349
|
const codeBlockRegex = /```(?:typescript|ts|tsx)\s*\n([\s\S]*?)```/gi;
|
|
@@ -387,13 +394,26 @@ class AiSession {
|
|
|
387
394
|
return session;
|
|
388
395
|
}
|
|
389
396
|
static #setChatModel(model, apiKey, { temperature = 0 } = {}) {
|
|
390
|
-
AiSession.#chat =
|
|
397
|
+
AiSession.#chat = AiSession.#createChatModel(model, apiKey, {
|
|
398
|
+
temperature,
|
|
399
|
+
streaming: true
|
|
400
|
+
});
|
|
401
|
+
return AiSession;
|
|
402
|
+
}
|
|
403
|
+
static #createChatModel(model, apiKey, { temperature = 0, streaming = false } = {}) {
|
|
404
|
+
if (isOpenAiLlmModel(model))
|
|
405
|
+
return new ChatOpenAI({
|
|
406
|
+
modelName: model,
|
|
407
|
+
temperature,
|
|
408
|
+
streaming,
|
|
409
|
+
openAIApiKey: apiKey
|
|
410
|
+
});
|
|
411
|
+
return new ChatDeepSeek({
|
|
391
412
|
modelName: model,
|
|
392
413
|
temperature,
|
|
393
|
-
streaming
|
|
414
|
+
streaming,
|
|
394
415
|
apiKey
|
|
395
416
|
});
|
|
396
|
-
return AiSession;
|
|
397
417
|
}
|
|
398
418
|
static async getLlmConfig() {
|
|
399
419
|
return await GlobalConfig.getLlmConfig();
|
|
@@ -414,11 +434,7 @@ class AiSession {
|
|
|
414
434
|
const spinner = new Spinner("Validating LLM API key...", {
|
|
415
435
|
prefix: `\uD83E\uDD16akan-editor`
|
|
416
436
|
}).start();
|
|
417
|
-
const chat =
|
|
418
|
-
modelName,
|
|
419
|
-
temperature: 0,
|
|
420
|
-
configuration: { baseURL: "https://api.deepseek.com/v1", apiKey }
|
|
421
|
-
});
|
|
437
|
+
const chat = AiSession.#createChatModel(modelName, apiKey);
|
|
422
438
|
try {
|
|
423
439
|
await chat.invoke("Hi, and just say 'ok'");
|
|
424
440
|
spinner.succeed("LLM API key is valid");
|
package/index.js
CHANGED
|
@@ -15,18 +15,6 @@ import { ChatOpenAI } from "@langchain/openai";
|
|
|
15
15
|
import { Logger as Logger2 } from "akanjs/common";
|
|
16
16
|
import chalk from "chalk";
|
|
17
17
|
|
|
18
|
-
// pkgs/@akanjs/devkit/cloud/constants.ts
|
|
19
|
-
var basePath = `${Bun.env.HOME ?? Bun.env.USERPROFILE}/.akan`;
|
|
20
|
-
var configPath = `${basePath}/config.json`;
|
|
21
|
-
var akanCloudHost = process.env.USE_AKANJS_PKGS === "true" ? "http://localhost" : "https://cloud.akanjs.com";
|
|
22
|
-
var akanCloudUrl = `${akanCloudHost}${process.env.USE_AKANJS_PKGS === "true" ? ":8282" : ""}/api`;
|
|
23
|
-
var defaultHostConfig = {};
|
|
24
|
-
var defaultAkanGlobalConfig = {
|
|
25
|
-
cloudHost: {},
|
|
26
|
-
remoteEnvServers: {},
|
|
27
|
-
llm: null
|
|
28
|
-
};
|
|
29
|
-
|
|
30
18
|
// pkgs/@akanjs/devkit/cloud/globalConfig.ts
|
|
31
19
|
import { mkdir } from "fs/promises";
|
|
32
20
|
import dayjs from "dayjs";
|
|
@@ -69,8 +57,19 @@ class FileSys {
|
|
|
69
57
|
}
|
|
70
58
|
}
|
|
71
59
|
|
|
60
|
+
// pkgs/@akanjs/devkit/cloud/constants.ts
|
|
61
|
+
var basePath = `${Bun.env.HOME ?? Bun.env.USERPROFILE}/.akan`;
|
|
62
|
+
var configPath = `${basePath}/config.json`;
|
|
63
|
+
var getDefaultHostConfig = (host = GlobalConfig.akanCloudHost) => ({ host });
|
|
64
|
+
var defaultAkanGlobalConfig = {
|
|
65
|
+
cloudHost: {},
|
|
66
|
+
remoteEnvServers: {},
|
|
67
|
+
llm: null
|
|
68
|
+
};
|
|
69
|
+
|
|
72
70
|
// pkgs/@akanjs/devkit/cloud/globalConfig.ts
|
|
73
71
|
class GlobalConfig {
|
|
72
|
+
static akanCloudHost = process.env.USE_AKANJS_PKGS === "true" ? `http://localhost:${process.env.CLOUD_HOST_PORT ?? 8283}` : "https://cloud.akanjs.com";
|
|
74
73
|
static async#getAkanGlobalConfig() {
|
|
75
74
|
const exists = await FileSys.fileExists(configPath);
|
|
76
75
|
const akanConfig = exists ? await FileSys.readJson(configPath) : {};
|
|
@@ -85,13 +84,13 @@ class GlobalConfig {
|
|
|
85
84
|
await mkdir(basePath, { recursive: true });
|
|
86
85
|
await Bun.write(configPath, JSON.stringify(akanConfig, null, 2));
|
|
87
86
|
}
|
|
88
|
-
static async getHostConfig(host = akanCloudHost) {
|
|
87
|
+
static async getHostConfig(host = GlobalConfig.akanCloudHost) {
|
|
89
88
|
const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
|
|
90
|
-
return GlobalConfig.toHostConfig(akanConfig.cloudHost[host] ??
|
|
89
|
+
return GlobalConfig.toHostConfig(akanConfig.cloudHost[host] ?? getDefaultHostConfig(host));
|
|
91
90
|
}
|
|
92
|
-
static async setHostConfig(
|
|
91
|
+
static async setHostConfig(config = getDefaultHostConfig()) {
|
|
93
92
|
const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
|
|
94
|
-
akanConfig.cloudHost[host] = GlobalConfig.toHostConfigDto(config);
|
|
93
|
+
akanConfig.cloudHost[config.host] = GlobalConfig.toHostConfigDto(config);
|
|
95
94
|
await GlobalConfig.#setAkanGlobalConfig(akanConfig);
|
|
96
95
|
}
|
|
97
96
|
static async getLlmConfig() {
|
|
@@ -143,6 +142,7 @@ class GlobalConfig {
|
|
|
143
142
|
}
|
|
144
143
|
static toHostConfigDto(hostConfig) {
|
|
145
144
|
return {
|
|
145
|
+
host: hostConfig.host,
|
|
146
146
|
auth: {
|
|
147
147
|
accessToken: hostConfig.auth?.accessToken ? GlobalConfig.toAccessTokenDto(hostConfig.auth.accessToken) : undefined,
|
|
148
148
|
self: hostConfig.auth?.self
|
|
@@ -151,6 +151,7 @@ class GlobalConfig {
|
|
|
151
151
|
}
|
|
152
152
|
static toHostConfig(hostConfigDto) {
|
|
153
153
|
return {
|
|
154
|
+
host: hostConfigDto.host,
|
|
154
155
|
auth: {
|
|
155
156
|
accessToken: hostConfigDto.auth?.accessToken ? GlobalConfig.toAccessToken(hostConfigDto.auth.accessToken) : undefined,
|
|
156
157
|
self: hostConfigDto.auth?.self
|
|
@@ -175,7 +176,7 @@ class HttpClient {
|
|
|
175
176
|
...headers
|
|
176
177
|
}
|
|
177
178
|
});
|
|
178
|
-
return response.json();
|
|
179
|
+
return await response.json();
|
|
179
180
|
}
|
|
180
181
|
async getFile(url, localPath, headers) {
|
|
181
182
|
const response = await fetch(`${this.baseUrl}${url}`, {
|
|
@@ -192,7 +193,7 @@ class HttpClient {
|
|
|
192
193
|
body: isFormData ? data : JSON.stringify(data),
|
|
193
194
|
headers: isFormData ? { ...this.headers, ...headers } : { "Content-Type": "application/json", ...this.headers, ...headers }
|
|
194
195
|
});
|
|
195
|
-
return response.json();
|
|
196
|
+
return await response.json();
|
|
196
197
|
}
|
|
197
198
|
setHeaders(headers) {
|
|
198
199
|
Object.assign(this.headers, headers);
|
|
@@ -204,21 +205,25 @@ class CloudApi {
|
|
|
204
205
|
#api;
|
|
205
206
|
#accessToken = null;
|
|
206
207
|
#workspace;
|
|
208
|
+
host;
|
|
209
|
+
url;
|
|
207
210
|
static async fromHost(workspace, host) {
|
|
208
211
|
const hostConfig = await GlobalConfig.getHostConfig(host);
|
|
209
212
|
return new CloudApi(workspace, hostConfig);
|
|
210
213
|
}
|
|
211
214
|
constructor(workspace, hostConfig) {
|
|
212
215
|
this.#workspace = workspace;
|
|
213
|
-
const host = akanCloudHost;
|
|
214
|
-
this.#api = new HttpClient(`${host}/api`);
|
|
215
216
|
this.#accessToken = hostConfig.auth?.accessToken ?? null;
|
|
217
|
+
this.host = hostConfig.host;
|
|
218
|
+
this.url = `${this.host}/api`;
|
|
219
|
+
this.#api = new HttpClient(this.url);
|
|
216
220
|
if (this.#accessToken && !GlobalConfig.needRefreshToken(this.#accessToken))
|
|
217
221
|
this.#api.setHeaders({
|
|
218
222
|
Authorization: `Bearer ${this.#accessToken.jwt}`
|
|
219
223
|
});
|
|
220
224
|
}
|
|
221
225
|
async uploadEnv(devProjectId, file) {
|
|
226
|
+
await this.#ensureAccessTokenLive();
|
|
222
227
|
const formData = new FormData;
|
|
223
228
|
formData.append("devProjectId", devProjectId);
|
|
224
229
|
formData.append("file", file);
|
|
@@ -226,18 +231,13 @@ class CloudApi {
|
|
|
226
231
|
return data;
|
|
227
232
|
}
|
|
228
233
|
async downloadEnv(devProjectId) {
|
|
234
|
+
await this.#ensureAccessTokenLive();
|
|
229
235
|
const localPath = `${this.#workspace.workspaceRoot}/local/env.tar`;
|
|
230
236
|
await this.#api.getFile(`/downloadEnv/${devProjectId}`, localPath);
|
|
231
237
|
return localPath;
|
|
232
238
|
}
|
|
233
239
|
async getRemoteAuthToken(remoteId) {
|
|
234
240
|
try {
|
|
235
|
-
if (this.#accessToken) {
|
|
236
|
-
if (GlobalConfig.needRefreshToken(this.#accessToken))
|
|
237
|
-
return await this.#refreshAuthToken();
|
|
238
|
-
else
|
|
239
|
-
return await this.#refreshAuthToken();
|
|
240
|
-
}
|
|
241
241
|
const accessToken = await this.#api.get(`/getRemoteAuthToken/${remoteId}`);
|
|
242
242
|
this.#accessToken = GlobalConfig.toAccessToken(accessToken);
|
|
243
243
|
this.#api.setHeaders({
|
|
@@ -248,14 +248,21 @@ class CloudApi {
|
|
|
248
248
|
return null;
|
|
249
249
|
}
|
|
250
250
|
}
|
|
251
|
-
async#
|
|
251
|
+
async#ensureAccessTokenLive({
|
|
252
|
+
allowUnauthorized = false
|
|
253
|
+
} = {}) {
|
|
254
|
+
if (!this.#accessToken)
|
|
255
|
+
throw new Error("No access token");
|
|
256
|
+
const needRefresh = GlobalConfig.needRefreshToken(this.#accessToken);
|
|
257
|
+
if (!needRefresh)
|
|
258
|
+
return this.#accessToken;
|
|
252
259
|
const refreshToken = this.#accessToken?.refreshToken;
|
|
253
260
|
if (!refreshToken)
|
|
254
261
|
throw new Error("No refresh token");
|
|
255
262
|
return await this.refreshAuthToken(refreshToken);
|
|
256
263
|
}
|
|
257
264
|
async refreshAuthToken(refreshToken) {
|
|
258
|
-
const response = await this.#api.post(`/
|
|
265
|
+
const response = await this.#api.post(`/refreshAuthToken`, { refreshToken });
|
|
259
266
|
this.#accessToken = GlobalConfig.toAccessToken(response);
|
|
260
267
|
this.#api.setHeaders({ Authorization: `Bearer ${this.#accessToken.jwt}` });
|
|
261
268
|
return this.#accessToken;
|
|
@@ -331,10 +338,10 @@ class Spinner {
|
|
|
331
338
|
|
|
332
339
|
// pkgs/@akanjs/devkit/aiEditor.ts
|
|
333
340
|
var MAX_ASK_TRY = 300;
|
|
334
|
-
var
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
341
|
+
var deepSeekLlmModels = ["deepseek-chat", "deepseek-reasoner"];
|
|
342
|
+
var openAiLlmModels = ["gpt-5.5", "gpt-4.1", "gpt-4.1-mini", "gpt-4o", "gpt-4o-mini"];
|
|
343
|
+
var supportedLlmModels = [...deepSeekLlmModels, ...openAiLlmModels];
|
|
344
|
+
var isOpenAiLlmModel = (model) => openAiLlmModels.includes(model);
|
|
338
345
|
var parseTypescriptFileBlocks = (text) => {
|
|
339
346
|
const fileBlocks = [];
|
|
340
347
|
const codeBlockRegex = /```(?:typescript|ts|tsx)\s*\n([\s\S]*?)```/gi;
|
|
@@ -385,13 +392,26 @@ class AiSession {
|
|
|
385
392
|
return session;
|
|
386
393
|
}
|
|
387
394
|
static #setChatModel(model, apiKey, { temperature = 0 } = {}) {
|
|
388
|
-
AiSession.#chat =
|
|
395
|
+
AiSession.#chat = AiSession.#createChatModel(model, apiKey, {
|
|
396
|
+
temperature,
|
|
397
|
+
streaming: true
|
|
398
|
+
});
|
|
399
|
+
return AiSession;
|
|
400
|
+
}
|
|
401
|
+
static #createChatModel(model, apiKey, { temperature = 0, streaming = false } = {}) {
|
|
402
|
+
if (isOpenAiLlmModel(model))
|
|
403
|
+
return new ChatOpenAI({
|
|
404
|
+
modelName: model,
|
|
405
|
+
temperature,
|
|
406
|
+
streaming,
|
|
407
|
+
openAIApiKey: apiKey
|
|
408
|
+
});
|
|
409
|
+
return new ChatDeepSeek({
|
|
389
410
|
modelName: model,
|
|
390
411
|
temperature,
|
|
391
|
-
streaming
|
|
412
|
+
streaming,
|
|
392
413
|
apiKey
|
|
393
414
|
});
|
|
394
|
-
return AiSession;
|
|
395
415
|
}
|
|
396
416
|
static async getLlmConfig() {
|
|
397
417
|
return await GlobalConfig.getLlmConfig();
|
|
@@ -412,11 +432,7 @@ class AiSession {
|
|
|
412
432
|
const spinner = new Spinner("Validating LLM API key...", {
|
|
413
433
|
prefix: `\uD83E\uDD16akan-editor`
|
|
414
434
|
}).start();
|
|
415
|
-
const chat =
|
|
416
|
-
modelName,
|
|
417
|
-
temperature: 0,
|
|
418
|
-
configuration: { baseURL: "https://api.deepseek.com/v1", apiKey }
|
|
419
|
-
});
|
|
435
|
+
const chat = AiSession.#createChatModel(modelName, apiKey);
|
|
420
436
|
try {
|
|
421
437
|
await chat.invoke("Hi, and just say 'ok'");
|
|
422
438
|
spinner.succeed("LLM API key is valid");
|
|
@@ -11273,8 +11289,8 @@ class CloudRunner extends runner("cloud") {
|
|
|
11273
11289
|
#getSshArgs(config, command3) {
|
|
11274
11290
|
return [...config.port ? ["-p", config.port.toString()] : [], this.#getSshTarget(config), command3];
|
|
11275
11291
|
}
|
|
11276
|
-
async login(workspace) {
|
|
11277
|
-
const config = await GlobalConfig.getHostConfig();
|
|
11292
|
+
async login(host, workspace) {
|
|
11293
|
+
const config = await GlobalConfig.getHostConfig(host);
|
|
11278
11294
|
const cloudApi2 = new CloudApi(workspace, config);
|
|
11279
11295
|
const self = config.auth ? await cloudApi2.getRemoteSelf() : null;
|
|
11280
11296
|
if (self) {
|
|
@@ -11284,7 +11300,7 @@ class CloudRunner extends runner("cloud") {
|
|
|
11284
11300
|
return true;
|
|
11285
11301
|
}
|
|
11286
11302
|
const remoteId = crypto.randomUUID();
|
|
11287
|
-
const signinUrl = `${
|
|
11303
|
+
const signinUrl = `${cloudApi2.host}/remoteAuth?remoteId=${encodeURIComponent(remoteId)}`;
|
|
11288
11304
|
Logger14.rawLog(chalk7.bold(`
|
|
11289
11305
|
${chalk7.green("\u27A4")} Authentication Required`));
|
|
11290
11306
|
Logger14.rawLog(chalk7.dim("Please visit or click the following URL:"));
|
|
@@ -11310,12 +11326,10 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
11310
11326
|
const accessToken = await cloudApi2.getRemoteAuthToken(remoteId);
|
|
11311
11327
|
const self2 = await cloudApi2.getRemoteSelf();
|
|
11312
11328
|
if (accessToken && self2) {
|
|
11313
|
-
await GlobalConfig.setHostConfig(
|
|
11314
|
-
auth: { accessToken, self: self2 }
|
|
11315
|
-
});
|
|
11329
|
+
await GlobalConfig.setHostConfig({ host: config.host, auth: { accessToken, self: self2 } });
|
|
11316
11330
|
Logger14.rawLog(chalk7.green(`\r\u2713 Authentication successful!`));
|
|
11317
11331
|
Logger14.rawLog(chalk7.green.bold(`
|
|
11318
|
-
\u2728 Welcome aboard, ${self2.nickname}!`));
|
|
11332
|
+
\u2728 Welcome aboard, ${self2.nickname ?? "anonymous"}!`));
|
|
11319
11333
|
Logger14.rawLog(chalk7.dim(`You're now ready to use Akan CLI!
|
|
11320
11334
|
`));
|
|
11321
11335
|
return true;
|
|
@@ -11324,12 +11338,12 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
11324
11338
|
}
|
|
11325
11339
|
throw new Error(chalk7.red("\u2716 Authentication timed out after 10 minutes. Please try again."));
|
|
11326
11340
|
}
|
|
11327
|
-
async logout() {
|
|
11328
|
-
const config = await GlobalConfig.getHostConfig();
|
|
11341
|
+
async logout(host) {
|
|
11342
|
+
const config = await GlobalConfig.getHostConfig(host);
|
|
11329
11343
|
if (config.auth?.self) {
|
|
11330
|
-
await GlobalConfig.setHostConfig(
|
|
11344
|
+
await GlobalConfig.setHostConfig(getDefaultHostConfig(config.host));
|
|
11331
11345
|
Logger14.rawLog(chalk7.magenta.bold(`
|
|
11332
|
-
\uD83D\uDC4B Goodbye, ${config.auth.self.nickname}!`));
|
|
11346
|
+
\uD83D\uDC4B Goodbye, ${config.auth.self.nickname ?? "anonymous"}!`));
|
|
11333
11347
|
Logger14.rawLog(chalk7.dim(`\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
11334
11348
|
`));
|
|
11335
11349
|
Logger14.rawLog(chalk7.cyan("You have been successfully logged out."));
|
|
@@ -11343,7 +11357,7 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
11343
11357
|
}
|
|
11344
11358
|
}
|
|
11345
11359
|
async setLlm() {
|
|
11346
|
-
await AiSession.init({ useExisting:
|
|
11360
|
+
await AiSession.init({ useExisting: false });
|
|
11347
11361
|
}
|
|
11348
11362
|
resetLlm() {
|
|
11349
11363
|
AiSession.setLlmConfig(null);
|
|
@@ -11520,11 +11534,11 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
11520
11534
|
|
|
11521
11535
|
// pkgs/@akanjs/cli/cloud/cloud.script.ts
|
|
11522
11536
|
class CloudScript extends script("cloud", [CloudRunner, ApplicationScript, PackageScript]) {
|
|
11523
|
-
async login(workspace) {
|
|
11524
|
-
await this.cloudRunner.login(workspace);
|
|
11537
|
+
async login(host, workspace) {
|
|
11538
|
+
await this.cloudRunner.login(host, workspace);
|
|
11525
11539
|
}
|
|
11526
|
-
async logout(workspace) {
|
|
11527
|
-
await this.cloudRunner.logout();
|
|
11540
|
+
async logout(host, workspace) {
|
|
11541
|
+
await this.cloudRunner.logout(host);
|
|
11528
11542
|
}
|
|
11529
11543
|
async setLlm(workspace) {
|
|
11530
11544
|
await this.cloudRunner.setLlm();
|
|
@@ -11580,11 +11594,11 @@ var localRegistryUrl = () => process.env.AKAN_NPM_REGISTRY ?? "http://127.0.0.1:
|
|
|
11580
11594
|
var resolveRegistryUrl = (registry) => registry === "local" ? localRegistryUrl() : undefined;
|
|
11581
11595
|
|
|
11582
11596
|
class CloudCommand extends command("cloud", [CloudScript], ({ public: target }) => ({
|
|
11583
|
-
login: target({ desc: "Login to Akan Cloud services" }).with(Workspace).exec(async function(workspace) {
|
|
11584
|
-
await this.cloudScript.login(workspace);
|
|
11597
|
+
login: target({ desc: "Login to Akan Cloud services" }).option("host", String, { desc: "host of the cloud", default: GlobalConfig.akanCloudHost }).with(Workspace).exec(async function(host, workspace) {
|
|
11598
|
+
await this.cloudScript.login(host, workspace);
|
|
11585
11599
|
}),
|
|
11586
|
-
logout: target({ desc: "Logout from Akan Cloud services" }).with(Workspace).exec(async function(workspace) {
|
|
11587
|
-
await this.cloudScript.logout(workspace);
|
|
11600
|
+
logout: target({ desc: "Logout from Akan Cloud services" }).option("host", String, { desc: "host of the cloud", default: GlobalConfig.akanCloudHost }).with(Workspace).exec(async function(host, workspace) {
|
|
11601
|
+
await this.cloudScript.logout(host, workspace);
|
|
11588
11602
|
}),
|
|
11589
11603
|
setLlm: target({ desc: "Configure LLM (Large Language Model) API key" }).with(Workspace).exec(async function(workspace) {
|
|
11590
11604
|
await this.cloudScript.setLlm(workspace);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akanjs/cli",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.2-rc.0",
|
|
4
4
|
"sourceType": "module",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"@langchain/openai": "^1.4.6",
|
|
36
36
|
"@tailwindcss/node": "^4.3.0",
|
|
37
37
|
"@trapezedev/project": "^7.1.4",
|
|
38
|
-
"akanjs": "2.2.
|
|
38
|
+
"akanjs": "2.2.2-rc.0",
|
|
39
39
|
"chalk": "^5.6.2",
|
|
40
40
|
"commander": "^14.0.3",
|
|
41
41
|
"daisyui": "^5.5.20",
|