@dexto/tui 1.13.5 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/dist/agent-backend.cjs +2 -0
  2. package/dist/agent-backend.d.ts +2 -0
  3. package/dist/agent-backend.d.ts.map +1 -1
  4. package/dist/agent-backend.js +2 -0
  5. package/dist/components/ApprovalPrompt.cjs +19 -17
  6. package/dist/components/ApprovalPrompt.d.ts +2 -1
  7. package/dist/components/ApprovalPrompt.d.ts.map +1 -1
  8. package/dist/components/ApprovalPrompt.js +19 -17
  9. package/dist/components/ApprovalPrompt.test.cjs +119 -0
  10. package/dist/components/ApprovalPrompt.test.d.ts +2 -0
  11. package/dist/components/ApprovalPrompt.test.d.ts.map +1 -0
  12. package/dist/components/ApprovalPrompt.test.js +120 -0
  13. package/dist/components/Footer.cjs +5 -1
  14. package/dist/components/Footer.d.ts.map +1 -1
  15. package/dist/components/Footer.js +5 -1
  16. package/dist/components/Footer.test.cjs +47 -0
  17. package/dist/components/Footer.test.d.ts +2 -0
  18. package/dist/components/Footer.test.d.ts.map +1 -0
  19. package/dist/components/Footer.test.js +46 -0
  20. package/dist/components/modes/AlternateBufferCLI.cjs +3 -1
  21. package/dist/components/modes/AlternateBufferCLI.d.ts.map +1 -1
  22. package/dist/components/modes/AlternateBufferCLI.js +3 -1
  23. package/dist/components/modes/StaticCLI.cjs +3 -1
  24. package/dist/components/modes/StaticCLI.d.ts.map +1 -1
  25. package/dist/components/modes/StaticCLI.js +3 -1
  26. package/dist/components/overlays/PermissionsSelector.cjs +139 -0
  27. package/dist/components/overlays/PermissionsSelector.d.ts +16 -0
  28. package/dist/components/overlays/PermissionsSelector.d.ts.map +1 -0
  29. package/dist/components/overlays/PermissionsSelector.js +115 -0
  30. package/dist/components/overlays/PermissionsSelector.test.cjs +105 -0
  31. package/dist/components/overlays/PermissionsSelector.test.d.ts +2 -0
  32. package/dist/components/overlays/PermissionsSelector.test.d.ts.map +1 -0
  33. package/dist/components/overlays/PermissionsSelector.test.js +104 -0
  34. package/dist/containers/InputContainer.cjs +108 -28
  35. package/dist/containers/InputContainer.d.ts +1 -0
  36. package/dist/containers/InputContainer.d.ts.map +1 -1
  37. package/dist/containers/InputContainer.js +108 -28
  38. package/dist/containers/OverlayContainer.cjs +15 -0
  39. package/dist/containers/OverlayContainer.d.ts.map +1 -1
  40. package/dist/containers/OverlayContainer.js +17 -0
  41. package/dist/hooks/useAgentEvents.cjs +6 -3
  42. package/dist/hooks/useAgentEvents.d.ts.map +1 -1
  43. package/dist/hooks/useAgentEvents.js +6 -3
  44. package/dist/hooks/useCLIState.cjs +28 -8
  45. package/dist/hooks/useCLIState.d.ts +1 -0
  46. package/dist/hooks/useCLIState.d.ts.map +1 -1
  47. package/dist/hooks/useCLIState.js +28 -8
  48. package/dist/hooks/useCLIState.test.cjs +583 -0
  49. package/dist/hooks/useCLIState.test.d.ts +2 -0
  50. package/dist/hooks/useCLIState.test.d.ts.map +1 -0
  51. package/dist/hooks/useCLIState.test.js +582 -0
  52. package/dist/index.d.cts +2 -0
  53. package/dist/interactive-commands/commands.test.cjs +6 -0
  54. package/dist/interactive-commands/commands.test.js +6 -0
  55. package/dist/interactive-commands/tool-commands.cjs +7 -0
  56. package/dist/interactive-commands/tool-commands.d.ts.map +1 -1
  57. package/dist/interactive-commands/tool-commands.js +7 -0
  58. package/dist/services/processStream.cjs +4 -2
  59. package/dist/services/processStream.d.ts.map +1 -1
  60. package/dist/services/processStream.js +4 -2
  61. package/dist/services/processStream.test.cjs +63 -0
  62. package/dist/services/processStream.test.js +63 -0
  63. package/dist/state/types.d.ts +1 -1
  64. package/dist/state/types.d.ts.map +1 -1
  65. package/dist/utils/approvalScope.cjs +35 -0
  66. package/dist/utils/approvalScope.d.ts +3 -0
  67. package/dist/utils/approvalScope.d.ts.map +1 -0
  68. package/dist/utils/approvalScope.js +11 -0
  69. package/dist/utils/commandOverlays.cjs +1 -0
  70. package/dist/utils/commandOverlays.d.ts.map +1 -1
  71. package/dist/utils/commandOverlays.js +1 -0
  72. package/package.json +5 -5
