kibi-mcp 0.14.2 → 0.14.3
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/server/docs.js +3 -29
- package/dist/server/tools.js +3 -9
- package/dist/tools/autopilot-candidates.js +10 -5
- package/dist/tools/autopilot-discovery.js +20 -6
- package/dist/tools/autopilot-generate.js +28 -14
- package/dist/tools/delete.js +10 -50
- package/dist/tools/model-requirement.js +10 -3
- package/dist/tools/skills.js +6 -2
- package/dist/tools/symbols.js +1 -1
- package/dist/tools/upsert.js +0 -11
- package/dist/tools-config.js +0 -23
- package/package.json +3 -6
- package/dist/tools/briefing-generate.js +0 -651
- package/dist/utils/brief-marker.js +0 -107
package/dist/server/docs.js
CHANGED
|
@@ -63,7 +63,7 @@ export const PROMPTS = [
|
|
|
63
63
|
"Call `kb_autopilot_generate` with the gathered context to synthesize candidate entities.",
|
|
64
64
|
"",
|
|
65
65
|
"This tool is **read-only**. It returns additive `structuredContent` with:",
|
|
66
|
-
"- `promptBlock`: review text that can be surfaced
|
|
66
|
+
"- `promptBlock`: review text that can be surfaced for optional human review",
|
|
67
67
|
"- `recommendedActions`: agent-facing next steps, including any REQ/SCEN/TEST authoring routed for manual handling",
|
|
68
68
|
"- `declaredContext`: the user-provided bootstrap context",
|
|
69
69
|
"- `confidence`: confidence summary for the generated output",
|
|
@@ -73,7 +73,7 @@ export const PROMPTS = [
|
|
|
73
73
|
"",
|
|
74
74
|
"## Step 3: Optional Human Review",
|
|
75
75
|
"",
|
|
76
|
-
"Surface the `promptBlock` and a summary of `candidates` when optional human review is useful. Human review is post-hoc/optional
|
|
76
|
+
"Surface the `promptBlock` and a summary of `candidates` when optional human review is useful. Human review is post-hoc/optional and must not block writes.",
|
|
77
77
|
"",
|
|
78
78
|
"## Step 4: Apply Candidates",
|
|
79
79
|
"",
|
|
@@ -83,37 +83,11 @@ export const PROMPTS = [
|
|
|
83
83
|
"3. Run `kb_check` after the batch to verify KB integrity.",
|
|
84
84
|
"",
|
|
85
85
|
"## Rules",
|
|
86
|
-
"- Human review is optional and post-hoc
|
|
86
|
+
"- Human review is optional and post-hoc; do not gate writes on synchronous sign-off.",
|
|
87
87
|
"- `kb_autopilot_generate` is strictly read-only; synthesis is the backend, not the actor.",
|
|
88
88
|
"- Guidance must stay MCP-only; do not suggest `kibi` CLI commands.",
|
|
89
89
|
].join("\n"),
|
|
90
90
|
},
|
|
91
|
-
{
|
|
92
|
-
name: "brief-kibi",
|
|
93
|
-
description: "Start-task workflow for generating a citation-backed Kibi briefing before risky work.",
|
|
94
|
-
text: [
|
|
95
|
-
"# Kibi Briefing Workflow",
|
|
96
|
-
"",
|
|
97
|
-
"Use this workflow at the start of a task when you need a deterministic, citation-backed Kibi briefing.",
|
|
98
|
-
"",
|
|
99
|
-
"## Step 1: Generate the briefing",
|
|
100
|
-
"",
|
|
101
|
-
"Call `kb_briefing_generate` with any relevant `taskText`, `sourceFiles`, and `seedIds`.",
|
|
102
|
-
"",
|
|
103
|
-
"This tool is read-only. It returns `briefingState`, `activationState`, `activationReason`, `freshness`, `confidence`, `tldr`, `promptBlock`, `entities`, `constraints`, `regressionRisks`, `missingEvidence`, and `citations`.",
|
|
104
|
-
"",
|
|
105
|
-
"## Step 2: Inspect readiness",
|
|
106
|
-
"",
|
|
107
|
-
"Inspect `briefingState` before acting.",
|
|
108
|
-
"- If `briefingState` is `ready`, continue using only cited output from the briefing.",
|
|
109
|
-
"- If `briefingState` is `no_briefing`, stop and proceed without inventing briefing claims.",
|
|
110
|
-
"",
|
|
111
|
-
"## Step 3: Use the cited output",
|
|
112
|
-
"",
|
|
113
|
-
"Use `constraints`, `regressionRisks`, `missingEvidence`, and `promptBlock` only when their claims are backed by the returned `citations` and cited `entities`.",
|
|
114
|
-
"Do not add uncited assertions, and do not treat omitted topics as verified.",
|
|
115
|
-
].join("\n"),
|
|
116
|
-
},
|
|
117
91
|
{
|
|
118
92
|
name: "kibi_overview",
|
|
119
93
|
description: "High-level model for using kibi-mcp safely and effectively.",
|
package/dist/server/tools.js
CHANGED
|
@@ -2,19 +2,18 @@ import { z } from "zod";
|
|
|
2
2
|
import { DIAGNOSTIC_MODE_ENABLED, appendUsageLogLine, deriveDiagnosticFields, extractToolCallPayload, } from "../diagnostics.js";
|
|
3
3
|
import { isMcpDebugEnabled } from "../env.js";
|
|
4
4
|
import { TOOLS } from "../tools-config.js";
|
|
5
|
+
import { handleKbAutopilotGenerate, } from "../tools/autopilot-generate.js";
|
|
5
6
|
import { handleKbCheck } from "../tools/check.js";
|
|
6
7
|
import { handleKbCoverage } from "../tools/coverage.js";
|
|
7
8
|
import { handleKbDelete } from "../tools/delete.js";
|
|
8
9
|
import { handleKbFindGaps } from "../tools/find-gaps.js";
|
|
9
10
|
import { handleKbGraph } from "../tools/graph.js";
|
|
11
|
+
import { handleKbModelRequirement, } from "../tools/model-requirement.js";
|
|
10
12
|
import { handleKbQuery } from "../tools/query.js";
|
|
11
13
|
import { handleKbSearch } from "../tools/search.js";
|
|
12
|
-
import { handleKbStatus } from "../tools/status.js";
|
|
13
14
|
import { handleKbSkillsList, handleKbSkillsLoad, handleKbSkillsRead, } from "../tools/skills.js";
|
|
15
|
+
import { handleKbStatus } from "../tools/status.js";
|
|
14
16
|
import { handleKbUpsert } from "../tools/upsert.js";
|
|
15
|
-
import { handleKbModelRequirement, } from "../tools/model-requirement.js";
|
|
16
|
-
import { handleKbAutopilotGenerate, } from "../tools/autopilot-generate.js";
|
|
17
|
-
import { handleKbBriefingGenerate, } from "../tools/briefing-generate.js";
|
|
18
17
|
const defaultToolsServerDeps = {
|
|
19
18
|
getSessionModule: () => import("./session.js"),
|
|
20
19
|
};
|
|
@@ -66,7 +65,6 @@ const DEFAULT_TOOLS_RUNTIME = {
|
|
|
66
65
|
handleKbUpsert,
|
|
67
66
|
handleKbModelRequirement,
|
|
68
67
|
handleKbAutopilotGenerate,
|
|
69
|
-
handleKbBriefingGenerate,
|
|
70
68
|
};
|
|
71
69
|
// implements REQ-008
|
|
72
70
|
function debugLog(...args) {
|
|
@@ -338,8 +336,4 @@ runtime = DEFAULT_TOOLS_RUNTIME) {
|
|
|
338
336
|
const prolog = await runtime.ensureProlog();
|
|
339
337
|
return runtime.handleKbAutopilotGenerate(prolog, args);
|
|
340
338
|
}, runtime);
|
|
341
|
-
addTool(server, "kb_briefing_generate", toolDef("kb_briefing_generate").description, toolDef("kb_briefing_generate").inputSchema, async (args) => {
|
|
342
|
-
const prolog = await runtime.ensureProlog();
|
|
343
|
-
return runtime.handleKbBriefingGenerate(prolog, args);
|
|
344
|
-
}, runtime);
|
|
345
339
|
}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
import { extractFromManifest } from "kibi-cli/extractors/manifest";
|
|
4
4
|
import { extractFromMarkdown } from "kibi-cli/extractors/markdown";
|
|
5
5
|
import { buildStrictWriteSet, modelRequirementClaims, } from "kibi-cli/public/check-types";
|
|
6
|
-
import path from "node:path";
|
|
7
6
|
import fs from "node:fs";
|
|
7
|
+
import path from "node:path";
|
|
8
8
|
import { createRepoIgnorePolicy } from "kibi-cli/ignore-policy";
|
|
9
9
|
import { estimateNormativeSignalConfidence, extractRequirementClaim, strictWriteSetToApplyPlan, writeSetPrimaryEntityId, } from "./model-requirement.js";
|
|
10
10
|
function slugify(value, maxLength = 80) {
|
|
@@ -223,7 +223,8 @@ export function buildGenericMarkdownCandidates(discoveryResult, existingEntities
|
|
|
223
223
|
let type = null;
|
|
224
224
|
let confidence = 0;
|
|
225
225
|
// ADR heuristic: headings that mention ADR or Architectural Decision
|
|
226
|
-
if (/\badr\b/i.test(heading) ||
|
|
226
|
+
if (/\badr\b/i.test(heading) ||
|
|
227
|
+
/architectur.*decision/i.test(heading)) {
|
|
227
228
|
type = "adr";
|
|
228
229
|
confidence = 0.9;
|
|
229
230
|
}
|
|
@@ -336,7 +337,8 @@ export function collectSourceOnlyAuthoringSignals(discoveryResult, existingEntit
|
|
|
336
337
|
evidence: [`generic_heading:${textRef}`],
|
|
337
338
|
}, seen);
|
|
338
339
|
}
|
|
339
|
-
if (/\b(tests?|verification)\b/i.test(heading) &&
|
|
340
|
+
if (/\b(tests?|verification)\b/i.test(heading) &&
|
|
341
|
+
0.82 >= minConfidence) {
|
|
340
342
|
pushSignal(signals, {
|
|
341
343
|
kind: "test",
|
|
342
344
|
title: `Author tests from ${heading}`,
|
|
@@ -354,7 +356,8 @@ export function collectSourceOnlyAuthoringSignals(discoveryResult, existingEntit
|
|
|
354
356
|
for (const item of discoveryResult.evidence ?? []) {
|
|
355
357
|
const confidence = typeof item.data.confidence === "number" ? item.data.confidence : 0;
|
|
356
358
|
if (item.kind === "test_topology" && confidence >= minConfidence) {
|
|
357
|
-
const sourcePath = item.absolutePath ??
|
|
359
|
+
const sourcePath = item.absolutePath ??
|
|
360
|
+
path.resolve(workspaceRoot, item.relativePath ?? item.label);
|
|
358
361
|
const relativePath = item.relativePath ?? item.label;
|
|
359
362
|
pushSignal(signals, {
|
|
360
363
|
kind: "test",
|
|
@@ -504,7 +507,9 @@ export function buildProviderEvidenceCandidates(discoveryResult, existingEntitie
|
|
|
504
507
|
const generatedId = `FACT-GEN-${slugify(slugSource, 64) || "evidence"}`.toUpperCase();
|
|
505
508
|
if (existingEntities.ids.has(generatedId))
|
|
506
509
|
continue;
|
|
507
|
-
const textRef = relativePath.includes("#")
|
|
510
|
+
const textRef = relativePath.includes("#")
|
|
511
|
+
? relativePath
|
|
512
|
+
: `${relativePath}`;
|
|
508
513
|
const evidence = Array.isArray(item.data.evidence)
|
|
509
514
|
? item.data.evidence.filter((value) => typeof value === "string")
|
|
510
515
|
: [];
|
|
@@ -7,11 +7,12 @@
|
|
|
7
7
|
import fs from "node:fs";
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
import fg from "fast-glob";
|
|
10
|
-
import { createRepoIgnorePolicy } from "kibi-cli/ignore-policy";
|
|
11
10
|
import * as cliSymbolCoordinator from "kibi-cli/extractors/symbols-coordinator";
|
|
11
|
+
import { createRepoIgnorePolicy } from "kibi-cli/ignore-policy";
|
|
12
12
|
import { runJsonModuleQuery } from "./core-module.js";
|
|
13
13
|
// implements REQ-001
|
|
14
14
|
export const AUTOPILOT_PROVIDER_ORDER = [
|
|
15
|
+
// implements REQ-001
|
|
15
16
|
"typed_kibi_docs",
|
|
16
17
|
"generic_repo_docs",
|
|
17
18
|
"repo_metadata",
|
|
@@ -323,7 +324,8 @@ function detectLanguagesFromPackageJson(packageJson) {
|
|
|
323
324
|
const bin = packageJson.bin;
|
|
324
325
|
if (typeof scripts === "object" && scripts) {
|
|
325
326
|
for (const value of Object.values(scripts)) {
|
|
326
|
-
if (typeof value === "string" &&
|
|
327
|
+
if (typeof value === "string" &&
|
|
328
|
+
/\.(cts|mts|ts|tsx)\b|\b(tsx|ts-node)\b/i.test(value)) {
|
|
327
329
|
detected.add("typescript");
|
|
328
330
|
}
|
|
329
331
|
if (typeof value === "string" && /\.(cjs|mjs|js|jsx)\b/i.test(value)) {
|
|
@@ -416,11 +418,21 @@ function runRepoMetadataProvider(workspaceRoot) {
|
|
|
416
418
|
};
|
|
417
419
|
}
|
|
418
420
|
function runRepoLayoutProvider(workspaceRoot, vendoredRoots) {
|
|
419
|
-
const layoutRoots = [
|
|
421
|
+
const layoutRoots = [
|
|
422
|
+
"src",
|
|
423
|
+
"app",
|
|
424
|
+
"apps",
|
|
425
|
+
"packages",
|
|
426
|
+
"tests",
|
|
427
|
+
"test",
|
|
428
|
+
"docs",
|
|
429
|
+
"scripts",
|
|
430
|
+
];
|
|
420
431
|
const evidence = [];
|
|
421
432
|
for (const relativePath of layoutRoots) {
|
|
422
433
|
const absolutePath = path.join(workspaceRoot, relativePath);
|
|
423
|
-
if (!fs.existsSync(absolutePath) ||
|
|
434
|
+
if (!fs.existsSync(absolutePath) ||
|
|
435
|
+
!fs.statSync(absolutePath).isDirectory()) {
|
|
424
436
|
continue;
|
|
425
437
|
}
|
|
426
438
|
evidence.push({
|
|
@@ -547,7 +559,8 @@ function runSourceSymbolsProvider(workspaceRoot, vendoredRoots) {
|
|
|
547
559
|
const scanWarnings = [];
|
|
548
560
|
for (const absolutePath of sortUnique(sourceFiles)) {
|
|
549
561
|
const relativePath = toRelativePosixPath(workspaceRoot, absolutePath);
|
|
550
|
-
const language = SOURCE_LANGUAGE_EXTENSIONS[path.extname(absolutePath).toLowerCase()] ??
|
|
562
|
+
const language = SOURCE_LANGUAGE_EXTENSIONS[path.extname(absolutePath).toLowerCase()] ??
|
|
563
|
+
"unknown";
|
|
551
564
|
detectedLanguages.add(language);
|
|
552
565
|
try {
|
|
553
566
|
const content = fs.readFileSync(absolutePath, "utf8");
|
|
@@ -558,7 +571,8 @@ function runSourceSymbolsProvider(workspaceRoot, vendoredRoots) {
|
|
|
558
571
|
language,
|
|
559
572
|
providerId: null,
|
|
560
573
|
module: {
|
|
561
|
-
title: path.basename(relativePath, path.extname(relativePath)) ||
|
|
574
|
+
title: path.basename(relativePath, path.extname(relativePath)) ||
|
|
575
|
+
relativePath,
|
|
562
576
|
analysisMode: "fallback",
|
|
563
577
|
fallbackReason: "provider_unavailable",
|
|
564
578
|
},
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import fg from "fast-glob";
|
|
3
3
|
import { createRepoIgnorePolicy } from "kibi-cli/ignore-policy";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { resolveWorkspaceRoot } from "../workspace.js";
|
|
5
|
+
import { buildGenericMarkdownCandidates, buildNormativeRequirementCandidates, buildProviderEvidenceCandidates, buildSymbolManifestCandidates, buildTypedMarkdownCandidates, collectSourceOnlyAuthoringSignals, } from "./autopilot-candidates.js";
|
|
6
6
|
import { discoverProviderEvidence, resolveActivationPolicy, } from "./autopilot-discovery.js";
|
|
7
7
|
import { loadEntities } from "./entity-query.js";
|
|
8
|
-
import {
|
|
8
|
+
import { getWorkspaceMigrationWarning } from "./model-requirement.js";
|
|
9
9
|
function clamp(value, min, max) {
|
|
10
10
|
return Math.max(min, Math.min(max, value));
|
|
11
11
|
}
|
|
@@ -115,8 +115,9 @@ function buildPromptBlock(workspaceRoot, activationState, activationMode, activa
|
|
|
115
115
|
else if (declaredContext.verificationAnchors.length > 0) {
|
|
116
116
|
bullets.push(`- Verify after kb_check with ${listSummary(declaredContext.verificationAnchors, 2)}.`);
|
|
117
117
|
}
|
|
118
|
-
if (activationMode === "attached_thin_handoff" ||
|
|
119
|
-
|
|
118
|
+
if (activationMode === "attached_thin_handoff" ||
|
|
119
|
+
activationMode === "attached_seeded_handoff") {
|
|
120
|
+
bullets.push("- Handoff: use kb_search, kb_query, or gap/coverage tools to work with existing KB.");
|
|
120
121
|
}
|
|
121
122
|
if (scanWarnings.length > 0) {
|
|
122
123
|
bullets.push(`- Scan diagnostics: ${scanWarnings.length} warning(s) during evidence collection.`);
|
|
@@ -159,7 +160,8 @@ function buildRecommendedActions(workspaceRoot, activationMode, activationReason
|
|
|
159
160
|
const candidateIds = candidateRecords
|
|
160
161
|
.map((candidate) => String(candidate.candidateId ?? ""))
|
|
161
162
|
.filter(Boolean);
|
|
162
|
-
const isActiveRepo = activationMode === "attached_thin_handoff" ||
|
|
163
|
+
const isActiveRepo = activationMode === "attached_thin_handoff" ||
|
|
164
|
+
activationMode === "attached_seeded_handoff";
|
|
163
165
|
actions.push({
|
|
164
166
|
order: order++,
|
|
165
167
|
kind: "query",
|
|
@@ -176,7 +178,7 @@ function buildRecommendedActions(workspaceRoot, activationMode, activationReason
|
|
|
176
178
|
actions.push({
|
|
177
179
|
order: order++,
|
|
178
180
|
kind: "handoff",
|
|
179
|
-
description: "Use
|
|
181
|
+
description: "Use kb_query or kb_graph with task-relevant IDs to inspect cited KB context.",
|
|
180
182
|
});
|
|
181
183
|
actions.push({
|
|
182
184
|
order: order++,
|
|
@@ -190,7 +192,8 @@ function buildRecommendedActions(workspaceRoot, activationMode, activationReason
|
|
|
190
192
|
actions.push({
|
|
191
193
|
order: order++,
|
|
192
194
|
kind: "handoff",
|
|
193
|
-
description: handoffMessage ??
|
|
195
|
+
description: handoffMessage ??
|
|
196
|
+
blockedActivationMessage(activationMode, activationReason),
|
|
194
197
|
});
|
|
195
198
|
}
|
|
196
199
|
else if (candidateIds.length > 0) {
|
|
@@ -276,7 +279,11 @@ function buildConfidence(activationMode, applyBlocked, declaredContext, candidat
|
|
|
276
279
|
}
|
|
277
280
|
const rounded = roundScore(score);
|
|
278
281
|
const level = rounded > 0.7 ? "high" : rounded >= 0.4 ? "medium" : "low";
|
|
279
|
-
const policy = level === "high"
|
|
282
|
+
const policy = level === "high"
|
|
283
|
+
? "full_actions"
|
|
284
|
+
: level === "medium"
|
|
285
|
+
? "review_required"
|
|
286
|
+
: "handoff_only";
|
|
280
287
|
if (policy === "review_required") {
|
|
281
288
|
reasons.push("Medium confidence: review recommended before applying.");
|
|
282
289
|
}
|
|
@@ -295,7 +302,8 @@ function buildTldr(activationMode, applyBlocked, candidateRecords, sourceOnlySig
|
|
|
295
302
|
if (candidateRecords.length > 0 || sourceOnlySignals.length > 0) {
|
|
296
303
|
return `Bootstrap guidance is ready in ${activationMode}: ${candidateRecords.length} safe candidate(s), ${sourceOnlySignals.length} source-only authoring follow-up(s), and apply remains blocked.`;
|
|
297
304
|
}
|
|
298
|
-
return handoffMessage ??
|
|
305
|
+
return (handoffMessage ??
|
|
306
|
+
blockedActivationMessage(activationMode, activationReason));
|
|
299
307
|
}
|
|
300
308
|
if (candidateRecords.length > 0 || sourceOnlySignals.length > 0) {
|
|
301
309
|
return `Bootstrap output is ready with ${candidateRecords.length} safe candidate(s) and ${sourceOnlySignals.length} source-only authoring follow-up(s).`;
|
|
@@ -352,7 +360,8 @@ function splitDiscoveredSources(workspaceRoot, candidates) {
|
|
|
352
360
|
}
|
|
353
361
|
return { markdownFiles, manifestFiles };
|
|
354
362
|
}
|
|
355
|
-
export async function handleKbAutopilotGenerate(
|
|
363
|
+
export async function handleKbAutopilotGenerate(
|
|
364
|
+
// implements REQ-mcp-init-kibi-autopilot-v1
|
|
356
365
|
_prolog, args) {
|
|
357
366
|
const { includeGenericMarkdown = true, minConfidence = 0.8, maxCandidates = 50, entityTypes, bootstrapContext, } = args;
|
|
358
367
|
const normalizedMinConfidence = clamp(minConfidence, 0.6, 0.95);
|
|
@@ -473,7 +482,9 @@ _prolog, args) {
|
|
|
473
482
|
const sourcePath = String(candidate.sourcePath || "");
|
|
474
483
|
const textRef = extractTextRefFromApplyPlan(candidate.applyPlan);
|
|
475
484
|
const titleKey = normalizeTitle(entityType, title);
|
|
476
|
-
const upsert = Array.isArray(candidate.applyPlan)
|
|
485
|
+
const upsert = Array.isArray(candidate.applyPlan)
|
|
486
|
+
? candidate.applyPlan[0]
|
|
487
|
+
: null;
|
|
477
488
|
let upsertId = "";
|
|
478
489
|
if (upsert && typeof upsert === "object") {
|
|
479
490
|
const upsertRecord = upsert;
|
|
@@ -545,7 +556,8 @@ _prolog, args) {
|
|
|
545
556
|
const explain = repoIgnore.explain(rel);
|
|
546
557
|
if (explain.ignored) {
|
|
547
558
|
// avoid duplicating existing suppressed entries for the same source
|
|
548
|
-
if (!suppressed.some((s) => String(s.sourcePath ?? "") === rel &&
|
|
559
|
+
if (!suppressed.some((s) => String(s.sourcePath ?? "") === rel &&
|
|
560
|
+
s.reason === "ignored_source")) {
|
|
549
561
|
suppressed.push({
|
|
550
562
|
candidateId: String("") /* no candidate id for ignored source */,
|
|
551
563
|
reason: "ignored_source",
|
|
@@ -567,7 +579,9 @@ _prolog, args) {
|
|
|
567
579
|
const recommendedActions = buildRecommendedActions(workspaceRoot, activation.activationMode, activation.reason, activation.handoffMessage, activation.applyBlocked, declaredContext, candidateRecords, sourceOnlySignals);
|
|
568
580
|
const tldr = buildTldr(activation.activationMode, activation.applyBlocked, candidateRecords, sourceOnlySignals, activation.reason, activation.handoffMessage);
|
|
569
581
|
// Apply confidence policy: medium and low confidence force applyBlocked
|
|
570
|
-
const effectiveApplyBlocked = activation.applyBlocked ||
|
|
582
|
+
const effectiveApplyBlocked = activation.applyBlocked ||
|
|
583
|
+
confidence.level === "medium" ||
|
|
584
|
+
confidence.level === "low";
|
|
571
585
|
const effectiveTldr = confidence.level === "low" && !activation.applyBlocked
|
|
572
586
|
? `Low-confidence bootstrap (${confidence.score}): review diagnostics before proceeding. ${tldr}`
|
|
573
587
|
: tldr;
|
package/dist/tools/delete.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { escapeAtom, parseEntityFromList, parseListOfLists } from "kibi-cli/prolog/codec";
|
|
2
|
-
import { writeBriefPendingMarker } from "../utils/brief-marker.js";
|
|
1
|
+
import { escapeAtom, parseEntityFromList, parseListOfLists, } from "kibi-cli/prolog/codec";
|
|
3
2
|
/**
|
|
4
3
|
* Handle kb.delete tool calls
|
|
5
4
|
* Prevents deletion of entities with dependents (referential integrity)
|
|
6
5
|
*/
|
|
7
|
-
export async function handleKbDelete(
|
|
6
|
+
export async function handleKbDelete(
|
|
7
|
+
// implements REQ-002, REQ-011
|
|
8
8
|
prolog, args) {
|
|
9
9
|
const { ids } = args;
|
|
10
10
|
if (!ids || ids.length === 0) {
|
|
@@ -13,8 +13,6 @@ prolog, args) {
|
|
|
13
13
|
let deleted = 0;
|
|
14
14
|
let skipped = 0;
|
|
15
15
|
const errors = [];
|
|
16
|
-
const pendingEntityIds = [];
|
|
17
|
-
const pendingRelationships = [];
|
|
18
16
|
try {
|
|
19
17
|
for (const id of ids) {
|
|
20
18
|
const safeId = escapeAtom(id);
|
|
@@ -45,7 +43,6 @@ prolog, args) {
|
|
|
45
43
|
}
|
|
46
44
|
// No dependents, safe to delete
|
|
47
45
|
const entityMetadata = await loadEntityMetadataForDelete(prolog, id, safeId);
|
|
48
|
-
const relationships = await loadOutgoingRelationshipsForDelete(prolog, safeId);
|
|
49
46
|
const deleteGoal = buildDeleteGoal(safeId, entityMetadata);
|
|
50
47
|
const deleteResult = await prolog.query(deleteGoal);
|
|
51
48
|
if (!deleteResult.success) {
|
|
@@ -54,8 +51,6 @@ prolog, args) {
|
|
|
54
51
|
}
|
|
55
52
|
else {
|
|
56
53
|
deleted++;
|
|
57
|
-
pendingEntityIds.push(id);
|
|
58
|
-
pendingRelationships.push(...relationships);
|
|
59
54
|
}
|
|
60
55
|
}
|
|
61
56
|
// Save KB to disk
|
|
@@ -63,14 +58,6 @@ prolog, args) {
|
|
|
63
58
|
if (!saveResult.success) {
|
|
64
59
|
throw new Error(`Failed to save KB after delete: ${saveResult.error || "Unknown error"}`);
|
|
65
60
|
}
|
|
66
|
-
if (pendingEntityIds.length > 0 || pendingRelationships.length > 0) {
|
|
67
|
-
writeBriefPendingMarker({
|
|
68
|
-
...(args._requestId ? { sessionId: args._requestId } : {}),
|
|
69
|
-
operation: "delete",
|
|
70
|
-
entityIds: pendingEntityIds,
|
|
71
|
-
relationships: pendingRelationships,
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
61
|
prolog.invalidateCache();
|
|
75
62
|
return {
|
|
76
63
|
content: [
|
|
@@ -96,7 +83,9 @@ async function loadEntityMetadataForDelete(prolog, id, safeId) {
|
|
|
96
83
|
if (!result.success) {
|
|
97
84
|
throw new Error(`Failed to load metadata for entity ${id}: ${result.error || "Unknown error"}`);
|
|
98
85
|
}
|
|
99
|
-
const rows = result.bindings.Results
|
|
86
|
+
const rows = result.bindings.Results
|
|
87
|
+
? parseListOfLists(result.bindings.Results)
|
|
88
|
+
: [];
|
|
100
89
|
if (rows.length === 0) {
|
|
101
90
|
throw new Error(`Failed to load metadata for entity ${id}: Entity not found`);
|
|
102
91
|
}
|
|
@@ -105,40 +94,11 @@ async function loadEntityMetadataForDelete(prolog, id, safeId) {
|
|
|
105
94
|
const { id: _entityId, type: _entityType, ...props } = entity;
|
|
106
95
|
return { type, props };
|
|
107
96
|
}
|
|
108
|
-
async function loadOutgoingRelationshipsForDelete(prolog, safeId) {
|
|
109
|
-
const result = await prolog.query(`findall([Type,'${safeId}',To], (member(Type, [depends_on, verified_by, validates, specified_by, relates_to, guards, publishes, consumes, implements, covered_by, executable_for, constrains, requires_property, supersedes, constrained_by]), kb_relationship(Type, '${safeId}', To)), Relationships)`);
|
|
110
|
-
if (!result.success) {
|
|
111
|
-
throw new Error(`Failed to load outgoing relationships for entity ${safeId}: ${result.error || "Unknown error"}`);
|
|
112
|
-
}
|
|
113
|
-
const rows = result.bindings.Relationships
|
|
114
|
-
? parseListOfLists(result.bindings.Relationships)
|
|
115
|
-
: [];
|
|
116
|
-
return rows.flatMap((row) => {
|
|
117
|
-
const type = row[0];
|
|
118
|
-
const from = row[1];
|
|
119
|
-
const to = row[2];
|
|
120
|
-
if (type === undefined || from === undefined || to === undefined) {
|
|
121
|
-
return [];
|
|
122
|
-
}
|
|
123
|
-
return [
|
|
124
|
-
{
|
|
125
|
-
type: normalizeDeleteRelationshipValue(type),
|
|
126
|
-
from: normalizeDeleteRelationshipValue(from),
|
|
127
|
-
to: normalizeDeleteRelationshipValue(to),
|
|
128
|
-
},
|
|
129
|
-
];
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
function normalizeDeleteRelationshipValue(value) {
|
|
133
|
-
const normalized = String(value);
|
|
134
|
-
if ((normalized.startsWith("'") && normalized.endsWith("'")) ||
|
|
135
|
-
(normalized.startsWith('"') && normalized.endsWith('"'))) {
|
|
136
|
-
return normalized.slice(1, -1);
|
|
137
|
-
}
|
|
138
|
-
return normalized;
|
|
139
|
-
}
|
|
140
97
|
function buildDeleteGoal(safeId, metadata) {
|
|
141
|
-
const auditProps = [
|
|
98
|
+
const auditProps = [
|
|
99
|
+
`id='${safeId}'`,
|
|
100
|
+
...serializeDeleteProps(metadata.props),
|
|
101
|
+
];
|
|
142
102
|
return `kb_retract_entity('${safeId}', ${metadata.type}, [${auditProps.join(", ")}])`;
|
|
143
103
|
}
|
|
144
104
|
function serializeDeleteProps(props) {
|
|
@@ -29,11 +29,15 @@ function normalizeSourceFiles(sourceFiles) {
|
|
|
29
29
|
return normalized;
|
|
30
30
|
}
|
|
31
31
|
function clampConfidence(confidence) {
|
|
32
|
-
const numeric = typeof confidence === "number" && Number.isFinite(confidence)
|
|
32
|
+
const numeric = typeof confidence === "number" && Number.isFinite(confidence)
|
|
33
|
+
? confidence
|
|
34
|
+
: 0.8;
|
|
33
35
|
return Math.round(Math.min(1, Math.max(0, numeric)) * 100) / 100;
|
|
34
36
|
}
|
|
35
37
|
function normalizeClaimValue(value) {
|
|
36
|
-
if (typeof value === "string" ||
|
|
38
|
+
if (typeof value === "string" ||
|
|
39
|
+
typeof value === "number" ||
|
|
40
|
+
typeof value === "boolean") {
|
|
37
41
|
if (typeof value === "number" && !Number.isFinite(value)) {
|
|
38
42
|
throw new Error("Requirement modeling failed: value must be a finite number");
|
|
39
43
|
}
|
|
@@ -58,7 +62,10 @@ function cleanPredicate(value) {
|
|
|
58
62
|
return trimSentenceTail(stripListPrefix(value)) || "statement";
|
|
59
63
|
}
|
|
60
64
|
function fallbackSubjectFromSource(source) {
|
|
61
|
-
const basename = path
|
|
65
|
+
const basename = path
|
|
66
|
+
.basename(source, path.extname(source))
|
|
67
|
+
.replace(/[-_]+/g, " ")
|
|
68
|
+
.trim();
|
|
62
69
|
return basename || "Requirement";
|
|
63
70
|
}
|
|
64
71
|
function hasExplicitClaimFields(args) {
|
package/dist/tools/skills.js
CHANGED
|
@@ -6,7 +6,9 @@ export async function handleKbSkillsList(_args) {
|
|
|
6
6
|
const skills = listBundledSkills();
|
|
7
7
|
const ids = skills.map((skill) => skill.id).join(", ") || "none";
|
|
8
8
|
return {
|
|
9
|
-
content: [
|
|
9
|
+
content: [
|
|
10
|
+
{ type: "text", text: `Found ${skills.length} bundled skills: ${ids}` },
|
|
11
|
+
],
|
|
10
12
|
structuredContent: { skills },
|
|
11
13
|
};
|
|
12
14
|
}
|
|
@@ -25,7 +27,9 @@ export async function handleKbSkillsLoad(args) {
|
|
|
25
27
|
metadata: bundle.manifest,
|
|
26
28
|
body: bundle.body,
|
|
27
29
|
resources,
|
|
28
|
-
contentHash: createHash("sha256")
|
|
30
|
+
contentHash: createHash("sha256")
|
|
31
|
+
.update(bundle.body, "utf8")
|
|
32
|
+
.digest("hex"),
|
|
29
33
|
sourceType: "bundled",
|
|
30
34
|
};
|
|
31
35
|
return {
|
package/dist/tools/symbols.js
CHANGED
|
@@ -270,7 +270,7 @@ function normalizeCoordinateRecord(value) {
|
|
|
270
270
|
if (!isRecord(value)) {
|
|
271
271
|
return null;
|
|
272
272
|
}
|
|
273
|
-
const { sourceColumn, sourceEndColumn, sourceEndLine, sourceFile, sourceLine } = value;
|
|
273
|
+
const { sourceColumn, sourceEndColumn, sourceEndLine, sourceFile, sourceLine, } = value;
|
|
274
274
|
if (typeof sourceFile !== "string" ||
|
|
275
275
|
typeof sourceLine !== "number" ||
|
|
276
276
|
typeof sourceColumn !== "number" ||
|
package/dist/tools/upsert.js
CHANGED
|
@@ -20,7 +20,6 @@ import { escapeAtom, toPrologAtom, toPrologString, } from "kibi-cli/prolog/codec
|
|
|
20
20
|
import entitySchema from "kibi-cli/schemas/entity";
|
|
21
21
|
import relationshipSchema from "kibi-cli/schemas/relationship";
|
|
22
22
|
import { isMcpDebugEnabled } from "../env.js";
|
|
23
|
-
import { writeBriefPendingMarker } from "../utils/brief-marker.js";
|
|
24
23
|
import { refreshCoordinatesForSymbolId } from "./symbols.js";
|
|
25
24
|
let refreshCoordinatesForSymbolIdImpl = refreshCoordinatesForSymbolId;
|
|
26
25
|
const ajv = new Ajv({ strict: false });
|
|
@@ -156,16 +155,6 @@ export async function handleKbUpsert(prolog, args) {
|
|
|
156
155
|
if (!saveResult.success) {
|
|
157
156
|
throw new Error(`Failed to save KB after upsert: ${saveResult.error || "Unknown error"}`);
|
|
158
157
|
}
|
|
159
|
-
writeBriefPendingMarker({
|
|
160
|
-
...(args._requestId ? { sessionId: args._requestId } : {}),
|
|
161
|
-
operation: "upsert",
|
|
162
|
-
entityIds: [id],
|
|
163
|
-
relationships: relationships.map((rel) => ({
|
|
164
|
-
from: String(rel.from),
|
|
165
|
-
to: String(rel.to),
|
|
166
|
-
type: String(rel.type),
|
|
167
|
-
})),
|
|
168
|
-
});
|
|
169
158
|
if (type === "symbol") {
|
|
170
159
|
try {
|
|
171
160
|
await refreshCoordinatesForSymbolIdImpl(id);
|
package/dist/tools-config.js
CHANGED
|
@@ -541,29 +541,6 @@ const BASE_TOOLS = [
|
|
|
541
541
|
},
|
|
542
542
|
},
|
|
543
543
|
},
|
|
544
|
-
{
|
|
545
|
-
name: "kb_briefing_generate",
|
|
546
|
-
description: "Generate a deterministic, read-only, start-task briefing from task text, source files, and seed IDs. No mutation side effects.",
|
|
547
|
-
inputSchema: {
|
|
548
|
-
type: "object",
|
|
549
|
-
properties: {
|
|
550
|
-
taskText: {
|
|
551
|
-
type: "string",
|
|
552
|
-
description: "Optional task description used to rank relevant cited entities for the briefing.",
|
|
553
|
-
},
|
|
554
|
-
sourceFiles: {
|
|
555
|
-
type: "array",
|
|
556
|
-
items: { type: "string" },
|
|
557
|
-
description: "Optional source-file paths used to gather cited entities for the briefing.",
|
|
558
|
-
},
|
|
559
|
-
seedIds: {
|
|
560
|
-
type: "array",
|
|
561
|
-
items: { type: "string" },
|
|
562
|
-
description: "Optional seed entity IDs used to anchor the briefing graph expansion.",
|
|
563
|
-
},
|
|
564
|
-
},
|
|
565
|
-
},
|
|
566
|
-
}
|
|
567
544
|
];
|
|
568
545
|
/**
|
|
569
546
|
* Inject _diagnostic_telemetry schema into tool inputs when diagnostic mode is enabled.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kibi-mcp",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.3",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
6
6
|
"ajv": "^8.18.0",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"fast-glob": "^3.2.12",
|
|
10
10
|
"gray-matter": "^4.0.3",
|
|
11
11
|
"js-yaml": "^4.1.0",
|
|
12
|
-
"kibi-cli": "^0.11.
|
|
12
|
+
"kibi-cli": "^0.11.3",
|
|
13
13
|
"kibi-core": "^0.5.3",
|
|
14
14
|
"mcpcat": "^0.1.12",
|
|
15
15
|
"ts-morph": "^23.0.0",
|
|
@@ -27,10 +27,7 @@
|
|
|
27
27
|
"build": "tsc -p tsconfig.json",
|
|
28
28
|
"prepack": "npm run build"
|
|
29
29
|
},
|
|
30
|
-
"files": [
|
|
31
|
-
"dist",
|
|
32
|
-
"bin"
|
|
33
|
-
],
|
|
30
|
+
"files": ["dist", "bin"],
|
|
34
31
|
"engines": {
|
|
35
32
|
"node": ">=18",
|
|
36
33
|
"bun": ">=1.0"
|