@svashevchenko/ez-know 0.1.0 → 0.2.0

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/dist/cli.js CHANGED
@@ -2393,679 +2393,909 @@ function buildKnowledgeGraphQLText(result) {
2393
2393
  });
2394
2394
  }
2395
2395
 
2396
- // packages/core/src/knowledge/patch/apply.ts
2397
- import { existsSync as existsSync3 } from "node:fs";
2398
- import { mkdir as mkdir2, rm, unlink, writeFile as writeFile2 } from "node:fs/promises";
2399
- import { dirname } from "node:path";
2400
-
2401
- // packages/core/src/knowledge/patch/validation.ts
2402
- import { readFile as readFile4, stat } from "node:fs/promises";
2403
- import { join as join4 } from "node:path";
2404
- async function buildSourceFingerprintInput(sourceFiles) {
2405
- const entries = await Promise.all(
2406
- sourceFiles.map(async (filePath) => {
2407
- const [fileStat, content] = await Promise.all([
2408
- stat(filePath),
2409
- readFile4(filePath, "utf8")
2410
- ]);
2411
- return {
2412
- path: filePath,
2413
- size: fileStat.size,
2414
- mtimeMs: fileStat.mtimeMs,
2415
- contentHash: sha256(content)
2416
- };
2417
- })
2418
- );
2419
- entries.sort((left, right) => left.path.localeCompare(right.path));
2420
- return entries;
2396
+ // packages/core/src/knowledge/schema-discovery.ts
2397
+ import {
2398
+ isAbstractType,
2399
+ isCompositeType,
2400
+ isListType,
2401
+ isNonNullType,
2402
+ isObjectType,
2403
+ isScalarType,
2404
+ isUnionType
2405
+ } from "graphql";
2406
+ var KNOWLEDGE_SCHEMA_RESOURCE_URI = "ez-know://schema";
2407
+ var KNOWLEDGE_SCHEMA_LOOKUP_URI = "ez-know://lookup/{target}";
2408
+ function unwrapType(type) {
2409
+ if (isNonNullType(type) || isListType(type)) {
2410
+ return unwrapType(type.ofType);
2411
+ }
2412
+ if (isObjectType(type) || isScalarType(type) || isUnionType(type) || isAbstractType(type)) {
2413
+ return { name: type.name, composite: type };
2414
+ }
2415
+ return { name: "Unknown", composite: type };
2421
2416
  }
2422
- function buildCanonicalPathForCollection(rootDir, domain, type) {
2423
- return join4(
2424
- rootDir,
2425
- domain,
2426
- KNOWLEDGE_EXTRACTION_TYPE_REGISTRY[type].storageFile
2427
- );
2417
+ function describeType(type) {
2418
+ if (isNonNullType(type)) {
2419
+ return `${describeType(type.ofType)}!`;
2420
+ }
2421
+ if (isListType(type)) {
2422
+ return `[${describeType(type.ofType)}]`;
2423
+ }
2424
+ if (isObjectType(type) || isScalarType(type) || isUnionType(type)) {
2425
+ return type.name;
2426
+ }
2427
+ if (isAbstractType(type)) {
2428
+ return type.name;
2429
+ }
2430
+ return "Unknown";
2428
2431
  }
2429
- function buildAffectedFileList(knowledgeRoot, operations) {
2430
- const affected = /* @__PURE__ */ new Set();
2431
- for (const operation of operations) {
2432
- affected.add(
2433
- buildCanonicalPathForCollection(
2434
- knowledgeRoot,
2435
- operation.domain,
2436
- operation.type
2437
- )
2438
- );
2432
+ function formatDefaultValue(value) {
2433
+ if (value === void 0 || value === null) {
2434
+ return null;
2439
2435
  }
2440
- return [...affected].sort((left, right) => left.localeCompare(right));
2436
+ return JSON.stringify(value) ?? String(value);
2441
2437
  }
2442
- function buildCollectionRecordsForDomain(state, type, domain) {
2443
- const records = [...state.byCollection[type].values()].filter(
2444
- (record2) => inferDomainForRecord(record2) === domain
2445
- );
2446
- records.sort((left, right) => left.id.localeCompare(right.id));
2447
- return records;
2438
+ function summarizeField(field) {
2439
+ const traversedType = unwrapType(field.type).composite;
2440
+ const traversesTo = isCompositeType(traversedType) && !isScalarType(traversedType) ? traversedType.name : null;
2441
+ return {
2442
+ name: field.name,
2443
+ type: describeType(field.type),
2444
+ description: field.description ?? null,
2445
+ arguments: field.args?.map((argument) => ({
2446
+ name: argument.name,
2447
+ type: describeType(argument.type),
2448
+ description: argument.description ?? null,
2449
+ defaultValue: formatDefaultValue(argument.defaultValue)
2450
+ })) ?? [],
2451
+ traversesTo
2452
+ };
2448
2453
  }
2449
- async function computeValidationResult(knowledgeRoot, patchId, patch, operations) {
2450
- const effectiveBase = await loadEffectiveKnowledgeStoreFromRoot(
2451
- knowledgeRoot,
2452
- {
2453
- selectedPatchId: patchId,
2454
- includeSelectedPatch: false
2455
- }
2456
- );
2457
- const simulation = simulateKnowledgePatch(
2458
- effectiveBase.store,
2459
- operations,
2460
- patchId
2461
- );
2462
- const affectedFiles = buildAffectedFileList(knowledgeRoot, operations);
2463
- const diagnostics = [
2464
- ...effectiveBase.diagnostics,
2465
- ...simulation.diagnostics
2466
- ];
2467
- if (diagnostics.length > 0) {
2468
- return knowledgePatchValidationResultSchema.parse({
2469
- valid: false,
2470
- diagnostics,
2471
- operationCount: operations.length,
2472
- appliedOperationIds: simulation.appliedOperationIds,
2473
- affectedFiles
2474
- });
2475
- }
2476
- const sourceFingerprint = await buildSourceFingerprintInput(
2477
- effectiveBase.store.sourceFiles
2478
- );
2479
- const fingerprint = sha256(
2480
- JSON.stringify({
2481
- schemaVersion: KNOWLEDGE_PATCH_SCHEMA_VERSION,
2482
- patch: {
2483
- id: patch.id,
2484
- status: patch.status,
2485
- updatedAt: patch.updatedAt
2486
- },
2487
- operations,
2488
- sourceFingerprint
2489
- })
2490
- );
2491
- return knowledgePatchValidationResultSchema.parse({
2492
- valid: true,
2493
- fingerprint,
2494
- diagnostics,
2495
- operationCount: operations.length,
2496
- appliedOperationIds: simulation.appliedOperationIds,
2497
- affectedFiles
2498
- });
2454
+ function summarizeObjectType(type) {
2455
+ const fields = Object.values(type.getFields()).map(summarizeField);
2456
+ return {
2457
+ name: type.name,
2458
+ description: type.description ?? null,
2459
+ fields,
2460
+ traversalFields: fields.filter((field) => field.traversesTo !== null).map((field) => field.name)
2461
+ };
2499
2462
  }
2500
- async function validateKnowledgePatch(envValue, patchId, cwd = process.cwd()) {
2501
- const knowledgeRoot = resolveKnowledgeRoot2(envValue, cwd);
2502
- const state = await readKnowledgePatch(envValue, patchId, cwd);
2503
- return computeValidationResult(
2504
- knowledgeRoot,
2505
- patchId,
2506
- state.patch,
2507
- state.operations
2508
- );
2463
+ function getObjectTypes(schema) {
2464
+ return Object.values(schema.getTypeMap()).filter((type) => isObjectType(type)).filter((type) => !type.name.startsWith("__")).filter((type) => type.name !== schema.getQueryType()?.name);
2509
2465
  }
2510
-
2511
- // packages/core/src/knowledge/patch/apply.ts
2512
- async function writeCanonicalFilesFromSimulation(knowledgeRoot, operations, simulationState) {
2513
- const plannedWrites = /* @__PURE__ */ new Map();
2514
- for (const operation of operations) {
2515
- const filePath = buildCanonicalPathForCollection(
2516
- knowledgeRoot,
2517
- operation.domain,
2518
- operation.type
2519
- );
2520
- const records = buildCollectionRecordsForDomain(
2521
- simulationState,
2522
- operation.type,
2523
- operation.domain
2524
- );
2525
- if (operation.type === "domains") {
2526
- if (records.length === 0) {
2527
- if (existsSync3(filePath)) {
2528
- await unlink(filePath);
2529
- }
2530
- continue;
2531
- }
2532
- plannedWrites.set(filePath, `${JSON.stringify(records[0], null, 2)}
2533
- `);
2534
- continue;
2535
- }
2536
- plannedWrites.set(filePath, `${JSON.stringify(records, null, 2)}
2537
- `);
2538
- }
2539
- for (const filePath of plannedWrites.keys()) {
2540
- await mkdir2(dirname(filePath), { recursive: true });
2541
- }
2542
- for (const [filePath, content] of plannedWrites.entries()) {
2543
- await writeFile2(filePath, content, "utf8");
2466
+ function buildKnowledgeSchemaDiscoveryDocument(schema) {
2467
+ const queryType2 = schema.getQueryType();
2468
+ if (!queryType2) {
2469
+ throw new Error("Knowledge GraphQL schema has no root query type.");
2544
2470
  }
2471
+ return {
2472
+ resource: {
2473
+ uri: KNOWLEDGE_SCHEMA_RESOURCE_URI,
2474
+ title: "Knowledge GraphQL Schema",
2475
+ description: "Canonical discovery view of the runtime knowledge GraphQL schema."
2476
+ },
2477
+ source: {
2478
+ kind: "runtime-schema",
2479
+ queryType: queryType2.name
2480
+ },
2481
+ rootQuery: summarizeObjectType(queryType2),
2482
+ objectTypes: getObjectTypes(schema).map(summarizeObjectType)
2483
+ };
2545
2484
  }
2546
- async function applyKnowledgePatch(envValue, input, cwd = process.cwd()) {
2547
- const parsedInput = knowledgePatchApplyToolInputSchema.parse(input);
2548
- const knowledgeRoot = resolveKnowledgeRoot2(envValue, cwd);
2549
- const patchDir = resolveKnowledgePatchDirectory(
2550
- envValue,
2551
- parsedInput.patchId,
2552
- cwd
2553
- );
2554
- const patchState = await loadPatchStateByDir(patchDir);
2555
- const validation = await computeValidationResult(
2556
- knowledgeRoot,
2557
- patchState.patch.id,
2558
- patchState.patch,
2559
- patchState.operations
2560
- );
2561
- const diagnostics = [...validation.diagnostics];
2562
- const pendingPatches = (await listKnowledgePatches(envValue, cwd)).filter(
2563
- (patch) => patch.status === "draft"
2564
- );
2565
- const firstPendingPatchId = pendingPatches[0]?.id;
2566
- if (firstPendingPatchId !== void 0 && firstPendingPatchId !== patchState.patch.id) {
2567
- diagnostics.push(
2568
- buildDiagnostic({
2569
- severity: "error",
2570
- code: "apply_out_of_order",
2571
- message: `Patch "${patchState.patch.id}" cannot be applied while earlier pending patch "${firstPendingPatchId}" still exists.`,
2572
- patchId: patchState.patch.id
2573
- })
2574
- );
2485
+ function getLookupMetadata(schema, target) {
2486
+ const queryType2 = schema.getQueryType();
2487
+ if (!queryType2) {
2488
+ throw new Error("Knowledge GraphQL schema has no root query type.");
2575
2489
  }
2576
- if (!parsedInput.approval.approved) {
2577
- diagnostics.push(
2578
- buildDiagnostic({
2579
- severity: "error",
2580
- code: "approval_required",
2581
- message: "Patch apply requires explicit approval.",
2582
- patchId: patchState.patch.id
2583
- })
2584
- );
2490
+ if (target === queryType2.name) {
2491
+ return {
2492
+ resource: {
2493
+ uri: `ez-know://lookup/${target}`,
2494
+ title: `Knowledge schema lookup: ${target}`,
2495
+ description: "Focused lookup of the root query fields and their arguments."
2496
+ },
2497
+ source: {
2498
+ kind: "runtime-schema",
2499
+ queryType: queryType2.name
2500
+ },
2501
+ lookup: {
2502
+ target: queryType2.name,
2503
+ kind: "root-query"
2504
+ },
2505
+ rootQuery: summarizeObjectType(queryType2)
2506
+ };
2585
2507
  }
2586
- if (firstPendingPatchId !== void 0 && firstPendingPatchId !== patchState.patch.id || !parsedInput.approval.approved || !validation.valid || parsedInput.approval.validationFingerprint !== validation.fingerprint) {
2587
- if (validation.valid && parsedInput.approval.validationFingerprint !== validation.fingerprint) {
2588
- diagnostics.push(
2589
- buildDiagnostic({
2590
- severity: "error",
2591
- code: "stale_validation_fingerprint",
2592
- message: "Patch validation fingerprint is stale. Revalidate before apply.",
2593
- patchId: patchState.patch.id
2594
- })
2595
- );
2596
- }
2508
+ const rootField = queryType2.getFields()[target];
2509
+ if (rootField) {
2597
2510
  return {
2598
- patchId: patchState.patch.id,
2599
- applied: false,
2600
- validation,
2601
- diagnostics,
2602
- deletedPatch: false
2511
+ resource: {
2512
+ uri: `ez-know://lookup/${target}`,
2513
+ title: `Knowledge schema lookup: ${target}`,
2514
+ description: "Focused lookup of a single root query field and its arguments."
2515
+ },
2516
+ source: {
2517
+ kind: "runtime-schema",
2518
+ queryType: queryType2.name
2519
+ },
2520
+ lookup: {
2521
+ target,
2522
+ kind: "root-field"
2523
+ },
2524
+ field: summarizeField(rootField),
2525
+ parentType: queryType2.name
2603
2526
  };
2604
2527
  }
2605
- const store = await loadKnowledgeStoreFromRoot(knowledgeRoot);
2606
- const simulation = simulateKnowledgePatch(
2607
- store,
2608
- patchState.operations,
2609
- patchState.patch.id
2610
- );
2611
- if (simulation.diagnostics.length > 0) {
2528
+ const objectType = schema.getType(target);
2529
+ if (objectType && isObjectType(objectType)) {
2530
+ const typeSummary = summarizeObjectType(objectType);
2531
+ const rootFields = Object.values(queryType2.getFields()).filter((field) => unwrapType(field.type).name === target).map((field) => field.name);
2612
2532
  return {
2613
- patchId: patchState.patch.id,
2614
- applied: false,
2615
- validation: {
2616
- ...validation,
2617
- valid: false,
2618
- diagnostics: simulation.diagnostics
2533
+ resource: {
2534
+ uri: `ez-know://lookup/${target}`,
2535
+ title: `Knowledge schema lookup: ${target}`,
2536
+ description: "Focused lookup of a single GraphQL type and its nested traversal fields."
2619
2537
  },
2620
- diagnostics: simulation.diagnostics,
2621
- deletedPatch: false
2538
+ source: {
2539
+ kind: "runtime-schema",
2540
+ queryType: queryType2.name
2541
+ },
2542
+ lookup: {
2543
+ target,
2544
+ kind: "object-type"
2545
+ },
2546
+ type: typeSummary,
2547
+ rootFields
2622
2548
  };
2623
2549
  }
2624
- await writeCanonicalFilesFromSimulation(
2625
- knowledgeRoot,
2626
- patchState.operations,
2627
- simulation.state
2550
+ throw new Error(
2551
+ `Unknown schema lookup target "${target}". Use a root field name, a type name, or "Query".`
2628
2552
  );
2629
- try {
2630
- await loadKnowledgeStoreFromRoot(knowledgeRoot);
2631
- } catch (error) {
2632
- const reloadDiagnostics = error instanceof KnowledgeStoreLoadError ? error.diagnostics.map(
2633
- (diagnostic) => buildDiagnostic({
2634
- severity: "critical",
2635
- code: diagnostic.kind,
2636
- message: diagnostic.message,
2637
- path: diagnostic.path ? [diagnostic.path] : void 0,
2638
- targetId: diagnostic.id
2639
- })
2640
- ) : [
2641
- buildDiagnostic({
2642
- severity: "critical",
2643
- code: "reload_failed",
2644
- message: "Canonical knowledge store reload failed after apply.",
2645
- patchId: patchState.patch.id
2646
- })
2647
- ];
2648
- return {
2649
- patchId: patchState.patch.id,
2650
- applied: false,
2651
- validation,
2652
- diagnostics: reloadDiagnostics,
2653
- deletedPatch: false
2654
- };
2553
+ }
2554
+ function buildKnowledgeSchemaLookupDocument(schema, target) {
2555
+ return getLookupMetadata(schema, target);
2556
+ }
2557
+ function listKnowledgeSchemaTargets(schema) {
2558
+ const queryType2 = schema.getQueryType();
2559
+ if (!queryType2) {
2560
+ throw new Error("Knowledge GraphQL schema has no root query type.");
2655
2561
  }
2656
- await rm(patchDir, { recursive: true, force: true });
2562
+ const objectTypeNames = getObjectTypes(schema).map((type) => type.name);
2563
+ const rootFieldNames = Object.keys(queryType2.getFields());
2564
+ const targetNames = ["Query", ...rootFieldNames, ...objectTypeNames];
2565
+ return Array.from(new Set(targetNames)).sort(
2566
+ (left, right) => left.localeCompare(right)
2567
+ );
2568
+ }
2569
+
2570
+ // packages/core/src/knowledge/resource-catalog.ts
2571
+ var KnowledgeResourceNotFoundError = class extends Error {
2572
+ constructor(uri, message = `Unknown ez-know resource URI "${uri}".`) {
2573
+ super(message);
2574
+ this.uri = uri;
2575
+ this.name = "KnowledgeResourceNotFoundError";
2576
+ }
2577
+ uri;
2578
+ code = "RESOURCE_NOT_FOUND";
2579
+ };
2580
+ var KnowledgeResourceUriError = class extends Error {
2581
+ constructor(uri, message) {
2582
+ super(message);
2583
+ this.uri = uri;
2584
+ this.name = "KnowledgeResourceUriError";
2585
+ }
2586
+ uri;
2587
+ code = "INVALID_RESOURCE_URI";
2588
+ };
2589
+ function createJsonResourceContent(uri, text) {
2657
2590
  return {
2658
- patchId: patchState.patch.id,
2659
- applied: true,
2660
- validation,
2661
- diagnostics: [],
2662
- deletedPatch: true
2591
+ uri,
2592
+ mimeType: "application/json",
2593
+ text
2663
2594
  };
2664
2595
  }
2665
-
2666
- // packages/core/src/knowledge/patch/scope-audit.ts
2667
- import { readdir as readdir2 } from "node:fs/promises";
2668
- import { isAbsolute as isAbsolute2, relative, resolve as resolve5, sep as sep2 } from "node:path";
2669
- import { z as z6 } from "zod/v4";
2670
- var compareScopeWithEvidenceInputSchema = z6.object({
2671
- patchId: z6.string().min(1),
2672
- rootFolder: z6.string().trim().min(1).optional()
2673
- });
2674
- var compareScopeWithEvidenceResultSchema = z6.object({
2675
- patchId: z6.string().min(1),
2676
- rootFolder: z6.string().min(1),
2677
- scopeFiles: z6.array(z6.string()),
2678
- coveredFiles: z6.array(z6.string()),
2679
- omittedFiles: z6.array(
2680
- z6.object({
2681
- path: z6.string(),
2682
- reason: z6.string()
2596
+ function createMarkdownResourceContent(uri, text) {
2597
+ return {
2598
+ uri,
2599
+ mimeType: "text/markdown",
2600
+ text
2601
+ };
2602
+ }
2603
+ function createKnowledgeSchemaResourceDefinition() {
2604
+ return {
2605
+ uri: KNOWLEDGE_SCHEMA_RESOURCE_URI,
2606
+ name: "knowledge-schema",
2607
+ title: "Knowledge GraphQL Schema",
2608
+ description: "Canonical runtime GraphQL schema discovery payload for the knowledge layer.",
2609
+ mimeType: "application/json",
2610
+ read: () => ({
2611
+ resource: {
2612
+ uri: KNOWLEDGE_SCHEMA_RESOURCE_URI,
2613
+ title: "Knowledge GraphQL Schema",
2614
+ description: "Canonical runtime GraphQL schema discovery payload for the knowledge layer.",
2615
+ mimeType: "application/json"
2616
+ },
2617
+ content: createJsonResourceContent(
2618
+ KNOWLEDGE_SCHEMA_RESOURCE_URI,
2619
+ createKnowledgeSchemaDiscoveryText()
2620
+ )
2683
2621
  })
2684
- ),
2685
- uncoveredFiles: z6.array(z6.string()),
2686
- outOfRootEvidenceFiles: z6.array(z6.string()),
2687
- message: z6.string()
2688
- });
2689
- function toPosixPath(value) {
2690
- return value.replaceAll(sep2, "/");
2622
+ };
2691
2623
  }
2692
- function normalizeAuditedRoot(rootFolder) {
2693
- return resolve5(rootFolder);
2624
+ function createKnowledgeExtractionTypesResourceDefinition() {
2625
+ return {
2626
+ uri: KNOWLEDGE_EXTRACTION_TYPES_RESOURCE_URI,
2627
+ name: "knowledge-extraction-types",
2628
+ title: "Knowledge Extraction Types",
2629
+ description: "Canonical registry of knowledge types supported by the extraction workflow.",
2630
+ mimeType: "application/json",
2631
+ read: () => ({
2632
+ resource: {
2633
+ uri: KNOWLEDGE_EXTRACTION_TYPES_RESOURCE_URI,
2634
+ title: "Knowledge Extraction Types",
2635
+ description: "Canonical registry of knowledge types supported by the extraction workflow.",
2636
+ mimeType: "application/json"
2637
+ },
2638
+ content: createJsonResourceContent(
2639
+ KNOWLEDGE_EXTRACTION_TYPES_RESOURCE_URI,
2640
+ JSON.stringify(buildKnowledgeExtractionTypeIndexDocument(), null, 2)
2641
+ )
2642
+ })
2643
+ };
2694
2644
  }
2695
- function isPathWithinRoot(rootFolder, filePath) {
2696
- const relativePath = toPosixPath(relative(rootFolder, filePath));
2697
- return Boolean(
2698
- relativePath && relativePath !== ".." && !relativePath.startsWith("../")
2645
+ function createKnowledgeSchemaLookupTemplateDefinition() {
2646
+ return {
2647
+ uriTemplate: KNOWLEDGE_SCHEMA_LOOKUP_URI,
2648
+ name: "knowledge-schema-lookup",
2649
+ title: "Knowledge Schema Lookup",
2650
+ description: "Focused runtime GraphQL schema lookup for a type name, root field, or Query.",
2651
+ mimeType: "application/json",
2652
+ list: () => listKnowledgeSchemaTargets(knowledgeGraphSchema).map((target) => ({
2653
+ uri: `ez-know://lookup/${target}`,
2654
+ name: target,
2655
+ title: `Knowledge schema lookup: ${target}`,
2656
+ description: target === "Query" ? "Focused lookup of the root query fields." : `Focused lookup of ${target}.`,
2657
+ mimeType: "application/json"
2658
+ })),
2659
+ read: (uri) => {
2660
+ const target = readUriSegment(uri, "ez-know://lookup/");
2661
+ try {
2662
+ return {
2663
+ resource: {
2664
+ uri,
2665
+ title: `Knowledge schema lookup: ${target}`,
2666
+ description: target === "Query" ? "Focused lookup of the root query fields and their arguments." : `Focused lookup of ${target}.`,
2667
+ mimeType: "application/json"
2668
+ },
2669
+ content: createJsonResourceContent(
2670
+ uri,
2671
+ createKnowledgeSchemaLookupText(target)
2672
+ )
2673
+ };
2674
+ } catch (error) {
2675
+ if (error instanceof Error) {
2676
+ throw new KnowledgeResourceUriError(uri, error.message);
2677
+ }
2678
+ throw error;
2679
+ }
2680
+ }
2681
+ };
2682
+ }
2683
+ function createKnowledgeExtractionSchemaTemplateDefinition() {
2684
+ return {
2685
+ uriTemplate: KNOWLEDGE_EXTRACTION_SCHEMA_RESOURCE_URI,
2686
+ name: "knowledge-extraction-schema",
2687
+ title: "Knowledge Extraction Schema",
2688
+ description: "Runtime JSON-schema discovery for a supported knowledge type.",
2689
+ mimeType: "application/json",
2690
+ list: () => listKnowledgeExtractionResourceTypes().map((definition) => ({
2691
+ uri: `ez-know://extraction/schema/${definition.collection}`,
2692
+ name: definition.collection,
2693
+ title: `${definition.title} Extraction Schema`,
2694
+ description: `Runtime schema discovery for ${definition.title.toLowerCase()}.`,
2695
+ mimeType: "application/json"
2696
+ })),
2697
+ read: (uri) => {
2698
+ const type = readUriSegment(uri, "ez-know://extraction/schema/");
2699
+ try {
2700
+ const document = buildKnowledgeExtractionSchemaDocument(type);
2701
+ return {
2702
+ resource: {
2703
+ uri: `ez-know://extraction/schema/${document.type.collection}`,
2704
+ title: `${document.type.title} Extraction Schema`,
2705
+ description: "Runtime JSON Schema view of the canonical knowledge object model.",
2706
+ mimeType: "application/json"
2707
+ },
2708
+ content: createJsonResourceContent(
2709
+ `ez-know://extraction/schema/${document.type.collection}`,
2710
+ JSON.stringify(document, null, 2)
2711
+ )
2712
+ };
2713
+ } catch (error) {
2714
+ if (error instanceof Error) {
2715
+ throw new KnowledgeResourceUriError(uri, error.message);
2716
+ }
2717
+ throw error;
2718
+ }
2719
+ }
2720
+ };
2721
+ }
2722
+ function createKnowledgeExtractionGuideTemplateDefinition() {
2723
+ return {
2724
+ uriTemplate: KNOWLEDGE_EXTRACTION_GUIDE_RESOURCE_URI,
2725
+ name: "knowledge-extraction-guide",
2726
+ title: "Knowledge Extraction Guide",
2727
+ description: "Checked-in Markdown guidance for a supported knowledge type.",
2728
+ mimeType: "text/markdown",
2729
+ list: () => listKnowledgeExtractionResourceTypes().map((definition) => ({
2730
+ uri: `ez-know://extraction/guide/${definition.collection}`,
2731
+ name: definition.collection,
2732
+ title: `${definition.title} Extraction Guide`,
2733
+ description: `Checked-in extraction guidance for ${definition.title.toLowerCase()}.`,
2734
+ mimeType: "text/markdown"
2735
+ })),
2736
+ read: async (uri) => {
2737
+ const type = readUriSegment(uri, "ez-know://extraction/guide/");
2738
+ try {
2739
+ const document = await buildKnowledgeExtractionGuideDocument(type);
2740
+ return {
2741
+ resource: {
2742
+ uri: `ez-know://extraction/guide/${document.type.collection}`,
2743
+ title: `${document.type.title} Extraction Guide`,
2744
+ description: "Checked-in Markdown guidance for extracting this knowledge type.",
2745
+ mimeType: "text/markdown"
2746
+ },
2747
+ content: createMarkdownResourceContent(
2748
+ `ez-know://extraction/guide/${document.type.collection}`,
2749
+ document.markdown
2750
+ )
2751
+ };
2752
+ } catch (error) {
2753
+ if (error instanceof Error) {
2754
+ throw new KnowledgeResourceUriError(uri, error.message);
2755
+ }
2756
+ throw error;
2757
+ }
2758
+ }
2759
+ };
2760
+ }
2761
+ function createKnowledgeSchemaDiscoveryText() {
2762
+ return JSON.stringify(buildKnowledgeSchemaDiscoveryDocument(knowledgeGraphSchema), null, 2);
2763
+ }
2764
+ function createKnowledgeSchemaLookupText(target) {
2765
+ return JSON.stringify(
2766
+ buildKnowledgeSchemaLookupDocument(knowledgeGraphSchema, target),
2767
+ null,
2768
+ 2
2699
2769
  );
2700
2770
  }
2701
- function normalizePathWithinRoot(rootFolder, filePath, outputRoot = rootFolder) {
2702
- let candidate;
2703
- if (isAbsolute2(filePath)) {
2704
- candidate = resolve5(filePath);
2705
- } else {
2706
- const repoRelativeCandidate = resolve5(outputRoot, filePath);
2707
- candidate = isPathWithinRoot(rootFolder, repoRelativeCandidate) ? repoRelativeCandidate : resolve5(rootFolder, filePath);
2771
+ function readUriSegment(uri, prefix) {
2772
+ if (!uri.startsWith(prefix)) {
2773
+ throw new KnowledgeResourceNotFoundError(uri);
2708
2774
  }
2709
- const relativePath = toPosixPath(relative(outputRoot, candidate));
2710
- if (!relativePath || relativePath === ".." || relativePath.startsWith("../")) {
2711
- return null;
2775
+ const segment = uri.slice(prefix.length);
2776
+ if (segment.length === 0 || segment.includes("/")) {
2777
+ throw new KnowledgeResourceUriError(
2778
+ uri,
2779
+ `Unsupported ez-know resource URI "${uri}".`
2780
+ );
2712
2781
  }
2713
- return relativePath;
2782
+ return segment;
2714
2783
  }
2715
- async function collectScopeFiles(currentDir, auditedRoot, patchStorageRoot, outputRoot) {
2716
- if (currentDir === patchStorageRoot) {
2717
- return [];
2784
+ var KNOWLEDGE_RESOURCE_DEFINITIONS = [
2785
+ createKnowledgeSchemaResourceDefinition(),
2786
+ createKnowledgeExtractionTypesResourceDefinition()
2787
+ ];
2788
+ var KNOWLEDGE_RESOURCE_TEMPLATE_DEFINITIONS = [
2789
+ createKnowledgeSchemaLookupTemplateDefinition(),
2790
+ createKnowledgeExtractionSchemaTemplateDefinition(),
2791
+ createKnowledgeExtractionGuideTemplateDefinition()
2792
+ ];
2793
+ function listKnowledgeResourceEntries() {
2794
+ return KNOWLEDGE_RESOURCE_DEFINITIONS.map(({ read: _read, ...metadata }) => ({
2795
+ ...metadata
2796
+ }));
2797
+ }
2798
+ function listKnowledgeResourceTemplateEntries() {
2799
+ return KNOWLEDGE_RESOURCE_TEMPLATE_DEFINITIONS.map(({ list: _list, read: _read, ...metadata }) => ({
2800
+ ...metadata
2801
+ }));
2802
+ }
2803
+ function listKnowledgeResourceTemplateResources(uriTemplate) {
2804
+ const template = KNOWLEDGE_RESOURCE_TEMPLATE_DEFINITIONS.find(
2805
+ (entry) => entry.uriTemplate === uriTemplate
2806
+ );
2807
+ if (!template) {
2808
+ throw new KnowledgeResourceNotFoundError(uriTemplate);
2718
2809
  }
2719
- const entries = await readdir2(currentDir, { withFileTypes: true });
2720
- const files = [];
2721
- for (const entry of entries) {
2722
- const entryPath = resolve5(currentDir, entry.name);
2723
- if (entry.isDirectory()) {
2724
- files.push(
2725
- ...await collectScopeFiles(
2726
- entryPath,
2727
- auditedRoot,
2728
- patchStorageRoot,
2729
- outputRoot
2730
- )
2731
- );
2732
- continue;
2733
- }
2734
- if (!entry.isFile()) {
2735
- continue;
2736
- }
2737
- const normalized = normalizePathWithinRoot(auditedRoot, entryPath, outputRoot);
2738
- if (normalized) {
2739
- files.push(normalized);
2740
- }
2810
+ return template.list();
2811
+ }
2812
+ function getKnowledgeResourceEntry(uri) {
2813
+ return KNOWLEDGE_RESOURCE_DEFINITIONS.find((entry) => entry.uri === uri);
2814
+ }
2815
+ async function readKnowledgeResourceDocument(uri) {
2816
+ const resource = getKnowledgeResourceEntry(uri);
2817
+ if (resource) {
2818
+ return await resource.read();
2819
+ }
2820
+ if (uri.startsWith("ez-know://lookup/")) {
2821
+ return await createKnowledgeSchemaLookupTemplateDefinition().read(uri);
2822
+ }
2823
+ if (uri.startsWith("ez-know://extraction/schema/")) {
2824
+ return await createKnowledgeExtractionSchemaTemplateDefinition().read(uri);
2825
+ }
2826
+ if (uri.startsWith("ez-know://extraction/guide/")) {
2827
+ return await createKnowledgeExtractionGuideTemplateDefinition().read(uri);
2828
+ }
2829
+ throw new KnowledgeResourceNotFoundError(uri);
2830
+ }
2831
+
2832
+ // packages/core/src/knowledge/patch/apply.ts
2833
+ import { existsSync as existsSync3 } from "node:fs";
2834
+ import { mkdir as mkdir2, rm, unlink, writeFile as writeFile2 } from "node:fs/promises";
2835
+ import { dirname } from "node:path";
2836
+
2837
+ // packages/core/src/knowledge/patch/validation.ts
2838
+ import { readFile as readFile4, stat } from "node:fs/promises";
2839
+ import { join as join4 } from "node:path";
2840
+ async function buildSourceFingerprintInput(sourceFiles) {
2841
+ const entries = await Promise.all(
2842
+ sourceFiles.map(async (filePath) => {
2843
+ const [fileStat, content] = await Promise.all([
2844
+ stat(filePath),
2845
+ readFile4(filePath, "utf8")
2846
+ ]);
2847
+ return {
2848
+ path: filePath,
2849
+ size: fileStat.size,
2850
+ mtimeMs: fileStat.mtimeMs,
2851
+ contentHash: sha256(content)
2852
+ };
2853
+ })
2854
+ );
2855
+ entries.sort((left, right) => left.path.localeCompare(right.path));
2856
+ return entries;
2857
+ }
2858
+ function buildCanonicalPathForCollection(rootDir, domain, type) {
2859
+ return join4(
2860
+ rootDir,
2861
+ domain,
2862
+ KNOWLEDGE_EXTRACTION_TYPE_REGISTRY[type].storageFile
2863
+ );
2864
+ }
2865
+ function buildAffectedFileList(knowledgeRoot, operations) {
2866
+ const affected = /* @__PURE__ */ new Set();
2867
+ for (const operation of operations) {
2868
+ affected.add(
2869
+ buildCanonicalPathForCollection(
2870
+ knowledgeRoot,
2871
+ operation.domain,
2872
+ operation.type
2873
+ )
2874
+ );
2741
2875
  }
2742
- return files;
2876
+ return [...affected].sort((left, right) => left.localeCompare(right));
2743
2877
  }
2744
- async function compareScopeWithEvidence(envValue, input, cwd = process.cwd()) {
2745
- const parsedInput = compareScopeWithEvidenceInputSchema.parse(input);
2746
- const patchState = await readKnowledgePatch(envValue, parsedInput.patchId, cwd);
2747
- const auditedRoot = normalizeAuditedRoot(
2748
- parsedInput.rootFolder ?? patchState.patch.rootFolder
2878
+ function buildCollectionRecordsForDomain(state, type, domain) {
2879
+ const records = [...state.byCollection[type].values()].filter(
2880
+ (record2) => inferDomainForRecord(record2) === domain
2749
2881
  );
2750
- const repositoryRoot = resolve5(cwd);
2751
- const effectiveState = await loadEffectiveKnowledgeStoreFromRoot(
2752
- resolveKnowledgeRoot2(envValue, cwd),
2882
+ records.sort((left, right) => left.id.localeCompare(right.id));
2883
+ return records;
2884
+ }
2885
+ async function computeValidationResult(knowledgeRoot, patchId, patch, operations) {
2886
+ const effectiveBase = await loadEffectiveKnowledgeStoreFromRoot(
2887
+ knowledgeRoot,
2753
2888
  {
2754
- selectedPatchId: parsedInput.patchId
2889
+ selectedPatchId: patchId,
2890
+ includeSelectedPatch: false
2755
2891
  }
2756
2892
  );
2757
- const effectivePatchIds = new Set(effectiveState.patchIds);
2758
- const coveredFiles = /* @__PURE__ */ new Set();
2759
- const outOfRootEvidenceFiles = /* @__PURE__ */ new Set();
2760
- for (const evidence of effectiveState.store.evidence) {
2761
- const provenance = effectiveState.provenance.get(evidence.id);
2762
- if (!provenance?.patchIds.some((patchId) => effectivePatchIds.has(patchId))) {
2763
- continue;
2764
- }
2765
- const sourcePath = evidence.location?.path;
2766
- if (!sourcePath) {
2767
- continue;
2768
- }
2769
- const normalized = normalizePathWithinRoot(
2770
- auditedRoot,
2771
- sourcePath,
2772
- repositoryRoot
2773
- );
2774
- if (normalized) {
2775
- coveredFiles.add(normalized);
2776
- continue;
2777
- }
2778
- outOfRootEvidenceFiles.add(sourcePath);
2779
- }
2780
- const omittedFiles = patchState.patch.omittedFiles.map((entry) => ({
2781
- path: entry.path,
2782
- reason: entry.reason
2783
- }));
2784
- const omittedFileSet = new Set(omittedFiles.map((entry) => entry.path));
2785
- const patchStorageRoot = resolve5(auditedRoot, KNOWLEDGE_PATCH_FOLDER_NAME);
2786
- const scopeFiles = (await collectScopeFiles(
2787
- auditedRoot,
2788
- auditedRoot,
2789
- patchStorageRoot,
2790
- repositoryRoot
2791
- )).sort((left, right) => left.localeCompare(right));
2792
- const uncoveredFiles = scopeFiles.filter(
2793
- (filePath) => !coveredFiles.has(filePath) && !omittedFileSet.has(filePath)
2893
+ const simulation = simulateKnowledgePatch(
2894
+ effectiveBase.store,
2895
+ operations,
2896
+ patchId
2794
2897
  );
2795
- const sortedCoveredFiles = [...coveredFiles].sort(
2796
- (left, right) => left.localeCompare(right)
2898
+ const affectedFiles = buildAffectedFileList(knowledgeRoot, operations);
2899
+ const diagnostics = [
2900
+ ...effectiveBase.diagnostics,
2901
+ ...simulation.diagnostics
2902
+ ];
2903
+ if (diagnostics.length > 0) {
2904
+ return knowledgePatchValidationResultSchema.parse({
2905
+ valid: false,
2906
+ diagnostics,
2907
+ operationCount: operations.length,
2908
+ appliedOperationIds: simulation.appliedOperationIds,
2909
+ affectedFiles
2910
+ });
2911
+ }
2912
+ const sourceFingerprint = await buildSourceFingerprintInput(
2913
+ effectiveBase.store.sourceFiles
2797
2914
  );
2798
- const sortedOutOfRootEvidenceFiles = [...outOfRootEvidenceFiles].sort(
2799
- (left, right) => left.localeCompare(right)
2915
+ const fingerprint = sha256(
2916
+ JSON.stringify({
2917
+ schemaVersion: KNOWLEDGE_PATCH_SCHEMA_VERSION,
2918
+ patch: {
2919
+ id: patch.id,
2920
+ status: patch.status,
2921
+ updatedAt: patch.updatedAt
2922
+ },
2923
+ operations,
2924
+ sourceFingerprint
2925
+ })
2800
2926
  );
2801
- const message = uncoveredFiles.length > 0 ? `Recheck ${uncoveredFiles.length} uncovered file(s): add evidence-backed knowledge or mark them omitted with a reason.` : "Scope audit complete. No uncovered files remain.";
2802
- return compareScopeWithEvidenceResultSchema.parse({
2803
- patchId: parsedInput.patchId,
2804
- rootFolder: auditedRoot,
2805
- scopeFiles,
2806
- coveredFiles: sortedCoveredFiles,
2807
- omittedFiles,
2808
- uncoveredFiles,
2809
- outOfRootEvidenceFiles: sortedOutOfRootEvidenceFiles,
2810
- message
2927
+ return knowledgePatchValidationResultSchema.parse({
2928
+ valid: true,
2929
+ fingerprint,
2930
+ diagnostics,
2931
+ operationCount: operations.length,
2932
+ appliedOperationIds: simulation.appliedOperationIds,
2933
+ affectedFiles
2811
2934
  });
2812
2935
  }
2813
-
2814
- // packages/core/src/knowledge/patch/index.ts
2815
- async function executeKnowledgePatchAction(envValue, input, cwd = process.cwd()) {
2816
- switch (input.action) {
2817
- case "create":
2818
- return createKnowledgePatch(envValue, input.patch, cwd);
2819
- case "list":
2820
- return listKnowledgePatches(envValue, cwd);
2821
- case "get":
2822
- return readKnowledgePatch(envValue, input.patchId, cwd);
2823
- case "add_operation":
2824
- return addKnowledgePatchOperation(
2825
- envValue,
2826
- input.patchId,
2827
- input.operation,
2828
- cwd
2829
- );
2830
- case "update_operation":
2831
- return updateKnowledgePatchOperation(
2832
- envValue,
2833
- input.patchId,
2834
- input.update,
2835
- cwd
2836
- );
2837
- case "update_metadata":
2838
- return updateKnowledgePatchMetadata(
2839
- envValue,
2840
- input.patchId,
2841
- input.metadata,
2842
- cwd
2843
- );
2844
- case "delete_operation":
2845
- return deleteKnowledgePatchOperation(
2846
- envValue,
2847
- input.patchId,
2848
- input.operationId,
2849
- cwd
2850
- );
2851
- case "validate":
2852
- return validateKnowledgePatch(envValue, input.patchId, cwd);
2853
- case "close":
2854
- return closeKnowledgePatch(envValue, input.patchId, cwd);
2855
- }
2856
- }
2857
- function buildKnowledgePatchToolText(result) {
2858
- return JSON.stringify(result, null, 2);
2936
+ async function validateKnowledgePatch(envValue, patchId, cwd = process.cwd()) {
2937
+ const knowledgeRoot = resolveKnowledgeRoot2(envValue, cwd);
2938
+ const state = await readKnowledgePatch(envValue, patchId, cwd);
2939
+ return computeValidationResult(
2940
+ knowledgeRoot,
2941
+ patchId,
2942
+ state.patch,
2943
+ state.operations
2944
+ );
2859
2945
  }
2860
2946
 
2861
- // packages/core/src/knowledge/schema-discovery.ts
2862
- import {
2863
- isAbstractType,
2864
- isCompositeType,
2865
- isListType,
2866
- isNonNullType,
2867
- isObjectType,
2868
- isScalarType,
2869
- isUnionType
2870
- } from "graphql";
2871
- var KNOWLEDGE_SCHEMA_RESOURCE_URI = "knowledge-schema://schema";
2872
- var KNOWLEDGE_SCHEMA_LOOKUP_URI = "knowledge-schema://lookup/{target}";
2873
- function unwrapType(type) {
2874
- if (isNonNullType(type) || isListType(type)) {
2875
- return unwrapType(type.ofType);
2876
- }
2877
- if (isObjectType(type) || isScalarType(type) || isUnionType(type) || isAbstractType(type)) {
2878
- return { name: type.name, composite: type };
2879
- }
2880
- return { name: "Unknown", composite: type };
2881
- }
2882
- function describeType(type) {
2883
- if (isNonNullType(type)) {
2884
- return `${describeType(type.ofType)}!`;
2885
- }
2886
- if (isListType(type)) {
2887
- return `[${describeType(type.ofType)}]`;
2888
- }
2889
- if (isObjectType(type) || isScalarType(type) || isUnionType(type)) {
2890
- return type.name;
2891
- }
2892
- if (isAbstractType(type)) {
2893
- return type.name;
2947
+ // packages/core/src/knowledge/patch/apply.ts
2948
+ async function writeCanonicalFilesFromSimulation(knowledgeRoot, operations, simulationState) {
2949
+ const plannedWrites = /* @__PURE__ */ new Map();
2950
+ for (const operation of operations) {
2951
+ const filePath = buildCanonicalPathForCollection(
2952
+ knowledgeRoot,
2953
+ operation.domain,
2954
+ operation.type
2955
+ );
2956
+ const records = buildCollectionRecordsForDomain(
2957
+ simulationState,
2958
+ operation.type,
2959
+ operation.domain
2960
+ );
2961
+ if (operation.type === "domains") {
2962
+ if (records.length === 0) {
2963
+ if (existsSync3(filePath)) {
2964
+ await unlink(filePath);
2965
+ }
2966
+ continue;
2967
+ }
2968
+ plannedWrites.set(filePath, `${JSON.stringify(records[0], null, 2)}
2969
+ `);
2970
+ continue;
2971
+ }
2972
+ plannedWrites.set(filePath, `${JSON.stringify(records, null, 2)}
2973
+ `);
2894
2974
  }
2895
- return "Unknown";
2896
- }
2897
- function formatDefaultValue(value) {
2898
- if (value === void 0 || value === null) {
2899
- return null;
2975
+ for (const filePath of plannedWrites.keys()) {
2976
+ await mkdir2(dirname(filePath), { recursive: true });
2900
2977
  }
2901
- return JSON.stringify(value) ?? String(value);
2902
- }
2903
- function summarizeField(field) {
2904
- const traversedType = unwrapType(field.type).composite;
2905
- const traversesTo = isCompositeType(traversedType) && !isScalarType(traversedType) ? traversedType.name : null;
2906
- return {
2907
- name: field.name,
2908
- type: describeType(field.type),
2909
- description: field.description ?? null,
2910
- arguments: field.args?.map((argument) => ({
2911
- name: argument.name,
2912
- type: describeType(argument.type),
2913
- description: argument.description ?? null,
2914
- defaultValue: formatDefaultValue(argument.defaultValue)
2915
- })) ?? [],
2916
- traversesTo
2917
- };
2918
- }
2919
- function summarizeObjectType(type) {
2920
- const fields = Object.values(type.getFields()).map(summarizeField);
2921
- return {
2922
- name: type.name,
2923
- description: type.description ?? null,
2924
- fields,
2925
- traversalFields: fields.filter((field) => field.traversesTo !== null).map((field) => field.name)
2926
- };
2927
- }
2928
- function getObjectTypes(schema) {
2929
- return Object.values(schema.getTypeMap()).filter((type) => isObjectType(type)).filter((type) => !type.name.startsWith("__")).filter((type) => type.name !== schema.getQueryType()?.name);
2930
- }
2931
- function buildKnowledgeSchemaDiscoveryDocument(schema) {
2932
- const queryType2 = schema.getQueryType();
2933
- if (!queryType2) {
2934
- throw new Error("Knowledge GraphQL schema has no root query type.");
2978
+ for (const [filePath, content] of plannedWrites.entries()) {
2979
+ await writeFile2(filePath, content, "utf8");
2935
2980
  }
2936
- return {
2937
- resource: {
2938
- uri: KNOWLEDGE_SCHEMA_RESOURCE_URI,
2939
- title: "Knowledge GraphQL Schema",
2940
- description: "Canonical discovery view of the runtime knowledge GraphQL schema."
2941
- },
2942
- source: {
2943
- kind: "runtime-schema",
2944
- queryType: queryType2.name
2945
- },
2946
- rootQuery: summarizeObjectType(queryType2),
2947
- objectTypes: getObjectTypes(schema).map(summarizeObjectType)
2948
- };
2949
2981
  }
2950
- function getLookupMetadata(schema, target) {
2951
- const queryType2 = schema.getQueryType();
2952
- if (!queryType2) {
2953
- throw new Error("Knowledge GraphQL schema has no root query type.");
2982
+ async function applyKnowledgePatch(envValue, input, cwd = process.cwd()) {
2983
+ const parsedInput = knowledgePatchApplyToolInputSchema.parse(input);
2984
+ const knowledgeRoot = resolveKnowledgeRoot2(envValue, cwd);
2985
+ const patchDir = resolveKnowledgePatchDirectory(
2986
+ envValue,
2987
+ parsedInput.patchId,
2988
+ cwd
2989
+ );
2990
+ const patchState = await loadPatchStateByDir(patchDir);
2991
+ const validation = await computeValidationResult(
2992
+ knowledgeRoot,
2993
+ patchState.patch.id,
2994
+ patchState.patch,
2995
+ patchState.operations
2996
+ );
2997
+ const diagnostics = [...validation.diagnostics];
2998
+ const pendingPatches = (await listKnowledgePatches(envValue, cwd)).filter(
2999
+ (patch) => patch.status === "draft"
3000
+ );
3001
+ const firstPendingPatchId = pendingPatches[0]?.id;
3002
+ if (firstPendingPatchId !== void 0 && firstPendingPatchId !== patchState.patch.id) {
3003
+ diagnostics.push(
3004
+ buildDiagnostic({
3005
+ severity: "error",
3006
+ code: "apply_out_of_order",
3007
+ message: `Patch "${patchState.patch.id}" cannot be applied while earlier pending patch "${firstPendingPatchId}" still exists.`,
3008
+ patchId: patchState.patch.id
3009
+ })
3010
+ );
2954
3011
  }
2955
- if (target === queryType2.name) {
3012
+ if (!parsedInput.approval.approved) {
3013
+ diagnostics.push(
3014
+ buildDiagnostic({
3015
+ severity: "error",
3016
+ code: "approval_required",
3017
+ message: "Patch apply requires explicit approval.",
3018
+ patchId: patchState.patch.id
3019
+ })
3020
+ );
3021
+ }
3022
+ if (firstPendingPatchId !== void 0 && firstPendingPatchId !== patchState.patch.id || !parsedInput.approval.approved || !validation.valid || parsedInput.approval.validationFingerprint !== validation.fingerprint) {
3023
+ if (validation.valid && parsedInput.approval.validationFingerprint !== validation.fingerprint) {
3024
+ diagnostics.push(
3025
+ buildDiagnostic({
3026
+ severity: "error",
3027
+ code: "stale_validation_fingerprint",
3028
+ message: "Patch validation fingerprint is stale. Revalidate before apply.",
3029
+ patchId: patchState.patch.id
3030
+ })
3031
+ );
3032
+ }
2956
3033
  return {
2957
- resource: {
2958
- uri: `knowledge-schema://lookup/${target}`,
2959
- title: `Knowledge schema lookup: ${target}`,
2960
- description: "Focused lookup of the root query fields and their arguments."
2961
- },
2962
- source: {
2963
- kind: "runtime-schema",
2964
- queryType: queryType2.name
2965
- },
2966
- lookup: {
2967
- target: queryType2.name,
2968
- kind: "root-query"
2969
- },
2970
- rootQuery: summarizeObjectType(queryType2)
3034
+ patchId: patchState.patch.id,
3035
+ applied: false,
3036
+ validation,
3037
+ diagnostics,
3038
+ deletedPatch: false
2971
3039
  };
2972
3040
  }
2973
- const rootField = queryType2.getFields()[target];
2974
- if (rootField) {
3041
+ const store = await loadKnowledgeStoreFromRoot(knowledgeRoot);
3042
+ const simulation = simulateKnowledgePatch(
3043
+ store,
3044
+ patchState.operations,
3045
+ patchState.patch.id
3046
+ );
3047
+ if (simulation.diagnostics.length > 0) {
2975
3048
  return {
2976
- resource: {
2977
- uri: `knowledge-schema://lookup/${target}`,
2978
- title: `Knowledge schema lookup: ${target}`,
2979
- description: "Focused lookup of a single root query field and its arguments."
2980
- },
2981
- source: {
2982
- kind: "runtime-schema",
2983
- queryType: queryType2.name
2984
- },
2985
- lookup: {
2986
- target,
2987
- kind: "root-field"
3049
+ patchId: patchState.patch.id,
3050
+ applied: false,
3051
+ validation: {
3052
+ ...validation,
3053
+ valid: false,
3054
+ diagnostics: simulation.diagnostics
2988
3055
  },
2989
- field: summarizeField(rootField),
2990
- parentType: queryType2.name
3056
+ diagnostics: simulation.diagnostics,
3057
+ deletedPatch: false
2991
3058
  };
2992
3059
  }
2993
- const objectType = schema.getType(target);
2994
- if (objectType && isObjectType(objectType)) {
2995
- const typeSummary = summarizeObjectType(objectType);
2996
- const rootFields = Object.values(queryType2.getFields()).filter((field) => unwrapType(field.type).name === target).map((field) => field.name);
3060
+ await writeCanonicalFilesFromSimulation(
3061
+ knowledgeRoot,
3062
+ patchState.operations,
3063
+ simulation.state
3064
+ );
3065
+ try {
3066
+ await loadKnowledgeStoreFromRoot(knowledgeRoot);
3067
+ } catch (error) {
3068
+ const reloadDiagnostics = error instanceof KnowledgeStoreLoadError ? error.diagnostics.map(
3069
+ (diagnostic) => buildDiagnostic({
3070
+ severity: "critical",
3071
+ code: diagnostic.kind,
3072
+ message: diagnostic.message,
3073
+ path: diagnostic.path ? [diagnostic.path] : void 0,
3074
+ targetId: diagnostic.id
3075
+ })
3076
+ ) : [
3077
+ buildDiagnostic({
3078
+ severity: "critical",
3079
+ code: "reload_failed",
3080
+ message: "Canonical knowledge store reload failed after apply.",
3081
+ patchId: patchState.patch.id
3082
+ })
3083
+ ];
2997
3084
  return {
2998
- resource: {
2999
- uri: `knowledge-schema://lookup/${target}`,
3000
- title: `Knowledge schema lookup: ${target}`,
3001
- description: "Focused lookup of a single GraphQL type and its nested traversal fields."
3002
- },
3003
- source: {
3004
- kind: "runtime-schema",
3005
- queryType: queryType2.name
3006
- },
3007
- lookup: {
3008
- target,
3009
- kind: "object-type"
3010
- },
3011
- type: typeSummary,
3012
- rootFields
3085
+ patchId: patchState.patch.id,
3086
+ applied: false,
3087
+ validation,
3088
+ diagnostics: reloadDiagnostics,
3089
+ deletedPatch: false
3013
3090
  };
3014
3091
  }
3015
- throw new Error(
3016
- `Unknown schema lookup target "${target}". Use a root field name, a type name, or "Query".`
3092
+ await rm(patchDir, { recursive: true, force: true });
3093
+ return {
3094
+ patchId: patchState.patch.id,
3095
+ applied: true,
3096
+ validation,
3097
+ diagnostics: [],
3098
+ deletedPatch: true
3099
+ };
3100
+ }
3101
+
3102
+ // packages/core/src/knowledge/patch/scope-audit.ts
3103
+ import { readdir as readdir2 } from "node:fs/promises";
3104
+ import { isAbsolute as isAbsolute2, relative, resolve as resolve5, sep as sep2 } from "node:path";
3105
+ import { z as z6 } from "zod/v4";
3106
+ var compareScopeWithEvidenceInputSchema = z6.object({
3107
+ patchId: z6.string().min(1),
3108
+ rootFolder: z6.string().trim().min(1).optional()
3109
+ });
3110
+ var compareScopeWithEvidenceResultSchema = z6.object({
3111
+ patchId: z6.string().min(1),
3112
+ rootFolder: z6.string().min(1),
3113
+ scopeFiles: z6.array(z6.string()),
3114
+ coveredFiles: z6.array(z6.string()),
3115
+ omittedFiles: z6.array(
3116
+ z6.object({
3117
+ path: z6.string(),
3118
+ reason: z6.string()
3119
+ })
3120
+ ),
3121
+ uncoveredFiles: z6.array(z6.string()),
3122
+ outOfRootEvidenceFiles: z6.array(z6.string()),
3123
+ message: z6.string()
3124
+ });
3125
+ function toPosixPath(value) {
3126
+ return value.replaceAll(sep2, "/");
3127
+ }
3128
+ function normalizeAuditedRoot(rootFolder) {
3129
+ return resolve5(rootFolder);
3130
+ }
3131
+ function isPathWithinRoot(rootFolder, filePath) {
3132
+ const relativePath = toPosixPath(relative(rootFolder, filePath));
3133
+ return Boolean(
3134
+ relativePath && relativePath !== ".." && !relativePath.startsWith("../")
3017
3135
  );
3018
3136
  }
3019
- function buildKnowledgeSchemaLookupDocument(schema, target) {
3020
- return getLookupMetadata(schema, target);
3137
+ function normalizePathWithinRoot(rootFolder, filePath, outputRoot = rootFolder) {
3138
+ let candidate;
3139
+ if (isAbsolute2(filePath)) {
3140
+ candidate = resolve5(filePath);
3141
+ } else {
3142
+ const repoRelativeCandidate = resolve5(outputRoot, filePath);
3143
+ candidate = isPathWithinRoot(rootFolder, repoRelativeCandidate) ? repoRelativeCandidate : resolve5(rootFolder, filePath);
3144
+ }
3145
+ const relativePath = toPosixPath(relative(outputRoot, candidate));
3146
+ if (!relativePath || relativePath === ".." || relativePath.startsWith("../")) {
3147
+ return null;
3148
+ }
3149
+ return relativePath;
3021
3150
  }
3022
- function createKnowledgeSchemaResourceText(schema) {
3023
- return JSON.stringify(buildKnowledgeSchemaDiscoveryDocument(schema), null, 2);
3151
+ async function collectScopeFiles(currentDir, auditedRoot, patchStorageRoot, outputRoot) {
3152
+ if (currentDir === patchStorageRoot) {
3153
+ return [];
3154
+ }
3155
+ const entries = await readdir2(currentDir, { withFileTypes: true });
3156
+ const files = [];
3157
+ for (const entry of entries) {
3158
+ const entryPath = resolve5(currentDir, entry.name);
3159
+ if (entry.isDirectory()) {
3160
+ files.push(
3161
+ ...await collectScopeFiles(
3162
+ entryPath,
3163
+ auditedRoot,
3164
+ patchStorageRoot,
3165
+ outputRoot
3166
+ )
3167
+ );
3168
+ continue;
3169
+ }
3170
+ if (!entry.isFile()) {
3171
+ continue;
3172
+ }
3173
+ const normalized = normalizePathWithinRoot(auditedRoot, entryPath, outputRoot);
3174
+ if (normalized) {
3175
+ files.push(normalized);
3176
+ }
3177
+ }
3178
+ return files;
3024
3179
  }
3025
- function createKnowledgeSchemaLookupText(schema, target) {
3026
- return JSON.stringify(
3027
- buildKnowledgeSchemaLookupDocument(schema, target),
3028
- null,
3029
- 2
3180
+ async function compareScopeWithEvidence(envValue, input, cwd = process.cwd()) {
3181
+ const parsedInput = compareScopeWithEvidenceInputSchema.parse(input);
3182
+ const patchState = await readKnowledgePatch(envValue, parsedInput.patchId, cwd);
3183
+ const auditedRoot = normalizeAuditedRoot(
3184
+ parsedInput.rootFolder ?? patchState.patch.rootFolder
3030
3185
  );
3031
- }
3032
- function listKnowledgeSchemaTargets(schema) {
3033
- const queryType2 = schema.getQueryType();
3034
- if (!queryType2) {
3035
- throw new Error("Knowledge GraphQL schema has no root query type.");
3186
+ const repositoryRoot = resolve5(cwd);
3187
+ const effectiveState = await loadEffectiveKnowledgeStoreFromRoot(
3188
+ resolveKnowledgeRoot2(envValue, cwd),
3189
+ {
3190
+ selectedPatchId: parsedInput.patchId
3191
+ }
3192
+ );
3193
+ const effectivePatchIds = new Set(effectiveState.patchIds);
3194
+ const coveredFiles = /* @__PURE__ */ new Set();
3195
+ const outOfRootEvidenceFiles = /* @__PURE__ */ new Set();
3196
+ for (const evidence of effectiveState.store.evidence) {
3197
+ const provenance = effectiveState.provenance.get(evidence.id);
3198
+ if (!provenance?.patchIds.some((patchId) => effectivePatchIds.has(patchId))) {
3199
+ continue;
3200
+ }
3201
+ const sourcePath = evidence.location?.path;
3202
+ if (!sourcePath) {
3203
+ continue;
3204
+ }
3205
+ const normalized = normalizePathWithinRoot(
3206
+ auditedRoot,
3207
+ sourcePath,
3208
+ repositoryRoot
3209
+ );
3210
+ if (normalized) {
3211
+ coveredFiles.add(normalized);
3212
+ continue;
3213
+ }
3214
+ outOfRootEvidenceFiles.add(sourcePath);
3036
3215
  }
3037
- const objectTypeNames = getObjectTypes(schema).map((type) => type.name);
3038
- const rootFieldNames = Object.keys(queryType2.getFields());
3039
- const targetNames = ["Query", ...rootFieldNames, ...objectTypeNames];
3040
- return Array.from(new Set(targetNames)).sort(
3216
+ const omittedFiles = patchState.patch.omittedFiles.map((entry) => ({
3217
+ path: entry.path,
3218
+ reason: entry.reason
3219
+ }));
3220
+ const omittedFileSet = new Set(omittedFiles.map((entry) => entry.path));
3221
+ const patchStorageRoot = resolve5(auditedRoot, KNOWLEDGE_PATCH_FOLDER_NAME);
3222
+ const scopeFiles = (await collectScopeFiles(
3223
+ auditedRoot,
3224
+ auditedRoot,
3225
+ patchStorageRoot,
3226
+ repositoryRoot
3227
+ )).sort((left, right) => left.localeCompare(right));
3228
+ const uncoveredFiles = scopeFiles.filter(
3229
+ (filePath) => !coveredFiles.has(filePath) && !omittedFileSet.has(filePath)
3230
+ );
3231
+ const sortedCoveredFiles = [...coveredFiles].sort(
3232
+ (left, right) => left.localeCompare(right)
3233
+ );
3234
+ const sortedOutOfRootEvidenceFiles = [...outOfRootEvidenceFiles].sort(
3041
3235
  (left, right) => left.localeCompare(right)
3042
3236
  );
3237
+ const message = uncoveredFiles.length > 0 ? `Recheck ${uncoveredFiles.length} uncovered file(s): add evidence-backed knowledge or mark them omitted with a reason.` : "Scope audit complete. No uncovered files remain.";
3238
+ return compareScopeWithEvidenceResultSchema.parse({
3239
+ patchId: parsedInput.patchId,
3240
+ rootFolder: auditedRoot,
3241
+ scopeFiles,
3242
+ coveredFiles: sortedCoveredFiles,
3243
+ omittedFiles,
3244
+ uncoveredFiles,
3245
+ outOfRootEvidenceFiles: sortedOutOfRootEvidenceFiles,
3246
+ message
3247
+ });
3043
3248
  }
3044
3249
 
3045
- // packages/mcp/src/resources/knowledge-extraction.ts
3046
- import { ResourceTemplate } from "@modelcontextprotocol/server";
3047
- function createJsonResourceContent(uri, text) {
3048
- return {
3049
- contents: [
3050
- {
3051
- uri,
3052
- mimeType: "application/json",
3053
- text
3054
- }
3055
- ]
3056
- };
3250
+ // packages/core/src/knowledge/patch/index.ts
3251
+ async function executeKnowledgePatchAction(envValue, input, cwd = process.cwd()) {
3252
+ switch (input.action) {
3253
+ case "create":
3254
+ return createKnowledgePatch(envValue, input.patch, cwd);
3255
+ case "list":
3256
+ return listKnowledgePatches(envValue, cwd);
3257
+ case "get":
3258
+ return readKnowledgePatch(envValue, input.patchId, cwd);
3259
+ case "add_operation":
3260
+ return addKnowledgePatchOperation(
3261
+ envValue,
3262
+ input.patchId,
3263
+ input.operation,
3264
+ cwd
3265
+ );
3266
+ case "update_operation":
3267
+ return updateKnowledgePatchOperation(
3268
+ envValue,
3269
+ input.patchId,
3270
+ input.update,
3271
+ cwd
3272
+ );
3273
+ case "update_metadata":
3274
+ return updateKnowledgePatchMetadata(
3275
+ envValue,
3276
+ input.patchId,
3277
+ input.metadata,
3278
+ cwd
3279
+ );
3280
+ case "delete_operation":
3281
+ return deleteKnowledgePatchOperation(
3282
+ envValue,
3283
+ input.patchId,
3284
+ input.operationId,
3285
+ cwd
3286
+ );
3287
+ case "validate":
3288
+ return validateKnowledgePatch(envValue, input.patchId, cwd);
3289
+ case "close":
3290
+ return closeKnowledgePatch(envValue, input.patchId, cwd);
3291
+ }
3057
3292
  }
3058
- function createMarkdownResourceContent(uri, text) {
3059
- return {
3060
- contents: [
3061
- {
3062
- uri,
3063
- mimeType: "text/markdown",
3064
- text
3065
- }
3066
- ]
3067
- };
3293
+ function buildKnowledgePatchToolText(result) {
3294
+ return JSON.stringify(result, null, 2);
3068
3295
  }
3296
+
3297
+ // packages/mcp/src/resources/knowledge-extraction.ts
3298
+ import { ResourceTemplate } from "@modelcontextprotocol/server";
3069
3299
  function listExtractionTypeNames() {
3070
3300
  return listKnowledgeExtractionResourceTypes().flatMap((definition) => [
3071
3301
  definition.collection,
@@ -3073,30 +3303,29 @@ function listExtractionTypeNames() {
3073
3303
  ]);
3074
3304
  }
3075
3305
  function registerKnowledgeExtractionResources(server) {
3306
+ const resource = getKnowledgeResourceEntry(KNOWLEDGE_EXTRACTION_TYPES_RESOURCE_URI);
3307
+ if (!resource) {
3308
+ throw new Error("Knowledge extraction resource metadata is missing.");
3309
+ }
3076
3310
  server.registerResource(
3077
- "knowledge-extraction-types",
3311
+ resource.name,
3078
3312
  KNOWLEDGE_EXTRACTION_TYPES_RESOURCE_URI,
3079
3313
  {
3080
- title: "Knowledge Extraction Types",
3081
- description: "Canonical registry of knowledge types supported by the extraction workflow.",
3082
- mimeType: "application/json"
3314
+ title: resource.title,
3315
+ description: resource.description,
3316
+ mimeType: resource.mimeType
3083
3317
  },
3084
- async (uri) => createJsonResourceContent(
3085
- uri.href,
3086
- JSON.stringify(buildKnowledgeExtractionTypeIndexDocument(), null, 2)
3087
- )
3318
+ async (uri) => ({
3319
+ contents: [(await readKnowledgeResourceDocument(uri.href)).content]
3320
+ })
3088
3321
  );
3089
3322
  server.registerResource(
3090
3323
  "knowledge-extraction-schema",
3091
3324
  new ResourceTemplate(KNOWLEDGE_EXTRACTION_SCHEMA_RESOURCE_URI, {
3092
3325
  list: async () => ({
3093
- resources: listKnowledgeExtractionResourceTypes().map((definition) => ({
3094
- uri: `ez-know://extraction/schema/${definition.collection}`,
3095
- name: definition.collection,
3096
- title: `${definition.title} Extraction Schema`,
3097
- description: `Runtime schema discovery for ${definition.title.toLowerCase()}.`,
3098
- mimeType: "application/json"
3099
- }))
3326
+ resources: listKnowledgeResourceTemplateResources(
3327
+ KNOWLEDGE_EXTRACTION_SCHEMA_RESOURCE_URI
3328
+ )
3100
3329
  }),
3101
3330
  complete: {
3102
3331
  type: async (value) => listExtractionTypeNames().filter(
@@ -3109,29 +3338,17 @@ function registerKnowledgeExtractionResources(server) {
3109
3338
  description: "Runtime JSON-schema discovery for a supported knowledge type.",
3110
3339
  mimeType: "application/json"
3111
3340
  },
3112
- async (_uri, variables) => {
3113
- const type = variables.type;
3114
- if (typeof type !== "string" || type.length === 0) {
3115
- throw new Error("Resource type is required.");
3116
- }
3117
- const document = buildKnowledgeExtractionSchemaDocument(type);
3118
- return createJsonResourceContent(
3119
- `ez-know://extraction/schema/${document.type.collection}`,
3120
- JSON.stringify(document, null, 2)
3121
- );
3122
- }
3341
+ async (uri) => ({
3342
+ contents: [(await readKnowledgeResourceDocument(uri.href)).content]
3343
+ })
3123
3344
  );
3124
3345
  server.registerResource(
3125
3346
  "knowledge-extraction-guide",
3126
3347
  new ResourceTemplate(KNOWLEDGE_EXTRACTION_GUIDE_RESOURCE_URI, {
3127
3348
  list: async () => ({
3128
- resources: listKnowledgeExtractionResourceTypes().map((definition) => ({
3129
- uri: `ez-know://extraction/guide/${definition.collection}`,
3130
- name: definition.collection,
3131
- title: `${definition.title} Extraction Guide`,
3132
- description: `Checked-in extraction guidance for ${definition.title.toLowerCase()}.`,
3133
- mimeType: "text/markdown"
3134
- }))
3349
+ resources: listKnowledgeResourceTemplateResources(
3350
+ KNOWLEDGE_EXTRACTION_GUIDE_RESOURCE_URI
3351
+ )
3135
3352
  }),
3136
3353
  complete: {
3137
3354
  type: async (value) => listExtractionTypeNames().filter(
@@ -3144,17 +3361,9 @@ function registerKnowledgeExtractionResources(server) {
3144
3361
  description: "Checked-in Markdown guidance for a supported knowledge type.",
3145
3362
  mimeType: "text/markdown"
3146
3363
  },
3147
- async (_uri, variables) => {
3148
- const type = variables.type;
3149
- if (typeof type !== "string" || type.length === 0) {
3150
- throw new Error("Resource type is required.");
3151
- }
3152
- const document = await buildKnowledgeExtractionGuideDocument(type);
3153
- return createMarkdownResourceContent(
3154
- `ez-know://extraction/guide/${document.type.collection}`,
3155
- document.markdown
3156
- );
3157
- }
3364
+ async (uri) => ({
3365
+ contents: [(await readKnowledgeResourceDocument(uri.href)).content]
3366
+ })
3158
3367
  );
3159
3368
  }
3160
3369
 
@@ -3218,6 +3427,104 @@ function registerKnowledgeGraphTool(server, getStore) {
3218
3427
  );
3219
3428
  }
3220
3429
 
3430
+ // packages/mcp/src/tools/legacy-resource-tools.ts
3431
+ import * as z8 from "zod/v4";
3432
+ function createTextToolResult(payload) {
3433
+ return {
3434
+ content: [
3435
+ {
3436
+ type: "text",
3437
+ text: JSON.stringify(payload, null, 2)
3438
+ }
3439
+ ]
3440
+ };
3441
+ }
3442
+ function serializeResourceError(error, uri) {
3443
+ if (error instanceof KnowledgeResourceNotFoundError || error instanceof KnowledgeResourceUriError) {
3444
+ return {
3445
+ error: {
3446
+ code: error.code,
3447
+ message: error.message,
3448
+ uri: error.uri
3449
+ }
3450
+ };
3451
+ }
3452
+ if (error instanceof Error) {
3453
+ return {
3454
+ error: {
3455
+ code: "RESOURCE_READ_FAILED",
3456
+ message: error.message,
3457
+ uri
3458
+ }
3459
+ };
3460
+ }
3461
+ return {
3462
+ error: {
3463
+ code: "RESOURCE_READ_FAILED",
3464
+ message: "Unknown resource read failure.",
3465
+ uri
3466
+ }
3467
+ };
3468
+ }
3469
+ function isLegacyResourceToolsEnabled(value = process.env.EZ_KNOW_LEGACY_RESOURCES) {
3470
+ if (value === void 0) {
3471
+ return false;
3472
+ }
3473
+ const normalized = value.trim().toLowerCase();
3474
+ if (normalized.length === 0) {
3475
+ return false;
3476
+ }
3477
+ return !["0", "false", "off", "no"].includes(normalized);
3478
+ }
3479
+ function registerLegacyResourceTools(server) {
3480
+ server.registerTool(
3481
+ "list_mcp_resources",
3482
+ {
3483
+ title: "Legacy MCP Resource List",
3484
+ description: "Lists the ez-know resources exposed through the legacy tool fallback.",
3485
+ inputSchema: z8.object({})
3486
+ },
3487
+ async () => createTextToolResult({
3488
+ resources: listKnowledgeResourceEntries()
3489
+ })
3490
+ );
3491
+ server.registerTool(
3492
+ "list_mcp_resource_templates",
3493
+ {
3494
+ title: "Legacy MCP Resource Templates",
3495
+ description: "Lists the ez-know resource templates exposed through the legacy tool fallback.",
3496
+ inputSchema: z8.object({})
3497
+ },
3498
+ async () => createTextToolResult({
3499
+ resourceTemplates: listKnowledgeResourceTemplateEntries()
3500
+ })
3501
+ );
3502
+ server.registerTool(
3503
+ "read_mcp_resource",
3504
+ {
3505
+ title: "Legacy MCP Resource Read",
3506
+ description: "Reads a single ez-know resource by URI through the legacy tool fallback.",
3507
+ inputSchema: z8.object({
3508
+ uri: z8.string().min(1)
3509
+ })
3510
+ },
3511
+ async (input) => {
3512
+ const parsedInput = z8.object({ uri: z8.string().min(1) }).parse(input);
3513
+ try {
3514
+ const result = await readKnowledgeResourceDocument(parsedInput.uri);
3515
+ return createTextToolResult({
3516
+ resource: result.resource,
3517
+ contents: [result.content]
3518
+ });
3519
+ } catch (error) {
3520
+ return createTextToolResult(
3521
+ serializeResourceError(error, parsedInput.uri)
3522
+ );
3523
+ }
3524
+ }
3525
+ );
3526
+ }
3527
+
3221
3528
  // packages/mcp/src/tools/knowledge-patch-apply.ts
3222
3529
  function registerKnowledgePatchApplyTool(server) {
3223
3530
  server.registerTool(
@@ -3274,43 +3581,29 @@ function registerKnowledgePatchTool(server) {
3274
3581
 
3275
3582
  // packages/mcp/src/resources/knowledge-schema.ts
3276
3583
  import { ResourceTemplate as ResourceTemplate2 } from "@modelcontextprotocol/server";
3277
- function createJsonResourceContent2(uri, text) {
3278
- return {
3279
- contents: [
3280
- {
3281
- uri,
3282
- mimeType: "application/json",
3283
- text
3284
- }
3285
- ]
3286
- };
3287
- }
3288
3584
  function registerKnowledgeSchemaResources(server) {
3585
+ const resource = getKnowledgeResourceEntry(KNOWLEDGE_SCHEMA_RESOURCE_URI);
3586
+ if (!resource) {
3587
+ throw new Error("Knowledge schema resource metadata is missing.");
3588
+ }
3289
3589
  server.registerResource(
3290
- "knowledge-schema",
3590
+ resource.name,
3291
3591
  KNOWLEDGE_SCHEMA_RESOURCE_URI,
3292
3592
  {
3293
- title: "Knowledge GraphQL Schema",
3294
- description: "Canonical runtime GraphQL schema discovery payload for the knowledge layer.",
3295
- mimeType: "application/json"
3593
+ title: resource.title,
3594
+ description: resource.description,
3595
+ mimeType: resource.mimeType
3296
3596
  },
3297
- async (uri) => createJsonResourceContent2(
3298
- uri.href,
3299
- createKnowledgeSchemaResourceText(knowledgeGraphSchema)
3300
- )
3597
+ async (uri) => ({
3598
+ contents: [(await readKnowledgeResourceDocument(uri.href)).content]
3599
+ })
3301
3600
  );
3302
3601
  server.registerResource(
3303
3602
  "knowledge-schema-lookup",
3304
3603
  new ResourceTemplate2(KNOWLEDGE_SCHEMA_LOOKUP_URI, {
3305
3604
  list: async () => ({
3306
- resources: listKnowledgeSchemaTargets(knowledgeGraphSchema).map(
3307
- (target) => ({
3308
- uri: `knowledge-schema://lookup/${target}`,
3309
- name: target,
3310
- title: `Knowledge schema lookup: ${target}`,
3311
- description: target === "Query" ? "Focused lookup of the root query fields." : `Focused lookup of ${target}.`,
3312
- mimeType: "application/json"
3313
- })
3605
+ resources: listKnowledgeResourceTemplateResources(
3606
+ KNOWLEDGE_SCHEMA_LOOKUP_URI
3314
3607
  )
3315
3608
  }),
3316
3609
  complete: {
@@ -3324,27 +3617,19 @@ function registerKnowledgeSchemaResources(server) {
3324
3617
  description: "Focused runtime GraphQL schema lookup for a type name, root field, or Query.",
3325
3618
  mimeType: "application/json"
3326
3619
  },
3327
- async (_uri, variables) => {
3328
- const target = variables.target;
3329
- if (typeof target !== "string" || target.length === 0) {
3330
- throw new Error("Resource target is required.");
3331
- }
3332
- return createJsonResourceContent2(
3333
- `knowledge-schema://lookup/${target}`,
3334
- createKnowledgeSchemaLookupText(knowledgeGraphSchema, target)
3335
- );
3336
- }
3620
+ async (uri) => ({
3621
+ contents: [(await readKnowledgeResourceDocument(uri.href)).content]
3622
+ })
3337
3623
  );
3338
3624
  }
3339
3625
 
3340
3626
  // packages/mcp/src/run.ts
3341
- async function startMcpServer() {
3342
- const server = new McpServer({
3343
- name: "ez-know",
3344
- version: "0.1.0"
3345
- });
3627
+ function registerMcpServerCapabilities(server) {
3346
3628
  registerKnowledgeSchemaResources(server);
3347
3629
  registerKnowledgeExtractionResources(server);
3630
+ if (isLegacyResourceToolsEnabled()) {
3631
+ registerLegacyResourceTools(server);
3632
+ }
3348
3633
  registerKnowledgeGraphTool(server, async () => {
3349
3634
  const effectiveState = await loadEffectiveKnowledgeStoreFromEnv(
3350
3635
  process.env.EZ_KNOW_ROOT
@@ -3354,6 +3639,13 @@ async function startMcpServer() {
3354
3639
  registerKnowledgePatchTool(server);
3355
3640
  registerKnowledgePatchApplyTool(server);
3356
3641
  registerCompareScopeWithEvidenceTool(server);
3642
+ }
3643
+ async function startMcpServer() {
3644
+ const server = new McpServer({
3645
+ name: "ez-know",
3646
+ version: "0.1.0"
3647
+ });
3648
+ registerMcpServerCapabilities(server);
3357
3649
  const transport = new StdioServerTransport();
3358
3650
  await server.connect(transport);
3359
3651
  }
@@ -3448,7 +3740,7 @@ import {
3448
3740
  OpenAPIRegistry,
3449
3741
  OpenApiGeneratorV3
3450
3742
  } from "@asteasolutions/zod-to-openapi";
3451
- import { z as z8 } from "zod/v4";
3743
+ import { z as z9 } from "zod/v4";
3452
3744
 
3453
3745
  // packages/rest/src/schema-registry.ts
3454
3746
  var REST_COLLECTION_SCHEMA_REGISTRY = {
@@ -3526,14 +3818,14 @@ var REST_CONFIDENCE_SCHEMA = confidenceSchema;
3526
3818
  var REST_CERTAINTY_SCHEMA = certaintySchema;
3527
3819
 
3528
3820
  // packages/rest/src/openapi.ts
3529
- extendZodWithOpenApi2(z8);
3821
+ extendZodWithOpenApi2(z9);
3530
3822
  var openApiRegistry = new OpenAPIRegistry();
3531
3823
  var restErrorResponseSchema = openApiRegistry.register(
3532
3824
  "RestErrorResponse",
3533
- z8.object({
3534
- error: z8.object({
3535
- code: z8.string(),
3536
- message: z8.string()
3825
+ z9.object({
3826
+ error: z9.object({
3827
+ code: z9.string(),
3828
+ message: z9.string()
3537
3829
  })
3538
3830
  }).openapi({
3539
3831
  description: "Standard REST error envelope."
@@ -3541,51 +3833,51 @@ var restErrorResponseSchema = openApiRegistry.register(
3541
3833
  );
3542
3834
  var restHealthResponseSchema = openApiRegistry.register(
3543
3835
  "RestHealthResponse",
3544
- z8.object({
3545
- service: z8.string(),
3546
- status: z8.literal("ok"),
3547
- storeAvailable: z8.boolean()
3836
+ z9.object({
3837
+ service: z9.string(),
3838
+ status: z9.literal("ok"),
3839
+ storeAvailable: z9.boolean()
3548
3840
  }).openapi({
3549
3841
  description: "Service health payload."
3550
3842
  })
3551
3843
  );
3552
3844
  var restPatchSummarySchema = openApiRegistry.register(
3553
3845
  "RestPatchSummary",
3554
- z8.object({
3555
- id: z8.string(),
3556
- status: z8.string(),
3557
- title: z8.string(),
3558
- description: z8.string().optional(),
3559
- rootFolder: z8.string(),
3560
- omittedFiles: z8.array(
3561
- z8.object({
3562
- path: z8.string(),
3563
- reason: z8.string()
3846
+ z9.object({
3847
+ id: z9.string(),
3848
+ status: z9.string(),
3849
+ title: z9.string(),
3850
+ description: z9.string().optional(),
3851
+ rootFolder: z9.string(),
3852
+ omittedFiles: z9.array(
3853
+ z9.object({
3854
+ path: z9.string(),
3855
+ reason: z9.string()
3564
3856
  })
3565
3857
  ),
3566
- operationCount: z8.number().int().min(0),
3567
- createdAt: z8.string(),
3568
- updatedAt: z8.string()
3858
+ operationCount: z9.number().int().min(0),
3859
+ createdAt: z9.string(),
3860
+ updatedAt: z9.string()
3569
3861
  }).openapi({
3570
3862
  description: "Patch inventory summary."
3571
3863
  })
3572
3864
  );
3573
3865
  var restPatchProvenanceEntrySchema = openApiRegistry.register(
3574
3866
  "RestPatchProvenanceEntry",
3575
- z8.object({
3576
- patchIds: z8.array(z8.string()),
3577
- patched: z8.boolean()
3867
+ z9.object({
3868
+ patchIds: z9.array(z9.string()),
3869
+ patched: z9.boolean()
3578
3870
  }).openapi({
3579
3871
  description: "Patch provenance for a previewed record."
3580
3872
  })
3581
3873
  );
3582
3874
  var restPatchFacetItemSchema = openApiRegistry.register(
3583
3875
  "RestPatchFacetItem",
3584
- z8.object({
3585
- id: z8.string(),
3586
- label: z8.string(),
3587
- patched: z8.boolean(),
3588
- provenancePatchIds: z8.array(z8.string())
3876
+ z9.object({
3877
+ id: z9.string(),
3878
+ label: z9.string(),
3879
+ patched: z9.boolean(),
3880
+ provenancePatchIds: z9.array(z9.string())
3589
3881
  }).openapi({
3590
3882
  description: "Patch-aware facet option."
3591
3883
  })
@@ -3600,7 +3892,7 @@ var certaintyRef = openApiRegistry.register(
3600
3892
  );
3601
3893
  var restOpenApiDocumentSchema = openApiRegistry.register(
3602
3894
  "RestOpenApiDocument",
3603
- z8.record(z8.string(), z8.unknown())
3895
+ z9.record(z9.string(), z9.unknown())
3604
3896
  );
3605
3897
  var previewCollectionResponseSchemas = /* @__PURE__ */ new Map();
3606
3898
  for (const collection of REST_COLLECTIONS) {
@@ -3621,24 +3913,24 @@ for (const collection of REST_COLLECTIONS) {
3621
3913
  const previewItemSchema = openApiRegistry.register(
3622
3914
  `${schemaDefinition.itemName}PreviewRecord`,
3623
3915
  itemSchemaSource.extend({
3624
- patched: z8.boolean(),
3625
- provenancePatchIds: z8.array(z8.string())
3916
+ patched: z9.boolean(),
3917
+ provenancePatchIds: z9.array(z9.string())
3626
3918
  })
3627
3919
  );
3628
3920
  const collectionResponseSchema = openApiRegistry.register(
3629
3921
  schemaDefinition.collectionResponseName,
3630
- z8.object({
3631
- items: z8.array(itemSchema),
3632
- count: z8.number().int().min(0)
3922
+ z9.object({
3923
+ items: z9.array(itemSchema),
3924
+ count: z9.number().int().min(0)
3633
3925
  }).openapi({
3634
3926
  description: `${schemaDefinition.itemName} collection response.`
3635
3927
  })
3636
3928
  );
3637
3929
  const previewCollectionResponseSchema = openApiRegistry.register(
3638
3930
  `${schemaDefinition.itemName}PreviewCollectionResponse`,
3639
- z8.object({
3640
- items: z8.array(previewItemSchema),
3641
- count: z8.number().int().min(0)
3931
+ z9.object({
3932
+ items: z9.array(previewItemSchema),
3933
+ count: z9.number().int().min(0)
3642
3934
  }).openapi({
3643
3935
  description: `${schemaDefinition.itemName} preview collection response.`
3644
3936
  })
@@ -3649,7 +3941,7 @@ for (const collection of REST_COLLECTIONS) {
3649
3941
  );
3650
3942
  const itemResponseSchema = openApiRegistry.register(
3651
3943
  schemaDefinition.itemResponseName,
3652
- z8.object({
3944
+ z9.object({
3653
3945
  item: itemSchema
3654
3946
  }).openapi({
3655
3947
  description: `${schemaDefinition.itemName} item response.`
@@ -3691,8 +3983,8 @@ for (const collection of REST_COLLECTIONS) {
3691
3983
  path: `${REST_V1_PREFIX}/${collection.route}/{id}`,
3692
3984
  summary: `Get ${collection.label.toLowerCase()} by id`,
3693
3985
  request: {
3694
- params: z8.object({
3695
- id: z8.string()
3986
+ params: z9.object({
3987
+ id: z9.string()
3696
3988
  })
3697
3989
  },
3698
3990
  responses: {
@@ -3725,25 +4017,25 @@ for (const collection of REST_COLLECTIONS) {
3725
4017
  }
3726
4018
  var restPatchInventoryResponseSchema = openApiRegistry.register(
3727
4019
  "RestPatchInventoryResponse",
3728
- z8.object({
3729
- items: z8.array(restPatchSummarySchema),
3730
- count: z8.number().int().min(0)
4020
+ z9.object({
4021
+ items: z9.array(restPatchSummarySchema),
4022
+ count: z9.number().int().min(0)
3731
4023
  }).openapi({
3732
4024
  description: "Patch inventory response."
3733
4025
  })
3734
4026
  );
3735
4027
  var restPatchPreviewResponseSchema = openApiRegistry.register(
3736
4028
  "RestPatchPreviewResponse",
3737
- z8.object({
3738
- selectedPatchId: z8.string(),
3739
- prefixPatchIds: z8.array(z8.string()),
3740
- patches: z8.array(restPatchSummarySchema),
3741
- provenance: z8.record(z8.string(), restPatchProvenanceEntrySchema),
3742
- facets: z8.object({
3743
- domains: z8.array(restPatchFacetItemSchema),
3744
- entities: z8.array(restPatchFacetItemSchema)
4029
+ z9.object({
4030
+ selectedPatchId: z9.string(),
4031
+ prefixPatchIds: z9.array(z9.string()),
4032
+ patches: z9.array(restPatchSummarySchema),
4033
+ provenance: z9.record(z9.string(), restPatchProvenanceEntrySchema),
4034
+ facets: z9.object({
4035
+ domains: z9.array(restPatchFacetItemSchema),
4036
+ entities: z9.array(restPatchFacetItemSchema)
3745
4037
  }).strict(),
3746
- collections: z8.object({
4038
+ collections: z9.object({
3747
4039
  domains: previewCollectionResponseSchemas.get("domains"),
3748
4040
  entities: previewCollectionResponseSchemas.get("entities"),
3749
4041
  relationships: previewCollectionResponseSchemas.get("relationships"),
@@ -3788,8 +4080,8 @@ openApiRegistry.registerPath({
3788
4080
  path: `${REST_V1_PREFIX}/${REST_PATCH_PREVIEW_PATH}`,
3789
4081
  summary: "Preview a patch prefix",
3790
4082
  request: {
3791
- params: z8.object({
3792
- patchId: z8.string()
4083
+ params: z9.object({
4084
+ patchId: z9.string()
3793
4085
  })
3794
4086
  },
3795
4087
  responses: {
@@ -3858,7 +4150,7 @@ openApiRegistry.registerPath({
3858
4150
  description: "Default Response",
3859
4151
  content: {
3860
4152
  "text/html": {
3861
- schema: z8.string()
4153
+ schema: z9.string()
3862
4154
  }
3863
4155
  }
3864
4156
  }
@@ -4612,7 +4904,7 @@ function renderHelpText() {
4612
4904
  "",
4613
4905
  "Launch modes:",
4614
4906
  " init",
4615
- " Prompts for a skills folder and installs bundled reference skills.",
4907
+ " Prompts for a skills folder and installs bundled ez-know skills.",
4616
4908
  " Config: interactive terminal",
4617
4909
  "",
4618
4910
  " mcp",