@theglitchking/semantic-memory 1.5.1 → 1.5.3

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 (75) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +43 -0
  4. package/README.md +4 -0
  5. package/dist/{chunk-25EIQWXL.js → chunk-44BQDRXD.js} +5 -5
  6. package/dist/chunk-44BQDRXD.js.map +1 -0
  7. package/dist/{chunk-2EELGTLX.js → chunk-D5QLNNA4.js} +2 -2
  8. package/dist/{chunk-A3KYHKB5.js → chunk-FTRXH2WC.js} +8 -4
  9. package/dist/chunk-FTRXH2WC.js.map +1 -0
  10. package/dist/{chunk-OWZWMB4P.js → chunk-FURCIJBO.js} +1 -1
  11. package/dist/chunk-FURCIJBO.js.map +1 -0
  12. package/dist/{chunk-V45NJIHI.js → chunk-IGHCVAAL.js} +19 -4
  13. package/dist/chunk-IGHCVAAL.js.map +1 -0
  14. package/dist/{chunk-S4KW7VH4.js → chunk-LGQPP5FQ.js} +8 -3
  15. package/dist/chunk-LGQPP5FQ.js.map +1 -0
  16. package/dist/{chunk-NTYYS53O.js → chunk-NBY4TRP7.js} +7 -3
  17. package/dist/chunk-NBY4TRP7.js.map +1 -0
  18. package/dist/chunk-OEF5U5GV.js +175 -0
  19. package/dist/chunk-OEF5U5GV.js.map +1 -0
  20. package/dist/{chunk-FM26NFTR.js → chunk-OFXQXVG5.js} +26 -12
  21. package/dist/chunk-OFXQXVG5.js.map +1 -0
  22. package/dist/{chunk-CSXZ7QUU.js → chunk-ROKSUJFM.js} +27 -17
  23. package/dist/chunk-ROKSUJFM.js.map +1 -0
  24. package/dist/{chunk-JPQHNG3R.js → chunk-SX427M2R.js} +10 -4
  25. package/dist/chunk-SX427M2R.js.map +1 -0
  26. package/dist/{chunk-7M3JZOYH.js → chunk-WZEKIUYG.js} +8 -4
  27. package/dist/chunk-WZEKIUYG.js.map +1 -0
  28. package/dist/{chunk-WSU4QIPB.js → chunk-XAXK7NM4.js} +14 -8
  29. package/dist/chunk-XAXK7NM4.js.map +1 -0
  30. package/dist/cli/index.js +15 -15
  31. package/dist/core/index.d.ts +24 -4
  32. package/dist/core/index.js +20 -12
  33. package/dist/core/redact.d.ts +36 -0
  34. package/dist/core/redact.js +18 -0
  35. package/dist/{dossier-2UG724LB.js → dossier-RWTIMGZN.js} +4 -3
  36. package/dist/healthcheck-A32IWPNV.js +20 -0
  37. package/dist/indexer-RAKJ7JR3.js +8 -0
  38. package/dist/{lexicon-5PXQEMUF.js → lexicon-IVNJTMWE.js} +5 -4
  39. package/dist/lint-HURYGO3V.js +17 -0
  40. package/dist/log-YIXF6CYM.js +11 -0
  41. package/dist/mcp/server.js +32 -27
  42. package/dist/mcp/server.js.map +1 -1
  43. package/dist/{profile-LXUEF7TX.js → profile-UE4YVTDC.js} +5 -4
  44. package/dist/{schema-ATFCLC6Y.js → schema-LY6533NJ.js} +2 -2
  45. package/dist/{search-AHKEFI2B.js → search-ZS6OW74K.js} +3 -3
  46. package/dist/{telemetry-GB2TEHVE.js → telemetry-B4KP3UVE.js} +4 -3
  47. package/dist/telemetry-B4KP3UVE.js.map +1 -0
  48. package/hooks/vault-context.js +112 -58
  49. package/package.json +10 -10
  50. package/dist/chunk-25EIQWXL.js.map +0 -1
  51. package/dist/chunk-7M3JZOYH.js.map +0 -1
  52. package/dist/chunk-A3KYHKB5.js.map +0 -1
  53. package/dist/chunk-CSXZ7QUU.js.map +0 -1
  54. package/dist/chunk-FM26NFTR.js.map +0 -1
  55. package/dist/chunk-JPQHNG3R.js.map +0 -1
  56. package/dist/chunk-NTYYS53O.js.map +0 -1
  57. package/dist/chunk-OWZWMB4P.js.map +0 -1
  58. package/dist/chunk-S4KW7VH4.js.map +0 -1
  59. package/dist/chunk-V45NJIHI.js.map +0 -1
  60. package/dist/chunk-WSU4QIPB.js.map +0 -1
  61. package/dist/healthcheck-IMB47LZE.js +0 -19
  62. package/dist/indexer-YW4O3VVM.js +0 -8
  63. package/dist/lint-XUQ7JDYX.js +0 -16
  64. package/dist/log-LQXIJXIA.js +0 -10
  65. /package/dist/{chunk-2EELGTLX.js.map → chunk-D5QLNNA4.js.map} +0 -0
  66. /package/dist/{dossier-2UG724LB.js.map → core/redact.js.map} +0 -0
  67. /package/dist/{healthcheck-IMB47LZE.js.map → dossier-RWTIMGZN.js.map} +0 -0
  68. /package/dist/{indexer-YW4O3VVM.js.map → healthcheck-A32IWPNV.js.map} +0 -0
  69. /package/dist/{lexicon-5PXQEMUF.js.map → indexer-RAKJ7JR3.js.map} +0 -0
  70. /package/dist/{lint-XUQ7JDYX.js.map → lexicon-IVNJTMWE.js.map} +0 -0
  71. /package/dist/{log-LQXIJXIA.js.map → lint-HURYGO3V.js.map} +0 -0
  72. /package/dist/{profile-LXUEF7TX.js.map → log-YIXF6CYM.js.map} +0 -0
  73. /package/dist/{schema-ATFCLC6Y.js.map → profile-UE4YVTDC.js.map} +0 -0
  74. /package/dist/{telemetry-GB2TEHVE.js.map → schema-LY6533NJ.js.map} +0 -0
  75. /package/dist/{search-AHKEFI2B.js.map → search-ZS6OW74K.js.map} +0 -0
