@a-company/paradigm 3.23.2 → 3.24.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 (30) hide show
  1. package/dist/{accept-orchestration-ORQRKKGR.js → accept-orchestration-AAYFKS74.js} +5 -5
  2. package/dist/chunk-4UC6AQOC.js +631 -0
  3. package/dist/{chunk-YOFP72IB.js → chunk-6EQRU7WC.js} +4 -4
  4. package/dist/{chunk-K34C7NAN.js → chunk-6UV47VRD.js} +1 -1
  5. package/dist/{chunk-Z42FOOVT.js → chunk-GC6X3YM7.js} +6 -6
  6. package/dist/{chunk-C3BK3E23.js → chunk-OXG5GVDJ.js} +1 -1
  7. package/dist/{chunk-XKAFTZOZ.js → chunk-VHSTF72C.js} +1 -1
  8. package/dist/{chunk-UI3XXVJ6.js → chunk-W4VFKZVF.js} +58 -1
  9. package/dist/{graph-5VSRBRKZ.js → chunk-Z7W7HNRG.js} +2 -1
  10. package/dist/context-audit-RI4R2WRH.js +549 -0
  11. package/dist/{diff-4XJZN4OB.js → diff-QC7PWIPF.js} +5 -5
  12. package/dist/{doctor-FINKMI66.js → doctor-RVODPMHJ.js} +1 -1
  13. package/dist/graph-ERNQQQ7C.js +12 -0
  14. package/dist/index.js +64 -30
  15. package/dist/mcp.js +841 -17
  16. package/dist/{orchestrate-6XGEA655.js → orchestrate-NNNWNELP.js} +8 -8
  17. package/dist/pipeline-3G2FRAKM.js +263 -0
  18. package/dist/{probe-T77FFIAG.js → probe-SN4BNXOC.js} +2 -1
  19. package/dist/{providers-VIBWDN5D.js → providers-NKGY36QF.js} +1 -1
  20. package/dist/{shift-SW3GSODO.js → shift-G42AEUHE.js} +15 -14
  21. package/dist/{spawn-JSV2HST3.js → spawn-52PASJJL.js} +3 -3
  22. package/dist/sweep-5POCF2E4.js +934 -0
  23. package/dist/{team-YIYA4ZLX.js → team-JZHIH7H5.js} +6 -6
  24. package/dist/university-content/courses/.purpose +307 -0
  25. package/dist/university-content/plsat/.purpose +131 -0
  26. package/dist/{workspace-S5Q5LVA6.js → workspace-L27RR5MF.js} +3 -2
  27. package/package.json +1 -1
  28. package/dist/chunk-ZMN3RAIT.js +0 -564
  29. package/dist/{chunk-XNUWLW73.js → chunk-7WTOOH23.js} +0 -0
  30. package/dist/{flow-UFMPVOEM.js → flow-KZKMMXJC.js} +1 -1