@@ -75,6 +75,8 @@ function getTuiCapabilities(agent) {
75
75
  }
76
76
  function isCommandSupported(agent, command, definition) {
77
77
  const capabilities = getTuiCapabilities(agent);
78
+ if (normalizeCommandName(command) === "permissions" && (!agent.getSessionApprovals || !agent.revokeSessionApproval))
79
+ return false;
78
80
  const supportedCommands = capabilities.supportedCommands;
79
81
  const candidates = /* @__PURE__ */ new Set([normalizeCommandName(command)]);
80
82
  if (definition?.name) {
@@ -35,6 +35,8 @@ export interface TuiEffectiveConfig {
35
35
  [key: string]: unknown;
36
36
  }
37
37
  export interface TuiAgentBackend extends Pick<DextoAgent, 'stream' | 'stop' | 'run' | 'listSessions' | 'getSessionMetadata' | 'getSessionHistory' | 'getSessionTitle' | 'setSessionTitle' | 'generateSessionTitle' | 'forkSession' | 'getCurrentLLMConfig' | 'hasSessionLLMOverride' | 'switchLLM' | 'getSupportedProviders' | 'getSupportedModels' | 'getContextStats' | 'clearContext' | 'compactContext' | 'steer' | 'followUp' | 'getSteerMessages' | 'getFollowUpMessages' | 'removeSteerMessage' | 'removeFollowUpMessage' | 'clearSteerQueue' | 'clearFollowUpQueue' | 'cancel' | 'searchMessages' | 'listPrompts' | 'refreshPrompts' | 'resolvePrompt' | 'getSystemPrompt' | 'loadToolkits' | 'listResources' | 'setLogLevel' | 'getAllTools' | 'getEnabledTools' | 'getAllMcpTools' | 'setGlobalDisabledTools' | 'setSessionDisabledTools' | 'setSessionAutoApproveTools' | 'getSessionAutoApproveTools' | 'getMcpServersWithStatus' | 'addMcpServer' | 'enableMcpServer' | 'disableMcpServer' | 'removeMcpServer' | 'restartMcpServer' | 'getMcpClients' | 'getMcpFailedConnections'> {
38
+ getSessionApprovals?: DextoAgent['getSessionApprovals'];
39
+ revokeSessionApproval?: DextoAgent['revokeSessionApproval'];
38
40
  createSession: (sessionId?: string) => Promise<{
39
41
  id: string;
40
42
  logger: Pick<RootLogger, 'getLevel' | 'getLogFilePath'>;
@@ -1 +1 @@
1
- {"version":3,"file":"agent-backend.d.ts","sourceRoot":"","sources":["../src/agent-backend.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-backend.d.ts","sourceRoot":"","sources":["../src/agent-backend.ts"],"names":[],"mappings":"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"}
@@ -43,6 +43,8 @@ function getTuiCapabilities(agent) {
43
43
  }
44
44
  function isCommandSupported(agent, command, definition) {
45
45
  const capabilities = getTuiCapabilities(agent);
46
+ if (normalizeCommandName(command) === "permissions" && (!agent.getSessionApprovals || !agent.revokeSessionApproval))
47
+ return false;
46
48
  const supportedCommands = capabilities.supportedCommands;
47
49
  const candidates = /* @__PURE__ */ new Set([normalizeCommandName(command)]);
48
50
  if (definition?.name) {
@@ -28,6 +28,7 @@ var import_core = require("@dexto/core");
28
28
  var import_ElicitationForm = require("./ElicitationForm.js");
29
29
  var import_renderers = require("./renderers/index.js");
30
30
  var import_toolUtils = require("../utils/toolUtils.js");
31
+ var import_approvalScope = require("../utils/approvalScope.js");
31
32
  var import_messageFormatting = require("../utils/messageFormatting.js");
32
33
  const ApprovalPrompt = (0, import_react.forwardRef)(
33
34
  ({ approval, onApprove, onDeny, onCancel }, ref) => {
@@ -36,7 +37,10 @@ const ApprovalPrompt = (0, import_react.forwardRef)(
36
37
  const toolName = approval.metadata.toolName;
37
38
  const toolArgs = approval.metadata.args || {};
38
39
  const approvalKey = typeof approval.metadata.approvalKey === "string" ? approval.metadata.approvalKey : void 0;
39
- const hasApprovalKey = approvalKey !== void 0;
40
+ const canRemember = approval.type === import_core.ApprovalType.TOOL_APPROVAL && approval.sessionId !== void 0 && approval.autoApproval !== "disallowed";
41
+ const rememberedScope = (0, import_approvalScope.formatApprovalScope)(
42
+ approvalKey !== void 0 ? { kind: "action", value: approvalKey } : { kind: "tool", value: toolName ?? "unknown" }
43
+ );
40
44
  const callDescriptionRaw = typeof approval.metadata.description === "string" ? approval.metadata.description : void 0;
41
45
  const callDescription = (0, import_react.useMemo)(() => {
42
46
  if (!callDescriptionRaw) return null;
@@ -48,6 +52,7 @@ const ApprovalPrompt = (0, import_react.forwardRef)(
48
52
  }, [callDescriptionRaw]);
49
53
  const isPlanReview = toolName === "plan_review";
50
54
  const isEditOrWriteTool = (0, import_toolUtils.isEditWriteTool)(toolName);
55
+ const canAcceptEdits = canRemember && isEditOrWriteTool && approvalKey === void 0;
51
56
  const presentationSnapshot = (0, import_react.useMemo)(() => {
52
57
  const raw = approval.metadata["presentationSnapshot"];
53
58
  return (0, import_core.isToolPresentationSnapshotV1)(raw) ? raw : void 0;
@@ -69,21 +74,18 @@ const ApprovalPrompt = (0, import_react.forwardRef)(
69
74
  if (isPlanReview) {
70
75
  options.push({ id: "plan-approve", label: "Approve" });
71
76
  options.push({ id: "plan-approve-accept-edits", label: "Approve + Accept All Edits" });
72
- } else if (isCommandApproval) {
73
- options.push({ id: "yes", label: "Yes" });
74
- options.push({ id: "no", label: "No" });
75
- } else if (hasApprovalKey) {
76
- options.push({ id: "yes", label: "Yes (once)" });
77
- options.push({ id: "yes-session", label: "Yes, remember this approval" });
78
- options.push({ id: "no", label: "No" });
79
- } else if (isEditOrWriteTool) {
80
- options.push({ id: "yes", label: "Yes" });
81
- options.push({ id: "yes-accept-edits", label: "Yes, and accept all edits" });
82
- options.push({ id: "no", label: "No" });
83
77
  } else {
84
- options.push({ id: "yes", label: "Yes" });
85
- options.push({ id: "yes-session", label: "Yes (Session)" });
86
- options.push({ id: "no", label: "No" });
78
+ options.push({ id: "yes", label: "Allow once" });
79
+ if (canRemember) {
80
+ options.push({
81
+ id: "yes-session",
82
+ label: `Allow ${rememberedScope} for this session`
83
+ });
84
+ }
85
+ if (canAcceptEdits) {
86
+ options.push({ id: "yes-accept-edits", label: "Allow all edits for this session" });
87
+ }
88
+ options.push({ id: "no", label: "Reject" });
87
89
  }
88
90
  (0, import_react.useEffect)(() => {
89
91
  selectedIndexRef.current = selectedIndex;
@@ -147,7 +149,7 @@ const ApprovalPrompt = (0, import_react.forwardRef)(
147
149
  onDeny();
148
150
  }
149
151
  return true;
150
- } else if (key.shift && key.tab && isEditOrWriteTool) {
152
+ } else if (key.shift && key.tab && canAcceptEdits) {
151
153
  onApprove({ enableAcceptEditsMode: true });
152
154
  return true;
153
155
  } else if (key.escape) {
@@ -159,7 +161,7 @@ const ApprovalPrompt = (0, import_react.forwardRef)(
159
161
  }),
160
162
  [
161
163
  isElicitation,
162
- isEditOrWriteTool,
164
+ canAcceptEdits,
163
165
  isPlanReview,
164
166
  options,
165
167
  onApprove,
@@ -1,8 +1,9 @@
1
1
  import React from 'react';
2
- import type { HostRuntimeContext } from '@dexto/core';
2
+ import type { HostRuntimeContext, ApprovalAutoApprovalPolicy } from '@dexto/core';
3
3
  import type { Key } from '../hooks/useInputOrchestrator.js';
4
4
  export interface ApprovalRequest {
5
5
  approvalId: string;
6
+ autoApproval?: ApprovalAutoApprovalPolicy;
6
7
  type: string;
7
8
  sessionId?: string;
8
9
  hostRuntime?: HostRuntimeContext;
@@ -1 +1 @@
1
- {"version":3,"file":"ApprovalPrompt.d.ts","sourceRoot":"","sources":["../../src/components/ApprovalPrompt.tsx"],"names":[],"mappings":"AAAA,OAAO,KAON,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,kBAAkB,EAAwC,MAAM,aAAa,CAAC;AAE5F,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kCAAkC,CAAC;AAM5D,MAAM,WAAW,eAAe;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,IAAI,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,oBAAoB;IACjC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrD;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC5B,mDAAmD;IACnD,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,gFAAgF;IAChF,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACnC;AAED,UAAU,mBAAmB;IACzB,QAAQ,EAAE,eAAe,CAAC;IAC1B,SAAS,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAC9C,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACxB;AAYD;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,kGAmY1B,CAAC"}
1
+ {"version":3,"file":"ApprovalPrompt.d.ts","sourceRoot":"","sources":["../../src/components/ApprovalPrompt.tsx"],"names":[],"mappings":"AAAA,OAAO,KAON,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EACR,kBAAkB,EAGlB,0BAA0B,EAC7B,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kCAAkC,CAAC;AAO5D,MAAM,WAAW,eAAe;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,0BAA0B,CAAC;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,IAAI,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,oBAAoB;IACjC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrD;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC5B,mDAAmD;IACnD,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,gFAAgF;IAChF,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACnC;AAED,UAAU,mBAAmB;IACzB,QAAQ,EAAE,eAAe,CAAC;IAC1B,SAAS,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAC9C,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACxB;AAYD;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,kGAsY1B,CAAC"}
@@ -12,6 +12,7 @@ import { ApprovalType, isToolPresentationSnapshotV1 } from "@dexto/core";
12
12
  import { ElicitationForm } from "./ElicitationForm.js";
13
13
  import { DiffPreview, CreateFilePreview } from "./renderers/index.js";
14
14
  import { isEditWriteTool } from "../utils/toolUtils.js";
15
+ import { formatApprovalScope } from "../utils/approvalScope.js";
15
16
  import { formatToolHeader } from "../utils/messageFormatting.js";
16
17
  const ApprovalPrompt = forwardRef(
17
18
  ({ approval, onApprove, onDeny, onCancel }, ref) => {
@@ -20,7 +21,10 @@ const ApprovalPrompt = forwardRef(
20
21
  const toolName = approval.metadata.toolName;
21
22
  const toolArgs = approval.metadata.args || {};
22
23
  const approvalKey = typeof approval.metadata.approvalKey === "string" ? approval.metadata.approvalKey : void 0;
23
- const hasApprovalKey = approvalKey !== void 0;
24
+ const canRemember = approval.type === ApprovalType.TOOL_APPROVAL && approval.sessionId !== void 0 && approval.autoApproval !== "disallowed";
25
+ const rememberedScope = formatApprovalScope(
26
+ approvalKey !== void 0 ? { kind: "action", value: approvalKey } : { kind: "tool", value: toolName ?? "unknown" }
27
+ );
24
28
  const callDescriptionRaw = typeof approval.metadata.description === "string" ? approval.metadata.description : void 0;
25
29
  const callDescription = useMemo(() => {
26
30
  if (!callDescriptionRaw) return null;
@@ -32,6 +36,7 @@ const ApprovalPrompt = forwardRef(
32
36
  }, [callDescriptionRaw]);
33
37
  const isPlanReview = toolName === "plan_review";
34
38
  const isEditOrWriteTool = isEditWriteTool(toolName);
39
+ const canAcceptEdits = canRemember && isEditOrWriteTool && approvalKey === void 0;
35
40
  const presentationSnapshot = useMemo(() => {
36
41
  const raw = approval.metadata["presentationSnapshot"];
37
42
  return isToolPresentationSnapshotV1(raw) ? raw : void 0;
@@ -53,21 +58,18 @@ const ApprovalPrompt = forwardRef(
53
58
  if (isPlanReview) {
54
59
  options.push({ id: "plan-approve", label: "Approve" });
55
60
  options.push({ id: "plan-approve-accept-edits", label: "Approve + Accept All Edits" });
56
- } else if (isCommandApproval) {
57
- options.push({ id: "yes", label: "Yes" });
58
- options.push({ id: "no", label: "No" });
59
- } else if (hasApprovalKey) {
60
- options.push({ id: "yes", label: "Yes (once)" });
61
- options.push({ id: "yes-session", label: "Yes, remember this approval" });
62
- options.push({ id: "no", label: "No" });
63
- } else if (isEditOrWriteTool) {
64
- options.push({ id: "yes", label: "Yes" });
65
- options.push({ id: "yes-accept-edits", label: "Yes, and accept all edits" });
66
- options.push({ id: "no", label: "No" });
67
61
  } else {
68
- options.push({ id: "yes", label: "Yes" });
69
- options.push({ id: "yes-session", label: "Yes (Session)" });
70
- options.push({ id: "no", label: "No" });
62
+ options.push({ id: "yes", label: "Allow once" });
63
+ if (canRemember) {
64
+ options.push({
65
+ id: "yes-session",
66
+ label: `Allow ${rememberedScope} for this session`
67
+ });
68
+ }
69
+ if (canAcceptEdits) {
70
+ options.push({ id: "yes-accept-edits", label: "Allow all edits for this session" });
71
+ }
72
+ options.push({ id: "no", label: "Reject" });
71
73
  }
72
74
  useEffect(() => {
73
75
  selectedIndexRef.current = selectedIndex;
@@ -131,7 +133,7 @@ const ApprovalPrompt = forwardRef(
131
133
  onDeny();
132
134
  }
133
135
  return true;
134
- } else if (key.shift && key.tab && isEditOrWriteTool) {
136
+ } else if (key.shift && key.tab && canAcceptEdits) {
135
137
  onApprove({ enableAcceptEditsMode: true });
136
138
  return true;
137
139
  } else if (key.escape) {
@@ -143,7 +145,7 @@ const ApprovalPrompt = forwardRef(
143
145
  }),
144
146
  [
145
147
  isElicitation,
146
- isEditOrWriteTool,
148
+ canAcceptEdits,
147
149
  isPlanReview,
148
150
  options,
149
151
  onApprove,
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ var import_react = require("react");
3
+ var import_node_stream = require("node:stream");
4
+ var import_ink = require("ink");
5
+ var import_vitest = require("vitest");
6
+ var import_ApprovalPrompt = require("./ApprovalPrompt.js");
7
+ const key = {
8
+ upArrow: false,
9
+ downArrow: false,
10
+ leftArrow: false,
11
+ rightArrow: false,
12
+ pageUp: false,
13
+ pageDown: false,
14
+ return: false,
15
+ escape: false,
16
+ ctrl: false,
17
+ shift: false,
18
+ meta: false,
19
+ tab: false,
20
+ backspace: false,
21
+ delete: false,
22
+ paste: false
23
+ };
24
+ (0, import_vitest.describe)("ApprovalPrompt", () => {
25
+ (0, import_vitest.it)("shows the remembered command scope and submits a session approval", async () => {
26
+ const stdout = Object.assign(new import_node_stream.PassThrough(), { columns: 120, rows: 40, isTTY: false });
27
+ let output = "";
28
+ stdout.on("data", (chunk) => {
29
+ output += String(chunk);
30
+ });
31
+ const ref = (0, import_react.createRef)();
32
+ const onApprove = import_vitest.vi.fn();
33
+ const view = (0, import_ink.render)(
34
+ (0, import_react.createElement)(import_ApprovalPrompt.ApprovalPrompt, {
35
+ ref,
36
+ approval: {
37
+ approvalId: "request",
38
+ type: "tool_approval",
39
+ sessionId: "a",
40
+ timestamp: /* @__PURE__ */ new Date(),
41
+ metadata: {
42
+ toolName: "bash_exec",
43
+ approvalKey: "bash:git status *",
44
+ args: { command: "git status --short" }
45
+ }
46
+ },
47
+ onApprove,
48
+ onDeny: import_vitest.vi.fn(),
49
+ onCancel: import_vitest.vi.fn()
50
+ }),
51
+ {
52
+ stdout,
53
+ // Ink buffers dynamic frames in CI unless debug rendering is enabled.
54
+ debug: true,
55
+ patchConsole: false,
56
+ exitOnCtrlC: false
57
+ }
58
+ );
59
+ try {
60
+ await import_vitest.vi.waitFor(() => (0, import_vitest.expect)(output).toContain("Allow git status * for this session"));
61
+ ref.current?.handleInput("", { ...key, downArrow: true });
62
+ await new Promise((resolve) => setTimeout(resolve, 20));
63
+ ref.current?.handleInput("", { ...key, return: true });
64
+ (0, import_vitest.expect)(onApprove).toHaveBeenCalledWith({ rememberChoice: true });
65
+ } finally {
66
+ view.unmount();
67
+ view.cleanup();
68
+ }
69
+ });
70
+ import_vitest.it.each([
71
+ { type: "command_approval", metadata: { toolName: "edit_file" } },
72
+ {
73
+ type: "tool_approval",
74
+ autoApproval: "disallowed",
75
+ metadata: { toolName: "edit_file" }
76
+ },
77
+ {
78
+ type: "tool_approval",
79
+ metadata: { toolName: "edit_file", approvalKey: "file:specific-path" }
80
+ }
81
+ ])("does not broaden restricted edit approvals: %j", async (request) => {
82
+ const stdout = Object.assign(new import_node_stream.PassThrough(), { columns: 120, rows: 40, isTTY: false });
83
+ let output = "";
84
+ stdout.on("data", (chunk) => {
85
+ output += String(chunk);
86
+ });
87
+ const ref = (0, import_react.createRef)();
88
+ const onApprove = import_vitest.vi.fn();
89
+ const view = (0, import_ink.render)(
90
+ (0, import_react.createElement)(import_ApprovalPrompt.ApprovalPrompt, {
91
+ ref,
92
+ approval: {
93
+ ...request,
94
+ approvalId: "restricted",
95
+ sessionId: "a",
96
+ timestamp: /* @__PURE__ */ new Date()
97
+ },
98
+ onApprove,
99
+ onDeny: import_vitest.vi.fn(),
100
+ onCancel: import_vitest.vi.fn()
101
+ }),
102
+ {
103
+ stdout,
104
+ debug: true,
105
+ patchConsole: false,
106
+ exitOnCtrlC: false
107
+ }
108
+ );
109
+ try {
110
+ await import_vitest.vi.waitFor(() => (0, import_vitest.expect)(output).toContain("Allow once"));
111
+ (0, import_vitest.expect)(output).not.toContain("Allow all edits for this session");
112
+ ref.current?.handleInput("", { ...key, shift: true, tab: true });
113
+ (0, import_vitest.expect)(onApprove).not.toHaveBeenCalled();
114
+ } finally {
115
+ view.unmount();
116
+ view.cleanup();
117
+ }
118
+ });
119
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ApprovalPrompt.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApprovalPrompt.test.d.ts","sourceRoot":"","sources":["../../src/components/ApprovalPrompt.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,120 @@
1
+ import { createElement, createRef } from "react";
2
+ import { PassThrough } from "node:stream";
3
+ import { render } from "ink";
4
+ import { describe, expect, it, vi } from "vitest";
5
+ import {
6
+ ApprovalPrompt
7
+ } from "./ApprovalPrompt.js";
8
+ const key = {
9
+ upArrow: false,
10
+ downArrow: false,
11
+ leftArrow: false,
12
+ rightArrow: false,
13
+ pageUp: false,
14
+ pageDown: false,
15
+ return: false,
16
+ escape: false,
17
+ ctrl: false,
18
+ shift: false,
19
+ meta: false,
20
+ tab: false,
21
+ backspace: false,
22
+ delete: false,
23
+ paste: false
24
+ };
25
+ describe("ApprovalPrompt", () => {
26
+ it("shows the remembered command scope and submits a session approval", async () => {
27
+ const stdout = Object.assign(new PassThrough(), { columns: 120, rows: 40, isTTY: false });
28
+ let output = "";
29
+ stdout.on("data", (chunk) => {
30
+ output += String(chunk);
31
+ });
32
+ const ref = createRef();
33
+ const onApprove = vi.fn();
34
+ const view = render(
35
+ createElement(ApprovalPrompt, {
36
+ ref,
37
+ approval: {
38
+ approvalId: "request",
39
+ type: "tool_approval",
40
+ sessionId: "a",
41
+ timestamp: /* @__PURE__ */ new Date(),
42
+ metadata: {
43
+ toolName: "bash_exec",
44
+ approvalKey: "bash:git status *",
45
+ args: { command: "git status --short" }
46
+ }
47
+ },
48
+ onApprove,
49
+ onDeny: vi.fn(),
50
+ onCancel: vi.fn()
51
+ }),
52
+ {
53
+ stdout,
54
+ // Ink buffers dynamic frames in CI unless debug rendering is enabled.
55
+ debug: true,
56
+ patchConsole: false,
57
+ exitOnCtrlC: false
58
+ }
59
+ );
60
+ try {
61
+ await vi.waitFor(() => expect(output).toContain("Allow git status * for this session"));
62
+ ref.current?.handleInput("", { ...key, downArrow: true });
63
+ await new Promise((resolve) => setTimeout(resolve, 20));
64
+ ref.current?.handleInput("", { ...key, return: true });
65
+ expect(onApprove).toHaveBeenCalledWith({ rememberChoice: true });
66
+ } finally {
67
+ view.unmount();
68
+ view.cleanup();
69
+ }
70
+ });
71
+ it.each([
72
+ { type: "command_approval", metadata: { toolName: "edit_file" } },
73
+ {
74
+ type: "tool_approval",
75
+ autoApproval: "disallowed",
76
+ metadata: { toolName: "edit_file" }
77
+ },
78
+ {
79
+ type: "tool_approval",
80
+ metadata: { toolName: "edit_file", approvalKey: "file:specific-path" }
81
+ }
82
+ ])("does not broaden restricted edit approvals: %j", async (request) => {
83
+ const stdout = Object.assign(new PassThrough(), { columns: 120, rows: 40, isTTY: false });
84
+ let output = "";
85
+ stdout.on("data", (chunk) => {
86
+ output += String(chunk);
87
+ });
88
+ const ref = createRef();
89
+ const onApprove = vi.fn();
90
+ const view = render(
91
+ createElement(ApprovalPrompt, {
92
+ ref,
93
+ approval: {
94
+ ...request,
95
+ approvalId: "restricted",
96
+ sessionId: "a",
97
+ timestamp: /* @__PURE__ */ new Date()
98
+ },
99
+ onApprove,
100
+ onDeny: vi.fn(),
101
+ onCancel: vi.fn()
102
+ }),
103
+ {
104
+ stdout,
105
+ debug: true,
106
+ patchConsole: false,
107
+ exitOnCtrlC: false
108
+ }
109
+ );
110
+ try {
111
+ await vi.waitFor(() => expect(output).toContain("Allow once"));
112
+ expect(output).not.toContain("Allow all edits for this session");
113
+ ref.current?.handleInput("", { ...key, shift: true, tab: true });
114
+ expect(onApprove).not.toHaveBeenCalled();
115
+ } finally {
116
+ view.unmount();
117
+ view.cleanup();
118
+ }
119
+ });
120
+ });
@@ -154,6 +154,10 @@ function Footer({
154
154
  "% context left"
155
155
  ] }) }),
156
156
  chatGPTRateLimitHint && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: chatGPTRateLimitColor, children: chatGPTRateLimitHint }) }),
157
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "gray", children: [
158
+ "approvals: ",
159
+ agent.getEffectiveConfig(sessionId ?? void 0).permissions.mode
160
+ ] }) }),
157
161
  isShellMode && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { children: [
158
162
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: "yellow", bold: true, children: "!" }),
159
163
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: "gray", children: " for shell mode" })
@@ -167,7 +171,7 @@ function Footer({
167
171
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: "gray", children: " (shift + tab to cycle)" })
168
172
  ] }),
169
173
  bypassPermissions && !planModeActive && !autoApproveEdits && !isShellMode && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { children: [
170
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: "redBright", bold: true, children: "bypass permissions" }),
174
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: "gray", children: "auto-approve (session)" }),
171
175
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: "gray", children: " (shift + tab to cycle)" })
172
176
  ] })
173
177
  ] });
@@ -1 +1 @@
1
- {"version":3,"file":"Footer.d.ts","sourceRoot":"","sources":["../../src/components/Footer.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EAAqB,KAAK,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAM7E,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEjF,UAAU,WAAW;IACjB,KAAK,EAAE,eAAe,CAAC;IACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,kEAAkE;IAClE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,sBAAsB,CAAC,EAAE,sBAAsB,GAAG,IAAI,CAAC;CAC1D;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,EACnB,KAAK,EACL,SAAS,EACT,SAAS,EACT,GAAG,EACH,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,WAAW,EACX,sBAAsB,GACzB,EAAE,WAAW,2CA8Kb"}
1
+ {"version":3,"file":"Footer.d.ts","sourceRoot":"","sources":["../../src/components/Footer.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EAAqB,KAAK,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAM7E,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEjF,UAAU,WAAW;IACjB,KAAK,EAAE,eAAe,CAAC;IACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,kEAAkE;IAClE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,sBAAsB,CAAC,EAAE,sBAAsB,GAAG,IAAI,CAAC;CAC1D;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,EACnB,KAAK,EACL,SAAS,EACT,SAAS,EACT,GAAG,EACH,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,WAAW,EACX,sBAAsB,GACzB,EAAE,WAAW,2CAkLb"}
@@ -124,6 +124,10 @@ function Footer({
124
124
  "% context left"
125
125
  ] }) }),
126
126
  chatGPTRateLimitHint && /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { color: chatGPTRateLimitColor, children: chatGPTRateLimitHint }) }),
