@jagilber-org/index-server 1.28.10 → 1.28.19

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 (73) hide show
  1. package/CHANGELOG.md +109 -1
  2. package/CONTRIBUTING.md +13 -0
  3. package/README.md +10 -14
  4. package/dist/config/featureConfig.js +4 -1
  5. package/dist/dashboard/client/admin.html +69 -29
  6. package/dist/dashboard/client/js/admin.embeddings.js +97 -5
  7. package/dist/dashboard/client/js/admin.instructions.js +1 -1
  8. package/dist/dashboard/server/AdminPanel.js +38 -0
  9. package/dist/dashboard/server/ApiRoutes.js +14 -1
  10. package/dist/dashboard/server/routes/embeddings.routes.js +76 -1
  11. package/dist/dashboard/server/routes/instructions.routes.js +4 -11
  12. package/dist/dashboard/server/routes/scripts.routes.js +35 -10
  13. package/dist/dashboard/server/routes/status.routes.js +77 -0
  14. package/dist/models/instruction.d.ts +2 -1
  15. package/dist/models/instruction.js +2 -0
  16. package/dist/schemas/index-server.code-schema.json +52478 -0
  17. package/dist/schemas/index.d.ts +7 -164
  18. package/dist/schemas/index.js +45 -63
  19. package/dist/schemas/instructionSchema.d.ts +46 -0
  20. package/dist/schemas/instructionSchema.js +159 -0
  21. package/{schemas → dist/schemas}/json-schema/instruction-content-type.schema.json +6 -4
  22. package/{schemas → dist/schemas}/json-schema/instruction-instruction-entry.schema.json +6 -4
  23. package/dist/schemas/manifest.json +78 -0
  24. package/dist/server/index-server.js +7 -1
  25. package/dist/services/bootstrapGating.js +2 -2
  26. package/dist/services/handlers/instructions.add.js +18 -0
  27. package/dist/services/handlers/instructions.groom.js +6 -1
  28. package/dist/services/handlers/instructions.import.js +42 -7
  29. package/dist/services/handlers.activation.js +3 -1
  30. package/dist/services/handlers.dashboardConfig.js +2 -1
  31. package/dist/services/handlers.feedback.d.ts +4 -4
  32. package/dist/services/handlers.feedback.js +390 -27
  33. package/dist/services/handlers.instructionSchema.js +73 -31
  34. package/dist/services/handlers.search.js +11 -6
  35. package/dist/services/indexLoader.js +7 -0
  36. package/dist/services/instructionRecordValidation.js +32 -84
  37. package/dist/services/mcpConfig/flagCatalog.d.ts +1 -1
  38. package/dist/services/mcpConfig/flagCatalog.js +2 -0
  39. package/dist/services/mcpConfig/formats.js +2 -6
  40. package/dist/services/seedBootstrap.contentModel.d.ts +13 -0
  41. package/dist/services/seedBootstrap.contentModel.js +166 -0
  42. package/dist/services/seedBootstrap.contentTypes.d.ts +5 -0
  43. package/dist/services/seedBootstrap.contentTypes.js +76 -0
  44. package/dist/services/seedBootstrap.d.ts +1 -0
  45. package/dist/services/seedBootstrap.js +87 -10
  46. package/dist/services/toolRegistry.js +52 -24
  47. package/dist/services/toolRegistry.zod.js +84 -37
  48. package/dist/versioning/schemaVersion.d.ts +1 -1
  49. package/dist/versioning/schemaVersion.js +1 -13
  50. package/package.json +17 -3
  51. package/schemas/index-server.code-schema.json +31019 -25047
  52. package/schemas/instruction.schema.json +16 -6
  53. package/schemas/manifest.json +3 -3
  54. package/scripts/README.md +20 -0
  55. package/scripts/build/README.md +41 -0
  56. package/scripts/build/setup-wizard-paths.mjs +27 -0
  57. package/scripts/build/setup-wizard.mjs +7 -21
  58. package/scripts/client/README.md +26 -0
  59. package/scripts/client/index-server-client.ps1 +203 -0
  60. package/scripts/client/index-server-client.sh +149 -0
  61. package/scripts/client/powershell-mcp-server.ps1 +83 -0
  62. package/scripts/client/powershell-mcp-template.ps1 +85 -0
  63. package/scripts/hooks/README.md +40 -0
  64. package/server.json +2 -2
  65. /package/{schemas → dist/schemas}/json-schema/SessionPersistence-persisted-admin-session.schema.json +0 -0
  66. /package/{schemas → dist/schemas}/json-schema/SessionPersistence-persisted-session-history-entry.schema.json +0 -0
  67. /package/{schemas → dist/schemas}/json-schema/SessionPersistence-persisted-web-socket-connection.schema.json +0 -0
  68. /package/{schemas → dist/schemas}/json-schema/SessionPersistence-session-persistence-config.schema.json +0 -0
  69. /package/{schemas → dist/schemas}/json-schema/SessionPersistence-session-persistence-data.schema.json +0 -0
  70. /package/{schemas → dist/schemas}/json-schema/SessionPersistence-session-persistence-manifest.schema.json +0 -0
  71. /package/{schemas → dist/schemas}/json-schema/SessionPersistence-session-persistence-metadata.schema.json +0 -0
  72. /package/{schemas → dist/schemas}/json-schema/instruction-audience-scope.schema.json +0 -0
  73. /package/{schemas → dist/schemas}/json-schema/instruction-requirement-level.schema.json +0 -0
