grain_pi_compat/lib.rs
1//! `grain-pi-compat` — run pi-style extensions on the grain runtime.
2//!
3//! [pi extensions](https://pi.dev/docs/latest/extensions) are TypeScript
4//! / JavaScript files exporting a factory:
5//!
6//! ```js
7//! // <workspace>/.pi/extensions/my-tool.js
8//! export default (pi) => {
9//! pi.registerTool({
10//! name: "shout",
11//! description: "Uppercases text",
12//! parameters: { type: "object", properties: { text: { type: "string" }}},
13//! execute: (args) => args.text.toUpperCase(),
14//! });
15//! };
16//! ```
17//!
18//! This crate adapts that shape to our [`grain_script_boa::BoaExtension`]
19//! by source-transforming each file: prepending a small shim that
20//! aliases pi's camelCase API onto `grain`'s snake_case API, then —
21//! when an `export default` factory entry is present — wrapping the
22//! call to feed it the `pi` object. The transformed file is written
23//! to a temp dir, then `BoaExtension::from_scripts_dir` loads it.
24//!
25//! ## What works in Phase 1
26//! - `pi.registerTool({ name, description, parameters, execute })`
27//! - `export default (pi) => {...}` factory entry
28//! - Top-level `pi.registerTool(...)` (no factory) — also fine
29//! - Discovery: `<workspace>/.pi/extensions/*.js` +
30//! `~/.pi/agent/extensions/*.js`
31//!
32//! ## Not yet (Phase 2+)
33//! - `pi.on(event, handler)` event subscriptions
34//! - `pi.registerCommand` / `pi.registerShortcut`
35//! - `ctx.ui.*` interactive prompts
36//! - TypeScript source via swc
37//! - npm package extensions
38
39pub mod extension;
40pub mod transform;
41
42pub use extension::{PiCommand, PiCompatError, PiExtension, PiNotification, PiShortcut};
43pub use transform::transform_pi_source;