Lines 5-45typescript
5import { mkdirSync, writeFileSync, copyFileSync, existsSync, chmodSync, readFileSync, readdirSync } from "node:fs";
6import { resolve, join, dirname, sep } from "node:path";
7import { homedir } from "node:os";
8import { runMain } from "./config.ts";
10const SRC = import.meta.dir; // package/src — holds the operational .ts to vendor
11const PKG = resolve(SRC, ".."); // package root — holds templates/
12const TEMPLATES = join(PKG, "templates");
14export const OPERATIONAL = [
15 "frontmatter.ts", "config.ts", "validate-logs.ts", "validate-vault.ts",
16 "capture.ts", "consolidate.ts", "dashboard.ts",
17 "index.ts", "snapshot.ts", "search.ts", "nightly.ts", "log-turn.ts", "link.ts",
20interface Item { value: string; dir: string; bucket: "semantic" | "episodic" | "extra"; label: string; selected: boolean
21interface Preset { items: Item[]; }
23function loadPreset(name: string): Preset {
24 if (!name || /[\/\\]/.test(name) || name === "." || name === "..")
25 throw new Error(`invalid --preset '${name}': must be a plain preset name, no path separators`);
26 return JSON.parse(readFileSync(join(TEMPLATES, "presets", `${name}.json`), "utf8"));
27}
MediumInstall Persistence
Source writes installer persistence such as shell profile or service configuration.
src/init.tsView on unpkg · L25 29/** join() that refuses to resolve outside `base` — blocks `..`-style traversal in user-supplied dir names. */
30function safeJoin(base: string, rel: string): string {
31 const full = resolve(base, rel);
32 if (full !== base && !full.startsWith(base + sep))
33 throw new Error(`unsafe path '${rel}' escapes target directory`);
37function buildConfig(name: string, items: Item[]) {
38 const semantic: Record<string, string> = {};
39 const episodic: Record<string, string> = {};
40 const extra: string[] = [];
41 for (const it of items) {
42 if (it.bucket === "semantic") semantic[it.value] = it.dir;
43 else if (it.bucket === "episodic") episodic[it.value] = it.dir;
44 else extra.push(it.dir);