mezame 0.8.42

An ACP client that bridges a local agent (Kiro CLI, Claude Agent CLI, Gemini CLI, Codex, ...) to a browser UI over WebSockets.
import { FolderIcon } from 'lucide-react';
import { useEffect, useRef, useState } from 'react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { mezameActions } from '@/hooks/useMezame';
import { cn } from '@/lib/utils';
import type { Session } from '@/types';

// Shows the session's working directory next to the mode/model pickers
// and lets the user spawn a sibling session pointed at a different
// path. Intentionally does NOT try to rebind the current session: ACP
// has no `session/set_cwd`, so changing cwd after `session/new` means
// starting a new session. We do that in a new tab so the existing log
// stays intact.
//
// Double-click (or Enter on focus) swaps the chip for an inline input
// preseeded with the current cwd. Commit spawns a new tab via
// mezameActions.newSession(cwd). Escape cancels.

type Props = {
  session: Session | null;
};

const SERVER_DEFAULT = 'server default';

// Middle-ellipsis for long paths so both the parent and leaf stay
// visible: `/Users/stefan/.../repos/mezame`.
const truncateMiddle = (value: string, max: number) => {
  if (value.length <= max) {
    return value;
  }
  const keep = Math.floor((max - 3) / 2);
  return `${value.slice(0, keep)}...${value.slice(-keep)}`;
};

const triggerClass = cn(
  'h-7 gap-1.5 rounded-md border border-border bg-card px-2 text-[11px] text-foreground',
  'hover:text-foreground hover:bg-accent',
  'data-[state=open]:bg-accent data-[state=open]:text-foreground'
);

export const CwdChip = ({ session }: Props) => {
  const [editing, setEditing] = useState(false);
  const [draft, setDraft] = useState('');
  const inputRef = useRef<HTMLInputElement>(null);

  useEffect(() => {
    if (editing) {
      inputRef.current?.focus();
      inputRef.current?.select();
    }
  }, [editing]);

  if (!session) {
    return null;
  }

  // Prefer the server-reported cwd (actual path the agent session opened
  // at). Fall back to the user-supplied override, and finally to empty
  // while the session is still connecting.
  const cwd = session.effectiveCwd ?? session.cwd ?? '';
  const display = cwd.length > 0 ? truncateMiddle(cwd, 48) : SERVER_DEFAULT;

  const startEdit = () => {
    setDraft(cwd);
    setEditing(true);
  };

  const cancel = () => {
    setEditing(false);
    setDraft('');
  };

  const commit = () => {
    const next = draft.trim();
    if (next.length === 0 || next === cwd) {
      cancel();
      return;
    }
    // Spawn a sibling tab. The store places new tabs leftmost and
    // activates them automatically.
    mezameActions.newSession(next);
    cancel();
  };
  if (editing) {
    return (
      <Input
        ref={inputRef}
        value={draft}
        onChange={(e) => setDraft(e.target.value)}
        onKeyDown={(e) => {
          if (e.key === 'Enter') {
            e.preventDefault();
            commit();
          } else if (e.key === 'Escape') {
            e.preventDefault();
            cancel();
          }
        }}
        onBlur={cancel}
        placeholder="/absolute/path"
        className="h-7 w-[22rem] max-w-[60vw] bg-card px-2 text-base md:text-[11px]"
        spellCheck={false}
        autoCapitalize="off"
        autoCorrect="off"
      />
    );
  }

  return (
    <Tooltip>
      <TooltipTrigger asChild>
        <Button
          type="button"
          variant="ghost"
          size="sm"
          onDoubleClick={startEdit}
          onKeyDown={(e) => {
            if (e.key === 'Enter' || e.key === ' ') {
              e.preventDefault();
              startEdit();
            }
          }}
          className={cn(triggerClass, 'max-w-[60vw]')}
          aria-label="Working directory (double-click to open a new session elsewhere)"
        >
          <FolderIcon className="size-3 shrink-0 text-[color:var(--primary)]" />
          <span className="truncate">{display}</span>
        </Button>
      </TooltipTrigger>
      <TooltipContent side="top" className="max-w-[60ch]">
        <div className="font-mono text-[11px]">{cwd || SERVER_DEFAULT}</div>
        <div className="text-[10px] text-muted-foreground">
          Double-click to open a new session in a different directory
        </div>
      </TooltipContent>
    </Tooltip>
  );
};