confer-cli 0.8.5

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">
  // File-type icon for a code-file row — extension → curated Material-subset
  // icon (icons.ts's `ft` table), with a short filename-override map for
  // names whose type isn't decidable from the extension alone (or that have
  // none), and a Lucide `file` fallback (tinted `--muted`) for anything
  // unmapped. design/43 Thread 3: never a whole-set import, hand-picked only.
  import Icon from './Icon.svelte';

  interface Props {
    /** Full path or bare filename — only the basename/extension matter. */
    path: string;
    size?: number;
  }

  let { path, size = 15 }: Props = $props();

  const EXT_MAP: Record<string, string> = {
    rs: 'rust',
    ts: 'typescript',
    mts: 'typescript',
    cts: 'typescript',
    tsx: 'react',
    jsx: 'react',
    js: 'javascript',
    mjs: 'javascript',
    cjs: 'javascript',
    svelte: 'svelte',
    py: 'python',
    swift: 'swift',
    go: 'go',
    md: 'markdown',
    mdx: 'markdown',
    json: 'json',
    toml: 'toml',
    yaml: 'yaml',
    yml: 'yaml',
    css: 'css',
    scss: 'css',
    html: 'html',
    htm: 'html',
    sh: 'shell',
    bash: 'shell',
    zsh: 'shell',
    sql: 'sql',
    rb: 'ruby',
    c: 'c',
    h: 'c',
    cpp: 'cpp',
    cc: 'cpp',
    cxx: 'cpp',
    hpp: 'cpp',
    java: 'java',
    png: 'image',
    jpg: 'image',
    jpeg: 'image',
    gif: 'image',
    svg: 'image',
    webp: 'image',
    lock: 'lock',
  };

  // Filenames the extension map gets wrong or that have no extension at all.
  const NAME_MAP: Record<string, string> = {
    'package.json': 'json',
    'package-lock.json': 'lock',
    'cargo.lock': 'lock',
    'pnpm-lock.yaml': 'lock',
    dockerfile: 'settings',
    makefile: 'settings',
    '.gitignore': 'settings',
  };

  function basename(p: string): string {
    return p.split('/').pop() || p;
  }

  const iconName = $derived.by((): string | null => {
    const name = basename(path).toLowerCase();
    if (NAME_MAP[name]) return NAME_MAP[name];
    const dot = name.lastIndexOf('.');
    const ext = dot > 0 ? name.slice(dot + 1) : '';
    return (ext && EXT_MAP[ext]) || null;
  });
</script>

{#if iconName}
  <Icon name={iconName} {size} />
{:else}
  <Icon name="file" {size} class="unmapped-icon" />
{/if}

<style>
  :global(.unmapped-icon) {
    color: var(--muted);
  }
</style>