mirror of
https://github.com/luckyyzh/pi-agent-integrated.git
synced 2026-10-03 02:59:35 +00:00
feat: integrate Pi backend and Pi Web
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
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",
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user