@@ -6,6 +6,8 @@ exports.hasZodSchema = hasZodSchema;
6
6
  const zod_1 = require("zod");
7
7
  const toolRegistry_1 = require("./toolRegistry");
8
8
  const runtimeConfig_1 = require("../config/runtimeConfig");
9
+ const instructionSchema_1 = require("../schemas/instructionSchema");
10
+ const instruction_1 = require("../models/instruction");
9
11
  /**
10
12
  * Complete Zod schema registry for all MCP index tools.
11
13
  * Zod schemas provide runtime validation with richer type inference.
@@ -35,7 +37,7 @@ const zDispatch = zod_1.z.object({
35
37
  keywords: zod_1.z.array(zod_1.z.string()).optional(),
36
38
  ids: zod_1.z.array(zod_1.z.string()).optional(),
37
39
  category: zod_1.z.string().optional(),
38
- contentType: zod_1.z.enum(['instruction', 'template', 'workflow', 'reference', 'example', 'agent', 'chat-session']).optional(),
40
+ contentType: zod_1.z.enum(instruction_1.CONTENT_TYPES).optional(),
39
41
  text: zod_1.z.string().optional(),
40
42
  includeCategories: zod_1.z.boolean().optional(),
41
43
  caseSensitive: zod_1.z.boolean().optional(),
@@ -77,53 +79,82 @@ const zDispatch = zod_1.z.object({
77
79
  function zInstructionBody() {
78
80
  return zod_1.z.string().min(1).max((0, runtimeConfig_1.getRuntimeConfig)().index.bodyWarnLength);
79
81
  }
80
- function buildZIndexEntry() {
81
- return zod_1.z.object({
82
+ /**
83
+ * Per-field Zod refinements for the canonical INPUT_KEYS surface.
84
+ *
85
+ * The canonical schema (schemas/instruction.schema.json) is the single
86
+ * source of truth for which fields callers may submit on `index_add` /
87
+ * `index_import`. The Ajv `validateInput` validator (compiled from that
88
+ * canonical schema) is the authoritative type/format/length gate and runs
89
+ * inside the handler.
90
+ *
91
+ * This Zod schema sits in front of the handler in the default validation
92
+ * mode (transport.validateParams). Its job is therefore narrow:
93
+ *
94
+ * 1. Accept EVERY canonical input field — never reject a field the
95
+ * canonical INPUT_SCHEMA accepts.
96
+ * 2. Reject truly unknown top-level entry keys (`.strict()`).
97
+ * 3. Provide light, fast checks (string length on body, enum on
98
+ * audience/etc.) so obvious garbage fails before the handler runs.
99
+ *
100
+ * Anything missing from this map is still accepted (as `unknown`) — the
101
+ * canonical Ajv validator will reject malformed payloads with the precise
102
+ * JSON-Schema error.
103
+ */
104
+ function buildEntryShape() {
105
+ const refinements = {
82
106
  id: zod_1.z.string().min(1),
83
- title: zod_1.z.string().min(1).optional(),
107
+ title: zod_1.z.string().min(1),
84
108
  body: zInstructionBody(),
85
- rationale: zod_1.z.string().optional(),
86
- priority: zod_1.z.number().int().min(1).max(100).optional(),
87
- audience: zod_1.z.string().optional(),
88
- requirement: zod_1.z.string().optional(),
89
- categories: zod_1.z.array(zod_1.z.string()).max(50).optional(),
90
- deprecatedBy: zod_1.z.string().optional(),
91
- riskScore: zod_1.z.number().optional(),
92
- version: zod_1.z.string().optional(),
93
- owner: zod_1.z.string().optional(),
94
- status: zod_1.z.enum(['approved', 'draft', 'review', 'deprecated']).optional(),
95
- priorityTier: zod_1.z.enum(['P1', 'P2', 'P3', 'P4']).optional(),
96
- classification: zod_1.z.enum(['public', 'internal', 'restricted']).optional(),
97
- lastReviewedAt: zod_1.z.string().optional(),
98
- nextReviewDue: zod_1.z.string().optional(),
99
- semanticSummary: zod_1.z.string().optional(),
100
- changeLog: zod_1.z.array(zod_1.z.object({}).passthrough()).optional(),
101
- contentType: zod_1.z.enum(['instruction', 'template', 'workflow', 'reference', 'example', 'agent', 'chat-session']).optional(),
102
- extensions: zod_1.z.record(zod_1.z.string(), zExtensionValue).optional()
103
- }).strict();
109
+ rationale: zod_1.z.string(),
110
+ priority: zod_1.z.number().int().min(1).max(100),
111
+ audience: zod_1.z.string(),
112
+ requirement: zod_1.z.string(),
113
+ categories: zod_1.z.array(zod_1.z.string()).max(50),
114
+ deprecatedBy: zod_1.z.string(),
115
+ riskScore: zod_1.z.number(),
116
+ version: zod_1.z.string(),
117
+ owner: zod_1.z.string(),
118
+ status: zod_1.z.enum(['approved', 'draft', 'review', 'deprecated']),
119
+ priorityTier: zod_1.z.enum(['P1', 'P2', 'P3', 'P4']),
120
+ classification: zod_1.z.enum(['public', 'internal', 'restricted']),
121
+ lastReviewedAt: zod_1.z.string(),
122
+ nextReviewDue: zod_1.z.string(),
123
+ semanticSummary: zod_1.z.string(),
124
+ changeLog: zod_1.z.array(zod_1.z.object({}).passthrough()),
125
+ contentType: zod_1.z.enum(instruction_1.CONTENT_TYPES),
126
+ extensions: zod_1.z.record(zod_1.z.string(), zExtensionValue),
127
+ };
128
+ const shape = {};
129
+ for (const key of instructionSchema_1.INPUT_KEYS) {
130
+ // Server-managed keys must never appear in the input shape.
131
+ if (instructionSchema_1.SERVER_MANAGED_KEYS.has(key))
132
+ continue;
133
+ const refined = refinements[key] ?? zod_1.z.unknown();
134
+ shape[key] = instructionSchema_1.REQUIRED_INPUT_KEYS.has(key) ? refined : refined.optional();
135
+ }
136
+ return shape;
104
137
  }
