codemate-ai 1.0.7 → 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 +411 -181
  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';
@@ -739,36 +739,43 @@ var init_WorkspaceCommand = __esm({
739
739
  super();
740
740
  this.configManager = configManager;
741
741
  }
742
- async execute(args) {
742
+ async execute(args, app) {
743
743
  const subcommand = args[0];
744
+ const sessionService = app.getContainer().get("session");
744
745
  try {
745
746
  switch (subcommand) {
746
747
  case "create":
747
- await this.create(this.parseCreateOptions(args.slice(1)));
748
+ await this.create(this.parseCreateOptions(args.slice(1)), sessionService);
748
749
  break;
749
750
  case "list":
750
- await this.list();
751
+ await this.list(sessionService);
751
752
  break;
752
753
  case "remove":
753
754
  case "delete":
754
- await this.remove(args[1]);
755
+ await this.remove(args[1], sessionService);
755
756
  break;
756
757
  case "complete":
757
- await this.complete();
758
+ await this.complete(sessionService);
758
759
  break;
759
760
  default:
760
- console.log("Usage: /workspace <create|list|remove|complete> [options]");
761
- console.log("");
762
- console.log("Commands:");
763
- console.log(" create [--name <name>] [-b <branch>] Create a new workspace");
764
- console.log(" list List all workspaces");
765
- console.log(" remove <name> Remove a workspace");
766
- console.log(
767
- " 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")
768
772
  );
769
773
  }
770
774
  } catch (error) {
771
- 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
+ );
772
779
  }
773
780
  }
774
781
  /**
@@ -796,110 +803,121 @@ var init_WorkspaceCommand = __esm({
796
803
  /**
797
804
  * 创建工作区
798
805
  */
799
- async create(options) {
806
+ async create(options, sessionService) {
800
807
  const workspaceName = options.name;
801
808
  if (!workspaceName) {
802
- console.log("\u274C Workspace name is required");
803
- console.log("Usage: /workspace create --name <workspace-name> [-b <branch>]");
804
- console.log("");
805
- console.log("Example:");
806
- console.log(" /workspace create --name feature-auth");
807
- 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
+ );
808
820
  return;
809
821
  }
810
822
  const config = this.configManager.config;
811
823
  const baseBranch = options.baseBranch || config.workspace?.baseBranch || "main";
812
824
  if (!this.branchExists(baseBranch)) {
813
- console.log(`\u274C Base branch '${baseBranch}' does not exist`);
814
- console.log("Available branches:");
825
+ let message = `\u274C Base branch '${baseBranch}' does not exist
826
+ Available branches:`;
815
827
  try {
816
828
  const branches = this.execGit("branch -a").split("\n").map(
817
829
  (line) => line.trim().replace(/^\*\s*/, "").replace(/^remotes\/origin\//, "")
818
830
  ).filter((line) => line && !line.includes("HEAD")).slice(0, 5);
819
- for (const branch of branches) {
820
- console.log(` - ${branch}`);
821
- }
831
+ message += `
832
+ ${branches.map((branch) => ` - ${branch}`).join("\n")}`;
822
833
  } catch {
823
- console.log(" (Unable to list branches)");
834
+ message += "\n (Unable to list branches)";
824
835
  }
836
+ await this.output(sessionService, message);
825
837
  return;
826
838
  }
827
839
  const workspacePath = this.getWorkspacePath(workspaceName);
828
840
  if (existsSync(workspacePath)) {
829
- console.log(`\u274C Workspace already exists: ${workspacePath}`);
841
+ await this.output(sessionService, `\u274C Workspace already exists: ${workspacePath}`);
830
842
  return;
831
843
  }
832
844
  const branchExists = this.branchExists(workspaceName);
833
- console.log(`\u{1F33F} Creating workspace '${workspaceName}'...`);
845
+ await this.output(sessionService, `\u{1F33F} Creating workspace '${workspaceName}'...`);
834
846
  try {
835
847
  if (branchExists && !options.newBranch) {
836
848
  this.execGit(`worktree add ${workspacePath} ${workspaceName}`);
837
849
  } else {
838
850
  this.execGit(`worktree add -b ${workspaceName} ${workspacePath} ${baseBranch}`);
839
851
  }
840
- console.log(`\u2705 Workspace created at: ${workspacePath}`);
841
- 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
+ );
842
857
  } catch (error) {
843
- console.error("\u274C Failed to create workspace");
858
+ await this.output(sessionService, "\u274C Failed to create workspace");
844
859
  throw error;
845
860
  }
846
861
  }
847
862
  /**
848
863
  * 列出所有工作区
849
864
  */
