@a-company/paradigm 3.14.1 → 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.
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// ../paradigm-mcp/src/tools/reindex.ts
|
|
4
|
-
import * as
|
|
5
|
-
import * as
|
|
6
|
-
import * as
|
|
4
|
+
import * as fs9 from "fs";
|
|
5
|
+
import * as path10 from "path";
|
|
6
|
+
import * as yaml8 from "js-yaml";
|
|
7
7
|
|
|
8
8
|
// ../paradigm-mcp/node_modules/.pnpm/@a-company+premise-core@0.2.0_typescript@5.9.3/node_modules/@a-company/premise-core/dist/index.js
|
|
9
9
|
import * as yaml3 from "js-yaml";
|
|
@@ -1991,8 +1991,8 @@ var SessionTracker = class {
|
|
|
1991
1991
|
* Extract resource type from URI
|
|
1992
1992
|
*/
|
|
1993
1993
|
extractResourceType(uri) {
|
|
1994
|
-
const
|
|
1995
|
-
const firstPart =
|
|
1994
|
+
const path11 = uri.replace("paradigm://", "");
|
|
1995
|
+
const firstPart = path11.split("/")[0];
|
|
1996
1996
|
return firstPart || "unknown";
|
|
1997
1997
|
}
|
|
1998
1998
|
/**
|
|
@@ -4389,8 +4389,8 @@ async function getAffectedPersonas(rootDir, symbol) {
|
|
|
4389
4389
|
}
|
|
4390
4390
|
return results;
|
|
4391
4391
|
}
|
|
4392
|
-
function deepGet(obj,
|
|
4393
|
-
const parts =
|
|
4392
|
+
function deepGet(obj, path11) {
|
|
4393
|
+
const parts = path11.split(/[.\[\]]+/).filter(Boolean);
|
|
4394
4394
|
let current = obj;
|
|
4395
4395
|
for (const part of parts) {
|
|
4396
4396
|
if (current == null || typeof current !== "object") return void 0;
|
|
@@ -4558,6 +4558,341 @@ async function validateAgainstSentinel(persona, options = {}) {
|
|
|
4558
4558
|
};
|
|
4559
4559
|
}
|
|
4560
4560
|
|
|
4561
|
+
// ../paradigm-mcp/src/utils/protocol-loader.ts
|
|
4562
|
+
import * as fs8 from "fs";
|
|
4563
|
+
import * as path9 from "path";
|
|
4564
|
+
import * as yaml7 from "js-yaml";
|
|
4565
|
+
var PROTOCOLS_DIR = ".paradigm/protocols";
|
|
4566
|
+
var INDEX_FILE2 = "index.yaml";
|
|
4567
|
+
async function loadProtocols(rootDir) {
|
|
4568
|
+
const protocolsDir = path9.join(rootDir, PROTOCOLS_DIR);
|
|
4569
|
+
if (!fs8.existsSync(protocolsDir)) {
|
|
4570
|
+
return [];
|
|
4571
|
+
}
|
|
4572
|
+
const files = fs8.readdirSync(protocolsDir).filter((f) => f.endsWith(".protocol")).sort();
|
|
4573
|
+
const protocols = [];
|
|
4574
|
+
for (const file of files) {
|
|
4575
|
+
try {
|
|
4576
|
+
const content = fs8.readFileSync(path9.join(protocolsDir, file), "utf8");
|
|
4577
|
+
const protocol = yaml7.load(content);
|
|
4578
|
+
if (protocol?.id && protocol?.name) {
|
|
4579
|
+
protocols.push(protocol);
|
|
4580
|
+
}
|
|
4581
|
+
} catch {
|
|
4582
|
+
}
|
|
4583
|
+
}
|
|
4584
|
+
return protocols;
|
|
4585
|
+
}
|
|
4586
|
+
async function loadProtocol(rootDir, id) {
|
|
4587
|
+
const slug = id.replace(/^P-/, "");
|
|
4588
|
+
const filePath = path9.join(rootDir, PROTOCOLS_DIR, `${slug}.protocol`);
|
|
4589
|
+
if (fs8.existsSync(filePath)) {
|
|
4590
|
+
try {
|
|
4591
|
+
const content = fs8.readFileSync(filePath, "utf8");
|
|
4592
|
+
return yaml7.load(content);
|
|
4593
|
+
} catch {
|
|
4594
|
+
return null;
|
|
4595
|
+
}
|
|
4596
|
+
}
|
|
4597
|
+
const protocols = await loadProtocols(rootDir);
|
|
4598
|
+
return protocols.find((p) => p.id === id) || null;
|
|
4599
|
+
}
|
|
4600
|
+
async function loadProtocolIndex(rootDir) {
|
|
4601
|
+
const indexPath = path9.join(rootDir, PROTOCOLS_DIR, INDEX_FILE2);
|
|
4602
|
+
if (!fs8.existsSync(indexPath)) {
|
|
4603
|
+
return null;
|
|
4604
|
+
}
|
|
4605
|
+
try {
|
|
4606
|
+
const content = fs8.readFileSync(indexPath, "utf8");
|
|
4607
|
+
return yaml7.load(content);
|
|
4608
|
+
} catch {
|
|
4609
|
+
return null;
|
|
4610
|
+
}
|
|
4611
|
+
}
|
|
4612
|
+
async function searchProtocols(rootDir, task, limit = 3) {
|
|
4613
|
+
const protocols = await loadProtocols(rootDir);
|
|
4614
|
+
if (protocols.length === 0) return [];
|
|
4615
|
+
const keywords = tokenize(task);
|
|
4616
|
+
if (keywords.length === 0) return [];
|
|
4617
|
+
const scored = [];
|
|
4618
|
+
for (const protocol of protocols) {
|
|
4619
|
+
let score = 0;
|
|
4620
|
+
for (const trigger of protocol.trigger) {
|
|
4621
|
+
const triggerLower = trigger.toLowerCase();
|
|
4622
|
+
for (const kw of keywords) {
|
|
4623
|
+
if (triggerLower.includes(kw)) {
|
|
4624
|
+
score += 3;
|
|
4625
|
+
}
|
|
4626
|
+
}
|
|
4627
|
+
}
|
|
4628
|
+
for (const tag of protocol.tags) {
|
|
4629
|
+
const tagLower = tag.toLowerCase();
|
|
4630
|
+
for (const kw of keywords) {
|
|
4631
|
+
if (tagLower.includes(kw) || kw.includes(tagLower)) {
|
|
4632
|
+
score += 2;
|
|
4633
|
+
}
|
|
4634
|
+
}
|
|
4635
|
+
}
|
|
4636
|
+
const nameLower = protocol.name.toLowerCase();
|
|
4637
|
+
const descLower = protocol.description.toLowerCase();
|
|
4638
|
+
for (const kw of keywords) {
|
|
4639
|
+
if (nameLower.includes(kw)) score += 1;
|
|
4640
|
+
if (descLower.includes(kw)) score += 1;
|
|
4641
|
+
}
|
|
4642
|
+
for (const step of protocol.steps) {
|
|
4643
|
+
if (step.notes) {
|
|
4644
|
+
const notesLower = step.notes.toLowerCase();
|
|
4645
|
+
for (const kw of keywords) {
|
|
4646
|
+
if (notesLower.includes(kw)) score += 0.5;
|
|
4647
|
+
}
|
|
4648
|
+
}
|
|
4649
|
+
}
|
|
4650
|
+
if (score > 0) {
|
|
4651
|
+
scored.push({ protocol, score });
|
|
4652
|
+
}
|
|
4653
|
+
}
|
|
4654
|
+
scored.sort((a, b) => b.score - a.score);
|
|
4655
|
+
return scored.slice(0, limit);
|
|
4656
|
+
}
|
|
4657
|
+
async function recordProtocol(rootDir, protocol) {
|
|
4658
|
+
const protocolsDir = path9.join(rootDir, PROTOCOLS_DIR);
|
|
4659
|
+
if (!fs8.existsSync(protocolsDir)) {
|
|
4660
|
+
fs8.mkdirSync(protocolsDir, { recursive: true });
|
|
4661
|
+
}
|
|
4662
|
+
const slug = slugify(protocol.name);
|
|
4663
|
+
const id = `P-${slug}`;
|
|
4664
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4665
|
+
const full = {
|
|
4666
|
+
id,
|
|
4667
|
+
name: protocol.name,
|
|
4668
|
+
description: protocol.description,
|
|
4669
|
+
trigger: protocol.trigger,
|
|
4670
|
+
tags: protocol.tags,
|
|
4671
|
+
symbols: protocol.symbols || [],
|
|
4672
|
+
exemplar: protocol.exemplar,
|
|
4673
|
+
steps: protocol.steps,
|
|
4674
|
+
recorded_from: protocol.recorded_from,
|
|
4675
|
+
recorded_at: now,
|
|
4676
|
+
last_verified: now,
|
|
4677
|
+
verified_by: protocol.verified_by || "claude-opus-4-6",
|
|
4678
|
+
status: "current"
|
|
4679
|
+
};
|
|
4680
|
+
const filePath = path9.join(protocolsDir, `${slug}.protocol`);
|
|
4681
|
+
fs8.writeFileSync(filePath, yaml7.dump(full, { lineWidth: -1, noRefs: true }), "utf8");
|
|
4682
|
+
return id;
|
|
4683
|
+
}
|
|
4684
|
+
async function updateProtocol(rootDir, id, partial, refresh = false) {
|
|
4685
|
+
const protocol = await loadProtocol(rootDir, id);
|
|
4686
|
+
if (!protocol) return false;
|
|
4687
|
+
if (partial.name !== void 0) protocol.name = partial.name;
|
|
4688
|
+
if (partial.description !== void 0) protocol.description = partial.description;
|
|
4689
|
+
if (partial.trigger !== void 0) protocol.trigger = partial.trigger;
|
|
4690
|
+
if (partial.tags !== void 0) protocol.tags = partial.tags;
|
|
4691
|
+
if (partial.symbols !== void 0) protocol.symbols = partial.symbols;
|
|
4692
|
+
if (partial.exemplar !== void 0) protocol.exemplar = partial.exemplar;
|
|
4693
|
+
if (partial.steps !== void 0) protocol.steps = partial.steps;
|
|
4694
|
+
if (partial.status !== void 0) protocol.status = partial.status;
|
|
4695
|
+
if (partial.verified_by !== void 0) protocol.verified_by = partial.verified_by;
|
|
4696
|
+
if (refresh) {
|
|
4697
|
+
protocol.last_verified = (/* @__PURE__ */ new Date()).toISOString();
|
|
4698
|
+
protocol.verified_by = partial.verified_by || "claude-opus-4-6";
|
|
4699
|
+
}
|
|
4700
|
+
const slug = id.replace(/^P-/, "");
|
|
4701
|
+
const filePath = path9.join(rootDir, PROTOCOLS_DIR, `${slug}.protocol`);
|
|
4702
|
+
fs8.writeFileSync(filePath, yaml7.dump(protocol, { lineWidth: -1, noRefs: true }), "utf8");
|
|
4703
|
+
return true;
|
|
4704
|
+
}
|
|
4705
|
+
function validateProtocol(rootDir, protocol) {
|
|
4706
|
+
const issues = [];
|
|
4707
|
+
let status = "current";
|
|
4708
|
+
if (protocol.exemplar) {
|
|
4709
|
+
const exemplarPath = path9.join(rootDir, protocol.exemplar);
|
|
4710
|
+
if (!fs8.existsSync(exemplarPath)) {
|
|
4711
|
+
issues.push(`Exemplar missing: ${protocol.exemplar}`);
|
|
4712
|
+
status = "broken";
|
|
4713
|
+
} else {
|
|
4714
|
+
const stat = fs8.statSync(exemplarPath);
|
|
4715
|
+
if (stat.mtime.toISOString() > protocol.last_verified) {
|
|
4716
|
+
issues.push(`Exemplar modified since last verified: ${protocol.exemplar}`);
|
|
4717
|
+
if (status !== "broken") status = "stale";
|
|
4718
|
+
}
|
|
4719
|
+
}
|
|
4720
|
+
}
|
|
4721
|
+
for (const step of protocol.steps) {
|
|
4722
|
+
if (step.template_from) {
|
|
4723
|
+
const templatePath = path9.join(rootDir, step.template_from);
|
|
4724
|
+
if (!fs8.existsSync(templatePath)) {
|
|
4725
|
+
issues.push(`Template file missing: ${step.template_from}`);
|
|
4726
|
+
status = "broken";
|
|
4727
|
+
}
|
|
4728
|
+
}
|
|
4729
|
+
if (step.action === "modify" && step.target) {
|
|
4730
|
+
const targetPath = path9.join(rootDir, step.target);
|
|
4731
|
+
if (!step.target.includes("{") && !fs8.existsSync(targetPath)) {
|
|
4732
|
+
issues.push(`Modify target missing: ${step.target}`);
|
|
4733
|
+
status = "broken";
|
|
4734
|
+
}
|
|
4735
|
+
}
|
|
4736
|
+
}
|
|
4737
|
+
return { status, issues };
|
|
4738
|
+
}
|
|
4739
|
+
async function rebuildProtocolIndex(rootDir) {
|
|
4740
|
+
const protocols = await loadProtocols(rootDir);
|
|
4741
|
+
const entries = [];
|
|
4742
|
+
let current = 0;
|
|
4743
|
+
let stale = 0;
|
|
4744
|
+
let broken = 0;
|
|
4745
|
+
for (const protocol of protocols) {
|
|
4746
|
+
const validation = validateProtocol(rootDir, protocol);
|
|
4747
|
+
if (protocol.status !== validation.status) {
|
|
4748
|
+
protocol.status = validation.status;
|
|
4749
|
+
const slug = protocol.id.replace(/^P-/, "");
|
|
4750
|
+
const filePath = path9.join(rootDir, PROTOCOLS_DIR, `${slug}.protocol`);
|
|
4751
|
+
if (fs8.existsSync(filePath)) {
|
|
4752
|
+
fs8.writeFileSync(filePath, yaml7.dump(protocol, { lineWidth: -1, noRefs: true }), "utf8");
|
|
4753
|
+
}
|
|
4754
|
+
}
|
|
4755
|
+
switch (validation.status) {
|
|
4756
|
+
case "current":
|
|
4757
|
+
current++;
|
|
4758
|
+
break;
|
|
4759
|
+
case "stale":
|
|
4760
|
+
stale++;
|
|
4761
|
+
break;
|
|
4762
|
+
case "broken":
|
|
4763
|
+
broken++;
|
|
4764
|
+
break;
|
|
4765
|
+
}
|
|
4766
|
+
entries.push({
|
|
4767
|
+
id: protocol.id,
|
|
4768
|
+
name: protocol.name,
|
|
4769
|
+
status: validation.status,
|
|
4770
|
+
last_verified: protocol.last_verified,
|
|
4771
|
+
trigger: protocol.trigger,
|
|
4772
|
+
tags: protocol.tags
|
|
4773
|
+
});
|
|
4774
|
+
}
|
|
4775
|
+
const index = {
|
|
4776
|
+
version: "1.0",
|
|
4777
|
+
generated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4778
|
+
protocols: entries,
|
|
4779
|
+
health: {
|
|
4780
|
+
total: protocols.length,
|
|
4781
|
+
current,
|
|
4782
|
+
stale,
|
|
4783
|
+
broken
|
|
4784
|
+
}
|
|
4785
|
+
};
|
|
4786
|
+
const protocolsDir = path9.join(rootDir, PROTOCOLS_DIR);
|
|
4787
|
+
if (protocols.length > 0) {
|
|
4788
|
+
if (!fs8.existsSync(protocolsDir)) {
|
|
4789
|
+
fs8.mkdirSync(protocolsDir, { recursive: true });
|
|
4790
|
+
}
|
|
4791
|
+
const indexPath = path9.join(protocolsDir, INDEX_FILE2);
|
|
4792
|
+
fs8.writeFileSync(indexPath, yaml7.dump(index, { lineWidth: -1, noRefs: true }), "utf8");
|
|
4793
|
+
}
|
|
4794
|
+
return index;
|
|
4795
|
+
}
|
|
4796
|
+
function detectProtocolSuggestion(rootDir, filesCreated, filesModified) {
|
|
4797
|
+
if (!filesCreated || filesCreated.length < 2) return null;
|
|
4798
|
+
const dirGroups = {};
|
|
4799
|
+
for (const file of filesCreated) {
|
|
4800
|
+
const dir = path9.dirname(file);
|
|
4801
|
+
if (!dirGroups[dir]) dirGroups[dir] = [];
|
|
4802
|
+
dirGroups[dir].push(file);
|
|
4803
|
+
}
|
|
4804
|
+
for (const [dir, created] of Object.entries(dirGroups)) {
|
|
4805
|
+
if (created.length < 2) continue;
|
|
4806
|
+
const absDir = path9.join(rootDir, dir);
|
|
4807
|
+
if (!fs8.existsSync(absDir)) continue;
|
|
4808
|
+
const existing = fs8.readdirSync(absDir).filter((f) => {
|
|
4809
|
+
const ext = path9.extname(f);
|
|
4810
|
+
return [".ts", ".tsx", ".js", ".jsx", ".rs", ".py"].includes(ext);
|
|
4811
|
+
});
|
|
4812
|
+
const preExisting = existing.filter((f) => !created.some((c) => path9.basename(c) === f));
|
|
4813
|
+
if (preExisting.length > 0) {
|
|
4814
|
+
const exemplar = path9.join(dir, preExisting[0]);
|
|
4815
|
+
const steps = [
|
|
4816
|
+
...created.map((f) => ({ action: "create", target: f })),
|
|
4817
|
+
...filesModified.map((f) => ({ action: "modify", target: f }))
|
|
4818
|
+
];
|
|
4819
|
+
return {
|
|
4820
|
+
hint: `This session created ${created.length} new files in ${dir}/ following existing patterns. Consider recording a protocol.`,
|
|
4821
|
+
draft: {
|
|
4822
|
+
name: `Add a ${path9.basename(dir).replace(/s$/, "")}`,
|
|
4823
|
+
exemplar,
|
|
4824
|
+
steps
|
|
4825
|
+
}
|
|
4826
|
+
};
|
|
4827
|
+
}
|
|
4828
|
+
}
|
|
4829
|
+
return null;
|
|
4830
|
+
}
|
|
4831
|
+
function tokenize(text) {
|
|
4832
|
+
return text.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w) => w.length > 1).filter((w) => !STOP_WORDS.has(w));
|
|
4833
|
+
}
|
|
4834
|
+
var STOP_WORDS = /* @__PURE__ */ new Set([
|
|
4835
|
+
"a",
|
|
4836
|
+
"an",
|
|
4837
|
+
"the",
|
|
4838
|
+
"is",
|
|
4839
|
+
"are",
|
|
4840
|
+
"was",
|
|
4841
|
+
"were",
|
|
4842
|
+
"be",
|
|
4843
|
+
"been",
|
|
4844
|
+
"to",
|
|
4845
|
+
"of",
|
|
4846
|
+
"in",
|
|
4847
|
+
"for",
|
|
4848
|
+
"on",
|
|
4849
|
+
"with",
|
|
4850
|
+
"at",
|
|
4851
|
+
"by",
|
|
4852
|
+
"from",
|
|
4853
|
+
"it",
|
|
4854
|
+
"this",
|
|
4855
|
+
"that",
|
|
4856
|
+
"and",
|
|
4857
|
+
"or",
|
|
4858
|
+
"but",
|
|
4859
|
+
"if",
|
|
4860
|
+
"then",
|
|
4861
|
+
"so",
|
|
4862
|
+
"as",
|
|
4863
|
+
"do",
|
|
4864
|
+
"does",
|
|
4865
|
+
"did",
|
|
4866
|
+
"will",
|
|
4867
|
+
"would",
|
|
4868
|
+
"can",
|
|
4869
|
+
"could",
|
|
4870
|
+
"should",
|
|
4871
|
+
"may",
|
|
4872
|
+
"might",
|
|
4873
|
+
"must",
|
|
4874
|
+
"shall",
|
|
4875
|
+
"i",
|
|
4876
|
+
"me",
|
|
4877
|
+
"my",
|
|
4878
|
+
"we",
|
|
4879
|
+
"our",
|
|
4880
|
+
"you",
|
|
4881
|
+
"your",
|
|
4882
|
+
"he",
|
|
4883
|
+
"she",
|
|
4884
|
+
"how",
|
|
4885
|
+
"what",
|
|
4886
|
+
"when",
|
|
4887
|
+
"where",
|
|
4888
|
+
"which",
|
|
4889
|
+
"who",
|
|
4890
|
+
"whom"
|
|
4891
|
+
]);
|
|
4892
|
+
function slugify(name) {
|
|
4893
|
+
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
4894
|
+
}
|
|
4895
|
+
|
|
4561
4896
|
// ../paradigm-mcp/src/tools/reindex.ts
|
|
4562
4897
|
var SYMBOL_CATEGORIES = {
|
|
4563
4898
|
"@": { category: "features", prefix: "@" },
|
|
@@ -4646,10 +4981,10 @@ async function rebuildStaticFiles(rootDir, ctx) {
|
|
|
4646
4981
|
} else {
|
|
4647
4982
|
aggregation = await aggregateFromDirectory(rootDir);
|
|
4648
4983
|
}
|
|
4649
|
-
const projectName = ctx?.projectName ||
|
|
4650
|
-
const paradigmDir =
|
|
4651
|
-
if (!
|
|
4652
|
-
|
|
4984
|
+
const projectName = ctx?.projectName || path10.basename(rootDir);
|
|
4985
|
+
const paradigmDir = path10.join(rootDir, ".paradigm");
|
|
4986
|
+
if (!fs9.existsSync(paradigmDir)) {
|
|
4987
|
+
fs9.mkdirSync(paradigmDir, { recursive: true });
|
|
4653
4988
|
}
|
|
4654
4989
|
const scanIndex = generateScanIndex(
|
|
4655
4990
|
{
|
|
@@ -4659,22 +4994,22 @@ async function rebuildStaticFiles(rootDir, ctx) {
|
|
|
4659
4994
|
},
|
|
4660
4995
|
{ projectName }
|
|
4661
4996
|
);
|
|
4662
|
-
const scanIndexPath =
|
|
4663
|
-
|
|
4997
|
+
const scanIndexPath = path10.join(paradigmDir, "scan-index.json");
|
|
4998
|
+
fs9.writeFileSync(scanIndexPath, serializeScanIndex(scanIndex), "utf8");
|
|
4664
4999
|
filesWritten.push(".paradigm/scan-index.json");
|
|
4665
5000
|
const navigatorData = buildNavigatorData(rootDir, aggregation);
|
|
4666
|
-
const navigatorPath =
|
|
4667
|
-
|
|
5001
|
+
const navigatorPath = path10.join(paradigmDir, "navigator.yaml");
|
|
5002
|
+
fs9.writeFileSync(
|
|
4668
5003
|
navigatorPath,
|
|
4669
|
-
|
|
5004
|
+
yaml8.dump(navigatorData, { indent: 2, lineWidth: 120, noRefs: true, sortKeys: false }),
|
|
4670
5005
|
"utf8"
|
|
4671
5006
|
);
|
|
4672
5007
|
filesWritten.push(".paradigm/navigator.yaml");
|
|
4673
5008
|
const flowIndex = generateFlowIndex(rootDir, aggregation.purposeFiles);
|
|
4674
5009
|
let flowCount = 0;
|
|
4675
5010
|
if (flowIndex && Object.keys(flowIndex.flows).length > 0) {
|
|
4676
|
-
const flowIndexPath =
|
|
4677
|
-
|
|
5011
|
+
const flowIndexPath = path10.join(paradigmDir, "flow-index.json");
|
|
5012
|
+
fs9.writeFileSync(flowIndexPath, JSON.stringify(flowIndex, null, 2), "utf8");
|
|
4678
5013
|
filesWritten.push(".paradigm/flow-index.json");
|
|
4679
5014
|
flowCount = Object.keys(flowIndex.flows).length;
|
|
4680
5015
|
}
|
|
@@ -4706,6 +5041,15 @@ async function rebuildStaticFiles(rootDir, ctx) {
|
|
|
4706
5041
|
}
|
|
4707
5042
|
} catch {
|
|
4708
5043
|
}
|
|
5044
|
+
let protocolHealth;
|
|
5045
|
+
try {
|
|
5046
|
+
const protocolIndex = await rebuildProtocolIndex(rootDir);
|
|
5047
|
+
if (protocolIndex.health.total > 0) {
|
|
5048
|
+
protocolHealth = protocolIndex.health;
|
|
5049
|
+
filesWritten.push(".paradigm/protocols/index.yaml");
|
|
5050
|
+
}
|
|
5051
|
+
} catch {
|
|
5052
|
+
}
|
|
4709
5053
|
const breakdown = {};
|
|
4710
5054
|
for (const sym of aggregation.symbols) {
|
|
4711
5055
|
breakdown[sym.type] = (breakdown[sym.type] || 0) + 1;
|
|
@@ -4717,7 +5061,8 @@ async function rebuildStaticFiles(rootDir, ctx) {
|
|
|
4717
5061
|
breakdown,
|
|
4718
5062
|
flowCount,
|
|
4719
5063
|
aspectGraphStats,
|
|
4720
|
-
personaCount
|
|
5064
|
+
personaCount,
|
|
5065
|
+
protocolHealth
|
|
4721
5066
|
};
|
|
4722
5067
|
}
|
|
4723
5068
|
function buildNavigatorData(rootDir, aggregation) {
|
|
@@ -4733,7 +5078,7 @@ function buildNavigatorData(rootDir, aggregation) {
|
|
|
4733
5078
|
function buildStructure(rootDir) {
|
|
4734
5079
|
const structure = {};
|
|
4735
5080
|
for (const [category, patterns] of Object.entries(DIRECTORY_PATTERNS)) {
|
|
4736
|
-
const existingPaths = patterns.filter((p) =>
|
|
5081
|
+
const existingPaths = patterns.filter((p) => fs9.existsSync(path10.join(rootDir, p)));
|
|
4737
5082
|
if (existingPaths.length > 0) {
|
|
4738
5083
|
const symbolInfo = Object.values(SYMBOL_CATEGORIES).find((s) => s.category === category);
|
|
4739
5084
|
structure[category] = { paths: existingPaths, symbol: symbolInfo?.prefix || "@" };
|
|
@@ -4744,7 +5089,7 @@ function buildStructure(rootDir) {
|
|
|
4744
5089
|
function buildKeyFiles(rootDir) {
|
|
4745
5090
|
const keyFiles = {};
|
|
4746
5091
|
for (const [category, patterns] of Object.entries(KEY_FILE_PATTERNS)) {
|
|
4747
|
-
const existingPaths = patterns.filter((p) =>
|
|
5092
|
+
const existingPaths = patterns.filter((p) => fs9.existsSync(path10.join(rootDir, p)));
|
|
4748
5093
|
if (existingPaths.length > 0) {
|
|
4749
5094
|
keyFiles[category] = existingPaths;
|
|
4750
5095
|
}
|
|
@@ -4760,10 +5105,10 @@ function buildSkipPatterns(rootDir) {
|
|
|
4760
5105
|
unless_testing: [...DEFAULT_SKIP_PATTERNS.unless_testing],
|
|
4761
5106
|
unless_docs: [...DEFAULT_SKIP_PATTERNS.unless_docs]
|
|
4762
5107
|
};
|
|
4763
|
-
const gitignorePath =
|
|
4764
|
-
if (
|
|
5108
|
+
const gitignorePath = path10.join(rootDir, ".gitignore");
|
|
5109
|
+
if (fs9.existsSync(gitignorePath)) {
|
|
4765
5110
|
try {
|
|
4766
|
-
const content =
|
|
5111
|
+
const content = fs9.readFileSync(gitignorePath, "utf8");
|
|
4767
5112
|
const gitignorePatterns = content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).filter(
|
|
4768
5113
|
(line) => line.endsWith("/") || line.includes("*") || ["node_modules", "dist", "build", ".cache"].some((p) => line.includes(p))
|
|
4769
5114
|
).slice(0, 20);
|
|
@@ -4812,11 +5157,11 @@ function buildSymbolMap(symbols, purposeFiles, _rootDir) {
|
|
|
4812
5157
|
symbolMap[symbolId] = symbol.filePath;
|
|
4813
5158
|
} else {
|
|
4814
5159
|
const matchingPurpose = purposeFiles.find((pf) => {
|
|
4815
|
-
const dir =
|
|
5160
|
+
const dir = path10.dirname(pf);
|
|
4816
5161
|
return dir.toLowerCase().includes(symbol.id.toLowerCase());
|
|
4817
5162
|
});
|
|
4818
5163
|
if (matchingPurpose) {
|
|
4819
|
-
symbolMap[symbolId] =
|
|
5164
|
+
symbolMap[symbolId] = path10.dirname(matchingPurpose) + "/";
|
|
4820
5165
|
}
|
|
4821
5166
|
}
|
|
4822
5167
|
}
|
|
@@ -4827,8 +5172,8 @@ function generateFlowIndex(rootDir, purposeFiles) {
|
|
|
4827
5172
|
const symbolToFlows = {};
|
|
4828
5173
|
for (const filePath of purposeFiles) {
|
|
4829
5174
|
try {
|
|
4830
|
-
const content =
|
|
4831
|
-
const data =
|
|
5175
|
+
const content = fs9.readFileSync(filePath, "utf8");
|
|
5176
|
+
const data = yaml8.load(content);
|
|
4832
5177
|
if (!data?.flows) continue;
|
|
4833
5178
|
if (Array.isArray(data.flows)) {
|
|
4834
5179
|
for (const flowItem of data.flows) {
|
|
@@ -4841,7 +5186,7 @@ function generateFlowIndex(rootDir, purposeFiles) {
|
|
|
4841
5186
|
id: flowId,
|
|
4842
5187
|
description: flow.description || "",
|
|
4843
5188
|
steps,
|
|
4844
|
-
definedIn:
|
|
5189
|
+
definedIn: path10.relative(rootDir, filePath)
|
|
4845
5190
|
};
|
|
4846
5191
|
indexFlowSymbols(flowId, steps, symbolToFlows);
|
|
4847
5192
|
}
|
|
@@ -4857,7 +5202,7 @@ function generateFlowIndex(rootDir, purposeFiles) {
|
|
|
4857
5202
|
trigger: flowDef.trigger,
|
|
4858
5203
|
steps,
|
|
4859
5204
|
validation: flowDef.validation,
|
|
4860
|
-
definedIn:
|
|
5205
|
+
definedIn: path10.relative(rootDir, filePath)
|
|
4861
5206
|
};
|
|
4862
5207
|
indexFlowSymbols(flowId, steps, symbolToFlows);
|
|
4863
5208
|
}
|
|
@@ -4965,6 +5310,14 @@ export {
|
|
|
4965
5310
|
getPersonaCoverage,
|
|
4966
5311
|
getAffectedPersonas,
|
|
4967
5312
|
validateAgainstSentinel,
|
|
5313
|
+
loadProtocols,
|
|
5314
|
+
loadProtocol,
|
|
5315
|
+
loadProtocolIndex,
|
|
5316
|
+
searchProtocols,
|
|
5317
|
+
recordProtocol,
|
|
5318
|
+
updateProtocol,
|
|
5319
|
+
validateProtocol,
|
|
5320
|
+
detectProtocolSuggestion,
|
|
4968
5321
|
getReindexToolsList,
|
|
4969
5322
|
handleReindexTool,
|
|
4970
5323
|
rebuildStaticFiles
|
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-
|
|
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-
|
|
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
|
});
|