@jagilber-org/index-server 1.22.1 → 1.26.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 (189) hide show
  1. package/CHANGELOG.md +87 -2
  2. package/CODE_OF_CONDUCT.md +2 -0
  3. package/CONTRIBUTING.md +32 -2
  4. package/README.md +82 -19
  5. package/SECURITY.md +17 -5
  6. package/dist/config/dashboardConfig.d.ts +3 -0
  7. package/dist/config/dashboardConfig.js +3 -0
  8. package/dist/config/defaultValues.d.ts +1 -1
  9. package/dist/config/defaultValues.js +1 -1
  10. package/dist/config/featureConfig.d.ts +2 -0
  11. package/dist/config/featureConfig.js +6 -1
  12. package/dist/config/runtimeConfig.d.ts +1 -1
  13. package/dist/config/runtimeConfig.js +8 -9
  14. package/dist/dashboard/client/admin.html +170 -53
  15. package/dist/dashboard/client/css/admin.css +132 -0
  16. package/dist/dashboard/client/js/admin.auth.js +25 -11
  17. package/dist/dashboard/client/js/admin.config.js +1 -1
  18. package/dist/dashboard/client/js/admin.feedback.js +328 -0
  19. package/dist/dashboard/client/js/admin.graph.js +120 -18
  20. package/dist/dashboard/client/js/admin.instructions.js +27 -13
  21. package/dist/dashboard/client/js/admin.logs.js +1 -5
  22. package/dist/dashboard/client/js/admin.maintenance.js +53 -8
  23. package/dist/dashboard/client/js/admin.messaging.js +1 -4
  24. package/dist/dashboard/client/js/admin.overview.js +5 -1
  25. package/dist/dashboard/client/js/admin.sessions.js +1 -1
  26. package/dist/dashboard/client/js/admin.utils.js +43 -1
  27. package/dist/dashboard/client/js/mermaid.min.js +813 -537
  28. package/dist/dashboard/export/DataExporter.js +2 -1
  29. package/dist/dashboard/server/AdminPanel.d.ts +3 -0
  30. package/dist/dashboard/server/AdminPanel.js +132 -35
  31. package/dist/dashboard/server/ApiRoutes.js +40 -9
  32. package/dist/dashboard/server/DashboardServer.js +1 -1
  33. package/dist/dashboard/server/FileMetricsStorage.d.ts +19 -0
  34. package/dist/dashboard/server/FileMetricsStorage.js +52 -5
  35. package/dist/dashboard/server/HttpTransport.js +6 -0
  36. package/dist/dashboard/server/InstanceManager.js +7 -2
  37. package/dist/dashboard/server/KnowledgeStore.js +7 -2
  38. package/dist/dashboard/server/MetricsCollector.d.ts +16 -0
  39. package/dist/dashboard/server/MetricsCollector.js +113 -17
  40. package/dist/dashboard/server/legacyDashboardHtml.js +7 -2
  41. package/dist/dashboard/server/middleware/ensureLoadedMiddleware.d.ts +1 -1
  42. package/dist/dashboard/server/middleware/ensureLoadedMiddleware.js +8 -3
  43. package/dist/dashboard/server/routes/admin.feedback.routes.d.ts +15 -0
  44. package/dist/dashboard/server/routes/admin.feedback.routes.js +188 -0
  45. package/dist/dashboard/server/routes/admin.routes.js +35 -27
  46. package/dist/dashboard/server/routes/alerts.routes.js +4 -3
  47. package/dist/dashboard/server/routes/api.feedback.routes.js +2 -1
  48. package/dist/dashboard/server/routes/api.usage.routes.js +8 -7
  49. package/dist/dashboard/server/routes/embeddings.routes.d.ts +2 -1
  50. package/dist/dashboard/server/routes/embeddings.routes.js +18 -9
  51. package/dist/dashboard/server/routes/graph.routes.js +10 -13
  52. package/dist/dashboard/server/routes/index.d.ts +1 -0
  53. package/dist/dashboard/server/routes/index.js +74 -39
  54. package/dist/dashboard/server/routes/instances.routes.js +2 -1
  55. package/dist/dashboard/server/routes/instructions.routes.js +46 -27
  56. package/dist/dashboard/server/routes/knowledge.routes.js +4 -3
  57. package/dist/dashboard/server/routes/logs.routes.js +5 -4
  58. package/dist/dashboard/server/routes/messaging.routes.js +15 -14
  59. package/dist/dashboard/server/routes/metrics.routes.js +14 -13
  60. package/dist/dashboard/server/routes/scripts.routes.js +6 -3
  61. package/dist/dashboard/server/routes/status.routes.js +5 -4
  62. package/dist/dashboard/server/routes/synthetic.routes.js +3 -2
  63. package/dist/dashboard/server/routes/usage.routes.js +2 -1
  64. package/dist/dashboard/server/utils/escapeHtml.d.ts +1 -0
  65. package/dist/dashboard/server/utils/escapeHtml.js +11 -0
  66. package/dist/dashboard/server/utils/pathContainment.d.ts +1 -0
  67. package/dist/dashboard/server/utils/pathContainment.js +15 -0
  68. package/dist/dashboard/server/wsInit.js +2 -2
  69. package/dist/lib/mcpStdioLogging.d.ts +165 -0
  70. package/dist/lib/mcpStdioLogging.js +287 -0
  71. package/dist/schemas/index.d.ts +37 -2
  72. package/dist/schemas/index.js +27 -3
  73. package/dist/server/backgroundServicesStartup.d.ts +7 -1
  74. package/dist/server/backgroundServicesStartup.js +25 -8
  75. package/dist/server/certInit.d.ts +97 -0
  76. package/dist/server/certInit.js +359 -0
  77. package/dist/server/certInit.types.d.ts +92 -0
  78. package/dist/server/certInit.types.js +34 -0
  79. package/dist/server/handshake/fallbackFrames.d.ts +31 -0
  80. package/dist/server/handshake/fallbackFrames.js +38 -0
  81. package/dist/server/handshake/initializeDetector.d.ts +31 -0
  82. package/dist/server/handshake/initializeDetector.js +88 -0
  83. package/dist/server/handshake/protocol.d.ts +15 -0
  84. package/dist/server/handshake/protocol.js +37 -0
  85. package/dist/server/handshake/readyEmitter.d.ts +6 -0
  86. package/dist/server/handshake/readyEmitter.js +88 -0
  87. package/dist/server/handshake/safetyFallbacks.d.ts +1 -0
  88. package/dist/server/handshake/safetyFallbacks.js +134 -0
  89. package/dist/server/handshake/stdinSniffer.d.ts +1 -0
  90. package/dist/server/handshake/stdinSniffer.js +260 -0
  91. package/dist/server/handshake/tracing.d.ts +16 -0
  92. package/dist/server/handshake/tracing.js +95 -0
  93. package/dist/server/handshakeManager.d.ts +23 -23
  94. package/dist/server/handshakeManager.js +36 -466
  95. package/dist/server/index-server.d.ts +23 -0
  96. package/dist/server/index-server.js +194 -9
  97. package/dist/server/mcpReadOnlySurfaces.d.ts +44 -0
  98. package/dist/server/mcpReadOnlySurfaces.js +297 -0
  99. package/dist/server/sdkServer.js +69 -7
  100. package/dist/server/transport.d.ts +5 -6
  101. package/dist/server/transport.js +46 -64
  102. package/dist/server/transportFactory.d.ts +3 -9
  103. package/dist/server/transportFactory.js +18 -380
  104. package/dist/services/atomicFs.d.ts +3 -0
  105. package/dist/services/atomicFs.js +171 -13
  106. package/dist/services/auditLog.d.ts +17 -2
  107. package/dist/services/auditLog.js +75 -14
  108. package/dist/services/bootstrapGating.js +1 -1
  109. package/dist/services/categoryRules.d.ts +10 -0
  110. package/dist/services/categoryRules.js +17 -0
  111. package/dist/services/classificationService.js +7 -5
  112. package/dist/services/embeddingService.d.ts +27 -11
  113. package/dist/services/embeddingService.js +51 -14
  114. package/dist/services/feedbackStorage.d.ts +39 -0
  115. package/dist/services/feedbackStorage.js +88 -0
  116. package/dist/services/handlers/instructions.add.js +429 -317
  117. package/dist/services/handlers/instructions.groom.js +128 -31
  118. package/dist/services/handlers/instructions.import.js +56 -23
  119. package/dist/services/handlers/instructions.patch.js +43 -32
  120. package/dist/services/handlers/instructions.query.js +20 -29
  121. package/dist/services/handlers/instructions.shared.d.ts +54 -0
  122. package/dist/services/handlers/instructions.shared.js +126 -1
  123. package/dist/services/handlers.activation.js +83 -81
  124. package/dist/services/handlers.dashboardConfig.d.ts +2 -2
  125. package/dist/services/handlers.dashboardConfig.js +1 -2
  126. package/dist/services/handlers.diagnostics.js +75 -54
  127. package/dist/services/handlers.feedback.d.ts +4 -11
  128. package/dist/services/handlers.feedback.js +11 -333
  129. package/dist/services/handlers.gates.js +69 -37
  130. package/dist/services/handlers.graph.js +2 -2
  131. package/dist/services/handlers.help.js +2 -2
  132. package/dist/services/handlers.instructionSchema.js +4 -2
  133. package/dist/services/handlers.integrity.js +42 -22
  134. package/dist/services/handlers.messaging.js +1 -1
  135. package/dist/services/handlers.metrics.js +51 -6
  136. package/dist/services/handlers.prompt.js +10 -2
  137. package/dist/services/handlers.search.js +94 -44
  138. package/dist/services/handlers.trace.js +1 -1
  139. package/dist/services/handlers.usage.js +38 -7
  140. package/dist/services/indexContext.d.ts +21 -1
  141. package/dist/services/indexContext.js +263 -78
  142. package/dist/services/indexLoader.d.ts +1 -0
  143. package/dist/services/indexLoader.js +28 -8
  144. package/dist/services/instructionRecordValidation.d.ts +39 -0
  145. package/dist/services/instructionRecordValidation.js +388 -0
  146. package/dist/services/instructions.dispatcher.js +4 -4
  147. package/dist/services/loaderSchemaValidator.d.ts +15 -0
  148. package/dist/services/loaderSchemaValidator.js +69 -0
  149. package/dist/services/logger.js +11 -2
  150. package/dist/services/mcpLogBridge.d.ts +49 -0
  151. package/dist/services/mcpLogBridge.js +83 -0
  152. package/dist/services/ownershipService.js +18 -8
  153. package/dist/services/performanceBaseline.js +23 -22
  154. package/dist/services/promptReviewService.d.ts +3 -1
  155. package/dist/services/promptReviewService.js +41 -13
  156. package/dist/services/regexSafety.d.ts +6 -0
  157. package/dist/services/regexSafety.js +46 -0
  158. package/dist/services/seedBootstrap.js +1 -1
  159. package/dist/services/storage/factory.d.ts +14 -1
  160. package/dist/services/storage/factory.js +61 -1
  161. package/dist/services/storage/jsonEmbeddingStore.d.ts +15 -0
  162. package/dist/services/storage/jsonEmbeddingStore.js +83 -0
  163. package/dist/services/storage/jsonFileStore.d.ts +3 -1
  164. package/dist/services/storage/jsonFileStore.js +8 -6
  165. package/dist/services/storage/migrationEngine.d.ts +13 -0
  166. package/dist/services/storage/migrationEngine.js +31 -0
  167. package/dist/services/storage/sqliteEmbeddingStore.d.ts +30 -0
  168. package/dist/services/storage/sqliteEmbeddingStore.js +222 -0
  169. package/dist/services/storage/sqliteStore.d.ts +3 -1
  170. package/dist/services/storage/sqliteStore.js +2 -2
  171. package/dist/services/storage/types.d.ts +48 -1
  172. package/dist/services/toolRegistry.js +77 -67
  173. package/dist/services/toolRegistry.zod.js +89 -86
  174. package/dist/services/tracing.js +5 -4
  175. package/dist/utils/envUtils.d.ts +4 -0
  176. package/dist/utils/envUtils.js +7 -0
  177. package/dist/utils/memoryMonitor.js +11 -10
  178. package/package.json +11 -4
  179. package/schemas/instruction.schema.json +38 -1
  180. package/scripts/copy-dashboard-assets.mjs +1 -1
  181. package/scripts/dist/README.md +1 -1
  182. package/scripts/setup-wizard.mjs +781 -0
  183. package/server.json +1 -0
  184. package/dist/externalClientLib.d.ts +0 -1
  185. package/dist/externalClientLib.js +0 -2
  186. package/dist/portableClientWrapper.d.ts +0 -1
  187. package/dist/portableClientWrapper.js +0 -2
  188. package/dist/services/indexingService.d.ts +0 -1
  189. package/dist/services/indexingService.js +0 -2
