@jagilber-org/index-server 1.27.2 → 1.28.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.
- package/CHANGELOG.md +47 -1
- package/CONTRIBUTING.md +3 -3
- package/dist/dashboard/client/admin.html +28 -28
- package/dist/dashboard/client/js/admin.feedback.js +1 -1
- package/dist/dashboard/client/js/admin.instructions.js +1 -1
- package/dist/dashboard/security/SecurityMonitor.js +2 -2
- package/dist/dashboard/server/AdminPanelState.js +5 -1
- package/dist/dashboard/server/ApiRoutes.js +2 -1
- package/dist/dashboard/server/MetricsCollector.js +3 -2
- package/dist/dashboard/server/WebSocketManager.js +2 -2
- package/dist/dashboard/server/middleware/ensureLoadedMiddleware.d.ts +1 -1
- package/dist/dashboard/server/middleware/ensureLoadedMiddleware.js +1 -1
- package/dist/dashboard/server/routes/api.usage.routes.js +5 -1
- package/dist/dashboard/server/routes/instructions.routes.js +142 -12
- package/dist/dashboard/server/routes/scripts.routes.js +1 -1
- package/dist/dashboard/server/routes/sqlite.routes.js +74 -0
- package/dist/models/instruction.d.ts +1 -1
- package/dist/schemas/index.d.ts +1 -1
- package/dist/schemas/index.js +1 -1
- package/dist/server/index-server.js +1 -1
- package/dist/services/auditLog.d.ts +1 -1
- package/dist/services/auditLog.js +1 -1
- package/dist/services/feedbackStorage.js +1 -1
- package/dist/services/handlers/instructions.add.js +36 -3
- package/dist/services/handlers.feedback.js +1 -1
- package/dist/services/handlers.instructionSchema.js +4 -4
- package/dist/services/handlers.search.js +3 -3
- package/dist/services/instructionRecordValidation.d.ts +3 -0
- package/dist/services/instructionRecordValidation.js +64 -4
- package/dist/services/seedBootstrap.js +2 -2
- package/dist/services/toolRegistry.js +8 -8
- package/dist/services/toolRegistry.zod.js +3 -3
- package/dist/versioning/schemaVersion.d.ts +1 -1
- package/dist/versioning/schemaVersion.js +47 -2
- package/package.json +44 -40
- package/schemas/index-server.code-schema.json +1 -1
- package/schemas/instruction.schema.json +3 -3
- package/schemas/json-schema/instruction-content-type.schema.json +1 -1
- package/schemas/json-schema/instruction-instruction-entry.schema.json +1 -1
- package/scripts/README.md +48 -0
- package/scripts/{generate-certs.mjs → build/generate-certs.mjs} +1 -1
- package/scripts/{setup-wizard.mjs → build/setup-wizard.mjs} +1 -1
- package/scripts/{setup-hooks.cjs → hooks/setup-hooks.cjs} +3 -3
- package/server.json +2 -2
- /package/scripts/{copy-dashboard-assets.mjs → build/copy-dashboard-assets.mjs} +0 -0
|
@@ -566,5 +566,79 @@ function createSqliteRoutes() {
|
|
|
566
566
|
return res.status(code).json({ success: false, error: err.message });
|
|
567
567
|
}
|
|
568
568
|
});
|
|
569
|
+
// ── Validation ────────────────────────────────────────────────────────
|
|
570
|
+
/** GET /sqlite/validate — Comprehensive database validation (read-only) */
|
|
571
|
+
router.get('/sqlite/validate', adminAuth_js_1.dashboardAdminAuth, (_req, res) => {
|
|
572
|
+
try {
|
|
573
|
+
assertSqliteActive();
|
|
574
|
+
const sqlitePath = getSqlitePath();
|
|
575
|
+
const db = new node_sqlite_1.DatabaseSync(sqlitePath, { readOnly: true });
|
|
576
|
+
const checks = [];
|
|
577
|
+
try {
|
|
578
|
+
// 1. Integrity check
|
|
579
|
+
const intRows = db.prepare('PRAGMA integrity_check').all();
|
|
580
|
+
const intOk = intRows.length === 1 && intRows[0].integrity_check === 'ok';
|
|
581
|
+
checks.push({ name: 'integrity_check', pass: intOk, detail: intOk ? 'ok' : JSON.stringify(intRows) });
|
|
582
|
+
// 2. Table counts
|
|
583
|
+
const instrCount = db.prepare('SELECT COUNT(*) as cnt FROM instructions').get()?.cnt ?? 0;
|
|
584
|
+
checks.push({ name: 'instructions_exist', pass: instrCount >= 0, detail: `count=${instrCount}` });
|
|
585
|
+
// 3. FTS5 sync
|
|
586
|
+
let ftsCount = -1;
|
|
587
|
+
try {
|
|
588
|
+
ftsCount = db.prepare('SELECT COUNT(*) as cnt FROM instructions_fts').get()?.cnt ?? -1;
|
|
589
|
+
checks.push({ name: 'fts5_sync', pass: ftsCount === instrCount, detail: `instructions=${instrCount}, fts=${ftsCount}` });
|
|
590
|
+
}
|
|
591
|
+
catch {
|
|
592
|
+
checks.push({ name: 'fts5_sync', pass: false, detail: 'FTS5 table not accessible' });
|
|
593
|
+
}
|
|
594
|
+
// 4. Orphaned usage records
|
|
595
|
+
try {
|
|
596
|
+
const orphanUsage = db.prepare('SELECT COUNT(*) as cnt FROM usage WHERE instruction_id NOT IN (SELECT id FROM instructions)').get()?.cnt ?? 0;
|
|
597
|
+
checks.push({ name: 'usage_no_orphans', pass: orphanUsage === 0, detail: `orphans=${orphanUsage}` });
|
|
598
|
+
}
|
|
599
|
+
catch {
|
|
600
|
+
checks.push({ name: 'usage_no_orphans', pass: true, detail: 'usage table not present (ok)' });
|
|
601
|
+
}
|
|
602
|
+
// 5. Embedding consistency
|
|
603
|
+
try {
|
|
604
|
+
const embCount = db.prepare('SELECT COUNT(*) as cnt FROM embeddings').get()?.cnt ?? 0;
|
|
605
|
+
const embMetaCount = db.prepare('SELECT COUNT(*) as cnt FROM embedding_meta').get()?.cnt ?? 0;
|
|
606
|
+
checks.push({ name: 'embedding_meta_sync', pass: embCount === embMetaCount, detail: `embeddings=${embCount}, meta=${embMetaCount}` });
|
|
607
|
+
const orphanEmb = db.prepare('SELECT COUNT(*) as cnt FROM embedding_meta WHERE instruction_id NOT IN (SELECT id FROM instructions)').get()?.cnt ?? 0;
|
|
608
|
+
checks.push({ name: 'embedding_no_orphans', pass: orphanEmb === 0, detail: `orphans=${orphanEmb}` });
|
|
609
|
+
}
|
|
610
|
+
catch {
|
|
611
|
+
checks.push({ name: 'embedding_meta_sync', pass: true, detail: 'embedding tables not present (ok)' });
|
|
612
|
+
}
|
|
613
|
+
// 6. NULL required fields
|
|
614
|
+
const nullIds = db.prepare("SELECT COUNT(*) as cnt FROM instructions WHERE id IS NULL OR id = ''").get()?.cnt ?? 0;
|
|
615
|
+
checks.push({ name: 'no_null_ids', pass: nullIds === 0, detail: `count=${nullIds}` });
|
|
616
|
+
const nullTitles = db.prepare("SELECT COUNT(*) as cnt FROM instructions WHERE title IS NULL OR title = ''").get()?.cnt ?? 0;
|
|
617
|
+
checks.push({ name: 'no_null_titles', pass: nullTitles === 0, detail: `count=${nullTitles}` });
|
|
618
|
+
const nullBodies = db.prepare("SELECT COUNT(*) as cnt FROM instructions WHERE body IS NULL OR body = ''").get()?.cnt ?? 0;
|
|
619
|
+
checks.push({ name: 'no_null_bodies', pass: nullBodies === 0, detail: `count=${nullBodies}` });
|
|
620
|
+
// 7. WAL mode
|
|
621
|
+
const jm = db.prepare('PRAGMA journal_mode').get();
|
|
622
|
+
const isWal = jm?.journal_mode === 'wal';
|
|
623
|
+
checks.push({ name: 'wal_mode', pass: isWal, detail: `journal_mode=${jm?.journal_mode ?? 'unknown'}` });
|
|
624
|
+
const allPass = checks.every(c => c.pass);
|
|
625
|
+
return res.json({
|
|
626
|
+
success: true,
|
|
627
|
+
valid: allPass,
|
|
628
|
+
totalChecks: checks.length,
|
|
629
|
+
passed: checks.filter(c => c.pass).length,
|
|
630
|
+
failed: checks.filter(c => !c.pass).length,
|
|
631
|
+
checks,
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
finally {
|
|
635
|
+
db.close();
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
catch (err) {
|
|
639
|
+
const code = err.statusCode ?? 500;
|
|
640
|
+
return res.status(code).json({ success: false, error: err.message });
|
|
641
|
+
}
|
|
642
|
+
});
|
|
569
643
|
return router;
|
|
570
644
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export type AudienceScope = 'individual' | 'group' | 'all';
|
|
2
2
|
export type RequirementLevel = 'mandatory' | 'critical' | 'recommended' | 'optional' | 'deprecated';
|
|
3
|
-
export type ContentType = 'instruction' | 'template' | '
|
|
3
|
+
export type ContentType = 'instruction' | 'template' | 'workflow' | 'reference' | 'example' | 'agent';
|
|
4
4
|
export interface InstructionEntry {
|
|
5
5
|
id: string;
|
|
6
6
|
title: string;
|
package/dist/schemas/index.d.ts
CHANGED
|
@@ -98,7 +98,7 @@ export declare const instructionEntry: {
|
|
|
98
98
|
};
|
|
99
99
|
};
|
|
100
100
|
readonly contentType: {
|
|
101
|
-
readonly enum: readonly ["instruction", "template", "
|
|
101
|
+
readonly enum: readonly ["instruction", "template", "workflow", "reference", "example", "agent"];
|
|
102
102
|
};
|
|
103
103
|
readonly version: {
|
|
104
104
|
readonly type: "string";
|
package/dist/schemas/index.js
CHANGED
|
@@ -44,7 +44,7 @@ exports.instructionEntry = {
|
|
|
44
44
|
workspaceId: { type: 'string' },
|
|
45
45
|
userId: { type: 'string' },
|
|
46
46
|
teamIds: { type: 'array', items: { type: 'string' } },
|
|
47
|
-
contentType: { enum: ['instruction', 'template', '
|
|
47
|
+
contentType: { enum: ['instruction', 'template', 'workflow', 'reference', 'example', 'agent'] },
|
|
48
48
|
version: { type: 'string' },
|
|
49
49
|
status: { enum: ['draft', 'review', 'approved', 'deprecated'] },
|
|
50
50
|
owner: { type: 'string' },
|
|
@@ -365,7 +365,7 @@ function parseArgs(argv) {
|
|
|
365
365
|
return config;
|
|
366
366
|
}
|
|
367
367
|
function launchSetupWizard(argv) {
|
|
368
|
-
const wizardPath = path_1.default.join(__dirname, '..', '..', 'scripts', 'setup-wizard.mjs');
|
|
368
|
+
const wizardPath = path_1.default.join(__dirname, '..', '..', 'scripts', 'build', 'setup-wizard.mjs');
|
|
369
369
|
// Forward all args after --setup/--configure to the wizard
|
|
370
370
|
const setupIdx = argv.findIndex(a => a === '--setup' || a === '--configure');
|
|
371
371
|
const forwardArgs = setupIdx >= 0 ? argv.slice(setupIdx + 1) : [];
|
|
@@ -4,7 +4,7 @@ export declare function runWithCorrelation<T>(correlationId: string, fn: () => T
|
|
|
4
4
|
export declare function getCurrentCorrelationId(): string | undefined;
|
|
5
5
|
/** Reset the cached audit log path, forcing re-resolution on next write. */
|
|
6
6
|
export declare function resetAuditLogCache(): void;
|
|
7
|
-
export type AuditKind = 'mutation' | 'read' | 'http';
|
|
7
|
+
export type AuditKind = 'mutation' | 'read' | 'http' | 'feedback';
|
|
8
8
|
export interface AuditEntry {
|
|
9
9
|
ts: string;
|
|
10
10
|
kind: AuditKind;
|
|
@@ -19,7 +19,7 @@ const logger_1 = require("./logger");
|
|
|
19
19
|
const toolRegistry_1 = require("./toolRegistry");
|
|
20
20
|
// Append-only JSONL audit log for all server operations.
|
|
21
21
|
// Each line: { ts, kind, action, ids?, meta? }
|
|
22
|
-
// kind: 'mutation' | 'read' | 'http' — classifies the entry type.
|
|
22
|
+
// kind: 'mutation' | 'read' | 'http' | 'feedback' — classifies the entry type.
|
|
23
23
|
// Path and enablement are driven by runtime configuration (instructions.auditLog).
|
|
24
24
|
// AsyncLocalStorage carries the correlation ID from registry wrapper into handler scope.
|
|
25
25
|
// This lets logAudit() calls inside handlers automatically include correlationId
|
|
@@ -83,6 +83,6 @@ function saveFeedbackStorage(storage) {
|
|
|
83
83
|
}
|
|
84
84
|
function generateFeedbackId(type, timestamp) {
|
|
85
85
|
const hash = (0, crypto_1.createHash)('sha256');
|
|
86
|
-
hash.update(`${type}-${timestamp}-${
|
|
86
|
+
hash.update(`${type}-${timestamp}-${(0, crypto_1.randomBytes)(8).toString('hex')}`);
|
|
87
87
|
return hash.digest('hex').substring(0, 16);
|
|
88
88
|
}
|
|
@@ -96,6 +96,22 @@ const instructions_shared_1 = require("./instructions.shared");
|
|
|
96
96
|
return { error: priorLoad };
|
|
97
97
|
return { error: { code: 'unknown', detail: 'missing-existing-entry', raw: 'missing-existing-entry' } };
|
|
98
98
|
};
|
|
99
|
+
const validateExistingCollisionFile = (filePath) => {
|
|
100
|
+
if (!fs_1.default.existsSync(filePath))
|
|
101
|
+
return [];
|
|
102
|
+
try {
|
|
103
|
+
const raw = JSON.parse(fs_1.default.readFileSync(filePath, 'utf8'));
|
|
104
|
+
const validationCandidate = { ...raw, schemaVersion: schemaVersion_1.SCHEMA_VERSION };
|
|
105
|
+
const validation = (0, instructionRecordValidation_1.validateInstructionRecord)(validationCandidate);
|
|
106
|
+
return validation.validationErrors
|
|
107
|
+
.filter((issue) => issue.includes('/classification'))
|
|
108
|
+
.map((issue) => (0, instructionRecordValidation_1.sanitizeErrorDetail)(issue) || 'existing entry failed validation');
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
const sanitized = (0, instructionRecordValidation_1.sanitizeLoadError)(err, 'parse_failed');
|
|
112
|
+
return [sanitized.detail];
|
|
113
|
+
}
|
|
114
|
+
};
|
|
99
115
|
const verifyReadBack = async (id, filePath, requestedCategories) => {
|
|
100
116
|
try {
|
|
101
117
|
(0, indexContext_1.invalidate)();
|
|
@@ -222,6 +238,12 @@ const instructions_shared_1 = require("./instructions.shared");
|
|
|
222
238
|
mutable.requirement = 'optional';
|
|
223
239
|
if (mutable.categories === undefined)
|
|
224
240
|
mutable.categories = [];
|
|
241
|
+
if (mutable.contentType === undefined)
|
|
242
|
+
mutable.contentType = 'instruction';
|
|
243
|
+
}
|
|
244
|
+
const surfaceValidation = (0, instructionRecordValidation_1.validateInstructionInputSurface)(e);
|
|
245
|
+
if (surfaceValidation.validationErrors.length) {
|
|
246
|
+
return failValidation('invalid_instruction', surfaceValidation.validationErrors, surfaceValidation.hints, { id: e.id });
|
|
225
247
|
}
|
|
226
248
|
const dir = (0, indexContext_1.getInstructionsDir)();
|
|
227
249
|
if (!fs_1.default.existsSync(dir))
|
|
@@ -257,9 +279,8 @@ const instructions_shared_1 = require("./instructions.shared");
|
|
|
257
279
|
e.title === undefined ? 'title: missing required field' : undefined,
|
|
258
280
|
e.body === undefined ? 'body: missing required field' : undefined,
|
|
259
281
|
].filter((issue) => !!issue);
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
return failValidation(requiredFieldErrors.length ? 'missing required fields' : 'invalid_instruction', [...requiredFieldErrors, ...surfaceValidation.validationErrors], surfaceValidation.hints, { id: e.id });
|
|
282
|
+
if (requiredFieldErrors.length) {
|
|
283
|
+
return failValidation('missing required fields', requiredFieldErrors, surfaceValidation.hints, { id: e.id });
|
|
263
284
|
}
|
|
264
285
|
const overwrite = !!p.overwrite;
|
|
265
286
|
const exists = overwrite ? ((await (0, indexContext_1.ensureLoadedAsync)()).byId.has(e.id) || fs_1.default.existsSync(file)) : false;
|
|
@@ -503,6 +524,18 @@ const instructions_shared_1 = require("./instructions.shared");
|
|
|
503
524
|
return failValidation('invalid_instruction', err.validationErrors, err.hints, { id: e.id });
|
|
504
525
|
}
|
|
505
526
|
if (!overwrite && (0, indexContext_1.isDuplicateInstructionWriteError)(err)) {
|
|
527
|
+
const existingValidationErrors = validateExistingCollisionFile(file);
|
|
528
|
+
if (existingValidationErrors.length) {
|
|
529
|
+
return {
|
|
530
|
+
id: e.id,
|
|
531
|
+
success: false,
|
|
532
|
+
skipped: false,
|
|
533
|
+
created: false,
|
|
534
|
+
overwritten: false,
|
|
535
|
+
error: 'existing_instruction_invalid',
|
|
536
|
+
validationErrors: existingValidationErrors,
|
|
537
|
+
};
|
|
538
|
+
}
|
|
506
539
|
let st0 = await (0, indexContext_1.ensureLoadedAsync)();
|
|
507
540
|
let visible = st0.byId.has(e.id);
|
|
508
541
|
let repaired = false;
|
|
@@ -71,7 +71,7 @@ function buildMinimalExample() {
|
|
|
71
71
|
categories: ["example", "documentation"],
|
|
72
72
|
primaryCategory: "example",
|
|
73
73
|
contentType: "instruction",
|
|
74
|
-
schemaVersion: "
|
|
74
|
+
schemaVersion: "5"
|
|
75
75
|
};
|
|
76
76
|
}
|
|
77
77
|
/**
|
|
@@ -89,7 +89,7 @@ function _buildComprehensiveExample() {
|
|
|
89
89
|
categories: ["example", "documentation", "governance"],
|
|
90
90
|
primaryCategory: "governance",
|
|
91
91
|
contentType: "instruction",
|
|
92
|
-
schemaVersion: "
|
|
92
|
+
schemaVersion: "5",
|
|
93
93
|
version: "1.0.0",
|
|
94
94
|
status: "approved",
|
|
95
95
|
owner: "platform-team",
|
|
@@ -170,8 +170,8 @@ function defineValidationRules() {
|
|
|
170
170
|
{ field: 'requirement', rule: 'Enum', constraint: 'One of: mandatory, critical, recommended, optional, deprecated' },
|
|
171
171
|
{ field: 'categories', rule: 'Array', constraint: '0-25 items, each 1-49 chars, lowercase, pattern: ^[a-z0-9][a-z0-9-_]{0,48}$' },
|
|
172
172
|
{ field: 'primaryCategory', rule: 'Reference', constraint: 'Must be a member of categories array if present' },
|
|
173
|
-
{ field: 'contentType', rule: 'Enum', constraint: 'One of: instruction (default), template,
|
|
174
|
-
{ field: 'schemaVersion', rule: 'Enum', constraint: 'Currently "
|
|
173
|
+
{ field: 'contentType', rule: 'Enum', constraint: 'One of: instruction (default), template, workflow, reference, example, agent' },
|
|
174
|
+
{ field: 'schemaVersion', rule: 'Enum', constraint: 'Currently "5"' },
|
|
175
175
|
{ field: 'sourceHash', rule: 'Pattern', constraint: 'SHA256 hex string (64 chars) when present' },
|
|
176
176
|
{ field: 'version', rule: 'Pattern', constraint: 'Semantic version: ^\\d+\\.\\d+\\.\\d+$ (e.g., "1.0.0")' },
|
|
177
177
|
{ field: 'status', rule: 'Enum', constraint: 'One of: draft, review, approved, deprecated' },
|
|
@@ -41,7 +41,7 @@ const SEARCH_SCHEMA = {
|
|
|
41
41
|
limit: { type: 'number', minimum: 1, maximum: 100, default: 50 },
|
|
42
42
|
includeCategories: { type: 'boolean', default: false },
|
|
43
43
|
caseSensitive: { type: 'boolean', default: false },
|
|
44
|
-
contentType: { type: 'string', enum: ['instruction', 'template', '
|
|
44
|
+
contentType: { type: 'string', enum: ['instruction', 'template', 'workflow', 'reference', 'example', 'agent'] }
|
|
45
45
|
},
|
|
46
46
|
example: { keywords: ['build', 'validate', 'discipline'], limit: 10, includeCategories: true }
|
|
47
47
|
};
|
|
@@ -394,7 +394,7 @@ function performSearch(params) {
|
|
|
394
394
|
const caseSensitive = params.caseSensitive ?? false;
|
|
395
395
|
const contentType = params.contentType;
|
|
396
396
|
// Validate contentType if provided
|
|
397
|
-
const validContentTypes = ['instruction', 'template', '
|
|
397
|
+
const validContentTypes = ['instruction', 'template', 'workflow', 'reference', 'example', 'agent'];
|
|
398
398
|
if (contentType && !validContentTypes.includes(contentType)) {
|
|
399
399
|
throw new Error(`Invalid contentType: must be one of ${validContentTypes.join(', ')}`);
|
|
400
400
|
}
|
|
@@ -556,7 +556,7 @@ async function handleInstructionsSearch(params) {
|
|
|
556
556
|
if (typeof params.contentType !== 'string') {
|
|
557
557
|
throw new Error('contentType must be a string');
|
|
558
558
|
}
|
|
559
|
-
const validContentTypes = ['instruction', 'template', '
|
|
559
|
+
const validContentTypes = ['instruction', 'template', 'workflow', 'reference', 'example', 'agent'];
|
|
560
560
|
if (!validContentTypes.includes(params.contentType)) {
|
|
561
561
|
throw new Error(`contentType must be one of: ${validContentTypes.join(', ')}`);
|
|
562
562
|
}
|
|
@@ -14,6 +14,9 @@ export declare class InstructionValidationError extends Error {
|
|
|
14
14
|
constructor(validationErrors: string[], hints?: string[], schemaRef?: string);
|
|
15
15
|
}
|
|
16
16
|
export declare const INSTRUCTION_ID_MAX_LENGTH = 120;
|
|
17
|
+
export declare const INSTRUCTION_ID_PATTERN: RegExp;
|
|
18
|
+
export declare function validateInstructionIdSurface(id: unknown): string[];
|
|
19
|
+
export declare function validateInstructionInputEnumMembership(entry: Record<string, unknown>): string[];
|
|
17
20
|
export declare function validateInstructionInputSurface(entry: Record<string, unknown>): InstructionValidationResult;
|
|
18
21
|
export declare function validateInstructionRecord(entry: InstructionEntry): InstructionValidationResult;
|
|
19
22
|
export declare function assertValidInstructionRecord(entry: InstructionEntry): InstructionEntry;
|
|
@@ -3,7 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.INSTRUCTION_INPUT_SCHEMA_REF = exports.INSTRUCTION_ID_MAX_LENGTH = exports.InstructionValidationError = void 0;
|
|
6
|
+
exports.INSTRUCTION_INPUT_SCHEMA_REF = exports.INSTRUCTION_ID_PATTERN = exports.INSTRUCTION_ID_MAX_LENGTH = exports.InstructionValidationError = void 0;
|
|
7
|
+
exports.validateInstructionIdSurface = validateInstructionIdSurface;
|
|
8
|
+
exports.validateInstructionInputEnumMembership = validateInstructionInputEnumMembership;
|
|
7
9
|
exports.validateInstructionInputSurface = validateInstructionInputSurface;
|
|
8
10
|
exports.validateInstructionRecord = validateInstructionRecord;
|
|
9
11
|
exports.assertValidInstructionRecord = assertValidInstructionRecord;
|
|
@@ -218,12 +220,16 @@ function applyWriteCompatibility(entry) {
|
|
|
218
220
|
else if (legacyRequirementMap[upper])
|
|
219
221
|
next.requirement = legacyRequirementMap[upper];
|
|
220
222
|
}
|
|
223
|
+
if (next.contentType === 'chat-session') {
|
|
224
|
+
next.contentType = 'workflow';
|
|
225
|
+
}
|
|
221
226
|
if (typeof next.priority !== 'number' || next.priority < 1 || next.priority > 100)
|
|
222
227
|
next.priority = 50;
|
|
223
228
|
return next;
|
|
224
229
|
}
|
|
225
230
|
// Matches the upper bound declared in schemas/instruction.schema.json (id maxLength).
|
|
226
231
|
exports.INSTRUCTION_ID_MAX_LENGTH = 120;
|
|
232
|
+
exports.INSTRUCTION_ID_PATTERN = /^[a-z0-9](?:[a-z0-9-_]{0,118}[a-z0-9])?$/;
|
|
227
233
|
function findIllegalControlChar(id) {
|
|
228
234
|
for (let i = 0; i < id.length; i++) {
|
|
229
235
|
const code = id.charCodeAt(i);
|
|
@@ -235,7 +241,7 @@ function findIllegalControlChar(id) {
|
|
|
235
241
|
}
|
|
236
242
|
return undefined;
|
|
237
243
|
}
|
|
238
|
-
function
|
|
244
|
+
function validateInstructionIdSurface(id) {
|
|
239
245
|
if (typeof id !== 'string' || !id.trim())
|
|
240
246
|
return ['id: missing required field'];
|
|
241
247
|
const illegal = findIllegalControlChar(id);
|
|
@@ -248,8 +254,48 @@ function validateIdSurface(id) {
|
|
|
248
254
|
if (id.includes('..') || id.includes('/') || id.includes('\\') || /[:*?"<>|]/.test(id)) {
|
|
249
255
|
return ['id: must be a safe instruction id without path traversal or path separators'];
|
|
250
256
|
}
|
|
257
|
+
if (!exports.INSTRUCTION_ID_PATTERN.test(id)) {
|
|
258
|
+
return ['id: must match /^[a-z0-9](?:[a-z0-9-_]{0,118}[a-z0-9])?$/ using lower-case ASCII letters, digits, hyphen, or underscore'];
|
|
259
|
+
}
|
|
251
260
|
return [];
|
|
252
261
|
}
|
|
262
|
+
// Enum membership checks for governance fields. These run at input-surface time so that
|
|
263
|
+
// invalid enum values are rejected early, before applyWriteCompatibility can silently
|
|
264
|
+
// coerce them (e.g. status:"active" → "approved", audience:"agents" → "group").
|
|
265
|
+
// However, values that ARE coercible by applyWriteCompatibility are accepted here to
|
|
266
|
+
// avoid rejecting inputs that would otherwise succeed after coercion.
|
|
267
|
+
const VALID_STATUS = ['approved', 'draft', 'review', 'deprecated'];
|
|
268
|
+
const COERCIBLE_STATUS = ['active'];
|
|
269
|
+
const VALID_PRIORITY_TIER = ['P1', 'P2', 'P3', 'P4'];
|
|
270
|
+
const VALID_CLASSIFICATION = ['public', 'internal', 'restricted'];
|
|
271
|
+
const VALID_CONTENT_TYPE = ['instruction', 'template', 'workflow', 'reference', 'example', 'agent'];
|
|
272
|
+
const COERCIBLE_CONTENT_TYPE = ['chat-session'];
|
|
273
|
+
const VALID_AUDIENCE = ['individual', 'group', 'all'];
|
|
274
|
+
const COERCIBLE_AUDIENCE = ['system', 'developers', 'developer', 'team', 'teams', 'users', 'dev', 'devs', 'testers', 'administrators', 'admins', 'agents', 'powershell script authors'];
|
|
275
|
+
const VALID_REQUIREMENT = ['mandatory', 'critical', 'recommended', 'optional', 'deprecated'];
|
|
276
|
+
const COERCIBLE_REQUIREMENT = ['MUST', 'SHOULD', 'MAY', 'CRITICAL', 'OPTIONAL', 'MANDATORY', 'DEPRECATED'];
|
|
277
|
+
function validateInstructionInputEnumMembership(entry) {
|
|
278
|
+
const errs = [];
|
|
279
|
+
if (typeof entry.status === 'string' && !VALID_STATUS.includes(entry.status) && !COERCIBLE_STATUS.includes(entry.status)) {
|
|
280
|
+
errs.push(`/status: must be one of ${VALID_STATUS.join(', ')}`);
|
|
281
|
+
}
|
|
282
|
+
if (typeof entry.priorityTier === 'string' && !VALID_PRIORITY_TIER.includes(entry.priorityTier)) {
|
|
283
|
+
errs.push(`/priorityTier: must be one of ${VALID_PRIORITY_TIER.join(', ')}`);
|
|
284
|
+
}
|
|
285
|
+
if (typeof entry.classification === 'string' && !VALID_CLASSIFICATION.includes(entry.classification)) {
|
|
286
|
+
errs.push(`/classification: must be one of ${VALID_CLASSIFICATION.join(', ')}`);
|
|
287
|
+
}
|
|
288
|
+
if (typeof entry.contentType === 'string' && !VALID_CONTENT_TYPE.includes(entry.contentType) && !COERCIBLE_CONTENT_TYPE.includes(entry.contentType)) {
|
|
289
|
+
errs.push(`/contentType: must be one of ${VALID_CONTENT_TYPE.join(', ')}`);
|
|
290
|
+
}
|
|
291
|
+
if (typeof entry.audience === 'string' && !VALID_AUDIENCE.includes(entry.audience) && !COERCIBLE_AUDIENCE.includes(entry.audience.toLowerCase())) {
|
|
292
|
+
errs.push(`/audience: must be one of ${VALID_AUDIENCE.join(', ')}`);
|
|
293
|
+
}
|
|
294
|
+
if (typeof entry.requirement === 'string' && !VALID_REQUIREMENT.includes(entry.requirement) && !COERCIBLE_REQUIREMENT.includes(entry.requirement.toUpperCase())) {
|
|
295
|
+
errs.push(`/requirement: must be one of ${VALID_REQUIREMENT.join(', ')}`);
|
|
296
|
+
}
|
|
297
|
+
return errs;
|
|
298
|
+
}
|
|
253
299
|
// Typed-field shape checks. These run for both strict and lax callers so that lax mode
|
|
254
300
|
// fills defaults for *missing* fields but never silently coerces wrong-typed inputs.
|
|
255
301
|
function validateTypedInputShape(entry) {
|
|
@@ -257,9 +303,22 @@ function validateTypedInputShape(entry) {
|
|
|
257
303
|
if (entry.priority !== undefined && typeof entry.priority !== 'number') {
|
|
258
304
|
errs.push(`/priority: must be a number, received ${typeof entry.priority}`);
|
|
259
305
|
}
|
|
306
|
+
else if (typeof entry.priority === 'number' && (!Number.isInteger(entry.priority) || entry.priority < 1 || entry.priority > 100)) {
|
|
307
|
+
errs.push('/priority: must be an integer from 1 to 100');
|
|
308
|
+
}
|
|
260
309
|
if (entry.categories !== undefined && !Array.isArray(entry.categories)) {
|
|
261
310
|
errs.push(`/categories: must be an array of strings, received ${typeof entry.categories}`);
|
|
262
311
|
}
|
|
312
|
+
else if (Array.isArray(entry.categories)) {
|
|
313
|
+
for (const [index, category] of entry.categories.entries()) {
|
|
314
|
+
if (typeof category !== 'string') {
|
|
315
|
+
errs.push(`/categories/${index}: must be a string, received ${typeof category}`);
|
|
316
|
+
}
|
|
317
|
+
else if (!/^[a-z0-9][a-z0-9-_]{0,48}$/.test(category.toLowerCase())) {
|
|
318
|
+
errs.push(`/categories/${index}: must match /^[a-z0-9][a-z0-9-_]{0,48}$/`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
263
322
|
if (entry.audience !== undefined && typeof entry.audience !== 'string') {
|
|
264
323
|
errs.push(`/audience: must be a string, received ${typeof entry.audience}`);
|
|
265
324
|
}
|
|
@@ -282,7 +341,7 @@ function validateTypedInputShape(entry) {
|
|
|
282
341
|
}
|
|
283
342
|
function validateInstructionInputSurface(entry) {
|
|
284
343
|
const validationErrors = [];
|
|
285
|
-
validationErrors.push(...
|
|
344
|
+
validationErrors.push(...validateInstructionIdSurface(entry.id));
|
|
286
345
|
for (const key of Object.keys(entry)) {
|
|
287
346
|
if (!ALLOWED_INPUT_KEYS.has(key)) {
|
|
288
347
|
validationErrors.push(`/: unexpected property "${key}"`);
|
|
@@ -292,6 +351,7 @@ function validateInstructionInputSurface(entry) {
|
|
|
292
351
|
validationErrors.push(`/${key}: null is not allowed`);
|
|
293
352
|
}
|
|
294
353
|
validationErrors.push(...validateTypedInputShape(entry));
|
|
354
|
+
validationErrors.push(...validateInstructionInputEnumMembership(entry));
|
|
295
355
|
return {
|
|
296
356
|
record: entry,
|
|
297
357
|
validationErrors: dedupe(validationErrors),
|
|
@@ -311,7 +371,7 @@ function validateInstructionRecord(entry) {
|
|
|
311
371
|
if (record.classification !== undefined && !['public', 'internal', 'restricted'].includes(record.classification)) {
|
|
312
372
|
validationErrors.push(`/classification: invalid value "${String(record.classification)}"`);
|
|
313
373
|
}
|
|
314
|
-
if (record.contentType !== undefined && !['instruction', 'template', '
|
|
374
|
+
if (record.contentType !== undefined && !['instruction', 'template', 'workflow', 'reference', 'example', 'agent'].includes(record.contentType)) {
|
|
315
375
|
validationErrors.push(`/contentType: invalid value "${String(record.contentType)}"`);
|
|
316
376
|
}
|
|
317
377
|
if (!validateInstructionSchema(record)) {
|
|
@@ -162,7 +162,7 @@ For full configuration options: see \`docs/mcp_configuration.md\` and \`docs/con
|
|
|
162
162
|
categories: ['bootstrap', 'mcp-activation', 'quick-start', 'documentation'],
|
|
163
163
|
owner: 'system',
|
|
164
164
|
version: 3,
|
|
165
|
-
schemaVersion: '
|
|
165
|
+
schemaVersion: '5',
|
|
166
166
|
semanticSummary: 'Index Server quick start: search-first workflow, knowledge contribution, copilot instructions setup, and MCP client configuration for AI agents'
|
|
167
167
|
}
|
|
168
168
|
},
|
|
@@ -179,7 +179,7 @@ For full configuration options: see \`docs/mcp_configuration.md\` and \`docs/con
|
|
|
179
179
|
categories: ['bootstrap', 'lifecycle'],
|
|
180
180
|
owner: 'system',
|
|
181
181
|
version: 1,
|
|
182
|
-
schemaVersion: '
|
|
182
|
+
schemaVersion: '5',
|
|
183
183
|
semanticSummary: 'Lifecycle and promotion guardrails after bootstrap confirmation',
|
|
184
184
|
reviewIntervalDays: 120
|
|
185
185
|
}
|
|
@@ -94,7 +94,7 @@ const INPUT_SCHEMAS = {
|
|
|
94
94
|
keywords: { type: 'array', items: { type: 'string' }, description: 'Explicit keyword array for search action when the caller wants direct token control.' },
|
|
95
95
|
ids: { type: 'array', items: { type: 'string' }, description: 'Array of instruction IDs for remove or export actions.' },
|
|
96
96
|
category: { type: 'string', description: 'Filter by category for list action.' },
|
|
97
|
-
contentType: { type: 'string', enum: ['instruction', 'template', '
|
|
97
|
+
contentType: { type: 'string', enum: ['instruction', 'template', 'workflow', 'reference', 'example', 'agent', 'chat-session'], description: 'Filter by content type for list, search, or query actions, or specify the entry content type for add action. Legacy "chat-session" write inputs are migrated to "workflow".' },
|
|
98
98
|
text: { type: 'string', description: 'Full-text search within query action.' },
|
|
99
99
|
includeCategories: { type: 'boolean', description: 'Search categories in addition to id/title/semanticSummary/body for search action.' },
|
|
100
100
|
caseSensitive: { type: 'boolean', description: 'Enable case-sensitive matching for search action.' },
|
|
@@ -148,7 +148,7 @@ const INPUT_SCHEMAS = {
|
|
|
148
148
|
'index_import': { type: 'object', additionalProperties: false, properties: {
|
|
149
149
|
entries: { oneOf: [
|
|
150
150
|
{ type: 'array', minItems: 1, items: { type: 'object', required: ['id', 'title', 'body', 'priority', 'audience', 'requirement'], additionalProperties: false, properties: {
|
|
151
|
-
id: { type: 'string' }, title: { type: 'string' }, body: { type: 'string' }, rationale: { type: 'string' }, priority: { type: 'number' }, audience: { type: 'string' }, requirement: { type: 'string' }, categories: { type: 'array', items: { type: 'string' } }, version: { type: 'string' }, owner: { type: 'string' }, status: { type: 'string', enum: ['approved', 'draft', 'review', 'deprecated'] }, priorityTier: { type: 'string', enum: ['P1', 'P2', 'P3', 'P4'] }, classification: { type: 'string', enum: ['public', 'internal', 'restricted'] }, lastReviewedAt: { type: 'string' }, nextReviewDue: { type: 'string' }, semanticSummary: { type: 'string' }, changeLog: { type: 'array', items: { type: 'object', additionalProperties: true } }, contentType: { type: 'string', enum: ['instruction', 'template', '
|
|
151
|
+
id: { type: 'string' }, title: { type: 'string' }, body: { type: 'string' }, rationale: { type: 'string' }, priority: { type: 'number' }, audience: { type: 'string' }, requirement: { type: 'string' }, categories: { type: 'array', items: { type: 'string' } }, version: { type: 'string' }, owner: { type: 'string' }, status: { type: 'string', enum: ['approved', 'draft', 'review', 'deprecated'] }, priorityTier: { type: 'string', enum: ['P1', 'P2', 'P3', 'P4'] }, classification: { type: 'string', enum: ['public', 'internal', 'restricted'] }, lastReviewedAt: { type: 'string' }, nextReviewDue: { type: 'string' }, semanticSummary: { type: 'string' }, changeLog: { type: 'array', items: { type: 'object', additionalProperties: true } }, contentType: { type: 'string', enum: ['instruction', 'template', 'workflow', 'reference', 'example', 'agent', 'chat-session'] }, extensions: extensionsInputSchema, mode: { type: 'string' }
|
|
152
152
|
} } },
|
|
153
153
|
{ type: 'string', description: 'Stringified JSON array of instruction entries, or a file path to a JSON array of instruction entries' }
|
|
154
154
|
] },
|
|
@@ -157,7 +157,7 @@ const INPUT_SCHEMAS = {
|
|
|
157
157
|
} },
|
|
158
158
|
'index_add': { type: 'object', additionalProperties: false, required: ['entry'], properties: {
|
|
159
159
|
entry: { type: 'object', required: ['id', 'body'], additionalProperties: false, properties: {
|
|
160
|
-
id: { type: 'string', maxLength: 120 }, title: { type: 'string' }, body: { type: 'string' }, rationale: { type: 'string' }, priority: { type: 'number' }, audience: { type: 'string' }, requirement: { type: 'string' }, categories: { type: 'array', items: { type: 'string' } }, deprecatedBy: { type: 'string' }, riskScore: { type: 'number' }, version: { type: 'string' }, owner: { type: 'string' }, status: { type: 'string', enum: ['approved', 'draft', 'review', 'deprecated'] }, priorityTier: { type: 'string', enum: ['P1', 'P2', 'P3', 'P4'] }, classification: { type: 'string', enum: ['public', 'internal', 'restricted'] }, lastReviewedAt: { type: 'string' }, nextReviewDue: { type: 'string' }, semanticSummary: { type: 'string' }, changeLog: { type: 'array', items: { type: 'object', additionalProperties: true } }, contentType: { type: 'string', enum: ['instruction', 'template', '
|
|
160
|
+
id: { type: 'string', minLength: 1, maxLength: 120, pattern: '^[a-z0-9](?:[a-z0-9-_]{0,118}[a-z0-9])?$' }, title: { type: 'string' }, body: { type: 'string' }, rationale: { type: 'string' }, priority: { type: 'number', minimum: 1, maximum: 100 }, audience: { type: 'string', enum: ['individual', 'group', 'all'] }, requirement: { type: 'string', enum: ['mandatory', 'critical', 'recommended', 'optional', 'deprecated'] }, categories: { type: 'array', items: { type: 'string', pattern: '^[a-z0-9][a-z0-9-_]{0,48}$' } }, deprecatedBy: { type: 'string' }, riskScore: { type: 'number' }, version: { type: 'string' }, owner: { type: 'string' }, status: { type: 'string', enum: ['approved', 'draft', 'review', 'deprecated'] }, priorityTier: { type: 'string', enum: ['P1', 'P2', 'P3', 'P4'] }, classification: { type: 'string', enum: ['public', 'internal', 'restricted'] }, lastReviewedAt: { type: 'string' }, nextReviewDue: { type: 'string' }, semanticSummary: { type: 'string' }, changeLog: { type: 'array', items: { type: 'object', additionalProperties: true } }, contentType: { type: 'string', enum: ['instruction', 'template', 'workflow', 'reference', 'example', 'agent', 'chat-session'] }, extensions: extensionsInputSchema
|
|
161
161
|
} },
|
|
162
162
|
overwrite: { type: 'boolean' },
|
|
163
163
|
lax: { type: 'boolean' }
|
|
@@ -221,7 +221,7 @@ const INPUT_SCHEMAS = {
|
|
|
221
221
|
limit: { type: 'number', minimum: 1, maximum: 100, default: 50, description: 'Maximum number of instruction IDs to return' },
|
|
222
222
|
includeCategories: { type: 'boolean', default: false, description: 'Include categories in search scope' },
|
|
223
223
|
caseSensitive: { type: 'boolean', default: false, description: 'Perform case-sensitive matching' },
|
|
224
|
-
contentType: { type: 'string', enum: ['instruction', 'template', '
|
|
224
|
+
contentType: { type: 'string', enum: ['instruction', 'template', 'workflow', 'reference', 'example', 'agent'], description: 'Filter results by content type (optional)' }
|
|
225
225
|
} },
|
|
226
226
|
// promote_from_repo tool
|
|
227
227
|
'promote_from_repo': { type: 'object', additionalProperties: false, required: ['repoPath'], properties: {
|
|
@@ -321,15 +321,16 @@ INPUT_SCHEMAS['trace_dump'] = { type: 'object', additionalProperties: false, pro
|
|
|
321
321
|
file: { type: 'string', description: 'Optional path to write the trace buffer JSON file' }
|
|
322
322
|
} };
|
|
323
323
|
// Stable & mutation classification lists (mirrors usage in toolHandlers; exported to remove duplication there).
|
|
324
|
-
exports.STABLE = new Set(['health_check', 'graph_export', 'index_dispatch', 'index_search', 'index_governanceHash', 'prompt_review', 'integrity_verify', 'usage_track', 'usage_hotset', 'metrics_snapshot', 'gates_evaluate', 'meta_tools', 'help_overview', 'index_schema', 'manifest_status', 'index_diagnostics', 'meta_activation_guide', 'meta_check_activation', 'bootstrap', 'bootstrap_status', 'feature_status', 'index_health', 'index_inspect', 'index_debug', 'integrity_manifest', 'messaging_read', 'messaging_list_channels', 'messaging_stats', 'messaging_get', 'messaging_thread', 'trace_dump']);
|
|
325
|
-
exports.MUTATION = new Set(['index_add', 'index_import', 'index_repair', 'index_reload', 'index_remove', 'index_groom', 'index_enrich', 'index_governanceUpdate', 'index_normalize', 'usage_flush', '
|
|
324
|
+
exports.STABLE = new Set(['health_check', 'feedback_submit', 'graph_export', 'index_dispatch', 'index_search', 'index_governanceHash', 'prompt_review', 'integrity_verify', 'usage_track', 'usage_hotset', 'metrics_snapshot', 'gates_evaluate', 'meta_tools', 'help_overview', 'index_schema', 'manifest_status', 'index_diagnostics', 'meta_activation_guide', 'meta_check_activation', 'bootstrap', 'bootstrap_status', 'feature_status', 'index_health', 'index_inspect', 'index_debug', 'integrity_manifest', 'messaging_read', 'messaging_list_channels', 'messaging_stats', 'messaging_get', 'messaging_thread', 'trace_dump']);
|
|
325
|
+
exports.MUTATION = new Set(['index_add', 'index_import', 'index_repair', 'index_reload', 'index_remove', 'index_groom', 'index_enrich', 'index_governanceUpdate', 'index_normalize', 'usage_flush', 'manifest_refresh', 'manifest_repair', 'promote_from_repo', 'bootstrap_request', 'bootstrap_confirmFinalize', 'messaging_send', 'messaging_ack', 'messaging_update', 'messaging_purge', 'messaging_reply', 'diagnostics_block', 'diagnostics_microtaskFlood', 'diagnostics_memoryPressure']);
|
|
326
326
|
// Tool tier classification (002-tool-consolidation spec)
|
|
327
327
|
// core: always visible, essential daily use
|
|
328
328
|
// extended: opt-in via INDEX_SERVER_FLAG_TOOLS_EXTENDED=1 or flags.json tools_extended:true
|
|
329
329
|
// admin: opt-in via INDEX_SERVER_FLAG_TOOLS_ADMIN=1, rarely needed ops/debug tools
|
|
330
330
|
const TOOL_TIERS = {
|
|
331
|
-
// Core (7
|
|
331
|
+
// Core (7 after feedback_dispatch removal; feedback_submit remains always visible for agent reporting)
|
|
332
332
|
'health_check': 'core',
|
|
333
|
+
'feedback_submit': 'core',
|
|
333
334
|
'index_dispatch': 'core',
|
|
334
335
|
'index_search': 'core',
|
|
335
336
|
'prompt_review': 'core',
|
|
@@ -351,7 +352,6 @@ const TOOL_TIERS = {
|
|
|
351
352
|
'promote_from_repo': 'extended',
|
|
352
353
|
'index_schema': 'extended',
|
|
353
354
|
// Admin (everything else)
|
|
354
|
-
'feedback_submit': 'admin',
|
|
355
355
|
'meta_tools': 'admin',
|
|
356
356
|
'meta_activation_guide': 'admin',
|
|
357
357
|
'meta_check_activation': 'admin',
|
|
@@ -35,7 +35,7 @@ const zDispatch = zod_1.z.object({
|
|
|
35
35
|
keywords: zod_1.z.array(zod_1.z.string()).optional(),
|
|
36
36
|
ids: zod_1.z.array(zod_1.z.string()).optional(),
|
|
37
37
|
category: zod_1.z.string().optional(),
|
|
38
|
-
contentType: zod_1.z.enum(['instruction', 'template', '
|
|
38
|
+
contentType: zod_1.z.enum(['instruction', 'template', 'workflow', 'reference', 'example', 'agent', 'chat-session']).optional(),
|
|
39
39
|
text: zod_1.z.string().optional(),
|
|
40
40
|
includeCategories: zod_1.z.boolean().optional(),
|
|
41
41
|
caseSensitive: zod_1.z.boolean().optional(),
|
|
@@ -98,7 +98,7 @@ function buildZIndexEntry() {
|
|
|
98
98
|
nextReviewDue: zod_1.z.string().optional(),
|
|
99
99
|
semanticSummary: zod_1.z.string().optional(),
|
|
100
100
|
changeLog: zod_1.z.array(zod_1.z.object({}).passthrough()).optional(),
|
|
101
|
-
contentType: zod_1.z.enum(['instruction', 'template', '
|
|
101
|
+
contentType: zod_1.z.enum(['instruction', 'template', 'workflow', 'reference', 'example', 'agent', 'chat-session']).optional(),
|
|
102
102
|
extensions: zod_1.z.record(zod_1.z.string(), zExtensionValue).optional()
|
|
103
103
|
}).strict();
|
|
104
104
|
}
|
|
@@ -166,7 +166,7 @@ const zSearch = zod_1.z.object({
|
|
|
166
166
|
limit: zod_1.z.number().int().min(1).max(100).default(50).optional(),
|
|
167
167
|
includeCategories: zod_1.z.boolean().default(false).optional(),
|
|
168
168
|
caseSensitive: zod_1.z.boolean().default(false).optional(),
|
|
169
|
-
contentType: zod_1.z.enum(['instruction', 'template', '
|
|
169
|
+
contentType: zod_1.z.enum(['instruction', 'template', 'workflow', 'reference', 'example', 'agent']).optional()
|
|
170
170
|
}).strict();
|
|
171
171
|
// ── Diagnostics ──────────────────────────────────────────────────────────────
|
|
172
172
|
const zDiagnostics = zod_1.z.object({
|