Skip to content

feat(maestro): wrap dispatch, session list/show, send --tab/--no-system-prompt#44

Merged
chr1syy merged 1 commit into
mainfrom
feat/cli-dispatch-session-wrappers
Jun 5, 2026
Merged

feat(maestro): wrap dispatch, session list/show, send --tab/--no-system-prompt#44
chr1syy merged 1 commit into
mainfrom
feat/cli-dispatch-session-wrappers

Conversation

@chr1syy
Copy link
Copy Markdown
Collaborator

@chr1syy chr1syy commented May 31, 2026

Summary

Wraps the four maestro-cli surfaces that landed upstream since the kernel refactor and that target relay-style external consumers (the dispatch + session PRs explicitly name Maestro-Discord/relay as the intended caller):

  • maestro.dispatch(agentId, message, { newTab?, tabId?, force? }) — hand a prompt to the running desktop app and get back { agentId, sessionId, tabId } so the caller can address the same tab on follow-up calls. (upstream dfdb77262)
  • maestro.sessionList() — enumerate every open AI tab across every agent. (upstream ac51048fa)
  • maestro.sessionShow(tabId, { since?, tail? }) — fetch a tab's conversation history; --since auto-detects ISO-8601 vs epoch ms/sec, so a previous response's messages[].timestamp round-trips directly. (upstream ac51048fa)
  • send() options bag — adds openTab (-t, focuses the tab after delivery) and noSystemPrompt (--no-system-prompt, opt out of the Maestro system context the CLI appends by default for parity with the desktop app — agent identity, git branch, history-file pointer, conductor profile).

