Creates the React Flow building blocks for the network diagram editor:
device type registry with icon/color mappings, DeviceNode component with
status indicators and connection handles, ConnectionEdge with per-type
styling, and nodeTypes/edgeTypes registration maps.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds all interfaces for network diagrams and device types including
DiagramNode, DiagramEdge, DeviceProperties, NetworkDiagramResponse,
AI generate request/response, import/export shapes, and list item types.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove duplicate Update/Close actions from chat toolbars (FlowPilotPage,
CockpitPage) — session lifecycle actions now live only in headers. Redesign
ViewToggle as a persistent tab bar with bottom-border active indicator and
ARIA attributes. Standardize all action naming: Resolve (emerald), Update
(blue), Close (rose), Pause (muted). Fix IncidentHeader Resolve from orange
to emerald. Delete unused FlowPilotActionBar component (227 lines). Update
ConcludeSessionModal copy to use forward-facing action verbs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Eliminates the dedicated ViewToggle row on CockpitPage by merging
it into IncidentHeader's action group via extraActions prop. Removes
subtitle from ViewToggle component entirely — the icon + label is
self-explanatory. Cleans up showSubtitle prop from all call sites.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The IncidentHeader overflow menu was see-through due to bg-elevated on
bg-card. Switched to bg-card with shadow-xl and fixed-scrim dismiss
pattern matching production FlowPilotSessionPage. Replaced unicode
ellipsis with MoreHorizontal icon + aria-label. Added Update button
(StatusUpdateModal) to IncidentHeader and FlowPilotPage header bar
for feature parity with production.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Reset triageMeta, psaTicketId, steps, and completedSteps when
activeChatId changes (prevents stale triage data from previous session
showing while AI processes the new one)
- Split the activeChatId and activeActions reset effects so triage
only resets on session switch, not on every new action set
- Add loading placeholders to cockpit work zone: spinner + "analyzing"
text in steps panel, "questions will appear here" in right panel
- Add centered "Starting session..." loader to FlowPilot page when
loading with no messages yet (prefill creation period)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Root cause: race condition between setActiveChatId and the persist
effect. When switching from session A to B, setActiveChatId(B) triggers
the persist effect which writes {chatId: B, questions: [A's data]} to
sessionStorage BEFORE the async selectChat clears the task lane. The
sessionStorage fallback then finds chatId === B and restores A's stale
task lane data.
Fix: clear task lane state synchronously in selectChat before the await.
Server-side pending_task_lane restores it if the new session has data.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix return type annotation on unified_chat_service.send_chat_message (6→7 tuple)
- Fix stale closure in CockpitPage handleStepComplete auto-advance logic
- Fix IncidentHeader copy link hardcoding /assistant/ path (now uses current URL)
- Wire psaTicketId from session data through to CockpitPage incident header
- Fix FlowPilotAsks showing only first question — add chevron navigation for all
- Redesign ViewToggle: add icons (MessageSquare/LayoutDashboard) and subtitles
- Move view toggle from chatbar toolbar to standalone row above input on dashboard
- Standardize toggle placement across dashboard, FlowPilot, and Cockpit pages
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backend: stop wiping pending_task_lane when AI response has no new
[ACTIONS]/[QUESTIONS] markers — previous task lane state is still
relevant until replaced by new markers.
Frontend (selectChat): don't eagerly clear task lane before server
response arrives; restore from sessionStorage as fallback when
pending_task_lane is null (covers sessions before backend fix).
StepsPanel: show description and command for all steps instead of
hiding behind hover/active-only visibility. Commands render as
inline code blocks.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Always load session data on mount even when urlSessionId matches
activeChatId, fixing empty state after view toggle between /assistant
and /cockpit (tasks/messages not showing until sidebar click)
- Add loadingRef for synchronous guards preventing duplicate sends,
duplicate session creation, and prefill races
- Fix stale evidence_items closure in CockpitPage handlers
- Move setLoading(true) before first await in handlePrefill and
handleResumeNew
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace all inline session management with the shared useAssistantSession
hook. Keep cockpit-specific state (triageMeta, workZonePct, steps, onboarding)
and handlers. Wire onSessionLoadedRef/onTriageUpdateRef callbacks. Add feature
flag redirect for flowpilot_cockpit. Update router and prefetch references.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Recreates the production AssistantChatPage as FlowPilotPage using the
shared useAssistantSession hook. Classic chat interface with ChatMessage
bubbles, TaskLane side panel, rich input with file uploads, and
conclude/status update modals. ViewToggle commented out pending Task 4.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
No external call sites existed. Feature gating now handled by
useFeatureFlag hook backed by the feature_flags system.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Selector-based hook reads from authStore.featureFlags.
Returns false for unknown keys (fail closed).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Loads resolved feature flags from /auth/me/feature-flags alongside
user, account, and subscription data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
handleSend, sendPrefill, and handleResumeNew all make async API calls
that can return after the user has switched to a different session. Without
a guard, the stale response overwrites the new session's questions/actions
state — causing the previous session's FlowPilot Asks to persist.
Fix: capture the session ID before each await and check currentChatRef
after — discarding the response if the user has since switched. This
matches the existing guard pattern in selectChat (lesson #106).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Stacked zone layout: incident header → work zone → drag handle →
conversation log → compose
- IncidentHeader wired with triageMeta state and field save handlers
- Work zone: StepsPanel (left) + FlowPilotAsks + WhatWeKnow (right)
- Drag-resizable split with localStorage persistence
- Compact conversation log with you:/fp: prefixes
- Triage state populated on session load/resume
- AI triage_update merged into header via mergeTriageUpdate()
- MSP-native language: FlowPilot, New Case, Close Case
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- IncidentHeader: labelled fields with per-field edit popovers
- StepsPanel: ordered step checklist (✓/→/○) with script CTA
- FlowPilotAsks: quick-reply buttons or free-text input
- WhatWeKnow: evidence list with status toggle and inline editing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- TriageMeta, EvidenceItem, TriageUpdate interfaces
- QuestionItem.options field for quick-reply buttons
- triage_update on ChatMessageResponse
- Triage fields on AISessionDetail for session resume
- updateTriage() and getHandoffDraft() API methods
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
#60a5fa (electric blue) is a light colour — near-white and muted-foreground
text on it produced ~1.9–2.1:1 contrast, well below WCAG AA.
- TreeNavigationPage: option number badges + timer badge → text-[#0e1016]
- StepChecklist: active step was blue badge on blue row (invisible); now
inverts to navy circle with blue number when current, dark-on-blue otherwise
- StepDetail: step number circle → text-[#0e1016] (was near-white on light blue)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Added 'All Scripts' as the first/default tab (no mine/shared filter) so the
page opens with every script the user can access. My Scripts and Team Scripts
tabs remain for filtered views.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
setCategory and setSearch called loadTemplates() with no arguments, dropping
the mine/shared filter set by the active tab — causing the list to show all
templates instead of the current user's scripts after any filter interaction.
Store now persists tabFilters whenever loadTemplates is called with explicit
filters, and reuses them for subsequent no-arg calls from setCategory/setSearch.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- script_builder endpoint: pg_advisory_xact_lock on user_id before
session count check, preventing concurrent creates from both passing
the MAX_SESSIONS_PER_USER guard
- script_builder_service send_message: pg_advisory_xact_lock on session_id
before message count check, preventing concurrent sends from both
passing the MAX_MESSAGES_PER_SESSION guard
- script_builder_service save_to_library: replace check-then-insert slug
logic with IntegrityError retry loop (3 attempts with fresh UUID suffix);
add unique constraint on script_templates.slug (migration 070)
- ScriptBuilderPage: add creatingSessionRef to serialize concurrent
handleSend calls that would otherwise both call createSession() while
session is still null
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Race condition: on page remount, selectChat(oldId) loads session data async.
If the user clicks New Chat before the API returns, the old session's
pending_task_lane was being applied to the new session's state, showing
stale tasks and blocking new ones from appearing.
Fix: currentChatRef tracks the most recently requested chat ID synchronously.
All chat-creation paths (selectChat, handleNewChat, handleResumeNew) update it
immediately. After each await in selectChat, bail if the ref no longer matches.
Also documents the pattern as Lesson 106 in CLAUDE.md for future reference.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
VITE_SENTRY_DSN is already set in Railway as a build arg. The hardcoded
fallback was unnecessary and triggered GitHub secret scanning alerts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- landing.css: hardcode --lp-btn to #60a5fa (lesson 104 — no var(--color-*) in landing.css)
- ScriptBuilderInput: suggestion chips now correctly disabled during generation
- ChatSidebar: wrapper onClick no longer fires onSelect while in confirming state
- SessionHistoryPage: fix loadMoreAiSessions race condition with generation counter;
flow session tab auto-activates when URL params target flow session filters
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>