@a-company/paradigm 3.14.0 → 3.15.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.
package/dist/mcp.js CHANGED
@@ -36,6 +36,7 @@ import {
36
36
  createPersona,
37
37
  deleteLoreEntry,
38
38
  deletePersona,
39
+ detectProtocolSuggestion,
39
40
  findPurposeFiles,
40
41
  getAffectedPersonas,
41
42
  getAllEdgesFor,
@@ -66,6 +67,9 @@ import {
66
67
  loadLoreTimeline,
67
68
  loadPersona,
68
69
  loadPersonas,
70
+ loadProtocol,
71
+ loadProtocolIndex,
72
+ loadProtocols,
69
73
  openAspectGraph,
70
74
  parseGateConfig,
71
75
  parsePurposeFileDetailed,
@@ -73,7 +77,9 @@ import {
73
77
  recordGlobalAntipattern,
74
78
  recordGlobalDecision,
75
79
  recordLoreEntry,
80
+ recordProtocol,
76
81
  removeStep,
82
+ searchProtocols,
77
83
  searchSymbols,
78
84
  serializePurposeFile,
79
85
  toolCache,
@@ -81,10 +87,12 @@ import {
81
87
  trackToolCall,
82
88
  updateLoreEntry,
83
89
  updatePersona,
90
+ updateProtocol,
84
91
  validateAgainstSentinel,
85
92
  validatePersona,
93
+ validateProtocol,
86
94
  validatePurposeFile
87
- } from "./chunk-O5ZO5LSW.js";
95
+ } from "./chunk-D4VBBKGV.js";
88
96
  import {
89
97
  getPluginUpdateNotice,
90
98
  schedulePluginUpdateCheck
@@ -8574,6 +8582,17 @@ async function handleLoreTool(name, args, ctx) {
8574
8582
  };
8575
8583
  const id = await recordLoreEntry(ctx.rootDir, entry);
8576
8584
  getSessionTracker().setLastLoreEntryId(id);
8585
+ let protocol_suggestion = null;
8586
+ try {
8587
+ if (files_created && files_created.length >= 2) {
8588
+ protocol_suggestion = detectProtocolSuggestion(
8589
+ ctx.rootDir,
8590
+ files_created,
8591
+ files_modified || []
8592
+ );
8593
+ }
8594
+ } catch {
8595
+ }
8577
8596
  return {
8578
8597
  handled: true,
8579
8598
  text: JSON.stringify({
@@ -8581,7 +8600,8 @@ async function handleLoreTool(name, args, ctx) {
8581
8600
  id,
8582
8601
  type,
8583
8602
  title,
8584
- message: "Lore entry recorded successfully"
8603
+ message: "Lore entry recorded successfully",
8604
+ ...protocol_suggestion ? { protocol_suggestion } : {}
8585
8605
  })
8586
8606
  };
8587
8607
  }
@@ -11553,6 +11573,364 @@ async function handlePersonaTool(name, args, ctx) {
11553
11573
  }
11554
11574
  }
11555
11575
 
11576
+ // ../paradigm-mcp/src/tools/protocols.ts
11577
+ function getProtocolsToolsList() {
11578
+ return [
11579
+ {
11580
+ name: "paradigm_protocol_search",
11581
+ description: "Search for protocols matching a task description. Call BEFORE exploring the codebase \u2014 if a matching protocol exists, follow its steps instead of discovering the pattern from scratch. Returns top matches with steps, exemplar, and freshness info. ~200 tokens.",
11582
+ inputSchema: {
11583
+ type: "object",
11584
+ properties: {
11585
+ task: {
11586
+ type: "string",
11587
+ description: 'Task description to search for (e.g., "add a new page", "add API route")'
11588
+ },
11589
+ limit: {
11590
+ type: "number",
11591
+ description: "Maximum results (default: 3)"
11592
+ }
11593
+ },
11594
+ required: ["task"]
11595
+ },
11596
+ annotations: {
11597
+ readOnlyHint: true,
11598
+ destructiveHint: false
11599
+ }
11600
+ },
11601
+ {
11602
+ name: "paradigm_protocol_get",
11603
+ description: "Get a specific protocol by ID with full details and freshness check. ~300 tokens.",
11604
+ inputSchema: {
11605
+ type: "object",
11606
+ properties: {
11607
+ id: {
11608
+ type: "string",
11609
+ description: 'Protocol ID (e.g., "P-add-view")'
11610
+ }
11611
+ },
11612
+ required: ["id"]
11613
+ },
11614
+ annotations: {
11615
+ readOnlyHint: true,
11616
+ destructiveHint: false
11617
+ }
11618
+ },
11619
+ {
11620
+ name: "paradigm_protocol_record",
11621
+ description: "Record a new protocol after completing repeatable work. Captures the steps you followed so future agents can skip exploration. ~100 tokens.",
11622
+ inputSchema: {
11623
+ type: "object",
11624
+ properties: {
11625
+ name: {
11626
+ type: "string",
11627
+ description: 'Protocol name (e.g., "Add a new view")'
11628
+ },
11629
+ description: {
11630
+ type: "string",
11631
+ description: "What this protocol accomplishes"
11632
+ },
11633
+ trigger: {
11634
+ type: "array",
11635
+ items: { type: "string" },
11636
+ description: 'Phrases that should match this protocol (e.g., ["add view", "new page"])'
11637
+ },
11638
+ tags: {
11639
+ type: "array",
11640
+ items: { type: "string" },
11641
+ description: 'Classification tags (e.g., ["ui", "frontend"])'
11642
+ },
11643
+ symbols: {
11644
+ type: "array",
11645
+ items: { type: "string" },
11646
+ description: 'Paradigm symbols involved (e.g., ["#logs-view"])'
11647
+ },
11648
+ exemplar: {
11649
+ type: "string",
11650
+ description: 'Canonical file to study for this pattern (e.g., "ui/src/views/LogsView.tsx")'
11651
+ },
11652
+ steps: {
11653
+ type: "array",
11654
+ items: {
11655
+ type: "object",
11656
+ properties: {
11657
+ action: {
11658
+ type: "string",
11659
+ enum: ["create", "modify", "run", "verify"],
11660
+ description: "Step action type"
11661
+ },
11662
+ target: {
11663
+ type: "string",
11664
+ description: "File path (supports {Name}/{name} placeholders)"
11665
+ },
11666
+ template_from: {
11667
+ type: "string",
11668
+ description: "File to use as template (for create actions)"
11669
+ },
11670
+ reference: {
11671
+ type: "string",
11672
+ description: "Where in the file to make changes (for modify actions)"
11673
+ },
11674
+ command: {
11675
+ type: "string",
11676
+ description: "Command to execute (for run actions)"
11677
+ },
11678
+ notes: {
11679
+ type: "string",
11680
+ description: "Additional guidance for this step"
11681
+ }
11682
+ },
11683
+ required: ["action"]
11684
+ },
11685
+ description: "Ordered steps to follow"
11686
+ },
11687
+ recorded_from: {
11688
+ type: "string",
11689
+ description: 'Lore entry ID this protocol was learned from (e.g., "L-2026-03-01-001")'
11690
+ }
11691
+ },
11692
+ required: ["name", "description", "trigger", "tags", "steps"]
11693
+ },
11694
+ annotations: {
11695
+ readOnlyHint: false,
11696
+ destructiveHint: false
11697
+ }
11698
+ },
11699
+ {
11700
+ name: "paradigm_protocol_update",
11701
+ description: "Update an existing protocol. Use refresh:true after successfully following a protocol to bump last_verified. ~100 tokens.",
11702
+ inputSchema: {
11703
+ type: "object",
11704
+ properties: {
11705
+ id: {
11706
+ type: "string",
11707
+ description: 'Protocol ID to update (e.g., "P-add-view")'
11708
+ },
11709
+ refresh: {
11710
+ type: "boolean",
11711
+ description: "Set true to bump last_verified to now (use after successfully following the protocol)"
11712
+ },
11713
+ name: { type: "string", description: "Updated name" },
11714
+ description: { type: "string", description: "Updated description" },
11715
+ trigger: {
11716
+ type: "array",
11717
+ items: { type: "string" },
11718
+ description: "Updated trigger phrases"
11719
+ },
11720
+ tags: {
11721
+ type: "array",
11722
+ items: { type: "string" },
11723
+ description: "Updated tags"
11724
+ },
11725
+ symbols: {
11726
+ type: "array",
11727
+ items: { type: "string" },
11728
+ description: "Updated symbols"
11729
+ },
11730
+ exemplar: { type: "string", description: "Updated exemplar path" },
11731
+ steps: {
11732
+ type: "array",
11733
+ items: {
11734
+ type: "object",
11735
+ properties: {
11736
+ action: { type: "string", enum: ["create", "modify", "run", "verify"] },
11737
+ target: { type: "string" },
11738
+ template_from: { type: "string" },
11739
+ reference: { type: "string" },
11740
+ command: { type: "string" },
11741
+ notes: { type: "string" }
11742
+ },
11743
+ required: ["action"]
11744
+ },
11745
+ description: "Updated steps"
11746
+ }
11747
+ },
11748
+ required: ["id"]
11749
+ },
11750
+ annotations: {
11751
+ readOnlyHint: false,
11752
+ destructiveHint: false
11753
+ }
11754
+ },
11755
+ {
11756
+ name: "paradigm_protocol_validate",
11757
+ description: "Validate protocol references \u2014 check that referenced files exist, exemplars haven't drifted. Validates all protocols if no ID given. ~200 tokens.",
11758
+ inputSchema: {
11759
+ type: "object",
11760
+ properties: {
11761
+ id: {
11762
+ type: "string",
11763
+ description: "Protocol ID to validate (omit to validate all)"
11764
+ }
11765
+ }
11766
+ },
11767
+ annotations: {
11768
+ readOnlyHint: true,
11769
+ destructiveHint: false
11770
+ }
11771
+ }
11772
+ ];
11773
+ }
11774
+ async function handleProtocolsTool(name, args, ctx) {
11775
+ switch (name) {
11776
+ case "paradigm_protocol_search": {
11777
+ const task = args.task;
11778
+ const limit = args.limit || 3;
11779
+ const results = await searchProtocols(ctx.rootDir, task, limit);
11780
+ if (results.length === 0) {
11781
+ return {
11782
+ handled: true,
11783
+ text: JSON.stringify({
11784
+ count: 0,
11785
+ task,
11786
+ message: "No matching protocol found. Consider recording one after completing this task."
11787
+ })
11788
+ };
11789
+ }
11790
+ return {
11791
+ handled: true,
11792
+ text: JSON.stringify({
11793
+ count: results.length,
11794
+ task,
11795
+ matches: results.map((r) => ({
11796
+ id: r.protocol.id,
11797
+ name: r.protocol.name,
11798
+ description: r.protocol.description,
11799
+ score: r.score,
11800
+ status: r.protocol.status,
11801
+ exemplar: r.protocol.exemplar,
11802
+ last_verified: r.protocol.last_verified,
11803
+ steps: r.protocol.steps.map(summarizeStep)
11804
+ }))
11805
+ }, null, 2)
11806
+ };
11807
+ }
11808
+ case "paradigm_protocol_get": {
11809
+ const id = args.id;
11810
+ const protocol = await loadProtocol(ctx.rootDir, id);
11811
+ if (!protocol) {
11812
+ return {
11813
+ handled: true,
11814
+ text: JSON.stringify({ error: `Protocol not found: ${id}` })
11815
+ };
11816
+ }
11817
+ const validation = validateProtocol(ctx.rootDir, protocol);
11818
+ return {
11819
+ handled: true,
11820
+ text: JSON.stringify({
11821
+ ...protocol,
11822
+ freshness: {
11823
+ status: validation.status,
11824
+ issues: validation.issues
11825
+ }
11826
+ }, null, 2)
11827
+ };
11828
+ }
11829
+ case "paradigm_protocol_record": {
11830
+ const steps = args.steps || [];
11831
+ const id = await recordProtocol(ctx.rootDir, {
11832
+ name: args.name,
11833
+ description: args.description,
11834
+ trigger: args.trigger || [],
11835
+ tags: args.tags || [],
11836
+ symbols: args.symbols || [],
11837
+ exemplar: args.exemplar,
11838
+ steps,
11839
+ recorded_from: args.recorded_from,
11840
+ verified_by: "claude-opus-4-6"
11841
+ });
11842
+ return {
11843
+ handled: true,
11844
+ text: JSON.stringify({
11845
+ success: true,
11846
+ id,
11847
+ name: args.name,
11848
+ message: "Protocol recorded successfully"
11849
+ })
11850
+ };
11851
+ }
11852
+ case "paradigm_protocol_update": {
11853
+ const id = args.id;
11854
+ const refresh = args.refresh;
11855
+ const partial = {};
11856
+ if (args.name !== void 0) partial.name = args.name;
11857
+ if (args.description !== void 0) partial.description = args.description;
11858
+ if (args.trigger !== void 0) partial.trigger = args.trigger;
11859
+ if (args.tags !== void 0) partial.tags = args.tags;
11860
+ if (args.symbols !== void 0) partial.symbols = args.symbols;
11861
+ if (args.exemplar !== void 0) partial.exemplar = args.exemplar;
11862
+ if (args.steps !== void 0) partial.steps = args.steps;
11863
+ const success = await updateProtocol(ctx.rootDir, id, partial, refresh === true);
11864
+ return {
11865
+ handled: true,
11866
+ text: JSON.stringify({
11867
+ success,
11868
+ id,
11869
+ refreshed: refresh === true,
11870
+ message: success ? refresh ? "Protocol updated and verified" : "Protocol updated" : `Protocol not found: ${id}`
11871
+ })
11872
+ };
11873
+ }
11874
+ case "paradigm_protocol_validate": {
11875
+ const id = args.id;
11876
+ if (id) {
11877
+ const protocol = await loadProtocol(ctx.rootDir, id);
11878
+ if (!protocol) {
11879
+ return {
11880
+ handled: true,
11881
+ text: JSON.stringify({ error: `Protocol not found: ${id}` })
11882
+ };
11883
+ }
11884
+ const result = validateProtocol(ctx.rootDir, protocol);
11885
+ return {
11886
+ handled: true,
11887
+ text: JSON.stringify({
11888
+ id: protocol.id,
11889
+ name: protocol.name,
11890
+ status: result.status,
11891
+ issues: result.issues,
11892
+ last_verified: protocol.last_verified
11893
+ }, null, 2)
11894
+ };
11895
+ }
11896
+ const protocols = await loadProtocols(ctx.rootDir);
11897
+ const results = protocols.map((p) => {
11898
+ const v = validateProtocol(ctx.rootDir, p);
11899
+ return {
11900
+ id: p.id,
11901
+ name: p.name,
11902
+ status: v.status,
11903
+ issues: v.issues,
11904
+ last_verified: p.last_verified
11905
+ };
11906
+ });
11907
+ const health = {
11908
+ total: results.length,
11909
+ current: results.filter((r) => r.status === "current").length,
11910
+ stale: results.filter((r) => r.status === "stale").length,
11911
+ broken: results.filter((r) => r.status === "broken").length
11912
+ };
11913
+ return {
11914
+ handled: true,
11915
+ text: JSON.stringify({ protocols: results, health }, null, 2)
11916
+ };
11917
+ }
11918
+ default:
11919
+ return { handled: false, text: "" };
11920
+ }
11921
+ }
11922
+ function summarizeStep(step) {
11923
+ const result = {
11924
+ action: step.action
11925
+ };
11926
+ if (step.target) result.target = step.target;
11927
+ if (step.template_from) result.template_from = step.template_from;
11928
+ if (step.reference) result.reference = step.reference;
11929
+ if (step.command) result.command = step.command;
11930
+ if (step.notes) result.notes = step.notes;
11931
+ return result;
11932
+ }
11933
+
11556
11934
  // ../paradigm-mcp/src/tools/fallback-grep.ts
11557
11935
  import * as path23 from "path";
11558
11936
  import { execSync as execSync3 } from "child_process";
@@ -11844,6 +12222,8 @@ function registerTools(server, getContext2, reloadContext2) {
11844
12222
  // Assessment loop tools
11845
12223
  ...getAssessmentToolsList(),
11846
12224
  ...getPersonaToolsList(),
12225
+ // Protocol tools
12226
+ ...getProtocolsToolsList(),
11847
12227
  // Plugin update check
11848
12228
  {
11849
12229
  name: "paradigm_plugin_check",
@@ -12226,7 +12606,7 @@ function registerTools(server, getContext2, reloadContext2) {
12226
12606
  };
12227
12607
  }
12228
12608
  case "paradigm_status": {
12229
- const text = await toolCache.getOrCompute("status", () => {
12609
+ const text = await toolCache.getOrCompute("status", async () => {
12230
12610
  const counts = getSymbolCounts(ctx.index);
12231
12611
  const total = Object.values(counts).reduce((a, b) => a + b, 0);
12232
12612
  const examples = {};
@@ -12237,6 +12617,14 @@ function registerTools(server, getContext2, reloadContext2) {
12237
12617
  const platform2 = os.platform();
12238
12618
  const isWindows = platform2 === "win32";
12239
12619
  const shell = isWindows ? "PowerShell/CMD" : platform2 === "darwin" ? "zsh/bash" : "bash";
12620
+ let protocols;
12621
+ try {
12622
+ const protocolIndex = await loadProtocolIndex(ctx.rootDir);
12623
+ if (protocolIndex && protocolIndex.health.total > 0) {
12624
+ protocols = protocolIndex.health;
12625
+ }
12626
+ } catch {
12627
+ }
12240
12628
  return JSON.stringify({
12241
12629
  project: ctx.projectName,
12242
12630
  symbolSystem: "v2",
@@ -12251,6 +12639,7 @@ function registerTools(server, getContext2, reloadContext2) {
12251
12639
  examples,
12252
12640
  hasPortalYaml: ctx.gateConfig !== null,
12253
12641
  purposeFiles: ctx.aggregation.purposeFiles.length,
12642
+ ...protocols ? { protocols } : {},
12254
12643
  note: "Symbol System v2: Use tags [feature], [state], [integration], [idea] for classification",
12255
12644
  environment: {
12256
12645
  os: platform2,
@@ -12465,7 +12854,7 @@ Update command:
12465
12854
  trackToolCall(noWsText.length, name);
12466
12855
  return { content: [{ type: "text", text: noWsText }] };
12467
12856
  }
12468
- const { rebuildStaticFiles: rebuildStaticFiles2 } = await import("./reindex-4OOME3TT.js");
12857
+ const { rebuildStaticFiles: rebuildStaticFiles2 } = await import("./reindex-T4N3NG73.js");
12469
12858
  const memberResults = [];
12470
12859
  for (const member of ctx.workspace.config.members) {
12471
12860
  const memberAbsPath = path24.resolve(path24.dirname(ctx.workspace.workspacePath), member.path);
@@ -12648,6 +13037,15 @@ Update command:
12648
13037
  };
12649
13038
  }
12650
13039
  }
13040
+ if (name.startsWith("paradigm_protocol_")) {
13041
+ const result = await handleProtocolsTool(name, args, ctx);
13042
+ if (result.handled) {
13043
+ trackToolCall(result.text.length, name);
13044
+ return {
13045
+ content: [{ type: "text", text: result.text }]
13046
+ };
13047
+ }
13048
+ }
12651
13049
  if (name === "paradigm_reindex") {
12652
13050
  const reload = reloadContext2 || (async () => {
12653
13051
  });
@@ -3,7 +3,7 @@ import {
3
3
  getReindexToolsList,
4
4
  handleReindexTool,
5
5
  rebuildStaticFiles
6
- } from "./chunk-O5ZO5LSW.js";
6
+ } from "./chunk-D4VBBKGV.js";
7
7
  export {
8
8
  getReindexToolsList,
9
9
  handleReindexTool,