package/dist/mcp.js CHANGED
@@ -2026,7 +2026,7 @@ function registerResources(server, getContext2) {
2026
2026
 
2027
2027
  // ../paradigm-mcp/src/tools/index.ts
2028
2028
  import * as os3 from "os";
2029
- import * as path26 from "path";
2029
+ import * as path28 from "path";
2030
2030
  import {
2031
2031
  ListToolsRequestSchema,
2032
2032
  CallToolRequestSchema
@@ -2790,7 +2790,7 @@ function navigateExplore(config, target, rootDir) {
2790
2790
  }
2791
2791
  if (result.paths.length === 0) {
2792
2792
  const areaSymbols = Object.entries(config.symbols).filter(
2793
- ([sym, path27]) => sym.toLowerCase().includes(targetLower) || path27.toLowerCase().includes(targetLower)
2793
+ ([sym, path29]) => sym.toLowerCase().includes(targetLower) || path29.toLowerCase().includes(targetLower)
2794
2794
  ).slice(0, 10);
2795
2795
  result.paths = [...new Set(areaSymbols.map(([, p]) => p))];
2796
2796
  result.symbols = areaSymbols.map(([s]) => s);
@@ -11288,8 +11288,8 @@ function generateRunId() {
11288
11288
  var TEMPLATE_REGEX = /\{\{([^}]+)\}\}/g;
11289
11289
  function interpolate(value, scope) {
11290
11290
  if (typeof value === "string") {
11291
- return value.replace(TEMPLATE_REGEX, (_match, path27) => {
11292
- const resolved = resolvePath(path27.trim(), scope);
11291
+ return value.replace(TEMPLATE_REGEX, (_match, path29) => {
11292
+ const resolved = resolvePath(path29.trim(), scope);
11293
11293
  return resolved !== void 0 ? String(resolved) : _match;
11294
11294
  });
11295
11295
  }
@@ -11322,8 +11322,8 @@ function resolvePath(dotPath, scope) {
11322
11322
  return void 0;
11323
11323
  }
11324
11324
  }
11325
- function deepGet(obj, path27) {
11326
- const parts = path27.split(/[.\[\]]+/).filter(Boolean);
11325
+ function deepGet(obj, path29) {
11326
+ const parts = path29.split(/[.\[\]]+/).filter(Boolean);
11327
11327
  let current = obj;
11328
11328
  for (const part of parts) {
11329
11329
  if (current == null || typeof current !== "object") return void 0;
@@ -11559,11 +11559,11 @@ async function runPersonaObject(rootDir, persona, options) {
11559
11559
  }
11560
11560
  async function runChain(rootDir, chainId, options) {
11561
11561
  const start = Date.now();
11562
- const fs23 = await import("fs");
11563
- const path27 = await import("path");
11564
- const yaml14 = await import("js-yaml");
11565
- const chainPath = path27.join(rootDir, ".paradigm", "personas", "chains", `${chainId}.yaml`);
11566
- if (!fs23.existsSync(chainPath)) {
11562
+ const fs25 = await import("fs");
11563
+ const path29 = await import("path");
11564
+ const yaml15 = await import("js-yaml");
11565
+ const chainPath = path29.join(rootDir, ".paradigm", "personas", "chains", `${chainId}.yaml`);
11566
+ if (!fs25.existsSync(chainPath)) {
11567
11567
  return {
11568
11568
  chain_id: chainId,
11569
11569
  status: "error",
@@ -11572,7 +11572,7 @@ async function runChain(rootDir, chainId, options) {
11572
11572
  duration_ms: Date.now() - start
11573
11573
  };
11574
11574
  }
11575
- const chain = yaml14.load(fs23.readFileSync(chainPath, "utf8"));
11575
+ const chain = yaml15.load(fs25.readFileSync(chainPath, "utf8"));
11576
11576
  let permutation;
11577
11577
  if (options.permutation && chain.permutations) {
11578
11578
  permutation = chain.permutations.find((p) => p.id === options.permutation);
@@ -11676,8 +11676,8 @@ function validateInterpolation(persona) {
11676
11676
  const serialized = JSON.stringify(step);
11677
11677
  const templates = serialized.match(TEMPLATE_REGEX) || [];
11678
11678
  for (const template of templates) {
11679
- const path27 = template.replace("{{", "").replace("}}", "").trim();
11680
- const [namespace, ...rest] = path27.split(".");
11679
+ const path29 = template.replace("{{", "").replace("}}", "").trim();
11680
+ const [namespace, ...rest] = path29.split(".");
11681
11681
  const key = rest.join(".");
11682
11682
  switch (namespace) {
11683
11683
  case "fixtures":
@@ -12939,8 +12939,811 @@ function buildGraphState(rootDir, symbolFilter, groups, links, graphName = "Gene
12939
12939
  };
12940
12940
  }
12941
12941
 
12942
- // ../paradigm-mcp/src/tools/fallback-grep.ts
12942
+ // ../paradigm-mcp/src/tools/heatmap.ts
12943
+ import * as fs23 from "fs";
12943
12944
  import * as path25 from "path";
12945
+ var HEAT_MAP_FILE = ".paradigm/heat-map.json";
12946
+ var CONFIDENCE_DECAY_RATE = 0.05;
12947
+ function getHeatmapToolsList() {
12948
+ return [
12949
+ {
12950
+ name: "paradigm_heatmap_query",
12951
+ description: "Query the adaptive heat map for historically relevant symbols given keywords. Returns associations sorted by confidence.",
12952
+ inputSchema: {
12953
+ type: "object",
12954
+ properties: {
12955
+ keywords: {
12956
+ type: "array",
12957
+ items: { type: "string" },
12958
+ description: "Keywords to search for in the heat map"
12959
+ }
12960
+ },
12961
+ required: ["keywords"]
12962
+ },
12963
+ annotations: {
12964
+ readOnlyHint: true,
12965
+ destructiveHint: false
12966
+ }
12967
+ },
12968
+ {
12969
+ name: "paradigm_heatmap_record",
12970
+ description: "Record a query-to-symbol association in the adaptive heat map. Use positive signal to reinforce, negative to correct.",
12971
+ inputSchema: {
12972
+ type: "object",
12973
+ properties: {
12974
+ keywords: {
12975
+ type: "array",
12976
+ items: { type: "string" },
12977
+ description: "Keywords that relate to the symbols"
12978
+ },
12979
+ symbols: {
12980
+ type: "array",
12981
+ items: { type: "string" },
12982
+ description: "Symbol IDs (with prefix) that are relevant"
12983
+ },
12984
+ aspects: {
12985
+ type: "array",
12986
+ items: { type: "string" },
12987
+ description: "Aspect IDs that are relevant (optional)"
12988
+ },
12989
+ context: {
12990
+ type: "string",
12991
+ description: "Why this association exists"
12992
+ },
12993
+ signal: {
12994
+ type: "string",
12995
+ enum: ["positive", "negative"],
12996
+ description: "Positive reinforces, negative reduces confidence"
12997
+ },
12998
+ correction: {
12999
+ type: "string",
13000
+ description: "Explanation if correcting a wrong association"
13001
+ }
13002
+ },
13003
+ required: ["keywords", "symbols", "signal"]
13004
+ },
13005
+ annotations: {
13006
+ readOnlyHint: false,
13007
+ destructiveHint: false
13008
+ }
13009
+ },
13010
+ {
13011
+ name: "paradigm_heatmap_stats",
13012
+ description: "Show heat map statistics \u2014 total associations, hot/cold keywords, top symbols, session count.",
13013
+ inputSchema: {
13014
+ type: "object",
13015
+ properties: {}
13016
+ },
13017
+ annotations: {
13018
+ readOnlyHint: true,
13019
+ destructiveHint: false
13020
+ }
13021
+ }
13022
+ ];
13023
+ }
13024
+ function loadHeatMap(projectDir2) {
13025
+ const filePath = path25.join(projectDir2, HEAT_MAP_FILE);
13026
+ if (!fs23.existsSync(filePath)) {
13027
+ return {
13028
+ version: "1.0",
13029
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
13030
+ sessionCount: 0,
13031
+ associations: []
13032
+ };
13033
+ }
13034
+ return JSON.parse(fs23.readFileSync(filePath, "utf8"));
13035
+ }
13036
+ function saveHeatMap(projectDir2, heatMap) {
13037
+ const filePath = path25.join(projectDir2, HEAT_MAP_FILE);
13038
+ const dir = path25.dirname(filePath);
13039
+ if (!fs23.existsSync(dir)) fs23.mkdirSync(dir, { recursive: true });
13040
+ heatMap.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
13041
+ fs23.writeFileSync(filePath, JSON.stringify(heatMap, null, 2), "utf8");
13042
+ }
13043
+ async function handleHeatmapQuery(args, projectDir2) {
13044
+ const heatMap = loadHeatMap(projectDir2);
13045
+ const now = Date.now();
13046
+ for (const assoc of heatMap.associations) {
13047
+ const daysSinceHit = (now - new Date(assoc.lastHit).getTime()) / (1e3 * 60 * 60 * 24);
13048
+ const decayPeriods = Math.floor(daysSinceHit / 30);
13049
+ if (decayPeriods > 0) {
13050
+ assoc.confidence = Math.max(
13051
+ 0.01,
13052
+ assoc.confidence * Math.pow(1 - CONFIDENCE_DECAY_RATE, decayPeriods)
13053
+ );
13054
+ }
13055
+ }
13056
+ const queryKeywords = args.keywords.map((k) => k.toLowerCase());
13057
+ const matches = heatMap.associations.filter(
13058
+ (a) => a.keywords.some(
13059
+ (k) => queryKeywords.some((qk) => k.includes(qk) || qk.includes(k))
13060
+ )
13061
+ ).sort((a, b) => b.confidence - a.confidence).slice(0, 10);
13062
+ return JSON.stringify({
13063
+ matches,
13064
+ totalAssociations: heatMap.associations.length
13065
+ });
13066
+ }
13067
+ async function handleHeatmapRecord(args, projectDir2) {
13068
+ const heatMap = loadHeatMap(projectDir2);
13069
+ const queryKeywords = args.keywords.map((k) => k.toLowerCase());
13070
+ const existing = heatMap.associations.find(
13071
+ (a) => a.keywords.some((k) => queryKeywords.includes(k))
13072
+ );
13073
+ if (args.signal === "positive") {
13074
+ if (existing) {
13075
+ existing.confidence = Math.min(1, existing.confidence + 0.05);
13076
+ existing.hitCount += 1;
13077
+ existing.lastHit = (/* @__PURE__ */ new Date()).toISOString();
13078
+ for (const s of args.symbols) {
13079
+ if (!existing.symbols.includes(s)) existing.symbols.push(s);
13080
+ }
13081
+ if (args.aspects) {
13082
+ if (!existing.aspects) existing.aspects = [];
13083
+ for (const a of args.aspects) {
13084
+ if (!existing.aspects.includes(a)) existing.aspects.push(a);
13085
+ }
13086
+ }
13087
+ for (const k of queryKeywords) {
13088
+ if (!existing.keywords.includes(k)) existing.keywords.push(k);
13089
+ }
13090
+ } else {
13091
+ heatMap.associations.push({
13092
+ keywords: queryKeywords,
13093
+ symbols: args.symbols,
13094
+ aspects: args.aspects,
13095
+ confidence: 0.5,
13096
+ hitCount: 1,
13097
+ lastHit: (/* @__PURE__ */ new Date()).toISOString()
13098
+ });
13099
+ }
13100
+ } else {
13101
+ if (existing) {
13102
+ existing.confidence = Math.max(0.01, existing.confidence - 0.15);
13103
+ if (args.correction) {
13104
+ for (const s of args.symbols) {
13105
+ const idx = existing.symbols.indexOf(s);
13106
+ if (idx >= 0) existing.symbols.splice(idx, 1);
13107
+ }
13108
+ }
13109
+ }
13110
+ }
13111
+ saveHeatMap(projectDir2, heatMap);
13112
+ return JSON.stringify({
13113
+ recorded: true,
13114
+ totalAssociations: heatMap.associations.length
13115
+ });
13116
+ }
13117
+ async function handleHeatmapStats(projectDir2) {
13118
+ const heatMap = loadHeatMap(projectDir2);
13119
+ const sorted = [...heatMap.associations].sort(
13120
+ (a, b) => b.confidence - a.confidence
13121
+ );
13122
+ const hot = sorted.filter((a) => a.confidence > 0.7);
13123
+ const cold = sorted.filter((a) => a.confidence < 0.3);
13124
+ return JSON.stringify({
13125
+ totalAssociations: heatMap.associations.length,
13126
+ sessionCount: heatMap.sessionCount,
13127
+ lastUpdated: heatMap.lastUpdated,
13128
+ hotAssociations: hot.slice(0, 5).map((a) => ({
13129
+ keywords: a.keywords,
13130
+ confidence: a.confidence,
13131
+ hitCount: a.hitCount
13132
+ })),
13133
+ coldAssociations: cold.slice(0, 5).map((a) => ({
13134
+ keywords: a.keywords,
13135
+ confidence: a.confidence,
13136
+ hitCount: a.hitCount
13137
+ })),
13138
+ topSymbols: getTopSymbols(heatMap)
13139
+ });
13140
+ }
13141
+ function getTopSymbols(heatMap) {
13142
+ const counts = /* @__PURE__ */ new Map();
13143
+ for (const a of heatMap.associations) {
13144
+ for (const s of a.symbols) {
13145
+ counts.set(s, (counts.get(s) || 0) + a.hitCount);
13146
+ }
13147
+ }
13148
+ return [...counts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 10).map(([symbol, mentions]) => ({ symbol, mentions }));
13149
+ }
13150
+ async function handleHeatmapTool(name, args, ctx) {
13151
+ switch (name) {
13152
+ case "paradigm_heatmap_query": {
13153
+ const text = await handleHeatmapQuery(
13154
+ args,
13155
+ ctx.rootDir
13156
+ );
13157
+ trackToolCall(text.length, name);
13158
+ return { handled: true, text };
13159
+ }
13160
+ case "paradigm_heatmap_record": {
13161
+ const text = await handleHeatmapRecord(
13162
+ args,
13163
+ ctx.rootDir
13164
+ );
13165
+ trackToolCall(text.length, name);
13166
+ return { handled: true, text };
13167
+ }
13168
+ case "paradigm_heatmap_stats": {
13169
+ const text = await handleHeatmapStats(ctx.rootDir);
13170
+ trackToolCall(text.length, name);
13171
+ return { handled: true, text };
13172
+ }
13173
+ default:
13174
+ return { handled: false, text: "" };
13175
+ }
13176
+ }
13177
+
13178
+ // ../paradigm-mcp/src/tools/pipeline.ts
13179
+ import * as fs24 from "fs";
13180
+ import * as path26 from "path";
13181
+ import * as yaml14 from "js-yaml";
13182
+ var STAGE_ORDER = ["specify", "plan", "task", "implement", "validate"];
13183
+ var PIPELINE_DIR = ".paradigm/pipeline";
13184
+ var DEFAULT_TEMPLATES = {
13185
+ "add-feature": {
13186
+ gates: { specify: "manual", plan: "manual", task: "auto", implement: "sentinel", validate: "sentinel" },
13187
+ description: "Standard feature addition with manual spec/plan review"
13188
+ },
13189
+ "bug-fix": {
13190
+ gates: { specify: "auto", plan: "auto", task: "auto", implement: "sentinel", validate: "sentinel" },
13191
+ description: "Quick bug fix with automated gates except validation"
13192
+ },
13193
+ "security-change": {
13194
+ gates: { specify: "manual", plan: "manual", task: "manual", implement: "manual", validate: "manual" },
13195
+ description: "Security-sensitive change with all-manual gates"
13196
+ },
13197
+ "refactor": {
13198
+ gates: { specify: "auto", plan: "manual", task: "auto", implement: "sentinel", validate: "sentinel" },
13199
+ description: "Code refactoring with manual plan review"
13200
+ }
13201
+ };
13202
+ function slugify2(name) {
13203
+ return name.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
13204
+ }
13205
+ function loadPipeline(projectDir2, feature) {
13206
+ const slug = slugify2(feature);
13207
+ const filePath = path26.join(projectDir2, PIPELINE_DIR, `${slug}.yaml`);
13208
+ if (!fs24.existsSync(filePath)) return null;
13209
+ return yaml14.load(fs24.readFileSync(filePath, "utf8"));
13210
+ }
13211
+ function savePipeline(projectDir2, pipeline) {
13212
+ const slug = slugify2(pipeline.feature);
13213
+ const dir = path26.join(projectDir2, PIPELINE_DIR);
13214
+ if (!fs24.existsSync(dir)) fs24.mkdirSync(dir, { recursive: true });
13215
+ const filePath = path26.join(dir, `${slug}.yaml`);
13216
+ fs24.writeFileSync(filePath, yaml14.dump(pipeline, { lineWidth: 120 }), "utf8");
13217
+ return filePath;
13218
+ }
13219
+ function listPipelines(projectDir2) {
13220
+ const dir = path26.join(projectDir2, PIPELINE_DIR);
13221
+ if (!fs24.existsSync(dir)) return [];
13222
+ return fs24.readdirSync(dir).filter((f) => f.endsWith(".yaml") && !f.startsWith("completed")).map((f) => {
13223
+ try {
13224
+ return yaml14.load(fs24.readFileSync(path26.join(dir, f), "utf8"));
13225
+ } catch {
13226
+ return null;
13227
+ }
13228
+ }).filter(Boolean);
13229
+ }
13230
+ function createPipeline(feature, gateConfig, template) {
13231
+ const stages = {
13232
+ specify: { status: "pending" },
13233
+ plan: { status: "pending" },
13234
+ task: { status: "pending" },
13235
+ implement: { status: "pending" },
13236
+ validate: { status: "pending" }
13237
+ };
13238
+ stages.specify.status = "in-progress";
13239
+ return {
13240
+ version: "1.0",
13241
+ feature: slugify2(feature),
13242
+ created: (/* @__PURE__ */ new Date()).toISOString(),
13243
+ current_stage: "specify",
13244
+ gate_config: gateConfig,
13245
+ template,
13246
+ stages
13247
+ };
13248
+ }
13249
+ function getNextStage(current) {
13250
+ const idx = STAGE_ORDER.indexOf(current);
13251
+ return idx < STAGE_ORDER.length - 1 ? STAGE_ORDER[idx + 1] : null;
13252
+ }
13253
+ function archivePipeline(projectDir2, pipeline) {
13254
+ const slug = slugify2(pipeline.feature);
13255
+ const completedDir = path26.join(projectDir2, PIPELINE_DIR, "completed");
13256
+ if (!fs24.existsSync(completedDir)) fs24.mkdirSync(completedDir, { recursive: true });
13257
+ const destPath = path26.join(completedDir, `${slug}.yaml`);
13258
+ fs24.writeFileSync(destPath, yaml14.dump(pipeline, { lineWidth: 120 }), "utf8");
13259
+ const activePath = path26.join(projectDir2, PIPELINE_DIR, `${slug}.yaml`);
13260
+ if (fs24.existsSync(activePath)) fs24.unlinkSync(activePath);
13261
+ }
13262
+ function getPipelineToolsList() {
13263
+ return [
13264
+ {
13265
+ name: "paradigm_pipeline_start",
13266
+ description: "Create a new spec pipeline for a feature. Uses templates (add-feature, bug-fix, security-change, refactor) or custom gate config. Returns pipeline state. ~200 tokens.",
13267
+ inputSchema: {
13268
+ type: "object",
13269
+ properties: {
13270
+ feature: {
13271
+ type: "string",
13272
+ description: "Feature name or description (will be slugified)"
13273
+ },
13274
+ template: {
13275
+ type: "string",
13276
+ enum: ["add-feature", "bug-fix", "security-change", "refactor"],
13277
+ description: "Pipeline template (default: add-feature)"
13278
+ },
13279
+ gates: {
13280
+ type: "object",
13281
+ properties: {
13282
+ specify: { type: "string", enum: ["auto", "manual", "sentinel"] },
13283
+ plan: { type: "string", enum: ["auto", "manual", "sentinel"] },
13284
+ task: { type: "string", enum: ["auto", "manual", "sentinel"] },
13285
+ implement: { type: "string", enum: ["auto", "manual", "sentinel"] },
13286
+ validate: { type: "string", enum: ["auto", "manual", "sentinel"] }
13287
+ },
13288
+ description: "Custom gate config (overrides template)"
13289
+ }
13290
+ },
13291
+ required: ["feature"]
13292
+ },
13293
+ annotations: {
13294
+ readOnlyHint: false,
13295
+ destructiveHint: false
13296
+ }
13297
+ },
13298
+ {
13299
+ name: "paradigm_pipeline_status",
13300
+ description: "Get pipeline status \u2014 current stage, progress, gate config. Pass feature name for specific pipeline, or omit for all active pipelines. ~200 tokens.",
13301
+ inputSchema: {
13302
+ type: "object",
13303
+ properties: {
13304
+ feature: {
13305
+ type: "string",
13306
+ description: "Feature name (omit to list all active pipelines)"
13307
+ }
13308
+ }
13309
+ },
13310
+ annotations: {
13311
+ readOnlyHint: true,
13312
+ destructiveHint: false
13313
+ }
13314
+ },
13315
+ {
13316
+ name: "paradigm_pipeline_advance",
13317
+ description: "Advance pipeline past the current gate. Marks current stage as approved and moves to the next stage. ~150 tokens.",
13318
+ inputSchema: {
13319
+ type: "object",
13320
+ properties: {
13321
+ feature: {
13322
+ type: "string",
13323
+ description: "Feature name"
13324
+ },
13325
+ approved_by: {
13326
+ type: "string",
13327
+ description: "Who approved this gate (default: agent)"
13328
+ }
13329
+ },
13330
+ required: ["feature"]
13331
+ },
13332
+ annotations: {
13333
+ readOnlyHint: false,
13334
+ destructiveHint: false
13335
+ }
13336
+ },
13337
+ {
13338
+ name: "paradigm_pipeline_configure",
13339
+ description: "Change gate modes on an active pipeline. Use to escalate or relax gates during development. ~150 tokens.",
13340
+ inputSchema: {
13341
+ type: "object",
13342
+ properties: {
13343
+ feature: {
13344
+ type: "string",
13345
+ description: "Feature name"
13346
+ },
13347
+ updates: {
13348
+ type: "object",
13349
+ properties: {
13350
+ specify: { type: "string", enum: ["auto", "manual", "sentinel"] },
13351
+ plan: { type: "string", enum: ["auto", "manual", "sentinel"] },
13352
+ task: { type: "string", enum: ["auto", "manual", "sentinel"] },
13353
+ implement: { type: "string", enum: ["auto", "manual", "sentinel"] },
13354
+ validate: { type: "string", enum: ["auto", "manual", "sentinel"] }
13355
+ },
13356
+ description: "Stage-to-gate-mode updates"
13357
+ },
13358
+ reason: {
13359
+ type: "string",
13360
+ description: "Reason for the configuration change"
13361
+ }
13362
+ },
13363
+ required: ["feature", "updates", "reason"]
13364
+ },
13365
+ annotations: {
13366
+ readOnlyHint: false,
13367
+ destructiveHint: false
13368
+ }
13369
+ },
13370
+ {
13371
+ name: "paradigm_pipeline_escalate",
13372
+ description: "Flag a pipeline stage for user input. Use when a gate requires a decision the agent cannot make autonomously. ~200 tokens.",
13373
+ inputSchema: {
13374
+ type: "object",
13375
+ properties: {
13376
+ feature: {
13377
+ type: "string",
13378
+ description: "Feature name"
13379
+ },
13380
+ stage: {
13381
+ type: "string",
13382
+ enum: ["specify", "plan", "task", "implement", "validate"],
13383
+ description: "Stage to escalate"
13384
+ },
13385
+ question: {
13386
+ type: "string",
13387
+ description: "Question for the user"
13388
+ },
13389
+ options: {
13390
+ type: "array",
13391
+ items: { type: "string" },
13392
+ description: "Available options for the user"
13393
+ },
13394
+ context: {
13395
+ type: "object",
13396
+ description: "Additional context for the decision"
13397
+ }
13398
+ },
13399
+ required: ["feature", "stage", "question", "options"]
13400
+ },
13401
+ annotations: {
13402
+ readOnlyHint: false,
13403
+ destructiveHint: false
13404
+ }
13405
+ },
13406
+ {
13407
+ name: "paradigm_pipeline_abort",
13408
+ description: "Cancel and archive an active pipeline. Use when a feature is abandoned or no longer needed. ~100 tokens.",
13409
+ inputSchema: {
13410
+ type: "object",
13411
+ properties: {
13412
+ feature: {
13413
+ type: "string",
13414
+ description: "Feature name"
13415
+ }
13416
+ },
13417
+ required: ["feature"]
13418
+ },
13419
+ annotations: {
13420
+ readOnlyHint: false,
13421
+ destructiveHint: true
13422
+ }
13423
+ },
13424
+ {
13425
+ name: "paradigm_pipeline_list",
13426
+ description: "List all active pipelines with current stages and progress. ~150 tokens.",
13427
+ inputSchema: {
13428
+ type: "object",
13429
+ properties: {}
13430
+ },
13431
+ annotations: {
13432
+ readOnlyHint: true,
13433
+ destructiveHint: false
13434
+ }
13435
+ }
13436
+ ];
13437
+ }
13438
+ async function handlePipelineTool(name, args, ctx) {
13439
+ switch (name) {
13440
+ case "paradigm_pipeline_start": {
13441
+ const feature = args.feature;
13442
+ const templateName = args.template || "add-feature";
13443
+ const customGates = args.gates;
13444
+ let gateConfig;
13445
+ if (customGates) {
13446
+ gateConfig = {
13447
+ specify: customGates.specify || "manual",
13448
+ plan: customGates.plan || "manual",
13449
+ task: customGates.task || "auto",
13450
+ implement: customGates.implement || "sentinel",
13451
+ validate: customGates.validate || "sentinel"
13452
+ };
13453
+ } else {
13454
+ const tmpl = DEFAULT_TEMPLATES[templateName];
13455
+ if (!tmpl) {
13456
+ return {
13457
+ handled: true,
13458
+ text: JSON.stringify({
13459
+ error: `Unknown template: ${templateName}`,
13460
+ available: Object.keys(DEFAULT_TEMPLATES)
13461
+ })
13462
+ };
13463
+ }
13464
+ gateConfig = tmpl.gates;
13465
+ }
13466
+ const pipeline = createPipeline(feature, gateConfig, templateName);
13467
+ const filePath = savePipeline(ctx.rootDir, pipeline);
13468
+ return {
13469
+ handled: true,
13470
+ text: JSON.stringify(
13471
+ {
13472
+ created: true,
13473
+ feature: pipeline.feature,
13474
+ template: templateName,
13475
+ file: filePath,
13476
+ current_stage: pipeline.current_stage,
13477
+ gate_config: pipeline.gate_config,
13478
+ stages: pipeline.stages,
13479
+ hint: `Pipeline '${pipeline.feature}' started at 'specify' stage. Create your spec, then call paradigm_pipeline_advance to move to 'plan'.`
13480
+ },
13481
+ null,
13482
+ 2
13483
+ )
13484
+ };
13485
+ }
13486
+ case "paradigm_pipeline_status": {
13487
+ const feature = args.feature;
13488
+ if (feature) {
13489
+ const pipeline = loadPipeline(ctx.rootDir, feature);
13490
+ if (!pipeline) {
13491
+ return {
13492
+ handled: true,
13493
+ text: JSON.stringify({ error: `Pipeline not found: ${feature}` })
13494
+ };
13495
+ }
13496
+ const completedStages = STAGE_ORDER.filter(
13497
+ (s) => pipeline.stages[s].status === "approved"
13498
+ ).length;
13499
+ return {
13500
+ handled: true,
13501
+ text: JSON.stringify(
13502
+ {
13503
+ feature: pipeline.feature,
13504
+ created: pipeline.created,
13505
+ template: pipeline.template,
13506
+ current_stage: pipeline.current_stage,
13507
+ progress: `${completedStages}/${STAGE_ORDER.length}`,
13508
+ gate_config: pipeline.gate_config,
13509
+ stages: pipeline.stages
13510
+ },
13511
+ null,
13512
+ 2
13513
+ )
13514
+ };
13515
+ }
13516
+ const pipelines = listPipelines(ctx.rootDir);
13517
+ if (pipelines.length === 0) {
13518
+ return {
13519
+ handled: true,
13520
+ text: JSON.stringify({
13521
+ count: 0,
13522
+ message: "No active pipelines. Use paradigm_pipeline_start to create one."
13523
+ })
13524
+ };
13525
+ }
13526
+ return {
13527
+ handled: true,
13528
+ text: JSON.stringify(
13529
+ {
13530
+ count: pipelines.length,
13531
+ pipelines: pipelines.map((p) => {
13532
+ const completed = STAGE_ORDER.filter(
13533
+ (s) => p.stages[s].status === "approved"
13534
+ ).length;
13535
+ return {
13536
+ feature: p.feature,
13537
+ current_stage: p.current_stage,
13538
+ progress: `${completed}/${STAGE_ORDER.length}`,
13539
+ template: p.template,
13540
+ created: p.created
13541
+ };
13542
+ })
13543
+ },
13544
+ null,
13545
+ 2
13546
+ )
13547
+ };
13548
+ }
13549
+ case "paradigm_pipeline_advance": {
13550
+ const feature = args.feature;
13551
+ const approvedBy = args.approved_by || "agent";
13552
+ const pipeline = loadPipeline(ctx.rootDir, feature);
13553
+ if (!pipeline) {
13554
+ return {
13555
+ handled: true,
13556
+ text: JSON.stringify({ error: `Pipeline not found: ${feature}` })
13557
+ };
13558
+ }
13559
+ const current = pipeline.current_stage;
13560
+ const gateMode = pipeline.gate_config[current];
13561
+ const next = getNextStage(current);
13562
+ pipeline.stages[current].status = "approved";
13563
+ pipeline.stages[current].approved_by = approvedBy;
13564
+ pipeline.stages[current].approved_at = (/* @__PURE__ */ new Date()).toISOString();
13565
+ if (gateMode === "auto") {
13566
+ pipeline.stages[current].auto_passed_at = (/* @__PURE__ */ new Date()).toISOString();
13567
+ }
13568
+ if (next) {
13569
+ pipeline.current_stage = next;
13570
+ pipeline.stages[next].status = "in-progress";
13571
+ savePipeline(ctx.rootDir, pipeline);
13572
+ return {
13573
+ handled: true,
13574
+ text: JSON.stringify(
13575
+ {
13576
+ advanced: true,
13577
+ from: current,
13578
+ to: next,
13579
+ gate_mode: gateMode,
13580
+ approved_by: approvedBy,
13581
+ pipeline: {
13582
+ feature: pipeline.feature,
13583
+ current_stage: pipeline.current_stage,
13584
+ stages: pipeline.stages
13585
+ }
13586
+ },
13587
+ null,
13588
+ 2
13589
+ )
13590
+ };
13591
+ }
13592
+ savePipeline(ctx.rootDir, pipeline);
13593
+ archivePipeline(ctx.rootDir, pipeline);
13594
+ return {
13595
+ handled: true,
13596
+ text: JSON.stringify(
13597
+ {
13598
+ completed: true,
13599
+ feature: pipeline.feature,
13600
+ message: `Pipeline '${pipeline.feature}' completed and archived.`,
13601
+ stages: pipeline.stages
13602
+ },
13603
+ null,
13604
+ 2
13605
+ )
13606
+ };
13607
+ }
13608
+ case "paradigm_pipeline_configure": {
13609
+ const feature = args.feature;
13610
+ const updates = args.updates;
13611
+ const reason = args.reason;
13612
+ const pipeline = loadPipeline(ctx.rootDir, feature);
13613
+ if (!pipeline) {
13614
+ return {
13615
+ handled: true,
13616
+ text: JSON.stringify({ error: `Pipeline not found: ${feature}` })
13617
+ };
13618
+ }
13619
+ const changes = [];
13620
+ for (const [stage, mode] of Object.entries(updates)) {
13621
+ if (STAGE_ORDER.includes(stage) && ["auto", "manual", "sentinel"].includes(mode)) {
13622
+ const old = pipeline.gate_config[stage];
13623
+ pipeline.gate_config[stage] = mode;
13624
+ changes.push({ stage, from: old, to: mode });
13625
+ }
13626
+ }
13627
+ if (changes.length === 0) {
13628
+ return {
13629
+ handled: true,
13630
+ text: JSON.stringify({
13631
+ error: "No valid gate updates provided",
13632
+ valid_stages: STAGE_ORDER,
13633
+ valid_modes: ["auto", "manual", "sentinel"]
13634
+ })
13635
+ };
13636
+ }
13637
+ savePipeline(ctx.rootDir, pipeline);
13638
+ return {
13639
+ handled: true,
13640
+ text: JSON.stringify(
13641
+ {
13642
+ configured: true,
13643
+ feature: pipeline.feature,
13644
+ changes,
13645
+ reason,
13646
+ gate_config: pipeline.gate_config
13647
+ },
13648
+ null,
13649
+ 2
13650
+ )
13651
+ };
13652
+ }
13653
+ case "paradigm_pipeline_escalate": {
13654
+ const feature = args.feature;
13655
+ const stage = args.stage;
13656
+ const question = args.question;
13657
+ const options = args.options;
13658
+ const context2 = args.context;
13659
+ const pipeline = loadPipeline(ctx.rootDir, feature);
13660
+ if (!pipeline) {
13661
+ return {
13662
+ handled: true,
13663
+ text: JSON.stringify({ error: `Pipeline not found: ${feature}` })
13664
+ };
13665
+ }
13666
+ pipeline.stages[stage].status = "blocked";
13667
+ pipeline.stages[stage].block_reason = question;
13668
+ savePipeline(ctx.rootDir, pipeline);
13669
+ return {
13670
+ handled: true,
13671
+ text: JSON.stringify(
13672
+ {
13673
+ escalated: true,
13674
+ feature: pipeline.feature,
13675
+ stage,
13676
+ question,
13677
+ options,
13678
+ context: context2 || {},
13679
+ current_gate: pipeline.gate_config[stage],
13680
+ instruction: "This pipeline stage requires user input. Present the question and options to the user, then use paradigm_pipeline_advance or paradigm_pipeline_configure based on their response."
13681
+ },
13682
+ null,
13683
+ 2
13684
+ )
13685
+ };
13686
+ }
13687
+ case "paradigm_pipeline_abort": {
13688
+ const feature = args.feature;
13689
+ const pipeline = loadPipeline(ctx.rootDir, feature);
13690
+ if (!pipeline) {
13691
+ return {
13692
+ handled: true,
13693
+ text: JSON.stringify({ error: `Pipeline not found: ${feature}` })
13694
+ };
13695
+ }
13696
+ archivePipeline(ctx.rootDir, pipeline);
13697
+ return {
13698
+ handled: true,
13699
+ text: JSON.stringify({
13700
+ aborted: true,
13701
+ feature: pipeline.feature,
13702
+ message: `Pipeline '${pipeline.feature}' aborted and archived.`
13703
+ })
13704
+ };
13705
+ }
13706
+ case "paradigm_pipeline_list": {
13707
+ const pipelines = listPipelines(ctx.rootDir);
13708
+ if (pipelines.length === 0) {
13709
+ return {
13710
+ handled: true,
13711
+ text: JSON.stringify({
13712
+ count: 0,
13713
+ message: "No active pipelines."
13714
+ })
13715
+ };
13716
+ }
13717
+ return {
13718
+ handled: true,
13719
+ text: JSON.stringify(
13720
+ {
13721
+ count: pipelines.length,
13722
+ pipelines: pipelines.map((p) => {
13723
+ const completed = STAGE_ORDER.filter(
13724
+ (s) => p.stages[s].status === "approved"
13725
+ ).length;
13726
+ return {
13727
+ feature: p.feature,
13728
+ current_stage: p.current_stage,
13729
+ progress: `${completed}/${STAGE_ORDER.length}`,
13730
+ template: p.template,
13731
+ created: p.created
13732
+ };
13733
+ })
13734
+ },
13735
+ null,
13736
+ 2
13737
+ )
13738
+ };
13739
+ }
13740
+ default:
13741
+ return { handled: false, text: "" };
13742
+ }
13743
+ }
13744
+
13745
+ // ../paradigm-mcp/src/tools/fallback-grep.ts
13746
+ import * as path27 from "path";
12944
13747
  import { execSync as execSync5 } from "child_process";
12945
13748
  function grepForReferences(rootDir, symbol, options = {}) {
12946
13749
  const { maxResults = 20 } = options;
@@ -12969,7 +13772,7 @@ function grepForReferences(rootDir, symbol, options = {}) {
12969
13772
  const match = line.match(/^(.+?):(\d+):(.*)$/);
12970
13773
  if (match) {
12971
13774
  const [, filePath, lineNum, content] = match;
12972
- const relativePath = path25.relative(rootDir, filePath);
13775
+ const relativePath = path27.relative(rootDir, filePath);
12973
13776
  let context2 = "unknown";
12974
13777
  if (relativePath.includes(".purpose") || relativePath.includes("portal.yaml")) {
12975
13778
  context2 = "purpose";
@@ -13234,6 +14037,10 @@ function registerTools(server, getContext2, reloadContext2) {
13234
14037
  ...getProtocolsToolsList(),
13235
14038
  // Graph generation tool
13236
14039
  ...getGraphToolsList(),
14040
+ // Heat map tools
14041
+ ...getHeatmapToolsList(),
14042
+ // Pipeline tools
14043
+ ...getPipelineToolsList(),
13237
14044
  // Plugin update check
13238
14045
  {
13239
14046
  name: "paradigm_plugin_check",
@@ -13867,7 +14674,7 @@ Update command:
13867
14674
  const { rebuildStaticFiles: rebuildStaticFiles2 } = await import("./reindex-CMZARW5K.js");
13868
14675
  const memberResults = [];
13869
14676
  for (const member of ctx.workspace.config.members) {
13870
- const memberAbsPath = path26.resolve(path26.dirname(ctx.workspace.workspacePath), member.path);
14677
+ const memberAbsPath = path28.resolve(path28.dirname(ctx.workspace.workspacePath), member.path);
13871
14678
  try {
13872
14679
  const result = await rebuildStaticFiles2(memberAbsPath);
13873
14680
  memberResults.push({
@@ -14065,6 +14872,23 @@ Update command:
14065
14872
  };
14066
14873
  }
14067
14874
  }
14875
+ if (name.startsWith("paradigm_heatmap_")) {
14876
+ const result = await handleHeatmapTool(name, args, ctx);
14877
+ if (result.handled) {
14878
+ return {
14879
+ content: [{ type: "text", text: result.text }]
14880
+ };
14881
+ }
14882
+ }
14883
+ if (name.startsWith("paradigm_pipeline_")) {
14884
+ const result = await handlePipelineTool(name, args, ctx);
14885
+ if (result.handled) {
14886
+ trackToolCall(result.text.length, name);
14887
+ return {
14888
+ content: [{ type: "text", text: result.text }]
14889
+ };
14890
+ }
14891
+ }
14068
14892
  if (name === "paradigm_reindex") {
14069
14893
  const reload = reloadContext2 || (async () => {
14070
14894
  });