105
138
  function buildZAdd() {
139
+ // index_add allows the handler to default required fields (e.g. priority,
140
+ // audience), so the entry contract here mirrors the canonical surface but
141
+ // does NOT enforce REQUIRED_INPUT_KEYS at the Zod layer. The handler /
142
+ // canonical Ajv `validateInput` apply the per-tool required[] minimum.
143
+ const entry = zod_1.z.object(Object.fromEntries(Object.entries(buildEntryShape()).map(([k, v]) => {
144
+ const t = v;
145
+ return [k, t.isOptional() ? t : t.optional()];
146
+ }))).strict();
106
147
  return zod_1.z.object({
107
- entry: buildZIndexEntry(),
148
+ entry,
108
149
  overwrite: zod_1.z.boolean().optional(),
109
150
  lax: zod_1.z.boolean().optional()
110
151
  }).strict();
111
152
  }
112
153
  function buildZImport() {
154
+ const entryItem = zod_1.z.object(buildEntryShape()).strict();
113
155
  return zod_1.z.object({
114
156
  entries: zod_1.z.union([
115
- zod_1.z.array(zod_1.z.object({
116
- id: zod_1.z.string(),
117
- title: zod_1.z.string(),
118
- body: zInstructionBody(),
119
- rationale: zod_1.z.string().optional(),
120
- priority: zod_1.z.number(),
121
- audience: zod_1.z.string(),
122
- requirement: zod_1.z.string(),
123
- categories: zod_1.z.array(zod_1.z.string()).optional(),
124
- extensions: zod_1.z.record(zod_1.z.string(), zExtensionValue).optional(),
125
- mode: zod_1.z.string().optional()
126
- }).passthrough()).min(1),
157
+ zod_1.z.array(entryItem).min(1),
127
158
  zod_1.z.string()
128
159
  ]).optional(),
129
160
  source: zod_1.z.string().optional(),
@@ -166,7 +197,7 @@ const zSearch = zod_1.z.object({
166
197
  limit: zod_1.z.number().int().min(1).max(100).default(50).optional(),
167
198
  includeCategories: zod_1.z.boolean().default(false).optional(),
168
199
  caseSensitive: zod_1.z.boolean().default(false).optional(),
169
- contentType: zod_1.z.enum(['instruction', 'template', 'workflow', 'reference', 'example', 'agent']).optional()
200
+ contentType: zod_1.z.enum(instruction_1.CONTENT_TYPES).optional()
170
201
  }).strict();
171
202
  // ── Diagnostics ──────────────────────────────────────────────────────────────
172
203
  const zDiagnostics = zod_1.z.object({
@@ -182,6 +213,21 @@ const zFeedbackSubmit = zod_1.z.object({
182
213
  metadata: zod_1.z.object({}).passthrough().optional(),
183
214
  tags: zod_1.z.array(zod_1.z.string()).max(10).optional()
184
215
  }).strict();
216
+ const zFeedbackManage = zod_1.z.object({
217
+ action: zod_1.z.enum(['submit', 'list', 'get', 'update', 'delete', 'stats']),
218
+ id: zod_1.z.string().min(1).optional(),
219
+ type: zod_1.z.enum(['issue', 'status', 'security', 'feature-request', 'bug-report', 'performance', 'usability', 'other']).optional(),
220
+ severity: zod_1.z.enum(['low', 'medium', 'high', 'critical']).optional(),
221
+ status: zod_1.z.enum(['new', 'acknowledged', 'in-progress', 'resolved', 'closed']).optional(),
222
+ title: zod_1.z.string().min(1).max(200).optional(),
223
+ description: zod_1.z.string().min(1).max(10000).optional(),
224
+ context: zod_1.z.object({}).passthrough().optional(),
225
+ metadata: zod_1.z.object({}).passthrough().optional(),
226
+ tags: zod_1.z.array(zod_1.z.string()).max(10).optional(),
227
+ limit: zod_1.z.number().int().min(1).max(200).optional(),
228
+ offset: zod_1.z.number().int().min(0).optional(),
229
+ since: zod_1.z.string().optional()
230
+ }).strict();
185
231
  // ── Usage ────────────────────────────────────────────────────────────────────
186
232
  const zUsageTrack = zod_1.z.object({
187
233
  id: zod_1.z.string().min(1),
@@ -277,6 +323,7 @@ const zodMap = {
277
323
  'index_schema': zEmpty,
278
324
  // Admin tools
279
325
  'feedback_submit': zFeedbackSubmit,
326
+ 'feedback_manage': zFeedbackManage,
280
327
  'meta_tools': zEmpty,
281
328
  'meta_activation_guide': zEmpty,
282
329
  'meta_check_activation': zMetaCheckActivation,
@@ -1,4 +1,4 @@
1
- export declare const SCHEMA_VERSION = "5";
1
+ export declare const SCHEMA_VERSION = "6";
2
2
  export interface MigrationResult {
3
3
  changed: boolean;
4
4
  notes?: string[];
@@ -6,7 +6,7 @@ exports.migrateInstructionRecord = migrateInstructionRecord;
6
6
  // Bump this when making a backward-incompatible on-disk schema change that
7
7
  // requires a migration rewrite. Migration logic should detect older versions
8
8
  // and transform + persist them once.
9
- exports.SCHEMA_VERSION = '5';
9
+ exports.SCHEMA_VERSION = '6';
10
10
  // Helper function for review interval computation (matches ClassificationService logic)
11
11
  function computeReviewIntervalDays(tier, requirement) {
12
12
  // Shorter intervals for higher criticality
@@ -57,14 +57,6 @@ function migrateInstructionRecord(rec) {
57
57
  // no-op: optional metadata fields are already valid if present
58
58
  notes.push('v3→v4: added optional metadata fields to schema');
59
59
  }
60
- // v4 → v5 migration: public persisted contentType "chat-session" was renamed
61
- // to "workflow". Preserve the workflow/runbook semantics instead of falling
62
- // through the generic invalid-enum fallback to "instruction".
63
- if (prevVersion === '4' && rec.contentType === 'chat-session') {
64
- rec.contentType = 'workflow';
65
- changed = true;
66
- notes.push('v4→v5: migrated legacy contentType "chat-session" to "workflow"');
67
- }
68
60
  // Clean optional nullable fields that upstream tools may emit as null
69
61
  // (riskScore must be number or absent — null causes AJV rejection)
70
62
  if ('riskScore' in rec && rec.riskScore === null) {
@@ -107,13 +99,9 @@ function migrateInstructionRecord(rec) {
107
99
  CRITICAL: 'critical', OPTIONAL: 'optional', MANDATORY: 'mandatory',
108
100
  DEPRECATED: 'deprecated', REQUIRED: 'mandatory',
109
101
  };
110
- const legacyContentTypeMap = {
111
- 'chat-session': 'workflow',
112
- };
113
102
  const enumDefaults = {
114
103
  audience: { valid: ['individual', 'group', 'all'], fallback: 'all', legacy: legacyAudienceMap },
115
104
  requirement: { valid: ['mandatory', 'critical', 'recommended', 'optional', 'deprecated'], fallback: 'optional', legacy: legacyRequirementMap },
116
- contentType: { valid: ['instruction', 'template', 'workflow', 'reference', 'example', 'agent'], fallback: 'instruction', legacy: legacyContentTypeMap },
117
105
  status: { valid: ['draft', 'review', 'approved', 'deprecated'], fallback: 'draft', legacy: legacyStatusMap },
118
106
  priorityTier: { valid: ['P1', 'P2', 'P3', 'P4'], fallback: 'P3' },
119
107
  classification: { valid: ['public', 'internal', 'restricted'], fallback: 'internal' },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jagilber-org/index-server",
3
- "version": "1.28.10",
3
+ "version": "1.28.19",
4
4
  "mcpName": "io.github.jagilber-org/index-server",
5
5
  "description": "MCP instruction indexing server with search, CRUD, validation, and cross-repo knowledge promotion.",
6
6
  "publishConfig": {
@@ -15,11 +15,15 @@
15
15
  "dist/",
16
16
  "!dist/tests/",
17
17
  "schemas/",
18
+ "!schemas/json-schema/",
19
+ "!schemas/archive/",
18
20
  "templates/",
21
+ "scripts/client/",
19
22
  "scripts/build/copy-dashboard-assets.mjs",
20
23
  "scripts/hooks/setup-hooks.cjs",
21
24
  "scripts/build/generate-certs.mjs",
22
25
  "scripts/build/setup-wizard.mjs",
26
+ "scripts/build/setup-wizard-paths.mjs",
23
27
  "server.json",
24
28
  "README.md",
25
29
  "LICENSE",
@@ -35,11 +39,12 @@
35
39
  "scripts": {
36
40
  "setup": "node scripts/build/setup-wizard.mjs",
37
41
  "instructions:normalize": "node scripts/migration/normalize-instructions.js",
38
- "build": "tsc -p tsconfig.json && node scripts/build/copy-dashboard-assets.mjs",
42
+ "build": "tsc -p tsconfig.json && node scripts/build/copy-dashboard-assets.mjs && node scripts/build/generate-tools-doc.mjs && node scripts/build/generate-tools-snapshot.mjs && node scripts/build/generate-schemas.mjs",
39
43
  "start": "node dist/server/index-server.js",
40
44
  "start-minimal": "node dist/minimal/index.js",
41
45
  "prestart": "npm run build",
42
46
  "pretest": "node scripts/testing/pretest-build-or-skip.mjs",
47
+ "build:ci": "node scripts/build/ci-build.mjs",
43
48
  "dev": "cross-env NODE_ENV=development node --watch dist/server/index-server.js",
44
49
  "build:watch": "tsc -w -p tsconfig.json",
45
50
  "check:dist": "npm run build && git diff --quiet --exit-code dist || (echo 'Dist out of date. Run npm run build and commit generated files.' && exit 1)",
@@ -82,14 +87,20 @@
82
87
  "perf:ci": "npm run perf:drift && npm run perf:trend && npm run perf:summary",
83
88
  "guard:env": "ts-node scripts/governance/enforce-config-usage.ts",
84
89
  "build:verify": "npm run typecheck && npm run build && npm run test:fast && npm run guard:env && npm run guard:decl",
90
+ "validate": "npm run build:verify",
91
+ "validate:template": "pwsh -NoProfile -File scripts/governance/validate-template-metadata.ps1 -RequireRepoAdoptionMatch",
92
+ "hooks:test": "pwsh -NoProfile -File scripts/testing/test-hook-regressions.ps1",
85
93
  "test:unit": "vitest run --config vitest.config.unit.ts",
86
94
  "test:unit:watch": "vitest --config vitest.config.unit.ts",
87
95
  "test:fast": "node scripts/testing/test-fast.mjs",
88
96
  "test:slow": "node scripts/testing/test-slow.mjs",
89
97
  "docs:tools": "node scripts/build/generate-tools-doc.mjs",
98
+ "schemas:generate": "node scripts/build/generate-schemas.mjs",
90
99
  "health:check": "node scripts/diagnostics/health-check.mjs",
91
100
  "guard:skips": "node scripts/governance/check-no-skips.mjs",
92
101
  "guard:baseline": "node scripts/governance/guard-baseline.mjs",
102
+ "guard:coverage": "node scripts/governance/check-coverage.mjs",
103
+ "guard:all": "npm run guard:env && npm run guard:skips && npm run guard:baseline && npm run guard:decl && npm run lint:instructions && npm run verify:manifest",
93
104
  "baseline:sentinel:update": "node scripts/governance/baseline-sentinel.mjs update",
94
105
  "baseline:sentinel:verify": "node scripts/governance/baseline-sentinel.mjs verify",
95
106
  "guard:decl": "node scripts/governance/guard-declarations.mjs",
@@ -147,7 +158,10 @@
147
158
  "@mermaid-js/layout-elk": {
148
159
  "uuid": "^14.0.0"
149
160
  },
150
- "@types/express-serve-static-core": "5.0.7"
161
+ "@types/express-serve-static-core": "5.0.7",
162
+ "fast-uri": "^3.1.2",
163
+ "hono": "^4.12.18",
164
+ "ip-address": "^10.1.1"
151
165
  },
152
166
  "optionalScripts": {},
153
167
  "promptReviewCriteriaVersion": "1.0.0",