@kaddo/mcp 3.112.2 → 3.114.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.
Files changed (2) hide show
  1. package/dist/index.js +26 -41
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -17319,24 +17319,13 @@ ${body}`);
17319
17319
  ${out.join("\n\n")}
17320
17320
  `.replace(/\n{3,}/g, "\n\n");
17321
17321
  }
17322
- function importedBody(title, type, sourceBody) {
17323
- const lines = sourceBody.split(/\r?\n/);
17324
- let i = 0;
17325
- while (i < lines.length && !lines[i].trim()) i++;
17326
- if (i < lines.length && /^#\s+/.test(lines[i])) {
17327
- i++;
17328
- while (i < lines.length && !lines[i].trim()) i++;
17329
- if (i < lines.length && /^>\s*Type:/i.test(lines[i])) i++;
17330
- }
17331
- const rest = lines.slice(i).join("\n").trim();
17332
- const preamble = `# ${title}
17333
-
17334
- > Type: ${type}`;
17335
- return rest ? `${preamble}
17336
-
17337
- ${rest}
17338
- ` : `${preamble}
17339
- `;
17322
+ function ensureH1(body, title) {
17323
+ const trimmed = body.trim();
17324
+ const firstMeaningful = trimmed.split(/\r?\n/).find((l2) => l2.trim());
17325
+ if (firstMeaningful && /^#\s+/.test(firstMeaningful.trim())) return trimmed;
17326
+ return `# ${title}
17327
+
17328
+ ${trimmed}`;
17340
17329
  }
17341
17330
  function serialize(data, body) {
17342
17331
  return matter82.stringify(`
@@ -17372,8 +17361,8 @@ function createWorkItem(dir, opts) {
17372
17361
  if (!type) throw new WorkItemWriteError("INVALID_INPUT", `Unknown Work Item type "${opts.type}".`);
17373
17362
  const id = nextWorkItemId(dir);
17374
17363
  const title = intent.split(/\r?\n/)[0].trim().slice(0, 120);
17375
- const summary = opts.summary?.trim() ? opts.summary.trim() : intent;
17376
17364
  const today22 = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
17365
+ const summary = opts.summary?.trim() || intent;
17377
17366
  const source = opts.source ? { ...opts.source, inferred: false } : { type: "manual", inferred: false };
17378
17367
  const data = {
17379
17368
  type,
@@ -17390,10 +17379,11 @@ function createWorkItem(dir, opts) {
17390
17379
  if (opts.originalSnapshot) data.original_snapshot = opts.originalSnapshot;
17391
17380
  const answers = opts.answers ?? {};
17392
17381
  const hasAnswers = Object.values(answers).some((v) => v?.trim());
17393
- const body = opts.body?.trim() ? importedBody(title, type, opts.body) : hasAnswers ? captureBody(title, type, answers) : freshBody({
17382
+ const providedBody = opts.body?.trim();
17383
+ const body = providedBody ? ensureH1(providedBody, title) : hasAnswers ? captureBody(title, type, answers) : freshBody({
17394
17384
  title,
17395
17385
  type,
17396
- summary: intent,
17386
+ summary,
17397
17387
  scopeUnknowns: [],
17398
17388
  affectedModules: [],
17399
17389
  moduleCoverage: [],
@@ -18123,7 +18113,7 @@ function parseContent(raw) {
18123
18113
  const title = extractTitle(frontmatterFields, bodyText);
18124
18114
  const candidateType = extractType(frontmatterFields);
18125
18115
  const sections = extractSections(bodyText);
18126
- const summary = deriveSummary(bodyText, title);
18116
+ const summary = bodyText || title;
18127
18117
  return {
18128
18118
  format,
18129
18119
  title,
@@ -18143,16 +18133,6 @@ function extractTitle(fields, body) {
18143
18133
  const firstLine = body.split(/\r?\n/).find((l2) => l2.trim());
18144
18134
  return (firstLine?.trim() ?? "Untitled Work Item").slice(0, 120);
18145
18135
  }
18146
- function deriveSummary(body, title) {
18147
- for (const line of body.split(/\r?\n/)) {
18148
- const t = line.trim();
18149
- if (!t) continue;
18150
- if (/^#{1,6}\s/.test(t)) continue;
18151
- if (/^>/.test(t)) continue;
18152
- return t.slice(0, 280);
18153
- }
18154
- return title;
18155
- }
18156
18136
  function extractType(fields) {
18157
18137
  const raw = typeof fields.work_type === "string" && fields.work_type.trim() ? fields.work_type.trim() : typeof fields.type === "string" && fields.type.trim() && fields.type !== "work-item" ? fields.type.trim() : void 0;
18158
18138
  if (!raw) return void 0;
@@ -18181,16 +18161,21 @@ function extractSections(body) {
18181
18161
  flush();
18182
18162
  return sections;
18183
18163
  }
18164
+ function deriveShortSummary(parsed) {
18165
+ const paragraph = parsed.body.split(/\n{2,}/).map((p) => p.trim()).find((p) => p && !/^#{1,6}\s/.test(p) && !/^>/.test(p) && p !== parsed.title);
18166
+ const base = paragraph ? paragraph.replace(/\s+/g, " ") : parsed.title;
18167
+ return base.length > 280 ? `${base.slice(0, 277).trimEnd()}\u2026` : base;
18168
+ }
18184
18169
  function normalizeImportFields(parsed, opts) {
18185
18170
  const discardedFields = [];
18186
18171
  for (const key of Object.keys(parsed.candidateFields)) {
18187
18172
  if (LIFECYCLE_FIELDS.has(key)) discardedFields.push(key);
18188
18173
  }
18189
18174
  const type = opts.userType ? normalizeType(opts.userType) ?? "feature" : parsed.type ?? "feature";
18190
- const intent = parsed.body && parsed.body !== parsed.title ? `${parsed.title}
18191
-
18192
- ${parsed.body}` : parsed.title;
18193
- const body = parsed.body && parsed.body.trim() !== parsed.title.trim() ? parsed.body : void 0;
18175
+ const hasRealBody = !!parsed.body && parsed.body !== parsed.title;
18176
+ const intent = parsed.title;
18177
+ const body = hasRealBody ? parsed.body : void 0;
18178
+ const summary = hasRealBody ? deriveShortSummary(parsed) : parsed.title;
18194
18179
  const source = {
18195
18180
  type: opts.importSource === "chat" ? "chat" : "external",
18196
18181
  imported_at: (/* @__PURE__ */ new Date()).toISOString().split("T")[0]
@@ -18198,14 +18183,14 @@ ${parsed.body}` : parsed.title;
18198
18183
  source.source_format = opts.sourceFormat;
18199
18184
  source.source_hash = opts.sourceHash;
18200
18185
  const snapshot = { title: parsed.title };
18201
- if (parsed.summary !== parsed.title) snapshot.description = parsed.summary;
18186
+ if (summary !== parsed.title) snapshot.description = summary;
18202
18187
  if (typeof parsed.candidateFields.type === "string") snapshot.type = parsed.candidateFields.type;
18203
18188
  if (typeof parsed.candidateFields.status === "string") snapshot.status = parsed.candidateFields.status;
18204
18189
  if (Array.isArray(parsed.candidateFields.labels)) {
18205
18190
  const labels = parsed.candidateFields.labels.filter((l2) => typeof l2 === "string");
18206
18191
  if (labels.length > 0) snapshot.labels = labels;
18207
18192
  }
18208
- return { type, intent, summary: parsed.summary, body, source, snapshot, discardedFields };
18193
+ return { type, intent, summary, body, source, snapshot, discardedFields };
18209
18194
  }
18210
18195
  function computeContentHash(raw) {
18211
18196
  return crypto3.createHash("sha256").update(raw.trim(), "utf-8").digest("hex");
@@ -18291,10 +18276,10 @@ function importWorkItem(dir, opts) {
18291
18276
  const result = createWorkItem(dir, {
18292
18277
  intent: normalized.intent,
18293
18278
  type: normalized.type,
18294
- source: normalized.source,
18295
- originalSnapshot: normalized.snapshot,
18296
18279
  summary: normalized.summary,
18297
- body: normalized.body
18280
+ body: normalized.body,
18281
+ source: normalized.source,
18282
+ originalSnapshot: normalized.snapshot
18298
18283
  });
18299
18284
  let refinementHandoff;
18300
18285
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/mcp",
3
- "version": "3.112.2",
3
+ "version": "3.114.0",
4
4
  "description": "MCP server for Kaddo project knowledge: read-only resources/tools/prompts plus safe derived generation under .kaddo/.",
5
5
  "license": "MIT",
6
6
  "repository": {