feat(pi): 3 new Pi Dev extensions — read-tweet, auto-context, task-lifecycle tools
CI / build (push) Has been cancelled
CI / build (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
||||
import { Type } from "@sinclair/typebox";
|
||||
|
||||
const BIRD_BIN = "/opt/homebrew/bin/bird";
|
||||
|
||||
const TweetParams = Type.Object({
|
||||
url: Type.String({ minLength: 1, description: "Tweet URL or numeric ID" }),
|
||||
mode: Type.Optional(
|
||||
Type.Union([
|
||||
Type.Literal("read"),
|
||||
Type.Literal("thread"),
|
||||
Type.Literal("replies"),
|
||||
]),
|
||||
),
|
||||
});
|
||||
|
||||
export default function (pi: ExtensionAPI) {
|
||||
pi.registerTool({
|
||||
name: "read_tweet",
|
||||
label: "Read Tweet",
|
||||
description:
|
||||
"Read an X/Twitter tweet or thread using the local bird CLI. " +
|
||||
"Returns tweet author, text, media, metrics, and timestamps. " +
|
||||
"Use this instead of webfetch for x.com/twitter.com URLs.",
|
||||
promptSnippet: "Read X/Twitter tweets with bird CLI",
|
||||
promptGuidelines: [
|
||||
"Use read_tweet when the user shares an x.com or twitter.com URL and asks what it says",
|
||||
"Use mode='thread' for full conversation threads",
|
||||
"Use mode='replies' to fetch replies to a tweet",
|
||||
"If fetch fails with auth errors, ask the user to sign in to x.com in their browser and retry",
|
||||
],
|
||||
parameters: TweetParams,
|
||||
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
||||
const { url, mode = "read" } = params;
|
||||
|
||||
try {
|
||||
const { execSync } = await import("child_process");
|
||||
const cmd = `${BIRD_BIN} ${mode} ${JSON.stringify(url)} --json`;
|
||||
const stdout = execSync(cmd, { encoding: "utf-8", timeout: 15000 });
|
||||
const parsed = JSON.parse(stdout);
|
||||
|
||||
const author = parsed.author?.name || parsed.author?.screen_name || "unknown";
|
||||
const text = parsed.text || parsed.content || "";
|
||||
const createdAt = parsed.created_at || "";
|
||||
const retweetCount = parsed.metrics?.retweet_count ?? parsed.metrics?.retweets ?? 0;
|
||||
const likeCount = parsed.metrics?.like_count ?? parsed.metrics?.likes ?? 0;
|
||||
const replyCount = parsed.metrics?.reply_count ?? parsed.metrics?.replies ?? 0;
|
||||
const mediaCount = parsed.media?.length ?? 0;
|
||||
const threadCount = parsed.thread?.tweets?.length ?? 0;
|
||||
const repliesCount = parsed.replies?.length ?? 0;
|
||||
|
||||
const lines: string[] = [];
|
||||
lines.push(`Author: ${author}`);
|
||||
if (createdAt) lines.push(`Posted: ${createdAt}`);
|
||||
lines.push("");
|
||||
lines.push(text);
|
||||
if (retweetCount || likeCount || replyCount) {
|
||||
lines.push("");
|
||||
lines.push(`Retweets: ${retweetCount} Likes: ${likeCount} Replies: ${replyCount}`);
|
||||
}
|
||||
if (mediaCount) lines.push(`Media: ${mediaCount} attachment(s)`);
|
||||
if (threadCount) lines.push(`Thread: ${threadCount} tweets total`);
|
||||
if (repliesCount) lines.push(`Replies fetched: ${repliesCount}`);
|
||||
|
||||
return {
|
||||
content: [
|
||||
{ type: "text", text: lines.join("\n") },
|
||||
{ type: "text", text: `\n--- raw ---\n${JSON.stringify(parsed, null, 2)}` },
|
||||
],
|
||||
details: {
|
||||
author,
|
||||
text: text.slice(0, 500),
|
||||
url,
|
||||
mode,
|
||||
tweetCount: threadCount || repliesCount || 1,
|
||||
},
|
||||
};
|
||||
} catch (e: any) {
|
||||
const errMsg = e.stderr || e.message || String(e);
|
||||
const hint = errMsg.includes("auth")
|
||||
? " Sign in to x.com in your browser and retry."
|
||||
: "";
|
||||
|
||||
return {
|
||||
content: [{ type: "text", text: `Failed to fetch tweet: ${errMsg}${hint}` }],
|
||||
details: { error: errMsg, url, mode },
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "pi-read-tweet",
|
||||
"version": "1.0.0",
|
||||
"description": "Read X/Twitter tweets using the local `bird` CLI — registered as a read_tweet tool for Pi Dev",
|
||||
"main": "index.ts",
|
||||
"type": "module",
|
||||
"peerDependencies": {
|
||||
"@earendil-works/pi-coding-agent": "*"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user