Introduces a provider-agnostic storage subsystem for file attachments. Includes local disk and S3 backends, asset/attachment DB schemas, issue attachment CRUD routes with multer upload, CLI configure/doctor/env integration, and enriched issue ancestors with project/goal resolution. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
54 lines
1.7 KiB
TypeScript
54 lines
1.7 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_-]+$/;
|
|
|
|
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 resolveHomeAwarePath(value: string): string {
|
|
return path.resolve(expandHomePrefix(value));
|
|
}
|