@drewpayment/mink 0.10.0 → 0.11.0-beta.1

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.
Files changed (60) hide show
  1. package/README.md +62 -1
  2. package/dashboard/out/404.html +1 -1
  3. package/dashboard/out/action-log.html +1 -1
  4. package/dashboard/out/action-log.txt +1 -1
  5. package/dashboard/out/activity.html +1 -1
  6. package/dashboard/out/activity.txt +1 -1
  7. package/dashboard/out/bugs.html +1 -1
  8. package/dashboard/out/bugs.txt +1 -1
  9. package/dashboard/out/capture.html +1 -1
  10. package/dashboard/out/capture.txt +1 -1
  11. package/dashboard/out/config.html +1 -1
  12. package/dashboard/out/config.txt +1 -1
  13. package/dashboard/out/daemon.html +1 -1
  14. package/dashboard/out/daemon.txt +1 -1
  15. package/dashboard/out/design.html +1 -1
  16. package/dashboard/out/design.txt +1 -1
  17. package/dashboard/out/discord.html +1 -1
  18. package/dashboard/out/discord.txt +1 -1
  19. package/dashboard/out/file-index.html +1 -1
  20. package/dashboard/out/file-index.txt +1 -1
  21. package/dashboard/out/index.html +1 -1
  22. package/dashboard/out/index.txt +1 -1
  23. package/dashboard/out/insights.html +1 -1
  24. package/dashboard/out/insights.txt +1 -1
  25. package/dashboard/out/learning.html +1 -1
  26. package/dashboard/out/learning.txt +1 -1
  27. package/dashboard/out/overview.html +1 -1
  28. package/dashboard/out/overview.txt +1 -1
  29. package/dashboard/out/scheduler.html +1 -1
  30. package/dashboard/out/scheduler.txt +1 -1
  31. package/dashboard/out/sync.html +1 -1
  32. package/dashboard/out/sync.txt +1 -1
  33. package/dashboard/out/tokens.html +1 -1
  34. package/dashboard/out/tokens.txt +1 -1
  35. package/dashboard/out/waste.html +1 -1
  36. package/dashboard/out/waste.txt +1 -1
  37. package/dashboard/out/wiki.html +1 -1
  38. package/dashboard/out/wiki.txt +1 -1
  39. package/dist/cli.js +1505 -896
  40. package/package.json +1 -1
  41. package/src/cli.ts +1 -1
  42. package/src/commands/init.ts +29 -4
  43. package/src/commands/note.ts +2 -2
  44. package/src/commands/scan.ts +29 -6
  45. package/src/commands/session-start.ts +8 -2
  46. package/src/commands/sync-migrate.ts +404 -7
  47. package/src/commands/sync.ts +5 -2
  48. package/src/commands/wiki.ts +19 -3
  49. package/src/core/dashboard-server.ts +13 -5
  50. package/src/core/git-identity.ts +120 -0
  51. package/src/core/note-index.ts +50 -1
  52. package/src/core/paths.ts +19 -3
  53. package/src/core/project-id.ts +142 -5
  54. package/src/core/project-registry.ts +122 -13
  55. package/src/core/scanner.ts +19 -3
  56. package/src/core/sync.ts +7 -1
  57. package/src/types/config.ts +9 -0
  58. package/src/types/note.ts +1 -0
  59. /package/dashboard/out/_next/static/{frTrvF6NV-Xl2bLk21NkY → WDjkNLHEd_wI-oOzLyblH}/_buildManifest.js +0 -0
  60. /package/dashboard/out/_next/static/{frTrvF6NV-Xl2bLk21NkY → WDjkNLHEd_wI-oOzLyblH}/_ssgManifest.js +0 -0
package/dist/cli.js CHANGED
@@ -163,19 +163,598 @@ function isSessionState(value) {
163
163
  }
164
164
  var init_session = () => {};
165
165
 
166
+ // src/core/git-identity.ts
167
+ import { execSync } from "child_process";
168
+ import { existsSync, realpathSync } from "fs";
169
+ function gitOut(cwd, args) {
170
+ if (!existsSync(cwd))
171
+ return null;
172
+ try {
173
+ return execSync(`git ${args}`, {
174
+ cwd,
175
+ timeout: GIT_TIMEOUT_MS,
176
+ stdio: ["pipe", "pipe", "pipe"]
177
+ }).toString().trim();
178
+ } catch {
179
+ return null;
180
+ }
181
+ }
182
+ function canonicalCwd(cwd) {
183
+ try {
184
+ return realpathSync(cwd);
185
+ } catch {
186
+ return cwd;
187
+ }
188
+ }
189
+ function getRepoRoot(cwd) {
190
+ const root = gitOut(canonicalCwd(cwd), "rev-parse --show-toplevel");
191
+ return root && root.length > 0 ? root : null;
192
+ }
193
+ function getRepoSubpath(cwd) {
194
+ const prefix = gitOut(canonicalCwd(cwd), "rev-parse --show-prefix");
195
+ if (prefix === null)
196
+ return "";
197
+ return prefix.replace(/\\/g, "/").replace(/\/+$/, "").replace(/^\/+/, "");
198
+ }
199
+ function getRepoRemote(cwd) {
200
+ const c = canonicalCwd(cwd);
201
+ const origin = gitOut(c, "config --get remote.origin.url");
202
+ if (origin && origin.length > 0)
203
+ return origin;
204
+ const list = gitOut(c, "remote");
205
+ if (!list)
206
+ return null;
207
+ const remotes = list.split(`
208
+ `).map((s) => s.trim()).filter((s) => s.length > 0).sort();
209
+ if (remotes.length === 0)
210
+ return null;
211
+ const url = gitOut(c, `config --get remote.${remotes[0]}.url`);
212
+ return url && url.length > 0 ? url : null;
213
+ }
214
+ function normalizeRemoteUrl(url) {
215
+ if (!url)
216
+ return "";
217
+ let s = url.trim();
218
+ if (s.length === 0)
219
+ return "";
220
+ if (/^(file:|\.\.?\/|\/)/i.test(s))
221
+ return "";
222
+ const scp = s.match(/^([^@\s]+)@([^:\s]+):(.+)$/);
223
+ if (scp) {
224
+ s = `ssh://${scp[1]}@${scp[2]}/${scp[3]}`;
225
+ }
226
+ s = s.replace(/^[a-z][a-z0-9+.-]*:\/\//i, "");
227
+ s = s.replace(/^[^@/]*@/, "");
228
+ s = s.replace(/\/+$/, "").replace(/\.git$/i, "");
229
+ return s.toLowerCase();
230
+ }
231
+ function deriveGitIdentity(cwd) {
232
+ const root = getRepoRoot(cwd);
233
+ if (!root)
234
+ return null;
235
+ const remoteRaw = getRepoRemote(cwd);
236
+ if (!remoteRaw)
237
+ return null;
238
+ const remote = normalizeRemoteUrl(remoteRaw);
239
+ if (!remote)
240
+ return null;
241
+ const subpath = getRepoSubpath(cwd);
242
+ return { remote, subpath };
243
+ }
244
+ var GIT_TIMEOUT_MS = 2000;
245
+ var init_git_identity = () => {};
246
+
247
+ // src/core/fs-utils.ts
248
+ var exports_fs_utils = {};
249
+ __export(exports_fs_utils, {
250
+ safeReadJson: () => safeReadJson,
251
+ safeAppendText: () => safeAppendText,
252
+ atomicWriteText: () => atomicWriteText,
253
+ atomicWriteJson: () => atomicWriteJson
254
+ });
255
+ import { writeFileSync, readFileSync, appendFileSync, renameSync, mkdirSync } from "fs";
256
+ import { dirname } from "path";
257
+ function atomicWriteJson(filePath, data) {
258
+ const tmp = filePath + ".tmp";
259
+ mkdirSync(dirname(filePath), { recursive: true });
260
+ writeFileSync(tmp, JSON.stringify(data, null, 2));
261
+ renameSync(tmp, filePath);
262
+ }
263
+ function atomicWriteText(filePath, content) {
264
+ const tmp = filePath + ".tmp";
265
+ mkdirSync(dirname(filePath), { recursive: true });
266
+ writeFileSync(tmp, content);
267
+ renameSync(tmp, filePath);
268
+ }
269
+ function safeAppendText(filePath, content) {
270
+ mkdirSync(dirname(filePath), { recursive: true });
271
+ appendFileSync(filePath, content);
272
+ }
273
+ function safeReadJson(filePath) {
274
+ try {
275
+ const raw = readFileSync(filePath, "utf-8");
276
+ return JSON.parse(raw);
277
+ } catch {
278
+ return null;
279
+ }
280
+ }
281
+ var init_fs_utils = () => {};
282
+
283
+ // src/types/config.ts
284
+ function isValidConfigKey(key) {
285
+ return VALID_KEYS.has(key);
286
+ }
287
+ function getConfigKeyMeta(key) {
288
+ return CONFIG_KEYS.find((k) => k.key === key);
289
+ }
290
+ var CONFIG_KEYS, VALID_KEYS;
291
+ var init_config = __esm(() => {
292
+ CONFIG_KEYS = [
293
+ {
294
+ key: "wiki.path",
295
+ default: "~/.mink/wiki",
296
+ envVar: "MINK_WIKI_PATH",
297
+ description: "Wiki vault location",
298
+ scope: "local"
299
+ },
300
+ {
301
+ key: "wiki.enabled",
302
+ default: "true",
303
+ envVar: "MINK_WIKI_ENABLED",
304
+ description: "Enable/disable the wiki feature",
305
+ scope: "shared"
306
+ },
307
+ {
308
+ key: "wiki.sync-mode",
309
+ default: "immediate",
310
+ envVar: "MINK_WIKI_SYNC_MODE",
311
+ description: "Sync mode: immediate or batched",
312
+ scope: "shared"
313
+ },
314
+ {
315
+ key: "wiki.git-backup",
316
+ default: "false",
317
+ envVar: "MINK_WIKI_GIT_BACKUP",
318
+ description: "Deprecated: use sync.enabled instead",
319
+ scope: "shared"
320
+ },
321
+ {
322
+ key: "wiki.git-remote",
323
+ default: "origin",
324
+ envVar: "MINK_WIKI_GIT_REMOTE",
325
+ description: "Deprecated: use sync.remote-url instead",
326
+ scope: "shared"
327
+ },
328
+ {
329
+ key: "notes.default-category",
330
+ default: "inbox",
331
+ envVar: "MINK_NOTES_DEFAULT_CATEGORY",
332
+ description: "Default category for notes captured via CLI",
333
+ scope: "shared"
334
+ },
335
+ {
336
+ key: "sync.enabled",
337
+ default: "false",
338
+ envVar: "MINK_SYNC_ENABLED",
339
+ description: "Enable/disable automatic git sync of ~/.mink",
340
+ scope: "shared"
341
+ },
342
+ {
343
+ key: "sync.remote-url",
344
+ default: "",
345
+ envVar: "MINK_SYNC_REMOTE_URL",
346
+ description: "Git remote URL for ~/.mink sync",
347
+ scope: "shared"
348
+ },
349
+ {
350
+ key: "sync.last-push",
351
+ default: "",
352
+ envVar: "MINK_SYNC_LAST_PUSH",
353
+ description: "ISO timestamp of last successful sync push",
354
+ scope: "local"
355
+ },
356
+ {
357
+ key: "sync.last-pull",
358
+ default: "",
359
+ envVar: "MINK_SYNC_LAST_PULL",
360
+ description: "ISO timestamp of last successful sync pull",
361
+ scope: "local"
362
+ },
363
+ {
364
+ key: "channel.discord.bot-token",
365
+ default: "",
366
+ envVar: "MINK_CHANNEL_DISCORD_BOT_TOKEN",
367
+ description: "Discord bot token for Claude Code Channels",
368
+ scope: "local"
369
+ },
370
+ {
371
+ key: "channel.discord.enabled",
372
+ default: "false",
373
+ envVar: "MINK_CHANNEL_DISCORD_ENABLED",
374
+ description: "Auto-start Discord channel when daemon starts",
375
+ scope: "local"
376
+ },
377
+ {
378
+ key: "channel.discord.allowlist",
379
+ default: "",
380
+ envVar: "MINK_CHANNEL_DISCORD_ALLOWLIST",
381
+ description: "Comma-separated list of Discord user IDs permitted to DM the bot",
382
+ scope: "local"
383
+ },
384
+ {
385
+ key: "channel.default-platform",
386
+ default: "discord",
387
+ envVar: "MINK_CHANNEL_DEFAULT_PLATFORM",
388
+ description: "Default platform for mink channel start",
389
+ scope: "shared"
390
+ },
391
+ {
392
+ key: "channel.skip-permissions",
393
+ default: "true",
394
+ envVar: "MINK_CHANNEL_SKIP_PERMISSIONS",
395
+ description: "Pass --dangerously-skip-permissions so the channel can run without terminal prompts",
396
+ scope: "shared"
397
+ },
398
+ {
399
+ key: "cli.auto-update",
400
+ default: "false",
401
+ envVar: "MINK_CLI_AUTO_UPDATE",
402
+ description: "Auto-upgrade the mink CLI on schedule via the background scheduler",
403
+ scope: "shared"
404
+ },
405
+ {
406
+ key: "cli.auto-update-schedule",
407
+ default: "0 4 * * *",
408
+ envVar: "MINK_CLI_AUTO_UPDATE_SCHEDULE",
409
+ description: "Cron expression governing the cli-self-update scheduled task",
410
+ scope: "shared"
411
+ },
412
+ {
413
+ key: "cli.auto-update-package-manager",
414
+ default: "auto",
415
+ envVar: "MINK_CLI_AUTO_UPDATE_PACKAGE_MANAGER",
416
+ description: "Force a package manager (auto|npm|bun) for self-upgrade installs",
417
+ scope: "local"
418
+ },
419
+ {
420
+ key: "projects.identity",
421
+ default: "path-derived",
422
+ envVar: "MINK_PROJECTS_IDENTITY",
423
+ description: "Project identity strategy: path-derived (legacy) or git-remote (stable across machines)",
424
+ scope: "shared"
425
+ }
426
+ ];
427
+ VALID_KEYS = new Set(CONFIG_KEYS.map((k) => k.key));
428
+ });
429
+
430
+ // src/core/global-config.ts
431
+ var exports_global_config = {};
432
+ __export(exports_global_config, {
433
+ setConfigValue: () => setConfigValue,
434
+ saveLocalConfig: () => saveLocalConfig,
435
+ saveGlobalConfig: () => saveGlobalConfig,
436
+ resolveConfigValue: () => resolveConfigValue,
437
+ resolveAllConfig: () => resolveAllConfig,
438
+ resetConfigKey: () => resetConfigKey,
439
+ resetAllConfig: () => resetAllConfig,
440
+ migrateConfigIfNeeded: () => migrateConfigIfNeeded,
441
+ loadLocalConfig: () => loadLocalConfig,
442
+ loadGlobalConfig: () => loadGlobalConfig
443
+ });
444
+ function loadConfigFile(path) {
445
+ const raw = safeReadJson(path);
446
+ if (raw === null)
447
+ return {};
448
+ if (typeof raw !== "object" || Array.isArray(raw)) {
449
+ console.warn("[mink] warning: corrupt config file at " + path);
450
+ return {};
451
+ }
452
+ return raw;
453
+ }
454
+ function loadGlobalConfig() {
455
+ return loadConfigFile(globalConfigPath());
456
+ }
457
+ function saveGlobalConfig(config) {
458
+ atomicWriteJson(globalConfigPath(), config);
459
+ }
460
+ function loadLocalConfig() {
461
+ return loadConfigFile(localConfigPath());
462
+ }
463
+ function saveLocalConfig(config) {
464
+ atomicWriteJson(localConfigPath(), config);
465
+ }
466
+ function loadConfigForScope(scope) {
467
+ return scope === "local" ? loadLocalConfig() : loadGlobalConfig();
468
+ }
469
+ function saveConfigForScope(scope, config) {
470
+ if (scope === "local") {
471
+ saveLocalConfig(config);
472
+ } else {
473
+ saveGlobalConfig(config);
474
+ }
475
+ }
476
+ function resolveConfigValue(key) {
477
+ const meta = getConfigKeyMeta(key);
478
+ const config = loadConfigForScope(meta.scope);
479
+ const envValue = process.env[meta.envVar];
480
+ const fileValue = config[key];
481
+ if (envValue !== undefined && envValue !== "") {
482
+ return {
483
+ value: envValue,
484
+ source: "environment variable",
485
+ scope: meta.scope,
486
+ configFileValue: fileValue
487
+ };
488
+ }
489
+ if (fileValue !== undefined) {
490
+ return { value: fileValue, source: "config file", scope: meta.scope };
491
+ }
492
+ return { value: meta.default, source: "default", scope: meta.scope };
493
+ }
494
+ function resolveAllConfig() {
495
+ return CONFIG_KEYS.map((meta) => ({
496
+ key: meta.key,
497
+ ...resolveConfigValue(meta.key)
498
+ }));
499
+ }
500
+ function setConfigValue(key, value) {
501
+ const meta = getConfigKeyMeta(key);
502
+ const config = loadConfigForScope(meta.scope);
503
+ config[key] = value;
504
+ saveConfigForScope(meta.scope, config);
505
+ }
506
+ function resetConfigKey(key) {
507
+ const meta = getConfigKeyMeta(key);
508
+ const config = loadConfigForScope(meta.scope);
509
+ delete config[key];
510
+ saveConfigForScope(meta.scope, config);
511
+ }
512
+ function resetAllConfig() {
513
+ saveGlobalConfig({});
514
+ saveLocalConfig({});
515
+ }
516
+ function migrateConfigIfNeeded() {
517
+ if (migrationRan)
518
+ return;
519
+ migrationRan = true;
520
+ const { existsSync: existsSync2 } = __require("fs");
521
+ if (existsSync2(localConfigPath()))
522
+ return;
523
+ const shared = loadGlobalConfig();
524
+ const localKeys = CONFIG_KEYS.filter((k) => k.scope === "local");
525
+ const localConfig = {};
526
+ let hasLocal = false;
527
+ for (const meta of localKeys) {
528
+ const val = shared[meta.key];
529
+ if (val !== undefined) {
530
+ localConfig[meta.key] = val;
531
+ delete shared[meta.key];
532
+ hasLocal = true;
533
+ }
534
+ }
535
+ if (hasLocal) {
536
+ saveLocalConfig(localConfig);
537
+ saveGlobalConfig(shared);
538
+ }
539
+ }
540
+ var migrationRan = false;
541
+ var init_global_config = __esm(() => {
542
+ init_paths();
543
+ init_fs_utils();
544
+ init_config();
545
+ });
546
+
166
547
  // src/core/project-id.ts
167
548
  import { createHash } from "crypto";
168
- import { basename } from "path";
549
+ import { basename, join } from "path";
550
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
169
551
  function slugify(name) {
170
552
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
171
553
  }
554
+ function shortHash(input) {
555
+ return createHash("sha256").update(input).digest("hex").slice(0, 6);
556
+ }
172
557
  function generateProjectId(absolutePath) {
173
558
  const normalized = absolutePath.replace(/\/+$/, "");
174
559
  const slug = slugify(basename(normalized));
175
- const hash = createHash("sha256").update(normalized).digest("hex").slice(0, 6);
560
+ const hash = shortHash(normalized);
176
561
  return `${slug}-${hash}`;
177
562
  }
178
- var init_project_id = () => {};
563
+ function validateProjectIdentifier(id) {
564
+ return typeof id === "string" && IDENTIFIER_PATTERN.test(id);
565
+ }
566
+ function readProjectOverride(cwd) {
567
+ const root = getRepoRoot(cwd) ?? cwd;
568
+ const overridePath = join(root, OVERRIDE_RELATIVE_PATH);
569
+ if (!existsSync2(overridePath))
570
+ return null;
571
+ let raw;
572
+ try {
573
+ raw = readFileSync2(overridePath, "utf-8");
574
+ } catch {
575
+ return null;
576
+ }
577
+ let parsed;
578
+ try {
579
+ parsed = JSON.parse(raw);
580
+ } catch {
581
+ warnInvalidOverride(overridePath, "file is not valid JSON");
582
+ return null;
583
+ }
584
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
585
+ warnInvalidOverride(overridePath, "expected a JSON object");
586
+ return null;
587
+ }
588
+ const id = parsed.projectId;
589
+ if (id === undefined)
590
+ return null;
591
+ if (!validateProjectIdentifier(id)) {
592
+ warnInvalidOverride(overridePath, "projectId must start with a letter or digit, contain only [a-z0-9._-], and be 1–128 characters");
593
+ return null;
594
+ }
595
+ return id;
596
+ }
597
+ function warnInvalidOverride(path, reason) {
598
+ if (warnedOverrides.has(path))
599
+ return;
600
+ warnedOverrides.add(path);
601
+ console.warn(`[mink] ignoring ${path}: ${reason}`);
602
+ }
603
+ function gitDerivedIdentity(cwd) {
604
+ const components = deriveGitIdentity(cwd);
605
+ if (!components)
606
+ return null;
607
+ const remoteLeaf = components.remote.split("/").filter((p) => p).pop();
608
+ const slugSource = components.subpath ? components.subpath.split("/").pop() : remoteLeaf ?? "project";
609
+ const slug = slugify(slugSource);
610
+ const hash = shortHash(`git:${components.remote}:${components.subpath}`);
611
+ return `${slug}-${hash}`;
612
+ }
613
+ function readIdentityMode() {
614
+ const envOverride = process.env.MINK_PROJECTS_IDENTITY;
615
+ if (envOverride === "git-remote" || envOverride === "path-derived") {
616
+ return envOverride;
617
+ }
618
+ try {
619
+ const { resolveConfigValue: resolveConfigValue2 } = (init_global_config(), __toCommonJS(exports_global_config));
620
+ const v = resolveConfigValue2("projects.identity").value;
621
+ if (v === "git-remote")
622
+ return "git-remote";
623
+ } catch {}
624
+ return "path-derived";
625
+ }
626
+ function resolveProjectIdentity(cwd) {
627
+ const mode = readIdentityMode();
628
+ if (mode === "path-derived") {
629
+ return { id: generateProjectId(cwd), source: "path-derived" };
630
+ }
631
+ const override = readProjectOverride(cwd);
632
+ if (override)
633
+ return { id: override, source: "override" };
634
+ const git = gitDerivedIdentity(cwd);
635
+ if (git)
636
+ return { id: git, source: "git-remote" };
637
+ return { id: generateProjectId(cwd), source: "path-derived" };
638
+ }
639
+ function projectIdFor(cwd) {
640
+ return resolveProjectIdentity(cwd).id;
641
+ }
642
+ var IDENTIFIER_PATTERN, OVERRIDE_RELATIVE_PATH = ".mink/project.json", warnedOverrides;
643
+ var init_project_id = __esm(() => {
644
+ init_git_identity();
645
+ IDENTIFIER_PATTERN = /^[a-z0-9][a-z0-9._-]{0,127}$/;
646
+ warnedOverrides = new Set;
647
+ });
648
+
649
+ // src/core/project-registry.ts
650
+ var exports_project_registry = {};
651
+ __export(exports_project_registry, {
652
+ setProjectPathForDevice: () => setProjectPathForDevice,
653
+ listRegisteredProjects: () => listRegisteredProjects,
654
+ getProjectMeta: () => getProjectMeta,
655
+ findProjectDirByIdOrAlias: () => findProjectDirByIdOrAlias,
656
+ addProjectAlias: () => addProjectAlias
657
+ });
658
+ import { readdirSync, existsSync as existsSync3 } from "fs";
659
+ import { join as join2 } from "path";
660
+ function projectMetaFilePath(projDir) {
661
+ return join2(projDir, "project-meta.json");
662
+ }
663
+ function getProjectMeta(projDir) {
664
+ const raw = safeReadJson(projectMetaFilePath(projDir));
665
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw))
666
+ return null;
667
+ const obj = raw;
668
+ if (typeof obj.cwd !== "string" || typeof obj.name !== "string")
669
+ return null;
670
+ const aliases = Array.isArray(obj.aliases) ? obj.aliases.filter((s) => typeof s === "string") : undefined;
671
+ const pathsByDevice = obj.pathsByDevice && typeof obj.pathsByDevice === "object" && !Array.isArray(obj.pathsByDevice) ? Object.fromEntries(Object.entries(obj.pathsByDevice).filter(([, v]) => typeof v === "string")) : undefined;
672
+ return {
673
+ cwd: obj.cwd,
674
+ name: obj.name,
675
+ initTimestamp: obj.initTimestamp ?? "",
676
+ version: obj.version ?? "0.1.0",
677
+ aliases,
678
+ pathsByDevice
679
+ };
680
+ }
681
+ function addProjectAlias(projDir, aliasId) {
682
+ const path = projectMetaFilePath(projDir);
683
+ const raw = safeReadJson(path);
684
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw))
685
+ return false;
686
+ const obj = raw;
687
+ const existing = Array.isArray(obj.aliases) ? obj.aliases.filter((s) => typeof s === "string") : [];
688
+ if (existing.includes(aliasId))
689
+ return false;
690
+ obj.aliases = [...existing, aliasId];
691
+ atomicWriteJson(path, obj);
692
+ return true;
693
+ }
694
+ function setProjectPathForDevice(projDir, deviceId, cwd) {
695
+ const path = projectMetaFilePath(projDir);
696
+ const raw = safeReadJson(path);
697
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw))
698
+ return;
699
+ const obj = raw;
700
+ const existing = obj.pathsByDevice && typeof obj.pathsByDevice === "object" && !Array.isArray(obj.pathsByDevice) ? { ...obj.pathsByDevice } : {};
701
+ if (Object.keys(existing).length === 0 && typeof obj.cwd === "string" && obj.cwd !== cwd) {
702
+ existing[deviceId] = obj.cwd;
703
+ }
704
+ existing[deviceId] = cwd;
705
+ obj.pathsByDevice = existing;
706
+ obj.cwd = cwd;
707
+ atomicWriteJson(path, obj);
708
+ }
709
+ function listRegisteredProjects() {
710
+ const projectsDir = join2(minkRoot(), "projects");
711
+ if (!existsSync3(projectsDir))
712
+ return [];
713
+ const entries = readdirSync(projectsDir, { withFileTypes: true });
714
+ const projects = [];
715
+ for (const entry of entries) {
716
+ if (!entry.isDirectory())
717
+ continue;
718
+ const projDir = join2(projectsDir, entry.name);
719
+ const meta = getProjectMeta(projDir);
720
+ if (meta) {
721
+ projects.push({
722
+ id: entry.name,
723
+ cwd: meta.cwd,
724
+ name: meta.name,
725
+ version: meta.version,
726
+ aliases: meta.aliases ?? [],
727
+ pathsByDevice: meta.pathsByDevice ?? {}
728
+ });
729
+ }
730
+ }
731
+ return projects;
732
+ }
733
+ function findProjectDirByIdOrAlias(id) {
734
+ const projectsDir = join2(minkRoot(), "projects");
735
+ if (!existsSync3(projectsDir))
736
+ return null;
737
+ const primary = join2(projectsDir, id);
738
+ if (existsSync3(primary))
739
+ return primary;
740
+ let entries;
741
+ try {
742
+ entries = readdirSync(projectsDir);
743
+ } catch {
744
+ return null;
745
+ }
746
+ for (const name of entries) {
747
+ const projDir = join2(projectsDir, name);
748
+ const meta = getProjectMeta(projDir);
749
+ if (meta?.aliases?.includes(id))
750
+ return projDir;
751
+ }
752
+ return null;
753
+ }
754
+ var init_project_registry = __esm(() => {
755
+ init_paths();
756
+ init_fs_utils();
757
+ });
179
758
 
180
759
  // src/core/paths.ts
181
760
  var exports_paths = {};
@@ -215,10 +794,11 @@ __export(exports_paths, {
215
794
  actionLogShardPath: () => actionLogShardPath,
216
795
  actionLogPath: () => actionLogPath
217
796
  });
218
- import { join } from "path";
797
+ import { join as join3 } from "path";
798
+ import { existsSync as existsSync4 } from "fs";
219
799
  import { homedir } from "os";
220
800
  function resolveMinkRoot() {
221
- return process.env.MINK_ROOT_OVERRIDE || join(homedir(), ".mink");
801
+ return process.env.MINK_ROOT_OVERRIDE || join3(homedir(), ".mink");
222
802
  }