@@ -1,5 +1,6 @@
1
1
  import Graph from 'graphology';
2
2
  import { EventEmitter } from 'node:events';
3
+ export { REDACTED, RedactMode, RedactResult, redact, redactDeep } from './redact.js';
3
4
 
4
5
  interface IndexedDocument {
5
6
  path: string;
@@ -182,13 +183,18 @@ declare class TextSearch {
182
183
  search(options: SearchTextOptions): SearchResult[];
183
184
  }
184
185
 
186
+ /** `redacted`: secrets masked in the content written (never the values). */
187
+ interface NoteWriteResult {
188
+ path: string;
189
+ redacted: number;
190
+ }
185
191
  declare class NoteCrud {
186
192
  private notesPath;
187
193
  constructor(notesPath: string);
188
- create(relativePath: string, content: string, frontmatter?: Record<string, unknown>): Promise<string>;
194
+ create(relativePath: string, content: string, frontmatter?: Record<string, unknown>): Promise<NoteWriteResult>;
189
195
  read(relativePath: string): Promise<string>;
190
196
  readMultiple(paths: string[]): Promise<Map<string, string>>;
191
- update(relativePath: string, content: string, options: UpdateNoteOptions): Promise<void>;
197
+ update(relativePath: string, content: string, options: UpdateNoteOptions): Promise<NoteWriteResult>;
192
198
  delete(relativePath: string): Promise<void>;
193
199
  move(fromPath: string, toPath: string): Promise<void>;
194
200
  private updateWikilinksAfterMove;
@@ -199,7 +205,9 @@ declare class FrontmatterManager {
199
205
  private notesPath;
200
206
  constructor(notesPath: string);
201
207
  get(relativePath: string): Promise<Record<string, unknown>>;
202
- update(relativePath: string, fields: Record<string, unknown>): Promise<void>;
208
+ update(relativePath: string, fields: Record<string, unknown>): Promise<{
209
+ redacted: number;
210
+ }>;
203
211
  }
204
212
  declare class TagManager {
205
213
  private notesPath;
@@ -252,7 +260,7 @@ interface VaultSchema {
252
260
  type Severity$1 = "warn" | "error";
253
261
  interface LintFinding {
254
262
  path: string;
255
- rule: "missing_provenance" | "stale" | "schema_violations" | "broken_links" | "code_symbols" | "decay_candidates" | "alias_conflicts" | "decoys";
263
+ rule: "missing_provenance" | "stale" | "schema_violations" | "broken_links" | "code_symbols" | "decay_candidates" | "alias_conflicts" | "decoys" | "secrets";
256
264
  severity: Severity$1;
257
265
  message: string;
258
266
  }
@@ -337,6 +345,8 @@ interface ApplyPatchOptions {
337
345
  interface AppliedOp {
338
346
  op: "create" | "update" | "delete" | "move";
339
347
  path: string;
348
+ /** secrets masked in this op's content; omitted when none */
349
+ redacted?: number;
340
350
  }
341
351
  interface ApplyPatchResult {
342
352
  ok: boolean;
@@ -530,6 +540,8 @@ interface LintReport {
530
540
  decay_candidates: LintFinding[];
531
541
  alias_conflicts: LintFinding[];
532
542
  decoys: LintFinding[];
543
+ /** only present when the opt-in secrets check ran */
544
+ secrets?: LintFinding[];
533
545
  };
534
546
  counts: {
535
547
  errors: number;
@@ -572,6 +584,14 @@ declare function lintVault(notesPath: string, opts?: {
572
584
  * signal (decision Q5). Opt-in; a no-op with no selection log.
573
585
  */
574
586
  checkDecoys?: boolean;
587
+ /**
588
+ * When true, run the secrets check (v1.5.3): flag notes that contain a secret
589
+ * (API key, token, password, private key — the redactor's precise set). Reports
590
+ * path, line and kind, never the value; nothing is rewritten. Opt-in, so the
591
+ * default report stays byte-stable. A real secret must be rotated: it is in
592
+ * git history if the note was ever committed.
593
+ */
594
+ checkSecrets?: boolean;
575
595
  }): Promise<LintReport>;
576
596
  declare function formatLintReport(report: LintReport, opts?: {
577
597
  rule?: keyof LintReport["byRule"];
@@ -2,7 +2,7 @@ import {
2
2
  filterToDrift,
3
3
  formatDriftBanner,
4
4
  runHealthcheck
5
- } from "../chunk-2EELGTLX.js";
5
+ } from "../chunk-D5QLNNA4.js";
6
6
  import {
7
7
  FrontmatterManager,
8
8
  INDEX_FILE,
@@ -18,38 +18,43 @@ import {
18
18
  regenDirectoryIndex,
19
19
  regenIndexesForPaths,
20
20
  regenerateAgentsContract
21
- } from "../chunk-CSXZ7QUU.js";
21
+ } from "../chunk-ROKSUJFM.js";
22
22
  import {
23
23
  formatLintReport,
24
24
  lintVault
25
- } from "../chunk-FM26NFTR.js";
26
- import "../chunk-NTYYS53O.js";
27
- import "../chunk-A3KYHKB5.js";
28
- import "../chunk-WSU4QIPB.js";
25
+ } from "../chunk-OFXQXVG5.js";
26
+ import "../chunk-5ZKNO6ZD.js";
27
+ import "../chunk-NBY4TRP7.js";
28
+ import "../chunk-FTRXH2WC.js";
29
+ import "../chunk-XAXK7NM4.js";
29
30
  import {
30
31
  SessionManager,
31
32
  deriveProjectRoot,
32
33
  deriveSessionDir
33
- } from "../chunk-S4KW7VH4.js";
34
+ } from "../chunk-LGQPP5FQ.js";
34
35
  import {
35
36
  Embedder,
36
37
  GraphBuilder,
37
38
  TextSearch,
38
39
  VectorIndex
39
- } from "../chunk-25EIQWXL.js";
40
+ } from "../chunk-44BQDRXD.js";
40
41
  import {
41
42
  Indexer
42
- } from "../chunk-V45NJIHI.js";
43
+ } from "../chunk-IGHCVAAL.js";
43
44
  import {
44
45
  logEvent,
45
46
  logQuery
46
- } from "../chunk-JPQHNG3R.js";
47
+ } from "../chunk-SX427M2R.js";
48
+ import {
49
+ REDACTED,
50
+ redact,
51
+ redactDeep
52
+ } from "../chunk-OEF5U5GV.js";
47
53
  import {
48
54
  installDefaultSchema,
49
55
  loadSchema,
50
56
  validateNote
51
- } from "../chunk-OWZWMB4P.js";
52
- import "../chunk-5ZKNO6ZD.js";
57
+ } from "../chunk-FURCIJBO.js";
53
58
  import "../chunk-PZ5AY32C.js";
54
59
  export {
55
60
  Embedder,
@@ -59,6 +64,7 @@ export {
59
64
  INDEX_OVERFLOW_THRESHOLD,
60
65
  Indexer,
61
66
  NoteCrud,
67
+ REDACTED,
62
68
  SessionManager,
63
69
  TagManager,
64
70
  TextSearch,
@@ -79,6 +85,8 @@ export {
79
85
  loadSchema,
80
86
  logEvent,
81
87
  logQuery,
88
+ redact,
89
+ redactDeep,
82
90
  regenDirectoryIndex,
83
91
  regenIndexesForPaths,
84
92
  regenerateAgentsContract,
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Secret redaction for everything semantic-memory writes to disk. Ported from jev-loop's
3
+ * redact.py: (1) exact values of secret-named env vars on this machine, (2) patterns.
4
+ *
5
+ * Two pattern sets:
6
+ * - "precise" (notes, frontmatter, dossiers, profile, lexicon): only shapes that are almost
7
+ * never ordinary content, because a false positive in a note is data loss.
8
+ * - "broad" (search log, log.md events, session state, capture-pending): precise plus long
9
+ * base64 / letter-and-digit tokens; over-redaction is fine in logs.
10
+ *
11
+ * Cannot catch a secret written in plain prose ("the password is hunter2"). Never logs values.
12
+ */
13
+ declare const REDACTED = "[REDACTED]";
14
+ type RedactMode = "precise" | "broad";
15
+ interface RedactResult {
16
+ text: string;
17
+ count: number;
18
+ }
19
+ /** Test seam: re-read env and settings on the next call. */
20
+ declare function resetRedactCache(): void;
21
+ declare function redact(text: string, mode?: RedactMode): RedactResult;
22
+ interface SecretLocation {
23
+ line: number;
24
+ kind: string;
25
+ }
26
+ /** Where precise-set secrets sit in a text (for lint_vault): 1-based line and kind, never the value. */
27
+ declare function findSecrets(text: string): SecretLocation[];
28
+ /** Redact every string inside a JSON-like value (for log payloads and state files). */
29
+ declare function redactDeep<T>(value: T, mode?: RedactMode): {
30
+ value: T;
31
+ count: number;
32
+ };
33
+ /** Suffix for a tool result: says how many secrets were masked, never which. "" when none. */
34
+ declare function redactedNote(count: number): string;
35
+
36
+ export { REDACTED, type RedactMode, type RedactResult, type SecretLocation, findSecrets, redact, redactDeep, redactedNote, resetRedactCache };
@@ -0,0 +1,18 @@
1
+ import {
2
+ REDACTED,
3
+ findSecrets,
4
+ redact,
5
+ redactDeep,
6
+ redactedNote,
7
+ resetRedactCache
8
+ } from "../chunk-OEF5U5GV.js";
9
+ import "../chunk-PZ5AY32C.js";
10
+ export {
11
+ REDACTED,
12
+ findSecrets,
13
+ redact,
14
+ redactDeep,
15
+ redactedNote,
16
+ resetRedactCache
17
+ };
18
+ //# sourceMappingURL=redact.js.map
@@ -15,8 +15,9 @@ import {
15
15
  resolveDossierPath,
16
16
  setCurrentState,
17
17
  slugifyEntity
18
- } from "./chunk-WSU4QIPB.js";
19
- import "./chunk-S4KW7VH4.js";
18
+ } from "./chunk-XAXK7NM4.js";
19
+ import "./chunk-LGQPP5FQ.js";
20
+ import "./chunk-OEF5U5GV.js";
20
21
  import "./chunk-PZ5AY32C.js";
21
22
  export {
22
23
  DOSSIER_DIR,
@@ -36,4 +37,4 @@ export {
36
37
  setCurrentState,
37
38
  slugifyEntity
38
39
  };
39
- //# sourceMappingURL=dossier-2UG724LB.js.map
40
+ //# sourceMappingURL=dossier-RWTIMGZN.js.map
@@ -0,0 +1,20 @@
1
+ import {
2
+ filterToDrift,
3
+ formatDriftBanner,
4
+ runHealthcheck
5
+ } from "./chunk-D5QLNNA4.js";
6
+ import "./chunk-OFXQXVG5.js";
7
+ import "./chunk-5ZKNO6ZD.js";
8
+ import "./chunk-NBY4TRP7.js";
9
+ import "./chunk-FTRXH2WC.js";
10
+ import "./chunk-XAXK7NM4.js";
11
+ import "./chunk-LGQPP5FQ.js";
12
+ import "./chunk-OEF5U5GV.js";
13
+ import "./chunk-FURCIJBO.js";
14
+ import "./chunk-PZ5AY32C.js";
15
+ export {
16
+ filterToDrift,
17
+ formatDriftBanner,
18
+ runHealthcheck
19
+ };
20
+ //# sourceMappingURL=healthcheck-A32IWPNV.js.map
@@ -0,0 +1,8 @@
1
+ import {
2
+ Indexer
3
+ } from "./chunk-IGHCVAAL.js";
4
+ import "./chunk-PZ5AY32C.js";
5
+ export {
6
+ Indexer
7
+ };
8
+ //# sourceMappingURL=indexer-RAKJ7JR3.js.map
@@ -8,9 +8,10 @@ import {
8
8
  normalizePhrase,
9
9
  removeAlias,
10
10
  slugify
11
- } from "./chunk-A3KYHKB5.js";
12
- import "./chunk-WSU4QIPB.js";
13
- import "./chunk-S4KW7VH4.js";
11
+ } from "./chunk-FTRXH2WC.js";
12
+ import "./chunk-XAXK7NM4.js";
13
+ import "./chunk-LGQPP5FQ.js";
14
+ import "./chunk-OEF5U5GV.js";
14
15
  import "./chunk-PZ5AY32C.js";
15
16
  export {
16
17
  addAlias,
@@ -23,4 +24,4 @@ export {
23
24
  removeAlias,
24
25
  slugify
25
26
  };
26
- //# sourceMappingURL=lexicon-5PXQEMUF.js.map
27
+ //# sourceMappingURL=lexicon-IVNJTMWE.js.map
@@ -0,0 +1,17 @@
1
+ import {
2
+ formatLintReport,
3
+ lintVault
4
+ } from "./chunk-OFXQXVG5.js";
5
+ import "./chunk-5ZKNO6ZD.js";
6
+ import "./chunk-NBY4TRP7.js";
7
+ import "./chunk-FTRXH2WC.js";
8
+ import "./chunk-XAXK7NM4.js";
9
+ import "./chunk-LGQPP5FQ.js";
10
+ import "./chunk-OEF5U5GV.js";
11
+ import "./chunk-FURCIJBO.js";
12
+ import "./chunk-PZ5AY32C.js";
13
+ export {
14
+ formatLintReport,
15
+ lintVault
16
+ };
17
+ //# sourceMappingURL=lint-HURYGO3V.js.map
@@ -0,0 +1,11 @@
1
+ import {
2
+ logEvent,
3
+ logQuery
4
+ } from "./chunk-SX427M2R.js";
5
+ import "./chunk-OEF5U5GV.js";
6
+ import "./chunk-PZ5AY32C.js";
7
+ export {
8
+ logEvent,
9
+ logQuery
10
+ };
11
+ //# sourceMappingURL=log-YIXF6CYM.js.map
@@ -3,7 +3,7 @@ import {
3
3
  initSpeakerProfile,
4
4
  readSpeakerProfile,
5
5
  updateProfileSection
6
- } from "../chunk-7M3JZOYH.js";
6
+ } from "../chunk-WZEKIUYG.js";
7
7
  import {
8
8
  FrontmatterManager,
9
9
  NoteCrud,
@@ -17,23 +17,28 @@ import {
17
17
  regenDirectoryIndex,
18
18
  regenIndexesForPaths,
19
19
  regenerateAgentsContract
20
- } from "../chunk-CSXZ7QUU.js";
20
+ } from "../chunk-ROKSUJFM.js";
21
21
  import {
22
22
  lintVault
23
- } from "../chunk-FM26NFTR.js";
23
+ } from "../chunk-OFXQXVG5.js";
24
+ import {
25
+ computeDecay,
26
+ loadDecayConfig,
27
+ normalizeVerifiedDate
28
+ } from "../chunk-5ZKNO6ZD.js";
24
29
  import {
25
30
  appendEvent,
26
31
  readSelectionLog,
27
32
  recordSearchForCorrelation,
28
33
  wasRecentlySearched
29
- } from "../chunk-NTYYS53O.js";
34
+ } from "../chunk-NBY4TRP7.js";
30
35
  import {
31
36
  addAlias,
32
37
  compileLexicon,
33
38
  expandQuery,
34
39
  loadLexiconCache,
35
40
  removeAlias
36
- } from "../chunk-A3KYHKB5.js";
41
+ } from "../chunk-FTRXH2WC.js";
37
42
  import {
38
43
  appendIncident,
39
44
  compileDossiers,
@@ -42,33 +47,31 @@ import {
42
47
  listDossiers,
43
48
  resolveDossierPath,
44
49
  setCurrentState
45
- } from "../chunk-WSU4QIPB.js";
50
+ } from "../chunk-XAXK7NM4.js";
46
51
  import {
47
52
  SessionManager,
48
53
  deriveProjectRoot,
49
54
  deriveSessionDir
50
- } from "../chunk-S4KW7VH4.js";
55
+ } from "../chunk-LGQPP5FQ.js";
51
56
  import {
52
57
  Embedder,
53
58
  GraphBuilder,
54
59
  TextSearch,
55
60
  VectorIndex
56
- } from "../chunk-25EIQWXL.js";
61
+ } from "../chunk-44BQDRXD.js";
57
62
  import {
58
63
  Indexer
59
- } from "../chunk-V45NJIHI.js";
64
+ } from "../chunk-IGHCVAAL.js";
60
65
  import {
61
66
  logEvent,
62
67
  logQuery
63
- } from "../chunk-JPQHNG3R.js";
68
+ } from "../chunk-SX427M2R.js";
64
69
  import {
65
- installDefaultSchema
66
- } from "../chunk-OWZWMB4P.js";
70
+ redactedNote
71
+ } from "../chunk-OEF5U5GV.js";
67
72
  import {
68
- computeDecay,
69
- loadDecayConfig,
70
- normalizeVerifiedDate
71
- } from "../chunk-5ZKNO6ZD.js";
73
+ installDefaultSchema
74
+ } from "../chunk-FURCIJBO.js";
72
75
  import {
73
76
  __export
74
77
  } from "../chunk-PZ5AY32C.js";