@@ -294,31 +294,6 @@ exports.instructionActions = {
294
294
  items = items.filter(e => e.title.toLowerCase().includes(text) || e.body.toLowerCase().includes(text) || (e.semanticSummary || '').toLowerCase().includes(text));
295
295
  pushStage('text');
296
296
  }
297
- try {
298
- const recent = st._recentAdds;
299
- if (recent) {
300
- const now = Date.now();
301
- const GRACE = 300;
302
- for (const [id, meta] of Object.entries(recent)) {
303
- if (now - meta.ts > GRACE)
304
- continue;
305
- if (items.some(e => e.id === id))
306
- continue;
307
- const catMatchAll = !catsAll.length || catsAll.every(c => meta.categories.includes(c));
308
- const catMatchAny = !catsAny.length || meta.categories.some(c => catsAny.includes(c));
309
- const catExcluded = catsEx.length && meta.categories.some(c => catsEx.includes(c));
310
- if (catMatchAll && catMatchAny && !catExcluded) {
311
- const injected = st.byId.get(id);
312
- if (injected) {
313
- items = items.concat([injected]);
314
- if ((0, instructions_shared_1.traceVisibility)())
315
- (0, tracing_1.emitTrace)('[trace:query:recent-add-injected]', { id, graceMs: now - meta.ts });
316
- }
317
- }
318
- }
319
- }
320
- }
321
- catch { /* ignore fallback */ }
322
297
  const total = items.length;
