Skip to content

Add Claude Code GitHub Workflow - #2

Merged
pedramamini merged 2 commits into
mainfrom
add-claude-github-actions-1764002617223
Nov 24, 2025
Merged

Add Claude Code GitHub Workflow#2
pedramamini merged 2 commits into
mainfrom
add-claude-github-actions-1764002617223

Conversation

@pedramamini

Copy link
Copy Markdown
Collaborator

🤖 Installing Claude Code GitHub App

This PR adds a GitHub Actions workflow that enables Claude Code integration in our repository.

What is Claude Code?

Claude Code is an AI coding agent that can help with:

  • Bug fixes and improvements
  • Documentation updates
  • Implementing new features
  • Code reviews and suggestions
  • Writing tests
  • And more!

How it works

Once this PR is merged, we'll be able to interact with Claude by mentioning @claude in a pull request or issue comment.
Once the workflow is triggered, Claude will analyze the comment and surrounding context, and execute on the request in a GitHub action.

Important Notes

  • This workflow won't take effect until this PR is merged
  • @claude mentions won't work until after the merge is complete
  • The workflow runs automatically whenever Claude is mentioned in PR or issue comments
  • Claude gets access to the entire PR or issue context including files, diffs, and previous comments

Security

  • Our Anthropic API key is securely stored as a GitHub Actions secret
  • Only users with write access to the repository can trigger the workflow
  • All Claude runs are stored in the GitHub Actions run history
  • Claude's default tools are limited to reading/writing files and interacting with our repo by creating comments, branches, and commits.
  • We can add more allowed tools by adding them to the workflow file like:
allowed_tools: Bash(npm install),Bash(npm run build),Bash(npm run lint),Bash(npm run test)

There's more information in the Claude Code action repo.

After merging this PR, let's try mentioning @claude in a comment on any PR to get started!

@pedramamini
pedramamini merged commit 4045294 into main Nov 24, 2025
1 check passed
@pedramamini
pedramamini deleted the add-claude-github-actions-1764002617223 branch November 24, 2025 16:44
This was referenced Dec 6, 2025
@claude claude Bot mentioned this pull request Dec 26, 2025
chr1syy referenced this pull request in chr1syy/Maestro Jan 12, 2026
chr1syy referenced this pull request in chr1syy/Maestro Jan 13, 2026
reachrazamair added a commit that referenced this pull request Feb 6, 2026
Address PR review feedback:

- Issue #1: Add early returns in openModal, closeModal, and closeAll
  to skip Map recreation when state hasn't changed. Prevents
  unnecessary selector re-evaluations across all subscribers.

- Issue #2: Add JSDoc to useModalActions() explaining that the ~40
  selector subscriptions are intentionally transitional — identical
  to old Context behavior. Components should migrate to direct
  useModalStore(selectModalOpen(...)) calls for granular subscriptions.

- Issue #5: Add 14 new tests covering no-op guard behavior (7 tests
  including render count verification), getModalActions() API surface
  and cross-call store sharing (3 tests), and useModalActions()
  reactive state and compatibility (4 tests).

Issues #3 (memory leak) and #4 (type overloads) are not actionable:
47 fixed modal IDs is bounded, and ModalDataFor<T> already resolves
to undefined for unmapped modals.
@claude claude Bot mentioned this pull request Feb 7, 2026
claudepalmeragent pushed a commit to claudepalmeragent/Maestro that referenced this pull request Feb 9, 2026
Adds investigation and planning documents for:

1. PRICING-BUGFIXES-PHASE2.md - Summary of 5 issues found during testing:
   - Issue RunMaestro#1: Agent Settings Detection - WORKING CORRECTLY
   - Issue RunMaestro#2: Folder Toggle Shows Blank - Minor bug, fix ready
   - Issue RunMaestro#3: Folder Detection Shows API - Critical bug, fix ready
   - Issue RunMaestro#4: Analysis of RunMaestro#1 vs RunMaestro#3
   - Issue RunMaestro#5: Dashboard costs - Requires separate plan

2. PRICING-DASHBOARD-COST-FIX.md - Comprehensive plan for Issue RunMaestro#5:
   - Root cause: Costs stored at API rates, billing mode never applied
   - Solution: Recalculate at storage time with proper billing mode
   - 6-phase implementation plan with database schema changes
   - Risk assessment and mitigation strategies
   - Timeline estimate: 12-18 hours

Auto Run fix documents created in /app/__AUTORUN/:
- PRICING-FIX-02-FOLDER-TOGGLE.md
- PRICING-FIX-03-FOLDER-DETECTION.md

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
claudepalmeragent pushed a commit to claudepalmeragent/Maestro that referenced this pull request Feb 9, 2026
…unMaestro#3)

Issue RunMaestro#2 - Folder toggle shows blank:
- Updated calculateProjectBillingState() to check detected modes when all agents are 'auto'
- If all detected modes match, shows that mode instead of 'mixed'

Issue RunMaestro#3 - Folder shows "API Key" instead of "Max":
- Extract SSH remote ID from session.sessionSshRemoteConfig when enabled
- Pass sshRemoteId to detectAuth() call for proper detection
- Added debug logging for verification

