///
import { fetchData, lift, NAME, pattern, UI } from "commontools";
/**
* Fetch the Cheeseboard pizza schedule via Toolshed's web-read endpoint and
* display a list of pizza descriptions inside the charm.
*
* Uses: fetchData, lift, map built-in, toolshed web-read endpoint
*/
const DATE_LINE_REGEX = /^[A-Z][a-z]{2}\s+[A-Z][a-z]{2}\s+\d{1,2}$/;
type CheeseboardEntry = [date: string, pizza: string];
/** Extract pizza descriptions from a web-read content blob. */
function extractPizzas(content: string): CheeseboardEntry[] {
const normalized = content.replace(/\r\n/g, "\n");
const lines = normalized.split("\n");
const pizzas: CheeseboardEntry[] = [];
for (let i = 0; i < lines.length; i++) {
const dateLine = lines[i].trim();
if (!DATE_LINE_REGEX.test(dateLine)) {
continue;
}
let cursor = i + 1;
while (cursor < lines.length && lines[cursor].trim() === "") {
cursor++;
}
if (lines[cursor]?.trim() !== "### Pizza") {
continue;
}
cursor++;
while (cursor < lines.length && lines[cursor].trim() === "") {
cursor++;
}
const descriptionLines: string[] = [];
for (; cursor < lines.length; cursor++) {
const current = lines[cursor].trim();
if (
current === "" ||
current.startsWith("### ") ||
DATE_LINE_REGEX.test(current)
) {
break;
}
descriptionLines.push(current);
}
if (descriptionLines.length > 0) {
pizzas.push([
dateLine,
descriptionLines.join(" "),
]);
}
}
return pizzas;
}
/** Shape of the Toolshed web-read response we care about. */
type WebReadResult = {
content: string;
metadata: {
title?: string;
author?: string;
date?: string;
word_count: number;
};
};
/** Reactive system will call this lift when the fetched data
is updated. it also allows us to call our pure function
`extractPizzas` and return the results
*/
const createPizzaListCell = lift<{ result: WebReadResult }, CheeseboardEntry[]>(
({ result }) => {
return extractPizzas(result?.content ?? "");
},
);
export default pattern(() => {
const cheeseBoardUrl =
"https://cheeseboardcollective.coop/home/pizza/pizza-schedule/";
const { result } = fetchData({
url: "/api/agent-tools/web-read",
mode: "json",
options: {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: {
url: cheeseBoardUrl,
max_tokens: 4000,
},
},
});
const pizzaList = createPizzaListCell({ result });
return {
[NAME]: "Cheeseboard",
[UI]: (
Cheeseboard
{cheeseBoardUrl}
Pizza list
{pizzaList.map(([date, pizza]) => (
-
{date}: {pizza}
))}
),
};
});