850
- async list() {
865
+ async list(sessionService) {
851
866
  try {
852
867
  const output = this.execGit("worktree list --porcelain");
853
868
  const workspaces = this.parseWorktreeList(output);
854
869
  if (workspaces.length === 0) {
855
- console.log("\u{1F4CB} No workspaces found");
870
+ await this.output(sessionService, "\u{1F4CB} No workspaces found");
856
871
  return;
857
872
  }
858
- console.log("\u{1F4CB} Workspaces:\n");
873
+ const lines = ["\u{1F4CB} Workspaces:", ""];
859
874
  for (const workspace of workspaces) {
860
875
  const marker = workspace.isCurrent ? "\u2192" : " ";
861
876
  const name = basename(workspace.path);
862
- console.log(`${marker} ${name}`);
863
- console.log(` Path: ${workspace.path}`);
864
- console.log(` Branch: ${workspace.branch}`);
865
- console.log(` Commit: ${workspace.commit.substring(0, 7)}`);
866
- 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("");
867
882
  }
883
+ await this.output(sessionService, lines.join("\n").trimEnd());
868
884
  } catch (error) {
869
- console.error("\u274C Failed to list workspaces");
885
+ await this.output(sessionService, "\u274C Failed to list workspaces");
870
886
  throw error;
871
887
  }
872
888
  }
873
889
  /**
874
890
  * 删除工作区
875
891
  */
876
- async remove(name) {
892
+ async remove(name, sessionService) {
877
893
  if (!name) {
878
- console.log("\u274C Workspace name is required");
879
- console.log("Usage: /workspace remove <name>");
894
+ await this.output(
895
+ sessionService,
896
+ "\u274C Workspace name is required\nUsage: /workspace remove <name>"
897
+ );
880
898
  return;
881
899
  }
882
900
  const workspacePath = this.getWorkspacePath(name);
883
901
  if (!existsSync(workspacePath)) {
884
- console.log(`\u274C Workspace not found: ${workspacePath}`);
902
+ await this.output(sessionService, `\u274C Workspace not found: ${workspacePath}`);
885
903
  return;
886
904
  }
887
- console.log(`\u{1F5D1}\uFE0F Removing workspace '${name}'...`);
905
+ await this.output(sessionService, `\u{1F5D1}\uFE0F Removing workspace '${name}'...`);
888
906
  try {
889
907
  this.execGit(`worktree remove ${workspacePath}`);
890
- console.log(`\u2705 Workspace removed: ${workspacePath}`);
908
+ await this.output(sessionService, `\u2705 Workspace removed: ${workspacePath}`);
891
909
  } catch (error) {
892
- console.error("\u274C Failed to remove workspace");
910
+ await this.output(sessionService, "\u274C Failed to remove workspace");
893
911
  throw error;
894
912
  }
895
913
  }
896
914
  /**
897
915
  * 完成并合并工作区
898
916
  */
899
- async complete() {
917
+ async complete(sessionService) {
900
918
  const currentBranch = this.getCurrentBranch();
901
919
  if (!currentBranch) {
902
- console.log("\u274C Not in a Git repository");
920
+ await this.output(sessionService, "\u274C Not in a Git repository");
903
921
  return;
904
922
  }
905
923
  const config = this.configManager.config;
@@ -908,28 +926,41 @@ var init_WorkspaceCommand = __esm({
908
926
  try {
909
927
  this.execGit("diff-index --quiet HEAD --");
910
928
  } catch {
911
- 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
+ );
912
933
  return;
913
934
  }
914
- console.log(`\u{1F500} Merging ${currentBranch} into ${baseBranch}...`);
935
+ await this.output(sessionService, `\u{1F500} Merging ${currentBranch} into ${baseBranch}...`);
915
936
  try {
916
937
  this.execGit(`checkout ${baseBranch}`);
917
938
  this.execGit(`merge ${currentBranch}`);
918
- console.log(`\u2705 Merged ${currentBranch} into ${baseBranch}`);
939
+ await this.output(sessionService, `\u2705 Merged ${currentBranch} into ${baseBranch}`);
919
940
  const workspacePath = process.cwd();
920
- console.log("\u{1F5D1}\uFE0F Removing workspace...");
941
+ await this.output(sessionService, "\u{1F5D1}\uFE0F Removing workspace...");
921
942
  process.chdir("..");
922
943
  this.execGit(`worktree remove ${workspacePath}`);
923
944
  if (autoDelete) {
924
- console.log(`\u{1F5D1}\uFE0F Deleting branch ${currentBranch}...`);
945
+ await this.output(sessionService, `\u{1F5D1}\uFE0F Deleting branch ${currentBranch}...`);
925
946
  this.execGit(`branch -d ${currentBranch}`);
926
947
  }
927
- console.log("\u2705 Workspace completed and merged!");
948
+ await this.output(sessionService, "\u2705 Workspace completed and merged!");
928
949
  } catch (error) {
929
- console.error("\u274C Failed to complete workspace");
950
+ await this.output(sessionService, "\u274C Failed to complete workspace");
930
951
  throw error;
931
952
  }
932
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
+ }
933
964
  /**
934
965
  * 获取项目名称
935
966
  */
@@ -8705,7 +8736,6 @@ var SessionService = class {
8705
8736
  }
8706
8737
  /**
8707
8738
  * 清除当前会话并创建新会话
8708
- * 对标Neovate的clear命令功能
8709
8739
  */
8710
8740
  async clear() {
8711
8741
  const newSession = await this.create();
@@ -9529,6 +9559,11 @@ var ExitCommand = class extends SlashCommand {
9529
9559
  description = "Exit the program";
9530
9560
  aliases = ["quit", "q"];
9531
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
+ }
9532
9567
  console.log("\u{1F44B} Goodbye!");
9533
9568
  await app.stop();
9534
9569
  process.exit(0);
@@ -9647,8 +9682,9 @@ var ConfigCommand = class extends SlashCommand {
9647
9682
  */
9648
9683
  async execute(args, app) {
9649
9684
  const configService = app.getContainer().get("config");
9685
+ const sessionService = app.getContainer().get("session");
9650
9686
  if (!configService) {
9651
- console.log("\u274C ConfigService not available");
9687
+ await this.outputResult(sessionService, "\u274C ConfigService not available");
9652
9688
  return;
9653
9689
  }
9654
9690
  const [action, ...rest] = args;
@@ -9672,6 +9708,16 @@ var ConfigCommand = class extends SlashCommand {
9672
9708
  default:
9673
9709
  result = this.getHelp();
9674
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
+ }
9675
9721
  console.log(result);
9676
9722
  }
9677
9723
  /**
@@ -9834,17 +9880,17 @@ var ForkCommand = class extends SlashCommand {
9834
9880
  async execute(args, app) {
9835
9881
  const sessionService = app.getContainer().get("session");
9836
9882
  if (!sessionService) {
9837
- console.log("\u274C SessionService not available");
9883
+ await this.output(void 0, "\u274C SessionService not available");
9838
9884
  return;
9839
9885
  }
9840
9886
  const currentSession = sessionService.getCurrent();
9841
9887
  if (!currentSession) {
9842
- console.log("\u274C No active session");
9888
+ await this.output(sessionService, "\u274C No active session");
9843
9889
  return;
9844
9890
  }
9845
9891
  const messages = currentSession.messages;
9846
9892
  if (messages.length === 0) {
9847
- console.log("\u274C No messages to fork from");
9893
+ await this.output(sessionService, "\u274C No messages to fork from");
9848
9894
  return;
9849
9895
  }
9850
9896
  if (args.length > 0) {
@@ -9852,7 +9898,7 @@ var ForkCommand = class extends SlashCommand {
9852
9898
  await this.forkFromMessage(sessionService, messageUuid);
9853
9899
  return;
9854
9900
  }
9855
- this.showForkSelector(messages);
9901
+ await this.showForkSelector(sessionService, messages);
9856
9902
  }
9857
9903
  /**
9858
9904
  * 从指定消息分叉
@@ -9862,27 +9908,36 @@ var ForkCommand = class extends SlashCommand {
9862
9908
  const newSession = await sessionService.fork({
9863
9909
  fromMessageUuid: messageUuid
9864
9910
  });
9865
- console.log(`\u2705 Session forked: ${newSession.id}`);
9866
- 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
+ );
9867
9916
  } catch (error) {
9868
- 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
+ );
9869
9921
  }
9870
9922
  }
9871
9923
  /**
9872
9924
  * 显示分叉选择器
9873
9925
  */
9874
- showForkSelector(messages) {
9926
+ async showForkSelector(sessionService, messages) {
9875
9927
  const messagesWithUuid = messages.filter((msg) => msg.uuid);
9876
9928
  if (messagesWithUuid.length === 0) {
9877
- console.log("\u274C No messages with UUID found. Fork requires enhanced messages.");
9878
- 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
+ );
9879
9933
  return;
9880
9934
  }
9881
9935
  const messageList = messagesWithUuid.map((msg, index) => {
9882
9936
  const preview = this.getMessagePreview(msg);
9883
9937
  return `${index + 1}. [${msg.uuid.slice(0, 8)}] ${msg.role}: ${preview}`;
9884
9938
  }).join("\n");
9885
- console.log(
9939
+ await this.output(
9940
+ sessionService,
9886
9941
  `
9887
9942
  \u{1F4CB} Select a message to fork from:
9888
9943
 
@@ -9894,6 +9949,16 @@ Example: /fork ${messagesWithUuid[0].uuid}
9894
9949
  `.trim()
9895
9950
  );
9896
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
+ }
9897
9962
  /**
9898
9963
  * 获取消息预览
9899
9964
  */
@@ -18181,22 +18246,23 @@ var SkillCommand = class extends SlashCommand {
18181
18246
  *
18182
18247
  * @param args 命令参数
18183
18248
  */
18184
- async execute(args) {
18249
+ async execute(args, app) {
18185
18250
  const subcommand = args[0];
18251
+ const sessionService = app.getContainer().get("session");
18186
18252
  switch (subcommand) {
18187
18253
  case "add":
18188
- await this.handleAdd(args.slice(1));
18254
+ await this.handleAdd(args.slice(1), sessionService);
18189
18255
  break;
18190
18256
  case "remove":
18191
18257
  case "rm":
18192
- await this.handleRemove(args.slice(1));
18258
+ await this.handleRemove(args.slice(1), sessionService);
18193
18259
  break;
18194
18260
  case "list":
18195
18261
  case "ls":
18196
- await this.handleList();
18262
+ await this.handleList(sessionService);
18197
18263
  break;
18198
18264
  default:
18199
- this.showHelp();
18265
+ await this.showHelp(sessionService);
18200
18266
  }
18201
18267
  }
18202
18268
  /**
@@ -18204,10 +18270,12 @@ var SkillCommand = class extends SlashCommand {
18204
18270
  *
18205
18271
  * 从 GitHub 安装技能
18206
18272
  */
18207
- async handleAdd(args) {
18273
+ async handleAdd(args, sessionService) {
18208
18274
  if (args.length === 0) {
18209
- console.error("Error: GitHub source is required");
18210
- 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
+ );
18211
18279
  return;
18212
18280
  }
18213
18281
  const source = args[0];
@@ -18223,8 +18291,12 @@ var SkillCommand = class extends SlashCommand {
18223
18291
  }
18224
18292
  try {
18225
18293
  await this.skillManager.addSkill(source, options);
18294
+ await this.output(
18295
+ sessionService,
18296
+ `\u2705 Skill installed: ${options.name || source.split("/").pop() || source}`
18297
+ );
18226
18298
  } catch (error) {
18227
- console.error(`Error: ${error}`);
18299
+ await this.output(sessionService, `Error: ${error}`);
18228
18300
  }
18229
18301
  }
18230
18302
  /**
@@ -18232,17 +18304,20 @@ var SkillCommand = class extends SlashCommand {
18232
18304
  *
18233
18305
  * 删除已安装的技能
18234
18306
  */
18235
- async handleRemove(args) {
18307
+ async handleRemove(args, sessionService) {
18236
18308
  if (args.length === 0) {
18237
- console.error("Error: Skill name is required");
18238
- console.log("Usage: /skill remove <name>");
18309
+ await this.output(
18310
+ sessionService,
18311
+ "Error: Skill name is required\nUsage: /skill remove <name>"
18312
+ );
18239
18313
  return;
18240
18314
  }
18241
18315
  const name = args[0];
18242
18316
  try {
18243
18317
  await this.skillManager.removeSkill(name);
18318
+ await this.output(sessionService, `\u2705 Skill removed: ${name}`);
18244
18319
  } catch (error) {
18245
- console.error(`Error: ${error}`);
18320
+ await this.output(sessionService, `Error: ${error}`);
18246
18321
  }
18247
18322
  }
18248
18323
  /**
@@ -18250,25 +18325,28 @@ var SkillCommand = class extends SlashCommand {
18250
18325
  *
18251
18326
  * 列出所有可用的技能
18252
18327
  */
18253
- async handleList() {
18328
+ async handleList(sessionService) {
18254
18329
  const skills = this.skillManager.listSkills();
18255
18330
  if (skills.length === 0) {
18256
- console.log("No skills found");
18331
+ await this.output(sessionService, "No skills found");
18257
18332
  return;
18258
18333
  }
18259
- console.log("\nAvailable Skills:\n");
18334
+ const lines = ["Available Skills:", ""];
18260
18335
  for (const skill of skills) {
18261
- console.log(` /${skill.name}`);
18262
- console.log(` ${skill.description}`);
18263
- console.log(` Source: ${skill.source}`);
18264
- console.log();
18336
+ lines.push(` /${skill.name}`);
18337
+ lines.push(` ${skill.description}`);
18338
+ lines.push(` Source: ${skill.source}`);
18339
+ lines.push("");
18265
18340
  }
18341
+ await this.output(sessionService, lines.join("\n").trimEnd());
18266
18342
  }
18267
18343
  /**
18268
18344
  * 显示帮助信息
18269
18345
  */
18270
- showHelp() {
18271
- console.log(`
18346
+ async showHelp(sessionService) {
18347
+ await this.output(
18348
+ sessionService,
18349
+ `
18272
18350
  Usage: /skill <subcommand> [options]
18273
18351
 
18274
18352
  Subcommands:
@@ -18282,7 +18360,18 @@ Examples:
18282
18360
  /skill add user/repo --name my-skill --overwrite
18283
18361
  /skill remove my-skill
18284
18362
  /skill list
18285
- `);
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);
18286
18375
  }
18287
18376
  };
18288
18377
 
@@ -18298,86 +18387,95 @@ var AgentCommand = class extends SlashCommand {
18298
18387
  super();
18299
18388
  this.agentManager = agentManager;
18300
18389
  }
18301
- async execute(args) {
18390
+ async execute(args, app) {
18391
+ const sessionService = app.getContainer().get("session");
18302
18392
  if (args.length === 0) {
18303
- this.showHelp();
18393
+ await this.showHelp(sessionService);
18304
18394
  return;
18305
18395
  }
18306
18396
  const subcommand = args[0];
18307
18397
  if (subcommand === "list") {
18308
- this.listAgents();
18398
+ await this.listAgents(sessionService);
18309
18399
  return;
18310
18400
  }
18311
18401
  const agentName = subcommand;
18312
18402
  const goal = args.slice(1).join(" ");
18313
18403
  if (!goal) {
18314
- console.log("\u274C Please provide a goal for the agent");
18315
- 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
+ );
18316
18409
  return;
18317
18410
  }
18318
- await this.delegateTask(agentName, goal);
18411
+ await this.delegateTask(agentName, goal, sessionService);
18319
18412
  }
18320
18413
  /**
18321
18414
  * 显示帮助信息
18322
18415
  */
18323
- showHelp() {
18324
- console.log("Agent Management Commands:");
18325
- console.log("");
18326
- console.log(" /agent list - List all available agents");
18327
- console.log(" /agent <name> <goal> - Delegate a task to an agent");
18328
- console.log("");
18329
- console.log("Examples:");
18330
- console.log(" /agent list");
18331
- console.log(' /agent explore "Find all TypeScript files"');
18332
- 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
+ );
18333
18431
  }
18334
18432
  /**
18335
18433
  * 列出所有 Agent
18336
18434
  */
18337
- listAgents() {
18435
+ async listAgents(sessionService) {
18338
18436
  const agents = this.agentManager.listAll();
18339
18437
  if (agents.length === 0) {
18340
- console.log("No agents available");
18438
+ await this.output(sessionService, "No agents available");
18341
18439
  return;
18342
18440
  }
18343
- console.log(`
18344
- \u{1F4CB} Available Agents (${agents.length}):
18345
- `);
18441
+ const lines = [`\u{1F4CB} Available Agents (${agents.length}):`, ""];
18346
18442
  for (const agent of agents) {
18347
- console.log(` \u{1F916} ${agent.name} (${agent.source})`);
18348
- console.log(` ${agent.description}`);
18443
+ lines.push(` \u{1F916} ${agent.name} (${agent.source})`);
18444
+ lines.push(` ${agent.description}`);
18349
18445
  if (agent.tools) {
18350
- console.log(` Tools: ${agent.tools.join(", ")}`);
18446
+ lines.push(` Tools: ${agent.tools.join(", ")}`);
18351
18447
  }
18352
18448
  if (agent.disallowedTools) {
18353
- console.log(` Disallowed: ${agent.disallowedTools.join(", ")}`);
18449
+ lines.push(` Disallowed: ${agent.disallowedTools.join(", ")}`);
18354
18450
  }
18355
18451
  if (agent.model) {
18356
- console.log(` Model: ${agent.model}`);
18452
+ lines.push(` Model: ${agent.model}`);
18357
18453
  }
18358
18454
  if (agent.forkContext) {
18359
- console.log(` Fork Context: ${agent.forkContext}`);
18455
+ lines.push(` Fork Context: ${agent.forkContext}`);
18360
18456
  }
18361
18457
  if (agent.color) {
18362
- console.log(` Color: ${agent.color}`);
18458
+ lines.push(` Color: ${agent.color}`);
18363
18459
  }
18364
- console.log("");
18460
+ lines.push("");
18365
18461
  }
18462
+ await this.output(sessionService, lines.join("\n").trimEnd());
18366
18463
  }
18367
18464
  /**
18368
18465
  * 委托任务给 Agent
18369
18466
  */
18370
- async delegateTask(agentName, goal) {
18467
+ async delegateTask(agentName, goal, sessionService) {
18371
18468
  if (!this.agentManager.has(agentName)) {
18372
- console.log(`\u274C Agent not found: ${agentName}`);
18373
- 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
+ );
18374
18474
  return;
18375
18475
  }
18376
18476
  try {
18377
- console.log(`
18378
- \u{1F916} Delegating task to ${agentName}...`);
18379
- console.log(` Goal: ${goal}
18380
- `);
18477
+ await this.output(sessionService, `\u{1F916} Delegating task to ${agentName}...
18478
+ Goal: ${goal}`);
18381
18479
  const result = await this.agentManager.delegate(
18382
18480
  {
18383
18481
  type: "custom",
@@ -18386,26 +18484,41 @@ var AgentCommand = class extends SlashCommand {
18386
18484
  agentName
18387
18485
  );
18388
18486
  if (result.success) {
18389
- console.log(`
18390
- \u2705 Task completed by ${agentName}`);
18487
+ let message = `\u2705 Task completed by ${agentName}`;
18391
18488
  if (result.message) {
18392
- console.log(` ${result.message}`);
18489
+ message += `
18490
+ ${result.message}`;
18393
18491
  }
18394
18492
  if (result.data) {
18395
- console.log(` Data: ${JSON.stringify(result.data, null, 2)}`);
18493
+ message += `
18494
+ Data: ${JSON.stringify(result.data, null, 2)}`;
18396
18495
  }
18496
+ await this.output(sessionService, message);
18397
18497
  } else {
18398
- console.log(`
18399
- \u274C Task failed`);
18498
+ let message = "\u274C Task failed";
18400
18499
  if (result.message) {
18401
- console.log(` ${result.message}`);
18500
+ message += `
18501
+ ${result.message}`;
18402
18502
  }
18503
+ await this.output(sessionService, message);
18403
18504
  }
18404
18505
  } catch (error) {
18405
- console.log(`
18406
- \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
+ );
18407
18510
  }
18408
18511
  }
18512
+ async output(sessionService, message) {
18513
+ if (sessionService) {
18514
+ await sessionService.addMessage({
18515
+ role: "assistant",
18516
+ content: message
18517
+ });
18518
+ return;
18519
+ }
18520
+ console.log(message);
18521
+ }
18409
18522
  };
18410
18523
 
18411
18524
  // src/commands/git/CommitCommand.ts
@@ -18422,53 +18535,83 @@ var CommitCommand = class extends SlashCommand {
18422
18535
  this.modelService = modelService;
18423
18536
  this.configManager = configManager;
18424
18537
  }
18425
- async execute(args) {
18538
+ async execute(args, app) {
18426
18539
  const options = this.parseOptions(args);
18540
+ const sessionService = app.getContainer().get("session");
18427
18541
  try {
18428
18542
  if (options.stage) {
18429
- console.log("\u{1F4E6} Staging all changes...");
18543
+ await this.output(sessionService, "\u{1F4E6} Staging all changes...");
18430
18544
  this.execCommand("git add -A");
18431
18545
  }
18432
- console.log("\u{1F50D} Analyzing changes...");
18546
+ await this.output(sessionService, "\u{1F50D} Analyzing changes...");
18433
18547
  const diff = await this.getDiff(true);
18434
18548
  if (!diff || diff.trim().length === 0) {
18435
- 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
+ );
18436
18553
  return;
18437
18554
  }
18438
18555
  let commitHistory = "";
18439
18556
  if (options.followStyle) {
18440
- console.log("\u{1F4DA} Learning commit style from history...");
18557
+ await this.output(sessionService, "\u{1F4DA} Learning commit style from history...");
18441
18558
  const history = await this.getCommitHistory(50);
18442
18559
  commitHistory = history.join("\n");
18443
18560
  }
18444
- console.log("\u{1F916} Generating commit message...");
18561
+ await this.output(sessionService, "\u{1F916} Generating commit message...");
18445
18562
  const commitMessage = await this.generateCommitMessage(diff, commitHistory, options);
18446
18563
  if (options.copy) {
18447
18564
  await this.copyToClipboard(commitMessage);
18448
- console.log("\u{1F4CB} Commit message copied to clipboard");
18449
- console.log("\n" + commitMessage);
18565
+ await this.output(
18566
+ sessionService,
18567
+ `\u{1F4CB} Commit message copied to clipboard
18568
+
18569
+ ${commitMessage}`
18570
+ );
18450
18571
  return;
18451
18572
  }
18452
- console.log("\n\u{1F4DD} Generated commit message:\n");
18453
- console.log(commitMessage);
18454
- console.log("");
18455
18573
  if (!options.commit) {
18456
- const confirmed = await this.confirmCommit();
18457
- if (!confirmed) {
18458
- console.log("\u274C Commit cancelled");
18459
- return;
18460
- }
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;
18461
18583
  }
18584
+ await this.output(
18585
+ sessionService,
18586
+ `\u{1F4DD} Generated commit message:
18587
+
18588
+ ${commitMessage}
18589
+
18590
+ \u{1F680} Creating commit...`
18591
+ );
18462
18592
  await this.executeCommit(commitMessage, options);
18463
- console.log("\u2705 Commit successful");
18593
+ await this.output(sessionService, "\u2705 Commit successful");
18464
18594
  if (options.push) {
18465
- console.log("\u{1F4E4} Pushing to remote...");
18595
+ await this.output(sessionService, "\u{1F4E4} Pushing to remote...");
18466
18596
  this.execCommand("git push");
18467
- console.log("\u2705 Push successful");
18597
+ await this.output(sessionService, "\u2705 Push successful");
18468
18598
  }
18469
18599
  } catch (error) {
18470
- 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;
18471
18613
  }
18614
+ console.log(message);
18472
18615
  }
18473
18616
  /**
18474
18617
  * 解析命令选项
@@ -18615,17 +18758,6 @@ Requirements:
18615
18758
 
18616
18759
  Output only the commit message, no explanations.`;
18617
18760
  }
18618
- /**
18619
- * 确认提交
18620
- */
18621
- async confirmCommit() {
18622
- console.log("Press Enter to commit, or Ctrl+C to cancel...");
18623
- return new Promise((resolve11) => {
18624
- process.stdin.once("data", () => {
18625
- resolve11(true);
18626
- });
18627
- });
18628
- }
18629
18761
  /**
18630
18762
  * 执行提交
18631
18763
  */
@@ -21106,6 +21238,18 @@ function useSession() {
21106
21238
  const { app, currentSession, setCurrentSession, setSessions } = useAppContext();
21107
21239
  const sessionService = app.getContainer().get("session");
21108
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
+ };
21109
21253
  useEffect(() => {
21110
21254
  const initSession = async () => {
21111
21255
  try {
@@ -21145,11 +21289,31 @@ function useSession() {
21145
21289
  const handleSessionLoaded = (data) => {
21146
21290
  setCurrentSession(data.session);
21147
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
+ };
21148
21304
  eventBus.on("session.created" /* SESSION_CREATED */, handleSessionCreated);
21149
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);
21150
21310
  return () => {
21151
21311
  eventBus.off("session.created" /* SESSION_CREATED */, handleSessionCreated);
21152
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);
21153
21317
  };
21154
21318
  }, [sessionService, eventBus, setCurrentSession, setSessions]);
21155
21319
  return {
@@ -21391,6 +21555,7 @@ var EnhancedMessageList = ({
21391
21555
 
21392
21556
  // src/ui/components/SimpleInput.tsx
21393
21557
  init_esm_shims();
21558
+ var MAX_VISIBLE_SUGGESTIONS = 8;
21394
21559
  var SimpleSuggestionEngine = class {
21395
21560
  commands = [
21396
21561
  "/help",
@@ -21463,6 +21628,7 @@ var SimpleInput = ({
21463
21628
  const [selectedIndex, setSelectedIndex] = useState(0);
21464
21629
  const [showSuggestions, setShowSuggestions] = useState(false);
21465
21630
  const suggestionEngine = useRef(new SimpleSuggestionEngine());
21631
+ const submittedValueRef = useRef(null);
21466
21632
  useEffect(() => {
21467
21633
  if (input.startsWith("/")) {
21468
21634
  const newSuggestions = suggestionEngine.current.getSuggestions(input);
@@ -21481,7 +21647,13 @@ var SimpleInput = ({
21481
21647
  } else if (key.downArrow) {
21482
21648
  setSelectedIndex((prev) => prev === suggestions.length - 1 ? 0 : prev + 1);
21483
21649
  } else if (key.return && suggestions[selectedIndex]) {
21484
- 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
+ }
21485
21657
  setShowSuggestions(false);
21486
21658
  } else if (key.escape) {
21487
21659
  setShowSuggestions(false);
@@ -21493,6 +21665,7 @@ var SimpleInput = ({
21493
21665
  const handleSubmit = useCallback(
21494
21666
  (value) => {
21495
21667
  if (!value.trim() || disabled) return;
21668
+ submittedValueRef.current = value;
21496
21669
  setInput("");
21497
21670
  setShowSuggestions(false);
21498
21671
  onSubmit(value);
@@ -21501,6 +21674,16 @@ var SimpleInput = ({
21501
21674
  );
21502
21675
  const promptSymbol = ">";
21503
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
+ ) : [];
21504
21687
  const getStatusIndicator = () => {
21505
21688
  switch (status) {
21506
21689
  case "thinking":
@@ -21513,7 +21696,7 @@ var SimpleInput = ({
21513
21696
  return "";
21514
21697
  }
21515
21698
  };
21516
- 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(
21517
21700
  TextInput,
21518
21701
  {
21519
21702
  value: input,
@@ -21521,21 +21704,22 @@ var SimpleInput = ({
21521
21704
  onSubmit: handleSubmit,
21522
21705
  placeholder
21523
21706
  }
21524
- ))), /* @__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(
21525
21708
  Text,
21526
21709
  {
21527
21710
  color: index === selectedIndex ? "cyan" : "gray",
21528
21711
  bold: index === selectedIndex
21529
21712
  },
21530
21713
  suggestion.text
21531
- )), /* @__PURE__ */ React.createElement(
21714
+ )), /* @__PURE__ */ React.createElement(Box, { flexGrow: 1 }, /* @__PURE__ */ React.createElement(
21532
21715
  Text,
21533
21716
  {
21534
21717
  color: index === selectedIndex ? "white" : "dim",
21535
- dimColor: index !== selectedIndex
21718
+ dimColor: index !== selectedIndex,
21719
+ wrap: "truncate-end"
21536
21720
  },
21537
21721
  suggestion.description
21538
- ))), /* @__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"))));
21539
21723
  };
21540
21724
 
21541
21725
  // src/ui/components/WelcomeScreen.tsx
@@ -22061,6 +22245,20 @@ function AppContent() {
22061
22245
  const [showResumeSelector, setShowResumeSelector] = useState(false);
22062
22246
  const [showMcpManager, setShowMcpManager] = useState(false);
22063
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]);
22064
22262
  const messagesRef = useRef([]);
22065
22263
  const [, forceUpdate] = useState({});
22066
22264
  const historyMessages = messagesRef.current;
@@ -22184,6 +22382,16 @@ function AppContent() {
22184
22382
  useInput(
22185
22383
  useCallback(
22186
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
+ }
22187
22395
  if (key.ctrl && input === "o") {
22188
22396
  clearTerminal();
22189
22397
  toggleTranscriptMode();
@@ -22191,7 +22399,7 @@ function AppContent() {
22191
22399
  return;
22192
22400
  }
22193
22401
  if (transcriptMode) {
22194
- if (key.escape || key.ctrl && input === "c") {
22402
+ if (key.escape) {
22195
22403
  clearTerminal();
22196
22404
  toggleTranscriptMode();
22197
22405
  refresh();
@@ -22202,7 +22410,17 @@ function AppContent() {
22202
22410
  return;
22203
22411
  }
22204
22412
  },
22205
- [transcriptMode, toggleTranscriptMode, refresh, showModelSelector]
22413
+ [
22414
+ transcriptMode,
22415
+ toggleTranscriptMode,
22416
+ refresh,
22417
+ showModelSelector,
22418
+ showRewindSelector,
22419
+ showResumeSelector,
22420
+ showMcpManager,
22421
+ showStatusManager,
22422
+ resetTransientUi
22423
+ ]
22206
22424
  )
22207
22425
  );
22208
22426
  const handleSubmit = useCallback(
@@ -22216,7 +22434,7 @@ function AppContent() {
22216
22434
  return;
22217
22435
  }
22218
22436
  if (value.trim().toLowerCase() === "exit" || value.trim().toLowerCase() === "quit") {
22219
- exit();
22437
+ await requestAppExit();
22220
22438
  return;
22221
22439
  }
22222
22440
  setTasks([]);
@@ -22256,7 +22474,7 @@ function AppContent() {
22256
22474
  setIsLoading(false);
22257
22475
  }
22258
22476
  },
22259
- [currentSession, app, sessionService, exit]
22477
+ [currentSession, app, sessionService, requestAppExit]
22260
22478
  );
22261
22479
  const handleModelSelect = useCallback(
22262
22480
  async (modelId) => {
@@ -22379,6 +22597,16 @@ function AppContent() {
22379
22597
  eventBus.off("show_model_selector", handleShowModelSelector);
22380
22598
  };
22381
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]);
22382
22610
  useEffect(() => {
22383
22611
  const eventBus = app.getContainer().get("eventBus");
22384
22612
  const handleShowRewindSelector = () => {
@@ -22746,7 +22974,9 @@ program.command("chat", { isDefault: true }).description("Start interactive chat
22746
22974
  await sessionService.initialize();
22747
22975
  console.log("\u2705 SessionService initialized");
22748
22976
  console.log("\n\u{1F3A8} Starting interactive UI...\n");
22749
- render(React.createElement(App, { app }));
22977
+ const inkApp = render(React.createElement(App, { app }));
22978
+ await inkApp.waitUntilExit();
22979
+ process.exit(0);
22750
22980
  } catch (error) {
22751
22981
  console.error("\u274C Fatal error:", error);
22752
22982
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codemate-ai",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "type": "module",
5
5
  "description": "Enterprise-grade AI coding assistant CLI",
6
6
  "main": "dist/cli.js",