Also:
- Archived original pricing enhancement plan
- Updated PRICING-BUGFIXES-PHASE2.md to reflect completed status
- Added 6 new unit tests for SSH remote detection

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
claudepalmeragent added a commit to claudepalmeragent/Maestro that referenced this pull request Feb 26, 2026
Adds investigation and planning documents for:

1. PRICING-BUGFIXES-PHASE2.md - Summary of 5 issues found during testing:
   - Issue RunMaestro#1: Agent Settings Detection - WORKING CORRECTLY
   - Issue RunMaestro#2: Folder Toggle Shows Blank - Minor bug, fix ready
   - Issue RunMaestro#3: Folder Detection Shows API - Critical bug, fix ready
   - Issue RunMaestro#4: Analysis of RunMaestro#1 vs RunMaestro#3
   - Issue RunMaestro#5: Dashboard costs - Requires separate plan

2. PRICING-DASHBOARD-COST-FIX.md - Comprehensive plan for Issue RunMaestro#5:
   - Root cause: Costs stored at API rates, billing mode never applied
   - Solution: Recalculate at storage time with proper billing mode
   - 6-phase implementation plan with database schema changes
   - Risk assessment and mitigation strategies
   - Timeline estimate: 12-18 hours

Auto Run fix documents created in /app/__AUTORUN/:
- PRICING-FIX-02-FOLDER-TOGGLE.md
- PRICING-FIX-03-FOLDER-DETECTION.md

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
claudepalmeragent added a commit to claudepalmeragent/Maestro that referenced this pull request Feb 26, 2026
…unMaestro#3)

Issue RunMaestro#2 - Folder toggle shows blank:
- Updated calculateProjectBillingState() to check detected modes when all agents are 'auto'
- If all detected modes match, shows that mode instead of 'mixed'

Issue RunMaestro#3 - Folder shows "API Key" instead of "Max":
- Extract SSH remote ID from session.sessionSshRemoteConfig when enabled
- Pass sshRemoteId to detectAuth() call for proper detection
- Added debug logging for verification

Also:
- Archived original pricing enhancement plan
- Updated PRICING-BUGFIXES-PHASE2.md to reflect completed status
- Added 6 new unit tests for SSH remote detection

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
reachrazamair added a commit that referenced this pull request Apr 15, 2026
Decomposes three monolithic frontend files into SRP-clean hooks + presentational
components while preserving all public interfaces. The UsePipelineStateReturn
27-field contract stays byte-for-byte identical so downstream consumers compile
unchanged.

usePipelineState (804 → 227 lines): extract pipelineValidation.ts (pure),
useCueSettings, usePipelineCrud, usePipelineMutations, usePipelinePersistence.

CuePipelineEditor (865 → ~360 lines): extract usePipelineCanvasCallbacks,
usePipelineKeyboard, usePipelineContextMenu, usePipelineViewport. The
useSelectionRef bridge is replaced by a stable adapter pattern that lets
mutation callbacks pick up fresh selection IDs without creating a circular
hook dependency.

CueModal (551 → ~250 lines): extract useCueGraphData (with cancellation
race guard), useCueToggle, CueModalHeader and CueDashboard presentational
components.

Three behavior fixes ride along:
 - Fix #1: useCueSettings.settingsLoaded gates handleSave so a Cmd+S in the
   race window between modal mount and IPC resolve no longer persists YAML
   with default settings; shows a warning toast instead.
 - Fix #2: usePipelinePersistence tracks the success/error idle-timeout in
   a ref and clears it on unmount + before each re-schedule, eliminating the
   "setState on unmounted component" warning when closing the modal mid-timer.
 - Fix #3: CueModal → CuePipelineEditor → usePipelineState → usePipelinePersistence
   wires a new optional onSaveSuccess callback to useCueGraphData.refreshGraphData,
   so the dashboard reflects post-save state without a manual tab switch.

+191 new tests across 14 new test files. Full suite: 25,427 passed / 0 failed.
reachrazamair added a commit that referenced this pull request May 9, 2026
Applies the still-valid issues from review of the §4.4 decomposition
and skips the rest with rationale below.

Behavior fixes:
- useAgentExitListener: move activeHiddenToolRef.delete() to AFTER the
  getActiveProcesses safety check so a false-positive exit event no
  longer drops bookkeeping for a process that's still alive.

Code-quality cleanups:
- useAgentSshRemoteListener: drop the redundant try/catch around the
  git probe IIFE. gitService.isRepo / getBranches / getTags route
  through createIpcMethod which already swallows IPC errors, reports
  to Sentry, and returns the configured default value, so the wrapper
  was dead code that risked masking genuine programmer errors.
- useAgentThinkingListener: collapse three near-identical
  updatedTabs.map() branches into a single map by computing the
  replacement logs once per chunk (append vs. clean-continuation vs.
  malformed-continuation). Behavior unchanged; ~30 lines lighter.
