diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b7d27b..17a374d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## [Unreleased] +## [1.9.1] — 2026-09-18 + +### Fixed + +- `plugins:` (and `nli:`) declared under an agent's entry in the named `cortex:` map of `agent.yaml` now reach `CortexConfig`. `extractFromNamedCortexMap` lifted the provider fields and the tool list but not these two, so only the legacy flat `cortex:` block could name a plugin — the repo-shipped plugin path 1.9.0 opened with `trusted: true` could not be declared from the config that `fozikio init` writes (#114). + ## [1.9.0] — 2026-09-18 ### Added diff --git a/package-lock.json b/package-lock.json index d21f919..764487e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@fozikio/cortex-engine", - "version": "1.9.0", + "version": "1.9.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@fozikio/cortex-engine", - "version": "1.9.0", + "version": "1.9.1", "license": "MIT", "dependencies": { "@fozikio/reflex": "^0.2.0", @@ -821,7 +821,7 @@ "optional": true }, "node_modules/@opentelemetry/api": { - "version": "1.9.0", + "version": "1.9.1", "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", "dev": true, diff --git a/package.json b/package.json index bcb231c..145f5f1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@fozikio/cortex-engine", - "version": "1.9.0", + "version": "1.9.1", "description": "Portable cognitive engine for AI agents — storage, embeddings, memory, FSRS, and MCP server", "type": "module", "main": "dist/index.js", diff --git a/src/bin/config-loader.test.ts b/src/bin/config-loader.test.ts index 6faefff..5089663 100644 --- a/src/bin/config-loader.test.ts +++ b/src/bin/config-loader.test.ts @@ -10,7 +10,7 @@ */ import { describe, it, expect, vi, afterEach } from 'vitest'; -import { mkdtempSync, rmSync } from 'node:fs'; +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { DEFAULT_CONFIG } from '../core/config.js'; @@ -97,3 +97,47 @@ describe('loadConfig with no config file', () => { } }); }); + +describe('loadConfig over a named cortex map (agent.yaml)', () => { + afterEach(() => { + vi.restoreAllMocks(); + }); + + it("lifts the primary entry's plugins and nli onto the config", () => { + const dir = mkdtempSync(join(tmpdir(), 'cortex-cfg-')); + try { + mkdirSync(join(dir, '.fozikio')); + writeFileSync( + join(dir, '.fozikio', 'agent.yaml'), + [ + 'agent:', + ' name: ledger', + 'agents:', + ' ledger:', + ' namespace: ledger', + 'cortex:', + ' ledger:', + ' store: sqlite', + ' embed: ollama', + ' llm: ollama', + ' primary: true', + ' collections_prefix: ledger_', + ' cognitive_tools: [query, observe]', + ' plugins:', + ' - ./.fozikio/plugins/codebase-mind/dist/index.js', + ' nli:', + ' enabled: true', + ' url: http://127.0.0.1:11435', + '', + ].join('\n'), + ); + const config = loadConfig(dir, 'ledger'); + expect(config.plugins).toEqual(['./.fozikio/plugins/codebase-mind/dist/index.js']); + expect(config.nli).toEqual({ enabled: true, url: 'http://127.0.0.1:11435' }); + expect(config.namespaces.ledger?.collections_prefix).toBe('ledger_'); + expect(config.namespaces.ledger?.cognitive_tools).toEqual(['query', 'observe']); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); +}); diff --git a/src/bin/config-loader.ts b/src/bin/config-loader.ts index d19cf51..ea9bf03 100644 --- a/src/bin/config-loader.ts +++ b/src/bin/config-loader.ts @@ -26,6 +26,9 @@ interface NamedCortexEntry { llm_options?: CortexConfig['llm_options']; embed_options?: CortexConfig['embed_options']; store_options?: CortexConfig['store_options']; + /** Plugin packages or paths (see plugins/loader.ts); lifted onto the config like the provider fields. */ + plugins?: CortexConfig['plugins']; + nli?: CortexConfig['nli']; } /** @@ -72,6 +75,11 @@ function extractFromNamedCortexMap(cortexMap: Record): if (entry.llm_options) partial.llm_options = entry.llm_options; if (entry.embed_options) partial.embed_options = entry.embed_options; if (entry.store_options) partial.store_options = entry.store_options; + // `plugins` and `nli` sit on CortexConfig beside the provider fields, but until 1.9.1 only the + // legacy flat `cortex:` block carried them through: the named map dropped both, so a repo's own + // plugin listed under its agent's entry (the 1.9.0 `trusted` path's whole point) never loaded. + if (entry.plugins) partial.plugins = entry.plugins; + if (entry.nli) partial.nli = entry.nli; if (entry.cognitive_tools || entry.collections_prefix) { partial.namespaces = {