trusty-analyze 0.2.0

Sidecar code-analysis daemon for trusty-search: complexity, smells, quality, facts
Documentation
<script>
  /*
   * Why: K-means concept clusters give a high-level "what is this codebase
   * about?" map; rendering each cluster as a card with its top centroid terms
   * is the most compact way to scan the conceptual landscape.
   * What: Card grid — one card per cluster — showing label, centroid term
   * chips, and chunk count. Method (bow|neural) and k are user-controllable.
   * Test: Select an index that has chunks; expect at least 1 card with terms.
   */
  import { onMount } from 'svelte';
  import {
    getSelectedIndex,
    getClusters,
    refreshClusters
  } from '../state.svelte.js';

  let selected = $derived(getSelectedIndex());
  let clusters = $derived(getClusters());
  let k = $state(8);
  let method = $state('bow');

  $effect(() => {
    if (!selected) return;
    refreshClusters(selected, { k, method }).catch(() => {});
  });

  onMount(() => {
    if (selected) refreshClusters(selected, { k, method }).catch(() => {});
  });
</script>

<h1 class="page-title">Concept Clusters</h1>

{#if !selected}
  <div class="card"><div class="empty">Select an index in the top bar.</div></div>
{:else}
  <div class="filter-bar">
    <label class="text-xs text-muted">
      k
      <input class="input" type="number" min="2" max="32" bind:value={k} style="margin-left: 8px; width: 90px" />
    </label>
    <label class="text-xs text-muted">
      Method
      <select class="select" bind:value={method} style="margin-left: 8px; width: 120px">
        <option value="bow">bow</option>
        <option value="neural">neural</option>
      </select>
    </label>
  </div>

  {#if clusters.length === 0}
    <div class="card"><div class="empty">Loading clusters…</div></div>
  {:else}
    <div class="cluster-grid">
      {#each clusters as c, i}
        <div class="cluster-card">
          <div class="cl-head">
            <span class="cl-num">#{i + 1}</span>
            <strong class="cl-label">{c.label || `cluster ${i + 1}`}</strong>
          </div>
          <div class="cl-chunks text-xs text-muted">
            {(c.chunk_ids?.length ?? c.size ?? 0)} chunks
          </div>
          {#if c.centroid_terms?.length}
            <div class="cl-terms">
              {#each c.centroid_terms.slice(0, 12) as t}
                <span class="tag">{typeof t === 'string' ? t : (t.term || t.token || '?')}</span>
              {/each}
            </div>
          {/if}
        </div>
      {/each}
    </div>
  {/if}
{/if}

<style>
  .page-title {
    font-size: var(--trusty-fs-xl);
    margin: 0 0 var(--trusty-space-5) 0;
    font-weight: 600;
  }
  .filter-bar {
    display: flex;
    gap: var(--trusty-space-4);
    align-items: center;
    margin-bottom: var(--trusty-space-4);
  }
  .cluster-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: var(--trusty-space-4);
  }
  .cluster-card {
    background: var(--trusty-card-bg);
    border: 1px solid var(--trusty-border);
    border-radius: var(--trusty-radius);
    padding: var(--trusty-space-4);
    box-shadow: var(--trusty-shadow-sm);
    display: flex;
    flex-direction: column;
    gap: var(--trusty-space-3);
  }
  .cl-head {
    display: flex;
    align-items: baseline;
    gap: 8px;
  }
  .cl-num {
    font-family: var(--trusty-mono);
    color: var(--trusty-text-muted);
    font-size: var(--trusty-fs-xs);
  }
  .cl-label {
    font-size: var(--trusty-fs-md);
  }
  .cl-terms {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
  }
  .cl-terms .tag {
    margin: 0;
    padding: 3px 8px;
    background: var(--trusty-accent-soft);
    color: var(--trusty-accent);
    border-radius: 999px;
  }
</style>