confer-cli 0.8.9

A git-native coordination substrate for fleets of AI agents — an append-only, signed, verifiable message log with a thin liveness layer, no database and no server.
<script lang="ts">
  // Shared click-to-copy affordance for the bare `msg_…`/`req_…` id — used
  // on Message's header, TicketRow, TicketFullPopover's header,
  // and MetaThread's `.gid` line (design/41 Phase 0, §4 "copy-id cluster").
  //
  // Hidden by default (opacity: 0) so it doesn't visually compete with the
  // rest of the row; each HOST component reveals it on the row's own
  // `:hover`/`:focus-within` via `:global(.copy-id-btn)` in ITS OWN scoped
  // style (Svelte scoped CSS can't reach into a child component's markup
  // otherwise). `(hover: none)` below (touch/no-pointer devices) always
  // shows it, per design/41.
  import Icon from './Icon.svelte';
  import { copyToClipboard } from '../clipboard';

  interface Props {
    /** The bare id to copy — e.g. `msg_a1b2` or `req_c3d4`. */
    id: string;
    /** Extra classes for host-specific placement/sizing. */
    class?: string;
  }

  let { id, class: klass = '' }: Props = $props();

  let copied = $state(false);
  let resetTimer: ReturnType<typeof setTimeout> | undefined;

  async function handleClick(e: MouseEvent) {
    // This button is nearly always nested inside a clickable row (a note,
    // board row, meta-thread node) — never let the copy action ALSO fire
    // the row's own onclick (select/navigate).
    e.stopPropagation();
    const ok = await copyToClipboard(id);
    if (!ok) return;
    copied = true;
    clearTimeout(resetTimer);
    resetTimer = setTimeout(() => {
      copied = false;
    }, 1200);
  }
</script>

<button
  type="button"
  class="copy-id-btn {klass}"
  class:copied
  onclick={handleClick}
  aria-label={copied ? `Copied ${id}` : `Copy id ${id}`}
  title={id}
  data-testid="copy-id-btn"
>
  <Icon name={copied ? 'check' : 'copy'} size={12} />
</button>

<style>
  .copy-id-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 20px;
    height: 20px;
    padding: 0;
    border: 1px solid var(--border-2);
    border-radius: 5px;
    background: var(--panel-2);
    color: var(--muted);
    cursor: pointer;
    opacity: 0;
    transition:
      opacity 0.12s ease,
      color 0.12s ease,
      border-color 0.12s ease,
      background 0.12s ease;
  }
  .copy-id-btn:hover,
  .copy-id-btn:focus-visible {
    opacity: 1;
    color: var(--text);
    border-color: var(--accent);
    background: var(--panel-3);
  }
  .copy-id-btn.copied {
    opacity: 1;
    color: var(--done);
    border-color: var(--done);
  }
  /* Touch/no-hover devices (design/41: "always-visible (touch)") — there is
     no hover state to reveal it via, so it must default to visible. */
  @media (hover: none) {
    .copy-id-btn {
      opacity: 1;
    }
  }
</style>