codemate-ai 1.0.6 → 1.0.8

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/dist/cli.js +526 -196
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -5,7 +5,7 @@ import * as fs21 from 'fs';
5
5
  import fs21__default, { existsSync, statSync, promises } from 'fs';
6
6
  import * as path18 from 'pathe';
7
7
  import { join, resolve, extname, basename } from 'pathe';
8
- import React, { createContext, useState, useRef, useEffect, useCallback, useMemo, useContext } from 'react';
8
+ import React, { createContext, useState, useRef, useCallback, useEffect, useMemo, useContext } from 'react';
9
9
  import { render, useApp, useInput, Box, Text } from 'ink';
10
10
  import Spinner3 from 'ink-spinner';
11
11
  import defu from 'defu';
@@ -384,10 +384,14 @@ var init_ConfigManager = __esm({
384
384
  constructor(options) {
385
385
  const { cwd, productName, argvConfig = {} } = options;
386
386
  const lowerProductName = productName.toLowerCase();
387
+ const legacyGlobalConfigPath = path18.join(homedir(), ".aiclirc.json");
387
388
  this.globalConfigPath = path18.join(homedir(), `.${lowerProductName}`, "config.json");
388
389
  this.projectConfigPath = path18.join(cwd, `.${lowerProductName}`, "config.json");
389
390
  const projectLocalConfigPath = path18.join(cwd, `.${lowerProductName}`, "config.local.json");
390
- this.globalConfig = this.loadConfig(this.globalConfigPath);
391
+ this.globalConfig = defu(
392
+ this.loadConfig(this.globalConfigPath),
393
+ this.loadConfig(legacyGlobalConfigPath)
394
+ );
391
395
  this.projectConfig = defu(
392
396
  this.loadConfig(projectLocalConfigPath),
393
397
  // 优先级高
@@ -423,6 +427,7 @@ var init_ConfigManager = __esm({
423
427
  )
424
428
  )
425
429
  );
430
+ this.normalizeConfig(config);
426
431
  config.planModel = config.planModel || config.model;
427
432
  config.smallModel = config.smallModel || config.model;
428
433
  config.visionModel = config.visionModel || config.model;
@@ -485,6 +490,26 @@ var init_ConfigManager = __esm({
485
490
  return {};
486
491
  }
487
492
  }
493
+ normalizeConfig(config) {
494
+ const legacyModel = config.model;
495
+ if (!legacyModel || typeof legacyModel !== "object") {
496
+ return;
497
+ }
498
+ const modelName = typeof legacyModel.model === "string" ? legacyModel.model : "deepseek-chat";
499
+ const providerKey = config._metadata?.provider || "deepseek";
500
+ config.model = modelName;
501
+ if (!config.provider) {
502
+ config.provider = {};
503
+ }
504
+ const existingProvider = config.provider[providerKey] || {};
505
+ config.provider[providerKey] = {
506
+ apiKey: existingProvider.apiKey || legacyModel.apiKey,
507
+ baseURL: existingProvider.baseURL || legacyModel.baseURL
508
+ };
509
+ if (config.temperature === void 0 && legacyModel.temperature !== void 0) {
510
+ config.temperature = legacyModel.temperature;
511
+ }
512
+ }
488
513
  /**
489
514
  * 保存配置文件
490
515
  *
@@ -714,36 +739,43 @@ var init_WorkspaceCommand = __esm({
714
739
  super();
715
740
  this.configManager = configManager;
716
741
  }
717
- async execute(args) {
742
+ async execute(args, app) {
718
743
  const subcommand = args[0];
744
+ const sessionService = app.getContainer().get("session");
719
745
  try {
720
746
  switch (subcommand) {
721
747
  case "create":
722
- await this.create(this.parseCreateOptions(args.slice(1)));
748
+ await this.create(this.parseCreateOptions(args.slice(1)), sessionService);
723
749
  break;
724
750
  case "list":
725
- await this.list();
751
+ await this.list(sessionService);
726
752
  break;
727
753
  case "remove":
728
754
  case "delete":
729
- await this.remove(args[1]);
755
+ await this.remove(args[1], sessionService);
730
756
  break;
731
757
  case "complete":
732
- await this.complete();
758
+ await this.complete(sessionService);
733
759
  break;
734
760
  default:
735
- console.log("Usage: /workspace <create|list|remove|complete> [options]");
736
- console.log("");
737
- console.log("Commands:");
738
- console.log(" create [--name <name>] [-b <branch>] Create a new workspace");
739
- console.log(" list List all workspaces");
740
- console.log(" remove <name> Remove a workspace");
741
- console.log(
742
- " complete Complete and merge current workspace"
761
+ await this.output(
762
+ sessionService,
763
+ [
764
+ "Usage: /workspace <create|list|remove|complete> [options]",
765
+ "",
766
+ "Commands:",
767
+ " create [--name <name>] [-b <branch>] Create a new workspace",
768
+ " list List all workspaces",
769
+ " remove <name> Remove a workspace",
770
+ " complete Complete and merge current workspace"
771
+ ].join("\n")
743
772
  );
744
773
  }
745
774
  } catch (error) {
746
- console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
775
+ await this.output(
776
+ sessionService,
777
+ `\u274C Error: ${error instanceof Error ? error.message : String(error)}`
778
+ );
747
779
  }
748
780
  }
749
781
  /**
@@ -771,110 +803,121 @@ var init_WorkspaceCommand = __esm({
771
803
  /**
772
804
  * 创建工作区
773
805
  */
774
- async create(options) {
806
+ async create(options, sessionService) {
775
807
  const workspaceName = options.name;
776
808
  if (!workspaceName) {
777
- console.log("\u274C Workspace name is required");
778
- console.log("Usage: /workspace create --name <workspace-name> [-b <branch>]");
779
- console.log("");
780
- console.log("Example:");
781
- console.log(" /workspace create --name feature-auth");
782
- console.log(" /workspace create --name bugfix-login -b develop");
809
+ await this.output(
810
+ sessionService,
811
+ [
812
+ "\u274C Workspace name is required",
813
+ "Usage: /workspace create --name <workspace-name> [-b <branch>]",
814
+ "",
815
+ "Example:",
816
+ " /workspace create --name feature-auth",
817
+ " /workspace create --name bugfix-login -b develop"
818
+ ].join("\n")
819
+ );
783
820
  return;
784
821
  }
785
822
  const config = this.configManager.config;
786
823
  const baseBranch = options.baseBranch || config.workspace?.baseBranch || "main";
787
824
  if (!this.branchExists(baseBranch)) {
788
- console.log(`\u274C Base branch '${baseBranch}' does not exist`);
789
- console.log("Available branches:");
825
+ let message = `\u274C Base branch '${baseBranch}' does not exist
826
+ Available branches:`;
790
827
  try {
791
828
  const branches = this.execGit("branch -a").split("\n").map(
792
829
  (line) => line.trim().replace(/^\*\s*/, "").replace(/^remotes\/origin\//, "")
793
830
  ).filter((line) => line && !line.includes("HEAD")).slice(0, 5);
794
- for (const branch of branches) {
795
- console.log(` - ${branch}`);
796
- }
831
+ message += `
832
+ ${branches.map((branch) => ` - ${branch}`).join("\n")}`;
797
833
  } catch {
798
- console.log(" (Unable to list branches)");
834
+ message += "\n (Unable to list branches)";
799
835
  }
836
+ await this.output(sessionService, message);
800
837
  return;
801
838
  }
802
839
  const workspacePath = this.getWorkspacePath(workspaceName);
803
840
  if (existsSync(workspacePath)) {
804
- console.log(`\u274C Workspace already exists: ${workspacePath}`);
841
+ await this.output(sessionService, `\u274C Workspace already exists: ${workspacePath}`);
805
842
  return;
806
843
  }
807
844
  const branchExists = this.branchExists(workspaceName);
808
- console.log(`\u{1F33F} Creating workspace '${workspaceName}'...`);
845
+ await this.output(sessionService, `\u{1F33F} Creating workspace '${workspaceName}'...`);
809
846
  try {
810
847
  if (branchExists && !options.newBranch) {
811
848
  this.execGit(`worktree add ${workspacePath} ${workspaceName}`);
812
849
  } else {
813
850
  this.execGit(`worktree add -b ${workspaceName} ${workspacePath} ${baseBranch}`);
814
851
  }
815
- console.log(`\u2705 Workspace created at: ${workspacePath}`);
816
- console.log(`\u{1F4A1} To start working: cd ${workspacePath}`);
852
+ await this.output(
853
+ sessionService,
854
+ `\u2705 Workspace created at: ${workspacePath}
855
+ \u{1F4A1} To start working: cd ${workspacePath}`
856
+ );
817
857
  } catch (error) {
818
- console.error("\u274C Failed to create workspace");
858
+ await this.output(sessionService, "\u274C Failed to create workspace");
819
859
  throw error;
820
860
  }
821
861
  }
822
862
  /**
823
863
  * 列出所有工作区
824
864
  */
825
- async list() {
865
+ async list(sessionService) {
826
866
  try {
827
867
  const output = this.execGit("worktree list --porcelain");
828
868
  const workspaces = this.parseWorktreeList(output);
829
869
  if (workspaces.length === 0) {
830
- console.log("\u{1F4CB} No workspaces found");
870
+ await this.output(sessionService, "\u{1F4CB} No workspaces found");
831
871
  return;
832
872
  }
833
- console.log("\u{1F4CB} Workspaces:\n");
873
+ const lines = ["\u{1F4CB} Workspaces:", ""];
834
874
  for (const workspace of workspaces) {
835
875
  const marker = workspace.isCurrent ? "\u2192" : " ";
836
876
  const name = basename(workspace.path);
837
- console.log(`${marker} ${name}`);
838
- console.log(` Path: ${workspace.path}`);
839
- console.log(` Branch: ${workspace.branch}`);
840
- console.log(` Commit: ${workspace.commit.substring(0, 7)}`);
841
- console.log("");
877
+ lines.push(`${marker} ${name}`);
878
+ lines.push(` Path: ${workspace.path}`);
879
+ lines.push(` Branch: ${workspace.branch}`);
880
+ lines.push(` Commit: ${workspace.commit.substring(0, 7)}`);
881
+ lines.push("");
842
882
  }
883
+ await this.output(sessionService, lines.join("\n").trimEnd());
843
884
  } catch (error) {
844
- console.error("\u274C Failed to list workspaces");
885
+ await this.output(sessionService, "\u274C Failed to list workspaces");
845
886
  throw error;
846
887
  }
847
888
  }
848
889
  /**
849
890
  * 删除工作区
850
891
  */
851
- async remove(name) {
892
+ async remove(name, sessionService) {
852
893
  if (!name) {
853
- console.log("\u274C Workspace name is required");
854
- console.log("Usage: /workspace remove <name>");
894
+ await this.output(
895
+ sessionService,
896
+ "\u274C Workspace name is required\nUsage: /workspace remove <name>"
897
+ );
855
898
  return;
856
899
  }
857
900
  const workspacePath = this.getWorkspacePath(name);
858
901
  if (!existsSync(workspacePath)) {
859
- console.log(`\u274C Workspace not found: ${workspacePath}`);
902
+ await this.output(sessionService, `\u274C Workspace not found: ${workspacePath}`);
860
903
  return;
861
904
  }
862
- console.log(`\u{1F5D1}\uFE0F Removing workspace '${name}'...`);
905
+ await this.output(sessionService, `\u{1F5D1}\uFE0F Removing workspace '${name}'...`);
863
906
  try {
864
907
  this.execGit(`worktree remove ${workspacePath}`);
865
- console.log(`\u2705 Workspace removed: ${workspacePath}`);
908
+ await this.output(sessionService, `\u2705 Workspace removed: ${workspacePath}`);
866
909
  } catch (error) {
867
- console.error("\u274C Failed to remove workspace");
910
+ await this.output(sessionService, "\u274C Failed to remove workspace");
868
911
  throw error;
869
912
  }
870
913
  }
871
914
  /**
872
915
  * 完成并合并工作区
873
916
  */
874
- async complete() {
917
+ async complete(sessionService) {
875
918
  const currentBranch = this.getCurrentBranch();
876
919
  if (!currentBranch) {
877
- console.log("\u274C Not in a Git repository");
920
+ await this.output(sessionService, "\u274C Not in a Git repository");
878
921
  return;
879
922
  }
880
923
  const config = this.configManager.config;
@@ -883,28 +926,41 @@ var init_WorkspaceCommand = __esm({
883
926
  try {
884
927
  this.execGit("diff-index --quiet HEAD --");
885
928
  } catch {
886
- console.log("\u274C You have uncommitted changes. Please commit or stash them first.");
929
+ await this.output(
930
+ sessionService,
931
+ "\u274C You have uncommitted changes. Please commit or stash them first."
932
+ );
887
933
  return;
888
934
  }
889
- console.log(`\u{1F500} Merging ${currentBranch} into ${baseBranch}...`);
935
+ await this.output(sessionService, `\u{1F500} Merging ${currentBranch} into ${baseBranch}...`);
890
936
  try {
891
937
  this.execGit(`checkout ${baseBranch}`);
892
938
  this.execGit(`merge ${currentBranch}`);
893
- console.log(`\u2705 Merged ${currentBranch} into ${baseBranch}`);
939
+ await this.output(sessionService, `\u2705 Merged ${currentBranch} into ${baseBranch}`);
894
940
  const workspacePath = process.cwd();
895
- console.log("\u{1F5D1}\uFE0F Removing workspace...");
941
+ await this.output(sessionService, "\u{1F5D1}\uFE0F Removing workspace...");
896
942
  process.chdir("..");
897
943
  this.execGit(`worktree remove ${workspacePath}`);
898
944
  if (autoDelete) {
899
- console.log(`\u{1F5D1}\uFE0F Deleting branch ${currentBranch}...`);
945
+ await this.output(sessionService, `\u{1F5D1}\uFE0F Deleting branch ${currentBranch}...`);
900
946
  this.execGit(`branch -d ${currentBranch}`);
901
947
  }
902
- console.log("\u2705 Workspace completed and merged!");
948
+ await this.output(sessionService, "\u2705 Workspace completed and merged!");
903
949
  } catch (error) {
904
- console.error("\u274C Failed to complete workspace");
950
+ await this.output(sessionService, "\u274C Failed to complete workspace");
905
951
  throw error;
906
952
  }
907
953
  }
954
+ async output(sessionService, message) {
955
+ if (sessionService) {
956
+ await sessionService.addMessage({
957
+ role: "assistant",
958
+ content: message
959
+ });
960
+ return;
961
+ }
962
+ console.log(message);
963
+ }
908
964
  /**
909
965
  * 获取项目名称
910
966
  */
@@ -8680,7 +8736,6 @@ var SessionService = class {
8680
8736
  }
8681
8737
  /**
8682
8738
  * 清除当前会话并创建新会话
8683
- * 对标Neovate的clear命令功能
8684
8739
  */
8685
8740
  async clear() {
8686
8741
  const newSession = await this.create();
@@ -9504,6 +9559,11 @@ var ExitCommand = class extends SlashCommand {
9504
9559
  description = "Exit the program";
9505
9560
  aliases = ["quit", "q"];
9506
9561
  async execute(_args, app) {
9562
+ const eventBus = app.getContainer().get("eventBus");
9563
+ if (eventBus.listenerCount("exit_app") > 0) {
9564
+ eventBus.emit("exit_app");
9565
+ return;
9566
+ }
9507
9567
  console.log("\u{1F44B} Goodbye!");
9508
9568
  await app.stop();
9509
9569
  process.exit(0);
@@ -9622,8 +9682,9 @@ var ConfigCommand = class extends SlashCommand {
9622
9682
  */
9623
9683
  async execute(args, app) {
9624
9684
  const configService = app.getContainer().get("config");
9685
+ const sessionService = app.getContainer().get("session");
9625
9686
  if (!configService) {
9626
- console.log("\u274C ConfigService not available");
9687
+ await this.outputResult(sessionService, "\u274C ConfigService not available");
9627
9688
  return;
9628
9689
  }
9629
9690
  const [action, ...rest] = args;
@@ -9647,6 +9708,16 @@ var ConfigCommand = class extends SlashCommand {
9647
9708
  default:
9648
9709
  result = this.getHelp();
9649
9710
  }
9711
+ await this.outputResult(sessionService, result);
9712
+ }
9713
+ async outputResult(sessionService, result) {
9714
+ if (sessionService) {
9715
+ await sessionService.addMessage({
9716
+ role: "assistant",
9717
+ content: result
9718
+ });
9719
+ return;
9720
+ }
9650
9721
  console.log(result);
9651
9722
  }
9652
9723
  /**
@@ -9809,17 +9880,17 @@ var ForkCommand = class extends SlashCommand {
9809
9880
  async execute(args, app) {
9810
9881
  const sessionService = app.getContainer().get("session");
9811
9882
  if (!sessionService) {
9812
- console.log("\u274C SessionService not available");
9883
+ await this.output(void 0, "\u274C SessionService not available");
9813
9884
  return;
9814
9885
  }
9815
9886
  const currentSession = sessionService.getCurrent();
9816
9887
  if (!currentSession) {
9817
- console.log("\u274C No active session");
9888
+ await this.output(sessionService, "\u274C No active session");
9818
9889
  return;
9819
9890
  }
9820
9891
  const messages = currentSession.messages;
9821
9892
  if (messages.length === 0) {
9822
- console.log("\u274C No messages to fork from");
9893
+ await this.output(sessionService, "\u274C No messages to fork from");
9823
9894
  return;
9824
9895
  }
9825
9896
  if (args.length > 0) {
@@ -9827,7 +9898,7 @@ var ForkCommand = class extends SlashCommand {
9827
9898
  await this.forkFromMessage(sessionService, messageUuid);
9828
9899
  return;
9829
9900
  }
9830
- this.showForkSelector(messages);
9901
+ await this.showForkSelector(sessionService, messages);
9831
9902
  }
9832
9903
  /**
9833
9904
  * 从指定消息分叉
@@ -9837,27 +9908,36 @@ var ForkCommand = class extends SlashCommand {
9837
9908
  const newSession = await sessionService.fork({
9838
9909
  fromMessageUuid: messageUuid
9839
9910
  });
9840
- console.log(`\u2705 Session forked: ${newSession.id}`);
9841
- console.log("Use /sessions to switch to it.");
9911
+ await this.output(
9912
+ sessionService,
9913
+ `\u2705 Session forked: ${newSession.id}
9914
+ Use /sessions to switch to it.`
9915
+ );
9842
9916
  } catch (error) {
9843
- console.log(`\u274C Fork failed: ${error instanceof Error ? error.message : "Unknown error"}`);
9917
+ await this.output(
9918
+ sessionService,
9919
+ `\u274C Fork failed: ${error instanceof Error ? error.message : "Unknown error"}`
9920
+ );
9844
9921
  }
9845
9922
  }
9846
9923
  /**
9847
9924
  * 显示分叉选择器
9848
9925
  */
9849
- showForkSelector(messages) {
9926
+ async showForkSelector(sessionService, messages) {
9850
9927
  const messagesWithUuid = messages.filter((msg) => msg.uuid);
9851
9928
  if (messagesWithUuid.length === 0) {
9852
- console.log("\u274C No messages with UUID found. Fork requires enhanced messages.");
9853
- console.log("\u{1F4A1} Tip: New messages will have UUIDs automatically.");
9929
+ await this.output(
9930
+ sessionService,
9931
+ "\u274C No messages with UUID found. Fork requires enhanced messages.\n\u{1F4A1} Tip: New messages will have UUIDs automatically."
9932
+ );
9854
9933
  return;
9855
9934
  }
9856
9935
  const messageList = messagesWithUuid.map((msg, index) => {
9857
9936
  const preview = this.getMessagePreview(msg);
9858
9937
  return `${index + 1}. [${msg.uuid.slice(0, 8)}] ${msg.role}: ${preview}`;
9859
9938
  }).join("\n");
9860
- console.log(
9939
+ await this.output(
9940
+ sessionService,
9861
9941
  `
9862
9942
  \u{1F4CB} Select a message to fork from:
9863
9943
 
@@ -9869,6 +9949,16 @@ Example: /fork ${messagesWithUuid[0].uuid}
9869
9949
  `.trim()
9870
9950
  );
9871
9951
  }
9952
+ async output(sessionService, message) {
9953
+ if (sessionService) {
9954
+ await sessionService.addMessage({
9955
+ role: "assistant",
9956
+ content: message
9957
+ });
9958
+ return;
9959
+ }
9960
+ console.log(message);
9961
+ }
9872
9962
  /**
9873
9963
  * 获取消息预览
9874
9964
  */
@@ -18156,22 +18246,23 @@ var SkillCommand = class extends SlashCommand {
18156
18246
  *
18157
18247
  * @param args 命令参数
18158
18248
  */
18159
- async execute(args) {
18249
+ async execute(args, app) {
18160
18250
  const subcommand = args[0];
18251
+ const sessionService = app.getContainer().get("session");
18161
18252
  switch (subcommand) {
18162
18253
  case "add":
18163
- await this.handleAdd(args.slice(1));
18254
+ await this.handleAdd(args.slice(1), sessionService);
18164
18255
  break;
18165
18256
  case "remove":
18166
18257
  case "rm":
18167
- await this.handleRemove(args.slice(1));
18258
+ await this.handleRemove(args.slice(1), sessionService);
18168
18259
  break;
18169
18260
  case "list":
18170
18261
  case "ls":
18171
- await this.handleList();
18262
+ await this.handleList(sessionService);
18172
18263
  break;
18173
18264
  default:
18174
- this.showHelp();
18265
+ await this.showHelp(sessionService);
18175
18266
  }
18176
18267
  }
18177
18268
  /**
@@ -18179,10 +18270,12 @@ var SkillCommand = class extends SlashCommand {
18179
18270
  *
18180
18271
  * 从 GitHub 安装技能
18181
18272
  */
18182
- async handleAdd(args) {
18273
+ async handleAdd(args, sessionService) {
18183
18274
  if (args.length === 0) {
18184
- console.error("Error: GitHub source is required");
18185
- console.log("Usage: /skill add <user/repo> [--name <name>] [--overwrite]");
18275
+ await this.output(
18276
+ sessionService,
18277
+ "Error: GitHub source is required\nUsage: /skill add <user/repo> [--name <name>] [--overwrite]"
18278
+ );
18186
18279
  return;
18187
18280
  }
18188
18281
  const source = args[0];
@@ -18198,8 +18291,12 @@ var SkillCommand = class extends SlashCommand {
18198
18291
  }
18199
18292
  try {
18200
18293
  await this.skillManager.addSkill(source, options);
18294
+ await this.output(
18295
+ sessionService,
18296
+ `\u2705 Skill installed: ${options.name || source.split("/").pop() || source}`
18297
+ );
18201
18298
  } catch (error) {
18202
- console.error(`Error: ${error}`);
18299
+ await this.output(sessionService, `Error: ${error}`);
18203
18300
  }
18204
18301
  }
18205
18302
  /**
@@ -18207,17 +18304,20 @@ var SkillCommand = class extends SlashCommand {
18207
18304
  *
18208
18305
  * 删除已安装的技能
18209
18306
  */
18210
- async handleRemove(args) {
18307
+ async handleRemove(args, sessionService) {
18211
18308
  if (args.length === 0) {
18212
- console.error("Error: Skill name is required");
18213
- console.log("Usage: /skill remove <name>");
18309
+ await this.output(
18310
+ sessionService,
18311
+ "Error: Skill name is required\nUsage: /skill remove <name>"
18312
+ );
18214
18313
  return;
18215
18314
  }
18216
18315
  const name = args[0];
18217
18316
  try {
18218
18317
  await this.skillManager.removeSkill(name);
18318
+ await this.output(sessionService, `\u2705 Skill removed: ${name}`);
18219
18319
  } catch (error) {
18220
- console.error(`Error: ${error}`);
18320
+ await this.output(sessionService, `Error: ${error}`);
18221
18321
  }
18222
18322
  }
18223
18323
  /**
@@ -18225,25 +18325,28 @@ var SkillCommand = class extends SlashCommand {
18225
18325
  *
18226
18326
  * 列出所有可用的技能
18227
18327
  */
18228
- async handleList() {
18328
+ async handleList(sessionService) {
18229
18329
  const skills = this.skillManager.listSkills();
18230
18330
  if (skills.length === 0) {
18231
- console.log("No skills found");
18331
+ await this.output(sessionService, "No skills found");
18232
18332
  return;
18233
18333
  }
18234
- console.log("\nAvailable Skills:\n");
18334
+ const lines = ["Available Skills:", ""];
18235
18335
  for (const skill of skills) {
18236
- console.log(` /${skill.name}`);
18237
- console.log(` ${skill.description}`);
18238
- console.log(` Source: ${skill.source}`);
18239
- console.log();
18336
+ lines.push(` /${skill.name}`);
18337
+ lines.push(` ${skill.description}`);
18338
+ lines.push(` Source: ${skill.source}`);
18339
+ lines.push("");
18240
18340
  }
18341
+ await this.output(sessionService, lines.join("\n").trimEnd());
18241
18342
  }
18242
18343
  /**
18243
18344
  * 显示帮助信息
18244
18345
  */
18245
- showHelp() {
18246
- console.log(`
18346
+ async showHelp(sessionService) {
18347
+ await this.output(
18348
+ sessionService,
18349
+ `
18247
18350
  Usage: /skill <subcommand> [options]
18248
18351
 
18249
18352
  Subcommands:
@@ -18257,7 +18360,18 @@ Examples:
18257
18360
  /skill add user/repo --name my-skill --overwrite
18258
18361
  /skill remove my-skill
18259
18362
  /skill list
18260
- `);
18363
+ `.trim()
18364
+ );
18365
+ }
18366
+ async output(sessionService, message) {
18367
+ if (sessionService) {
18368
+ await sessionService.addMessage({
18369
+ role: "assistant",
18370
+ content: message
18371
+ });
18372
+ return;
18373
+ }
18374
+ console.log(message);
18261
18375
  }
18262
18376
  };
18263
18377
 
@@ -18273,86 +18387,95 @@ var AgentCommand = class extends SlashCommand {
18273
18387
  super();
18274
18388
  this.agentManager = agentManager;
18275
18389
  }
18276
- async execute(args) {
18390
+ async execute(args, app) {
18391
+ const sessionService = app.getContainer().get("session");
18277
18392
  if (args.length === 0) {
18278
- this.showHelp();
18393
+ await this.showHelp(sessionService);
18279
18394
  return;
18280
18395
  }
18281
18396
  const subcommand = args[0];
18282
18397
  if (subcommand === "list") {
18283
- this.listAgents();
18398
+ await this.listAgents(sessionService);
18284
18399
  return;
18285
18400
  }
18286
18401
  const agentName = subcommand;
18287
18402
  const goal = args.slice(1).join(" ");
18288
18403
  if (!goal) {
18289
- console.log("\u274C Please provide a goal for the agent");
18290
- console.log(`Usage: /agent ${agentName} <goal>`);
18404
+ await this.output(
18405
+ sessionService,
18406
+ `\u274C Please provide a goal for the agent
18407
+ Usage: /agent ${agentName} <goal>`
18408
+ );
18291
18409
  return;
18292
18410
  }
18293
- await this.delegateTask(agentName, goal);
18411
+ await this.delegateTask(agentName, goal, sessionService);
18294
18412
  }
18295
18413
  /**
18296
18414
  * 显示帮助信息
18297
18415
  */
18298
- showHelp() {
18299
- console.log("Agent Management Commands:");
18300
- console.log("");
18301
- console.log(" /agent list - List all available agents");
18302
- console.log(" /agent <name> <goal> - Delegate a task to an agent");
18303
- console.log("");
18304
- console.log("Examples:");
18305
- console.log(" /agent list");
18306
- console.log(' /agent explore "Find all TypeScript files"');
18307
- console.log(' /agent code-reviewer "Review the authentication code"');
18416
+ async showHelp(sessionService) {
18417
+ await this.output(
18418
+ sessionService,
18419
+ [
18420
+ "Agent Management Commands:",
18421
+ "",
18422
+ " /agent list - List all available agents",
18423
+ " /agent <name> <goal> - Delegate a task to an agent",
18424
+ "",
18425
+ "Examples:",
18426
+ " /agent list",
18427
+ ' /agent explore "Find all TypeScript files"',
18428
+ ' /agent general-purpose "Summarize current project status"'
18429
+ ].join("\n")
18430
+ );
18308
18431
  }
18309
18432
  /**
18310
18433
  * 列出所有 Agent
18311
18434
  */
18312
- listAgents() {
18435
+ async listAgents(sessionService) {
18313
18436
  const agents = this.agentManager.listAll();
18314
18437
  if (agents.length === 0) {
18315
- console.log("No agents available");
18438
+ await this.output(sessionService, "No agents available");
18316
18439
  return;
18317
18440
  }
18318
- console.log(`
18319
- \u{1F4CB} Available Agents (${agents.length}):
18320
- `);
18441
+ const lines = [`\u{1F4CB} Available Agents (${agents.length}):`, ""];
18321
18442
  for (const agent of agents) {
18322
- console.log(` \u{1F916} ${agent.name} (${agent.source})`);
18323
- console.log(` ${agent.description}`);
18443
+ lines.push(` \u{1F916} ${agent.name} (${agent.source})`);
18444
+ lines.push(` ${agent.description}`);
18324
18445
  if (agent.tools) {
18325
- console.log(` Tools: ${agent.tools.join(", ")}`);
18446
+ lines.push(` Tools: ${agent.tools.join(", ")}`);
18326
18447
  }
18327
18448
  if (agent.disallowedTools) {
18328
- console.log(` Disallowed: ${agent.disallowedTools.join(", ")}`);
18449
+ lines.push(` Disallowed: ${agent.disallowedTools.join(", ")}`);
18329
18450
  }
18330
18451
  if (agent.model) {
18331
- console.log(` Model: ${agent.model}`);
18452
+ lines.push(` Model: ${agent.model}`);
18332
18453
  }
18333
18454
  if (agent.forkContext) {
18334
- console.log(` Fork Context: ${agent.forkContext}`);
18455
+ lines.push(` Fork Context: ${agent.forkContext}`);
18335
18456
  }
18336
18457
  if (agent.color) {
18337
- console.log(` Color: ${agent.color}`);
18458
+ lines.push(` Color: ${agent.color}`);
18338
18459
  }
18339
- console.log("");
18460
+ lines.push("");
18340
18461
  }
18462
+ await this.output(sessionService, lines.join("\n").trimEnd());
18341
18463
  }
18342
18464
  /**
18343
18465
  * 委托任务给 Agent
18344
18466
  */
18345
- async delegateTask(agentName, goal) {
18467
+ async delegateTask(agentName, goal, sessionService) {
18346
18468
  if (!this.agentManager.has(agentName)) {
18347
- console.log(`\u274C Agent not found: ${agentName}`);
18348
- console.log("\u{1F4A1} Use /agent list to see available agents");
18469
+ await this.output(
18470
+ sessionService,
18471
+ `\u274C Agent not found: ${agentName}
18472
+ \u{1F4A1} Use /agent list to see available agents`
18473
+ );
18349
18474
  return;
18350
18475
  }
18351
18476
  try {
18352
- console.log(`
18353
- \u{1F916} Delegating task to ${agentName}...`);
18354
- console.log(` Goal: ${goal}
18355
- `);
18477
+ await this.output(sessionService, `\u{1F916} Delegating task to ${agentName}...
18478
+ Goal: ${goal}`);
18356
18479
  const result = await this.agentManager.delegate(
18357
18480
  {
18358
18481
  type: "custom",
@@ -18361,25 +18484,40 @@ var AgentCommand = class extends SlashCommand {
18361
18484
  agentName
18362
18485
  );
18363
18486
  if (result.success) {
18364
- console.log(`
18365
- \u2705 Task completed by ${agentName}`);
18487
+ let message = `\u2705 Task completed by ${agentName}`;
18366
18488
  if (result.message) {
18367
- console.log(` ${result.message}`);
18489
+ message += `
18490
+ ${result.message}`;
18368
18491
  }
18369
18492
  if (result.data) {
18370
- console.log(` Data: ${JSON.stringify(result.data, null, 2)}`);
18493
+ message += `
18494
+ Data: ${JSON.stringify(result.data, null, 2)}`;
18371
18495
  }
18496
+ await this.output(sessionService, message);
18372
18497
  } else {
18373
- console.log(`
18374
- \u274C Task failed`);
18498
+ let message = "\u274C Task failed";
18375
18499
  if (result.message) {
18376
- console.log(` ${result.message}`);
18500
+ message += `
18501
+ ${result.message}`;
18377
18502
  }
18503
+ await this.output(sessionService, message);
18378
18504
  }
18379
18505
  } catch (error) {
18380
- console.log(`
18381
- \u274C Error: ${error instanceof Error ? error.message : String(error)}`);
18506
+ await this.output(
18507
+ sessionService,
18508
+ `\u274C Error: ${error instanceof Error ? error.message : String(error)}`
18509
+ );
18510
+ }
18511
+ }
18512
+ async output(sessionService, message) {
18513
+ if (sessionService) {
18514
+ await sessionService.addMessage({
18515
+ role: "assistant",
18516
+ content: message
18517
+ });
18518
+ return;
18382
18519
  }
18520
+ console.log(message);
18383
18521
  }
18384
18522
  };
18385
18523
 
@@ -18397,53 +18535,83 @@ var CommitCommand = class extends SlashCommand {
18397
18535
  this.modelService = modelService;
18398
18536
  this.configManager = configManager;
18399
18537
  }
18400
- async execute(args) {
18538
+ async execute(args, app) {
18401
18539
  const options = this.parseOptions(args);
18540
+ const sessionService = app.getContainer().get("session");
18402
18541
  try {
18403
18542
  if (options.stage) {
18404
- console.log("\u{1F4E6} Staging all changes...");
18543
+ await this.output(sessionService, "\u{1F4E6} Staging all changes...");
18405
18544
  this.execCommand("git add -A");
18406
18545
  }
18407
- console.log("\u{1F50D} Analyzing changes...");
18546
+ await this.output(sessionService, "\u{1F50D} Analyzing changes...");
18408
18547
  const diff = await this.getDiff(true);
18409
18548
  if (!diff || diff.trim().length === 0) {
18410
- console.log("\u274C No changes to commit");
18549
+ await this.output(
18550
+ sessionService,
18551
+ "\u274C No staged changes to commit. Stage files first or run `/commit --stage`."
18552
+ );
18411
18553
  return;
18412
18554
  }
18413
18555
  let commitHistory = "";
18414
18556
  if (options.followStyle) {
18415
- console.log("\u{1F4DA} Learning commit style from history...");
18557
+ await this.output(sessionService, "\u{1F4DA} Learning commit style from history...");
18416
18558
  const history = await this.getCommitHistory(50);
18417
18559
  commitHistory = history.join("\n");
18418
18560
  }
18419
- console.log("\u{1F916} Generating commit message...");
18561
+ await this.output(sessionService, "\u{1F916} Generating commit message...");
18420
18562
  const commitMessage = await this.generateCommitMessage(diff, commitHistory, options);
18421
18563
  if (options.copy) {
18422
18564
  await this.copyToClipboard(commitMessage);
18423
- console.log("\u{1F4CB} Commit message copied to clipboard");
18424
- console.log("\n" + commitMessage);
18565
+ await this.output(
18566
+ sessionService,
18567
+ `\u{1F4CB} Commit message copied to clipboard
18568
+
18569
+ ${commitMessage}`
18570
+ );
18425
18571
  return;
18426
18572
  }
18427
- console.log("\n\u{1F4DD} Generated commit message:\n");
18428
- console.log(commitMessage);
18429
- console.log("");
18430
18573
  if (!options.commit) {
18431
- const confirmed = await this.confirmCommit();
18432
- if (!confirmed) {
18433
- console.log("\u274C Commit cancelled");
18434
- return;
18435
- }
18574
+ await this.output(
18575
+ sessionService,
18576
+ `\u{1F4DD} Generated commit message:
18577
+
18578
+ ${commitMessage}
18579
+
18580
+ Use \`/commit --commit\` to create the commit, or \`/commit --copy\` to copy the message.`
18581
+ );
18582
+ return;
18436
18583
  }
18584
+ await this.output(
18585
+ sessionService,
18586
+ `\u{1F4DD} Generated commit message:
18587
+
18588
+ ${commitMessage}
18589
+
18590
+ \u{1F680} Creating commit...`
18591
+ );
18437
18592
  await this.executeCommit(commitMessage, options);
18438
- console.log("\u2705 Commit successful");
18593
+ await this.output(sessionService, "\u2705 Commit successful");
18439
18594
  if (options.push) {
18440
- console.log("\u{1F4E4} Pushing to remote...");
18595
+ await this.output(sessionService, "\u{1F4E4} Pushing to remote...");
18441
18596
  this.execCommand("git push");
18442
- console.log("\u2705 Push successful");
18597
+ await this.output(sessionService, "\u2705 Push successful");
18443
18598
  }
18444
18599
  } catch (error) {
18445
- console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
18600
+ await this.output(
18601
+ sessionService,
18602
+ `\u274C Error: ${error instanceof Error ? error.message : String(error)}`
18603
+ );
18604
+ }
18605
+ }
18606
+ async output(sessionService, message) {
18607
+ if (sessionService) {
18608
+ await sessionService.addMessage({
18609
+ role: "assistant",
18610
+ content: message
18611
+ });
18612
+ return;
18446
18613
  }
18614
+ console.log(message);
18447
18615
  }
18448
18616
  /**
18449
18617
  * 解析命令选项
@@ -18590,17 +18758,6 @@ Requirements:
18590
18758
 
18591
18759
  Output only the commit message, no explanations.`;
18592
18760
  }
18593
- /**
18594
- * 确认提交
18595
- */
18596
- async confirmCommit() {
18597
- console.log("Press Enter to commit, or Ctrl+C to cancel...");
18598
- return new Promise((resolve11) => {
18599
- process.stdin.once("data", () => {
18600
- resolve11(true);
18601
- });
18602
- });
18603
- }
18604
18761
  /**
18605
18762
  * 执行提交
18606
18763
  */
@@ -20916,13 +21073,73 @@ var ConfigService = class {
20916
21073
  */
20917
21074
  getModelConfig() {
20918
21075
  const config = this.getConfig();
21076
+ const legacyModel = typeof config.model === "object" ? config.model : void 0;
21077
+ const providerKey = this.getProviderKey(config) || "deepseek";
21078
+ const providerConfig = config.provider?.[providerKey];
21079
+ const envConfig = this.getProviderEnvConfig(providerKey);
20919
21080
  return {
20920
- apiKey: process.env.DEEPSEEK_API_KEY || "",
20921
- baseURL: process.env.DEEPSEEK_BASE_URL || "https://api.deepseek.com",
20922
- model: config.model || "deepseek-chat",
20923
- temperature: config.temperature || 0.7
21081
+ apiKey: envConfig.apiKey || providerConfig?.apiKey || legacyModel?.apiKey || "",
21082
+ baseURL: envConfig.baseURL || providerConfig?.baseURL || legacyModel?.baseURL || this.getDefaultBaseURL(providerKey),
21083
+ model: (typeof config.model === "string" ? config.model : void 0) || legacyModel?.model || this.getDefaultModel(providerKey),
21084
+ temperature: config.temperature ?? legacyModel?.temperature ?? 0.7
20924
21085
  };
20925
21086
  }
21087
+ getProviderKey(config) {
21088
+ const metadataProvider = config._metadata?.provider;
21089
+ if (typeof metadataProvider === "string" && metadataProvider.trim()) {
21090
+ return metadataProvider;
21091
+ }
21092
+ const providerKeys = config.provider ? Object.keys(config.provider) : [];
21093
+ if (providerKeys.length === 1) {
21094
+ return providerKeys[0];
21095
+ }
21096
+ return void 0;
21097
+ }
21098
+ getDefaultModel(providerKey) {
21099
+ const defaults = {
21100
+ openai: "gpt-4",
21101
+ anthropic: "claude-3-5-sonnet-20241022",
21102
+ deepseek: "deepseek-chat",
21103
+ openrouter: "anthropic/claude-3.5-sonnet",
21104
+ custom: "gpt-4"
21105
+ };
21106
+ return defaults[providerKey] || "deepseek-chat";
21107
+ }
21108
+ getDefaultBaseURL(providerKey) {
21109
+ const defaults = {
21110
+ openai: "https://api.openai.com/v1",
21111
+ anthropic: "https://api.anthropic.com",
21112
+ deepseek: "https://api.deepseek.com",
21113
+ openrouter: "https://openrouter.ai/api/v1",
21114
+ custom: "https://api.openai.com/v1"
21115
+ };
21116
+ return defaults[providerKey] || "https://api.deepseek.com";
21117
+ }
21118
+ getProviderEnvConfig(providerKey) {
21119
+ const envMap = {
21120
+ openai: {
21121
+ apiKey: process.env.OPENAI_API_KEY,
21122
+ baseURL: process.env.OPENAI_BASE_URL
21123
+ },
21124
+ anthropic: {
21125
+ apiKey: process.env.ANTHROPIC_API_KEY,
21126
+ baseURL: process.env.ANTHROPIC_BASE_URL
21127
+ },
21128
+ deepseek: {
21129
+ apiKey: process.env.DEEPSEEK_API_KEY,
21130
+ baseURL: process.env.DEEPSEEK_BASE_URL
21131
+ },
21132
+ openrouter: {
21133
+ apiKey: process.env.OPENROUTER_API_KEY,
21134
+ baseURL: process.env.OPENROUTER_BASE_URL
21135
+ },
21136
+ custom: {
21137
+ apiKey: process.env.OPENAI_API_KEY,
21138
+ baseURL: process.env.OPENAI_BASE_URL
21139
+ }
21140
+ };
21141
+ return envMap[providerKey] || {};
21142
+ }
20926
21143
  /**
20927
21144
  * 获取应用配置(向后兼容)
20928
21145
  */
@@ -21021,6 +21238,18 @@ function useSession() {
21021
21238
  const { app, currentSession, setCurrentSession, setSessions } = useAppContext();
21022
21239
  const sessionService = app.getContainer().get("session");
21023
21240
  const eventBus = app.getContainer().get("eventBus");
21241
+ const syncCurrentSession = () => {
21242
+ const session = sessionService.getCurrent();
21243
+ if (!session) {
21244
+ return;
21245
+ }
21246
+ setCurrentSession({
21247
+ ...session,
21248
+ messages: session.messages.slice(),
21249
+ config: session.config ? { ...session.config } : void 0
21250
+ });
21251
+ setSessions(sessionService.list());
21252
+ };
21024
21253
  useEffect(() => {
21025
21254
  const initSession = async () => {
21026
21255
  try {
@@ -21060,11 +21289,31 @@ function useSession() {
21060
21289
  const handleSessionLoaded = (data) => {
21061
21290
  setCurrentSession(data.session);
21062
21291
  };
21292
+ const handleMessageSent = () => {
21293
+ syncCurrentSession();
21294
+ };
21295
+ const handleSessionSaved = () => {
21296
+ syncCurrentSession();
21297
+ };
21298
+ const handleSessionUpdated = () => {
21299
+ syncCurrentSession();
21300
+ };
21301
+ const handleSessionResumed = () => {
21302
+ syncCurrentSession();
21303
+ };
21063
21304
  eventBus.on("session.created" /* SESSION_CREATED */, handleSessionCreated);
21064
21305
  eventBus.on("session.loaded" /* SESSION_LOADED */, handleSessionLoaded);
21306
+ eventBus.on("message.sent" /* MESSAGE_SENT */, handleMessageSent);
21307
+ eventBus.on("session.saved" /* SESSION_SAVED */, handleSessionSaved);
21308
+ eventBus.on("session_updated", handleSessionUpdated);
21309
+ eventBus.on("session:resumed", handleSessionResumed);
21065
21310
  return () => {
21066
21311
  eventBus.off("session.created" /* SESSION_CREATED */, handleSessionCreated);
21067
21312
  eventBus.off("session.loaded" /* SESSION_LOADED */, handleSessionLoaded);
21313
+ eventBus.off("message.sent" /* MESSAGE_SENT */, handleMessageSent);
21314
+ eventBus.off("session.saved" /* SESSION_SAVED */, handleSessionSaved);
21315
+ eventBus.off("session_updated", handleSessionUpdated);
21316
+ eventBus.off("session:resumed", handleSessionResumed);
21068
21317
  };
21069
21318
  }, [sessionService, eventBus, setCurrentSession, setSessions]);
21070
21319
  return {
@@ -21306,6 +21555,7 @@ var EnhancedMessageList = ({
21306
21555
 
21307
21556
  // src/ui/components/SimpleInput.tsx
21308
21557
  init_esm_shims();
21558
+ var MAX_VISIBLE_SUGGESTIONS = 8;
21309
21559
  var SimpleSuggestionEngine = class {
21310
21560
  commands = [
21311
21561
  "/help",
@@ -21378,6 +21628,7 @@ var SimpleInput = ({
21378
21628
  const [selectedIndex, setSelectedIndex] = useState(0);
21379
21629
  const [showSuggestions, setShowSuggestions] = useState(false);
21380
21630
  const suggestionEngine = useRef(new SimpleSuggestionEngine());
21631
+ const submittedValueRef = useRef(null);
21381
21632
  useEffect(() => {
21382
21633
  if (input.startsWith("/")) {
21383
21634
  const newSuggestions = suggestionEngine.current.getSuggestions(input);
@@ -21396,7 +21647,13 @@ var SimpleInput = ({
21396
21647
  } else if (key.downArrow) {
21397
21648
  setSelectedIndex((prev) => prev === suggestions.length - 1 ? 0 : prev + 1);
21398
21649
  } else if (key.return && suggestions[selectedIndex]) {
21399
- setInput(suggestions[selectedIndex].text);
21650
+ const selectedSuggestion = suggestions[selectedIndex].text;
21651
+ if (input !== selectedSuggestion) {
21652
+ setInput(selectedSuggestion);
21653
+ } else if (submittedValueRef.current === selectedSuggestion) {
21654
+ setInput("");
21655
+ submittedValueRef.current = null;
21656
+ }
21400
21657
  setShowSuggestions(false);
21401
21658
  } else if (key.escape) {
21402
21659
  setShowSuggestions(false);
@@ -21408,6 +21665,7 @@ var SimpleInput = ({
21408
21665
  const handleSubmit = useCallback(
21409
21666
  (value) => {
21410
21667
  if (!value.trim() || disabled) return;
21668
+ submittedValueRef.current = value;
21411
21669
  setInput("");
21412
21670
  setShowSuggestions(false);
21413
21671
  onSubmit(value);
@@ -21416,6 +21674,16 @@ var SimpleInput = ({
21416
21674
  );
21417
21675
  const promptSymbol = ">";
21418
21676
  const promptColor = input.startsWith("/") ? "blue" : "green";
21677
+ const visibleSuggestions = showSuggestions && suggestions.length > 0 ? Array.from(
21678
+ { length: Math.min(MAX_VISIBLE_SUGGESTIONS, suggestions.length) },
21679
+ (_, offset) => {
21680
+ const index = (selectedIndex + offset) % suggestions.length;
21681
+ return {
21682
+ suggestion: suggestions[index],
21683
+ index
21684
+ };
21685
+ }
21686
+ ) : [];
21419
21687
  const getStatusIndicator = () => {
21420
21688
  switch (status) {
21421
21689
  case "thinking":
@@ -21428,7 +21696,7 @@ var SimpleInput = ({
21428
21696
  return "";
21429
21697
  }
21430
21698
  };
21431
- return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, status !== "idle" && /* @__PURE__ */ React.createElement(Box, { marginBottom: 1, paddingX: 2 }, /* @__PURE__ */ React.createElement(Text, { color: "yellow" }, getStatusIndicator())), !disabled && /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Box, { paddingX: 2 }, /* @__PURE__ */ React.createElement(Text, { color: "gray" }, "\u2500".repeat(80))), /* @__PURE__ */ React.createElement(Box, { paddingX: 2, paddingY: 0 }, /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", alignItems: "center" }, /* @__PURE__ */ React.createElement(Text, { color: promptColor, bold: true }, promptSymbol, " "), /* @__PURE__ */ React.createElement(
21699
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, status !== "idle" && /* @__PURE__ */ React.createElement(Box, { marginBottom: 1, paddingX: 2 }, /* @__PURE__ */ React.createElement(Text, { color: "yellow" }, getStatusIndicator())), input.length === 0 && !showSuggestions && /* @__PURE__ */ React.createElement(Box, { paddingX: 2, marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "gray", dimColor: true }, "Type / for commands \u2022 Enter to send")), !disabled && /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Box, { paddingX: 2 }, /* @__PURE__ */ React.createElement(Text, { color: "gray" }, "\u2500".repeat(80))), /* @__PURE__ */ React.createElement(Box, { paddingX: 2 }, /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", alignItems: "center" }, /* @__PURE__ */ React.createElement(Text, { color: promptColor, bold: true }, promptSymbol, " "), /* @__PURE__ */ React.createElement(
21432
21700
  TextInput,
21433
21701
  {
21434
21702
  value: input,
@@ -21436,21 +21704,22 @@ var SimpleInput = ({
21436
21704
  onSubmit: handleSubmit,
21437
21705
  placeholder
21438
21706
  }
21439
- ))), /* @__PURE__ */ React.createElement(Box, { paddingX: 2 }, /* @__PURE__ */ React.createElement(Text, { color: "gray" }, "\u2500".repeat(80)))), showSuggestions && suggestions.length > 0 && /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", paddingX: 2, marginTop: 1 }, suggestions.slice(0, 8).map((suggestion, index) => /* @__PURE__ */ React.createElement(Box, { key: index, flexDirection: "row" }, /* @__PURE__ */ React.createElement(Box, { width: 20 }, /* @__PURE__ */ React.createElement(
21707
+ ))), /* @__PURE__ */ React.createElement(Box, { paddingX: 2 }, /* @__PURE__ */ React.createElement(Text, { color: "gray" }, "\u2500".repeat(80)))), showSuggestions && suggestions.length > 0 && /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", paddingX: 2, marginTop: 1 }, visibleSuggestions.map(({ suggestion, index }) => /* @__PURE__ */ React.createElement(Box, { key: `${suggestion.text}-${index}`, flexDirection: "row", width: "100%" }, /* @__PURE__ */ React.createElement(Box, { width: 20, flexShrink: 0 }, /* @__PURE__ */ React.createElement(
21440
21708
  Text,
21441
21709
  {
21442
21710
  color: index === selectedIndex ? "cyan" : "gray",
21443
21711
  bold: index === selectedIndex
21444
21712
  },
21445
21713
  suggestion.text
21446
- )), /* @__PURE__ */ React.createElement(
21714
+ )), /* @__PURE__ */ React.createElement(Box, { flexGrow: 1 }, /* @__PURE__ */ React.createElement(
21447
21715
  Text,
21448
21716
  {
21449
21717
  color: index === selectedIndex ? "white" : "dim",
21450
- dimColor: index !== selectedIndex
21718
+ dimColor: index !== selectedIndex,
21719
+ wrap: "truncate-end"
21451
21720
  },
21452
21721
  suggestion.description
21453
- ))), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "gray", dimColor: true }, "\u2191\u2193 navigate \u2022 Enter/Tab select \u2022 Esc cancel"))), input.length === 0 && !showSuggestions && /* @__PURE__ */ React.createElement(Box, { paddingX: 2, paddingTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "gray", dimColor: true }, "Type / for commands \u2022 Enter to send")));
21722
+ )))), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "gray", dimColor: true }, "\u2191\u2193 navigate \u2022 Enter/Tab select \u2022 Esc cancel"))));
21454
21723
  };
21455
21724
 
21456
21725
  // src/ui/components/WelcomeScreen.tsx
@@ -21976,6 +22245,20 @@ function AppContent() {
21976
22245
  const [showResumeSelector, setShowResumeSelector] = useState(false);
21977
22246
  const [showMcpManager, setShowMcpManager] = useState(false);
21978
22247
  const [showStatusManager, setShowStatusManager] = useState(false);
22248
+ const resetTransientUi = useCallback(() => {
22249
+ setShowModelSelector(false);
22250
+ setShowRewindSelector(false);
22251
+ setShowResumeSelector(false);
22252
+ setShowMcpManager(false);
22253
+ setShowStatusManager(false);
22254
+ }, []);
22255
+ const requestAppExit = useCallback(async () => {
22256
+ try {
22257
+ await app.stop();
22258
+ } finally {
22259
+ exit();
22260
+ }
22261
+ }, [app, exit]);
21979
22262
  const messagesRef = useRef([]);
21980
22263
  const [, forceUpdate] = useState({});
21981
22264
  const historyMessages = messagesRef.current;
@@ -22099,6 +22382,16 @@ function AppContent() {
22099
22382
  useInput(
22100
22383
  useCallback(
22101
22384
  (input, key) => {
22385
+ if (key.ctrl && input === "c") {
22386
+ if (transcriptMode) {
22387
+ clearTerminal();
22388
+ toggleTranscriptMode();
22389
+ refresh();
22390
+ } else {
22391
+ resetTransientUi();
22392
+ }
22393
+ return;
22394
+ }
22102
22395
  if (key.ctrl && input === "o") {
22103
22396
  clearTerminal();
22104
22397
  toggleTranscriptMode();
@@ -22106,7 +22399,7 @@ function AppContent() {
22106
22399
  return;
22107
22400
  }
22108
22401
  if (transcriptMode) {
22109
- if (key.escape || key.ctrl && input === "c") {
22402
+ if (key.escape) {
22110
22403
  clearTerminal();
22111
22404
  toggleTranscriptMode();
22112
22405
  refresh();
@@ -22117,7 +22410,17 @@ function AppContent() {
22117
22410
  return;
22118
22411
  }
22119
22412
  },
22120
- [transcriptMode, toggleTranscriptMode, refresh, showModelSelector]
22413
+ [
22414
+ transcriptMode,
22415
+ toggleTranscriptMode,
22416
+ refresh,
22417
+ showModelSelector,
22418
+ showRewindSelector,
22419
+ showResumeSelector,
22420
+ showMcpManager,
22421
+ showStatusManager,
22422
+ resetTransientUi
22423
+ ]
22121
22424
  )
22122
22425
  );
22123
22426
  const handleSubmit = useCallback(
@@ -22131,7 +22434,7 @@ function AppContent() {
22131
22434
  return;
22132
22435
  }
22133
22436
  if (value.trim().toLowerCase() === "exit" || value.trim().toLowerCase() === "quit") {
22134
- exit();
22437
+ await requestAppExit();
22135
22438
  return;
22136
22439
  }
22137
22440
  setTasks([]);
@@ -22171,7 +22474,7 @@ function AppContent() {
22171
22474
  setIsLoading(false);
22172
22475
  }
22173
22476
  },
22174
- [currentSession, app, sessionService, exit]
22477
+ [currentSession, app, sessionService, requestAppExit]
22175
22478
  );
22176
22479
  const handleModelSelect = useCallback(
22177
22480
  async (modelId) => {
@@ -22182,11 +22485,20 @@ function AppContent() {
22182
22485
  try {
22183
22486
  modelService.updateConfig({ model: modelId });
22184
22487
  setCurrentModelId(modelId);
22488
+ let missingApiKey = false;
22489
+ let configPath = "~/.codemate/config.json";
22185
22490
  try {
22186
22491
  const configService = app.getContainer().get("config");
22187
22492
  if (configService && typeof configService.setConfig === "function") {
22188
22493
  configService.setConfig(false, "model", modelId);
22189
22494
  }
22495
+ if (configService && typeof configService.getGlobalConfigPath === "function") {
22496
+ configPath = configService.getGlobalConfigPath();
22497
+ }
22498
+ if (configService && typeof configService.getModelConfig === "function") {
22499
+ const modelConfig = configService.getModelConfig();
22500
+ missingApiKey = !modelConfig.apiKey;
22501
+ }
22190
22502
  } catch (error) {
22191
22503
  console.log("ConfigService not available, model change is temporary");
22192
22504
  }
@@ -22194,7 +22506,7 @@ function AppContent() {
22194
22506
  role: "assistant",
22195
22507
  content: `\u2705 Model changed to ${modelId}
22196
22508
 
22197
- \u{1F504} The model has been updated for this session. To make this change permanent, update your .aiclirc.json configuration file.`
22509
+ \u{1F504} The model has been updated for this session. To make this change permanent, update your ${configPath} configuration file.${missingApiKey ? "\n\n\u26A0\uFE0F No API key configured. Run `codemate config` or set the provider API key in the config file to use this model." : ""}`
22198
22510
  });
22199
22511
  const eventBus = app.getContainer().get("eventBus");
22200
22512
  eventBus.emit("model_changed", { newModel: modelId, previousModel: previousModelId });
@@ -22285,6 +22597,16 @@ function AppContent() {
22285
22597
  eventBus.off("show_model_selector", handleShowModelSelector);
22286
22598
  };
22287
22599
  }, [app]);
22600
+ useEffect(() => {
22601
+ const eventBus = app.getContainer().get("eventBus");
22602
+ const handleExitApp = () => {
22603
+ void requestAppExit();
22604
+ };
22605
+ eventBus.on("exit_app", handleExitApp);
22606
+ return () => {
22607
+ eventBus.off("exit_app", handleExitApp);
22608
+ };
22609
+ }, [app, requestAppExit]);
22288
22610
  useEffect(() => {
22289
22611
  const eventBus = app.getContainer().get("eventBus");
22290
22612
  const handleShowRewindSelector = () => {
@@ -22460,10 +22782,13 @@ function App({ app }) {
22460
22782
  // src/utils/firstRun.ts
22461
22783
  init_esm_shims();
22462
22784
  function isFirstRun() {
22463
- const configPath = getConfigPath();
22464
- return !fs21__default.existsSync(configPath);
22785
+ return !fs21__default.existsSync(getConfigPath()) && !fs21__default.existsSync(getLegacyConfigPath());
22465
22786
  }
22466
22787
  function getConfigPath() {
22788
+ const homeDir = os4__default.homedir();
22789
+ return path18.join(homeDir, ".codemate", "config.json");
22790
+ }
22791
+ function getLegacyConfigPath() {
22467
22792
  const homeDir = os4__default.homedir();
22468
22793
  return path18.join(homeDir, ".aiclirc.json");
22469
22794
  }
@@ -22489,12 +22814,14 @@ function createDefaultConfig(apiKey, provider, model, baseURL) {
22489
22814
  logLevel: "info",
22490
22815
  workDir: process.cwd()
22491
22816
  },
22492
- model: {
22493
- apiKey,
22494
- baseURL: baseURL || defaultBaseURLs[provider] || "https://api.openai.com/v1",
22495
- model: model || defaultModels[provider] || "gpt-4",
22496
- temperature: 0.7
22817
+ model: model || defaultModels[provider] || "gpt-4",
22818
+ provider: {
22819
+ [provider]: {
22820
+ apiKey,
22821
+ baseURL: baseURL || defaultBaseURLs[provider] || "https://api.openai.com/v1"
22822
+ }
22497
22823
  },
22824
+ temperature: 0.7,
22498
22825
  tools: {
22499
22826
  enabled: [
22500
22827
  "read_file",
@@ -22528,6 +22855,7 @@ function createDefaultConfig(apiKey, provider, model, baseURL) {
22528
22855
  }
22529
22856
  };
22530
22857
  const configPath = getConfigPath();
22858
+ fs21__default.mkdirSync(path18.dirname(configPath), { recursive: true });
22531
22859
  fs21__default.writeFileSync(configPath, JSON.stringify(config, null, 2));
22532
22860
  }
22533
22861
 
@@ -22588,7 +22916,7 @@ async function runFirstTimeSetup() {
22588
22916
  rl.close();
22589
22917
  createDefaultConfig(apiKey.trim(), providerKey, model, baseURL || PROVIDERS[providerKey].baseURL);
22590
22918
  console.log("");
22591
- console.log("\u2705 \u914D\u7F6E\u5DF2\u4FDD\u5B58\u5230: ~/.aiclirc.json");
22919
+ console.log("\u2705 \u914D\u7F6E\u5DF2\u4FDD\u5B58\u5230: ~/.codemate/config.json");
22592
22920
  console.log("");
22593
22921
  console.log(`\u63D0\u4F9B\u5546: ${PROVIDERS[providerKey].name}`);
22594
22922
  console.log(`\u6A21\u578B: ${model}`);
@@ -22646,7 +22974,9 @@ program.command("chat", { isDefault: true }).description("Start interactive chat
22646
22974
  await sessionService.initialize();
22647
22975
  console.log("\u2705 SessionService initialized");
22648
22976
  console.log("\n\u{1F3A8} Starting interactive UI...\n");
22649
- render(React.createElement(App, { app }));
22977
+ const inkApp = render(React.createElement(App, { app }));
22978
+ await inkApp.waitUntilExit();
22979
+ process.exit(0);
22650
22980
  } catch (error) {
22651
22981
  console.error("\u274C Fatal error:", error);
22652
22982
  process.exit(1);
@@ -22656,7 +22986,7 @@ program.command("config").description("Configure or reconfigure CodeMate AI").ac
22656
22986
  try {
22657
22987
  console.log("\n\u{1F527} CodeMate AI \u914D\u7F6E\u5411\u5BFC\n");
22658
22988
  if (!isFirstRun()) {
22659
- console.log("\u5F53\u524D\u914D\u7F6E\u6587\u4EF6: ~/.aiclirc.json");
22989
+ console.log("\u5F53\u524D\u914D\u7F6E\u6587\u4EF6: ~/.codemate/config.json");
22660
22990
  console.log("\u6B64\u64CD\u4F5C\u5C06\u8986\u76D6\u73B0\u6709\u914D\u7F6E\u3002\n");
22661
22991
  }
22662
22992
  await runFirstTimeSetup();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codemate-ai",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "type": "module",
5
5
  "description": "Enterprise-grade AI coding assistant CLI",
6
6
  "main": "dist/cli.js",