refactor: finish companion rename migration

Complete the remaining pi-to-companion rename across companion-os, web, vm-orchestrator, docker, and archived fixtures.

Verification:
- semantic rg sweeps for Pi/piConfig/getPi/.pi runtime references
- npm run check in apps/companion-os (fails in this worktree: biome not found)

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Harivansh Rathi 2026-03-10 07:39:32 -05:00
parent e8fe3d54af
commit 536241053c
303 changed files with 3603 additions and 3602 deletions

View file

@ -22,20 +22,20 @@ import type {
AgentState,
AgentTool,
ThinkingLevel,
} from "@mariozechner/pi-agent-core";
} from "@mariozechner/companion-agent-core";
import type {
AssistantMessage,
ImageContent,
Message,
Model,
TextContent,
} from "@mariozechner/pi-ai";
} from "@mariozechner/companion-ai";
import {
isContextOverflow,
modelsAreEqual,
resetApiProviders,
supportsXhigh,
} from "@mariozechner/pi-ai";
} from "@mariozechner/companion-ai";
import { getDocsPath } from "../config.js";
import { theme } from "../modes/interactive/theme/theme.js";
import { stripFrontmatter } from "../utils/frontmatter.js";
@ -1023,7 +1023,7 @@ export class AgentSession {
/**
* Send a prompt to the agent.
* - Handles extension commands (registered via pi.registerCommand) immediately, even during streaming
* - Handles extension commands (registered via companion.registerCommand) immediately, even during streaming
* - Expands file-based prompt templates by default
* - During streaming, queues via steer() or followUp() based on streamingBehavior option
* - Validates model and API key before sending (when not streaming)
@ -1034,7 +1034,7 @@ export class AgentSession {
const expandPromptTemplates = options?.expandPromptTemplates ?? true;
// Handle extension commands first (execute immediately, even during streaming)
// Extension commands manage their own LLM interaction via pi.sendMessage()
// Extension commands manage their own LLM interaction via companion.sendMessage()
if (expandPromptTemplates && text.startsWith("/")) {
const handled = await this._tryExecuteExtensionCommand(text);
if (handled) {

View file

@ -2,7 +2,7 @@
* Credential storage for API keys and OAuth tokens.
* Handles loading, saving, and refreshing credentials from auth.json.
*
* Uses file locking to prevent race conditions when multiple pi instances
* Uses file locking to prevent race conditions when multiple companion instances
* try to refresh tokens simultaneously.
*/
@ -11,12 +11,12 @@ import {
type OAuthCredentials,
type OAuthLoginCallbacks,
type OAuthProviderId,
} from "@mariozechner/pi-ai";
} from "@mariozechner/companion-ai";
import {
getOAuthApiKey,
getOAuthProvider,
getOAuthProviders,
} from "@mariozechner/pi-ai/oauth";
} from "@mariozechner/companion-ai/oauth";
import {
chmodSync,
existsSync,
@ -373,7 +373,7 @@ export class AuthStorage {
/**
* Refresh OAuth token with backend locking to prevent race conditions.
* Multiple pi instances may try to refresh simultaneously when tokens expire.
* Multiple companion instances may try to refresh simultaneously when tokens expire.
*/
private async refreshOAuthTokenWithLock(
providerId: OAuthProviderId,

View file

@ -120,7 +120,7 @@ export function executeBash(
// Start writing to temp file if exceeds threshold
if (totalBytes > DEFAULT_MAX_BYTES && !tempFilePath) {
const id = randomBytes(8).toString("hex");
tempFilePath = join(tmpdir(), `pi-bash-${id}.log`);
tempFilePath = join(tmpdir(), `companion-bash-${id}.log`);
tempFileStream = createWriteStream(tempFilePath);
// Write already-buffered chunks to temp file
for (const chunk of outputChunks) {
@ -223,7 +223,7 @@ export async function executeBashWithOperations(
// Start writing to temp file if exceeds threshold
if (totalBytes > DEFAULT_MAX_BYTES && !tempFilePath) {
const id = randomBytes(8).toString("hex");
tempFilePath = join(tmpdir(), `pi-bash-${id}.log`);
tempFilePath = join(tmpdir(), `companion-bash-${id}.log`);
tempFileStream = createWriteStream(tempFilePath);
for (const chunk of outputChunks) {
tempFileStream.write(chunk);

View file

@ -5,9 +5,9 @@
* a summary of the branch being left so context isn't lost.
*/
import type { AgentMessage } from "@mariozechner/pi-agent-core";
import type { Model } from "@mariozechner/pi-ai";
import { completeSimple } from "@mariozechner/pi-ai";
import type { AgentMessage } from "@mariozechner/companion-agent-core";
import type { Model } from "@mariozechner/companion-ai";
import { completeSimple } from "@mariozechner/companion-ai";
import {
convertToLlm,
createBranchSummaryMessage,
@ -206,7 +206,7 @@ export function prepareBranchEntries(
// First pass: collect file ops from ALL entries (even if they don't fit in token budget)
// This ensures we capture cumulative file tracking from nested branch summaries
// Only extract from pi-generated summaries (fromHook !== true), not extension-generated ones
// Only extract from companion-generated summaries (fromHook !== true), not extension-generated ones
for (const entry of entries) {
if (entry.type === "branch_summary" && !entry.fromHook && entry.details) {
const details = entry.details as BranchSummaryDetails;

View file

@ -5,9 +5,9 @@
* and after compaction the session is reloaded.
*/
import type { AgentMessage } from "@mariozechner/pi-agent-core";
import type { AssistantMessage, Model, Usage } from "@mariozechner/pi-ai";
import { completeSimple } from "@mariozechner/pi-ai";
import type { AgentMessage } from "@mariozechner/companion-agent-core";
import type { AssistantMessage, Model, Usage } from "@mariozechner/companion-ai";
import { completeSimple } from "@mariozechner/companion-ai";
import {
convertToLlm,
createBranchSummaryMessage,
@ -45,7 +45,7 @@ function extractFileOperations(
): FileOperations {
const fileOps = createFileOps();
// Collect from previous compaction's details (if pi-generated)
// Collect from previous compaction's details (if companion-generated)
if (prevCompactionIndex >= 0) {
const prevCompaction = entries[prevCompactionIndex] as CompactionEntry;
if (!prevCompaction.fromHook && prevCompaction.details) {

View file

@ -2,8 +2,8 @@
* Shared utilities for compaction and branch summarization.
*/
import type { AgentMessage } from "@mariozechner/pi-agent-core";
import type { Message } from "@mariozechner/pi-ai";
import type { AgentMessage } from "@mariozechner/companion-agent-core";
import type { Message } from "@mariozechner/companion-ai";
// ============================================================================
// File Operation Tracking

View file

@ -1,3 +1,3 @@
import type { ThinkingLevel } from "@mariozechner/pi-agent-core";
import type { ThinkingLevel } from "@mariozechner/companion-agent-core";
export const DEFAULT_THINKING_LEVEL: ThinkingLevel = "medium";

View file

@ -1,4 +1,4 @@
import type { AgentState } from "@mariozechner/pi-agent-core";
import type { AgentState } from "@mariozechner/companion-agent-core";
import { existsSync, readFileSync, writeFileSync } from "fs";
import { basename, join } from "path";
import { APP_NAME, getExportTemplateDir } from "../../config.js";

View file

@ -27,7 +27,7 @@
// Parse URL parameters for deep linking: leafId and targetId
// Check for injected params (when loaded in iframe via srcdoc) or use window.location
const injectedParams = document.querySelector('meta[name="pi-url-params"]');
const injectedParams = document.querySelector('meta[name="companion-url-params"]');
const searchString = injectedParams
? injectedParams.content
: window.location.search.substring(1);
@ -1227,7 +1227,7 @@
function buildShareUrl(entryId) {
// Check for injected base URL (used when loaded in iframe via srcdoc)
const baseUrlMeta = document.querySelector(
'meta[name="pi-share-base-url"]',
'meta[name="companion-share-base-url"]',
);
const baseUrl = baseUrlMeta
? baseUrlMeta.content

View file

@ -5,7 +5,7 @@
* and converting the ANSI output to HTML.
*/
import type { ImageContent, TextContent } from "@mariozechner/pi-ai";
import type { ImageContent, TextContent } from "@mariozechner/companion-ai";
import type { Theme } from "../../modes/interactive/theme/theme.js";
import type { ToolDefinition } from "../extensions/types.js";
import { ansiLinesToHtml } from "./ansi-to-html.js";

View file

@ -4864,7 +4864,7 @@ var hljs = (function () {
keyword:
"and break do else elseif end for goto if in local not or repeat return then until while",
built_in:
"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove",
"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp companion cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove",
},
contains: i.concat([
{
@ -6293,7 +6293,7 @@ var hljs = (function () {
literal:
"NULL NA TRUE FALSE Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10",
built_in:
"LETTERS letters month.abb month.name pi T F abs acos acosh all any anyNA Arg as.call as.character as.complex as.double as.environment as.integer as.logical as.null.default as.numeric as.raw asin asinh atan atanh attr attributes baseenv browser c call ceiling class Conj cos cosh cospi cummax cummin cumprod cumsum digamma dim dimnames emptyenv exp expression floor forceAndCall gamma gc.time globalenv Im interactive invisible is.array is.atomic is.call is.character is.complex is.double is.environment is.expression is.finite is.function is.infinite is.integer is.language is.list is.logical is.matrix is.na is.name is.nan is.null is.numeric is.object is.pairlist is.raw is.recursive is.single is.symbol lazyLoadDBfetch length lgamma list log max min missing Mod names nargs nzchar oldClass on.exit pos.to.env proc.time prod quote range Re rep retracemem return round seq_along seq_len seq.int sign signif sin sinh sinpi sqrt standardGeneric substitute sum switch tan tanh tanpi tracemem trigamma trunc unclass untracemem UseMethod xtfrm",
"LETTERS letters month.abb month.name companion T F abs acos acosh all any anyNA Arg as.call as.character as.complex as.double as.environment as.integer as.logical as.null.default as.numeric as.raw asin asinh atan atanh attr attributes baseenv browser c call ceiling class Conj cos cosh cospi cummax cummin cumprod cumsum digamma dim dimnames emptyenv exp expression floor forceAndCall gamma gc.time globalenv Im interactive invisible is.array is.atomic is.call is.character is.complex is.double is.environment is.expression is.finite is.function is.infinite is.integer is.language is.list is.logical is.matrix is.na is.name is.nan is.null is.numeric is.object is.pairlist is.raw is.recursive is.single is.symbol lazyLoadDBfetch length lgamma list log max min missing Mod names nargs nzchar oldClass on.exit pos.to.env proc.time prod quote range Re rep retracemem return round seq_along seq_len seq.int sign signif sin sinh sinpi sqrt standardGeneric substitute sum switch tan tanh tanpi tracemem trigamma trunc unclass untracemem UseMethod xtfrm",
},
contains: [
e.COMMENT(/#'/, /$/, {

View file

@ -10,18 +10,18 @@ import * as os from "node:os";
import * as path from "node:path";
import { fileURLToPath } from "node:url";
import { createJiti } from "@mariozechner/jiti";
import * as _bundledPiAgentCore from "@mariozechner/pi-agent-core";
import * as _bundledPiAi from "@mariozechner/pi-ai";
import * as _bundledPiAiOauth from "@mariozechner/pi-ai/oauth";
import type { KeyId } from "@mariozechner/pi-tui";
import * as _bundledPiTui from "@mariozechner/pi-tui";
import * as _bundledPiAgentCore from "@mariozechner/companion-agent-core";
import * as _bundledPiAi from "@mariozechner/companion-ai";
import * as _bundledPiAiOauth from "@mariozechner/companion-ai/oauth";
import type { KeyId } from "@mariozechner/companion-tui";
import * as _bundledPiTui from "@mariozechner/companion-tui";
// Static imports of packages that extensions may use.
// These MUST be static so Bun bundles them into the compiled binary.
// The virtualModules option then makes them available to extensions.
import * as _bundledTypebox from "@sinclair/typebox";
import { getAgentDir, isBunBinary } from "../../config.js";
// NOTE: This import works because loader.ts exports are NOT re-exported from index.ts,
// avoiding a circular dependency. Extensions can import from @mariozechner/pi-coding-agent.
// avoiding a circular dependency. Extensions can import from @mariozechner/companion-coding-agent.
import * as _bundledPiCodingAgent from "../../index.js";
import { createEventBus, type EventBus } from "../event-bus.js";
import type { ExecOptions } from "../exec.js";
@ -41,11 +41,11 @@ import type {
/** Modules available to extensions via virtualModules (for compiled Bun binary) */
const VIRTUAL_MODULES: Record<string, unknown> = {
"@sinclair/typebox": _bundledTypebox,
"@mariozechner/pi-agent-core": _bundledPiAgentCore,
"@mariozechner/pi-tui": _bundledPiTui,
"@mariozechner/pi-ai": _bundledPiAi,
"@mariozechner/pi-ai/oauth": _bundledPiAiOauth,
"@mariozechner/pi-coding-agent": _bundledPiCodingAgent,
"@mariozechner/companion-agent-core": _bundledPiAgentCore,
"@mariozechner/companion-tui": _bundledPiTui,
"@mariozechner/companion-ai": _bundledPiAi,
"@mariozechner/companion-ai/oauth": _bundledPiAiOauth,
"@mariozechner/companion-coding-agent": _bundledPiCodingAgent,
};
const require = createRequire(import.meta.url);
@ -80,22 +80,22 @@ function getAliases(): Record<string, string> {
};
_aliases = {
"@mariozechner/pi-coding-agent": packageIndex,
"@mariozechner/pi-agent-core": resolveWorkspaceOrImport(
"@mariozechner/companion-coding-agent": packageIndex,
"@mariozechner/companion-agent-core": resolveWorkspaceOrImport(
"agent/dist/index.js",
"@mariozechner/pi-agent-core",
"@mariozechner/companion-agent-core",
),
"@mariozechner/pi-tui": resolveWorkspaceOrImport(
"@mariozechner/companion-tui": resolveWorkspaceOrImport(
"tui/dist/index.js",
"@mariozechner/pi-tui",
"@mariozechner/companion-tui",
),
"@mariozechner/pi-ai": resolveWorkspaceOrImport(
"@mariozechner/companion-ai": resolveWorkspaceOrImport(
"ai/dist/index.js",
"@mariozechner/pi-ai",
"@mariozechner/companion-ai",
),
"@mariozechner/pi-ai/oauth": resolveWorkspaceOrImport(
"@mariozechner/companion-ai/oauth": resolveWorkspaceOrImport(
"ai/dist/oauth.js",
"@mariozechner/pi-ai/oauth",
"@mariozechner/companion-ai/oauth",
),
"@sinclair/typebox": typeboxRoot,
};
@ -454,8 +454,8 @@ function readPiManifest(packageJsonPath: string): PiManifest | null {
try {
const content = fs.readFileSync(packageJsonPath, "utf-8");
const pkg = JSON.parse(content);
if (pkg.pi && typeof pkg.pi === "object") {
return pkg.pi as PiManifest;
if (pkg.companion && typeof pkg.companion === "object") {
return pkg.companion as PiManifest;
}
return null;
} catch {
@ -471,13 +471,13 @@ function isExtensionFile(name: string): boolean {
* Resolve extension entry points from a directory.
*
* Checks for:
* 1. package.json with "pi.extensions" field -> returns declared paths
* 1. package.json with "companion.extensions" field -> returns declared paths
* 2. index.ts or index.js -> returns the index file
*
* Returns resolved paths or null if no entry points found.
*/
function resolveExtensionEntries(dir: string): string[] | null {
// Check for package.json with "pi" field first
// Check for package.json with "companion" field first
const packageJsonPath = path.join(dir, "package.json");
if (fs.existsSync(packageJsonPath)) {
const manifest = readPiManifest(packageJsonPath);
@ -514,7 +514,7 @@ function resolveExtensionEntries(dir: string): string[] | null {
* Discovery rules:
* 1. Direct files: `extensions/*.ts` or `*.js` load
* 2. Subdirectory with index: `extensions/* /index.ts` or `index.js` load
* 3. Subdirectory with package.json: `extensions/* /package.json` with "pi" field load what it declares
* 3. Subdirectory with package.json: `extensions/* /package.json` with "companion" field load what it declares
*
* No recursion beyond one level. Complex packages must use package.json manifest.
*/
@ -577,8 +577,8 @@ export async function discoverAndLoadExtensions(
}
};
// 1. Project-local extensions: cwd/.pi/extensions/
const localExtDir = path.join(cwd, ".pi", "extensions");
// 1. Project-local extensions: cwd/.companion/extensions/
const localExtDir = path.join(cwd, ".companion", "extensions");
addPaths(discoverExtensionsInDir(localExtDir));
// 2. Global extensions: agentDir/extensions/
@ -589,7 +589,7 @@ export async function discoverAndLoadExtensions(
for (const p of configuredPaths) {
const resolved = resolvePath(p, cwd);
if (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {
// Check for package.json with pi manifest or index.ts
// Check for package.json with companion manifest or index.ts
const entries = resolveExtensionEntries(resolved);
if (entries) {
addPaths(entries);

View file

@ -2,9 +2,9 @@
* Extension runner - executes extensions and manages their lifecycle.
*/
import type { AgentMessage } from "@mariozechner/pi-agent-core";
import type { ImageContent, Model } from "@mariozechner/pi-ai";
import type { KeyId } from "@mariozechner/pi-tui";
import type { AgentMessage } from "@mariozechner/companion-agent-core";
import type { ImageContent, Model } from "@mariozechner/companion-ai";
import type { KeyId } from "@mariozechner/companion-tui";
import { type Theme, theme } from "../../modes/interactive/theme/theme.js";
import type { ResourceDiagnostic } from "../diagnostics.js";
import type { KeyAction, KeybindingsConfig } from "../keybindings.js";

View file

@ -13,7 +13,7 @@ import type {
AgentToolResult,
AgentToolUpdateCallback,
ThinkingLevel,
} from "@mariozechner/pi-agent-core";
} from "@mariozechner/companion-agent-core";
import type {
Api,
AssistantMessageEvent,
@ -26,7 +26,7 @@ import type {
SimpleStreamOptions,
TextContent,
ToolResultMessage,
} from "@mariozechner/pi-ai";
} from "@mariozechner/companion-ai";
import type {
AutocompleteItem,
Component,
@ -36,7 +36,7 @@ import type {
OverlayHandle,
OverlayOptions,
TUI,
} from "@mariozechner/pi-tui";
} from "@mariozechner/companion-tui";
import type { Static, TSchema } from "@sinclair/typebox";
import type { Theme } from "../../modes/interactive/theme/theme.js";
import type { BashResult } from "../bash-executor.js";
@ -223,12 +223,12 @@ export interface ExtensionUIContext {
* - `keybindings`: KeybindingsManager for app-level keybindings
*
* For full app keybinding support (escape, ctrl+d, model switching, etc.),
* extend `CustomEditor` from `@mariozechner/pi-coding-agent` and call
* extend `CustomEditor` from `@mariozechner/companion-coding-agent` and call
* `super.handleInput(data)` for keys you don't handle.
*
* @example
* ```ts
* import { CustomEditor } from "@mariozechner/pi-coding-agent";
* import { CustomEditor } from "@mariozechner/companion-coding-agent";
*
* class VimEditor extends CustomEditor {
* private mode: "normal" | "insert" = "insert";
@ -316,7 +316,7 @@ export interface ExtensionContext {
abort(): void;
/** Whether there are queued messages waiting */
hasPendingMessages(): boolean;
/** Gracefully shutdown pi and exit. Available in all contexts. */
/** Gracefully shutdown companion and exit. Available in all contexts. */
shutdown(): void;
/** Get current context usage for the active model. */
getContextUsage(): ContextUsage | undefined;
@ -1251,7 +1251,7 @@ export interface ExtensionAPI {
*
* @example
* // Register a new provider with custom models
* pi.registerProvider("my-proxy", {
* companion.registerProvider("my-proxy", {
* baseUrl: "https://proxy.example.com",
* apiKey: "PROXY_API_KEY",
* api: "anthropic-messages",
@ -1270,13 +1270,13 @@ export interface ExtensionAPI {
*
* @example
* // Override baseUrl for an existing provider
* pi.registerProvider("anthropic", {
* companion.registerProvider("anthropic", {
* baseUrl: "https://proxy.example.com"
* });
*
* @example
* // Register provider with OAuth support
* pi.registerProvider("corporate-ai", {
* companion.registerProvider("corporate-ai", {
* baseUrl: "https://ai.corp.com",
* api: "openai-responses",
* models: [...],
@ -1301,7 +1301,7 @@ export interface ExtensionAPI {
* the initial load phase.
*
* @example
* pi.unregisterProvider("my-proxy");
* companion.unregisterProvider("my-proxy");
*/
unregisterProvider(name: string): void;
@ -1313,7 +1313,7 @@ export interface ExtensionAPI {
// Provider Registration Types
// ============================================================================
/** Configuration for registering a provider via pi.registerProvider(). */
/** Configuration for registering a provider via companion.registerProvider(). */
export interface ProviderConfig {
/** Base URL for the API endpoint. Required when defining models. */
baseUrl?: string;
@ -1381,7 +1381,7 @@ export interface ProviderModelConfig {
}
/** Extension factory function type. Supports both sync and async initialization. */
export type ExtensionFactory = (pi: ExtensionAPI) => void | Promise<void>;
export type ExtensionFactory = (companion: ExtensionAPI) => void | Promise<void>;
// ============================================================================
// Loaded Extension Types
@ -1480,7 +1480,7 @@ export interface ExtensionRuntimeState {
}
/**
* Action implementations for pi.* API methods.
* Action implementations for companion.* API methods.
* Provided to runner.initialize(), copied into the shared runtime.
*/
export interface ExtensionActions {

View file

@ -5,7 +5,7 @@
import type {
AgentTool,
AgentToolUpdateCallback,
} from "@mariozechner/pi-agent-core";
} from "@mariozechner/companion-agent-core";
import type { ExtensionRunner } from "./runner.js";
import type { RegisteredTool, ToolCallEventResult } from "./types.js";

View file

@ -1,4 +1,4 @@
import type { AgentMessage } from "@mariozechner/pi-agent-core";
import type { AgentMessage } from "@mariozechner/companion-agent-core";
import type { AgentSession } from "../agent-session.js";
import type {
GatewayMessageRequest,

View file

@ -61,7 +61,7 @@ let activeGatewayRuntime: GatewayRuntime | null = null;
type JsonRecord = Record<string, unknown>;
type PiChannelsSettings = JsonRecord & {
type CompanionChannelsSettings = JsonRecord & {
adapters?: Record<string, JsonRecord>;
bridge?: JsonRecord;
slack?: JsonRecord;
@ -1031,7 +1031,7 @@ export class GatewayRuntime {
path.slice(this.config.webhook.basePath.length).replace(/^\/+/, "") ||
"default";
if (this.config.webhook.secret) {
const presentedSecret = request.headers["x-pi-webhook-secret"];
const presentedSecret = request.headers["x-companion-webhook-secret"];
if (presentedSecret !== this.config.webhook.secret) {
this.writeJson(response, 401, { error: "Invalid webhook secret" });
return;
@ -1388,7 +1388,7 @@ export class GatewayRuntime {
this.primarySession.settingsManager.applyOverrides(patch as Settings);
}
private getPiChannelsSettings(): PiChannelsSettings {
private getCompanionChannelsSettings(): CompanionChannelsSettings {
const globalSettings = this.primarySession.settingsManager.getGlobalSettings();
const projectSettings =
this.primarySession.settingsManager.getProjectSettings();
@ -1396,12 +1396,12 @@ export class GatewayRuntime {
isRecord(globalSettings) ? globalSettings : {},
isRecord(projectSettings) ? projectSettings : {},
);
const piChannels = mergedSettings["pi-channels"];
return isRecord(piChannels) ? (piChannels as PiChannelsSettings) : {};
const piChannels = mergedSettings["companion-channels"];
return isRecord(piChannels) ? (piChannels as CompanionChannelsSettings) : {};
}
private buildSlackChannelStatus(
config: PiChannelsSettings,
config: CompanionChannelsSettings,
bridgeEnabled: boolean,
): ChannelStatus {
const adapters = isRecord(config.adapters) ? config.adapters : {};
@ -1419,13 +1419,13 @@ export class GatewayRuntime {
if (hasConfig) {
if (!adapter) {
error = 'Slack requires `pi-channels.adapters.slack = { "type": "slack" }`.';
error = 'Slack requires `companion-channels.adapters.slack = { "type": "slack" }`.';
} else if (adapterType !== "slack") {
error = 'Slack adapter type must be "slack".';
} else if (!appToken) {
error = "Slack requires pi-channels.slack.appToken.";
error = "Slack requires companion-channels.slack.appToken.";
} else if (!botToken) {
error = "Slack requires pi-channels.slack.botToken.";
error = "Slack requires companion-channels.slack.botToken.";
} else {
configured = true;
}
@ -1433,7 +1433,7 @@ export class GatewayRuntime {
if (configured && !bridgeEnabled) {
error =
"Slack is configured, but pi-channels.bridge.enabled is false, so messages will not reach the agent.";
"Slack is configured, but companion-channels.bridge.enabled is false, so messages will not reach the agent.";
}
return {
@ -1447,7 +1447,7 @@ export class GatewayRuntime {
}
private buildTelegramChannelStatus(
config: PiChannelsSettings,
config: CompanionChannelsSettings,
bridgeEnabled: boolean,
): ChannelStatus {
const adapters = isRecord(config.adapters) ? config.adapters : {};
@ -1464,14 +1464,14 @@ export class GatewayRuntime {
if (hasConfig) {
if (!adapter) {
error =
'Telegram requires `pi-channels.adapters.telegram = { "type": "telegram", "botToken": "...", "polling": true }`.';
'Telegram requires `companion-channels.adapters.telegram = { "type": "telegram", "botToken": "...", "polling": true }`.';
} else if (adapterType !== "telegram") {
error = 'Telegram adapter type must be "telegram".';
} else if (!botToken) {
error = "Telegram requires pi-channels.adapters.telegram.botToken.";
error = "Telegram requires companion-channels.adapters.telegram.botToken.";
} else if (!pollingEnabled) {
error =
"Telegram requires pi-channels.adapters.telegram.polling = true.";
"Telegram requires companion-channels.adapters.telegram.polling = true.";
} else {
configured = true;
}
@ -1479,7 +1479,7 @@ export class GatewayRuntime {
if (configured && !bridgeEnabled) {
error =
"Telegram is configured, but pi-channels.bridge.enabled is false, so messages will not reach the agent.";
"Telegram is configured, but companion-channels.bridge.enabled is false, so messages will not reach the agent.";
}
return {
@ -1493,7 +1493,7 @@ export class GatewayRuntime {
}
private handleGetChannelsStatus(): ChannelStatus[] {
const config = this.getPiChannelsSettings();
const config = this.getCompanionChannelsSettings();
const bridgeEnabled = config.bridge?.enabled === true;
return [

View file

@ -1,4 +1,4 @@
import type { AgentMessage } from "@mariozechner/pi-agent-core";
import type { AgentMessage } from "@mariozechner/companion-agent-core";
import type { HistoryMessage, HistoryPart } from "./types.js";
export interface GatewayTransientToolResult {

View file

@ -1,4 +1,4 @@
import type { ImageContent } from "@mariozechner/pi-ai";
import type { ImageContent } from "@mariozechner/companion-ai";
import type { AgentSession } from "../agent-session.js";
export interface GatewayConfig {

View file

@ -6,7 +6,7 @@ import {
type KeyId,
matchesKey,
setEditorKeybindings,
} from "@mariozechner/pi-tui";
} from "@mariozechner/companion-tui";
import { existsSync, readFileSync } from "fs";
import { join } from "path";
import { getAgentDir } from "../config.js";

View file

@ -9,17 +9,17 @@ import {
import { createRequire } from "node:module";
import { homedir } from "node:os";
import { basename, join, resolve } from "node:path";
import type { AgentMessage } from "@mariozechner/pi-agent-core";
import type { AgentMessage } from "@mariozechner/companion-agent-core";
import {
completeSimple,
type Model,
type TextContent,
} from "@mariozechner/pi-ai";
} from "@mariozechner/companion-ai";
import { parseFrontmatter } from "../../utils/frontmatter.js";
import type { SettingsManager } from "../settings-manager.js";
import type { ReadonlySessionManager } from "../session-manager.js";
const DEFAULT_STORAGE_DIR = join(homedir(), ".pi", "memory");
const DEFAULT_STORAGE_DIR = join(homedir(), ".companion", "memory");
const MAX_EPISODE_CHARS = 4_000;
const MAX_EPISODES = 5_000;
const DEFAULT_CORE_TOKEN_BUDGET = 700;
@ -1487,9 +1487,9 @@ function resolveLegacyProjectDir(
cwd: string,
): string | null {
const settings = asRecord(settingsManager.getGlobalSettings()) ?? {};
const legacySettings = asRecord(settings["pi-memory-md"]) ?? {};
const legacySettings = asRecord(settings["companion-memory-md"]) ?? {};
const configuredRoot =
asString(legacySettings.localPath) ?? join(homedir(), ".pi", "memory-md");
asString(legacySettings.localPath) ?? join(homedir(), ".companion", "memory-md");
const legacyRoot = expandHomePath(configuredRoot);
const legacyProjectDir = join(legacyRoot, basename(cwd));
if (existsSync(legacyProjectDir)) {

View file

@ -5,8 +5,8 @@
* and provides a transformer to convert them to LLM-compatible messages.
*/
import type { AgentMessage } from "@mariozechner/pi-agent-core";
import type { ImageContent, Message, TextContent } from "@mariozechner/pi-ai";
import type { AgentMessage } from "@mariozechner/companion-agent-core";
import type { ImageContent, Message, TextContent } from "@mariozechner/companion-ai";
export const COMPACTION_SUMMARY_PREFIX = `The conversation history before this point was compacted into the following summary:
@ -67,7 +67,7 @@ export interface CompactionSummaryMessage {
}
// Extend CustomAgentMessages via declaration merging
declare module "@mariozechner/pi-agent-core" {
declare module "@mariozechner/companion-agent-core" {
interface CustomAgentMessages {
bashExecution: BashExecutionMessage;
custom: CustomMessage;

View file

@ -16,11 +16,11 @@ import {
registerApiProvider,
resetApiProviders,
type SimpleStreamOptions,
} from "@mariozechner/pi-ai";
} from "@mariozechner/companion-ai";
import {
registerOAuthProvider,
resetOAuthProviders,
} from "@mariozechner/pi-ai/oauth";
} from "@mariozechner/companion-ai/oauth";
import { type Static, Type } from "@sinclair/typebox";
import AjvModule from "ajv";
import { existsSync, readFileSync } from "fs";

View file

@ -2,13 +2,13 @@
* Model resolution, scoping, and initial selection
*/
import type { ThinkingLevel } from "@mariozechner/pi-agent-core";
import type { ThinkingLevel } from "@mariozechner/companion-agent-core";
import {
type Api,
type KnownProvider,
type Model,
modelsAreEqual,
} from "@mariozechner/pi-ai";
} from "@mariozechner/companion-ai";
import chalk from "chalk";
import { minimatch } from "minimatch";
import { isValidThinkingLevel } from "../cli/args.js";

View file

@ -20,7 +20,7 @@ import type { PackageSource, SettingsManager } from "./settings-manager.js";
const NETWORK_TIMEOUT_MS = 10000;
function isOfflineModeEnabled(): boolean {
const value = process.env.PI_OFFLINE;
const value = process.env.COMPANION_OFFLINE;
if (!value) return false;
return (
value === "1" ||
@ -445,8 +445,8 @@ function collectAutoThemeEntries(dir: string): string[] {
function readPiManifestFile(packageJsonPath: string): PiManifest | null {
try {
const content = readFileSync(packageJsonPath, "utf-8");
const pkg = JSON.parse(content) as { pi?: PiManifest };
return pkg.pi ?? null;
const pkg = JSON.parse(content) as { companion?: PiManifest };
return pkg.companion ?? null;
} catch {
return null;
}
@ -1529,7 +1529,7 @@ export class DefaultPackageManager implements PackageManager {
this.ensureGitIgnore(installRoot);
const packageJsonPath = join(installRoot, "package.json");
if (!existsSync(packageJsonPath)) {
const pkgJson = { name: "pi-extensions", private: true };
const pkgJson = { name: "companion-extensions", private: true };
writeFileSync(packageJsonPath, JSON.stringify(pkgJson, null, 2), "utf-8");
}
}
@ -1595,7 +1595,7 @@ export class DefaultPackageManager implements PackageManager {
.update(`${prefix}-${suffix ?? ""}`)
.digest("hex")
.slice(0, 8);
return join(tmpdir(), "pi-extensions", prefix, hash, suffix ?? "");
return join(tmpdir(), "companion-extensions", prefix, hash, suffix ?? "");
}
private getBaseDirForScope(scope: SourceScope): string {
@ -1784,8 +1784,8 @@ export class DefaultPackageManager implements PackageManager {
try {
const content = readFileSync(packageJsonPath, "utf-8");
const pkg = JSON.parse(content) as { pi?: PiManifest };
return pkg.pi ?? null;
const pkg = JSON.parse(content) as { companion?: PiManifest };
return pkg.companion ?? null;
} catch {
return null;
}

View file

@ -3,8 +3,8 @@ import {
Agent,
type AgentMessage,
type ThinkingLevel,
} from "@mariozechner/pi-agent-core";
import type { Message, Model } from "@mariozechner/pi-ai";
} from "@mariozechner/companion-agent-core";
import type { Message, Model } from "@mariozechner/companion-ai";
import { getAgentDir, getDocsPath } from "../config.js";
import { AgentSession } from "./agent-session.js";
import { AuthStorage } from "./auth-storage.js";
@ -52,7 +52,7 @@ import {
export interface CreateAgentSessionOptions {
/** Working directory for project-local discovery. Default: process.cwd() */
cwd?: string;
/** Global config directory. Default: ~/.pi/agent */
/** Global config directory. Default: ~/.companion/agent */
agentDir?: string;
/** Auth storage for credentials. Default: AuthStorage.create(agentDir/auth.json) */
@ -149,7 +149,7 @@ function getDefaultAgentDir(): string {
* const { session } = await createAgentSession();
*
* // With explicit model
* import { getModel } from '@mariozechner/pi-ai';
* import { getModel } from '@mariozechner/companion-ai';
* const { session } = await createAgentSession({
* model: getModel('anthropic', 'claude-opus-4-6'),
* thinkingLevel: 'high',

View file

@ -1,5 +1,5 @@
import type { AgentMessage } from "@mariozechner/pi-agent-core";
import type { ImageContent, Message, TextContent } from "@mariozechner/pi-ai";
import type { AgentMessage } from "@mariozechner/companion-agent-core";
import type { ImageContent, Message, TextContent } from "@mariozechner/companion-ai";
import { randomUUID } from "crypto";
import {
appendFileSync,
@ -72,7 +72,7 @@ export interface CompactionEntry<T = unknown> extends SessionEntryBase {
tokensBefore: number;
/** Extension-specific data (e.g., ArtifactIndex, version markers for structured compaction) */
details?: T;
/** True if generated by an extension, undefined/false if pi-generated (backward compatible) */
/** True if generated by an extension, undefined/false if companion-generated (backward compatible) */
fromHook?: boolean;
}
@ -82,7 +82,7 @@ export interface BranchSummaryEntry<T = unknown> extends SessionEntryBase {
summary: string;
/** Extension-specific data (not sent to LLM) */
details?: T;
/** True if generated by an extension, false if pi-generated */
/** True if generated by an extension, false if companion-generated */
fromHook?: boolean;
}
@ -448,7 +448,7 @@ export function buildSessionContext(
/**
* Compute the default session directory for a cwd.
* Encodes cwd into a safe directory name under ~/.pi/agent/sessions/.
* Encodes cwd into a safe directory name under ~/.companion/agent/sessions/.
*/
function getDefaultSessionDir(cwd: string): string {
const safePath = `--${cwd.replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`;
@ -1332,7 +1332,7 @@ export class SessionManager {
/**
* Create a new session.
* @param cwd Working directory (stored in session header)
* @param sessionDir Optional session directory. If omitted, uses default (~/.pi/agent/sessions/<encoded-cwd>/).
* @param sessionDir Optional session directory. If omitted, uses default (~/.companion/agent/sessions/<encoded-cwd>/).
*/
static create(cwd: string, sessionDir?: string): SessionManager {
const dir = sessionDir ?? getDefaultSessionDir(cwd);
@ -1359,7 +1359,7 @@ export class SessionManager {
/**
* Continue the most recent session, or create new if none.
* @param cwd Working directory
* @param sessionDir Optional session directory. If omitted, uses default (~/.pi/agent/sessions/<encoded-cwd>/).
* @param sessionDir Optional session directory. If omitted, uses default (~/.companion/agent/sessions/<encoded-cwd>/).
*/
static continueRecent(cwd: string, sessionDir?: string): SessionManager {
const dir = sessionDir ?? getDefaultSessionDir(cwd);
@ -1438,7 +1438,7 @@ export class SessionManager {
/**
* List all sessions for a directory.
* @param cwd Working directory (used to compute default session directory)
* @param sessionDir Optional session directory. If omitted, uses default (~/.pi/agent/sessions/<encoded-cwd>/).
* @param sessionDir Optional session directory. If omitted, uses default (~/.companion/agent/sessions/<encoded-cwd>/).
* @param onProgress Optional callback for progress updates (loaded, total)
*/
static async list(

View file

@ -1,4 +1,4 @@
import type { Transport } from "@mariozechner/pi-ai";
import type { Transport } from "@mariozechner/companion-ai";
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
import { dirname, join } from "path";
import lockfile from "proper-lockfile";
@ -944,7 +944,7 @@ export class SettingsManager {
if (this.settings.terminal?.clearOnShrink !== undefined) {
return this.settings.terminal.clearOnShrink;
}
return process.env.PI_CLEAR_ON_SHRINK === "1";
return process.env.COMPANION_CLEAR_ON_SHRINK === "1";
}
setClearOnShrink(enabled: boolean): void {
@ -1023,7 +1023,7 @@ export class SettingsManager {
getShowHardwareCursor(): boolean {
return (
this.settings.showHardwareCursor ?? process.env.PI_HARDWARE_CURSOR === "1"
this.settings.showHardwareCursor ?? process.env.COMPANION_HARDWARE_CURSOR === "1"
);
}

View file

@ -361,7 +361,7 @@ function escapeXml(str: string): string {
export interface LoadSkillsOptions {
/** Working directory for project-local skills. Default: process.cwd() */
cwd?: string;
/** Agent config directory for global skills. Default: ~/.pi/agent */
/** Agent config directory for global skills. Default: ~/.companion/agent */
agentDir?: string;
/** Explicit skill paths (files or directories) */
skillPaths?: string[];

View file

@ -40,5 +40,5 @@ export const BUILTIN_SLASH_COMMANDS: ReadonlyArray<BuiltinSlashCommand> = [
name: "reload",
description: "Reload extensions, skills, prompts, and themes",
},
{ name: "quit", description: "Quit pi" },
{ name: "quit", description: "Quit companion" },
];

View file

@ -1,9 +1,9 @@
/**
* Central timing instrumentation for startup profiling.
* Enable with PI_TIMING=1 environment variable.
* Enable with COMPANION_TIMING=1 environment variable.
*/
const ENABLED = process.env.PI_TIMING === "1";
const ENABLED = process.env.COMPANION_TIMING === "1";
const timings: Array<{ label: string; ms: number }> = [];
let lastTime = Date.now();

View file

@ -2,7 +2,7 @@ import { randomBytes } from "node:crypto";
import { createWriteStream, existsSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import type { AgentTool } from "@mariozechner/pi-agent-core";
import type { AgentTool } from "@mariozechner/companion-agent-core";
import { type Static, Type } from "@sinclair/typebox";
import { spawn } from "child_process";
import {
@ -23,7 +23,7 @@ import {
*/
function getTempFilePath(): string {
const id = randomBytes(8).toString("hex");
return join(tmpdir(), `pi-bash-${id}.log`);
return join(tmpdir(), `companion-bash-${id}.log`);
}
/**

View file

@ -3,7 +3,7 @@ import { randomBytes } from "node:crypto";
import { existsSync, mkdirSync } from "node:fs";
import { tmpdir } from "node:os";
import { join, resolve } from "node:path";
import type { AgentTool } from "@mariozechner/pi-agent-core";
import type { AgentTool } from "@mariozechner/companion-agent-core";
import { type Static, Type } from "@sinclair/typebox";
import { getAgentDir } from "../../config.js";
import {
@ -28,7 +28,7 @@ const browserSnapshotModes = ["interactive", "full"] as const;
const browserLoadStates = ["load", "domcontentloaded", "networkidle"] as const;
const DEFAULT_BROWSER_COMMAND =
process.env.PI_AGENT_BROWSER_COMMAND || "agent-browser";
process.env.COMPANION_AGENT_BROWSER_COMMAND || "agent-browser";
const DEFAULT_BROWSER_TIMEOUT_SECONDS = 90;
const browserSchema = Type.Object({
@ -78,7 +78,7 @@ const browserSchema = Type.Object({
stateName: Type.Optional(
Type.String({
description:
"Named browser state checkpoint stored under ~/.pi/agent/browser/states/",
"Named browser state checkpoint stored under ~/.companion/agent/browser/states/",
}),
),
});
@ -230,7 +230,7 @@ function getBrowserStateDir(cwd: string, options?: BrowserToolOptions): string {
function createTempScreenshotPath(): string {
const id = randomBytes(8).toString("hex");
return join(tmpdir(), `pi-browser-screenshot-${id}.png`);
return join(tmpdir(), `companion-browser-screenshot-${id}.png`);
}
function normalizeOutput(chunks: Buffer[]): string {

View file

@ -1,4 +1,4 @@
import type { AgentTool } from "@mariozechner/pi-agent-core";
import type { AgentTool } from "@mariozechner/companion-agent-core";
import { type Static, Type } from "@sinclair/typebox";
import { constants } from "fs";
import {

View file

@ -1,4 +1,4 @@
import type { AgentTool } from "@mariozechner/pi-agent-core";
import type { AgentTool } from "@mariozechner/companion-agent-core";
import { type Static, Type } from "@sinclair/typebox";
import { spawnSync } from "child_process";
import { existsSync } from "fs";

View file

@ -1,5 +1,5 @@
import { createInterface } from "node:readline";
import type { AgentTool } from "@mariozechner/pi-agent-core";
import type { AgentTool } from "@mariozechner/companion-agent-core";
import { type Static, Type } from "@sinclair/typebox";
import { spawn } from "child_process";
import { readFileSync, statSync } from "fs";

View file

@ -77,7 +77,7 @@ export {
writeTool,
} from "./write.js";
import type { AgentTool } from "@mariozechner/pi-agent-core";
import type { AgentTool } from "@mariozechner/companion-agent-core";
import { type BashToolOptions, bashTool, createBashTool } from "./bash.js";
import {
browserTool,
@ -91,7 +91,7 @@ import { createLsTool, lsTool } from "./ls.js";
import { createReadTool, type ReadToolOptions, readTool } from "./read.js";
import { createWriteTool, writeTool } from "./write.js";
/** Tool type (AgentTool from pi-ai) */
/** Tool type (AgentTool from companion-ai) */
export type Tool = AgentTool<any>;
// Read-only tools for exploration without modification (using process.cwd())

View file

@ -1,4 +1,4 @@
import type { AgentTool } from "@mariozechner/pi-agent-core";
import type { AgentTool } from "@mariozechner/companion-agent-core";
import { type Static, Type } from "@sinclair/typebox";
import { existsSync, readdirSync, statSync } from "fs";
import nodePath from "path";

View file

@ -1,5 +1,5 @@
import type { AgentTool } from "@mariozechner/pi-agent-core";
import type { ImageContent, TextContent } from "@mariozechner/pi-ai";
import type { AgentTool } from "@mariozechner/companion-agent-core";
import type { ImageContent, TextContent } from "@mariozechner/companion-ai";
import { type Static, Type } from "@sinclair/typebox";
import { constants } from "fs";
import { access as fsAccess, readFile as fsReadFile } from "fs/promises";

View file

@ -1,4 +1,4 @@
import type { AgentTool } from "@mariozechner/pi-agent-core";
import type { AgentTool } from "@mariozechner/companion-agent-core";
import { type Static, Type } from "@sinclair/typebox";
import { mkdir as fsMkdir, writeFile as fsWriteFile } from "fs/promises";
import { dirname } from "path";