Skip to content

Add Paseo schedule commands to Maestro CLI#1030

Open
IAKGnaHz wants to merge 3 commits into
RunMaestro:mainfrom
IAKGnaHz:feat/paseo-schedule-cli
Open

Add Paseo schedule commands to Maestro CLI#1030
IAKGnaHz wants to merge 3 commits into
RunMaestro:mainfrom
IAKGnaHz:feat/paseo-schedule-cli

Conversation

@IAKGnaHz

@IAKGnaHz IAKGnaHz commented May 21, 2026

Copy link
Copy Markdown

Summary

This PR adds a small, CLI-first integration point between Maestro and Paseo by introducing a maestro-cli paseo schedule ... command group.

The goal is to let Maestro act as the user-facing orchestration entrypoint while delegating agent lifecycle, recurring execution, timelines, and visibility to a running Paseo daemon.

Background

Maestro already provides a useful agent-oriented CLI surface (send, playbooks, settings, session inspection) and is well positioned to act as an orchestration layer for higher-level workflows. Paseo, meanwhile, provides a daemon-backed execution model with a native UI for inspecting agent timelines, schedule runs, logs, and multi-agent progress.

In local testing, the most reliable integration path was not to ask an intermediate agent to run shell commands, but to let Maestro call the Paseo CLI directly and return the structured result to the user or automation layer.

That gives a clean division of responsibilities:

  • Maestro owns task intake, orchestration, templates, and future planning/delegation flows.
  • Paseo owns spawned agent execution, recurring schedules, timeline/log visibility, and daemon state.

Research / Findings

A short local spike validated the following:

  • A running Paseo desktop app exposes a reachable local daemon.
  • The bundled Paseo CLI can manage that daemon from the terminal.
  • paseo schedule create can create bounded scheduled agent runs with --max-runs and --expires-in, which is important for safe automation.
  • Schedule runs show up in Paseo's UI/daemon timeline and can be inspected with paseo schedule ls and paseo schedule logs <id>.
  • Providers such as codex and claude are discovered by Paseo and can be selected per scheduled task.
  • For now, this PR intentionally focuses on schedule management. One-off paseo run --title support would be a natural follow-up because it provides better UI titles for ad hoc delegated tasks.

Changes

This PR adds:

  • A Paseo CLI adapter in src/cli/services/paseo.ts

    • Resolves the Paseo CLI path from, in order:
      • an explicit --cli-path
      • PASEO_CLI_PATH
      • the macOS bundled app path (/Applications/Paseo.app/Contents/Resources/bin/paseo)
      • paseo from PATH
    • Executes Paseo commands via child_process.spawn
    • Returns stdout/stderr and surfaces non-zero exits as errors
  • A new command module in src/cli/commands/paseo.ts

    • paseo schedule create <prompt>
    • paseo schedule ls
    • paseo schedule logs <schedule-id>
    • Supports --json, --host, and --cli-path
  • CLI registration in src/cli/index.ts

  • Unit coverage for both service and command layers

Example Usage

maestro-cli paseo schedule ls

maestro-cli paseo schedule create \
  --every 30m \
  --name repo-health-check \
  --provider codex \
  --cwd /path/to/repo \
  --max-runs 8 \
  --expires-in 4h \
  "Check the repo health, run focused checks, and summarize the result."

maestro-cli paseo schedule logs <schedule-id>

Safety Notes

The schedule creation path exposes Paseo's built-in bounding controls:

  • --max-runs
  • --expires-in
  • --no-run-now
  • explicit --cwd
  • explicit provider selection

These are useful defaults for higher-level orchestration because Maestro can create visible, bounded Paseo work without creating unbounded recurring agents.

Validation

Targeted checks:

npx tsc -p tsconfig.cli.json --noEmit
npx vitest run src/__tests__/cli/services/paseo.test.ts src/__tests__/cli/commands/paseo.test.ts src/__tests__/cli/commands/send.test.ts src/__tests__/cli/services/agent-spawner.test.ts

Full push validation also passed:

Test Files  546 passed | 1 skipped (547)
Tests       22548 passed | 107 skipped (22655)

The push hook also ran:

  • npm run build:prompts
  • npm run format:check:all
  • npm run lint
  • npm run lint:eslint
  • npm run test

lint:eslint reported one existing warning in src/main/web-server/web-server-factory.ts, but no errors.