127
+ /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
128
+ "approvals: ",
129
+ agent.getEffectiveConfig(sessionId ?? void 0).permissions.mode
130
+ ] }) }),
127
131
  isShellMode && /* @__PURE__ */ jsxs(Box, { children: [
128
132
  /* @__PURE__ */ jsx(Text, { color: "yellow", bold: true, children: "!" }),
129
133
  /* @__PURE__ */ jsx(Text, { color: "gray", children: " for shell mode" })
@@ -137,7 +141,7 @@ function Footer({
137
141
  /* @__PURE__ */ jsx(Text, { color: "gray", children: " (shift + tab to cycle)" })
138
142
  ] }),
139
143
  bypassPermissions && !planModeActive && !autoApproveEdits && !isShellMode && /* @__PURE__ */ jsxs(Box, { children: [
140
- /* @__PURE__ */ jsx(Text, { color: "redBright", bold: true, children: "bypass permissions" }),
144
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: "auto-approve (session)" }),
141
145
  /* @__PURE__ */ jsx(Text, { color: "gray", children: " (shift + tab to cycle)" })
142
146
  ] })
143
147
  ] });
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ var import_react = require("react");
3
+ var import_node_stream = require("node:stream");
4
+ var import_ink = require("ink");
5
+ var import_vitest = require("vitest");
6
+ var import_Footer = require("./Footer.js");
7
+ (0, import_vitest.describe)("configured approval policy in the TUI footer", () => {
8
+ import_vitest.it.each(["manual", "auto-approve"])(
9
+ "shows %s independently of session shortcuts",
10
+ async (mode) => {
11
+ const stdout = Object.assign(new import_node_stream.PassThrough(), {
12
+ columns: 120,
13
+ rows: 40,
14
+ isTTY: false
15
+ });
16
+ let output = "";
17
+ stdout.on("data", (chunk) => {
18
+ output += String(chunk);
19
+ });
20
+ const agent = {
21
+ capabilities: { contextStats: false },
22
+ getEffectiveConfig: () => ({ permissions: { mode } })
23
+ };
24
+ const view = (0, import_ink.render)(
25
+ (0, import_react.createElement)(import_Footer.Footer, {
26
+ agent,
27
+ sessionId: null,
28
+ modelName: "test-model",
29
+ autoApproveEdits: true
30
+ }),
31
+ {
32
+ stdout,
33
+ debug: true,
34
+ patchConsole: false,
35
+ exitOnCtrlC: false
36
+ }
37
+ );
38
+ try {
39
+ await import_vitest.vi.waitFor(() => (0, import_vitest.expect)(output).toContain(`approvals: ${mode}`));
40
+ (0, import_vitest.expect)(output).toContain("accept edits");
41
+ } finally {
42
+ view.unmount();
43
+ stdout.destroy();
44
+ }
45
+ }
46
+ );
47
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=Footer.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Footer.test.d.ts","sourceRoot":"","sources":["../../src/components/Footer.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,46 @@
1
+ import { createElement } from "react";
2
+ import { PassThrough } from "node:stream";
3
+ import { render } from "ink";
4
+ import { describe, expect, it, vi } from "vitest";
5
+ import { Footer } from "./Footer.js";
6
+ describe("configured approval policy in the TUI footer", () => {
7
+ it.each(["manual", "auto-approve"])(
8
+ "shows %s independently of session shortcuts",
9
+ async (mode) => {
10
+ const stdout = Object.assign(new PassThrough(), {
11
+ columns: 120,
12
+ rows: 40,
13
+ isTTY: false
14
+ });
15
+ let output = "";
16
+ stdout.on("data", (chunk) => {
17
+ output += String(chunk);
18
+ });
19
+ const agent = {
20
+ capabilities: { contextStats: false },
21
+ getEffectiveConfig: () => ({ permissions: { mode } })
22
+ };
23
+ const view = render(
24
+ createElement(Footer, {
25
+ agent,
26
+ sessionId: null,
27
+ modelName: "test-model",
28
+ autoApproveEdits: true
29
+ }),
30
+ {
31
+ stdout,
32
+ debug: true,
33
+ patchConsole: false,
34
+ exitOnCtrlC: false
35
+ }
36
+ );
37
+ try {
38
+ await vi.waitFor(() => expect(output).toContain(`approvals: ${mode}`));
39
+ expect(output).toContain("accept edits");
40
+ } finally {
41
+ view.unmount();
42
+ stdout.destroy();
43
+ }
44
+ }
45
+ );
46
+ });
@@ -84,7 +84,8 @@ function AlternateBufferCLI({
84
84
  inputService,
85
85
  buffer,
86
86
  overlayContainerRef,
87
- visibleMessages
87
+ visibleMessages,
88
+ isHydratingHistory
88
89
  } = (0, import_useCLIState.useCLIState)({
89
90
  agent,
90
91
  initialSessionId,
@@ -303,6 +304,7 @@ function AlternateBufferCLI({
303
304
  ui,
304
305
  session,
305
306
  initialPrompt,
307
+ isHydratingHistory,
306
308
  approval,
307
309
  steerMessages,
308
310
  queuedMessages,
@@ -1 +1 @@
1
- {"version":3,"file":"AlternateBufferCLI.d.ts","sourceRoot":"","sources":["../../../src/components/modes/AlternateBufferCLI.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAG9D,OAAO,KAAK,EAAW,WAAW,EAAE,MAAM,sBAAsB,CAAC;AA+BjE,UAAU,uBAAuB;IAC7B,KAAK,EAAE,eAAe,CAAC;IACvB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,WAAW,EAAE,WAAW,CAAC;IACzB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,6DAA6D;IAC7D,YAAY,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAAC,EAC/B,KAAK,EACL,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,cAAc,EACd,wBAAgC,EAChC,kBAAkB,EAClB,YAAmB,GACtB,EAAE,uBAAuB,2CA+XzB"}
1
+ {"version":3,"file":"AlternateBufferCLI.d.ts","sourceRoot":"","sources":["../../../src/components/modes/AlternateBufferCLI.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAG9D,OAAO,KAAK,EAAW,WAAW,EAAE,MAAM,sBAAsB,CAAC;AA+BjE,UAAU,uBAAuB;IAC7B,KAAK,EAAE,eAAe,CAAC;IACvB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,WAAW,EAAE,WAAW,CAAC;IACzB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,6DAA6D;IAC7D,YAAY,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAAC,EAC/B,KAAK,EACL,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,cAAc,EACd,wBAAgC,EAChC,kBAAkB,EAClB,YAAmB,GACtB,EAAE,uBAAuB,2CAiYzB"}