@kaddo/mcp 3.32.0 → 3.34.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 +73 -22
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2991,6 +2991,24 @@ function serializeDriftJson(r) {
2991
2991
  }
2992
2992
 
2993
2993
  // ../cli/src/core/open-questions.ts
2994
+ var RESOLUTION_TOKENS = {
2995
+ open: "open",
2996
+ resolved: "resolved",
2997
+ assumed: "assumed",
2998
+ deferred: "deferred",
2999
+ abierta: "open",
3000
+ resuelta: "resolved",
3001
+ asumida: "assumed",
3002
+ diferida: "deferred"
3003
+ };
3004
+ function parseResolution(line) {
3005
+ const m = line.match(/^\[([a-zA-Záéí]+)\]\s*(.*)$/);
3006
+ if (m) {
3007
+ const status = RESOLUTION_TOKENS[m[1].toLowerCase()];
3008
+ if (status) return { text: m[2].trim(), resolution_status: status };
3009
+ }
3010
+ return { text: line.trim(), resolution_status: "open" };
3011
+ }
2994
3012
  var SOURCES = [
2995
3013
  "knowledge/business/business.md",
2996
3014
  "knowledge/product/product.md",
@@ -3082,10 +3100,17 @@ function extractFromMarkdown(md) {
3082
3100
  for (let i = start + 1; i < lines.length; i++) {
3083
3101
  const line = lines[i];
3084
3102
  if (/^#{1,6}\s+/.test(line)) break;
3103
+ const meta = line.match(/^\s+(?:[-*])\s+(\w+)\s*:\s*(.+?)\s*$/);
3104
+ if (meta && out.length > 0) {
3105
+ if (meta[1].toLowerCase() === "note") out[out.length - 1].resolution_note = meta[2].trim();
3106
+ continue;
3107
+ }
3085
3108
  const m = line.match(/^\s*(?:[-*]|\d+\.)\s+(.+?)\s*$/);
3086
3109
  if (m) {
3087
- const q = m[1].trim();
3088
- if (q && !/^_.*_$/.test(q)) out.push(q);
3110
+ const raw = m[1].trim();
3111
+ if (!raw || /^_.*_$/.test(raw)) continue;
3112
+ const { text: text2, resolution_status } = parseResolution(raw);
3113
+ if (text2) out.push({ text: text2, resolution_status });
3089
3114
  }
3090
3115
  }
3091
3116
  return out;
@@ -3119,29 +3144,37 @@ function buildOpenQuestionsReport(dir, now = /* @__PURE__ */ new Date()) {
3119
3144
  } catch {
3120
3145
  continue;
3121
3146
  }
3122
- for (const q of extractFromMarkdown(md)) {
3147
+ for (const eq of extractFromMarkdown(md)) {
3123
3148
  seq += 1;
3124
- const { classification, reason } = classifyQuestion(q);
3149
+ const { classification, reason } = classifyQuestion(eq.text);
3125
3150
  questions.push({
3126
3151
  id: `OQ-${String(seq).padStart(3, "0")}`,
3127
3152
  source,
3128
3153
  section: "Open Questions",
3129
- question: q,
3154
+ question: eq.text,
3130
3155
  classification,
3156
+ resolution_status: eq.resolution_status,
3131
3157
  reason,
3132
- ...classification === "blocking" ? { suggested_assumption: suggestedAssumption(q) } : {}
3158
+ ...eq.resolution_note ? { resolution_note: eq.resolution_note } : {},
3159
+ ...classification === "blocking" && eq.resolution_status === "open" ? { suggested_assumption: suggestedAssumption(eq.text) } : {}
3133
3160
  });
3134
3161
  }
3135
3162
  }
3136
3163
  const blocking = questions.filter((q) => q.classification === "blocking");
3137
3164
  const important = questions.filter((q) => q.classification === "important");
3138
3165
  const deferred = questions.filter((q) => q.classification === "deferred");
3166
+ const blockingOpen = blocking.filter((q) => q.resolution_status === "open");
3167
+ const importantOpen = important.filter((q) => q.resolution_status === "open");
3168
+ const byStatus = (s) => questions.filter((q) => q.resolution_status === s);
3169
+ const resolved = byStatus("resolved");
3170
+ const assumed = byStatus("assumed");
3171
+ const deferredStatus = byStatus("deferred");
3139
3172
  let readiness;
3140
3173
  if (questions.length === 0) readiness = "unknown";
3141
- else if (blocking.length > 0) readiness = "needs_decisions";
3174
+ else if (blockingOpen.length > 0) readiness = "needs_decisions";
3142
3175
  else readiness = "ready";
3143
- const suggested_assumptions = blocking.map((q) => q.suggested_assumption).filter(Boolean);
3144
- const recommended_next_step = readiness === "needs_decisions" ? "Confirm suggested assumptions with the user (resolve, assume or defer blocking questions) before generating the roadmap." : readiness === "ready" ? "No blocking questions \u2014 you can proceed to the roadmap (review important questions when convenient)." : "No open questions found. Run `kaddo bootstrap` to capture early questions, or proceed.";
3176
+ const suggested_assumptions = blockingOpen.map((q) => q.suggested_assumption).filter(Boolean);
3177
+ const recommended_next_step = readiness === "needs_decisions" ? "Confirm suggested assumptions with the user (resolve, assume or defer blocking open questions) before generating the roadmap." : readiness === "ready" ? "No blocking open questions \u2014 you can proceed to the roadmap. Surfaced assumptions/deferred items are informational." : "No open questions found. Run `kaddo bootstrap` to capture early questions, or proceed.";
3145
3178
  return {
3146
3179
  generated_at: now.toISOString(),
3147
3180
  project,
@@ -3150,12 +3183,23 @@ function buildOpenQuestionsReport(dir, now = /* @__PURE__ */ new Date()) {
3150
3183
  roadmap_readiness: readiness,
3151
3184
  blocking: blocking.length,
3152
3185
  important: important.length,
3153
- deferred: deferred.length
3186
+ deferred: deferred.length,
3187
+ blocking_open: blockingOpen.length,
3188
+ important_open: importantOpen.length,
3189
+ resolution: {
3190
+ open: byStatus("open").length,
3191
+ resolved: resolved.length,
3192
+ assumed: assumed.length,
3193
+ deferred: deferredStatus.length
3194
+ }
3154
3195
  },
3155
3196
  questions,
3156
3197
  blocking_questions: blocking,
3157
3198
  important_questions: important,
3158
3199
  deferred_questions: deferred,
3200
+ resolved_questions: resolved,
3201
+ assumed_questions: assumed,
3202
+ deferred_status_questions: deferredStatus,
3159
3203
  suggested_assumptions,
3160
3204
  recommended_next_step
3161
3205
  };
@@ -3169,18 +3213,18 @@ function renderOpenQuestionsMarkdown(r) {
3169
3213
  L.push("## Summary", "");
3170
3214
  L.push(`- Open questions found: ${r.summary.open_questions}`);
3171
3215
  L.push(`- Roadmap readiness: ${r.summary.roadmap_readiness}`);
3172
- L.push(`- Blocking: ${r.summary.blocking}`);
3173
- L.push(`- Important: ${r.summary.important}`);
3174
- L.push(`- Deferred: ${r.summary.deferred}`);
3216
+ L.push(`- By resolution \u2014 open: ${r.summary.resolution.open}, resolved: ${r.summary.resolution.resolved}, assumed: ${r.summary.resolution.assumed}, deferred: ${r.summary.resolution.deferred}`);
3217
+ L.push(`- Blocking open: ${r.summary.blocking_open}, important open: ${r.summary.important_open}`);
3175
3218
  L.push("");
3176
3219
  if (r.summary.open_questions === 0) {
3177
3220
  L.push("No `## Open Questions` sections found in business / product / codebase / roadmap.", "");
3178
3221
  L.push("## Recommended Next Step", "", r.recommended_next_step, "");
3179
3222
  return L.join("\n");
3180
3223
  }
3181
- L.push("## Blocking Questions", "");
3182
- if (r.blocking_questions.length === 0) L.push("_None._", "");
3183
- for (const q of r.blocking_questions) {
3224
+ const blockingOpen = r.blocking_questions.filter((q) => q.resolution_status === "open");
3225
+ L.push("## Blocking Open Questions", "");
3226
+ if (blockingOpen.length === 0) L.push("_None \u2014 nothing blocks readiness._", "");
3227
+ for (const q of blockingOpen) {
3184
3228
  L.push(`### ${q.id}`, "");
3185
3229
  L.push(`- Source: \`${q.source}\``);
3186
3230
  L.push(`- Question: ${q.question}`);
@@ -3188,13 +3232,18 @@ function renderOpenQuestionsMarkdown(r) {
3188
3232
  if (q.suggested_assumption) L.push(`- Suggested assumption: ${q.suggested_assumption}`);
3189
3233
  L.push("");
3190
3234
  }
3235
+ const renderStatusList = (title, items) => {
3236
+ L.push(`## ${title}`, "");
3237
+ if (items.length === 0) L.push("_None._");
3238
+ for (const q of items) L.push(`- ${q.question}${q.resolution_note ? ` \u2014 _${q.resolution_note}_` : ""}`);
3239
+ L.push("");
3240
+ };
3241
+ renderStatusList("Resolved", r.resolved_questions);
3242
+ renderStatusList("Assumed (decisions to revisit)", r.assumed_questions);
3243
+ renderStatusList("Deferred (out of current scope)", r.deferred_status_questions);
3191
3244
  L.push("## Important Questions", "");
3192
3245
  if (r.important_questions.length === 0) L.push("_None._");
3193
- for (const q of r.important_questions) L.push(`- ${q.question}`);
3194
- L.push("");
3195
- L.push("## Deferred Questions", "");
3196
- if (r.deferred_questions.length === 0) L.push("_None._");
3197
- for (const q of r.deferred_questions) L.push(`- ${q.question}`);
3246
+ for (const q of r.important_questions) L.push(`- [${q.resolution_status}] ${q.question}`);
3198
3247
  L.push("");
3199
3248
  if (r.suggested_assumptions.length > 0) {
3200
3249
  L.push("## Suggested Assumptions", "");
@@ -3212,10 +3261,12 @@ function roadmapReadinessSummary(dir) {
3212
3261
  return {
3213
3262
  roadmap_readiness: r.summary.roadmap_readiness,
3214
3263
  blocking_questions: r.summary.blocking,
3264
+ blocking_open: r.summary.blocking_open,
3215
3265
  important_questions: r.summary.important,
3216
3266
  deferred_questions: r.summary.deferred,
3267
+ resolution: r.summary.resolution,
3217
3268
  suggested_assumptions: r.suggested_assumptions,
3218
- recommended_next_step: r.summary.roadmap_readiness === "needs_decisions" ? "Resolve, assume, or defer blocking questions before generating roadmap." : r.recommended_next_step
3269
+ recommended_next_step: r.summary.roadmap_readiness === "needs_decisions" ? "Resolve, assume, or defer blocking open questions before generating roadmap." : r.recommended_next_step
3219
3270
  };
3220
3271
  }
3221
3272
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/mcp",
3
- "version": "3.32.0",
3
+ "version": "3.34.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": {