Follow-up Plan

This is deliberately a small integration slice. Follow-up improvements that would build on it:

  1. Add maestro-cli paseo run support

    • Wrap paseo run --title --detach --provider --cwd
    • Use this for one-off delegated tasks where UI titles matter
  2. Add a higher-level delegate command

    • Generate a structured task plan
    • Use Claude or another reasoning-heavy provider for planning/review
    • Use Codex or another execution-heavy provider for implementation/checking
    • Dispatch approved tasks through the Paseo adapter
  3. Persist Paseo IDs in Maestro-side task records

    • schedule id
    • agent id
    • provider
    • cwd
    • created time
    • status/log lookup metadata
  4. Add richer output parsing for --json

    • Return typed schedule objects from the adapter instead of raw stdout when JSON is requested
  5. Expose this from playbooks or future workflow templates

    • Recurring maintenance jobs
    • repo health checks
    • multi-agent research/implementation/review loops

Summary by CodeRabbit

  • New Features
    • Added a top-level Paseo CLI group with run plus schedule commands (create, list, logs), supporting host/CLI-path selection and --json output.
  • Tests
    • Added unit tests covering Paseo commands and the CLI adapter, including success/failure paths, output handling, and argument/exec wiring.
  • Chores
    • Added a CLI adapter to invoke and capture output from the local Paseo executable and registered the new commands.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 21, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 43ace49a-0648-47ac-b242-293ff9eab1c0

📥 Commits

Reviewing files that changed from the base of the PR and between 5b7c5b8 and c18b39f.

📒 Files selected for processing (5)
  • src/__tests__/cli/commands/paseo.test.ts
  • src/__tests__/cli/services/paseo.test.ts
  • src/cli/commands/paseo.ts
  • src/cli/index.ts
  • src/cli/services/paseo.ts

📝 Walkthrough

Hidden review stack artifact

Walkthrough

Adds a Paseo CLI adapter that resolves and runs a local paseo executable, command handlers for run and schedule operations (create/ls/logs) with standardized success/error printing, CLI registration for the new commands, and unit tests for service and command layers.

Changes

Paseo CLI Integration

Layer / File(s) Summary
Paseo CLI service implementation
src/cli/services/paseo.ts
Defines option/result types, resolves the paseo executable path (explicit, env, macOS bundled, fallback), implements runPaseoCommand to spawn and accumulate stdout/stderr, and exports createPaseoSchedule, runPaseoAgent, listPaseoSchedules, getPaseoScheduleLogs.
Paseo service layer tests
src/__tests__/cli/services/paseo.test.ts
Mocks fs, os.platform, and child_process.spawn, provides helpers to simulate child stdout/stderr and close/error events, and tests CLI path resolution, runPaseoCommand success/failure behaviors, and argument construction for create/run/list/logs.
Paseo command handlers
src/cli/commands/paseo.ts
Defines PaseoBaseOptions, command-specific option interfaces, printResult/printError helpers (JSON vs formatted), and exports handlers paseoRun, paseoScheduleCreate, paseoScheduleList, paseoScheduleLogs that call service functions and handle output/errors.
Paseo command layer tests
src/__tests__/cli/commands/paseo.test.ts
Mocks the paseo service functions and formatError to verify handlers call services with correct arguments, log trimmed stdout/stderr on success, and emit JSON or formatted errors and call process.exit(1) on failures.
CLI command registration
src/cli/index.ts
Imports Paseo handlers and registers a top-level paseo command with run <prompt> and paseo schedule subcommands: create <prompt>, ls, and logs <schedule-id>, wiring options like --host, --cli-path, and --json.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

ready to merge

Suggested reviewers

  • pedramamini

Poem

🐰 I hopped through code to add a route,
Paseo schedules now sprout and shout,
Run, list, and logs all play their part,
Tests hum softly — each passing heart,
A carrot for the CI, no doubt.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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 clearly and concisely summarizes the main change: adding Paseo schedule commands to the Maestro CLI. It is specific, directly related to the core addition, and helps teammates quickly understand the primary purpose.
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 unit tests (beta)
  • Create PR with unit tests

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.

@greptile-apps

greptile-apps Bot commented May 21, 2026

Copy link
Copy Markdown

Greptile Summary

