@jim80net/memex-core 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/origin.js ADDED
@@ -0,0 +1,490 @@
1
+ /**
2
+ * Shared origin root resolution, symlink projection, and materialize writes.
3
+ *
4
+ * Design: design/shared-origin-sync-profile.md (XO-gated 2026-07-10).
5
+ * Locked: ~/.memex default + resolver; absolute symlinks v1; partial apply
6
+ * + report conflicts; one-release memex-claude → ~/.memex compat symlink.
7
+ */
8
+ import { lstat, mkdir, readdir, readFile, readlink, realpath, rename, rm, symlink, writeFile, } from "node:fs/promises";
9
+ import { homedir } from "node:os";
10
+ import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
11
+ import { withFileLock } from "./file-lock.js";
12
+ import { git, isGitRepo } from "./git-helpers.js";
13
+ // ---------------------------------------------------------------------------
14
+ // Path helpers
15
+ // ---------------------------------------------------------------------------
16
+ const ENV_ORIGIN = "MEMEX_ORIGIN";
17
+ /**
18
+ * Expand `~/…` against homeDir; leave other paths for resolve().
19
+ */
20
+ export function expandUserPath(path, homeDir) {
21
+ if (path === "~")
22
+ return homeDir;
23
+ if (path.startsWith(`~/`) || path.startsWith(`~${sep}`)) {
24
+ return join(homeDir, path.slice(2));
25
+ }
26
+ return path;
27
+ }
28
+ /**
29
+ * Resolve to an absolute path. Rejects empty input.
30
+ */
31
+ export function toAbsolutePath(path, homeDir) {
32
+ const expanded = expandUserPath(path.trim(), homeDir);
33
+ if (!expanded) {
34
+ throw new Error("path must be non-empty");
35
+ }
36
+ return resolve(expanded);
37
+ }
38
+ /**
39
+ * True when `candidate` is exactly `root` or a path under `root`
40
+ * (after resolve). Does not follow symlinks on the inputs.
41
+ */
42
+ export function isPathInsideRoot(root, candidate) {
43
+ const r = resolve(root);
44
+ const c = resolve(candidate);
45
+ if (c === r)
46
+ return true;
47
+ const prefix = r.endsWith(sep) ? r : r + sep;
48
+ return c.startsWith(prefix);
49
+ }
50
+ /**
51
+ * Join origin root + relative path with traversal rejection.
52
+ * `relPath` must not be absolute and must stay under root.
53
+ */
54
+ export function resolveUnderOrigin(originRoot, relPath) {
55
+ const root = resolve(originRoot);
56
+ const cleaned = relPath.replace(/\\/g, "/").replace(/^\/+/, "");
57
+ if (!cleaned || cleaned === ".") {
58
+ throw new Error(`origin-relative path must be non-empty: ${JSON.stringify(relPath)}`);
59
+ }
60
+ if (isAbsolute(relPath) || isAbsolute(cleaned)) {
61
+ throw new Error(`origin-relative path must not be absolute: ${JSON.stringify(relPath)}`);
62
+ }
63
+ const abs = resolve(root, cleaned);
64
+ if (!isPathInsideRoot(root, abs)) {
65
+ throw new Error(`path escapes origin root: ${JSON.stringify(relPath)}`);
66
+ }
67
+ return abs;
68
+ }
69
+ async function pathExists(path) {
70
+ try {
71
+ await lstat(path);
72
+ return true;
73
+ }
74
+ catch {
75
+ return false;
76
+ }
77
+ }
78
+ // ---------------------------------------------------------------------------
79
+ // resolveOriginRoot
80
+ // ---------------------------------------------------------------------------
81
+ /**
82
+ * Resolve the shared origin root.
83
+ *
84
+ * Precedence (XO-locked):
85
+ * 1. explicit `opts.root`
86
+ * 2. env `MEMEX_ORIGIN`
87
+ * 3. existing `~/.memex`
88
+ * 4. existing `~/.local/share/memex` (XDG / historical grok default)
89
+ * 5. existing `~/.local/share/memex-claude` (legacy live corpus)
90
+ * 6. product default `~/.memex` (may not exist yet)
91
+ */
92
+ export async function resolveOriginRoot(opts = {}) {
93
+ const home = opts.homeDir ?? homedir();
94
+ const env = opts.env ?? process.env;
95
+ const preferDefault = opts.preferDefaultWhenMissing !== false;
96
+ const defaultRoot = join(home, ".memex");
97
+ const xdgRoot = join(home, ".local", "share", "memex");
98
+ const legacyClaude = join(home, ".local", "share", "memex-claude");
99
+ if (opts.root !== undefined && opts.root.trim() !== "") {
100
+ const root = toAbsolutePath(opts.root, home);
101
+ return { root, source: "explicit", exists: await pathExists(root) };
102
+ }
103
+ const envVal = env[ENV_ORIGIN];
104
+ if (typeof envVal === "string" && envVal.trim() !== "") {
105
+ const root = toAbsolutePath(envVal, home);
106
+ return { root, source: "env", exists: await pathExists(root) };
107
+ }
108
+ if (await pathExists(defaultRoot)) {
109
+ return { root: resolve(defaultRoot), source: "default", exists: true };
110
+ }
111
+ if (await pathExists(xdgRoot)) {
112
+ return { root: resolve(xdgRoot), source: "xdg", exists: true };
113
+ }
114
+ if (await pathExists(legacyClaude)) {
115
+ return { root: resolve(legacyClaude), source: "legacy-claude", exists: true };
116
+ }
117
+ if (preferDefault) {
118
+ return { root: resolve(defaultRoot), source: "default", exists: false };
119
+ }
120
+ return { root: resolve(defaultRoot), source: "default", exists: false };
121
+ }
122
+ /** Product-default origin path for a given home (does not touch the filesystem). */
123
+ export function defaultOriginRoot(homeDir = homedir()) {
124
+ return resolve(join(homeDir, ".memex"));
125
+ }
126
+ /** Legacy claude corpus path (compat / migrate source). */
127
+ export function legacyClaudeOriginRoot(homeDir = homedir()) {
128
+ return resolve(join(homeDir, ".local", "share", "memex-claude"));
129
+ }
130
+ function patternToSuffix(pattern) {
131
+ // v1: only support "*.ext" style → suffix match
132
+ const p = pattern ?? "*.md";
133
+ if (p.startsWith("*"))
134
+ return p.slice(1);
135
+ return p;
136
+ }
137
+ async function listFileEntries(originDir, suffix) {
138
+ let names;
139
+ try {
140
+ names = await readdir(originDir);
141
+ }
142
+ catch {
143
+ return [];
144
+ }
145
+ const out = [];
146
+ for (const name of names) {
147
+ if (!name.endsWith(suffix))
148
+ continue;
149
+ const absPath = join(originDir, name);
150
+ try {
151
+ const st = await lstat(absPath);
152
+ // Follow only for type check of the origin entry itself if it's a link? Origin
153
+ // entries should be real files. Accept regular files; skip dirs/symlinks-to-dirs.
154
+ if (st.isFile() || (st.isSymbolicLink() && (await isSymlinkToFile(absPath)))) {
155
+ out.push({ name, absPath: resolve(absPath) });
156
+ }
157
+ }
158
+ catch {
159
+ // skip
160
+ }
161
+ }
162
+ return out;
163
+ }
164
+ async function isSymlinkToFile(path) {
165
+ try {
166
+ const st = await lstat(await realpath(path));
167
+ return st.isFile();
168
+ }
169
+ catch {
170
+ return false;
171
+ }
172
+ }
173
+ async function listSkillDirEntries(originDir) {
174
+ let names;
175
+ try {
176
+ names = await readdir(originDir);
177
+ }
178
+ catch {
179
+ return [];
180
+ }
181
+ const out = [];
182
+ for (const name of names) {
183
+ const skillDir = join(originDir, name);
184
+ const skillMd = join(skillDir, "SKILL.md");
185
+ try {
186
+ const dirStat = await lstat(skillDir);
187
+ if (!dirStat.isDirectory() && !dirStat.isSymbolicLink())
188
+ continue;
189
+ const mdStat = await lstat(skillMd);
190
+ if (!mdStat.isFile() && !mdStat.isSymbolicLink())
191
+ continue;
192
+ out.push({ name, absPath: resolve(skillDir) });
193
+ }
194
+ catch {
195
+ // skip
196
+ }
197
+ }
198
+ return out;
199
+ }
200
+ /**
201
+ * Classify existing target path for projection planning.
202
+ * Uses lstat (does not follow the final target symlink for type).
203
+ */
204
+ async function classifyTarget(targetPath, originPath, originRoot, relinkManaged) {
205
+ let st;
206
+ try {
207
+ st = await lstat(targetPath);
208
+ }
209
+ catch {
210
+ return "create";
211
+ }
212
+ if (st.isSymbolicLink()) {
213
+ let linkTarget;
214
+ try {
215
+ linkTarget = await readlink(targetPath);
216
+ }
217
+ catch {
218
+ return "broken-unmanaged";
219
+ }
220
+ // Normalize link target to absolute for comparison (v1 uses absolute links).
221
+ const absLink = isAbsolute(linkTarget)
222
+ ? resolve(linkTarget)
223
+ : resolve(dirname(targetPath), linkTarget);
224
+ const originAbs = resolve(originPath);
225
+ // Same destination (string or realpath when both exist)
226
+ if (absLink === originAbs)
227
+ return "noop";
228
+ try {
229
+ const [a, b] = await Promise.all([realpath(targetPath), realpath(originPath)]);
230
+ if (a === b)
231
+ return "noop";
232
+ }
233
+ catch {
234
+ // broken or missing origin — fall through
235
+ }
236
+ if (isPathInsideRoot(originRoot, absLink)) {
237
+ return relinkManaged ? "relink" : "foreign-symlink";
238
+ }
239
+ // Broken symlink: only relink if the *link text* was under origin
240
+ try {
241
+ await realpath(targetPath);
242
+ // resolved outside origin
243
+ return "foreign-symlink";
244
+ }
245
+ catch {
246
+ if (relinkManaged && isPathInsideRoot(originRoot, absLink)) {
247
+ return "relink";
248
+ }
249
+ return "broken-unmanaged";
250
+ }
251
+ }
252
+ if (st.isDirectory())
253
+ return "real-dir";
254
+ if (st.isFile())
255
+ return "real-file";
256
+ return "type-mismatch";
257
+ }
258
+ /**
259
+ * Build a projection plan: which dirs to ensure, which links to create/relink/noop,
260
+ * and which paths conflict (fail-closed — never clobber real files).
261
+ */
262
+ export async function planProjection(originRoot, targets, opts = {}) {
263
+ const root = resolve(originRoot);
264
+ const relinkManaged = opts.relinkManaged !== false;
265
+ const ensureDirs = new Set();
266
+ const links = [];
267
+ const conflicts = [];
268
+ for (const target of targets) {
269
+ const targetDir = resolve(target.targetDir);
270
+ const originDir = resolveUnderOrigin(root, target.originRelDir);
271
+ const initDir = target.initTargetDir !== false;
272
+ if (initDir)
273
+ ensureDirs.add(targetDir);
274
+ const entries = target.entryKind === "skill-dirs"
275
+ ? await listSkillDirEntries(originDir)
276
+ : await listFileEntries(originDir, patternToSuffix(target.pattern));
277
+ for (const entry of entries) {
278
+ const targetPath = join(targetDir, entry.name);
279
+ const originPath = entry.absPath;
280
+ if (!isPathInsideRoot(root, originPath)) {
281
+ conflicts.push({
282
+ targetPath,
283
+ originPath,
284
+ reason: "type-mismatch",
285
+ });
286
+ continue;
287
+ }
288
+ const decision = await classifyTarget(targetPath, originPath, root, relinkManaged);
289
+ if (decision === "create" || decision === "relink" || decision === "noop") {
290
+ links.push({ targetPath, originPath, action: decision });
291
+ }
292
+ else {
293
+ conflicts.push({ targetPath, originPath, reason: decision });
294
+ }
295
+ }
296
+ }
297
+ return {
298
+ ensureDirs: [...ensureDirs].sort(),
299
+ links,
300
+ conflicts,
301
+ };
302
+ }
303
+ /**
304
+ * Apply a projection plan with **partial success**: non-conflicting links are
305
+ * applied; conflicts are reported and never applied (XO-locked).
306
+ *
307
+ * Symlinks are **absolute** (v1).
308
+ */
309
+ export async function applyProjection(plan, _opts = {}) {
310
+ for (const dir of plan.ensureDirs) {
311
+ await mkdir(dir, { recursive: true });
312
+ }
313
+ let linked = 0;
314
+ let skipped = 0;
315
+ for (const link of plan.links) {
316
+ if (link.action === "noop") {
317
+ skipped++;
318
+ continue;
319
+ }
320
+ // Parent of target (may be deeper than ensureDirs for safety)
321
+ await mkdir(dirname(link.targetPath), { recursive: true });
322
+ if (link.action === "relink") {
323
+ await rm(link.targetPath, { force: true });
324
+ }
325
+ // Absolute symlink (v1)
326
+ const originAbs = resolve(link.originPath);
327
+ await symlink(originAbs, link.targetPath);
328
+ linked++;
329
+ }
330
+ return {
331
+ linked,
332
+ skipped,
333
+ conflicts: [...plan.conflicts],
334
+ };
335
+ }
336
+ // ---------------------------------------------------------------------------
337
+ // materializeEntry
338
+ // ---------------------------------------------------------------------------
339
+ /**
340
+ * Write one corpus entry under origin.root with per-file lock.
341
+ * Does not commit. Rejects path traversal outside origin.
342
+ */
343
+ export async function materializeEntry(originRoot, input) {
344
+ const absPath = resolveUnderOrigin(originRoot, input.originRelPath);
345
+ // Parent dirs must exist before acquireLock (lock is `${absPath}.lock` via mkdir).
346
+ await mkdir(dirname(absPath), { recursive: true });
347
+ return withFileLock(absPath, async () => {
348
+ let existing = null;
349
+ try {
350
+ const st = await lstat(absPath);
351
+ if (st.isSymbolicLink()) {
352
+ return {
353
+ status: "conflict",
354
+ absPath,
355
+ reason: "destination is a symlink; refuse to materialize through unmanaged link",
356
+ };
357
+ }
358
+ if (st.isDirectory()) {
359
+ return {
360
+ status: "conflict",
361
+ absPath,
362
+ reason: "destination is a directory",
363
+ };
364
+ }
365
+ existing = await readFile(absPath, "utf-8");
366
+ }
367
+ catch {
368
+ existing = null;
369
+ }
370
+ if (existing !== null) {
371
+ if (existing === input.content) {
372
+ return { status: "unchanged", absPath };
373
+ }
374
+ if (input.failIfChanged) {
375
+ return {
376
+ status: "conflict",
377
+ absPath,
378
+ reason: "destination exists with different content (failIfChanged)",
379
+ };
380
+ }
381
+ await writeFile(absPath, input.content, "utf-8");
382
+ return { status: "updated", absPath };
383
+ }
384
+ await writeFile(absPath, input.content, "utf-8");
385
+ return { status: "created", absPath };
386
+ });
387
+ }
388
+ /**
389
+ * Stage and commit specific origin-relative paths when origin is a git repo.
390
+ * Does not push.
391
+ */
392
+ export async function commitOriginPaths(originRoot, relPaths, message) {
393
+ const root = resolve(originRoot);
394
+ if (!(await isGitRepo(root)))
395
+ return "not-a-repo";
396
+ try {
397
+ const absPaths = [];
398
+ for (const rel of relPaths) {
399
+ absPaths.push(resolveUnderOrigin(root, rel));
400
+ }
401
+ // git add prefers paths relative to repo root
402
+ for (const abs of absPaths) {
403
+ const rel = relative(root, abs);
404
+ await git(["add", "--", rel], root);
405
+ }
406
+ const { stdout } = await git(["status", "--porcelain"], root);
407
+ if (!stdout.trim())
408
+ return "no-changes";
409
+ await git(["commit", "-m", message], root);
410
+ return "committed";
411
+ }
412
+ catch (err) {
413
+ return `failed: ${err instanceof Error ? err.message : String(err)}`;
414
+ }
415
+ }
416
+ /**
417
+ * Install one-release backward-compat symlink:
418
+ * `~/.local/share/memex-claude` → `~/.memex` (or custom paths).
419
+ *
420
+ * Fail-closed if legacy path is a real file/dir (non-link).
421
+ */
422
+ export async function installLegacyOriginCompatSymlink(defaultRoot, opts = {}) {
423
+ const home = opts.homeDir ?? homedir();
424
+ const legacy = resolve(opts.legacyPath ?? legacyClaudeOriginRoot(home));
425
+ const dest = resolve(defaultRoot);
426
+ if (!(await pathExists(dest))) {
427
+ return "skipped-missing-default";
428
+ }
429
+ try {
430
+ const st = await lstat(legacy);
431
+ if (st.isSymbolicLink()) {
432
+ const cur = await readlink(legacy);
433
+ const absCur = isAbsolute(cur) ? resolve(cur) : resolve(dirname(legacy), cur);
434
+ if (absCur === dest)
435
+ return "already";
436
+ try {
437
+ if ((await realpath(legacy)) === (await realpath(dest)))
438
+ return "already";
439
+ }
440
+ catch {
441
+ // fall through to conflict if we cannot safely replace
442
+ }
443
+ return "conflict";
444
+ }
445
+ return "conflict";
446
+ }
447
+ catch {
448
+ // missing — create
449
+ }
450
+ await mkdir(dirname(legacy), { recursive: true });
451
+ await symlink(dest, legacy);
452
+ return "created";
453
+ }
454
+ /**
455
+ * Move an existing origin tree to the product default (`~/.memex`) and
456
+ * optionally install the one-release legacy compat symlink.
457
+ */
458
+ export async function migrateOriginToDefault(opts = {}) {
459
+ const home = opts.homeDir ?? homedir();
460
+ const to = defaultOriginRoot(home);
461
+ const from = resolve(opts.from ?? legacyClaudeOriginRoot(home));
462
+ if (from === to) {
463
+ return { status: "already-at-default", root: to };
464
+ }
465
+ if (!(await pathExists(from))) {
466
+ return { status: "source-missing", from };
467
+ }
468
+ if (await pathExists(to)) {
469
+ return { status: "destination-exists", to };
470
+ }
471
+ try {
472
+ await mkdir(dirname(to), { recursive: true });
473
+ await rename(from, to);
474
+ }
475
+ catch (err) {
476
+ return {
477
+ status: "failed",
478
+ reason: err instanceof Error ? err.message : String(err),
479
+ };
480
+ }
481
+ let compat = "skipped-missing-default";
482
+ if (opts.installCompatSymlink !== false) {
483
+ compat = await installLegacyOriginCompatSymlink(to, {
484
+ legacyPath: from,
485
+ homeDir: home,
486
+ });
487
+ }
488
+ return { status: "migrated", from, to, compat };
489
+ }
490
+ //# sourceMappingURL=origin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"origin.js","sourceRoot":"","sources":["../src/origin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,84 @@
1
+ import type { ScanDirs } from "./skill-index.js";
2
+ /** A scan root with a stable, host-free label for portable handles. */
3
+ export type ScanRoot = {
4
+ key: string;
5
+ rootPath: string;
6
+ };
7
+ export type ScanRootRegistry = ScanRoot[];
8
+ export type ScanRootSpec = ScanDirs;
9
+ export type HarnessKind = "grok" | "claude" | "codex" | "hermes";
10
+ export type ScanRootContext = {
11
+ cwd: string;
12
+ syncRepoDir?: string;
13
+ syncEnabled?: boolean;
14
+ globalSkillsDirs: string[];
15
+ globalRulesDirs: string[];
16
+ projectSkillsDir: string;
17
+ projectRulesDir: string;
18
+ harness: HarnessKind;
19
+ };
20
+ export declare const HANDLE_PREFIX = "memex://";
21
+ export type PortableLocationWarn = (message: string) => void;
22
+ /** Filesystem path + optional memory section name (fragment decoded once). */
23
+ export type ResolvedPortableLocation = {
24
+ filePath: string;
25
+ sectionName?: string;
26
+ };
27
+ /**
28
+ * Portable handles are opaque location tokens — not general URIs.
29
+ * Form: memex://{rootKey}/{posix-rel}[#{fragment}]
30
+ */
31
+ /** Injective escape for rel segments and fragments (% first, then #). */
32
+ export declare function escapePortableText(text: string): string;
33
+ /** Reverse of escapePortableText (# last on decode, then %). */
34
+ export declare function unescapePortableText(text: string): string;
35
+ /** @alias escapePortableText */
36
+ export declare const encodeFragment: typeof escapePortableText;
37
+ /** @alias unescapePortableText */
38
+ export declare const decodeFragment: typeof unescapePortableText;
39
+ /**
40
+ * Split at the last literal '#' — escaped #s are %23 and do not split.
41
+ * Fragment is unescaped exactly once.
42
+ */
43
+ export declare function splitPortableHandle(handle: string): {
44
+ body: string;
45
+ fragment?: string;
46
+ };
47
+ /** Stable fallback rootKey from normalized absolute dir path (§4.4 path-hash option). */
48
+ export declare function stableUnclassifiedKey(kind: "skill" | "rule" | "memory", dir: string): string;
49
+ /**
50
+ * Build labeled scan roots from harness context and scan directory spec.
51
+ * Same semantic root MUST use the same rootKey on every host (normative catalog).
52
+ */
53
+ export declare function buildScanRoots(ctx: ScanRootContext, spec: ScanRootSpec): ScanRootRegistry;
54
+ /**
55
+ * Absolute path (+ optional #fragment) → portable handle.
56
+ * Fail-open: returns null when mapping is impossible (caller should skip-with-warning).
57
+ */
58
+ export declare function encodePortableLocation(registry: ScanRootRegistry, absolute: string, warn?: PortableLocationWarn, fragment?: string): string | null;
59
+ /**
60
+ * Portable handle → absolute file path + optional section name.
61
+ * Fragment is split and %23-unescaped exactly once — never rejoin with '#'.
62
+ * Fail-closed on traversal escape.
63
+ */
64
+ export declare function decodePortableLocationResolved(registry: ScanRootRegistry, handle: string): ResolvedPortableLocation;
65
+ /**
66
+ * Portable handle → absolute path string (legacy join form).
67
+ * Prefer decodePortableLocationResolved when a fragment may be present.
68
+ */
69
+ export declare function decodePortableLocation(registry: ScanRootRegistry, handle: string): string;
70
+ /**
71
+ * Resolve portable handle or legacy absolute path for filesystem I/O.
72
+ * Phase 2: agent-facing read tools MUST pass `allowAbsolute: false` so untrusted
73
+ * absolute paths cannot bypass containment (memex-grok#19 closes only then).
74
+ */
75
+ export declare function resolvePortableLocationResolved(registry: ScanRootRegistry, input: string, options?: {
76
+ warn?: PortableLocationWarn;
77
+ allowAbsolute?: boolean;
78
+ }): ResolvedPortableLocation;
79
+ /** @deprecated Prefer resolvePortableLocationResolved to avoid fragment double-decode. */
80
+ export declare function resolvePortableLocation(registry: ScanRootRegistry, input: string, options?: {
81
+ warn?: PortableLocationWarn;
82
+ allowAbsolute?: boolean;
83
+ }): string;
84
+ //# sourceMappingURL=portable-location.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"portable-location.d.ts","sourceRoot":"","sources":["../src/portable-location.ts"],"names":[],"mappings":"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"}