@agentxm/client-core 0.22.0 → 0.22.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/src/unstable/agent-capabilities/derive.d.ts.map +1 -1
  2. package/dist/src/unstable/agent-capabilities/derive.js.map +1 -1
  3. package/dist/src/unstable/agents/instructions.d.ts.map +1 -1
  4. package/dist/src/unstable/agents/instructions.js.map +1 -1
  5. package/dist/src/unstable/auth/auth-client.d.ts.map +1 -1
  6. package/dist/src/unstable/auth/auth-client.js.map +1 -1
  7. package/dist/src/unstable/commands/install-artifact.d.ts.map +1 -1
  8. package/dist/src/unstable/commands/install-artifact.js.map +1 -1
  9. package/dist/src/unstable/commands/operations/disable.d.ts.map +1 -1
  10. package/dist/src/unstable/commands/operations/disable.js.map +1 -1
  11. package/dist/src/unstable/commands/operations/enable.d.ts.map +1 -1
  12. package/dist/src/unstable/commands/operations/enable.js.map +1 -1
  13. package/dist/src/unstable/commands/refs.d.ts.map +1 -1
  14. package/dist/src/unstable/files/generators.d.ts.map +1 -1
  15. package/dist/src/unstable/files/generators.js.map +1 -1
  16. package/dist/src/unstable/files/refs.d.ts.map +1 -1
  17. package/dist/src/unstable/knowledge/index.d.ts +1 -1
  18. package/dist/src/unstable/knowledge/index.d.ts.map +1 -1
  19. package/dist/src/unstable/knowledge/index.js +1 -1
  20. package/dist/src/unstable/knowledge/index.js.map +1 -1
  21. package/dist/src/unstable/knowledge/okf.d.ts +10 -1
  22. package/dist/src/unstable/knowledge/okf.d.ts.map +1 -1
  23. package/dist/src/unstable/knowledge/okf.js +422 -16
  24. package/dist/src/unstable/knowledge/okf.js.map +1 -1
  25. package/dist/src/unstable/knowledge/refs.d.ts.map +1 -1
  26. package/dist/src/unstable/lint/catalog/files-accessor/contexts.d.ts.map +1 -1
  27. package/dist/src/unstable/lint/catalog/files-accessor/contexts.js.map +1 -1
  28. package/dist/src/unstable/lint/catalog/pack-accessor/contexts.d.ts.map +1 -1
  29. package/dist/src/unstable/lint/catalog/pack-accessor/contexts.js.map +1 -1
  30. package/dist/src/unstable/lint/catalog/pack-accessor/platform.d.ts.map +1 -1
  31. package/dist/src/unstable/lint/catalog/pack-accessor/platform.js.map +1 -1
  32. package/dist/src/unstable/lint/catalog/skill-accessor/contexts.d.ts.map +1 -1
  33. package/dist/src/unstable/lint/catalog/skill-accessor/contexts.js.map +1 -1
  34. package/dist/src/unstable/lint/catalog/skill-accessor/platform.d.ts.map +1 -1
  35. package/dist/src/unstable/lint/catalog/skill-accessor/platform.js.map +1 -1
  36. package/dist/src/unstable/lint/catalog/workspace/lockfile-valid.d.ts.map +1 -1
  37. package/dist/src/unstable/lint/catalog/workspace/lockfile-valid.js.map +1 -1
  38. package/dist/src/unstable/lint/catalog/workspace/settings-schema-valid.d.ts.map +1 -1
  39. package/dist/src/unstable/lint/catalog/workspace/settings-schema-valid.js.map +1 -1
  40. package/dist/src/unstable/mcps/refs.d.ts.map +1 -1
  41. package/dist/src/unstable/packs/dependency-resolution.d.ts.map +1 -1
  42. package/dist/src/unstable/packs/dependency-resolution.js.map +1 -1
  43. package/dist/src/unstable/plan/apply-plan.d.ts.map +1 -1
  44. package/dist/src/unstable/plan/apply-plan.js.map +1 -1
  45. package/dist/src/unstable/publish/ingest-limits.d.ts.map +1 -1
  46. package/dist/src/unstable/publish/ingest-limits.js.map +1 -1
  47. package/dist/src/unstable/registry/__generated__/registry-client.d.ts.map +1 -1
  48. package/dist/src/unstable/registry/__generated__/registry-client.js.map +1 -1
  49. package/dist/src/unstable/skills/refs.d.ts.map +1 -1
  50. package/dist/src/unstable/sources/types.d.ts.map +1 -1
  51. package/dist/src/unstable/subagents/refs.d.ts.map +1 -1
  52. package/dist/src/unstable/telemetry/__generated__/telemetry-client.d.ts.map +1 -1
  53. package/dist/src/unstable/telemetry/__generated__/telemetry-client.js.map +1 -1
  54. package/dist/src/unstable/utils/build-zip-archive.d.ts +1 -1
  55. package/dist/src/unstable/utils/build-zip-archive.d.ts.map +1 -1
  56. package/dist/src/unstable/workspace/read-model/extensions/files.d.ts.map +1 -1
  57. package/dist/src/unstable/workspace/read-model/extensions/files.js.map +1 -1
  58. package/dist/src/unstable/workspace/read-model/extensions/inventory.d.ts.map +1 -1
  59. package/dist/src/unstable/workspace/read-model/extensions/inventory.js.map +1 -1
  60. package/dist/src/unstable/workspace/read-model/extensions/pack.d.ts.map +1 -1
  61. package/dist/src/unstable/workspace/read-model/extensions/pack.js.map +1 -1
  62. package/dist/src/unstable/workspace/read-model/scanners/types.d.ts.map +1 -1
  63. package/dist/src/unstable/workspace/read-model/scanners/types.js.map +1 -1
  64. package/dist/src/unstable/workspace/read-model-record-types.d.ts.map +1 -1
  65. package/package.json +10 -10
