import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent"; const notes = [ { id: "reed", habitat: "marsh", text: "Fictional reed bends beside the footbridge." }, { id: "fern", habitat: "woodland", text: "Fictional fern grows beneath the oak." }, ] as const; type FieldNote = (typeof notes)[number]; type FieldNotesDetails = | { operations: string[]; ids: FieldNote["id"][]; writes: false } | { matches: FieldNote[] }; export default function fieldNotes(pi: ExtensionAPI): void { const { Type } = pi.typebox; const parameters = Type.Object({ op: Type.Union([Type.Literal("discover"), Type.Literal("inspect"), Type.Literal("query")]), value: Type.Optional(Type.String()), }); pi.registerTool({ name: "field_notes", label: "Field notes", description: "Read fictional field notes: discover operations, inspect one id, or query text. No writes.", parameters, async execute(_id, params) { if (params.op === "discover") { const details: FieldNotesDetails = { operations: ["discover", "inspect", "query"], ids: notes.map(note => note.id), writes: false }; return { content: [{ type: "text", text: JSON.stringify(details) }], details }; } const value = params.value?.trim().toLowerCase() ?? ""; if (params.op === "inspect" && !notes.some(note => note.id === value)) { throw new Error("Unknown note id. Discover ids with field_notes first."); } const matches = notes.filter(note => params.op === "inspect" ? note.id === value : `${note.id} ${note.habitat} ${note.text}`.toLowerCase().includes(value)); return { content: [{ type: "text", text: JSON.stringify(matches) }], details: { matches } }; }, }); pi.registerCommand("field-notes", { description: "Read the fictional field notebook", async handler(args, ctx) { const value = args.trim().toLowerCase(); const matches = notes.filter(note => !value || note.id === value); ctx.ui.notify(matches.length ? matches.map(note => `${note.id}: ${note.text}`).join("\n") : "Unknown note. Try /field-notes reed.", matches.length ? "info" : "warning"); }, }); }