johnandersen777.bsky.social/knotless
git that lives in your Atmosphere account
Forked from chadtmiller.com/knotless
0
0
<script lang="ts">
import { onMount } from 'svelte';
/** A conversation with an agent connected to knotless-mcp, played as it would happen: what you ask typed out, each tool call running then done, the answer streamed a word at a time. */
type Line = { you: string } | { says: string } | { tool: string; detail: string };
const lines: Line[] = [
{
you: 'Put this project on knotless as you.bsky.social/tally, and open an issue for each TODO in the README.'
},
{ tool: 'create_repo', detail: 'you.bsky.social/tally' },
{ tool: 'commit', detail: 'main · 14 files' },
{ tool: 'open_issue', detail: 'Dates in ISO 8601 are read as text' },
{ tool: 'open_issue', detail: 'Totals round each line, not the sum' },
{ says: 'tally is up, with two issues from the README’s TODOs.' },
{ you: 'Fix the dates one and open a pull for it.' },
{ tool: 'create_branch', detail: 'fix/iso-dates' },
{ tool: 'commit', detail: 'fix/iso-dates · src/parse.rs, tests/dates.rs' },
{ tool: 'open_pull', detail: 'Read ISO 8601 dates, fixes the dates issue' },
{ tool: 'checks', detail: 'check passed · test passed' },
{ says: 'The pull is open and its checks pass. It closes the issue when it merges.' },
{ you: 'bob.bsky.social reviewed it. Anything to change?' },
{ tool: 'show_item', detail: '1 comment from bob.bsky.social' },
{ tool: 'commit', detail: 'fix/iso-dates · src/parse.rs' },
{ tool: 'comment', detail: 'Kept the UTC offset, as you asked.' },
{ tool: 'merge', detail: 'queued' },
{
says: 'Bob asked to keep the UTC offset, so I did, told him, and queued the pull: it lands once its batch passes.'
}
];
// How long each beat takes, in ms: a key typed, a pause before sending,
// the agent thinking, a tool call running, a word of its answer, and a
// pause to read it before the next request.
const KEY = 38;
const SEND = 600;
const THINK = 1100;
const CALL = 900;
const WORD = 90;
const READ = 2200;
// Lines before `at` are done, after it not yet shown; `part` is how far
// into it: characters typed, words said, or 1 once a tool call is done.
// Drawn finished until it plays, as it is without script or motion.
let at = $state(lines.length);
let part = $state(0);
let thinking = $state(false);
let run = 0;
let box = $state<HTMLElement>();
const words = (s: string) => s.split(' ');
const wait = (ms: number, mine: number) =>
new Promise<boolean>((done) => setTimeout(() => done(mine === run), ms));
async function play() {
const mine = ++run;
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
at = i;
part = 0;
if ('you' in line) {
for (let c = 1; c <= line.you.length; c++) {
part = c;
if (!(await wait(KEY, mine))) return;
}
if (!(await wait(SEND, mine))) return;
} else {
if (!('tool' in lines[i - 1])) {
thinking = true;
if (!(await wait(THINK, mine))) return;
thinking = false;
}
if ('tool' in line) {
if (!(await wait(CALL, mine))) return;
part = 1;
} else {
for (let w = 1; w <= words(line.says).length; w++) {
part = w;
if (!(await wait(WORD, mine))) return;
}
if (i < lines.length - 1 && !(await wait(READ, mine))) return;
}
}
}
at = lines.length;
}
onMount(() => {
// A browser driven by a test, as the shots are, sees it finished.
if (navigator.webdriver || matchMedia('(prefers-reduced-motion: reduce)').matches) return;
at = -1;
const seen = new IntersectionObserver(
([e]) => {
if (!e.isIntersecting) return;
seen.disconnect();
play();
},
{ threshold: 0.3 }
);
if (box) seen.observe(box);
return () => {
seen.disconnect();
run++;
};
});
</script>
<figure class="agent-chat" bind:this={box}>
<ol aria-live="off">
{#each lines as line, i (i)}
{@const now = i === at && !thinking}
{@const hidden = i > at || (i === at && thinking)}
{#if 'you' in line}
<li class="you" class:hidden>
<span class="who">You: </span>{#if now}<span>{line.you.slice(0, part)}</span><span
class="rest">{line.you.slice(part)}</span
>{:else}{line.you}{/if}
</li>
{:else if 'says' in line}
<li class="says" class:hidden>
{#if i === at && thinking}<span class="dots" aria-label="Thinking"
><i></i><i></i><i></i></span
>{/if}<span class="who">Claude: </span>{#if now}<span
>{words(line.says).slice(0, part).join(' ')}</span
><span class="rest">
{words(line.says).slice(part).join(' ')}</span
>{:else}{line.says}{/if}
</li>
{:else}
<li class="tool" class:hidden class:running={now && part === 0}>
{#if i === at && thinking}<span class="dots" aria-label="Thinking"
><i></i><i></i><i></i></span
>{/if}<b class="mark"></b><code>{line.tool}</code><span>{line.detail}</span>
</li>
{/if}
{/each}
</ol>
<figcaption>
Claude Code with knotless-mcp <button class="btn" type="button" onclick={play}
>Play again</button
>
</figcaption>
</figure>