@@ -1 +1 @@
1
- {"version":3,"file":"refs.d.ts","sourceRoot":"","sources":["../../../../src/unstable/files/refs.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,qBAAqB,EACrB,mBAAmB,EACnB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EACV,cAAc,EACd,WAAW,EACX,cAAc,EACd,eAAe,EAChB,MAAM,qBAAqB,CAAC;AAE7B,oBAAoB;AACpB,MAAM,MAAM,iBAAiB,GAAG,qBAAqB,CAAC,YAAY,EAAE,cAAc,CAAC,GACjF,mBAAmB,CAAC;AACtB,oBAAoB;AACpB,MAAM,MAAM,gBAAgB,GAAG,qBAAqB,CAAC,UAAU,EAAE,cAAc,CAAC,GAC9E,kBAAkB,CAAC;AACrB,oBAAoB;AACpB,MAAM,MAAM,aAAa,GAAG,qBAAqB,CAAC,OAAO,EAAE,WAAW,CAAC,GAAG,eAAe,CAAC;AAC1F,oBAAoB;AACpB,MAAM,MAAM,iBAAiB,GAAG,qBAAqB,CAAC,WAAW,EAAE,eAAe,CAAC,GACjF,mBAAmB,CAAC;AAEtB,oBAAoB;AACpB,MAAM,MAAM,iBAAiB,GACzB,iBAAiB,GACjB,gBAAgB,GAChB,aAAa,GACb,iBAAiB,CAAC"}
1
+ {"version":3,"file":"refs.d.ts","sourceRoot":"","sources":["../../../../src/unstable/files/refs.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,qBAAqB,EACrB,mBAAmB,EACnB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EACV,cAAc,EACd,WAAW,EACX,cAAc,EACd,eAAe,EAChB,MAAM,qBAAqB,CAAC;AAE7B,oBAAoB;AACpB,MAAM,MAAM,iBAAiB,GAAG,qBAAqB,CAAC,YAAY,EAAE,cAAc,CAAC,GACjF,mBAAmB,CAAC;AACtB,oBAAoB;AACpB,MAAM,MAAM,gBAAgB,GAAG,qBAAqB,CAAC,UAAU,EAAE,cAAc,CAAC,GAC9E,kBAAkB,CAAC;AACrB,oBAAoB;AACpB,MAAM,MAAM,aAAa,GAAG,qBAAqB,CAAC,OAAO,EAAE,WAAW,CAAC,GAAG,eAAe,CAAC;AAC1F,oBAAoB;AACpB,MAAM,MAAM,iBAAiB,GAAG,qBAAqB,CAAC,WAAW,EAAE,eAAe,CAAC,GACjF,mBAAmB,CAAC;AAEtB,oBAAoB;AACpB,MAAM,MAAM,iBAAiB,GAC3B,iBAAiB,GAAG,gBAAgB,GAAG,aAAa,GAAG,iBAAiB,CAAC"}
@@ -1,5 +1,5 @@
1
1
  export { KNOWLEDGE_EXTENSION_DIR, KNOWLEDGE_MANIFEST_FILENAME, KNOWLEDGE_MANIFEST_SCHEMA_URL, KNOWLEDGE_SOURCE_DIR, KnowledgeManifestSchema, type KnowledgeManifest, } from "./manifest-schema.js";
2
- export { inspectKnowledgeBundle, openKnowledgeConcept, searchKnowledgeConcepts, type KnowledgeConcept, type KnowledgeDiagnostic, type KnowledgeInspection, } from "./okf.js";
2
+ export { inspectKnowledgeBundle, inspectKnowledgeEntries, openKnowledgeConcept, searchKnowledgeConcepts, type KnowledgeBundleEntry, type KnowledgeConcept, type KnowledgeDiagnostic, type KnowledgeInspection, } from "./okf.js";
3
3
  export type { GitHostedKnowledgeRef, KnowledgeExtensionRef, LocalKnowledgeRef, RegistryKnowledgeRef, WorkspaceKnowledgeRef, } from "./refs.js";
4
4
  export { KnowledgeManager, KnowledgeManagerLive, type KnowledgeManagerService } from "./manager.js";
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/unstable/knowledge/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,2BAA2B,EAC3B,6BAA6B,EAC7B,oBAAoB,EACpB,uBAAuB,EACvB,KAAK,iBAAiB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,uBAAuB,EACvB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,GACzB,MAAM,UAAU,CAAC;AAClB,YAAY,EACV,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,KAAK,uBAAuB,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/unstable/knowledge/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,2BAA2B,EAC3B,6BAA6B,EAC7B,oBAAoB,EACpB,uBAAuB,EACvB,KAAK,iBAAiB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,oBAAoB,EACpB,uBAAuB,EACvB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,GACzB,MAAM,UAAU,CAAC;AAClB,YAAY,EACV,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,KAAK,uBAAuB,EAAE,MAAM,cAAc,CAAC"}
@@ -1,4 +1,4 @@
1
1
  export { KNOWLEDGE_EXTENSION_DIR, KNOWLEDGE_MANIFEST_FILENAME, KNOWLEDGE_MANIFEST_SCHEMA_URL, KNOWLEDGE_SOURCE_DIR, KnowledgeManifestSchema, } from "./manifest-schema.js";
2
- export { inspectKnowledgeBundle, openKnowledgeConcept, searchKnowledgeConcepts, } from "./okf.js";
2
+ export { inspectKnowledgeBundle, inspectKnowledgeEntries, openKnowledgeConcept, searchKnowledgeConcepts, } from "./okf.js";
3
3
  export { KnowledgeManager, KnowledgeManagerLive } from "./manager.js";
4
4
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/unstable/knowledge/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,2BAA2B,EAC3B,6BAA6B,EAC7B,oBAAoB,EACpB,uBAAuB,GAExB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,uBAAuB,GAIxB,MAAM,UAAU,CAAC;AAQlB,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAgC,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/unstable/knowledge/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,2BAA2B,EAC3B,6BAA6B,EAC7B,oBAAoB,EACpB,uBAAuB,GAExB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,oBAAoB,EACpB,uBAAuB,GAKxB,MAAM,UAAU,CAAC;AAQlB,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAgC,MAAM,cAAc,CAAC"}
@@ -8,23 +8,32 @@ export interface KnowledgeConcept {
8
8
  readonly type?: string;
9
9
  readonly description?: string;
10
10
  readonly tags?: ReadonlyArray<string>;
11
+ readonly resource?: string;
12
+ readonly timestamp?: string;
11
13
  readonly relativePath: string;
12
14
  readonly body: string;
13
15
  }
14
16
  export interface KnowledgeDiagnostic {
15
- readonly code: "bundle-too-large" | "file-too-large" | "invalid-tags" | "missing-root-index" | "missing-okf-version" | "missing-title" | "missing-description" | "missing-tags" | "suspicious-instruction" | "symbolic-link" | "too-many-files" | "unsupported-okf-version" | "missing-type" | "invalid-frontmatter";
17
+ readonly code: "bundle-too-large" | "file-too-large" | "invalid-tags" | "missing-root-index" | "missing-okf-version" | "missing-title" | "missing-description" | "missing-tags" | "symbolic-link" | "too-many-files" | "unsupported-okf-version" | "missing-type" | "invalid-frontmatter" | "case-collision" | "dangerous-uri" | "detected-secret" | "unsafe-path" | "invalid-index" | "invalid-log" | "invalid-resource" | "invalid-timestamp" | "broken-internal-link" | "escaping-link" | "unreachable-concept" | "missing-index-entry" | "stale-index-entry" | "embedded-html" | "malformed-citation" | "duplicate-resource" | "inconsistent-type" | "large-concept" | "large-index" | "unreferenced-asset";
16
18
  readonly severity: "error" | "warning";
17
19
  readonly relativePath: string;
20
+ readonly line?: number;
18
21
  readonly message: string;
19
22
  }
20
23
  export interface KnowledgeInspection {
21
24
  readonly concepts: ReadonlyArray<KnowledgeConcept>;
22
25
  readonly diagnostics: ReadonlyArray<KnowledgeDiagnostic>;
23
26
  }
27
+ export interface KnowledgeBundleEntry {
28
+ readonly relativePath: string;
29
+ readonly type: FileSystem.File.Type;
30
+ readonly size: bigint;
31
+ }
24
32
  /**
25
33
  * Inspect an OKF bundle. The root index requirement is an explicit AgentXM
26
34
  * profile constraint; upstream OKF 0.1 itself permits a root without it.
27
35
  */
36
+ export declare const inspectKnowledgeEntries: <E>(entries: ReadonlyArray<KnowledgeBundleEntry>, readMarkdown: (relativePath: string) => Effect.Effect<string, E>) => Effect.Effect<KnowledgeInspection, E>;
28
37
  export declare const inspectKnowledgeBundle: (sourceRoot: string) => Effect.Effect<KnowledgeInspection, unknown, FileSystem.FileSystem | Path.Path>;
29
38
  export declare const searchKnowledgeConcepts: (concepts: ReadonlyArray<KnowledgeConcept>, query: string) => ReadonlyArray<KnowledgeConcept>;
30
39
  export declare const openKnowledgeConcept: (concepts: ReadonlyArray<KnowledgeConcept>, id: string) => KnowledgeConcept | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"okf.d.ts","sourceRoot":"","sources":["../../../../src/unstable/knowledge/okf.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAEhF,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,UAAU,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC;AAIpC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACtC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EACT,kBAAkB,GAClB,gBAAgB,GAChB,cAAc,GACd,oBAAoB,GACpB,qBAAqB,GACrB,eAAe,GACf,qBAAqB,GACrB,cAAc,GACd,wBAAwB,GACxB,eAAe,GACf,gBAAgB,GAChB,yBAAyB,GACzB,cAAc,GACd,qBAAqB,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;IACnD,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;CAC1D;AAkDD;;;GAGG;AACH,eAAO,MAAM,sBAAsB,GACjC,YAAY,MAAM,KACjB,MAAM,CAAC,MAAM,CAAC,mBAAmB,EAAE,OAAO,EAAE,UAAU,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,CAsK5E,CAAC;AAEL,eAAO,MAAM,uBAAuB,GAClC,UAAU,aAAa,CAAC,gBAAgB,CAAC,EACzC,OAAO,MAAM,KACZ,aAAa,CAAC,gBAAgB,CAQhC,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,UAAU,aAAa,CAAC,gBAAgB,CAAC,EACzC,IAAI,MAAM,KACT,gBAAgB,GAAG,SAA0D,CAAC"}
1
+ {"version":3,"file":"okf.d.ts","sourceRoot":"","sources":["../../../../src/unstable/knowledge/okf.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAEhF,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,UAAU,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC;AAIpC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACtC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EACT,kBAAkB,GAClB,gBAAgB,GAChB,cAAc,GACd,oBAAoB,GACpB,qBAAqB,GACrB,eAAe,GACf,qBAAqB,GACrB,cAAc,GACd,eAAe,GACf,gBAAgB,GAChB,yBAAyB,GACzB,cAAc,GACd,qBAAqB,GACrB,gBAAgB,GAChB,eAAe,GACf,iBAAiB,GACjB,aAAa,GACb,eAAe,GACf,aAAa,GACb,kBAAkB,GAClB,mBAAmB,GACnB,sBAAsB,GACtB,eAAe,GACf,qBAAqB,GACrB,qBAAqB,GACrB,mBAAmB,GACnB,eAAe,GACf,oBAAoB,GACpB,oBAAoB,GACpB,mBAAmB,GACnB,eAAe,GACf,aAAa,GACb,oBAAoB,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;IACnD,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;CAC1D;AAQD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAqJD;;;GAGG;AACH,eAAO,MAAM,uBAAuB,GAAI,CAAC,EACvC,SAAS,aAAa,CAAC,oBAAoB,CAAC,EAC5C,cAAc,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,KAC/D,MAAM,CAAC,MAAM,CAAC,mBAAmB,EAAE,CAAC,CA2enC,CAAC;AAEL,eAAO,MAAM,sBAAsB,GACjC,YAAY,MAAM,KACjB,MAAM,CAAC,MAAM,CAAC,mBAAmB,EAAE,OAAO,EAAE,UAAU,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,CAQ5E,CAAC;AAEL,eAAO,MAAM,uBAAuB,GAClC,UAAU,aAAa,CAAC,gBAAgB,CAAC,EACzC,OAAO,MAAM,KACZ,aAAa,CAAC,gBAAgB,CAQhC,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,UAAU,aAAa,CAAC,gBAAgB,CAAC,EACzC,IAAI,MAAM,KACT,gBAAgB,GAAG,SAA0D,CAAC"}
@@ -8,7 +8,8 @@ const RESERVED_BASENAMES = new Set(["index.md", "log.md"]);
8
8
  const MAX_FILE_BYTES = 1024n * 1024n;
9
9
  const MAX_BUNDLE_BYTES = 10n * 1024n * 1024n;
10
10
  const MAX_BUNDLE_FILES = 1_000;
11
- const SUSPICIOUS_INSTRUCTION = /\b(?:ignore|disregard|override)\b.{0,80}\b(?:previous|prior|system|developer|user|workspace)\b.{0,40}\b(?:instruction|prompt|message|rule)s?\b/is;
11
+ const LARGE_CONCEPT_BYTES = 128n * 1024n;
12
+ const LARGE_INDEX_BYTES = 256n * 1024n;
12
13
  const bundleEntries = (root, current) => Effect.gen(function* () {
13
14
  const fs = yield* FileSystem.FileSystem;
14
15
  const path = yield* Path.Path;
@@ -22,7 +23,7 @@ const bundleEntries = (root, current) => Effect.gen(function* () {
22
23
  }
23
24
  else {
24
25
  files.push({
25
- relativePath: path.relative(root, absolute),
26
+ relativePath: path.relative(root, absolute).replace(/\\/g, "/"),
26
27
  type: stat.type,
27
28
  size: stat.size,
28
29
  });
@@ -39,19 +40,119 @@ const firstHeading = (body) => {
39
40
  return undefined;
40
41
  };
41
42
  const conceptId = (relativePath) => relativePath.replace(/\.md$/i, "");
43
+ const markdownLinks = (body) => {
44
+ const links = [];
45
+ const pattern = /!?\[[^\]]*\]\(([^)\s]+)(?:\s+["'][^"']*["'])?\)/g;
46
+ for (const match of body.matchAll(pattern)) {
47
+ const target = match[1];
48
+ if (target === undefined)
49
+ continue;
50
+ const offset = match.index ?? 0;
51
+ links.push({
52
+ target,
53
+ line: body.slice(0, offset).split(/\r?\n/).length,
54
+ });
55
+ }
56
+ return links;
57
+ };
58
+ const metadataField = (metadata, key) => {
59
+ if (typeof metadata !== "object" || metadata === null)
60
+ return undefined;
61
+ return Object.entries(metadata).find(([entryKey]) => entryKey === key)?.[1];
62
+ };
63
+ const normalizedPath = (sourcePath, target) => {
64
+ const pathOnly = (target.split("#", 1)[0] ?? "").split("?", 1)[0] ?? "";
65
+ if (pathOnly.length === 0 || pathOnly.startsWith("//") || /^[a-z][a-z0-9+.-]*:/i.test(pathOnly)) {
66
+ return null;
67
+ }
68
+ const decoded = (() => {
69
+ try {
70
+ return decodeURIComponent(pathOnly);
71
+ }
72
+ catch {
73
+ return pathOnly;
74
+ }
75
+ })();
76
+ const sourceSegments = sourcePath.split("/").slice(0, -1);
77
+ const segments = decoded.startsWith("/")
78
+ ? decoded.slice(1).split("/")
79
+ : [...sourceSegments, ...decoded.split("/")];
80
+ const resolved = [];
81
+ let escaped = false;
82
+ for (const segment of segments) {
83
+ if (segment.length === 0 || segment === ".")
84
+ continue;
85
+ if (segment === "..") {
86
+ if (resolved.length === 0)
87
+ escaped = true;
88
+ else
89
+ resolved.pop();
90
+ }
91
+ else {
92
+ resolved.push(segment);
93
+ }
94
+ }
95
+ return { path: resolved.join("/"), escaped };
96
+ };
97
+ const activeScheme = (target) => /^(?:javascript|vbscript|data):/i.test(target.trim());
98
+ const validIsoTimestamp = (value) => /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/.test(value) &&
99
+ !Number.isNaN(Date.parse(value));
100
+ const validResource = (value) => {
101
+ if (activeScheme(value))
102
+ return false;
103
+ try {
104
+ const parsed = new URL(value);
105
+ return parsed.protocol.length > 1;
106
+ }
107
+ catch {
108
+ return false;
109
+ }
110
+ };
111
+ const secretPatterns = [
112
+ /-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/,
113
+ /\bAKIA[0-9A-Z]{16}\b/,
114
+ /\b(?:ghp|github_pat)_[A-Za-z0-9_]{20,}\b/,
115
+ /\b(?:sk_live|rk_live)_[A-Za-z0-9]{20,}\b/,
116
+ ];
117
+ const secretLine = (raw) => {
118
+ const lines = raw.split(/\r?\n/);
119
+ const index = lines.findIndex((line) => secretPatterns.some((pattern) => pattern.test(line)));
120
+ return index === -1 ? undefined : index + 1;
121
+ };
122
+ const isReserved = (relativePath) => {
123
+ const baseName = relativePath.replace(/\\/g, "/").split("/").at(-1)?.toLowerCase();
124
+ return baseName !== undefined && RESERVED_BASENAMES.has(baseName);
125
+ };
126
+ const resolvedMarkdownTarget = (sourcePath, target, markdownPaths) => {
127
+ const normalized = normalizedPath(sourcePath, target);
128
+ if (normalized === null || normalized.escaped)
129
+ return normalized;
130
+ const candidates = normalized.path.toLowerCase().endsWith(".md")
131
+ ? [normalized.path]
132
+ : [normalized.path, `${normalized.path}.md`, `${normalized.path}/index.md`];
133
+ return {
134
+ path: candidates.find((candidate) => markdownPaths.has(candidate)) ??
135
+ candidates[0] ??
136
+ normalized.path,
137
+ escaped: false,
138
+ };
139
+ };
42
140
  /**
43
141
  * Inspect an OKF bundle. The root index requirement is an explicit AgentXM
44
142
  * profile constraint; upstream OKF 0.1 itself permits a root without it.
45
143
  */
46
- export const inspectKnowledgeBundle = (sourceRoot) => Effect.gen(function* () {
47
- const fs = yield* FileSystem.FileSystem;
48
- const path = yield* Path.Path;
49
- const entries = yield* bundleEntries(sourceRoot, sourceRoot);
144
+ export const inspectKnowledgeEntries = (entries, readMarkdown) => Effect.gen(function* () {
50
145
  const files = entries
51
146
  .filter((entry) => entry.type === "File" && entry.relativePath.toLowerCase().endsWith(".md"))
52
- .map((entry) => entry.relativePath);
147
+ .map((entry) => entry.relativePath)
148
+ .sort((left, right) => left.localeCompare(right));
149
+ const markdownPaths = new Set(files);
150
+ const allFilePaths = new Set(entries.filter((entry) => entry.type === "File").map((entry) => entry.relativePath));
53
151
  const diagnostics = [];
54
152
  const concepts = [];
153
+ const linksByPath = new Map();
154
+ const resources = new Map();
155
+ const types = new Map();
55
156
  if (entries.length > MAX_BUNDLE_FILES) {
56
157
  diagnostics.push({
57
158
  code: "too-many-files",
@@ -69,7 +170,24 @@ export const inspectKnowledgeBundle = (sourceRoot) => Effect.gen(function* () {
69
170
  message: "Knowledge bundle exceeds the 10 MiB uncompressed safety limit.",
70
171
  });
71
172
  }
173
+ const pathsByCase = new Map();
72
174
  for (const entry of entries) {
175
+ const segments = entry.relativePath.split("/");
176
+ if (entry.relativePath.startsWith("/") ||
177
+ entry.relativePath.includes("\\") ||
178
+ entry.relativePath.includes("\0") ||
179
+ segments.some((segment) => segment.length === 0 || segment === "." || segment === "..")) {
180
+ diagnostics.push({
181
+ code: "unsafe-path",
182
+ severity: "error",
183
+ relativePath: entry.relativePath,
184
+ message: `${entry.relativePath} is not a safe bundle-relative path.`,
185
+ });
186
+ }
187
+ const folded = entry.relativePath.normalize("NFC").toLocaleLowerCase();
188
+ const colliding = pathsByCase.get(folded) ?? [];
189
+ colliding.push(entry.relativePath);
190
+ pathsByCase.set(folded, colliding);
73
191
  if (entry.type === "SymbolicLink") {
74
192
  diagnostics.push({
75
193
  code: "symbolic-link",
@@ -86,6 +204,38 @@ export const inspectKnowledgeBundle = (sourceRoot) => Effect.gen(function* () {
86
204
  message: `${entry.relativePath} exceeds the 1 MiB per-file safety limit.`,
87
205
  });
88
206
  }
207
+ if (entry.type === "File" &&
208
+ entry.relativePath.toLowerCase().endsWith(".md") &&
209
+ isReserved(entry.relativePath) &&
210
+ entry.relativePath.toLowerCase().endsWith("index.md") &&
211
+ entry.size > LARGE_INDEX_BYTES) {
212
+ diagnostics.push({
213
+ code: "large-index",
214
+ severity: "warning",
215
+ relativePath: entry.relativePath,
216
+ message: `${entry.relativePath} is unusually large for progressive discovery.`,
217
+ });
218
+ }
219
+ else if (entry.type === "File" &&
220
+ entry.relativePath.toLowerCase().endsWith(".md") &&
221
+ entry.size > LARGE_CONCEPT_BYTES) {
222
+ diagnostics.push({
223
+ code: "large-concept",
224
+ severity: "warning",
225
+ relativePath: entry.relativePath,
226
+ message: `${entry.relativePath} is unusually large and may be expensive to consume.`,
227
+ });
228
+ }
229
+ }
230
+ for (const colliding of pathsByCase.values()) {
231
+ if (new Set(colliding).size > 1) {
232
+ diagnostics.push({
233
+ code: "case-collision",
234
+ severity: "error",
235
+ relativePath: colliding[0] ?? ".",
236
+ message: `Bundle paths collide on case-insensitive filesystems: ${colliding.join(", ")}.`,
237
+ });
238
+ }
89
239
  }
90
240
  if (!files.includes("index.md")) {
91
241
  diagnostics.push({
@@ -96,7 +246,48 @@ export const inspectKnowledgeBundle = (sourceRoot) => Effect.gen(function* () {
96
246
  });
97
247
  }
98
248
  for (const relativePath of files) {
99
- const raw = yield* fs.readFileString(path.join(sourceRoot, relativePath));
249
+ const raw = yield* readMarkdown(relativePath);
250
+ const links = markdownLinks(raw);
251
+ linksByPath.set(relativePath, links);
252
+ const foundSecretLine = secretLine(raw);
253
+ if (foundSecretLine !== undefined) {
254
+ diagnostics.push({
255
+ code: "detected-secret",
256
+ severity: "error",
257
+ relativePath,
258
+ line: foundSecretLine,
259
+ message: `${relativePath} contains a high-confidence credential or private key pattern.`,
260
+ });
261
+ }
262
+ for (const link of links) {
263
+ if (activeScheme(link.target)) {
264
+ diagnostics.push({
265
+ code: "dangerous-uri",
266
+ severity: "error",
267
+ relativePath,
268
+ line: link.line,
269
+ message: `${relativePath} contains a dangerous active URI scheme.`,
270
+ });
271
+ }
272
+ }
273
+ const activeHtmlUri = /\b(?:href|src)\s*=\s*["']\s*(?:javascript|vbscript|data):/i.exec(raw);
274
+ if (activeHtmlUri !== null) {
275
+ diagnostics.push({
276
+ code: "dangerous-uri",
277
+ severity: "error",
278
+ relativePath,
279
+ line: raw.slice(0, activeHtmlUri.index).split(/\r?\n/).length,
280
+ message: `${relativePath} contains a dangerous active URI scheme.`,
281
+ });
282
+ }
283
+ if (/<\/?(?:script|iframe|object|embed|form|style|video|audio|svg|math)\b[^>]*>/i.test(raw)) {
284
+ diagnostics.push({
285
+ code: "embedded-html",
286
+ severity: "warning",
287
+ relativePath,
288
+ message: `${relativePath} contains embedded HTML; consumers must sanitize it.`,
289
+ });
290
+ }
100
291
  const parsed = yield* parseFrontmatterEffect(raw).pipe(Effect.option);
101
292
  if (Option.isNone(parsed)) {
102
293
  diagnostics.push({
@@ -107,9 +298,65 @@ export const inspectKnowledgeBundle = (sourceRoot) => Effect.gen(function* () {
107
298
  });
108
299
  continue;
109
300
  }
110
- const baseName = path.basename(relativePath).toLowerCase();
301
+ const baseName = (relativePath.replace(/\\/g, "/").split("/").at(-1) ?? relativePath).toLowerCase();
111
302
  const metadata = parsed.value.frontmatter;
112
303
  const isMetadata = typeof metadata === "object" && metadata !== null;
304
+ if (baseName === "index.md") {
305
+ if (relativePath !== "index.md" && metadata !== undefined) {
306
+ diagnostics.push({
307
+ code: "invalid-index",
308
+ severity: "error",
309
+ relativePath,
310
+ message: `${relativePath} is a reserved index and must not contain frontmatter.`,
311
+ });
312
+ }
313
+ if (firstHeading(parsed.value.body) === undefined) {
314
+ diagnostics.push({
315
+ code: "invalid-index",
316
+ severity: "error",
317
+ relativePath,
318
+ message: `${relativePath} must contain at least one level-one section heading.`,
319
+ });
320
+ }
321
+ }
322
+ if (baseName === "log.md") {
323
+ if (metadata !== undefined) {
324
+ diagnostics.push({
325
+ code: "invalid-log",
326
+ severity: "error",
327
+ relativePath,
328
+ message: `${relativePath} is a reserved log and must not contain frontmatter.`,
329
+ });
330
+ }
331
+ const dateHeadings = parsed.value.body
332
+ .split(/\r?\n/)
333
+ .map((line, index) => ({ line, number: index + 1 }))
334
+ .filter(({ line }) => /^##\s+/.test(line));
335
+ if (dateHeadings.some(({ line }) => !/^##\s+\d{4}-\d{2}-\d{2}\s*$/.test(line)) ||
336
+ dateHeadings.some(({ line }) => {
337
+ const value = line.replace(/^##\s+/, "").trim();
338
+ const parsedDate = Date.parse(`${value}T00:00:00Z`);
339
+ return Number.isNaN(parsedDate);
340
+ })) {
341
+ const invalid = dateHeadings.find(({ line }) => !/^##\s+\d{4}-\d{2}-\d{2}\s*$/.test(line));
342
+ diagnostics.push({
343
+ code: "invalid-log",
344
+ severity: "error",
345
+ relativePath,
346
+ ...(invalid === undefined ? {} : { line: invalid.number }),
347
+ message: `${relativePath} date headings must use valid ISO 8601 YYYY-MM-DD dates.`,
348
+ });
349
+ }
350
+ const dates = dateHeadings.map(({ line }) => line.replace(/^##\s+/, "").trim());
351
+ if (dates.some((date, index) => index > 0 && date > (dates[index - 1] ?? date))) {
352
+ diagnostics.push({
353
+ code: "invalid-log",
354
+ severity: "error",
355
+ relativePath,
356
+ message: `${relativePath} date headings must be newest first.`,
357
+ });
358
+ }
359
+ }
113
360
  const type = isMetadata &&
114
361
  "type" in metadata &&
115
362
  typeof metadata.type === "string" &&
@@ -125,6 +372,10 @@ export const inspectKnowledgeBundle = (sourceRoot) => Effect.gen(function* () {
125
372
  metadata.tags.every((tag) => typeof tag === "string")
126
373
  ? metadata.tags
127
374
  : undefined;
375
+ const resourceValue = metadataField(metadata, "resource");
376
+ const resource = typeof resourceValue === "string" ? resourceValue : undefined;
377
+ const timestampValue = metadataField(metadata, "timestamp");
378
+ const timestamp = typeof timestampValue === "string" ? timestampValue : undefined;
128
379
  if (isMetadata && "tags" in metadata && metadata.tags !== undefined && tags === undefined) {
129
380
  diagnostics.push({
130
381
  code: "invalid-tags",
@@ -152,6 +403,26 @@ export const inspectKnowledgeBundle = (sourceRoot) => Effect.gen(function* () {
152
403
  });
153
404
  }
154
405
  }
406
+ if (!RESERVED_BASENAMES.has(baseName) &&
407
+ resourceValue !== undefined &&
408
+ (resource === undefined || !validResource(resource))) {
409
+ diagnostics.push({
410
+ code: "invalid-resource",
411
+ severity: "error",
412
+ relativePath,
413
+ message: `${relativePath} resource must be a safe absolute URI.`,
414
+ });
415
+ }
416
+ if (!RESERVED_BASENAMES.has(baseName) &&
417
+ timestampValue !== undefined &&
418
+ (timestamp === undefined || !validIsoTimestamp(timestamp))) {
419
+ diagnostics.push({
420
+ code: "invalid-timestamp",
421
+ severity: "error",
422
+ relativePath,
423
+ message: `${relativePath} timestamp must be an ISO 8601 date-time with a timezone.`,
424
+ });
425
+ }
155
426
  if (!RESERVED_BASENAMES.has(baseName) && type === undefined) {
156
427
  diagnostics.push({
157
428
  code: "missing-type",
@@ -185,13 +456,31 @@ export const inspectKnowledgeBundle = (sourceRoot) => Effect.gen(function* () {
185
456
  message: `${relativePath} should include frontmatter tags for discovery.`,
186
457
  });
187
458
  }
188
- if (SUSPICIOUS_INSTRUCTION.test(parsed.value.body)) {
189
- diagnostics.push({
190
- code: "suspicious-instruction",
191
- severity: "warning",
192
- relativePath,
193
- message: `${relativePath} contains instruction-like text that may be prompt injection; review it before publishing.`,
194
- });
459
+ if (!RESERVED_BASENAMES.has(baseName) && resource !== undefined && validResource(resource)) {
460
+ const matching = resources.get(resource) ?? [];
461
+ matching.push(relativePath);
462
+ resources.set(resource, matching);
463
+ }
464
+ if (!RESERVED_BASENAMES.has(baseName) && type !== undefined) {
465
+ const spellings = types.get(type.toLocaleLowerCase()) ?? new Set();
466
+ spellings.add(type);
467
+ types.set(type.toLocaleLowerCase(), spellings);
468
+ }
469
+ const citationHeading = parsed.value.body.search(/^#\s+Citations\s*$/im);
470
+ if (citationHeading >= 0) {
471
+ const citationBody = parsed.value.body.slice(citationHeading).split(/\r?\n/).slice(1);
472
+ const malformedIndex = citationBody.findIndex((line) => /^\s*\[\d+\]/.test(line) && !/^\s*\[\d+\]\s+\[[^\]]+\]\([^)]+\)/.test(line));
473
+ if (malformedIndex >= 0) {
474
+ diagnostics.push({
475
+ code: "malformed-citation",
476
+ severity: "warning",
477
+ relativePath,
478
+ line: parsed.value.body.slice(0, citationHeading).split(/\r?\n/).length +
479
+ malformedIndex +
480
+ 2,
481
+ message: `${relativePath} contains a malformed numbered citation.`,
482
+ });
483
+ }
195
484
  }
196
485
  concepts.push({
197
486
  id: conceptId(relativePath),
@@ -199,12 +488,129 @@ export const inspectKnowledgeBundle = (sourceRoot) => Effect.gen(function* () {
199
488
  ...(type === undefined ? {} : { type }),
200
489
  ...(description === undefined ? {} : { description }),
201
490
  ...(tags === undefined ? {} : { tags }),
491
+ ...(resource === undefined ? {} : { resource }),
492
+ ...(timestamp === undefined ? {} : { timestamp }),
202
493
  relativePath,
203
494
  body: parsed.value.body,
204
495
  });
205
496
  }
497
+ const outgoing = new Map();
498
+ const referencedFiles = new Set();
499
+ for (const [sourcePath, links] of linksByPath) {
500
+ const targets = new Set();
501
+ for (const link of links) {
502
+ const normalized = normalizedPath(sourcePath, link.target);
503
+ if (normalized === null)
504
+ continue;
505
+ if (normalized.escaped) {
506
+ diagnostics.push({
507
+ code: "escaping-link",
508
+ severity: "warning",
509
+ relativePath: sourcePath,
510
+ line: link.line,
511
+ message: `${sourcePath} links outside the Knowledge bundle.`,
512
+ });
513
+ continue;
514
+ }
515
+ const resolved = resolvedMarkdownTarget(sourcePath, link.target, markdownPaths);
516
+ const targetPath = resolved?.path ?? normalized.path;
517
+ if (allFilePaths.has(targetPath))
518
+ referencedFiles.add(targetPath);
519
+ if (markdownPaths.has(targetPath)) {
520
+ targets.add(targetPath);
521
+ }
522
+ else if (!allFilePaths.has(targetPath)) {
523
+ diagnostics.push({
524
+ code: sourcePath.toLowerCase().endsWith("index.md")
525
+ ? "stale-index-entry"
526
+ : "broken-internal-link",
527
+ severity: "warning",
528
+ relativePath: sourcePath,
529
+ line: link.line,
530
+ message: `${sourcePath} links to missing bundle path ${link.target}.`,
531
+ });
532
+ }
533
+ }
534
+ outgoing.set(sourcePath, targets);
535
+ }
536
+ const reachable = new Set();
537
+ const hasRootIndex = files.includes("index.md");
538
+ const pending = hasRootIndex ? ["index.md"] : [];
539
+ while (pending.length > 0) {
540
+ const current = pending.shift();
541
+ if (current === undefined || reachable.has(current))
542
+ continue;
543
+ reachable.add(current);
544
+ for (const target of outgoing.get(current) ?? [])
545
+ pending.push(target);
546
+ }
547
+ for (const concept of concepts) {
548
+ if (hasRootIndex &&
549
+ !isReserved(concept.relativePath) &&
550
+ !reachable.has(concept.relativePath)) {
551
+ diagnostics.push({
552
+ code: "unreachable-concept",
553
+ severity: "warning",
554
+ relativePath: concept.relativePath,
555
+ message: `${concept.relativePath} is not reachable from the root index.`,
556
+ });
557
+ }
558
+ if (!isReserved(concept.relativePath)) {
559
+ const directory = concept.relativePath.split("/").slice(0, -1).join("/");
560
+ const nearestIndex = directory.length === 0 ? "index.md" : `${directory}/index.md`;
561
+ if (markdownPaths.has(nearestIndex) &&
562
+ !(outgoing.get(nearestIndex) ?? new Set()).has(concept.relativePath)) {
563
+ diagnostics.push({
564
+ code: "missing-index-entry",
565
+ severity: "warning",
566
+ relativePath: nearestIndex,
567
+ message: `${nearestIndex} does not link to ${concept.relativePath}.`,
568
+ });
569
+ }
570
+ }
571
+ }
572
+ for (const entry of entries) {
573
+ if (entry.type === "File" &&
574
+ !entry.relativePath.toLowerCase().endsWith(".md") &&
575
+ !referencedFiles.has(entry.relativePath)) {
576
+ diagnostics.push({
577
+ code: "unreferenced-asset",
578
+ severity: "warning",
579
+ relativePath: entry.relativePath,
580
+ message: `${entry.relativePath} is not referenced by any Markdown document.`,
581
+ });
582
+ }
583
+ }
584
+ for (const [resource, matching] of resources) {
585
+ if (matching.length > 1) {
586
+ for (const relativePath of matching) {
587
+ diagnostics.push({
588
+ code: "duplicate-resource",
589
+ severity: "warning",
590
+ relativePath,
591
+ message: `${relativePath} shares canonical resource ${resource} with another concept.`,
592
+ });
593
+ }
594
+ }
595
+ }
596
+ for (const spellings of types.values()) {
597
+ if (spellings.size > 1) {
598
+ diagnostics.push({
599
+ code: "inconsistent-type",
600
+ severity: "warning",
601
+ relativePath: ".",
602
+ message: `Concept type spellings differ only by casing: ${[...spellings].sort().join(", ")}.`,
603
+ });
604
+ }
605
+ }
206
606
  return { concepts, diagnostics };
207
607
  });
608
+ export const inspectKnowledgeBundle = (sourceRoot) => Effect.gen(function* () {
609
+ const fs = yield* FileSystem.FileSystem;
610
+ const path = yield* Path.Path;
611
+ const entries = yield* bundleEntries(sourceRoot, sourceRoot);
612
+ return yield* inspectKnowledgeEntries(entries, (relativePath) => fs.readFileString(path.join(sourceRoot, relativePath)));
613
+ });
208
614
  export const searchKnowledgeConcepts = (concepts, query) => {
209
615
  const needle = query.trim().toLocaleLowerCase();
210
616
  if (needle.length === 0)