wsb-daemon 0.275.7622

wsb's daemon: the workbench, the GitHub mirror's schedule and peer continuity, for every workspace on the machine
<script lang="ts">
  // The record of working: the machine's agent sessions, starting at the ones
  // that ran in this worktree and widening to its project or to all of them,
  // with plan documents — session by-products — as a collapsible section
  // beneath them rather than a container of their own.
  import SessionList from "./SessionList.svelte";
  import PlansSidebar from "./panels/PlansSidebar.svelte";
  import { workbench } from "../../stores/workbench.svelte.js";
  import { sync } from "../../stores/sync.svelte.js";
  import SidebarHeader from "./SidebarHeader.svelte";
  import AppIcon from "../layout/AppIcon.svelte";

  let plansOpen = $state(false);

  /** The stream-backed sync expressed as the promise the shared header owns. */
  function refreshSessions(): Promise<void> {
    return new Promise<void>((resolve, reject) => {
      const started = sync.triggerSync(resolve, reject);
      // The header is already disabled while `sync.syncing`; this only covers
      // a sync started between the click and this callback running.
      if (!started) resolve();
    });
  }
</script>

<div class="sessions-panel">
  <!--
    The same bar every other panel wears. Sessions had none: its one action —
    re-reading the transcripts — sat inside the list's filter row, which is
    the only place in the workbench that put a refresh anywhere but the top.
  -->
  <SidebarHeader
    title="Sessions"
    onrefresh={refreshSessions}
    refreshing={sync.syncing}
    refreshTitle="Sync sessions (r)"
  >
    {#snippet actions()}
      <!--
        The statistics open in the content view. They were on the welcome page —
        four charts, a heatmap and a filter bar — which made the first thing
        anyone saw a study rather than a glance. They belong to sessions, so the
        way in is here, in the bar every panel puts its actions in.
      -->
      <button
        class="panel-action-btn"
        title="Session statistics — activity, heatmaps, top sessions"
        aria-label="Session statistics"
        onclick={() => workbench.openSessionStatistics()}
      >
        <AppIcon name="chart" size={14} />
      </button>
    {/snippet}
  </SidebarHeader>

  <div class="sessions-slot">
    <SessionList />
  </div>
  <div class="plans-section" class:open={plansOpen}>
    <button
      class="plans-toggle"
      onclick={() => (plansOpen = !plansOpen)}
      aria-expanded={plansOpen}
    >
      <span class="plans-caret"><AppIcon name={plansOpen ? "chevron-down" : "chevron-right"} size={11} /></span>
      Plans
    </button>
    {#if plansOpen}
      <div class="plans-body">
        <PlansSidebar />
      </div>
    {/if}
  </div>
</div>

<style>
  .sessions-panel {
    display: flex;
    flex-direction: column;
    min-height: 0;
    height: 100%;
  }

  .sessions-slot {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }

  .plans-section {
    flex-shrink: 0;
    border-top: 1px solid var(--vscode-panel-border);
  }

  .plans-section.open {
    max-height: 40%;
    display: flex;
    flex-direction: column;
  }

  .plans-toggle {
    display: flex;
    align-items: center;
    gap: var(--wb-spacing-6);
    width: 100%;
    text-align: left;
    padding: var(--wb-spacing-6) var(--wb-spacing-12);
    font-size: var(--wb-font-size-11);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    opacity: 0.7;
    color: inherit;
    background: none;
    border: none;
    cursor: pointer;
  }

  .plans-toggle:hover {
    opacity: 1;
  }

  .plans-caret {
    font-size: var(--wb-font-size-9);
  }

  .plans-body {
    min-height: 0;
    overflow-y: auto;
  }
</style>