pi-plus-sdk
v0.2.23
Published
pi coding agent with the pi-plus override layer as an embeddable library (pi-plus-sdk)
Readme
plus-api
Builds the pi-plus-sdk npm package: pi with the pi-plus override layer as an
embeddable library, for hosts that run pi in-process (e.g. a desktop app) instead of
running the pipi CLI. The CLI counterpart is ../plus-cli (the
pi-plus package); the shared override core is ../plus.
Usage
import { createPlusAgentSession } from "pi-plus-sdk";
const { session } = await createPlusAgentSession({
cwd: projectDir,
ui: {
select: async (title, options) => showPicker(title, options),
confirm: async (title, message) => showConfirm(title, message),
input: async (title, placeholder) => showInput(title, placeholder),
},
// Hosts without a pi CLI on PATH should exclude the subagent tool: it
// launches a pi subprocess and could otherwise relaunch the host app.
excludeTools: ["subagent"],
});
await session.prompt("Review this repository");- The full pi-plus layer is included: the compaction/context/reasoning overrides are
baked into
api.jsby the shared bundle-time redirect plugin, and the eleven non-TUI pi-plus extensions (subagent, tasks, memory, plan, ask-user, hooks, context-guard, recap,/cd,/init, web-search) are registered exactly as the CLI wrapper registers them. No CLI logic ships in this artifact: no hub command dispatch (pipi profile ...), no completion, no pipi help text, no banner/vim/tab-title/plain-tools. - Profile management ships as a library: the curated
@earendil-works/pi-hubsurface is re-exported (src/profiles.ts) —loadProfiles/findProfile/ addProfile/addProfileModel/updateProfile/removeProfile/removeProfileModel/ renameProfile/setDefaultProfile/clearDefaultProfile/getDefaultProfileName/ setProfileDefaultModelfor~/.pi/profiles.json, andmaterializeProfile/removeProfileDir/profileDirFor/AGENT_DIR/ syncProfilePackagesToSourcefor the per-profile agent dirs. Hosts get the exact contract thepipiCLI dispatches instead of reimplementing it. - The pi-plus context settings ship as a library:
readPiPlusSettings/updatePiPlusSettingsand theget/setAutoCompactThresholdPercent,get/setContextFloorTokens,get/setContextWindowCapTokenshelpers (plus formatters/parsers) manage thepiPlusblock of the base agentsettings.jsonthat drives auto-compaction trigger math — the same store the pipi TUI/settingsrows edit. Hosts store their own keys in the same block via the generic pair. Session history management completes the surface:SessionManager.listAllto enumerate,SessionManager.search(query)to match titles and transcript text, andSessionManager.deleteSession(path)to remove a transcript. - Pi package maintenance ships as a library (
src/packages.ts):listPackages,installPackage,removePackage, andupdatePackagesare the programmatic form ofpi install/remove/list/update --extensions— the pi packages (extensions, skills, prompts, themes) surface from pi.dev/docs/latest/packages. They take explicitcwd/agentDir(or a caller-ownedSettingsManager) plusprojectTrustedand anonProgresscallback; project-scope (local) writes are refused by the underlying manager when the project is not trusted. - Provider login ships as a library (
src/auth.ts):loginProvider(providerId, { agentDir?, interaction?, signal?, method? })runs pi's model-runtime login flow (OAuth login page / API-key setup — the same flowpipi profile add <name> -p <provider>and the--sign-inflag onpipi profile add/profile updatetrigger) and persists the credential to<agentDir>/auth.json;createTerminalAuthInteraction()provides the readline terminal UI for CLI use, and hosts pass their ownAuthInteractionto drive the prompts from a custom UI. To mirror the CLI's sign-in token overwrite, write the returned credential'skeyintoProfile.tokenviaupdateProfile(and clear the field for OAuth logins, whose credential only lives in the profile'sauth.json— a stored token would overwrite it at the next launch). pi-plus disables the TUI/login(theinteractive-modeandslash-commandscore redirects are baked in here too), so this is the login entry for the whole product. createPlusAgentSession()extends the upstreamcreateAgentSession(re-exported, with the whole upstream SDK surface) and always binds extensions once — do not callsession.bindExtensions()yourself. Passuidialog handlers to get workingask_userquestions (bound with mode"rpc", so the tool falls back to sequential select/input/confirm dialogs bridged to your UI); omituifor a headless session.createPlusAgentSessionRuntime()returns anAgentSessionRuntimeinstead of a single session: the same pi-plus layer and one-bind-per-session rules, plus the CLI's session-replacement machinery —runtime.cd-style switches (switchSession),newSession, andfork(with{position: "at"}for the CLI's in-place/clone). The pi-plus/cd//initextensions and anything else needingcommandContextActionswork out of the box: the factory wires runtime-routed actions by default (override via thecommandContextActionsoption). The live session isruntime.sessionand changes on every replacement — re-subscribe in theonRebindcallback (it also fires for the initial bind) and never callbindExtensions()yourself.runtime.dispose()is async and emitssession_shutdown.session.setAutoCompactionEnabled(bool)writes the global<agentDir>/settings.jsoncompaction flag (not a per-session setting), so a host toggle labeled per-session would surprise users — it also flips behavior for thepipiCLI sharing that agent dir.- Session recap failures are observable: the recap extension (auto-titles the
session after the first prompt and every compaction) publishes every failed title
call to
subscribeToRecapFailures(listener)—{ sessionId, reason: "timeout" | "error", message }— so a host can surface "session name not set" in its own UI or trigger a retry. In-process only (one process hosts the session). Hosts that wireui.notifyalso receive the failure as a transcript warning through the notify bridge. - The staged
package.jsonhas anexportsmap, so deep imports are not reachable;api.d.tsre-exports the@earendil-works/pi-coding-agenttypes (exact-pinned dependency, type resolution only — the runtime is self-contained). mainis re-exported from the upstream barrel but redirects to a stub that throws: the CLI entry is not part of the SDK. LikewiseparseArgs/ArgsandSettingsSelectorComponentare upstream pi's versions, not the pipi-branded CLI wrappers.
Building the artifact
npm run build:offline # at the repo root, first
npm run build # in packages/plus-api
npm publish --access public --ignore-scripts # in packages/plus-api/dist/npmTests
npx vitest run # from packages/plus-api