- useAgentUsageListener: replace the magic "-5" buffer with a named
  constant ESTIMATED_USAGE_YELLOW_GAP_PCT and document why we keep
  estimates below the user's yellow threshold.
- autorunSynopsisPrompt: replace `result.content!` with
  `result.content ?? ''` so cachedAutorunSynopsisPrompt always
  satisfies the `string | null` type contract even if the IPC layer
  ever violates the success-implies-content invariant.

Test improvements:
- useAgentSshRemoteListener.test: the "same remote already attached"
  case had zero assertions (vacuous pass). Now sets isGitRepo=true and
  asserts the git probe functions were not called.
- useAgentThinkingListener.test: the RAF cleanup test only checked
  cancelAnimationFrame was invoked. The mock is now cancellable
  (id -> callback Map; cancelAnimationFrame removes from the queue),
  and the test additionally calls flushRaf() AFTER unmount and asserts
  no logs were appended — proves the cancelled callback truly cannot
  fire.
- useAgentUsageListener.test: the "routes usage updates" test only
  checked that updateUsage was called. Now uses
  toHaveBeenNthCalledWith for both the per-tab and per-session calls;
  added a second test that asserts ai-tab-format ids carry the tabId
  on call #1 and null on call #2.
- exitSynopsis.test: the UUID-prefix test only covered uppercase. New
  positive test pins the case-sensitive contract by asserting that
  lowercase 8-hex tab names ARE persisted (the auto-generated fallback
  is always uppercase, so lowercase can only have been user-typed).

Skipped (with reason):
- "Make UUID-prefix regex case-insensitive" — the only fallback path
  uses `agentSessionId.substring(0, 8).toUpperCase()`, so lowercase
  8-hex names can only have come from the user typing them. Making
  the regex case-insensitive would silently drop those custom names.
- "Use parsed.actualSessionId instead of parsed.baseSessionId in
  useAgentErrorListener" — the original (pre-decomposition) code used
  baseSessionId intentionally to attribute batch-suffix errors to the
  user-visible session. Changing would break that attribution. The
  "match useAgentSessionIdListener" claim is misleading because that
  listener bails on isBatchSession() before parsing.
- "Re-throw on getActiveProcesses safety-check failure" — pre-refactor
  code swallowed too; the current logger.error path is not silent
  (forwards to main with full context). Re-throwing would leave the
  agent's tab in a permanently busy state on transient IPC failures
  for very limited Sentry value.
- "Move IPC + flag-mutation outside useAgentSessionIdListener
  reducer" — the targetTab/isClaudeCode lookup IS the bulk of the
  reducer body, so hoisting would force a duplicate pass. The IPC is
  idempotent (no harm if double-fired in StrictMode dev). Out of
  minimal-change scope.

Validation: 179 / 179 listener tests passing (was 177);
27,722 / 108 skipped / 0 failing across the full suite (+2 from the
new lowercase UUID and ai-tab routing tests). Zero type errors, zero
lint errors.
trillium added a commit to trillium/Maestro that referenced this pull request Jun 8, 2026
…unMaestro#2)

Lifts src/renderer/components/DeleteGroupChatModal.tsx (77 LOC, 0 IPC,
0 Electron-only API) verbatim into src/webFull/components/, with a
6-story parity catalog (3 happy + 3 negative) and a barrel re-export.

This is leaf-parade batch RunMaestro#2 per the Architect plan-reeval-3 audit and
follows the exact pattern that closed the L2.4 CreateGroupModal lift:
- Theme prop convention preserved (per L2.1 / L2.3 / L2.4 precedent)
- MODAL_PRIORITIES resolved via the existing webFull re-export shim
- Modal + ModalFooter from the L2.1 primitives
- Catalog uses only the allowed assertion vocabulary

Renderer-side consumers (AppModals, useGroupChatHandlers,
useSessionListProps, App.tsx, modalStore.ts) are NOT touched. Feature
wiring into the webFull tree is a downstream-layer concern.

Closes ISC-44.layer-2.5.delete_groupchat as [x] CLOSED. Reserves the
ISC-44.layer-2.5.* namespace for the next leaf-parade batch entries.

Scope guards:
- git diff main..HEAD -- src/renderer/ src/web/ src/main/ src/server/
  | wc -c -> 0
- npm run lint -> clean (tsc -p tsconfig.lint.json + main + cli)
- npx vitest run src/webFull/components/DeleteGroupChatModal.parity.test.ts
  -> 6 tests passed
- npm run build:webfull -> exit 0 (latent surface area, not yet wired
  into the entry)
trillium added a commit to trillium/Maestro that referenced this pull request Jun 8, 2026
…alize cross-fork import from GroupChatMessages

Lift `src/renderer/utils/participantColors.ts` into `src/webFull/utils/participantColors.ts`. Pure utility — not a component. Precondition RunMaestro#2 for the upcoming GroupChatInput lift per Architect audit RunMaestro#7.

Why
====

The L2.5 leaf-groupchat-messages lift accepted six cross-fork imports as transitive surface. The MarkdownRenderer lift already neutralized one. This lift neutralizes a second — the `generateParticipantColor` + `buildParticipantColorMap` import.

