@drewpayment/mink 0.10.0 → 0.10.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 (48) 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 +102 -31
  40. package/package.json +1 -1
  41. package/src/cli.ts +1 -1
  42. package/src/commands/scan.ts +29 -6
  43. package/src/commands/wiki.ts +19 -3
  44. package/src/core/note-index.ts +50 -1
  45. package/src/core/scanner.ts +19 -3
  46. package/src/types/note.ts +1 -0
  47. /package/dashboard/out/_next/static/{frTrvF6NV-Xl2bLk21NkY → e0QWU9rPMeSlJJLTwij89}/_buildManifest.js +0 -0
  48. /package/dashboard/out/_next/static/{frTrvF6NV-Xl2bLk21NkY → e0QWU9rPMeSlJJLTwij89}/_ssgManifest.js +0 -0
@@ -1,8 +1,13 @@
1
1
  import { readFileSync } from "fs";
2
- import { join } from "path";
2
+ import { join, relative } from "path";
3
3
  import { fileIndexPath, configPath } from "../core/paths";
4
4
  import { atomicWriteJson, safeReadJson } from "../core/fs-utils";
5
- import { scanProject, loadConfig, getExcludes } from "../core/scanner";
5
+ import {
6
+ scanProject,
7
+ scanProjectWithStats,
8
+ loadConfig,
9
+ getExcludes,
10
+ } from "../core/scanner";
6
11
  import { extractDescription } from "../core/description";
7
12
  import { estimateTokens } from "../core/token-estimate";
