~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/knotless

git that lives in your Atmosphere account

knotless.dev
1 collaborator

knotless 0.13.0 Latest 2 packages, 1 image

1
10

A promo of what someone can do with knotless, filmed on the pages

Open chadtmiller.com wants to merge into main from chadtmiller.com/knotless:marketing/promo
marketing/video/change/sample.jsondeleted+0−310
@@ -1,310 +0,0 @@
{
"host": "knotless.dev",
"repo": "chadtmiller.com/knotless",
"pull": {
"uri": "at://did:plc:bcgltzqazw5tb6k2g3ttenbj/dev.knotless.pull/3mzth2v6xpbk7",
"url": "https://knotless.dev/chadtmiller.com/knotless/pull/did:plc:bcgltzqazw5tb6k2g3ttenbj/3mzth2v6xpbk7",
"title": "A profile's private repositories show their pushes to those who may read them",
"author": "chadtmiller.com",
"branch": "serve/private-activity",
"base": "main",
"opened": "2026-11-08T22:20:45.478Z",
"state": "merged"
},
"diff": {
"files": [
{
"path": "crates/knotless-serve/src/lib.rs",
"added": 4,
"removed": 4
},
{
"path": "crates/knotless-serve/src/web/actor.rs",
"added": 30,
"removed": 3
},
{
"path": "crates/knotless-serve/tests/gateway.rs",
"added": 16,
"removed": 9
},
{
"path": "docs/design/access.md",
"added": 1,
"removed": 1
},
{
"path": "docs/reference/api.md",
"added": 5,
"removed": 1
},
{
"path": "lexicons/dev/knotless/getActorActivity.json",
"added": 1,
"removed": 1
}
],
"excerpt": {
"path": "crates/knotless-serve/src/web/actor.rs",
"lines": [
{
"mark": " ",
"n": 373,
"text": "}"
},
{
"mark": " ",
"n": 374,
"text": ""
},
{
"mark": "+",
"n": 375,
"text": "/// The pushes to `did`'s private repositories that `viewer` may read"
},
{
"mark": "+",
"n": 376,
"text": "/// ([`private_of`]), as this server's index of their spaces counts them."
},
{
"mark": "+",
"n": 377,
"text": "fn private_pushes("
},
{
"mark": "+",
"n": 378,
"text": " app: &Arc<App>,"
},
{
"mark": "+",
"n": 379,
"text": " did: &str,"
},
{
"mark": "+",
"n": 380,
"text": " viewer: Option<String>,"
},
{
"mark": "+",
"n": 381,
"text": " since: Option<&str>,"
},
{
"mark": "+",
"n": 382,
"text": " tz: &str,"
},
{
"mark": "+",
"n": 383,
"text": ") -> rusqlite::Result<Vec<crate::index::RepoPushes>> {"
},
{
"mark": "+",
"n": 384,
"text": " let shown = private_of(app, did, viewer).unwrap_or_default();"
},
{
"mark": "+",
"n": 385,
"text": " let names: HashSet<String> = shown.into_iter().map(|(name, _, _)| name).collect();"
},
{
"mark": "+",
"n": 386,
"text": " let Some(index) = app.spaces.as_ref().filter(|_| !names.is_empty()) else {"
}
]
}
},
"pushes": [
{
"commit": "65f5493b372769d9b5c4b6d07d4038af49109cda",
"at": "2026-11-08T22:20:52.622Z",
"checks": [
{
"workflow": "docs",
"status": "success",
"skipped": false,
"started": "2026-11-08T22:20:52.622Z",
"finished": "2026-11-08T22:21:08.682Z"
},
{
"workflow": "check",
"status": "success",
"skipped": false,
"started": "2026-11-08T22:20:52.941Z",
"finished": "2026-11-08T22:21:15.894Z"
},
{
"workflow": "web",
"status": "success",
"skipped": false,
"started": "2026-11-08T22:20:52.931Z",
"finished": "2026-11-08T22:21:15.955Z"
},
{
"workflow": "lexicons",
"status": "success",
"skipped": false,
"started": "2026-11-08T22:21:14.293Z",
"finished": "2026-11-08T22:21:23.684Z"
},
{
"workflow": "ios",
"status": "success",
"skipped": false,
"started": "2026-11-08T22:21:13.329Z",
"finished": "2026-11-08T22:22:16.371Z"
},
{
"workflow": "shots",
"status": "success",
"skipped": false,
"started": "2026-11-08T22:21:22.499Z",
"finished": "2026-11-08T22:22:16.685Z"
},
{
"workflow": "e2e",
"status": "success",
"skipped": false,
"started": "2026-11-08T22:20:52.623Z",
"finished": "2026-11-08T22:25:49.817Z"
},
{
"workflow": "test",
"status": "success",
"skipped": false,
"started": "2026-11-08T22:22:13.073Z",
"finished": "2026-11-08T22:29:08.956Z"
}
]
},
{
"commit": "d5a939294d78ef674a3ed1f988b34129feea48b3",
"at": "2026-11-08T22:29:14.102Z",
"checks": [
{
"workflow": "docs",
"status": "success",
"skipped": false,
"started": "2026-11-08T22:29:14.102Z",
"finished": "2026-11-08T22:29:25.385Z"
},
{
"workflow": "check",
"status": "success",
"skipped": false,
"started": "2026-11-08T22:29:14.417Z",
"finished": "2026-11-08T22:29:33.042Z"
},
{
"workflow": "lexicons",
"status": "success",
"skipped": false,
"started": "2026-11-08T22:29:31.445Z",
"finished": "2026-11-08T22:29:35.737Z"
},
{
"workflow": "ios",
"status": "success",
"skipped": false,
"started": "2026-11-08T22:29:23.795Z",
"finished": "2026-11-08T22:30:05.990Z"
},
{
"workflow": "shots",
"status": "success",
"skipped": false,
"started": "2026-11-08T22:29:35.268Z",
"finished": "2026-11-08T22:30:12.063Z"
},
{
"workflow": "web",
"status": "success",
"skipped": false,
"started": "2026-11-08T22:30:10.093Z",
"finished": "2026-11-08T22:30:38.109Z"
},
{
"workflow": "e2e",
"status": "success",
"skipped": false,
"started": "2026-11-08T22:29:14.102Z",
"finished": "2026-11-08T22:33:25.681Z"
},
{
"workflow": "test",
"status": "success",
"skipped": false,
"started": "2026-11-08T22:30:03.015Z",
"finished": "2026-11-08T22:37:10.101Z"
}
]
}
],
"reviews": [
{
"by": "review.knotless.dev",
"verdict": "changes",
"at": "2026-11-08T22:22:05.245Z",
"commit": "65f5493b372769d9b5c4b6d07d4038af49109cda",
"said": "The activity change is sound. getActorActivity now sits behind the viewer middleware and adds only the private repositories private_of allows. The new test covers the member, no one, and an outsider.",
"line": {
"path": ".knotless/workflows/deploy.yml",
"line": 104,
"said": "Dropping chadtmiller.com/group-host here depends on an invite that was never left for the existing share."
}
},
{
"by": "review.knotless.dev",
"verdict": "approve",
"at": "2026-11-08T22:29:30.940Z",
"commit": "d5a939294d78ef674a3ed1f988b34129feea48b3",
"said": "The unrelated commit is gone. pull_diff now shows only the activity change, with the matching docs and lexicon text, so the title and body describe the pull.",
"line": null
}
],
"queued": "2026-11-08T22:37:24.182Z",
"landed": {
"commit": "9382c0bbb9f6ad694a8a39deaffc2ebc706c6ac5",
"at": "2026-11-08T22:37:31Z",
"batch": true
},
"deploy": {
"workflow": "deploy",
"status": "success",
"started": "2026-11-08T22:38:12.898Z",
"finished": "2026-11-08T22:46:23.896Z",
"steps": [
{
"name": "tools",
"ms": 1139,
"status": "success"
},
{
"name": "build",
"ms": 433042,
"status": "success"
},
{
"name": "deploy",
"ms": 40955,
"status": "success"
},
{
"name": "image",
"ms": 4894,
"status": "success"
},
{
"name": "runner host",
"ms": 6291,
"status": "success"
}
]
}
}
marketing/video/change/story.mjsdeleted+0−276
@@ -1,276 +0,0 @@
// A pull's way from its first push to the deploy that shipped it, read
// from the appview through `knotless-mcp --read-only`, as the Change video
// tells it: each push and its checks, each review, the queue, the commit it
// landed as and the deploy of that commit. Written to out/stories/<rkey>.json.
//
// node change/story.mjs https://knotless.dev/<handle>/<name>/pull/<did>/<rkey>
// node change/story.mjs <handle>/<name> <pull at-uri> [--deploy <workflow>]
//
// Nothing here is made up: a stage the pull never reached (unreviewed, merged
// by hand, never deployed) is left out, and the video skips it.
import { spawn } from 'node:child_process';
import { mkdirSync, writeFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
const root = join(dirname(fileURLToPath(import.meta.url)), '..');
const host = new URL(process.env.KNOTLESS_APPVIEW || 'https://knotless.dev').host;
const args = process.argv.slice(2);
const flag = (name, otherwise) => {
const i = args.indexOf(name);
if (i < 0) return otherwise;
const [, value] = args.splice(i, 2);
return value;
};
const deployWorkflow = flag('--deploy', 'deploy');
const [repo, uri] = (() => {
if (args[0]?.startsWith('http')) {
const [handle, name, kind, did, rkey] = new URL(args[0]).pathname.split('/').filter(Boolean);
if (kind !== 'pull') throw new Error(`not a pull's page: ${args[0]}`);
return [`${handle}/${name}`, `at://${did}/dev.knotless.pull/${rkey}`];
}
if (args.length !== 2) {
console.error('usage: story.mjs <pull page url> | <handle>/<name> <pull at-uri>');
process.exit(2);
}
return args;
})();
/// The tools of a read-only knotless-mcp, called in turn over its stdio.
const mcp = () => {
const child = spawn('knotless-mcp', ['--read-only'], { stdio: ['pipe', 'pipe', 'inherit'] });
const waiting = new Map();
let id = 0;
let buf = '';
child.stdout.on('data', (d) => {
buf += d;
for (let i = buf.indexOf('\n'); i >= 0; i = buf.indexOf('\n')) {
const line = buf.slice(0, i);
buf = buf.slice(i + 1);
if (!line.trim()) continue;
const m = JSON.parse(line);
waiting.get(m.id)?.(m);
waiting.delete(m.id);
}
});
const ask = (method, params) =>
new Promise((resolve, reject) => {
const n = ++id;
waiting.set(n, (m) => (m.error ? reject(new Error(m.error.message)) : resolve(m.result)));
child.stdin.write(`${JSON.stringify({ jsonrpc: '2.0', id: n, method, params })}\n`);
});
const ready = ask('initialize', {
protocolVersion: '2025-06-18',
capabilities: {},
clientInfo: { name: 'knotless-video', version: '0' }
}).then(() =>
child.stdin.write(
`${JSON.stringify({ jsonrpc: '2.0', method: 'notifications/initialized' })}\n`
)
);
return {
/// The tool's text, as JSON when `json`.
call: async (name, args, json = true) => {
await ready;
const r = await ask('tools/call', { name, arguments: args });
const text = r.content.find((c) => c.type === 'text')?.text ?? '';
if (r.isError) throw new Error(`${name}: ${text}`);
return json ? JSON.parse(text) : text;
},
close: () => child.kill()
};
};
/// The diff's files, each with its lines, from pull_diff's numbered form:
/// `old new | ±text` under each `diff --git` and `@@` head.
const parseDiff = (text) => {
const files = [];
let file;
let hunk;
for (const line of text.split('\n')) {
if (line.startsWith('diff --git ')) {
file = { path: line.split(' b/').pop(), added: 0, removed: 0, hunks: [] };
files.push(file);
continue;
}
if (!file) continue;
if (line.startsWith('@@')) {
hunk = { head: line, lines: [] };
file.hunks.push(hunk);
continue;
}
const m = /^\s*(\d*)\s+(\d*) \| ([ +-])(.*)$/.exec(line);
if (!m || !hunk) continue;
const [, old, now, mark, body] = m;
if (mark === '+') file.added++;
if (mark === '-') file.removed++;
hunk.lines.push({ mark, n: Number(now || old), text: body });
}
return files;
};
// What a reader of the video learns least from: words about the change,
// rather than the change, and then its tests.
const prose = /(^docs\/|\.md$|^\.changeset\/|CHANGELOG|\.lock$|package-lock\.json$|fixtures)/;
const tests = /(\/tests?\/|_test\.|\.test\.|\.spec\.)/;
/// The stretch of the diff that says most: of the code (not its tests, if
/// it has any other), the hunk adding the most lines, cut to `most` lines
/// from just before its first change.
const excerpt = (files, most = 14) => {
const code = files.filter((f) => !prose.test(f.path));
const source = code.filter((f) => !tests.test(f.path));
const pool = source.length ? source : code.length ? code : files;
const pick = pool
.flatMap((f) => f.hunks.map((h) => ({ path: f.path, h })))
.map((x) => ({ ...x, added: x.h.lines.filter((l) => l.mark === '+').length }))
.sort((a, b) => b.added - a.added)[0];
if (!pick) return null;
const lines = pick.h.lines;
const first = lines.findIndex((l) => l.mark !== ' ');
const start = Math.max(0, Math.min(first - 2, lines.length - most));
return {
path: pick.path,
lines: lines.slice(start, start + most).map((l) => ({
...l,
text: l.text.replace(/\t/g, ' ').trimEnd()
}))
};
};
/// A body's opening sentences, as many whole ones as fit in `most`
/// characters (the first cut short if it alone does not), as plain text.
const firstSaid = (body, most = 200) => {
const plain = body
.replace(/```[\s\S]*?```/g, '')
.replace(/\*\*|`|^#+\s*|^>\s*/gm, '')
.replace(/\s+/g, ' ')
.trim();
const sentences = plain.split(/(?<=[.!?])\s+/);
let said = '';
for (const s of sentences) {
if (`${said} ${s}`.trim().length > most) break;
said = `${said} ${s}`.trim();
}
if (said) return said;
return `${plain.slice(0, most - 1).trimEnd()}…`;
};
const at = (t) => new Date(t).getTime();
const tools = mcp();
try {
const shown = await tools.call('pull_show', { repo, uri });
const pull = shown.item;
const files = parseDiff(await tools.call('pull_diff', { repo, uri }, false));
const runs = await tools.call('run_list', { repo, pull: uri }).catch(() => []);
// A push is the commit the pull's checks ran at, first seen when the first
// of them started; its checks are the latest of each workflow there.
const byCommit = new Map();
for (const r of runs) {
const list = byCommit.get(r.commit) ?? [];
if (!list.some((s) => s.workflow === r.workflow)) list.push(r);
byCommit.set(r.commit, list);
}
const pushes = [...byCommit.entries()]
.map(([commit, checks]) => ({
commit,
at: checks.map((c) => c.startedAt).sort()[0],
checks: checks
.map((c) => ({
workflow: c.workflow,
status: c.status,
skipped: Boolean(c.skipped),
started: c.startedAt,
finished: c.finishedAt ?? null
}))
.sort((a, b) => at(a.finished ?? a.started) - at(b.finished ?? b.started))
}))
.sort((a, b) => at(a.at) - at(b.at));
// Each review, with the first of the line comments it left.
const reviews = shown.comments
.filter((c) => c.verdict)
.map((c) => {
const line = shown.comments.find((l) => l.review === c.uri && l.line);
return {
by: c.handle,
verdict: c.verdict,
at: c.createdAt,
commit: c.commit,
said: firstSaid(c.body),
line: line
? { path: line.line.path, line: line.line.line, said: firstSaid(line.body, 140) }
: null
};
});
// Landed: the commit on the base the merge made, dated when it was made.
const merged = pull.merged ?? null;
const landedCommit = merged && shown.compare?.commits?.find((c) => c.sha === merged);
const landed = merged
? {
commit: merged,
at: landedCommit?.committer?.date ?? null,
batch: Boolean(pull.mergedBatch)
}
: null;
// Deployed: the deploy workflow's run at the landed commit, on the base.
let deploy = null;
if (merged) {
const onBase = await tools
.call('run_list', { repo, ref: pull.base, commit: merged, workflow: deployWorkflow })
.catch(() => []);
const run = onBase[0];
if (run)
deploy = {
workflow: run.workflow,
status: run.status,
started: run.startedAt,
finished: run.finishedAt ?? null,
steps: run.steps
.filter((s) => s.durationMs >= 1000)
.map((s) => ({ name: s.name, ms: s.durationMs, status: s.status }))
};
}
const story = {
host,
repo,
pull: {
uri,
url: `https://${host}/${repo}/pull/${uri.split('/')[2]}/${uri.split('/').pop()}`,
title: pull.title,
author: pull.handle,
branch: pull.head.branch,
base: pull.base,
opened: pull.createdAt,
state: pull.state
},
diff: {
files: files.map(({ path, added, removed }) => ({ path, added, removed })),
excerpt: excerpt(files)
},
pushes,
reviews,
queued: pull.queue?.createdAt ?? null,
landed,
deploy
};
const out = join(root, 'out/stories');
mkdirSync(out, { recursive: true });
const file = join(out, `${uri.split('/').pop()}.json`);
writeFileSync(file, `${JSON.stringify(story, null, 1)}\n`);
const span = deploy?.finished ?? landed?.at ?? pushes.at(-1)?.at;
const minutes = span ? Math.round((at(span) - at(pull.createdAt)) / 60000) : 0;
console.log(
`${file}: ${files.length} files, ${pushes.length} pushes, ${reviews.length} reviews, ` +
`${landed ? 'landed' : 'not landed'}, ${deploy ? 'deployed' : 'no deploy'}; ${minutes} min`
);
} finally {
tools.close();
}
marketing/video/public/sfx/click.wavnew+0−0
A binary file, not shown.
marketing/video/public/sfx/key1.wavnew+0−0
A binary file, not shown.
marketing/video/public/sfx/key2.wavnew+0−0
A binary file, not shown.
marketing/video/public/sfx/key3.wavnew+0−0
A binary file, not shown.
marketing/video/shoot/scenes/agent.mjsnew+103−0
@@ -0,0 +1,103 @@
// alice asks Claude Code for a change, and it makes it over knotless's MCP
// tools as her, from a branch to an open pull, with no checkout. The run
// is real (and costs model usage): its transcript is what the video shows,
// as public/agent/agent.json. Then the pull it opened, on the pages.
import { spawn } from 'node:child_process';
import { mkdirSync, writeFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { environment, root } from '../../../../harness/shots/world.mjs';
import { film } from '../camera.mjs';
import { REPO } from './push.mjs';
const here = join(dirname(fileURLToPath(import.meta.url)), '../..');
export const ASK = `Add an Install section to the README of knotless://alice.test/${REPO} (cargo install --path .) and open a pull for it.`;
/// Claude Code, given only the knotless tools as `who`, doing `ask`: what it
/// said and the tools it called, in order.
async function claude(world, who, ask) {
const dir = join(world.dir, who, 'claude');
mkdirSync(dir, { recursive: true });
const config = join(dir, 'mcp.json');
writeFileSync(
config,
JSON.stringify({
mcpServers: {
knotless: {
type: 'stdio',
command: join(root, 'target/debug/knotless-mcp'),
args: [],
env: environment(world, world.dir, who)
}
}
})
);
const args = [
'-p',
ask,
'--mcp-config',
config,
'--strict-mcp-config',
'--tools',
'',
'--allowedTools',
'mcp__knotless',
'--output-format',
'stream-json',
'--verbose',
'--no-session-persistence',
'--setting-sources',
''
];
const said = [];
const child = spawn('claude', args, { cwd: dir, stdio: ['ignore', 'pipe', 'inherit'] });
let buf = '';
child.stdout.on('data', (d) => {
buf += d;
for (let i = buf.indexOf('\n'); i >= 0; i = buf.indexOf('\n')) {
const line = buf.slice(0, i);
buf = buf.slice(i + 1);
if (!line.trim()) continue;
const m = JSON.parse(line);
if (m.type !== 'assistant') continue;
for (const c of m.message.content ?? []) {
if (c.type === 'text' && c.text.trim()) said.push({ kind: 'text', text: c.text.trim() });
if (c.type === 'tool_use')
said.push({ kind: 'tool', text: c.name.replace(/^mcp__knotless__/, '') });
}
}
});
const code = await new Promise((r) => child.on('close', (c) => r(c ?? 1)));
if (code !== 0) throw new Error(`claude exited ${code}`);
return said;
}
export default {
as: 'alice',
start: () => `/alice.test/${REPO}`,
prepare: async ({ world }) => {
const said = await claude(world, 'alice', ASK);
mkdirSync(join(here, 'public/agent'), { recursive: true });
writeFileSync(
join(here, 'public/agent/agent.json'),
JSON.stringify({ ask: ASK, said }, null, 1)
);
console.log(` agent: ${said.length} steps`);
},
film: async ({ page, world, size, take }) => {
const shot = await film(take, page, size);
try {
await shot.open(`${world.base}/alice.test/${REPO}/pulls`);
await shot.hold(900);
shot.mark('pulls');
await shot.click(page.locator('a[href*="/pull/"]').first());
await page.waitForURL(/\/pull\//);
shot.mark('pull');
await shot.hold(2200);
} finally {
await shot.cut();
}
}
};
marketing/video/shoot/scenes/checks.mjsnew+39−0
@@ -0,0 +1,39 @@
// The pull's checks, as alice's runner reports them while she watches: each
// running, then passing, the page following as each lands. Reported here
// as a runner would, since the world runs no runner.
import { check } from '../act.mjs';
import { film } from '../camera.mjs';
import { REPO } from './push.mjs';
const WORKFLOWS = ['build', 'test', 'lint'];
export default {
as: 'alice',
start: (world, cast) => cast.pull,
film: async ({ page, world, size, take, cast }) => {
const shot = await film(take, page, size);
const report = (workflow, status, started) =>
check(world, 'alice', REPO, 'celsius', cast.tip, workflow, status, started);
try {
await shot.open(world.base + cast.pull);
await shot.hold(800);
const started = new Date().toISOString();
for (const w of WORKFLOWS) await report(w, 'running', started);
const box = page.getByText(/still running/i).first();
await box.waitFor({ timeout: 20_000 });
await shot.reveal(box);
shot.mark('running');
await shot.hold(1500);
for (const w of WORKFLOWS) {
await report(w, 'success', started);
await shot.hold(900);
}
await page.getByText('All checks have passed').waitFor({ timeout: 20_000 });
shot.mark('passed');
await shot.hold(1800);
} finally {
await shot.cut();
}
}
};
marketing/video/shoot/scenes/login.mjsnew+45−0
@@ -0,0 +1,45 @@
// alice comes to her new repository and logs in with the account she
// already has: her handle, then her own PDS's page to sign in and approve.
import { film, ready } from '../camera.mjs';
import { REPO } from './push.mjs';
export default {
as: 'alice',
login: false,
start: () => `/alice.test/${REPO}`,
film: async ({ page, world, size, take }) => {
const alice = world.accounts.find((a) => a.handle === 'alice.test');
const shot = await film(take, page, size);
try {
await shot.open(`${world.base}/alice.test/${REPO}`);
await shot.hold(1200);
shot.mark('repo');
await shot.click(page.getByRole('button', { name: 'Log in' }));
const dialog = page.getByRole('dialog', { name: 'Log in with your Atmosphere account' });
await shot.type(dialog.getByLabel('Handle'), alice.handle, { delay: 70 });
shot.mark('asked');
await shot.click(dialog.getByRole('button', { name: 'Log in' }));
await page.waitForURL((u) => u.origin === new URL(world.pds).origin);
await page.getByRole('textbox', { name: 'Password' }).waitFor();
shot.mark('pds');
await shot.hold(500);
await shot.type(page.getByRole('textbox', { name: 'Password' }), alice.password, {
delay: 45
});
await shot.click(page.getByRole('button', { name: 'Sign in' }));
const yes = page.getByRole('button', { name: /^(accept|authorize|allow)$/i });
await yes.waitFor();
await shot.hold(500);
shot.mark('approve');
await shot.click(yes);
await page.waitForURL((u) => u.pathname === `/alice.test/${REPO}`);
await ready(page);
await page.getByLabel('Your account').waitFor();
shot.mark('in');
await shot.hold(1500);
} finally {
await shot.cut();
}
}
};
marketing/video/shoot/scenes/merge.mjsnew+27−0
@@ -0,0 +1,27 @@
// alice merges her approved pull, its checks passed, from its page.
import { film } from '../camera.mjs';
export default {
as: 'alice',
start: (world, cast) => cast.pull,
film: async ({ page, world, size, take, cast }) => {
const shot = await film(take, page, size);
try {
await shot.open(world.base + cast.pull);
await shot.hold(700);
const box = page.locator('.merge-box');
await box.scrollIntoViewIfNeeded();
await shot.hold(900);
shot.mark('merge');
await shot.click(box.getByRole('button', { name: 'Merge pull' }));
const merged = page.locator('.event', { hasText: 'Merged as' });
await merged.waitFor({ timeout: 30_000 });
await merged.scrollIntoViewIfNeeded();
shot.mark('merged');
await shot.hold(2000);
} finally {
await shot.cut();
}
}
};
marketing/video/shoot/scenes/pull.mjsnew+38−0
@@ -0,0 +1,38 @@
// alice opens a pull of her celsius branch from the repository's pages.
import { film } from '../camera.mjs';
import { REPO } from './push.mjs';
export default {
as: 'alice',
start: () => `/alice.test/${REPO}`,
film: async ({ page, world, size, take, cast }) => {
const shot = await film(take, page, size);
try {
await shot.open(`${world.base}/alice.test/${REPO}/pulls/new`);
await shot.hold(900);
shot.mark('new');
const branch = page.getByLabel('Branch');
await shot.click(branch);
await branch.selectOption('celsius');
const ready = page.locator('.compare-ready');
await ready.waitFor();
shot.mark('chose');
await shot.hold(900);
await shot.click(ready.getByRole('button', { name: 'Open pull' }));
const title = page.getByRole('textbox', { name: 'Title' });
await title.fill('');
await shot.type(title, 'Show temperatures in Celsius', { delay: 50 });
await shot.hold(300);
shot.mark('open');
await shot.click(page.getByRole('button', { name: 'Open pull', exact: true }));
await page.waitForURL(/\/pull\//);
await page.getByRole('heading', { name: 'Show temperatures in Celsius' }).waitFor();
shot.mark('opened');
await shot.hold(1800);
cast.pull = new URL(page.url()).pathname;
} finally {
await shot.cut();
}
}
};
marketing/video/shoot/scenes/push.mjsnew+94−0
@@ -0,0 +1,94 @@
// alice makes a repository and pushes to it with plain git, from her own
// terminal: the commands run for real, and what they print is what the
// video's terminal shows. Off camera, a branch for the next scenes' pull.
import { mkdirSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
import { run, terminal } from '../act.mjs';
export const REPO = 'forecast';
const README = `# forecast
The weather tomorrow, in your terminal.
\`\`\`
$ forecast lisbon
lisbon tomorrow: high 71°F, low 55°F
\`\`\`
`;
const MAIN = `use std::env;
fn main() {
let city = env::args().nth(1).unwrap_or_else(|| "lisbon".into());
let (high, low) = forecast(&city);
println!("{city} tomorrow: high {high}°F, low {low}°F");
}
fn forecast(city: &str) -> (i32, i32) {
let seed = city.bytes().map(i32::from).sum::<i32>();
(60 + seed % 25, 45 + seed % 15)
}
`;
const CELSIUS = `use std::env;
fn main() {
let args: Vec<String> = env::args().skip(1).collect();
let celsius = args.iter().any(|a| a == "--celsius");
let city = args
.iter()
.find(|a| !a.starts_with("--"))
.cloned()
.unwrap_or_else(|| "lisbon".into());
let (high, low) = forecast(&city);
if celsius {
println!("{city} tomorrow: high {}°C, low {}°C", to_celsius(high), to_celsius(low));
} else {
println!("{city} tomorrow: high {high}°F, low {low}°F");
}
}
fn to_celsius(f: i32) -> i32 {
(f - 32) * 5 / 9
}
fn forecast(city: &str) -> (i32, i32) {
let seed = city.bytes().map(i32::from).sum::<i32>();
(60 + seed % 25, 45 + seed % 15)
}
`;
export default {
prepare: async ({ world, cast }) => {
const dir = join(world.dir, 'alice', REPO);
mkdirSync(join(dir, 'src'), { recursive: true });
writeFileSync(join(dir, 'README.md'), README);
writeFileSync(join(dir, 'src/main.rs'), MAIN);
const git = (...args) => run(world, 'alice', dir, 'git', args);
git('init', '-q', '-b', 'main');
git('add', '-A');
git('commit', '-q', '-m', 'Tomorrow, in your terminal');
const url = `knotless://alice.test/${REPO}`;
const shell = terminal(world, 'alice', dir);
shell.run('knotless', [
'repo',
'create',
url,
'--description',
'The weather tomorrow, in your terminal'
]);
git('remote', 'add', 'origin', url);
shell.run('git', ['push', '-u', 'origin', 'main']);
shell.save('push');
// Her runner reports its checks; the branch the pull brings in.
run(world, 'alice', dir, 'knotless', ['runner', 'add', url, 'alice.test']);
git('switch', '-q', '-c', 'celsius');
writeFileSync(join(dir, 'src/main.rs'), CELSIUS);
git('commit', '-q', '-am', 'Show temperatures in Celsius with --celsius');
git('push', '-q', 'origin', 'celsius');
cast.dir = dir;
cast.tip = git('rev-parse', 'HEAD');
}
};
marketing/video/shoot/scenes/review.mjs+20−31
@@ -1,58 +1,47 @@
// alice reviews bob's pull into tally: a comment on a line it adds, the
// review approved, then the pull merged from its page, squashed into one
// commit on her protected main.
// bob reviews alice's pull: a comment on the line that reads --celsius,
// then the review approved.
import { film } from '../camera.mjs';
export default {
as: 'alice',
start: (world) => `${world.views['pull-open']}/files`,
film: async ({ page, world, size, take }) => {
const pull = world.base + world.views['pull-open'];
as: 'bob',
start: (world, cast) => `${cast.pull}/files`,
film: async ({ page, world, size, take, cast }) => {
const shot = await film(take, page, size);
try {
await shot.open(`${pull}/files`);
await shot.open(`${world.base}${cast.pull}/files`);
await shot.hold(900);
shot.mark('files');
// The line the pull adds that reads `--json`, with the button that comments on it.
const row = page
.locator('tr', { has: page.locator('button[aria-label^="Comment on line"]') })
.filter({ hasText: '"--json"' })
.filter({ hasText: '"--celsius"' })
.first();
shot.mark('line');
await shot.point(row);
await shot.hold(300);
await shot.click(row.locator('button[aria-label^="Comment on line"]'));
const box = page.getByRole('textbox', { name: /^Comment on line/ });
await shot.type(box, 'Could this say `--format json`, to leave room for others?', {
delay: 40
});
await shot.hold(300);
await shot.type(
page.getByRole('textbox', { name: /^Comment on line/ }),
'Could -c work too?',
{ delay: 55 }
);
await shot.hold(250);
await shot.click(page.getByRole('button', { name: 'Start a review' }));
await page.locator('.pending-line').waitFor();
shot.mark('commented');
await shot.hold(700);
await shot.hold(600);
await shot.click(page.locator('.review-menu > summary'));
shot.mark('finish');
const menu = page.locator('.review-menu .menu');
await shot.type(menu.getByPlaceholder('Leave a comment'), 'Looks good with that.', {
delay: 45
await shot.type(menu.getByPlaceholder('Leave a comment'), 'Nice one, ship it.', {
delay: 50
});
await shot.click(menu.getByText('Approve', { exact: true }));
await shot.hold(250);
await shot.hold(200);
await shot.click(menu.getByRole('button', { name: 'Approve', exact: true }));
await page.locator('.review-menu .menu').waitFor({ state: 'hidden' });
await menu.waitFor({ state: 'hidden' });
shot.mark('approved');
await shot.hold(900);
await shot.open(pull);
await shot.hold(700);
const box2 = page.locator('.merge-box');
await box2.scrollIntoViewIfNeeded();
shot.mark('merge');
await shot.click(box2.getByRole('button', { name: 'Merge pull' }));
await page.locator('.event', { hasText: 'Merged as' }).waitFor({ timeout: 30_000 });
await page.locator('.event', { hasText: 'Merged as' }).scrollIntoViewIfNeeded();
shot.mark('merged');
await shot.hold(2200);
await shot.hold(1200);
} finally {
await shot.cut();
}
marketing/video/shoot/scenes/star.mjsdeleted+0−22
@@ -1,22 +0,0 @@
// bob finds alice's notes and stars it: the count goes up as he clicks.
import { film } from '../camera.mjs';
export default {
as: 'bob',
start: () => '/alice.test/notes',
film: async ({ page, world, size, take }) => {
const shot = await film(take, page, size);
try {
await shot.open(`${world.base}/alice.test/notes`);
await shot.hold(1000);
shot.mark('star');
await shot.click(page.getByRole('button', { name: 'Star', exact: true }));
await page.getByRole('button', { name: 'Starred' }).waitFor();
shot.mark('starred');
await shot.hold(1800);
} finally {
await shot.cut();
}
}
};
marketing/video/shoot/act.mjsnew+101−0
marketing/video/shoot/camera.mjs+28−10
marketing/video/shoot/shoot.mjs+25−21
marketing/video/video/change/Checks.tsxdeleted+0−153
marketing/video/video/change/Deploy.tsxdeleted+0−100
marketing/video/video/change/Diff.tsxdeleted+0−158
marketing/video/video/change/Land.tsxdeleted+0−90
marketing/video/video/change/Review.tsxdeleted+0−93
marketing/video/video/change/Terminal.tsxdeleted+0−72
marketing/video/video/Agent.tsxnew+133−0
marketing/video/video/Change.tsxdeleted+0−329
marketing/video/video/Feature.tsxdeleted+0−166
marketing/video/video/Footage.tsx+60−32
marketing/video/video/kit.tsx+12−164
marketing/video/video/look.ts+0−5
marketing/video/video/Promo.tsxnew+323−0
marketing/video/video/Root.tsx+7−24
marketing/video/video/Sounds.tsxnew+39−0
marketing/video/video/story.tsdeleted+0−65
marketing/video/video/Terminal.tsxnew+89−0
marketing/video/.DS_Storenew+0−0
A binary file, not shown.
marketing/video/package.json+1−2
marketing/video/render.mjs+26−32
marketing/video/sfx.mjsnew+82−0
marketing/README.md+32−24
.gitignore+2−0
Justfile+10−14