Lift decision: pure surface only
=================================

Renderer source has three groups of exports:

1. Pure color generation (`generateParticipantColor`, `buildParticipantColorMap`, `MODERATOR_COLOR_INDEX`, `COLOR_PALETTE_SIZE`) — pure.
2. Pure pref-aware color generation (`buildParticipantColorMapWithPreferences`, `ParticipantColorInfo` type) — pure.
3. Preference persistence (`loadColorPreferences`, `saveColorPreferences`, `COLOR_PREF_KEY`) — touches `window.maestro.settings.{get,set}`. Impure.

The cross-fork import being neutralized only consumes group (1). No current webFull consumer of group (3). Lift carries groups (1) + (2) + the `normalizeMentionName` / `mentionMatches` re-exports from `shared/group-chat-types`. Lift omits group (3). The header comment on the lifted file documents the omission explicitly: when a webFull consumer needs persisted color preferences, the right move is a webFull settings adapter (likely WS-backed), not a smuggled `window.maestro` reference here.

Import-path adapts (one)
========================

`Theme` from `'../types'` → `'../../shared/theme-types'`. Standard L2.5 swap — webFull has no `types/` aggregator, and the renderer `types/index.ts` is itself just a re-export of the shared type, so this is structurally a no-op for the type system.

GroupChatMessages retarget
==========================

`src/webFull/components/GroupChatMessages.tsx` flips from `'../../renderer/utils/participantColors'` → `'../utils/participantColors'`. Surgical 2-byte path edit. Cross-fork edge gone. Parity catalog still 6/6.

Utility test (NOT a parity catalog)
====================================

The brief explicitly carved out utilities from the parity-catalog rule. `src/webFull/utils/participantColors.test.ts` ships 21 vitest cases across 5 describe-blocks covering: `generateParticipantColor` determinism + HSL shape + Moderator-reserved hue + light/dark theme variation + palette wrapping + saturation/lightness clamps; `buildParticipantColorMap` empty/single/ordered/over-palette cases; `buildParticipantColorMapWithPreferences` Moderator reservation + preference honoring + index-0 rejection for non-Moderator preferences; palette constants pinning; re-export shape.

Verification
============

- Pre-flight grep on renderer source → 2 hits (both inside the omitted persistence functions).
- Pre-flight grep on lifted source → empty.
- Lint: `MAESTRO_HEADLESS=1 npm run lint` → clean (after `build:prompts`).
- Util test: 21/21 PASS.
- Regression test: GroupChatMessages parity catalog still 6/6 PASS.
- Cross-fork edge check: empty (gone).
- Scope guard: `git diff main..HEAD -- src/web/ src/renderer/ src/main/ src/server/` → 0 bytes.

Files
=====

NEW:
- src/webFull/utils/participantColors.ts
- src/webFull/utils/participantColors.test.ts

MODIFIED (additive):
- src/webFull/utils/index.ts (Layer 2.5 leaf-parade primitives section added — additive)
- src/webFull/components/GroupChatMessages.tsx (1-line retarget — cross-fork edge gone)
- ISA.md (Decision entry + ISC-44.layer-2.5.participant_colors_util [x] CLOSED)

NOT touched: src/web/, src/renderer/, src/main/, src/server/.
trillium added a commit to trillium/Maestro that referenced this pull request Jun 8, 2026
…o zero

Per audit RunMaestro#9, lift `src/renderer/components/GroupChatInput.tsx` (662 LOC, 0
IPC at module load, 0 Electron-only API per pre-flight grep) verbatim into
`src/webFull/components/GroupChatInput.tsx`. Both audit-RunMaestro#9 preconditions
are now on `main`: (1) `QueuedItemsList` lift
(ISC-44.layer-2.5.queued_items_list), and (2) `participantColors` util
lift (ISC-44.layer-2.5.participant_colors_util). With both landed, every
transitive component/util dep resolves inside the webFull tree.

Import-path adapts (six, matching the L2.5 precedent set by
`GroupChatPanel` / `GroupChatHeader`):
- `Theme` from `'../types'` → `'../../shared/theme-types'`
- `GroupChatParticipant` + `GroupChatState` from `'../types'` →
  `'../../shared/group-chat-types'`
- `Group` from `'../types'` → `'../../shared/types'`
- `Session` + `QueuedItem` + `Shortcut` from `'../types'` →
  `'../../renderer/types'` (three cross-fork pure data-shape imports,
  matching the GroupChatPanel precedent; the renderer types barrel is
  IPC-clean per pre-flight grep)
- `shortcutFormatter` helpers → `'../utils/shortcutFormatter'` (webFull
  shim; fourth consumer)
- `QueuedItemsList` → `'./QueuedItemsList'` (precondition RunMaestro#1)
- `normalizeMentionName` → `'../utils/participantColors'` (precondition RunMaestro#2)

Settings-store adapt (strip-and-promote-to-prop): the renderer's line 117
`useSettingsStore((s) => s.spellCheck)` hook call is stripped and
`spellCheck?: boolean` is promoted onto the prop surface with a `true`
default matching the renderer store's initial state. Host wiring is
downstream. Precedent: `AppOverlays` strips three store hooks and
promotes the values onto its prop surface; `SessionList` strips a similar
set.

GroupChatPanel cross-fork drain: this commit also retargets
`src/webFull/components/GroupChatPanel.tsx` line 84 from
`'../../renderer/components/GroupChatInput'` → `'./GroupChatInput'`.
That was the last cross-fork *component* edge in `GroupChatPanel` (per
the `leaf-groupchat-panel` evidence). `GroupChatPanel`'s remaining
cross-fork edges are now exclusively the three pure data-shape type
imports `Session` / `QueuedItem` / `Shortcut` from
`'../../renderer/types'` — same edges as `GroupChatInput` itself; they
collapse together when those interfaces are replicated to `src/shared/`
in a future downstream cleanup. `GroupChatPanel.parity.test.ts`
regression check passes 7/7 after the retarget — no behavioral drift.

Parity catalog (`GroupChatInput.parity.test.ts`, 10 stories: 5 happy + 5
negative; 7 catalog-shape vitest guards). Happy: textarea + idle
placeholder, busy placeholder swap, Send-button title-swap,
Read-Only-pill literal copy, QueuedItemsList composition via
`"QUEUED (3)"` copy. Negative: queue-suppression-when-empty,
prompt-composer-suppression-when-not-wired,
mention-dropdown-not-rendered-on-mount, no-modal-shape pin (structural
guard against future drift toward `[role="dialog"]`), and a no-IPC /
no-WS lifecycle pin. Render-shape vocabulary guard pins happy-path
stories to `hasElement` / `hasText` only; IPC-leakage guard pins the
banned-target list.

Renderer-side consumers UNTOUCHED. Feature wiring into the webFull tree
is a downstream-layer concern.

Verification:
- `npm run lint` clean for `src/webFull/` (zero new errors vs baseline)
- `npx vitest run src/webFull/components/GroupChatInput.parity.test.ts`
  → 7/7 passed
- `npx vitest run src/webFull/components/GroupChatPanel.parity.test.ts`
  → 7/7 regression still passing
- `grep 'renderer/components/GroupChatInput' src/webFull/components/GroupChatPanel.tsx`
  → no actual import-line matches (only doc-comment evidence trail)
- `git diff main -- src/web/ src/renderer/ src/main/ src/server/` → 0 bytes

Files added:
- src/webFull/components/GroupChatInput.tsx
- src/webFull/components/GroupChatInput.parity.test.ts

Files modified (additive only):
- src/webFull/components/index.ts (barrel export)

Files modified (cross-fork drain, permitted by brief):
- src/webFull/components/GroupChatPanel.tsx (one-line import flip)

ISA: ISC-44.layer-2.5.groupchat_input flipped to `[x]` CLOSED;
Decision entry added documenting the lift and the GroupChatPanel
cross-fork drain.

Closes: ISC-44.layer-2.5.groupchat_input
trillium added a commit to trillium/Maestro that referenced this pull request Jun 8, 2026
Audit RunMaestro#14 recommendation RunMaestro#2. Freezes the contract for the webFull WS
process-lifecycle frame family BEFORE the wizard Phase 3 engine port
starts. The create_session frame shipped in 18fcada was the first
family member; this Decision is the canonical reference for the six
remaining siblings.

Family members:
  - create_session / create_session_result (SHIPPED, commit 18fcada)
  - process_spawn (Client->Server, DEFERRED to wave-16)
  - process_kill (Client->Server, DEFERRED)
  - process_data (Server->Client, DEFERRED, MUST raw-chunk)
  - process_exit (Server->Client, DEFERRED)
  - process_thinking_chunk (Server->Client, OPTIONAL capability)
  - process_tool_execution (Server->Client, OPTIONAL capability)

Three contract vectors locked in:
  - SSH passthrough via sessionSshRemoteConfig + wrapSpawnWithSsh()
  - process_data raw chunking (no batching, no newline framing)
  - Optional capability flags for thinking-chunk + tool-execution

Naming convention: snake_case for WS frame type field; renderer
callback registry keys match frame type verbatim (matches the
create_session / create_session_result precedent).

Pre-port discipline: Wizard Phase 3 engine files (conversationManager,
phaseGenerator, inlineWizardConversation, inlineWizardDocumentGeneration)
DO NOT START until the family ships. Phase 1 leaves land independently.

Adds ISC-44.ws.process_lifecycle_family (open) tracking the umbrella;
it blocks ISC-44.wizard.phase_3_engines.

No code touched. Zero diff vs main on src/, infra/, tests/. ISA.md only.

Verification: npm run build:prompts succeeds.
jSydorowicz21 added a commit that referenced this pull request Jun 27, 2026
…ity, SDK publish CI

Three more plugin-interface roadmap items, all OS-agnostic.

#2 Dispatch via the Pianola risk gate:
- New pure plugin-dispatch-gate (rateRisk): a HIGH-risk cue-trigger prompt is
  never auto-dispatch-eligible. The scheduler now risk-classifies dispatch
  triggers and SURFACES them to the user instead of silently skipping. Auto-fire
  additionally requires a live agents:dispatch grant (never bypasses consent)
  and a wired sink - actual auto-execution to an agent stays inert pending the
  Phase-3 sandbox decision, so this ships the gate + surfacing, not unsupervised
  dispatch.

#7 Per-plugin observability:
- The sandbox host tracks per-plugin total calls, in-flight/peak, last-active,
  crash count, and a bounded (50) recent-log ring buffer - observation only; the
  MAX_IN_FLIGHT/RATE enforcement is unchanged. New gated plugins:get-activity
  channel + preload bridge + a PluginActivityView in the Plugins settings panel.

#6 SDK publish CI:
- .github/workflows/plugin-sdk-publish.yml builds + tests + publishes
  @maestro/plugin-sdk on a plugin-sdk-v* tag or manual dispatch (checkout +
  setup-node v4, bun install, npm publish via NPM_TOKEN).

Verification: tsc (lint/main/cli) clean; ESLint + Prettier clean; affected
suites green (shared/plugins + main/plugins + ipc plugins = 221; dispatch gate +
scheduler host = 7; sandbox-host activity + handlers = 16; existing host = 4).
jSydorowicz21 added a commit that referenced this pull request Jul 3, 2026
…ity, SDK publish CI

Three more plugin-interface roadmap items, all OS-agnostic.

#2 Dispatch via the Pianola risk gate:
- New pure plugin-dispatch-gate (rateRisk): a HIGH-risk cue-trigger prompt is
  never auto-dispatch-eligible. The scheduler now risk-classifies dispatch
  triggers and SURFACES them to the user instead of silently skipping. Auto-fire
  additionally requires a live agents:dispatch grant (never bypasses consent)
  and a wired sink - actual auto-execution to an agent stays inert pending the
  Phase-3 sandbox decision, so this ships the gate + surfacing, not unsupervised
  dispatch.

#7 Per-plugin observability:
- The sandbox host tracks per-plugin total calls, in-flight/peak, last-active,
  crash count, and a bounded (50) recent-log ring buffer - observation only; the
  MAX_IN_FLIGHT/RATE enforcement is unchanged. New gated plugins:get-activity
  channel + preload bridge + a PluginActivityView in the Plugins settings panel.

#6 SDK publish CI:
- .github/workflows/plugin-sdk-publish.yml builds + tests + publishes
  @maestro/plugin-sdk on a plugin-sdk-v* tag or manual dispatch (checkout +
  setup-node v4, bun install, npm publish via NPM_TOKEN).

Verification: tsc (lint/main/cli) clean; ESLint + Prettier clean; affected
suites green (shared/plugins + main/plugins + ipc plugins = 221; dispatch gate +
scheduler host = 7; sandbox-host activity + handlers = 16; existing host = 4).
jSydorowicz21 pushed a commit to stevenmgordon/Maestro that referenced this pull request Jul 9, 2026
From the branch review (10 findings). Fixed here:
- RunMaestro#1 decision cards: reply with force=true so a choice made mid-turn isn't
  silently dropped by the renderer busy guard while the UI reports success.
- RunMaestro#2 cadenza bridge: gate cadenzaView on the concerto flag like movementView, so
  the feature is fully inert when off (no invisible in-app store population).
- RunMaestro#4 BlockView crash: coerce agent-authored leaf values (table cells/headers,
  heading, badge, callout, group/section titles, text) via toText(), and wrap the
  view in an error boundary, so an object-valued field can't blank the whole app.
- RunMaestro#5 movement add/update clamp x/y >= 0 like move, so a panel can't be stranded
  off-screen with its only drag handle + close button.
- RunMaestro#6 HUD interval leak: let the 'closed' handler own teardown; closeCadenzaHudWindow
  no longer nulls hudWindow early (which skipped clearInterval(hoverPoll)).
- RunMaestro#7 HUD rect effect: key ResizeObserver setup on card ids, re-report positions in
  a light effect, so a drag doesn't rebuild the observer every frame.
- RunMaestro#10 settings search: add encore-concerto entry + data-setting-id anchor.
- minors: export/reuse ORANGE_HEX, selectSessionById in resolveAgentName, fix
  stale cadenza.ts path in first-party.ts comment.

Regression tests added for RunMaestro#4 (object cell coerces) and RunMaestro#5 (clamp). Deferred and
tracked separately: RunMaestro#3 (cadenza chip->HUD routing), RunMaestro#8 (store/drag dedup), RunMaestro#9
(first-party contribution point + HUD window lifecycle) - all tie to the HUD
architecture and need a design decision.
jSydorowicz21 pushed a commit to stevenmgordon/Maestro that referenced this pull request Jul 10, 2026
From the branch review (10 findings). Fixed here:
- RunMaestro#1 decision cards: reply with force=true so a choice made mid-turn isn't
  silently dropped by the renderer busy guard while the UI reports success.
- RunMaestro#2 cadenza bridge: gate cadenzaView on the concerto flag like movementView, so
  the feature is fully inert when off (no invisible in-app store population).
- RunMaestro#4 BlockView crash: coerce agent-authored leaf values (table cells/headers,
  heading, badge, callout, group/section titles, text) via toText(), and wrap the
  view in an error boundary, so an object-valued field can't blank the whole app.
- RunMaestro#5 movement add/update clamp x/y >= 0 like move, so a panel can't be stranded
  off-screen with its only drag handle + close button.
- RunMaestro#6 HUD interval leak: let the 'closed' handler own teardown; closeCadenzaHudWindow
  no longer nulls hudWindow early (which skipped clearInterval(hoverPoll)).
- RunMaestro#7 HUD rect effect: key ResizeObserver setup on card ids, re-report positions in
  a light effect, so a drag doesn't rebuild the observer every frame.
- RunMaestro#10 settings search: add encore-concerto entry + data-setting-id anchor.
- minors: export/reuse ORANGE_HEX, selectSessionById in resolveAgentName, fix
  stale cadenza.ts path in first-party.ts comment.

Regression tests added for RunMaestro#4 (object cell coerces) and RunMaestro#5 (clamp). Deferred and
tracked separately: RunMaestro#3 (cadenza chip->HUD routing), RunMaestro#8 (store/drag dedup), RunMaestro#9
(first-party contribution point + HUD window lifecycle) - all tie to the HUD
architecture and need a design decision.
chr1syy added a commit that referenced this pull request Jul 11, 2026
* feat(usage): add per-agent Context Timeline inspector

Adds a turn-by-turn view of how an agent's context window fills over a
run, inspired by the interactive context-window visualization that landed
in the Claude Code docs.