323
298
  const limit = Math.min(Math.max((p.limit ?? 100), 1), 1000);
324
299
  const offset = Math.max((p.offset ?? 0), 0);
@@ -377,8 +352,22 @@ exports.instructionActions = {
377
352
  return { error: 'missing id' };
378
353
  const st = (0, indexContext_1.ensureLoaded)();
379
354
  const entry = st.byId.get(id);
380
- if (!entry)
355
+ if (!entry) {
356
+ // Check if the file exists on disk but was skipped during load (#208)
357
+ const dir = (0, indexContext_1.getInstructionsDir)();
358
+ const filePath = path_1.default.join(dir, `${id}.json`);
359
+ const fileExists = fs_1.default.existsSync(filePath);
360
+ if (fileExists) {
361
+ // File exists but wasn't loaded — check loadErrors for the reason
362
+ const loadError = st.loadErrors?.find(e => {
363
+ const fileName = path_1.default.basename(e.file);
364
+ return e.file === `${id}.json` || fileName === `${id}.json` || e.file.endsWith(`${path_1.default.sep}${id}.json`);
365
+ });
366
+ const skipReason = loadError?.error || 'unknown (file exists but was not loaded)';
367
+ return { id, exists: false, fileMissing: false, skipped: true, skipReason };
368
+ }
381
369
  return { id, exists: false, fileMissing: true };
370
+ }
382
371
  let schemaErrors;
383
372
  let classificationIssues;
384
373
  let normalized;
@@ -438,9 +427,11 @@ exports.instructionActions = {
438
427
  catch {
439
428
  recursionRisk = effectiveGovernanceLike === 0 ? 'none' : (leakageRatio < 0.01 ? 'warning' : 'critical');
440
429
  }
430
+ // #131: surface invariant-repair summary so operators can detect silent reconstruction
431
+ const invariantRepairs = (0, indexContext_1.getInvariantRepairSummary)();
441
432
  const snapshot = path_1.default.join(process.cwd(), 'snapshots', 'canonical-instructions.json');
442
433
  if (!fs_1.default.existsSync(snapshot))
443
- return { snapshot: 'missing', hash: st.hash, count: st.list.length, governanceHash, recursionRisk, leakage: { governanceLike, keywordHit, leakageRatio }, summary };
434
+ return { snapshot: 'missing', hash: st.hash, count: st.list.length, governanceHash, recursionRisk, leakage: { governanceLike, keywordHit, leakageRatio }, summary, invariantRepairs };
444
435
  try {
445
436
  const raw = JSON.parse(fs_1.default.readFileSync(snapshot, 'utf8'));
446
437
  const snapItems = raw.items || [];
@@ -455,10 +446,10 @@ exports.instructionActions = {
455
446
  changed.push(e.id);
456
447
  }
457
448
  const extra = snapItems.filter(i => !st.byId.has(i.id)).map(i => i.id);
458
- return { snapshot: 'present', hash: st.hash, count: st.list.length, missing, changed, extra, drift: missing.length + changed.length + extra.length, governanceHash, recursionRisk, leakage: { governanceLike, keywordHit, leakageRatio }, summary };
449
+ return { snapshot: 'present', hash: st.hash, count: st.list.length, missing, changed, extra, drift: missing.length + changed.length + extra.length, governanceHash, recursionRisk, leakage: { governanceLike, keywordHit, leakageRatio }, summary, invariantRepairs };
459
450
  }
460
451
  catch (e) {
461
- return { snapshot: 'error', error: e instanceof Error ? e.message : String(e), hash: st.hash, governanceHash, recursionRisk, leakage: { governanceLike, keywordHit, leakageRatio }, summary };
452
+ return { snapshot: 'error', error: e instanceof Error ? e.message : String(e), hash: st.hash, governanceHash, recursionRisk, leakage: { governanceLike, keywordHit, leakageRatio }, summary, invariantRepairs };
462
453
  }
463
454
  });
