Files
paperclip/server/src/home-paths.ts
Forgotten 9f049aa4f3 feat: resolve agent workspace from session/project/fallback
Heartbeat service resolves cwd from task session, project primary
workspace, or agent home directory (~/.paperclip/instances/.../workspaces/).
Adapters receive workspace context and forward it as env vars and
session params. cwd is now optional in adapter config.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 08:38:58 -06:00

63 lines
2.0 KiB
TypeScript

import os from "node:os";
import path from "node:path";
const DEFAULT_INSTANCE_ID = "default";
const INSTANCE_ID_RE = /^[a-zA-Z0-9_-]+$/;
const PATH_SEGMENT_RE = /^[a-zA-Z0-9_-]+$/;
function expandHomePrefix(value: string): string {
if (value === "~") return os.homedir();
if (value.startsWith("~/")) return path.resolve(os.homedir(), value.slice(2));
return value;
}
export function resolvePaperclipHomeDir(): string {
const envHome = process.env.PAPERCLIP_HOME?.trim();
if (envHome) return path.resolve(expandHomePrefix(envHome));
return path.resolve(os.homedir(), ".paperclip");
}
export function resolvePaperclipInstanceId(): string {
const raw = process.env.PAPERCLIP_INSTANCE_ID?.trim() || DEFAULT_INSTANCE_ID;
if (!INSTANCE_ID_RE.test(raw)) {
throw new Error(`Invalid PAPERCLIP_INSTANCE_ID '${raw}'.`);
}
return raw;
}
export function resolvePaperclipInstanceRoot(): string {
return path.resolve(resolvePaperclipHomeDir(), "instances", resolvePaperclipInstanceId());
}
export function resolveDefaultConfigPath(): string {
return path.resolve(resolvePaperclipInstanceRoot(), "config.json");
}
export function resolveDefaultEmbeddedPostgresDir(): string {
return path.resolve(resolvePaperclipInstanceRoot(), "db");
}
export function resolveDefaultLogsDir(): string {
return path.resolve(resolvePaperclipInstanceRoot(), "logs");
}
export function resolveDefaultSecretsKeyFilePath(): string {
return path.resolve(resolvePaperclipInstanceRoot(), "secrets", "master.key");
}
export function resolveDefaultStorageDir(): string {
return path.resolve(resolvePaperclipInstanceRoot(), "data", "storage");
}
export function resolveDefaultAgentWorkspaceDir(agentId: string): string {
const trimmed = agentId.trim();
if (!PATH_SEGMENT_RE.test(trimmed)) {
throw new Error(`Invalid agent id for workspace path '${agentId}'.`);
}
return path.resolve(resolvePaperclipInstanceRoot(), "workspaces", trimmed);
}
export function resolveHomeAwarePath(value: string): string {
return path.resolve(expandHomePrefix(value));
}