chadtmiller.com/knotless
Git hosted in your atproto account, on any stock PDS, fast enough for agents.
git clone knotless://chadtmiller.com/knotlessneeds the knotless git helper. set it up
// How the pages put things into words.
const encoder = new TextEncoder();
/** A path for a URL: each segment percent-encoded, the slashes kept. */
export function urlPath(path: string): string {
let out = '';
for (const b of encoder.encode(path)) {
const c = String.fromCharCode(b);
out += /[A-Za-z0-9\-._~/:@]/.test(c) ? c : `%${b.toString(16).toUpperCase().padStart(2, '0')}`;
}
return out;
}
/** The page of `owner`'s repository `name`, and what follows. */
export const repoHref = (owner: string, name: string, tail = '') =>
`/${urlPath(owner)}/${urlPath(name)}${tail}`;
const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
/** `2026-10-20T…` as `Oct 20, 2026`; anything else as it is. */
export function date(iso: string): string {
const [y, m, d] = [iso.slice(0, 4), iso.slice(5, 7), iso.slice(8, 10)];
const month = MONTHS[Number(m) - 1];
const day = Number(d);
if (y.length < 4 || !month || !/^\d\d$/.test(m) || !/^\d+$/.test(d)) return iso;
return `${month} ${day}, ${y}`;
}
const WEEKDAYS = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
const LONG_MONTHS = [
'january', 'february', 'march', 'april', 'may', 'june',
'july', 'august', 'september', 'october', 'november', 'december'
];
/** `2026-10-09` as `friday, october 9`. */
export function weekday(iso: string): string {
const d = new Date(`${iso.slice(0, 10)}T00:00:00Z`);
if (isNaN(+d)) return iso;
return `${WEEKDAYS[d.getUTCDay()]}, ${LONG_MONTHS[d.getUTCMonth()]} ${d.getUTCDate()}`;
}
/** A commit message's first line. */
export const subject = (message: string) => message.split('\n')[0];
export function size(bytes: number): string {
if (bytes < 1024) return `${bytes} B`;
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}
export const plural = (n: number, one: string, many: string) => `${n} ${n === 1 ? one : many}`;
export const capitalized = (s: string) => s.charAt(0).toUpperCase() + s.slice(1);
/** A branch or tag as it is called, without the `refs/…/` before it. */
export const shortRef = (ref: string) => ref.replace(/^refs\/(heads|tags)\//, '');
/** A hue from 0 to 359 that `name` picks, the same each time. */
export function hue(name: string): number {
let h = 7;
for (const b of encoder.encode(name)) h = (Math.imul(h, 31) + b) >>> 0;
return h % 360;
}
/** The first letter or digit of `name`. */
export const initial = (name: string) => /[\p{L}\p{N}]/u.exec(name)?.[0] ?? '?';
/** The first paragraph of Markdown, as plain text, cut short. */
export function excerpt(text: string, max: number): string {
const plain = text.split('\n\n')[0].replaceAll('\n', ' ').replace(/[`*]/g, '');
const chars = [...plain];
return chars.length > max ? `${chars.slice(0, max).join('').trimEnd()}…` : plain;
}
/** The page of the pull or issue at `uri`, on the repository at `repo`. */
export function itemHref(repo: string, uri: string): string {
const [, , did, , rkey] = uri.split('/');
return `${repo}/${kindOf(uri)}/${did}/${rkey}`;
}
/** Commits a push is walked for: a push that brought this many brought at least as many. */
const WALKED = 100;
/** How many commits a push brought, in words. */
export function commits(n: number): string {
if (n === 0) return 'nothing new';
if (n === 1) return '1 commit';
return n >= WALKED ? `${WALKED}+ commits` : `${n} commits`;
}
/** What a comment with `verdict` did. */
export function said(verdict?: string | null): string {
if (verdict === 'approve') return 'approved';
if (verdict === 'changes') return 'asked for changes on';
return 'commented on';
}
/** What moving to `state` did. */
export const changed = (state: string) => (state === 'open' ? 'reopened' : state);
/** `pull` or `issue`, for the record at `uri`. */
export const kindOf = (uri: string) => (uri.split('/')[3] === 'dev.knotless.pull' ? 'pull' : 'issue');