Conversation
There was a problem hiding this comment.
Pull request overview
This PR expands automated coverage across the VS Code extension, CLI traceability helpers, and MCP tools, while improving VS Code hover-provider test isolation via an explicit dependency-injection seam.
Changes:
- Add extensive Bun-based unit tests for VS Code providers (Tree/CodeLens/CodeAction/Hover) plus a reusable VS Code mock module.
- Add broad unit coverage for MCP tools (
kb_upsert, entity query, delete) and CLI traceability/query utilities. - Introduce a dependency-injection seam in
KibiHoverProviderto prevent cross-test mock leakage; bump package versions and update changelogs accordingly.
Reviewed changes
Copilot reviewed 31 out of 31 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/vscode/tests/treeProvider.test.ts | Adds comprehensive TreeProvider unit coverage using filesystem fixtures and VS Code mocks. |
| packages/vscode/tests/shared/vscode-mock.ts | Introduces a reusable VS Code module mock with resettable state for test isolation. |
| packages/vscode/tests/relationshipCache.test.ts | Adds unit tests for relationship cache behavior (get/set/TTL/inflight). |
| packages/vscode/tests/hoverProvider.test.ts | Adds hover-provider unit tests (caching, cancellation, CLI parsing) using injected deps. |
| packages/vscode/tests/codeLensProvider.test.ts | Adds extensive CodeLens provider tests (watchers, debounce, caching, resolve). |
| packages/vscode/tests/codeActionProvider.test.ts | Adds CodeAction provider tests plus browse/open helper behavior verification. |
| packages/vscode/src/hoverProvider.ts | Adds deps?: Partial<HoverProviderDeps> seam and routes CLI/markdown calls through deps. |
| packages/vscode/package.json | Bumps kibi-vscode version to 0.2.3 and reformats arrays. |
| packages/vscode/CHANGELOG.md | Adds 0.2.3 entry documenting hover-provider DI seam. |
| packages/opencode/tests/logger.test.ts | Adds Vitest coverage for structured logging behavior and client reset semantics. |
| packages/opencode/package.json | Bumps kibi-opencode version to 0.5.3. |
| packages/opencode/CHANGELOG.md | Adds 0.5.3 release notes for workspace/logging improvements. |
| packages/mcp/tests/tools/upsert.test.ts | Adds extensive kb_upsert unit coverage including validation and failure formatting paths. |
| packages/mcp/tests/tools/entity-query.test.ts | Adds unit tests for entity-query helper functions and Prolog binding parsing. |
| packages/mcp/tests/tools/delete.test.ts | Adds unit tests for delete handler (existence, dependents, escaping, error handling). |
| packages/mcp/package.json | Bumps kibi-mcp version to 0.5.1 and updates kibi-cli dependency to ^0.4.2. |
| packages/mcp/CHANGELOG.md | Adds 0.5.1 entry describing new upsert coverage and dependency update. |
| packages/cli/tests/traceability/validate.test.ts | Adds direct edge-case coverage for Prolog parsing helpers via __test__. |
| packages/cli/tests/traceability/symbol-extract.test.ts | Adds broad symbol-extraction tests covering caching and multiple fallback strategies. |
| packages/cli/tests/traceability/markdown-validate.test.ts | Adds markdown staged validation tests for frontmatter handling and parse errors. |
| packages/cli/tests/traceability/git-staged.test.ts | Adds staged-file parsing tests with both mocked git output and real temp repo cases. |
| packages/cli/tests/query/service.test.ts | Adds query service tests covering goal building, codec integration, filtering, pagination. |
| packages/cli/tests/extractors/symbols-coordinator.test.ts | Adds coordinator tests covering ts-morph delegation and regex fallback behavior. |
| packages/cli/tests/commands/discovery-shared.test.ts | Adds tests for Prolog attachment, JSON module queries, and table rendering paths. |
| packages/cli/tests/commands/aggregated-checks.test.ts | Adds tests for aggregated checks parsing, filtering, and error cases. |
| packages/cli/src/traceability/validate.ts | Exports __test__ helpers for edge-case testing of internal Prolog parsing utilities. |
| packages/cli/package.json | Bumps kibi-cli version to 0.4.2. |
| packages/cli/CHANGELOG.md | Adds 0.4.2 entry documenting exported __test__ helpers. |
| documentation/tests/TEST-mcp-upsert-coverage.md | Adds a documentation test entity describing validation/coverage steps for MCP upsert. |
| .changeset/opencode-plugin-logging-remediation.md | Removes changeset file (presumably consumed by versioning). |
| .changeset/honor-sync-path-bootstrap.md | Removes changeset file (presumably consumed by versioning). |
Comments suppressed due to low confidence (2)
packages/vscode/src/hoverProvider.ts:168
queryRelationshipsViaClibuilds a shell command by interpolatingsymbolIdinto a single string passed toexecSync. IfsymbolIdcontains shell metacharacters this becomes command-injection prone. PreferexecFileSync/spawnSyncwith an args array (or strictly validate/escape IDs) so the CLI receivessymbolIdas a literal argument.
private async queryRelationshipsViaCli(
symbolId: string,
): Promise<Array<{ type: string; from: string; to: string }>> {
try {
const output = this.deps.execCli(
`bun run packages/cli/bin/kibi query --relationships ${symbolId} --format json`,
{
cwd: this.workspaceRoot,
encoding: "utf8",
timeout: 10000,
stdio: ["ignore", "pipe", "ignore"],
},
);
packages/vscode/src/hoverProvider.ts:264
queryEntityViaCliinterpolatesentityIddirectly into a shell command string. Even if IDs are expected to be well-formed, this is a command-injection vector if a malicious ID ever reaches this codepath. UseexecFileSync/spawnSyncwith args (or enforce a strict^[A-Z]+-[A-Za-z0-9_-]+$-style validation) before executing.
private async queryEntityViaCli(
entityId: string,
): Promise<EntityDetails | null> {
try {
// Extract entity type from ID prefix (e.g., REQ-001 -> req)
const typeMatch = entityId.match(/^([A-Z]+)-/);
if (!typeMatch) return null;
const typePrefix = typeMatch[1];
const typeMap: Record<string, string> = {
REQ: "req",
SCEN: "scenario",
TEST: "test",
ADR: "adr",
FLAG: "flag",
EVENT: "event",
SYM: "symbol",
};
const entityType = typeMap[typePrefix];
if (!entityType) return null;
const output = this.deps.execCli(
`bun run packages/cli/bin/kibi query ${entityType} --id ${entityId} --format json`,
{
cwd: this.workspaceRoot,
encoding: "utf8",
timeout: 10000,
stdio: ["ignore", "pipe", "ignore"],
},
);
| const { | ||
| buildHoverMarkdown: realBuildHoverMarkdown, | ||
| categorizeEntities: realCategorizeEntities, | ||
| formatLensTitle: realFormatLensTitle, | ||
| } = await import("../src/helpers?real"); |
There was a problem hiding this comment.
The destructuring import from ../src/helpers?real includes realCategorizeEntities and realFormatLensTitle, but they are never used. With biome check . enabled, unused imports/locals can fail CI; remove the unused bindings or add assertions that use them.
| const { | |
| buildHoverMarkdown: realBuildHoverMarkdown, | |
| categorizeEntities: realCategorizeEntities, | |
| formatLensTitle: realFormatLensTitle, | |
| } = await import("../src/helpers?real"); | |
| const { buildHoverMarkdown: realBuildHoverMarkdown } = await import( | |
| "../src/helpers?real" | |
| ); |
| const initialKibiMcpDebug = process.env.KIBI_MCP_DEBUG ?? ""; | ||
|
|
||
| function createMockProlog( | ||
| handler: (goal: string) => Promise<QueryResult> | QueryResult, | ||
| ) { | ||
| const query = mock(async (goal: string) => { | ||
| const result = await handler(goal); | ||
| return { bindings: {}, ...result }; | ||
| }); | ||
| const invalidateCache = mock(() => {}); | ||
|
|
||
| return { | ||
| query, | ||
| invalidateCache, | ||
| prolog: { | ||
| query, | ||
| invalidateCache, | ||
| } as unknown as PrologProcess, | ||
| }; | ||
| } | ||
|
|
||
| afterEach(() => { | ||
| mock.restore(); | ||
| process.env.KIBI_MCP_DEBUG = initialKibiMcpDebug; | ||
| }); |
There was a problem hiding this comment.
initialKibiMcpDebug is captured as process.env.KIBI_MCP_DEBUG ?? "" and later restored via assignment. If the env var was originally unset, this leaves it set to an empty string instead of restoring undefined, which can change behavior for later tests. Capture the original value as string | undefined and restore by deleting the key when it was originally undefined.
| expect(transactionGoal).toContain("value_int=30"); | ||
| expect(transactionGoal).toContain("closed_world=false"); | ||
| expect(transactionGoal).toContain('tags=["alpha","beta"]'); | ||
| expect(transactionGoal).toContain('owner="undefined"'); |
There was a problem hiding this comment.
This test asserts owner: undefined is encoded as owner="undefined" in the Prolog transaction goal. That locks in a surprising serialization behavior; it’s usually safer to omit undefined/null properties entirely when building the property list. Consider updating the encoder (and the expectation here) to skip undefined values so accidental undefineds don’t persist into the KB.
| expect(transactionGoal).toContain('owner="undefined"'); | |
| expect(transactionGoal).not.toContain("owner="); |
| const { KibiTreeDataProvider } = await import("../src/treeProvider"); | ||
|
|
||
| type TreeProviderInstance = InstanceType<typeof KibiTreeDataProvider>; | ||
|
|
||
| let tmpDir: string; |
There was a problem hiding this comment.
TreeProviderInstance type alias is declared but never used. If Biome/TS unused checks run on tests, this can fail CI; remove the alias or use it to type provider where appropriate.
|
@copilot apply changes based on the comments in this thread in a separate PR. |
…ps, unused type) Agent-Logs-Url: https://github.com/Looted/kibi/sessions/3d0a4d79-9903-4572-9709-bdd79879f7d8 Co-authored-by: Looted <6255880+Looted@users.noreply.github.com>
fix: address PR review feedback on test isolation and undefined property encoding
…r coverage Add mock.restore() to afterEach hook to clean up mock.module mocks after each test. This prevents the mock from upsert.test.ts from leaking into symbols.test.ts when running with --coverage flag. Fixes: 9 refreshCoordinatesForSymbolId tests failing on CI Root cause: Bun hoists mock.module() calls; snip without cleanup, mocks leak across test files under coverage instrumentation.
No description provided.