@drewpayment/mink 0.12.0-beta.3 → 0.12.0-beta.5

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 (47) hide show
  1. package/dashboard/out/404.html +1 -1
  2. package/dashboard/out/action-log.html +1 -1
  3. package/dashboard/out/action-log.txt +1 -1
  4. package/dashboard/out/activity.html +1 -1
  5. package/dashboard/out/activity.txt +1 -1
  6. package/dashboard/out/bugs.html +1 -1
  7. package/dashboard/out/bugs.txt +1 -1
  8. package/dashboard/out/capture.html +1 -1
  9. package/dashboard/out/capture.txt +1 -1
  10. package/dashboard/out/config.html +1 -1
  11. package/dashboard/out/config.txt +1 -1
  12. package/dashboard/out/daemon.html +1 -1
  13. package/dashboard/out/daemon.txt +1 -1
  14. package/dashboard/out/design.html +1 -1
  15. package/dashboard/out/design.txt +1 -1
  16. package/dashboard/out/discord.html +1 -1
  17. package/dashboard/out/discord.txt +1 -1
  18. package/dashboard/out/file-index.html +1 -1
  19. package/dashboard/out/file-index.txt +1 -1
  20. package/dashboard/out/index.html +1 -1
  21. package/dashboard/out/index.txt +1 -1
  22. package/dashboard/out/insights.html +1 -1
  23. package/dashboard/out/insights.txt +1 -1
  24. package/dashboard/out/learning.html +1 -1
  25. package/dashboard/out/learning.txt +1 -1
  26. package/dashboard/out/overview.html +1 -1
  27. package/dashboard/out/overview.txt +1 -1
  28. package/dashboard/out/scheduler.html +1 -1
  29. package/dashboard/out/scheduler.txt +1 -1
  30. package/dashboard/out/sync.html +1 -1
  31. package/dashboard/out/sync.txt +1 -1
  32. package/dashboard/out/tokens.html +1 -1
  33. package/dashboard/out/tokens.txt +1 -1
  34. package/dashboard/out/waste.html +1 -1
  35. package/dashboard/out/waste.txt +1 -1
  36. package/dashboard/out/wiki.html +1 -1
  37. package/dashboard/out/wiki.txt +1 -1
  38. package/dist/cli.bun.js +139 -57
  39. package/dist/cli.node.js +139 -57
  40. package/package.json +1 -1
  41. package/src/commands/dashboard.ts +49 -3
  42. package/src/commands/post-read.ts +94 -9
  43. package/src/core/framework-advisor/generate.ts +11 -1
  44. package/src/core/note-linker.ts +12 -7
  45. package/src/types/hook-input.ts +10 -0
  46. /package/dashboard/out/_next/static/{qQncyEK2SSmDpJw1uhqt9 → eZlC6TEe7TWUABN2-Ho0J}/_buildManifest.js +0 -0
  47. /package/dashboard/out/_next/static/{qQncyEK2SSmDpJw1uhqt9 → eZlC6TEe7TWUABN2-Ho0J}/_ssgManifest.js +0 -0
package/dist/cli.node.js CHANGED
@@ -2681,15 +2681,8 @@ function addBacklink(targetNotePath, sourceTitle) {
2681
2681
  }
2682
2682
  }
2683
2683
  function updateMasterIndex(vaultRootPath) {
2684
- const now = new Date().toISOString().split("T")[0];
2685
2684
  const sections = [
2686
- `---`,
2687
- `updated: "${new Date().toISOString()}"`,
2688
- `---`,
2689
- ``,
2690
2685
  `# Knowledge Base`,
2691
- ``,
2692
- `> Last updated: ${now}`,
2693
2686
  ``
2694
2687
  ];
2695
2688
  const categories = [
@@ -2722,6 +2715,13 @@ function updateMasterIndex(vaultRootPath) {
2722
2715
  }
2723
2716
  sections.push("");
2724
2717
  }
2718
+ const nowIso = new Date().toISOString();
2719
+ const nowDate = nowIso.split("T")[0];
2720
+ sections.push(`---`);
2721
+ sections.push(``);
2722
+ sections.push(`<!-- mink:footer (volatile — keep at end of file) -->`);
2723
+ sections.push(`> Last updated: ${nowDate} (${nowIso})`);
2724
+ sections.push(``);
2725
2725
  const indexPath = vaultMasterIndexPath();
2726
2726
  atomicWriteText(indexPath, sections.join(`
2727
2727
  `));
@@ -7098,20 +7098,46 @@ var init_pre_read = __esm(() => {
7098
7098
  var exports_post_read = {};
7099
7099
  __export(exports_post_read, {
7100
7100
  postRead: () => postRead,
7101
+ extractContent: () => extractContent,
7101
7102
  analyzePostRead: () => analyzePostRead
7102
7103
  });
7103
7104
  import { relative as relative5 } from "path";
7105
+ import { readFileSync as readFileSync19 } from "fs";
7104
7106
  function analyzePostRead(filePath, content, index) {
7105
7107
  if (isBinaryFile(filePath, content ?? undefined)) {
7106
7108
  const entry = index ? index.lookupEntry(filePath) : null;
7107
- return { estimatedTokens: 0, indexHit: !!entry, source: "none" };
7109
+ return {
7110
+ estimatedTokens: 0,
7111
+ indexHit: !!entry,
7112
+ source: "none",
7113
+ indexEntry: null
7114
+ };
7108
7115
  }
7109
7116
  if (content !== null && content.length > 0) {
7110
7117
  const entry = index ? index.lookupEntry(filePath) : null;
7118
+ const tokens = estimateTokens2(content, filePath);
7119
+ let indexEntry = null;
7120
+ if (!entry) {
7121
+ let description = "";
7122
+ try {
7123
+ description = extractDescription(filePath, content);
7124
+ } catch {
7125
+ description = "";
7126
+ }
7127
+ const now = new Date().toISOString();
7128
+ indexEntry = {
7129
+ filePath,
7130
+ description,
7131
+ estimatedTokens: tokens,
7132
+ lastModified: now,
7133
+ lastIndexed: now
7134
+ };
7135
+ }
7111
7136
  return {
7112
- estimatedTokens: estimateTokens2(content, filePath),
7137
+ estimatedTokens: tokens,
7113
7138
  indexHit: !!entry,
7114
- source: "content"
7139
+ source: "content",
7140
+ indexEntry
7115
7141
  };
7116
7142
  }
7117
7143
  if (index) {
@@ -7120,11 +7146,17 @@ function analyzePostRead(filePath, content, index) {
7120
7146
  return {
7121
7147
  estimatedTokens: entry.estimatedTokens,
7122
7148
  indexHit: true,
7123
- source: "index-fallback"
7149
+ source: "index-fallback",
7150
+ indexEntry: null
7124
7151
  };
7125
7152
  }
7126
7153
  }
7127
- return { estimatedTokens: 0, indexHit: false, source: "none" };
7154
+ return {
7155
+ estimatedTokens: 0,
7156
+ indexHit: false,
7157
+ source: "none",
7158
+ indexEntry: null
7159
+ };
7128
7160
  }
7129
7161
  function isPostToolUseInput(value) {
7130
7162
  if (value === null || typeof value !== "object")
@@ -7137,9 +7169,22 @@ function isPostToolUseInput(value) {
7137
7169
  return true;
7138
7170
  }
7139
7171
  function extractContent(input) {
7140
- if (!input.tool_output)
7141
- return null;
7142
- if (typeof input.tool_output.content === "string") {
7172
+ const tr = input.tool_response;
7173
+ if (tr) {
7174
+ if (typeof tr.content === "string")
7175
+ return tr.content;
7176
+ if (Array.isArray(tr.content)) {
7177
+ const parts = tr.content.map((p) => p && typeof p.text === "string" ? p.text : "").filter((s) => s.length > 0);
7178
+ if (parts.length > 0)
7179
+ return parts.join("");
7180
+ }
7181
+ if (tr.file && typeof tr.file.content === "string") {
7182
+ return tr.file.content;
7183
+ }
7184
+ if (typeof tr.text === "string")
7185
+ return tr.text;
7186
+ }
7187
+ if (input.tool_output && typeof input.tool_output.content === "string") {
7143
7188
  return input.tool_output.content;
7144
7189
  }
7145
7190
  return null;
@@ -7159,8 +7204,19 @@ async function postRead(cwd) {
7159
7204
  const rawState = safeReadJson(sessionPath(cwd));
7160
7205
  const state = isSessionState(rawState) ? rawState : createSessionState();
7161
7206
  const repo = FileIndexRepo.for(cwd);
7162
- const content = extractContent(input);
7207
+ let content = null;
7208
+ try {
7209
+ content = readFileSync19(absolutePath, "utf-8");
7210
+ } catch {}
7211
+ if (content === null) {
7212
+ content = extractContent(input);
7213
+ }
7163
7214
  const result = analyzePostRead(filePath, content, repo);
7215
+ if (result.indexEntry) {
7216
+ try {
7217
+ repo.upsert(result.indexEntry);
7218
+ } catch {}
7219
+ }
7164
7220
  recordRead(state, filePath, result.estimatedTokens, result.indexHit);
7165
7221
  try {
7166
7222
  const logWriter = createActionLogWriter(actionLogShardPath(cwd, getOrCreateDeviceId()));
@@ -7177,6 +7233,7 @@ var init_post_read = __esm(() => {
7177
7233
  init_session();
7178
7234
  init_file_index_repo();
7179
7235
  init_token_estimate();
7236
+ init_description();
7180
7237
  init_action_log();
7181
7238
  init_device();
7182
7239
  });
@@ -7377,7 +7434,7 @@ __export(exports_post_write, {
7377
7434
  analyzePostWrite: () => analyzePostWrite
7378
7435
  });
7379
7436
  import { relative as relative7 } from "path";
7380
- import { readFileSync as readFileSync19 } from "fs";
7437
+ import { readFileSync as readFileSync20 } from "fs";
7381
7438
  function analyzePostWrite(filePath, fileContent, index) {
7382
7439
  if (isWriteExcluded(filePath)) {
7383
7440
  return {
@@ -7441,7 +7498,7 @@ async function postWrite(cwd) {
7441
7498
  const filePath = relative7(cwd, absolutePath);
7442
7499
  let fileContent = null;
7443
7500
  try {
7444
- fileContent = readFileSync19(absolutePath, "utf-8");
7501
+ fileContent = readFileSync20(absolutePath, "utf-8");
7445
7502
  } catch {}
7446
7503
  const rawState = safeReadJson(sessionPath(cwd));
7447
7504
  const state = isSessionState(rawState) ? rawState : createSessionState();
@@ -7794,7 +7851,7 @@ __export(exports_self_update, {
7794
7851
  PACKAGE_NAME: () => PACKAGE_NAME
7795
7852
  });
7796
7853
  import { spawnSync as spawnSync2 } from "child_process";
7797
- import { existsSync as existsSync26, readFileSync as readFileSync20 } from "fs";
7854
+ import { existsSync as existsSync26, readFileSync as readFileSync21 } from "fs";
7798
7855
  import { dirname as dirname11 } from "path";
7799
7856
  import { join as join23 } from "path";
7800
7857
  function parseSemver(input) {
@@ -7861,7 +7918,7 @@ function getInstallInfo() {
7861
7918
  }
7862
7919
  let currentVersion = "0.0.0";
7863
7920
  try {
7864
- const pkg = JSON.parse(readFileSync20(packageJsonPath, "utf-8"));
7921
+ const pkg = JSON.parse(readFileSync21(packageJsonPath, "utf-8"));
7865
7922
  if (typeof pkg.version === "string")
7866
7923
  currentVersion = pkg.version;
7867
7924
  } catch {}
@@ -7934,7 +7991,7 @@ function appendLogEntry(entry) {
7934
7991
  }
7935
7992
  function rotateLogIfNeeded(path) {
7936
7993
  try {
7937
- const content = readFileSync20(path, "utf-8");
7994
+ const content = readFileSync21(path, "utf-8");
7938
7995
  const lines = content.split(`
7939
7996
  `);
7940
7997
  if (lines.length <= LOG_MAX_LINES + 1)
@@ -8037,7 +8094,7 @@ async function runSelfUpgradeInner(opts) {
8037
8094
  }
8038
8095
  let verifiedVersion = latest;
8039
8096
  try {
8040
- const pkg = JSON.parse(readFileSync20(info.packageJsonPath, "utf-8"));
8097
+ const pkg = JSON.parse(readFileSync21(info.packageJsonPath, "utf-8"));
8041
8098
  if (typeof pkg.version === "string")
8042
8099
  verifiedVersion = pkg.version;
8043
8100
  } catch {}
@@ -8143,10 +8200,10 @@ async function executeTask(taskId, projectCwd) {
8143
8200
  if (task.actionType === "ai-cli") {
8144
8201
  try {
8145
8202
  const { learningMemoryPath: learningMemoryPath5 } = await Promise.resolve().then(() => (init_paths(), exports_paths));
8146
- const { readFileSync: readFileSync21 } = await import("fs");
8203
+ const { readFileSync: readFileSync22 } = await import("fs");
8147
8204
  let memoryContent;
8148
8205
  try {
8149
- memoryContent = readFileSync21(learningMemoryPath5(projectCwd), "utf-8");
8206
+ memoryContent = readFileSync22(learningMemoryPath5(projectCwd), "utf-8");
8150
8207
  } catch {
8151
8208
  console.log("[mink] no learning memory found, skipping reflection");
8152
8209
  return;
@@ -8711,7 +8768,7 @@ var init_cron = __esm(() => {
8711
8768
 
8712
8769
  // src/core/vault-templates.ts
8713
8770
  import { join as join24 } from "path";
8714
- import { existsSync as existsSync27, writeFileSync as writeFileSync9, readFileSync as readFileSync21, mkdirSync as mkdirSync13 } from "fs";
8771
+ import { existsSync as existsSync27, writeFileSync as writeFileSync9, readFileSync as readFileSync22, mkdirSync as mkdirSync13 } from "fs";
8715
8772
  function seedTemplates(templatesDir) {
8716
8773
  mkdirSync13(templatesDir, { recursive: true });
8717
8774
  for (const [name, content] of Object.entries(DEFAULT_TEMPLATES)) {
@@ -8725,7 +8782,7 @@ function loadTemplate(templatesDir, templateName, vars) {
8725
8782
  const filePath = join24(templatesDir, `${templateName}.md`);
8726
8783
  let content;
8727
8784
  if (existsSync27(filePath)) {
8728
- content = readFileSync21(filePath, "utf-8");
8785
+ content = readFileSync22(filePath, "utf-8");
8729
8786
  } else if (DEFAULT_TEMPLATES[templateName]) {
8730
8787
  content = DEFAULT_TEMPLATES[templateName];
8731
8788
  } else {
@@ -8879,7 +8936,7 @@ category: resources
8879
8936
 
8880
8937
  // src/core/note-writer.ts
8881
8938
  import { join as join25 } from "path";
8882
- import { existsSync as existsSync28, readFileSync as readFileSync22 } from "fs";
8939
+ import { existsSync as existsSync28, readFileSync as readFileSync23 } from "fs";
8883
8940
  import { createHash as createHash4 } from "crypto";
8884
8941
  function sha256(content) {
8885
8942
  return createHash4("sha256").update(content).digest("hex");
@@ -8904,7 +8961,7 @@ function resolveUniqueNotePath(dir, baseSlug, content) {
8904
8961
  }
8905
8962
  function sameContent(filePath, expectedHash) {
8906
8963
  try {
8907
- return sha256(readFileSync22(filePath, "utf-8")) === expectedHash;
8964
+ return sha256(readFileSync23(filePath, "utf-8")) === expectedHash;
8908
8965
  } catch {
8909
8966
  return false;
8910
8967
  }
@@ -9013,7 +9070,7 @@ ${content}
9013
9070
  return filePath;
9014
9071
  }
9015
9072
  function ingestFile(sourcePath, meta) {
9016
- const raw = readFileSync22(sourcePath, "utf-8");
9073
+ const raw = readFileSync23(sourcePath, "utf-8");
9017
9074
  const now = new Date().toISOString();
9018
9075
  const headingMatch = raw.match(/^#\s+(.+)$/m);
9019
9076
  const title = headingMatch?.[1] ?? sourcePath.split("/").pop().replace(/\.md$/, "");
@@ -9085,7 +9142,7 @@ var init_design_eval = __esm(() => {
9085
9142
  });
9086
9143
 
9087
9144
  // src/core/dashboard-api.ts
9088
- import { existsSync as existsSync29, readFileSync as readFileSync23 } from "fs";
9145
+ import { existsSync as existsSync29, readFileSync as readFileSync24 } from "fs";
9089
9146
  import { readdirSync as readdirSync9, readFileSync as readFileSyncFS, existsSync as fsExistsSync } from "fs";
9090
9147
  import { join as join26, resolve as resolve5, normalize, sep } from "path";
9091
9148
  import { execSync as execSync6 } from "child_process";
@@ -9113,7 +9170,7 @@ function checkTextFile2(name, filePath) {
9113
9170
  if (!existsSync29(filePath))
9114
9171
  return { name, status: "missing" };
9115
9172
  try {
9116
- readFileSync23(filePath, "utf-8");
9173
+ readFileSync24(filePath, "utf-8");
9117
9174
  return { name, status: "ok" };
9118
9175
  } catch {
9119
9176
  return { name, status: "corrupt" };
@@ -9123,7 +9180,7 @@ function checkDbFile2(name, filePath) {
9123
9180
  if (!existsSync29(filePath))
9124
9181
  return { name, status: "missing" };
9125
9182
  try {
9126
- const header = readFileSync23(filePath).slice(0, 16).toString("utf-8");
9183
+ const header = readFileSync24(filePath).slice(0, 16).toString("utf-8");
9127
9184
  return header.startsWith("SQLite format 3") ? { name, status: "ok" } : { name, status: "corrupt" };
9128
9185
  } catch {
9129
9186
  return { name, status: "corrupt" };
@@ -10497,25 +10554,45 @@ var init_dashboard_server = __esm(() => {
10497
10554
  // src/commands/dashboard.ts
10498
10555
  var exports_dashboard = {};
10499
10556
  __export(exports_dashboard, {
10557
+ resolveStartupCwd: () => resolveStartupCwd,
10500
10558
  dashboard: () => dashboard
10501
10559
  });
10502
10560
  import { existsSync as existsSync31 } from "fs";
10561
+ function resolveStartupCwd(cwd, registered = listRegisteredProjects()) {
10562
+ if (existsSync31(projectDir(cwd))) {
10563
+ return { kind: "active", cwd };
10564
+ }
10565
+ if (registered.length === 0) {
10566
+ return { kind: "none" };
10567
+ }
10568
+ const fallback = [...registered].sort((a, b) => a.name.localeCompare(b.name))[0];
10569
+ return { kind: "fallback", cwd: fallback.cwd, project: fallback };
10570
+ }
10503
10571
  async function dashboard(cwd, args) {
10504
- if (!existsSync31(projectDir(cwd))) {
10505
- console.error("[mink] project not initialized. Run: mink init");
10572
+ const resolution = resolveStartupCwd(cwd);
10573
+ if (resolution.kind === "none") {
10574
+ console.error("[mink] no mink projects found. Run `mink init` in a project first.");
10506
10575
  process.exit(1);
10507
10576
  }
10577
+ if (resolution.kind === "fallback") {
10578
+ console.log(`[mink] not in a mink project — starting dashboard with "${resolution.project.name}". ` + "Use the in-app project switcher to change projects.");
10579
+ }
10580
+ const startupCwd = resolution.cwd;
10508
10581
  const portArg = args.find((a) => a.startsWith("--port="));
10509
10582
  const port = portArg ? parseInt(portArg.split("=")[1], 10) : 4040;
10510
10583
  const noOpen = args.includes("--no-open");
10511
10584
  const { startDashboardServer: startDashboardServer2 } = await Promise.resolve().then(() => (init_dashboard_server(), exports_dashboard_server));
10512
- const { url } = await startDashboardServer2(cwd, { port, open: !noOpen });
10585
+ const { url } = await startDashboardServer2(startupCwd, {
10586
+ port,
10587
+ open: !noOpen
10588
+ });
10513
10589
  console.log(`[mink] dashboard running at ${url}`);
10514
10590
  console.log("[mink] press Ctrl+C to stop");
10515
10591
  await new Promise(() => {});
10516
10592
  }
10517
10593
  var init_dashboard = __esm(() => {
10518
10594
  init_paths();
10595
+ init_project_registry();
10519
10596
  });
10520
10597
 
10521
10598
  // src/commands/init.ts
@@ -10765,7 +10842,7 @@ var exports_daemon = {};
10765
10842
  __export(exports_daemon, {
10766
10843
  daemon: () => daemon
10767
10844
  });
10768
- import { readFileSync as readFileSync24, existsSync as existsSync34 } from "fs";
10845
+ import { readFileSync as readFileSync25, existsSync as existsSync34 } from "fs";
10769
10846
  async function daemon(cwd, args) {
10770
10847
  const subcommand = args[0];
10771
10848
  switch (subcommand) {
@@ -10786,7 +10863,7 @@ async function daemon(cwd, args) {
10786
10863
  return;
10787
10864
  }
10788
10865
  try {
10789
- const content = readFileSync24(logPath, "utf-8");
10866
+ const content = readFileSync25(logPath, "utf-8");
10790
10867
  const lines = content.split(`
10791
10868
  `);
10792
10869
  const tail = lines.slice(-50).join(`
@@ -11367,7 +11444,7 @@ var init_restore = __esm(() => {
11367
11444
  });
11368
11445
 
11369
11446
  // src/core/design-eval/server-detect.ts
11370
- import { readFileSync as readFileSync25 } from "fs";
11447
+ import { readFileSync as readFileSync26 } from "fs";
11371
11448
  import { join as join30 } from "path";
11372
11449
  async function probePort(port) {
11373
11450
  try {
@@ -11390,7 +11467,7 @@ async function findRunningServer(ports = DEFAULT_PROBE_PORTS) {
11390
11467
  }
11391
11468
  function detectDevCommand(cwd) {
11392
11469
  try {
11393
- const raw = readFileSync25(join30(cwd, "package.json"), "utf-8");
11470
+ const raw = readFileSync26(join30(cwd, "package.json"), "utf-8");
11394
11471
  const pkg = JSON.parse(raw);
11395
11472
  const scripts = pkg.scripts;
11396
11473
  if (!scripts || typeof scripts !== "object")
@@ -83759,7 +83836,7 @@ var init_fileUtil = __esm(() => {
83759
83836
  // node_modules/@puppeteer/browsers/lib/esm/install.js
83760
83837
  import assert2 from "node:assert";
83761
83838
  import { spawnSync as spawnSync4 } from "node:child_process";
83762
- import { existsSync as existsSync36, readFileSync as readFileSync26 } from "node:fs";
83839
+ import { existsSync as existsSync36, readFileSync as readFileSync27 } from "node:fs";
83763
83840
  import { mkdir as mkdir2, unlink } from "node:fs/promises";
83764
83841
  import os5 from "node:os";
83765
83842
  import path8 from "node:path";
@@ -83849,7 +83926,7 @@ async function installDeps(installedBrowser) {
83849
83926
  debugInstall(`deb.deps file was not found at ${depsPath}`);
83850
83927
  return;
83851
83928
  }
83852
- const data = readFileSync26(depsPath, "utf-8").split(`
83929
+ const data = readFileSync27(depsPath, "utf-8").split(`
83853
83930
  `).join(",");
83854
83931
  if (process.getuid?.() !== 0) {
83855
83932
  throw new Error("Installing system dependencies requires root privileges");
@@ -85374,14 +85451,14 @@ var init_yerror = __esm(() => {
85374
85451
  });
85375
85452
 
85376
85453
  // node_modules/y18n/build/lib/platform-shims/node.js
85377
- import { readFileSync as readFileSync27, statSync as statSync14, writeFile } from "fs";
85454
+ import { readFileSync as readFileSync28, statSync as statSync14, writeFile } from "fs";
85378
85455
  import { format as format2 } from "util";
85379
85456
  import { resolve as resolve12 } from "path";
85380
85457
  var node_default;
85381
85458
  var init_node = __esm(() => {
85382
85459
  node_default = {
85383
85460
  fs: {
85384
- readFileSync: readFileSync27,
85461
+ readFileSync: readFileSync28,
85385
85462
  writeFile
85386
85463
  },
85387
85464
  format: format2,
@@ -85566,7 +85643,7 @@ var init_y18n = __esm(() => {
85566
85643
  // node_modules/yargs/lib/platform-shims/esm.mjs
85567
85644
  import { notStrictEqual, strictEqual } from "assert";
85568
85645
  import { inspect } from "util";
85569
- import { readFileSync as readFileSync28 } from "fs";
85646
+ import { readFileSync as readFileSync29 } from "fs";
85570
85647
  import { fileURLToPath } from "url";
85571
85648
  import { basename as basename9, dirname as dirname16, extname as extname3, relative as relative9, resolve as resolve13 } from "path";
85572
85649
  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;
@@ -85615,7 +85692,7 @@ var init_esm = __esm(() => {
85615
85692
  nextTick: process.nextTick,
85616
85693
  stdColumns: typeof process.stdout.columns !== "undefined" ? process.stdout.columns : null
85617
85694
  },
85618
- readFileSync: readFileSync28,
85695
+ readFileSync: readFileSync29,
85619
85696
  require: () => {
85620
85697
  throw new YError(REQUIRE_ERROR);
85621
85698
  },
@@ -91874,7 +91951,7 @@ function generateKnowledgeMarkdown(k) {
91874
91951
  const parts = [];
91875
91952
  parts.push(`# Framework Advisor Knowledge Base`);
91876
91953
  parts.push("");
91877
- parts.push(`> Generated: ${k.generatedAt} | Version: ${k.version} | Frameworks: ${k.frameworks.length}`);
91954
+ parts.push(`> Version: ${k.version} | Frameworks: ${k.frameworks.length}`);
91878
91955
  parts.push("");
91879
91956
  parts.push("## Comparison Matrix");
91880
91957
  parts.push("");
@@ -91930,6 +92007,11 @@ function generateKnowledgeMarkdown(k) {
91930
92007
  parts.push("");
91931
92008
  }
91932
92009
  }
92010
+ parts.push(`---`);
92011
+ parts.push(``);
92012
+ parts.push(`<!-- mink:footer (volatile — keep at end of file) -->`);
92013
+ parts.push(`> Generated: ${k.generatedAt}`);
92014
+ parts.push(``);
91933
92015
  return parts.join(`
91934
92016
  `);
91935
92017
  }
@@ -92405,7 +92487,7 @@ __export(exports_note, {
92405
92487
  note: () => note
92406
92488
  });
92407
92489
  import { resolve as resolve15 } from "path";
92408
- import { existsSync as existsSync40, readFileSync as readFileSync29 } from "fs";
92490
+ import { existsSync as existsSync40, readFileSync as readFileSync30 } from "fs";
92409
92491
  async function note(cwd, args) {
92410
92492
  if (!isWikiEnabled()) {
92411
92493
  console.error("[mink] wiki feature is disabled");
@@ -92430,7 +92512,7 @@ async function note(cwd, args) {
92430
92512
  const date = new Date().toISOString().split("T")[0];
92431
92513
  const content = parsed.positional || parsed.body || "";
92432
92514
  const filePath = appendToDaily(date, content);
92433
- updateVaultIndexForFile(filePath, readFileSync29(filePath, "utf-8"));
92515
+ updateVaultIndexForFile(filePath, readFileSync30(filePath, "utf-8"));
92434
92516
  console.log(`[mink] daily note: ${filePath}`);
92435
92517
  return;
92436
92518
  }
@@ -92763,7 +92845,7 @@ import { homedir as homedir7 } from "os";
92763
92845
  import {
92764
92846
  existsSync as existsSync42,
92765
92847
  mkdirSync as mkdirSync18,
92766
- readFileSync as readFileSync30,
92848
+ readFileSync as readFileSync31,
92767
92849
  writeFileSync as writeFileSync11
92768
92850
  } from "fs";
92769
92851
  import { createHash as createHash5 } from "crypto";
@@ -92787,7 +92869,7 @@ function getMinkVersion() {
92787
92869
  const pkgPath = join36(dir, "package.json");
92788
92870
  if (existsSync42(pkgPath)) {
92789
92871
  try {
92790
- const pkg = JSON.parse(readFileSync30(pkgPath, "utf-8"));
92872
+ const pkg = JSON.parse(readFileSync31(pkgPath, "utf-8"));
92791
92873
  if (pkg.name && pkg.version)
92792
92874
  return pkg.version;
92793
92875
  } catch {}
@@ -92825,7 +92907,7 @@ function installAgentDefinition(opts) {
92825
92907
  if (opts.skip && existsSync42(installed)) {
92826
92908
  return { action: "skipped", path: installed };
92827
92909
  }
92828
- const template = readFileSync30(templatePath, "utf-8");
92910
+ const template = readFileSync31(templatePath, "utf-8");
92829
92911
  const rendered = renderTemplate(template, {
92830
92912
  MINK_ROOT: minkRoot(),
92831
92913
  VAULT_PATH: resolveVaultPath(),
@@ -92833,7 +92915,7 @@ function installAgentDefinition(opts) {
92833
92915
  });
92834
92916
  const exists = existsSync42(installed);
92835
92917
  if (!opts.force && exists) {
92836
- const current = readFileSync30(installed, "utf-8");
92918
+ const current = readFileSync31(installed, "utf-8");
92837
92919
  if (sha2562(current) === sha2562(rendered)) {
92838
92920
  return { action: "unchanged", path: installed };
92839
92921
  }
@@ -92961,7 +93043,7 @@ var init_agent = __esm(() => {
92961
93043
  });
92962
93044
 
92963
93045
  // src/core/sync-merge-drivers.ts
92964
- import { readFileSync as readFileSync31, writeFileSync as writeFileSync12, appendFileSync as appendFileSync2, copyFileSync as copyFileSync2, unlinkSync as unlinkSync7 } from "fs";
93046
+ import { readFileSync as readFileSync32, writeFileSync as writeFileSync12, appendFileSync as appendFileSync2, copyFileSync as copyFileSync2, unlinkSync as unlinkSync7 } from "fs";
92965
93047
  import { join as join37 } from "path";
92966
93048
  function logWarning(driver, args, err) {
92967
93049
  try {
@@ -92972,14 +93054,14 @@ function logWarning(driver, args, err) {
92972
93054
  }
92973
93055
  function readJsonOrNull(path12) {
92974
93056
  try {
92975
- return JSON.parse(readFileSync31(path12, "utf-8"));
93057
+ return JSON.parse(readFileSync32(path12, "utf-8"));
92976
93058
  } catch {
92977
93059
  return null;
92978
93060
  }
92979
93061
  }
92980
93062
  function readTextOrEmpty(path12) {
92981
93063
  try {
92982
- return readFileSync31(path12, "utf-8");
93064
+ return readFileSync32(path12, "utf-8");
92983
93065
  } catch {
92984
93066
  return "";
92985
93067
  }
@@ -93869,9 +93951,9 @@ switch (command2) {
93869
93951
  const { resolve: resolve18, dirname: dirname20, basename: basename10 } = await import("path");
93870
93952
  const bundlePath = new URL(import.meta.url).pathname;
93871
93953
  const cliPath = resolve18(dirname20(bundlePath));
93872
- const { readFileSync: readFileSync32 } = await import("fs");
93954
+ const { readFileSync: readFileSync33 } = await import("fs");
93873
93955
  try {
93874
- const pkg = JSON.parse(readFileSync32(resolve18(cliPath, "../package.json"), "utf-8"));
93956
+ const pkg = JSON.parse(readFileSync33(resolve18(cliPath, "../package.json"), "utf-8"));
93875
93957
  console.log(`mink ${pkg.version}`);
93876
93958
  } catch {
93877
93959
  console.log("mink (unknown version)");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drewpayment/mink",
3
- "version": "0.12.0-beta.3",
3
+ "version": "0.12.0-beta.5",
4
4
  "description": "A hidden presence that moves alongside the developer — token efficiency and cross-project wiki for AI coding assistants",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,18 +1,64 @@
1
1
  import { existsSync } from "fs";
2
2
  import { projectDir } from "../core/paths";
3
+ import {
4
+ listRegisteredProjects,
5
+ type RegisteredProject,
6
+ } from "../core/project-registry";
7
+
8
+ export type StartupResolution =
9
+ | { kind: "active"; cwd: string }
10
+ | { kind: "fallback"; cwd: string; project: RegisteredProject }
11
+ | { kind: "none" };
12
+
13
+ /**
14
+ * Resolve which project's cwd to hand to the dashboard server at startup.
15
+ *
16
+ * The dashboard UI has an in-app project switcher, so `mink dashboard` does
17
+ * not need to be launched from inside an active mink project. When the cwd
18
+ * is not an initialized project, fall back to any registered project — the
19
+ * user can switch from there.
20
+ */
21
+ export function resolveStartupCwd(
22
+ cwd: string,
23
+ registered: RegisteredProject[] = listRegisteredProjects(),
24
+ ): StartupResolution {
25
+ if (existsSync(projectDir(cwd))) {
26
+ return { kind: "active", cwd };
27
+ }
28
+ if (registered.length === 0) {
29
+ return { kind: "none" };
30
+ }
31
+ const fallback = [...registered].sort((a, b) =>
32
+ a.name.localeCompare(b.name),
33
+ )[0];
34
+ return { kind: "fallback", cwd: fallback.cwd, project: fallback };
35
+ }
3
36
 
4
37
  export async function dashboard(cwd: string, args: string[]): Promise<void> {
5
- if (!existsSync(projectDir(cwd))) {
6
- console.error("[mink] project not initialized. Run: mink init");
38
+ const resolution = resolveStartupCwd(cwd);
39
+ if (resolution.kind === "none") {
40
+ console.error(
41
+ "[mink] no mink projects found. Run `mink init` in a project first.",
42
+ );
7
43
  process.exit(1);
8
44
  }
45
+ if (resolution.kind === "fallback") {
46
+ console.log(
47
+ `[mink] not in a mink project — starting dashboard with "${resolution.project.name}". ` +
48
+ "Use the in-app project switcher to change projects.",
49
+ );
50
+ }
51
+ const startupCwd = resolution.cwd;
9
52
 
10
53
  const portArg = args.find((a) => a.startsWith("--port="));
11
54
  const port = portArg ? parseInt(portArg.split("=")[1], 10) : 4040;
12
55
  const noOpen = args.includes("--no-open");
13
56
 
14
57
  const { startDashboardServer } = await import("../core/dashboard-server");
15
- const { url } = await startDashboardServer(cwd, { port, open: !noOpen });
58
+ const { url } = await startDashboardServer(startupCwd, {
59
+ port,
60
+ open: !noOpen,
61
+ });
16
62
 
17
63
  console.log(`[mink] dashboard running at ${url}`);
18
64
  console.log("[mink] press Ctrl+C to stop");