Commit Graph

3213 Commits

Author SHA1 Message Date
Fusion
8160f6fcf6 test(FN-2863): expand quick chat default-model recovery coverage
- Assert default-model auto-selection initializes a model session with project-scoped context
- Verify quick chat input stays disabled until default-model session bootstrap completes
- Add parity coverage for default-model initialization when agents are present
2026-04-28 14:25:56 -07:00
Fusion
a481a68b16 feat(FN-2865): add notification provider abstractions
- Add shared notification event/payload/provider config types in core
- Introduce notification module exports with provider interface and dispatcher implementation
- Extend settings schema to accept notificationProviders configuration
- Add dispatcher unit coverage for provider filtering, failures, and delivery behavior
2026-04-28 14:25:56 -07:00
Fusion
cb5c628f00 fix(FN-2863): retry quick chat session init for default model
- Allow session initialization to retry when the same target key is selected but no active session exists
- Gate duplicate-init short-circuit behind activeSession/sessionsLoading so model-mode startup can recover
- Expand the effect dependency list to track session readiness inputs used by the retry guard
2026-04-28 14:25:56 -07:00
gsxdsm
b1a232a98a fix(tui): swap [3]/[4] hotkeys to Stats/Utilities
The live number-key handler hard-coded [3]→utilities, [4]→stats and
returned early, masking a parallel NUMBER_KEY_ORDER table. Update the
live mapping and remove the dead duplicate handler + constant.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 14:25:56 -07:00
Fusion
81c6f01e9e feat(FN-2723): show node health in dashboard routing selectors
- Add node status indicators and labels to task creation, quick entry, task form, and settings node selectors
- Surface selected node health in list bulk-edit controls with status dot styling for online/connecting/offline/error states
- Update dashboard component CSS and shared styles for consistent node status presentation
- Include changeset documenting unavailable-node routing policy and default node behavior
2026-04-28 14:25:56 -07:00
Fusion
0975e24512 fix(FN-2722): simplify dashboard TUI header and panel switching behavior
- Remove stdout header overlay patching and related frame recovery hooks from the dashboard TUI controller
- Keep panel switching logic lightweight by relying on normal state updates without forced recover cycles
- Adjust status footer and utility/system panel rendering to maintain a single-line, truncation-friendly layout
- Add explicit number-key panel mapping while preserving existing tab/cycle panel order
2026-04-28 14:25:56 -07:00
Fusion
ff58623c32 fix(FN-2861): harden planning session recovery and retry UX
- Add planning and subtask retry routes with session-lock checks and proper API error mapping
- Improve planning session execution with timeout/abort handling, stop-generation support, and resilient stream catch-up behavior
- Update Planning Mode modal to handle reconnects, retry-from-error flow, stop action, and cross-tab session state synchronization
- Expand dashboard tests for planning routes, planning session behavior, and PlanningModeModal retry/error coverage
2026-04-28 14:25:55 -07:00
gsxdsm
2f7ba29ead fix(dashboard,core): bound AI session prompt() with timeout + abort
Subtask, mission-interview, and milestone/slice-interview sessions could pin
their `generating` state forever when the underlying provider stream stalled
silently or a tool call hung. Wrap each `agent.session.prompt()` in a new
GenerationGuard helper (per-session AbortController + timer) so a stuck turn
becomes a bounded error users can retry. Adds matching `stop*Generation`
exports and threads abort through cleanup so dismissing a modal cancels the
in-flight call instead of leaking it.

Also closes the gh-cli tool hang vector: `runGhAsync` / `runGhJsonAsync` now
accept `{ signal, timeoutMs }` (default 30s). Github-touching extension tools
forward the AI tool's signal so an aborted agent kills the `gh` child instead
of orphaning it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 14:25:55 -07:00
gsxdsm
596982dd75 feat(FN-2862): merge fusion/fn-2862 2026-04-28 14:25:55 -07:00
gsxdsm
38933c770a fix(engine): make pi.js imports static to fail fast on partial dist
Replace lazy `await import("./pi.js")` and `require("./pi.js")` calls in
runtime-resolution, agent-session-helpers, agent-heartbeat, and
cron-runner with top-level static imports. These dynamic imports were
documented as plugin-decoupling, but pi.js is already eagerly loaded
through index.ts re-exports and static imports in executor/merger/
reviewer/triage/mission-execution-loop, so the deferral never paid off
in practice.