Behavioral notes

  • send()'s positional signature is folded into an options bag — the queue is the only caller and is updated in the same commit. Defaults preserve current behavior: system prompt included, tab not opened.
  • The CLI { success: false, error, code } envelope is unwrapped into native Errors so the new methods throw with the same ergonomics as the existing wrappers (createGist, directorSynopsis, etc.).
  • dispatch reuses send's stdout-recovery fall-through for the case where the CLI exits non-zero but still emits a parseable JSON error on stdout.
  • The --no-system-prompt flag exists on the RC branches the user is running (PR #1003 on maestro-p-rc and friends). Once it lands in upstream main, default behavior is "include the prompt" — matching what we set here.

Pairing pattern this unlocks

const { tabId } = await maestro.dispatch(agentId, prompt, { newTab: true });
// ... later, poll without re-sending ...
const { messages } = await maestro.sessionShow(tabId, { since: lastTimestamp });

Test plan

  • npx tsc --noEmit — clean
  • npm test — 211/211 pass
  • Manual smoke once an RC build is installed: dispatch --new-tab against a live desktop, then sessionShow with the returned tabId.

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features
    • Added desktop session dispatch functionality for sending prompts directly to applications
    • Added ability to list open sessions and retrieve detailed conversation history
    • Enhanced message sending with additional configuration options including tab management and system prompt customization

…em-prompt

Adds wrappers for the four CLI surfaces that landed in upstream Maestro
since the kernel refactor and that target relay-style external consumers:

- maestro.dispatch(agentId, message, { newTab?, tabId?, force? }) —
  hand a prompt to the desktop app and return { agentId, sessionId,
  tabId } so callers can address the same tab on follow-up calls.
- maestro.sessionList() — enumerate every open AI tab across every
  agent in the running desktop.
- maestro.sessionShow(tabId, { since?, tail? }) — fetch a tab's
  conversation history; --since auto-detects ISO-8601 vs epoch ms/sec.
- maestro.send() options bag now exposes openTab (-t, focus the tab
  after delivery) and noSystemPrompt (--no-system-prompt, opt out of
  the Maestro system context the CLI appends by default).

send()'s positional signature is folded into an options bag — the
queue is the only caller, updated in the same commit. Defaults
preserve current behavior: system prompt included, tab not opened.

Error envelopes from the CLI ({ success: false, error, code }) are
unwrapped into native Errors so the new methods throw with the same
ergonomics as the existing wrappers. dispatch reuses send's
stdout-recovery fall-through for the non-zero-exit-with-JSON case.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 31, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR refactors the maestro service API and adds new functionality for desktop dispatch delivery and session management. It introduces four data type contracts, refactors maestro.send from positional to options-based parameters, adds three new async methods (dispatch, sessionList, sessionShow), and updates the queue consumer to use the new signature.

Changes

Maestro Service API Expansion

Layer / File(s) Summary
Data Contracts for Desktop Dispatch and Session History
src/core/maestro.ts
Introduces DispatchResult, DesktopSessionEntry, SessionHistoryMessage, and SessionHistory interfaces to model desktop dispatch outcomes and session/tab conversation history.
maestro.send Refactoring to Options Object
src/core/maestro.ts
Refactors maestro.send from positional parameters (sessionId, readOnly) to a single options object parameter supporting sessionId, readOnly, openTab, and noSystemPrompt, with conditional CLI flag construction.
New maestro Methods (dispatch, sessionList, sessionShow)
src/core/maestro.ts
Adds dispatch (submits prompt to desktop app, validates incompatible options, returns tab/session id), sessionList (lists open desktop sessions, throws on failure), and sessionShow (retrieves timestamped conversation history for a tab, supports since/tail parameters). Each method uses runSpawn, JSON parsing, and stdout: fallback extraction.
Queue Integration of Refactored maestro.send
src/core/queue.ts
Updates QueueDeps contract to reflect new options object signature for maestro.send, and adjusts the queue's send call site to pass sessionId and readOnly via options object.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Three new methods hop into town,
dispatch, sessionList wear the crown,
sessionShow brings history to light,
While send trades positional for options bright! 🎯

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changes: adding maestro service wrappers for dispatch, session management, and send method enhancements with new CLI flags.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/cli-dispatch-session-wrappers

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/core/maestro.ts`:
- Around line 47-56: The DispatchResult path currently returns { success: false,
error, code } for parsed error envelopes which makes await callers treat
failures as fulfilled; update the dispatch function so that after parsing the
dispatch envelope (the branch that currently produces DispatchResult) you detect
error/code fields and throw an Error (or a specialized exception carrying
error/code) instead of returning success: false, and apply the same behavior to
the stdout: fallback path so both parsed and fallback error envelopes reject;
keep returning DispatchResult only for truly successful envelopes (including
agentId/sessionId/tabId). Also mirror this change at the other dispatch handling
block referenced (lines around 371-385) so both code paths consistently throw on
parsed errors.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9c548ce1-8db7-498f-819a-48b552f699c9

📥 Commits

Reviewing files that changed from the base of the PR and between 67e737c and ac3ecef.

📒 Files selected for processing (2)
  • src/core/maestro.ts
  • src/core/queue.ts

Comment thread src/core/maestro.ts
Comment on lines +47 to +56
export interface DispatchResult {
success: boolean;
agentId?: string;
/** Tab id the prompt was delivered to. Identical to `tabId` — the CLI emits
* both keys so polling consumers can use either. */
sessionId?: string | null;
tabId?: string | null;
error?: string;
code?: string;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Throw on parsed dispatch error envelopes.

dispatch() currently resolves with { success: false, error, code } from both the normal parse path and the stdout: fallback path. That breaks the wrapper contract the PR describes and makes a failed dispatch look like a successful await, leaving consumers with nullable IDs on the resolved path.

💡 Suggested fix
 export interface DispatchResult {
-  success: boolean;
-  agentId?: string;
+  success: true;
+  agentId: string;
   /** Tab id the prompt was delivered to. Identical to `tabId` — the CLI emits
    *  both keys so polling consumers can use either. */
-  sessionId?: string | null;
-  tabId?: string | null;
-  error?: string;
-  code?: string;
+  sessionId: string | null;
+  tabId: string | null;
 }
@@
   async dispatch(
@@
   ): Promise<DispatchResult> {
@@
     try {
       const raw = await runSpawn(args);
-      return JSON.parse(raw) as DispatchResult;
+      const parsed = JSON.parse(raw) as
+        | DispatchResult
+        | { success: false; error?: string; code?: string };
+      if (parsed.success === false) {
+        throw new Error(`dispatch failed: ${parsed.error ?? 'unknown'} (${parsed.code ?? 'UNKNOWN'})`);
+      }
+      return parsed;
     } catch (err: unknown) {
@@
       if (stdoutMatch) {
         try {
-          return JSON.parse(stdoutMatch[1]) as DispatchResult;
+          const parsed = JSON.parse(stdoutMatch[1]) as
+            | DispatchResult
+            | { success: false; error?: string; code?: string };
+          if (parsed.success === false) {
+            throw new Error(`dispatch failed: ${parsed.error ?? 'unknown'} (${parsed.code ?? 'UNKNOWN'})`);
+          }
+          return parsed;
         } catch {
           /* fall through */
         }
       }
       throw err;

Also applies to: 371-385

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/maestro.ts` around lines 47 - 56, The DispatchResult path currently
returns { success: false, error, code } for parsed error envelopes which makes
await callers treat failures as fulfilled; update the dispatch function so that
after parsing the dispatch envelope (the branch that currently produces
DispatchResult) you detect error/code fields and throw an Error (or a
specialized exception carrying error/code) instead of returning success: false,
and apply the same behavior to the stdout: fallback path so both parsed and
fallback error envelopes reject; keep returning DispatchResult only for truly
successful envelopes (including agentId/sessionId/tabId). Also mirror this
change at the other dispatch handling block referenced (lines around 371-385) so
both code paths consistently throw on parsed errors.

@chr1syy chr1syy merged commit 86aa703 into main Jun 5, 2026
3 checks passed
@chr1syy chr1syy deleted the feat/cli-dispatch-session-wrappers branch June 5, 2026 18:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant