Add Claude Code GitHub Workflow - #2
Merged
Merged
Conversation
This was referenced Nov 27, 2025
Merged
Merged
This was referenced Dec 14, 2025
Merged
Merged
Merged
This was referenced Jan 3, 2026
This was referenced Feb 4, 2026
Merged
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.
Merged
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>
This was referenced Feb 11, 2026
5 tasks
10 tasks
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>
7 tasks
4 tasks
5 tasks
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.
This was referenced May 3, 2026
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.
This was referenced May 29, 2026
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 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:
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
Security
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!