@contentrain/mcp 1.5.2 → 1.8.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/README.md +8 -7
- package/dist/{apply-manager-BJ3nKEls.mjs → apply-manager-BRmB27H5.mjs} +5 -5
- package/dist/{apply-manager-BJ3nKEls.mjs.map → apply-manager-BRmB27H5.mjs.map} +1 -1
- package/dist/branch-lifecycle-7dQoF22r.d.mts +141 -0
- package/dist/branch-lifecycle-7dQoF22r.d.mts.map +1 -0
- package/dist/branch-lifecycle-D7tXOE4f.mjs +444 -0
- package/dist/branch-lifecycle-D7tXOE4f.mjs.map +1 -0
- package/dist/{config-Lw7vpK9n.mjs → config-DlFcTxFG.mjs} +3 -2
- package/dist/config-DlFcTxFG.mjs.map +1 -0
- package/dist/{context-DS40WOdw.mjs → context-CYN__o3Q.mjs} +24 -11
- package/dist/context-CYN__o3Q.mjs.map +1 -0
- package/dist/core/apply-manager.mjs +6 -6
- package/dist/core/config.d.mts.map +1 -1
- package/dist/core/config.mjs +1 -1
- package/dist/core/context.d.mts +20 -2
- package/dist/core/context.d.mts.map +1 -1
- package/dist/core/context.mjs +2 -2
- package/dist/core/doctor.mjs +3 -3
- package/dist/core/ops/index.d.mts +7 -0
- package/dist/core/ops/index.d.mts.map +1 -1
- package/dist/core/ops/index.mjs +1 -1
- package/dist/core/validator/index.mjs +2 -2
- package/dist/{detect-DL9mFmaS.mjs → detect-eWS6lvoH.mjs} +1 -1
- package/dist/{detect-DL9mFmaS.mjs.map → detect-eWS6lvoH.mjs.map} +1 -1
- package/dist/{doctor-Dxu_SzZy.mjs → doctor-qiUKCy9b.mjs} +34 -15
- package/dist/doctor-qiUKCy9b.mjs.map +1 -0
- package/dist/git/branch-lifecycle.d.mts +2 -57
- package/dist/git/branch-lifecycle.mjs +3 -3
- package/dist/git/transaction.d.mts +2 -0
- package/dist/git/transaction.d.mts.map +1 -1
- package/dist/git/transaction.mjs +5 -4
- package/dist/{id-CIO9s0x_.mjs → id-DV_T9Ic8.mjs} +1 -1
- package/dist/{id-CIO9s0x_.mjs.map → id-DV_T9Ic8.mjs.map} +1 -1
- package/dist/index.mjs +12 -12
- package/dist/{local-BJEAd4Ub.mjs → local-BZEUWBoC.mjs} +9 -12
- package/dist/local-BZEUWBoC.mjs.map +1 -0
- package/dist/{ops-DjEWi5Wa.mjs → ops-Dh2T3u53.mjs} +90 -5
- package/dist/ops-Dh2T3u53.mjs.map +1 -0
- package/dist/providers/github/index.d.mts +23 -2
- package/dist/providers/github/index.d.mts.map +1 -1
- package/dist/providers/github/index.mjs +112 -51
- package/dist/providers/github/index.mjs.map +1 -1
- package/dist/providers/gitlab/index.d.mts +3 -1
- package/dist/providers/gitlab/index.d.mts.map +1 -1
- package/dist/providers/gitlab/index.mjs +21 -5
- package/dist/providers/gitlab/index.mjs.map +1 -1
- package/dist/providers/local/index.mjs +7 -6
- package/dist/server/http/index.d.mts +1 -1
- package/dist/server/http/index.mjs +12 -12
- package/dist/{server-WqGx6ait.d.mts → server-DZBcZWhE.d.mts} +1 -1
- package/dist/{server-WqGx6ait.d.mts.map → server-DZBcZWhE.d.mts.map} +1 -1
- package/dist/{server-RwV1Ig5l.mjs → server-tTuinKHD.mjs} +60 -25
- package/dist/server-tTuinKHD.mjs.map +1 -0
- package/dist/server.d.mts +1 -1
- package/dist/server.mjs +12 -12
- package/dist/{transaction-LiTjan9Q.mjs → transaction-qliKvBRL.mjs} +104 -60
- package/dist/transaction-qliKvBRL.mjs.map +1 -0
- package/dist/util/detect.mjs +1 -1
- package/dist/util/id.mjs +1 -1
- package/dist/{validator-Bo06QPVB.mjs → validator-Z3DGNWQ6.mjs} +2 -2
- package/dist/{validator-Bo06QPVB.mjs.map → validator-Z3DGNWQ6.mjs.map} +1 -1
- package/package.json +2 -2
- package/dist/branch-lifecycle-DjX3MXNG.mjs +0 -149
- package/dist/branch-lifecycle-DjX3MXNG.mjs.map +0 -1
- package/dist/config-Lw7vpK9n.mjs.map +0 -1
- package/dist/context-DS40WOdw.mjs.map +0 -1
- package/dist/doctor-Dxu_SzZy.mjs.map +0 -1
- package/dist/git/branch-lifecycle.d.mts.map +0 -1
- package/dist/local-BJEAd4Ub.mjs.map +0 -1
- package/dist/ops-DjEWi5Wa.mjs.map +0 -1
- package/dist/server-RwV1Ig5l.mjs.map +0 -1
- package/dist/transaction-LiTjan9Q.mjs.map +0 -1
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { i as planContentDelete, n as planModelDelete, r as planContentSave, t as planModelSave } from "./ops-
|
|
1
|
+
import { i as planContentDelete, n as planModelDelete, r as planContentSave, t as planModelSave } from "./ops-Dh2T3u53.mjs";
|
|
2
2
|
import { n as contentFilePath, t as contentDirPath } from "./paths-CYl5vCBD.mjs";
|
|
3
3
|
import { a as readJson, n as ensureDir, r as pathExists, s as writeJson, t as contentrainDir } from "./fs-DLbVB-Ek.mjs";
|
|
4
|
-
import { n as readVocabulary, t as readConfig } from "./config-
|
|
4
|
+
import { n as readVocabulary, t as readConfig } from "./config-DlFcTxFG.mjs";
|
|
5
5
|
import { S as writeContent, _ as resolveMdFilePath, a as fieldDefZodSchema, c as validateModelDefinition, d as listContent, g as resolveLocaleStrategy, h as resolveJsonFilePath, l as writeModel, m as resolveContentDir, n as checkReferences, o as listModels, r as countEntries, s as readModel, u as deleteContent } from "./model-manager-BhLsUgaB.mjs";
|
|
6
6
|
import { n as readMeta, r as writeMeta } from "./meta-manager-C900rEyG.mjs";
|
|
7
|
-
import { n as readContext } from "./context-
|
|
8
|
-
import {
|
|
9
|
-
import { n as
|
|
10
|
-
import { t as
|
|
11
|
-
import {
|
|
7
|
+
import { n as readContext } from "./context-CYN__o3Q.mjs";
|
|
8
|
+
import { a as deleteRemoteBranch, c as pruneMergedRemoteBranches, i as cleanupMergedBranches, n as checkBranchHealth, s as listRemoteCrBranches } from "./branch-lifecycle-D7tXOE4f.mjs";
|
|
9
|
+
import { i as mergeBranch, n as createTransaction, r as ensureContentBranch, t as buildBranchName } from "./transaction-qliKvBRL.mjs";
|
|
10
|
+
import { n as isMerged, t as LocalProvider } from "./local-BZEUWBoC.mjs";
|
|
11
|
+
import { t as detectStack } from "./detect-eWS6lvoH.mjs";
|
|
12
12
|
import { t as TOOL_ANNOTATIONS } from "./annotations-BFJbfSKe.mjs";
|
|
13
13
|
import { n as listTemplates, t as getTemplate } from "./templates-VrLVqfe5.mjs";
|
|
14
|
-
import { t as validateProject } from "./validator-
|
|
14
|
+
import { t as validateProject } from "./validator-Z3DGNWQ6.mjs";
|
|
15
15
|
import { t as OverlayReader } from "./overlay-reader-CUs9jgqk.mjs";
|
|
16
16
|
import { t as buildGraph } from "./graph-builder-DXv2JEp-.mjs";
|
|
17
17
|
import { n as scanSummary, t as scanCandidates } from "./scanner-DKMwc03k.mjs";
|
|
18
|
-
import { n as applyExtract, r as applyReuse } from "./apply-manager-
|
|
19
|
-
import { t as runDoctor } from "./doctor-
|
|
18
|
+
import { n as applyExtract, r as applyReuse } from "./apply-manager-BRmB27H5.mjs";
|
|
19
|
+
import { t as runDoctor } from "./doctor-qiUKCy9b.mjs";
|
|
20
20
|
import { join } from "node:path";
|
|
21
21
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
22
22
|
import { CONTENTRAIN_BRANCH } from "@contentrain/types";
|
|
@@ -1030,7 +1030,7 @@ const validateModel = validateModelDefinition;
|
|
|
1030
1030
|
//#endregion
|
|
1031
1031
|
//#region src/tools/content.ts
|
|
1032
1032
|
function registerContentTools(server, provider, projectRoot) {
|
|
1033
|
-
server.tool("contentrain_content_save", "Save content entries. Entry format varies by model kind: DICTIONARY — provide \"locale\" and \"data\" (flat key-value, all string values); \"id\" and \"slug\" are ignored; data keys are the identities. COLLECTION — provide \"locale\" and \"data\"; \"id\" is optional (auto-generated if omitted); \"slug\" is ignored. DOCUMENT — provide \"slug\" (required), \"locale\", and \"data\"; use the \"body\" key inside data for markdown content. SINGLETON — provide only \"locale\" and \"data\". Changes are auto-committed to git — do NOT manually edit .contentrain/ files after calling this tool.", {
|
|
1033
|
+
server.tool("contentrain_content_save", "Save content entries. Entry format varies by model kind: DICTIONARY — provide \"locale\" and \"data\" (flat key-value, all string values); \"id\" and \"slug\" are ignored; data keys are the identities. COLLECTION — provide \"locale\" and \"data\"; \"id\" is optional (auto-generated if omitted); \"slug\" is ignored. DOCUMENT — provide \"slug\" (required), \"locale\", and \"data\"; use the \"body\" key inside data for markdown content. SINGLETON — provide only \"locale\" and \"data\". MEDIA FIELDS (image/video/file): for a media-library asset, pass its storage path (\"media/...\") or URL; in cloud mode these are automatically normalized to absolute public delivery URLs on save (in markdown bodies too), so saved content renders in a browser anywhere with no SDK — in local mode the relative path is kept as-is. For external images (e.g. a CDN or Unsplash URL), pass the URL directly; it is saved untouched. Changes are auto-committed to git — do NOT manually edit .contentrain/ files after calling this tool.", {
|
|
1034
1034
|
model: z.string().describe("Model ID"),
|
|
1035
1035
|
entries: z.array(z.object({
|
|
1036
1036
|
id: z.string().optional().describe("Entry ID (collection only, auto-generated if omitted)"),
|
|
@@ -1118,7 +1118,8 @@ function registerContentTools(server, provider, projectRoot) {
|
|
|
1118
1118
|
model,
|
|
1119
1119
|
entries: input.entries,
|
|
1120
1120
|
config,
|
|
1121
|
-
vocabulary
|
|
1121
|
+
vocabulary,
|
|
1122
|
+
mediaBaseUrl: provider.mediaBaseUrl
|
|
1122
1123
|
});
|
|
1123
1124
|
} catch (error) {
|
|
1124
1125
|
return {
|
|
@@ -1575,10 +1576,15 @@ function registerWorkflowTools(server, provider, projectRoot) {
|
|
|
1575
1576
|
await git.push(remoteName, CONTENTRAIN_BRANCH);
|
|
1576
1577
|
} catch {}
|
|
1577
1578
|
const cleanup = await cleanupMergedBranches(projectRoot);
|
|
1579
|
+
const remotePrune = await pruneMergedRemoteBranches(projectRoot, {
|
|
1580
|
+
config,
|
|
1581
|
+
max: 20
|
|
1582
|
+
});
|
|
1578
1583
|
const nextSteps = [];
|
|
1579
1584
|
if (pushed.length > 0) nextSteps.push("Create PRs on your git platform for review");
|
|
1580
1585
|
if (pushed.length > 0) nextSteps.push("For merge: use contentrain_merge or direct user to http://localhost:3333/branches");
|
|
1581
1586
|
if (errors.length > 0) nextSteps.push("Fix push errors and retry");
|
|
1587
|
+
if (remotePrune.errors.length > 0) nextSteps.push("Some merged remote branches could not be pruned — run `contentrain prune`");
|
|
1582
1588
|
if (cleanup.remaining >= 50) nextSteps.push(`Warning: ${cleanup.remaining} active contentrain branches. Consider reviewing old branches.`);
|
|
1583
1589
|
return { content: [{
|
|
1584
1590
|
type: "text",
|
|
@@ -1592,6 +1598,7 @@ function registerWorkflowTools(server, provider, projectRoot) {
|
|
|
1592
1598
|
deleted: cleanup.deleted,
|
|
1593
1599
|
remaining: cleanup.remaining
|
|
1594
1600
|
} : void 0,
|
|
1601
|
+
remote_cleanup: remotePrune.deleted.length > 0 ? { deleted: remotePrune.deleted.length } : void 0,
|
|
1595
1602
|
next_steps: nextSteps
|
|
1596
1603
|
}, null, 2)
|
|
1597
1604
|
}] };
|
|
@@ -1643,10 +1650,12 @@ function registerWorkflowTools(server, provider, projectRoot) {
|
|
|
1643
1650
|
action: result.action,
|
|
1644
1651
|
commit: result.commit,
|
|
1645
1652
|
sync: result.sync,
|
|
1653
|
+
...result.remote ? { remote: result.remote } : {},
|
|
1646
1654
|
next_steps: [
|
|
1647
1655
|
"Run `contentrain generate` (or `npx contentrain-query generate`) to update the SDK client",
|
|
1648
1656
|
"Run contentrain_validate to verify content integrity",
|
|
1649
|
-
result.sync.skipped.length > 0 ? `${result.sync.skipped.length} file(s) skipped due to local changes — resolve manually` : ""
|
|
1657
|
+
result.sync.skipped.length > 0 ? `${result.sync.skipped.length} file(s) skipped due to local changes — resolve manually` : "",
|
|
1658
|
+
result.remote?.warning ? `Remote copy not deleted (${result.remote.warning}) — delete it manually: git push <remote> --delete ${targetBranch}` : ""
|
|
1650
1659
|
].filter(Boolean)
|
|
1651
1660
|
}, null, 2)
|
|
1652
1661
|
}] };
|
|
@@ -1660,12 +1669,17 @@ function registerWorkflowTools(server, provider, projectRoot) {
|
|
|
1660
1669
|
};
|
|
1661
1670
|
}
|
|
1662
1671
|
});
|
|
1663
|
-
server.tool("contentrain_branch_list", "List pending contentrain (cr/*) branches with their merge status against the contentrain branch. Use this to discover branch names for contentrain_merge / contentrain_branch_delete, and to monitor branch-health limits (warning at 50, blocked at 80 unmerged).", {
|
|
1672
|
+
server.tool("contentrain_branch_list", "List pending contentrain (cr/*) branches with their merge status against the contentrain branch. Use this to discover branch names for contentrain_merge / contentrain_branch_delete, and to monitor branch-health limits (warning at 50, blocked at 80 unmerged).", {
|
|
1673
|
+
unmerged_only: z.boolean().optional().describe("Only list branches not yet merged into contentrain. Default: false"),
|
|
1674
|
+
remote: z.boolean().optional().describe("Also check the git remote: annotate entries with on_remote and report remote-only cr/* leftovers. Requires network. Default: false")
|
|
1675
|
+
}, TOOL_ANNOTATIONS["contentrain_branch_list"], async (input) => {
|
|
1664
1676
|
if (!provider.capabilities.localWorktree || !projectRoot) return capabilityError("contentrain_branch_list", "localWorktree");
|
|
1665
1677
|
try {
|
|
1666
1678
|
const git = simpleGit(projectRoot);
|
|
1667
1679
|
const summary = await git.branchLocal();
|
|
1668
1680
|
const crBranches = summary.all.filter((b) => b.startsWith("cr/") && b !== CONTENTRAIN_BRANCH);
|
|
1681
|
+
const remoteList = input.remote ? await listRemoteCrBranches(projectRoot) : void 0;
|
|
1682
|
+
const remoteNames = remoteList && !remoteList.error ? new Set(remoteList.branches.map((b) => b.name)) : void 0;
|
|
1669
1683
|
const ordered = (await Promise.all(crBranches.map(async (name) => {
|
|
1670
1684
|
const [merged, ts] = await Promise.all([isMerged(projectRoot, name, CONTENTRAIN_BRANCH), git.raw([
|
|
1671
1685
|
"log",
|
|
@@ -1677,17 +1691,21 @@ function registerWorkflowTools(server, provider, projectRoot) {
|
|
|
1677
1691
|
name,
|
|
1678
1692
|
sha: summary.branches[name]?.commit ?? "",
|
|
1679
1693
|
merged,
|
|
1680
|
-
lastCommit: ts
|
|
1694
|
+
lastCommit: ts,
|
|
1695
|
+
...remoteNames ? { on_remote: remoteNames.has(name) } : {}
|
|
1681
1696
|
};
|
|
1682
1697
|
}))).toSorted((left, right) => right.lastCommit.localeCompare(left.lastCommit));
|
|
1683
1698
|
const filtered = input.unmerged_only ? ordered.filter((b) => !b.merged) : ordered;
|
|
1684
1699
|
const health = await checkBranchHealth(projectRoot);
|
|
1700
|
+
const localNames = new Set(crBranches);
|
|
1701
|
+
const remoteExtras = input.remote ? remoteList === null ? { remote_error: "No git remote configured." } : remoteList.error ? { remote_error: remoteList.error } : { remote_only: remoteList.branches.filter((b) => !localNames.has(b.name)).map((b) => b.name) } : {};
|
|
1685
1702
|
return { content: [{
|
|
1686
1703
|
type: "text",
|
|
1687
1704
|
text: JSON.stringify({
|
|
1688
1705
|
total: ordered.length,
|
|
1689
1706
|
unmerged: ordered.filter((b) => !b.merged).length,
|
|
1690
1707
|
branches: filtered,
|
|
1708
|
+
...remoteExtras,
|
|
1691
1709
|
health: {
|
|
1692
1710
|
warning: health.warning,
|
|
1693
1711
|
blocked: health.blocked,
|
|
@@ -1720,28 +1738,45 @@ function registerWorkflowTools(server, provider, projectRoot) {
|
|
|
1720
1738
|
};
|
|
1721
1739
|
try {
|
|
1722
1740
|
const git = simpleGit(projectRoot);
|
|
1723
|
-
if (!(await git.branchLocal()).all.includes(input.branch))
|
|
1724
|
-
|
|
1741
|
+
if (!(await git.branchLocal()).all.includes(input.branch)) {
|
|
1742
|
+
const remoteOnly = await deleteRemoteBranch(projectRoot, input.branch);
|
|
1743
|
+
if (remoteOnly.deleted) return { content: [{
|
|
1725
1744
|
type: "text",
|
|
1726
1745
|
text: JSON.stringify({
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1746
|
+
status: "deleted",
|
|
1747
|
+
branch: input.branch,
|
|
1748
|
+
scope: "remote-only",
|
|
1749
|
+
message: "Branch was not present locally; its remote copy was deleted."
|
|
1750
|
+
}, null, 2)
|
|
1751
|
+
}] };
|
|
1752
|
+
return {
|
|
1753
|
+
content: [{
|
|
1754
|
+
type: "text",
|
|
1755
|
+
text: JSON.stringify({
|
|
1756
|
+
error: `Branch "${input.branch}" not found locally${remoteOnly.skipped === "not-found" ? " or on the remote" : ""}.`,
|
|
1757
|
+
...remoteOnly.warning ? { remote_warning: remoteOnly.warning } : {},
|
|
1758
|
+
next_steps: ["List branches with contentrain_branch_list"]
|
|
1759
|
+
})
|
|
1760
|
+
}],
|
|
1761
|
+
isError: true
|
|
1762
|
+
};
|
|
1763
|
+
}
|
|
1733
1764
|
const merged = await isMerged(projectRoot, input.branch, CONTENTRAIN_BRANCH);
|
|
1734
1765
|
await git.raw([
|
|
1735
1766
|
"branch",
|
|
1736
1767
|
"-D",
|
|
1737
1768
|
input.branch
|
|
1738
1769
|
]);
|
|
1770
|
+
const remote = await deleteRemoteBranch(projectRoot, input.branch);
|
|
1739
1771
|
return { content: [{
|
|
1740
1772
|
type: "text",
|
|
1741
1773
|
text: JSON.stringify({
|
|
1742
1774
|
status: "deleted",
|
|
1743
1775
|
branch: input.branch,
|
|
1744
1776
|
was_merged: merged,
|
|
1777
|
+
remote_deleted: remote.deleted,
|
|
1778
|
+
...remote.skipped ? { remote_skipped: remote.skipped } : {},
|
|
1779
|
+
...remote.warning ? { remote_warning: remote.warning } : {},
|
|
1745
1780
|
warning: merged ? void 0 : "Branch was not merged — its commits were discarded."
|
|
1746
1781
|
}, null, 2)
|
|
1747
1782
|
}] };
|
|
@@ -2333,7 +2368,7 @@ function registerDoctorTools(server, _provider, projectRoot) {
|
|
|
2333
2368
|
}
|
|
2334
2369
|
//#endregion
|
|
2335
2370
|
//#region package.json
|
|
2336
|
-
var version = "1.
|
|
2371
|
+
var version = "1.8.0";
|
|
2337
2372
|
//#endregion
|
|
2338
2373
|
//#region src/server.ts
|
|
2339
2374
|
function createServer(input) {
|
|
@@ -2374,4 +2409,4 @@ function resolveServerContext(input) {
|
|
|
2374
2409
|
//#endregion
|
|
2375
2410
|
export { createServer as t };
|
|
2376
2411
|
|
|
2377
|
-
//# sourceMappingURL=server-
|
|
2412
|
+
//# sourceMappingURL=server-tTuinKHD.mjs.map
|