The deferral did, however, introduce a TOCTOU race: a tsc rebuild that
momentarily emptied dist/pi.js would let the engine load fine and only
fail minutes later when the first session was created (e.g. FN-2860
errored two minutes into execution while pi.js was being rewritten).
With static imports, a missing/half-built dist now fails immediately at
process startup with a clear stack — verified by `mv dist/pi.js
dist/pi.js.bak` reproducing ERR_MODULE_NOT_FOUND on the first import of
runtime-resolution.js.

Also drops the DefaultPiRuntime.describeModelFn cache, which only
existed to paper over the require-on-first-call latency.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 14:25:55 -07:00
gsxdsm
479f25d50f fix(FN-2855): scope task diff base to baseCommitSha when branch is null
When a dependency task merges and its branch is deleted, self-healing nulls
the dependent task's baseBranch. Both resolveDiffBase (dashboard) and
resolveTaskDiffBaseRef (merger) defaulted to "main" in that case, widening
the diff range to merge-base(HEAD, main) and surfacing unrelated history —
e.g. FN-2855 reported 108 changed files instead of 16. Skip the merge-base
step when baseBranch is unset and a baseCommitSha is recorded; fall back to
"main" only for legacy tasks lacking both hints.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 14:25:55 -07:00
Fusion
0c241b017f feat(FN-2855): route scheduled tasks using effective node resolution
- Add an effective node resolver with task override, project default, and local fallback precedence.
- Wire scheduler dispatch to persist effectiveNodeId/effectiveNodeSource and log resolved node routing.
- Add coverage for effective node resolution and scheduler node routing integration behavior.
- Stabilize workspace test resolution by adding @fusion/core and @fusion/plugin-sdk aliases across Vitest configs.
2026-04-28 14:25:55 -07:00
Fusion
c9f75a3aad fix(FN-2859): reduce background AI pill height in executor footer
- Tighten background task indicator pill padding to reduce vertical footprint
- Lower line-height to keep icon/text alignment after the size reduction
- Reduce mobile min-height so the footer pill no longer appears oversized
2026-04-28 14:25:55 -07:00
Fusion
4672d11e3c feat(FN-2854): ship node routing persistence and dashboard workflow updates
- Add effective node routing fields to task types/store, persist them in SQLite, and expand regression coverage for node override guard behavior
- Add dashboard and API support for manual memory dream processing/trigger actions plus expanded memory regression tests
- Improve task creation and task detail model/node UX, including quick chat default model selection and workflow/settings UI polish
- Apply mobile/dashboard UX fixes (form input zoom prevention, expand toggle styling, input layout tweaks) and update extension/docs/changelogs for the release
2026-04-28 14:25:55 -07:00
Fusion
6d5ca2cc91 test(FN-2733): expand memory dreams regression coverage
- Add ProjectEngine memory dreams wiring tests for startup ordering, settings-change resync, and unrelated-setting no-op behavior
- Cover degraded-mode startup and settings-update failure paths to ensure sync errors are logged without stopping the engine
- Extend MemoryView Dream Now tests for success, failure toast handling, and disabled loading-state behavior
2026-04-28 14:25:55 -07:00
Fusion
f19ecac8f5 feat(FN-2848): add manual memory dream API trigger
- Add POST /api/memory/dream route that runs project and agent dream processing with AI prompt execution
- Expose triggerMemoryDreams() in dashboard legacy API client for direct dream invocation
- Switch SettingsModal and useMemoryData Dream Now actions from automation lookup to the new endpoint
- Update dashboard route, hook, and settings modal tests to cover success and error handling
- Add a patch changeset for @runfusion/fusion documenting the new endpoint and client helper
2026-04-28 14:25:55 -07:00
Fusion
1d9d9f4e7f feat(FN-2843): auto-select quick chat default model
- Extend /models API responses to include optional defaultProvider/defaultModelId from global settings, including empty and error paths
- Update QuickChatFAB to prefer the configured default model on load and fall back to first-model selection only when no agents exist
- Move quick chat model tag/title-wrap inline styles into QuickChatFAB.css using dashboard design tokens
- Add QuickChatFAB tests covering default-model auto-selection with and without agents and legacy behavior when no default is configured
2026-04-28 14:25:55 -07:00
Fusion
7414184705 feat(FN-2837): add infusion.ai links to update notices
- Add a Learn more link to the update-available banner alongside release notes
- Refactor SettingsModal update-result rendering into a shared helper and include the infusion.ai link when updates exist
- Add dedicated SettingsModal link styling with hover and focus-visible states using dashboard tokens
- Update banner and settings tests to assert the new Learn more link behavior
- Add a patch changeset for @runfusion/fusion documenting the update notice link addition
2026-04-28 14:25:55 -07:00
Fusion
270db8a16c feat(FN-2842): polish workflow result expand toggle styling
- Add dedicated styles for the workflow result expand icon button with token-based sizing and alignment
- Add hover and focus-visible states for clearer interaction feedback and keyboard accessibility
- Increase mobile touch target sizing for both workflow edit and expand toggles using design tokens
2026-04-28 14:25:55 -07:00
Fusion
7dc8a43a4e fix(FN-2838): prevent mobile zoom on dashboard form inputs
- Add global `touch-action: manipulation` on html/body to reduce gesture-triggered zoom
- Set mobile input font-size to 16px for terminal, nodes, and scripts modal form fields
- Extend mobile CSS regression tests to assert the global touch-action rule
2026-04-28 14:25:55 -07:00
Fusion
0b8ffa1528 feat(FN-2732): add manual dream processing actions in dashboard
- Extend useMemoryData with triggerDreamNow and dreamRunning state by locating and invoking the Memory Dreams automation
- Add Dream Now actions to MemoryView and SettingsModal memory settings with loading UI, success/error toasts, and file refresh in MemoryView
- Expand hook and component tests to cover dream-trigger visibility and execution flows in both views
- Update terminal mobile keyboard layout CSS contract expectations for the current mobile modal width and min-height rules
2026-04-28 14:25:55 -07:00
Fusion
789afc30b0 feat(FN-2721): enforce node override guard across task workflows
- Add a core node-override-guard module, export it from @fusion/core, and enforce conflicts in store updates
- Add API route and CLI extension safeguards so nodeId override updates are blocked when ownership would conflict
- Wire node override routing and validation through dashboard quick-create, list, modal, settings, and task form/detail surfaces
- Add focused unit and integration tests for core guard logic, workflow routes, and dashboard node override UX
2026-04-28 14:25:55 -07:00
Fusion
3174f0dc64 chore(release): v0.7.1
Version bump via changesets.
2026-04-28 14:25:55 -07:00
gsxdsm
ad4690329a chore(release): v0.7.1
Version bump via changesets.
2026-04-28 00:36:24 -07:00
gsxdsm
ce6dcefef2 fix(dashboard): mobile polish, modal layout fixes, keyboard-aware terminal + add 0.7.1 changeset
- WorkflowStepManager: fix React error #310 ("Rendered more hooks than during
  the previous render") that broke the workflow steps panel from loading.
  `useOverlayDismiss` was being called after `if (!isOpen) return null`, so
  the hook count differed between open/closed renders. Move the hook above
  the early return.
