@akanjs/devkit 2.2.2-rc.0 → 2.2.2

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 (2) hide show
  1. package/aiEditor.ts +20 -76
  2. package/package.json +2 -2
package/aiEditor.ts CHANGED
@@ -21,7 +21,7 @@ const MAX_ASK_TRY = 300;
21
21
 
22
22
  const deepSeekLlmModels = ["deepseek-chat", "deepseek-reasoner"] as const;
23
23
 
24
- const openAiLlmModels = ["gpt-5.5", "gpt-4.1", "gpt-4.1-mini", "gpt-4o", "gpt-4o-mini"] as const;
24
+ const openAiLlmModels = ["gpt-5.5"] as const;
25
25
 
26
26
  export const supportedLlmModels = [...deepSeekLlmModels, ...openAiLlmModels] as const;
27
27
  export type SupportedLlmModel = (typeof supportedLlmModels)[number];
@@ -60,44 +60,25 @@ export const parseTypescriptFileBlocks = (text: string): FileContent[] => {
60
60
  return fileBlocks;
61
61
  };
62
62
 
63
- export const preserveTypescriptResponseContent = (
64
- previousContent: string,
65
- nextContent: string,
66
- ) => {
63
+ export const preserveTypescriptResponseContent = (previousContent: string, nextContent: string) => {
67
64
  const previousWrites = parseTypescriptFileBlocks(previousContent);
68
65
  const nextWrites = parseTypescriptFileBlocks(nextContent);
69
- if (previousWrites.length > 0 && nextWrites.length === 0)
70
- return previousContent;
66
+ if (previousWrites.length > 0 && nextWrites.length === 0) return previousContent;
71
67
  return nextContent;
72
68
  };
73
69
 
74
70
  export class AiSession {
75
71
  static #cacheDir = "node_modules/.cache/akan/aiSession";
76
72
  static #chat: ChatDeepSeek | ChatOpenAI | null = null;
77
- static async init({
78
- temperature = 0,
79
- useExisting = true,
80
- }: {
81
- temperature?: number;
82
- useExisting?: boolean;
83
- } = {}) {
73
+ static async init({ temperature = 0, useExisting = true }: { temperature?: number; useExisting?: boolean } = {}) {
84
74
  if (useExisting) {
85
75
  const llmConfig = await AiSession.getLlmConfig();
86
76
  if (llmConfig) {
87
77
  AiSession.#setChatModel(llmConfig.model, llmConfig.apiKey);
88
- Logger.rawLog(
89
- chalk.dim(
90
- `🤖akan editor uses existing LLM config (${llmConfig.model})`,
91
- ),
92
- );
78
+ Logger.rawLog(chalk.dim(`🤖akan editor uses existing LLM config (${llmConfig.model})`));
93
79
  return AiSession;
94
80
  }
95
- } else
96
- Logger.rawLog(
97
- chalk.yellow(
98
- "🤖akan-editor is not initialized. LLM configuration should be set first.",
99
- ),
100
- );
81
+ } else Logger.rawLog(chalk.yellow("🤖akan-editor is not initialized. LLM configuration should be set first."));
101
82
 
102
83
  const llmConfig = await AiSession.#requestLlmConfig();
103
84
  const { model, apiKey } = llmConfig;
@@ -136,9 +117,7 @@ export class AiSession {
136
117
  static async getLlmConfig() {
137
118
  return await GlobalConfig.getLlmConfig();
138
119
  }
139
- static async setLlmConfig(
140
- llmConfig: { model: SupportedLlmModel; apiKey: string } | null,
141
- ) {
120
+ static async setLlmConfig(llmConfig: { model: SupportedLlmModel; apiKey: string } | null) {
142
121
  await GlobalConfig.setLlmConfig(llmConfig);
143
122
  return AiSession;
144
123
  }
@@ -206,10 +185,7 @@ export class AiSession {
206
185
  }
207
186
  async #saveCache() {
208
187
  const cacheFilePath = `${AiSession.#cacheDir}/${this.sessionKey}.json`;
209
- await this.workspace.writeJson(
210
- cacheFilePath,
211
- mapChatMessagesToStoredMessages(this.messageHistory),
212
- );
188
+ await this.workspace.writeJson(cacheFilePath, mapChatMessagesToStoredMessages(this.messageHistory));
213
189
  }
214
190
  async ask(
215
191
  question: string,
@@ -225,8 +201,7 @@ export class AiSession {
225
201
  if (!AiSession.#chat) await AiSession.init();
226
202
  if (this.#cacheLoadPromise) await this.#cacheLoadPromise;
227
203
 
228
- if (!AiSession.#chat)
229
- throw new Error("Failed to initialize the AI session");
204
+ if (!AiSession.#chat) throw new Error("Failed to initialize the AI session");
230
205
  const loader = new Spinner(`${AiSession.#chat.model} is thinking...`, {
231
206
  prefix: `🤖akan-editor`,
232
207
  }).start();
@@ -237,13 +212,10 @@ export class AiSession {
237
212
  let reasoningResponse = "",
238
213
  fullResponse = "";
239
214
  for await (const chunk of stream) {
240
- if (loader.isSpinning())
241
- loader.succeed(`${AiSession.#chat.model} responded`);
215
+ if (loader.isSpinning()) loader.succeed(`${AiSession.#chat.model} responded`);
242
216
 
243
217
  if (!fullResponse.length) {
244
- const reasoningContent =
245
- (chunk.additional_kwargs as { reasoning_content?: string })
246
- .reasoning_content ?? "";
218
+ const reasoningContent = (chunk.additional_kwargs as { reasoning_content?: string }).reasoning_content ?? "";
247
219
  if (reasoningContent.length) {
248
220
  reasoningResponse += reasoningContent;
249
221
  onReasoning(reasoningContent);
@@ -271,14 +243,7 @@ export class AiSession {
271
243
  }
272
244
  async edit(
273
245
  question: string,
274
- {
275
- onChunk,
276
- onReasoning,
277
- maxTry = MAX_ASK_TRY,
278
- validate,
279
- approve,
280
- fallbackToPreviousTypescript,
281
- }: EditOptions = {},
246
+ { onChunk, onReasoning, maxTry = MAX_ASK_TRY, validate, approve, fallbackToPreviousTypescript }: EditOptions = {},
282
247
  ) {
283
248
  for (let tryCount = 0; tryCount < maxTry; tryCount++) {
284
249
  let response = await this.ask(question, { onChunk, onReasoning });
@@ -292,10 +257,7 @@ ${validate.map((v) => `- ${v}`).join("\n")}`;
292
257
  response = {
293
258
  ...validateResponse,
294
259
  content: fallbackToPreviousTypescript
295
- ? preserveTypescriptResponseContent(
296
- response.content,
297
- validateResponse.content,
298
- )
260
+ ? preserveTypescriptResponseContent(response.content, validateResponse.content)
299
261
  : validateResponse.content,
300
262
  };
301
263
  }
@@ -333,17 +295,11 @@ ${validate.map((v) => `- ${v}`).join("\n")}`;
333
295
  // const toolMessages = messages.map(
334
296
  // (message) => new ToolMessage({ content: message.content, tool_call_id: message.type })
335
297
  // );
336
- const toolMessages = messages.map(
337
- (message) => new HumanMessage(message.content),
338
- );
298
+ const toolMessages = messages.map((message) => new HumanMessage(message.content));
339
299
  this.messageHistory.push(...toolMessages);
340
300
  return this;
341
301
  }
342
- async writeTypescripts(
343
- question: string,
344
- executor: Executor,
345
- options: EditOptions = {},
346
- ) {
302
+ async writeTypescripts(question: string, executor: Executor, options: EditOptions = {}) {
347
303
  const content = await this.edit(question, {
348
304
  ...options,
349
305
  fallbackToPreviousTypescript: true,
@@ -353,15 +309,10 @@ ${validate.map((v) => `- ${v}`).join("\n")}`;
353
309
  throw new Error(
354
310
  "No parseable TypeScript file blocks were found in the AI response. Include `// File: <path>` in each code block.",
355
311
  );
356
- for (const write of writes)
357
- await executor.writeFile(write.filePath, write.content);
312
+ for (const write of writes) await executor.writeFile(write.filePath, write.content);
358
313
  return await this.#tryFixTypescripts(writes, executor, options);
359
314
  }
360
- async #editTypescripts(
361
- question: string,
362
- options: EditOptions = {},
363
- fallbackWrites?: FileContent[],
364
- ) {
315
+ async #editTypescripts(question: string, options: EditOptions = {}, fallbackWrites?: FileContent[]) {
365
316
  const content = await this.edit(question, {
366
317
  ...options,
367
318
  fallbackToPreviousTypescript: true,
@@ -374,11 +325,7 @@ ${validate.map((v) => `- ${v}`).join("\n")}`;
374
325
  );
375
326
  return writes;
376
327
  }
377
- async #tryFixTypescripts(
378
- writes: FileContent[],
379
- executor: Executor,
380
- options: EditOptions = {},
381
- ) {
328
+ async #tryFixTypescripts(writes: FileContent[], executor: Executor, options: EditOptions = {}) {
382
329
  const MAX_EDIT_TRY = 5;
383
330
  for (let tryCount = 0; tryCount < MAX_EDIT_TRY; tryCount++) {
384
331
  const loader = new Spinner(`Type checking and linting...`, {
@@ -396,9 +343,7 @@ ${validate.map((v) => `- ${v}`).join("\n")}`;
396
343
  );
397
344
  const hasAnyFix = fileChecks.some((fileCheck) => fileCheck.needFix);
398
345
  if (hasAnyFix) {
399
- loader.fail(
400
- "Type checking and linting has some errors, try to fix them",
401
- );
346
+ loader.fail("Type checking and linting has some errors, try to fix them");
402
347
  fileChecks.forEach((fileCheck) => {
403
348
  Logger.rawLog(
404
349
  `TypeCheck Result \n${fileCheck.typeCheckResult.message}\nLint Result \n${fileCheck.lintResult.message}`,
@@ -417,8 +362,7 @@ ${validate.map((v) => `- ${v}`).join("\n")}`;
417
362
  },
418
363
  writes,
419
364
  );
420
- for (const write of writes)
421
- await executor.writeFile(write.filePath, write.content);
365
+ for (const write of writes) await executor.writeFile(write.filePath, write.content);
422
366
  } else {
423
367
  loader.succeed("Type checking and linting has no errors");
424
368
  return writes;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akanjs/devkit",
3
- "version": "2.2.2-rc.0",
3
+ "version": "2.2.2",
4
4
  "sourceType": "module",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -32,7 +32,7 @@
32
32
  "@langchain/openai": "^1.4.6",
33
33
  "@tailwindcss/node": "^4.3.0",
34
34
  "@trapezedev/project": "^7.1.4",
35
- "akanjs": "2.2.2-rc.0",
35
+ "akanjs": "2.2.2",
36
36
  "chalk": "^5.6.2",
37
37
  "commander": "^14.0.3",
38
38
  "daisyui": "^5.5.20",