Provider-agnostic by construction: it taps the single per-turn usage
stream every provider already feeds (process:usage -> useAgentUsageListener)
and stores normalized UsageStats points, so there is no per-agent code.
The window denominator is provider-reported when available (e.g. Codex)
and a static estimate otherwise; the panel says so rather than implying
false precision. Providers that only report usage at end-of-run (e.g.
Factory Droid) show a single point instead of an evolving series.

- contextTimelineStore: in-memory, bounded, always-on per-session capture
- useAgentUsageListener: records one point per usage event (no new IPC)
- ContextTimelinePanel: floating inspector, opened by clicking the
  context-usage readout in the Main Panel header; anchored bottom-left so
  it never collides with the Thought Stream panel
- unit tests for the store lifecycle and buffer bounding

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(context-timeline): address review feedback

- De-duplicate context-window resolution: compute resolvedWindow once and
  reuse it for both the timeline point and the accumulated-growth fallback,
  fixing a terminal-case divergence (Greptile/CodeRabbit).
- Prune per-session buffers on agent deletion: add removeSession() to the
  store and call it from sessionStore.removeSession so deleted agents don't
  leak buffers; it also hides the panel if the deleted session was focused.
- Guard the misleading overflow readout: on an accumulated multi-tool turn
  whose raw tokens exceed the window, cap the displayed figure to the window
  and flag it ("200k+ / 200k") instead of implying an impossible breach.
- Tests: assert the selector's stable-empty-array identity (toBe) and cover
  removeSession (focused + unfocused panel).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(context-timeline): address second-round review feedback

- Exclude synthetic runs (synopsis / Auto Run batch) from the timeline: they
  map to the parent baseSessionId but consume a separate process context, so
  recording them polluted the visible agent's timeline. Only interactive runs
  (ai-tab / legacy-ai / regular) are recorded now, matching the visible usage
  gauge which keys off actualSessionId. (chatgpt-codex-connector)
- Skip Copilot output-only deltas (output tokens only, zero input/cache) so a
  normal Copilot run no longer dips to just the latest output tokens between
  context snapshots; mirrors the snapshot-preserving guard in
  useBatchedSessionUpdates. (chatgpt-codex-connector)
- Drive the per-row bar width from the same source as the % label/color
  (provider percentage when available, else tokens/window ratio) so width and
  label can't visually disagree. (CodeRabbit)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(context-timeline): address third-round review feedback

- Register the inspector as an OVERLAY layer, not a modal: opening a passive
  inspector was tripping hasOpenModal() and suppressing global shortcuts +
  file-tree navigation. Extends useModalLayer with an optional layerType
  ('modal' default, 'overlay' opt-in); the inspector still takes Escape to
  minimize but no longer blocks shortcuts. (chatgpt-codex-connector)
- Hide the inspector while any real modal is open, so its high z-index can't
  float it above lower-z dialogs (Create PR, expanded Auto Run) that own the
  foreground. It stays registered (Escape still works) but renders nothing.
  (chatgpt-codex-connector)
- Prune timeline buffers from setSessions deletions: the real delete flows
  (single-agent, group delete) filter the array and call setSessions directly,
  bypassing removeSession. Diff old vs new on length-decrease and drop the
  vanished agents' buffers there. (chatgpt-codex-connector)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(context-timeline): stop blocking shortcuts; fix modal-state read; a11y

