feat: add claude, codex, and opencode integrations
This commit is contained in:
parent
ca4270b31f
commit
28fb23cdaf
|
|
@ -0,0 +1,198 @@
|
|||
# integrations
|
||||
|
||||
herdr works without any hook or plugin setup.
|
||||
|
||||
out of the box, it detects supported agents by combining foreground process detection with screen heuristics. that is enough to give you workspace awareness with zero configuration.
|
||||
|
||||
optional integrations improve the semantic signal on top of that.
|
||||
|
||||
## how herdr uses integrations
|
||||
|
||||
herdr uses a hybrid model:
|
||||
|
||||
- **process detection** owns pane identity, liveness, and "the process is gone"
|
||||
- **agent integrations** report semantic state like `working`, `blocked`, and `idle` when the tool exposes those events
|
||||
- **screen heuristics** remain the fallback for gaps, unsupported tools, or incomplete hook surfaces
|
||||
|
||||
that means hooks/plugins do **not** become the source of truth for pane ownership. they enrich state reporting; they do not replace process detection.
|
||||
|
||||
## install commands
|
||||
|
||||
```bash
|
||||
herdr integration install pi
|
||||
herdr integration install claude
|
||||
herdr integration install codex
|
||||
herdr integration install opencode
|
||||
```
|
||||
|
||||
## uninstall commands
|
||||
|
||||
```bash
|
||||
herdr integration uninstall pi
|
||||
herdr integration uninstall claude
|
||||
herdr integration uninstall codex
|
||||
herdr integration uninstall opencode
|
||||
```
|
||||
|
||||
## pi
|
||||
|
||||
install:
|
||||
|
||||
```bash
|
||||
herdr integration install pi
|
||||
```
|
||||
|
||||
this writes the bundled pi extension to:
|
||||
|
||||
```text
|
||||
~/.pi/agent/extensions/herdr-agent-state.ts
|
||||
```
|
||||
|
||||
pi is the cleanest integration. it already has an authoritative hook model, so herdr can get direct state reports without guessing as much from the terminal.
|
||||
|
||||
uninstall:
|
||||
|
||||
```bash
|
||||
herdr integration uninstall pi
|
||||
```
|
||||
|
||||
this removes:
|
||||
|
||||
```text
|
||||
~/.pi/agent/extensions/herdr-agent-state.ts
|
||||
```
|
||||
|
||||
## claude code
|
||||
|
||||
install:
|
||||
|
||||
```bash
|
||||
herdr integration install claude
|
||||
```
|
||||
|
||||
this:
|
||||
|
||||
- writes the hook script to `~/.claude/hooks/herdr-agent-state.sh`
|
||||
- updates `~/.claude/settings.json`
|
||||
|
||||
current hook mapping:
|
||||
|
||||
- `UserPromptSubmit` → `working`
|
||||
- `PreToolUse` → `working`
|
||||
- `PermissionRequest` → `blocked`
|
||||
- `Stop` → `idle`
|
||||
- `SessionEnd` → `release`
|
||||
|
||||
notes:
|
||||
|
||||
- claude's current hook surface improves state reporting, but it is not a perfect permission lifecycle.
|
||||
- when a permission prompt is canceled, claude does not currently give herdr a clean hook event that always resolves the pane out of `blocked` immediately.
|
||||
- that is acceptable in herdr's model: process detection still owns liveness, and heuristics remain the fallback for unresolved edges.
|
||||
|
||||
uninstall:
|
||||
|
||||
```bash
|
||||
herdr integration uninstall claude
|
||||
```
|
||||
|
||||
this:
|
||||
|
||||
- removes `~/.claude/hooks/herdr-agent-state.sh`
|
||||
- removes herdr-owned hook entries from `~/.claude/settings.json`
|
||||
|
||||
## codex
|
||||
|
||||
install:
|
||||
|
||||
```bash
|
||||
herdr integration install codex
|
||||
```
|
||||
|
||||
this:
|
||||
|
||||
- writes the hook script to `~/.codex/herdr-agent-state.sh`
|
||||
- updates `~/.codex/hooks.json`
|
||||
- ensures `codex_hooks = true` in `~/.codex/config.toml`
|
||||
|
||||
current hook mapping:
|
||||
|
||||
- `SessionStart` → `idle`
|
||||
- `UserPromptSubmit` → `working`
|
||||
- `PreToolUse` → `working`
|
||||
- `Stop` → `idle`
|
||||
|
||||
notes:
|
||||
|
||||
- codex does **not** currently expose a permission-specific hook like claude or opencode, so `blocked` still depends on herdr's normal heuristics.
|
||||
- codex currently renders hook lifecycle messages in its own tui, for example `Running SessionStart hook` and `SessionStart hook (completed)`.
|
||||
- that noise is an upstream codex limitation, not a herdr-specific issue.
|
||||
- codex has a `suppressOutput` field in its hook output schema, but it is currently not effective for suppressing those tui lifecycle lines.
|
||||
|
||||
uninstall:
|
||||
|
||||
```bash
|
||||
herdr integration uninstall codex
|
||||
```
|
||||
|
||||
this:
|
||||
|
||||
- removes `~/.codex/herdr-agent-state.sh`
|
||||
- removes herdr-owned hook entries from `~/.codex/hooks.json`
|
||||
- intentionally leaves `~/.codex/config.toml` alone
|
||||
|
||||
that last point is deliberate: herdr does **not** try to guess whether `codex_hooks = true` is still needed for some other codex hook setup.
|
||||
|
||||
## opencode
|
||||
|
||||
install:
|
||||
|
||||
```bash
|
||||
herdr integration install opencode
|
||||
```
|
||||
|
||||
this writes the bundled plugin to:
|
||||
|
||||
```text
|
||||
~/.config/opencode/plugins/herdr-agent-state.js
|
||||
```
|
||||
|
||||
current plugin mapping:
|
||||
|
||||
- `permission.asked` → `blocked`
|
||||
- `permission.replied: once|always` → `working`
|
||||
- `permission.replied: reject` → `idle`
|
||||
- `session.status: busy|retry` → `working`
|
||||
- `session.status: idle` → `idle`
|
||||
- `session.idle` → `idle`
|
||||
|
||||
notes:
|
||||
|
||||
- opencode has the richest event surface of the currently supported integrations.
|
||||
- herdr intentionally does **not** guess that `session.deleted` means process exit. process detection still owns liveness and pane identity.
|
||||
|
||||
uninstall:
|
||||
|
||||
```bash
|
||||
herdr integration uninstall opencode
|
||||
```
|
||||
|
||||
this removes:
|
||||
|
||||
```text
|
||||
~/.config/opencode/plugins/herdr-agent-state.js
|
||||
```
|
||||
|
||||
## known limitations
|
||||
|
||||
- these integrations only activate inside herdr-managed panes.
|
||||
- if an agent has an incomplete hook surface, herdr falls back to process detection and screen heuristics rather than inventing lease or ttl behavior.
|
||||
- codex currently shows hook lifecycle chatter in its own tui until upstream adds a real silent mode.
|
||||
|
||||
## troubleshooting
|
||||
|
||||
if an install command succeeds but you do not see improved state reporting:
|
||||
|
||||
1. make sure you launched the agent inside a herdr pane
|
||||
2. restart the agent session so it picks up the new hook/plugin config
|
||||
3. verify the expected config file was written to the path above
|
||||
4. remember that unsupported transitions still fall back to herdr's built-in heuristics
|
||||
34
README.md
34
README.md
|
|
@ -7,7 +7,7 @@
|
|||
<p align="center">herd your agents.</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://herdr.dev">herdr.dev</a> · <a href="#install">install</a> · <a href="#usage">usage</a> · <a href="./CONFIGURATION.md">configuration</a> · <a href="./SKILL.md">agent skill</a> · <a href="./SOCKET_API.md">socket api</a>
|
||||
<a href="https://herdr.dev">herdr.dev</a> · <a href="#install">install</a> · <a href="#usage">usage</a> · <a href="./INTEGRATIONS.md">integrations</a> · <a href="./CONFIGURATION.md">configuration</a> · <a href="./SKILL.md">agent skill</a> · <a href="./SOCKET_API.md">socket api</a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
|
@ -239,10 +239,42 @@ this means detection works with any supported agent, installed any way, with zer
|
|||
|
||||
the heuristics are pattern-matched against each agent's actual terminal output: prompt boxes, spinners, waiting-for-input messages, tool execution indicators. detection runs on a separate async task per pane, polled every 300-500ms, decoupled from terminal rendering.
|
||||
|
||||
## optional direct integrations
|
||||
|
||||
herdr also supports optional direct integrations for tools that expose hooks or plugins:
|
||||
|
||||
- [pi](./INTEGRATIONS.md#pi)
|
||||
- [claude code](./INTEGRATIONS.md#claude-code)
|
||||
- [codex](./INTEGRATIONS.md#codex)
|
||||
- [opencode](./INTEGRATIONS.md#opencode)
|
||||
|
||||
install them with:
|
||||
|
||||
```bash
|
||||
herdr integration install pi
|
||||
herdr integration install claude
|
||||
herdr integration install codex
|
||||
herdr integration install opencode
|
||||
```
|
||||
|
||||
remove them with:
|
||||
|
||||
```bash
|
||||
herdr integration uninstall pi
|
||||
herdr integration uninstall claude
|
||||
herdr integration uninstall codex
|
||||
herdr integration uninstall opencode
|
||||
```
|
||||
|
||||
these integrations improve semantic state reporting, but they do not replace herdr's core process detection model. for setup details, file locations, caveats, and uninstall behavior, see [`INTEGRATIONS.md`](./INTEGRATIONS.md).
|
||||
|
||||
known codex caveat: codex currently renders hook lifecycle lines in its own tui when hooks are enabled. that noise is upstream codex behavior, not herdr-specific.
|
||||
|
||||
## api and automation
|
||||
|
||||
for direct integration details, use the docs instead of reverse-engineering the README:
|
||||
|
||||
- [`INTEGRATIONS.md`](./INTEGRATIONS.md) — install and behavior notes for pi, claude code, codex, and opencode
|
||||
- [`SKILL.md`](./SKILL.md) — reusable agent skill for agents already running inside herdr
|
||||
- [`SOCKET_API.md`](./SOCKET_API.md) — canonical socket protocol + cli wrapper reference
|
||||
|
||||
|
|
|
|||
140
src/cli.rs
140
src/cli.rs
|
|
@ -99,6 +99,7 @@ fn run_integration_command(args: &[String]) -> std::io::Result<i32> {
|
|||
|
||||
match subcommand {
|
||||
"install" => integration_install(&args[1..]),
|
||||
"uninstall" => integration_uninstall(&args[1..]),
|
||||
_ => {
|
||||
print_integration_help();
|
||||
Ok(2)
|
||||
|
|
@ -450,11 +451,11 @@ fn pane_run(args: &[String]) -> std::io::Result<i32> {
|
|||
|
||||
fn integration_install(args: &[String]) -> std::io::Result<i32> {
|
||||
let Some(target) = args.first().map(|arg| arg.as_str()) else {
|
||||
eprintln!("usage: herdr integration install <pi>");
|
||||
eprintln!("usage: herdr integration install <pi|claude|codex|opencode>");
|
||||
return Ok(2);
|
||||
};
|
||||
if args.len() != 1 {
|
||||
eprintln!("usage: herdr integration install <pi>");
|
||||
eprintln!("usage: herdr integration install <pi|claude|codex|opencode>");
|
||||
return Ok(2);
|
||||
}
|
||||
|
||||
|
|
@ -464,9 +465,135 @@ fn integration_install(args: &[String]) -> std::io::Result<i32> {
|
|||
println!("installed pi integration to {}", path.display());
|
||||
Ok(0)
|
||||
}
|
||||
"claude" => {
|
||||
let installed = crate::integration::install_claude()?;
|
||||
println!(
|
||||
"installed claude integration hook to {}",
|
||||
installed.hook_path.display()
|
||||
);
|
||||
println!(
|
||||
"ensured claude settings at {}",
|
||||
installed.settings_path.display()
|
||||
);
|
||||
Ok(0)
|
||||
}
|
||||
"codex" => {
|
||||
let installed = crate::integration::install_codex()?;
|
||||
println!(
|
||||
"installed codex integration hook to {}",
|
||||
installed.hook_path.display()
|
||||
);
|
||||
println!("ensured codex hooks at {}", installed.hooks_path.display());
|
||||
println!(
|
||||
"ensured codex config at {}",
|
||||
installed.config_path.display()
|
||||
);
|
||||
Ok(0)
|
||||
}
|
||||
"opencode" => {
|
||||
let installed = crate::integration::install_opencode()?;
|
||||
println!(
|
||||
"installed opencode integration plugin to {}",
|
||||
installed.plugin_path.display()
|
||||
);
|
||||
Ok(0)
|
||||
}
|
||||
_ => {
|
||||
eprintln!("unknown integration target: {target}");
|
||||
eprintln!("currently supported: pi");
|
||||
eprintln!("currently supported: pi, claude, codex, opencode");
|
||||
Ok(2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn integration_uninstall(args: &[String]) -> std::io::Result<i32> {
|
||||
let Some(target) = args.first().map(|arg| arg.as_str()) else {
|
||||
eprintln!("usage: herdr integration uninstall <pi|claude|codex|opencode>");
|
||||
return Ok(2);
|
||||
};
|
||||
if args.len() != 1 {
|
||||
eprintln!("usage: herdr integration uninstall <pi|claude|codex|opencode>");
|
||||
return Ok(2);
|
||||
}
|
||||
|
||||
match target {
|
||||
"pi" => {
|
||||
let result = crate::integration::uninstall_pi()?;
|
||||
if result.removed_extension {
|
||||
println!(
|
||||
"removed pi integration extension at {}",
|
||||
result.extension_path.display()
|
||||
);
|
||||
} else {
|
||||
println!(
|
||||
"no pi integration extension found at {}",
|
||||
result.extension_path.display()
|
||||
);
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
"claude" => {
|
||||
let result = crate::integration::uninstall_claude()?;
|
||||
if result.removed_hook_file {
|
||||
println!("removed claude hook at {}", result.hook_path.display());
|
||||
} else {
|
||||
println!("no claude hook found at {}", result.hook_path.display());
|
||||
}
|
||||
if result.updated_settings {
|
||||
println!(
|
||||
"removed herdr claude hook entries from {}",
|
||||
result.settings_path.display()
|
||||
);
|
||||
} else {
|
||||
println!(
|
||||
"no herdr claude hook entries found in {}",
|
||||
result.settings_path.display()
|
||||
);
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
"codex" => {
|
||||
let result = crate::integration::uninstall_codex()?;
|
||||
if result.removed_hook_file {
|
||||
println!("removed codex hook at {}", result.hook_path.display());
|
||||
} else {
|
||||
println!("no codex hook found at {}", result.hook_path.display());
|
||||
}
|
||||
if result.updated_hooks {
|
||||
println!(
|
||||
"removed herdr codex hook entries from {}",
|
||||
result.hooks_path.display()
|
||||
);
|
||||
} else {
|
||||
println!(
|
||||
"no herdr codex hook entries found in {}",
|
||||
result.hooks_path.display()
|
||||
);
|
||||
}
|
||||
println!(
|
||||
"left codex config unchanged at {}",
|
||||
result.config_path.display()
|
||||
);
|
||||
Ok(0)
|
||||
}
|
||||
"opencode" => {
|
||||
let result = crate::integration::uninstall_opencode()?;
|
||||
if result.removed_plugin {
|
||||
println!(
|
||||
"removed opencode integration plugin at {}",
|
||||
result.plugin_path.display()
|
||||
);
|
||||
} else {
|
||||
println!(
|
||||
"no opencode integration plugin found at {}",
|
||||
result.plugin_path.display()
|
||||
);
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
_ => {
|
||||
eprintln!("unknown integration target: {target}");
|
||||
eprintln!("currently supported: pi, claude, codex, opencode");
|
||||
Ok(2)
|
||||
}
|
||||
}
|
||||
|
|
@ -786,6 +913,13 @@ fn print_wait_help() {
|
|||
fn print_integration_help() {
|
||||
eprintln!("herdr integration commands:");
|
||||
eprintln!(" herdr integration install pi");
|
||||
eprintln!(" herdr integration install claude");
|
||||
eprintln!(" herdr integration install codex");
|
||||
eprintln!(" herdr integration install opencode");
|
||||
eprintln!(" herdr integration uninstall pi");
|
||||
eprintln!(" herdr integration uninstall claude");
|
||||
eprintln!(" herdr integration uninstall codex");
|
||||
eprintln!(" herdr integration uninstall opencode");
|
||||
}
|
||||
|
||||
fn _print_json<T: Serialize>(value: &T) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
#!/bin/sh
|
||||
# installed by herdr
|
||||
# safe to edit. this hook only activates inside herdr-managed panes.
|
||||
|
||||
set -eu
|
||||
|
||||
action="${1:-}"
|
||||
cat >/dev/null 2>/dev/null || true
|
||||
|
||||
case "$action" in
|
||||
working|idle|blocked|release) ;;
|
||||
*) exit 0 ;;
|
||||
esac
|
||||
|
||||
[ "${HERDR_ENV:-}" = "1" ] || exit 0
|
||||
[ -n "${HERDR_SOCKET_PATH:-}" ] || exit 0
|
||||
[ -n "${HERDR_PANE_ID:-}" ] || exit 0
|
||||
command -v python3 >/dev/null 2>&1 || exit 0
|
||||
|
||||
HERDR_ACTION="$action" python3 - <<'PY'
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import socket
|
||||
import time
|
||||
|
||||
source = "herdr:claude"
|
||||
action = os.environ.get("HERDR_ACTION", "")
|
||||
pane_id = os.environ.get("HERDR_PANE_ID")
|
||||
socket_path = os.environ.get("HERDR_SOCKET_PATH")
|
||||
|
||||
if not pane_id or not socket_path:
|
||||
raise SystemExit(0)
|
||||
|
||||
request_id = f"{source}:{int(time.time() * 1000)}:{random.randrange(1_000_000):06d}"
|
||||
if action == "release":
|
||||
request = {
|
||||
"id": request_id,
|
||||
"method": "pane.release_agent",
|
||||
"params": {
|
||||
"pane_id": pane_id,
|
||||
"source": source,
|
||||
"agent": "claude",
|
||||
},
|
||||
}
|
||||
else:
|
||||
request = {
|
||||
"id": request_id,
|
||||
"method": "pane.report_agent",
|
||||
"params": {
|
||||
"pane_id": pane_id,
|
||||
"source": source,
|
||||
"agent": "claude",
|
||||
"state": action,
|
||||
},
|
||||
}
|
||||
|
||||
try:
|
||||
client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
client.settimeout(0.5)
|
||||
client.connect(socket_path)
|
||||
client.sendall((json.dumps(request) + "\n").encode())
|
||||
try:
|
||||
client.recv(4096)
|
||||
except Exception:
|
||||
pass
|
||||
client.close()
|
||||
except Exception:
|
||||
pass
|
||||
PY
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
#!/bin/sh
|
||||
# installed by herdr
|
||||
# safe to edit. this hook only activates inside herdr-managed panes.
|
||||
|
||||
set -eu
|
||||
|
||||
action="${1:-}"
|
||||
cat >/dev/null 2>/dev/null || true
|
||||
|
||||
case "$action" in
|
||||
working|idle|blocked|release) ;;
|
||||
*) exit 0 ;;
|
||||
esac
|
||||
|
||||
[ "${HERDR_ENV:-}" = "1" ] || exit 0
|
||||
[ -n "${HERDR_SOCKET_PATH:-}" ] || exit 0
|
||||
[ -n "${HERDR_PANE_ID:-}" ] || exit 0
|
||||
command -v python3 >/dev/null 2>&1 || exit 0
|
||||
|
||||
HERDR_ACTION="$action" python3 - <<'PY'
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import socket
|
||||
import time
|
||||
|
||||
source = "herdr:codex"
|
||||
action = os.environ.get("HERDR_ACTION", "")
|
||||
pane_id = os.environ.get("HERDR_PANE_ID")
|
||||
socket_path = os.environ.get("HERDR_SOCKET_PATH")
|
||||
|
||||
if not pane_id or not socket_path:
|
||||
raise SystemExit(0)
|
||||
|
||||
request_id = f"{source}:{int(time.time() * 1000)}:{random.randrange(1_000_000):06d}"
|
||||
if action == "release":
|
||||
request = {
|
||||
"id": request_id,
|
||||
"method": "pane.release_agent",
|
||||
"params": {
|
||||
"pane_id": pane_id,
|
||||
"source": source,
|
||||
"agent": "codex",
|
||||
},
|
||||
}
|
||||
else:
|
||||
request = {
|
||||
"id": request_id,
|
||||
"method": "pane.report_agent",
|
||||
"params": {
|
||||
"pane_id": pane_id,
|
||||
"source": source,
|
||||
"agent": "codex",
|
||||
"state": action,
|
||||
},
|
||||
}
|
||||
|
||||
try:
|
||||
client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
client.settimeout(0.5)
|
||||
client.connect(socket_path)
|
||||
client.sendall((json.dumps(request) + "\n").encode())
|
||||
try:
|
||||
client.recv(4096)
|
||||
except Exception:
|
||||
pass
|
||||
client.close()
|
||||
except Exception:
|
||||
pass
|
||||
PY
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
import net from "node:net";
|
||||
|
||||
const SOURCE = "herdr:opencode";
|
||||
|
||||
function reportState(action) {
|
||||
const paneId = process.env.HERDR_PANE_ID;
|
||||
const socketPath = process.env.HERDR_SOCKET_PATH;
|
||||
|
||||
if (!paneId || !socketPath) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const requestId = `${SOURCE}:${Date.now()}:${Math.floor(Math.random() * 1_000_000)
|
||||
.toString()
|
||||
.padStart(6, "0")}`;
|
||||
const request = {
|
||||
id: requestId,
|
||||
method: action === "release" ? "pane.release_agent" : "pane.report_agent",
|
||||
params:
|
||||
action === "release"
|
||||
? {
|
||||
pane_id: paneId,
|
||||
source: SOURCE,
|
||||
agent: "opencode",
|
||||
}
|
||||
: {
|
||||
pane_id: paneId,
|
||||
source: SOURCE,
|
||||
agent: "opencode",
|
||||
state: action,
|
||||
},
|
||||
};
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const client = net.createConnection(socketPath, () => {
|
||||
client.write(`${JSON.stringify(request)}\n`);
|
||||
});
|
||||
|
||||
const finish = () => {
|
||||
client.destroy();
|
||||
resolve();
|
||||
};
|
||||
|
||||
client.setTimeout(500, finish);
|
||||
client.on("data", finish);
|
||||
client.on("error", finish);
|
||||
client.on("end", finish);
|
||||
client.on("close", resolve);
|
||||
});
|
||||
}
|
||||
|
||||
export const HerdrAgentStatePlugin = async () => {
|
||||
if (
|
||||
process.env.HERDR_ENV !== "1" ||
|
||||
!process.env.HERDR_SOCKET_PATH ||
|
||||
!process.env.HERDR_PANE_ID
|
||||
) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {
|
||||
event: async ({ event }) => {
|
||||
const type = event?.type;
|
||||
const properties = event?.properties ?? {};
|
||||
|
||||
switch (type) {
|
||||
case "permission.asked":
|
||||
await reportState("blocked");
|
||||
break;
|
||||
case "permission.replied": {
|
||||
const reply = properties.reply ?? properties.response;
|
||||
if (reply === "reject") {
|
||||
await reportState("idle");
|
||||
} else if (reply === "once" || reply === "always") {
|
||||
await reportState("working");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "session.status": {
|
||||
const status =
|
||||
typeof properties.status === "string"
|
||||
? properties.status
|
||||
: properties.status?.type;
|
||||
if (status === "busy" || status === "retry") {
|
||||
await reportState("working");
|
||||
} else if (status === "idle") {
|
||||
await reportState("idle");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "session.idle":
|
||||
await reportState("idle");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -195,7 +195,7 @@ fn main() -> io::Result<()> {
|
|||
println!(" workspace workspace helpers over the socket api");
|
||||
println!(" pane pane control helpers over the socket api");
|
||||
println!(" wait blocking wait helpers over the socket api");
|
||||
println!(" integration install built-in agent integrations");
|
||||
println!(" integration manage built-in agent integrations");
|
||||
println!();
|
||||
println!("Options:");
|
||||
println!(" --no-session Don't restore or save sessions");
|
||||
|
|
|
|||
Loading…
Reference in New Issue