This PR introduces maestro-cli paseo schedule ... (and paseo run) commands that delegate agent lifecycle and schedule management to a running Paseo daemon via the bundled Paseo CLI binary. The implementation is clean and well-tested overall.

  • src/cli/services/paseo.ts \u2014 resolves the Paseo CLI path (explicit arg \u2192 env var \u2192 macOS bundle \u2192 PATH), spawns the process with child_process.spawn, and builds correctly ordered argument lists for schedule create, schedule ls, schedule logs, and run; the runNow tri-state boolean is handled correctly.
  • src/cli/commands/paseo.ts / src/cli/index.ts \u2014 thin command layer wires Commander.js actions to the service functions with consistent --json / human-readable error output.
  • One logic gap: runPaseoAgent appends --wait-timeout unconditionally, so a user invoking paseo run --wait-timeout 5m <prompt> (without --no-detach) sends both --detach and --wait-timeout to Paseo \u2014 contradictory flags that will either be rejected or silently drop the timeout.

Confidence Score: 4/5

Safe to merge after fixing the --detach/--wait-timeout flag conflict in runPaseoAgent.

The new Paseo integration is well-structured and the runNow tri-state is correctly handled. One concrete defect exists: runPaseoAgent forwards --wait-timeout even when --detach is active, so any user who passes --wait-timeout without --no-detach sends contradictory flags to the Paseo CLI, which will either error or silently ignore the timeout.

src/cli/services/paseo.ts — the runPaseoAgent function needs the --wait-timeout guard.

Important Files Changed

Filename Overview
src/cli/services/paseo.ts Paseo CLI adapter: correctly resolves CLI path and handles runNow tri-state, but passes --wait-timeout alongside --detach when both apply, producing contradictory flags to the Paseo process.
src/cli/commands/paseo.ts Command layer cleanly delegates to the service, handles JSON vs human-readable error output, and trims whitespace from stdout/stderr before printing.
src/cli/index.ts Registers the paseo command group with schedule subcommands; Commander default of detach:true is consistent with service logic except for the wait-timeout conflict noted in the service file.
src/tests/cli/services/paseo.test.ts Good coverage of path resolution, spawn wiring, and runNow tri-state; missing a test for --wait-timeout combined with the default detach:true/undefined path, which would expose the flag conflict.
src/tests/cli/commands/paseo.test.ts Covers success and error paths for all four commands, including JSON vs human-readable error output and process.exit behaviour.

Sequence Diagram

sequenceDiagram
    participant User
    participant MaestroCLI as maestro-cli
    participant PaseoService as paseo.ts (service)
    participant PaseoCLI as paseo (binary)
    participant PaseoDeamon as Paseo Daemon

    User->>MaestroCLI: paseo schedule create --every 5m "prompt"
    MaestroCLI->>PaseoService: createPaseoSchedule(prompt, options)
    PaseoService->>PaseoService: resolvePaseoCliPath()
    Note over PaseoService: explicit → env → macOS bundle → PATH
    PaseoService->>PaseoCLI: spawn(cliPath, args)
    PaseoCLI->>PaseoDeamon: register schedule
    PaseoDeamon-->>PaseoCLI: schedule ID
    PaseoCLI-->>PaseoService: stdout
    PaseoService-->>MaestroCLI: "{stdout, stderr}"
    MaestroCLI-->>User: prints stdout

    User->>MaestroCLI: paseo schedule ls
    MaestroCLI->>PaseoService: listPaseoSchedules(options)
    PaseoService->>PaseoCLI: spawn(cliPath, ["schedule","ls"])
    PaseoCLI->>PaseoDeamon: list schedules
    PaseoDeamon-->>PaseoCLI: schedule list
    PaseoCLI-->>PaseoService: stdout
    PaseoService-->>MaestroCLI: "{stdout, stderr}"
    MaestroCLI-->>User: prints schedule list
Loading

Reviews (2): Last reviewed commit: "Add titled Paseo run command" | Re-trigger Greptile

Comment thread src/cli/services/paseo.ts
Comment thread src/cli/services/paseo.ts Outdated
Comment thread src/cli/services/paseo.ts
Comment thread src/cli/services/paseo.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/__tests__/cli/services/paseo.test.ts (1)

98-102: ⚡ Quick win

Add test coverage for spawn failure.

