@robota-sdk/agent-cli 3.0.0-beta.1 → 3.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/node/bin.cjs CHANGED
@@ -625,7 +625,7 @@ function InputArea({ onSubmit, isDisabled, registry }) {
625
625
  var import_react4 = __toESM(require("react"), 1);
626
626
  var import_ink7 = require("ink");
627
627
  var import_jsx_runtime7 = require("react/jsx-runtime");
628
- var OPTIONS = ["Allow", "Deny"];
628
+ var OPTIONS = ["Allow", "Allow always (this session)", "Deny"];
629
629
  function formatArgs2(args) {
630
630
  const entries = Object.entries(args);
631
631
  if (entries.length === 0) return "(no arguments)";
@@ -641,10 +641,12 @@ function PermissionPrompt({ request }) {
641
641
  setSelected(0);
642
642
  }
643
643
  const doResolve = import_react4.default.useCallback(
644
- (allowed) => {
644
+ (index) => {
645
645
  if (resolvedRef.current) return;
646
646
  resolvedRef.current = true;
647
- request.resolve(allowed);
647
+ if (index === 0) request.resolve(true);
648
+ else if (index === 1) request.resolve("allow-session");
649
+ else request.resolve(false);
648
650
  },
649
651
  [request]
650
652
  );
@@ -655,11 +657,13 @@ function PermissionPrompt({ request }) {
655
657
  } else if (key.downArrow || key.rightArrow) {
656
658
  setSelected((prev) => prev < OPTIONS.length - 1 ? prev + 1 : prev);
657
659
  } else if (key.return) {
658
- doResolve(selected === 0);
659
- } else if (input === "y" || input === "a" || input === "1") {
660
- doResolve(true);
661
- } else if (input === "n" || input === "d" || input === "2") {
662
- doResolve(false);
660
+ doResolve(selected);
661
+ } else if (input === "y" || input === "1") {
662
+ doResolve(0);
663
+ } else if (input === "a" || input === "2") {
664
+ doResolve(1);
665
+ } else if (input === "n" || input === "d" || input === "3") {
666
+ doResolve(2);
663
667
  }
664
668
  });
665
669
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
@@ -719,11 +723,11 @@ function useSession(props) {
719
723
  setPermissionRequest({
720
724
  toolName: next.toolName,
721
725
  toolArgs: next.toolArgs,
722
- resolve: (allowed) => {
726
+ resolve: (result) => {
723
727
  permissionQueueRef.current.shift();
724
728
  processingRef.current = false;
725
729
  setPermissionRequest(null);
726
- next.resolve(allowed);
730
+ next.resolve(result);
727
731
  setTimeout(() => processNextPermission(), 0);
728
732
  }
729
733
  });
@@ -739,10 +743,12 @@ function useSession(props) {
739
743
  const onTextDelta = (delta) => {
740
744
  setStreamingText((prev) => prev + delta);
741
745
  };
746
+ const paths = (0, import_agent_sdk.projectPaths)(props.cwd ?? process.cwd());
742
747
  sessionRef.current = new import_agent_sdk.Session({
743
748
  config: props.config,
744
749
  context: props.context,
745
750
  terminal: NOOP_TERMINAL,
751
+ sessionLogger: new import_agent_sdk.FileSessionLogger(paths.logs),
746
752
  projectInfo: props.projectInfo,
747
753
  sessionStore: props.sessionStore,
748
754
  permissionMode: props.permissionMode,
@@ -813,6 +819,26 @@ async function executeSlashCommand(cmd, parts, session, addMessage, setMessages,
813
819
  Messages: ${session.getMessageCount()}`
814
820
  });
815
821
  return true;
822
+ case "permissions": {
823
+ const mode = session.getPermissionMode();
824
+ const sessionAllowed = session.getSessionAllowedTools();
825
+ const lines = [`Permission mode: ${mode}`];
826
+ if (sessionAllowed.length > 0) {
827
+ lines.push(`Session-approved tools: ${sessionAllowed.join(", ")}`);
828
+ } else {
829
+ lines.push("No session-approved tools.");
830
+ }
831
+ addMessage({ role: "system", content: lines.join("\n") });
832
+ return true;
833
+ }
834
+ case "context": {
835
+ const ctx = session.getContextState();
836
+ addMessage({
837
+ role: "system",
838
+ content: `Context: ${ctx.usedTokens.toLocaleString()} / ${ctx.maxTokens.toLocaleString()} tokens (${Math.round(ctx.usedPercentage)}%)`
839
+ });
840
+ return true;
841
+ }
816
842
  case "exit":
817
843
  exit();
818
844
  return true;
@@ -860,8 +886,12 @@ async function runSessionPrompt(prompt, session, addMessage, clearStreamingText,
860
886
  setContextPercentage(session.getContextState().usedPercentage);
861
887
  } catch (err) {
862
888
  clearStreamingText();
863
- const errMsg = err instanceof Error ? err.message : String(err);
864
- addMessage({ role: "system", content: `Error: ${errMsg}` });
889
+ if (err instanceof DOMException && err.name === "AbortError") {
890
+ addMessage({ role: "system", content: "Cancelled." });
891
+ } else {
892
+ const errMsg = err instanceof Error ? err.message : String(err);
893
+ addMessage({ role: "system", content: `Error: ${errMsg}` });
894
+ }
865
895
  } finally {
866
896
  setIsThinking(false);
867
897
  }
@@ -945,8 +975,9 @@ function App(props) {
945
975
  (0, import_ink8.useInput)(
946
976
  (_input, key) => {
947
977
  if (key.ctrl && _input === "c") exit();
978
+ if (key.escape && isThinking) session.abort();
948
979
  },
949
- { isActive: !permissionRequest && !isThinking }
980
+ { isActive: !permissionRequest }
950
981
  );
951
982
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Box, { flexDirection: "column", children: [
952
983
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
@@ -1153,10 +1184,12 @@ async function startCli() {
1153
1184
  process.exit(1);
1154
1185
  }
1155
1186
  const terminal = new PrintTerminal();
1187
+ const paths = (0, import_agent_sdk2.projectPaths)(cwd);
1156
1188
  const session = new import_agent_sdk2.Session({
1157
1189
  config,
1158
1190
  context,
1159
1191
  terminal,
1192
+ sessionLogger: new import_agent_sdk2.FileSessionLogger(paths.logs),
1160
1193
  projectInfo,
1161
1194
  permissionMode: args.permissionMode,
1162
1195
  systemPromptBuilder: import_agent_sdk2.buildSystemPrompt,
package/dist/node/bin.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  startCli
4
- } from "./chunk-C56WFH5S.js";
4
+ } from "./chunk-MO7RIZFR.js";
5
5
 
6
6
  // src/bin.ts
7
7
  startCli().catch((err) => {
@@ -10,7 +10,9 @@ import {
10
10
  detectProject,
11
11
  Session as Session2,
12
12
  SessionStore,
13
- buildSystemPrompt
13
+ FileSessionLogger as FileSessionLogger2,
14
+ buildSystemPrompt,
15
+ projectPaths as projectPaths2
14
16
  } from "@robota-sdk/agent-sdk";
15
17
 
16
18
  // src/permissions/permission-prompt.ts
@@ -39,7 +41,7 @@ import { render } from "ink";
39
41
  // src/ui/App.tsx
40
42
  import { useState as useState4, useCallback as useCallback2, useRef as useRef2 } from "react";
41
43
  import { Box as Box6, Text as Text8, useApp, useInput as useInput4 } from "ink";
42
- import { Session } from "@robota-sdk/agent-sdk";
44
+ import { Session, FileSessionLogger, projectPaths } from "@robota-sdk/agent-sdk";
43
45
 
44
46
  // src/commands/command-registry.ts
45
47
  var CommandRegistry = class {
@@ -607,7 +609,7 @@ function InputArea({ onSubmit, isDisabled, registry }) {
607
609
  import React4 from "react";
608
610
  import { Box as Box5, Text as Text7, useInput as useInput3 } from "ink";
609
611
  import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
610
- var OPTIONS = ["Allow", "Deny"];
612
+ var OPTIONS = ["Allow", "Allow always (this session)", "Deny"];
611
613
  function formatArgs2(args) {
612
614
  const entries = Object.entries(args);
613
615
  if (entries.length === 0) return "(no arguments)";
@@ -623,10 +625,12 @@ function PermissionPrompt({ request }) {
623
625
  setSelected(0);
624
626
  }
625
627
  const doResolve = React4.useCallback(
626
- (allowed) => {
628
+ (index) => {
627
629
  if (resolvedRef.current) return;
628
630
  resolvedRef.current = true;
629
- request.resolve(allowed);
631
+ if (index === 0) request.resolve(true);
632
+ else if (index === 1) request.resolve("allow-session");
633
+ else request.resolve(false);
630
634
  },
631
635
  [request]
632
636
  );
@@ -637,11 +641,13 @@ function PermissionPrompt({ request }) {
637
641
  } else if (key.downArrow || key.rightArrow) {
638
642
  setSelected((prev) => prev < OPTIONS.length - 1 ? prev + 1 : prev);
639
643
  } else if (key.return) {
640
- doResolve(selected === 0);
641
- } else if (input === "y" || input === "a" || input === "1") {
642
- doResolve(true);
643
- } else if (input === "n" || input === "d" || input === "2") {
644
- doResolve(false);
644
+ doResolve(selected);
645
+ } else if (input === "y" || input === "1") {
646
+ doResolve(0);
647
+ } else if (input === "a" || input === "2") {
648
+ doResolve(1);
649
+ } else if (input === "n" || input === "d" || input === "3") {
650
+ doResolve(2);
645
651
  }
646
652
  });
647
653
  return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
@@ -701,11 +707,11 @@ function useSession(props) {
701
707
  setPermissionRequest({
702
708
  toolName: next.toolName,
703
709
  toolArgs: next.toolArgs,
704
- resolve: (allowed) => {
710
+ resolve: (result) => {
705
711
  permissionQueueRef.current.shift();
706
712
  processingRef.current = false;
707
713
  setPermissionRequest(null);
708
- next.resolve(allowed);
714
+ next.resolve(result);
709
715
  setTimeout(() => processNextPermission(), 0);
710
716
  }
711
717
  });
@@ -721,10 +727,12 @@ function useSession(props) {
721
727
  const onTextDelta = (delta) => {
722
728
  setStreamingText((prev) => prev + delta);
723
729
  };
730
+ const paths = projectPaths(props.cwd ?? process.cwd());
724
731
  sessionRef.current = new Session({
725
732
  config: props.config,
726
733
  context: props.context,
727
734
  terminal: NOOP_TERMINAL,
735
+ sessionLogger: new FileSessionLogger(paths.logs),
728
736
  projectInfo: props.projectInfo,
729
737
  sessionStore: props.sessionStore,
730
738
  permissionMode: props.permissionMode,
@@ -795,6 +803,26 @@ async function executeSlashCommand(cmd, parts, session, addMessage, setMessages,
795
803
  Messages: ${session.getMessageCount()}`
796
804
  });
797
805
  return true;
806
+ case "permissions": {
807
+ const mode = session.getPermissionMode();
808
+ const sessionAllowed = session.getSessionAllowedTools();
809
+ const lines = [`Permission mode: ${mode}`];
810
+ if (sessionAllowed.length > 0) {
811
+ lines.push(`Session-approved tools: ${sessionAllowed.join(", ")}`);
812
+ } else {
813
+ lines.push("No session-approved tools.");
814
+ }
815
+ addMessage({ role: "system", content: lines.join("\n") });
816
+ return true;
817
+ }
818
+ case "context": {
819
+ const ctx = session.getContextState();
820
+ addMessage({
821
+ role: "system",
822
+ content: `Context: ${ctx.usedTokens.toLocaleString()} / ${ctx.maxTokens.toLocaleString()} tokens (${Math.round(ctx.usedPercentage)}%)`
823
+ });
824
+ return true;
825
+ }
798
826
  case "exit":
799
827
  exit();
800
828
  return true;
@@ -842,8 +870,12 @@ async function runSessionPrompt(prompt, session, addMessage, clearStreamingText,
842
870
  setContextPercentage(session.getContextState().usedPercentage);
843
871
  } catch (err) {
844
872
  clearStreamingText();
845
- const errMsg = err instanceof Error ? err.message : String(err);
846
- addMessage({ role: "system", content: `Error: ${errMsg}` });
873
+ if (err instanceof DOMException && err.name === "AbortError") {
874
+ addMessage({ role: "system", content: "Cancelled." });
875
+ } else {
876
+ const errMsg = err instanceof Error ? err.message : String(err);
877
+ addMessage({ role: "system", content: `Error: ${errMsg}` });
878
+ }
847
879
  } finally {
848
880
  setIsThinking(false);
849
881
  }
@@ -927,8 +959,9 @@ function App(props) {
927
959
  useInput4(
928
960
  (_input, key) => {
929
961
  if (key.ctrl && _input === "c") exit();
962
+ if (key.escape && isThinking) session.abort();
930
963
  },
931
- { isActive: !permissionRequest && !isThinking }
964
+ { isActive: !permissionRequest }
932
965
  );
933
966
  return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
934
967
  /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
@@ -1134,10 +1167,12 @@ async function startCli() {
1134
1167
  process.exit(1);
1135
1168
  }
1136
1169
  const terminal = new PrintTerminal();
1170
+ const paths = projectPaths2(cwd);
1137
1171
  const session = new Session2({
1138
1172
  config,
1139
1173
  context,
1140
1174
  terminal,
1175
+ sessionLogger: new FileSessionLogger2(paths.logs),
1141
1176
  projectInfo,
1142
1177
  permissionMode: args.permissionMode,
1143
1178
  systemPromptBuilder: buildSystemPrompt,
@@ -641,7 +641,7 @@ function InputArea({ onSubmit, isDisabled, registry }) {
641
641
  var import_react4 = __toESM(require("react"), 1);
642
642
  var import_ink7 = require("ink");
643
643
  var import_jsx_runtime7 = require("react/jsx-runtime");
644
- var OPTIONS = ["Allow", "Deny"];
644
+ var OPTIONS = ["Allow", "Allow always (this session)", "Deny"];
645
645
  function formatArgs2(args) {
646
646
  const entries = Object.entries(args);
647
647
  if (entries.length === 0) return "(no arguments)";
@@ -657,10 +657,12 @@ function PermissionPrompt({ request }) {
657
657
  setSelected(0);
658
658
  }
659
659
  const doResolve = import_react4.default.useCallback(
660
- (allowed) => {
660
+ (index) => {
661
661
  if (resolvedRef.current) return;
662
662
  resolvedRef.current = true;
663
- request.resolve(allowed);
663
+ if (index === 0) request.resolve(true);
664
+ else if (index === 1) request.resolve("allow-session");
665
+ else request.resolve(false);
664
666
  },
665
667
  [request]
666
668
  );
@@ -671,11 +673,13 @@ function PermissionPrompt({ request }) {
671
673
  } else if (key.downArrow || key.rightArrow) {
672
674
  setSelected((prev) => prev < OPTIONS.length - 1 ? prev + 1 : prev);
673
675
  } else if (key.return) {
674
- doResolve(selected === 0);
675
- } else if (input === "y" || input === "a" || input === "1") {
676
- doResolve(true);
677
- } else if (input === "n" || input === "d" || input === "2") {
678
- doResolve(false);
676
+ doResolve(selected);
677
+ } else if (input === "y" || input === "1") {
678
+ doResolve(0);
679
+ } else if (input === "a" || input === "2") {
680
+ doResolve(1);
681
+ } else if (input === "n" || input === "d" || input === "3") {
682
+ doResolve(2);
679
683
  }
680
684
  });
681
685
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
@@ -735,11 +739,11 @@ function useSession(props) {
735
739
  setPermissionRequest({
736
740
  toolName: next.toolName,
737
741
  toolArgs: next.toolArgs,
738
- resolve: (allowed) => {
742
+ resolve: (result) => {
739
743
  permissionQueueRef.current.shift();
740
744
  processingRef.current = false;
741
745
  setPermissionRequest(null);
742
- next.resolve(allowed);
746
+ next.resolve(result);
743
747
  setTimeout(() => processNextPermission(), 0);
744
748
  }
745
749
  });
@@ -755,10 +759,12 @@ function useSession(props) {
755
759
  const onTextDelta = (delta) => {
756
760
  setStreamingText((prev) => prev + delta);
757
761
  };
762
+ const paths = (0, import_agent_sdk.projectPaths)(props.cwd ?? process.cwd());
758
763
  sessionRef.current = new import_agent_sdk.Session({
759
764
  config: props.config,
760
765
  context: props.context,
761
766
  terminal: NOOP_TERMINAL,
767
+ sessionLogger: new import_agent_sdk.FileSessionLogger(paths.logs),
762
768
  projectInfo: props.projectInfo,
763
769
  sessionStore: props.sessionStore,
764
770
  permissionMode: props.permissionMode,
@@ -829,6 +835,26 @@ async function executeSlashCommand(cmd, parts, session, addMessage, setMessages,
829
835
  Messages: ${session.getMessageCount()}`
830
836
  });
831
837
  return true;
838
+ case "permissions": {
839
+ const mode = session.getPermissionMode();
840
+ const sessionAllowed = session.getSessionAllowedTools();
841
+ const lines = [`Permission mode: ${mode}`];
842
+ if (sessionAllowed.length > 0) {
843
+ lines.push(`Session-approved tools: ${sessionAllowed.join(", ")}`);
844
+ } else {
845
+ lines.push("No session-approved tools.");
846
+ }
847
+ addMessage({ role: "system", content: lines.join("\n") });
848
+ return true;
849
+ }
850
+ case "context": {
851
+ const ctx = session.getContextState();
852
+ addMessage({
853
+ role: "system",
854
+ content: `Context: ${ctx.usedTokens.toLocaleString()} / ${ctx.maxTokens.toLocaleString()} tokens (${Math.round(ctx.usedPercentage)}%)`
855
+ });
856
+ return true;
857
+ }
832
858
  case "exit":
833
859
  exit();
834
860
  return true;
@@ -876,8 +902,12 @@ async function runSessionPrompt(prompt, session, addMessage, clearStreamingText,
876
902
  setContextPercentage(session.getContextState().usedPercentage);
877
903
  } catch (err) {
878
904
  clearStreamingText();
879
- const errMsg = err instanceof Error ? err.message : String(err);
880
- addMessage({ role: "system", content: `Error: ${errMsg}` });
905
+ if (err instanceof DOMException && err.name === "AbortError") {
906
+ addMessage({ role: "system", content: "Cancelled." });
907
+ } else {
908
+ const errMsg = err instanceof Error ? err.message : String(err);
909
+ addMessage({ role: "system", content: `Error: ${errMsg}` });
910
+ }
881
911
  } finally {
882
912
  setIsThinking(false);
883
913
  }
@@ -961,8 +991,9 @@ function App(props) {
961
991
  (0, import_ink8.useInput)(
962
992
  (_input, key) => {
963
993
  if (key.ctrl && _input === "c") exit();
994
+ if (key.escape && isThinking) session.abort();
964
995
  },
965
- { isActive: !permissionRequest && !isThinking }
996
+ { isActive: !permissionRequest }
966
997
  );
967
998
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Box, { flexDirection: "column", children: [
968
999
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink8.Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
@@ -1169,10 +1200,12 @@ async function startCli() {
1169
1200
  process.exit(1);
1170
1201
  }
1171
1202
  const terminal = new PrintTerminal();
1203
+ const paths = (0, import_agent_sdk2.projectPaths)(cwd);
1172
1204
  const session = new import_agent_sdk2.Session({
1173
1205
  config,
1174
1206
  context,
1175
1207
  terminal,
1208
+ sessionLogger: new import_agent_sdk2.FileSessionLogger(paths.logs),
1176
1209
  projectInfo,
1177
1210
  permissionMode: args.permissionMode,
1178
1211
  systemPromptBuilder: import_agent_sdk2.buildSystemPrompt,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  startCli
3
- } from "./chunk-C56WFH5S.js";
3
+ } from "./chunk-MO7RIZFR.js";
4
4
 
5
5
  // src/index.ts
6
6
  import { Session, SessionStore, query, TRUST_TO_MODE } from "@robota-sdk/agent-sdk";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robota-sdk/agent-cli",
3
- "version": "3.0.0-beta.1",
3
+ "version": "3.0.0-beta.3",
4
4
  "description": "AI coding assistant CLI built on Robota SDK",
5
5
  "type": "module",
6
6
  "bin": {
@@ -35,8 +35,8 @@
35
35
  "marked-terminal": "^7.3.0",
36
36
  "react": "19.2.4",
37
37
  "string-width": "^8.2.0",
38
- "@robota-sdk/agent-core": "3.0.0-beta.1",
39
- "@robota-sdk/agent-sdk": "3.0.0-beta.1"
38
+ "@robota-sdk/agent-core": "3.0.0-beta.3",
39
+ "@robota-sdk/agent-sdk": "3.0.0-beta.3"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/marked": "^6.0.0",