Root-cause pass on the layer integration:

- The inspector no longer registers a layer at all. Any layer (even an
  overlay) trips hasOpenLayers()/hasOpenModal() and suppresses global
  shortcuts (Cmd+K, Cmd+N) + file-tree keys while open - wrong for a passive
  inspector. It's dismissed via its own X/minimize buttons. This reverts the
  overlay layerType experiment, so useModalLayer is back to pristine and the
  unused CONTEXT_TIMELINE priority is removed. (chatgpt-codex-connector #1/#2)
- Fix the modal-state read: it imported hooks/ui/useLayerStack (the stack
  CREATOR, with its own useState) instead of the context accessor, so
  hasOpenModal() observed a private empty stack and never hid the panel. Now
  imports contexts/LayerStackContext, so the hide-while-modal-open guard
  actually works. (chatgpt-codex-connector #4)
- Make the header opener keyboard accessible: role="button", tabIndex, an
  aria-label, and Enter/Space handling, so the inspector is reachable without
  a mouse in this keyboard-first UI. (chatgpt-codex-connector #3)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(context-timeline): respect configured/custom context windows

The timeline denominator now matches the header gauge's window precedence
(resolveConfiguredContextWindow): a per-agent `customContextWindow` or a
`[1m]` model marker wins over the reported/static window. Previously a
session configured for e.g. 1M had timeline points stored against a 200k
denominator with an inflated percentage while the header gauge used 1M.

The per-row percentage is now derived from that same configured-aware
window, so the row is internally consistent and agrees with the header. The
async agent-config lookup is intentionally skipped on this hot per-turn
path; the two synchronous sources cover the configured cases that would
otherwise mis-size. (chatgpt-codex-connector)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(context-timeline): plot cumulative context for Codex, not per-turn deltas

Addresses the P2 review thread on useAgentUsageListener: for providers whose
CLI reports cumulative session usage that we delta-normalize before emitting
(Codex), the timeline was recording each per-turn DELTA as the context figure,
so a long Codex conversation showed low, non-growing fill even as the window
actually filled.

- StdoutHandler.normalizeUsageToDelta now attaches the pre-normalization
  cumulative totals as `absoluteUsage` on the emitted UsageStats. The top-level
  fields stay per-turn deltas (correct for token accumulation); `absoluteUsage`
  carries the running total that actually occupies the context window. Only set
  on delta events - the first event is already absolute.
- The Context Timeline listener plots contextTokens/percentage from
  `absoluteUsage` when present, falling back to the per-turn stats for per-call
  providers (Claude/Copilot/OpenCode). The point's per-turn token chips stay as
  the deltas (this turn's activity).
- Added `absoluteUsage` (optional) to the shared UsageStats type.

Tests: StdoutHandler asserts the cumulative snapshot rides along on the delta
event (and is absent on the first raw event); the listener asserts the timeline
plots occupancy from the absolute totals, not the delta.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(context-timeline): scope absoluteUsage to Codex; keep output-only turns, drop repeats, fix focus ring

Follow-up review on the Codex context fix:

- Restrict `absoluteUsage` to combined-context providers (Codex).
  normalizeUsageToDelta also runs for Claude Code, which can look monotonic for
  the first turns of a session; Claude's per-call values are NOT cumulative
  occupancy, so attaching a snapshot there would let the timeline plot
  cumulative token spend as context fill. Gated on COMBINED_CONTEXT_AGENTS.
- Do not drop Codex output-only turns: the output-only skip now applies only
  when there is no `absoluteUsage`. A Codex output-only turn still carries an
  absolute snapshot reflecting real context growth and must be recorded.
- Coalesce duplicate Codex usage events: Codex emits a usage update for BOTH the
  token_count event and turn.completed with identical cumulative totals, so the
  second is an all-zero delta. Skip no-activity events so the panel doesn't gain
  a duplicate row / repeated context point.
- Restore keyboard focus visibility on the context-timeline trigger: the
  focusable header widget dropped the native outline with no replacement; add a
  focus-visible ring (keyboard-first UI).

Tests: Claude Code delta carries no absoluteUsage; Codex delta does; Codex
output-only turn is recorded from the absolute snapshot; zero-delta Codex repeat
is skipped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(context-timeline): honor provider-configured context window in the timeline

Follow-up review: the timeline listener sized points from only the per-session
custom window and the model marker, while the header gauge also resolves the
provider's configured window via the async getConfig step. For agents whose
window is configured at the provider level only (e.g. OpenCode, which doesn't
report contextWindow live), the timeline plotted against the static table while
the gauge used the configured value.

Add a small synchronous cache in contextWindowResolver (getCached... +
ensureConfiguredContextWindowCached) so the hot per-turn listener can honor the
provider-configured window without awaiting getConfig on every event: the two
sync sources still take precedence and cover the common cases immediately, and
the cache - primed off-path - closes the gap on subsequent turns. Provider-config
edits that don't change the per-session key are picked up on the next load.

Test: an OpenCode session with no per-session override and no reported window
sizes the timeline against the cached 300k provider window once primed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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