agent-orchestrator/.changeset
Harshit Singh Bhandari a610601158
refactor(agent-claude-code): split activity detection; remove dead JSONL cases; detect blocked from api_error (#1927)
* refactor(agent-claude-code): split activity detection into its own module; remove dead JSONL cases

Move `getActivityState`, `findClaudeProcess`, the ps-cache, `classifyTerminalOutput`, `findLatestSessionFile`, and `toClaudeProjectPath` into a new `activity-detection.ts`. `index.ts` shrinks by ~190 lines and now delegates via thin wrappers; `toClaudeProjectPath` and `resetPsCache` are re-exported so existing unit-test and integration-test import sites keep working.

Drop two switch branches that could never fire: `case "permission_request"` → `waiting_input` and `case "error"` → `blocked`. Verified by reading every JSONL under `~/.claude/projects/`: Claude emits `agent-color, agent-name, ai-title, assistant, attachment, custom-title, file-history-snapshot, last-prompt, permission-mode, pr-link, progress, queue-operation, summary, system, user` — but never a top-level `permission_request` or `error`. Permission prompts have no native-JSONL signal at all (they only sit in the terminal until the user answers); API errors arrive under `type:"system"` with `subtype:"api_error"` / `level:"error"`, not as a top-level `error` type. `waiting_input` and `blocked` continue to flow through the terminal-regex → AO activity-JSONL path that was added upstream — that path is now the only source, which matches reality.

Behavior preserved: the cascade (process check → native JSONL → AO actionable → AO age-decay fallback → stale-native) is byte-equivalent for every type Claude actually emits. Four tests that wrote fake `permission_request` / `error` JSONL deleted.

* feat(agent-claude-code,core): detect blocked from Claude api_error JSONL entries

Extend `readLastJsonlEntry` in core to also surface top-level `subtype` and `level` fields (additive — existing return shape unchanged). Map `{type:"system", level:"error"}` to `blocked` in `getClaudeActivityState`.

Claude writes API errors as `{type:"system", subtype:"api_error", level:"error", cause:{code:"ConnectionRefused"|"FailedToOpenSocket"|...}, retryAttempt:N, maxRetries:10}`. When the LAST JSONL entry has that shape, Claude is mid-retry-loop or has exhausted retries — surfacing as `blocked` lets stuck-detection fire. Other `system` subtypes (`compact_boundary`, `local_command`, `turn_duration`, `away_summary`, etc.) continue to map to `ready`/`idle` by age via the `entry.lastLevel !== "error"` branch.

Closes the only remaining "no live producer" gap from the PR description: previously `blocked` had a slot in the cascade but no writer. Now native JSONL fills it directly, no AO activity-log roundtrip needed.

Tests:
- "blocked for 'system' api_error (level: error)"
- "ready for non-error 'system' subtypes (compact_boundary)"
- "'system' api_error ignores staleness (always blocked)"

Existing `system` test (no level field) continues to map to `ready` — verified.

* fix(agent-claude-code): require api_error subtype AND error level for blocked

Tighten the system-entry gate per @greptile-apps review on #1927. Today only `api_error` carries `level:"error"` under `type:"system"`, but pinning both fields makes intent explicit and prevents silent drift if Claude ever adds a non-fatal error-level diagnostic later.

Test locks the tightened gate: `{type:"system", subtype:"future_diagnostic", level:"error"}` → `ready` (not `blocked`).

* test(core): cover lastSubtype/lastLevel extraction in readLastJsonlEntry

Per reviewer note on #1927: the consumer side (claude-code plugin) tested the new fields, but the producer side in core didn't. Lock the extraction behavior so future refactors of `readLastJsonlEntry` can't regress silently.

Covers: real Claude api_error shape, absent fields, non-string field types.
2026-05-19 18:00:54 +05:30
..
README.md feat: publish to npm under @composio scope (#32) 2026-02-15 04:28:57 +05:30
activity-events-webhooks-mux.md feat(web): activity events for webhooks and mux WebSocket (#1656) (#1693) 2026-05-18 18:54:00 +05:30
claude-activity-detection-split.md refactor(agent-claude-code): split activity detection; remove dead JSONL cases; detect blocked from api_error (#1927) 2026-05-19 18:00:54 +05:30
cli-activity-events.md feat(cli): wire activity events into CLI commands and supervisor lifecycle (#1698) 2026-05-18 21:04:25 +05:30
config.json feat(notifier): make notifier system robust with manual harness and desktop setup (#1736) 2026-05-19 14:48:40 +05:30
fix-done-bar-scroll.md fix(web): bound project page wrapper so dashboard body scrolls (closes #1923) (#1929) 2026-05-19 14:38:24 +05:30
issue-1660-recovery-metadata-events.md feat(core): activity events for recovery, metadata corruption, agent-report (#1692) 2026-05-18 17:27:36 +05:30
launch-orchestrator-clean.md feat(web,core): "Launch Orchestrator (clean context)" button (#1904) 2026-05-17 21:16:25 +05:30
linear-transient-retry.md feat(cli): wire activity events into CLI commands and supervisor lifecycle (#1698) 2026-05-18 21:04:25 +05:30
notifier-release-links.md feat(notifier): make notifier system robust with manual harness and desktop setup (#1736) 2026-05-19 14:48:40 +05:30
quiet-sqlite-rebuild.md fix(cli): rebuild better-sqlite3 on install + quieter ABI-mismatch warning (closes #1822) (#1824) 2026-05-18 04:02:26 +05:30
restore-button-pr-merged.md fix(web): show Restore button for every exited session, including pr_merged (#1909) 2026-05-19 02:50:34 +05:30

README.md

Changesets

Hello and welcome! This folder has been automatically generated by @changesets/cli, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it in our repository

We have a quick list of common questions to get you started engaging with this project in
our documentation