@ksm0709/context 0.0.35 → 0.0.36
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/cli/index.js +3 -1
- package/dist/index.js +3 -1
- package/dist/mcp.js +139 -15
- package/dist/omc/session-start-hook.js +3 -1
- package/dist/omx/index.mjs +3 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -27,7 +27,7 @@ function resolveContextDir(projectDir) {
|
|
|
27
27
|
// package.json
|
|
28
28
|
var package_default = {
|
|
29
29
|
name: "@ksm0709/context",
|
|
30
|
-
version: "0.0.
|
|
30
|
+
version: "0.0.36",
|
|
31
31
|
author: {
|
|
32
32
|
name: "TaehoKang",
|
|
33
33
|
email: "ksm07091@gmail.com"
|
|
@@ -325,6 +325,8 @@ var DEFAULT_DAILY_NOTE_GUIDE = `# \uB370\uC77C\uB9AC \uB178\uD2B8 \uAE30\uB85D \
|
|
|
325
325
|
var DEFAULT_NOTE_GUIDE = `# \uC9C0\uC2DD \uB178\uD2B8 \uC791\uC131 \uBC0F \uAD00\uB9AC \uAC00\uC774\uB4DC
|
|
326
326
|
|
|
327
327
|
- [ ] **\uB178\uD2B8 \uC0DD\uC131**: \`context_mcp_create_knowledge_note\` \uB3C4\uAD6C\uB97C \uC0AC\uC6A9\uD558\uC5EC \uC0DD\uC131\uD558\uC138\uC694.
|
|
328
|
+
- [ ] \uD15C\uD50C\uB9BF \uBAA8\uB4DC\uC5D0\uC11C\uB294 \uBA3C\uC800 \`.context/templates/<template>.md\`\uB97C \uC77D\uACE0, **\uC644\uC131\uB41C markdown \uC804\uCCB4**\uB97C \`content\`\uB85C \uC804\uB2EC\uD558\uC138\uC694.
|
|
329
|
+
- [ ] \uD15C\uD50C\uB9BF \uBAA8\uB4DC\uC5D0\uC11C\uB294 \`tags\`/\`linked_notes\`\uB97C \uB530\uB85C \uB118\uAE30\uC9C0 \uB9C8\uC138\uC694. \uAD00\uB828 \uB178\uD2B8\uC640 \uBA54\uD0C0\uB370\uC774\uD130\uB294 markdown \uBCF8\uBB38\uC5D0 \uC9C1\uC811 \uC791\uC131\uD574\uC57C \uD569\uB2C8\uB2E4.
|
|
328
330
|
- [ ] \uC81C\uD154\uCE74\uC2A4\uD150(Zettelkasten) 3\uB300 \uC6D0\uCE59 \uC900\uC218:
|
|
329
331
|
- [ ] \uC6D0\uC790\uC131: \uD55C \uB178\uD2B8\uB2F9 \uD55C \uC8FC\uC81C
|
|
330
332
|
- [ ] \uC5F0\uACB0: \uACE0\uB9BD\uB41C \uB178\uD2B8 \uBC29\uC9C0
|
package/dist/index.js
CHANGED
|
@@ -25,7 +25,7 @@ import { join as join2 } from "path";
|
|
|
25
25
|
// package.json
|
|
26
26
|
var package_default = {
|
|
27
27
|
name: "@ksm0709/context",
|
|
28
|
-
version: "0.0.
|
|
28
|
+
version: "0.0.36",
|
|
29
29
|
author: {
|
|
30
30
|
name: "TaehoKang",
|
|
31
31
|
email: "ksm07091@gmail.com"
|
|
@@ -323,6 +323,8 @@ var DEFAULT_DAILY_NOTE_GUIDE = `# \uB370\uC77C\uB9AC \uB178\uD2B8 \uAE30\uB85D \
|
|
|
323
323
|
var DEFAULT_NOTE_GUIDE = `# \uC9C0\uC2DD \uB178\uD2B8 \uC791\uC131 \uBC0F \uAD00\uB9AC \uAC00\uC774\uB4DC
|
|
324
324
|
|
|
325
325
|
- [ ] **\uB178\uD2B8 \uC0DD\uC131**: \`context_mcp_create_knowledge_note\` \uB3C4\uAD6C\uB97C \uC0AC\uC6A9\uD558\uC5EC \uC0DD\uC131\uD558\uC138\uC694.
|
|
326
|
+
- [ ] \uD15C\uD50C\uB9BF \uBAA8\uB4DC\uC5D0\uC11C\uB294 \uBA3C\uC800 \`.context/templates/<template>.md\`\uB97C \uC77D\uACE0, **\uC644\uC131\uB41C markdown \uC804\uCCB4**\uB97C \`content\`\uB85C \uC804\uB2EC\uD558\uC138\uC694.
|
|
327
|
+
- [ ] \uD15C\uD50C\uB9BF \uBAA8\uB4DC\uC5D0\uC11C\uB294 \`tags\`/\`linked_notes\`\uB97C \uB530\uB85C \uB118\uAE30\uC9C0 \uB9C8\uC138\uC694. \uAD00\uB828 \uB178\uD2B8\uC640 \uBA54\uD0C0\uB370\uC774\uD130\uB294 markdown \uBCF8\uBB38\uC5D0 \uC9C1\uC811 \uC791\uC131\uD574\uC57C \uD569\uB2C8\uB2E4.
|
|
326
328
|
- [ ] \uC81C\uD154\uCE74\uC2A4\uD150(Zettelkasten) 3\uB300 \uC6D0\uCE59 \uC900\uC218:
|
|
327
329
|
- [ ] \uC6D0\uC790\uC131: \uD55C \uB178\uD2B8\uB2F9 \uD55C \uC8FC\uC81C
|
|
328
330
|
- [ ] \uC5F0\uACB0: \uACE0\uB9BD\uB41C \uB178\uD2B8 \uBC29\uC9C0
|
package/dist/mcp.js
CHANGED
|
@@ -33093,6 +33093,100 @@ function stripExtension(file2) {
|
|
|
33093
33093
|
return file2.endsWith(".md") ? file2.slice(0, -3) : file2;
|
|
33094
33094
|
}
|
|
33095
33095
|
|
|
33096
|
+
// src/lib/knowledge-note-template-validation.ts
|
|
33097
|
+
var HEADING_REGEX2 = /^(#{1,3})\s+(.+)$/;
|
|
33098
|
+
var ADDITIONAL_FORBIDDEN_SNIPPETS = ["[\uC81C\uBAA9]", "[\uAC04\uB2E8\uD55C \uC124\uBA85]", "TODO"];
|
|
33099
|
+
var RELATED_NOTES_TITLES = ["\uAD00\uB828 \uB178\uD2B8", "Related Notes"];
|
|
33100
|
+
function escapeRegExp(value) {
|
|
33101
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
33102
|
+
}
|
|
33103
|
+
function parseMarkdownHeadings(content) {
|
|
33104
|
+
const lines = content.split(`
|
|
33105
|
+
`);
|
|
33106
|
+
return lines.flatMap((line, index) => {
|
|
33107
|
+
const match = line.match(HEADING_REGEX2);
|
|
33108
|
+
if (!match) {
|
|
33109
|
+
return [];
|
|
33110
|
+
}
|
|
33111
|
+
return [
|
|
33112
|
+
{
|
|
33113
|
+
level: match[1].length,
|
|
33114
|
+
line: index,
|
|
33115
|
+
raw: line.trim(),
|
|
33116
|
+
text: match[2].trim()
|
|
33117
|
+
}
|
|
33118
|
+
];
|
|
33119
|
+
});
|
|
33120
|
+
}
|
|
33121
|
+
function buildHeadingPattern(templateText) {
|
|
33122
|
+
const escaped = escapeRegExp(templateText).replace(/\\\[[^\]]+\\\]/g, "(.+)");
|
|
33123
|
+
return new RegExp(`^${escaped}$`);
|
|
33124
|
+
}
|
|
33125
|
+
function headingMatches(template, candidate) {
|
|
33126
|
+
if (template.level !== candidate.level) {
|
|
33127
|
+
return false;
|
|
33128
|
+
}
|
|
33129
|
+
return buildHeadingPattern(template.text).test(candidate.text);
|
|
33130
|
+
}
|
|
33131
|
+
function collectForbiddenSnippets(templateContent) {
|
|
33132
|
+
const snippets = new Set(ADDITIONAL_FORBIDDEN_SNIPPETS);
|
|
33133
|
+
for (const line of templateContent.split(`
|
|
33134
|
+
`)) {
|
|
33135
|
+
const trimmed = line.trim();
|
|
33136
|
+
if (!trimmed) {
|
|
33137
|
+
continue;
|
|
33138
|
+
}
|
|
33139
|
+
const headingMatch = trimmed.match(HEADING_REGEX2);
|
|
33140
|
+
if (headingMatch) {
|
|
33141
|
+
if (trimmed.includes("[") || trimmed.includes("...") || trimmed.includes("TODO")) {
|
|
33142
|
+
snippets.add(trimmed);
|
|
33143
|
+
}
|
|
33144
|
+
continue;
|
|
33145
|
+
}
|
|
33146
|
+
snippets.add(trimmed);
|
|
33147
|
+
}
|
|
33148
|
+
return [...snippets];
|
|
33149
|
+
}
|
|
33150
|
+
function isRelatedNotesHeading(heading) {
|
|
33151
|
+
return RELATED_NOTES_TITLES.includes(heading.text);
|
|
33152
|
+
}
|
|
33153
|
+
function validateTemplatedKnowledgeNoteContent(templateContent, content) {
|
|
33154
|
+
const templateHeadings = parseMarkdownHeadings(templateContent);
|
|
33155
|
+
const contentHeadings = parseMarkdownHeadings(content);
|
|
33156
|
+
const contentLines = content.split(`
|
|
33157
|
+
`);
|
|
33158
|
+
const errors3 = [];
|
|
33159
|
+
const matchedHeadings = [];
|
|
33160
|
+
let searchStart = 0;
|
|
33161
|
+
for (const templateHeading of templateHeadings) {
|
|
33162
|
+
const matchIndex = contentHeadings.findIndex((candidate, index) => index >= searchStart && headingMatches(templateHeading, candidate));
|
|
33163
|
+
if (matchIndex === -1) {
|
|
33164
|
+
errors3.push(`Missing required heading: ${templateHeading.raw}`);
|
|
33165
|
+
continue;
|
|
33166
|
+
}
|
|
33167
|
+
matchedHeadings.push(contentHeadings[matchIndex]);
|
|
33168
|
+
searchStart = matchIndex + 1;
|
|
33169
|
+
}
|
|
33170
|
+
for (const forbiddenSnippet of collectForbiddenSnippets(templateContent)) {
|
|
33171
|
+
if (content.includes(forbiddenSnippet)) {
|
|
33172
|
+
errors3.push(`Template placeholder was not replaced: ${forbiddenSnippet}`);
|
|
33173
|
+
}
|
|
33174
|
+
}
|
|
33175
|
+
matchedHeadings.forEach((heading, index) => {
|
|
33176
|
+
const nextHeadingLine = matchedHeadings[index + 1]?.line ?? contentLines.length;
|
|
33177
|
+
const sectionBody = contentLines.slice(heading.line + 1, nextHeadingLine).join(`
|
|
33178
|
+
`).trim();
|
|
33179
|
+
if (heading.level > 1 && !sectionBody) {
|
|
33180
|
+
errors3.push(`Section is empty: ${heading.raw}`);
|
|
33181
|
+
return;
|
|
33182
|
+
}
|
|
33183
|
+
if (isRelatedNotesHeading(heading) && !/\[\[[^[\]]+\]\]/.test(sectionBody)) {
|
|
33184
|
+
errors3.push(`Related notes section must include at least one wikilink: ${heading.raw}`);
|
|
33185
|
+
}
|
|
33186
|
+
});
|
|
33187
|
+
return { errors: errors3 };
|
|
33188
|
+
}
|
|
33189
|
+
|
|
33096
33190
|
// src/lib/mcp-server.ts
|
|
33097
33191
|
function startMcpServer() {
|
|
33098
33192
|
const server = new McpServer({
|
|
@@ -33283,13 +33377,13 @@ function startMcpServer() {
|
|
|
33283
33377
|
}
|
|
33284
33378
|
});
|
|
33285
33379
|
server.registerTool("create_knowledge_note", {
|
|
33286
|
-
description: "Create a new Zettelkasten knowledge note with frontmatter and wikilinks.
|
|
33380
|
+
description: "Create a new Zettelkasten knowledge note with frontmatter and wikilinks. When you provide `template`, first read `.context/templates/<template>.md` and pass fully completed markdown in `content`. Available templates: adr (Architecture Decision Records), pattern (Design patterns), bug (Bug reports and analysis), gotcha (Pitfalls and gotchas), decision (General decisions), context (General context and background), runbook (Procedures and runbooks), insight (Insights and learnings).",
|
|
33287
33381
|
inputSchema: {
|
|
33288
33382
|
title: exports_external.string().describe("The title of the note"),
|
|
33289
|
-
content: exports_external.string().describe("The main content of the note"),
|
|
33290
|
-
tags: exports_external.array(exports_external.string()).optional().describe("Optional tags for the note"),
|
|
33291
|
-
linked_notes: exports_external.array(exports_external.string()).optional().describe("Optional list of related note titles to link to"),
|
|
33292
|
-
template: exports_external.enum(["adr", "pattern", "bug", "gotcha", "decision", "context", "runbook", "insight"]).optional().describe("Optional template to
|
|
33383
|
+
content: exports_external.string().describe("The main content of the note. When `template` is set, this must be the complete markdown document that already follows the template."),
|
|
33384
|
+
tags: exports_external.array(exports_external.string()).optional().describe("Optional tags for the note. Not supported when `template` is set."),
|
|
33385
|
+
linked_notes: exports_external.array(exports_external.string()).optional().describe("Optional list of related note titles to link to. Not supported when `template` is set; include related notes directly in the markdown content instead."),
|
|
33386
|
+
template: exports_external.enum(["adr", "pattern", "bug", "gotcha", "decision", "context", "runbook", "insight"]).optional().describe("Optional template to validate against. Read the template file first and pass fully completed markdown in `content`.")
|
|
33293
33387
|
}
|
|
33294
33388
|
}, async ({ title, content, tags, linked_notes, template }) => {
|
|
33295
33389
|
try {
|
|
@@ -33300,18 +33394,48 @@ function startMcpServer() {
|
|
|
33300
33394
|
const date6 = new Date().toISOString().split("T")[0];
|
|
33301
33395
|
let fileContent = "";
|
|
33302
33396
|
if (template) {
|
|
33397
|
+
if (tags && tags.length > 0) {
|
|
33398
|
+
return {
|
|
33399
|
+
content: [
|
|
33400
|
+
{
|
|
33401
|
+
type: "text",
|
|
33402
|
+
text: "Error creating knowledge note: `tags` is not supported in template mode. Read the template and include any frontmatter or metadata directly in the markdown content."
|
|
33403
|
+
}
|
|
33404
|
+
],
|
|
33405
|
+
isError: true
|
|
33406
|
+
};
|
|
33407
|
+
}
|
|
33408
|
+
if (linked_notes && linked_notes.length > 0) {
|
|
33409
|
+
return {
|
|
33410
|
+
content: [
|
|
33411
|
+
{
|
|
33412
|
+
type: "text",
|
|
33413
|
+
text: "Error creating knowledge note: `linked_notes` is not supported in template mode. Read the template and include related notes directly in the markdown content."
|
|
33414
|
+
}
|
|
33415
|
+
],
|
|
33416
|
+
isError: true
|
|
33417
|
+
};
|
|
33418
|
+
}
|
|
33303
33419
|
const templatePath = path2.resolve(process.cwd(), `.context/templates/${template}.md`);
|
|
33304
|
-
|
|
33305
|
-
|
|
33306
|
-
|
|
33307
|
-
|
|
33308
|
-
|
|
33309
|
-
|
|
33310
|
-
|
|
33311
|
-
|
|
33312
|
-
|
|
33313
|
-
|
|
33420
|
+
const templateContent = await fs2.readFile(templatePath, "utf-8");
|
|
33421
|
+
const validation = validateTemplatedKnowledgeNoteContent(templateContent, content);
|
|
33422
|
+
if (validation.errors.length > 0) {
|
|
33423
|
+
return {
|
|
33424
|
+
content: [
|
|
33425
|
+
{
|
|
33426
|
+
type: "text",
|
|
33427
|
+
text: `Error creating knowledge note: template content is invalid.
|
|
33428
|
+
- ${validation.errors.join(`
|
|
33429
|
+
- `)}
|
|
33430
|
+
Read the template and provide the fully completed markdown document in \`content\`.`
|
|
33431
|
+
}
|
|
33432
|
+
],
|
|
33433
|
+
isError: true
|
|
33434
|
+
};
|
|
33314
33435
|
}
|
|
33436
|
+
fileContent = content.endsWith(`
|
|
33437
|
+
`) ? content : `${content}
|
|
33438
|
+
`;
|
|
33315
33439
|
} else {
|
|
33316
33440
|
fileContent = `---
|
|
33317
33441
|
`;
|
|
@@ -20,7 +20,7 @@ function resolveContextDir(projectDir) {
|
|
|
20
20
|
// package.json
|
|
21
21
|
var package_default = {
|
|
22
22
|
name: "@ksm0709/context",
|
|
23
|
-
version: "0.0.
|
|
23
|
+
version: "0.0.36",
|
|
24
24
|
author: {
|
|
25
25
|
name: "TaehoKang",
|
|
26
26
|
email: "ksm07091@gmail.com"
|
|
@@ -318,6 +318,8 @@ var DEFAULT_DAILY_NOTE_GUIDE = `# \uB370\uC77C\uB9AC \uB178\uD2B8 \uAE30\uB85D \
|
|
|
318
318
|
var DEFAULT_NOTE_GUIDE = `# \uC9C0\uC2DD \uB178\uD2B8 \uC791\uC131 \uBC0F \uAD00\uB9AC \uAC00\uC774\uB4DC
|
|
319
319
|
|
|
320
320
|
- [ ] **\uB178\uD2B8 \uC0DD\uC131**: \`context_mcp_create_knowledge_note\` \uB3C4\uAD6C\uB97C \uC0AC\uC6A9\uD558\uC5EC \uC0DD\uC131\uD558\uC138\uC694.
|
|
321
|
+
- [ ] \uD15C\uD50C\uB9BF \uBAA8\uB4DC\uC5D0\uC11C\uB294 \uBA3C\uC800 \`.context/templates/<template>.md\`\uB97C \uC77D\uACE0, **\uC644\uC131\uB41C markdown \uC804\uCCB4**\uB97C \`content\`\uB85C \uC804\uB2EC\uD558\uC138\uC694.
|
|
322
|
+
- [ ] \uD15C\uD50C\uB9BF \uBAA8\uB4DC\uC5D0\uC11C\uB294 \`tags\`/\`linked_notes\`\uB97C \uB530\uB85C \uB118\uAE30\uC9C0 \uB9C8\uC138\uC694. \uAD00\uB828 \uB178\uD2B8\uC640 \uBA54\uD0C0\uB370\uC774\uD130\uB294 markdown \uBCF8\uBB38\uC5D0 \uC9C1\uC811 \uC791\uC131\uD574\uC57C \uD569\uB2C8\uB2E4.
|
|
321
323
|
- [ ] \uC81C\uD154\uCE74\uC2A4\uD150(Zettelkasten) 3\uB300 \uC6D0\uCE59 \uC900\uC218:
|
|
322
324
|
- [ ] \uC6D0\uC790\uC131: \uD55C \uB178\uD2B8\uB2F9 \uD55C \uC8FC\uC81C
|
|
323
325
|
- [ ] \uC5F0\uACB0: \uACE0\uB9BD\uB41C \uB178\uD2B8 \uBC29\uC9C0
|
package/dist/omx/index.mjs
CHANGED
|
@@ -105,7 +105,7 @@ import { join as join3 } from "node:path";
|
|
|
105
105
|
// package.json
|
|
106
106
|
var package_default = {
|
|
107
107
|
name: "@ksm0709/context",
|
|
108
|
-
version: "0.0.
|
|
108
|
+
version: "0.0.36",
|
|
109
109
|
author: {
|
|
110
110
|
name: "TaehoKang",
|
|
111
111
|
email: "ksm07091@gmail.com"
|
|
@@ -403,6 +403,8 @@ var DEFAULT_DAILY_NOTE_GUIDE = `# 데일리 노트 기록 가이드
|
|
|
403
403
|
var DEFAULT_NOTE_GUIDE = `# 지식 노트 작성 및 관리 가이드
|
|
404
404
|
|
|
405
405
|
- [ ] **노트 생성**: \`context_mcp_create_knowledge_note\` 도구를 사용하여 생성하세요.
|
|
406
|
+
- [ ] 템플릿 모드에서는 먼저 \`.context/templates/<template>.md\`를 읽고, **완성된 markdown 전체**를 \`content\`로 전달하세요.
|
|
407
|
+
- [ ] 템플릿 모드에서는 \`tags\`/\`linked_notes\`를 따로 넘기지 마세요. 관련 노트와 메타데이터는 markdown 본문에 직접 작성해야 합니다.
|
|
406
408
|
- [ ] 제텔카스텐(Zettelkasten) 3대 원칙 준수:
|
|
407
409
|
- [ ] 원자성: 한 노트당 한 주제
|
|
408
410
|
- [ ] 연결: 고립된 노트 방지
|