@@ -4692,8 +4695,8 @@ function registerWriteTools(server, ctx) {
4692
4695
  frontmatter: external_exports.record(external_exports.unknown()).optional()
4693
4696
  },
4694
4697
  async ({ path, content, frontmatter }) => {
4695
- await ctx.crud.create(path, content, frontmatter);
4696
- return ctx.textResponse(`Created: ${path}`);
4698
+ const { redacted } = await ctx.crud.create(path, content, frontmatter);
4699
+ return ctx.textResponse(`Created: ${path}${redactedNote(redacted)}`);
4697
4700
  }
4698
4701
  );
4699
4702
  server.tool(
@@ -4706,8 +4709,8 @@ function registerWriteTools(server, ctx) {
4706
4709
  heading: external_exports.string().optional()
4707
4710
  },
4708
4711
  async ({ path, content, mode, heading }) => {
4709
- await ctx.crud.update(path, content, { mode, heading });
4710
- return ctx.textResponse(`Updated: ${path} (${mode})`);
4712
+ const { redacted } = await ctx.crud.update(path, content, { mode, heading });
4713
+ return ctx.textResponse(`Updated: ${path} (${mode})${redactedNote(redacted)}`);
4711
4714
  }
4712
4715
  );
4713
4716
  server.tool(
@@ -5198,7 +5201,8 @@ var RULE_KEY_FOR_CHECK = {
5198
5201
  code_symbols: "code_symbols",
5199
5202
  decay_candidates: "decay_candidates",
5200
5203
  alias_conflicts: "alias_conflicts",
5201
- decoys: "decoys"
5204
+ decoys: "decoys",
5205
+ secrets: "secrets"
5202
5206
  };
5203
5207
  function registerLintTools(server, ctx) {
5204
5208
  server.tool(
@@ -5239,10 +5243,10 @@ function registerLintTools(server, ctx) {
5239
5243
  );
5240
5244
  server.tool(
5241
5245
  "lint_vault",
5242
- "Run lint rules across the vault. Default returns the full LintReport with all findings grouped by rule. Pass `checks` to filter to specific rules (schema, provenance, stale, broken_links, code_symbols, decay_candidates) \u2014 when filtered, byRule contains only the requested rules. Two checks are opt-in only (never in the default report): `code_symbols` flags inline-code file-path references that no longer exist under the project root (no-op outside a code repo); `decay_candidates` cross-references the selection log against current decay to surface frequently-retrieved-but-decayed notes (no-op with no selection log). `decoys` flags notes retrieved 3+ times but never cited - surfaced for review, never auto-down-ranked (v1.5 Q5).",
5246
+ "Run lint rules across the vault. Default returns the full LintReport with all findings grouped by rule. Pass `checks` to filter to specific rules (schema, provenance, stale, broken_links, code_symbols, decay_candidates) \u2014 when filtered, byRule contains only the requested rules. Two checks are opt-in only (never in the default report): `code_symbols` flags inline-code file-path references that no longer exist under the project root (no-op outside a code repo); `decay_candidates` cross-references the selection log against current decay to surface frequently-retrieved-but-decayed notes (no-op with no selection log). `decoys` flags notes retrieved 3+ times but never cited - surfaced for review, never auto-down-ranked (v1.5 Q5). `secrets` flags notes containing an API key, token, password or private key (path, line, kind \u2014 never the value; nothing is rewritten): rotate the secret, then remove it.",
5243
5247
  {
5244
5248
  pathGlob: external_exports.string().optional(),
5245
- checks: external_exports.array(external_exports.enum(["schema", "provenance", "stale", "broken_links", "code_symbols", "decay_candidates", "alias_conflicts", "decoys"])).optional().describe("Filter to specific lint rules. Omit for full report (excludes the opt-in code_symbols / decay_candidates / alias_conflicts / decoys).")
5249
+ checks: external_exports.array(external_exports.enum(["schema", "provenance", "stale", "broken_links", "code_symbols", "decay_candidates", "alias_conflicts", "decoys", "secrets"])).optional().describe("Filter to specific lint rules. Omit for full report (excludes the opt-in code_symbols / decay_candidates / alias_conflicts / decoys / secrets).")
5246
5250
  },
5247
5251
  async ({ pathGlob, checks }) => {
5248
5252
  const report = await lintVault(ctx.notesPath, {
@@ -5250,7 +5254,8 @@ function registerLintTools(server, ctx) {
5250
5254
  checkCodeSymbols: !!checks?.includes("code_symbols"),
5251
5255
  checkDecayCandidates: !!checks?.includes("decay_candidates"),
5252
5256
  checkAliasConflicts: !!checks?.includes("alias_conflicts"),
5253
- checkDecoys: !!checks?.includes("decoys")
5257
+ checkDecoys: !!checks?.includes("decoys"),
5258
+ checkSecrets: !!checks?.includes("secrets")
5254
5259
  });
5255
5260
  if (!checks || checks.length === 0) {
5256
5261
  return ctx.textResponse(JSON.stringify(report, null, 2));
@@ -5349,8 +5354,8 @@ function registerMetadataTools(server, ctx) {
5349
5354
  "Set or delete YAML frontmatter keys \u2014 pass null to delete a key",
5350
5355
  { path: external_exports.string(), fields: external_exports.record(external_exports.unknown()) },
5351
5356
  async ({ path, fields }) => {
5352
- await ctx.frontmatterManager.update(path, fields);
5353
- return ctx.textResponse(`Frontmatter updated: ${path}`);
5357
+ const { redacted } = await ctx.frontmatterManager.update(path, fields);
5358
+ return ctx.textResponse(`Frontmatter updated: ${path}${redactedNote(redacted)}`);
5354
5359
  }
5355
5360
  );
5356
5361
  server.tool(
@@ -5771,7 +5776,7 @@ async function createServer(notesPath, options = {}) {
5771
5776
  await ctx.fullIndex();
5772
5777
  } else {
5773
5778
  ctx.tryLoadCachedIndex().then((cached) => {
5774
- if (!cached) ctx.backgroundIndex();
5779
+ if (!cached || ctx.getIndexState() === "stale") ctx.backgroundIndex();
5775
5780
  }).catch((err) => {
5776
5781
  process.stderr.write(`Startup error: ${err?.message ?? err}
5777
5782
  `);