@tomingtoming/kioq 0.7.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.
@@ -0,0 +1,1305 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { z } from "zod";
4
+ import { lintStructureResponseModeHint, lintStructureResponsePlan, summarizeLintStructureResponse, } from "./auditResponseSummary.js";
5
+ import { loadConfig } from "./config.js";
6
+ import { memoryContractResponseModeHint, memoryContractResponsePlan, summarizeMemoryContractResponse, } from "./contractResponseSummary.js";
7
+ import { summarizeNoConflict } from "./conflictSummary.js";
8
+ import { LocalNoteStore } from "./noteStore.js";
9
+ import { GitHubStorage, LocalFsStorage } from "./storage/index.js";
10
+ import { normalizeDateInput, preview } from "./normalizers.js";
11
+ import { summarizeDeleteImpact, summarizeRenameImpact } from "./operationImpact.js";
12
+ import { summarizeBacklinksResponse, summarizeContextBundleResponse, summarizeReadNoteResponse, summarizeRecentResponse, summarizeResolveLinksResponse, summarizeSearchResponse, } from "./readResponseSummary.js";
13
+ import { summarizeLintChangeTrigger, summarizeReadChangeTrigger } from "./changeTriggerSummary.js";
14
+ import { RESPONSE_MODE_VALUES, normalizeResponseMode, responseModeAtLeast } from "./responseMode.js";
15
+ import { TOOL_SCOPE_LABELS, responsibilityWarningCode } from "./toolScope.js";
16
+ import { summarizeAppendResponse, summarizeDeleteResponse, summarizePromoteResponse, summarizeRenameResponse, summarizeWriteFlowResponse, summarizeWriteNoteResponse, } from "./writeResponseSummary.js";
17
+ function textResult(text) {
18
+ return {
19
+ content: [{ type: "text", text }],
20
+ };
21
+ }
22
+ function normalizeError(error) {
23
+ if (error instanceof Error) {
24
+ return error.message;
25
+ }
26
+ return String(error);
27
+ }
28
+ function insertBeforeLine(lines, prefix, line) {
29
+ const index = lines.findIndex((item) => item.startsWith(prefix));
30
+ if (index >= 0) {
31
+ lines.splice(index, 0, line);
32
+ return;
33
+ }
34
+ lines.push(line);
35
+ }
36
+ function appendUnresolvedWikiLinks(lines, unresolved) {
37
+ if (unresolved.length === 0) {
38
+ return;
39
+ }
40
+ lines.push("");
41
+ lines.push("未解決 WikiLink:");
42
+ unresolved.forEach((target, index) => {
43
+ lines.push(`${index + 1}. ${target}`);
44
+ });
45
+ }
46
+ function appendUnresolvedLinkHints(lines, hints) {
47
+ if (hints.length === 0) {
48
+ return;
49
+ }
50
+ lines.push("");
51
+ lines.push("未解決 WikiLink 候補:");
52
+ hints.forEach((hint, index) => {
53
+ lines.push(`${index + 1}. target: ${hint.target}`);
54
+ if (hint.suggestions.length === 0) {
55
+ lines.push(" suggestion: (none)");
56
+ return;
57
+ }
58
+ hint.suggestions.forEach((suggestion) => {
59
+ const reasons = suggestion.reasons.length > 0 ? suggestion.reasons.join(",") : "-";
60
+ lines.push(` suggestion: ${suggestion.title} (${suggestion.filePath}) score=${suggestion.score} reasons=${reasons}`);
61
+ });
62
+ });
63
+ }
64
+ function appendDuplicateWarnings(lines, warnings) {
65
+ if (warnings.length === 0) {
66
+ return;
67
+ }
68
+ lines.push("");
69
+ lines.push("重複警告:");
70
+ warnings.forEach((warning, index) => {
71
+ lines.push(`${index + 1}. kind: ${warning.kind}`);
72
+ lines.push(` value: ${warning.value}`);
73
+ lines.push(` count: ${warning.count}`);
74
+ warning.examples.forEach((example) => {
75
+ lines.push(` example: ${example}`);
76
+ });
77
+ });
78
+ }
79
+ function appendStructureScore(lines, structureScore) {
80
+ lines.push(`structure_score: ${structureScore.score} (${structureScore.grade})`);
81
+ if (structureScore.nextActions.length === 0) {
82
+ lines.push("structure_next_actions: (none)");
83
+ return;
84
+ }
85
+ lines.push("structure_next_actions:");
86
+ structureScore.nextActions.forEach((action, index) => {
87
+ lines.push(`${index + 1}. ${action}`);
88
+ });
89
+ }
90
+ function appendMemoryContract(lines, contract) {
91
+ lines.push(`memory_contract: ${contract.status} (v${contract.version})`);
92
+ lines.push(`memory_contract_signals: resolved=${contract.signals.resolvedLinks} unresolved=${contract.signals.unresolvedLinks} backlinks=${contract.signals.backlinks} parent=${contract.signals.parentLinks} related=${contract.signals.relatedLinks} tags=${contract.signals.tags}`);
93
+ if (contract.violations.length === 0) {
94
+ lines.push("memory_contract_violations: (none)");
95
+ return;
96
+ }
97
+ lines.push("memory_contract_violations:");
98
+ contract.violations.forEach((violation, index) => {
99
+ lines.push(`${index + 1}. ${violation.code}`);
100
+ lines.push(` message: ${violation.message}`);
101
+ lines.push(` suggestion: ${violation.suggestion}`);
102
+ });
103
+ }
104
+ function appendBoundaryWarnings(lines, warnings) {
105
+ if (warnings.length === 0) {
106
+ return;
107
+ }
108
+ lines.push("");
109
+ lines.push("boundary_warnings:");
110
+ warnings.forEach((warning, index) => {
111
+ lines.push(`${index + 1}. ${warning.code}`);
112
+ lines.push(` message: ${warning.message}`);
113
+ lines.push(` suggestion: ${warning.suggestion}`);
114
+ });
115
+ }
116
+ function appendScopeLabel(lines, scopeLabel) {
117
+ lines.push(`scope_label: ${scopeLabel}`);
118
+ }
119
+ function appendResponsibilityWarning(lines, warnings) {
120
+ lines.push(`responsibility_warning: ${responsibilityWarningCode(warnings)}`);
121
+ }
122
+ function appendTemplateHints(lines, hints) {
123
+ lines.push(`template_hint_primary: ${hints.primary}`);
124
+ lines.push(`template_hint_doc: docs/note-templates.md`);
125
+ if (hints.alternatives && hints.alternatives.length > 0) {
126
+ lines.push(`template_hint_alternatives: ${hints.alternatives.join(", ")}`);
127
+ }
128
+ lines.push(`template_hint_reason: ${hints.reason}`);
129
+ if (hints.whenToSwitch) {
130
+ lines.push(`template_hint_when_to_switch: ${hints.whenToSwitch}`);
131
+ }
132
+ }
133
+ function appendIndexNoteCandidates(lines, candidates, heading = "index_note_candidates") {
134
+ lines.push(`${heading}: ${candidates.length}`);
135
+ if (candidates.length === 0) {
136
+ return;
137
+ }
138
+ candidates.forEach((item, index) => {
139
+ lines.push(`${index + 1}. ${item.title}`);
140
+ lines.push(` permalink: ${item.permalink}`);
141
+ lines.push(` file: ${item.filePath}`);
142
+ lines.push(` score: ${item.score}`);
143
+ lines.push(` reasons: ${item.reasons.join(", ")}`);
144
+ });
145
+ }
146
+ function appendExplorationGuidance(lines, guidance) {
147
+ const hasDirectoryScopeHint = Boolean(guidance.directoryScopeHint);
148
+ const hasQueryPresets = guidance.queryPresets.length > 0;
149
+ if (!hasDirectoryScopeHint && !hasQueryPresets) {
150
+ return;
151
+ }
152
+ lines.push("");
153
+ lines.push("exploration_guidance:");
154
+ if (guidance.directoryScopeHint) {
155
+ lines.push("directory_scope_hint:");
156
+ lines.push(` tool: ${guidance.directoryScopeHint.suggestedTool}`);
157
+ lines.push(` directory: ${guidance.directoryScopeHint.directory}`);
158
+ lines.push(` reason: ${guidance.directoryScopeHint.reason}`);
159
+ }
160
+ else {
161
+ lines.push("directory_scope_hint: (none)");
162
+ }
163
+ lines.push(`query_presets: ${guidance.queryPresets.length}`);
164
+ guidance.queryPresets.forEach((preset, index) => {
165
+ lines.push(`${index + 1}. ${preset.query}`);
166
+ lines.push(` reason: ${preset.reason}`);
167
+ });
168
+ }
169
+ function appendIndexLike(lines, indexLike, reasons, prefix = "") {
170
+ const key = prefix.length > 0 ? `${prefix}_index_like` : "index_like";
171
+ const reasonsKey = prefix.length > 0 ? `${prefix}_index_like_reasons` : "index_like_reasons";
172
+ lines.push(`${key}: ${indexLike ? "yes" : "no"}`);
173
+ lines.push(`${reasonsKey}: ${indexLike && reasons.length > 0 ? reasons.join(", ") : "(none)"}`);
174
+ }
175
+ function appendDocumentClarity(lines, clarity, verbose) {
176
+ lines.push(`document_clarity: ${clarity.status}`);
177
+ lines.push(`title_presence: ${clarity.titlePresence ? "yes" : "no"}`);
178
+ lines.push(`summary_presence: ${clarity.summaryPresence ? "yes" : "no"}`);
179
+ lines.push(`list_ratio: ${clarity.listRatio}`);
180
+ lines.push(`long_sentence_count: ${clarity.longSentenceCount}`);
181
+ if (verbose) {
182
+ lines.push(`clarity_attention_reasons: ${clarity.attentionReasons.length > 0 ? clarity.attentionReasons.join(", ") : "(none)"}`);
183
+ }
184
+ }
185
+ function appendProjectHealthSummary(lines, health) {
186
+ const auditSummary = summarizeLintStructureResponse({
187
+ unresolvedWikiLinkCount: health.unresolvedWikiLinkCount,
188
+ memoryContractViolationCount: health.memoryContractViolationCount,
189
+ duplicateWarningCount: health.duplicateWarningCount,
190
+ dependencyDirectionViolationCount: health.technicalDebtSignals.dependencyDirectionViolationCount,
191
+ weakStructureCount: health.weakStructureCount,
192
+ orphanNoteCount: health.orphanNoteCount,
193
+ staleFlowCount: health.technicalDebtSignals.staleFlowCount,
194
+ singleUseTagCandidateCount: health.technicalDebtSignals.singleUseTagCandidateCount,
195
+ titleBodyMismatchCandidateCount: health.technicalDebtSignals.titleBodyMismatchCandidateCount,
196
+ firstIssueTitle: health.issues[0]?.noteTitle,
197
+ });
198
+ const hasAttention = health.unresolvedWikiLinkCount > 0
199
+ || health.duplicateWarningCount > 0
200
+ || health.technicalDebtSignals.dependencyDirectionViolationCount > 0
201
+ || health.memoryContractViolationCount > 0
202
+ || health.weakStructureCount > 0
203
+ || health.orphanNoteCount > 0;
204
+ lines.push("");
205
+ lines.push("project_health:");
206
+ lines.push(`- status: ${hasAttention ? "attention" : "ok"}`);
207
+ lines.push(`- project: ${health.project}`);
208
+ lines.push(`- notes: ${health.noteCount}`);
209
+ lines.push(`- avg_structure_score: ${health.averageScore}`);
210
+ lines.push(`- grades: A=${health.gradeCounts.A} B=${health.gradeCounts.B} C=${health.gradeCounts.C} D=${health.gradeCounts.D}`);
211
+ lines.push(`- unresolved_wikilinks: ${health.unresolvedWikiLinkCount}`);
212
+ lines.push(`- orphan_notes: ${health.orphanNoteCount}`);
213
+ lines.push(`- duplicate_warnings: ${health.duplicateWarningCount}`);
214
+ lines.push(`- weak_structure_notes: ${health.weakStructureCount}`);
215
+ lines.push(`- memory_contract_violations: ${health.memoryContractViolationCount}`);
216
+ lines.push(`- dependency_direction_violations: ${health.technicalDebtSignals.dependencyDirectionViolationCount}`);
217
+ lines.push(`- primary_quality_signal: ${auditSummary.primaryQualitySignal}`);
218
+ lines.push(`- next_recommended_action: ${auditSummary.nextRecommendedAction}`);
219
+ if (auditSummary.nextRecommendedTarget) {
220
+ lines.push(`- next_recommended_target: ${auditSummary.nextRecommendedTarget}`);
221
+ }
222
+ lines.push(`- stale_flow_count: ${health.technicalDebtSignals.staleFlowCount} (days>=${health.technicalDebtSignals.staleFlowDays})`);
223
+ lines.push(`- stale_flow_age_buckets: near_threshold=${health.technicalDebtSignals.staleFlowAgeBuckets.nearThreshold} aging=${health.technicalDebtSignals.staleFlowAgeBuckets.aging} long_stale=${health.technicalDebtSignals.staleFlowAgeBuckets.longStale}`);
224
+ lines.push(`- oldest_stale_flow_days: ${health.technicalDebtSignals.oldestStaleFlowDays ?? "(none)"}`);
225
+ lines.push(`- cleanup_ratio: ${health.technicalDebtSignals.cleanupRatio}`);
226
+ lines.push(`- cleanup_ready_count: ${health.technicalDebtSignals.cleanupReadyCount}`);
227
+ lines.push(`- attention_note_count: ${health.technicalDebtSignals.attentionNoteCount}`);
228
+ lines.push(`- dependency_direction_violation_count: ${health.technicalDebtSignals.dependencyDirectionViolationCount}`);
229
+ lines.push(`- single_use_tag_candidate_count: ${health.technicalDebtSignals.singleUseTagCandidateCount}`);
230
+ lines.push(`- title_body_mismatch_candidate_count: ${health.technicalDebtSignals.titleBodyMismatchCandidateCount}`);
231
+ lines.push(`- unresolved_wikilinks_delta: unavailable (${health.technicalDebtSignals.unresolvedWikilinksDeltaStatus})`);
232
+ if (health.issues.length === 0) {
233
+ lines.push("- top_issues: (none)");
234
+ return;
235
+ }
236
+ lines.push("- top_issues:");
237
+ health.issues.forEach((issue, index) => {
238
+ lines.push(` ${index + 1}. [${issue.severity}] ${issue.category} (${issue.notePath})`);
239
+ lines.push(` suggestion: ${issue.suggestion}`);
240
+ });
241
+ }
242
+ function appendReadResponseSummary(lines, summary) {
243
+ lines.push(`primary_navigation_signal: ${summary.primaryNavigationSignal}`);
244
+ lines.push(`primary_quality_signal: ${summary.primaryQualitySignal}`);
245
+ lines.push(`next_recommended_action: ${summary.nextRecommendedAction}`);
246
+ if (summary.nextRecommendedTarget) {
247
+ lines.push(`next_recommended_target: ${summary.nextRecommendedTarget}`);
248
+ }
249
+ }
250
+ function appendAuditResponseSummary(lines, summary) {
251
+ lines.push(`primary_navigation_signal: ${summary.primaryNavigationSignal}`);
252
+ lines.push(`primary_quality_signal: ${summary.primaryQualitySignal}`);
253
+ lines.push(`next_recommended_action: ${summary.nextRecommendedAction}`);
254
+ if (summary.nextRecommendedTarget) {
255
+ lines.push(`next_recommended_target: ${summary.nextRecommendedTarget}`);
256
+ }
257
+ if (summary.recommendedResponseMode) {
258
+ lines.push(`recommended_response_mode: ${summary.recommendedResponseMode}`);
259
+ }
260
+ if (summary.responseModeHint) {
261
+ lines.push(`response_mode_hint: ${summary.responseModeHint}`);
262
+ }
263
+ }
264
+ function appendChangeTriggerSummary(lines, summary) {
265
+ lines.push(`change_trigger: ${summary.code}`);
266
+ if (summary.code === "none") {
267
+ return;
268
+ }
269
+ lines.push(`trigger_confidence: ${summary.confidence}`);
270
+ lines.push(`cascade_targets: ${summary.cascadeTargets?.join(", ") ?? "(none)"}`);
271
+ lines.push(`noise_risk: ${summary.noiseRisk}`);
272
+ }
273
+ function appendOperationImpact(lines, impact) {
274
+ lines.push(`impact_score: ${impact.impactScore}`);
275
+ lines.push(`requires_backup: ${impact.requiresBackup ? "yes" : "no"}`);
276
+ lines.push(`impact_reasons: ${impact.reasons.join(", ")}`);
277
+ }
278
+ function appendConflictSummary(lines, summary) {
279
+ lines.push(`conflict_type: ${summary.conflictType}`);
280
+ lines.push(`server_updated: ${summary.serverUpdated}`);
281
+ lines.push(`retry_hint: ${summary.retryHint}`);
282
+ }
283
+ const responseModeSchema = z.enum(RESPONSE_MODE_VALUES).optional().describe("default: standard");
284
+ async function main() {
285
+ const config = loadConfig();
286
+ const storage = config.github
287
+ ? new GitHubStorage(config.github, config.root)
288
+ : new LocalFsStorage(config.root);
289
+ await storage.ensureRoot();
290
+ const store = new LocalNoteStore(config, storage);
291
+ const appendStorageContext = (lines) => {
292
+ lines.push(`storage_backend: ${config.github ? "github" : "filesystem"}`);
293
+ lines.push(`storage_root: ${config.root}`);
294
+ if (config.github) {
295
+ lines.push(`storage_repo: ${config.github.owner}/${config.github.repo}`);
296
+ lines.push(`storage_branch: ${config.github.branch}`);
297
+ }
298
+ };
299
+ const appendAutoProjectHealth = async (lines) => {
300
+ try {
301
+ const health = await store.lintStructure({
302
+ limit: 3,
303
+ });
304
+ appendProjectHealthSummary(lines, health);
305
+ }
306
+ catch (error) {
307
+ lines.push("");
308
+ lines.push(`project_health: unavailable (${normalizeError(error)})`);
309
+ }
310
+ };
311
+ const server = new McpServer({
312
+ name: "kioq",
313
+ version: "0.7.0",
314
+ });
315
+ server.tool("recent_notes", "最近更新したノートを一覧します。", {
316
+ limit: z.number().int().min(1).max(50).optional().describe("最大件数 (default: 10)"),
317
+ directory: z.string().min(1).optional().describe("指定時は配下ディレクトリに限定"),
318
+ response_mode: responseModeSchema,
319
+ }, async ({ limit, directory, response_mode }) => {
320
+ const responseMode = normalizeResponseMode(response_mode);
321
+ const result = await store.recentNotes({
322
+ limit: limit ?? 10,
323
+ directory,
324
+ });
325
+ const firstIndexLike = result.results.find((item) => item.indexLike);
326
+ const summary = summarizeRecentResponse({
327
+ resultCount: result.results.length,
328
+ firstResultTitle: result.results[0]?.title,
329
+ hasIndexLikeResult: Boolean(firstIndexLike),
330
+ firstIndexLikeTitle: firstIndexLike?.title,
331
+ indexCandidateCount: result.indexNoteCandidates.length,
332
+ firstIndexCandidateTitle: result.indexNoteCandidates[0]?.title,
333
+ });
334
+ const lines = [];
335
+ lines.push(`対象プロジェクト: ${result.project}`);
336
+ appendStorageContext(lines);
337
+ appendScopeLabel(lines, TOOL_SCOPE_LABELS.recent_notes);
338
+ lines.push(`response_mode: ${responseMode}`);
339
+ appendReadResponseSummary(lines, summary);
340
+ lines.push(`件数: ${result.results.length}`);
341
+ lines.push("");
342
+ if (result.results.length === 0) {
343
+ lines.push("候補が見つかりませんでした。");
344
+ }
345
+ else {
346
+ result.results.forEach((item, index) => {
347
+ lines.push(`${index + 1}. ${item.title}`);
348
+ lines.push(` updated: ${item.updated}`);
349
+ if (responseModeAtLeast(responseMode, "standard")) {
350
+ lines.push(` permalink: ${item.permalink}`);
351
+ lines.push(` file: ${item.filePath}`);
352
+ lines.push(` index_like: ${item.indexLike ? "yes" : "no"}`);
353
+ }
354
+ if (responseModeAtLeast(responseMode, "verbose")) {
355
+ lines.push(` index_like_reasons: ${item.indexLike && item.indexReasons.length > 0 ? item.indexReasons.join(", ") : "(none)"}`);
356
+ }
357
+ });
358
+ }
359
+ if (responseModeAtLeast(responseMode, "verbose")) {
360
+ lines.push("");
361
+ appendIndexNoteCandidates(lines, result.indexNoteCandidates, "recommended_indexes");
362
+ }
363
+ if (responseModeAtLeast(responseMode, "verbose")) {
364
+ await appendAutoProjectHealth(lines);
365
+ }
366
+ return textResult(lines.join("\n"));
367
+ });
368
+ server.tool("search_notes", "ローカルの markdown ノートを検索します。", {
369
+ query: z.string().min(1),
370
+ limit: z.number().int().min(1).max(50).optional().describe("最大件数 (default: 8)"),
371
+ after_date: z.string().optional().describe("YYYY-MM-DD 形式。更新日で絞り込み"),
372
+ response_mode: responseModeSchema,
373
+ }, async ({ query, limit, after_date, response_mode }) => {
374
+ const responseMode = normalizeResponseMode(response_mode);
375
+ const normalizedAfterDate = normalizeDateInput(after_date);
376
+ if (after_date && !normalizedAfterDate) {
377
+ return textResult(`after_date の形式が不正です: ${after_date} (YYYY-MM-DD)`);
378
+ }
379
+ const result = await store.searchNotes({
380
+ query,
381
+ limit: limit ?? 8,
382
+ afterDate: normalizedAfterDate,
383
+ });
384
+ const firstIndexLike = result.results.find((item) => item.indexLike);
385
+ const summary = summarizeSearchResponse({
386
+ resultCount: result.results.length,
387
+ firstResultTitle: result.results[0]?.title,
388
+ hasIndexLikeResult: Boolean(firstIndexLike),
389
+ firstIndexLikeTitle: firstIndexLike?.title,
390
+ indexCandidateCount: result.indexNoteCandidates.length,
391
+ firstIndexCandidateTitle: result.indexNoteCandidates[0]?.title,
392
+ });
393
+ const lines = [];
394
+ lines.push(`検索クエリ: ${query}`);
395
+ lines.push(`対象プロジェクト: ${result.project}`);
396
+ appendStorageContext(lines);
397
+ appendScopeLabel(lines, TOOL_SCOPE_LABELS.search_notes);
398
+ lines.push(`response_mode: ${responseMode}`);
399
+ appendReadResponseSummary(lines, summary);
400
+ lines.push(`ヒット件数: ${result.results.length}`);
401
+ lines.push(`exact_identifier_matches: ${result.exactIdentifierMatchCount}`);
402
+ lines.push("");
403
+ if (result.results.length === 0) {
404
+ lines.push("候補が見つかりませんでした。");
405
+ }
406
+ else {
407
+ result.results.forEach((item, index) => {
408
+ lines.push(`${index + 1}. ${item.title}`);
409
+ lines.push(` score: ${item.score}`);
410
+ lines.push(` 抜粋: ${preview(item.content, config.previewLength)}`);
411
+ if (responseModeAtLeast(responseMode, "standard")) {
412
+ lines.push(` permalink: ${item.permalink}`);
413
+ lines.push(` file: ${item.filePath}`);
414
+ lines.push(` exact_identifier_match: ${item.exactIdentifierMatch ? "yes" : "no"}`);
415
+ lines.push(` index_like: ${item.indexLike ? "yes" : "no"}`);
416
+ }
417
+ if (responseModeAtLeast(responseMode, "verbose")) {
418
+ lines.push(` index_like_reasons: ${item.indexLike && item.indexReasons.length > 0 ? item.indexReasons.join(", ") : "(none)"}`);
419
+ }
420
+ });
421
+ }
422
+ if (responseModeAtLeast(responseMode, "verbose")) {
423
+ lines.push("");
424
+ appendIndexNoteCandidates(lines, result.indexNoteCandidates, "recommended_indexes");
425
+ }
426
+ if (responseModeAtLeast(responseMode, "standard")) {
427
+ appendExplorationGuidance(lines, result.explorationGuidance);
428
+ }
429
+ return textResult(lines.join("\n"));
430
+ });
431
+ server.tool("read_note", "ノートを identifier (title / permalink / relative path) で読み取ります。", {
432
+ identifier: z.string().min(1),
433
+ response_mode: responseModeSchema,
434
+ }, async ({ identifier, response_mode }) => {
435
+ const responseMode = normalizeResponseMode(response_mode);
436
+ try {
437
+ const result = await store.readNote(identifier);
438
+ const summary = summarizeReadNoteResponse({
439
+ indexLike: result.indexLike,
440
+ unresolvedWikiLinkCount: result.unresolvedWikiLinks.length,
441
+ boundaryWarningCount: result.boundaryWarnings.length,
442
+ orphanWarning: result.orphanWarning,
443
+ backlinkCount: result.backlinkCount,
444
+ clarityAttention: result.documentClarity.status === "attention",
445
+ indexCandidateTitle: result.indexNoteCandidates[0]?.title,
446
+ });
447
+ const changeTrigger = summarizeReadChangeTrigger({
448
+ unresolvedWikiLinkCount: result.unresolvedWikiLinks.length,
449
+ boundaryWarningCount: result.boundaryWarnings.length,
450
+ orphanWarning: result.orphanWarning,
451
+ clarityAttention: result.documentClarity.status === "attention",
452
+ indexCandidateAvailable: result.indexNoteCandidates.length > 0,
453
+ });
454
+ const lines = [
455
+ `identifier: ${identifier}`,
456
+ `project: ${result.project}`,
457
+ `storage_backend: ${config.github ? "github" : "filesystem"}`,
458
+ `storage_root: ${config.root}`,
459
+ `scope_label: ${TOOL_SCOPE_LABELS.read_note}`,
460
+ `response_mode: ${responseMode}`,
461
+ `primary_navigation_signal: ${summary.primaryNavigationSignal}`,
462
+ `primary_quality_signal: ${summary.primaryQualitySignal}`,
463
+ `next_recommended_action: ${summary.nextRecommendedAction}`,
464
+ `file: ${result.note.relativePath}`,
465
+ `permalink: ${result.note.permalink}`,
466
+ ];
467
+ if (config.github) {
468
+ lines.splice(4, 0, `storage_repo: ${config.github.owner}/${config.github.repo}`, `storage_branch: ${config.github.branch}`);
469
+ }
470
+ if (summary.nextRecommendedTarget) {
471
+ insertBeforeLine(lines, "next_recommended_action:", `next_recommended_target: ${summary.nextRecommendedTarget}`);
472
+ }
473
+ appendChangeTriggerSummary(lines, changeTrigger);
474
+ appendResponsibilityWarning(lines, result.boundaryWarnings);
475
+ appendBoundaryWarnings(lines, result.boundaryWarnings);
476
+ if (responseModeAtLeast(responseMode, "standard")) {
477
+ lines.push(`link_health: ${result.linkHealth.resolved}/${result.linkHealth.total} resolved`);
478
+ lines.push(`backlinks: ${result.backlinkCount}`);
479
+ lines.push(`orphan_warning: ${result.orphanWarning ? "yes" : "no"}`);
480
+ appendDocumentClarity(lines, result.documentClarity, responseModeAtLeast(responseMode, "verbose"));
481
+ appendUnresolvedWikiLinks(lines, result.unresolvedWikiLinks);
482
+ }
483
+ if (responseModeAtLeast(responseMode, "verbose")) {
484
+ appendIndexLike(lines, result.indexLike, result.indexReasons);
485
+ appendIndexNoteCandidates(lines, result.indexNoteCandidates);
486
+ appendUnresolvedLinkHints(lines, result.unresolvedLinkHints);
487
+ }
488
+ lines.push("");
489
+ lines.push("--- note ---");
490
+ lines.push(result.note.raw);
491
+ return textResult(lines.join("\n"));
492
+ }
493
+ catch (error) {
494
+ let fallback;
495
+ try {
496
+ fallback = await store.suggestNotes({
497
+ query: identifier,
498
+ limit: 5,
499
+ });
500
+ }
501
+ catch {
502
+ fallback = undefined;
503
+ }
504
+ const lines = [];
505
+ lines.push(`read_note に失敗: ${normalizeError(error)}`);
506
+ appendStorageContext(lines);
507
+ appendScopeLabel(lines, TOOL_SCOPE_LABELS.read_note);
508
+ lines.push(`response_mode: ${responseMode}`);
509
+ lines.push("近い候補:");
510
+ if (!fallback || fallback.results.length === 0) {
511
+ lines.push("- 候補なし");
512
+ }
513
+ else {
514
+ fallback.results.forEach((item, index) => {
515
+ lines.push(`${index + 1}. ${item.title}`);
516
+ lines.push(` score: ${item.score}`);
517
+ lines.push(` permalink: ${item.permalink}`);
518
+ lines.push(` file: ${item.filePath}`);
519
+ lines.push(` exact_identifier_match: ${item.exactIdentifierMatch ? "yes" : "no"}`);
520
+ });
521
+ }
522
+ return textResult(lines.join("\n"));
523
+ }
524
+ });
525
+ server.tool("resolve_links", "ノート内の WikiLink を解決し、リンク先の存在状況を返します。", {
526
+ identifier: z.string().min(1),
527
+ response_mode: responseModeSchema,
528
+ }, async ({ identifier, response_mode }) => {
529
+ const responseMode = normalizeResponseMode(response_mode);
530
+ const result = await store.resolveLinks({
531
+ identifier,
532
+ });
533
+ const unresolvedLinkCount = result.links.filter((link) => !link.resolved).length;
534
+ const summary = summarizeResolveLinksResponse({
535
+ indexLike: result.indexLike,
536
+ unresolvedLinkCount,
537
+ boundaryWarningCount: result.boundaryWarnings.length,
538
+ indexCandidateTitle: result.indexNoteCandidates[0]?.title,
539
+ });
540
+ const lines = [];
541
+ lines.push(`identifier: ${identifier}`);
542
+ lines.push(`project: ${result.project}`);
543
+ appendStorageContext(lines);
544
+ appendScopeLabel(lines, TOOL_SCOPE_LABELS.resolve_links);
545
+ lines.push(`response_mode: ${responseMode}`);
546
+ appendReadResponseSummary(lines, summary);
547
+ appendResponsibilityWarning(lines, result.boundaryWarnings);
548
+ lines.push(`file: ${result.note.relativePath}`);
549
+ lines.push(`wikilinks: ${result.links.length}`);
550
+ if (responseModeAtLeast(responseMode, "verbose")) {
551
+ appendIndexLike(lines, result.indexLike, result.indexReasons);
552
+ }
553
+ appendBoundaryWarnings(lines, result.boundaryWarnings);
554
+ lines.push("");
555
+ if (result.links.length === 0) {
556
+ lines.push("WikiLink は見つかりませんでした。");
557
+ }
558
+ else {
559
+ result.links.forEach((link, index) => {
560
+ lines.push(`${index + 1}. ${link.raw}`);
561
+ if (link.resolved) {
562
+ lines.push(` resolved: yes`);
563
+ lines.push(` to: ${link.resolvedTitle} (${link.resolvedFilePath})`);
564
+ }
565
+ else {
566
+ lines.push(` resolved: no`);
567
+ lines.push(` reason: ${link.reason ?? "unknown"}`);
568
+ lines.push(` target: ${link.target}`);
569
+ }
570
+ });
571
+ }
572
+ if (responseModeAtLeast(responseMode, "verbose")) {
573
+ lines.push("");
574
+ appendIndexNoteCandidates(lines, result.indexNoteCandidates);
575
+ }
576
+ return textResult(lines.join("\n"));
577
+ });
578
+ server.tool("list_backlinks", "指定ノートへのバックリンク一覧を返します。", {
579
+ identifier: z.string().min(1),
580
+ limit: z.number().int().min(1).max(100).optional().describe("最大件数 (default: 20)"),
581
+ response_mode: responseModeSchema,
582
+ }, async ({ identifier, limit, response_mode }) => {
583
+ const responseMode = normalizeResponseMode(response_mode);
584
+ const result = await store.listBacklinks({
585
+ identifier,
586
+ limit: limit ?? 20,
587
+ });
588
+ const summary = summarizeBacklinksResponse({
589
+ indexLike: result.indexLike,
590
+ backlinkCount: result.backlinks.length,
591
+ boundaryWarningCount: result.boundaryWarnings.length,
592
+ firstBacklinkTitle: result.backlinks[0]?.title,
593
+ indexCandidateTitle: result.indexNoteCandidates[0]?.title,
594
+ });
595
+ const lines = [];
596
+ lines.push(`target: ${result.target.title}`);
597
+ lines.push(`project: ${result.project}`);
598
+ appendStorageContext(lines);
599
+ appendScopeLabel(lines, TOOL_SCOPE_LABELS.list_backlinks);
600
+ lines.push(`response_mode: ${responseMode}`);
601
+ appendReadResponseSummary(lines, summary);
602
+ appendResponsibilityWarning(lines, result.boundaryWarnings);
603
+ if (responseModeAtLeast(responseMode, "verbose")) {
604
+ appendIndexLike(lines, result.indexLike, result.indexReasons, "target");
605
+ }
606
+ appendBoundaryWarnings(lines, result.boundaryWarnings);
607
+ lines.push(`backlinks: ${result.backlinks.length}`);
608
+ lines.push("");
609
+ if (result.backlinks.length === 0) {
610
+ lines.push("バックリンクは見つかりませんでした。");
611
+ }
612
+ else {
613
+ result.backlinks.forEach((item, index) => {
614
+ lines.push(`${index + 1}. ${item.title}`);
615
+ lines.push(` count: ${item.count}`);
616
+ if (responseModeAtLeast(responseMode, "standard")) {
617
+ lines.push(` file: ${item.filePath}`);
618
+ lines.push(` updated: ${item.updated}`);
619
+ }
620
+ item.examples.forEach((example) => {
621
+ lines.push(` example: ${example}`);
622
+ });
623
+ });
624
+ }
625
+ if (responseModeAtLeast(responseMode, "verbose")) {
626
+ lines.push("");
627
+ appendIndexNoteCandidates(lines, result.indexNoteCandidates);
628
+ }
629
+ return textResult(lines.join("\n"));
630
+ });
631
+ server.tool("context_bundle", "指定ノートを中心に、関連ノートを優先度付きで返します。", {
632
+ identifier: z.string().min(1),
633
+ limit: z.number().int().min(1).max(30).optional().describe("最大件数 (default: 8)"),
634
+ response_mode: responseModeSchema,
635
+ }, async ({ identifier, limit, response_mode }) => {
636
+ const responseMode = normalizeResponseMode(response_mode);
637
+ const result = await store.contextBundle({
638
+ identifier,
639
+ limit: limit ?? 8,
640
+ });
641
+ const summary = summarizeContextBundleResponse({
642
+ sourceIndexLike: result.source.indexLike,
643
+ bundleItemCount: result.items.length,
644
+ boundaryWarningCount: result.source.boundaryWarnings.length,
645
+ firstBundleItemTitle: result.items[0]?.title,
646
+ indexCandidateTitle: result.indexNoteCandidates[0]?.title,
647
+ });
648
+ const lines = [];
649
+ lines.push(`source: ${result.source.title}`);
650
+ lines.push(`project: ${result.project}`);
651
+ appendStorageContext(lines);
652
+ appendScopeLabel(lines, TOOL_SCOPE_LABELS.context_bundle);
653
+ lines.push(`response_mode: ${responseMode}`);
654
+ appendReadResponseSummary(lines, summary);
655
+ appendResponsibilityWarning(lines, result.source.boundaryWarnings);
656
+ if (responseModeAtLeast(responseMode, "standard")) {
657
+ lines.push(`memory_kind: ${result.source.memoryKind}`);
658
+ lines.push(`file: ${result.source.filePath}`);
659
+ }
660
+ if (responseModeAtLeast(responseMode, "verbose")) {
661
+ appendIndexLike(lines, result.source.indexLike, result.source.indexReasons, "source");
662
+ }
663
+ appendBoundaryWarnings(lines, result.source.boundaryWarnings);
664
+ lines.push(`bundle_items: ${result.items.length}`);
665
+ lines.push("");
666
+ if (result.items.length === 0) {
667
+ lines.push("関連ノートは見つかりませんでした。");
668
+ }
669
+ else {
670
+ result.items.forEach((item, index) => {
671
+ lines.push(`${index + 1}. ${item.title}`);
672
+ lines.push(` score: ${item.score}`);
673
+ if (responseModeAtLeast(responseMode, "standard")) {
674
+ lines.push(` memory_kind: ${item.memoryKind}`);
675
+ lines.push(` file: ${item.filePath}`);
676
+ }
677
+ if (responseModeAtLeast(responseMode, "verbose")) {
678
+ lines.push(` reasons: ${item.reasons.join(", ")}`);
679
+ }
680
+ });
681
+ }
682
+ if (responseModeAtLeast(responseMode, "verbose")) {
683
+ lines.push("");
684
+ appendIndexNoteCandidates(lines, result.indexNoteCandidates);
685
+ }
686
+ if (responseModeAtLeast(responseMode, "standard")) {
687
+ appendExplorationGuidance(lines, result.explorationGuidance);
688
+ }
689
+ return textResult(lines.join("\n"));
690
+ });
691
+ server.tool("memory_contract", "kioq の Memory Contract(構造化ルール)を返します。", {
692
+ response_mode: responseModeSchema,
693
+ }, async ({ response_mode }) => {
694
+ const responseMode = normalizeResponseMode(response_mode);
695
+ const plan = memoryContractResponsePlan(responseMode);
696
+ const summary = {
697
+ ...summarizeMemoryContractResponse(),
698
+ ...memoryContractResponseModeHint(responseMode),
699
+ };
700
+ const contract = store.getMemoryContract();
701
+ const lines = [];
702
+ appendStorageContext(lines);
703
+ appendScopeLabel(lines, TOOL_SCOPE_LABELS.memory_contract);
704
+ lines.push(`response_mode: ${responseMode}`);
705
+ appendAuditResponseSummary(lines, summary);
706
+ lines.push(`memory_contract_version: ${contract.version}`);
707
+ lines.push(`required_frontmatter: ${contract.requiredFrontmatter.join(", ")}`);
708
+ lines.push(`flow_required_frontmatter: ${contract.flowRequiredFrontmatter.join(", ")}`);
709
+ lines.push(`parent_markers: ${contract.parentLinkMarkers.join(", ")}`);
710
+ lines.push(`source_metadata_canonical_field: ${contract.optionalSourceMetadata.canonicalField}`);
711
+ lines.push(`source_metadata_auxiliary_fields: ${contract.optionalSourceMetadata.auxiliaryFields.join(", ")}`);
712
+ lines.push(`index_threshold_score_at_least: ${contract.indexNavigationPolicy.thresholds.scoreAtLeast}`);
713
+ lines.push(`index_threshold_index_sections_at_least: ${contract.indexNavigationPolicy.thresholds.indexSectionsAtLeast}`);
714
+ lines.push(`technical_debt_threshold_stale_flow_days: ${contract.technicalDebtPolicy.thresholds.staleFlowDays}`);
715
+ lines.push("sample_templates_available: stock, flow, index");
716
+ if (!plan.includePolicyRules) {
717
+ return textResult(lines.join("\n"));
718
+ }
719
+ lines.push("requirements:");
720
+ lines.push(`- min_resolved_links: ${contract.requirements.minResolvedLinks}`);
721
+ lines.push(`- min_backlinks: ${contract.requirements.minBacklinks}`);
722
+ lines.push(`- min_parent_links: ${contract.requirements.minParentLinks}`);
723
+ lines.push(`- min_related_links: ${contract.requirements.minRelatedLinks}`);
724
+ lines.push(`- max_unresolved_links: ${contract.requirements.maxUnresolvedLinks}`);
725
+ lines.push(`- min_tags: ${contract.requirements.minTags}`);
726
+ lines.push("flow_requirements:");
727
+ lines.push(`- min_resolved_links: ${contract.flowRequirements.minResolvedLinks}`);
728
+ lines.push(`- min_backlinks: ${contract.flowRequirements.minBacklinks}`);
729
+ lines.push(`- min_parent_links: ${contract.flowRequirements.minParentLinks}`);
730
+ lines.push(`- min_related_links: ${contract.flowRequirements.minRelatedLinks}`);
731
+ lines.push(`- max_unresolved_links: ${contract.flowRequirements.maxUnresolvedLinks}`);
732
+ lines.push(`- min_tags: ${contract.flowRequirements.minTags}`);
733
+ lines.push("optional_source_metadata:");
734
+ lines.push(`- canonical_field: ${contract.optionalSourceMetadata.canonicalField}`);
735
+ lines.push(`- auxiliary_fields: ${contract.optionalSourceMetadata.auxiliaryFields.join(", ")}`);
736
+ contract.optionalSourceMetadata.rules.forEach((rule) => {
737
+ lines.push(`- rule: ${rule}`);
738
+ });
739
+ lines.push("index_navigation_policy:");
740
+ lines.push(`- excluded_memory_kinds: ${contract.indexNavigationPolicy.excludedMemoryKinds.join(", ")}`);
741
+ lines.push(`- threshold_score_at_least: ${contract.indexNavigationPolicy.thresholds.scoreAtLeast}`);
742
+ lines.push(`- threshold_index_sections_at_least: ${contract.indexNavigationPolicy.thresholds.indexSectionsAtLeast}`);
743
+ lines.push(`- configurable_via_env: ${contract.indexNavigationPolicy.configurableVia.env.join(", ")}`);
744
+ lines.push(`- configurable_via_cli: ${contract.indexNavigationPolicy.configurableVia.cli.join(", ")}`);
745
+ if (plan.includePolicySignals) {
746
+ contract.indexNavigationPolicy.signals.forEach((signal) => {
747
+ lines.push(`- signal: ${signal.code} weight=${signal.weight} description=${signal.description}`);
748
+ });
749
+ }
750
+ contract.indexNavigationPolicy.rules.forEach((rule) => {
751
+ lines.push(`- rule: ${rule}`);
752
+ });
753
+ lines.push("technical_debt_policy:");
754
+ lines.push(`- signals: ${contract.technicalDebtPolicy.signals.join(", ")}`);
755
+ lines.push(`- stale_flow_states: ${contract.technicalDebtPolicy.staleFlowStates.join(", ")}`);
756
+ lines.push(`- threshold_stale_flow_days: ${contract.technicalDebtPolicy.thresholds.staleFlowDays}`);
757
+ lines.push(`- stale_flow_age_bucket_near_threshold: ${contract.technicalDebtPolicy.staleFlowAgeBuckets.nearThreshold}`);
758
+ lines.push(`- stale_flow_age_bucket_aging: ${contract.technicalDebtPolicy.staleFlowAgeBuckets.aging}`);
759
+ lines.push(`- stale_flow_age_bucket_long_stale: ${contract.technicalDebtPolicy.staleFlowAgeBuckets.longStale}`);
760
+ lines.push(`- cleanup_ratio_definition: ${contract.technicalDebtPolicy.cleanupRatioDefinition}`);
761
+ lines.push(`- cleanup_ready_count_definition: ${contract.technicalDebtPolicy.cleanupReadyCountDefinition}`);
762
+ lines.push(`- attention_note_count_definition: ${contract.technicalDebtPolicy.attentionNoteCountDefinition}`);
763
+ lines.push(`- dependency_direction_violation_count_definition: ${contract.technicalDebtPolicy.dependencyDirectionViolationCountDefinition}`);
764
+ lines.push(`- single_use_tag_candidate_count_definition: ${contract.technicalDebtPolicy.singleUseTagCandidateCountDefinition}`);
765
+ lines.push(`- title_body_mismatch_candidate_count_definition: ${contract.technicalDebtPolicy.titleBodyMismatchCandidateCountDefinition}`);
766
+ lines.push(`- unresolved_wikilinks_delta_status: ${contract.technicalDebtPolicy.unresolvedWikilinksDeltaStatus}`);
767
+ lines.push(`- configurable_via_env: ${contract.technicalDebtPolicy.configurableVia.env.join(", ")}`);
768
+ lines.push(`- configurable_via_cli: ${contract.technicalDebtPolicy.configurableVia.cli.join(", ")}`);
769
+ lines.push("response_mode_policy:");
770
+ lines.push(`- supported_read_tools: ${contract.responseModePolicy.supportedTools.read.join(", ")}`);
771
+ lines.push(`- supported_audit_tools: ${contract.responseModePolicy.supportedTools.audit.join(", ")}`);
772
+ lines.push(`- minimal: ${contract.responseModePolicy.modes.minimal}`);
773
+ lines.push(`- standard: ${contract.responseModePolicy.modes.standard}`);
774
+ lines.push(`- verbose: ${contract.responseModePolicy.modes.verbose}`);
775
+ contract.responseModePolicy.rules.forEach((rule) => {
776
+ lines.push(`- rule: ${rule}`);
777
+ });
778
+ if (plan.includeSampleTemplates) {
779
+ lines.push("");
780
+ lines.push("sample_template_stock:");
781
+ lines.push("```md");
782
+ contract.sampleTemplates.stock.forEach((line) => lines.push(line));
783
+ lines.push("```");
784
+ lines.push("");
785
+ lines.push("sample_template_flow:");
786
+ lines.push("```md");
787
+ contract.sampleTemplates.flow.forEach((line) => lines.push(line));
788
+ lines.push("```");
789
+ lines.push("");
790
+ lines.push("sample_template_index:");
791
+ lines.push("```md");
792
+ contract.sampleTemplates.index.forEach((line) => lines.push(line));
793
+ lines.push("```");
794
+ }
795
+ return textResult(lines.join("\n"));
796
+ });
797
+ server.tool("lint_structure", "構造化を促すために、ノート群の問題を診断して優先順位付きで返します。", {
798
+ limit: z.number().int().min(1).max(200).optional().describe("返却する issue 最大件数 (default: 50)"),
799
+ response_mode: responseModeSchema,
800
+ }, async ({ limit, response_mode }) => {
801
+ const responseMode = normalizeResponseMode(response_mode);
802
+ const plan = lintStructureResponsePlan(responseMode);
803
+ const result = await store.lintStructure({
804
+ limit: limit ?? 50,
805
+ });
806
+ const summaryBase = {
807
+ unresolvedWikiLinkCount: result.unresolvedWikiLinkCount,
808
+ memoryContractViolationCount: result.memoryContractViolationCount,
809
+ duplicateWarningCount: result.duplicateWarningCount,
810
+ dependencyDirectionViolationCount: result.technicalDebtSignals.dependencyDirectionViolationCount,
811
+ weakStructureCount: result.weakStructureCount,
812
+ orphanNoteCount: result.orphanNoteCount,
813
+ staleFlowCount: result.technicalDebtSignals.staleFlowCount,
814
+ singleUseTagCandidateCount: result.technicalDebtSignals.singleUseTagCandidateCount,
815
+ titleBodyMismatchCandidateCount: result.technicalDebtSignals.titleBodyMismatchCandidateCount,
816
+ firstIssueTitle: result.issues[0]?.noteTitle,
817
+ };
818
+ const summary = {
819
+ ...summarizeLintStructureResponse(summaryBase),
820
+ ...lintStructureResponseModeHint({
821
+ mode: responseMode,
822
+ unresolvedWikiLinkCount: summaryBase.unresolvedWikiLinkCount,
823
+ memoryContractViolationCount: summaryBase.memoryContractViolationCount,
824
+ duplicateWarningCount: summaryBase.duplicateWarningCount,
825
+ dependencyDirectionViolationCount: summaryBase.dependencyDirectionViolationCount,
826
+ weakStructureCount: summaryBase.weakStructureCount,
827
+ orphanNoteCount: summaryBase.orphanNoteCount,
828
+ staleFlowCount: summaryBase.staleFlowCount,
829
+ singleUseTagCandidateCount: summaryBase.singleUseTagCandidateCount,
830
+ titleBodyMismatchCandidateCount: summaryBase.titleBodyMismatchCandidateCount,
831
+ }),
832
+ };
833
+ const changeTrigger = summarizeLintChangeTrigger({
834
+ unresolvedWikiLinkCount: summaryBase.unresolvedWikiLinkCount,
835
+ memoryContractViolationCount: summaryBase.memoryContractViolationCount,
836
+ duplicateWarningCount: summaryBase.duplicateWarningCount,
837
+ dependencyDirectionViolationCount: summaryBase.dependencyDirectionViolationCount,
838
+ weakStructureCount: summaryBase.weakStructureCount,
839
+ orphanNoteCount: summaryBase.orphanNoteCount,
840
+ staleFlowCount: summaryBase.staleFlowCount,
841
+ singleUseTagCandidateCount: summaryBase.singleUseTagCandidateCount,
842
+ titleBodyMismatchCandidateCount: summaryBase.titleBodyMismatchCandidateCount,
843
+ });
844
+ const lines = [];
845
+ lines.push(`project: ${result.project}`);
846
+ appendStorageContext(lines);
847
+ appendScopeLabel(lines, TOOL_SCOPE_LABELS.lint_structure);
848
+ lines.push(`response_mode: ${responseMode}`);
849
+ appendAuditResponseSummary(lines, summary);
850
+ appendChangeTriggerSummary(lines, changeTrigger);
851
+ lines.push(`notes: ${result.noteCount}`);
852
+ lines.push(`average_structure_score: ${result.averageScore}`);
853
+ lines.push(`grades: A=${result.gradeCounts.A} B=${result.gradeCounts.B} C=${result.gradeCounts.C} D=${result.gradeCounts.D}`);
854
+ lines.push(`unresolved_wikilinks: ${result.unresolvedWikiLinkCount}`);
855
+ lines.push(`orphan_notes: ${result.orphanNoteCount}`);
856
+ lines.push(`duplicate_warnings: ${result.duplicateWarningCount}`);
857
+ lines.push(`dependency_direction_violations: ${result.technicalDebtSignals.dependencyDirectionViolationCount}`);
858
+ lines.push(`weak_structure_notes: ${result.weakStructureCount}`);
859
+ lines.push(`memory_contract_violations: ${result.memoryContractViolationCount}`);
860
+ lines.push(`stale_flow_count: ${result.technicalDebtSignals.staleFlowCount} (days>=${result.technicalDebtSignals.staleFlowDays})`);
861
+ if (plan.includeDebtBreakdown) {
862
+ lines.push(`stale_flow_age_buckets: near_threshold=${result.technicalDebtSignals.staleFlowAgeBuckets.nearThreshold} aging=${result.technicalDebtSignals.staleFlowAgeBuckets.aging} long_stale=${result.technicalDebtSignals.staleFlowAgeBuckets.longStale}`);
863
+ lines.push(`oldest_stale_flow_days: ${result.technicalDebtSignals.oldestStaleFlowDays ?? "(none)"}`);
864
+ lines.push(`cleanup_ratio: ${result.technicalDebtSignals.cleanupRatio}`);
865
+ lines.push(`cleanup_ready_count: ${result.technicalDebtSignals.cleanupReadyCount}`);
866
+ lines.push(`attention_note_count: ${result.technicalDebtSignals.attentionNoteCount}`);
867
+ lines.push(`dependency_direction_violation_count: ${result.technicalDebtSignals.dependencyDirectionViolationCount}`);
868
+ lines.push(`single_use_tag_candidate_count: ${result.technicalDebtSignals.singleUseTagCandidateCount}`);
869
+ lines.push(`title_body_mismatch_candidate_count: ${result.technicalDebtSignals.titleBodyMismatchCandidateCount}`);
870
+ lines.push(`unresolved_wikilinks_delta: unavailable (${result.technicalDebtSignals.unresolvedWikilinksDeltaStatus})`);
871
+ }
872
+ lines.push(`issues: ${result.issues.length}`);
873
+ if (result.issues.length === 0) {
874
+ lines.push("");
875
+ lines.push("問題は見つかりませんでした。");
876
+ }
877
+ else if (plan.includeDetailedIssues) {
878
+ lines.push("");
879
+ result.issues.forEach((issue, index) => {
880
+ lines.push(`${index + 1}. [${issue.severity}] ${issue.category}`);
881
+ lines.push(` note: ${issue.noteTitle}`);
882
+ lines.push(` file: ${issue.notePath}`);
883
+ lines.push(` message: ${issue.message}`);
884
+ lines.push(` suggestion: ${issue.suggestion}`);
885
+ });
886
+ }
887
+ else if (plan.includeCompactIssues) {
888
+ lines.push("");
889
+ lines.push("top_issues:");
890
+ result.issues.forEach((issue, index) => {
891
+ lines.push(`${index + 1}. [${issue.severity}] ${issue.category} :: ${issue.noteTitle}`);
892
+ });
893
+ }
894
+ if (result.orphanRepairQueue.length > 0 && responseMode !== "minimal") {
895
+ lines.push("");
896
+ lines.push("orphan_repair_queue:");
897
+ result.orphanRepairQueue.forEach((item, index) => {
898
+ if (responseMode === "verbose") {
899
+ lines.push(`${index + 1}. ${item.noteTitle}`);
900
+ lines.push(` file: ${item.notePath}`);
901
+ lines.push(` category: ${item.category}`);
902
+ lines.push(` impact: ${item.impact}`);
903
+ if (item.suggestedParent) {
904
+ lines.push(` suggested_parent: ${item.suggestedParent.title} (${item.suggestedParent.permalink})`);
905
+ lines.push(` reasons: ${item.suggestedParent.reasons.join(", ")}`);
906
+ }
907
+ return;
908
+ }
909
+ const suffix = item.suggestedParent
910
+ ? ` -> ${item.suggestedParent.title}`
911
+ : " -> (manual)";
912
+ lines.push(`${index + 1}. ${item.noteTitle} :: ${item.category}${suffix}`);
913
+ });
914
+ }
915
+ return textResult(lines.join("\n"));
916
+ });
917
+ server.tool("write_note", "ローカル markdown ノートを作成/更新します。", {
918
+ title: z.string().min(1),
919
+ content: z.string().min(1),
920
+ directory: z.string().min(1).optional().describe("default: KIOQ_DEFAULT_DIRECTORY または Inbox"),
921
+ tags: z.array(z.string()).optional(),
922
+ note_type: z.string().optional().describe("例: note / decision / task"),
923
+ }, async ({ title, content, directory, tags, note_type }) => {
924
+ const result = await store.writeNote({
925
+ title,
926
+ content,
927
+ directory,
928
+ tags,
929
+ noteType: note_type,
930
+ });
931
+ const summary = summarizeWriteNoteResponse({
932
+ operation: result.operation,
933
+ unresolvedWikiLinkCount: result.unresolvedWikiLinks.length,
934
+ boundaryWarningCount: result.boundaryWarnings.length,
935
+ memoryContractStatus: result.memoryContract.status,
936
+ duplicateWarningCount: result.duplicateWarnings.length,
937
+ orphanWarning: result.orphanWarning,
938
+ title: result.title,
939
+ });
940
+ const lines = [
941
+ "ノートを作成/更新しました。",
942
+ `project: ${result.project}`,
943
+ `scope_label: ${TOOL_SCOPE_LABELS.write_note}`,
944
+ `primary_navigation_signal: ${summary.primaryNavigationSignal}`,
945
+ `primary_quality_signal: ${summary.primaryQualitySignal}`,
946
+ `next_recommended_action: ${summary.nextRecommendedAction}`,
947
+ `operation: ${result.operation}`,
948
+ `file: ${result.relativePath}`,
949
+ `permalink: ${result.permalink}`,
950
+ `title: ${result.title}`,
951
+ `link_health: ${result.linkHealth.resolved}/${result.linkHealth.total} resolved`,
952
+ `backlinks: ${result.backlinkCount}`,
953
+ `orphan_warning: ${result.orphanWarning ? "yes" : "no"}`,
954
+ ];
955
+ lines.splice(2, 0, ...[
956
+ `storage_backend: ${config.github ? "github" : "filesystem"}`,
957
+ `storage_root: ${config.root}`,
958
+ ...(config.github
959
+ ? [`storage_repo: ${config.github.owner}/${config.github.repo}`, `storage_branch: ${config.github.branch}`]
960
+ : []),
961
+ ]);
962
+ if (summary.nextRecommendedTarget) {
963
+ insertBeforeLine(lines, "next_recommended_action:", `next_recommended_target: ${summary.nextRecommendedTarget}`);
964
+ }
965
+ appendConflictSummary(lines, summarizeNoConflict({ serverUpdated: result.serverUpdated }));
966
+ appendResponsibilityWarning(lines, result.boundaryWarnings);
967
+ appendStructureScore(lines, result.structureScore);
968
+ appendMemoryContract(lines, result.memoryContract);
969
+ appendBoundaryWarnings(lines, result.boundaryWarnings);
970
+ appendTemplateHints(lines, {
971
+ primary: "stock",
972
+ alternatives: ["index"],
973
+ reason: "通常ノートとして知識を残すときは stock template を基準にする",
974
+ whenToSwitch: "再訪導線を固定したい入口ノートなら index template に切り替える",
975
+ });
976
+ appendUnresolvedWikiLinks(lines, result.unresolvedWikiLinks);
977
+ appendUnresolvedLinkHints(lines, result.unresolvedLinkHints);
978
+ appendDuplicateWarnings(lines, result.duplicateWarnings);
979
+ await appendAutoProjectHealth(lines);
980
+ return textResult(lines.join("\n"));
981
+ });
982
+ server.tool("write_flow_note", "flow ノートを構造テンプレート付きで作成/更新します。", {
983
+ title: z.string().min(1),
984
+ question: z.string().min(1),
985
+ next_action: z.string().min(1),
986
+ parent_stock: z.string().min(1),
987
+ related: z.array(z.string()).optional().describe("追加の関連リンク先"),
988
+ details: z.string().optional().describe("## Notes に入れる本文"),
989
+ directory: z.string().min(1).optional().describe("default: Flow"),
990
+ tags: z.array(z.string()).optional(),
991
+ flow_state: z.string().optional().describe("capture / active / blocked / done / promoted / dropped"),
992
+ }, async ({ title, question, next_action, parent_stock, related, details, directory, tags, flow_state }) => {
993
+ const result = await store.writeFlowNote({
994
+ title,
995
+ question,
996
+ nextAction: next_action,
997
+ parentStock: parent_stock,
998
+ related,
999
+ details,
1000
+ directory,
1001
+ tags,
1002
+ flowState: flow_state,
1003
+ });
1004
+ const summary = summarizeWriteFlowResponse({
1005
+ operation: result.operation,
1006
+ unresolvedWikiLinkCount: result.unresolvedWikiLinks.length,
1007
+ boundaryWarningCount: result.boundaryWarnings.length,
1008
+ memoryContractStatus: result.memoryContract.status,
1009
+ duplicateWarningCount: result.duplicateWarnings.length,
1010
+ orphanWarning: result.orphanWarning,
1011
+ title: result.title,
1012
+ parentStockResolved: result.parentStockResolved,
1013
+ parentStock: result.parentStock,
1014
+ });
1015
+ const lines = [
1016
+ "flow ノートを作成/更新しました。",
1017
+ `project: ${result.project}`,
1018
+ `scope_label: ${TOOL_SCOPE_LABELS.write_flow_note}`,
1019
+ `primary_navigation_signal: ${summary.primaryNavigationSignal}`,
1020
+ `primary_quality_signal: ${summary.primaryQualitySignal}`,
1021
+ `next_recommended_action: ${summary.nextRecommendedAction}`,
1022
+ `operation: ${result.operation}`,
1023
+ `file: ${result.relativePath}`,
1024
+ `permalink: ${result.permalink}`,
1025
+ `title: ${result.title}`,
1026
+ `flow_state: ${result.flowState}`,
1027
+ `parent_stock: ${result.parentStock}`,
1028
+ `parent_stock_resolved: ${result.parentStockResolved ? "yes" : "no"}`,
1029
+ `link_health: ${result.linkHealth.resolved}/${result.linkHealth.total} resolved`,
1030
+ `backlinks: ${result.backlinkCount}`,
1031
+ `orphan_warning: ${result.orphanWarning ? "yes" : "no"}`,
1032
+ ];
1033
+ lines.splice(2, 0, ...[
1034
+ `storage_backend: ${config.github ? "github" : "filesystem"}`,
1035
+ `storage_root: ${config.root}`,
1036
+ ...(config.github
1037
+ ? [`storage_repo: ${config.github.owner}/${config.github.repo}`, `storage_branch: ${config.github.branch}`]
1038
+ : []),
1039
+ ]);
1040
+ if (summary.nextRecommendedTarget) {
1041
+ insertBeforeLine(lines, "next_recommended_action:", `next_recommended_target: ${summary.nextRecommendedTarget}`);
1042
+ }
1043
+ appendConflictSummary(lines, summarizeNoConflict({ serverUpdated: result.serverUpdated }));
1044
+ appendResponsibilityWarning(lines, result.boundaryWarnings);
1045
+ appendStructureScore(lines, result.structureScore);
1046
+ appendMemoryContract(lines, result.memoryContract);
1047
+ appendBoundaryWarnings(lines, result.boundaryWarnings);
1048
+ appendTemplateHints(lines, {
1049
+ primary: "flow",
1050
+ alternatives: ["stock", "index"],
1051
+ reason: "進行中の問いと next_action を残すときは flow template を基準にする",
1052
+ whenToSwitch: "知識として固まったら stock、再訪入口を作るなら index template を使う",
1053
+ });
1054
+ appendUnresolvedWikiLinks(lines, result.unresolvedWikiLinks);
1055
+ appendUnresolvedLinkHints(lines, result.unresolvedLinkHints);
1056
+ appendDuplicateWarnings(lines, result.duplicateWarnings);
1057
+ await appendAutoProjectHealth(lines);
1058
+ return textResult(lines.join("\n"));
1059
+ });
1060
+ server.tool("promote_to_stock", "flow ノートを stock ノートへ昇格させ、flow 側の状態を promoted に更新します。", {
1061
+ flow_identifier: z.string().min(1),
1062
+ stock_title: z.string().min(1).optional(),
1063
+ directory: z.string().min(1).optional().describe("default: Stock"),
1064
+ tags: z.array(z.string()).optional(),
1065
+ note_type: z.string().optional().describe("default: stock"),
1066
+ }, async ({ flow_identifier, stock_title, directory, tags, note_type }) => {
1067
+ const result = await store.promoteToStock({
1068
+ flowIdentifier: flow_identifier,
1069
+ stockTitle: stock_title,
1070
+ directory,
1071
+ tags,
1072
+ noteType: note_type,
1073
+ });
1074
+ const summary = summarizePromoteResponse({
1075
+ stockTitle: result.stock.title,
1076
+ sourceFlowTitle: result.sourceFlow.title,
1077
+ });
1078
+ const lines = [
1079
+ "flow を stock に昇格しました。",
1080
+ `project: ${result.project}`,
1081
+ `scope_label: ${TOOL_SCOPE_LABELS.promote_to_stock}`,
1082
+ `primary_navigation_signal: ${summary.primaryNavigationSignal}`,
1083
+ `primary_quality_signal: ${summary.primaryQualitySignal}`,
1084
+ `next_recommended_action: ${summary.nextRecommendedAction}`,
1085
+ `source_flow: ${result.sourceFlow.title}`,
1086
+ `source_file: ${result.sourceFlow.relativePath}`,
1087
+ `source_permalink: ${result.sourceFlow.permalink}`,
1088
+ `stock: ${result.stock.title}`,
1089
+ `stock_file: ${result.stock.relativePath}`,
1090
+ `stock_permalink: ${result.stock.permalink}`,
1091
+ `flow_state: ${result.flowState}`,
1092
+ ];
1093
+ lines.splice(2, 0, ...[
1094
+ `storage_backend: ${config.github ? "github" : "filesystem"}`,
1095
+ `storage_root: ${config.root}`,
1096
+ ...(config.github
1097
+ ? [`storage_repo: ${config.github.owner}/${config.github.repo}`, `storage_branch: ${config.github.branch}`]
1098
+ : []),
1099
+ ]);
1100
+ if (summary.nextRecommendedTarget) {
1101
+ insertBeforeLine(lines, "next_recommended_action:", `next_recommended_target: ${summary.nextRecommendedTarget}`);
1102
+ }
1103
+ appendTemplateHints(lines, {
1104
+ primary: "stock",
1105
+ alternatives: ["index"],
1106
+ reason: "昇格後のノートは再利用知識として stock template を基準に保つ",
1107
+ whenToSwitch: "複数ノートの入口にしたいときだけ index template を使う",
1108
+ });
1109
+ await appendAutoProjectHealth(lines);
1110
+ return textResult(lines.join("\n"));
1111
+ });
1112
+ server.tool("append_note", "既存ノートの末尾に追記します。必要なら作成もできます。", {
1113
+ identifier: z.string().min(1),
1114
+ content: z.string().min(1),
1115
+ create_if_missing: z.boolean().optional().describe("true ならノート未存在時に作成"),
1116
+ directory: z.string().min(1).optional().describe("create_if_missing=true 時の作成先"),
1117
+ tags: z.array(z.string()).optional().describe("create_if_missing=true 時の tags"),
1118
+ note_type: z.string().optional().describe("create_if_missing=true 時の type"),
1119
+ }, async ({ identifier, content, create_if_missing, directory, tags, note_type }) => {
1120
+ const result = await store.appendNote({
1121
+ identifier,
1122
+ content,
1123
+ createIfMissing: create_if_missing,
1124
+ directory,
1125
+ tags,
1126
+ noteType: note_type,
1127
+ });
1128
+ const summary = summarizeAppendResponse({
1129
+ operation: result.operation,
1130
+ unresolvedWikiLinkCount: result.unresolvedWikiLinks.length,
1131
+ boundaryWarningCount: result.boundaryWarnings.length,
1132
+ memoryContractStatus: result.memoryContract.status,
1133
+ duplicateWarningCount: result.duplicateWarnings.length,
1134
+ orphanWarning: result.orphanWarning,
1135
+ title: result.title,
1136
+ });
1137
+ const lines = [
1138
+ "ノートを処理しました。",
1139
+ `project: ${result.project}`,
1140
+ `scope_label: ${TOOL_SCOPE_LABELS.append_note}`,
1141
+ `primary_navigation_signal: ${summary.primaryNavigationSignal}`,
1142
+ `primary_quality_signal: ${summary.primaryQualitySignal}`,
1143
+ `next_recommended_action: ${summary.nextRecommendedAction}`,
1144
+ `operation: ${result.operation}`,
1145
+ `file: ${result.relativePath}`,
1146
+ `permalink: ${result.permalink}`,
1147
+ `title: ${result.title}`,
1148
+ `link_health: ${result.linkHealth.resolved}/${result.linkHealth.total} resolved`,
1149
+ `backlinks: ${result.backlinkCount}`,
1150
+ `orphan_warning: ${result.orphanWarning ? "yes" : "no"}`,
1151
+ ];
1152
+ lines.splice(2, 0, ...[
1153
+ `storage_backend: ${config.github ? "github" : "filesystem"}`,
1154
+ `storage_root: ${config.root}`,
1155
+ ...(config.github
1156
+ ? [`storage_repo: ${config.github.owner}/${config.github.repo}`, `storage_branch: ${config.github.branch}`]
1157
+ : []),
1158
+ ]);
1159
+ if (summary.nextRecommendedTarget) {
1160
+ insertBeforeLine(lines, "next_recommended_action:", `next_recommended_target: ${summary.nextRecommendedTarget}`);
1161
+ }
1162
+ appendConflictSummary(lines, summarizeNoConflict({ serverUpdated: result.serverUpdated }));
1163
+ appendResponsibilityWarning(lines, result.boundaryWarnings);
1164
+ appendStructureScore(lines, result.structureScore);
1165
+ appendMemoryContract(lines, result.memoryContract);
1166
+ appendBoundaryWarnings(lines, result.boundaryWarnings);
1167
+ if (result.operation === "created") {
1168
+ appendTemplateHints(lines, {
1169
+ primary: "stock",
1170
+ alternatives: ["index"],
1171
+ reason: "新規作成ノートとしては stock template が最小の出発点になる",
1172
+ whenToSwitch: "入口ノートとして作るなら index template に切り替える",
1173
+ });
1174
+ }
1175
+ appendUnresolvedWikiLinks(lines, result.unresolvedWikiLinks);
1176
+ appendUnresolvedLinkHints(lines, result.unresolvedLinkHints);
1177
+ appendDuplicateWarnings(lines, result.duplicateWarnings);
1178
+ await appendAutoProjectHealth(lines);
1179
+ return textResult(lines.join("\n"));
1180
+ });
1181
+ server.tool("delete_note", "ノートを削除します。削除影響のリンク情報も返します。", {
1182
+ identifier: z.string().min(1),
1183
+ }, async ({ identifier }) => {
1184
+ const result = await store.deleteNote({
1185
+ identifier,
1186
+ });
1187
+ const projectUnresolvedDelta = result.projectLinkHealthAfter.unresolved - result.projectLinkHealthBefore.unresolved;
1188
+ const impact = summarizeDeleteImpact({
1189
+ projectUnresolvedDelta,
1190
+ backlinksToDeleted: result.backlinksToDeleted,
1191
+ });
1192
+ const summary = summarizeDeleteResponse({
1193
+ unresolvedWikiLinkCount: result.unresolvedWikiLinks.length,
1194
+ projectUnresolvedDelta,
1195
+ backlinksToDeleted: result.backlinksToDeleted,
1196
+ deletedTitle: result.title,
1197
+ });
1198
+ const lines = [
1199
+ "ノートを削除しました。",
1200
+ `project: ${result.project}`,
1201
+ `scope_label: ${TOOL_SCOPE_LABELS.delete_note}`,
1202
+ `primary_navigation_signal: ${summary.primaryNavigationSignal}`,
1203
+ `primary_quality_signal: ${summary.primaryQualitySignal}`,
1204
+ `next_recommended_action: ${summary.nextRecommendedAction}`,
1205
+ `deleted: ${result.title} (${result.relativePath})`,
1206
+ `permalink: ${result.permalink}`,
1207
+ `backlinks_to_deleted: ${result.backlinksToDeleted}`,
1208
+ `deleted_note_link_health_before: ${result.deletedNoteLinkHealth.resolved}/${result.deletedNoteLinkHealth.total}`,
1209
+ `project_link_health_before: ${result.projectLinkHealthBefore.resolved}/${result.projectLinkHealthBefore.total}`,
1210
+ `project_link_health_after: ${result.projectLinkHealthAfter.resolved}/${result.projectLinkHealthAfter.total}`,
1211
+ `project_unresolved_delta: ${projectUnresolvedDelta}`,
1212
+ ];
1213
+ lines.splice(2, 0, ...[
1214
+ `storage_backend: ${config.github ? "github" : "filesystem"}`,
1215
+ `storage_root: ${config.root}`,
1216
+ ...(config.github
1217
+ ? [`storage_repo: ${config.github.owner}/${config.github.repo}`, `storage_branch: ${config.github.branch}`]
1218
+ : []),
1219
+ ]);
1220
+ if (summary.nextRecommendedTarget) {
1221
+ insertBeforeLine(lines, "next_recommended_action:", `next_recommended_target: ${summary.nextRecommendedTarget}`);
1222
+ }
1223
+ appendConflictSummary(lines, summarizeNoConflict({ serverUpdated: result.serverUpdated }));
1224
+ appendOperationImpact(lines, impact);
1225
+ appendStructureScore(lines, result.structureScoreBeforeDelete);
1226
+ appendMemoryContract(lines, result.memoryContractBeforeDelete);
1227
+ appendUnresolvedWikiLinks(lines, result.unresolvedWikiLinks);
1228
+ appendUnresolvedLinkHints(lines, result.unresolvedLinkHints);
1229
+ await appendAutoProjectHealth(lines);
1230
+ return textResult(lines.join("\n"));
1231
+ });
1232
+ server.tool("rename_note", "ノートをリネームし、必要に応じて WikiLink 参照を追従更新します。", {
1233
+ identifier: z.string().min(1),
1234
+ new_title: z.string().min(1),
1235
+ directory: z.string().min(1).optional().describe("新しい相対ディレクトリ"),
1236
+ update_links: z.boolean().optional().describe("default: true"),
1237
+ }, async ({ identifier, new_title, directory, update_links }) => {
1238
+ const result = await store.renameNote({
1239
+ identifier,
1240
+ newTitle: new_title,
1241
+ directory,
1242
+ updateLinks: update_links,
1243
+ });
1244
+ const projectUnresolvedDelta = result.projectLinkHealthAfter.unresolved - result.projectLinkHealthBefore.unresolved;
1245
+ const impact = summarizeRenameImpact({
1246
+ projectUnresolvedDelta,
1247
+ updatedLinks: result.updatedLinks,
1248
+ updatedFiles: result.updatedFiles,
1249
+ backlinkCount: result.backlinkCount,
1250
+ });
1251
+ const summary = summarizeRenameResponse({
1252
+ unresolvedWikiLinkCount: result.unresolvedWikiLinks.length,
1253
+ boundaryWarningCount: 0,
1254
+ memoryContractStatus: result.memoryContract.status,
1255
+ duplicateWarningCount: 0,
1256
+ orphanWarning: result.orphanWarning,
1257
+ title: result.oldTitle,
1258
+ updatedLinks: result.updatedLinks,
1259
+ newTitle: result.newTitle,
1260
+ projectUnresolvedDelta,
1261
+ });
1262
+ const lines = [
1263
+ "ノートをリネームしました。",
1264
+ `project: ${result.project}`,
1265
+ `scope_label: ${TOOL_SCOPE_LABELS.rename_note}`,
1266
+ `primary_navigation_signal: ${summary.primaryNavigationSignal}`,
1267
+ `primary_quality_signal: ${summary.primaryQualitySignal}`,
1268
+ `next_recommended_action: ${summary.nextRecommendedAction}`,
1269
+ `old: ${result.oldTitle} (${result.oldRelativePath})`,
1270
+ `new: ${result.newTitle} (${result.newRelativePath})`,
1271
+ `links_updated: ${result.updatedLinks}`,
1272
+ `files_updated: ${result.updatedFiles}`,
1273
+ `renamed_note_link_health: ${result.renamedNoteLinkHealth.resolved}/${result.renamedNoteLinkHealth.total}`,
1274
+ `backlinks: ${result.backlinkCount}`,
1275
+ `orphan_warning: ${result.orphanWarning ? "yes" : "no"}`,
1276
+ `project_link_health_before: ${result.projectLinkHealthBefore.resolved}/${result.projectLinkHealthBefore.total}`,
1277
+ `project_link_health_after: ${result.projectLinkHealthAfter.resolved}/${result.projectLinkHealthAfter.total}`,
1278
+ `project_unresolved_delta: ${projectUnresolvedDelta}`,
1279
+ ];
1280
+ lines.splice(2, 0, ...[
1281
+ `storage_backend: ${config.github ? "github" : "filesystem"}`,
1282
+ `storage_root: ${config.root}`,
1283
+ ...(config.github
1284
+ ? [`storage_repo: ${config.github.owner}/${config.github.repo}`, `storage_branch: ${config.github.branch}`]
1285
+ : []),
1286
+ ]);
1287
+ if (summary.nextRecommendedTarget) {
1288
+ insertBeforeLine(lines, "next_recommended_action:", `next_recommended_target: ${summary.nextRecommendedTarget}`);
1289
+ }
1290
+ appendConflictSummary(lines, summarizeNoConflict({ serverUpdated: result.serverUpdated }));
1291
+ appendOperationImpact(lines, impact);
1292
+ appendStructureScore(lines, result.structureScore);
1293
+ appendMemoryContract(lines, result.memoryContract);
1294
+ appendUnresolvedWikiLinks(lines, result.unresolvedWikiLinks);
1295
+ appendUnresolvedLinkHints(lines, result.unresolvedLinkHints);
1296
+ await appendAutoProjectHealth(lines);
1297
+ return textResult(lines.join("\n"));
1298
+ });
1299
+ const transport = new StdioServerTransport();
1300
+ await server.connect(transport);
1301
+ }
1302
+ main().catch((error) => {
1303
+ console.error("[kioq] failed to start", error);
1304
+ process.exit(1);
1305
+ });