@mcptoolshop/claude-synergy 1.0.0 → 1.1.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/CHANGELOG.md +51 -0
- package/CONTRIBUTING.md +5 -4
- package/README.es.md +78 -26
- package/README.fr.md +77 -25
- package/README.hi.md +78 -26
- package/README.it.md +75 -23
- package/README.ja.md +78 -26
- package/README.md +78 -27
- package/README.pt-BR.md +77 -25
- package/README.zh.md +77 -25
- package/dist/chunk-H3466JDH.js +1564 -0
- package/dist/{chunk-HCIZPSW4.js → chunk-HZEQG3WT.js} +281 -1
- package/dist/cli.js +279 -457
- package/dist/ingest-Z45YH7OX.js +8 -0
- package/dist/mcp-server.js +252 -17
- package/package.json +1 -1
- package/products.yaml +12 -6
- package/schema-vec.sql +9 -5
- package/dist/chunk-YFGUTT22.js +0 -754
- package/dist/ingest-3LJNQWS7.js +0 -6
package/dist/mcp-server.js
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
browseChanges,
|
|
4
|
+
compareVersions,
|
|
3
5
|
entityFrequency,
|
|
6
|
+
getChangesSince,
|
|
7
|
+
getSynergy,
|
|
4
8
|
hybridSearch,
|
|
5
9
|
listProducts,
|
|
10
|
+
listSynergies,
|
|
6
11
|
lookupEntity,
|
|
7
12
|
openDb,
|
|
8
13
|
recentReleases,
|
|
9
14
|
searchChanges
|
|
10
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-H3466JDH.js";
|
|
11
16
|
|
|
12
17
|
// src/mcp-server.ts
|
|
13
18
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -63,6 +68,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
63
68
|
mode: { type: "string", enum: ["hybrid", "fts"], description: "hybrid = FTS5+vec via RRF (best for concepts); fts = BM25 only (best for exact terms)", default: "hybrid" },
|
|
64
69
|
product: { type: "string", description: "Limit to one product (e.g. claude-code, claude-agent-sdk-python, anthropic-cli)" },
|
|
65
70
|
since: { type: "string", description: "YYYY-MM-DD lower bound on release date" },
|
|
71
|
+
until: { type: "string", description: "YYYY-MM-DD upper bound on release date" },
|
|
66
72
|
kind: { type: "string", description: "Filter by change kind: added | fixed | breaking | deprecated | renamed | removed | improved | changed" },
|
|
67
73
|
rerank: { type: "string", enum: ["none", "ollama-judge"], description: "Rerank top-K candidates (hybrid mode only). Defaults to none for speed.", default: "none" },
|
|
68
74
|
limit: { type: "number", description: "Max results (default 10)", default: 10 }
|
|
@@ -93,6 +99,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
93
99
|
type: "object",
|
|
94
100
|
properties: {
|
|
95
101
|
product: { type: "string", description: "Limit to one product" },
|
|
102
|
+
since: { type: "string", description: "YYYY-MM-DD lower bound on release date" },
|
|
96
103
|
limit: { type: "number", description: "Max releases", default: 20 }
|
|
97
104
|
}
|
|
98
105
|
}
|
|
@@ -132,7 +139,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
132
139
|
{
|
|
133
140
|
name: "list_synergies",
|
|
134
141
|
description: "List curated cross-product workflows (Claude Design \u2194 Code bundle, MCP server portability, etc). Each synergy describes a composition pattern with evidence.",
|
|
135
|
-
inputSchema: {
|
|
142
|
+
inputSchema: {
|
|
143
|
+
type: "object",
|
|
144
|
+
properties: {
|
|
145
|
+
product: { type: "string", description: "Filter to synergies that mention this product (e.g. claude-code)" }
|
|
146
|
+
}
|
|
147
|
+
}
|
|
136
148
|
},
|
|
137
149
|
{
|
|
138
150
|
name: "read_synergy",
|
|
@@ -142,6 +154,47 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
142
154
|
properties: { name: { type: "string", description: "Synergy name from list_synergies (e.g. skill-portability)" } },
|
|
143
155
|
required: ["name"]
|
|
144
156
|
}
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
name: "get_changes_since",
|
|
160
|
+
description: 'Get all changes in a date window, grouped by product+version. The LLM-orientation tool: "what shipped in the last 7 days" without needing a search term. Use this before recommending features to know the current ground truth.',
|
|
161
|
+
inputSchema: {
|
|
162
|
+
type: "object",
|
|
163
|
+
properties: {
|
|
164
|
+
since: { type: "string", description: "Lower bound \u2014 YYYY-MM-DD, full ISO, or relative (e.g. 7d, 2w, 1m, 1y)" },
|
|
165
|
+
until: { type: "string", description: "Upper bound \u2014 YYYY-MM-DD, full ISO, or relative; defaults to now" },
|
|
166
|
+
product: { type: "string", description: "Limit to one product" },
|
|
167
|
+
kind: { type: "string", description: "Filter by change kind: added | fixed | breaking | deprecated | renamed | removed | improved | changed" },
|
|
168
|
+
limit: { type: "number", description: "Max change rows returned (default 200)", default: 200 }
|
|
169
|
+
},
|
|
170
|
+
required: ["since"]
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
name: "search_breaking_changes",
|
|
175
|
+
description: "Browse breaking changes in a date window. No search term required \u2014 returns all changes with kind=breaking, most recent first. Use this for upgrade-planning and migration workflows.",
|
|
176
|
+
inputSchema: {
|
|
177
|
+
type: "object",
|
|
178
|
+
properties: {
|
|
179
|
+
product: { type: "string", description: "Limit to one product" },
|
|
180
|
+
since: { type: "string", description: "Lower bound \u2014 YYYY-MM-DD, full ISO, or relative (e.g. 7d)" },
|
|
181
|
+
until: { type: "string", description: "Upper bound \u2014 YYYY-MM-DD, full ISO, or relative; defaults to now" },
|
|
182
|
+
limit: { type: "number", description: "Max results (default 50)", default: 50 }
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
name: "compare_versions",
|
|
188
|
+
description: 'Cumulative diff between two versions of a product, grouped by intermediate release. Use for upgrade planning ("I am on python 0.88.0, what changed through 0.94.0?"). Single call replaces N+1 get_release lookups.',
|
|
189
|
+
inputSchema: {
|
|
190
|
+
type: "object",
|
|
191
|
+
properties: {
|
|
192
|
+
product: { type: "string", description: "Product slug (e.g. anthropic-sdk-python)" },
|
|
193
|
+
from_version: { type: "string", description: "Starting version, exclusive (you are already on this)" },
|
|
194
|
+
to_version: { type: "string", description: "Target version, inclusive" }
|
|
195
|
+
},
|
|
196
|
+
required: ["product", "from_version", "to_version"]
|
|
197
|
+
}
|
|
145
198
|
}
|
|
146
199
|
]
|
|
147
200
|
}));
|
|
@@ -229,6 +282,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
229
282
|
mode: optEnum(r, "mode", SEARCH_MODES, "search"),
|
|
230
283
|
product: optString(r, "product", "search"),
|
|
231
284
|
since: optString(r, "since", "search"),
|
|
285
|
+
until: optString(r, "until", "search"),
|
|
232
286
|
kind: optString(r, "kind", "search"),
|
|
233
287
|
rerank: optEnum(r, "rerank", RERANK_MODES, "search"),
|
|
234
288
|
limit: optInt(r, "limit", "search")
|
|
@@ -266,6 +320,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
266
320
|
type: "text",
|
|
267
321
|
text: handleLatestReleases({
|
|
268
322
|
product: optString(r, "product", "latest_releases"),
|
|
323
|
+
since: optString(r, "since", "latest_releases"),
|
|
269
324
|
limit: optInt(r, "limit", "latest_releases")
|
|
270
325
|
})
|
|
271
326
|
}
|
|
@@ -306,8 +361,17 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
306
361
|
]
|
|
307
362
|
};
|
|
308
363
|
}
|
|
309
|
-
case "list_synergies":
|
|
310
|
-
|
|
364
|
+
case "list_synergies": {
|
|
365
|
+
const r = asRecord(args ?? {}, "list_synergies");
|
|
366
|
+
return {
|
|
367
|
+
content: [
|
|
368
|
+
{
|
|
369
|
+
type: "text",
|
|
370
|
+
text: handleListSynergies({ product: optString(r, "product", "list_synergies") })
|
|
371
|
+
}
|
|
372
|
+
]
|
|
373
|
+
};
|
|
374
|
+
}
|
|
311
375
|
case "read_synergy": {
|
|
312
376
|
const r = asRecord(args, "read_synergy");
|
|
313
377
|
const synName = requireString(r, "name", "read_synergy");
|
|
@@ -319,6 +383,54 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
319
383
|
}
|
|
320
384
|
return { content: [{ type: "text", text: handleReadSynergy({ name: synName }) }] };
|
|
321
385
|
}
|
|
386
|
+
case "get_changes_since": {
|
|
387
|
+
const r = asRecord(args, "get_changes_since");
|
|
388
|
+
return {
|
|
389
|
+
content: [
|
|
390
|
+
{
|
|
391
|
+
type: "text",
|
|
392
|
+
text: handleGetChangesSince({
|
|
393
|
+
since: requireString(r, "since", "get_changes_since"),
|
|
394
|
+
until: optString(r, "until", "get_changes_since"),
|
|
395
|
+
product: optString(r, "product", "get_changes_since"),
|
|
396
|
+
kind: optString(r, "kind", "get_changes_since"),
|
|
397
|
+
limit: optInt(r, "limit", "get_changes_since")
|
|
398
|
+
})
|
|
399
|
+
}
|
|
400
|
+
]
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
case "search_breaking_changes": {
|
|
404
|
+
const r = asRecord(args ?? {}, "search_breaking_changes");
|
|
405
|
+
return {
|
|
406
|
+
content: [
|
|
407
|
+
{
|
|
408
|
+
type: "text",
|
|
409
|
+
text: handleSearchBreakingChanges({
|
|
410
|
+
product: optString(r, "product", "search_breaking_changes"),
|
|
411
|
+
since: optString(r, "since", "search_breaking_changes"),
|
|
412
|
+
until: optString(r, "until", "search_breaking_changes"),
|
|
413
|
+
limit: optInt(r, "limit", "search_breaking_changes")
|
|
414
|
+
})
|
|
415
|
+
}
|
|
416
|
+
]
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
case "compare_versions": {
|
|
420
|
+
const r = asRecord(args, "compare_versions");
|
|
421
|
+
return {
|
|
422
|
+
content: [
|
|
423
|
+
{
|
|
424
|
+
type: "text",
|
|
425
|
+
text: handleCompareVersions({
|
|
426
|
+
product: requireString(r, "product", "compare_versions"),
|
|
427
|
+
from_version: requireString(r, "from_version", "compare_versions"),
|
|
428
|
+
to_version: requireString(r, "to_version", "compare_versions")
|
|
429
|
+
})
|
|
430
|
+
}
|
|
431
|
+
]
|
|
432
|
+
};
|
|
433
|
+
}
|
|
322
434
|
default:
|
|
323
435
|
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
324
436
|
}
|
|
@@ -334,6 +446,7 @@ async function handleSearch(args) {
|
|
|
334
446
|
const results2 = searchChanges(db, args.query, {
|
|
335
447
|
product: args.product,
|
|
336
448
|
since: args.since,
|
|
449
|
+
until: args.until,
|
|
337
450
|
kind: args.kind,
|
|
338
451
|
limit
|
|
339
452
|
});
|
|
@@ -355,6 +468,7 @@ async function handleSearch(args) {
|
|
|
355
468
|
const results = await hybridSearch(db, args.query, {
|
|
356
469
|
product: args.product,
|
|
357
470
|
since: args.since,
|
|
471
|
+
until: args.until,
|
|
358
472
|
kind: args.kind,
|
|
359
473
|
rerankProviderName: args.rerank ?? "none",
|
|
360
474
|
limit
|
|
@@ -396,7 +510,7 @@ function handleLookupEntity(args) {
|
|
|
396
510
|
}
|
|
397
511
|
function handleLatestReleases(args) {
|
|
398
512
|
const limit = args.limit ?? 20;
|
|
399
|
-
const releases = recentReleases(db, args.product, limit);
|
|
513
|
+
const releases = recentReleases(db, args.product, limit, args.since);
|
|
400
514
|
if (releases.length === 0) return "(no releases)";
|
|
401
515
|
return releases.map((r) => `${r.released_at} ${r.product}@${r.version} (${r.change_count} change${r.change_count === 1 ? "" : "s"})`).join("\n");
|
|
402
516
|
}
|
|
@@ -436,52 +550,173 @@ function handleTopEntities(args) {
|
|
|
436
550
|
if (results.length === 0) return `(no entities of type ${args.type})`;
|
|
437
551
|
return results.map((r) => `${String(r.count).padStart(4)} ${r.first_seen ?? "????-??-??"} ${r.value}`).join("\n");
|
|
438
552
|
}
|
|
439
|
-
function
|
|
553
|
+
function dbSynergiesEmpty() {
|
|
554
|
+
try {
|
|
555
|
+
const row = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='synergies'`).get();
|
|
556
|
+
if (!row) return true;
|
|
557
|
+
const count = db.prepare(`SELECT COUNT(*) AS n FROM synergies`).get();
|
|
558
|
+
return !count || count.n === 0;
|
|
559
|
+
} catch {
|
|
560
|
+
return true;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
function handleListSynergies(args = {}) {
|
|
564
|
+
if (!dbSynergiesEmpty()) {
|
|
565
|
+
try {
|
|
566
|
+
const rows = listSynergies(db, args.product ? { product: args.product } : void 0);
|
|
567
|
+
if (rows.length === 0) {
|
|
568
|
+
return args.product ? `(no synergies mention product "${args.product}")` : "(no synergies)";
|
|
569
|
+
}
|
|
570
|
+
const lines = [`Synergies (${rows.length}):
|
|
571
|
+
`];
|
|
572
|
+
for (const s of rows) {
|
|
573
|
+
const name = s.name ?? "";
|
|
574
|
+
const title = s.title ?? name;
|
|
575
|
+
const products = Array.isArray(s.products) ? s.products.join(", ") : s.products ?? "unknown";
|
|
576
|
+
const trigger = s.trigger ?? "";
|
|
577
|
+
lines.push(`- ${name}: ${title}`);
|
|
578
|
+
lines.push(` products: ${products}`);
|
|
579
|
+
if (trigger) lines.push(` trigger: ${trigger}`);
|
|
580
|
+
lines.push("");
|
|
581
|
+
}
|
|
582
|
+
return lines.join("\n");
|
|
583
|
+
} catch {
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
return listSynergiesFromDisk(args.product);
|
|
587
|
+
}
|
|
588
|
+
function listSynergiesFromDisk(productFilter) {
|
|
440
589
|
if (!existsSync(SYNERGIES_DIR)) return "(synergies dir not found)";
|
|
441
590
|
const files = readdirSync(SYNERGIES_DIR).filter((f) => f.endsWith(".md") && f !== "INDEX.md");
|
|
442
591
|
if (files.length === 0) return "(no synergies)";
|
|
443
|
-
const lines = [
|
|
444
|
-
|
|
592
|
+
const lines = [];
|
|
593
|
+
let count = 0;
|
|
445
594
|
for (const f of files) {
|
|
446
595
|
try {
|
|
447
596
|
const raw = readFileSync(join(SYNERGIES_DIR, f), "utf-8");
|
|
448
597
|
const { data } = matter(raw);
|
|
598
|
+
const products = Array.isArray(data.products) ? data.products : [];
|
|
599
|
+
if (productFilter && !products.includes(productFilter)) continue;
|
|
449
600
|
const name = data.name ?? f.replace(/\.md$/, "");
|
|
450
601
|
const title = data.title ?? name;
|
|
451
|
-
const products = Array.isArray(data.products) ? data.products.join(", ") : "unknown";
|
|
452
602
|
const trigger = data.trigger ?? "";
|
|
453
603
|
lines.push(`- ${name}: ${title}`);
|
|
454
|
-
lines.push(` products: ${products}`);
|
|
604
|
+
lines.push(` products: ${products.length > 0 ? products.join(", ") : "unknown"}`);
|
|
455
605
|
if (trigger) lines.push(` trigger: ${trigger}`);
|
|
456
606
|
lines.push("");
|
|
607
|
+
count += 1;
|
|
457
608
|
} catch {
|
|
458
609
|
}
|
|
459
610
|
}
|
|
460
|
-
|
|
611
|
+
if (count === 0) {
|
|
612
|
+
return productFilter ? `(no synergies mention product "${productFilter}")` : "(no synergies)";
|
|
613
|
+
}
|
|
614
|
+
return [`Synergies (${count}):
|
|
615
|
+
`, ...lines].join("\n");
|
|
461
616
|
}
|
|
462
617
|
function handleReadSynergy(args) {
|
|
463
|
-
if (!existsSync(SYNERGIES_DIR)) return "(synergies dir not found)";
|
|
464
618
|
if (!SYNERGY_NAME_RE.test(args.name)) {
|
|
465
619
|
return `(synergy not found: ${args.name})`;
|
|
466
620
|
}
|
|
621
|
+
if (!dbSynergiesEmpty()) {
|
|
622
|
+
try {
|
|
623
|
+
const synergy = getSynergy(db, args.name);
|
|
624
|
+
if (synergy && synergy.body) {
|
|
625
|
+
return synergy.body;
|
|
626
|
+
}
|
|
627
|
+
} catch {
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
if (!existsSync(SYNERGIES_DIR)) return `(synergy not found: ${args.name})`;
|
|
467
631
|
const files = readdirSync(SYNERGIES_DIR).filter((f) => f.endsWith(".md"));
|
|
468
632
|
const targetFile = files.find((f) => basename(f, ".md") === args.name);
|
|
469
633
|
if (targetFile) {
|
|
470
|
-
|
|
471
|
-
return raw;
|
|
634
|
+
return readFileSync(join(SYNERGIES_DIR, targetFile), "utf-8");
|
|
472
635
|
}
|
|
473
636
|
for (const f of files) {
|
|
474
637
|
try {
|
|
475
638
|
const raw = readFileSync(join(SYNERGIES_DIR, f), "utf-8");
|
|
476
639
|
const { data } = matter(raw);
|
|
477
|
-
if (data.name === args.name)
|
|
478
|
-
return raw;
|
|
479
|
-
}
|
|
640
|
+
if (data.name === args.name) return raw;
|
|
480
641
|
} catch {
|
|
481
642
|
}
|
|
482
643
|
}
|
|
483
644
|
return `(synergy not found: ${args.name})`;
|
|
484
645
|
}
|
|
646
|
+
function formatChangesSinceResults(results) {
|
|
647
|
+
if (results.length === 0) {
|
|
648
|
+
return "(no changes in window \u2014 try widening --since)";
|
|
649
|
+
}
|
|
650
|
+
const lines = [];
|
|
651
|
+
let total = 0;
|
|
652
|
+
for (const rel of results) {
|
|
653
|
+
const date = rel.released_at ?? "????-??-??";
|
|
654
|
+
lines.push(`${date} ${rel.product}@${rel.version} (${rel.changes.length} change${rel.changes.length === 1 ? "" : "s"})`);
|
|
655
|
+
for (const c of rel.changes) {
|
|
656
|
+
lines.push(` - [${c.kind}] ${c.text}`);
|
|
657
|
+
}
|
|
658
|
+
lines.push("");
|
|
659
|
+
total += rel.changes.length;
|
|
660
|
+
}
|
|
661
|
+
lines.push(`${total} change${total === 1 ? "" : "s"} across ${results.length} release${results.length === 1 ? "" : "s"}`);
|
|
662
|
+
return lines.join("\n");
|
|
663
|
+
}
|
|
664
|
+
function handleGetChangesSince(args) {
|
|
665
|
+
let results;
|
|
666
|
+
try {
|
|
667
|
+
results = getChangesSince(db, {
|
|
668
|
+
since: args.since,
|
|
669
|
+
until: args.until,
|
|
670
|
+
product: args.product,
|
|
671
|
+
kind: args.kind,
|
|
672
|
+
limit: args.limit ?? 200
|
|
673
|
+
});
|
|
674
|
+
} catch (e) {
|
|
675
|
+
throw new McpError(ErrorCode.InvalidParams, `get_changes_since: ${e.message}`);
|
|
676
|
+
}
|
|
677
|
+
return formatChangesSinceResults(results);
|
|
678
|
+
}
|
|
679
|
+
function handleSearchBreakingChanges(args) {
|
|
680
|
+
let results;
|
|
681
|
+
try {
|
|
682
|
+
results = browseChanges(db, {
|
|
683
|
+
product: args.product,
|
|
684
|
+
since: args.since,
|
|
685
|
+
until: args.until,
|
|
686
|
+
kind: "breaking",
|
|
687
|
+
limit: args.limit ?? 50
|
|
688
|
+
});
|
|
689
|
+
} catch (e) {
|
|
690
|
+
throw new McpError(ErrorCode.InvalidParams, `search_breaking_changes: ${e.message}`);
|
|
691
|
+
}
|
|
692
|
+
if (results.length === 0) {
|
|
693
|
+
return "(no breaking changes \u2014 note: ingest may not have classified any changes as breaking yet)";
|
|
694
|
+
}
|
|
695
|
+
const lines = [];
|
|
696
|
+
for (const r of results) {
|
|
697
|
+
lines.push(`${r.released_at ?? "????-??-??"} ${r.product}@${r.version} [${r.kind}]`);
|
|
698
|
+
lines.push(` ${r.text}`);
|
|
699
|
+
lines.push("");
|
|
700
|
+
}
|
|
701
|
+
lines.push(`${results.length} breaking change${results.length === 1 ? "" : "s"}`);
|
|
702
|
+
return lines.join("\n");
|
|
703
|
+
}
|
|
704
|
+
function handleCompareVersions(args) {
|
|
705
|
+
let results;
|
|
706
|
+
try {
|
|
707
|
+
results = compareVersions(db, {
|
|
708
|
+
product: args.product,
|
|
709
|
+
fromVersion: args.from_version,
|
|
710
|
+
toVersion: args.to_version
|
|
711
|
+
});
|
|
712
|
+
} catch (e) {
|
|
713
|
+
throw new McpError(ErrorCode.InvalidParams, `compare_versions: ${e.message}`);
|
|
714
|
+
}
|
|
715
|
+
if (results.length === 0) {
|
|
716
|
+
return `(no intermediate releases between ${args.product}@${args.from_version} and ${args.product}@${args.to_version})`;
|
|
717
|
+
}
|
|
718
|
+
return formatChangesSinceResults(results);
|
|
719
|
+
}
|
|
485
720
|
function shutdownMcp() {
|
|
486
721
|
try {
|
|
487
722
|
db.close();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcptoolshop/claude-synergy",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Local mirror of Anthropic product changelogs + curated cross-product synergies. So the LLM agent inside the harness knows what the harness can do.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
package/products.yaml
CHANGED
|
@@ -62,14 +62,20 @@
|
|
|
62
62
|
|
|
63
63
|
products:
|
|
64
64
|
|
|
65
|
-
# ── Tier
|
|
65
|
+
# ── Tier 1 / Anthropic flagship product ──────────────────────────────────
|
|
66
|
+
# FE-1 (2026-05-22): wired up automated sync via GH Releases. The repo
|
|
67
|
+
# publishes a per-version GitHub Release whose body mirrors CHANGELOG.md,
|
|
68
|
+
# so gh-releases yields strictly richer data than parsing the raw file
|
|
69
|
+
# (released_at, html_url, tag_name are all structured). Bumped to tier 1
|
|
70
|
+
# from tier 2 to reflect that this is now a Structured-API source.
|
|
66
71
|
- name: claude-code
|
|
67
72
|
display_name: Claude Code
|
|
68
|
-
tier:
|
|
69
|
-
source_url: https://github.com/anthropics/claude-code
|
|
70
|
-
fetch_strategy:
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
tier: 1
|
|
74
|
+
source_url: https://github.com/anthropics/claude-code
|
|
75
|
+
fetch_strategy: gh-releases
|
|
76
|
+
fetch:
|
|
77
|
+
type: gh-releases
|
|
78
|
+
repo: anthropics/claude-code
|
|
73
79
|
|
|
74
80
|
# ── Tier 3 / HTML feeds ──────────────────────────────────────────────────
|
|
75
81
|
- name: claude-api
|
package/schema-vec.sql
CHANGED
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
-- Run after schema.sql. Tables here are independent of Tier 2a's changes_fts,
|
|
3
3
|
-- so naive FTS still works on the raw bullets while hybrid uses the contextualized layer.
|
|
4
4
|
--
|
|
5
|
-
-- Dimension:
|
|
5
|
+
-- Dimension: configurable, stored in `schema_meta` under the key
|
|
6
|
+
-- `embedding_dim` (see src/db.ts). The `chunks_vec` virtual table is created
|
|
7
|
+
-- in code by initVecSchema() in src/embed.ts using the negotiated dim so that
|
|
8
|
+
-- switching providers (Ollama 768d, Voyage 768d-truncated, OpenAI 1536d, etc.)
|
|
9
|
+
-- works without manual schema edits. Default is 768 (nomic-embed-text native;
|
|
10
|
+
-- Voyage 3 truncatable via Matryoshka).
|
|
6
11
|
-- One row per change. Reranking deferred.
|
|
7
12
|
|
|
8
13
|
CREATE TABLE IF NOT EXISTS chunks (
|
|
@@ -22,10 +27,9 @@ CREATE TABLE IF NOT EXISTS chunks (
|
|
|
22
27
|
CREATE INDEX IF NOT EXISTS idx_chunks_product ON chunks(product, released_at);
|
|
23
28
|
CREATE INDEX IF NOT EXISTS idx_chunks_change ON chunks(change_id);
|
|
24
29
|
|
|
25
|
-
--
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
);
|
|
30
|
+
-- NOTE: `chunks_vec` is created dynamically by src/embed.ts initVecSchema()
|
|
31
|
+
-- so its dimension can match the configured embedding provider. The legacy
|
|
32
|
+
-- 768-dim definition is preserved in db migration code for backward compat.
|
|
29
33
|
|
|
30
34
|
-- FTS5 over the contextualized text (separate from changes_fts which indexes raw bullets)
|
|
31
35
|
CREATE VIRTUAL TABLE IF NOT EXISTS chunks_fts USING fts5(
|