mirror of
https://github.com/luckyyzh/pi-agent-integrated.git
synced 2026-10-03 02:59:35 +00:00
124 lines
3.8 KiB
TypeScript
124 lines
3.8 KiB
TypeScript
import { existsSync, realpathSync } from "fs";
|
|
import { isAbsolute, relative, resolve, sep } from "path";
|
|
import {
|
|
SettingsManager,
|
|
type ResourceDiagnostic,
|
|
type Skill,
|
|
} from "@earendil-works/pi-coding-agent";
|
|
|
|
export const MANAGED_RUNTIME_ENV = "PI_AGENT_MANAGED_RUNTIME";
|
|
|
|
export interface ManagedRuntimePaths {
|
|
appRoot: string;
|
|
dataDir: string;
|
|
agentDir: string;
|
|
resourcesDir: string;
|
|
skillsHomeDir: string;
|
|
stateDir: string;
|
|
managedSkillRoots: string[];
|
|
}
|
|
|
|
export interface AppResourceLoaderOptions {
|
|
additionalExtensionPaths?: string[];
|
|
additionalSkillPaths?: string[];
|
|
additionalPromptTemplatePaths?: string[];
|
|
additionalThemePaths?: string[];
|
|
skillsOverride?: (base: { skills: Skill[]; diagnostics: ResourceDiagnostic[] }) => {
|
|
skills: Skill[];
|
|
diagnostics: ResourceDiagnostic[];
|
|
};
|
|
}
|
|
|
|
export function isManagedRuntime(): boolean {
|
|
return process.env[MANAGED_RUNTIME_ENV] === "1";
|
|
}
|
|
|
|
function requiredPath(name: string): string {
|
|
const value = process.env[name];
|
|
if (!value) throw new Error(`${name} is required in managed runtime mode`);
|
|
return resolve(value);
|
|
}
|
|
|
|
export function getManagedRuntimePaths(): ManagedRuntimePaths {
|
|
const appRoot = requiredPath("PI_AGENT_APP_ROOT");
|
|
const dataDir = requiredPath("PI_AGENT_DATA_DIR");
|
|
const agentDir = requiredPath("PI_CODING_AGENT_DIR");
|
|
const resourcesDir = requiredPath("PI_AGENT_RESOURCES_DIR");
|
|
const skillsHomeDir = requiredPath("PI_AGENT_SKILLS_HOME");
|
|
const stateDir = resolve(process.env.XDG_STATE_HOME ?? `${dataDir}/state`);
|
|
return {
|
|
appRoot,
|
|
dataDir,
|
|
agentDir,
|
|
resourcesDir,
|
|
skillsHomeDir,
|
|
stateDir,
|
|
managedSkillRoots: [
|
|
resolve(resourcesDir, "skills"),
|
|
resolve(agentDir, "skills"),
|
|
resolve(skillsHomeDir, ".agents", "skills"),
|
|
resolve(skillsHomeDir, ".pi", "agent", "skills"),
|
|
],
|
|
};
|
|
}
|
|
|
|
function canonicalPath(path: string): string {
|
|
const resolved = resolve(path);
|
|
if (!existsSync(resolved)) return resolved;
|
|
try {
|
|
return realpathSync.native(resolved);
|
|
} catch {
|
|
return resolved;
|
|
}
|
|
}
|
|
|
|
export function isManagedPath(path: string): boolean {
|
|
if (!isManagedRuntime()) return true;
|
|
const candidate = canonicalPath(path);
|
|
const { appRoot, dataDir, resourcesDir } = getManagedRuntimePaths();
|
|
return [appRoot, dataDir, resourcesDir].some((root) => {
|
|
const rel = relative(canonicalPath(root), candidate);
|
|
return rel === "" || (rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute(rel));
|
|
});
|
|
}
|
|
|
|
export function createAppSettingsManager(
|
|
cwd: string,
|
|
agentDir: string,
|
|
projectTrusted = true,
|
|
): SettingsManager {
|
|
return SettingsManager.create(cwd, agentDir, {
|
|
projectTrusted: isManagedRuntime() ? false : projectTrusted,
|
|
});
|
|
}
|
|
|
|
export function getAppResourceLoaderOptions(): AppResourceLoaderOptions {
|
|
if (!isManagedRuntime()) return {};
|
|
|
|
const { resourcesDir, managedSkillRoots } = getManagedRuntimePaths();
|
|
return {
|
|
additionalExtensionPaths: [resolve(resourcesDir, "extensions")],
|
|
additionalSkillPaths: managedSkillRoots,
|
|
additionalPromptTemplatePaths: [resolve(resourcesDir, "prompts")],
|
|
additionalThemePaths: [resolve(resourcesDir, "themes")],
|
|
skillsOverride: ({ skills, diagnostics }) => ({
|
|
skills: skills.filter((skill) => isManagedPath(skill.filePath)),
|
|
diagnostics: diagnostics.filter((diagnostic) => !diagnostic.path || isManagedPath(diagnostic.path)),
|
|
}),
|
|
};
|
|
}
|
|
|
|
export function getSkillsCliEnvironment(): NodeJS.ProcessEnv {
|
|
if (!isManagedRuntime()) return { ...process.env, FORCE_COLOR: "0" };
|
|
|
|
const { dataDir, skillsHomeDir, stateDir } = getManagedRuntimePaths();
|
|
return {
|
|
...process.env,
|
|
HOME: skillsHomeDir,
|
|
USERPROFILE: skillsHomeDir,
|
|
XDG_STATE_HOME: stateDir,
|
|
npm_config_cache: resolve(dataDir, "cache", "npm"),
|
|
FORCE_COLOR: "0",
|
|
};
|
|
}
|