223
803
  function minkRoot() {
224
804
  if (process.env.MINK_ROOT_OVERRIDE) {
@@ -227,104 +807,113 @@ function minkRoot() {
227
807
  return MINK_ROOT;
228
808
  }
229
809
  function projectDir(cwd) {
230
- const id = generateProjectId(cwd);
231
- return join(minkRoot(), "projects", id);
810
+ const id = projectIdFor(cwd);
811
+ const primary = join3(minkRoot(), "projects", id);
812
+ if (existsSync4(primary))
813
+ return primary;
814
+ try {
815
+ const { findProjectDirByIdOrAlias: findProjectDirByIdOrAlias2 } = (init_project_registry(), __toCommonJS(exports_project_registry));
816
+ const aliased = findProjectDirByIdOrAlias2(id);
817
+ if (aliased)
818
+ return aliased;
819
+ } catch {}
820
+ return primary;
232
821
  }
233
822
  function sessionPath(cwd) {
234
- return join(projectDir(cwd), "session.json");
823
+ return join3(projectDir(cwd), "session.json");
235
824
  }
236
825
  function fileIndexPath(cwd) {
237
- return join(projectDir(cwd), "file-index.json");
826
+ return join3(projectDir(cwd), "file-index.json");
238
827
  }
239
828
  function configPath(cwd) {
240
- return join(projectDir(cwd), "config.json");
829
+ return join3(projectDir(cwd), "config.json");
241
830
  }
242
831
  function learningMemoryPath(cwd) {
243
- return join(projectDir(cwd), "learning-memory.md");
832
+ return join3(projectDir(cwd), "learning-memory.md");
244
833
  }
245
834
  function tokenLedgerPath(cwd) {
246
- return join(projectDir(cwd), "token-ledger.json");
835
+ return join3(projectDir(cwd), "token-ledger.json");
247
836
  }
248
837
  function tokenLedgerArchivePath(cwd) {
249
- return join(projectDir(cwd), "token-ledger-archive.json");
838
+ return join3(projectDir(cwd), "token-ledger-archive.json");
250
839
  }
251
840
  function bugMemoryPath(cwd) {
252
- return join(projectDir(cwd), "bug-memory.json");
841
+ return join3(projectDir(cwd), "bug-memory.json");
253
842
  }
254
843
  function actionLogPath(cwd) {
255
- return join(projectDir(cwd), "action-log.md");
844
+ return join3(projectDir(cwd), "action-log.md");
256
845
  }
257
846
  function schedulerPidPath() {
258
- return join(minkRoot(), "scheduler.pid");
847
+ return join3(minkRoot(), "scheduler.pid");
259
848
  }
260
849
  function schedulerLogPath() {
261
- return join(minkRoot(), "scheduler.log");
850
+ return join3(minkRoot(), "scheduler.log");
262
851
  }
263
852
  function schedulerManifestPath(cwd) {
264
- return join(projectDir(cwd), "scheduler-manifest.json");
853
+ return join3(projectDir(cwd), "scheduler-manifest.json");
265
854
  }
266
855
  function channelPidPath() {
267
- return join(minkRoot(), "channel.pid");
856
+ return join3(minkRoot(), "channel.pid");
268
857
  }
269
858
  function channelLogPath() {
270
- return join(minkRoot(), "channel.log");
859
+ return join3(minkRoot(), "channel.log");
271
860
  }
272
861
  function globalConfigPath() {
273
- return join(minkRoot(), "config");
862
+ return join3(minkRoot(), "config");
274
863
  }
275
864
  function localConfigPath() {
276
- return join(minkRoot(), "config.local");
865
+ return join3(minkRoot(), "config.local");
277
866
  }
278
867
  function deviceIdPath() {
279
- return join(minkRoot(), "device-id");
868
+ return join3(minkRoot(), "device-id");
280
869
  }
281
870
  function deviceRegistryPath() {
282
- return join(minkRoot(), "devices.json");
871
+ return join3(minkRoot(), "devices.json");
283
872
  }
284
873
  function projectMetaPath(cwd) {
285
- return join(projectDir(cwd), "project-meta.json");
874
+ return join3(projectDir(cwd), "project-meta.json");
286
875
  }
287
876
  function backupDirPath(cwd) {
288
- return join(projectDir(cwd), "backups");
877
+ return join3(projectDir(cwd), "backups");
289
878
  }
290
879
  function syncVersionPath() {
291
- return join(minkRoot(), ".mink-sync-version");
880
+ return join3(minkRoot(), ".mink-sync-version");
292
881
  }
293
882
  function projectStateDir(cwd) {
294
- return join(projectDir(cwd), "state");
883
+ return join3(projectDir(cwd), "state");
295
884
  }
296
885
  function deviceShardDir(cwd, deviceId) {
297
- return join(projectStateDir(cwd), deviceId);
886
+ return join3(projectStateDir(cwd), deviceId);
298
887
  }
299
888
  function tokenLedgerShardPath(cwd, deviceId) {
300
- return join(deviceShardDir(cwd, deviceId), "token-ledger.json");
889
+ return join3(deviceShardDir(cwd, deviceId), "token-ledger.json");
301
890
  }
302
891
  function tokenLedgerArchiveShardPath(cwd, deviceId) {
303
- return join(deviceShardDir(cwd, deviceId), "token-ledger-archive.json");
892
+ return join3(deviceShardDir(cwd, deviceId), "token-ledger-archive.json");
304
893
  }
305
894
  function bugMemoryShardPath(cwd, deviceId) {
306
- return join(deviceShardDir(cwd, deviceId), "bug-memory.json");
895
+ return join3(deviceShardDir(cwd, deviceId), "bug-memory.json");
307
896
  }
308
897
  function actionLogShardPath(cwd, deviceId) {
309
- return join(deviceShardDir(cwd, deviceId), "action-log.md");
898
+ return join3(deviceShardDir(cwd, deviceId), "action-log.md");
310
899
  }
311
900
  function learningMemorySidecarPath(cwd, deviceId) {
312
- return join(projectDir(cwd), `learning-memory.${deviceId}.md`);
901
+ return join3(projectDir(cwd), `learning-memory.${deviceId}.md`);
313
902
  }
314
903
  function fileIndexCountersPath(cwd) {
315
- return join(projectDir(cwd), ".mink-state-counters.json");
904
+ return join3(projectDir(cwd), ".mink-state-counters.json");
316
905
  }
317
906
  function designCapturesDir(cwd) {
318
- return join(projectDir(cwd), "design-captures");
907
+ return join3(projectDir(cwd), "design-captures");
319
908
  }
320
909
  function designReportPath(cwd) {
321
- return join(projectDir(cwd), "design-report.json");
910
+ return join3(projectDir(cwd), "design-report.json");
322
911
  }
323
912
  function frameworkAdvisorPath(cwd) {
324
- return join(projectDir(cwd), "framework-advisor.md");
913
+ return join3(projectDir(cwd), "framework-advisor.md");
325
914
  }
326
915
  function frameworkAdvisorJsonPath(cwd) {
327
- return join(projectDir(cwd), "framework-advisor.json");
916
+ return join3(projectDir(cwd), "framework-advisor.json");
328
917
  }
329
918
  var MINK_ROOT;
330
919
  var init_paths = __esm(() => {
@@ -332,42 +921,6 @@ var init_paths = __esm(() => {
332
921
  MINK_ROOT = resolveMinkRoot();
333
922
  });
334
923
 
335
- // src/core/fs-utils.ts
336
- var exports_fs_utils = {};
337
- __export(exports_fs_utils, {
338
- safeReadJson: () => safeReadJson,
339
- safeAppendText: () => safeAppendText,
340
- atomicWriteText: () => atomicWriteText,
341
- atomicWriteJson: () => atomicWriteJson
342
- });
343
- import { writeFileSync, readFileSync, appendFileSync, renameSync, mkdirSync } from "fs";
344
- import { dirname } from "path";
345
- function atomicWriteJson(filePath, data) {
346
- const tmp = filePath + ".tmp";
347
- mkdirSync(dirname(filePath), { recursive: true });
348
- writeFileSync(tmp, JSON.stringify(data, null, 2));
349
- renameSync(tmp, filePath);
350
- }
351
- function atomicWriteText(filePath, content) {
352
- const tmp = filePath + ".tmp";
353
- mkdirSync(dirname(filePath), { recursive: true });
354
- writeFileSync(tmp, content);
355
- renameSync(tmp, filePath);
356
- }
357
- function safeAppendText(filePath, content) {
358
- mkdirSync(dirname(filePath), { recursive: true });
359
- appendFileSync(filePath, content);
360
- }
361
- function safeReadJson(filePath) {
362
- try {
363
- const raw = readFileSync(filePath, "utf-8");
364
- return JSON.parse(raw);
365
- } catch {
366
- return null;
367
- }
368
- }
369
- var init_fs_utils = () => {};
370
-
371
924
  // src/core/action-log.ts
372
925
  var exports_action_log = {};
373
926
  __export(exports_action_log, {
@@ -386,7 +939,7 @@ __export(exports_action_log, {
386
939
  consolidateLog: () => consolidateLog,
387
940
  appendToLog: () => appendToLog
388
941
  });
389
- import { readFileSync as readFileSync2 } from "fs";
942
+ import { readFileSync as readFileSync3 } from "fs";
390
943
  function truncatePath(filePath, maxLen = 60) {
391
944
  if (filePath.length <= maxLen)
392
945
  return filePath;
@@ -473,7 +1026,7 @@ function appendToLog(logPath, text) {
473
1026
  }
474
1027
  function safeReadLog(logPath) {
475
1028
  try {
476
- return readFileSync2(logPath, "utf-8");
1029
+ return readFileSync3(logPath, "utf-8");
477
1030
  } catch {
478
1031
  return "";
479
1032
  }
@@ -618,14 +1171,14 @@ __export(exports_device, {
618
1171
  listDevices: () => listDevices,
619
1172
  getOrCreateDeviceId: () => getOrCreateDeviceId
620
1173
  });
621
- import { existsSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
1174
+ import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
622
1175
  import { dirname as dirname2 } from "path";
623
1176
  import { hostname, platform } from "os";
624
1177
  import { randomUUID } from "crypto";
625
1178
  function getOrCreateDeviceId() {
626
1179
  const idPath = deviceIdPath();
627
- if (existsSync(idPath)) {
628
- return readFileSync3(idPath, "utf-8").trim();
1180
+ if (existsSync5(idPath)) {
1181
+ return readFileSync4(idPath, "utf-8").trim();
629
1182
  }
630
1183
  const id = randomUUID();
631
1184
  mkdirSync2(dirname2(idPath), { recursive: true });
@@ -683,263 +1236,6 @@ var init_device = __esm(() => {
683
1236
  init_fs_utils();
684
1237
  });
685
1238
 
686
- // src/types/config.ts
687
- function isValidConfigKey(key) {
688
- return VALID_KEYS.has(key);
689
- }
690
- function getConfigKeyMeta(key) {
691
- return CONFIG_KEYS.find((k) => k.key === key);
692
- }
693
- var CONFIG_KEYS, VALID_KEYS;
694
- var init_config = __esm(() => {
695
- CONFIG_KEYS = [
696
- {
697
- key: "wiki.path",
698
- default: "~/.mink/wiki",
699
- envVar: "MINK_WIKI_PATH",
700
- description: "Wiki vault location",
701
- scope: "local"
702
- },
703
- {
704
- key: "wiki.enabled",
705
- default: "true",
706
- envVar: "MINK_WIKI_ENABLED",
707
- description: "Enable/disable the wiki feature",
708
- scope: "shared"
709
- },
710
- {
711
- key: "wiki.sync-mode",
712
- default: "immediate",
713
- envVar: "MINK_WIKI_SYNC_MODE",
714
- description: "Sync mode: immediate or batched",
715
- scope: "shared"
716
- },
717
- {
718
- key: "wiki.git-backup",
719
- default: "false",
720
- envVar: "MINK_WIKI_GIT_BACKUP",
721
- description: "Deprecated: use sync.enabled instead",
722
- scope: "shared"
723
- },
724
- {
725
- key: "wiki.git-remote",
726
- default: "origin",
727
- envVar: "MINK_WIKI_GIT_REMOTE",
728
- description: "Deprecated: use sync.remote-url instead",
729
- scope: "shared"
730
- },
731
- {
732
- key: "notes.default-category",
733
- default: "inbox",
734
- envVar: "MINK_NOTES_DEFAULT_CATEGORY",
735
- description: "Default category for notes captured via CLI",
736
- scope: "shared"
737
- },
738
- {
739
- key: "sync.enabled",
740
- default: "false",
741
- envVar: "MINK_SYNC_ENABLED",
742
- description: "Enable/disable automatic git sync of ~/.mink",
743
- scope: "shared"
744
- },
745
- {
746
- key: "sync.remote-url",
747
- default: "",
748
- envVar: "MINK_SYNC_REMOTE_URL",
749
- description: "Git remote URL for ~/.mink sync",
750
- scope: "shared"
751
- },
752
- {
753
- key: "sync.last-push",
754
- default: "",
755
- envVar: "MINK_SYNC_LAST_PUSH",
756
- description: "ISO timestamp of last successful sync push",
757
- scope: "local"
758
- },
759
- {
760
- key: "sync.last-pull",
761
- default: "",
762
- envVar: "MINK_SYNC_LAST_PULL",
763
- description: "ISO timestamp of last successful sync pull",
764
- scope: "local"
765
- },
766
- {
767
- key: "channel.discord.bot-token",
768
- default: "",
769
- envVar: "MINK_CHANNEL_DISCORD_BOT_TOKEN",
770
- description: "Discord bot token for Claude Code Channels",
771
- scope: "local"
772
- },
773
- {
774
- key: "channel.discord.enabled",
775
- default: "false",
776
- envVar: "MINK_CHANNEL_DISCORD_ENABLED",
777
- description: "Auto-start Discord channel when daemon starts",
778
- scope: "local"
779
- },
780
- {
781
- key: "channel.discord.allowlist",
782
- default: "",
783
- envVar: "MINK_CHANNEL_DISCORD_ALLOWLIST",
784
- description: "Comma-separated list of Discord user IDs permitted to DM the bot",
785
- scope: "local"
786
- },
787
- {
788
- key: "channel.default-platform",
789
- default: "discord",
790
- envVar: "MINK_CHANNEL_DEFAULT_PLATFORM",
791
- description: "Default platform for mink channel start",
792
- scope: "shared"
793
- },
794
- {
795
- key: "channel.skip-permissions",
796
- default: "true",
797
- envVar: "MINK_CHANNEL_SKIP_PERMISSIONS",
798
- description: "Pass --dangerously-skip-permissions so the channel can run without terminal prompts",
799
- scope: "shared"
800
- },
801
- {
802
- key: "cli.auto-update",
803
- default: "false",
804
- envVar: "MINK_CLI_AUTO_UPDATE",
805
- description: "Auto-upgrade the mink CLI on schedule via the background scheduler",
806
- scope: "shared"
807
- },
808
- {
809
- key: "cli.auto-update-schedule",
810
- default: "0 4 * * *",
811
- envVar: "MINK_CLI_AUTO_UPDATE_SCHEDULE",
812
- description: "Cron expression governing the cli-self-update scheduled task",
813
- scope: "shared"
814
- },
815
- {
816
- key: "cli.auto-update-package-manager",
817
- default: "auto",
818
- envVar: "MINK_CLI_AUTO_UPDATE_PACKAGE_MANAGER",
819
- description: "Force a package manager (auto|npm|bun) for self-upgrade installs",
820
- scope: "local"
821
- }
822
- ];
823
- VALID_KEYS = new Set(CONFIG_KEYS.map((k) => k.key));
824
- });
825
-
826
- // src/core/global-config.ts
827
- var exports_global_config = {};
828
- __export(exports_global_config, {
829
- setConfigValue: () => setConfigValue,
830
- saveLocalConfig: () => saveLocalConfig,
831
- saveGlobalConfig: () => saveGlobalConfig,
832
- resolveConfigValue: () => resolveConfigValue,
833
- resolveAllConfig: () => resolveAllConfig,
834
- resetConfigKey: () => resetConfigKey,
835
- resetAllConfig: () => resetAllConfig,
836
- migrateConfigIfNeeded: () => migrateConfigIfNeeded,
837
- loadLocalConfig: () => loadLocalConfig,
838
- loadGlobalConfig: () => loadGlobalConfig
839
- });
840
- function loadConfigFile(path) {
841
- const raw = safeReadJson(path);
842
- if (raw === null)
843
- return {};
844
- if (typeof raw !== "object" || Array.isArray(raw)) {
845
- console.warn("[mink] warning: corrupt config file at " + path);
846
- return {};
847
- }
848
- return raw;
849
- }
850
- function loadGlobalConfig() {
851
- return loadConfigFile(globalConfigPath());
852
- }
853
- function saveGlobalConfig(config) {
854
- atomicWriteJson(globalConfigPath(), config);
855
- }
856
- function loadLocalConfig() {
857
- return loadConfigFile(localConfigPath());
858
- }
859
- function saveLocalConfig(config) {
860
- atomicWriteJson(localConfigPath(), config);
861
- }
862
- function loadConfigForScope(scope) {
863
- return scope === "local" ? loadLocalConfig() : loadGlobalConfig();
864
- }
865
- function saveConfigForScope(scope, config) {
866
- if (scope === "local") {
867
- saveLocalConfig(config);
868
- } else {
869
- saveGlobalConfig(config);
870
- }
871
- }
872
- function resolveConfigValue(key) {
873
- const meta = getConfigKeyMeta(key);
874
- const config = loadConfigForScope(meta.scope);
875
- const envValue = process.env[meta.envVar];
876
- const fileValue = config[key];
877
- if (envValue !== undefined && envValue !== "") {
878
- return {
879
- value: envValue,
880
- source: "environment variable",
881
- scope: meta.scope,
882
- configFileValue: fileValue
883
- };
884
- }
885
- if (fileValue !== undefined) {
886
- return { value: fileValue, source: "config file", scope: meta.scope };
887
- }
888
- return { value: meta.default, source: "default", scope: meta.scope };
889
- }
890
- function resolveAllConfig() {
891
- return CONFIG_KEYS.map((meta) => ({
892
- key: meta.key,
893
- ...resolveConfigValue(meta.key)
894
- }));
895
- }
896
- function setConfigValue(key, value) {
897
- const meta = getConfigKeyMeta(key);
898
- const config = loadConfigForScope(meta.scope);
899
- config[key] = value;
900
- saveConfigForScope(meta.scope, config);
901
- }
902
- function resetConfigKey(key) {
903
- const meta = getConfigKeyMeta(key);
904
- const config = loadConfigForScope(meta.scope);
905
- delete config[key];
906
- saveConfigForScope(meta.scope, config);
907
- }
908
- function resetAllConfig() {
909
- saveGlobalConfig({});
910
- saveLocalConfig({});
911
- }
912
- function migrateConfigIfNeeded() {
913
- if (migrationRan)
914
- return;
915
- migrationRan = true;
916
- const { existsSync: existsSync2 } = __require("fs");
917
- if (existsSync2(localConfigPath()))
918
- return;
919
- const shared = loadGlobalConfig();
920
- const localKeys = CONFIG_KEYS.filter((k) => k.scope === "local");
921
- const localConfig = {};
922
- let hasLocal = false;
923
- for (const meta of localKeys) {
924
- const val = shared[meta.key];
925
- if (val !== undefined) {
926
- localConfig[meta.key] = val;
927
- delete shared[meta.key];
928
- hasLocal = true;
929
- }
930
- }
931
- if (hasLocal) {
932
- saveLocalConfig(localConfig);
933
- saveGlobalConfig(shared);
934
- }
935
- }
936
- var migrationRan = false;
937
- var init_global_config = __esm(() => {
938
- init_paths();
939
- init_fs_utils();
940
- init_config();
941
- });
942
-
943
1239
  // src/core/vault.ts
944
1240
  var exports_vault = {};
945
1241
  __export(exports_vault, {
@@ -966,54 +1262,54 @@ __export(exports_vault, {
966
1262
  ensureVaultStructure: () => ensureVaultStructure,
967
1263
  categoryToDir: () => categoryToDir
968
1264
  });
969
- import { join as join2, basename as basename2, resolve } from "path";
1265
+ import { join as join4, basename as basename2, resolve } from "path";
970
1266
  import { homedir as homedir2 } from "os";
971
- import { existsSync as existsSync2, mkdirSync as mkdirSync3, symlinkSync, unlinkSync, lstatSync, readlinkSync } from "fs";
1267
+ import { existsSync as existsSync6, mkdirSync as mkdirSync3, symlinkSync, unlinkSync, lstatSync, readlinkSync } from "fs";
972
1268
  function resolveVaultPath() {
973
1269
  const resolved = resolveConfigValue("wiki.path");
974
1270
  const raw = resolved.value;
975
- const expanded = raw.startsWith("~/") ? join2(homedir2(), raw.slice(2)) : raw;
1271
+ const expanded = raw.startsWith("~/") ? join4(homedir2(), raw.slice(2)) : raw;
976
1272
  return resolve(expanded);
977
1273
  }
978
1274
  function vaultRoot() {
979
1275
  return resolveVaultPath();
980
1276
  }
981
1277
  function vaultInbox() {
982
- return join2(resolveVaultPath(), "inbox");
1278
+ return join4(resolveVaultPath(), "inbox");
983
1279
  }
984
1280
  function vaultProjects(slug) {
985
- const base = join2(resolveVaultPath(), "projects");
986
- return slug ? join2(base, slug) : base;
1281
+ const base = join4(resolveVaultPath(), "projects");
1282
+ return slug ? join4(base, slug) : base;
987
1283
  }
988
1284
  function vaultAreas() {
989
- return join2(resolveVaultPath(), "areas");
1285
+ return join4(resolveVaultPath(), "areas");
990
1286
  }
991
1287
  function vaultDailyDir() {
992
- return join2(resolveVaultPath(), "areas", "daily");
1288
+ return join4(resolveVaultPath(), "areas", "daily");
993
1289
  }
994
1290
  function vaultResources() {
995
- return join2(resolveVaultPath(), "resources");
1291
+ return join4(resolveVaultPath(), "resources");
996
1292
  }
997
1293
  function vaultArchives() {
998
- return join2(resolveVaultPath(), "archives");
1294
+ return join4(resolveVaultPath(), "archives");
999
1295
  }
1000
1296
  function vaultTemplates() {
1001
- return join2(resolveVaultPath(), "templates");
1297
+ return join4(resolveVaultPath(), "templates");
1002
1298
  }
1003
1299
  function vaultPatterns() {
1004
- return join2(resolveVaultPath(), "patterns");
1300
+ return join4(resolveVaultPath(), "patterns");
1005
1301
  }
1006
1302
  function vaultManifestPath() {
1007
- return join2(resolveVaultPath(), ".mink-vault.json");
1303
+ return join4(resolveVaultPath(), ".mink-vault.json");
1008
1304
  }
1009
1305
  function vaultIndexPath() {
1010
- return join2(resolveVaultPath(), ".mink-index.json");
1306
+ return join4(resolveVaultPath(), ".mink-index.json");
1011
1307
  }
1012
1308
  function vaultMasterIndexPath() {
1013
- return join2(resolveVaultPath(), "_index.md");
1309
+ return join4(resolveVaultPath(), "_index.md");
1014
1310
  }
1015
1311
  function isVaultInitialized() {
1016
- return existsSync2(vaultManifestPath());
1312
+ return existsSync6(vaultManifestPath());
1017
1313
  }
1018
1314
  function isInsideVault(cwd) {
1019
1315
  const vault = resolveVaultPath();
@@ -1034,23 +1330,23 @@ function loadVaultManifest() {
1034
1330
  function ensureVaultStructure() {
1035
1331
  const root = resolveVaultPath();
1036
1332
  for (const dir of VAULT_DIRS) {
1037
- mkdirSync3(join2(root, dir), { recursive: true });
1333
+ mkdirSync3(join4(root, dir), { recursive: true });
1038
1334
  }
1039
1335
  }
1040
1336
  function categoryToDir(category, projectSlug) {
1041
1337
  const root = resolveVaultPath();
1042
1338
  switch (category) {
1043
1339
  case "projects":
1044
- return projectSlug ? join2(root, "projects", projectSlug) : join2(root, "projects");
1340
+ return projectSlug ? join4(root, "projects", projectSlug) : join4(root, "projects");
1045
1341
  case "areas":
1046
- return join2(root, "areas");
1342
+ return join4(root, "areas");
1047
1343
  case "resources":
1048
- return join2(root, "resources");
1344
+ return join4(root, "resources");
1049
1345
  case "archives":
1050
- return join2(root, "archives");
1346
+ return join4(root, "archives");
1051
1347
  case "inbox":
1052
1348
  default:
1053
- return join2(root, "inbox");
1349
+ return join4(root, "inbox");
1054
1350
  }
1055
1351
  }
1056
1352
  function saveManifest(manifest) {
@@ -1058,16 +1354,16 @@ function saveManifest(manifest) {
1058
1354
  }
1059
1355
  function linkExternal(targetPath, name) {
1060
1356
  const root = resolveVaultPath();
1061
- const absTarget = targetPath.startsWith("~/") ? join2(homedir2(), targetPath.slice(2)) : resolve(targetPath);
1062
- if (!existsSync2(absTarget)) {
1357
+ const absTarget = targetPath.startsWith("~/") ? join4(homedir2(), targetPath.slice(2)) : resolve(targetPath);
1358
+ if (!existsSync6(absTarget)) {
1063
1359
  return { ok: false, error: `target does not exist: ${absTarget}` };
1064
1360
  }
1065
1361
  if (!lstatSync(absTarget).isDirectory()) {
1066
1362
  return { ok: false, error: `target is not a directory: ${absTarget}` };
1067
1363
  }
1068
1364
  const linkName = name ?? basename2(absTarget);
1069
- const linkPath = join2(root, linkName);
1070
- if (existsSync2(linkPath)) {
1365
+ const linkPath = join4(root, linkName);
1366
+ if (existsSync6(linkPath)) {
1071
1367
  if (lstatSync(linkPath).isSymbolicLink()) {
1072
1368
  const existing = readlinkSync(linkPath);
1073
1369
  if (existing === absTarget) {
@@ -1089,8 +1385,8 @@ function linkExternal(targetPath, name) {
1089
1385
  }
1090
1386
  function unlinkExternal(name) {
1091
1387
  const root = resolveVaultPath();
1092
- const linkPath = join2(root, name);
1093
- if (!existsSync2(linkPath)) {
1388
+ const linkPath = join4(root, name);
1389
+ if (!existsSync6(linkPath)) {
1094
1390
  return { ok: false, error: `no link named "${name}" in the vault` };
1095
1391
  }
1096
1392
  if (!lstatSync(linkPath).isSymbolicLink()) {
@@ -1113,7 +1409,7 @@ var init_vault = __esm(() => {
1113
1409
  init_global_config();
1114
1410
  init_fs_utils();
1115
1411
  init_fs_utils();
1116
- DEFAULT_VAULT_PATH = join2(homedir2(), ".mink", "wiki");
1412
+ DEFAULT_VAULT_PATH = join4(homedir2(), ".mink", "wiki");
1117
1413
  VAULT_DIRS = [
1118
1414
  "",
1119
1415
  "inbox",
@@ -1128,11 +1424,12 @@ var init_vault = __esm(() => {
1128
1424
  });
1129
1425
 
1130
1426
  // src/core/note-index.ts
1131
- import { join as join3 } from "path";
1132
- import { readFileSync as readFileSync4, readdirSync, statSync } from "fs";
1427
+ import { join as join5 } from "path";
1428
+ import { readFileSync as readFileSync5, readdirSync as readdirSync2, statSync } from "fs";
1133
1429
  function createEmptyVaultIndex() {
1134
1430
  return {
1135
1431
  lastScanTimestamp: "",
1432
+ lastFullScanTimestamp: "",
1136
1433
  totalNotes: 0,
1137
1434
  entries: {}
1138
1435
  };
@@ -1261,12 +1558,14 @@ function rebuildVaultIndex() {
1261
1558
  const files = collectAllMarkdown(root);
1262
1559
  for (const file of files) {
1263
1560
  try {
1264
- const content = readFileSync4(file.absolutePath, "utf-8");
1561
+ const content = readFileSync5(file.absolutePath, "utf-8");
1265
1562
  const entry = buildEntryFromContent(file.relativePath, content, new Date(file.mtimeMs).toISOString());
1266
1563
  updateVaultEntry(index, entry);
1267
1564
  } catch {}
1268
1565
  }
1269
- index.lastScanTimestamp = new Date().toISOString();
1566
+ const now = new Date().toISOString();
1567
+ index.lastScanTimestamp = now;
1568
+ index.lastFullScanTimestamp = now;
1270
1569
  saveVaultIndex(index);
1271
1570
  return index;
1272
1571
  }
@@ -1279,17 +1578,51 @@ function getRecentNotes(n) {
1279
1578
  const index = loadVaultIndex();
1280
1579
  return Object.values(index.entries).sort((a, b) => b.lastModified.localeCompare(a.lastModified)).slice(0, n);
1281
1580
  }
1581
+ function vaultIndexStaleness() {
1582
+ const index = loadVaultIndex();
1583
+ const root = resolveVaultPath();
1584
+ const diskCount = collectAllMarkdown(root).length;
1585
+ const indexCount = Object.keys(index.entries).length;
1586
+ const lastFullScan = index.lastFullScanTimestamp || null;
1587
+ if (!lastFullScan) {
1588
+ return {
1589
+ isStale: true,
1590
+ reason: "no full scan on record",
1591
+ diskCount,
1592
+ indexCount,
1593
+ lastFullScan: null
1594
+ };
1595
+ }
1596
+ const delta = Math.abs(diskCount - indexCount);
1597
+ const threshold = Math.max(5, Math.floor(diskCount * 0.05));
1598
+ if (delta >= threshold) {
1599
+ return {
1600
+ isStale: true,
1601
+ reason: `${diskCount} files on disk but ${indexCount} in index`,
1602
+ diskCount,
1603
+ indexCount,
1604
+ lastFullScan
1605
+ };
1606
+ }
1607
+ return {
1608
+ isStale: false,
1609
+ reason: null,
1610
+ diskCount,
1611
+ indexCount,
1612
+ lastFullScan
1613
+ };
1614
+ }
1282
1615
  function collectAllMarkdown(rootPath) {
1283
1616
  const files = [];
1284
1617
  function walk(dir) {
1285
1618
  try {
1286
- const entries = readdirSync(dir, { withFileTypes: true });
1619
+ const entries = readdirSync2(dir, { withFileTypes: true });
1287
1620
  for (const entry of entries) {
1288
1621
  if (VAULT_EXCLUDES.has(entry.name))
1289
1622
  continue;
1290
1623
  if (entry.name.startsWith("."))
1291
1624
  continue;
1292
- const fullPath = join3(dir, entry.name);
1625
+ const fullPath = join5(dir, entry.name);
1293
1626
  if (entry.isDirectory()) {
1294
1627
  walk(fullPath);
1295
1628
  } else if (entry.name.endsWith(".md")) {
@@ -1320,11 +1653,11 @@ var init_note_index = __esm(() => {
1320
1653
  });
1321
1654
 
1322
1655
  // src/core/conflict-park.ts
1323
- import { execSync } from "child_process";
1324
- import { existsSync as existsSync4 } from "fs";
1325
- import { join as join4 } from "path";
1656
+ import { execSync as execSync2 } from "child_process";
1657
+ import { existsSync as existsSync8 } from "fs";
1658
+ import { join as join6 } from "path";
1326
1659
  function git(args) {
1327
- return execSync(`git ${args}`, {
1660
+ return execSync2(`git ${args}`, {
1328
1661
  cwd: minkRoot(),
1329
1662
  timeout: GIT_TIMEOUT,
1330
1663
  stdio: ["pipe", "pipe", "pipe"]
@@ -1339,7 +1672,7 @@ function gitSafe(args) {
1339
1672
  }
1340
1673
  function parkConflictingState(reason) {
1341
1674
  const root = minkRoot();
1342
- const inMerge = existsSync4(join4(root, ".git", "MERGE_HEAD")) || existsSync4(join4(root, ".git", "rebase-merge")) || existsSync4(join4(root, ".git", "rebase-apply"));
1675
+ const inMerge = existsSync8(join6(root, ".git", "MERGE_HEAD")) || existsSync8(join6(root, ".git", "rebase-merge")) || existsSync8(join6(root, ".git", "rebase-apply"));
1343
1676
  if (inMerge) {
1344
1677
  gitSafe("merge --abort");
1345
1678
  gitSafe("rebase --abort");
@@ -1396,12 +1729,12 @@ __export(exports_sync, {
1396
1729
  disconnectSync: () => disconnectSync,
1397
1730
  MINK_SYNC_VERSION: () => MINK_SYNC_VERSION
1398
1731
  });
1399
- import { existsSync as existsSync5, writeFileSync as writeFileSync3, readFileSync as readFileSync5 } from "fs";
1400
- import { join as join5 } from "path";
1401
- import { execSync as execSync2 } from "child_process";
1732
+ import { existsSync as existsSync9, writeFileSync as writeFileSync3, readFileSync as readFileSync6 } from "fs";
1733
+ import { join as join7 } from "path";
1734
+ import { execSync as execSync3 } from "child_process";
1402
1735
  function readSyncVersion() {
1403
1736
  try {
1404
- const raw = readFileSync5(syncVersionPath(), "utf-8").trim();
1737
+ const raw = readFileSync6(syncVersionPath(), "utf-8").trim();
1405
1738
  const n = parseInt(raw, 10);
1406
1739
  return Number.isFinite(n) && n > 0 ? n : 1;
1407
1740
  } catch {
@@ -1413,7 +1746,7 @@ function writeSyncVersion(version) {
1413
1746
  `);
1414
1747
  }
1415
1748
  function git2(args, timeoutMs = GIT_TIMEOUT2) {
1416
- return execSync2(`git ${args}`, {
1749
+ return execSync3(`git ${args}`, {
1417
1750
  cwd: minkRoot(),
1418
1751
  timeout: timeoutMs,
1419
1752
  stdio: ["pipe", "pipe", "pipe"]
@@ -1430,14 +1763,14 @@ function isSyncInitialized() {
1430
1763
  const enabled = resolveConfigValue("sync.enabled").value;
1431
1764
  if (enabled !== "true")
1432
1765
  return false;
1433
- return existsSync5(join5(minkRoot(), ".git"));
1766
+ return existsSync9(join7(minkRoot(), ".git"));
1434
1767
  }
1435
1768
  function ensureGitignore() {
1436
- const gitignorePath = join5(minkRoot(), ".gitignore");
1769
+ const gitignorePath = join7(minkRoot(), ".gitignore");
1437
1770
  writeFileSync3(gitignorePath, GITIGNORE_CONTENTS);
1438
1771
  }
1439
1772
  function ensureGitAttributes() {
1440
- const path = join5(minkRoot(), ".gitattributes");
1773
+ const path = join7(minkRoot(), ".gitattributes");
1441
1774
  writeFileSync3(path, GITATTRIBUTES_CONTENTS);
1442
1775
  }
1443
1776
  function ensureMergeDriversRegistered() {
@@ -1451,7 +1784,7 @@ function ensureMergeDriversRegistered() {
1451
1784
  }
1452
1785
  function getSyncStatus() {
1453
1786
  const enabled = resolveConfigValue("sync.enabled").value === "true";
1454
- const gitInitialized = existsSync5(join5(minkRoot(), ".git"));
1787
+ const gitInitialized = existsSync9(join7(minkRoot(), ".git"));
1455
1788
  const remoteUrl = resolveConfigValue("sync.remote-url").value;
1456
1789
  const lastPush = resolveConfigValue("sync.last-push").value;
1457
1790
  const lastPull = resolveConfigValue("sync.last-pull").value;
@@ -1477,8 +1810,8 @@ function getSyncStatus() {
1477
1810
  }
1478
1811
  function initSync(remoteUrl) {
1479
1812
  const root = minkRoot();
1480
- const gitDir = join5(root, ".git");
1481
- if (existsSync5(gitDir)) {
1813
+ const gitDir = join7(root, ".git");
1814
+ if (existsSync9(gitDir)) {
1482
1815
  console.log("[mink] sync is already initialized in " + root);
1483
1816
  console.log("[mink] run 'mink sync disconnect' first to reinitialize");
1484
1817
  return;
@@ -1619,8 +1952,8 @@ function syncPush(onMessage = (msg) => console.error(msg)) {
1619
1952
  }
1620
1953
  function disconnectSync() {
1621
1954
  const root = minkRoot();
1622
- const gitDir = join5(root, ".git");
1623
- if (!existsSync5(gitDir)) {
1955
+ const gitDir = join7(root, ".git");
1956
+ if (!existsSync9(gitDir)) {
1624
1957
  console.log("[mink] sync is not initialized — nothing to disconnect");
1625
1958
  return;
1626
1959
  }
@@ -1642,7 +1975,7 @@ function detectRemoteDefaultBranch() {
1642
1975
  `).map((b) => b.trim()).filter((b) => b.startsWith("origin/") && !b.includes("HEAD")).map((b) => b.replace("origin/", ""))[0];
1643
1976
  return first ?? "main";
1644
1977
  }
1645
- var GIT_TIMEOUT2 = 5000, PUSH_TIMEOUT = 1e4, FETCH_TIMEOUT = 15000, MINK_SYNC_VERSION = 2, GITIGNORE_CONTENTS = `# Runtime state — machine-specific
1978
+ var GIT_TIMEOUT2 = 5000, PUSH_TIMEOUT = 1e4, FETCH_TIMEOUT = 15000, MINK_SYNC_VERSION = 3, GITIGNORE_CONTENTS = `# Runtime state — machine-specific
1646
1979
  scheduler.pid
1647
1980
  scheduler.log
1648
1981
  channel.pid
@@ -1692,22 +2025,25 @@ var init_sync = __esm(() => {
1692
2025
  var exports_sync_migrate = {};
1693
2026
  __export(exports_sync_migrate, {
1694
2027
  syncMigrateCommand: () => syncMigrateCommand,
2028
+ rollbackProjectIdentities: () => rollbackProjectIdentities,
2029
+ planIdentityMigration: () => planIdentityMigration,
1695
2030
  migrateSyncLayout: () => migrateSyncLayout
1696
2031
  });
1697
2032
  import {
1698
- existsSync as existsSync6,
1699
- readdirSync as readdirSync2,
2033
+ existsSync as existsSync10,
2034
+ readdirSync as readdirSync3,
1700
2035
  statSync as statSync2,
1701
2036
  mkdirSync as mkdirSync4,
1702
2037
  writeFileSync as writeFileSync4,
2038
+ readFileSync as readFileSync7,
1703
2039
  renameSync as renameSync2,
1704
2040
  unlinkSync as unlinkSync2
1705
2041
  } from "fs";
1706
- import { join as join6 } from "path";
1707
- import { execSync as execSync3 } from "child_process";
2042
+ import { join as join8 } from "path";
2043
+ import { execSync as execSync4 } from "child_process";
1708
2044
  function gitSafe3(args, timeoutMs = 5000) {
1709
2045
  try {
1710
- return execSync3(`git ${args}`, {
2046
+ return execSync4(`git ${args}`, {
1711
2047
  cwd: minkRoot(),
1712
2048
  timeout: timeoutMs,
1713
2049
  stdio: ["pipe", "pipe", "pipe"]
@@ -1717,8 +2053,8 @@ function gitSafe3(args, timeoutMs = 5000) {
1717
2053
  }
1718
2054
  }
1719
2055
  function acquireLock() {
1720
- const path = join6(minkRoot(), MIGRATE_LOCK);
1721
- if (existsSync6(path)) {
2056
+ const path = join8(minkRoot(), MIGRATE_LOCK);
2057
+ if (existsSync10(path)) {
1722
2058
  try {
1723
2059
  const ageMs = Date.now() - statSync2(path).mtimeMs;
1724
2060
  if (ageMs < MIGRATE_LOCK_STALE_MS)
@@ -1735,13 +2071,13 @@ function acquireLock() {
1735
2071
  }
1736
2072
  function releaseLock() {
1737
2073
  try {
1738
- unlinkSync2(join6(minkRoot(), MIGRATE_LOCK));
2074
+ unlinkSync2(join8(minkRoot(), MIGRATE_LOCK));
1739
2075
  } catch {}
1740
2076
  }
1741
2077
  function migrateFile(from, to) {
1742
- if (!existsSync6(from))
2078
+ if (!existsSync10(from))
1743
2079
  return true;
1744
- mkdirSync4(join6(to, ".."), { recursive: true });
2080
+ mkdirSync4(join8(to, ".."), { recursive: true });
1745
2081
  if (gitSafe3(`mv "${from}" "${to}"`) !== null)
1746
2082
  return true;
1747
2083
  try {
@@ -1752,7 +2088,7 @@ function migrateFile(from, to) {
1752
2088
  }
1753
2089
  }
1754
2090
  function migrateProject(projDir, deviceId) {
1755
- const shardDir = join6(projDir, "state", deviceId);
2091
+ const shardDir = join8(projDir, "state", deviceId);
1756
2092
  mkdirSync4(shardDir, { recursive: true });
1757
2093
  for (const file of [
1758
2094
  "token-ledger.json",
@@ -1760,25 +2096,25 @@ function migrateProject(projDir, deviceId) {
1760
2096
  "bug-memory.json",
1761
2097
  "action-log.md"
1762
2098
  ]) {
1763
- const legacy = join6(projDir, file);
1764
- const shard = join6(shardDir, file);
1765
- if (existsSync6(shard))
2099
+ const legacy = join8(projDir, file);
2100
+ const shard = join8(shardDir, file);
2101
+ if (existsSync10(shard))
1766
2102
  continue;
1767
2103
  migrateFile(legacy, shard);
1768
2104
  }
1769
- const sidecar = join6(projDir, `learning-memory.${deviceId}.md`);
1770
- if (!existsSync6(sidecar)) {
2105
+ const sidecar = join8(projDir, `learning-memory.${deviceId}.md`);
2106
+ if (!existsSync10(sidecar)) {
1771
2107
  try {
1772
2108
  writeFileSync4(sidecar, "");
1773
2109
  } catch {}
1774
2110
  }
1775
2111
  for (const f of ["session.json", "scheduler-manifest.json"]) {
1776
- if (existsSync6(join6(projDir, f))) {
1777
- gitSafe3(`rm --cached "${join6(projDir, f)}"`);
2112
+ if (existsSync10(join8(projDir, f))) {
2113
+ gitSafe3(`rm --cached "${join8(projDir, f)}"`);
1778
2114
  }
1779
2115
  }
1780
- const indexPath = join6(projDir, "file-index.json");
1781
- if (existsSync6(indexPath)) {
2116
+ const indexPath = join8(projDir, "file-index.json");
2117
+ if (existsSync10(indexPath)) {
1782
2118
  const raw = safeReadJson(indexPath);
1783
2119
  if (raw && typeof raw.header === "object" && raw.header !== null && (raw.header.lifetimeHits > 0 || raw.header.lifetimeMisses > 0)) {
1784
2120
  atomicWriteJson(fileIndexCountersPathFor(projDir), {
@@ -1792,31 +2128,31 @@ function migrateProject(projDir, deviceId) {
1792
2128
  }
1793
2129
  }
1794
2130
  function fileIndexCountersPathFor(projDir) {
1795
- return join6(projDir, ".mink-state-counters.json");
2131
+ return join8(projDir, ".mink-state-counters.json");
1796
2132
  }
1797
2133
  function listProjects() {
1798
- const projectsRoot = join6(minkRoot(), "projects");
1799
- if (!existsSync6(projectsRoot))
2134
+ const projectsRoot = join8(minkRoot(), "projects");
2135
+ if (!existsSync10(projectsRoot))
1800
2136
  return [];
1801
2137
  try {
1802
- return readdirSync2(projectsRoot).filter((name) => {
2138
+ return readdirSync3(projectsRoot).filter((name) => {
1803
2139
  try {
1804
- return statSync2(join6(projectsRoot, name)).isDirectory();
2140
+ return statSync2(join8(projectsRoot, name)).isDirectory();
1805
2141
  } catch {
1806
2142
  return false;
1807
2143
  }
1808
- }).map((name) => join6(projectsRoot, name));
2144
+ }).map((name) => join8(projectsRoot, name));
1809
2145
  } catch {
1810
2146
  return [];
1811
2147
  }
1812
2148
  }
1813
2149
  function projectNeedsMigration(projDir) {
1814
- const stateDir = join6(projDir, "state");
1815
- if (existsSync6(stateDir)) {
2150
+ const stateDir = join8(projDir, "state");
2151
+ if (existsSync10(stateDir)) {
1816
2152
  try {
1817
- const shards = readdirSync2(stateDir).filter((d) => {
2153
+ const shards = readdirSync3(stateDir).filter((d) => {
1818
2154
  try {
1819
- return statSync2(join6(stateDir, d)).isDirectory();
2155
+ return statSync2(join8(stateDir, d)).isDirectory();
1820
2156
  } catch {
1821
2157
  return false;
1822
2158
  }
@@ -1831,7 +2167,7 @@ function projectNeedsMigration(projDir) {
1831
2167
  "bug-memory.json",
1832
2168
  "action-log.md"
1833
2169
  ]) {
1834
- if (existsSync6(join6(projDir, f)))
2170
+ if (existsSync10(join8(projDir, f)))
1835
2171
  return true;
1836
2172
  }
1837
2173
  return false;
@@ -1839,10 +2175,208 @@ function projectNeedsMigration(projDir) {
1839
2175
  function listProjectsNeedingMigration() {
1840
2176
  return listProjects().filter(projectNeedsMigration);
1841
2177
  }
2178
+ function planIdentityMigration() {
2179
+ const plan = [];
2180
+ if (resolveConfigValue("projects.identity").value !== "git-remote") {
2181
+ return plan;
2182
+ }
2183
+ const projectsRoot = join8(minkRoot(), "projects");
2184
+ if (!existsSync10(projectsRoot))
2185
+ return plan;
2186
+ let entries;
2187
+ try {
2188
+ entries = readdirSync3(projectsRoot);
2189
+ } catch {
2190
+ return plan;
2191
+ }
2192
+ for (const oldId of entries) {
2193
+ const oldProjDir = join8(projectsRoot, oldId);
2194
+ try {
2195
+ if (!statSync2(oldProjDir).isDirectory())
2196
+ continue;
2197
+ } catch {
2198
+ continue;
2199
+ }
2200
+ const meta = getProjectMeta(oldProjDir);
2201
+ if (!meta)
2202
+ continue;
2203
+ if (!existsSync10(meta.cwd)) {
2204
+ plan.push({
2205
+ oldId,
2206
+ newId: null,
2207
+ cwd: meta.cwd,
2208
+ action: "skip-no-cwd",
2209
+ reason: "working-copy path not reachable on this device"
2210
+ });
2211
+ continue;
2212
+ }
2213
+ let newId;
2214
+ try {
2215
+ newId = resolveProjectIdentity(meta.cwd).id;
2216
+ } catch {
2217
+ continue;
2218
+ }
2219
+ if (newId === oldId) {
2220
+ plan.push({ oldId, newId, cwd: meta.cwd, action: "skip-unchanged" });
2221
+ continue;
2222
+ }
2223
+ const newProjDir = join8(projectsRoot, newId);
2224
+ if (existsSync10(newProjDir)) {
2225
+ plan.push({
2226
+ oldId,
2227
+ newId,
2228
+ cwd: meta.cwd,
2229
+ action: "skip-converged",
2230
+ reason: "destination already exists (from sync); alias-only update"
2231
+ });
2232
+ continue;
2233
+ }
2234
+ plan.push({ oldId, newId, cwd: meta.cwd, action: "rename" });
2235
+ }
2236
+ return plan;
2237
+ }
2238
+ function identityBackupRoot(timestamp) {
2239
+ return join8(minkRoot(), IDENTITY_BACKUP_DIRNAME, timestamp);
2240
+ }
2241
+ function ensureIdentityBackupTimestamp() {
2242
+ const now = new Date;
2243
+ return `${now.getUTCFullYear()}${String(now.getUTCMonth() + 1).padStart(2, "0")}${String(now.getUTCDate()).padStart(2, "0")}-${String(now.getUTCHours()).padStart(2, "0")}${String(now.getUTCMinutes()).padStart(2, "0")}${String(now.getUTCSeconds()).padStart(2, "0")}`;
2244
+ }
2245
+ function backupProjectForRollback(srcDir, backupDir) {
2246
+ try {
2247
+ mkdirSync4(backupDir, { recursive: true });
2248
+ copyDirRecursive(srcDir, backupDir, new Set(["backups"]));
2249
+ return backupDir;
2250
+ } catch {
2251
+ return null;
2252
+ }
2253
+ }
2254
+ function copyDirRecursive(src, dest, excludeNames) {
2255
+ mkdirSync4(dest, { recursive: true });
2256
+ const entries = readdirSync3(src, { withFileTypes: true });
2257
+ for (const entry of entries) {
2258
+ if (excludeNames.has(entry.name))
2259
+ continue;
2260
+ const srcPath = join8(src, entry.name);
2261
+ const destPath = join8(dest, entry.name);
2262
+ if (entry.isDirectory()) {
2263
+ copyDirRecursive(srcPath, destPath, excludeNames);
2264
+ } else if (entry.isFile()) {
2265
+ writeFileSync4(destPath, readFileSync7(srcPath));
2266
+ }
2267
+ }
2268
+ }
2269
+ function migrateProjectIdentities(deviceId) {
2270
+ if (resolveConfigValue("projects.identity").value !== "git-remote") {
2271
+ return { renamed: 0, visited: 0, backupDir: null };
2272
+ }
2273
+ const plan = planIdentityMigration();
2274
+ const willRename = plan.filter((p) => p.action === "rename");
2275
+ let backupRoot = null;
2276
+ if (willRename.length > 0) {
2277
+ backupRoot = identityBackupRoot(ensureIdentityBackupTimestamp());
2278
+ }
2279
+ let renamed = 0;
2280
+ let visited = plan.length;
2281
+ const projectsRoot = join8(minkRoot(), "projects");
2282
+ for (const entry of plan) {
2283
+ const oldProjDir = join8(projectsRoot, entry.oldId);
2284
+ if (entry.cwd && entry.action !== "skip-no-cwd") {
2285
+ try {
2286
+ setProjectPathForDevice(oldProjDir, deviceId, entry.cwd);
2287
+ } catch {}
2288
+ }
2289
+ if (entry.action === "skip-converged" && entry.newId) {
2290
+ const newProjDir2 = join8(projectsRoot, entry.newId);
2291
+ try {
2292
+ addProjectAlias(newProjDir2, entry.oldId);
2293
+ if (entry.cwd) {
2294
+ setProjectPathForDevice(newProjDir2, deviceId, entry.cwd);
2295
+ }
2296
+ } catch {}
2297
+ continue;
2298
+ }
2299
+ if (entry.action !== "rename" || !entry.newId)
2300
+ continue;
2301
+ if (backupRoot) {
2302
+ backupProjectForRollback(oldProjDir, join8(backupRoot, entry.oldId));
2303
+ }
2304
+ const newProjDir = join8(projectsRoot, entry.newId);
2305
+ const moved = gitSafe3(`mv "${oldProjDir}" "${newProjDir}"`) !== null || (() => {
2306
+ try {
2307
+ renameSync2(oldProjDir, newProjDir);
2308
+ return true;
2309
+ } catch {
2310
+ return false;
2311
+ }
2312
+ })();
2313
+ if (!moved)
2314
+ continue;
2315
+ try {
2316
+ addProjectAlias(newProjDir, entry.oldId);
2317
+ if (entry.cwd) {
2318
+ setProjectPathForDevice(newProjDir, deviceId, entry.cwd);
2319
+ }
2320
+ } catch {}
2321
+ renamed++;
2322
+ }
2323
+ return { renamed, visited, backupDir: backupRoot };
2324
+ }
2325
+ function rollbackProjectIdentities() {
2326
+ const results = [];
2327
+ const projectsRoot = join8(minkRoot(), "projects");
2328
+ if (!existsSync10(projectsRoot))
2329
+ return results;
2330
+ let entries;
2331
+ try {
2332
+ entries = readdirSync3(projectsRoot);
2333
+ } catch {
2334
+ return results;
2335
+ }
2336
+ for (const currentId of entries) {
2337
+ const projDir = join8(projectsRoot, currentId);
2338
+ try {
2339
+ if (!statSync2(projDir).isDirectory())
2340
+ continue;
2341
+ } catch {
2342
+ continue;
2343
+ }
2344
+ const meta = getProjectMeta(projDir);
2345
+ if (!meta || !meta.aliases || meta.aliases.length === 0)
2346
+ continue;
2347
+ const restoredId = meta.aliases[meta.aliases.length - 1];
2348
+ const targetDir = join8(projectsRoot, restoredId);
2349
+ if (existsSync10(targetDir)) {
2350
+ results.push({ currentId, restoredId, ok: false });
2351
+ continue;
2352
+ }
2353
+ const remainingAliases = meta.aliases.slice(0, -1);
2354
+ const metaPath = join8(projDir, "project-meta.json");
2355
+ try {
2356
+ const raw = safeReadJson(metaPath);
2357
+ if (raw && typeof raw === "object" && !Array.isArray(raw)) {
2358
+ const obj = raw;
2359
+ obj.aliases = remainingAliases;
2360
+ atomicWriteJson(metaPath, obj);
2361
+ }
2362
+ } catch {}
2363
+ const moved = gitSafe3(`mv "${projDir}" "${targetDir}"`) !== null || (() => {
2364
+ try {
2365
+ renameSync2(projDir, targetDir);
2366
+ return true;
2367
+ } catch {
2368
+ return false;
2369
+ }
2370
+ })();
2371
+ results.push({ currentId, restoredId, ok: moved });
2372
+ }
2373
+ return results;
2374
+ }
1842
2375
  function migrateSyncLayout() {
1843
2376
  const fromVersion = readSyncVersion();
1844
2377
  const pending = listProjectsNeedingMigration();
1845
- if (fromVersion >= MINK_SYNC_VERSION && pending.length === 0) {
2378
+ const identityMode = resolveConfigValue("projects.identity").value;
2379
+ if (fromVersion >= MINK_SYNC_VERSION && pending.length === 0 && identityMode !== "git-remote") {
1846
2380
  return {
1847
2381
  ranMigration: false,
1848
2382
  fromVersion,
@@ -1887,13 +2421,18 @@ function migrateSyncLayout() {
1887
2421
  processed++;
1888
2422
  } catch {}
1889
2423
  }
2424
+ let identity = { renamed: 0, visited: 0 };
2425
+ try {
2426
+ identity = migrateProjectIdentities(deviceId);
2427
+ } catch {}
1890
2428
  if (remaining === 0 && listProjectsNeedingMigration().length === 0) {
1891
2429
  writeSyncVersion(MINK_SYNC_VERSION);
1892
2430
  }
1893
- if (isSyncInitialized() && processed > 0) {
2431
+ if (isSyncInitialized() && (processed > 0 || identity.renamed > 0)) {
1894
2432
  gitSafe3("add -A");
1895
2433
  gitSafe3(`reset HEAD ".sync-migrate.lock"`);
1896
- gitSafe3(`commit -m "mink: migrate sync layout v${fromVersion} -> v${MINK_SYNC_VERSION} (device ${deviceId.slice(0, 8)}, ${processed} projects)"`);
2434
+ const summary = identity.renamed > 0 ? `${processed} projects, ${identity.renamed} renamed for identity v3` : `${processed} projects`;
2435
+ gitSafe3(`commit -m "mink: migrate sync layout v${fromVersion} -> v${MINK_SYNC_VERSION} (device ${deviceId.slice(0, 8)}, ${summary})"`);
1897
2436
  }
1898
2437
  if (stashed) {
1899
2438
  gitSafe3("stash pop");
@@ -1907,7 +2446,56 @@ function migrateSyncLayout() {
1907
2446
  releaseLock();
1908
2447
  }
1909
2448
  }
1910
- function syncMigrateCommand() {
2449
+ function syncMigrateCommand(args = []) {
2450
+ const dryRun = args.includes("--dry-run");
2451
+ const rollback = args.includes("--rollback");
2452
+ if (rollback && dryRun) {
2453
+ console.error("[mink] --rollback and --dry-run cannot be combined");
2454
+ process.exit(1);
2455
+ }
2456
+ if (dryRun) {
2457
+ const plan = planIdentityMigration();
2458
+ if (plan.length === 0) {
2459
+ console.log("[mink] sync migrate --dry-run: no projects to rename (flag is off or no projects on disk)");
2460
+ return;
2461
+ }
2462
+ const renames = plan.filter((p) => p.action === "rename");
2463
+ const converged = plan.filter((p) => p.action === "skip-converged");
2464
+ const skippedNoCwd = plan.filter((p) => p.action === "skip-no-cwd");
2465
+ const unchanged = plan.filter((p) => p.action === "skip-unchanged");
2466
+ console.log(`[mink] sync migrate --dry-run: ${renames.length} rename(s), ${converged.length} alias-only, ${skippedNoCwd.length} skipped (no cwd), ${unchanged.length} unchanged`);
2467
+ for (const p of renames) {
2468
+ console.log(` rename: ${p.oldId} → ${p.newId}`);
2469
+ }
2470
+ for (const p of converged) {
2471
+ console.log(` alias: ${p.oldId} → ${p.newId} (already on disk)`);
2472
+ }
2473
+ for (const p of skippedNoCwd) {
2474
+ console.log(` skip: ${p.oldId} — ${p.reason}`);
2475
+ }
2476
+ return;
2477
+ }
2478
+ if (rollback) {
2479
+ const results = rollbackProjectIdentities();
2480
+ if (results.length === 0) {
2481
+ console.log("[mink] sync migrate --rollback: nothing to roll back");
2482
+ return;
2483
+ }
2484
+ const ok = results.filter((r) => r.ok);
2485
+ const failed = results.filter((r) => !r.ok);
2486
+ console.log(`[mink] sync migrate --rollback: ${ok.length} restored, ${failed.length} failed`);
2487
+ for (const r of ok) {
2488
+ console.log(` restored: ${r.currentId} → ${r.restoredId}`);
2489
+ }
2490
+ for (const r of failed) {
2491
+ console.log(` failed: ${r.currentId} → ${r.restoredId} (destination already exists or rename blocked)`);
2492
+ }
2493
+ if (ok.length > 0) {
2494
+ console.log(`
2495
+ [mink] tip: set projects.identity=path-derived to prevent the next session-start from re-migrating`);
2496
+ }
2497
+ return;
2498
+ }
1911
2499
  const result = migrateSyncLayout();
1912
2500
  if (!result.ranMigration) {
1913
2501
  console.log(`[mink] sync migrate: ${result.message ?? "no-op"}`);
@@ -1915,12 +2503,15 @@ function syncMigrateCommand() {
1915
2503
  }
1916
2504
  console.log(`[mink] sync migrate: v${result.fromVersion} → v${result.toVersion} complete`);
1917
2505
  }
1918
- var MIGRATE_LOCK = ".sync-migrate.lock", MIGRATE_LOCK_STALE_MS = 300000, MIGRATE_BUDGET_MS = 5000;
2506
+ var MIGRATE_LOCK = ".sync-migrate.lock", MIGRATE_LOCK_STALE_MS = 300000, MIGRATE_BUDGET_MS = 5000, IDENTITY_BACKUP_DIRNAME = ".identity-rollback";
1919
2507
  var init_sync_migrate = __esm(() => {
1920
2508
  init_paths();
1921
2509
  init_sync();
1922
2510
  init_device();
1923
2511
  init_fs_utils();
2512
+ init_project_id();
2513
+ init_project_registry();
2514
+ init_global_config();
1924
2515
  });
1925
2516
 
1926
2517
  // src/core/note-linker.ts
@@ -1931,8 +2522,8 @@ __export(exports_note_linker, {
1931
2522
  extractWikilinks: () => extractWikilinks,
1932
2523
  addBacklink: () => addBacklink
1933
2524
  });
1934
- import { join as join7 } from "path";
1935
- import { existsSync as existsSync7, readFileSync as readFileSync7, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
2525
+ import { join as join9 } from "path";
2526
+ import { existsSync as existsSync11, readFileSync as readFileSync8, readdirSync as readdirSync4, statSync as statSync3 } from "fs";
1936
2527
  function extractWikilinks(content) {
1937
2528
  const links = [];
1938
2529
  let match;
@@ -1958,9 +2549,9 @@ function insertWikilinks(content, targets) {
1958
2549
  return result;
1959
2550
  }
1960
2551
  function addBacklink(targetNotePath, sourceTitle) {
1961
- if (!existsSync7(targetNotePath))
2552
+ if (!existsSync11(targetNotePath))
1962
2553
  return;
1963
- const content = readFileSync7(targetNotePath, "utf-8");
2554
+ const content = readFileSync8(targetNotePath, "utf-8");
1964
2555
  if (content.includes(`[[${sourceTitle}]]`))
1965
2556
  return;
1966
2557
  const backlinkSection = `
@@ -2002,8 +2593,8 @@ function updateMasterIndex(vaultRootPath) {
2002
2593
  { name: "Patterns", dir: "patterns", emoji: "" }
2003
2594
  ];
2004
2595
  for (const cat of categories) {
2005
- const dirPath = join7(vaultRootPath, cat.dir);
2006
- if (!existsSync7(dirPath))
2596
+ const dirPath = join9(vaultRootPath, cat.dir);
2597
+ if (!existsSync11(dirPath))
2007
2598
  continue;
2008
2599
  const files = collectMarkdownFiles(dirPath, vaultRootPath);
2009
2600
  if (files.length === 0 && cat.dir !== "inbox")
@@ -2030,9 +2621,9 @@ function updateMasterIndex(vaultRootPath) {
2030
2621
  function collectMarkdownFiles(dirPath, rootPath) {
2031
2622
  const files = [];
2032
2623
  try {
2033
- const entries = readdirSync3(dirPath, { withFileTypes: true });
2624
+ const entries = readdirSync4(dirPath, { withFileTypes: true });
2034
2625
  for (const entry of entries) {
2035
- const fullPath = join7(dirPath, entry.name);
2626
+ const fullPath = join9(dirPath, entry.name);
2036
2627
  if (entry.isDirectory()) {
2037
2628
  files.push(...collectMarkdownFiles(fullPath, rootPath));
2038
2629
  } else if (entry.name.endsWith(".md") && !entry.name.startsWith("_")) {
@@ -2165,7 +2756,7 @@ var init_learning_memory = __esm(() => {
2165
2756
  });
2166
2757
 
2167
2758
  // src/core/token-ledger.ts
2168
- import { join as join8 } from "path";
2759
+ import { join as join10 } from "path";
2169
2760
  function addToLifetime(lifetime, session) {
2170
2761
  lifetime.totalTokens += session.totals.estimatedTokens;
2171
2762
  lifetime.totalReads += session.totals.readCount;
@@ -2296,13 +2887,13 @@ function createLedgerFinalizer(projectDir2, deviceIdOrThreshold, archiveThreshol
2296
2887
  let archivePath;
2297
2888
  let threshold;
2298
2889
  if (typeof deviceIdOrThreshold === "string") {
2299
- const shardDir = join8(projectDir2, "state", deviceIdOrThreshold);
2300
- ledgerPath = join8(shardDir, "token-ledger.json");
2301
- archivePath = join8(shardDir, "token-ledger-archive.json");
2890
+ const shardDir = join10(projectDir2, "state", deviceIdOrThreshold);
2891
+ ledgerPath = join10(shardDir, "token-ledger.json");
2892
+ archivePath = join10(shardDir, "token-ledger-archive.json");
2302
2893
  threshold = archiveThreshold;
2303
2894
  } else {
2304
- ledgerPath = join8(projectDir2, "token-ledger.json");
2305
- archivePath = join8(projectDir2, "token-ledger-archive.json");
2895
+ ledgerPath = join10(projectDir2, "token-ledger.json");
2896
+ archivePath = join10(projectDir2, "token-ledger-archive.json");
2306
2897
  threshold = deviceIdOrThreshold ?? archiveThreshold;
2307
2898
  }
2308
2899
  return {
@@ -2442,16 +3033,16 @@ var init_bug_memory = __esm(() => {
2442
3033
  });
2443
3034
 
2444
3035
  // src/core/state-aggregator.ts
2445
- import { existsSync as existsSync8, readdirSync as readdirSync4, readFileSync as readFileSync8, statSync as statSync4 } from "fs";
2446
- import { join as join9 } from "path";
3036
+ import { existsSync as existsSync12, readdirSync as readdirSync5, readFileSync as readFileSync9, statSync as statSync4 } from "fs";
3037
+ import { join as join11 } from "path";
2447
3038
  function listDeviceShardsAt(projDir) {
2448
- const stateDir = join9(projDir, "state");
2449
- if (!existsSync8(stateDir))
3039
+ const stateDir = join11(projDir, "state");
3040
+ if (!existsSync12(stateDir))
2450
3041
  return [];
2451
3042
  try {
2452
- return readdirSync4(stateDir).filter((name) => {
3043
+ return readdirSync5(stateDir).filter((name) => {
2453
3044
  try {
2454
- return statSync4(join9(stateDir, name)).isDirectory();
3045
+ return statSync4(join11(stateDir, name)).isDirectory();
2455
3046
  } catch {
2456
3047
  return false;
2457
3048
  }
@@ -2461,16 +3052,16 @@ function listDeviceShardsAt(projDir) {
2461
3052
  }
2462
3053
  }
2463
3054
  function listLearningMemorySidecarPathsAt(projDir) {
2464
- if (!existsSync8(projDir))
3055
+ if (!existsSync12(projDir))
2465
3056
  return [];
2466
3057
  try {
2467
- return readdirSync4(projDir).filter((f) => SIDECAR_RE.test(f)).map((f) => join9(projDir, f));
3058
+ return readdirSync5(projDir).filter((f) => SIDECAR_RE.test(f)).map((f) => join11(projDir, f));
2468
3059
  } catch {
2469
3060
  return [];
2470
3061
  }
2471
3062
  }
2472
3063
  function shardPath(projDir, deviceId, file) {
2473
- return join9(projDir, "state", deviceId, file);
3064
+ return join11(projDir, "state", deviceId, file);
2474
3065
  }
2475
3066
  function addLifetime(target, source) {
2476
3067
  target.totalTokens += source.totalTokens;
@@ -2487,12 +3078,12 @@ function aggregateTokenLedgerAt(projDir) {
2487
3078
  const seenSessions = new Set;
2488
3079
  const sources = [
2489
3080
  ...listDeviceShardsAt(projDir).map((id) => shardPath(projDir, id, "token-ledger.json")),
2490
- join9(projDir, "token-ledger.json")
3081
+ join11(projDir, "token-ledger.json")
2491
3082
  ];
2492
3083
  const seenFlagKeys = new Set;
2493
3084
  const wasteFlags = [];
2494
3085
  for (const path of sources) {
2495
- if (!existsSync8(path))
3086
+ if (!existsSync12(path))
2496
3087
  continue;
2497
3088
  const ledger = loadLedger(path);
2498
3089
  addLifetime(merged.lifetime, ledger.lifetime);
@@ -2526,10 +3117,10 @@ function aggregateBugMemoryAt(projDir) {
2526
3117
  let maxNextId = 1;
2527
3118
  const sources = [
2528
3119
  ...listDeviceShardsAt(projDir).map((id) => shardPath(projDir, id, "bug-memory.json")),
2529
- join9(projDir, "bug-memory.json")
3120
+ join11(projDir, "bug-memory.json")
2530
3121
  ];
2531
3122
  for (const path of sources) {
2532
- if (!existsSync8(path))
3123
+ if (!existsSync12(path))
2533
3124
  continue;
2534
3125
  const mem = loadBugMemory(path);
2535
3126
  if (mem.nextId > maxNextId)
@@ -2569,10 +3160,10 @@ function aggregateActionLogAt(projDir) {
2569
3160
  let order = 0;
2570
3161
  const sources = [
2571
3162
  ...listDeviceShardsAt(projDir).map((id) => shardPath(projDir, id, "action-log.md")),
2572
- join9(projDir, "action-log.md")
3163
+ join11(projDir, "action-log.md")
2573
3164
  ];
2574
3165
  for (const path of sources) {
2575
- if (!existsSync8(path))
3166
+ if (!existsSync12(path))
2576
3167
  continue;
2577
3168
  const content = safeReadLog(path);
2578
3169
  if (!content)
@@ -2597,11 +3188,11 @@ function aggregateActionLog(cwd) {
2597
3188
  return aggregateActionLogAt(projectDir(cwd));
2598
3189
  }
2599
3190
  function aggregateLearningMemoryAt(projDir) {
2600
- const canonicalPath = join9(projDir, "learning-memory.md");
3191
+ const canonicalPath = join11(projDir, "learning-memory.md");
2601
3192
  let merged;
2602
- if (existsSync8(canonicalPath)) {
3193
+ if (existsSync12(canonicalPath)) {
2603
3194
  try {
2604
- merged = parseLearningMemory(readFileSync8(canonicalPath, "utf-8"));
3195
+ merged = parseLearningMemory(readFileSync9(canonicalPath, "utf-8"));
2605
3196
  } catch {
2606
3197
  merged = createEmptyLearningMemory("unknown");
2607
3198
  }
@@ -2611,7 +3202,7 @@ function aggregateLearningMemoryAt(projDir) {
2611
3202
  for (const sidecarPath of listLearningMemorySidecarPathsAt(projDir)) {
2612
3203
  let sidecar;
2613
3204
  try {
2614
- sidecar = parseLearningMemory(readFileSync8(sidecarPath, "utf-8"));
3205
+ sidecar = parseLearningMemory(readFileSync9(sidecarPath, "utf-8"));
2615
3206
  } catch {
2616
3207
  continue;
2617
3208
  }
@@ -2918,12 +3509,12 @@ var exports_reflect = {};
2918
3509
  __export(exports_reflect, {
2919
3510
  reflect: () => reflect
2920
3511
  });
2921
- import { existsSync as existsSync9 } from "fs";
3512
+ import { existsSync as existsSync13 } from "fs";
2922
3513
  import { dirname as dirname3 } from "path";
2923
3514
  function reflect(_cwd, memoryPath, configPath2) {
2924
3515
  const projDir = dirname3(memoryPath);
2925
3516
  const mem = aggregateLearningMemoryAt(projDir);
2926
- if (totalEntryCount(mem) === 0 && !existsSync9(memoryPath)) {
3517
+ if (totalEntryCount(mem) === 0 && !existsSync13(memoryPath)) {
2927
3518
  console.log("[mink] no learning memory found");
2928
3519
  return null;
2929
3520
  }
@@ -2982,10 +3573,11 @@ __export(exports_paths2, {
2982
3573
  actionLogShardPath: () => actionLogShardPath2,
2983
3574
  actionLogPath: () => actionLogPath2
2984
3575
  });
2985
- import { join as join11 } from "path";
3576
+ import { join as join13 } from "path";
3577
+ import { existsSync as existsSync15 } from "fs";
2986
3578
  import { homedir as homedir3 } from "os";
2987
3579
  function resolveMinkRoot2() {
2988
- return process.env.MINK_ROOT_OVERRIDE || join11(homedir3(), ".mink");
3580
+ return process.env.MINK_ROOT_OVERRIDE || join13(homedir3(), ".mink");
2989
3581
  }
2990
3582
  function minkRoot2() {
2991
3583
  if (process.env.MINK_ROOT_OVERRIDE) {
@@ -2994,104 +3586,113 @@ function minkRoot2() {
2994
3586
  return MINK_ROOT2;
2995
3587
  }
2996
3588
  function projectDir2(cwd) {
2997
- const id = generateProjectId(cwd);
2998
- return join11(minkRoot2(), "projects", id);
3589
+ const id = projectIdFor(cwd);
3590
+ const primary = join13(minkRoot2(), "projects", id);
3591
+ if (existsSync15(primary))
3592
+ return primary;
3593
+ try {
3594
+ const { findProjectDirByIdOrAlias: findProjectDirByIdOrAlias2 } = (init_project_registry(), __toCommonJS(exports_project_registry));
3595
+ const aliased = findProjectDirByIdOrAlias2(id);
3596
+ if (aliased)
3597
+ return aliased;
3598
+ } catch {}
3599
+ return primary;
2999
3600
  }
3000
3601
  function sessionPath2(cwd) {
3001
- return join11(projectDir2(cwd), "session.json");
3602
+ return join13(projectDir2(cwd), "session.json");
3002
3603
  }
3003
3604
  function fileIndexPath2(cwd) {
3004
- return join11(projectDir2(cwd), "file-index.json");
3605
+ return join13(projectDir2(cwd), "file-index.json");
3005
3606
  }
3006
3607
  function configPath2(cwd) {
3007
- return join11(projectDir2(cwd), "config.json");
3608
+ return join13(projectDir2(cwd), "config.json");
3008
3609
  }
3009
3610
  function learningMemoryPath2(cwd) {
3010
- return join11(projectDir2(cwd), "learning-memory.md");
3611
+ return join13(projectDir2(cwd), "learning-memory.md");
3011
3612
  }
3012
3613
  function tokenLedgerPath2(cwd) {
3013
- return join11(projectDir2(cwd), "token-ledger.json");
3614
+ return join13(projectDir2(cwd), "token-ledger.json");
3014
3615
  }
3015
3616
  function tokenLedgerArchivePath2(cwd) {
3016
- return join11(projectDir2(cwd), "token-ledger-archive.json");
3617
+ return join13(projectDir2(cwd), "token-ledger-archive.json");
3017
3618
  }
3018
3619
  function bugMemoryPath2(cwd) {
3019
- return join11(projectDir2(cwd), "bug-memory.json");
3620
+ return join13(projectDir2(cwd), "bug-memory.json");
3020
3621
  }
3021
3622
  function actionLogPath2(cwd) {
3022
- return join11(projectDir2(cwd), "action-log.md");
3623
+ return join13(projectDir2(cwd), "action-log.md");
3023
3624
  }
3024
3625
  function schedulerPidPath2() {
3025
- return join11(minkRoot2(), "scheduler.pid");
3626
+ return join13(minkRoot2(), "scheduler.pid");
3026
3627
  }
3027
3628
  function schedulerLogPath2() {
3028
- return join11(minkRoot2(), "scheduler.log");
3629
+ return join13(minkRoot2(), "scheduler.log");
3029
3630
  }
3030
3631
  function schedulerManifestPath2(cwd) {
3031
- return join11(projectDir2(cwd), "scheduler-manifest.json");
3632
+ return join13(projectDir2(cwd), "scheduler-manifest.json");
3032
3633
  }
3033
3634
  function channelPidPath2() {
3034
- return join11(minkRoot2(), "channel.pid");
3635
+ return join13(minkRoot2(), "channel.pid");
3035
3636
  }
3036
3637
  function channelLogPath2() {
3037
- return join11(minkRoot2(), "channel.log");
3638
+ return join13(minkRoot2(), "channel.log");
3038
3639
  }
3039
3640
  function globalConfigPath2() {
3040
- return join11(minkRoot2(), "config");
3641
+ return join13(minkRoot2(), "config");
3041
3642
  }
3042
3643
  function localConfigPath2() {
3043
- return join11(minkRoot2(), "config.local");
3644
+ return join13(minkRoot2(), "config.local");
3044
3645
  }
3045
3646
  function deviceIdPath2() {
3046
- return join11(minkRoot2(), "device-id");
3647
+ return join13(minkRoot2(), "device-id");
3047
3648
  }
3048
3649
  function deviceRegistryPath2() {
3049
- return join11(minkRoot2(), "devices.json");
3650
+ return join13(minkRoot2(), "devices.json");
3050
3651
  }
3051
3652
  function projectMetaPath2(cwd) {
3052
- return join11(projectDir2(cwd), "project-meta.json");
3653
+ return join13(projectDir2(cwd), "project-meta.json");
3053
3654
  }
3054
3655
  function backupDirPath2(cwd) {
3055
- return join11(projectDir2(cwd), "backups");
3656
+ return join13(projectDir2(cwd), "backups");
3056
3657
  }
3057
3658
  function syncVersionPath2() {
3058
- return join11(minkRoot2(), ".mink-sync-version");
3659
+ return join13(minkRoot2(), ".mink-sync-version");
3059
3660
  }
3060
3661
  function projectStateDir2(cwd) {
3061
- return join11(projectDir2(cwd), "state");
3662
+ return join13(projectDir2(cwd), "state");
3062
3663
  }
3063
3664
  function deviceShardDir2(cwd, deviceId) {
3064
- return join11(projectStateDir2(cwd), deviceId);
3665
+ return join13(projectStateDir2(cwd), deviceId);
3065
3666
  }
3066
3667
  function tokenLedgerShardPath2(cwd, deviceId) {
3067
- return join11(deviceShardDir2(cwd, deviceId), "token-ledger.json");
3668
+ return join13(deviceShardDir2(cwd, deviceId), "token-ledger.json");
3068
3669
  }
3069
3670
  function tokenLedgerArchiveShardPath2(cwd, deviceId) {
3070
- return join11(deviceShardDir2(cwd, deviceId), "token-ledger-archive.json");
3671
+ return join13(deviceShardDir2(cwd, deviceId), "token-ledger-archive.json");
3071
3672
  }
3072
3673
  function bugMemoryShardPath2(cwd, deviceId) {
3073
- return join11(deviceShardDir2(cwd, deviceId), "bug-memory.json");
3674
+ return join13(deviceShardDir2(cwd, deviceId), "bug-memory.json");
3074
3675
  }
3075
3676
  function actionLogShardPath2(cwd, deviceId) {
3076
- return join11(deviceShardDir2(cwd, deviceId), "action-log.md");
3677
+ return join13(deviceShardDir2(cwd, deviceId), "action-log.md");
3077
3678
  }
3078
3679
  function learningMemorySidecarPath2(cwd, deviceId) {
3079
- return join11(projectDir2(cwd), `learning-memory.${deviceId}.md`);
3680
+ return join13(projectDir2(cwd), `learning-memory.${deviceId}.md`);
3080
3681
  }
3081
3682
  function fileIndexCountersPath3(cwd) {
3082
- return join11(projectDir2(cwd), ".mink-state-counters.json");
3683
+ return join13(projectDir2(cwd), ".mink-state-counters.json");
3083
3684
  }
3084
3685
  function designCapturesDir2(cwd) {
3085
- return join11(projectDir2(cwd), "design-captures");
3686
+ return join13(projectDir2(cwd), "design-captures");
3086
3687
  }
3087
3688
  function designReportPath2(cwd) {
3088
- return join11(projectDir2(cwd), "design-report.json");
3689
+ return join13(projectDir2(cwd), "design-report.json");
3089
3690
  }
3090
3691
  function frameworkAdvisorPath2(cwd) {
3091
- return join11(projectDir2(cwd), "framework-advisor.md");
3692
+ return join13(projectDir2(cwd), "framework-advisor.md");
3092
3693
  }
3093
3694
  function frameworkAdvisorJsonPath2(cwd) {
3094
- return join11(projectDir2(cwd), "framework-advisor.json");
3695
+ return join13(projectDir2(cwd), "framework-advisor.json");
3095
3696
  }
3096
3697
  var MINK_ROOT2;
3097
3698
  var init_paths2 = __esm(() => {
@@ -3108,13 +3709,13 @@ __export(exports_backup, {
3108
3709
  });
3109
3710
  import {
3110
3711
  mkdirSync as mkdirSync6,
3111
- readdirSync as readdirSync5,
3112
- readFileSync as readFileSync10,
3712
+ readdirSync as readdirSync6,
3713
+ readFileSync as readFileSync11,
3113
3714
  writeFileSync as writeFileSync5,
3114
- existsSync as existsSync11,
3715
+ existsSync as existsSync16,
3115
3716
  statSync as statSync6
3116
3717
  } from "fs";
3117
- import { join as join12 } from "path";
3718
+ import { join as join14 } from "path";
3118
3719
  function formatTimestamp(date) {
3119
3720
  const y = date.getFullYear();
3120
3721
  const mo = String(date.getMonth() + 1).padStart(2, "0");
@@ -3127,14 +3728,14 @@ function formatTimestamp(date) {
3127
3728
  }
3128
3729
  function copyDirectoryFiles(srcDir, destDir, excludeDirs) {
3129
3730
  mkdirSync6(destDir, { recursive: true });
3130
- const entries = readdirSync5(srcDir, { withFileTypes: true });
3731
+ const entries = readdirSync6(srcDir, { withFileTypes: true });
3131
3732
  for (const entry of entries) {
3132
3733
  if (entry.isDirectory()) {
3133
3734
  if (excludeDirs.includes(entry.name))
3134
3735
  continue;
3135
- copyDirectoryFiles(join12(srcDir, entry.name), join12(destDir, entry.name), excludeDirs);
3736
+ copyDirectoryFiles(join14(srcDir, entry.name), join14(destDir, entry.name), excludeDirs);
3136
3737
  } else if (entry.isFile()) {
3137
- writeFileSync5(join12(destDir, entry.name), readFileSync10(join12(srcDir, entry.name)));
3738
+ writeFileSync5(join14(destDir, entry.name), readFileSync11(join14(srcDir, entry.name)));
3138
3739
  }
3139
3740
  }
3140
3741
  }
@@ -3143,25 +3744,25 @@ function createBackup(cwd) {
3143
3744
  const dir = backupDirPath(cwd);
3144
3745
  let name = base;
3145
3746
  let suffix = 1;
3146
- while (existsSync11(join12(dir, name))) {
3747
+ while (existsSync16(join14(dir, name))) {
3147
3748
  name = `${base}-${suffix}`;
3148
3749
  suffix++;
3149
3750
  }
3150
3751
  const src = projectDir(cwd);
3151
- const dest = join12(dir, name);
3752
+ const dest = join14(dir, name);
3152
3753
  copyDirectoryFiles(src, dest, ["backups"]);
3153
3754
  return name;
3154
3755
  }
3155
3756
  function listBackups(cwd) {
3156
3757
  const dir = backupDirPath(cwd);
3157
- if (!existsSync11(dir))
3758
+ if (!existsSync16(dir))
3158
3759
  return [];
3159
- const entries = readdirSync5(dir, { withFileTypes: true });
3760
+ const entries = readdirSync6(dir, { withFileTypes: true });
3160
3761
  const backups = [];
3161
3762
  for (const entry of entries) {
3162
3763
  if (!entry.isDirectory() || !entry.name.startsWith("backup-"))
3163
3764
  continue;
3164
- const backupPath = join12(dir, entry.name);
3765
+ const backupPath = join14(dir, entry.name);
3165
3766
  const match = entry.name.match(/^backup-(\d{4})(\d{2})(\d{2})-(\d{2})(\d{2})(\d{2})(\d{3})?(?:-\d+)?$/);
3166
3767
  let timestamp;
3167
3768
  if (match) {
@@ -3171,7 +3772,7 @@ function listBackups(cwd) {
3171
3772
  }
3172
3773
  let fileCount = 0;
3173
3774
  try {
3174
- fileCount = readdirSync5(backupPath).length;
3775
+ fileCount = readdirSync6(backupPath).length;
3175
3776
  } catch {}
3176
3777
  backups.push({ name: entry.name, timestamp, path: backupPath, fileCount });
3177
3778
  }
@@ -3184,8 +3785,8 @@ function listBackups(cwd) {
3184
3785
  return backups;
3185
3786
  }
3186
3787
  function restoreBackup(cwd, backupName) {
3187
- const backupPath = join12(backupDirPath(cwd), backupName);
3188
- if (!existsSync11(backupPath)) {
3788
+ const backupPath = join14(backupDirPath(cwd), backupName);
3789
+ if (!existsSync16(backupPath)) {
3189
3790
  throw new Error(`backup not found: ${backupName}`);
3190
3791
  }
3191
3792
  createBackup(cwd);
@@ -3196,8 +3797,8 @@ var init_backup = __esm(() => {
3196
3797
  });
3197
3798
 
3198
3799
  // src/core/scanner.ts
3199
- import { readdirSync as readdirSync6, statSync as statSync7 } from "fs";
3200
- import { join as join13, relative } from "path";
3800
+ import { readdirSync as readdirSync7, statSync as statSync7 } from "fs";
3801
+ import { join as join15, relative } from "path";
3201
3802
  function matchesPattern(name, pattern) {
3202
3803
  if (pattern.includes("*")) {
3203
3804
  const regex = new RegExp("^" + pattern.replace(/\./g, "\\.").replace(/\*/g, ".*") + "$");
@@ -3211,7 +3812,7 @@ function isExcluded(name, excludes) {
3211
3812
  function walkDirectory(dir, projectRoot, excludes, results) {
3212
3813
  let entries;
3213
3814
  try {
3214
- entries = readdirSync6(dir, { withFileTypes: true });
3815
+ entries = readdirSync7(dir, { withFileTypes: true });
3215
3816
  } catch {
3216
3817
  return;
3217
3818
  }
@@ -3221,14 +3822,14 @@ function walkDirectory(dir, projectRoot, excludes, results) {
3221
3822
  if (entry.isDirectory()) {
3222
3823
  if (isExcluded(entry.name, excludes))
3223
3824
  continue;
3224
- walkDirectory(join13(dir, entry.name), projectRoot, excludes, results);
3825
+ walkDirectory(join15(dir, entry.name), projectRoot, excludes, results);
3225
3826
  continue;
3226
3827
  }
3227
3828
  if (entry.isFile()) {
3228
3829
  if (isExcluded(entry.name, excludes))
3229
3830
  continue;
3230
3831
  try {
3231
- const fullPath = join13(dir, entry.name);
3832
+ const fullPath = join15(dir, entry.name);
3232
3833
  const stat = statSync7(fullPath);
3233
3834
  results.push({
3234
3835
  relativePath: relative(projectRoot, fullPath),
@@ -3247,11 +3848,16 @@ function loadConfig(configPath3) {
3247
3848
  function getExcludes(config) {
3248
3849
  return [...DEFAULT_EXCLUDES, ...config.excludePatterns ?? []];
3249
3850
  }
3250
- function scanProject(projectRoot, excludes, maxFiles = DEFAULT_MAX_FILES) {
3851
+ function scanProjectWithStats(projectRoot, excludes, maxFiles = DEFAULT_MAX_FILES) {
3251
3852
  const results = [];
3252
3853
  walkDirectory(projectRoot, projectRoot, excludes, results);
3253
3854
  results.sort((a, b) => b.mtimeMs - a.mtimeMs);
3254
- return results.slice(0, maxFiles);
3855
+ const totalScanned = results.length;
3856
+ const files = results.slice(0, maxFiles);
3857
+ return { files, totalScanned, truncated: totalScanned - files.length };
3858
+ }
3859
+ function scanProject(projectRoot, excludes, maxFiles = DEFAULT_MAX_FILES) {
3860
+ return scanProjectWithStats(projectRoot, excludes, maxFiles).files;
3255
3861
  }
3256
3862
  var DEFAULT_EXCLUDES, DEFAULT_MAX_FILES = 500;
3257
3863
  var init_scanner = __esm(() => {
@@ -3549,8 +4155,12 @@ var exports_scan = {};
3549
4155
  __export(exports_scan, {
3550
4156
  scan: () => scan
3551
4157
  });
3552
- import { readFileSync as readFileSync11 } from "fs";
3553
- import { join as join14 } from "path";
4158
+ import { readFileSync as readFileSync12 } from "fs";
4159
+ import { join as join16, relative as relative2 } from "path";
4160
+ function configRelativePath(cfgPath, cwd) {
4161
+ const rel = relative2(cwd, cfgPath);
4162
+ return rel.startsWith("..") ? cfgPath : rel;
4163
+ }
3554
4164
  function loadExistingIndex(indexPath) {
3555
4165
  const raw = safeReadJson(indexPath);
3556
4166
  if (isFileIndex(raw))
@@ -3595,15 +4205,16 @@ function scan(cwd, options) {
3595
4205
  }
3596
4206
  const start = Date.now();
3597
4207
  const index = loadExistingIndex(idxPath);
3598
- const scanned = scanProject(cwd, excludes, maxFiles);
4208
+ const stats = scanProjectWithStats(cwd, excludes, maxFiles);
4209
+ const scanned = stats.files;
3599
4210
  const newIndex = createEmptyIndex();
3600
4211
  newIndex.header.lifetimeHits = index.header.lifetimeHits;
3601
4212
  newIndex.header.lifetimeMisses = index.header.lifetimeMisses;
3602
4213
  for (const file of scanned) {
3603
- const fullPath = join14(cwd, file.relativePath);
4214
+ const fullPath = join16(cwd, file.relativePath);
3604
4215
  let content;
3605
4216
  try {
3606
- content = readFileSync11(fullPath, "utf-8");
4217
+ content = readFileSync12(fullPath, "utf-8");
3607
4218
  } catch {
3608
4219
  continue;
3609
4220
  }
@@ -3619,7 +4230,13 @@ function scan(cwd, options) {
3619
4230
  newIndex.header.lastScanTimestamp = new Date().toISOString();
3620
4231
  atomicWriteJson(idxPath, newIndex);
3621
4232
  const elapsed = Date.now() - start;
3622
- console.log(`[mink] indexed ${newIndex.header.totalFiles} files in ${elapsed}ms`);
4233
+ if (stats.truncated > 0) {
4234
+ console.log(`[mink] scanned ${stats.totalScanned} files; indexed ${newIndex.header.totalFiles} most recent in ${elapsed}ms`);
4235
+ console.log(` ${stats.truncated} files past maxFiles=${maxFiles} were not indexed`);
4236
+ console.log(` raise the cap by setting "maxFiles" in ${configRelativePath(cfgPath, cwd)}`);
4237
+ } else {
4238
+ console.log(`[mink] indexed ${newIndex.header.totalFiles} files in ${elapsed}ms`);
4239
+ }
3623
4240
  }
3624
4241
  var init_scan = __esm(() => {
3625
4242
  init_paths();
@@ -3638,13 +4255,13 @@ __export(exports_seed, {
3638
4255
  parseGoMod: () => parseGoMod,
3639
4256
  parseCargoToml: () => parseCargoToml
3640
4257
  });
3641
- import { basename as basename4, join as join15 } from "path";
3642
- import { readFileSync as readFileSync12, existsSync as existsSync12 } from "fs";
4258
+ import { basename as basename4, join as join17 } from "path";
4259
+ import { readFileSync as readFileSync13, existsSync as existsSync17 } from "fs";
3643
4260
  function readFile(filePath) {
3644
- if (!existsSync12(filePath))
4261
+ if (!existsSync17(filePath))
3645
4262
  return null;
3646
4263
  try {
3647
- return readFileSync12(filePath, "utf-8");
4264
+ return readFileSync13(filePath, "utf-8");
3648
4265
  } catch {
3649
4266
  return null;
3650
4267
  }
@@ -3734,10 +4351,10 @@ function parseGoMod(filePath) {
3734
4351
  }
3735
4352
  function seedLearningMemory(projectRoot) {
3736
4353
  const parsers = [
3737
- () => parsePackageJson(join15(projectRoot, "package.json")),
3738
- () => parsePyprojectToml(join15(projectRoot, "pyproject.toml")),
3739
- () => parseCargoToml(join15(projectRoot, "Cargo.toml")),
3740
- () => parseGoMod(join15(projectRoot, "go.mod"))
4354
+ () => parsePackageJson(join17(projectRoot, "package.json")),
4355
+ () => parsePyprojectToml(join17(projectRoot, "pyproject.toml")),
4356
+ () => parseCargoToml(join17(projectRoot, "Cargo.toml")),
4357
+ () => parseGoMod(join17(projectRoot, "go.mod"))
3741
4358
  ];
3742
4359
  const infos = parsers.map((fn) => fn()).filter((info) => info !== null);
3743
4360
  const projectName = infos.find((i) => i.projectName)?.projectName ?? basename4(projectRoot);
@@ -3821,12 +4438,12 @@ __export(exports_init, {
3821
4438
  detectRuntime: () => detectRuntime,
3822
4439
  buildHooksConfig: () => buildHooksConfig
3823
4440
  });
3824
- import { execSync as execSync4 } from "child_process";
3825
- import { mkdirSync as mkdirSync7, existsSync as existsSync13 } from "fs";
3826
- import { resolve as resolve2, dirname as dirname5, basename as basename5, join as join16 } from "path";
4441
+ import { execSync as execSync5 } from "child_process";
4442
+ import { mkdirSync as mkdirSync7, existsSync as existsSync18 } from "fs";
4443
+ import { resolve as resolve2, dirname as dirname5, basename as basename5, join as join18 } from "path";
3827
4444
  function detectRuntime() {
3828
4445
  try {
3829
- execSync4("bun --version", { stdio: "ignore" });
4446
+ execSync5("bun --version", { stdio: "ignore" });
3830
4447
  return "bun";
3831
4448
  } catch {
3832
4449
  return "node";
@@ -3839,8 +4456,8 @@ function resolveCliPath() {
3839
4456
  return selfPath;
3840
4457
  }
3841
4458
  const projectRoot = resolve2(selfDir, "../..");
3842
- const distPath = join16(projectRoot, "dist", "cli.js");
3843
- if (existsSync13(distPath))
4459
+ const distPath = join18(projectRoot, "dist", "cli.js");
4460
+ if (existsSync18(distPath))
3844
4461
  return distPath;
3845
4462
  return resolve2(selfDir, "../cli.ts");
3846
4463
  }
@@ -3900,9 +4517,9 @@ function mergeHooksIntoSettings(settingsPath, newHooks) {
3900
4517
  }
3901
4518
  function isExistingInstallation(cwd) {
3902
4519
  const dir = projectDir(cwd);
3903
- if (!existsSync13(dir))
4520
+ if (!existsSync18(dir))
3904
4521
  return false;
3905
- return existsSync13(join16(dir, "file-index.json"));
4522
+ return existsSync18(join18(dir, "file-index.json"));
3906
4523
  }
3907
4524
  async function init(cwd) {
3908
4525
  const runtime = detectRuntime();
@@ -3920,16 +4537,20 @@ async function init(cwd) {
3920
4537
  mergeHooksIntoSettings(settingsPath, hooks);
3921
4538
  const rulePath = writeMinkRule(cwd);
3922
4539
  mkdirSync7(dir, { recursive: true });
3923
- const projectId = generateProjectId(cwd);
4540
+ const identity = resolveProjectIdentity(cwd);
4541
+ const projectId = identity.id;
3924
4542
  const isNotesProject = isWikiEnabled() && isVaultInitialized() && isInsideVault(cwd);
3925
4543
  const metaPath = projectMetaPath(cwd);
3926
4544
  const existingMeta = safeReadJson(metaPath);
4545
+ const deviceId = getOrCreateDeviceId();
4546
+ const existingPathsByDevice = existingMeta?.pathsByDevice && typeof existingMeta.pathsByDevice === "object" && !Array.isArray(existingMeta.pathsByDevice) ? existingMeta.pathsByDevice : {};
3927
4547
  atomicWriteJson(metaPath, {
3928
4548
  ...existingMeta ?? {},
3929
4549
  cwd,
3930
4550
  name: basename5(cwd),
3931
4551
  initTimestamp: existingMeta?.initTimestamp ?? new Date().toISOString(),
3932
4552
  version: "0.1.0",
4553
+ pathsByDevice: { ...existingPathsByDevice, [deviceId]: cwd },
3933
4554
  ...isNotesProject ? { projectType: "notes" } : {}
3934
4555
  });
3935
4556
  if (upgrading) {
@@ -3939,17 +4560,23 @@ async function init(cwd) {
3939
4560
  console.log(` rule: ${rulePath}`);
3940
4561
  } else {
3941
4562
  console.log(`[mink] initialized`);
3942
- console.log(` project: ${projectId}`);
4563
+ console.log(` project: ${projectId} (${identity.source})`);
3943
4564
  console.log(` state: ${dir}`);
3944
4565
  console.log(` runtime: ${runtime}`);
3945
4566
  console.log(` hooks: ${settingsPath}`);
3946
4567
  console.log(` rule: ${rulePath}`);
3947
4568
  }
4569
+ if (identity.source === "path-derived") {
4570
+ const root = getRepoRoot(cwd);
4571
+ if (root && !getRepoRemote(cwd)) {
4572
+ console.log(` note: this repo has no remote configured. Project state will not unify across machines until you add one and run \`mink config projects.identity git-remote\`.`);
4573
+ }
4574
+ }
3948
4575
  const { scan: scan2 } = await Promise.resolve().then(() => (init_scan(), exports_scan));
3949
4576
  scan2(cwd, { check: false });
3950
4577
  const { learningMemoryPath: learningMemoryPath3 } = await Promise.resolve().then(() => (init_paths(), exports_paths));
3951
4578
  const memPath = learningMemoryPath3(cwd);
3952
- if (!existsSync13(memPath)) {
4579
+ if (!existsSync18(memPath)) {
3953
4580
  const { seedLearningMemory: seedLearningMemory2 } = await Promise.resolve().then(() => (init_seed(), exports_seed));
3954
4581
  const { serializeLearningMemory: serializeLearningMemory2 } = await Promise.resolve().then(() => (init_learning_memory(), exports_learning_memory));
3955
4582
  const mem = seedLearningMemory2(cwd);
@@ -3958,8 +4585,8 @@ async function init(cwd) {
3958
4585
  if (isWikiEnabled() && isVaultInitialized() && !isNotesProject) {
3959
4586
  try {
3960
4587
  const projectSlug = basename5(cwd);
3961
- const overviewPath = join16(vaultProjects(projectSlug), "overview.md");
3962
- if (!existsSync13(overviewPath)) {
4588
+ const overviewPath = join18(vaultProjects(projectSlug), "overview.md");
4589
+ if (!existsSync18(overviewPath)) {
3963
4590
  const now = new Date().toISOString();
3964
4591
  const overview = [
3965
4592
  `---`,
@@ -4008,6 +4635,8 @@ var init_init = __esm(() => {
4008
4635
  init_paths();
4009
4636
  init_project_id();
4010
4637
  init_fs_utils();
4638
+ init_device();
4639
+ init_git_identity();
4011
4640
  init_vault();
4012
4641
  });
4013
4642
 
@@ -4046,12 +4675,12 @@ var init_state_counters = __esm(() => {
4046
4675
  });
4047
4676
 
4048
4677
  // src/core/channel-templates.ts
4049
- import { join as join17 } from "path";
4050
- import { existsSync as existsSync14, writeFileSync as writeFileSync6, mkdirSync as mkdirSync8 } from "fs";
4678
+ import { join as join19 } from "path";
4679
+ import { existsSync as existsSync19, writeFileSync as writeFileSync6, mkdirSync as mkdirSync8 } from "fs";
4051
4680
  function writeCompanionClaudeMd(vaultPath, overwrite = false) {
4052
4681
  mkdirSync8(vaultPath, { recursive: true });
4053
- const claudeMdPath = join17(vaultPath, "CLAUDE.md");
4054
- if (existsSync14(claudeMdPath) && !overwrite) {
4682
+ const claudeMdPath = join19(vaultPath, "CLAUDE.md");
4683
+ if (existsSync19(claudeMdPath) && !overwrite) {
4055
4684
  return false;
4056
4685
  }
4057
4686
  writeFileSync6(claudeMdPath, COMPANION_CLAUDE_MD);
@@ -4203,12 +4832,12 @@ mink wiki rebuild-index
4203
4832
  var init_channel_templates = () => {};
4204
4833
 
4205
4834
  // src/core/channel-process.ts
4206
- import { readFileSync as readFileSync13, writeFileSync as writeFileSync7, unlinkSync as unlinkSync3, mkdirSync as mkdirSync9, existsSync as existsSync15 } from "fs";
4207
- import { dirname as dirname6, join as join18 } from "path";
4835
+ import { readFileSync as readFileSync14, writeFileSync as writeFileSync7, unlinkSync as unlinkSync3, mkdirSync as mkdirSync9, existsSync as existsSync20 } from "fs";
4836
+ import { dirname as dirname6, join as join20 } from "path";
4208
4837
  import { spawnSync } from "child_process";
4209
4838
  function readChannelPidFile() {
4210
4839
  try {
4211
- const raw = readFileSync13(channelPidPath(), "utf-8");
4840
+ const raw = readFileSync14(channelPidPath(), "utf-8");
4212
4841
  const data = JSON.parse(raw);
4213
4842
  if (data && typeof data.session === "string" && typeof data.platform === "string" && typeof data.startedAt === "string" && typeof data.vaultPath === "string") {
4214
4843
  return data;
@@ -4350,18 +4979,18 @@ function getChannelLogs() {
4350
4979
  return null;
4351
4980
  if (!screenSessionExists(pidData.session))
4352
4981
  return null;
4353
- const tmpPath = join18(minkRoot(), `.channel-capture-${Date.now()}-${process.pid}.txt`);
4982
+ const tmpPath = join20(minkRoot(), `.channel-capture-${Date.now()}-${process.pid}.txt`);
4354
4983
  const result = spawnSync("screen", ["-S", pidData.session, "-X", "hardcopy", "-h", tmpPath], { stdio: "ignore" });
4355
4984
  if (result.status !== 0)
4356
4985
  return null;
4357
4986
  for (let i = 0;i < 20; i++) {
4358
- if (existsSync15(tmpPath))
4987
+ if (existsSync20(tmpPath))
4359
4988
  break;
4360
4989
  const delayUntil = Date.now() + 50;
4361
4990
  while (Date.now() < delayUntil) {}
4362
4991
  }
4363
4992
  try {
4364
- const content = readFileSync13(tmpPath, "utf-8");
4993
+ const content = readFileSync14(tmpPath, "utf-8");
4365
4994
  try {
4366
4995
  unlinkSync3(tmpPath);
4367
4996
  } catch {}
@@ -4535,12 +5164,12 @@ var init_runtime = __esm(() => {
4535
5164
  });
4536
5165
 
4537
5166
  // src/core/daemon.ts
4538
- import { readFileSync as readFileSync14, writeFileSync as writeFileSync8, unlinkSync as unlinkSync4, openSync } from "fs";
5167
+ import { readFileSync as readFileSync15, writeFileSync as writeFileSync8, unlinkSync as unlinkSync4, openSync } from "fs";
4539
5168
  import { mkdirSync as mkdirSync10 } from "fs";
4540
5169
  import { dirname as dirname7, resolve as resolve3 } from "path";
4541
5170
  function readPidFile() {
4542
5171
  try {
4543
- const raw = readFileSync14(schedulerPidPath(), "utf-8");
5172
+ const raw = readFileSync15(schedulerPidPath(), "utf-8");
4544
5173
  const data = JSON.parse(raw);
4545
5174
  if (data && typeof data.pid === "number" && typeof data.startedAt === "string" && typeof data.projectCwd === "string") {
4546
5175
  return data;
@@ -4694,9 +5323,9 @@ var exports_status = {};
4694
5323
  __export(exports_status, {
4695
5324
  status: () => status
4696
5325
  });
4697
- import { existsSync as existsSync17, readFileSync as readFileSync15, statSync as statSync8 } from "fs";
5326
+ import { existsSync as existsSync22, readFileSync as readFileSync16, statSync as statSync8 } from "fs";
4698
5327
  function checkJsonFile(name, filePath, validator) {
4699
- if (!existsSync17(filePath))
5328
+ if (!existsSync22(filePath))
4700
5329
  return { name, path: filePath, status: "missing" };
4701
5330
  const data = safeReadJson(filePath);
4702
5331
  if (data === null)
@@ -4706,10 +5335,10 @@ function checkJsonFile(name, filePath, validator) {
4706
5335
  return { name, path: filePath, status: "ok" };
4707
5336
  }
4708
5337
  function checkTextFile(name, filePath) {
4709
- if (!existsSync17(filePath))
5338
+ if (!existsSync22(filePath))
4710
5339
  return { name, path: filePath, status: "missing" };
4711
5340
  try {
4712
- readFileSync15(filePath, "utf-8");
5341
+ readFileSync16(filePath, "utf-8");
4713
5342
  return { name, path: filePath, status: "ok" };
4714
5343
  } catch {
4715
5344
  return { name, path: filePath, status: "corrupt" };
@@ -4783,7 +5412,7 @@ function status(cwd) {
4783
5412
  console.log(` Decision Log: ${mem.sections["Decision Log"].length}`);
4784
5413
  console.log(` Total entries: ${total}`);
4785
5414
  const memPath = learningMemoryPath(cwd);
4786
- if (existsSync17(memPath)) {
5415
+ if (existsSync22(memPath)) {
4787
5416
  const mtime = statSync8(memPath).mtime;
4788
5417
  console.log(` Canonical last modified: ${mtime.toISOString()}`);
4789
5418
  }
@@ -4828,8 +5457,12 @@ var exports_scan2 = {};
4828
5457
  __export(exports_scan2, {
4829
5458
  scan: () => scan2
4830
5459
  });
4831
- import { readFileSync as readFileSync16 } from "fs";
4832
- import { join as join19 } from "path";
5460
+ import { readFileSync as readFileSync17 } from "fs";
5461
+ import { join as join21, relative as relative3 } from "path";
5462
+ function configRelativePath2(cfgPath, cwd) {
5463
+ const rel = relative3(cwd, cfgPath);
5464
+ return rel.startsWith("..") ? cfgPath : rel;
5465
+ }
4833
5466
  function loadExistingIndex2(indexPath) {
4834
5467
  const raw = safeReadJson(indexPath);
4835
5468
  if (isFileIndex(raw))
@@ -4874,15 +5507,16 @@ function scan2(cwd, options) {
4874
5507
  }
4875
5508
  const start = Date.now();
4876
5509
  const index = loadExistingIndex2(idxPath);
4877
- const scanned = scanProject(cwd, excludes, maxFiles);
5510
+ const stats = scanProjectWithStats(cwd, excludes, maxFiles);
5511
+ const scanned = stats.files;
4878
5512
  const newIndex = createEmptyIndex();
4879
5513
  newIndex.header.lifetimeHits = index.header.lifetimeHits;
4880
5514
  newIndex.header.lifetimeMisses = index.header.lifetimeMisses;
4881
5515
  for (const file of scanned) {
4882
- const fullPath = join19(cwd, file.relativePath);
5516
+ const fullPath = join21(cwd, file.relativePath);
4883
5517
  let content;
4884
5518
  try {
4885
- content = readFileSync16(fullPath, "utf-8");
5519
+ content = readFileSync17(fullPath, "utf-8");
4886
5520
  } catch {
4887
5521
  continue;
4888
5522
  }
@@ -4898,7 +5532,13 @@ function scan2(cwd, options) {
4898
5532
  newIndex.header.lastScanTimestamp = new Date().toISOString();
4899
5533
  atomicWriteJson(idxPath, newIndex);
4900
5534
  const elapsed = Date.now() - start;
4901
- console.log(`[mink] indexed ${newIndex.header.totalFiles} files in ${elapsed}ms`);
5535
+ if (stats.truncated > 0) {
5536
+ console.log(`[mink] scanned ${stats.totalScanned} files; indexed ${newIndex.header.totalFiles} most recent in ${elapsed}ms`);
5537
+ console.log(` ${stats.truncated} files past maxFiles=${maxFiles} were not indexed`);
5538
+ console.log(` raise the cap by setting "maxFiles" in ${configRelativePath2(cfgPath, cwd)}`);
5539
+ } else {
5540
+ console.log(`[mink] indexed ${newIndex.header.totalFiles} files in ${elapsed}ms`);
5541
+ }
4902
5542
  }
4903
5543
  var init_scan2 = __esm(() => {
4904
5544
  init_paths();
@@ -4913,12 +5553,12 @@ var exports_reflect2 = {};
4913
5553
  __export(exports_reflect2, {
4914
5554
  reflect: () => reflect2
4915
5555
  });
4916
- import { existsSync as existsSync18 } from "fs";
5556
+ import { existsSync as existsSync23 } from "fs";
4917
5557
  import { dirname as dirname8 } from "path";
4918
5558
  function reflect2(_cwd, memoryPath, configPath3) {
4919
5559
  const projDir = dirname8(memoryPath);
4920
5560
  const mem = aggregateLearningMemoryAt(projDir);
4921
- if (totalEntryCount(mem) === 0 && !existsSync18(memoryPath)) {
5561
+ if (totalEntryCount(mem) === 0 && !existsSync23(memoryPath)) {
4922
5562
  console.log("[mink] no learning memory found");
4923
5563
  return null;
4924
5564
  }
@@ -4961,7 +5601,7 @@ __export(exports_pre_read, {
4961
5601
  preRead: () => preRead,
4962
5602
  analyzePreRead: () => analyzePreRead
4963
5603
  });
4964
- import { relative as relative2 } from "path";
5604
+ import { relative as relative4 } from "path";
4965
5605
  function analyzePreRead(filePath, state, index) {
4966
5606
  const warnings = [];
4967
5607
  let repeatedRead = false;
@@ -5003,7 +5643,7 @@ async function preRead(cwd) {
5003
5643
  const absolutePath = input.tool_input.file_path;
5004
5644
  if (!absolutePath)
5005
5645
  return;
5006
- const filePath = relative2(cwd, absolutePath);
5646
+ const filePath = relative4(cwd, absolutePath);
5007
5647
  const rawState = safeReadJson(sessionPath(cwd));
5008
5648
  const state = isSessionState(rawState) ? rawState : createSessionState();
5009
5649
  const rawIndex = safeReadJson(fileIndexPath(cwd));
@@ -5039,7 +5679,7 @@ __export(exports_post_read, {
5039
5679
  postRead: () => postRead,
5040
5680
  analyzePostRead: () => analyzePostRead
5041
5681
  });
5042
- import { relative as relative3 } from "path";
5682
+ import { relative as relative5 } from "path";
5043
5683
  function analyzePostRead(filePath, content, index) {
5044
5684
  if (isBinaryFile(filePath, content ?? undefined)) {
5045
5685
  const entry = index ? lookupEntry(index, filePath) : null;
@@ -5094,7 +5734,7 @@ async function postRead(cwd) {
5094
5734
  const absolutePath = input.tool_input.file_path;
5095
5735
  if (!absolutePath)
5096
5736
  return;
5097
- const filePath = relative3(cwd, absolutePath);
5737
+ const filePath = relative5(cwd, absolutePath);
5098
5738
  const rawState = safeReadJson(sessionPath(cwd));
5099
5739
  const state = isSessionState(rawState) ? rawState : createSessionState();
5100
5740
  const rawIndex = safeReadJson(fileIndexPath(cwd));
@@ -5205,7 +5845,7 @@ __export(exports_pre_write, {
5205
5845
  preWrite: () => preWrite,
5206
5846
  analyzePreWrite: () => analyzePreWrite
5207
5847
  });
5208
- import { relative as relative4 } from "path";
5848
+ import { relative as relative6 } from "path";
5209
5849
  function analyzePreWrite(filePath, writeContent, doNotRepeatEntries, bugMemory) {
5210
5850
  const warnings = [];
5211
5851
  const allMatches = [];
@@ -5255,7 +5895,7 @@ async function preWrite(cwd) {
5255
5895
  const absolutePath = input.tool_input.file_path;
5256
5896
  if (!absolutePath)
5257
5897
  return;
5258
- const filePath = relative4(cwd, absolutePath);
5898
+ const filePath = relative6(cwd, absolutePath);
5259
5899
  const writeContent = extractWriteContent(input);
5260
5900
  let doNotRepeatEntries = [];
5261
5901
  try {
@@ -5315,8 +5955,8 @@ __export(exports_post_write, {
5315
5955
  postWrite: () => postWrite,
5316
5956
  analyzePostWrite: () => analyzePostWrite
5317
5957
  });
5318
- import { relative as relative5 } from "path";
5319
- import { readFileSync as readFileSync17 } from "fs";
5958
+ import { relative as relative7 } from "path";
5959
+ import { readFileSync as readFileSync18 } from "fs";
5320
5960
  function analyzePostWrite(filePath, fileContent, index) {
5321
5961
  if (isWriteExcluded(filePath)) {
5322
5962
  return {
@@ -5377,10 +6017,10 @@ async function postWrite(cwd) {
5377
6017
  const absolutePath = input.tool_input.file_path;
5378
6018
  if (!absolutePath)
5379
6019
  return;
5380
- const filePath = relative5(cwd, absolutePath);
6020
+ const filePath = relative7(cwd, absolutePath);
5381
6021
  let fileContent = null;
5382
6022
  try {
5383
- fileContent = readFileSync17(absolutePath, "utf-8");
6023
+ fileContent = readFileSync18(absolutePath, "utf-8");
5384
6024
  } catch {}
5385
6025
  const rawState = safeReadJson(sessionPath(cwd));
5386
6026
  const state = isSessionState(rawState) ? rawState : createSessionState();
@@ -5742,9 +6382,9 @@ __export(exports_self_update, {
5742
6382
  PACKAGE_NAME: () => PACKAGE_NAME
5743
6383
  });
5744
6384
  import { spawnSync as spawnSync2 } from "child_process";
5745
- import { existsSync as existsSync19, readFileSync as readFileSync18 } from "fs";
6385
+ import { existsSync as existsSync24, readFileSync as readFileSync19 } from "fs";
5746
6386
  import { dirname as dirname9 } from "path";
5747
- import { join as join20 } from "path";
6387
+ import { join as join22 } from "path";
5748
6388
  function parseSemver(input) {
5749
6389
  const trimmed = input.trim().replace(/^v/, "");
5750
6390
  if (!trimmed)
@@ -5794,8 +6434,8 @@ function getInstallInfo() {
5794
6434
  let dir = dirname9(selfPath);
5795
6435
  let packageJsonPath = null;
5796
6436
  for (let i = 0;i < 10; i++) {
5797
- const candidate = join20(dir, "package.json");
5798
- if (existsSync19(candidate)) {
6437
+ const candidate = join22(dir, "package.json");
6438
+ if (existsSync24(candidate)) {
5799
6439
  packageJsonPath = candidate;
5800
6440
  break;
5801
6441
  }
@@ -5809,7 +6449,7 @@ function getInstallInfo() {
5809
6449
  }
5810
6450
  let currentVersion = "0.0.0";
5811
6451
  try {
5812
- const pkg = JSON.parse(readFileSync18(packageJsonPath, "utf-8"));
6452
+ const pkg = JSON.parse(readFileSync19(packageJsonPath, "utf-8"));
5813
6453
  if (typeof pkg.version === "string")
5814
6454
  currentVersion = pkg.version;
5815
6455
  } catch {}
@@ -5869,7 +6509,7 @@ function buildInstallCommand(pm, version) {
5869
6509
  return ["npm", "install", "-g", ref];
5870
6510
  }
5871
6511
  function selfUpdateLogPath() {
5872
- return join20(minkRoot(), "self-update.log");
6512
+ return join22(minkRoot(), "self-update.log");
5873
6513
  }
5874
6514
  function appendLogEntry(entry) {
5875
6515
  const path = selfUpdateLogPath();
@@ -5882,7 +6522,7 @@ function appendLogEntry(entry) {
5882
6522
  }
5883
6523
  function rotateLogIfNeeded(path) {
5884
6524
  try {
5885
- const content = readFileSync18(path, "utf-8");
6525
+ const content = readFileSync19(path, "utf-8");
5886
6526
  const lines = content.split(`
5887
6527
  `);
5888
6528
  if (lines.length <= LOG_MAX_LINES + 1)
@@ -5985,7 +6625,7 @@ async function runSelfUpgradeInner(opts) {
5985
6625
  }
5986
6626
  let verifiedVersion = latest;
5987
6627
  try {
5988
- const pkg = JSON.parse(readFileSync18(info.packageJsonPath, "utf-8"));
6628
+ const pkg = JSON.parse(readFileSync19(info.packageJsonPath, "utf-8"));
5989
6629
  if (typeof pkg.version === "string")
5990
6630
  verifiedVersion = pkg.version;
5991
6631
  } catch {}
@@ -6091,10 +6731,10 @@ async function executeTask(taskId, projectCwd) {
6091
6731
  if (task.actionType === "ai-cli") {
6092
6732
  try {
6093
6733
  const { learningMemoryPath: learningMemoryPath5 } = await Promise.resolve().then(() => (init_paths(), exports_paths));
6094
- const { readFileSync: readFileSync19 } = await import("fs");
6734
+ const { readFileSync: readFileSync20 } = await import("fs");
6095
6735
  let memoryContent;
6096
6736
  try {
6097
- memoryContent = readFileSync19(learningMemoryPath5(projectCwd), "utf-8");
6737
+ memoryContent = readFileSync20(learningMemoryPath5(projectCwd), "utf-8");
6098
6738
  } catch {
6099
6739
  console.log("[mink] no learning memory found, skipping reflection");
6100
6740
  return;
@@ -6658,22 +7298,22 @@ var init_cron = __esm(() => {
6658
7298
  });
6659
7299
 
6660
7300
  // src/core/vault-templates.ts
6661
- import { join as join21 } from "path";
6662
- import { existsSync as existsSync20, writeFileSync as writeFileSync9, readFileSync as readFileSync19, mkdirSync as mkdirSync11 } from "fs";
7301
+ import { join as join23 } from "path";
7302
+ import { existsSync as existsSync25, writeFileSync as writeFileSync9, readFileSync as readFileSync20, mkdirSync as mkdirSync11 } from "fs";
6663
7303
  function seedTemplates(templatesDir) {
6664
7304
  mkdirSync11(templatesDir, { recursive: true });
6665
7305
  for (const [name, content] of Object.entries(DEFAULT_TEMPLATES)) {
6666
- const filePath = join21(templatesDir, `${name}.md`);
6667
- if (!existsSync20(filePath)) {
7306
+ const filePath = join23(templatesDir, `${name}.md`);
7307
+ if (!existsSync25(filePath)) {
6668
7308
  writeFileSync9(filePath, content);
6669
7309
  }
6670
7310
  }
6671
7311
  }
6672
7312
  function loadTemplate(templatesDir, templateName, vars) {
6673
- const filePath = join21(templatesDir, `${templateName}.md`);
7313
+ const filePath = join23(templatesDir, `${templateName}.md`);
6674
7314
  let content;
6675
- if (existsSync20(filePath)) {
6676
- content = readFileSync19(filePath, "utf-8");
7315
+ if (existsSync25(filePath)) {
7316
+ content = readFileSync20(filePath, "utf-8");
6677
7317
  } else if (DEFAULT_TEMPLATES[templateName]) {
6678
7318
  content = DEFAULT_TEMPLATES[templateName];
6679
7319
  } else {
@@ -6826,33 +7466,33 @@ category: resources
6826
7466
  });
6827
7467
 
6828
7468
  // src/core/note-writer.ts
6829
- import { join as join22 } from "path";
6830
- import { existsSync as existsSync21, readFileSync as readFileSync20 } from "fs";
7469
+ import { join as join24 } from "path";
7470
+ import { existsSync as existsSync26, readFileSync as readFileSync21 } from "fs";
6831
7471
  import { createHash as createHash2 } from "crypto";
6832
7472
  function sha256(content) {
6833
7473
  return createHash2("sha256").update(content).digest("hex");
6834
7474
  }
6835
7475
  function resolveUniqueNotePath(dir, baseSlug, content) {
6836
7476
  const targetHash = sha256(content);
6837
- const primary = join22(dir, `${baseSlug}.md`);
6838
- if (!existsSync21(primary))
7477
+ const primary = join24(dir, `${baseSlug}.md`);
7478
+ if (!existsSync26(primary))
6839
7479
  return primary;
6840
7480
  if (sameContent(primary, targetHash))
6841
7481
  return primary;
6842
7482
  const dev4 = getOrCreateDeviceId().replace(/-/g, "").slice(0, 4);
6843
7483
  for (let i = 0;i < MAX_COLLISION_ATTEMPTS; i++) {
6844
7484
  const suffix = i === 0 ? dev4 : `${dev4}-${i + 1}`;
6845
- const candidate = join22(dir, `${baseSlug}-${suffix}.md`);
6846
- if (!existsSync21(candidate))
7485
+ const candidate = join24(dir, `${baseSlug}-${suffix}.md`);
7486
+ if (!existsSync26(candidate))
6847
7487
  return candidate;
6848
7488
  if (sameContent(candidate, targetHash))
6849
7489
  return candidate;
6850
7490
  }
6851
- return join22(dir, `${baseSlug}-${Date.now()}.md`);
7491
+ return join24(dir, `${baseSlug}-${Date.now()}.md`);
6852
7492
  }
6853
7493
  function sameContent(filePath, expectedHash) {
6854
7494
  try {
6855
- return sha256(readFileSync20(filePath, "utf-8")) === expectedHash;
7495
+ return sha256(readFileSync21(filePath, "utf-8")) === expectedHash;
6856
7496
  } catch {
6857
7497
  return false;
6858
7498
  }
@@ -6923,8 +7563,8 @@ ${meta.body}
6923
7563
  }
6924
7564
  function appendToDaily(date, content) {
6925
7565
  const dir = vaultDailyDir();
6926
- const filePath = join22(dir, `${date}.md`);
6927
- if (existsSync21(filePath)) {
7566
+ const filePath = join24(dir, `${date}.md`);
7567
+ if (existsSync26(filePath)) {
6928
7568
  const timestamp = new Date().toLocaleTimeString("en-US", {
6929
7569
  hour: "2-digit",
6930
7570
  minute: "2-digit",
@@ -6961,7 +7601,7 @@ ${content}
6961
7601
  return filePath;
6962
7602
  }
6963
7603
  function ingestFile(sourcePath, meta) {
6964
- const raw = readFileSync20(sourcePath, "utf-8");
7604
+ const raw = readFileSync21(sourcePath, "utf-8");
6965
7605
  const now = new Date().toISOString();
6966
7606
  const headingMatch = raw.match(/^#\s+(.+)$/m);
6967
7607
  const title = headingMatch?.[1] ?? sourcePath.split("/").pop().replace(/\.md$/, "");
@@ -7033,10 +7673,10 @@ var init_design_eval = __esm(() => {
7033
7673
  });
7034
7674
 
7035
7675
  // src/core/dashboard-api.ts
7036
- import { existsSync as existsSync22, readFileSync as readFileSync21 } from "fs";
7037
- import { readdirSync as readdirSync7, readFileSync as readFileSyncFS, existsSync as fsExistsSync } from "fs";
7038
- import { join as join23, resolve as resolve5, normalize, sep } from "path";
7039
- import { execSync as execSync5 } from "child_process";
7676
+ import { existsSync as existsSync27, readFileSync as readFileSync22 } from "fs";
7677
+ import { readdirSync as readdirSync8, readFileSync as readFileSyncFS, existsSync as fsExistsSync } from "fs";
7678
+ import { join as join25, resolve as resolve5, normalize, sep } from "path";
7679
+ import { execSync as execSync6 } from "child_process";
7040
7680
  function isSecretKey(key) {
7041
7681
  return SECRET_KEY_PATTERNS.some((re) => re.test(key));
7042
7682
  }
@@ -7048,7 +7688,7 @@ function maskSecret(value, showLast = 4) {
7048
7688
  return "••••" + value.slice(-showLast);
7049
7689
  }
7050
7690
  function checkJsonFile2(name, filePath, validator) {
7051
- if (!existsSync22(filePath))
7691
+ if (!existsSync27(filePath))
7052
7692
  return { name, status: "missing" };
7053
7693
  const data = safeReadJson(filePath);
7054
7694
  if (data === null)
@@ -7058,10 +7698,10 @@ function checkJsonFile2(name, filePath, validator) {
7058
7698
  return { name, status: "ok" };
7059
7699
  }
7060
7700
  function checkTextFile2(name, filePath) {
7061
- if (!existsSync22(filePath))
7701
+ if (!existsSync27(filePath))
7062
7702
  return { name, status: "missing" };
7063
7703
  try {
7064
- readFileSync21(filePath, "utf-8");
7704
+ readFileSync22(filePath, "utf-8");
7065
7705
  return { name, status: "ok" };
7066
7706
  } catch {
7067
7707
  return { name, status: "corrupt" };
@@ -7233,7 +7873,7 @@ function getAheadBehind(branch) {
7233
7873
  if (!branch)
7234
7874
  return { ahead: 0, behind: 0 };
7235
7875
  try {
7236
- const raw = execSync5(`git rev-list --left-right --count origin/${branch}...${branch}`, { cwd: minkRoot(), timeout: 5000, stdio: ["pipe", "pipe", "pipe"] }).toString().trim();
7876
+ const raw = execSync6(`git rev-list --left-right --count origin/${branch}...${branch}`, { cwd: minkRoot(), timeout: 5000, stdio: ["pipe", "pipe", "pipe"] }).toString().trim();
7237
7877
  const [behindStr, aheadStr] = raw.split(/\s+/);
7238
7878
  return {
7239
7879
  behind: Number(behindStr) || 0,
@@ -7245,7 +7885,7 @@ function getAheadBehind(branch) {
7245
7885
  }
7246
7886
  function getPendingChanges() {
7247
7887
  try {
7248
- const raw = execSync5("git status --porcelain", {
7888
+ const raw = execSync6("git status --porcelain", {
7249
7889
  cwd: minkRoot(),
7250
7890
  timeout: 5000,
7251
7891
  stdio: ["pipe", "pipe", "pipe"]
@@ -7314,10 +7954,10 @@ function loadChannelPanel() {
7314
7954
  function countMarkdownIn(dir) {
7315
7955
  let count = 0;
7316
7956
  try {
7317
- for (const entry of readdirSync7(dir, { withFileTypes: true })) {
7957
+ for (const entry of readdirSync8(dir, { withFileTypes: true })) {
7318
7958
  if (WIKI_TREE_EXCLUDES.has(entry.name) || entry.name.startsWith("."))
7319
7959
  continue;
7320
- const fullPath = join23(dir, entry.name);
7960
+ const fullPath = join25(dir, entry.name);
7321
7961
  if (entry.isDirectory()) {
7322
7962
  count += countMarkdownIn(fullPath);
7323
7963
  } else if (entry.name.endsWith(".md") && !entry.name.startsWith("_")) {
@@ -7334,7 +7974,7 @@ function buildVaultTree(root) {
7334
7974
  return;
7335
7975
  let entries = [];
7336
7976
  try {
7337
- entries = readdirSync7(dir, { withFileTypes: true }).filter((e) => !WIKI_TREE_EXCLUDES.has(e.name) && !e.name.startsWith(".")).map((e) => ({ name: e.name, isDir: e.isDirectory() }));
7977
+ entries = readdirSync8(dir, { withFileTypes: true }).filter((e) => !WIKI_TREE_EXCLUDES.has(e.name) && !e.name.startsWith(".")).map((e) => ({ name: e.name, isDir: e.isDirectory() }));
7338
7978
  } catch {
7339
7979
  return;
7340
7980
  }
@@ -7346,7 +7986,7 @@ function buildVaultTree(root) {
7346
7986
  for (const entry of entries) {
7347
7987
  if (!entry.isDir)
7348
7988
  continue;
7349
- const fullPath = join23(dir, entry.name);
7989
+ const fullPath = join25(dir, entry.name);
7350
7990
  const relPath = fullPath.slice(root.length + 1);
7351
7991
  const count = countMarkdownIn(fullPath);
7352
7992
  nodes.push({ name: entry.name, path: relPath, count, depth });
@@ -7769,7 +8409,7 @@ async function triggerIngestFile(sourcePath, category, tags, dedupKey) {
7769
8409
  if (!isValidCategory(category)) {
7770
8410
  return { success: false, error: `Invalid category: ${category}` };
7771
8411
  }
7772
- const expanded = sourcePath.startsWith("~/") ? join23(process.env.HOME ?? "", sourcePath.slice(2)) : sourcePath;
8412
+ const expanded = sourcePath.startsWith("~/") ? join25(process.env.HOME ?? "", sourcePath.slice(2)) : sourcePath;
7773
8413
  if (!fsExistsSync(expanded)) {
7774
8414
  return { success: false, error: `Source file not found: ${sourcePath}` };
7775
8415
  }
@@ -7848,61 +8488,14 @@ var init_dashboard_api = __esm(() => {
7848
8488
  dedupCache = new Map;
7849
8489
  });
7850
8490
 
7851
- // src/core/project-registry.ts
7852
- import { readdirSync as readdirSync8, existsSync as existsSync23 } from "fs";
7853
- import { join as join24 } from "path";
7854
- function getProjectMeta(projDir) {
7855
- const metaPath = join24(projDir, "project-meta.json");
7856
- const raw = safeReadJson(metaPath);
7857
- if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
7858
- return null;
7859
- }
7860
- const obj = raw;
7861
- if (typeof obj.cwd !== "string" || typeof obj.name !== "string") {
7862
- return null;
7863
- }
7864
- return {
7865
- cwd: obj.cwd,
7866
- name: obj.name,
7867
- initTimestamp: obj.initTimestamp ?? "",
7868
- version: obj.version ?? "0.1.0"
7869
- };
7870
- }
7871
- function listRegisteredProjects() {
7872
- const projectsDir = join24(minkRoot(), "projects");
7873
- if (!existsSync23(projectsDir))
7874
- return [];
7875
- const entries = readdirSync8(projectsDir, { withFileTypes: true });
7876
- const projects = [];
7877
- for (const entry of entries) {
7878
- if (!entry.isDirectory())
7879
- continue;
7880
- const projDir = join24(projectsDir, entry.name);
7881
- const meta = getProjectMeta(projDir);
7882
- if (meta) {
7883
- projects.push({
7884
- id: entry.name,
7885
- cwd: meta.cwd,
7886
- name: meta.name,
7887
- version: meta.version
7888
- });
7889
- }
7890
- }
7891
- return projects;
7892
- }
7893
- var init_project_registry = __esm(() => {
7894
- init_paths();
7895
- init_fs_utils();
7896
- });
7897
-
7898
8491
  // src/core/dashboard-server.ts
7899
8492
  var exports_dashboard_server = {};
7900
8493
  __export(exports_dashboard_server, {
7901
8494
  startDashboardServer: () => startDashboardServer
7902
8495
  });
7903
8496
  import { watch } from "fs";
7904
- import { existsSync as existsSync24 } from "fs";
7905
- import { basename as basename7, dirname as dirname10, join as join25, extname as extname2 } from "path";
8497
+ import { existsSync as existsSync28 } from "fs";
8498
+ import { basename as basename7, dirname as dirname10, join as join26, extname as extname2 } from "path";
7906
8499
 
7907
8500
  class SSEManager {
7908
8501
  clients = new Map;
@@ -7963,18 +8556,18 @@ function resolveProjectCwd(url, defaultCwd) {
7963
8556
  const projectId = url.searchParams.get("project");
7964
8557
  if (!projectId)
7965
8558
  return defaultCwd;
7966
- if (projectId === generateProjectId(defaultCwd))
8559
+ if (projectId === projectIdFor(defaultCwd))
7967
8560
  return defaultCwd;
7968
8561
  const projects = listRegisteredProjects();
7969
- const match = projects.find((p) => p.id === projectId);
8562
+ const match = projects.find((p) => p.id === projectId) ?? projects.find((p) => p.aliases.includes(projectId));
7970
8563
  if (!match)
7971
8564
  return null;
7972
8565
  return match.cwd;
7973
8566
  }
7974
8567
  function getProjectsList(startupCwd, activeCwd) {
7975
- const activeId = generateProjectId(activeCwd);
8568
+ const activeId = projectIdFor(activeCwd);
7976
8569
  const registered = listRegisteredProjects();
7977
- const startupId = generateProjectId(startupCwd);
8570
+ const startupId = projectIdFor(startupCwd);
7978
8571
  const hasStartup = registered.some((p) => p.id === startupId);
7979
8572
  if (!hasStartup) {
7980
8573
  const meta = getProjectMeta(projectDir(startupCwd));
@@ -7982,7 +8575,9 @@ function getProjectsList(startupCwd, activeCwd) {
7982
8575
  id: startupId,
7983
8576
  cwd: startupCwd,
7984
8577
  name: meta?.name ?? basename7(startupCwd),
7985
- version: meta?.version ?? "0.1.0"
8578
+ version: meta?.version ?? "0.1.0",
8579
+ aliases: meta?.aliases ?? [],
8580
+ pathsByDevice: meta?.pathsByDevice ?? {}
7986
8581
  });
7987
8582
  }
7988
8583
  if (activeId !== startupId) {
@@ -7993,7 +8588,9 @@ function getProjectsList(startupCwd, activeCwd) {
7993
8588
  id: activeId,
7994
8589
  cwd: activeCwd,
7995
8590
  name: meta?.name ?? basename7(activeCwd),
7996
- version: meta?.version ?? "0.1.0"
8591
+ version: meta?.version ?? "0.1.0",
8592
+ aliases: meta?.aliases ?? [],
8593
+ pathsByDevice: meta?.pathsByDevice ?? {}
7997
8594
  });
7998
8595
  }
7999
8596
  }
@@ -8078,12 +8675,12 @@ async function startDashboardServer(cwd, options = {}) {
8078
8675
  const __dir = dirname10(new URL(import.meta.url).pathname);
8079
8676
  let pkgRoot = __dir;
8080
8677
  while (pkgRoot !== dirname10(pkgRoot)) {
8081
- if (existsSync24(join25(pkgRoot, "package.json")))
8678
+ if (existsSync28(join26(pkgRoot, "package.json")))
8082
8679
  break;
8083
8680
  pkgRoot = dirname10(pkgRoot);
8084
8681
  }
8085
- const dashboardOutDir = join25(pkgRoot, "dashboard", "out");
8086
- const dashboardBuilt = existsSync24(join25(dashboardOutDir, "index.html"));
8682
+ const dashboardOutDir = join26(pkgRoot, "dashboard", "out");
8683
+ const dashboardBuilt = existsSync28(join26(dashboardOutDir, "index.html"));
8087
8684
  let clientIdCounter = 0;
8088
8685
  if (!dashboardBuilt) {
8089
8686
  console.warn("[mink] dashboard not built. Run: cd dashboard && bun run build");
@@ -8113,9 +8710,9 @@ async function startDashboardServer(cwd, options = {}) {
8113
8710
  } else {
8114
8711
  let filePath;
8115
8712
  if (pathname === "/") {
8116
- filePath = join25(dashboardOutDir, "index.html");
8713
+ filePath = join26(dashboardOutDir, "index.html");
8117
8714
  } else {
8118
- filePath = join25(dashboardOutDir, pathname);
8715
+ filePath = join26(dashboardOutDir, pathname);
8119
8716
  }
8120
8717
  if (!filePath.startsWith(dashboardOutDir)) {
8121
8718
  return jsonResponse({ error: "Forbidden" }, 403);
@@ -8128,7 +8725,7 @@ async function startDashboardServer(cwd, options = {}) {
8128
8725
  const htmlServed = await serveFile(filePath + ".html", "text/html; charset=utf-8");
8129
8726
  if (htmlServed)
8130
8727
  return htmlServed;
8131
- const indexServed = await serveFile(join25(dashboardOutDir, "index.html"), "text/html; charset=utf-8");
8728
+ const indexServed = await serveFile(join26(dashboardOutDir, "index.html"), "text/html; charset=utf-8");
8132
8729
  if (indexServed)
8133
8730
  return indexServed;
8134
8731
  }
@@ -8237,7 +8834,7 @@ retry: 3000
8237
8834
  if (!filename || filename.includes("..") || filename.includes("/")) {
8238
8835
  return jsonResponse({ error: "Invalid filename" }, 400);
8239
8836
  }
8240
- const imgPath = join25(designCapturesDir(resolvedCwd), filename);
8837
+ const imgPath = join26(designCapturesDir(resolvedCwd), filename);
8241
8838
  const served = await serveFile(imgPath, "image/jpeg");
8242
8839
  if (served) {
8243
8840
  served.headers.set("Cache-Control", "public, max-age=60");
@@ -8471,9 +9068,9 @@ var exports_dashboard = {};
8471
9068
  __export(exports_dashboard, {
8472
9069
  dashboard: () => dashboard
8473
9070
  });
8474
- import { existsSync as existsSync25 } from "fs";
9071
+ import { existsSync as existsSync29 } from "fs";
8475
9072
  async function dashboard(cwd, args) {
8476
- if (!existsSync25(projectDir(cwd))) {
9073
+ if (!existsSync29(projectDir(cwd))) {
8477
9074
  console.error("[mink] project not initialized. Run: mink init");
8478
9075
  process.exit(1);
8479
9076
  }
@@ -8491,8 +9088,8 @@ var init_dashboard = __esm(() => {
8491
9088
  });
8492
9089
 
8493
9090
  // src/commands/init.ts
8494
- import { mkdirSync as mkdirSync12, existsSync as existsSync26 } from "fs";
8495
- import { resolve as resolve6, dirname as dirname11, basename as basename8, join as join26 } from "path";
9091
+ import { mkdirSync as mkdirSync12, existsSync as existsSync30 } from "fs";
9092
+ import { resolve as resolve6, dirname as dirname11, basename as basename8, join as join27 } from "path";
8496
9093
  function resolveCliPath2() {
8497
9094
  const selfPath = new URL(import.meta.url).pathname;
8498
9095
  const selfDir = dirname11(selfPath);
@@ -8500,8 +9097,8 @@ function resolveCliPath2() {
8500
9097
  return selfPath;
8501
9098
  }
8502
9099
  const projectRoot = resolve6(selfDir, "../..");
8503
- const distPath = join26(projectRoot, "dist", "cli.js");
8504
- if (existsSync26(distPath))
9100
+ const distPath = join27(projectRoot, "dist", "cli.js");
9101
+ if (existsSync30(distPath))
8505
9102
  return distPath;
8506
9103
  return resolve6(selfDir, "../cli.ts");
8507
9104
  }
@@ -8557,14 +9154,16 @@ var init_init2 = __esm(() => {
8557
9154
  init_paths();
8558
9155
  init_project_id();
8559
9156
  init_fs_utils();
9157
+ init_device();
9158
+ init_git_identity();
8560
9159
  init_vault();
8561
9160
  });
8562
9161
 
8563
9162
  // src/core/daemon-service.ts
8564
- import { execSync as execSync6 } from "child_process";
8565
- import { existsSync as existsSync27, mkdirSync as mkdirSync13, unlinkSync as unlinkSync5, writeFileSync as writeFileSync10 } from "fs";
9163
+ import { execSync as execSync7 } from "child_process";
9164
+ import { existsSync as existsSync31, mkdirSync as mkdirSync13, unlinkSync as unlinkSync5, writeFileSync as writeFileSync10 } from "fs";
8566
9165
  import { homedir as homedir4 } from "os";
8567
- import { dirname as dirname12, join as join27 } from "path";
9166
+ import { dirname as dirname12, join as join28 } from "path";
8568
9167
  function detectPlatform() {
8569
9168
  if (process.platform === "linux")
8570
9169
  return "systemd";
@@ -8574,7 +9173,7 @@ function detectPlatform() {
8574
9173
  }
8575
9174
  function resolveServiceInvocation() {
8576
9175
  const entry = process.argv[1];
8577
- if (entry && !/\.(js|ts|mjs|cjs)$/.test(entry) && existsSync27(entry)) {
9176
+ if (entry && !/\.(js|ts|mjs|cjs)$/.test(entry) && existsSync31(entry)) {
8578
9177
  return {
8579
9178
  executable: entry,
8580
9179
  args: ["daemon", "start"],
@@ -8592,11 +9191,11 @@ function resolveServiceInvocation() {
8592
9191
  function servicePaths(platform2) {
8593
9192
  const home = homedir4();
8594
9193
  if (platform2 === "systemd") {
8595
- const unitDir2 = join27(home, ".config", "systemd", "user");
8596
- return { unitDir: unitDir2, unitFile: join27(unitDir2, "mink-daemon.service") };
9194
+ const unitDir2 = join28(home, ".config", "systemd", "user");
9195
+ return { unitDir: unitDir2, unitFile: join28(unitDir2, "mink-daemon.service") };
8597
9196
  }
8598
- const unitDir = join27(home, "Library", "LaunchAgents");
8599
- return { unitDir, unitFile: join27(unitDir, "com.mink.daemon.plist") };
9197
+ const unitDir = join28(home, "Library", "LaunchAgents");
9198
+ return { unitDir, unitFile: join28(unitDir, "com.mink.daemon.plist") };
8600
9199
  }
8601
9200
  function renderSystemdUnit(inv) {
8602
9201
  const execStart = [inv.executable, ...inv.args].join(" ");
@@ -8670,7 +9269,7 @@ function installService(options = {}) {
8670
9269
  process.exit(1);
8671
9270
  }
8672
9271
  const paths = servicePaths(platform2);
8673
- if (existsSync27(paths.unitFile) && !options.force) {
9272
+ if (existsSync31(paths.unitFile) && !options.force) {
8674
9273
  console.error(`[mink] unit file already exists: ${paths.unitFile}`);
8675
9274
  console.error(" re-run with --force to overwrite, or run `mink daemon uninstall` first");
8676
9275
  process.exit(1);
@@ -8680,7 +9279,7 @@ function installService(options = {}) {
8680
9279
  if (platform2 === "systemd") {
8681
9280
  writeFileSync10(paths.unitFile, renderSystemdUnit(inv));
8682
9281
  try {
8683
- execSync6("systemctl --user daemon-reload", { stdio: "ignore" });
9282
+ execSync7("systemctl --user daemon-reload", { stdio: "ignore" });
8684
9283
  } catch {}
8685
9284
  console.log(`[mink] wrote ${paths.unitFile}`);
8686
9285
  console.log("[mink] next steps:");
@@ -8703,24 +9302,24 @@ function uninstallService() {
8703
9302
  process.exit(1);
8704
9303
  }
8705
9304
  const paths = servicePaths(platform2);
8706
- if (!existsSync27(paths.unitFile)) {
9305
+ if (!existsSync31(paths.unitFile)) {
8707
9306
  console.log(`[mink] no unit file at ${paths.unitFile} — nothing to uninstall`);
8708
9307
  return;
8709
9308
  }
8710
9309
  if (platform2 === "systemd") {
8711
9310
  try {
8712
- execSync6("systemctl --user disable --now mink-daemon.service", {
9311
+ execSync7("systemctl --user disable --now mink-daemon.service", {
8713
9312
  stdio: "ignore"
8714
9313
  });
8715
9314
  } catch {}
8716
9315
  unlinkSync5(paths.unitFile);
8717
9316
  try {
8718
- execSync6("systemctl --user daemon-reload", { stdio: "ignore" });
9317
+ execSync7("systemctl --user daemon-reload", { stdio: "ignore" });
8719
9318
  } catch {}
8720
9319
  console.log(`[mink] removed ${paths.unitFile}`);
8721
9320
  } else {
8722
9321
  try {
8723
- execSync6(`launchctl unload -w ${paths.unitFile}`, { stdio: "ignore" });
9322
+ execSync7(`launchctl unload -w ${paths.unitFile}`, { stdio: "ignore" });
8724
9323
  } catch {}
8725
9324
  unlinkSync5(paths.unitFile);
8726
9325
  console.log(`[mink] removed ${paths.unitFile}`);
@@ -8735,7 +9334,7 @@ var exports_daemon = {};
8735
9334
  __export(exports_daemon, {
8736
9335
  daemon: () => daemon
8737
9336
  });
8738
- import { readFileSync as readFileSync22, existsSync as existsSync28 } from "fs";
9337
+ import { readFileSync as readFileSync23, existsSync as existsSync32 } from "fs";
8739
9338
  async function daemon(cwd, args) {
8740
9339
  const subcommand = args[0];
8741
9340
  switch (subcommand) {
@@ -8751,12 +9350,12 @@ async function daemon(cwd, args) {
8751
9350
  break;
8752
9351
  case "logs": {
8753
9352
  const logPath = schedulerLogPath();
8754
- if (!existsSync28(logPath)) {
9353
+ if (!existsSync32(logPath)) {
8755
9354
  console.log("[mink] no log file found");
8756
9355
  return;
8757
9356
  }
8758
9357
  try {
8759
- const content = readFileSync22(logPath, "utf-8");
9358
+ const content = readFileSync23(logPath, "utf-8");
8760
9359
  const lines = content.split(`
8761
9360
  `);
8762
9361
  const tail = lines.slice(-50).join(`
@@ -9337,8 +9936,8 @@ var init_restore = __esm(() => {
9337
9936
  });
9338
9937
 
9339
9938
  // src/core/design-eval/server-detect.ts
9340
- import { readFileSync as readFileSync23 } from "fs";
9341
- import { join as join28 } from "path";
9939
+ import { readFileSync as readFileSync24 } from "fs";
9940
+ import { join as join29 } from "path";
9342
9941
  async function probePort(port) {
9343
9942
  try {
9344
9943
  const controller = new AbortController;
@@ -9360,7 +9959,7 @@ async function findRunningServer(ports = DEFAULT_PROBE_PORTS) {
9360
9959
  }
9361
9960
  function detectDevCommand(cwd) {
9362
9961
  try {
9363
- const raw = readFileSync23(join28(cwd, "package.json"), "utf-8");
9962
+ const raw = readFileSync24(join29(cwd, "package.json"), "utf-8");
9364
9963
  const pkg = JSON.parse(raw);
9365
9964
  const scripts = pkg.scripts;
9366
9965
  if (!scripts || typeof scripts !== "object")
@@ -9380,10 +9979,10 @@ var init_server_detect = __esm(() => {
9380
9979
  });
9381
9980
 
9382
9981
  // src/core/design-eval/route-detect.ts
9383
- import { existsSync as existsSync29, readdirSync as readdirSync9, statSync as statSync11 } from "fs";
9384
- import { join as join29, relative as relative6, sep as sep2 } from "path";
9982
+ import { existsSync as existsSync33, readdirSync as readdirSync9, statSync as statSync11 } from "fs";
9983
+ import { join as join30, relative as relative8, sep as sep2 } from "path";
9385
9984
  function detectFramework(cwd) {
9386
- const has = (name) => ["js", "mjs", "ts", "cjs"].some((ext) => existsSync29(join29(cwd, `${name}.${ext}`))) || existsSync29(join29(cwd, name));
9985
+ const has = (name) => ["js", "mjs", "ts", "cjs"].some((ext) => existsSync33(join30(cwd, `${name}.${ext}`))) || existsSync33(join30(cwd, name));
9387
9986
  if (has("next.config"))
9388
9987
  return "nextjs";
9389
9988
  if (has("svelte.config"))
@@ -9408,11 +10007,11 @@ function detectRoutes(cwd) {
9408
10007
  }
9409
10008
  function detectNextRoutes(cwd) {
9410
10009
  const routes = [];
9411
- const appDir = join29(cwd, "app");
9412
- if (existsSync29(appDir)) {
10010
+ const appDir = join30(cwd, "app");
10011
+ if (existsSync33(appDir)) {
9413
10012
  const pageFiles = findFiles(appDir, /^page\.(tsx?|jsx?)$/);
9414
10013
  for (const file of pageFiles) {
9415
- const rel = relative6(appDir, file);
10014
+ const rel = relative8(appDir, file);
9416
10015
  const dir = rel.replace(/([/\\])?page\.(tsx?|jsx?)$/, "");
9417
10016
  const route = dir === "" ? "/" : `/${dir.split(sep2).join("/")}`;
9418
10017
  if (/\[|@|\(/.test(route))
@@ -9420,11 +10019,11 @@ function detectNextRoutes(cwd) {
9420
10019
  routes.push(route);
9421
10020
  }
9422
10021
  }
9423
- const pagesDir = join29(cwd, "pages");
9424
- if (existsSync29(pagesDir)) {
10022
+ const pagesDir = join30(cwd, "pages");
10023
+ if (existsSync33(pagesDir)) {
9425
10024
  const pageFiles = findFiles(pagesDir, /\.(tsx?|jsx?)$/);
9426
10025
  for (const file of pageFiles) {
9427
- const rel = relative6(pagesDir, file);
10026
+ const rel = relative8(pagesDir, file);
9428
10027
  const name = rel.replace(/\.(tsx?|jsx?)$/, "");
9429
10028
  if (/^_(app|document|error)/.test(name))
9430
10029
  continue;
@@ -9440,13 +10039,13 @@ function detectNextRoutes(cwd) {
9440
10039
  return unique.length > 0 ? unique.sort() : ["/"];
9441
10040
  }
9442
10041
  function detectSvelteKitRoutes(cwd) {
9443
- const routesDir = join29(cwd, "src", "routes");
9444
- if (!existsSync29(routesDir))
10042
+ const routesDir = join30(cwd, "src", "routes");
10043
+ if (!existsSync33(routesDir))
9445
10044
  return ["/"];
9446
10045
  const routes = [];
9447
10046
  const pageFiles = findFiles(routesDir, /^\+page\.svelte$/);
9448
10047
  for (const file of pageFiles) {
9449
- const rel = relative6(routesDir, file);
10048
+ const rel = relative8(routesDir, file);
9450
10049
  const dir = rel.replace(/([/\\])?\+page\.svelte$/, "");
9451
10050
  const route = dir === "" ? "/" : `/${dir.split(sep2).join("/")}`;
9452
10051
  if (/\[|\(/.test(route))
@@ -9456,13 +10055,13 @@ function detectSvelteKitRoutes(cwd) {
9456
10055
  return routes.length > 0 ? routes.sort() : ["/"];
9457
10056
  }
9458
10057
  function detectNuxtRoutes(cwd) {
9459
- const pagesDir = join29(cwd, "pages");
9460
- if (!existsSync29(pagesDir))
10058
+ const pagesDir = join30(cwd, "pages");
10059
+ if (!existsSync33(pagesDir))
9461
10060
  return ["/"];
9462
10061
  const routes = [];
9463
10062
  const vueFiles = findFiles(pagesDir, /\.vue$/);
9464
10063
  for (const file of vueFiles) {
9465
- const rel = relative6(pagesDir, file);
10064
+ const rel = relative8(pagesDir, file);
9466
10065
  const name = rel.replace(/\.vue$/, "");
9467
10066
  if (/\[/.test(name))
9468
10067
  continue;
@@ -9483,7 +10082,7 @@ function findFiles(dir, pattern) {
9483
10082
  for (const entry of entries) {
9484
10083
  if (entry.startsWith(".") || entry === "node_modules")
9485
10084
  continue;
9486
- const full = join29(current, entry);
10085
+ const full = join30(current, entry);
9487
10086
  try {
9488
10087
  const stat2 = statSync11(full);
9489
10088
  if (stat2.isDirectory()) {
@@ -58187,7 +58786,7 @@ var require_util2 = __commonJS((exports) => {
58187
58786
  return path;
58188
58787
  }
58189
58788
  exports.normalize = normalize2;
58190
- function join30(aRoot, aPath) {
58789
+ function join31(aRoot, aPath) {
58191
58790
  if (aRoot === "") {
58192
58791
  aRoot = ".";
58193
58792
  }
@@ -58219,11 +58818,11 @@ var require_util2 = __commonJS((exports) => {
58219
58818
  }
58220
58819
  return joined;
58221
58820
  }
58222
- exports.join = join30;
58821
+ exports.join = join31;
58223
58822
  exports.isAbsolute = function(aPath) {
58224
58823
  return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
58225
58824
  };
58226
- function relative7(aRoot, aPath) {
58825
+ function relative9(aRoot, aPath) {
58227
58826
  if (aRoot === "") {
58228
58827
  aRoot = ".";
58229
58828
  }
@@ -58242,7 +58841,7 @@ var require_util2 = __commonJS((exports) => {
58242
58841
  }
58243
58842
  return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1);
58244
58843
  }
58245
- exports.relative = relative7;
58844
+ exports.relative = relative9;
58246
58845
  var supportsNullProto = function() {
58247
58846
  var obj = Object.create(null);
58248
58847
  return !("__proto__" in obj);
@@ -58392,7 +58991,7 @@ var require_util2 = __commonJS((exports) => {
58392
58991
  parsed.path = parsed.path.substring(0, index + 1);
58393
58992
  }
58394
58993
  }
58395
- sourceURL = join30(urlGenerate(parsed), sourceURL);
58994
+ sourceURL = join31(urlGenerate(parsed), sourceURL);
58396
58995
  }
58397
58996
  return normalize2(sourceURL);
58398
58997
  }
@@ -60124,7 +60723,7 @@ var require_escodegen = __commonJS((exports) => {
60124
60723
  function noEmptySpace() {
60125
60724
  return space ? space : " ";
60126
60725
  }
60127
- function join30(left, right) {
60726
+ function join31(left, right) {
60128
60727
  var leftSource, rightSource, leftCharCode, rightCharCode;
60129
60728
  leftSource = toSourceNodeWhenNeeded(left).toString();
60130
60729
  if (leftSource.length === 0) {
@@ -60465,8 +61064,8 @@ var require_escodegen = __commonJS((exports) => {
60465
61064
  } else {
60466
61065
  result.push(that.generateExpression(stmt.left, Precedence.Call, E_TTT));
60467
61066
  }
60468
- result = join30(result, operator);
60469
- result = [join30(result, that.generateExpression(stmt.right, Precedence.Assignment, E_TTT)), ")"];
61067
+ result = join31(result, operator);
61068
+ result = [join31(result, that.generateExpression(stmt.right, Precedence.Assignment, E_TTT)), ")"];
60470
61069
  });
60471
61070
  result.push(this.maybeBlock(stmt.body, flags));
60472
61071
  return result;
@@ -60604,11 +61203,11 @@ var require_escodegen = __commonJS((exports) => {
60604
61203
  var result, fragment;
60605
61204
  result = ["class"];
60606
61205
  if (stmt.id) {
60607
- result = join30(result, this.generateExpression(stmt.id, Precedence.Sequence, E_TTT));
61206
+ result = join31(result, this.generateExpression(stmt.id, Precedence.Sequence, E_TTT));
60608
61207
  }
60609
61208
  if (stmt.superClass) {
60610
- fragment = join30("extends", this.generateExpression(stmt.superClass, Precedence.Unary, E_TTT));
60611
- result = join30(result, fragment);
61209
+ fragment = join31("extends", this.generateExpression(stmt.superClass, Precedence.Unary, E_TTT));
61210
+ result = join31(result, fragment);
60612
61211
  }
60613
61212
  result.push(space);
60614
61213
  result.push(this.generateStatement(stmt.body, S_TFFT));
@@ -60621,9 +61220,9 @@ var require_escodegen = __commonJS((exports) => {
60621
61220
  return escapeDirective(stmt.directive) + this.semicolon(flags);
60622
61221
  },
60623
61222
  DoWhileStatement: function(stmt, flags) {
60624
- var result = join30("do", this.maybeBlock(stmt.body, S_TFFF));
61223
+ var result = join31("do", this.maybeBlock(stmt.body, S_TFFF));
60625
61224
  result = this.maybeBlockSuffix(stmt.body, result);
60626
- return join30(result, [
61225
+ return join31(result, [
60627
61226
  "while" + space + "(",
60628
61227
  this.generateExpression(stmt.test, Precedence.Sequence, E_TTT),
60629
61228
  ")" + this.semicolon(flags)
@@ -60659,11 +61258,11 @@ var require_escodegen = __commonJS((exports) => {
60659
61258
  ExportDefaultDeclaration: function(stmt, flags) {
60660
61259
  var result = ["export"], bodyFlags;
60661
61260
  bodyFlags = flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF;
60662
- result = join30(result, "default");
61261
+ result = join31(result, "default");
60663
61262
  if (isStatement(stmt.declaration)) {
60664
- result = join30(result, this.generateStatement(stmt.declaration, bodyFlags));
61263
+ result = join31(result, this.generateStatement(stmt.declaration, bodyFlags));
60665
61264
  } else {
60666
- result = join30(result, this.generateExpression(stmt.declaration, Precedence.Assignment, E_TTT) + this.semicolon(flags));
61265
+ result = join31(result, this.generateExpression(stmt.declaration, Precedence.Assignment, E_TTT) + this.semicolon(flags));
60667
61266
  }
60668
61267
  return result;
60669
61268
  },
@@ -60671,15 +61270,15 @@ var require_escodegen = __commonJS((exports) => {
60671
61270
  var result = ["export"], bodyFlags, that = this;
60672
61271
  bodyFlags = flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF;
60673
61272
  if (stmt.declaration) {
60674
- return join30(result, this.generateStatement(stmt.declaration, bodyFlags));
61273
+ return join31(result, this.generateStatement(stmt.declaration, bodyFlags));
60675
61274
  }
60676
61275
  if (stmt.specifiers) {
60677
61276
  if (stmt.specifiers.length === 0) {
60678
- result = join30(result, "{" + space + "}");
61277
+ result = join31(result, "{" + space + "}");
60679
61278
  } else if (stmt.specifiers[0].type === Syntax.ExportBatchSpecifier) {
60680
- result = join30(result, this.generateExpression(stmt.specifiers[0], Precedence.Sequence, E_TTT));
61279
+ result = join31(result, this.generateExpression(stmt.specifiers[0], Precedence.Sequence, E_TTT));
60681
61280
  } else {
60682
- result = join30(result, "{");
61281
+ result = join31(result, "{");
60683
61282
  withIndent(function(indent2) {
60684
61283
  var i, iz;
60685
61284
  result.push(newline);
@@ -60697,7 +61296,7 @@ var require_escodegen = __commonJS((exports) => {
60697
61296
  result.push(base + "}");
60698
61297
  }
60699
61298
  if (stmt.source) {
60700
- result = join30(result, [
61299
+ result = join31(result, [
60701
61300
  "from" + space,
60702
61301
  this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
60703
61302
  this.semicolon(flags)
@@ -60781,7 +61380,7 @@ var require_escodegen = __commonJS((exports) => {
60781
61380
  ];
60782
61381
  cursor = 0;
60783
61382
  if (stmt.specifiers[cursor].type === Syntax.ImportDefaultSpecifier) {
60784
- result = join30(result, [
61383
+ result = join31(result, [
60785
61384
  this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
60786
61385
  ]);
60787
61386
  ++cursor;
@@ -60791,7 +61390,7 @@ var require_escodegen = __commonJS((exports) => {
60791
61390
  result.push(",");
60792
61391
  }
60793
61392
  if (stmt.specifiers[cursor].type === Syntax.ImportNamespaceSpecifier) {
60794
- result = join30(result, [
61393
+ result = join31(result, [
60795
61394
  space,
60796
61395
  this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
60797
61396
  ]);
@@ -60820,7 +61419,7 @@ var require_escodegen = __commonJS((exports) => {
60820
61419
  }
60821
61420
  }
60822
61421
  }
60823
- result = join30(result, [
61422
+ result = join31(result, [
60824
61423
  "from" + space,
60825
61424
  this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
60826
61425
  this.semicolon(flags)
@@ -60874,7 +61473,7 @@ var require_escodegen = __commonJS((exports) => {
60874
61473
  return result;
60875
61474
  },
60876
61475
  ThrowStatement: function(stmt, flags) {
60877
- return [join30("throw", this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)), this.semicolon(flags)];
61476
+ return [join31("throw", this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)), this.semicolon(flags)];
60878
61477
  },
60879
61478
  TryStatement: function(stmt, flags) {
60880
61479
  var result, i, iz, guardedHandlers;
@@ -60882,7 +61481,7 @@ var require_escodegen = __commonJS((exports) => {
60882
61481
  result = this.maybeBlockSuffix(stmt.block, result);
60883
61482
  if (stmt.handlers) {
60884
61483
  for (i = 0, iz = stmt.handlers.length;i < iz; ++i) {
60885
- result = join30(result, this.generateStatement(stmt.handlers[i], S_TFFF));
61484
+ result = join31(result, this.generateStatement(stmt.handlers[i], S_TFFF));
60886
61485
  if (stmt.finalizer || i + 1 !== iz) {
60887
61486
  result = this.maybeBlockSuffix(stmt.handlers[i].body, result);
60888
61487
  }
@@ -60890,7 +61489,7 @@ var require_escodegen = __commonJS((exports) => {
60890
61489
  } else {
60891
61490
  guardedHandlers = stmt.guardedHandlers || [];
60892
61491
  for (i = 0, iz = guardedHandlers.length;i < iz; ++i) {
60893
- result = join30(result, this.generateStatement(guardedHandlers[i], S_TFFF));
61492
+ result = join31(result, this.generateStatement(guardedHandlers[i], S_TFFF));
60894
61493
  if (stmt.finalizer || i + 1 !== iz) {
60895
61494
  result = this.maybeBlockSuffix(guardedHandlers[i].body, result);
60896
61495
  }
@@ -60898,13 +61497,13 @@ var require_escodegen = __commonJS((exports) => {
60898
61497
  if (stmt.handler) {
60899
61498
  if (Array.isArray(stmt.handler)) {
60900
61499
  for (i = 0, iz = stmt.handler.length;i < iz; ++i) {
60901
- result = join30(result, this.generateStatement(stmt.handler[i], S_TFFF));
61500
+ result = join31(result, this.generateStatement(stmt.handler[i], S_TFFF));
60902
61501
  if (stmt.finalizer || i + 1 !== iz) {
60903
61502
  result = this.maybeBlockSuffix(stmt.handler[i].body, result);
60904
61503
  }
60905
61504
  }
60906
61505
  } else {
60907
- result = join30(result, this.generateStatement(stmt.handler, S_TFFF));
61506
+ result = join31(result, this.generateStatement(stmt.handler, S_TFFF));
60908
61507
  if (stmt.finalizer) {
60909
61508
  result = this.maybeBlockSuffix(stmt.handler.body, result);
60910
61509
  }
@@ -60912,7 +61511,7 @@ var require_escodegen = __commonJS((exports) => {
60912
61511
  }
60913
61512
  }
60914
61513
  if (stmt.finalizer) {
60915
- result = join30(result, ["finally", this.maybeBlock(stmt.finalizer, S_TFFF)]);
61514
+ result = join31(result, ["finally", this.maybeBlock(stmt.finalizer, S_TFFF)]);
60916
61515
  }
60917
61516
  return result;
60918
61517
  },
@@ -60946,7 +61545,7 @@ var require_escodegen = __commonJS((exports) => {
60946
61545
  withIndent(function() {
60947
61546
  if (stmt.test) {
60948
61547
  result = [
60949
- join30("case", that.generateExpression(stmt.test, Precedence.Sequence, E_TTT)),
61548
+ join31("case", that.generateExpression(stmt.test, Precedence.Sequence, E_TTT)),
60950
61549
  ":"
60951
61550
  ];
60952
61551
  } else {
@@ -60994,9 +61593,9 @@ var require_escodegen = __commonJS((exports) => {
60994
61593
  result.push(this.maybeBlock(stmt.consequent, S_TFFF));
60995
61594
  result = this.maybeBlockSuffix(stmt.consequent, result);
60996
61595
  if (stmt.alternate.type === Syntax.IfStatement) {
60997
- result = join30(result, ["else ", this.generateStatement(stmt.alternate, bodyFlags)]);
61596
+ result = join31(result, ["else ", this.generateStatement(stmt.alternate, bodyFlags)]);
60998
61597
  } else {
60999
- result = join30(result, join30("else", this.maybeBlock(stmt.alternate, bodyFlags)));
61598
+ result = join31(result, join31("else", this.maybeBlock(stmt.alternate, bodyFlags)));
61000
61599
  }
61001
61600
  } else {
61002
61601
  result.push(this.maybeBlock(stmt.consequent, bodyFlags));
@@ -61098,7 +61697,7 @@ var require_escodegen = __commonJS((exports) => {
61098
61697
  },
61099
61698
  ReturnStatement: function(stmt, flags) {
61100
61699
  if (stmt.argument) {
61101
- return [join30("return", this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)), this.semicolon(flags)];
61700
+ return [join31("return", this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)), this.semicolon(flags)];
61102
61701
  }
61103
61702
  return ["return" + this.semicolon(flags)];
61104
61703
  },
@@ -61180,14 +61779,14 @@ var require_escodegen = __commonJS((exports) => {
61180
61779
  if (leftSource.charCodeAt(leftSource.length - 1) === 47 && esutils.code.isIdentifierPartES5(expr.operator.charCodeAt(0))) {
61181
61780
  result = [fragment, noEmptySpace(), expr.operator];
61182
61781
  } else {
61183
- result = join30(fragment, expr.operator);
61782
+ result = join31(fragment, expr.operator);
61184
61783
  }
61185
61784
  fragment = this.generateExpression(expr.right, rightPrecedence, flags);
61186
61785
  if (expr.operator === "/" && fragment.toString().charAt(0) === "/" || expr.operator.slice(-1) === "<" && fragment.toString().slice(0, 3) === "!--") {
61187
61786
  result.push(noEmptySpace());
61188
61787
  result.push(fragment);
61189
61788
  } else {
61190
- result = join30(result, fragment);
61789
+ result = join31(result, fragment);
61191
61790
  }
61192
61791
  if (expr.operator === "in" && !(flags & F_ALLOW_IN)) {
61193
61792
  return ["(", result, ")"];
@@ -61227,7 +61826,7 @@ var require_escodegen = __commonJS((exports) => {
61227
61826
  var result, length, i, iz, itemFlags;
61228
61827
  length = expr["arguments"].length;
61229
61828
  itemFlags = flags & F_ALLOW_UNPARATH_NEW && !parentheses && length === 0 ? E_TFT : E_TFF;
61230
- result = join30("new", this.generateExpression(expr.callee, Precedence.New, itemFlags));
61829
+ result = join31("new", this.generateExpression(expr.callee, Precedence.New, itemFlags));
61231
61830
  if (!(flags & F_ALLOW_UNPARATH_NEW) || parentheses || length > 0) {
61232
61831
  result.push("(");
61233
61832
  for (i = 0, iz = length;i < iz; ++i) {
@@ -61274,11 +61873,11 @@ var require_escodegen = __commonJS((exports) => {
61274
61873
  var result, fragment, rightCharCode, leftSource, leftCharCode;
61275
61874
  fragment = this.generateExpression(expr.argument, Precedence.Unary, E_TTT);
61276
61875
  if (space === "") {
61277
- result = join30(expr.operator, fragment);
61876
+ result = join31(expr.operator, fragment);
61278
61877
  } else {
61279
61878
  result = [expr.operator];
61280
61879
  if (expr.operator.length > 2) {
61281
- result = join30(result, fragment);
61880
+ result = join31(result, fragment);
61282
61881
  } else {
61283
61882
  leftSource = toSourceNodeWhenNeeded(result).toString();
61284
61883
  leftCharCode = leftSource.charCodeAt(leftSource.length - 1);
@@ -61301,12 +61900,12 @@ var require_escodegen = __commonJS((exports) => {
61301
61900
  result = "yield";
61302
61901
  }
61303
61902
  if (expr.argument) {
61304
- result = join30(result, this.generateExpression(expr.argument, Precedence.Yield, E_TTT));
61903
+ result = join31(result, this.generateExpression(expr.argument, Precedence.Yield, E_TTT));
61305
61904
  }
61306
61905
  return parenthesize(result, Precedence.Yield, precedence);
61307
61906
  },
61308
61907
  AwaitExpression: function(expr, precedence, flags) {
61309
- var result = join30(expr.all ? "await*" : "await", this.generateExpression(expr.argument, Precedence.Await, E_TTT));
61908
+ var result = join31(expr.all ? "await*" : "await", this.generateExpression(expr.argument, Precedence.Await, E_TTT));
61310
61909
  return parenthesize(result, Precedence.Await, precedence);
61311
61910
  },
61312
61911
  UpdateExpression: function(expr, precedence, flags) {
@@ -61378,11 +61977,11 @@ var require_escodegen = __commonJS((exports) => {
61378
61977
  var result, fragment;
61379
61978
  result = ["class"];
61380
61979
  if (expr.id) {
61381
- result = join30(result, this.generateExpression(expr.id, Precedence.Sequence, E_TTT));
61980
+ result = join31(result, this.generateExpression(expr.id, Precedence.Sequence, E_TTT));
61382
61981
  }
61383
61982
  if (expr.superClass) {
61384
- fragment = join30("extends", this.generateExpression(expr.superClass, Precedence.Unary, E_TTT));
61385
- result = join30(result, fragment);
61983
+ fragment = join31("extends", this.generateExpression(expr.superClass, Precedence.Unary, E_TTT));
61984
+ result = join31(result, fragment);
61386
61985
  }
61387
61986
  result.push(space);
61388
61987
  result.push(this.generateStatement(expr.body, S_TFFT));
@@ -61397,7 +61996,7 @@ var require_escodegen = __commonJS((exports) => {
61397
61996
  }
61398
61997
  if (expr.kind === "get" || expr.kind === "set") {
61399
61998
  fragment = [
61400
- join30(expr.kind, this.generatePropertyKey(expr.key, expr.computed)),
61999
+ join31(expr.kind, this.generatePropertyKey(expr.key, expr.computed)),
61401
62000
  this.generateFunctionBody(expr.value)
61402
62001
  ];
61403
62002
  } else {
@@ -61407,7 +62006,7 @@ var require_escodegen = __commonJS((exports) => {
61407
62006
  this.generateFunctionBody(expr.value)
61408
62007
  ];
61409
62008
  }
61410
- return join30(result, fragment);
62009
+ return join31(result, fragment);
61411
62010
  },
61412
62011
  Property: function(expr, precedence, flags) {
61413
62012
  if (expr.kind === "get" || expr.kind === "set") {
@@ -61601,7 +62200,7 @@ var require_escodegen = __commonJS((exports) => {
61601
62200
  for (i = 0, iz = expr.blocks.length;i < iz; ++i) {
61602
62201
  fragment = that.generateExpression(expr.blocks[i], Precedence.Sequence, E_TTT);
61603
62202
  if (i > 0 || extra.moz.comprehensionExpressionStartsWithAssignment) {
61604
- result = join30(result, fragment);
62203
+ result = join31(result, fragment);
61605
62204
  } else {
61606
62205
  result.push(fragment);
61607
62206
  }
@@ -61609,13 +62208,13 @@ var require_escodegen = __commonJS((exports) => {
61609
62208
  });
61610
62209
  }
61611
62210
  if (expr.filter) {
61612
- result = join30(result, "if" + space);
62211
+ result = join31(result, "if" + space);
61613
62212
  fragment = this.generateExpression(expr.filter, Precedence.Sequence, E_TTT);
61614
- result = join30(result, ["(", fragment, ")"]);
62213
+ result = join31(result, ["(", fragment, ")"]);
61615
62214
  }
61616
62215
  if (!extra.moz.comprehensionExpressionStartsWithAssignment) {
61617
62216
  fragment = this.generateExpression(expr.body, Precedence.Assignment, E_TTT);
61618
- result = join30(result, fragment);
62217
+ result = join31(result, fragment);
61619
62218
  }
61620
62219
  result.push(expr.type === Syntax.GeneratorExpression ? ")" : "]");
61621
62220
  return result;
@@ -61631,8 +62230,8 @@ var require_escodegen = __commonJS((exports) => {
61631
62230
  } else {
61632
62231
  fragment = this.generateExpression(expr.left, Precedence.Call, E_TTT);
61633
62232
  }
61634
- fragment = join30(fragment, expr.of ? "of" : "in");
61635
- fragment = join30(fragment, this.generateExpression(expr.right, Precedence.Sequence, E_TTT));
62233
+ fragment = join31(fragment, expr.of ? "of" : "in");
62234
+ fragment = join31(fragment, this.generateExpression(expr.right, Precedence.Sequence, E_TTT));
61636
62235
  return ["for" + space + "(", fragment, ")"];
61637
62236
  },
61638
62237
  SpreadElement: function(expr, precedence, flags) {
@@ -75337,7 +75936,7 @@ var init_httpUtil = __esm(() => {
75337
75936
  });
75338
75937
 
75339
75938
  // node_modules/@puppeteer/browsers/lib/esm/browser-data/chrome.js
75340
- import { execSync as execSync7 } from "node:child_process";
75939
+ import { execSync as execSync8 } from "node:child_process";
75341
75940
  import os from "node:os";
75342
75941
  import path from "node:path";
75343
75942
  function folder(platform2) {
@@ -75427,7 +76026,7 @@ function getChromeWindowsLocation(channel2, locationsPrefixes) {
75427
76026
  }
75428
76027
  function getWslVariable(variable) {
75429
76028
  try {
75430
- const result = execSync7(`cmd.exe /c echo %${variable.toLocaleUpperCase()}%`, {
76029
+ const result = execSync8(`cmd.exe /c echo %${variable.toLocaleUpperCase()}%`, {
75431
76030
  stdio: ["ignore", "pipe", "ignore"],
75432
76031
  encoding: "utf-8"
75433
76032
  }).trim();
@@ -75438,7 +76037,7 @@ function getWslVariable(variable) {
75438
76037
  return;
75439
76038
  }
75440
76039
  function getWslLocation(channel2) {
75441
- const wslVersion = execSync7("wslinfo --version", {
76040
+ const wslVersion = execSync8("wslinfo --version", {
75442
76041
  stdio: ["ignore", "pipe", "ignore"],
75443
76042
  encoding: "utf-8"
75444
76043
  }).trim();
@@ -75454,7 +76053,7 @@ function getWslLocation(channel2) {
75454
76053
  }
75455
76054
  const windowsPath = getChromeWindowsLocation(channel2, wslPrefixes);
75456
76055
  return windowsPath.map((path2) => {
75457
- return execSync7(`wslpath "${path2}"`).toString().trim();
76056
+ return execSync8(`wslpath "${path2}"`).toString().trim();
75458
76057
  });
75459
76058
  }
75460
76059
  function getChromeLinuxOrWslLocation(channel2) {
@@ -81729,7 +82328,7 @@ var init_fileUtil = __esm(() => {
81729
82328
  // node_modules/@puppeteer/browsers/lib/esm/install.js
81730
82329
  import assert2 from "node:assert";
81731
82330
  import { spawnSync as spawnSync4 } from "node:child_process";
81732
- import { existsSync as existsSync30, readFileSync as readFileSync24 } from "node:fs";
82331
+ import { existsSync as existsSync34, readFileSync as readFileSync25 } from "node:fs";
81733
82332
  import { mkdir as mkdir2, unlink } from "node:fs/promises";
81734
82333
  import os5 from "node:os";
81735
82334
  import path8 from "node:path";
@@ -81782,7 +82381,7 @@ async function installWithProviders(options) {
81782
82381
  continue;
81783
82382
  }
81784
82383
  debugInstall(`Successfully got URL from ${provider.getName()}: ${url}`);
81785
- if (!existsSync30(browserRoot)) {
82384
+ if (!existsSync34(browserRoot)) {
81786
82385
  await mkdir2(browserRoot, { recursive: true });
81787
82386
  }
81788
82387
  return await installUrl(url, options, provider);
@@ -81815,11 +82414,11 @@ async function installDeps(installedBrowser) {
81815
82414
  return;
81816
82415
  }
81817
82416
  const depsPath = path8.join(path8.dirname(installedBrowser.executablePath), "deb.deps");
81818
- if (!existsSync30(depsPath)) {
82417
+ if (!existsSync34(depsPath)) {
81819
82418
  debugInstall(`deb.deps file was not found at ${depsPath}`);
81820
82419
  return;
81821
82420
  }
81822
- const data = readFileSync24(depsPath, "utf-8").split(`
82421
+ const data = readFileSync25(depsPath, "utf-8").split(`
81823
82422
  `).join(",");
81824
82423
  if (process.getuid?.() !== 0) {
81825
82424
  throw new Error("Installing system dependencies requires root privileges");
@@ -81857,11 +82456,11 @@ async function installUrl(url, options, provider) {
81857
82456
  const cache = new Cache(options.cacheDir);
81858
82457
  const browserRoot = cache.browserRoot(options.browser);
81859
82458
  const archivePath = path8.join(browserRoot, `${options.buildId}-${fileName}`);
81860
- if (!existsSync30(browserRoot)) {
82459
+ if (!existsSync34(browserRoot)) {
81861
82460
  await mkdir2(browserRoot, { recursive: true });
81862
82461
  }
81863
82462
  if (!options.unpack) {
81864
- if (existsSync30(archivePath)) {
82463
+ if (existsSync34(archivePath)) {
81865
82464
  return archivePath;
81866
82465
  }
81867
82466
  debugInstall(`Downloading binary from ${url}`);
@@ -81882,8 +82481,8 @@ async function installUrl(url, options, provider) {
81882
82481
  cache.writeExecutablePath(options.browser, options.platform, options.buildId, relativeExecutablePath6);
81883
82482
  }
81884
82483
  try {
81885
- if (existsSync30(outputPath)) {
81886
- if (!existsSync30(installedBrowser.executablePath)) {
82484
+ if (existsSync34(outputPath)) {
82485
+ if (!existsSync34(installedBrowser.executablePath)) {
81887
82486
  throw new Error(`The browser folder (${outputPath}) exists but the executable (${installedBrowser.executablePath}) is missing`);
81888
82487
  }
81889
82488
  await runSetup(installedBrowser);
@@ -81892,7 +82491,7 @@ async function installUrl(url, options, provider) {
81892
82491
  }
81893
82492
  return installedBrowser;
81894
82493
  }
81895
- if (!existsSync30(archivePath)) {
82494
+ if (!existsSync34(archivePath)) {
81896
82495
  debugInstall(`Downloading binary from ${url}`);
81897
82496
  try {
81898
82497
  debugTime("download");
@@ -81921,7 +82520,7 @@ async function installUrl(url, options, provider) {
81921
82520
  }
81922
82521
  return installedBrowser;
81923
82522
  } finally {
81924
- if (existsSync30(archivePath)) {
82523
+ if (existsSync34(archivePath)) {
81925
82524
  await unlink(archivePath);
81926
82525
  }
81927
82526
  }
@@ -81932,7 +82531,7 @@ async function runSetup(installedBrowser) {
81932
82531
  debugTime("permissions");
81933
82532
  const browserDir = path8.dirname(installedBrowser.executablePath);
81934
82533
  const setupExePath = path8.join(browserDir, "setup.exe");
81935
- if (!existsSync30(setupExePath)) {
82534
+ if (!existsSync34(setupExePath)) {
81936
82535
  return;
81937
82536
  }
81938
82537
  spawnSync4(path8.join(browserDir, "setup.exe"), [`--configure-browser-in-directory=` + browserDir], {
@@ -83298,8 +83897,7 @@ var init_lib2 = __esm(() => {
83298
83897
  require: (path9) => {
83299
83898
  if (true) {
83300
83899
  return __require(path9);
83301
- } else
83302
- ;
83900
+ }
83303
83901
  }
83304
83902
  });
83305
83903
  yargsParser.detailed = function(args, opts) {
@@ -83345,14 +83943,14 @@ var init_yerror = __esm(() => {
83345
83943
  });
83346
83944
 
83347
83945
  // node_modules/y18n/build/lib/platform-shims/node.js
83348
- import { readFileSync as readFileSync25, statSync as statSync13, writeFile } from "fs";
83946
+ import { readFileSync as readFileSync26, statSync as statSync13, writeFile } from "fs";
83349
83947
  import { format as format2 } from "util";
83350
83948
  import { resolve as resolve12 } from "path";
83351
83949
  var node_default;
83352
83950
  var init_node = __esm(() => {
83353
83951
  node_default = {
83354
83952
  fs: {
83355
- readFileSync: readFileSync25,
83953
+ readFileSync: readFileSync26,
83356
83954
  writeFile
83357
83955
  },
83358
83956
  format: format2,
@@ -83537,9 +84135,9 @@ var init_y18n = __esm(() => {
83537
84135
  // node_modules/yargs/lib/platform-shims/esm.mjs
83538
84136
  import { notStrictEqual, strictEqual } from "assert";
83539
84137
  import { inspect } from "util";
83540
- import { readFileSync as readFileSync26 } from "fs";
84138
+ import { readFileSync as readFileSync27 } from "fs";
83541
84139
  import { fileURLToPath } from "url";
83542
- import { basename as basename9, dirname as dirname14, extname as extname3, relative as relative7, resolve as resolve13 } from "path";
84140
+ import { basename as basename9, dirname as dirname14, extname as extname3, relative as relative9, resolve as resolve13 } from "path";
83543
84141
  var REQUIRE_ERROR = "require is not supported by ESM", REQUIRE_DIRECTORY_ERROR = "loading a directory of commands is not supported yet for ESM", __dirname2, mainFilename, esm_default;
83544
84142
  var init_esm = __esm(() => {
83545
84143
  init_cliui();
@@ -83574,7 +84172,7 @@ var init_esm = __esm(() => {
83574
84172
  basename: basename9,
83575
84173
  dirname: dirname14,
83576
84174
  extname: extname3,
83577
- relative: relative7,
84175
+ relative: relative9,
83578
84176
  resolve: resolve13
83579
84177
  },
83580
84178
  process: {
@@ -83586,7 +84184,7 @@ var init_esm = __esm(() => {
83586
84184
  nextTick: process.nextTick,
83587
84185
  stdColumns: typeof process.stdout.columns !== "undefined" ? process.stdout.columns : null
83588
84186
  },
83589
- readFileSync: readFileSync26,
84187
+ readFileSync: readFileSync27,
83590
84188
  require: () => {
83591
84189
  throw new YError(REQUIRE_ERROR);
83592
84190
  },
@@ -87285,9 +87883,9 @@ async function getConnectionTransport(options) {
87285
87883
  throw new Error("Could not detect required browser platform");
87286
87884
  }
87287
87885
  const { convertPuppeteerChannelToBrowsersChannel: convertPuppeteerChannelToBrowsersChannel2 } = await Promise.resolve().then(() => (init_LaunchOptions(), exports_LaunchOptions));
87288
- const { join: join31 } = await import("node:path");
87886
+ const { join: join32 } = await import("node:path");
87289
87887
  const userDataDir = resolveDefaultUserDataDir3(Browser7.CHROME, platform2, convertPuppeteerChannelToBrowsersChannel2(options.channel));
87290
- const portPath = join31(userDataDir, "DevToolsActivePort");
87888
+ const portPath = join32(userDataDir, "DevToolsActivePort");
87291
87889
  try {
87292
87890
  const fileContent = await environment.value.fs.promises.readFile(portPath, "ascii");
87293
87891
  const [rawPort, rawPath] = fileContent.split(`
@@ -87511,9 +88109,9 @@ var init_PipeTransport = __esm(() => {
87511
88109
  });
87512
88110
 
87513
88111
  // node_modules/puppeteer-core/lib/esm/puppeteer/node/BrowserLauncher.js
87514
- import { existsSync as existsSync31 } from "node:fs";
88112
+ import { existsSync as existsSync35 } from "node:fs";
87515
88113
  import { tmpdir } from "node:os";
87516
- import { join as join31 } from "node:path";
88114
+ import { join as join32 } from "node:path";
87517
88115
 
87518
88116
  class BrowserLauncher {
87519
88117
  #browser;
@@ -87538,7 +88136,7 @@ class BrowserLauncher {
87538
88136
  ...options,
87539
88137
  protocol
87540
88138
  });
87541
- if (!existsSync31(launchArgs.executablePath)) {
88139
+ if (!existsSync35(launchArgs.executablePath)) {
87542
88140
  throw new Error(`Browser was not found at the configured executablePath (${launchArgs.executablePath})`);
87543
88141
  }
87544
88142
  const usePipe = launchArgs.args.includes("--remote-debugging-pipe");
@@ -87613,7 +88211,7 @@ class BrowserLauncher {
87613
88211
  browserCloseCallback();
87614
88212
  const logs = browserProcess.getRecentLogs().join(`
87615
88213
  `);
87616
- if (logs.includes("Failed to create a ProcessSingleton for your profile directory") || process.platform === "win32" && existsSync31(join31(launchArgs.userDataDir, "lockfile"))) {
88214
+ if (logs.includes("Failed to create a ProcessSingleton for your profile directory") || process.platform === "win32" && existsSync35(join32(launchArgs.userDataDir, "lockfile"))) {
87617
88215
  throw new Error(`The browser is already running for ${launchArgs.userDataDir}. Use a different \`userDataDir\` or stop the running browser first.`);
87618
88216
  }
87619
88217
  if (logs.includes("Missing X server") && options.headless === false) {
@@ -87703,12 +88301,12 @@ class BrowserLauncher {
87703
88301
  });
87704
88302
  }
87705
88303
  getProfilePath() {
87706
- return join31(this.puppeteer.configuration.temporaryDirectory ?? tmpdir(), `puppeteer_dev_${this.browser}_profile-`);
88304
+ return join32(this.puppeteer.configuration.temporaryDirectory ?? tmpdir(), `puppeteer_dev_${this.browser}_profile-`);
87707
88305
  }
87708
88306
  resolveExecutablePath(headless, validatePath = true) {
87709
88307
  let executablePath = this.puppeteer.configuration.executablePath;
87710
88308
  if (executablePath) {
87711
- if (validatePath && !existsSync31(executablePath)) {
88309
+ if (validatePath && !existsSync35(executablePath)) {
87712
88310
  throw new Error(`Tried to find the browser at the configured path (${executablePath}), but no executable was found.`);
87713
88311
  }
87714
88312
  return executablePath;
@@ -87731,7 +88329,7 @@ class BrowserLauncher {
87731
88329
  browser: browserType,
87732
88330
  buildId: this.puppeteer.browserVersion
87733
88331
  });
87734
- if (validatePath && !existsSync31(executablePath)) {
88332
+ if (validatePath && !existsSync35(executablePath)) {
87735
88333
  const configVersion = this.puppeteer.configuration?.[this.browser]?.version;
87736
88334
  if (configVersion) {
87737
88335
  throw new Error(`Tried to find the browser at the configured path (${executablePath}) for version ${configVersion}, but no executable was found.`);
@@ -88546,17 +89144,17 @@ var init_puppeteer_core = __esm(() => {
88546
89144
  });
88547
89145
 
88548
89146
  // src/core/design-eval/capture.ts
88549
- import { mkdirSync as mkdirSync14, statSync as statSync14, existsSync as existsSync32 } from "fs";
88550
- import { join as join32 } from "path";
89147
+ import { mkdirSync as mkdirSync14, statSync as statSync14, existsSync as existsSync36 } from "fs";
89148
+ import { join as join33 } from "path";
88551
89149
  function findBrowser() {
88552
89150
  const platform2 = process.platform;
88553
89151
  const paths = CHROME_PATHS[platform2] ?? [];
88554
89152
  for (const p of paths) {
88555
- if (existsSync32(p))
89153
+ if (existsSync36(p))
88556
89154
  return p;
88557
89155
  }
88558
- const minkBrowsers = join32(minkRoot(), "browsers");
88559
- if (existsSync32(minkBrowsers)) {
89156
+ const minkBrowsers = join33(minkRoot(), "browsers");
89157
+ if (existsSync36(minkBrowsers)) {
88560
89158
  const found = findChromeInDir(minkBrowsers);
88561
89159
  if (found)
88562
89160
  return found;
@@ -88577,7 +89175,7 @@ function findChromeInDir(dir) {
88577
89175
  try {
88578
89176
  const entries = readdirSync11(dir);
88579
89177
  for (const entry of entries) {
88580
- const full = join32(dir, entry);
89178
+ const full = join33(dir, entry);
88581
89179
  try {
88582
89180
  const stat2 = statSync15(full);
88583
89181
  if (stat2.isDirectory()) {
@@ -88625,7 +89223,7 @@ async function captureRoute(page, route, baseUrl, viewport, options) {
88625
89223
  const y = section * viewport.height;
88626
89224
  const clipHeight = Math.min(viewport.height, pageHeight - y);
88627
89225
  const fileName = `${prefix}-${viewport.name}-${section}.jpg`;
88628
- const filePath = join32(options.outputDir, fileName);
89226
+ const filePath = join33(options.outputDir, fileName);
88629
89227
  await page.screenshot({
88630
89228
  path: filePath,
88631
89229
  type: "jpeg",
@@ -90089,7 +90687,7 @@ var exports_wiki = {};
90089
90687
  __export(exports_wiki, {
90090
90688
  wiki: () => wiki
90091
90689
  });
90092
- import { existsSync as existsSync33, statSync as statSync15 } from "fs";
90690
+ import { existsSync as existsSync37, statSync as statSync15 } from "fs";
90093
90691
  import { resolve as resolve14 } from "path";
90094
90692
  import { homedir as homedir5 } from "os";
90095
90693
  async function wiki(_cwd, args) {
@@ -90102,6 +90700,7 @@ async function wiki(_cwd, args) {
90102
90700
  wikiStatus();
90103
90701
  break;
90104
90702
  case "rebuild-index":
90703
+ case "scan":
90105
90704
  wikiRebuildIndex();
90106
90705
  break;
90107
90706
  case "organize":
@@ -90121,7 +90720,8 @@ async function wiki(_cwd, args) {
90121
90720
  console.log();
90122
90721
  console.log(" init Initialize the notes/wiki vault");
90123
90722
  console.log(" status Show vault statistics");
90124
- console.log(" rebuild-index Full rescan and reindex of vault");
90723
+ console.log(" rebuild-index Full rescan and reindex of vault (alias: scan)");
90724
+ console.log(" scan Alias for rebuild-index");
90125
90725
  console.log(" organize List inbox notes needing categorization");
90126
90726
  console.log(" link <path> [name] Symlink external notes into the vault");
90127
90727
  console.log(" unlink <name> Remove a symlinked directory from the vault");
@@ -90145,7 +90745,7 @@ async function wikiInit(args) {
90145
90745
  console.log(`[mink] initializing vault at ${targetPath}`);
90146
90746
  console.log(" (set a custom path with: mink wiki init /path/to/vault)");
90147
90747
  }
90148
- const isExisting = existsSync33(targetPath) && statSync15(targetPath).isDirectory();
90748
+ const isExisting = existsSync37(targetPath) && statSync15(targetPath).isDirectory();
90149
90749
  setConfigValue("wiki.path", targetPath);
90150
90750
  ensureVaultStructure();
90151
90751
  seedTemplates(vaultTemplates());
@@ -90210,6 +90810,11 @@ function wikiStatus() {
90210
90810
  return;
90211
90811
  }
90212
90812
  const vaultPath = resolveVaultPath();
90813
+ const staleness = vaultIndexStaleness();
90814
+ if (staleness.isStale) {
90815
+ console.log(`[mink] vault index is stale (${staleness.reason}) — rebuilding...`);
90816
+ rebuildVaultIndex();
90817
+ }
90213
90818
  const index = loadVaultIndex();
90214
90819
  const categoryCounts = {
90215
90820
  inbox: 0,
@@ -90232,7 +90837,8 @@ function wikiStatus() {
90232
90837
  console.log(` ${cat.padEnd(12)} ${count}`);
90233
90838
  }
90234
90839
  console.log();
90235
- console.log(` last indexed: ${index.lastScanTimestamp || "never"}`);
90840
+ console.log(` last full scan: ${index.lastFullScanTimestamp || "never"}`);
90841
+ console.log(` last update: ${index.lastScanTimestamp || "never"}`);
90236
90842
  const links = listLinks();
90237
90843
  if (links.length > 0) {
90238
90844
  console.log();
@@ -90368,7 +90974,7 @@ __export(exports_note, {
90368
90974
  note: () => note
90369
90975
  });
90370
90976
  import { resolve as resolve15 } from "path";
90371
- import { existsSync as existsSync34, readFileSync as readFileSync27 } from "fs";
90977
+ import { existsSync as existsSync38, readFileSync as readFileSync28 } from "fs";
90372
90978
  async function note(cwd, args) {
90373
90979
  if (!isWikiEnabled()) {
90374
90980
  console.error("[mink] wiki feature is disabled");
@@ -90393,13 +90999,13 @@ async function note(cwd, args) {
90393
90999
  const date = new Date().toISOString().split("T")[0];
90394
91000
  const content = parsed.positional || parsed.body || "";
90395
91001
  const filePath = appendToDaily(date, content);
90396
- updateVaultIndexForFile(filePath, readFileSync27(filePath, "utf-8"));
91002
+ updateVaultIndexForFile(filePath, readFileSync28(filePath, "utf-8"));
90397
91003
  console.log(`[mink] daily note: ${filePath}`);
90398
91004
  return;
90399
91005
  }
90400
91006
  if (parsed.file) {
90401
91007
  const sourcePath = resolve15(cwd, parsed.file);
90402
- if (!existsSync34(sourcePath)) {
91008
+ if (!existsSync38(sourcePath)) {
90403
91009
  console.error(`[mink] file not found: ${sourcePath}`);
90404
91010
  process.exit(1);
90405
91011
  }
@@ -90481,7 +91087,7 @@ function detectSourceProject(cwd) {
90481
91087
  const vaultPath = resolveVaultPath();
90482
91088
  if (cwd.startsWith(vaultPath))
90483
91089
  return;
90484
- return generateProjectId(cwd);
91090
+ return projectIdFor(cwd);
90485
91091
  } catch {
90486
91092
  return;
90487
91093
  }
@@ -90560,10 +91166,10 @@ var exports_skill = {};
90560
91166
  __export(exports_skill, {
90561
91167
  skill: () => skill
90562
91168
  });
90563
- import { join as join33, resolve as resolve16, dirname as dirname16 } from "path";
91169
+ import { join as join34, resolve as resolve16, dirname as dirname16 } from "path";
90564
91170
  import { homedir as homedir6 } from "os";
90565
91171
  import {
90566
- existsSync as existsSync35,
91172
+ existsSync as existsSync39,
90567
91173
  mkdirSync as mkdirSync15,
90568
91174
  copyFileSync,
90569
91175
  unlinkSync as unlinkSync6,
@@ -90575,8 +91181,8 @@ import {
90575
91181
  function getSkillsSourceDir() {
90576
91182
  let dir = dirname16(new URL(import.meta.url).pathname);
90577
91183
  while (true) {
90578
- if (existsSync35(join33(dir, "package.json")) && existsSync35(join33(dir, "skills"))) {
90579
- return join33(dir, "skills");
91184
+ if (existsSync39(join34(dir, "package.json")) && existsSync39(join34(dir, "skills"))) {
91185
+ return join34(dir, "skills");
90580
91186
  }
90581
91187
  const parent = dirname16(dir);
90582
91188
  if (parent === dir)
@@ -90587,12 +91193,12 @@ function getSkillsSourceDir() {
90587
91193
  }
90588
91194
  function getAvailableSkills() {
90589
91195
  const dir = getSkillsSourceDir();
90590
- if (!existsSync35(dir))
91196
+ if (!existsSync39(dir))
90591
91197
  return [];
90592
- return readdirSync11(dir, { withFileTypes: true }).filter((d) => d.isDirectory() && existsSync35(join33(dir, d.name, "SKILL.md"))).map((d) => d.name);
91198
+ return readdirSync11(dir, { withFileTypes: true }).filter((d) => d.isDirectory() && existsSync39(join34(dir, d.name, "SKILL.md"))).map((d) => d.name);
90593
91199
  }
90594
91200
  function isInstalled(skillName) {
90595
- return existsSync35(join33(AGENTS_SKILLS_DIR, skillName, "SKILL.md"));
91201
+ return existsSync39(join34(AGENTS_SKILLS_DIR, skillName, "SKILL.md"));
90596
91202
  }
90597
91203
  async function skill(args) {
90598
91204
  const sub = args[0];
@@ -90628,26 +91234,26 @@ function skillInstall(name) {
90628
91234
  }
90629
91235
  mkdirSync15(AGENTS_SKILLS_DIR, { recursive: true });
90630
91236
  for (const skillName of skills) {
90631
- const srcDir = join33(sourceDir, skillName);
90632
- const srcFile = join33(srcDir, "SKILL.md");
90633
- const destDir = join33(AGENTS_SKILLS_DIR, skillName);
90634
- if (!existsSync35(srcFile)) {
91237
+ const srcDir = join34(sourceDir, skillName);
91238
+ const srcFile = join34(srcDir, "SKILL.md");
91239
+ const destDir = join34(AGENTS_SKILLS_DIR, skillName);
91240
+ if (!existsSync39(srcFile)) {
90635
91241
  console.error(`[mink] skill not found: ${skillName}`);
90636
91242
  continue;
90637
91243
  }
90638
91244
  mkdirSync15(destDir, { recursive: true });
90639
- copyDirRecursive(srcDir, destDir);
91245
+ copyDirRecursive2(srcDir, destDir);
90640
91246
  mkdirSync15(CLAUDE_SKILLS_DIR, { recursive: true });
90641
- const symlink = join33(CLAUDE_SKILLS_DIR, skillName);
91247
+ const symlink = join34(CLAUDE_SKILLS_DIR, skillName);
90642
91248
  try {
90643
- if (existsSync35(symlink)) {
91249
+ if (existsSync39(symlink)) {
90644
91250
  if (lstatSync2(symlink).isSymbolicLink() || lstatSync2(symlink).isFile()) {
90645
91251
  unlinkSync6(symlink);
90646
91252
  } else {
90647
91253
  rmSync(symlink, { recursive: true, force: true });
90648
91254
  }
90649
91255
  }
90650
- const relativeTarget = join33("..", "..", ".agents", "skills", skillName);
91256
+ const relativeTarget = join34("..", "..", ".agents", "skills", skillName);
90651
91257
  symlinkSync2(relativeTarget, symlink);
90652
91258
  } catch {}
90653
91259
  console.log(`[mink] installed: ${skillName} -> ${destDir}`);
@@ -90658,15 +91264,15 @@ function skillInstall(name) {
90658
91264
  function skillUninstall(name) {
90659
91265
  const skills = name ? [name] : getAvailableSkills();
90660
91266
  for (const skillName of skills) {
90661
- const destDir = join33(AGENTS_SKILLS_DIR, skillName);
90662
- if (!existsSync35(destDir)) {
91267
+ const destDir = join34(AGENTS_SKILLS_DIR, skillName);
91268
+ if (!existsSync39(destDir)) {
90663
91269
  console.log(`[mink] not installed: ${skillName}`);
90664
91270
  continue;
90665
91271
  }
90666
91272
  rmSync(destDir, { recursive: true, force: true });
90667
- const symlink = join33(CLAUDE_SKILLS_DIR, skillName);
91273
+ const symlink = join34(CLAUDE_SKILLS_DIR, skillName);
90668
91274
  try {
90669
- if (existsSync35(symlink))
91275
+ if (existsSync39(symlink))
90670
91276
  unlinkSync6(symlink);
90671
91277
  } catch {}
90672
91278
  console.log(`[mink] uninstalled: ${skillName}`);
@@ -90681,7 +91287,7 @@ function skillList() {
90681
91287
  if (installed.length > 0) {
90682
91288
  console.log(" Installed:");
90683
91289
  for (const s of installed) {
90684
- console.log(` ${s} (${join33(AGENTS_SKILLS_DIR, s)})`);
91290
+ console.log(` ${s} (${join34(AGENTS_SKILLS_DIR, s)})`);
90685
91291
  }
90686
91292
  }
90687
91293
  if (notInstalled.length > 0) {
@@ -90697,14 +91303,14 @@ function skillList() {
90697
91303
  console.log(" Install with: mink skill install");
90698
91304
  console.log(" Or via skills CLI: npx skills add drewpayment/mink");
90699
91305
  }
90700
- function copyDirRecursive(src, dest) {
91306
+ function copyDirRecursive2(src, dest) {
90701
91307
  const entries = readdirSync11(src, { withFileTypes: true });
90702
91308
  for (const entry of entries) {
90703
- const srcPath = join33(src, entry.name);
90704
- const destPath = join33(dest, entry.name);
91309
+ const srcPath = join34(src, entry.name);
91310
+ const destPath = join34(dest, entry.name);
90705
91311
  if (entry.isDirectory()) {
90706
91312
  mkdirSync15(destPath, { recursive: true });
90707
- copyDirRecursive(srcPath, destPath);
91313
+ copyDirRecursive2(srcPath, destPath);
90708
91314
  } else {
90709
91315
  copyFileSync(srcPath, destPath);
90710
91316
  }
@@ -90712,8 +91318,8 @@ function copyDirRecursive(src, dest) {
90712
91318
  }
90713
91319
  var AGENTS_SKILLS_DIR, CLAUDE_SKILLS_DIR;
90714
91320
  var init_skill = __esm(() => {
90715
- AGENTS_SKILLS_DIR = join33(homedir6(), ".agents", "skills");
90716
- CLAUDE_SKILLS_DIR = join33(homedir6(), ".claude", "skills");
91321
+ AGENTS_SKILLS_DIR = join34(homedir6(), ".agents", "skills");
91322
+ CLAUDE_SKILLS_DIR = join34(homedir6(), ".claude", "skills");
90717
91323
  });
90718
91324
 
90719
91325
  // src/commands/agent.ts
@@ -90721,12 +91327,12 @@ var exports_agent = {};
90721
91327
  __export(exports_agent, {
90722
91328
  agent: () => agent
90723
91329
  });
90724
- import { join as join34, resolve as resolve17, dirname as dirname17 } from "path";
91330
+ import { join as join35, resolve as resolve17, dirname as dirname17 } from "path";
90725
91331
  import { homedir as homedir7 } from "os";
90726
91332
  import {
90727
- existsSync as existsSync36,
91333
+ existsSync as existsSync40,
90728
91334
  mkdirSync as mkdirSync16,
90729
- readFileSync as readFileSync28,
91335
+ readFileSync as readFileSync29,
90730
91336
  writeFileSync as writeFileSync11
90731
91337
  } from "fs";
90732
91338
  import { createHash as createHash3 } from "crypto";
@@ -90734,8 +91340,8 @@ import { spawnSync as spawnSync6 } from "child_process";
90734
91340
  function getAgentTemplatePath() {
90735
91341
  let dir = dirname17(new URL(import.meta.url).pathname);
90736
91342
  while (true) {
90737
- if (existsSync36(join34(dir, "package.json")) && existsSync36(join34(dir, "agents", TEMPLATE_FILE))) {
90738
- return join34(dir, "agents", TEMPLATE_FILE);
91343
+ if (existsSync40(join35(dir, "package.json")) && existsSync40(join35(dir, "agents", TEMPLATE_FILE))) {
91344
+ return join35(dir, "agents", TEMPLATE_FILE);
90739
91345
  }
90740
91346
  const parent = dirname17(dir);
90741
91347
  if (parent === dir)
@@ -90747,10 +91353,10 @@ function getAgentTemplatePath() {
90747
91353
  function getMinkVersion() {
90748
91354
  let dir = dirname17(new URL(import.meta.url).pathname);
90749
91355
  while (true) {
90750
- const pkgPath = join34(dir, "package.json");
90751
- if (existsSync36(pkgPath)) {
91356
+ const pkgPath = join35(dir, "package.json");
91357
+ if (existsSync40(pkgPath)) {
90752
91358
  try {
90753
- const pkg = JSON.parse(readFileSync28(pkgPath, "utf-8"));
91359
+ const pkg = JSON.parse(readFileSync29(pkgPath, "utf-8"));
90754
91360
  if (pkg.name && pkg.version)
90755
91361
  return pkg.version;
90756
91362
  } catch {}
@@ -90773,30 +91379,30 @@ function sha2562(text) {
90773
91379
  return createHash3("sha256").update(text).digest("hex");
90774
91380
  }
90775
91381
  function claudeAgentsDir() {
90776
- return join34(homedir7(), ".claude", "agents");
91382
+ return join35(homedir7(), ".claude", "agents");
90777
91383
  }
90778
91384
  function installedAgentPath() {
90779
- return join34(claudeAgentsDir(), INSTALLED_FILE);
91385
+ return join35(claudeAgentsDir(), INSTALLED_FILE);
90780
91386
  }
90781
91387
  function installAgentDefinition(opts) {
90782
91388
  const templatePath = getAgentTemplatePath();
90783
- if (!existsSync36(templatePath)) {
91389
+ if (!existsSync40(templatePath)) {
90784
91390
  throw new Error(`[mink agent] bundled agent template not found at ${templatePath}
90785
91391
  ` + " This usually means the package was installed without bundled assets.");
90786
91392
  }
90787
91393
  const installed = installedAgentPath();
90788
- if (opts.skip && existsSync36(installed)) {
91394
+ if (opts.skip && existsSync40(installed)) {
90789
91395
  return { action: "skipped", path: installed };
90790
91396
  }
90791
- const template = readFileSync28(templatePath, "utf-8");
91397
+ const template = readFileSync29(templatePath, "utf-8");
90792
91398
  const rendered = renderTemplate(template, {
90793
91399
  MINK_ROOT: minkRoot(),
90794
91400
  VAULT_PATH: resolveVaultPath(),
90795
91401
  MINK_VERSION: getMinkVersion()
90796
91402
  });
90797
- const exists = existsSync36(installed);
91403
+ const exists = existsSync40(installed);
90798
91404
  if (!opts.force && exists) {
90799
- const current = readFileSync28(installed, "utf-8");
91405
+ const current = readFileSync29(installed, "utf-8");
90800
91406
  if (sha2562(current) === sha2562(rendered)) {
90801
91407
  return { action: "unchanged", path: installed };
90802
91408
  }
@@ -90872,7 +91478,7 @@ async function agent(_cwd, rawArgs) {
90872
91478
  }
90873
91479
  const skipUpdate = args.noUpdate || process.env.MINK_AGENT_NO_UPDATE === "1";
90874
91480
  const root = minkRoot();
90875
- if (!existsSync36(root)) {
91481
+ if (!existsSync40(root)) {
90876
91482
  mkdirSync16(root, { recursive: true });
90877
91483
  }
90878
91484
  let result;
@@ -90924,25 +91530,25 @@ var init_agent = __esm(() => {
90924
91530
  });
90925
91531
 
90926
91532
  // src/core/sync-merge-drivers.ts
90927
- import { readFileSync as readFileSync29, writeFileSync as writeFileSync12, appendFileSync as appendFileSync2 } from "fs";
90928
- import { join as join35 } from "path";
91533
+ import { readFileSync as readFileSync30, writeFileSync as writeFileSync12, appendFileSync as appendFileSync2 } from "fs";
91534
+ import { join as join36 } from "path";
90929
91535
  function logWarning(driver, args, err) {
90930
91536
  try {
90931
91537
  const line = `[${new Date().toISOString()}] ${driver} fallback for ${args.filePath}: ${err instanceof Error ? err.message : String(err)}
90932
91538
  `;
90933
- appendFileSync2(join35(minkRoot(), "sync-warnings.log"), line);
91539
+ appendFileSync2(join36(minkRoot(), "sync-warnings.log"), line);
90934
91540
  } catch {}
90935
91541
  }
90936
91542
  function readJsonOrNull(path12) {
90937
91543
  try {
90938
- return JSON.parse(readFileSync29(path12, "utf-8"));
91544
+ return JSON.parse(readFileSync30(path12, "utf-8"));
90939
91545
  } catch {
90940
91546
  return null;
90941
91547
  }
90942
91548
  }
90943
91549
  function readTextOrEmpty(path12) {
90944
91550
  try {
90945
- return readFileSync29(path12, "utf-8");
91551
+ return readFileSync30(path12, "utf-8");
90946
91552
  } catch {
90947
91553
  return "";
90948
91554
  }
@@ -91116,12 +91722,13 @@ async function sync(args) {
91116
91722
  return handleReconcile(args.slice(1));
91117
91723
  case "migrate": {
91118
91724
  const { syncMigrateCommand: syncMigrateCommand2 } = await Promise.resolve().then(() => (init_sync_migrate(), exports_sync_migrate));
91119
- syncMigrateCommand2();
91725
+ syncMigrateCommand2(args.slice(1));
91120
91726
  return;
91121
91727
  }
91122
91728
  default:
91123
91729
  console.error(`[mink] unknown sync subcommand: ${subcommand}`);
91124
- console.error("Usage: mink sync [init|status|push|pull|pause|resume|disconnect|reconcile|migrate|merge-driver]");
91730
+ console.error("Usage: mink sync [init|status|push|pull|pause|resume|disconnect|reconcile|merge-driver]");
91731
+ console.error(" mink sync migrate [--dry-run|--rollback]");
91125
91732
  process.exit(1);
91126
91733
  }
91127
91734
  }
@@ -91343,7 +91950,9 @@ function sessionStart(cwd) {
91343
91950
  } catch {}
91344
91951
  try {
91345
91952
  const { readSyncVersion: readSyncVersion2, MINK_SYNC_VERSION: MINK_SYNC_VERSION2 } = (init_sync(), __toCommonJS(exports_sync));
91346
- if (readSyncVersion2() < MINK_SYNC_VERSION2) {
91953
+ const { resolveConfigValue: resolveConfigValue2 } = (init_global_config(), __toCommonJS(exports_global_config));
91954
+ const identityOn = resolveConfigValue2("projects.identity").value === "git-remote";
91955
+ if (readSyncVersion2() < MINK_SYNC_VERSION2 || identityOn) {
91347
91956
  const { migrateSyncLayout: migrateSyncLayout2 } = (init_sync_migrate(), __toCommonJS(exports_sync_migrate));
91348
91957
  migrateSyncLayout2();
91349
91958
  }
@@ -91367,13 +91976,13 @@ function sessionStart(cwd) {
91367
91976
  const index = loadVaultIndex();
91368
91977
  const inboxCount = Object.values(index.entries).filter((e) => e.category === "inbox").length;
91369
91978
  try {
91370
- const { join: join8 } = __require("path");
91371
- const { existsSync: existsSync8 } = __require("fs");
91979
+ const { join: join10 } = __require("path");
91980
+ const { existsSync: existsSync12 } = __require("fs");
91372
91981
  const { resolveVaultPath: resolveVaultPath2 } = (init_vault(), __toCommonJS(exports_vault));
91373
91982
  const { updateMasterIndex: updateMasterIndex2 } = (init_note_linker(), __toCommonJS(exports_note_linker));
91374
91983
  const vaultPath = resolveVaultPath2();
91375
- const masterIndexPath = join8(vaultPath, "_index.md");
91376
- if (!existsSync8(masterIndexPath)) {
91984
+ const masterIndexPath = join10(vaultPath, "_index.md");
91985
+ if (!existsSync12(masterIndexPath)) {
91377
91986
  updateMasterIndex2(vaultPath);
91378
91987
  }
91379
91988
  } catch {}
@@ -91397,8 +92006,8 @@ init_state_aggregator();
91397
92006
  init_action_log();
91398
92007
  init_device();
91399
92008
  init_vault();
91400
- import { statSync as statSync5, existsSync as existsSync10, readFileSync as readFileSync9 } from "fs";
91401
- import { join as join10, dirname as dirname4 } from "path";
92009
+ import { statSync as statSync5, existsSync as existsSync14, readFileSync as readFileSync10 } from "fs";
92010
+ import { join as join12, dirname as dirname4 } from "path";
91402
92011
  function hasActivity(state) {
91403
92012
  return Object.keys(state.reads).length > 0 || state.writes.length > 0;
91404
92013
  }
@@ -91440,10 +92049,10 @@ function sessionStop(sessionFile, finalizer, onReminder = (msg) => console.error
91440
92049
  effectiveFinalizer.updateSession(summary);
91441
92050
  }
91442
92051
  try {
91443
- const logPath = join10(projDir, "state", deviceId, "action-log.md");
92052
+ const logPath = join12(projDir, "state", deviceId, "action-log.md");
91444
92053
  const logWriter = createActionLogWriter(logPath);
91445
92054
  logWriter.appendSessionEnd(summary);
91446
- const cfgRaw = safeReadJson(join10(projDir, "config.json"));
92055
+ const cfgRaw = safeReadJson(join12(projDir, "config.json"));
91447
92056
  consolidateLog(logPath, {
91448
92057
  maxEntries: cfgRaw?.actionLogMaxEntries ?? 200,
91449
92058
  retentionDays: cfgRaw?.actionLogRetentionDays ?? 7
@@ -91460,9 +92069,9 @@ function sessionStop(sessionFile, finalizer, onReminder = (msg) => console.error
91460
92069
  }
91461
92070
  }
91462
92071
  }
91463
- const memoryPath = join10(projDir, "learning-memory.md");
91464
- const cfgPath = join10(projDir, "config.json");
91465
- if (existsSync10(memoryPath)) {
92072
+ const memoryPath = join12(projDir, "learning-memory.md");
92073
+ const cfgPath = join12(projDir, "config.json");
92074
+ if (existsSync14(memoryPath)) {
91466
92075
  reflect(projDir, memoryPath, cfgPath);
91467
92076
  }
91468
92077
  if (isLearningMemoryStale(memoryPath)) {
@@ -91482,13 +92091,13 @@ function sessionStop(sessionFile, finalizer, onReminder = (msg) => console.error
91482
92091
  atomicWriteJson(sessionFile, state);
91483
92092
  }
91484
92093
  function writeSessionToWiki(state, projDir) {
91485
- const metaRaw = safeReadJson(join10(projDir, "project-meta.json"));
92094
+ const metaRaw = safeReadJson(join12(projDir, "project-meta.json"));
91486
92095
  const projectName = metaRaw?.name ?? "unknown";
91487
92096
  const date = new Date().toISOString().split("T")[0];
91488
92097
  const readCount = Object.keys(state.reads).length;
91489
92098
  const writeCount = state.writes.length;
91490
- const sessionDir = join10(vaultProjects(projectName), "sessions");
91491
- const sessionFile = join10(sessionDir, `${date}.md`);
92099
+ const sessionDir = join12(vaultProjects(projectName), "sessions");
92100
+ const sessionFile = join12(sessionDir, `${date}.md`);
91492
92101
  const timestamp = new Date().toLocaleTimeString("en-US", {
91493
92102
  hour: "2-digit",
91494
92103
  minute: "2-digit",
@@ -91513,8 +92122,8 @@ function writeSessionToWiki(state, projDir) {
91513
92122
  }
91514
92123
  }
91515
92124
  entry.push("");
91516
- if (existsSync10(sessionFile)) {
91517
- const existing = readFileSync9(sessionFile, "utf-8");
92125
+ if (existsSync14(sessionFile)) {
92126
+ const existing = readFileSync10(sessionFile, "utf-8");
91518
92127
  atomicWriteText(sessionFile, existing.trimEnd() + `
91519
92128
  ` + entry.join(`
91520
92129
  `));
@@ -91695,9 +92304,9 @@ switch (command2) {
91695
92304
  case "-v": {
91696
92305
  const { resolve: resolve18, dirname: dirname18 } = await import("path");
91697
92306
  const cliPath = resolve18(dirname18(new URL(import.meta.url).pathname));
91698
- const { readFileSync: readFileSync30 } = await import("fs");
92307
+ const { readFileSync: readFileSync31 } = await import("fs");
91699
92308
  try {
91700
- const pkg = JSON.parse(readFileSync30(resolve18(cliPath, "../package.json"), "utf-8"));
92309
+ const pkg = JSON.parse(readFileSync31(resolve18(cliPath, "../package.json"), "utf-8"));
91701
92310
  console.log(`mink ${pkg.version}`);
91702
92311
  } catch {
91703
92312
  console.log("mink (unknown version)");
@@ -91719,7 +92328,7 @@ switch (command2) {
91719
92328
  console.log(" config [key] [value] Manage global user settings");
91720
92329
  console.log();
91721
92330
  console.log("Notes & Wiki:");
91722
- console.log(" wiki <cmd> Manage the notes/wiki vault (init|status|link|unlink|links|rebuild-index|organize)");
92331
+ console.log(" wiki <cmd> Manage the notes/wiki vault (init|status|link|unlink|links|rebuild-index|scan|organize)");
91723
92332
  console.log(' note "text" Capture a note to the vault');
91724
92333
  console.log(" note --daily [text] Create or append to today's daily note");
91725
92334
  console.log(" note list [filters] List notes (--category, --tag, --recent)");