diff --git a/README.md b/README.md
index 2c966d5..87a8282 100644
--- a/README.md
+++ b/README.md
@@ -128,7 +128,7 @@ Explorbot provides a real-time TUI (Terminal User Interface) with three main are
│ ⯈ AddScenario(Verify company name field is pre-populated, HIGH) │
│ ⯈ AddScenario(Change company name and verify persistence, HIGH) │
│ ⯈ AddScenario(Navigate away and return to verify name persists, HIGH) │
-│ Done. Press [ESC] to enable input │
+│ Done. Press [ESC] to enable input. Press [CTRL + t] to toggle session timer │
└─────────────────────────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ > /plan user-management │
@@ -153,6 +153,8 @@ Explorbot provides a real-time TUI (Terminal User Interface) with three main are
**Tasks Pane**: Shows generated test scenarios with priorities and status
+**Session Timer**: An optional timer displayed next to the activity line at the bottom of the TUI. It shows how much time has been spent in the current Explorbot session and can be toggled on and off with the `CTRL + t` key.
+
### Available Commands
**Application Commands:**
@@ -168,6 +170,12 @@ Explorbot provides a real-time TUI (Terminal User Interface) with three main are
- `I.fillField(locator, value)` - Fill form inputs
- All standard CodeceptJS commands are supported
+### Keyboard Shortcuts
+While using the TUI:
+- `ESC` — enable the input line when Explorbot is waiting for commands
+- `t` — toggle the session timer panel that shows elapsed time for the current session
+- `Ctrl + C` — exit the current Explorbot session
+
## Command Line Usage
Explorbot provides several commands through the `maclay` CLI tool:
diff --git a/src/components/ActivityPane.tsx b/src/components/ActivityPane.tsx
index 49dd4ee..1b29cae 100644
--- a/src/components/ActivityPane.tsx
+++ b/src/components/ActivityPane.tsx
@@ -32,7 +32,7 @@ const ActivityPane: React.FC = () => {
if (!activity) {
return (
- Done. Press [ESC] to enable input
+ Done. Press [ESC] to enable input. Press [CTRL + t] to toggle session timer.
);
}
diff --git a/src/components/App.tsx b/src/components/App.tsx
index 9c239fa..48538e4 100644
--- a/src/components/App.tsx
+++ b/src/components/App.tsx
@@ -1,5 +1,5 @@
import { Box, Text, useInput } from 'ink';
-import React, { useEffect, useState } from 'react';
+import React, { useEffect, useRef, useState } from 'react';
import { CommandHandler } from '../command-handler.js';
import type { ExplorBot, ExplorBotOptions } from '../explorbot.ts';
import type { StateTransition, WebPageState } from '../state-manager.js';
@@ -9,6 +9,7 @@ import InputPane from './InputPane.js';
import LogPane from './LogPane.js';
import StateTransitionPane from './StateTransitionPane.js';
import TaskPane from './TaskPane.js';
+import SessionTimer from './SessionTimer.js';
interface AppProps {
explorBot: ExplorBot;
@@ -17,6 +18,8 @@ interface AppProps {
}
export function App({ explorBot, initialShowInput = false, exitOnEmptyInput = false }: AppProps) {
+ const sessionStartedAtRef = useRef(Date.now());
+ const [showSessionTimer, setShowSessionTimer] = useState(false);
const [showInput, setShowInput] = useState(initialShowInput);
const [currentState, setCurrentState] = useState(null);
const [lastTransition, setLastTransition] = useState(null);
@@ -87,24 +90,40 @@ export function App({ explorBot, initialShowInput = false, exitOnEmptyInput = fa
return () => clearInterval(interval);
}, [explorBot]);
- // Handle keyboard input - ESC to enable input, Ctrl-C to exit
useInput((input, key) => {
+ if (key.ctrl && input === 't') {
+ setShowSessionTimer((prev) => !prev);
+ return;
+ }
+
if (key.escape) {
setShowInput(true);
+ return;
}
+
if (key.ctrl && input === 'c') {
process.exit(0);
}
});
+
return (
-
+
+ {showSessionTimer && (
+
+ )}
{showInput && }
diff --git a/src/components/SessionTimer.tsx b/src/components/SessionTimer.tsx
new file mode 100644
index 0000000..151e121
--- /dev/null
+++ b/src/components/SessionTimer.tsx
@@ -0,0 +1,39 @@
+import React, { useEffect, useState } from 'react';
+import { Box, Text } from 'ink';
+
+type SessionTimerProps = {
+ startedAt: number;
+};
+
+const pad = (n: number) => String(n).padStart(2, '0');
+
+const SessionTimer: React.FC = ({ startedAt }) => {
+ const [now, setNow] = useState(() => Date.now());
+
+ useEffect(() => {
+ const id = setInterval(() => {
+ setNow(Date.now());
+ }, 1000);
+
+ return () => clearInterval(id);
+ }, []);
+
+ const diffSec = Math.floor((now - startedAt) / 1000);
+ const seconds = diffSec % 60;
+ const minutes = Math.floor(diffSec / 60) % 60;
+ const hours = Math.floor(diffSec / 3600);
+
+ return (
+
+
+ Session time: {pad(hours)}:{pad(minutes)}:{pad(seconds)}
+
+
+ );
+};
+
+export default SessionTimer;
\ No newline at end of file