← back to ddgonzal3__rally

Function bodies 465 total

All specs Real LLM only Function bodies
SmallDocIcon function · typescript · L303-L322 (20 LOC)
src/components/FileIcons.tsx
function SmallDocIcon({ color }: { color: string }) {
  return (
    <svg width="16" height="16" viewBox="0 0 14 14" style={{ flexShrink: 0 }}>
      <path
        d="M3.5 1.5h4.5L11 4.5v8H3.5z"
        stroke={color}
        strokeWidth="0.9"
        fill="none"
        opacity={0.7}
      />
      <path
        d="M8 1.5v3h3"
        stroke={color}
        strokeWidth="0.9"
        fill="none"
        opacity={0.7}
      />
    </svg>
  );
}
FlightCanvas function · typescript · L966-L1013 (48 LOC)
src/components/FlightCanvas.tsx
export function FlightCanvas() {
  const activeWorkspaceId = useWorkspaceStore((s) => s.activeWorkspaceId);
  const hasActiveWorkspace = useWorkspaceStore(
    (s) => !!s.activeWorkspaceId && s.workspaces.some((w) => w.id === s.activeWorkspaceId)
  );

  // Collect IDs of all workspaces that have flight layouts (or are active),
  // as a stable string to avoid returning new arrays from the selector.
  const mountedIdsString = useWorkspaceStore((s) => {
    const wsIds = new Set(s.workspaces.map((w) => w.id));
    const ids = new Set<string>();
    for (const id of Object.keys(s.flightLayouts)) {
      if (wsIds.has(id)) ids.add(id);
    }
    if (s.activeWorkspaceId && wsIds.has(s.activeWorkspaceId)) {
      ids.add(s.activeWorkspaceId);
    }
    return Array.from(ids).join("\n");
  });
  const mountedIds = useMemo(
    () => (mountedIdsString ? mountedIdsString.split("\n") : []),
    [mountedIdsString]
  );

  if (!hasActiveWorkspace) {
    return (
      <div style={canvasStyles.emp
FlightHUD function · typescript · L19-L64 (46 LOC)
src/components/FlightHUD.tsx
export function FlightHUD({ workspaceId, zoom, focusMode, onToggleFocus, autoFocus, onToggleAutoFocus }: FlightHUDProps) {
  const addFlightPod = useWorkspaceStore((s) => s.addFlightPod);
  const setFlightViewport = useWorkspaceStore((s) => s.setFlightViewport);

  const updateFlightPod = useWorkspaceStore((s) => s.updateFlightPod);
  const pods = useWorkspaceStore((s) => s.flightLayouts[workspaceId]?.pods);

  const handleAddClaude = () => addFlightPod(workspaceId, "claude");
  const handleAddTerminal = () => addFlightPod(workspaceId, "terminal");
  const handleResetZoom = () => setFlightViewport(workspaceId, { zoom: 1.0 });
  const handleResetSizes = () => {
    if (!pods) return;
    // In focus mode, cap width so ≥2 pods fit (same logic as navigateTo)
    const container = document.querySelector("[data-flight-canvas]") as HTMLElement | null;
    let maxW = Infinity;
    if (focusMode && container) {
      const rect = container.getBoundingClientRect();
      const parentZoom = rect
PodScriptDot function · typescript · L18-L148 (131 LOC)
src/components/FlightPodFooter.tsx
function PodScriptDot({
  repoPath,
  scriptName,
  scriptEntry,
}: {
  repoPath: string;
  scriptName: string;
  scriptEntry: ScriptEntry | undefined;
}) {
  const scriptRuns = useWorkspaceStore((s) => s.scriptRuns);
  const runScript = useWorkspaceStore((s) => s.runScript);
  const stopScript = useWorkspaceStore((s) => s.stopScript);
  const clearScript = useWorkspaceStore((s) => s.clearScript);
  const openStatusBarDrawer = useWorkspaceStore((s) => s.openStatusBarDrawer);
  const statusBarDrawer = useWorkspaceStore((s) => s.statusBarDrawer);

  const key = `${repoPath}:${scriptName}`;
  const run = scriptRuns[key];
  const isRunning = run?.status === "running";
  const isWatcher = isWatcherScript(scriptName);
  const command = scriptEntry?.command ?? scriptName;
  const displayName = getDisplayName(scriptName);

  const isDrawerOpen =
    statusBarDrawer?.repoPath === repoPath &&
    statusBarDrawer?.scriptName === scriptName;

  let buildStatus: WatcherBuildStatus;
  if (isWatcher)
FlightPodFooter function · typescript · L151-L207 (57 LOC)
src/components/FlightPodFooter.tsx
export function FlightPodFooter({ repoPath }: { repoPath: string }) {
  const rallyConfig = useWorkspaceStore((s) => s.rallyConfigs[repoPath]);
  const loadRallyConfig = useWorkspaceStore((s) => s.loadRallyConfig);
  const [scriptCache, setScriptCache] = useState<ScriptEntry[]>([]);

  useEffect(() => {
    if (!rallyConfig) loadRallyConfig(repoPath);
    api.listScripts(repoPath).then(setScriptCache).catch(() => {});
  }, [repoPath, loadRallyConfig, rallyConfig]);

  const scripts = rallyConfig?.statusBar ?? [];
  if (scripts.length === 0) return null;

  const repoName = repoPath.split("/").pop() ?? repoPath;

  return (
    <div
      onContextMenu={(e) => e.preventDefault()}
      style={{
        height: 28,
        display: "flex",
        alignItems: "center",
        gap: 0,
        paddingLeft: 8,
        paddingRight: 10,
        paddingBottom: 2,
        borderTop: "1px solid rgba(255, 255, 255, 0.06)",
        flexShrink: 0,
        overflow: "hidden",
        userSelect: "
snapToNeighbors function · typescript · L28-L88 (61 LOC)
src/components/FlightPod.tsx
export function snapToNeighbors(
  moving: SnapEdges,
  others: SnapEdges[],
  mode: "drag" | "resize",
): SnapEdges {
  let { x, y, width, height } = moving;
  const left = x;
  const right = x + width;
  const top = y;
  const bottom = y + height;

  let snappedX = false;
  let snappedY = false;

  for (const o of others) {
    const oLeft = o.x;
    const oRight = o.x + o.width;
    const oTop = o.y;
    const oBottom = o.y + o.height;

    const gap = MIN_POD_GAP;

    if (!snappedX) {
      if (mode === "drag") {
        // Snap with gap: right edge → other left edge (with gap between)
        if (Math.abs(right + gap - oLeft) < SNAP_THRESHOLD) { x = oLeft - width - gap; snappedX = true; }
        // Left edge → other right edge (with gap between)
        else if (Math.abs(left - gap - oRight) < SNAP_THRESHOLD) { x = oRight + gap; snappedX = true; }
        // Align left edges
        else if (Math.abs(left - oLeft) < SNAP_THRESHOLD) { x = oLeft; snappedX = true; }
        // Alig
preventOverlap function · typescript · L96-L148 (53 LOC)
src/components/FlightPod.tsx
export function preventOverlap(
  moving: SnapEdges,
  others: SnapEdges[],
  rawPos?: { x: number; y: number },
): SnapEdges {
  let { x, y } = moving;
  const { width, height } = moving;

  for (const o of others) {
    // Check if they overlap (with MIN_POD_GAP margin)
    const overlapX = x < o.x + o.width + MIN_POD_GAP && x + width + MIN_POD_GAP > o.x;
    const overlapY = y < o.y + o.height + MIN_POD_GAP && y + height + MIN_POD_GAP > o.y;

    if (overlapX && overlapY) {
      // If we have the raw cursor position, check if the user is pushing
      // deep enough into the overlap to signal they want stacking
      if (rawPos) {
        const rawOverlapX = rawPos.x < o.x + o.width + MIN_POD_GAP && rawPos.x + width + MIN_POD_GAP > o.x;
        const rawOverlapY = rawPos.y < o.y + o.height + MIN_POD_GAP && rawPos.y + height + MIN_POD_GAP > o.y;

        if (rawOverlapX && rawOverlapY) {
          // Measure how deep the raw position is into the overlap zone
          const depthRig
Want fix-PRs on findings? Install Repobility's GitHub App · github.com/apps/repobility-bot
GitDiffContent function · typescript · L16-L256 (241 LOC)
src/components/GitDiffOverlay.tsx
export function GitDiffContent({ rootPath }: GitDiffContentProps) {
  const activeTab = useWorkspaceStore((s) => s.gitDiffActiveTab);
  const setActiveTab = useWorkspaceStore((s) => s.setGitDiffActiveTab);
  const scrollToFile = useWorkspaceStore((s) => s.gitDiffScrollToFile);
  const gitStatus = useWorkspaceStore((s) => s.gitStatuses[rootPath]);
  const mainBranch = useWorkspaceStore((s) => {
    const ws = s.workspaces.find((w) => w.paths.includes(rootPath));
    return ws?.main_branch ?? "main";
  });

  const {
    unstagedFiles,
    stagedFiles,
    commits,
    diffStatAdd,
    diffStatDel,
    loading,
    fetchDiffs,
    handleStage,
    handleUnstage,
    handleDiscard,
    handleRevertAll,
    revertConfirming,
    handleStageAll,
    handleUnstageAll,
    handleCreatePr,
    creatingPr,
    unstagedCount,
    stagedCount,
    hasStaged,
    hasPr,
    createPrVisible,
  } = useGitDiffActions({ rootPath, mainBranch });

  const [commitModalOpen, setCommitModalOpen] = useState
MarkdownPreview function · typescript · L10-L34 (25 LOC)
src/components/MarkdownPreview.tsx
  function MarkdownPreview({ content, onScroll }, ref) {
    const html = useMemo(() => renderMarkdown(content), [content]);

    return (
      <div
        ref={ref}
        style={styles.container}
        onScroll={
          onScroll
            ? (e) => {
                const el = e.currentTarget;
                onScroll(el.scrollTop, el.scrollHeight, el.clientHeight);
              }
            : undefined
        }
      >
        <style>{markdownStyles}</style>
        <div
          className="md-body"
          style={styles.body}
          dangerouslySetInnerHTML={{ __html: html }}
        />
      </div>
    );
  },
paneHasActiveSession function · typescript · L28-L31 (4 LOC)
src/components/PaneGroupView.tsx
function paneHasActiveSession(pane: Pane | undefined): boolean {
  if (!pane) return false;
  return !!(pane.ptyId && (pane.type === "claude" || pane.type === "terminal"));
}
isClaudeCodeTitle function · typescript · L41-L44 (4 LOC)
src/components/PaneGroupView.tsx
function isClaudeCodeTitle(title: string): boolean {
  const lower = title.toLowerCase();
  return lower === "claude" || lower.startsWith("claude ");
}
paneLabel function · typescript · L46-L80 (35 LOC)
src/components/PaneGroupView.tsx
function paneLabel(
  pane: Pane,
  isDirty: boolean,
  workspacePath?: string,
): string {
  // User-set custom title always takes priority for renamable pane types
  if (
    pane.customTitle &&
    (pane.type === "terminal" ||
      pane.type === "claude" ||
      pane.type === "claude-launcher")
  ) {
    return pane.customTitle;
  }
  if (pane.type === "claude-launcher") {
    const cwd = pane.cwd || workspacePath || "";
    return cwd.split("/").pop() || "Claude Code";
  }
  if (pane.type === "claude") {
    const cwd = pane.cwd || workspacePath || "";
    return cwd.split("/").pop() || "claude";
  }
  if (pane.type === "webview") return pane.title;
  if (pane.type === "editor" || pane.type === "diff")
    return isDirty ? `${pane.title} *` : pane.title;
  if (pane.type === "terminal" && isClaudeCodeTitle(pane.title)) {
    const cwd = pane.cwd || workspacePath || "";
    return cwd.split("/").pop() || "claude";
  }
  if (pane.type === "terminal") {
    const cwd = pane.cwd || wo
paneTooltip function · typescript · L82-L89 (8 LOC)
src/components/PaneGroupView.tsx
function paneTooltip(pane: Pane): string {
  if (pane.type === "editor" && pane.filePath) return pane.filePath;
  if (pane.type === "webview" && pane.webviewUrl) return pane.webviewUrl;
  if (pane.type === "diff" && pane.cwd)
    return pane.filePath ? `${pane.cwd}/${pane.filePath}` : pane.cwd;
  if (pane.cwd) return pane.cwd;
  return pane.title;
}
startRename function · typescript · L174-L183 (10 LOC)
src/components/PaneGroupView.tsx
  function startRename(pane: Pane) {
    if (
      pane.type !== "terminal" &&
      pane.type !== "claude" &&
      pane.type !== "claude-launcher"
    )
      return;
    setRenamingPaneId(pane.id);
    setRenameValue(pane.customTitle || paneLabel(pane, false, workspacePath));
  }
commitRename function · typescript · L185-L191 (7 LOC)
src/components/PaneGroupView.tsx
  function commitRename(paneId: string) {
    const trimmed = renameValue.trim();
    if (trimmed) {
      transformPane(workspaceId, groupId, paneId, { customTitle: trimmed });
    }
    setRenamingPaneId(null);
  }
Repobility's GitHub App fixes findings like these · https://github.com/apps/repobility-bot
cancelRename function · typescript · L193-L195 (3 LOC)
src/components/PaneGroupView.tsx
  function cancelRename() {
    setRenamingPaneId(null);
  }
handleAction function · typescript · L230-L243 (14 LOC)
src/components/PaneGroupView.tsx
  function handleAction(actionType: PendingAction["type"]) {
    if (actionType === "terminal") {
      window.dispatchEvent(
        new CustomEvent<RequestNewTerminalCwdDetail>(
          REQUEST_NEW_TERMINAL_CWD_EVENT,
          { detail: { workspaceId, groupId } },
        ),
      );
      return;
    }

    const activePane = group.panes.find((p) => p.id === activePaneId);
    executeAction(actionType, activePane?.cwd || workspacePath);
  }
handleTabMouseDown function · typescript · L279-L407 (129 LOC)
src/components/PaneGroupView.tsx
  function handleTabMouseDown(e: React.MouseEvent, paneId: string) {
    // Only left click
    if (e.button !== 0) return;
    // Don't start drag from close button
    if ((e.target as HTMLElement).closest("[data-close]")) return;

    e.preventDefault(); // Prevent text selection during drag

    const startX = e.clientX;
    const startY = e.clientY;
    const tabsContainer = (e.currentTarget as HTMLElement).parentElement;
    dragStartRef.current = { x: startX, y: startY, paneId };
    let reordering = false;
    let dropGap = -1;

    // Drop indicator line (VS Code style)
    const indicator = document.createElement("div");
    indicator.style.cssText =
      "position:fixed;width:2px;background:var(--text-primary);border-radius:1px;pointer-events:none;z-index:100;display:none;will-change:left;";

    const onMouseMove = (ev: MouseEvent) => {
      ev.preventDefault();
      if (!dragStartRef.current) return;
      const dx = ev.clientX - startX;
      const dy = ev.clientY - st
BreadcrumbBar function · typescript · L901-L974 (74 LOC)
src/components/PaneGroupView.tsx
function BreadcrumbBar({
  panes,
  activePaneId,
  workspacePaths,
}: {
  panes: Pane[];
  activePaneId: string;
  workspacePaths: string[];
}) {
  const activePane = panes.find((p) => p.id === activePaneId);
  if (!activePane || activePane.type !== "editor" || !activePane.filePath)
    return null;

  const filePath = activePane.filePath;

  // Find which workspace root this file belongs to
  const matchingRoot = workspacePaths.find((p) => filePath.startsWith(p + "/"));
  if (!matchingRoot) return null;

  const rootName = matchingRoot.split("/").pop() ?? matchingRoot;
  const relativePath = filePath.slice(matchingRoot.length + 1);
  const segments = relativePath.split("/");

  const isFile = (i: number) => i === segments.length - 1;

  return (
    <div style={bcStyles.bar}>
      <svg
        width="18"
        height="13"
        viewBox="0 0 18 14"
        fill="none"
        style={{ flexShrink: 0, position: "relative", top: 1 }}
      >
        <path
          d="M1.5 3C1.5 2.1
shouldCacheInactivePane function · typescript · L1009-L1012 (4 LOC)
src/components/PaneGroupView.tsx
function shouldCacheInactivePane(pane: Pane | undefined): boolean {
  if (!pane) return false;
  return pane.type === "terminal" || pane.type === "claude" || pane.type === "webview";
}
handleFocusGroup function · typescript · L1074-L1084 (11 LOC)
src/components/PaneGroupView.tsx
    function handleFocusGroup(e: Event) {
      const targetId = (e as CustomEvent).detail;
      if (targetId === groupId && contentRef.current) {
        requestAnimationFrame(() => {
          const textarea = contentRef.current?.querySelector(
            "textarea.xterm-helper-textarea",
          ) as HTMLTextAreaElement | null;
          textarea?.focus();
        });
      }
    }
PaneLayout function · typescript · L52-L100 (49 LOC)
src/components/PaneLayout.tsx
export function PaneLayout() {
  const activeWorkspaceId = useWorkspaceStore((s) => s.activeWorkspaceId);
  const hasActiveWorkspace = useWorkspaceStore(
    (s) => !!s.activeWorkspaceId && s.workspaces.some((w) => w.id === s.activeWorkspaceId)
  );

  // Return a stable string (joined IDs) so Zustand's Object.is check prevents
  // re-renders when the set of mounted workspaces hasn't actually changed.
  // See PITFALLS.md — returning a new array from a selector causes render loops.
  const mountedIdsString = useWorkspaceStore((s) => {
    const wsIds = new Set(s.workspaces.map((w) => w.id));
    const ids = new Set<string>();
    for (const id of Object.keys(s.layouts)) {
      if (wsIds.has(id)) ids.add(id);
    }
    if (s.activeWorkspaceId && wsIds.has(s.activeWorkspaceId)) {
      ids.add(s.activeWorkspaceId);
    }
    return Array.from(ids).join("\n");
  });
  const mountedWorkspaceIds = useMemo(
    () => (mountedIdsString ? mountedIdsString.split("\n") : []),
    [mountedIdsSt
PortPill function · typescript · L9-L26 (18 LOC)
src/components/PortPill.tsx
export function PortPill({ port: p, onClick }: PortPillProps) {
  return (
    <span
      key={p.port}
      onMouseDown={(e) => {
        e.stopPropagation();
      }}
      onClick={(e) => {
        e.stopPropagation();
        onClick(p.url);
      }}
      title={`Open ${p.url}`}
      style={pillStyle}
    >
      :{p.port}
    </span>
  );
}
Provenance: Repobility (https://repobility.com) — every score reproducible from /scan/
shortenPath function · typescript · L18-L20 (3 LOC)
src/components/ProductChatPanel.tsx
function shortenPath(p: string): string {
  return p.replace(/^\/Users\/[^/]+/, "~");
}
buildFileTree function · typescript · L26-L75 (50 LOC)
src/components/PrReviewOverlay.tsx
function buildFileTree(files: DiffFile[]): FileTreeNode[] {
  const root: FileTreeNode[] = [];

  for (const file of files) {
    const fp = file.newPath || file.oldPath;
    const parts = fp.split("/");
    let current = root;

    for (let i = 0; i < parts.length; i++) {
      const part = parts[i];
      const pathSoFar = parts.slice(0, i + 1).join("/");
      const isLeaf = i === parts.length - 1;
      let existing = current.find((n) => n.name === part && n.path === pathSoFar);

      if (!existing) {
        existing = { name: part, path: pathSoFar, children: [] };
        if (isLeaf) existing.file = file;
        current.push(existing);
      }
      current = existing.children;
    }
  }

  // Collapse single-child directories: src/components → src/components
  function collapse(nodes: FileTreeNode[]): FileTreeNode[] {
    return nodes.map((node) => {
      node.children = collapse(node.children);
      if (node.children.length === 1 && !node.file && !node.children[0].file) {
 
collapse function · typescript · L50-L59 (10 LOC)
src/components/PrReviewOverlay.tsx
  function collapse(nodes: FileTreeNode[]): FileTreeNode[] {
    return nodes.map((node) => {
      node.children = collapse(node.children);
      if (node.children.length === 1 && !node.file && !node.children[0].file) {
        const child = node.children[0];
        return { ...child, name: `${node.name}/${child.name}` };
      }
      return node;
    });
  }
sortTree function · typescript · L62-L72 (11 LOC)
src/components/PrReviewOverlay.tsx
  function sortTree(nodes: FileTreeNode[]): FileTreeNode[] {
    nodes.sort((a, b) => {
      const aIsDir = a.children.length > 0 || !a.file;
      const bIsDir = b.children.length > 0 || !b.file;
      if (aIsDir && !bIsDir) return -1;
      if (!aIsDir && bIsDir) return 1;
      return a.name.localeCompare(b.name);
    });
    for (const n of nodes) sortTree(n.children);
    return nodes;
  }
buildTimeline function · typescript · L82-L95 (14 LOC)
src/components/PrReviewOverlay.tsx
function buildTimeline(comments: PrComment[], reviews: PrReview[]): TimelineItem[] {
  const items: TimelineItem[] = [
    ...comments.map((c) => ({ kind: "comment" as const, data: c })),
    ...reviews
      .filter((r) => r.body.trim().length > 0 || r.state !== "COMMENTED")
      .map((r) => ({ kind: "review" as const, data: r })),
  ];
  items.sort(
    (a, b) =>
      new Date(a.data.created_at).getTime() -
      new Date(b.data.created_at).getTime(),
  );
  return items;
}
getStatusColor function · typescript · L759-L764 (6 LOC)
src/components/PrReviewOverlay.tsx
function getStatusColor(file: DiffFile): string {
  return file.isNew ? statusColors.new
    : file.isDeleted ? statusColors.deleted
    : file.isRenamed ? statusColors.renamed
    : statusColors.modified;
}
getStatusLetter function · typescript · L765-L767 (3 LOC)
src/components/PrReviewOverlay.tsx
function getStatusLetter(file: DiffFile): string {
  return file.isNew ? "A" : file.isDeleted ? "D" : file.isRenamed ? "R" : "M";
}
ConversationTab function · typescript · L857-L951 (95 LOC)
src/components/PrReviewOverlay.tsx
function ConversationTab({
  details,
  loading,
  timeline,
  bodyHtml,
}: {
  details: PrDetails | null;
  loading: boolean;
  timeline: TimelineItem[];
  bodyHtml: string | null;
}) {
  if (loading) {
    return <div style={st.empty}>Loading...</div>;
  }
  if (!details) {
    return <div style={st.empty}>No PR data</div>;
  }

  const hasTimeline = timeline.length > 0;

  if (!bodyHtml && !hasTimeline) {
    return (
      <div style={st.empty}>
        No description or comments
      </div>
    );
  }

  return (
    <div style={st.conversationList}>
      {/* PR description rendered as markdown */}
      {bodyHtml && (
        <div style={st.conversationCard}>
          <div style={st.conversationHeader}>
            <span style={st.conversationAuthor}>{details.author}</span>
            <span style={st.conversationLabel}>author</span>
            {details.created_at && (
              <span style={st.conversationDate}>{relativeTime(details.created_at)}</span>
            )}
   
All rows scored by the Repobility analyzer (https://repobility.com)
fuzzyMatch function · typescript · L37-L62 (26 LOC)
src/components/QuickOpen.tsx
function fuzzyMatch(query: string, target: string): FuzzyResult | null {
  const lowerQuery = query.toLowerCase();
  const lowerTarget = target.toLowerCase();
  const indices: number[] = [];
  let qi = 0;
  let score = 0;
  let lastMatchIndex = -1;

  for (let ti = 0; ti < target.length && qi < lowerQuery.length; ti++) {
    if (lowerTarget[ti] === lowerQuery[qi]) {
      indices.push(ti);
      if (lastMatchIndex === ti - 1) score += 10;
      if (ti === 0 || "/\\-_ .".includes(target[ti - 1])) score += 5;
      if (target[ti] === query[qi]) score += 3;
      if (lastMatchIndex >= 0) {
        const gap = ti - lastMatchIndex - 1;
        if (gap > 0) score -= gap;
      }
      lastMatchIndex = ti;
      qi++;
    }
  }

  if (qi < lowerQuery.length) return null;
  return { score, indices };
}
baseName function · typescript · L64-L67 (4 LOC)
src/components/QuickOpen.tsx
function baseName(path: string): string {
  const i = path.lastIndexOf("/");
  return i >= 0 ? path.slice(i + 1) : path;
}
parentDir function · typescript · L69-L72 (4 LOC)
src/components/QuickOpen.tsx
function parentDir(path: string): string {
  const i = path.lastIndexOf("/");
  return i > 0 ? path.slice(0, i) : path;
}
HighlightedText function · typescript · L76-L109 (34 LOC)
src/components/QuickOpen.tsx
function HighlightedText({
  text,
  indices,
}: {
  text: string;
  indices: Set<number>;
}) {
  const spans: React.ReactNode[] = [];
  let run = "";
  let runHighlighted = false;

  for (let i = 0; i <= text.length; i++) {
    const isHighlighted = indices.has(i);
    if (i === text.length || isHighlighted !== runHighlighted) {
      if (run) {
        spans.push(
          runHighlighted ? (
            <span key={i} style={{ color: "#2aaaff", fontWeight: 700 }}>
              {run}
            </span>
          ) : (
            <span key={i}>{run}</span>
          ),
        );
      }
      run = i < text.length ? text[i] : "";
      runHighlighted = isHighlighted;
    } else {
      run += text[i];
    }
  }

  return <>{spans}</>;
}
FolderRowIcon function · typescript · L111-L122 (12 LOC)
src/components/QuickOpen.tsx
function FolderRowIcon() {
  return (
    <svg width="16" height="16" viewBox="0 0 16 16" fill="none" style={{ flexShrink: 0 }}>
      <path
        d="M2 4.5C2 3.67 2.67 3 3.5 3H6.4L7.5 4.3H12.5C13.33 4.3 14 4.97 14 5.8V11.5C14 12.33 13.33 13 12.5 13H3.5C2.67 13 2 12.33 2 11.5V4.5Z"
        stroke="#8aa9d6"
        strokeWidth="1.2"
        strokeLinejoin="round"
      />
    </svg>
  );
}
RepoSwitcher function · typescript · L10-L131 (122 LOC)
src/components/RepoSwitcher.tsx
export function RepoSwitcher({ workspaceId, rootPath }: RepoSwitcherProps) {
  const [open, setOpen] = useState(false);
  const [dropdownPos, setDropdownPos] = useState<{ top: number; left: number } | null>(null);
  const buttonRef = useRef<HTMLButtonElement>(null);
  const dropdownRef = useRef<HTMLDivElement>(null);

  const workspace = useWorkspaceStore((s) => s.workspaces.find((w) => w.id === workspaceId));
  const setActivePathIndex = useWorkspaceStore((s) => s.setActivePathIndex);
  const refreshGitStatusForPath = useWorkspaceStore((s) => s.refreshGitStatusForPath);

  const paths = workspace?.paths ?? [];
  const mainBranch = workspace?.main_branch ?? "main";
  const currentBasename = rootPath.split("/").pop() || rootPath;

  const openDropdown = useCallback(() => {
    if (buttonRef.current) {
      const rect = buttonRef.current.getBoundingClientRect();
      setDropdownPos({ top: rect.bottom + 4, left: rect.left });
    }
    setOpen(true);
  }, []);

  const handleSelect = us
collectPeerHandles function · typescript · L25-L78 (54 LOC)
src/components/ResizeHandle.tsx
function collectPeerHandles(handle: HTMLElement, direction: SplitDirection): PeerHandle[] {
  const parent = handle.parentElement;
  if (!parent) return [];

  const grandparent = parent.parentElement;
  if (!grandparent) return [];

  const isVertical = direction === "vertical";
  const peers: PeerHandle[] = [];

  const greatGrandparent = grandparent.parentElement;
  if (!greatGrandparent) return peers;

  const siblingContainers = greatGrandparent.children;
  for (let i = 0; i < siblingContainers.length; i++) {
    const sibling = siblingContainers[i] as HTMLElement;
    if (sibling === grandparent) continue;

    const handles = sibling.querySelectorAll<HTMLElement>('[style*="cursor"]');
    for (const peerHandle of handles) {
      const cursor = peerHandle.style.cursor;
      const isPeerSameDirection =
        (isVertical && cursor === "row-resize") ||
        (!isVertical && cursor === "col-resize");
      if (!isPeerSameDirection) continue;

      const peerParent = peerHandle
ResizeHandle function · typescript · L80-L299 (220 LOC)
src/components/ResizeHandle.tsx
export function ResizeHandle({ direction, ratio, onResize }: ResizeHandleProps) {
  const handleRef = useRef<HTMLDivElement>(null);
  const lineRef = useRef<HTMLDivElement>(null);
  const dragging = useRef(false);
  const onResizeRef = useRef(onResize);
  onResizeRef.current = onResize;
  const ratioRef = useRef(ratio);
  ratioRef.current = ratio;

  const isRowHandle = direction === "vertical";

  const resetLine = useCallback(() => {
    if (lineRef.current) lineRef.current.style.background = "var(--border)";
  }, []);

  const highlightLine = useCallback(() => {
    if (lineRef.current) lineRef.current.style.background = "var(--resize-hover)";
  }, []);

  const onMouseDown = useCallback(
    (e: React.MouseEvent) => {
      e.preventDefault();
      dragging.current = true;
      const handle = handleRef.current;
      if (!handle) return;

      const parent = handle.parentElement;
      if (!parent) return;

      const rect = parent.getBoundingClientRect();
      const handleRec
Want fix-PRs on findings? Install Repobility's GitHub App · github.com/apps/repobility-bot
ScriptEditor function · typescript · L6-L81 (76 LOC)
src/components/ScriptEditor.tsx
export function ScriptEditor() {
  const [scripts, setScripts] = useState<RallyScriptInfo[]>([]);
  const [loading, setLoading] = useState(true);
  const activeWorkspaceId = useWorkspaceStore((s) => s.activeWorkspaceId);
  const openFile = useWorkspaceStore((s) => s.openFile);

  const refresh = async () => {
    try {
      const result = await api.listRallyScripts();
      setScripts(result);
    } catch (e) {
      console.error("Failed to list rally scripts:", e);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    refresh();
  }, []);

  const handleOpen = (script: RallyScriptInfo) => {
    if (!activeWorkspaceId) return;
    openFile(activeWorkspaceId, script.path);
  };

  const handleRestore = async (script: RallyScriptInfo) => {
    try {
      await api.restoreRallyScript(script.name);
      await refresh();
    } catch (e) {
      console.error("Failed to restore script:", e);
    }
  };

  const cliScripts = scripts.filter((s) => s.category === "scr
Section function · typescript · L83-L97 (15 LOC)
src/components/ScriptEditor.tsx
function Section({ title, subtitle, children }: {
  title: string;
  subtitle: string;
  children: React.ReactNode;
}) {
  return (
    <div style={styles.section}>
      <div style={styles.sectionHeader}>
        <span style={styles.sectionTitle}>{title}</span>
        <span style={styles.sectionSubtitle}>{subtitle}</span>
      </div>
      {children}
    </div>
  );
}
basename function · typescript · L30-L34 (5 LOC)
src/components/SearchPanel.tsx
function basename(path: string): string {
  const trimmed = path.replace(/\/+$/, "");
  const idx = trimmed.lastIndexOf("/");
  return idx >= 0 ? trimmed.slice(idx + 1) : trimmed;
}
dirname function · typescript · L36-L40 (5 LOC)
src/components/SearchPanel.tsx
function dirname(path: string): string {
  const trimmed = path.replace(/\/+$/, "");
  const idx = trimmed.lastIndexOf("/");
  return idx >= 0 ? trimmed.slice(0, idx) : "";
}
findRepoForFile function · typescript · L42-L49 (8 LOC)
src/components/SearchPanel.tsx
function findRepoForFile(filePath: string, sortedRoots: string[]): string {
  for (const root of sortedRoots) {
    if (filePath === root || filePath.startsWith(`${root}/`)) {
      return root;
    }
  }
  return dirname(filePath) || filePath;
}
defaultSearchState function · typescript · L65-L79 (15 LOC)
src/components/SearchPanel.tsx
function defaultSearchState(): PerWorkspaceSearchState {
  return {
    query: "",
    caseSensitive: false,
    wholeWord: false,
    useRegex: false,
    results: [],
    hasSearched: false,
    collapsedFiles: new Set(),
    replaceOpen: false,
    replaceValue: "",
    preserveCase: false,
    collapsedRepos: new Set(),
  };
}
dirname function · typescript · L22-L25 (4 LOC)
src/components/SettingsPanel.tsx
function dirname(path: string): string {
  const idx = path.lastIndexOf("/");
  return idx > 0 ? path.slice(0, idx) : "/";
}
GlobalConfigExplorer function · typescript · L226-L395 (170 LOC)
src/components/SettingsPanel.tsx
export function GlobalConfigExplorer() {
  const activeWorkspaceId = useWorkspaceStore((s) => s.activeWorkspaceId);
  const openFile = useWorkspaceStore((s) => s.openFile);

  const [claudeDir, setClaudeDir] = useState<string | null>(null);
  const [loaded, setLoaded] = useState(false);
  const [entries, setEntries] = useState<FileEntry[]>([]);
  const [expandedFolders, setExpandedFolders] = useState<Set<string>>(new Set());
  const [newItem, setNewItem] = useState<{
    parentPath: string;
    kind: "file" | "dir";
  } | null>(null);

  // Resolve ~/.claude/ directory on mount
  useEffect(() => {
    let cancelled = false;
    invoke<ConfigFile[]>("list_claude_configs", { workspacePath: null })
      .then((files) => {
        if (cancelled) return;
        const global = files.find(
          (f) => f.file_type === "claude-md" && f.path.endsWith("/.claude/CLAUDE.md"),
        );
        const dir = global ? dirname(global.path) : null;
        setClaudeDir(dir);
        if (dir) {
  
Repobility's GitHub App fixes findings like these · https://github.com/apps/repobility-bot
getDisplayState function · typescript · L25-L87 (63 LOC)
src/components/ShipStatusPill.tsx
function getDisplayState(session: ShipSession, livePrUrl: string | null) {
  const hasSignal = !!session.signal;
  const isManualReview = hasSignal && session.signal!.verdict === "manual_review";
  const isAutoMerge = hasSignal && session.signal!.verdict === "auto_merge";
  const hasError = session.exited && session.exitCode !== null && session.exitCode !== 0;
  const isFinishing = session.exited && !hasSignal && !hasError;

  if (isManualReview) {
    return {
      title: `Review Needed — PR #${session.signal!.pr_number}`,
      subtitle: session.signal!.summary || "Manual review required",
      extra: session.signal!.flagged_items?.length
        ? `${session.signal!.flagged_items.length} flagged item${session.signal!.flagged_items.length !== 1 ? "s" : ""}`
        : null,
      accentColor: "#f59e0b",
      titleColor: "#e8b930",
      prUrl: session.signal!.pr_url,
    };
  }
  if (isAutoMerge) {
    return {
      title: `Merging PR #${session.signal!.pr_number}`,
      subtitle
ShipStatusPill function · typescript · L89-L214 (126 LOC)
src/components/ShipStatusPill.tsx
export function ShipStatusPill() {
  const session = useWorkspaceStore((s) => s.shipSession);
  const activeWorkspaceId = useWorkspaceStore((s) => s.activeWorkspaceId);
  const prStatuses = useWorkspaceStore((s) => s.prStatuses);
  const dismissShipSession = useWorkspaceStore((s) => s.dismissShipSession);
  const dockShipSession = useWorkspaceStore((s) => s.dockShipSession);
  const [expanded, setExpanded] = useState(false);
  const panelRef = useRef<HTMLDivElement>(null);

  // Close on outside click when expanded
  useEffect(() => {
    if (!expanded) return;
    function handleClick(e: MouseEvent) {
      if (panelRef.current && !panelRef.current.contains(e.target as Node)) {
        setExpanded(false);
      }
    }
    const timer = setTimeout(() => {
      document.addEventListener("mousedown", handleClick);
    }, 50);
    return () => {
      clearTimeout(timer);
      document.removeEventListener("mousedown", handleClick);
    };
  }, [expanded]);

  if (!session) return null;
handleClick function · typescript · L101-L105 (5 LOC)
src/components/ShipStatusPill.tsx
    function handleClick(e: MouseEvent) {
      if (panelRef.current && !panelRef.current.contains(e.target as Node)) {
        setExpanded(false);
      }
    }
‹ prevpage 3 / 10next ›