- ModelOnboardingModal: API-key input + Save button now span the full card
  width on mobile via negative inline margins that bleed past the card's
  horizontal padding, so the form sits flush to the card edges instead of
  picking up a chunky left indent from the icon-row's flex start position.
- TerminalModal: same desktop-min-width-pinning bug as the onboarding modal.
  Reset min-width/min-height to 0 on mobile with `!important` so persisted
  desktop sizes from useModalResizePersist cannot re-pin the modal at 480×320
  on smaller phones. Also add `!important` to the keyboard-overlap height/
  max-height so the visual-viewport adjustment wins against the new
  fullscreen rule — without this the terminal stayed at 100dvh while the
  mobile keyboard covered the bottom of the screen.
- Add 0.7.1 changeset covering the full mobile polish + paperclip CLI parity
  + plugin runtime registry fallback + SCHEMA_VERSION bump series.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 00:35:48 -07:00
gsxdsm
67f9b6a18a fix(dashboard): portal NewAgentDialog so it escapes the AgentsView stacking context
On mobile the dialog was rendering with its top hidden behind the in-page
\"Agents\" header. The dialog wasn't actually positioned wrong — its overlay
is `position: fixed; inset: 0`. The problem was that NewAgentDialog
rendered as a child of `.agents-view` (which has `overflow: hidden` and
`position: relative`), and an ancestor stacking context combined with the
relative+overflow parent prevented the fixed overlay from escaping above
the page header in the painter's order.

