agent-lookout 0.2.3 → 0.2.4
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/CHANGELOG.md +18 -0
- package/PRIVACY.md +59 -15
- package/README.md +10 -6
- package/SECURITY.md +16 -6
- package/dist/THIRD-PARTY-LICENSES.md +195 -0
- package/dist/assets/{HistoryPanel-DMnhIoFB.js → HistoryPanel-CIjshvhu.js} +1 -1
- package/dist/assets/SessionPanel-eBOdTLD9.js +1 -0
- package/dist/assets/index-B-myfVQS.js +2 -0
- package/dist/assets/index-Cceyz9yZ.css +1 -0
- package/dist/assets/radix-BH0JH8UU.js +41 -0
- package/dist/cli/agent-lookout.js +4 -4
- package/dist/cli/{chunk-GOX5UB5L.js → chunk-63XPRBHW.js} +85 -3
- package/dist/cli/{chunk-54ODUY75.js → chunk-KNOLJ3IC.js} +1 -1
- package/dist/cli/{chunk-4C34YX6S.js → chunk-XVXSGVEW.js} +6 -2
- package/dist/cli/mcpServer-HGH6PY4W.js +23664 -0
- package/dist/cli/{startCommand-H6O35VYR.js → startCommand-KNXMVM2U.js} +3996 -2822
- package/dist/index.html +3 -3
- package/docs/API.md +169 -62
- package/docs/GUIDE.md +127 -58
- package/package.json +5 -5
- package/dist/assets/SessionPanel-BNm9wCzf.js +0 -1
- package/dist/assets/atkinson-hyperlegible-mono-latin-400-normal-Cmjm2dBj.woff +0 -0
- package/dist/assets/atkinson-hyperlegible-mono-latin-500-normal-BV5ipwqM.woff +0 -0
- package/dist/assets/atkinson-hyperlegible-mono-latin-600-normal-CuPF9o0F.woff +0 -0
- package/dist/assets/atkinson-hyperlegible-mono-latin-ext-400-normal-ITMuFrSK.woff +0 -0
- package/dist/assets/atkinson-hyperlegible-mono-latin-ext-500-normal-BiHEOgiK.woff +0 -0
- package/dist/assets/atkinson-hyperlegible-mono-latin-ext-600-normal-ZiH-ObRk.woff +0 -0
- package/dist/assets/atkinson-hyperlegible-next-latin-400-normal-DPp7N0cD.woff +0 -0
- package/dist/assets/atkinson-hyperlegible-next-latin-500-normal-B0CYqHl3.woff +0 -0
- package/dist/assets/atkinson-hyperlegible-next-latin-600-normal-BhgCag5w.woff +0 -0
- package/dist/assets/atkinson-hyperlegible-next-latin-ext-400-normal-qxMiU51n.woff +0 -0
- package/dist/assets/atkinson-hyperlegible-next-latin-ext-500-normal-oZS3KxrF.woff +0 -0
- package/dist/assets/atkinson-hyperlegible-next-latin-ext-600-normal-BBAQIogt.woff +0 -0
- package/dist/assets/index-Ckda8OV4.js +0 -2
- package/dist/assets/index-DFR77qn5.css +0 -1
- package/dist/assets/radix-27o0jeIu.js +0 -41
- package/dist/cli/mcpServer-QQFQR6DC.js +0 -246
package/docs/GUIDE.md
CHANGED
|
@@ -64,6 +64,8 @@ When the list is too narrow for every column, the app is left out first and then
|
|
|
64
64
|
|
|
65
65
|
A Claude Code session in VS Code, inside tmux or in a tab of Terminal or iTerm2 has a Jump button here too.
|
|
66
66
|
|
|
67
|
+
Claude Code sessions idle for a day or more whose process still runs are also listed over the list, under Left running, where they can be hidden or ended: see [Sessions left running](#sessions-left-running).
|
|
68
|
+
|
|
67
69
|
Click a row, or move to its name with Tab and press Enter, to open the session's [details](#a-sessions-details).
|
|
68
70
|
|
|
69
71
|
The switch at the top right of the Sessions list, or under its title on a phone, chooses List, Repos or Board. Repos groups the same rows by [repository](#repositories), and Board lays them out in columns.
|
|
@@ -101,12 +103,13 @@ The details show everything Agent Lookout knows about the session:
|
|
|
101
103
|
- its agent, and the app it runs in when that is known
|
|
102
104
|
- the full path of its folder, which you can select and copy
|
|
103
105
|
- its [repository](#repositories), and its [branch](#branches) or the commit when no branch is checked out
|
|
106
|
+
- with pull requests on, its branch's [pull request](#pull-requests): its number and title, a link that opens it on github.com in your browser, whether it is open, a draft, merged or closed, and how many of its checks are failing, pending and passing
|
|
104
107
|
- when it started and its process ID, when its agent reports them
|
|
105
108
|
- how many times it waited for you and how long in all, over the same time as the bars in the Needs you panel
|
|
106
109
|
- its own events, newest first, as the Events log shows them
|
|
107
110
|
- its row of the Timeline over the last hour
|
|
108
111
|
|
|
109
|
-
A session with a Jump button has it at the top of its details, and it works as it does in the list. It is the amber one while the session needs you.
|
|
112
|
+
A session with a Jump button has it at the top of its details, and it works as it does in the list. It is the amber one while the session needs you. A session Agent Lookout can stop has a [Stop](#stop-a-session) button beside it.
|
|
110
113
|
|
|
111
114
|
Each session's details have an address of their own, such as `#overview/session/claude-code:` followed by the session's ID, so a bookmark or a reload opens them again, and the browser's Back button closes them. `Esc` or the close button closes them too, and puts focus back on the session's name. If the session leaves the list while its details are open, they say so and keep what was last known of it. An address for a session Agent Lookout is not watching says so, with a button back to the Overview.
|
|
112
115
|
|
|
@@ -159,9 +162,31 @@ git worktree add ../storefront-billing -b billing-webhooks
|
|
|
159
162
|
|
|
160
163
|
Repos then lists both sessions under `storefront`, each with its own folder and branch.
|
|
161
164
|
|
|
165
|
+
#### Pull requests
|
|
166
|
+
|
|
167
|
+
Agent Lookout can show the pull request on github.com for each session's branch, and whether its checks pass, so a session whose pull request has a failing check stands out. It is off unless you turn it on, because it asks GitHub: start Agent Lookout with `AGENT_LOOKOUT_PULL_REQUESTS=on`.
|
|
168
|
+
|
|
169
|
+
```sh
|
|
170
|
+
AGENT_LOOKOUT_PULL_REQUESTS=on npx agent-lookout
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
It asks through your own [GitHub CLI](https://cli.github.com), `gh`, with the login `gh` already has, so Agent Lookout never sees or keeps a token. Install `gh` and run `gh auth login` once if you have not. Agent Lookout looks for `gh` on your `PATH`, then in `/opt/homebrew/bin`, `/usr/local/bin`, `/opt/local/bin` and `/usr/bin`, as it does for tmux.
|
|
174
|
+
|
|
175
|
+
With it on:
|
|
176
|
+
|
|
177
|
+
- A session's details have a Pull request fact under its branch: the pull request's number and title, as a link that opens it on github.com in your browser, and under them whether it is open, a draft, merged or closed and how its checks stand, such as `Open, 2 checks failing, 1 pending, 4 passing`. A check that was skipped or ended neutral counts as passing, and one that was cancelled or timed out as failing.
|
|
178
|
+
- In the Sessions list and on the board, a branch whose pull request is open, or a draft, and has a check failing has a small cross after it. Hover over it, or move to it with Tab, to read which pull request and how its checks stand. The list shows it under the folder, and so leaves it out in a narrow window, as it does the branch.
|
|
179
|
+
- `agent-lookout mcp` gives each session's pull request as its number and how its checks stand, and `agent-lookout status --json` does for a waiting session. Neither gives the title.
|
|
180
|
+
|
|
181
|
+
Agent Lookout asks only about a branch of a repository whose remote is on github.com. It reads the remote from the repository's own `config` file, as it reads the branch from `HEAD`, and runs no git command. A remote on any other host, a GitHub Enterprise server's among them, is passed over, as is a host name your SSH configuration stands in for github.com. It never asks about the repository's default branch, the one its remote's `HEAD` names, or `main` or `master` when that was never written. Nor does it ask about a branch whose name is only digits, such as `51` or `#51`, which `gh` would take for the number of a pull request rather than a branch. It asks for a pull request from the branch of the same name, the way `gh pr view` does, in the repository `gh repo set-default` chose, or else in the remote named `upstream`, `github` or `origin`, in that order. A branch pushed to someone else's copy, a fork, is looked for as `owner:branch`.
|
|
182
|
+
|
|
183
|
+
It asks `gh` once for each repository and branch your sessions are on, however many sessions are on it, and again only after 2 minutes, never on every poll. So a pull request you open, or a check that finishes, shows within about 2 minutes. Each question runs `gh pr view` and waits up to 15 seconds for it. A branch no session is on any more is forgotten.
|
|
184
|
+
|
|
185
|
+
The Pull requests card in Settings says whether this is on, and when `gh` was last asked. Without `gh`, or with `gh` not signed in, it says so, and no pull request is shown until that changes: Agent Lookout keeps working as before. What `gh` sends GitHub, for each question, is the repository's owner and name and the branch's name, with `gh`'s own login. [PRIVACY.md](../PRIVACY.md#gh) has the details.
|
|
186
|
+
|
|
162
187
|
#### Events
|
|
163
188
|
|
|
164
|
-
The Events log records each session appearing, changing status and ending, newest first. When a wait ends, it says how long the wait lasted if it saw the wait begin. When Agent Lookout measured nothing for a while in the last hour, such as while the computer was asleep or Agent Lookout was stopped, a row says when watching resumed and how long was not measured. The log is kept on this computer with the charts' counts, so a restart does not empty it: see [History](#history). While the log still holds everything since Agent Lookout started, it ends with Started watching, and its heading says since when, with the day when that was not today. Once the history has been cleared, it ends with History cleared instead.
|
|
189
|
+
The Events log records each session appearing, changing status and ending, newest first, and each session [stopped](#stop-a-session) from Agent Lookout. When a wait ends, it says how long the wait lasted if it saw the wait begin. When Agent Lookout measured nothing for a while in the last hour, such as while the computer was asleep or Agent Lookout was stopped, a row says when watching resumed and how long was not measured. The log is kept on this computer with the charts' counts, so a restart does not empty it: see [History](#history). While the log still holds everything since Agent Lookout started, it ends with Started watching, and its heading says since when, with the day when that was not today. Once the history has been cleared, it ends with History cleared instead.
|
|
165
190
|
|
|
166
191
|
When you come back to the tab after it was in the background or minimised, or open the dashboard again, a line in the log marks where you left off, such as New since 14:02:37, and the log's heading says how many events arrived since, such as 3 new. The events above the line are the new ones. The line and the count go once the line has been in view for 10 seconds, or when you open Sources or Settings. If more arrived than the log shows at once, scroll down the log to the line. With the tab in front all the time there is never a line. Events that arrive while the line is showing join the new ones above it. A wait among the new events has its usual mark, and nothing else changes colour. The one thing kept for this is the time you left off, in your browser.
|
|
167
192
|
|
|
@@ -191,13 +216,13 @@ When an agent is not on this computer, its card says Not found, and after the fi
|
|
|
191
216
|
|
|
192
217
|
#### What each agent can report
|
|
193
218
|
|
|
194
|
-
Under the cards, What each agent can report has a row for each agent and a column for each thing Agent Lookout can show of its sessions, with Yes, No or Partly in each. Point at No or Partly, or move to it with Tab, to read why. In a narrow window each agent has a block of its own, with the reason under each No and Partly. A No means Agent Lookout cannot show it for that agent's sessions, so not seeing it is not good news. The [branch](#branches) is not in the table, because it is read the same way for every agent.
|
|
219
|
+
Under the cards, What each agent can report has a row for each agent and a column for each thing Agent Lookout can show of its sessions, and for [Stop](#stop-a-session), what it can do to one, with Yes, No or Partly in each. Point at No or Partly, or move to it with Tab, to read why. In a narrow window each agent has a block of its own, with the reason under each No and Partly. A No means Agent Lookout cannot show it for that agent's sessions, so not seeing it is not good news. The [branch](#branches) is not in the table, because it is read the same way for every agent.
|
|
195
220
|
|
|
196
|
-
| Agent | Working and idle | Needs you | Finished | Failed | Names | Jump | Quiet for |
|
|
197
|
-
| ------------ | ---------------- | --------- | -------- | ------ | ------ | ------ | --------- |
|
|
198
|
-
| Claude Code | Yes | Yes | Partly | Partly | Yes | Partly | No |
|
|
199
|
-
| Codex | Yes | No | Partly | No | Partly | No | Yes |
|
|
200
|
-
| Status files | Partly | Partly | Partly | Partly | Partly | No | Partly |
|
|
221
|
+
| Agent | Working and idle | Needs you | Finished | Failed | Names | Jump | Quiet for | Stop |
|
|
222
|
+
| ------------ | ---------------- | --------- | -------- | ------ | ------ | ------ | --------- | ------ |
|
|
223
|
+
| Claude Code | Yes | Yes | Partly | Partly | Yes | Partly | No | Partly |
|
|
224
|
+
| Codex | Yes | No | Partly | No | Partly | No | Yes | No |
|
|
225
|
+
| Status files | Partly | Partly | Partly | Partly | Partly | No | Partly | No |
|
|
201
226
|
|
|
202
227
|
Why, for each No and Partly:
|
|
203
228
|
|
|
@@ -205,11 +230,13 @@ Why, for each No and Partly:
|
|
|
205
230
|
- Claude Code, Failed: Only background jobs. Any other session leaves the list without saying how it ended.
|
|
206
231
|
- Claude Code, Jump: In VS Code, in tmux, and in a tab of Terminal or iTerm2 on a Mac. Not in the desktop app or another terminal.
|
|
207
232
|
- Claude Code, Quiet for: The file Agent Lookout reads is not rewritten as a session works.
|
|
233
|
+
- Claude Code, Stop: In a terminal, in VS Code and for background jobs. Not in the desktop app.
|
|
208
234
|
- Codex, Needs you: Codex does not record approval waits, so a session waiting for you shows as working.
|
|
209
235
|
- Codex, Finished: From Codex 0.155 on, once no Codex program has the session open.
|
|
210
236
|
- Codex, Failed: Codex does not record errors in its files.
|
|
211
237
|
- Codex, Names: The desktop app does not keep its titles in the names file Agent Lookout reads, so its sessions take their folder's name.
|
|
212
238
|
- Codex, Jump: Codex's files name no process to find, and Codex documents no link to a session.
|
|
239
|
+
- Codex, Stop: Codex's files name no process that Agent Lookout could confirm and stop.
|
|
213
240
|
- Status files, Working and idle: If the agent writes working and idle.
|
|
214
241
|
- Status files, Needs you: If the agent writes waiting.
|
|
215
242
|
- Status files, Finished: If the agent writes finished.
|
|
@@ -217,10 +244,11 @@ Why, for each No and Partly:
|
|
|
217
244
|
- Status files, Names: If the agent writes a name. Otherwise the folder's or the file's name is used.
|
|
218
245
|
- Status files, Jump: Nothing in a status file is used to reach a session.
|
|
219
246
|
- Status files, Quiet for: If the agent writes its file again as it works.
|
|
247
|
+
- Status files, Stop: Any program can write a status file, so nothing in one is used to stop a session.
|
|
220
248
|
|
|
221
249
|
### Settings
|
|
222
250
|
|
|
223
|
-
Settings has
|
|
251
|
+
Settings has seven cards, and in the Mac app two more, [Menu bar](#menu-bar) and [Updates](#updates). Theme chooses Night, which is the default, Day, or System, which follows your computer's setting. Notifications turns notifications on and off, for the dashboard page and for Agent Lookout itself, and chooses what sends one. History says where the Events log and the charts are kept, how much they hold and since when, and clears them. Email says whether Agent Lookout emails you, and for what, and Webhook whether it posts to a webhook, such as a Slack channel's, and for what. Pull requests says whether each session's [pull request](#pull-requests) is shown, and whether `gh` can be asked for them. All three are set up when you start it, not here. This copy shows the version you are running and where Agent Lookout sends your data: nowhere, or only in the emails and webhook posts you set up, and with pull requests on, the names of repositories and branches to GitHub, through `gh`, unless `gh` was not found or is not signed in, when nothing goes to GitHub.
|
|
224
252
|
|
|
225
253
|
#### Notifications
|
|
226
254
|
|
|
@@ -538,6 +566,39 @@ In the [desktop app](#desktop-app) the collector runs inside Agent Lookout itsel
|
|
|
538
566
|
|
|
539
567
|
To stop Agent Lookout looking for tabs at all, start it with `AGENT_LOOKOUT_TERMINAL_JUMP=off`. It then runs neither `ps` for this nor `osascript` for Jump, and sessions in Terminal and iTerm2 have no button. [PRIVACY.md](../PRIVACY.md#terminal-and-iterm2) lists what it reads and runs.
|
|
540
568
|
|
|
569
|
+
## Stop a session
|
|
570
|
+
|
|
571
|
+
A Claude Code session that runs in a terminal or in VS Code, and a Claude Code background job, has a Stop button at the top of its [details](#a-sessions-details), beside its Jump. Stop ends the session's process. It is not an interrupt: the session ends, and what it was doing stops part-way. Its conversation is kept, so `claude --resume` with the session's ID opens it again, and VS Code opens it from its session history. Agent Lookout stops a session only when you press Stop and confirm, and never on its own.
|
|
572
|
+
|
|
573
|
+
Stop asks first, at the top of the details: it names the session, says that its process ends now and how to open the conversation again, and, for a session that is working or waiting for you, that what it is doing stops part-way or that its question is left unanswered. Focus goes to Cancel, so pressing Enter does not stop it. Press Stop session to stop it.
|
|
574
|
+
|
|
575
|
+
Agent Lookout then checks again that the process is that session: it reads the session's file in `~/.claude/sessions` again and asks `ps` when the process started, and does nothing unless both agree with what it found before. A session in a terminal or VS Code is sent SIGTERM, which ends Claude Code the way closing it does, and Agent Lookout waits up to 10 seconds for it to end. A background job is stopped with `claude stop` and its ID, since Claude Code would start its process again if it were ended another way. The session leaves the list within a second or two, a background job shows as finished, and the Events log says it was stopped from Agent Lookout.
|
|
576
|
+
|
|
577
|
+
| What the details say | Why |
|
|
578
|
+
| --------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
|
579
|
+
| Stopped. Its process has ended, and its conversation is kept. | It worked. |
|
|
580
|
+
| Asked to stop, still running. It had not ended 10 seconds later. | SIGTERM was sent and the process has not ended. Nothing stronger is sent. Look at the session where it runs. |
|
|
581
|
+
| Agent Lookout cannot confirm this process is that session, so it did not stop it. | Its file in `~/.claude/sessions` changed, or `ps` gave another start time, as when the process ID now belongs to another program. |
|
|
582
|
+
| That session has already ended. | It ended before Stop reached it. |
|
|
583
|
+
| Agent Lookout is not allowed to stop this process. | The process is another user's, or one Agent Lookout itself runs in or was started from, such as the session whose terminal started it. |
|
|
584
|
+
|
|
585
|
+
#### Which sessions have Stop
|
|
586
|
+
|
|
587
|
+
- A Claude Code session in a terminal of any app, tmux included, or in VS Code, whose file in `~/.claude/sessions` says it is an interactive session and records when its process started.
|
|
588
|
+
- A Claude Code background job, while Agent Lookout runs the `claude` command: not with `AGENT_LOOKOUT_CLAUDE_FEED=off`, and not with `AGENT_LOOKOUT_CLAUDE_HOME` set and `AGENT_LOOKOUT_CLAUDE_BIN` not.
|
|
589
|
+
- Not a session in Claude Code's desktop app, which looks after its own processes: its details say to stop it there. Not a session whose file does not say what kind it is, or which app it runs in.
|
|
590
|
+
- Not a Codex session, and not a session from a status file.
|
|
591
|
+
|
|
592
|
+
### Sessions left running
|
|
593
|
+
|
|
594
|
+
Closing a Claude Code tab in VS Code can leave its process running, and the session then sits idle for days. Over the Sessions list, or the board, a band says how many Claude Code sessions have been idle for a day or more with their process still running: those Agent Lookout can stop, and those in the desktop app. Press Review… to list them, the longest idle first, each with its folder, its app and how long it has been idle, and Close to fold the list again. They stay in the list under Idle too.
|
|
595
|
+
|
|
596
|
+
Hide until it changes takes one out of Left running, in this browser only, until its status next changes. It does nothing to the session.
|
|
597
|
+
|
|
598
|
+
End all… lists each one again with a tick, all ticked, up to 20, which is as many as it ends at a time. Untick any you want to keep, and press End, which says how many it ends, such as End 3 sessions. Each one is stopped as Stop stops it, after the same checks, and only if it is still idle since the moment the list showed: a session that has done anything since is left running, even if it is idle again. A line then says what came of it, such as Ended 2. Left 1 running because it became active., and each row says what became of it. A session in the desktop app is listed with a line that says to stop it there, and has no tick.
|
|
599
|
+
|
|
600
|
+
To take Stop and the ending of sessions left running away altogether, start Agent Lookout with `AGENT_LOOKOUT_STOP=off`. [PRIVACY.md](../PRIVACY.md#stopping-a-session) says what Agent Lookout checks and runs to stop a session.
|
|
601
|
+
|
|
541
602
|
## Keyboard
|
|
542
603
|
|
|
543
604
|
Every view answers to a few keys. Press `?` to see them all.
|
|
@@ -644,17 +705,18 @@ With `--json` it prints:
|
|
|
644
705
|
}
|
|
645
706
|
```
|
|
646
707
|
|
|
647
|
-
| Field | What it holds
|
|
648
|
-
| -------------------------------------- |
|
|
649
|
-
| `counted` | `false` until an agent has been read, when the numbers below are not a count
|
|
650
|
-
| `needsYou`, `working`, `idle`, `stale` | How many sessions have each status, counted as above
|
|
651
|
-
| `waiting` | The sessions that need you, longest wait first
|
|
652
|
-
| `id` | The session's id, as `/api/sessions` gives it
|
|
653
|
-
| `name` | The session's name, exactly as its agent gave it
|
|
654
|
-
| `agent` | `Claude Code`, or the agent a [status file](#your-own-agents) names
|
|
655
|
-
| `reason` | `permission`, `question` or `other`
|
|
656
|
-
| `waitingSince` | When the wait began, in milliseconds since 1970, or `null` when that is not known
|
|
657
|
-
| `waitedMs` | How long it has waited, in milliseconds, or `null`
|
|
708
|
+
| Field | What it holds |
|
|
709
|
+
| -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
710
|
+
| `counted` | `false` until an agent has been read, when the numbers below are not a count |
|
|
711
|
+
| `needsYou`, `working`, `idle`, `stale` | How many sessions have each status, counted as above |
|
|
712
|
+
| `waiting` | The sessions that need you, longest wait first |
|
|
713
|
+
| `id` | The session's id, as `/api/sessions` gives it |
|
|
714
|
+
| `name` | The session's name, exactly as its agent gave it |
|
|
715
|
+
| `agent` | `Claude Code`, or the agent a [status file](#your-own-agents) names |
|
|
716
|
+
| `reason` | `permission`, `question` or `other` |
|
|
717
|
+
| `waitingSince` | When the wait began, in milliseconds since 1970, or `null` when that is not known |
|
|
718
|
+
| `waitedMs` | How long it has waited, in milliseconds, or `null` |
|
|
719
|
+
| `pullRequest` | With [pull requests](#pull-requests) on, `{ number, checks }` for its branch's pull request, with `checks` `failing`, `pending`, `passing` or `none`. Left out when there is none |
|
|
658
720
|
|
|
659
721
|
Any character in a name that a terminal would act on is written as a `\u` escape, so the JSON is safe to print too.
|
|
660
722
|
|
|
@@ -711,7 +773,7 @@ The prompt then runs the command each time it is drawn, which adds about a tenth
|
|
|
711
773
|
|
|
712
774
|
## For your agents
|
|
713
775
|
|
|
714
|
-
`agent-lookout mcp` lets an AI agent ask which sessions are running and which need you, so one agent can keep track of the others. It is a [Model Context Protocol](https://modelcontextprotocol.io) server. The agent's app starts it and speaks to it over stdin and stdout, so it listens on no port. It asks the Agent Lookout that is already running, the way `agent-lookout status` does, and starts nothing. Its tools only read: none of them can jump to a session, answer one or change a notification.
|
|
776
|
+
`agent-lookout mcp` lets an AI agent ask which sessions are running and which need you, so one agent can keep track of the others. It is a [Model Context Protocol](https://modelcontextprotocol.io) server. The agent's app starts it and speaks to it over stdin and stdout, so it listens on no port. It asks the Agent Lookout that is already running, the way `agent-lookout status` does, and starts nothing. Its tools only read: none of them can jump to a session, stop one, answer one or change a notification.
|
|
715
777
|
|
|
716
778
|
To add it to Claude Code, run this once:
|
|
717
779
|
|
|
@@ -751,11 +813,11 @@ It finds Agent Lookout as `agent-lookout status` does: at `http://127.0.0.1:4777
|
|
|
751
813
|
|
|
752
814
|
It has three tools:
|
|
753
815
|
|
|
754
|
-
| Tool | Answers
|
|
755
|
-
| ---------------------- |
|
|
756
|
-
| `list_sessions` | Every session, those that need you first, longest wait first, then the rest by status, with its `id`, `name`, `agent`, `status`, the `reason` when it needs you, its `folder`, `branch` or `commit`, `app`, `since` and, for a working session, `quietFor`. Give it a `status` to list only those |
|
|
757
|
-
| `sessions_needing_you` | The sessions that need you, longest wait first, with how long each has waited, and a `summary` in one sentence
|
|
758
|
-
| `sources` | Each source's state, as the Sources view says it, and its row of [what each agent can report](#what-each-agent-can-report), with the reason for each no and partly
|
|
816
|
+
| Tool | Answers |
|
|
817
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
818
|
+
| `list_sessions` | Every session, those that need you first, longest wait first, then the rest by status, with its `id`, `name`, `agent`, `status`, the `reason` when it needs you, its `folder`, `branch` or `commit`, with [pull requests](#pull-requests) on its `pullRequest`, `app`, `since` and, for a working session, `quietFor`. Give it a `status` to list only those |
|
|
819
|
+
| `sessions_needing_you` | The sessions that need you, longest wait first, with how long each has waited, and a `summary` in one sentence |
|
|
820
|
+
| `sources` | Each source's state, as the Sources view says it, and its row of [what each agent can report](#what-each-agent-can-report), with the reason for each no and partly |
|
|
759
821
|
|
|
760
822
|
Each answers in JSON. `sessions_needing_you` gives, for example:
|
|
761
823
|
|
|
@@ -773,6 +835,7 @@ Each answers in JSON. `sessions_needing_you` gives, for example:
|
|
|
773
835
|
"folder": "storefront",
|
|
774
836
|
"branch": null,
|
|
775
837
|
"commit": null,
|
|
838
|
+
"pullRequest": null,
|
|
776
839
|
"app": "VS Code",
|
|
777
840
|
"since": "2026-10-06T09:09:48.000Z",
|
|
778
841
|
"waited": "4m 12s",
|
|
@@ -783,7 +846,7 @@ Each answers in JSON. `sessions_needing_you` gives, for example:
|
|
|
783
846
|
}
|
|
784
847
|
```
|
|
785
848
|
|
|
786
|
-
Times are in ISO 8601. A field that is not known is `null`. `counted` is `false` until Agent Lookout has read an agent, when an empty list says nothing, and the summary says so. When an agent's sessions could not be read, such as Claude Code's, the summary names that agent and says its sessions are not counted. `quietFor` is how long a working session's agent has written nothing to the file it is read from, given whenever the agent's source gives that time. From 5 minutes it is what the Sessions list shows as [Quiet for](#quiet-for). Not every agent can report a wait: a Codex session waiting for your approval shows as working. `sources` says which can report what.
|
|
849
|
+
Times are in ISO 8601. A field that is not known is `null`. `counted` is `false` until Agent Lookout has read an agent, when an empty list says nothing, and the summary says so. When an agent's sessions could not be read, such as Claude Code's, the summary names that agent and says its sessions are not counted. `pullRequest` is `{ "number": 51, "checks": "failing" }` for a branch whose pull request Agent Lookout found, with `checks` one of `failing`, `pending`, `passing` and `none`, and `null` for every other session and whenever `AGENT_LOOKOUT_PULL_REQUESTS` is not `on`. It never holds the title, which someone else may have written. `quietFor` is how long a working session's agent has written nothing to the file it is read from, given whenever the agent's source gives that time. From 5 minutes it is what the Sessions list shows as [Quiet for](#quiet-for). Not every agent can report a wait: a Codex session waiting for your approval shows as working. `sources` says which can report what.
|
|
787
850
|
|
|
788
851
|
A session's name, its agent's name, its folder and its branch are written by other programs, such as an agent that writes a [status file](#your-own-agents). The tools say so in their descriptions and in each answer, the summary puts each name in quotation marks, and anything a terminal would act on is taken out of them, as `agent-lookout status` does, and so is any character that shows nothing, in which words could be hidden from you but not from a model. An agent should still treat them as data, never as instructions.
|
|
789
852
|
|
|
@@ -852,13 +915,13 @@ These are macOS only:
|
|
|
852
915
|
- Notifications with no dashboard tab open. On a Mac Agent Lookout shows those itself with `osascript`, which Linux does not have, so on Linux it shows none. Started with `AGENT_LOOKOUT_NOTIFICATIONS=on`, it prints a line saying so. Showing them with `notify-send` is left out for now. Keep a dashboard tab open to be notified.
|
|
853
916
|
- [Jump to a tab of Terminal or iTerm2](#a-session-in-a-tab-of-terminal-or-iterm2), the two Mac apps it can bring forward. A session in a Linux terminal that is not running tmux has no Jump button.
|
|
854
917
|
|
|
855
|
-
If the clock is set by more than a minute while a Claude Code session runs, that session can drop off the list until it is restarted. Linux's `ps` works out when a process started from the clock, so the start time it gives then no longer matches the one in the session's registry file, and the file looks like one a crashed session left behind.
|
|
918
|
+
If the clock is set by more than a minute while a Claude Code session runs, that session can drop off the list until it is restarted. Linux's `ps` works out when a process started from the clock, so the start time it gives then no longer matches the one in the session's registry file, and the file looks like one a crashed session left behind. Stop asks more, a start time within a second of the recorded one, so if the clock is set by more than a second, Stop says it cannot confirm that session's process until the session is restarted.
|
|
856
919
|
|
|
857
920
|
Agent Lookout runs `ps` from `/usr/bin` or `/bin`. Where it is not there, as on NixOS, no session in tmux has a Jump button, and a registry file left behind by a session that crashed shows as a session if another program is given its process ID.
|
|
858
921
|
|
|
859
922
|
## What it does not do yet
|
|
860
923
|
|
|
861
|
-
It cannot
|
|
924
|
+
It cannot resume or answer a session. It [stops](#stop-a-session) a Claude Code session only when you press Stop and confirm, and not one in the desktop app, a Codex session or a session from a status file. An agent through [`agent-lookout mcp`](#for-your-agents), whose tools only read, can do none of these. It covers Claude Code and Codex, and any agent that writes a [status file](#your-own-agents), and only sessions on this computer. Cloud sessions, Codex cloud tasks and browser chats do not appear. [What each agent can report](#what-each-agent-can-report) has a table of what each agent can and cannot show.
|
|
862
925
|
|
|
863
926
|
A notification, an email or a post is sent for four events only: a session starting to wait, finishing, failing or ending. Only Claude Code sessions and sessions from a status file can be seen waiting. A Claude Code session that is not a background job does not say how it ended, so it sends Ended, never Finished or Failed. A Claude Code background job that starts and ends between two runs of the `claude` command, which is run every 30 seconds, leaves the list before the command lists it as finished, so it too sends Ended. A session from a Codex older than 0.155 is never shown as finished, so it sends Ended when it leaves the list, a day after it was last used. With no dashboard tab open, notifications are shown on a Mac only. Those come from Script Editor, unless Agent Lookout runs as the [desktop app](#desktop-app), cannot open the session, and are not cleared when the session moves on.
|
|
864
927
|
|
|
@@ -884,37 +947,39 @@ Put a setting in front of the command that starts Agent Lookout:
|
|
|
884
947
|
AGENT_LOOKOUT_CLAUDE_FEED=off npx agent-lookout
|
|
885
948
|
```
|
|
886
949
|
|
|
887
|
-
| Setting | What it does
|
|
888
|
-
| ------------------------------ |
|
|
889
|
-
| `AGENT_LOOKOUT_PORT` | The port `npx agent-lookout`, `agent-lookout` and `npm start` listen on. The default is 4777.
|
|
890
|
-
| `AGENT_LOOKOUT_HOST` | The address `npx agent-lookout`, `agent-lookout` and `npm start` listen on: `127.0.0.1`, which is the default, `localhost` or `::1`. Anything else is refused, so other computers cannot reach it.
|
|
891
|
-
| `AGENT_LOOKOUT_CLAUDE_BIN` | The full path of the `claude` program. When set, it is the only place Agent Lookout looks.
|
|
892
|
-
| `AGENT_LOOKOUT_CLAUDE_HOME` | A folder to read in place of `~/.claude`. When set, the `claude` command is not run unless `AGENT_LOOKOUT_CLAUDE_BIN` is set too.
|
|
893
|
-
| `AGENT_LOOKOUT_CLAUDE_FEED` | Set to `off` and Agent Lookout never runs the `claude` command. Sessions come from the session files alone, and finished or failed background jobs are not listed.
|
|
894
|
-
| `AGENT_LOOKOUT_WAITING_TEXT` | Set to `off` and Agent Lookout never opens a Claude Code transcript. A waiting session then shows its reason alone, without what it is asking.
|
|
895
|
-
| `AGENT_LOOKOUT_CODEX_HOME` | A folder to read in place of the Codex folder. A folder with no `sessions` folder in it shows no Codex sessions.
|
|
896
|
-
| `CODEX_HOME` | Codex's own setting for where it keeps its files. When it is set, Agent Lookout reads that folder too, unless `AGENT_LOOKOUT_CODEX_HOME` is set.
|
|
897
|
-
| `AGENT_LOOKOUT_STATUS_DIR` | A folder of [status files](#your-own-agents) to read in place of `~/.agent-lookout/sessions`.
|
|
898
|
-
| `AGENT_LOOKOUT_HISTORY` | Set to `off` and Agent Lookout keeps the Events log and the charts in memory only and writes nothing to disk, so they start empty each time it starts. See [History](#history).
|
|
899
|
-
| `AGENT_LOOKOUT_HISTORY_DIR` | A folder to keep the [history](#history) in, in place of `~/.agent-lookout/history`.
|
|
900
|
-
| `AGENT_LOOKOUT_NOTIFICATIONS` | Set to `on` and, on a Mac, Agent Lookout shows notifications of waits itself from the moment it starts. A dashboard page that has notifications off turns them off again. Anywhere else it prints a line saying it shows none itself.
|
|
901
|
-
| `AGENT_LOOKOUT_TMUX` | Set to `off` and Agent Lookout never runs `tmux`. Sessions in tmux are still listed, without a Jump button.
|
|
902
|
-
| `AGENT_LOOKOUT_TERMINAL_JUMP` | Set to `off` and Agent Lookout never looks for, or brings forward, a tab of Terminal or iTerm2. Sessions there are still listed, without a Jump button.
|
|
903
|
-
| `
|
|
904
|
-
| `
|
|
905
|
-
| `
|
|
906
|
-
| `
|
|
907
|
-
| `
|
|
908
|
-
| `
|
|
909
|
-
| `
|
|
910
|
-
| `
|
|
911
|
-
| `
|
|
912
|
-
| `
|
|
913
|
-
| `
|
|
950
|
+
| Setting | What it does |
|
|
951
|
+
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
952
|
+
| `AGENT_LOOKOUT_PORT` | The port `npx agent-lookout`, `agent-lookout` and `npm start` listen on. The default is 4777. |
|
|
953
|
+
| `AGENT_LOOKOUT_HOST` | The address `npx agent-lookout`, `agent-lookout` and `npm start` listen on: `127.0.0.1`, which is the default, `localhost` or `::1`. Anything else is refused, so other computers cannot reach it. |
|
|
954
|
+
| `AGENT_LOOKOUT_CLAUDE_BIN` | The full path of the `claude` program. When set, it is the only place Agent Lookout looks. |
|
|
955
|
+
| `AGENT_LOOKOUT_CLAUDE_HOME` | A folder to read in place of `~/.claude`. When set, the `claude` command is not run unless `AGENT_LOOKOUT_CLAUDE_BIN` is set too. |
|
|
956
|
+
| `AGENT_LOOKOUT_CLAUDE_FEED` | Set to `off` and Agent Lookout never runs the `claude` command. Sessions come from the session files alone, and finished or failed background jobs are not listed. |
|
|
957
|
+
| `AGENT_LOOKOUT_WAITING_TEXT` | Set to `off` and Agent Lookout never opens a Claude Code transcript. A waiting session then shows its reason alone, without what it is asking. |
|
|
958
|
+
| `AGENT_LOOKOUT_CODEX_HOME` | A folder to read in place of the Codex folder. A folder with no `sessions` folder in it shows no Codex sessions. |
|
|
959
|
+
| `CODEX_HOME` | Codex's own setting for where it keeps its files. When it is set, Agent Lookout reads that folder too, unless `AGENT_LOOKOUT_CODEX_HOME` is set. |
|
|
960
|
+
| `AGENT_LOOKOUT_STATUS_DIR` | A folder of [status files](#your-own-agents) to read in place of `~/.agent-lookout/sessions`. |
|
|
961
|
+
| `AGENT_LOOKOUT_HISTORY` | Set to `off` and Agent Lookout keeps the Events log and the charts in memory only and writes nothing to disk, so they start empty each time it starts. See [History](#history). |
|
|
962
|
+
| `AGENT_LOOKOUT_HISTORY_DIR` | A folder to keep the [history](#history) in, in place of `~/.agent-lookout/history`. |
|
|
963
|
+
| `AGENT_LOOKOUT_NOTIFICATIONS` | Set to `on` and, on a Mac, Agent Lookout shows notifications of waits itself from the moment it starts. A dashboard page that has notifications off turns them off again. Anywhere else it prints a line saying it shows none itself. |
|
|
964
|
+
| `AGENT_LOOKOUT_TMUX` | Set to `off` and Agent Lookout never runs `tmux`. Sessions in tmux are still listed, without a Jump button. |
|
|
965
|
+
| `AGENT_LOOKOUT_TERMINAL_JUMP` | Set to `off` and Agent Lookout never looks for, or brings forward, a tab of Terminal or iTerm2. Sessions there are still listed, without a Jump button. |
|
|
966
|
+
| `AGENT_LOOKOUT_STOP` | Set to `off` and Agent Lookout never stops a session: no session has a Stop button, Left running has no End all…, and the server answers no request to stop one. |
|
|
967
|
+
| `AGENT_LOOKOUT_EMAIL_TO` | The one address emails go to. With `AGENT_LOOKOUT_SMTP_URL` set too, it turns [email](#email) on. |
|
|
968
|
+
| `AGENT_LOOKOUT_SMTP_URL` | The mail server emails go through, with the user name and password: `smtps://name:password@server:port`. |
|
|
969
|
+
| `AGENT_LOOKOUT_EMAIL_FROM` | The address emails come from. The default is the address they go to. |
|
|
970
|
+
| `AGENT_LOOKOUT_EMAIL_AFTER` | How many seconds a wait lasts before it is emailed, from 0 to 86400. The default is 60. |
|
|
971
|
+
| `AGENT_LOOKOUT_EMAIL_EVENTS` | What is emailed: `needs-you`, `finished`, `failed` and `ended`, any of them, separated by commas. The default is `needs-you`. |
|
|
972
|
+
| `AGENT_LOOKOUT_EMAIL_ASKING` | Set to `on` and the email for a wait says what the session is asking, such as `Run: npm test`, which can hold a command, a web address or a file's full path. The default is `off`. See [Email](#what-a-waiting-session-is-asking-by-email). |
|
|
973
|
+
| `AGENT_LOOKOUT_WEBHOOK_URL` | The one address [webhook](#webhook) posts go to, beginning with `https://`. It turns the webhook on. |
|
|
974
|
+
| `AGENT_LOOKOUT_WEBHOOK_EVENTS` | What is posted, as for `AGENT_LOOKOUT_EMAIL_EVENTS`. The default is `needs-you`. |
|
|
975
|
+
| `AGENT_LOOKOUT_WEBHOOK_AFTER` | How many seconds a wait lasts before it is posted, from 0 to 86400. The default is 60. |
|
|
976
|
+
| `AGENT_LOOKOUT_WEBHOOK_ASKING` | Set to `on` and the post for a wait says what the session is asking, as `AGENT_LOOKOUT_EMAIL_ASKING` does for email. The default is `off`. See [Webhook](#what-a-waiting-session-is-asking-in-a-post). |
|
|
977
|
+
| `AGENT_LOOKOUT_PULL_REQUESTS` | Set to `on` and Agent Lookout asks your own `gh` for each session's [pull request](#pull-requests) on github.com and its checks, and shows them. The default is `off`. With it on, the names of the repository and the branch go to GitHub, through `gh`, with `gh`'s own login. Any value but `on` or `off` leaves it off, and the card and the terminal name the setting |
|
|
978
|
+
| `AGENT_LOOKOUT_URL` | The address `agent-lookout status` and `agent-lookout mcp` ask, such as `http://127.0.0.1:4778`, in place of `http://127.0.0.1:4777` and then `http://localhost:5173`. Only an address on this computer is accepted. Set it where the command runs, not where Agent Lookout starts. |
|
|
914
979
|
|
|
915
980
|
To see the empty screen, set `AGENT_LOOKOUT_CLAUDE_HOME`, `AGENT_LOOKOUT_CODEX_HOME`, `AGENT_LOOKOUT_STATUS_DIR` and `AGENT_LOOKOUT_HISTORY_DIR` to an empty folder. With only the first set, Codex sessions and sessions from status files still appear.
|
|
916
981
|
|
|
917
|
-
The Claude Code, transcript, Codex, status file, history, notification, tmux, terminal tab, email and
|
|
982
|
+
The Claude Code, transcript, Codex, status file, history, notification, tmux, terminal tab, stop, email, webhook and pull request settings work with `npx agent-lookout` and `agent-lookout`, and in a clone with `npm start` and `npm run dev`. The port and address settings apply to `npx agent-lookout`, `agent-lookout` and `npm start`, and `AGENT_LOOKOUT_URL` to `agent-lookout status` and `agent-lookout mcp` only. To choose the port for `npm run dev`, pass it after `--`:
|
|
918
983
|
|
|
919
984
|
```sh
|
|
920
985
|
npm run dev -- --port 5180
|
|
@@ -950,7 +1015,7 @@ It prints `{"ok":true,"version":"0.2.1"}`, or a later version number. If you run
|
|
|
950
1015
|
|
|
951
1016
|
Every other setting under [Settings you can change](#settings-you-can-change) works with it as with `npm start`. It ends with 0 when you press Ctrl+C, and with 1 when it cannot start, such as when the port is in use. Under `npx agent-lookout`, the shell reports the interrupt instead, as exit code 130.
|
|
952
1017
|
|
|
953
|
-
Agent Lookout is on npm, so `npx agent-lookout` starts it with nothing to clone or install first, and `npx agent-lookout --open` opens it in the browser as well. npm downloads the package the first time,
|
|
1018
|
+
Agent Lookout is on npm, so `npx agent-lookout` starts it with nothing to clone or install first, and `npx agent-lookout --open` opens it in the browser as well. npm downloads the package the first time, under 2 MB with what it needs and about 4 MB once installed, and keeps it in its cache. The package holds the built dashboard and the collector as plain JavaScript, so it needs Node.js and nothing else. Each time, npx asks npm's registry whether a newer version is out, as it does for any package it runs. To start it without that, install it once with `npm install -g agent-lookout` and run `agent-lookout`.
|
|
954
1019
|
|
|
955
1020
|
In a clone, run `npm run build` and `npm link` once in the `agent-lookout` folder, then `agent-lookout` from any folder.
|
|
956
1021
|
|
|
@@ -1088,6 +1153,10 @@ Use `http://localhost:5173` if you started it with `npm run dev`. It prints the
|
|
|
1088
1153
|
3. If it says where posts go and nothing more, no wait has lasted the delay since Agent Lookout started. A session that was already waiting when it started sends nothing.
|
|
1089
1154
|
4. If it says when the last post went, the service took it. Check the channel the webhook was made for, and that the app is still allowed to post there.
|
|
1090
1155
|
|
|
1156
|
+
### No pull request shows
|
|
1157
|
+
|
|
1158
|
+
Pull requests are off unless Agent Lookout was started with `AGENT_LOOKOUT_PULL_REQUESTS=on`. The Pull requests card in Settings says whether they are on, and whether `gh` was found and is signed in: run `gh auth status` in a terminal to check, and `gh auth login` to sign in. A session shows one only when its branch has a pull request on github.com, its repository's remote is on github.com, and the branch is not the default one and is not named with digits alone, such as `51`. A new pull request, or a check that has finished, shows within about 2 minutes. The Mac app opened from the Finder or the Dock gets none of your shell's settings: [Desktop app](#desktop-app) says how to give it one.
|
|
1159
|
+
|
|
1091
1160
|
### The page says Agent Lookout has stopped updating
|
|
1092
1161
|
|
|
1093
1162
|
The program serving the page has stopped. The page keeps the last thing it saw, under a notice that says how old it is, and its timers stop at the last moment it heard from Agent Lookout. Start it again with `npx agent-lookout`, or in a clone with `npm start` or `npm run dev`, and the page catches up on its own.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-lookout",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Shows the AI agent sessions on your computer in one browser page, and which need you.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-agents",
|
|
@@ -71,14 +71,13 @@
|
|
|
71
71
|
"check": "npm run check:layout && npm run typecheck && npm run lint && npm run format:check && npm run test"
|
|
72
72
|
},
|
|
73
73
|
"dependencies": {
|
|
74
|
-
"
|
|
75
|
-
"nodemailer": "^10.0.15",
|
|
76
|
-
"zod": "^4.6.5"
|
|
74
|
+
"nodemailer": "^10.0.15"
|
|
77
75
|
},
|
|
78
76
|
"devDependencies": {
|
|
79
77
|
"@eslint/js": "^10.0.1",
|
|
80
78
|
"@fontsource/atkinson-hyperlegible-mono": "^5.3.0",
|
|
81
79
|
"@fontsource/atkinson-hyperlegible-next": "^5.3.0",
|
|
80
|
+
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
82
81
|
"@tailwindcss/vite": "^4.3.3",
|
|
83
82
|
"@types/node": "^20.19.43",
|
|
84
83
|
"@types/react": "^19.3.0",
|
|
@@ -110,6 +109,7 @@
|
|
|
110
109
|
"typescript-eslint": "^8.71.0",
|
|
111
110
|
"vite": "^7.3.6",
|
|
112
111
|
"vitest": "^4.1.11",
|
|
113
|
-
"vitest-browser-react": "^2.3.0"
|
|
112
|
+
"vitest-browser-react": "^2.3.0",
|
|
113
|
+
"zod": "^4.6.5"
|
|
114
114
|
}
|
|
115
115
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as y,j as e}from"./react-C2DiJaR6.js";import{w as F,u as A,J as $,c as E,D as L,l as M,n as O,M as v,o as q,p as D,q as C,F as I,v as h,x as P,y as k,O as R,f as g,T as W,z as B,A as J,B as K,E as _,G as z,I as G,K as U,N as w,P as S,Q as H,R as Q,L as V,U as X}from"./index-Ckda8OV4.js";import"./motion-BAhdRuCw.js";import"./radix-27o0jeIu.js";const T=[];function Y(s,n){const t=CSS.escape(s),a=[...document.querySelectorAll(`:is([data-slot="session-row"], [data-slot="board-card"], [data-slot="hero-session"])[data-session="${t}"] a[data-part="name"]`)];return n!==null&&a.includes(n)?n:a.find(l=>!l.closest('[data-slot="hero-session"]'))??a[0]??null}function Z({session:s,gone:n,asOf:t,now:a}){const l=s.status==="finished"||s.status==="failed",r=B(s),o=r?"stale":n&&s.status==="needs-you"?"answered":s.status,c=s.statusSince,i=c!==null?Math.max(0,t-c):null,m=J(s,t),d=s.status==="needs-you",p=d?K(s):null,j=d&&!n&&s.waitingText?.trim()||null,u=c!==null?`${l?"at":r?"idle since":"since"} ${k(c,a)}`:"time not reported",x=[d?_(s):null,u,m&&z(m)].filter(f=>typeof f=="string");return e.jsxs(h,{label:"Status",note:j?e.jsxs(e.Fragment,{children:[e.jsx(H,{"data-part":"asking",lines:2,className:"wrap-anywhere",children:j}),p&&e.jsx("span",{className:"block",children:p})]}):p??void 0,children:[e.jsxs("span",{className:"inline-flex items-center gap-2",children:[e.jsx(G,{kind:o}),e.jsx("span",{"data-part":"status",children:r?"Stale":U[s.status]}),i!==null&&e.jsxs("span",{"data-part":"duration",className:"tabular-nums",children:[e.jsx("span",{className:"sr-only",children:l?` ${w(i)} ago`:` for ${w(i)}`}),e.jsxs("span",{"aria-hidden":!0,children:[S(i),l&&" ago"]})]})]}),e.jsx("span",{"data-part":"since",className:"block text-caption font-normal text-ink-secondary tabular-nums",children:x.join(", ")})]})}function ee({session:s,state:n,now:t,asOf:a}){const l=y.useMemo(()=>Q({sessions:n.snapshot?.sessions??T,events:n.events,history:n.history,now:t,asOf:a,eventsFull:n.events.length>=v}),[n.snapshot,n.events,n.history,t,a]);if(!l)return e.jsxs(h,{label:"Waits",children:["Not known",e.jsx("span",{className:"block text-caption font-normal text-ink-secondary",children:"The history could not be read"})]});const r=l.sessions.find(i=>i.id===s.id),o=l.period.today?"today":`since ${g(l.period.from)}`;let c="None";if(r){const i=`${r.startKnown?"":"at least "}${S(r.ms)}`;c=r.times===1?`Once, ${i}`:`${r.times} times, ${i} in all`}return e.jsxs(h,{label:"Waits",children:[e.jsx("span",{"data-part":"waits",className:"tabular-nums",children:c}),e.jsx("span",{className:"block text-caption font-normal text-ink-secondary",children:o})]})}function N({title:s,aside:n,children:t,...a}){return e.jsxs("section",{...a,"aria-label":s,className:"mt-6",children:[e.jsxs("div",{className:"flex items-baseline justify-between gap-4 border-b border-hairline pb-2",children:[e.jsx("h3",{className:"text-body font-semibold text-ink",children:s}),n&&e.jsx("p",{className:"text-caption text-ink-muted",children:n})]}),t]})}function se({session:s,gone:n,state:t,now:a,asOf:l}){const r=t.snapshot?.sources??[],o=t.snapshot?.sessions??T,c=O(s.surface),i=t.events.length>=v,m=y.useMemo(()=>q(t.events.filter(u=>u.sessionId===s.id),o),[t.events,o,s.id]),d=D(t.events,t.history,i),p=y.useMemo(()=>t.history?C({sessions:o,events:t.events,history:t.history,now:a,asOf:l,eventsFull:i}):null,[o,t.events,t.history,a,l,i]),j=p?.rows.find(u=>u.id===s.id);return e.jsxs(e.Fragment,{children:[n&&e.jsx("p",{"data-part":"gone",className:"mt-4 text-body text-ink-secondary",children:"This session has left the list. Here is what was last known of it."}),e.jsxs(I,{className:"mt-3",children:[e.jsx(Z,{session:s,gone:n,asOf:l,now:a}),e.jsx(h,{label:"Agent",children:P(s,r)}),c!==null&&e.jsx(h,{label:"App",children:c}),e.jsx(h,{label:"Folder",mono:s.cwd!==null,children:s.cwd!==null?e.jsx("span",{"data-part":"folder",className:"wrap-anywhere select-text",children:s.cwd.split("/").map((u,x,f)=>e.jsxs(y.Fragment,{children:[u,x<f.length-1&&e.jsxs(e.Fragment,{children:["/",e.jsx("wbr",{})]})]},x))}):"Not known"}),s.git?.repository!==void 0&&e.jsx(h,{label:"Repository",children:e.jsx("span",{"data-part":"repository",className:"wrap-anywhere",children:s.git.repository.name})}),s.git?.branch!==void 0?e.jsx(h,{label:"Branch",children:e.jsx("span",{"data-part":"branch",className:"wrap-anywhere",children:s.git.branch})}):s.git?.commit!==void 0&&e.jsx(h,{label:"Commit",mono:!0,children:s.git.commit}),e.jsx(h,{label:"Started",children:e.jsx("span",{className:"tabular-nums",children:s.startedAt!==null?k(s.startedAt,a):"Not reported"})}),s.pid!==void 0&&e.jsx(h,{label:"Process",mono:!0,note:s.alive===!1?"The process has ended.":void 0,children:s.pid}),e.jsx(ee,{session:s,state:t,now:a,asOf:l})]}),e.jsx(N,{"data-part":"events",title:"Events",aside:d?`since ${g(d.at)}`:void 0,children:m.length>0?e.jsx(R,{entries:m,now:a,className:"pt-0.5"}):e.jsxs("p",{className:"py-2.5 text-body text-ink-secondary",children:["Nothing has happened to this session"," ",d?`since ${g(d.at)}`:"yet","."]})}),e.jsx(N,{"data-part":"timeline",title:"Timeline",aside:"last hour",children:p&&j?e.jsx(W,{timeline:p,rows:[j],named:!1,label:"Its last hour",className:"pt-3"}):e.jsx("p",{className:"py-2.5 text-body text-ink-secondary",children:p?"It did not run in the last hour.":"The last hour could not be read. The page asks again every two seconds."})})]})}function te({sessionId:s,open:n,onClose:t,state:a,now:l}){const r=a.snapshot?.sessions.find(b=>b.id===s)??null,[o,c]=y.useState(null);r!==null&&r!==o?.session?c({session:r,at:a.lastOkAt??l}):r===null&&o?.session.waitingText!==void 0&&c({...o,session:F(o.session)});const i=r??o?.session??null,m=r===null&&o!==null,d=A(i??{id:s,source:"status-files",surface:"unknown",links:{}}),p=m&&o?o.at:a.phase==="stalled"&&a.lastOkAt!==null?a.lastOkAt:l,j=d.outcome!==null||d.asking!==null;let u,x,f="wide";return i?(u=i.name,x=e.jsxs(e.Fragment,{children:[!m&&e.jsx("div",{className:E("flex flex-wrap items-center gap-x-2 gap-y-1",j&&"mt-3"),children:e.jsx($,{session:i,jump:d})}),e.jsx(se,{session:i,gone:m,state:a,now:l,asOf:p})]})):a.snapshot===null?(u="Session",x=e.jsx(V,{label:"Reading sessions",className:"justify-start px-0 pt-5 pb-1"})):(u="No such session",f="sm",x=e.jsxs("div",{"data-part":"missing",children:[e.jsx("p",{className:"mt-2 text-body text-ink-secondary",children:"Agent Lookout is not watching a session at this address. It may have ended before this page was opened."}),e.jsx(X,{className:"mt-4",onClick:t,children:"Go to the Overview"})]})),e.jsx(L,{open:n,onOpenChange:b=>{b||t()},title:u,size:f,focusTitle:!0,returnFocus:b=>Y(s,b)??document.querySelector("main"),actions:i&&!m&&e.jsx(M,{session:i,jump:d,variant:i.status==="needs-you"?"needs-you":"quiet"}),children:x})}function re({sessionId:s,onClose:n,state:t,now:a}){const[l,r]=y.useState(s);return s!==null&&s!==l&&r(s),l===null?null:e.jsx(te,{sessionId:l,open:s!==null,onClose:n,state:t,now:a},l)}export{re as SessionPanel};
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|