Repository navigation
Conversation
Introduce lightweight Profiles: a named override bundle layered on an existing base agent that overrides model, reasoning effort, role system-prompt, and optionally extra CLI args - same binary, cwd, and SSH config as the base agent. Profiles are the "assignee" primitive the Board (later phases) wires cards to. - src/shared/profiles/types.ts: AgentProfile type, pure resolveProfileSpawnOverrides (profile -> base agent -> undefined) mapping onto existing SpawnAgentOptions fields (no new spawn params), and a reusable validateAgentProfile guard. - src/main/profiles/profile-storage.ts: per-project .maestro/profiles.yaml load/save/list/upsert/delete using the shared js-yaml dep; skips malformed/duplicate entries with a logged warning. - IPC: profiles:list/upsert/delete handler + preload bridge + window.maestro.profiles namespace, following the Cue handler pattern. - UI: minimal ProfilesModal (list + create by base agent/model/effort/role), registered with useModalLayer and select-none. - Tests: resolution-order + validation unit tests; storage round-trip and malformed-skip tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Introduce the persistent Board: a per-project task DAG stored in .maestro/board.yaml (human-diffable, git-trackable, mirroring the Cue and Phase 1 Profiles conventions). This phase is the data foundation only - no dispatcher (Phase 3) and no rich UI (Phase 4). - src/shared/board/types.ts: pure BoardCard / CardStatus / CardRun / WorktreeRef / Board contracts with per-status meaning comments, plus validateBoardCard/validateBoard guards mirroring Phase 1's profile validator. - src/shared/board/graph.ts: pure DAG helpers consumed by the Phase 3 dispatcher - getEligibleCards (todo cards with all parents done), getBlockers (not-done parents), hasCycle (iterative 3-color DFS; self-parent = cycle, dangling parent id ignored). Fully unit-tested (22 cases). - src/main/board/board-storage.ts: single owner of .maestro/board.yaml using the shared js-yaml dep (no new dependency). load/save/list/get + card mutations (addCard, updateCard, updateCardStatus, deleteCard); save rejects a cyclic graph via hasCycle, load skips malformed cards/boards with a logged warning. Adds BOARD_CONFIG_PATH to shared/maestro-paths.ts. 13 tests. - IPC: board:list/get/addCard/updateCard/setCardStatus/deleteCard handler + preload bridge + typed window.maestro.board namespace, following the Cue and Profiles handler pattern; registered in the main process. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Make the Board actually run: a board-dispatch pass on the existing Cue engine heartbeat tick drains each project's task DAG - promote eligible cards, spawn the assignee profile through the existing executeCuePrompt path (SSH/custom config honored), enforce a WIP cap, and move cards to done/blocked from completion markers (marker wins, else exit status). - src/shared/board/cardMarkers.ts: parseCardMarkers (card-complete / card-block), modeled on goalMarkers. - src/main/board/board-dispatcher.ts: pure-ish orchestrator with all side effects injected (testable without Electron); promote / WIP-cap claim / marker+exit completion / circuit breaker (2 failures) / stale-running reclaim. - src/main/board/board-spawn.ts: resolve card profile -> base agent and run via executeCuePrompt. - src/main/cue/cue-engine.ts: boardDispatchTick on the shared heartbeat tick (no second timer), one dispatcher per board, gated on BOTH maestroCue && board (Board requires Cue) read fresh each tick. - src/shared/plugins/first-party.ts: BOARD_FIRST_PARTY_PLUGIN (mirrors Cue; dispatch/spawn stay host-owned). - renderer: board Encore flag + default + Extensions beta tile. - tests: cardMarkers + dispatcher lifecycle (A->B->C under cap 1, block marker, circuit breaker) with fakes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Visual kanban surface over the persistent task DAG (Phase 2 IPC), dispatched on the Cue tick (Phase 3). Six status columns, a card create/edit editor, parent-dependency badges, and manual drag-to-move. - src/renderer/components/BoardModal.tsx: six-column kanban, live-polled board state, inline card editor (title/body/assignee-profile/status/ optional worktree/parents), client-side hasCycle guard with inline error, HTML5 drag-to-move calling setCardStatus (coarse-pointer haptic), "waiting on N" blocker badges via getBlockers. - board:create IPC: createBoard in board-storage + handler + preload + global.d.ts, so the UI can stand up the first board on demand. - modalStore/AppStandaloneModals/App.tsx: boardModal state, lazy render gated on encoreFeatures.board, force-close when board OR maestroCue turns off (Board depends on Cue), entry point gated on both flags. - Entry points: Quick Actions "Board" command (threaded onOpenBoard through the AppModals chain) + "Open Board" button in the Extensions Board tile (mirrors Pianola). - Extensions dependency gate: BUILTIN_DEPENDENCIES (board -> maestroCue, first dependent flag) + isDependencyMet; ExtensionDetails disables the Board Enable toggle with a "Requires Maestro Cue" tooltip when Cue is off. - Fixed the Phase 1 ProfilesModal captureException signature bug. - Tests: BoardModal card-create + cycle-rejection interaction, createBoard storage, extensionModel dependency gate; updated stale BUILTIN_FEATURES enumeration to include board. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… Phase 5) Round out the Board with headless CLI control, an OPTIONAL off-by-default auto-decompose layer, structured completion-handoff metadata, and docs. The manual Board (Phases 1-4) stays fully useful without any of the new layers. - CLI: new `maestro-cli board` (list / show / add-card / set-status / tick) and `maestro-cli profile` (list / create / delete) commands, registered in src/cli/index.ts. They delegate to the SAME Electron-free board/profile storage the IPC uses (no drift). `board tick` reuses the Phase 3 pure dispatcher helpers (promote/claim/apply/reclaim) and the existing CLI spawnAgent path - honoring SSH + profile model/effort/role/args overrides - so no second spawn implementation. Repo try/catch-at-boundary convention. - Auto-decompose (off by default): board-level `autoDecompose?: boolean` flag + new framework-free src/main/board/board-decompose.ts. Gated strictly on the flag; takes up to DEFAULT_AUTO_DECOMPOSE_PER_TICK (3) triage cards per pass, runs one LLM pass each, parses fenced/bare JSON, clamps dependsOn to earlier/in-range/non-self indices (always acyclic), wires children to the triage umbrella + siblings, and retires the triage card to done so it is never re-expanded. Editable prompt src/prompts/board-decompose.md registered as PROMPT_IDS.BOARD_DECOMPOSE. Wired into CLI `board tick` and the desktop engine (cue-engine maybeAutoDecompose, guarded fire-and-forget; index.ts wiring). - Handoff: shared CARD_HANDOFF_REMINDER (one copy for CLI + desktop) prepended to every card prompt, asking for a `card-complete | summary` marker covering the four handoff questions. Summary capture already lands via applyCardResult; BoardModal now shows an expandable "Last run summary". Optional metadata. - Docs: new docs/agent-guides/BOARD.md + user-facing docs/board.md (registered in docs.json under Encore Features), plus two CLAUDE.md key-files rows. No em/en-dashes; docs/releases.md untouched. - Tests: board-decompose (flag-off never expands + cap/wiring/retirement), board + profile CLI round-trips, autoDecompose YAML round-trip. tsc clean, eslint clean, 108 board/profile/CLI/UI tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Let any opted-in agent in a board's project directory pick up cards, instead of pinning every card to one fixed agent. The board stays per-project and git-tracked; the "who runs it" binding changes from one agent to a free pool. Model: - Pool = agents with `boardWorker: true` whose cwd is inside the board's project dir (or a sub-folder). Opt-in via a toggle on EditAgentModal (default OFF, so interactive agents are never hijacked). - A card names a role (`assigneeProfileId`) and/or pins an agent (`assigneeAgentId`); at least one is required. Role-only cards float to any free worker; pinned cards run on that agent with its own settings. - `AgentProfile.baseAgentId` is now optional: absent = a pure pool role. - One card per worker (tracked via `CardRun.workerAgentId`, recomputed from the persisted board each tick so it survives restarts). All workers busy -> the card stays `ready` and retries next tick (no waiting/reservation). Dispatcher: additive `assign` dep + `claimReadyCardsPooled` + pooled tick path; the legacy single-agent path is untouched when `assign` is absent. Pool selection lives in one shared, pure module (`shared/board/pool.ts`) used by the desktop engine, the CLI (`board tick`), and BoardModal. UI: BoardModal card editor gains Role + "Pin to agent" selects and a role/pin/pool badge; ProfilesModal base agent gains a "None (pool role)" option; the board-worker toggle on EditAgentModal. CLI: `board add-card --assignee <role> --assignee-agent <pin>`, and `profile create --pool` for base-agent-less roles. Also fixes auto-decompose to inherit a pinned agent (agent-only triage cards would otherwise fan into children that validation drops), and a latent getBlockers() arg-order bug in `board show`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
# Conflicts: # src/__tests__/renderer/components/Settings/Extensions/extensionModel.test.ts # src/renderer/components/Settings/Extensions/extensionModel.ts # src/renderer/stores/settingsStore.ts # src/renderer/types/index.ts # src/shared/plugins/first-party.ts
…erywhere The toolbar pill displayed "Full Access" for a tab whose permissionMode was never set (defaulting the DISPLAY to 'full'), but the spawn path passed the raw undefined through to buildAgentArgs, which only grants the bypass on a literal 'full'. So Claude Code (whose --dangerously-skip-permissions lives only in fullAccessArgs) spawned in the default permission model and had every tool call denied - the box said Full Access while the agent was actually denied, and goal-driven / document Auto Run deadlocked. Introduce resolveTabPermissionMode() as the single source of truth for what an unset permissionMode means and call it from both the toolbar (display) and the interactive spawn path so they can no longer drift. Auto Run, which has no active tab, now spawns with permissionMode: 'full' explicitly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds the static foundation for Time-Traveling Stream Rules: - TTSR_CONFIG_PATH / TTSR_RULES_DIR / ttsrRuleFilePath() in the shared maestro-paths module (no scattered path strings). - src/shared/ttsr-types.ts: serializable rule schema, the four validated enums, project settings, and the Gate A per-agent capability matrix (verified per parser, not inferred from agents/capabilities.ts). - src/main/ttsr/config/: repository (single fs owner of .maestro/rules and .maestro/ttsr.yaml, chokidar watch), normalizer (js-yaml frontmatter, regex compile-check, enum validation, Gate A agent defaulting), and the loader facade with name-collision first-wins. - 13 unit tests covering normalization, invalid-regex drop, shadowing, enum fallback, disabledRules, missing/unparseable/invalid configs. Also vendors the authoritative plan at plans/ttsr-implementation-plan.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…gin, settings section Completes Phase 1 of plans/ttsr-implementation-plan.md: - 4-file settings pipeline for the `ttsr` group (ttsrEnabled, ttsrDisabledRules, ttsrContextMode, ttsrBuiltinRules) across settingsMetadata.ts, main/stores/defaults.ts, settingsStore.ts (state + setters + validated hydrate) and useSettings. - `ttsr` Encore flag on EncoreFeatureFlags + TTSR_FIRST_PARTY_PLUGIN (com.maestro.ttsr) registered in FIRST_PARTY_PLUGINS, so the FirstPartyEncoreFlag compile-assert covers it. Marked beta in the marketplace tile list. - TtsrSettingsSection (chromeless extension-detail body) wired into EncoreTab's settingsBodies with the data-setting-id="encore-ttsr" wrapper, plus the matching searchableSettings registry entry. - isTtsrContextMode() guard in shared/ttsr-types.ts, used by the settings-store hydrate path. npm run lint (all 3 tsconfigs), eslint, prettier and the touched suites (Settings 488, plugins/cli/ttsr/settingsStore 542) are green.
Adds the detection half of Phase 2 as a standalone, injectable subsystem: - ttsr-state-store.ts: main-authoritative repeat/injection state (Gate B), keyed by (maestroSessionId, providerSessionId, ruleName), with a pending bucket folded in once the session-id event lands, plus snapshot/hydrate for the Phase 3 persistence seam. - ttsr-matcher.ts: pure predicates - agents gate, scope narrowing, picomatch glob path gate (relativizes absolute paths, normalizes separators), regex evaluation, and the interruptMode x source classification table. - ttsr-tool-extract.ts: edit/write snapshots from both parser event shapes (toolUseBlocks and toolName + toolState.input), including codex patch additions recovery per Gate A's partial AST support. - ttsr-manager.ts: the per-session matcher - prose/thinking buffers with boundary overlap, tool-content matching, repeat policy, interrupt vs deferred buckets, and the ttsr:matched payload. Dependencies are injected so the process manager never imports TTSR directly. 67 tests green across the TTSR suite; all three tsconfigs and eslint clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wires the Phase 2 detection core into the live agent stream. - ParsedEventObserver seam in StdoutHandler.handleParsedEvent, right after parseJsonObject: the only place that sees partial prose (dropped by the public thinking-chunk/data events for several agents), thinking, and tool calls with full input payloads for every structured agent. Injected via ProcessManager.setParsedEventObserver so process-manager keeps no TTSR import. A throwing observer is contained and reported, never taken out on the agent's output stream. - TtsrSpawnRegistry: main-authoritative record of each in-flight turn (agent, project root, original prompt, provider session id), fed from the public spawn / session-id / exit events. ManagedProcess holds no prompt, so this is Phase 3's only source for originalGoal. - TtsrRuntime: composes registry + rule cache + TtsrManager, reads the ttsrEnabled AND encoreFeatures.ttsr gate live, and reports ttsr:matched. A broken rule directory degrades to "no rules", never to a broken stream. - installTtsrRuntime() called once from main; the OpenCode SDK spawn path now emits the spawn event too, so its turns are observed (and agent-run capture no longer misses them). 18 new tests; three tsconfigs, eslint, and the process-manager / agent-run / opencode-server / process-listeners suites green.
Completes Phase 2 by wiring the AST half of the matcher: - `ttsr-ast.ts`: lazy-loaded `@ast-grep/napi` matcher (same lazy-require degradation pattern as `@napi-rs/keyring`), plus the extension -> grammar map. Only the five grammars bundled with the core napi package are supported (ts/tsx/js/jsx/css/html); other file types skip AST rather than guess, since Maestro does not ship dynamic grammars. - `TtsrManager.observeAst`: async structural pass over edit/write snapshots, sharing the agents gate, glob path gate, repeat policy and interrupt/defer buckets with the regex path. Identical consecutive snapshots are skipped. - `TtsrManager.needsAstCheck`: sync gate so the stream tap allocates no promise for AST-free turns. - `TtsrRuntime`: drives the AST pass off the synchronous path and exposes `flushAst()` so Phase 3 (and tests) can settle it deterministically. - packaging: `@ast-grep/napi` added to `asarUnpack` next to the other native modules (`npmRebuild: false` holds - napi-rs prebuilds are ABI-stable). Verified: 399 tests green (ttsr + process-manager), tsc clean on all three configs, eslint clean.
…d payload Turns a detected interrupting match into a real abort: signal the in-flight process (interrupt for contextMode keep, kill for discard), wait for its exit so stdout is drained, then emit the ttsr:triggered payload the renderer needs to respawn the corrective turn. - ttsr-injection.ts: <system-interrupt>/<system-reminder> rendering, per-rule dedupe, attribute escaping, and the degraded fresh-mode goal restatement. - ttsr-interrupt-driver.ts: abort lifecycle, ttsrAbortPending flag, late-match folding, exit timeout, and the Gate A resume-vs-degraded split. - TtsrRuntime drains the manager's interrupt bucket after every sync observation and after each AST pass settles; noteExit runs before the spawn registry entry is dropped so the payload keeps its meta. - TtsrTriggeredPayload added to shared/ttsr-types. 25 new tests; 417 TTSR + process-manager tests green, tsc clean on all three configs.
…ive respawn Closes the interrupt loop: main aborts the offending turn, the renderer continues the conversation with the <system-interrupt> prompt. - ttsr:abortPending push (new, emitted before the signal) so the exit listener treats the abort as a TTSR interruption instead of a failed turn - it would otherwise idle the tab and dequeue onto the same process id before the corrective spawn lands. - src/main/preload/ttsr.ts push-event bridge (onAbortPending/onTriggered/ onMatched), registered in preload/index.ts and typed in global.d.ts. - ttsrStore: renderer display cache + the ttsrAbortPending flag (Gate B - main stays authoritative). - ttsrRespawn: resolveTtsrTarget via the shared session-id parser and buildTtsrRespawnConfig, which reuses the normal spawn rules (permission mode, YOLO filtering, per-session overrides, SSH, Windows stdin) and takes providerSessionId from the payload, not the tab cache. - useTtsr, mounted in App.tsx behind the ttsr Encore flag, runs the corrective turn and marks the tab busy with a transcript notice. 211 tests green (TTSR suites + agent listeners), tsc clean on all three configs.
Non-interrupting matches queue a <system-reminder> main-side; the spawn path now drains that queue and prepends it to the conversation's next prompt (Maestro has no tool-result hook to fold guidance in-band). - TtsrRuntime.takeDeferredReminders() renders + clears the queue, gated on the global TTSR switch. - applyTtsrReminders() applies it in handle-spawn via an injected drain, so the process handlers keep no TTSR import. - Bound the manager's retained state: reminders are capped per conversation and a turn that ends with an empty queue drops its session state (Auto Run mints a fresh session id per task).
`once` and `after-gap` only mean anything if they outlive the process, so the main-authoritative state store now round-trips through disk: - TtsrStateStore stamps `updatedAt` per conversation and fires an `onChange` callback on every mutation (hydrate deliberately does not). - New ttsr-state-persistence.ts owns the `ttsr-state` electron-store namespace behind a swappable backend: debounced writes, TTL (30d) plus a 500-conversation cap prune on read and write, and disk errors logged and swallowed so a failing write never breaks the output stream. - TtsrRuntime builds the state store, hydrates it before the first observation, and exposes flushState()/dispose(); installTtsrRuntime wires the real backend (pass `persistence: null` for in-memory). - main/index.ts flushes on `will-quit` so a rule that fired seconds before shutdown is still remembered next launch. 137 TTSR tests green, tsc clean across lint/main configs.
An interrupted turn was silent unless the user happened to be watching that tab. The interrupt path now raises a sticky orange toast on the existing remote:notifyToast channel (no new notification primitive), unwrapping the composite process id to the bare agent id so the renderer can resolve the agent and jump to the interrupted tab. ttsr:triggered is sent first: the corrective respawn should already be in flight before the user is told about it. Toast failures are logged, never thrown - the reinject matters more. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Runs each in-scope agent's real provider stdout through its real parser, the runtime tap, the matcher and the interrupt driver, then records the prose / ast / resume axes from what the pipeline actually did and compares that with the plan's scope table and TTSR_AGENT_CAPABILITIES. - claude-code, codex, opencode, factory-droid: pass (clean resume) - copilot-cli, grok: degraded fresh reinject, as Gate A specifies - terminal: excluded, the spawn registry never registers it - feature-off is a total no-op per agent, rules are not even read Also corrects the StdoutHandler tap comment: the observer is always installed and gates itself live, rather than being installed conditionally.
Eight findings from reviewing the goal-driven Auto Run output. Blocking: - Only AI-tab spawns are registered. TTSR aborts in main but can only respawn into an AI tab, so registering Auto Run tasks, synopsis, tab naming or group-chat participants let it kill an unattended turn it could never restart. Adds parseAiTabSpawnId() alongside the existing coworking regex; tabId now comes from the spawn id (no caller sets config.tabId). - ttsrContextMode had no consumer. TtsrProjectSettings.contextMode is now optional so "unset" differs from "keep", resolving project yaml -> global setting -> keep. - The corrective respawn dropped the Auto Run read-only gate, so a rule firing during a non-worktree run handed the new turn write access the aborted one lacked. Mirrors useInputProcessing, forced-parallel exempt. Correctness: - Carry the original goal across a corrective respawn, so a second interrupt on a degraded agent restates the user's request rather than the previous injection. - Bound interrupts per conversation (MAX_TTSR_INTERRUPTS, persisted). Past it, matches defer to reminders instead of killing turns forever. - Drop the 5s rule cache TTL: loading is synchronous disk IO and ran inside StdoutHandler. Rules load at spawn time and invalidate via the watcher that was already written but never wired. - A throwing interrupt()/kill() left abortPending set forever, wedging the tab busy. The driver now withdraws over a new ttsr:abortCleared channel, which is what clearAbortPending existed for. Also removes the unused ttsrBuiltinRules setting and endTurn's dead finalText param, and fixes a pre-existing failure in the first-party plugin registry test (never updated when com.maestro.ttsr landed). The acceptance matrix report now states that its evidence is an in-process run with a stubbed ProcessManager, not a live per-agent E2E. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
"Stop the agent doing X" was mostly not expressible. The scope vocabulary covered prose and file content only, and extractEditSnapshots classified just the file-mutating tools, so shell calls were invisible to TTSR. A rule like "never force-push" could only match the agent talking about it, which fires on "I won't force-push" and misses the actual command. Adds a tool:bash scope matching the command a shell tool is about to run, sourced from Bash (claude-code), shell (codex), bash (opencode) and the run_* spellings, with argv arrays joined into one matchable line. Gate A gains a shellEvents axis; factory-droid and grok report no tool calls, so the loader keeps command rules off them and says why. globs now gate only the file-bearing scopes. A command has no path, so a bash rule with globs previously matched nothing at all; it is now ignored with a load-time warning rather than silently never firing. The acceptance matrix measures the new axis per agent from real parser output, so a parser that stops surfacing commands fails the suite instead of leaving those rules quietly inert. Renames the extractor to extractToolSnapshots/TtsrToolSnapshot now that it covers more than edits. Interrupting stays corrective, not preventive: the command is matched as the tool call streams, so a fast one may already have run. Documented in the acceptance record rather than implied away. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rules were already project-scoped on disk but had no UI, so the only way
to add one was to hand-write a file the user had no way to discover.
Adds a Rules tab to the Right Bar, which is implicitly scoped to the
agent being viewed: its cwd is the project root every call names. That
is why this is not in Settings, which is global and cannot express "in
this repo". The tab lists the project's rules, surfaces load warnings
(the only signal a rule that can never fire otherwise gives), and
exposes the per-project `enabled` and `contextMode` from
.maestro/ttsr.yaml. Leaving contextMode unset hands the choice back to
the global setting rather than pinning it.
Authoring is delegated to the agent instead of a form. Rule files are
markdown and the agent already writes files, so a new prompt teaches it
the schema and the tab sends that brief plus the user's request as a
normal turn; the agent writes the file, the watcher notices, the list
refreshes. Nothing to outgrow, and the user can iterate conversationally
("narrower", "it fires too often"). Settings writes merge rather than
overwrite so a hand-written config survives a toggle.
Also fixes a bug this path would have hit constantly: a rule file
necessarily contains the text its own rule looks for, so writing
.maestro/rules/no-console-log.md tripped a tool:write console.log rule.
Verified before fixing, now covered. TTSR no longer matches its own
config at the one extraction choke point.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…fullaccess # Conflicts: # src/__tests__/renderer/hooks/useAgentExecution.test.ts # src/__tests__/shared/agentMetadata.test.ts # src/main/preload/index.ts # src/renderer/App.tsx # src/renderer/components/AppModals/AppSessionModals.tsx # src/renderer/components/NewInstanceModal/EditAgentModal.tsx # src/renderer/components/NewInstanceModal/types.ts # src/renderer/hooks/session/useSessionLifecycle.ts
…eload, breaker fairness (Board 10x Phase 1) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… priority (Board 10x Phase 2)
- board:changed push event replaces the 2.5s kanban poll. board-storage
exposes setBoardSavedListener; index.ts broadcasts { projectRoot } to
every window plus the web-desktop bridge. Storage stays host-agnostic
so the CLI (no webContents) is unaffected.
- Cancellation: board-spawn remembers the Cue runId per card and kills it
via stopCueRun; the dispatcher gains cancelSpawn + cancelCard and a
cancel tombstone so the killed run's late resolution cannot re-finalize
the card as a failure. New 'canceled' run outcome returns the card to
todo and is excluded from the circuit breaker. board:cancelCard IPC
routes through the live dispatcher, with a storage-only finalize
fallback for cards left running by a previous app run. UI: stop button
on running tiles, drag-out of the running column now refuses with an
explanatory toast.
- Terminal transitions notify through the existing remote:notifyToast
relay (green done / red sticky blocked, sourceAgent 'Board').
- Safe destructive actions: two-click tile delete that names how many
dependents get re-parented, a ConfirmModal discard gate for unsaved
editor changes on Escape/backdrop/Back, and a delete button visible on
focus-within and always visible on coarse pointers.
- Card priority (high/normal/low, normal never serialized) drives one
shared ready-card dispatch order for both claim paths; surfaced in the
card editor, as a tile badge, and via `board add-card --priority`.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…s, bash self-trip - Interrupt budget is charged once per real abort: matches that drain while an abort is already pending are folded, not gated and charged again. - A withdrawn abort refunds the charge, re-arms the matched rules and re-queues their guidance as deferred reminders; a corrective turn that never spawns is recovered on the next spawn of that session. - Conversation state keys on the parsed tab identity, so a forced-parallel spawn id no longer mints a fresh conversation per turn. - Shell commands that write TTSR's own config no longer trip tool:bash rules. - Deferred reminders drain transactionally: the queue is cleared only after the spawn succeeds, so a throwing spawn no longer destroys queued guidance. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…Board 10x Phase 3) Close the headless-parity gap so a CI box or a headless host can drive the Board end to end without ever opening the desktop app. New CLI surface: board create | rename | delete (delete refuses non-done cards without --force) board update-card | remove-card (running cards are refused / need --force) board watch (board tick on a timer, SIGINT to stop) profile update | show (update keeps the id, so cards keep resolving) Storage gains renameBoard / deleteBoard and an options bag on createBoard (maxInProgress, autoDecompose). The non-done guard rail lives in storage, not the CLI, so the desktop path inherits it; board:rename / board:delete IPC, preload, and renderer types are plumbed for the Phase 6 UI. board tick and board watch now share one tickBoardsOnce pass. The CLI has no handle on an in-flight card process, so remove-card --force says plainly that the run was not canceled rather than implying a kill it cannot perform. docs/cli-reference.md regenerated (npm run gen:cli-reference); BOARD.md and board.md refreshed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…s panel Renderer robustness: - useTtsr gates the corrective respawn behind useOwnedSessionGate. TTSR pushes are broadcast to every window and web-desktop client, so two renderers were both respawning; the second spawn killed the first mid-flight and could double the <system-interrupt> in the transcript. Non-owning windows still record display state. - A failed respawn now releases the whole session, not just the tab. The aborted turn's exit is suppressed by the abort-pending flag, so nothing else could clear session.state / busySource / thinkingStartTime - the agent span forever with queue dispatch blocked. releaseAfterFailedRespawn() idles both, clears the abort mark, and toasts red with the rules and the spawn error. - Abort-pending marks can no longer suppress exits forever: entries carry a timestamp, isTtsrAbortPending() drops anything older than 30s, and useTtsr's cleanup wipes standing marks on unmount / when the Encore flag flips off. Rules panel: - New ttsr:rulesChanged push (runtime -> safeSend -> preload -> service -> panel, debounced 300ms) so the agent-driven authoring loop ends on a fresh list instead of a stale one. - listRules returns every rule with a `disabled` flag instead of hiding disabled ones; the panel dims them and adds an always-visible on/off toggle that writes the project ttsr.yaml or clears the global ttsrDisabledRules setting, whichever holds the rule. The matcher still only ever sees enabled rules - loadTtsrConfigDetailed.rules is unchanged and the new disabledRules list is for the management surface alone. - Delete uses the codebase's existing two-step arm pattern (4s auto-disarm) instead of firing on one click in a hover cluster. App: - handleSendPromptToAgent toasts yellow when no agent input is available instead of silently dropping the click. No existing test renders App.tsx or covers this path, so the added coverage is panel-side only: the Rules panel does not offer the hand-off when no handler is wired. Suites run: useTtsr, TtsrRulesPanel, services/ttsr, ttsrRespawn, ipc/handlers/ttsr (74 green), plus ttsr-runtime (38) and ttsr-config-loader (18) to confirm matcher-side filtering is unchanged.
- extract the local git worktree provisioning out of the git:worktreeSetup IPC handler into src/main/utils/git-worktree.ts so Auto Run and the Board share one implementation - add pure branch/path naming (src/shared/board/worktree.ts) and the Board provisioning wrapper (src/main/board/board-worktree.ts, Electron-free so the CLI uses the identical path) - spawn worktree cards with the checkout as cwd (desktop + CLI), record worktreePath/worktreeBranch on the CardRun, refuse isolation on SSH remotes - add the 'Run in isolated worktree' toggle, a branch badge on card tiles, the branch in the completion toast and last run summary, and a 'Worktree cards' section in docs/board.md with the merge-back commands Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adapt local commit 83c579b99 to the current Relay host contract, preserving receipt support and cancellation checks. Include Relay filter migration, provider session metadata, and CLI History labels.
Restore the production receipt call and its two regression tests from local commit 21d04b5f1 without reverting the newer CLI socket cancellation path.
… credit Codifies how GHSA-q8p2-cpg2-fhpc was handled: intake across email, GHSAs and issues (with a weekly sweep for advisories stuck in triage), validation on both branches, realistic CVSS scoring, the draft advisory and CVE request, fix on main and hand port to rc, stable-then-RC release, publish-then-announce ordering with the conductor's go for irreversible sends, credits, and reporter email templates. Linked from CLAUDE.md, SECURITY.md and the release runbook.
The advisory page keeps showing Request CVE after a request, and the API returns 202 on every call, so the runbook's "confirm on the page" step could never pass. Request once, note the date, poll cve_id, and open a Support ticket after 3 working days.
…in-own-prs-20261006
…in-own-prs-20261006
…in-own-prs-20261006
…in-own-prs-20261006
…in-own-prs-20261006
…in-own-prs-20261006
…in-own-prs-20261006
# Conflicts: # src/renderer/hooks/settings/useSettings.ts
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
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. Comment |
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.
This draft exposes the previously local-only RC integration and compatibility resolutions for review. It preserves all features in the latest verified local Linux package, based on upstream rc 0c81052, including host media settings, Relay/progress/permissions, terminal notifications, Board/Profiles, TTSR and the other pending Chris PRs.
Included dependency PRs: #1720, #1695, #1691, #1666, #1653, #1652, #1644, #1354, #1298, #1273 and #1272; host media settings are also submitted separately. This cumulative review branch gives PR coverage to every remaining local merge resolution, including notification compatibility and shared web-contents guarding. It is intentionally a draft aggregate while its dependencies remain open. All PRs target rc.
The prior exact head 4a135ca passed 2618 integration tests, 34 SDK tests, type checks, lint and packaged native/media/settings/PR-feature checks. It produced the prior .deb SHA256 d9e18b014a26fcfdb382674ce850358d896ff9221bd8bae95da0838e80e840f6. Provenance and conflict notes are in the local delivery records.
This review PR is not an authorization to merge upstream. The new Relay conversation change is reviewed in a separate dependent PR and merged only into the local test build.