Render the dialog through `createPortal(..., document.body)` so the
overlay attaches at the document root, escaping every parent stacking
context. This is the standard React modal pattern.

All 9639 dashboard tests still pass — React Testing Library queries
traverse portals transparently.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 00:23:45 -07:00
gsxdsm
66df2c7149 fix(dashboard): mobile polish — single-row api key input, NewAgentDialog safe-area + scroll
ModelOnboardingModal:
- API-key row was forced to flex-direction: column on mobile, stacking the
  input above the Save button and doubling the vertical space inside the
  already-cramped provider card. Switch to flex-direction: row with the
  input growing (flex: 1, left-aligned) and Save shrunk to its label
  (right-aligned). Tighten input/button min-height to 32px and shrink the
  button's inline padding.
- Tighten surrounding form: gap → --space-xs, label font-size → 11px with
  no margin-bottom, helper paragraphs → 11px / line-height 1.35.

NewAgentDialog:
- Top of the dialog was cut off under the iOS notch / status bar. Added
  env(safe-area-inset-top) to the mobile header padding-top, and
  env(safe-area-inset-bottom) to the footer padding-bottom so the home
  indicator doesn't cover the action buttons.
- Body wasn't scrolling because the flex child kept its default
  min-height: auto, making the dialog grow past the viewport and never
  trigger overflow-y: auto. Added min-height: 0 + flex: 1 1 auto on the
  body, and flex-shrink: 0 on the header/footer/steps so only the body
  gives up height.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 00:18:31 -07:00
gsxdsm
8e5b761669 fix(dashboard): compact onboarding provider cards on mobile
Previous mobile rule forced .onboarding-provider-card to flex-direction:
column with --space-lg padding, so the icon, body, and actions each took
their own full-width row and every card rendered ~140px tall on a phone.

Keep the icon inline beside the name + description (the row layout the
desktop already uses, just tighter), shrink the icon container to
list-item-bullet size, drop name/description font sizes a notch, and rely
on the existing flex-wrap so the API-key form / action buttons still drop
to their own row underneath. Also evenly split simple action rows (Connect
/ Skip) across the full width for easier tap targets.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 00:15:09 -07:00
gsxdsm
700943a952 fix(dashboard): mobile layout polish for onboarding/new-agent modals + settings auth gutter
- ModelOnboardingModal: the desktop base set min-width: 640px / min-height:
  480px and the mobile media query only reset max-width — but min-width
  always wins over max-width in size resolution, so the modal stayed pinned
  at 640px and overflowed any phone narrower than that. Compounding it,
  useModalResizePersist writes inline width/height from saved desktop
  sessions (e.g. 1100px), and inline styles beat the media query. Reset
  min-width/min-height to 0 in the mobile rule and force fullscreen
  (100vw/100dvh) with !important so the persisted desktop size cannot
  re-pin the modal off-screen. Also disable resize on mobile.