8
13
  import {
@@ -13,6 +18,11 @@ import {
13
18
  } from "../core/index-store";
14
19
  import type { FileIndex, FileIndexEntry } from "../types/file-index";
15
20
 
21
+ function configRelativePath(cfgPath: string, cwd: string): string {
22
+ const rel = relative(cwd, cfgPath);
23
+ return rel.startsWith("..") ? cfgPath : rel;
24
+ }
25
+
16
26
  function loadExistingIndex(indexPath: string): FileIndex {
17
27
  const raw = safeReadJson(indexPath);
18
28
  if (isFileIndex(raw)) return raw;
@@ -64,7 +74,8 @@ export function scan(cwd: string, options: { check: boolean }): void {
64
74
  const start = Date.now();
65
75
  const index = loadExistingIndex(idxPath);
66
76
 
67
- const scanned = scanProject(cwd, excludes, maxFiles);
77
+ const stats = scanProjectWithStats(cwd, excludes, maxFiles);
78
+ const scanned = stats.files;
68
79
 
69
80
  // Build new entries, preserving lifetime counters
70
81
  const newIndex = createEmptyIndex();
@@ -95,7 +106,19 @@ export function scan(cwd: string, options: { check: boolean }): void {
95
106
  atomicWriteJson(idxPath, newIndex);
96
107
 
97
108
  const elapsed = Date.now() - start;
98
- console.log(
99
- `[mink] indexed ${newIndex.header.totalFiles} files in ${elapsed}ms`
100
- );
109
+ if (stats.truncated > 0) {
110
+ console.log(
111
+ `[mink] scanned ${stats.totalScanned} files; indexed ${newIndex.header.totalFiles} most recent in ${elapsed}ms`
112
+ );
113
+ console.log(
114
+ ` ${stats.truncated} files past maxFiles=${maxFiles} were not indexed`
115
+ );
116
+ console.log(
117
+ ` raise the cap by setting "maxFiles" in ${configRelativePath(cfgPath, cwd)}`
118
+ );
119
+ } else {
120
+ console.log(
121
+ `[mink] indexed ${newIndex.header.totalFiles} files in ${elapsed}ms`
122
+ );
123
+ }
101
124
  }
@@ -14,7 +14,11 @@ import {
14
14
  import { atomicWriteJson } from "../core/fs-utils";
15
15
  import { setConfigValue } from "../core/global-config";
16
16
  import { seedTemplates } from "../core/vault-templates";
17
- import { rebuildVaultIndex, loadVaultIndex } from "../core/note-index";
17
+ import {
18
+ rebuildVaultIndex,
19
+ loadVaultIndex,
20
+ vaultIndexStaleness,
21
+ } from "../core/note-index";
18
22
  import { updateMasterIndex } from "../core/note-linker";
19
23
  import type { VaultManifest, NoteCategory } from "../types/note";
20
24
 
@@ -32,6 +36,7 @@ export async function wiki(
32
36
  wikiStatus();
33
37
  break;
34
38
  case "rebuild-index":
39
+ case "scan":
35
40
  wikiRebuildIndex();
36
41
  break;
37
42
  case "organize":
@@ -51,7 +56,8 @@ export async function wiki(
51
56
  console.log();
52
57
  console.log(" init Initialize the notes/wiki vault");
53
58
  console.log(" status Show vault statistics");
54
- console.log(" rebuild-index Full rescan and reindex of vault");
59
+ console.log(" rebuild-index Full rescan and reindex of vault (alias: scan)");
60
+ console.log(" scan Alias for rebuild-index");
55
61
  console.log(" organize List inbox notes needing categorization");
56
62
  console.log(" link <path> [name] Symlink external notes into the vault");
57
63
  console.log(" unlink <name> Remove a symlinked directory from the vault");
@@ -174,6 +180,13 @@ function wikiStatus(): void {
174
180
  }
175
181
 
176
182
  const vaultPath = resolveVaultPath();
183
+ const staleness = vaultIndexStaleness();
184
+ if (staleness.isStale) {
185
+ console.log(
186
+ `[mink] vault index is stale (${staleness.reason}) — rebuilding...`
187
+ );
188
+ rebuildVaultIndex();
189
+ }
177
190
  const index = loadVaultIndex();
178
191
 
179
192
  const categoryCounts: Record<string, number> = {
@@ -200,7 +213,10 @@ function wikiStatus(): void {
200
213
  }
201
214
  console.log();
202
215
  console.log(
203
- ` last indexed: ${index.lastScanTimestamp || "never"}`
216
+ ` last full scan: ${index.lastFullScanTimestamp || "never"}`
217
+ );
218
+ console.log(
219
+ ` last update: ${index.lastScanTimestamp || "never"}`
204
220
  );
205
221
 
206
222
  const links = listLinks();
@@ -7,6 +7,7 @@ import type { VaultIndex, VaultIndexEntry, NoteCategory } from "../types/note";
7
7
  export function createEmptyVaultIndex(): VaultIndex {
8
8
  return {
9
9
  lastScanTimestamp: "",
10
+ lastFullScanTimestamp: "",
10
11
  totalNotes: 0,
11
12
  entries: {},
12
13
  };
@@ -182,7 +183,9 @@ export function rebuildVaultIndex(): VaultIndex {
182
183
  }
183
184
  }
184
185
 
185
- index.lastScanTimestamp = new Date().toISOString();
186
+ const now = new Date().toISOString();
187
+ index.lastScanTimestamp = now;
188
+ index.lastFullScanTimestamp = now;
186
189
  saveVaultIndex(index);
187
190
  return index;
188
191
  }
@@ -219,6 +222,52 @@ export function getRecentNotes(n: number): VaultIndexEntry[] {
219
222
  .slice(0, n);
220
223
  }
221
224
 
225
+ export interface VaultStaleness {
226
+ isStale: boolean;
227
+ reason: string | null;
228
+ diskCount: number;
229
+ indexCount: number;
230
+ lastFullScan: string | null;
231
+ }
232
+
233
+ export function vaultIndexStaleness(): VaultStaleness {
234
+ const index = loadVaultIndex();
235
+ const root = resolveVaultPath();
236
+ const diskCount = collectAllMarkdown(root).length;
237
+ const indexCount = Object.keys(index.entries).length;
238
+ const lastFullScan = index.lastFullScanTimestamp || null;
239
+
240
+ if (!lastFullScan) {
241
+ return {
242
+ isStale: true,
243
+ reason: "no full scan on record",
244
+ diskCount,
245
+ indexCount,
246
+ lastFullScan: null,
247
+ };
248
+ }
249
+
250
+ const delta = Math.abs(diskCount - indexCount);
251
+ const threshold = Math.max(5, Math.floor(diskCount * 0.05));
252
+ if (delta >= threshold) {
253
+ return {
254
+ isStale: true,
255
+ reason: `${diskCount} files on disk but ${indexCount} in index`,
256
+ diskCount,
257
+ indexCount,
258
+ lastFullScan,
259
+ };
260
+ }
261
+
262
+ return {
263
+ isStale: false,
264
+ reason: null,
265
+ diskCount,
266
+ indexCount,
267
+ lastFullScan,
268
+ };
269
+ }
270
+
222
271
  interface ScannedMarkdown {
223
272
  absolutePath: string;
224
273
  relativePath: string;
@@ -87,13 +87,29 @@ export function getExcludes(config: ProjectConfig): string[] {
87
87
  return [...DEFAULT_EXCLUDES, ...(config.excludePatterns ?? [])];
88
88
  }
89
89
 
90
- export function scanProject(
90
+ export interface ScanStats {
91
+ files: ScannedFile[];
92
+ totalScanned: number;
93
+ truncated: number;
94
+ }
95
+
96
+ export function scanProjectWithStats(
91
97
  projectRoot: string,
92
98
  excludes: string[],
93
99
  maxFiles: number = DEFAULT_MAX_FILES
94
- ): ScannedFile[] {
100
+ ): ScanStats {
95
101
  const results: ScannedFile[] = [];
96
102
  walkDirectory(projectRoot, projectRoot, excludes, results);
97
103
  results.sort((a, b) => b.mtimeMs - a.mtimeMs);
98
- return results.slice(0, maxFiles);
104
+ const totalScanned = results.length;
105
+ const files = results.slice(0, maxFiles);
106
+ return { files, totalScanned, truncated: totalScanned - files.length };
107
+ }
108
+
109
+ export function scanProject(
110
+ projectRoot: string,
111
+ excludes: string[],
112
+ maxFiles: number = DEFAULT_MAX_FILES
113
+ ): ScannedFile[] {
114
+ return scanProjectWithStats(projectRoot, excludes, maxFiles).files;
99
115
  }
package/src/types/note.ts CHANGED
@@ -62,6 +62,7 @@ export interface VaultIndexEntry {
62
62
 
63
63
  export interface VaultIndex {
64
64
  lastScanTimestamp: string;
65
+ lastFullScanTimestamp?: string;
65
66
  totalNotes: number;
66
67
  entries: Record<string, VaultIndexEntry>;
67
68
  }