The test suite covers non-zero exit codes but not spawn errors (when childProcess.spawn emits an 'error' event, handled at line 89-91 in paseo.ts). This occurs when the executable cannot be spawned (e.g., command not found, permission denied).

Consider adding a test case for this scenario to ensure the error handling at line 89-91 in paseo.ts works correctly.

📋 Suggested test case
it('rejects when spawn fails', async () => {
	const child = new EventEmitter() as EventEmitter & {
		stdout: Readable;
		stderr: Readable;
	};
	child.stdout = new Readable({ read() {} });
	child.stderr = new Readable({ read() {} });
	
	vi.mocked(spawn).mockReturnValue(child as any);
	
	setImmediate(() => {
		child.emit('error', new Error('ENOENT: command not found'));
	});
	
	await expect(runPaseoCommand(['schedule', 'ls'], { cliPath: '/missing/paseo' }))
		.rejects.toThrow('Failed to run Paseo CLI');
});
🤖 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/__tests__/cli/services/paseo.test.ts` around lines 98 - 102, Add a new
test that simulates a spawn failure by mocking childProcess.spawn (used by
runPaseoCommand) to return an EventEmitter-like child that has stdout and stderr
Readable streams, then emit an 'error' event (e.g., new Error('ENOENT: command
not found')) via setImmediate; assert that runPaseoCommand rejects with the
expected message (the same message produced in paseo.ts's spawn 'error' handler,
e.g., 'Failed to run Paseo CLI'). This will exercise the spawn error handler in
paseo.ts and ensure runPaseoCommand correctly surfaces spawn failures.
🤖 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/cli/commands/paseo.ts`:
- Around line 54-59: The catch blocks in the CLI command handlers (around
createPaseoSchedule, the other two handlers on the same file) currently only
call printError; import captureException from src/utils/sentry.ts and report
unexpected errors to Sentry before printing: in each catch, detect expected
operational errors (e.g., known custom error types/messages such as "daemon
unavailable" or "invalid schedule ID") and skip Sentry, otherwise call
captureException(error) supplying any available context (e.g., the command name
and options) and then call printError(error, options.json); ensure the import
for captureException is added at the top of the file and that the catch blocks
around createPaseoSchedule, the handler at lines ~63–68, and the handler at
~75–80 follow this pattern.

In `@src/cli/services/paseo.ts`:
- Around line 136-141: The code currently appends both '--run-now' and
'--no-run-now' when options.runNow and options.noRunNow are both true; modify
the block around the args push (the options.runNow / options.noRunNow handling
in paseo.ts) to enforce mutual exclusivity: detect if both flags are set and
either throw a clear error (or log and exit) or decide a single precedence
(e.g., prefer noRunNow) and only push one flag. Ensure the check runs before
pushing to args so only one of '--run-now' or '--no-run-now' is ever added.

---

Nitpick comments:
In `@src/__tests__/cli/services/paseo.test.ts`:
- Around line 98-102: Add a new test that simulates a spawn failure by mocking
childProcess.spawn (used by runPaseoCommand) to return an EventEmitter-like
child that has stdout and stderr Readable streams, then emit an 'error' event
(e.g., new Error('ENOENT: command not found')) via setImmediate; assert that
runPaseoCommand rejects with the expected message (the same message produced in
paseo.ts's spawn 'error' handler, e.g., 'Failed to run Paseo CLI'). This will
exercise the spawn error handler in paseo.ts and ensure runPaseoCommand
correctly surfaces spawn failures.
🪄 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: ab9d4201-5e2c-4807-b419-2bbecaa768b7

📥 Commits

Reviewing files that changed from the base of the PR and between 1006e3b and 6f8d7ea.

📒 Files selected for processing (5)
  • src/__tests__/cli/commands/paseo.test.ts
  • src/__tests__/cli/services/paseo.test.ts
  • src/cli/commands/paseo.ts
  • src/cli/index.ts
  • src/cli/services/paseo.ts

Comment thread src/cli/commands/paseo.ts
Comment on lines +54 to +59
try {
const result = await createPaseoSchedule(prompt, options);
printResult(result);
} catch (error) {
printError(error, options.json);
}

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 | 🏗️ Heavy lift

Integrate Sentry for error tracking as required by coding guidelines.

All three command handlers catch errors without using Sentry utilities for production error tracking. As per coding guidelines, unexpected errors should be reported to Sentry for observability, even in CLI contexts.

Consider:

  1. Import captureException from src/utils/sentry.ts
  2. Distinguish expected operational errors (daemon unavailable, invalid schedule ID) from unexpected errors (bugs, crashes)
  3. For unexpected errors, call captureException(error) with appropriate context before printError
  4. For expected errors, proceed with current handling

Alternatively, if all CLI errors should be tracked in production, add captureException(error) at the start of each catch block.

As per coding guidelines: "Use Sentry utilities (captureException, captureMessage) from src/utils/sentry.ts for explicit error reporting with context."

Also applies to: 63-68, 75-80

🤖 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/cli/commands/paseo.ts` around lines 54 - 59, The catch blocks in the CLI
command handlers (around createPaseoSchedule, the other two handlers on the same
file) currently only call printError; import captureException from
src/utils/sentry.ts and report unexpected errors to Sentry before printing: in
each catch, detect expected operational errors (e.g., known custom error
types/messages such as "daemon unavailable" or "invalid schedule ID") and skip
Sentry, otherwise call captureException(error) supplying any available context
(e.g., the command name and options) and then call printError(error,
options.json); ensure the import for captureException is added at the top of the
file and that the catch blocks around createPaseoSchedule, the handler at lines
~63–68, and the handler at ~75–80 follow this pattern.

Comment thread src/cli/services/paseo.ts Outdated
@pedramamini

Copy link
Copy Markdown
Collaborator

@IAKGnaHz thanks for the contribution — clean integration slice and the safety bounding story is the right one. A few items from the AI reviews look worth addressing before this merges:

P1 — --no-run-now is silently dropped (Greptile)
This one matters because the PR description calls --no-run-now out as a key safety control. Commander.js negation options map both --run-now and --no-run-now onto a single runNow boolean (true/false) — it never populates a separate noRunNow field. So in src/cli/services/paseo.ts the if (options.noRunNow) branch is unreachable when the flag comes from the CLI, and --no-run-now is never forwarded to Paseo.

Suggested shape: collapse runNow/noRunNow into a single tri-state runNow?: boolean on PaseoScheduleCreateOptions and emit with strict equality:

if (options.runNow === true) {
  args.push('--run-now');
} else if (options.runNow === false) {
  args.push('--no-run-now');
}

That also resolves CodeRabbit's mutual-exclusivity concern — both flags can't be set at once anymore.

Sentry reporting in CLI catch blocks (CodeRabbit)
Per CLAUDE.md, unexpected errors should reach Sentry via captureException. The three handlers in src/cli/commands/paseo.ts currently only call printError. Worth calling captureException(error, { command: 'paseo schedule …' }) for unexpected failures (skip Sentry for known operational errors like daemon-unavailable or invalid schedule id).

Nit — null exit code message (Greptile P2)
When the child is killed by a signal, code is null and the error reads "Paseo exited with code null". A code ?? '(signal)' fallback in the error message in runPaseoCommand makes that case readable.

Nit — spawn-failure test (CodeRabbit)
Worth adding a test that mocks child.emit('error', …) to exercise the spawn-error path in paseo.ts. Right now non-zero exits are covered but the spawn-error handler isn't.

Once those are in (especially the P1) I'm happy to take another pass. Thanks again!

@IAKGnaHz

IAKGnaHz commented May 21, 2026

Copy link
Copy Markdown
Author

Thanks for the review. I pushed a follow-up commit addressing the concrete feedback:

  • Fixed Commander negation forwarding for --no-run-now by treating runNow as a tri-state value. --run-now now forwards true, --no-run-now forwards false, and the omitted case forwards neither flag.
  • Removed the unused noRunNow option shape from the CLI/service types.
  • Improved the null-exit-code path so a signal-style close no longer reports Paseo exited with code null.
  • Added coverage for both explicit run-now controls and spawn failure handling.

Validation run locally and in the push hook:

  • npx tsc -p tsconfig.cli.json --noEmit
  • npx vitest run src/__tests__/cli/services/paseo.test.ts src/__tests__/cli/commands/paseo.test.ts src/__tests__/cli/commands/send.test.ts src/__tests__/cli/services/agent-spawner.test.ts
  • Full push validation: format check, lint, eslint, and full test suite. Final result: 546 passed / 1 skipped test files, 22551 passed / 107 skipped tests.

On the Sentry suggestion: I checked the existing Sentry utilities and they currently live under src/main/utils/sentry.ts, backed by @sentry/electron/main. The CLI tsconfig is intentionally scoped to src/cli, src/shared, src/prompts, and src/types, so I did not wire the Electron main-process helper into this standalone Node CLI slice. I agree CLI telemetry could be useful, but I think it should be introduced as a separate CLI-safe reporting utility rather than coupling this adapter to the Electron main process.

@IAKGnaHz

Copy link
Copy Markdown
Author

I pushed one more small follow-up commit: c18b39f Add titled Paseo run command.

Reason: during local UI testing, schedule-created work is visible as schedule activity but the spawned one-off agents do not get the schedule name as their agent title. For the delegation workflow, one-off tasks should be easy to inspect in Paseo while we iterate on the orchestration layer.

This adds maestro-cli paseo run <prompt> as a CLI wrapper around paseo run, with detached titled execution as the default path:

maestro-cli paseo run \
  --title "Repo Health Check" \
  --provider codex \
  --cwd /path/to/repo \
  --detach \
  "Check the repo health and summarize the result."

Supported options include --title, --provider, --model, --thinking, --mode, --cwd, --detach / --no-detach, --wait-timeout, --host, --cli-path, and --json.

I also ran a real smoke test through the built Maestro CLI against the local Paseo daemon:

node dist/cli/maestro-cli.js paseo run \
  --title "Maestro Run Title Smoke" \
  --provider codex \
  --cwd /Users/admin/Documents/AMH/ALL-AI \
  --detach \
  --json \
  "..."

Paseo returned an agent with title: "Maestro Run Title Smoke"; paseo inspect <agent-id> --json showed Name: "Maestro Run Title Smoke", Status: "idle", and Archived: false. The agent also wrote the requested smoke-test artifact.

Validation:

  • npx tsc -p tsconfig.cli.json --noEmit
  • npx vitest run src/__tests__/cli/services/paseo.test.ts src/__tests__/cli/commands/paseo.test.ts src/__tests__/cli/commands/send.test.ts src/__tests__/cli/services/agent-spawner.test.ts
  • Full push validation passed: 546 passed / 1 skipped test files, 22554 passed / 107 skipped tests.

This keeps schedule create for recurring/delayed work, while giving Maestro a better default for visible one-off delegated tasks.

@jSydorowicz21

Copy link
Copy Markdown
Contributor

@greptile @CodeRabbit please re-review this pr

@jSydorowicz21

Copy link
Copy Markdown
Contributor

@IAKGnaHz Can you retarget this to the RC branch? Our branching strategy is to give things time to cook in a release candidate before we merge to mainline

@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== src/cli/services/paseo.ts ==="
cat src/cli/services/paseo.ts

echo ""
echo "=== src/cli/commands/paseo.ts ==="
cat src/cli/commands/paseo.ts

echo ""
echo "=== src/cli/index.ts (paseo section) ==="
grep -n "paseo" src/cli/index.ts -A 5 -B 2

echo ""
echo "=== src/__tests__/cli/services/paseo.test.ts ==="
cat src/__tests__/cli/services/paseo.test.ts

echo ""
echo "=== src/__tests__/cli/commands/paseo.test.ts ==="
cat src/__tests__/cli/commands/paseo.test.ts

Length of output: 20854


🏁 Script executed:

#!/bin/bash
echo "=== Full paseo block in src/cli/index.ts ==="
awk '/\/\/ Paseo commands/,/\/\/ Settings commands/' src/cli/index.ts

Length of output: 2828


🏁 Script executed:

#!/bin/bash
echo "=== Commander.js version ==="
node -e "const p = require('./node_modules/commander/package.json'); console.log(p.version)"

echo ""
echo "=== Commander option parsing for --no-run-now (test behavior) ==="
node -e "
const { Command } = require('commander');
const cmd = new Command();
cmd
  .option('--run-now', 'Fire one immediate run on creation')
  .option('--no-run-now', 'Wait for the first cadence interval');

// Test 1: --run-now
cmd.parse(['node', 'test', '--run-now']);
console.log('--run-now:', JSON.stringify(cmd.opts()));

// Test 2: --no-run-now
const cmd2 = new Command();
cmd2
  .option('--run-now', 'Fire one immediate run on creation')
  .option('--no-run-now', 'Wait for the first cadence interval');
cmd2.parse(['node', 'test', '--no-run-now']);
console.log('--no-run-now:', JSON.stringify(cmd2.opts()));

// Test 3: neither
const cmd3 = new Command();
cmd3
  .option('--run-now', 'Fire one immediate run on creation')
  .option('--no-run-now', 'Wait for the first cadence interval');
cmd3.parse(['node', 'test']);
console.log('neither:', JSON.stringify(cmd3.opts()));
"

Length of output: 3184


🏁 Script executed:

#!/bin/bash
grep -i "commander" package.json

Length of output: 115


🌐 Web query:

Commander.js: what happens when you declare both .option('--run-now') and .option('--no-run-now') explicitly? Does --no-run-now set runNow=false or noRunNow=true?

Length of output: 14827



@jSydorowicz21 — re-review complete. Here's the full picture after the follow-up commits:


✅ P1 — --no-run-now tri-state (fully fixed)

The service now correctly uses strict equality:

if (options.runNow === true)  { args.push('--run-now'); }
else if (options.runNow === false) { args.push('--no-run-now'); }
// undefined → neither flag forwarded

And Commander v14 handles this correctly: when .option('--run-now') is declared first, adding .option('--no-run-now') afterward maps to the same runNow property (true/false/undefined) — it does not create a separate noRunNow property. The Commander docs confirm: "If you define --foo first, adding --no-foo does not change the default value from what it would otherwise be." Combined positive+negative options have been supported since Commander v3; this repo uses v14. The tri-state round-trip works end-to-end.

✅ Null exit code (fixed)

code === null now produces 'Paseo exited without an exit code' — clear and accurate for signal-killed children.

✅ Spawn-failure test (added)

The child.emit('error', new Error('ENOENT')) path is now covered, exercising the child.on('error', ...) handler with the correct expected message.

✅ Sentry (reasonably deferred)

The src/main/utils/sentry.ts utility is scoped to the Electron main process and sits outside the CLI tsconfig. Introducing a CLI-safe reporting utility as a follow-up is the right call — coupling this adapter to Electron main would be the wrong direction.

maestro-cli paseo run (new command — looks clean)

  • runPaseoAgent defaults to --detach via options.detach !== false, consistent with Commander's true default on --detach.
  • --no-detach correctly sets detach = false via Commander negation, omitting the flag.
  • Both the detached-default and explicit-foreground test cases are covered.
  • Real smoke test against a live Paseo daemon validated titled agent creation.

No blocking issues remain. The integration is clean, the safety bounding story (explicit --cwd, provider selection, --max-runs, --expires-in, --no-run-now) is intact, and all previously flagged items have been addressed. This looks good to merge. 🐇


🧠 Learnings used
Learnt from: jSydorowicz21
Repo: RunMaestro/Maestro PR: 0
File: :0-0
Timestamp: 2026-03-18T03:05:59.524Z
Learning: In RunMaestro/Maestro (src/renderer/stores/agentStore.ts, command spawn path ~line 455), slash commands never set `interjectionLogId` on their queued items. Therefore the interjection delivery-tracking code (marking delivered/failed) is never reached for commands — only message-type items created by the interjection flow in `useInputProcessing.ts` carry `interjectionLogId`. Do not flag command interjections as "never transitioning out of queued" in future reviews.

Comment thread src/cli/services/paseo.ts
Comment on lines +172 to +176
if (options.detach !== false) {
args.push('--detach');
}
addOption(args, '--wait-timeout', options.waitTimeout);
addCommonOptions(args, options);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 --wait-timeout forwarded together with --detach

--detach is pushed whenever options.detach !== false (including when detach is undefined). --wait-timeout is then unconditionally appended from addOption. Because Commander sets detach: true by default, any invocation of maestro-cli paseo run --wait-timeout 5m <prompt> (without --no-detach) sends both --detach and --wait-timeout 5m to Paseo — contradictory flags that will either error or silently drop the timeout. The --wait-timeout option should only be forwarded when detach is explicitly false.

Suggested change
if (options.detach !== false) {
args.push('--detach');
}
addOption(args, '--wait-timeout', options.waitTimeout);
addCommonOptions(args, options);
if (options.detach !== false) {
args.push('--detach');
} else {
addOption(args, '--wait-timeout', options.waitTimeout);
}

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.

3 participants