- NewAgentDialog: had no mobile media query at all. Added a max-width: 768px
  block that drops the overlay padding, fills 100vw/100dvh, removes the
  border-radius, tightens header/footer/steps padding, locks body scroll
  with overscroll-behavior: contain + -webkit-overflow-scrolling: touch
  (so iOS doesn't bubble the scroll up and trap users above the footer),
  and stacks the footer buttons full-width. Also switched the desktop
  max-height from 100vh to 100dvh so iOS Safari's collapsing URL bar
  doesn't push the footer under the address bar.

- SettingsModal auth panel: reduced .auth-panel-body padding-inline from
  --space-xl (24px) to --space-md (12px) so each provider card gets more
  horizontal room — the cards are dense enough that the wider gutter
  wasted visible width without any visual benefit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 00:14:21 -07:00
gsxdsm
774726ad3a fix(core): bump SCHEMA_VERSION to 49 so the nodeId task-column migration runs
Migration 49 (`ALTER TABLE tasks ADD COLUMN nodeId TEXT`) was added with
SCHEMA_VERSION still pinned to 48. Existing DBs at version 48 hit the
`if (version >= SCHEMA_VERSION) return;` early exit, so the column was never
created — `TaskStore.listTasks` then crashed at startup with
`no such column: nodeId` and the dashboard exited before initialization.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 00:04:51 -07:00
gsxdsm
0a3c28d872 chore(dashboard): UI polish — Hermes logo, settings header heights, simplify agent card actions
- Use bundled Nous Research SVG (inverted) on the Hermes runtime card
  instead of the generic ProviderIcon.
- Lock GitHub-star and Help buttons in the settings header to a uniform
  26px height so the differing icon sizes don't misalign them.
- Drop the inline Delete button from the idle/terminated agent-card
  states — deletion stays available from the agent detail view.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 23:27:41 -07:00
gsxdsm
2229815bad fix: harden cross-platform paths and child-process handling
Replace process.env.HOME fallbacks with os.homedir() in dashboard usage
probes and the hermes plugin profile resolver so unset HOME no longer
yields literal "~" paths. Skip POSIX process-group semantics on Windows
in engine/merger and dashboard-tui's pgrep-based vitest killer. Add
shell: true to npx spawns in CLI skills/extension so .cmd shims resolve
on Windows, and route test:build-exe through cross-env.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 23:27:27 -07:00
gsxdsm
02d68f945d fix(dashboard): restore NodeStatusIndicator tests and fix routes.ts typecheck
- packages/dashboard/src/routes.ts: hermes/openclaw runtime metadata declares
  `version` as `string | undefined`, but BUNDLED_PLUGIN_RUNTIMES requires
  `string`. Coalesce to "0.0.0" so the bundled fallback list type-checks.
- packages/dashboard/app/components/__tests__/NodeStatusIndicator.test.tsx:
  the file had been reduced to a stub ("placeholder") which the test runner
  parsed as an undefined identifier. Restore the original 155-line suite from
  fc23e522a; the underlying NodeStatusIndicator component is unchanged.

All 9639 dashboard tests pass; pnpm typecheck is clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 23:26:47 -07:00
gsxdsm
4d48be9a5c fix(dashboard): expose bundled hermes/openclaw/paperclip runtimes in /api/plugins/runtimes
Merge metadata for the three example runtime plugins bundled as workspace
dependencies of @fusion/dashboard with pluginLoader.getPluginRuntimes(), so
the NewAgentDialog "Plugin Runtime" dropdown populates without requiring
an explicit `fn plugin install`. Installed plugins override the bundled
fallback by runtimeId.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 23:24:21 -07:00
gsxdsm
a6697ee7ca feat(paperclip-runtime): route Paperclip calls through paperclipai CLI in Local CLI mode
The Paperclip runtime card's Local CLI tab previously only derived an apiUrl
from the local config and then made HTTP calls itself, so the Test action and
the company/agent pickers ignored the user's onboarded CLI auth context.

Add CLI-backed variants for every Paperclip call that has a `paperclipai`
counterpart, and route through them when transport=cli — both from the
settings card and from the runtime adapter's prompt path.

- New plugin functions spawning `paperclipai … --json`:
  * probePaperclipViaCli, listCompaniesViaCli, listCompanyAgentsViaCli
    (settings card test + pickers)
  * createIssueViaCli, getIssueViaCli, agentsMeViaCli (runtime hot path)
- New dashboard routes: /providers/paperclip/cli-status, /cli-companies,
  /cli-agents (read-only façades over the plugin's CLI helpers)
- PaperclipRuntimeCard: branches on transport=cli to use the cli-* fetchers
- PaperclipRuntimeAdapter: stores transport on the session and routes
  createIssue/getIssue + identity derivation through CLI variants in CLI mode;
  raises a clear error when agentId is unset in CLI mode (paperclipai has no
  /agents/me equivalent)
- getIssueComments / wakeAgent / getRunEvents stay on HTTP (no matching
  paperclipai subcommands) and continue to use the apiKey discovered from
  the local paperclipai config, so CLI mode still works end-to-end
- Tests: 9 new paperclip-client tests covering each CLI variant + 5 new
  adapter tests for the Local-CLI transport branch (64/64 plugin tests pass)
- Update routes.test for the existing BUNDLED_PLUGIN_RUNTIMES fallback so
  the bundled hermes/openclaw/paperclip entries are expected alongside
  installed plugins

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 23:06:20 -07:00
gsxdsm
08a4ae01f7 feat(FN-2719): merge fusion/fn-2719 2026-04-27 22:53:51 -07:00
Fusion
a3a6794c41 feat(FN-2718): add unavailable node policy setting and validation
- Define and export unavailable node policy types in core settings interfaces
- Add project-level unavailable node policy default and runtime validation helper
- Add core unit coverage for unavailable node policy parsing and acceptance cases
- Guard Paperclip mint requests to include companyId only when available for type-safe payloads
- Document unavailable node policy in the settings reference
2026-04-27 22:40:08 -07:00
gsxdsm
4a3a8dce7c chore(release): v0.7.0
Version bump via changesets.
2026-04-27 22:34:32 -07:00
gsxdsm
b30e017a34 chore: add 0.7.0 changeset for runtime plugins
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 22:33:56 -07:00
Fusion
d3e1c28cef fix(plugins): re-export probe symbols + declare plugin deps in dashboard
- Hermes / OpenClaw plugin index.ts now re-export `probeHermesBinary` /
  `probeOpenClawBinary` and their status types so the dashboard's
  `runtime-provider-probes.ts` façade can import them via the public
  package entry instead of deep paths.
- Dashboard `package.json` adds `@fusion-plugin-examples/hermes-runtime`,
  `…/openclaw-runtime`, `…/paperclip-runtime` as workspace deps so
  pnpm symlinks them into `packages/dashboard/node_modules/`. Without
  these, the new probe imports failed with "Cannot find module" during
  `pnpm typecheck`.

This clears 6 of the 9 outstanding typecheck errors. The remaining 3 are
in the in-flight Hermes plugin rewrite (runtime-adapter still imports
from a deleted `./pi-module.js`; the new `index.ts` calls a factory
with the wrong arg type) and should be resolved by the same change set
that landed the rewrite.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 22:17:54 -07:00
gsxdsm
1a1bec1fb4 test(dashboard): align CSS-contract + onboarding tests with current contracts
Two long-standing test failures, root-caused and fixed.

terminal-mobile-keyboard-layout.test.ts (2 tests)
  CSS structure changed: the desktop terminal modal moved its initial
  width/height into companion `:not([style*="width"])` /
  `:not([style*="height"])` rules so persisted resize values can win
  over the default. The tests still searched the base block. Updated
  the helpers to extract from each rule explicitly, asserting:
    width: min(1800px, …)            in the :not([style*="width"]) rule
    max-width: calc(100vw - …)       in the base rule
    85vh                             somewhere in the :not([style*="height"]) rule
    min-height + max-height: calc(100dvh - 40px)  in the base rule
  Same constraints, just reflecting the current selector layout.

ModelOnboardingModal.test.tsx (2 tests)
  Component refactor (commit f3d918997) made the "what GitHub unlocks"
  feature list conditional on `!isGitHubReady`, so the test that mocks
  `authenticated: true` no longer sees "Import issues as tasks". And
  the gh-CLI optional explanation copy was rewritten to "OAuth from
  the dashboard is optional" instead of "OAuth integration in
  Settings → Authentication is optional". Updated:
    - "shows connected state": assert the new connected-state
      sentence ("GitHub is connected — issue imports …") instead of
      the now-hidden feature list line.
    - "explains gh CLI auth": use getAllByText for the two-place
      "GitHub CLI is already authenticated" copy and match the
      current "OAuth from the dashboard is optional" sentence.
  Also adds the missing `afterEach` import to silence its TS error.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:16:45 -07:00
gsxdsm
aa86dcc05c fix(dashboard): scale stats values to fit metric box without overflow
Token counts on the task detail Stats panel could overflow the metric
box for large values (e.g. 10-digit comma-separated totals). Switched
each metric to a container-query inline-size context and gave the
value a fluid font-size of `clamp(13px, 13cqw, 28px)` so it grows to
fill the box up to a 28px cap and shrinks down to 13px on narrow grid
columns. Combined with `min-width: 0`, `overflow-wrap: anywhere`, and
the metric's `overflow: hidden`, long values now stay within the box
and short values render as large as they can without dominating.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:06:06 -07:00
gsxdsm
f3d918997c fix(dashboard): wider/resizable onboarding modal + GitHub CLI-aware messaging
- ModelOnboardingModal: native CSS resize with persisted size via
  useModalResizePersist; default ~1100px wide; modal scrolls inside
  the content area instead of clipping.
- Provider cards flex-wrap so the API-key form drops to a full-width
  row instead of being squished into a fixed side column. Connected
  badge no longer stretches the full body width.
- Step changes now reset content scrollTop so each page lands at the
  top.
- GitHub step: prominent GitHub mark via ProviderIcon; when gh CLI is
  authenticated the intro reads as 'you are all set', primary CTA
  becomes 'Continue with gh CLI auth', and a secondary
  'Connect OAuth (optional)' button is offered.
- CustomModelDropdown: highlight init runs once per open session, and
  filter changes reset highlight to top + scrollTop=0, fixing the
  scroll-fight when filtering models.
- TUI dashboard: at >=150 cols, Stats panel sits to the left of Logs;
  bottom row drops to Utilities + Settings.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:05:45 -07:00
gsxdsm
4b9fd3dd64 fix(dashboard): clear all 661 test-file type errors
Production typecheck (tsconfig.json + tsconfig.app.json) was already
clean, but a third config that includes test files surfaced 661 errors
across 60+ test files — accumulated drift between mock fixtures and
production types. Six parallel typescript-pro agents fixed every one
without touching production code.

Per-scope before/after (errors → 0):
  ChatView                                                     183
  Mailbox + Agent suite (5 files)                              156
  Task / Modal suite (6 files)                                 127
  App + small components (12 files)                             96
  Hooks + api/auth (8 files)                                    48
  Long tail (32 files)                                          51
  -----------------------------------------------------------------
  Total                                                        661

Major fix categories:
- Untyped state objects inferring `never[]` / `null` literals (root
  cause of ~120 errors in ChatView alone — added a single
  `UseChatReturn` annotation)
- Mock objects missing fields that became required: `WorkflowStep.mode`,
  `ChatMessage.thinkingOutput / metadata`, `ChatSession.projectId`,
  `Task.log`, `ProjectHealth` fields, `PtyTerminalSessionInfo.createdAt`,
  `Agent.metadata`, `InboxResponse.total`, etc.
- Mock objects with stale fields that no longer exist:
  `AgentBudgetStatus.budgetPeriod`, `truncated` on log responses,
  `OutboxResponse.unreadCount`, `MergeResult.source/target/details`
- Modal props that became required (e.g. `PlanningModeModal.onTasksCreated`)
- String literals not in narrowed unions (`Column`, `WorkflowStepPhase`,
  `InsightStatus`, `AgentLogType`, etc.)
- `querySelector` returning `Element` cast to `HTMLElement` for
  `@testing-library/react`'s `within()`
- Vitest mock typing: `.mock.calls` access needing `vi.mocked(...)`,
  zero-param tuple handling, generic `vi.fn(() => [])` inferring
  `never[]`

Helpers introduced in test files (no shared infra):
- `makeSettings(overrides)` in ModelSelectorTab.test.tsx
- `makePromptOverrides(overrides)` in AgentPromptsManager.test.tsx
- `FileBrowserTestOverrides` type alias in FileBrowser.test.tsx
- `makeInboxResponse / makeOutboxResponse` in MailboxView.test.tsx

Verification:
- tsc -p tsconfig.json:        exit 0
- tsc -p tsconfig.app.json:    exit 0
- tsc -p tsconfig.test-check.json (new — includes test files): exit 0
- vitest run:                  9639 / 9641 (2 pre-existing failures
                               in terminal-mobile-keyboard-layout.test.ts
                               unrelated to this work; verified via
                               `git stash` + run on clean HEAD)

Adds packages/dashboard/tsconfig.test-check.json to keep this regression
guard available locally — same as tsconfig.app.json minus the test
exclude.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:59:52 -07:00
gsxdsm
8c554211f3 fix(dashboard): card timer matches stats panel + resizable Changes diff modal
Two related dashboard fixes.

1. Card timer mismatch: the board card timer chip showed only workflow
   runtime (e.g. <1m on FN-2716) while the task detail Stats panel
   reported "Total execution time" of 7m+ for the same task. Cause —
   the slim board listing strips `task.log` to keep payloads small, so
   the card's client-side `[timing]` log scan returned 0. Now the slim
   path aggregates `[timing] … in <N>ms` durations server-side into a
   new `task.timedExecutionMs` field before stripping the log; the
   card prefers this aggregate, falling back to the client scan when
   the full log is loaded (TaskDetailModal). Wire payload stays slim.

2. View Changes diff modal: defaulted to `90vw × 80vh` and was not
   user-resizable. Switched to `min(95vw, 2200px) × min(90vh, ...)`
   default with `resize: both`, persisted via useModalResizePersist
   (`fusion:changes-diff-modal-size`). Mobile keeps fullscreen layout.
   Overlay dismiss switched to the shared `useOverlayDismiss` hook so
   resize-drags that release on the overlay don't close the modal.

Updated the diff modal's regression tests to match the new constraint
shape (still asserts max-height clamps to viewport via calc()).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:55:46 -07:00
gsxdsm
4e2caaf605 docs: add Discord link and badge to README
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:45:04 -07:00
gsxdsm
938b0c62a0 fix(dashboard): no resize-drag dismiss across all resizable modals + Claude CLI in Authenticated group
When a user drags the native CSS resize grip from inside a modal and
releases the mouse over the overlay, the synthesised click event
targets the common ancestor (the overlay) — fooling the existing
e.target === e.currentTarget dismiss check. Audited every modal with
`resize: both` and switched them to a shared mousedown→mouseup tracking
pattern (new useOverlayDismiss hook) so dismiss only fires when both
events land on the overlay.

Modals fixed: TaskDetail, Settings, FileBrowser, GitHubImport,
GitManager, ScheduledTasks, Scripts, WorkflowStepManager. (Terminal
and AgentDetail were already fixed in 56e8e7324; PlanningModeModal
already had the right pattern inline.)

Also: in Settings → Authentication, the "Anthropic via Claude CLI"
card now lives inside the Authenticated group when authenticated and
the Available group otherwise, instead of floating at the top.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:36:24 -07:00
gsxdsm
56e8e73244 fix(dashboard): resizable terminal + agent detail modals, no resize-drag dismiss
Terminal modal and agent detail view are now resizable via the native
CSS grip with sizes persisted per-modal in localStorage. Mobile keeps
fullscreen layout (resize disabled, !important overrides any persisted
desktop dimensions).

Both modals previously dismissed when a drag-resize started inside the
modal but released over the overlay — the synthesised click event
targets the common ancestor (overlay), tripping the e.target ===
e.currentTarget dismiss check. Switched to mousedown→mouseup tracking
so dismiss only fires when both events land on the overlay.

Terminal additionally observes its own pixel box via ResizeObserver
and refits xterm on every grip drag — `resize: both` doesn't emit
window resize.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:30:05 -07:00
gsxdsm
cdddc602f9 feat(dashboard): add fireworksai and qwen-ai provider id aliases
Two more brand-id spellings observed in the wild that previously fell
through to the generic Cpu glyph:
  fireworksai → FireworksIcon (joins fireworks / fireworks-ai)
  qwen-ai     → QwenIcon       (joins qwen / qwen-coder / alibaba / tongyi)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:25:10 -07:00
gsxdsm
bb340206bf feat(dashboard): add Cerebras / Groq / Vercel icons + cover all pi-ai catalog providers
Audited the pi-ai built-in model catalog provider IDs against the
ProviderIcon registry and filled every remaining gap.

New icons:
  --provider-cerebras    (#f1592a)  → CerebrasIcon (concentric arcs)
  --provider-groq        (#f55036)  → GroqIcon     (lightning bolt)
  --provider-vercel      (text)     → VercelIcon   (triangle wordmark)

New aliases routed to existing icons:
  minimax-cn               → MiniMaxIcon
  azure-openai-responses   → AzureIcon
  google-gemini-cli        → GeminiIcon
  google-generative-ai     → GeminiIcon
  opencode-go              → OpencodeIcon
  vercel-ai-gateway        → VercelIcon

After this commit every provider id emitted by `@mariozechner/pi-ai`'s
register-builtins (anthropic, openai, openai-codex, google,
google-vertex, google-gemini-cli, google-antigravity,
amazon-bedrock, mistral, openrouter, fireworks, cerebras, groq,
huggingface, kimi-coding, minimax, minimax-cn, zai, xai, opencode,
opencode-go, github-copilot, azure-openai-responses,
vercel-ai-gateway) plus the user-curated set (qwen, lm-studio,
hugging-face, alibaba/tongyi, hf, lmstudio…) renders a brand icon
instead of falling back to the generic Cpu glyph.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:22:42 -07:00