464
455
  (0, registry_1.registerHandler)('index_debug', () => {
@@ -29,4 +29,58 @@ export declare function guard<TParams, TResult>(name: string, fn: (p: TParams) =
29
29
  export declare function traceVisibility(): boolean;
30
30
  export declare function traceInstructionVisibility(id: string, phase: string, extra?: Record<string, unknown>): void;
31
31
  export declare function traceEnvSnapshot(phase: string, extra?: Record<string, unknown>): void;
32
+ /** Returns true if the category string is considered junk (numeric prefix, single char, case-ticket ID). */
33
+ export declare function isJunkCategory(cat: string): boolean;
34
+ /** Normalize a categories array: deduplicate, lowercase, remove junk, remove plural duplicates, sort. */
35
+ export declare function normalizeCategories(cats: unknown[]): string[];
36
+ /** Compute SHA-256 hash of an instruction body. */
37
+ export declare function computeSourceHash(body: string): string;
38
+ /** Bump a semver version string. Returns the new version string. */
39
+ export declare function bumpVersion(currentVersion: string | undefined, bump: 'patch' | 'minor' | 'major'): string;
40
+ /** Create a changelog entry object for an instruction version change. */
41
+ export declare function createChangeLogEntry(version: string, summary: string): {
42
+ version: string;
43
+ changedAt: string;
44
+ summary: string;
45
+ };
46
+ /**
47
+ * Normalize categories supplied as input to add/import handlers:
48
+ * filter to non-empty strings, lowercase, deduplicate, and sort.
49
+ *
50
+ * Distinct from {@link normalizeCategories} (used by groom), which also
51
+ * strips junk patterns and plural duplicates.
52
+ */
53
+ export declare function normalizeInputCategories(cats: unknown): string[];
54
+ type ChangeLogArr = NonNullable<InstructionEntry['changeLog']>;
55
+ export interface RepairChangeLogOptions {
56
+ /** Final/expected version that the last entry must end with. */
57
+ finalVersion: string;
58
+ /** ISO timestamp to use as `now`. */
59
+ now: string;
60
+ /** Fallback entry pushed when the supplied changeLog is empty/invalid. */
61
+ fallback: {
62
+ version: string;
63
+ changedAt: string;
64
+ summary: string;
65
+ };
66
+ /** Summary to use when appending a trailing entry to reach finalVersion. */
67
+ trailingSummary: string;
68
+ }
69
+ /**
70
+ * Repair a changelog array: drop malformed entries, ensure non-empty,
71
+ * and ensure the last entry's version matches `finalVersion`.
72
+ *
73
+ * Used by the overwrite/merge and new-entry paths in `index_add` plus any
74
+ * other handler that needs to normalize a user-supplied changeLog.
75
+ */
76
+ export declare function repairChangeLog(cl: unknown, options: RepairChangeLogOptions): ChangeLogArr;
77
+ /** Governance keys merged from input into the entry by `index_add`. */
78
+ export declare const ADD_GOVERNANCE_KEYS: readonly (keyof ImportEntry)[];
79
+ /** Governance keys merged from input into the entry by `index_import`.
80
+ * Differs from {@link ADD_GOVERNANCE_KEYS} by also including `changeLog`,
81
+ * since import accepts changeLog directly without invoking repair logic.
82
+ */
83
+ export declare const IMPORT_GOVERNANCE_KEYS: readonly (keyof ImportEntry)[];
84
+ /** Copy defined governance fields from `source` into `target` for the given keys. */
85
+ export declare function applyGovernanceKeys(target: InstructionEntry, source: ImportEntry, keys: readonly (keyof ImportEntry)[]): void;
32
86
  export {};
@@ -1,5 +1,9 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.IMPORT_GOVERNANCE_KEYS = exports.ADD_GOVERNANCE_KEYS = void 0;
3
7
  exports.isMutationEnabled = isMutationEnabled;
4
8
  exports.isCI = isCI;
5
9
  exports.limitResponseSize = limitResponseSize;
@@ -7,6 +11,16 @@ exports.guard = guard;
7
11
  exports.traceVisibility = traceVisibility;
8
12
  exports.traceInstructionVisibility = traceInstructionVisibility;
9
13
  exports.traceEnvSnapshot = traceEnvSnapshot;
14
+ exports.isJunkCategory = isJunkCategory;
15
+ exports.normalizeCategories = normalizeCategories;
16
+ exports.computeSourceHash = computeSourceHash;
17
+ exports.bumpVersion = bumpVersion;
18
+ exports.createChangeLogEntry = createChangeLogEntry;
19
+ exports.normalizeInputCategories = normalizeInputCategories;
20
+ exports.repairChangeLog = repairChangeLog;
21
+ exports.applyGovernanceKeys = applyGovernanceKeys;
22
+ // Shared utilities used across instruction handler submodules.
23
+ const crypto_1 = __importDefault(require("crypto"));
10
24
  const indexContext_1 = require("../indexContext");
11
25
  const runtimeConfig_1 = require("../../config/runtimeConfig");
12
26
  const tracing_1 = require("../tracing");
@@ -38,7 +52,7 @@ function guard(name, fn) {
38
52
  return (p) => {
39
53
  const viaDispatcher = !!(p && typeof p === 'object' && p._viaDispatcher);
40
54
  if (!isMutationEnabled() && !viaDispatcher) {
41
- throw { code: -32601, message: `Mutation disabled. Use index_dispatch with action parameter instead of direct ${name} calls. Set INDEX_SERVER_MUTATION=1 to enable direct calls.`, data: { method: name, alternative: 'index_dispatch', reason: 'mutation_disabled' } };
55
+ throw { code: -32601, message: `Direct mutation calls are disabled by the current runtime override. Use index_dispatch with an action parameter instead of direct ${name} calls, or remove INDEX_SERVER_MUTATION=0 to re-enable direct calls.`, data: { method: name, alternative: 'index_dispatch', reason: 'mutation_disabled' } };
42
56
  }
43
57
  return fn(p);
44
58
  };
@@ -89,3 +103,114 @@ function traceEnvSnapshot(phase, extra) {
89
103
  }
90
104
  catch { /* ignore env tracing errors */ }
91
105
  }
106
+ // ── Shared category normalization (#135) ──────────────────────────
107
+ // Extracted from groom handler to eliminate duplication across groom/normalize/repair.
108
+ /** Returns true if the category string is considered junk (numeric prefix, single char, case-ticket ID). */
109
+ function isJunkCategory(cat) {
110
+ return /^\d/.test(cat) || cat.length <= 1 || /^case-\d{6,}$/.test(cat);
111
+ }
112
+ /** Normalize a categories array: deduplicate, lowercase, remove junk, remove plural duplicates, sort. */
113
+ function normalizeCategories(cats) {
114
+ let normCats = Array.from(new Set((cats || []).filter(c => typeof c === 'string').map(c => c.toLowerCase())));
115
+ normCats = normCats.filter(c => !isJunkCategory(c));
116
+ normCats = normCats.filter(cat => !(cat.endsWith('s') && normCats.includes(cat.slice(0, -1))));
117
+ return normCats.sort();
118
+ }
119
+ // ── Shared source hash computation (#135) ─────────────────────────
120
+ /** Compute SHA-256 hash of an instruction body. */
121
+ function computeSourceHash(body) {
122
+ return crypto_1.default.createHash('sha256').update(body, 'utf8').digest('hex');
123
+ }
124
+ // ── Shared version bump logic (#135) ──────────────────────────────
125
+ /** Bump a semver version string. Returns the new version string. */
126
+ function bumpVersion(currentVersion, bump) {
127
+ const parts = (currentVersion || '1.0.0').split('.').map(n => parseInt(n || '0', 10));
128
+ while (parts.length < 3)
129
+ parts.push(0);
130
+ if (bump === 'major') {
131
+ parts[0]++;
132
+ parts[1] = 0;
133
+ parts[2] = 0;
134
+ }
135
+ else if (bump === 'minor') {
136
+ parts[1]++;
137
+ parts[2] = 0;
138
+ }
139
+ else if (bump === 'patch') {
140
+ parts[2]++;
141
+ }
142
+ return parts.join('.');
143
+ }
144
+ // ── Shared changelog entry creation (#135) ────────────────────────
145
+ /** Create a changelog entry object for an instruction version change. */
146
+ function createChangeLogEntry(version, summary) {
147
+ return { version, changedAt: new Date().toISOString(), summary };
148
+ }
149
+ // ── Shared input-side category normalization (#135) ──────────────
150
+ /**
151
+ * Normalize categories supplied as input to add/import handlers:
152
+ * filter to non-empty strings, lowercase, deduplicate, and sort.
153
+ *
154
+ * Distinct from {@link normalizeCategories} (used by groom), which also
155
+ * strips junk patterns and plural duplicates.
156
+ */
157
+ function normalizeInputCategories(cats) {
158
+ const arr = Array.isArray(cats) ? cats : [];
159
+ return Array.from(new Set(arr
160
+ .filter((c) => typeof c === 'string' && c.trim().length > 0)
161
+ .map(c => c.toLowerCase()))).sort();
162
+ }
163
+ /**
164
+ * Repair a changelog array: drop malformed entries, ensure non-empty,
165
+ * and ensure the last entry's version matches `finalVersion`.
166
+ *
167
+ * Used by the overwrite/merge and new-entry paths in `index_add` plus any
168
+ * other handler that needs to normalize a user-supplied changeLog.
169
+ */
170
+ function repairChangeLog(cl, options) {
171
+ const out = [];
172
+ if (Array.isArray(cl)) {
173
+ for (const entry of cl) {
174
+ if (!entry || typeof entry !== 'object')
175
+ continue;
176
+ const { version: v, changedAt: ca, summary: sum } = entry;
177
+ if (typeof v === 'string' && v.trim() && typeof sum === 'string' && sum.trim()) {
178
+ const caIso = typeof ca === 'string' && /T/.test(ca) ? ca : options.now;
179
+ out.push({ version: v.trim(), changedAt: caIso, summary: sum.trim() });
180
+ }
181
+ }
182
+ }
183
+ if (!out.length) {
184
+ out.push({ ...options.fallback });
185
+ }
186
+ const lastVer = out[out.length - 1].version;
187
+ if (lastVer !== options.finalVersion) {
188
+ out.push({ version: options.finalVersion, changedAt: options.now, summary: options.trailingSummary });
189
+ }
190
+ return out;
191
+ }
192
+ // ── Shared governance key merge (#135) ────────────────────────────
193
+ /** Governance keys merged from input into the entry by `index_add`. */
194
+ exports.ADD_GOVERNANCE_KEYS = [
195
+ 'version', 'owner', 'status', 'priorityTier', 'classification',
196
+ 'lastReviewedAt', 'nextReviewDue', 'semanticSummary', 'contentType', 'extensions'
197
+ ];
198
+ /** Governance keys merged from input into the entry by `index_import`.
199
+ * Differs from {@link ADD_GOVERNANCE_KEYS} by also including `changeLog`,
200
+ * since import accepts changeLog directly without invoking repair logic.
201
+ */
202
+ exports.IMPORT_GOVERNANCE_KEYS = [
203
+ 'version', 'owner', 'status', 'priorityTier', 'classification',
204
+ 'lastReviewedAt', 'nextReviewDue', 'changeLog', 'semanticSummary',
205
+ 'contentType', 'extensions'
206
+ ];
207
+ /** Copy defined governance fields from `source` into `target` for the given keys. */
208
+ function applyGovernanceKeys(target, source, keys) {
209
+ const t = target;
210
+ for (const k of keys) {
211
+ const v = source[k];
212
+ if (v !== undefined) {
213
+ t[k] = v;
214
+ }
215
+ }
216
+ }
@@ -13,89 +13,91 @@ Object.defineProperty(exports, "__esModule", { value: true });
13
13
  * Created: 2026-02-01 (in response to repeated multi-session activation pain)
14
14
  */
15
15
  const registry_1 = require("../server/registry");
16
+ const envUtils_1 = require("../utils/envUtils");
16
17
  const ACTIVATION_GUIDE_VERSION = '1.0.0';
17
18
  (0, registry_1.registerHandler)('meta_activation_guide', () => {
19
+ const diagnosticsEnabled = (0, envUtils_1.dangerousDiagnosticsEnabled)();
20
+ const categories = {
21
+ instructionManagement: {
22
+ function: 'activate_instruction_management_and_operations_tools()',
23
+ description: 'Core instruction index operations: add, search, dispatch, remove, repair, import, normalize, reload',
24
+ tools: [
25
+ 'index_add',
26
+ 'index_dispatch',
27
+ 'index_search',
28
+ 'index_remove',
29
+ 'index_repair',
30
+ 'index_import',
31
+ 'index_health',
32
+ 'index_normalize',
33
+ 'index_reload',
34
+ 'usage_track',
35
+ 'usage_hotset',
36
+ 'manifest_refresh'
37
+ ],
38
+ toolCount: 12
39
+ },
40
+ graphAndSchema: {
41
+ function: 'activate_instruction_graph_and_schema_tools()',
42
+ description: 'Instruction graph export and JSON schema retrieval',
43
+ tools: ['graph_export', 'index_schema'],
44
+ toolCount: 2
45
+ },
46
+ governance: {
47
+ function: 'activate_governance_management_tools()',
48
+ description: 'Governance operations: enrich placeholder fields, compute/update governance hash',
49
+ tools: [
50
+ 'index_enrich',
51
+ 'index_governanceHash',
52
+ 'index_governanceUpdate'
53
+ ],
54
+ toolCount: 3
55
+ },
56
+ manifest: {
57
+ function: 'activate_manifest_management_tools()',
58
+ description: 'index manifest repair and status checks',
59
+ tools: ['manifest_repair', 'manifest_status'],
60
+ toolCount: 2
61
+ },
62
+ bootstrap: {
63
+ function: 'activate_bootstrap_management_tools()',
64
+ description: 'Bootstrap confirmation and finalization for guarded mutations',
65
+ tools: [
66
+ 'bootstrap_request',
67
+ 'bootstrap_confirmFinalize',
68
+ 'bootstrap_status'
69
+ ],
70
+ toolCount: 3
71
+ },
72
+ health: {
73
+ function: 'activate_feedback_and_health_monitoring_tools()',
74
+ description: 'Feedback submission and system health monitoring',
75
+ tools: [
76
+ 'feedback_submit',
77
+ 'health_check'
78
+ ],
79
+ toolCount: 2
80
+ }
81
+ };
82
+ if (diagnosticsEnabled) {
83
+ categories.diagnostics = {
84
+ function: 'activate_diagnostic_stress_testing_tools()',
85
+ description: 'CPU/memory/microtask stress testing for performance analysis',
86
+ tools: [
87
+ 'diagnostics_block',
88
+ 'diagnostics_memoryPressure',
89
+ 'diagnostics_microtaskFlood'
90
+ ],
91
+ toolCount: 3
92
+ };
93
+ }
18
94
  return {
19
95
  version: ACTIVATION_GUIDE_VERSION,
20
96
  generatedAt: new Date().toISOString(),
21
97
  problem: 'Index Server tools show as "disabled by the user" in VSCode even when properly configured in settings.json (chat.mcp.tools)',
22
98
  rootCause: 'Settings.json configuration provides permission framework but does NOT trigger actual tool enablement. Activation functions must be called explicitly.',
23
99
  solution: 'Call VSCode activation functions to enable tool categories. These functions are VSCode client-side features that must be invoked before using MCP tools.',
24
- categories: {
25
- instructionManagement: {
26
- function: 'activate_instruction_management_and_operations_tools()',
27
- description: 'Core instruction index operations: add, search, dispatch, remove, repair, import, normalize, reload',
28
- tools: [
29
- 'index_add',
30
- 'index_dispatch',
31
- 'index_search',
32
- 'index_remove',
33
- 'index_repair',
34
- 'index_import',
35
- 'index_health',
36
- 'index_normalize',
37
- 'index_reload',
38
- 'usage_track',
39
- 'usage_hotset',
40
- 'manifest_refresh'
41
- ],
42
- toolCount: 12
43
- },
44
- graphAndSchema: {
45
- function: 'activate_instruction_graph_and_schema_tools()',
46
- description: 'Instruction graph export and JSON schema retrieval',
47
- tools: ['graph_export', 'index_schema'],
48
- toolCount: 2
49
- },
50
- governance: {
51
- function: 'activate_governance_management_tools()',
52
- description: 'Governance operations: enrich placeholder fields, compute/update governance hash',
53
- tools: [
54
- 'index_enrich',
55
- 'index_governanceHash',
56
- 'index_governanceUpdate'
57
- ],
58
- toolCount: 3
59
- },
60
- manifest: {
61
- function: 'activate_manifest_management_tools()',
62
- description: 'index manifest repair and status checks',
63
- tools: ['manifest_repair', 'manifest_status'],
64
- toolCount: 2
65
- },
66
- bootstrap: {
67
- function: 'activate_bootstrap_management_tools()',
68
- description: 'Bootstrap confirmation and finalization for guarded mutations',
69
- tools: [
70
- 'bootstrap_request',
71
- 'bootstrap_confirmFinalize',
72
- 'bootstrap_status'
73
- ],
74
- toolCount: 3
75
- },
76
- diagnostics: {
77
- function: 'activate_diagnostic_stress_testing_tools()',
78
- description: 'CPU/memory/microtask stress testing for performance analysis',
79
- tools: [
80
- 'diagnostics_block',
81
- 'diagnostics_memoryPressure',
82
- 'diagnostics_microtaskFlood'
83
- ],
84
- toolCount: 3
85
- },
86
- health: {
87
- function: 'activate_feedback_and_health_monitoring_tools()',
88
- description: 'Feedback submission and system health monitoring',
89
- tools: [
90
- 'feedback_submit',
91
- 'feedback_list',
92
- 'feedback_health',
93
- 'feedback_stats',
94
- 'health_check'
95
- ],
96
- toolCount: 5
97
- }
98
- },
100
+ categories,
99
101
  quickStart: {
100
102
  step1: 'Identify which tool you need (e.g., index_search)',
101
103
  step2: 'Find matching category in activation categories above (e.g., instructionManagement)',
@@ -145,6 +147,7 @@ const ACTIVATION_GUIDE_VERSION = '1.0.0';
145
147
  };
146
148
  }
147
149
  // Map tool names to activation categories
150
+ const diagnosticsEnabled = (0, envUtils_1.dangerousDiagnosticsEnabled)();
148
151
  const toolMapping = {
149
152
  'index_add': { category: 'instructionManagement', function: 'activate_instruction_management_and_operations_tools' },
150
153
  'index_dispatch': { category: 'instructionManagement', function: 'activate_instruction_management_and_operations_tools' },
@@ -168,15 +171,14 @@ const ACTIVATION_GUIDE_VERSION = '1.0.0';
168
171
  'bootstrap_request': { category: 'bootstrap', function: 'activate_bootstrap_management_tools' },
169
172
  'bootstrap_confirmFinalize': { category: 'bootstrap', function: 'activate_bootstrap_management_tools' },
170
173
  'bootstrap_status': { category: 'bootstrap', function: 'activate_bootstrap_management_tools' },
171
- 'diagnostics_block': { category: 'diagnostics', function: 'activate_diagnostic_stress_testing_tools' },
172
- 'diagnostics_memoryPressure': { category: 'diagnostics', function: 'activate_diagnostic_stress_testing_tools' },
173
- 'diagnostics_microtaskFlood': { category: 'diagnostics', function: 'activate_diagnostic_stress_testing_tools' },
174
174
  'feedback_submit': { category: 'health', function: 'activate_feedback_and_health_monitoring_tools' },
175
- 'feedback_list': { category: 'health', function: 'activate_feedback_and_health_monitoring_tools' },
176
- 'feedback_health': { category: 'health', function: 'activate_feedback_and_health_monitoring_tools' },
177
- 'feedback_stats': { category: 'health', function: 'activate_feedback_and_health_monitoring_tools' },
178
175
  'health_check': { category: 'health', function: 'activate_feedback_and_health_monitoring_tools' }
179
176
  };
177
+ if (diagnosticsEnabled) {
178
+ toolMapping['diagnostics_block'] = { category: 'diagnostics', function: 'activate_diagnostic_stress_testing_tools' };
179
+ toolMapping['diagnostics_memoryPressure'] = { category: 'diagnostics', function: 'activate_diagnostic_stress_testing_tools' };
180
+ toolMapping['diagnostics_microtaskFlood'] = { category: 'diagnostics', function: 'activate_diagnostic_stress_testing_tools' };
181
+ }
180
182
  const mapping = toolMapping[toolName];
181
183
  if (!mapping) {
182
184
  return {
@@ -7,7 +7,7 @@
7
7
  * - Default semantics
8
8
  * - Category (core | dashboard | instructions | manifest | tracing | diagnostics | stress | usage | validation | auth | metrics | experimental)
9
9
  * - Description
10
- * - Stability (stable | diagnostic | experimental | deprecated | reserved)
10
+ * - Stability (stable | diagnostic | experimental | reserved)
11
11
  * - Since (version first introduced when known – best effort)
12
12
  *
13
13
  * The list is curated (not discovered dynamically) to ensure ordering stability and to include flags
@@ -18,7 +18,7 @@ export interface FlagMeta {
18
18
  name: string;
19
19
  category: string;
20
20
  description: string;
21
- stability: 'stable' | 'diagnostic' | 'experimental' | 'deprecated' | 'reserved';
21
+ stability: 'stable' | 'diagnostic' | 'experimental' | 'reserved';
22
22
  since?: string;
23
23
  default?: string;
24
24
  type?: 'boolean' | 'string' | 'number';
@@ -8,7 +8,7 @@ const envUtils_1 = require("../utils/envUtils");
8
8
  exports.FLAG_REGISTRY = [
9
9
  // Core operation & dashboard
10
10
  { name: 'INDEX_SERVER_DIR', category: 'core', description: 'Instructions catalog directory. Defaults to ./instructions relative to CWD.', stability: 'stable', default: './instructions', type: 'string', since: '1.0.0' },
11
- { name: 'INDEX_SERVER_MUTATION', category: 'core', description: 'Enable mutation tools (add/import/remove/enrich/governance updates).', stability: 'stable', default: 'off', type: 'boolean', since: '1.0.0' },
11
+ { name: 'INDEX_SERVER_MUTATION', category: 'core', description: 'Override mutation tools (unset or 1 = enabled, 0 = read-only).', stability: 'stable', default: 'on', type: 'boolean', since: '1.0.0' },
12
12
  { name: 'INDEX_SERVER_VERBOSE_LOGGING', category: 'core', description: 'Verbose logging (handshake, dispatch timings).', stability: 'stable', default: 'off', type: 'boolean', since: '1.0.0' },
13
13
  { name: 'INDEX_SERVER_LOG_DIAG', category: 'diagnostics', description: 'Diagnostic logging (lower-level/internal).', stability: 'diagnostic', default: 'off', type: 'boolean', since: '1.0.0' },
14
14
  { name: 'INDEX_SERVER_DASHBOARD', category: 'dashboard', description: 'Enable admin dashboard HTTP server.', stability: 'stable', default: 'off', type: 'boolean', since: '1.0.0' },
@@ -72,7 +72,6 @@ exports.FLAG_REGISTRY = [
72
72
  { name: 'INDEX_SERVER_MEMORY_MONITOR', category: 'diagnostics', description: 'Enable periodic memory usage sampling/logging.', stability: 'diagnostic', default: 'off', type: 'boolean', since: '1.1.0' },
73
73
  { name: 'INDEX_SERVER_LOG_MUTATION', category: 'diagnostics', description: 'Emit mutation-specific verbose logs.', stability: 'diagnostic', default: 'off', type: 'boolean', since: '1.1.0' },
74
74
  // Legacy / removed (for awareness; not parsed at runtime)
75
- { name: 'INDEX_SERVER_SHORTCIRCUIT', category: 'deprecated', description: 'Removed legacy short-circuit handshake path.', stability: 'deprecated', default: '(removed)', since: '<1.1.0' },
76
75
  // Multi-instance / leader-follower
77
76
  { name: 'INDEX_SERVER_MODE', category: 'multi-instance', description: 'Instance mode: standalone (default), leader, follower, auto.', stability: 'experimental', default: 'standalone', type: 'string', since: '1.8.5' },
78
77
  { name: 'INDEX_SERVER_LEADER_PORT', category: 'multi-instance', description: 'HTTP port for leader MCP transport (thin clients connect here).', stability: 'experimental', default: '9090', type: 'number', since: '1.8.5' },