contentrain 0.3.1 → 0.3.2
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 +2 -2
- package/dist/{diff-otz0kGqT.mjs → diff-Cq6iSnaD.mjs} +45 -13
- package/dist/index.mjs +4 -4
- package/dist/{serve-CaCZMeHF.mjs → serve-DL4LhWxl.mjs} +1 -1
- package/dist/{server-DW0KXB0T.mjs → server-WLDOAZa4.mjs} +94 -36
- package/dist/{status-kF5miVty.mjs → status-Bi9HYgcA.mjs} +38 -5
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -135,7 +135,7 @@ contentrain generate --watch
|
|
|
135
135
|
|
|
136
136
|
## 👀 Review Workflow
|
|
137
137
|
|
|
138
|
-
Most write operations create `contentrain
|
|
138
|
+
Most write operations create feature branches from the dedicated `contentrain` branch. In review mode, these branches are pushed to remote for team review. In auto-merge mode, they are merged into the `contentrain` branch and baseBranch is advanced via update-ref.
|
|
139
139
|
|
|
140
140
|
Use:
|
|
141
141
|
|
|
@@ -146,7 +146,7 @@ contentrain diff
|
|
|
146
146
|
|
|
147
147
|
to understand:
|
|
148
148
|
|
|
149
|
-
- how many active review branches exist
|
|
149
|
+
- how many active review branches exist on the `contentrain` branch
|
|
150
150
|
- whether branch health is blocking new writes
|
|
151
151
|
- what changed before merging or deleting a branch
|
|
152
152
|
|
|
@@ -4,6 +4,10 @@ import { defineCommand } from "citty";
|
|
|
4
4
|
import { confirm, intro, isCancel, log, outro, select } from "@clack/prompts";
|
|
5
5
|
import { simpleGit } from "simple-git";
|
|
6
6
|
import { readConfig } from "@contentrain/mcp/core/config";
|
|
7
|
+
import { CONTENTRAIN_BRANCH } from "@contentrain/types";
|
|
8
|
+
import { tmpdir } from "node:os";
|
|
9
|
+
import { randomUUID } from "node:crypto";
|
|
10
|
+
import { join } from "node:path";
|
|
7
11
|
//#region src/commands/diff.ts
|
|
8
12
|
var diff_default = defineCommand({
|
|
9
13
|
meta: {
|
|
@@ -19,17 +23,16 @@ var diff_default = defineCommand({
|
|
|
19
23
|
const projectRoot = await resolveProjectRoot(args.root);
|
|
20
24
|
const git = simpleGit(projectRoot);
|
|
21
25
|
intro(pc.bold("contentrain diff"));
|
|
22
|
-
const
|
|
23
|
-
if (
|
|
26
|
+
const featureBranches = (await git.branch(["--list", "cr/*"])).all.filter((b) => b !== CONTENTRAIN_BRANCH);
|
|
27
|
+
if (featureBranches.length === 0) {
|
|
24
28
|
log.message("No pending contentrain branches.");
|
|
25
29
|
outro("");
|
|
26
30
|
return;
|
|
27
31
|
}
|
|
28
|
-
log.info(pc.bold(`Pending branches (${
|
|
29
|
-
const
|
|
30
|
-
const baseBranch = process.env["CONTENTRAIN_BRANCH"] ?? config?.repository?.default_branch ?? ((await git.raw(["branch", "--show-current"])).trim() || "main");
|
|
32
|
+
log.info(pc.bold(`Pending branches (${featureBranches.length})`));
|
|
33
|
+
const baseBranch = (await readConfig(projectRoot))?.repository?.default_branch ?? ((await git.raw(["branch", "--show-current"])).trim() || "main");
|
|
31
34
|
const branchInfos = [];
|
|
32
|
-
for (const branch of
|
|
35
|
+
for (const branch of featureBranches) try {
|
|
33
36
|
const diffStat = await git.diffSummary([`${baseBranch}...${branch}`]);
|
|
34
37
|
branchInfos.push({
|
|
35
38
|
name: branch,
|
|
@@ -92,13 +95,42 @@ var diff_default = defineCommand({
|
|
|
92
95
|
}
|
|
93
96
|
if (action === "merge") {
|
|
94
97
|
const confirmMerge = await confirm({ message: `Merge ${selectedBranch} into ${baseBranch}?` });
|
|
95
|
-
if (!isCancel(confirmMerge) && confirmMerge)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
if (!isCancel(confirmMerge) && confirmMerge) {
|
|
99
|
+
const mergePath = join(tmpdir(), `cr-merge-${randomUUID()}`);
|
|
100
|
+
try {
|
|
101
|
+
if (!(await git.branchLocal()).all.includes(CONTENTRAIN_BRANCH)) await git.branch([CONTENTRAIN_BRANCH, baseBranch]);
|
|
102
|
+
await git.raw([
|
|
103
|
+
"worktree",
|
|
104
|
+
"add",
|
|
105
|
+
mergePath,
|
|
106
|
+
CONTENTRAIN_BRANCH
|
|
107
|
+
]);
|
|
108
|
+
const mergeGit = simpleGit(mergePath);
|
|
109
|
+
await mergeGit.merge([baseBranch, "--no-edit"]).catch(() => {});
|
|
110
|
+
await mergeGit.merge([selectedBranch, "--no-edit"]);
|
|
111
|
+
const tip = (await mergeGit.raw(["rev-parse", "HEAD"])).trim();
|
|
112
|
+
await git.raw([
|
|
113
|
+
"update-ref",
|
|
114
|
+
`refs/heads/${baseBranch}`,
|
|
115
|
+
tip
|
|
116
|
+
]);
|
|
117
|
+
if ((await git.raw(["branch", "--show-current"])).trim() === baseBranch) await git.checkout([
|
|
118
|
+
tip,
|
|
119
|
+
"--",
|
|
120
|
+
".contentrain/"
|
|
121
|
+
]);
|
|
122
|
+
await git.deleteLocalBranch(selectedBranch, true);
|
|
123
|
+
log.success(`Merged and deleted ${selectedBranch}`);
|
|
124
|
+
} catch (error) {
|
|
125
|
+
log.error(`Merge failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
126
|
+
} finally {
|
|
127
|
+
await git.raw([
|
|
128
|
+
"worktree",
|
|
129
|
+
"remove",
|
|
130
|
+
mergePath,
|
|
131
|
+
"--force"
|
|
132
|
+
]).catch(() => {});
|
|
133
|
+
}
|
|
102
134
|
}
|
|
103
135
|
} else if (action === "delete") {
|
|
104
136
|
const confirmDelete = await confirm({ message: `Delete ${selectedBranch}? This cannot be undone.` });
|
package/dist/index.mjs
CHANGED
|
@@ -5,17 +5,17 @@ import { defineCommand, runMain } from "citty";
|
|
|
5
5
|
runMain(defineCommand({
|
|
6
6
|
meta: {
|
|
7
7
|
name: "contentrain",
|
|
8
|
-
version: "0.3.
|
|
8
|
+
version: "0.3.2",
|
|
9
9
|
description: "Contentrain CLI — AI content governance infrastructure"
|
|
10
10
|
},
|
|
11
11
|
subCommands: {
|
|
12
12
|
init: () => import("./init-BARgfYUV.mjs").then((m) => m.default),
|
|
13
|
-
status: () => import("./status-
|
|
13
|
+
status: () => import("./status-Bi9HYgcA.mjs").then((m) => m.default),
|
|
14
14
|
doctor: () => import("./doctor-DyKjAIKH.mjs").then((m) => m.default),
|
|
15
15
|
validate: () => import("./validate-DnVamp3p.mjs").then((m) => m.default),
|
|
16
|
-
serve: () => import("./serve-
|
|
16
|
+
serve: () => import("./serve-DL4LhWxl.mjs").then((m) => m.default),
|
|
17
17
|
generate: () => import("./generate-DDEDRLdy.mjs").then((m) => m.default),
|
|
18
|
-
diff: () => import("./diff-
|
|
18
|
+
diff: () => import("./diff-Cq6iSnaD.mjs").then((m) => m.default)
|
|
19
19
|
}
|
|
20
20
|
}));
|
|
21
21
|
//#endregion
|
|
@@ -66,7 +66,7 @@ var serve_default = defineCommand({
|
|
|
66
66
|
consola.warn("Serve UI not found. Running in API-only mode.");
|
|
67
67
|
consola.info("UI will be available after building: cd packages/cli/src/serve-ui && pnpm build");
|
|
68
68
|
}
|
|
69
|
-
const { createServeApp } = await import("./server-
|
|
69
|
+
const { createServeApp } = await import("./server-WLDOAZa4.mjs");
|
|
70
70
|
const { app, handleUpgrade } = await createServeApp({
|
|
71
71
|
projectRoot,
|
|
72
72
|
port,
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { simpleGit } from "simple-git";
|
|
2
|
+
import { CONTENTRAIN_BRANCH } from "@contentrain/types";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
2
5
|
import { join } from "node:path";
|
|
3
6
|
import { readFile, unlink, writeFile } from "node:fs/promises";
|
|
4
7
|
import { existsSync, readFileSync } from "node:fs";
|
|
@@ -202,18 +205,19 @@ async function createServeApp(options) {
|
|
|
202
205
|
}));
|
|
203
206
|
router.add("/api/branches", defineEventHandler(async () => {
|
|
204
207
|
const branches = await simpleGit(projectRoot).branchLocal();
|
|
205
|
-
const crBranches = branches.all.filter((b) => b.startsWith("
|
|
208
|
+
const crBranches = branches.all.filter((b) => b.startsWith("cr/")).map((b) => ({
|
|
206
209
|
name: b,
|
|
207
|
-
current: b === branches.current
|
|
210
|
+
current: b === branches.current,
|
|
211
|
+
system: b === CONTENTRAIN_BRANCH
|
|
208
212
|
}));
|
|
209
213
|
return {
|
|
210
214
|
branches: crBranches,
|
|
211
|
-
total: crBranches.length
|
|
215
|
+
total: crBranches.filter((b) => !b.system).length
|
|
212
216
|
};
|
|
213
217
|
}));
|
|
214
218
|
router.add("/api/branches/diff", defineEventHandler(async (event) => {
|
|
215
219
|
const branchName = getQuery(event)["name"];
|
|
216
|
-
if (!branchName?.startsWith("
|
|
220
|
+
if (!branchName?.startsWith("cr/")) throw createError({
|
|
217
221
|
statusCode: 400,
|
|
218
222
|
message: "Invalid branch name"
|
|
219
223
|
});
|
|
@@ -232,29 +236,53 @@ async function createServeApp(options) {
|
|
|
232
236
|
message: "Method not allowed"
|
|
233
237
|
});
|
|
234
238
|
const branchName = (await readBody(event)).branch;
|
|
235
|
-
if (!branchName?.startsWith("
|
|
239
|
+
if (!branchName?.startsWith("cr/")) throw createError({
|
|
236
240
|
statusCode: 400,
|
|
237
241
|
message: "Invalid branch name"
|
|
238
242
|
});
|
|
239
243
|
const git = simpleGit(projectRoot);
|
|
240
244
|
const baseBranch = getDefaultBranch();
|
|
241
|
-
await git.
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
"
|
|
245
|
-
"
|
|
246
|
-
|
|
245
|
+
if (!(await git.branchLocal()).all.includes(CONTENTRAIN_BRANCH)) await git.branch([CONTENTRAIN_BRANCH, baseBranch]);
|
|
246
|
+
const mergePath = join(tmpdir(), `cr-merge-${randomUUID()}`);
|
|
247
|
+
await git.raw([
|
|
248
|
+
"worktree",
|
|
249
|
+
"add",
|
|
250
|
+
mergePath,
|
|
251
|
+
CONTENTRAIN_BRANCH
|
|
247
252
|
]);
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
253
|
+
const mergeGit = simpleGit(mergePath);
|
|
254
|
+
try {
|
|
255
|
+
await mergeGit.merge([baseBranch, "--no-edit"]).catch(() => {});
|
|
256
|
+
await mergeGit.merge([branchName, "--no-edit"]);
|
|
257
|
+
const tip = (await mergeGit.raw(["rev-parse", "HEAD"])).trim();
|
|
258
|
+
await git.raw([
|
|
259
|
+
"update-ref",
|
|
260
|
+
`refs/heads/${baseBranch}`,
|
|
261
|
+
tip
|
|
262
|
+
]);
|
|
263
|
+
if ((await git.raw(["branch", "--show-current"])).trim() === baseBranch) await git.checkout([
|
|
264
|
+
tip,
|
|
265
|
+
"--",
|
|
266
|
+
".contentrain/"
|
|
267
|
+
]);
|
|
268
|
+
await git.deleteLocalBranch(branchName, true);
|
|
269
|
+
broadcast({
|
|
270
|
+
type: "branch:merged",
|
|
271
|
+
branch: branchName
|
|
272
|
+
});
|
|
273
|
+
return {
|
|
274
|
+
status: "merged",
|
|
275
|
+
branch: branchName,
|
|
276
|
+
into: baseBranch
|
|
277
|
+
};
|
|
278
|
+
} finally {
|
|
279
|
+
await git.raw([
|
|
280
|
+
"worktree",
|
|
281
|
+
"remove",
|
|
282
|
+
mergePath,
|
|
283
|
+
"--force"
|
|
284
|
+
]).catch(() => {});
|
|
285
|
+
}
|
|
258
286
|
}));
|
|
259
287
|
router.add("/api/branches/reject", defineEventHandler(async (event) => {
|
|
260
288
|
if (event.method !== "POST") throw createError({
|
|
@@ -262,7 +290,7 @@ async function createServeApp(options) {
|
|
|
262
290
|
message: "Method not allowed"
|
|
263
291
|
});
|
|
264
292
|
const branchName = (await readBody(event)).branch;
|
|
265
|
-
if (!branchName?.startsWith("
|
|
293
|
+
if (!branchName?.startsWith("cr/")) throw createError({
|
|
266
294
|
statusCode: 400,
|
|
267
295
|
message: "Invalid branch name"
|
|
268
296
|
});
|
|
@@ -417,7 +445,7 @@ async function createServeApp(options) {
|
|
|
417
445
|
const op = JSON.parse(raw)?.lastOperation;
|
|
418
446
|
if (op?.tool === "contentrain_scan" || op?.tool === "contentrain_apply") lastNormalize = op;
|
|
419
447
|
} catch {}
|
|
420
|
-
const branches = (await simpleGit(projectRoot).branchLocal()).all.filter((b) => b.startsWith("
|
|
448
|
+
const branches = (await simpleGit(projectRoot).branchLocal()).all.filter((b) => b.startsWith("cr/normalize/")).map((b) => ({ name: b }));
|
|
421
449
|
return {
|
|
422
450
|
lastOperation: lastNormalize,
|
|
423
451
|
pendingBranches: branches
|
|
@@ -511,23 +539,53 @@ async function createServeApp(options) {
|
|
|
511
539
|
message: "Method not allowed"
|
|
512
540
|
});
|
|
513
541
|
const branchName = (await readBody(event)).branch;
|
|
514
|
-
if (!branchName?.startsWith("
|
|
542
|
+
if (!branchName?.startsWith("cr/")) throw createError({
|
|
515
543
|
statusCode: 400,
|
|
516
544
|
message: "Invalid branch name"
|
|
517
545
|
});
|
|
518
546
|
const git = simpleGit(projectRoot);
|
|
519
|
-
const
|
|
520
|
-
await git.
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
547
|
+
const baseBranch = getDefaultBranch();
|
|
548
|
+
if (!(await git.branchLocal()).all.includes(CONTENTRAIN_BRANCH)) await git.branch([CONTENTRAIN_BRANCH, baseBranch]);
|
|
549
|
+
const mergePath = join(tmpdir(), `cr-merge-${randomUUID()}`);
|
|
550
|
+
await git.raw([
|
|
551
|
+
"worktree",
|
|
552
|
+
"add",
|
|
553
|
+
mergePath,
|
|
554
|
+
CONTENTRAIN_BRANCH
|
|
555
|
+
]);
|
|
556
|
+
const mergeGit = simpleGit(mergePath);
|
|
557
|
+
try {
|
|
558
|
+
await mergeGit.merge([baseBranch, "--no-edit"]).catch(() => {});
|
|
559
|
+
await mergeGit.merge([branchName, "--no-edit"]);
|
|
560
|
+
const tip = (await mergeGit.raw(["rev-parse", "HEAD"])).trim();
|
|
561
|
+
await git.raw([
|
|
562
|
+
"update-ref",
|
|
563
|
+
`refs/heads/${baseBranch}`,
|
|
564
|
+
tip
|
|
565
|
+
]);
|
|
566
|
+
if ((await git.raw(["branch", "--show-current"])).trim() === baseBranch) await git.checkout([
|
|
567
|
+
tip,
|
|
568
|
+
"--",
|
|
569
|
+
".contentrain/"
|
|
570
|
+
]);
|
|
571
|
+
await git.deleteLocalBranch(branchName, true);
|
|
572
|
+
broadcast({
|
|
573
|
+
type: "branch:merged",
|
|
574
|
+
branch: branchName
|
|
575
|
+
});
|
|
576
|
+
return {
|
|
577
|
+
status: "merged",
|
|
578
|
+
branch: branchName,
|
|
579
|
+
into: baseBranch
|
|
580
|
+
};
|
|
581
|
+
} finally {
|
|
582
|
+
await git.raw([
|
|
583
|
+
"worktree",
|
|
584
|
+
"remove",
|
|
585
|
+
mergePath,
|
|
586
|
+
"--force"
|
|
587
|
+
]).catch(() => {});
|
|
588
|
+
}
|
|
531
589
|
}));
|
|
532
590
|
router.add("/api/normalize/sources", defineEventHandler(async () => {
|
|
533
591
|
const sourcesPath = join(crDir, "normalize-sources.json");
|
|
@@ -3,6 +3,7 @@ import { i as pc, n as formatPercent, r as formatTable, t as formatCount } from
|
|
|
3
3
|
import { defineCommand } from "citty";
|
|
4
4
|
import { intro, log, outro } from "@clack/prompts";
|
|
5
5
|
import { simpleGit } from "simple-git";
|
|
6
|
+
import { CONTENTRAIN_BRANCH } from "@contentrain/types";
|
|
6
7
|
import { countEntries, readModel } from "@contentrain/mcp/core/model-manager";
|
|
7
8
|
import { validateProject } from "@contentrain/mcp/core/validator";
|
|
8
9
|
//#region src/commands/status.ts
|
|
@@ -43,7 +44,22 @@ var status_default = defineCommand({
|
|
|
43
44
|
};
|
|
44
45
|
} catch {}
|
|
45
46
|
try {
|
|
46
|
-
|
|
47
|
+
const git = simpleGit(projectRoot);
|
|
48
|
+
const branches = await git.branch(["--list", "cr/*"]);
|
|
49
|
+
const allLocal = await git.branchLocal();
|
|
50
|
+
jsonResult["pending_branches"] = branches.all.filter((b) => b !== CONTENTRAIN_BRANCH);
|
|
51
|
+
const contentBranchExists = allLocal.all.includes(CONTENTRAIN_BRANCH);
|
|
52
|
+
const contentBranchInfo = { exists: contentBranchExists };
|
|
53
|
+
if (contentBranchExists) try {
|
|
54
|
+
const baseBranch = ctx.config?.repository?.default_branch ?? "main";
|
|
55
|
+
const aheadRaw = await git.raw([
|
|
56
|
+
"rev-list",
|
|
57
|
+
"--count",
|
|
58
|
+
`${baseBranch}..${CONTENTRAIN_BRANCH}`
|
|
59
|
+
]);
|
|
60
|
+
contentBranchInfo["ahead"] = Number.parseInt(aheadRaw.trim(), 10);
|
|
61
|
+
} catch {}
|
|
62
|
+
jsonResult["content_branch"] = contentBranchInfo;
|
|
47
63
|
} catch {}
|
|
48
64
|
}
|
|
49
65
|
process.stdout.write(JSON.stringify(jsonResult, null, 2));
|
|
@@ -91,9 +107,26 @@ var status_default = defineCommand({
|
|
|
91
107
|
], rows));
|
|
92
108
|
} else log.message(" No models yet. Run `contentrain init` with a template or create models.");
|
|
93
109
|
try {
|
|
94
|
-
const
|
|
95
|
-
if (
|
|
96
|
-
const
|
|
110
|
+
const git = simpleGit(projectRoot);
|
|
111
|
+
if ((await git.branchLocal()).all.includes(CONTENTRAIN_BRANCH)) try {
|
|
112
|
+
const baseBranch = ctx.config?.repository?.default_branch ?? "main";
|
|
113
|
+
const aheadRaw = await git.raw([
|
|
114
|
+
"rev-list",
|
|
115
|
+
"--count",
|
|
116
|
+
`${baseBranch}..${CONTENTRAIN_BRANCH}`
|
|
117
|
+
]);
|
|
118
|
+
const ahead = Number.parseInt(aheadRaw.trim(), 10);
|
|
119
|
+
if (ahead > 0) {
|
|
120
|
+
log.info(pc.bold(`\nContent branch`));
|
|
121
|
+
log.message(` ${pc.cyan(CONTENTRAIN_BRANCH)} is ${pc.yellow(String(ahead))} commit(s) ahead of ${baseBranch}`);
|
|
122
|
+
} else {
|
|
123
|
+
log.info(pc.bold(`\nContent branch`));
|
|
124
|
+
log.message(` ${pc.cyan(CONTENTRAIN_BRANCH)} is in sync with ${baseBranch}`);
|
|
125
|
+
}
|
|
126
|
+
} catch {}
|
|
127
|
+
const featureBranches = (await git.branch(["--list", "cr/*"])).all.filter((b) => b !== CONTENTRAIN_BRANCH);
|
|
128
|
+
if (featureBranches.length > 0) {
|
|
129
|
+
const count = featureBranches.length;
|
|
97
130
|
if (count >= 80) {
|
|
98
131
|
log.error(pc.bold(`\nBLOCKED: ${count} active contentrain branches (limit: 80)`));
|
|
99
132
|
log.message(` New writes are blocked. Merge or delete old branches with ${pc.cyan("contentrain diff")}.`);
|
|
@@ -101,7 +134,7 @@ var status_default = defineCommand({
|
|
|
101
134
|
log.warning(pc.bold(`\nWARNING: ${count} active contentrain branches (limit: 50)`));
|
|
102
135
|
log.message(` Consider merging or deleting old branches with ${pc.cyan("contentrain diff")}.`);
|
|
103
136
|
} else log.info(pc.bold(`\nPending branches (${count})`));
|
|
104
|
-
for (const branch of
|
|
137
|
+
for (const branch of featureBranches) log.message(` ${pc.yellow("●")} ${branch}`);
|
|
105
138
|
log.message(` Run ${pc.cyan("contentrain diff")} to review.`);
|
|
106
139
|
}
|
|
107
140
|
} catch {}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "contentrain",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "CLI for Contentrain — AI content governance infrastructure",
|
|
6
6
|
"type": "module",
|
|
@@ -46,10 +46,10 @@
|
|
|
46
46
|
"picocolors": "^1.1.0",
|
|
47
47
|
"simple-git": "^3.27.0",
|
|
48
48
|
"ws": "^8.18.0",
|
|
49
|
-
"@contentrain/rules": "0.3.
|
|
50
|
-
"@contentrain/mcp": "1.0
|
|
51
|
-
"@contentrain/query": "5.1.
|
|
52
|
-
"@contentrain/types": "0.
|
|
49
|
+
"@contentrain/rules": "0.3.1",
|
|
50
|
+
"@contentrain/mcp": "1.1.0",
|
|
51
|
+
"@contentrain/query": "5.1.1",
|
|
52
|
+
"@contentrain/types": "0.3.0"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@types/ws": "^8.5.0",
|