contentrain 0.8.1 → 0.9.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.
@@ -3,7 +3,7 @@ import { c as saveDefaults, n as resolveStudioClient } from "./client-CJsHr9Db.m
3
3
  import { n as openBrowser, t as startOAuthServer } from "./oauth-server-BSgPLV_2.mjs";
4
4
  import { defineCommand } from "citty";
5
5
  import { confirm, intro, isCancel, log, outro, select, spinner, text } from "@clack/prompts";
6
- import { simpleGit } from "simple-git";
6
+ import { createGit } from "@contentrain/mcp/git/identity";
7
7
  //#region src/studio/commands/connect.ts
8
8
  var connect_default = defineCommand({
9
9
  meta: {
@@ -120,7 +120,7 @@ var connect_default = defineCommand({
120
120
  s3?.start("Detecting git remote...");
121
121
  let detectedRepoFullName = null;
122
122
  try {
123
- const origin = (await simpleGit(process.cwd()).getRemotes(true)).find((r) => r.name === "origin");
123
+ const origin = (await createGit(process.cwd()).getRemotes(true)).find((r) => r.name === "origin");
124
124
  if (origin?.refs?.fetch) detectedRepoFullName = parseGitHubRepoFromUrl(origin.refs.fetch);
125
125
  } catch {}
126
126
  const repos = await client.listGitHubRepos(installation.id);
@@ -1,7 +1,7 @@
1
1
  import { join } from "node:path";
2
2
  import { writeModel } from "@contentrain/mcp/core/model-manager";
3
3
  import { ensureDir, writeJson } from "@contentrain/mcp/util/fs";
4
- import { simpleGit } from "simple-git";
4
+ import { createGit } from "@contentrain/mcp/git/identity";
5
5
  import { getTemplate } from "@contentrain/mcp/templates";
6
6
  import { mkdtemp, rm, writeFile } from "node:fs/promises";
7
7
  import { tmpdir } from "node:os";
@@ -12,7 +12,7 @@ import { tmpdir } from "node:os";
12
12
  */
13
13
  async function createDemoProject() {
14
14
  const dir = await mkdtemp(join(tmpdir(), "contentrain-demo-"));
15
- const git = simpleGit(dir);
15
+ const git = createGit(dir);
16
16
  await git.init();
17
17
  await git.addConfig("user.email", "ai@contentrain.io");
18
18
  await git.addConfig("user.name", "Contentrain Demo");
@@ -63,6 +63,7 @@ var describe_default = defineCommand({
63
63
  log.message(` Kind: ${pc.cyan(String(result["kind"] ?? "—"))}`);
64
64
  log.message(` Domain: ${String(result["domain"] ?? "—")}`);
65
65
  log.message(` i18n: ${result["i18n"] ? pc.green("yes") : pc.dim("no")}`);
66
+ log.message(` Title: ${String(result["title_field"] ?? pc.red("— missing, run: contentrain validate --fix"))}`);
66
67
  if (result["description"]) log.message(` About: ${String(result["description"])}`);
67
68
  const stats = result["stats"];
68
69
  if (stats) {
@@ -2,7 +2,7 @@ import { i as pc } from "./ui-B8l_LC36.mjs";
2
2
  import { r as resolveProjectRoot } from "./context-OskMGy8y.mjs";
3
3
  import { defineCommand } from "citty";
4
4
  import { confirm, intro, isCancel, log, outro, select } from "@clack/prompts";
5
- import { simpleGit } from "simple-git";
5
+ import { createGit } from "@contentrain/mcp/git/identity";
6
6
  import { CONTENTRAIN_BRANCH } from "@contentrain/types";
7
7
  import { mergeBranch } from "@contentrain/mcp/git/transaction";
8
8
  import { branchDiff, deleteRemoteBranch } from "@contentrain/mcp/git/branch-lifecycle";
@@ -26,7 +26,7 @@ var diff_default = defineCommand({
26
26
  },
27
27
  async run({ args }) {
28
28
  const projectRoot = await resolveProjectRoot(args.root);
29
- const git = simpleGit(projectRoot);
29
+ const git = createGit(projectRoot);
30
30
  const useJson = Boolean(args.json);
31
31
  if (!useJson) intro(pc.bold("contentrain diff"));
32
32
  const featureBranches = (await git.branch(["--list", "cr/*"])).all.filter((b) => b !== CONTENTRAIN_BRANCH);
@@ -1,6 +1,6 @@
1
1
  import { join } from "node:path";
2
2
  import { ensureDir, pathExists } from "@contentrain/mcp/util/fs";
3
- import { simpleGit } from "simple-git";
3
+ import { createGit } from "@contentrain/mcp/git/identity";
4
4
  import { appendFile, readFile, writeFile } from "node:fs/promises";
5
5
  //#region src/utils/ide.ts
6
6
  const AGENT_SKILL_NAMES = [
@@ -188,7 +188,7 @@ async function installIdeRulesAndSkills(projectRoot, ide, resolveRuleFile, resol
188
188
  let installed = 0;
189
189
  let updated = 0;
190
190
  const rulesDir = join(projectRoot, ide.rulesDir);
191
- const git = simpleGit(projectRoot);
191
+ const git = createGit(projectRoot);
192
192
  const filesToAdd = [];
193
193
  if (resolveRuleFile) {
194
194
  await ensureDir(rulesDir);
@@ -276,7 +276,7 @@ async function addClaudeMdReference(projectRoot) {
276
276
  "- **Skills** are in `.claude/skills/` — loaded on demand by the agent",
277
277
  "- **Docs:** https://ai.contentrain.io"
278
278
  ].join("\n");
279
- const git = simpleGit(projectRoot);
279
+ const git = createGit(projectRoot);
280
280
  if (await pathExists(claudeMdPath)) {
281
281
  if (!(await readFile(claudeMdPath, "utf-8")).includes(marker)) {
282
282
  await appendFile(claudeMdPath, `\n\n${reference}\n`);
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  import { i as pc } from "./ui-B8l_LC36.mjs";
3
3
  import { defineCommand, runMain } from "citty";
4
4
  //#region package.json
5
- var version = "0.8.1";
5
+ var version = "0.9.0";
6
6
  //#endregion
7
7
  //#region src/utils/debug.ts
8
8
  /**
@@ -43,21 +43,21 @@ runMain(defineCommand({
43
43
  description: "Contentrain CLI — AI content governance infrastructure"
44
44
  },
45
45
  subCommands: {
46
- init: () => import("./init-BuoJKTt1.mjs").then((m) => m.default),
47
- status: () => import("./status-CKHWrsUI.mjs").then((m) => m.default),
46
+ init: () => import("./init-BYzWdWAH.mjs").then((m) => m.default),
47
+ status: () => import("./status-DhhEDuTh.mjs").then((m) => m.default),
48
48
  doctor: () => import("./doctor-MOf_LQEL.mjs").then((m) => m.default),
49
- validate: () => import("./validate-CW8FCCd4.mjs").then((m) => m.default),
50
- serve: () => import("./serve-BmBWp_3O.mjs").then((m) => m.default),
49
+ validate: () => import("./validate-CBPJDGH4.mjs").then((m) => m.default),
50
+ serve: () => import("./serve-BbJlmK0r.mjs").then((m) => m.default),
51
51
  generate: () => import("./generate-VI3xEA3Q.mjs").then((m) => m.default),
52
- diff: () => import("./diff-DqWPyJZF.mjs").then((m) => m.default),
53
- merge: () => import("./merge-Dm4Kl1u8.mjs").then((m) => m.default),
52
+ diff: () => import("./diff-BUGOF3SZ.mjs").then((m) => m.default),
53
+ merge: () => import("./merge-pPg9upjo.mjs").then((m) => m.default),
54
54
  prune: () => import("./prune-DCcyYVcD.mjs").then((m) => m.default),
55
- describe: () => import("./describe-DJ5H9Cxm.mjs").then((m) => m.default),
55
+ describe: () => import("./describe-CpQROC9y.mjs").then((m) => m.default),
56
56
  "describe-format": () => import("./describe-format-CUAqB0C4.mjs").then((m) => m.default),
57
57
  scaffold: () => import("./scaffold-irxW-vdX.mjs").then((m) => m.default),
58
- setup: () => import("./setup-DdoWlLFE.mjs").then((m) => m.default),
59
- skills: () => import("./skills-_LEBO_GH.mjs").then((m) => m.default),
60
- studio: () => import("./studio-DVVkj4QL.mjs").then((m) => m.default)
58
+ setup: () => import("./setup-seyBYKIP.mjs").then((m) => m.default),
59
+ skills: () => import("./skills-X_wFbJXX.mjs").then((m) => m.default),
60
+ studio: () => import("./studio-aKJw68fB.mjs").then((m) => m.default)
61
61
  }
62
62
  }));
63
63
  //#endregion
@@ -1,12 +1,12 @@
1
1
  import { i as pc } from "./ui-B8l_LC36.mjs";
2
2
  import { r as resolveProjectRoot, t as loadProjectContext } from "./context-OskMGy8y.mjs";
3
- import { a as createPackageResolver, c as writeMcpConfig, i as addClaudeMdReference, n as IDE_CONFIGS, o as detectIdes, s as installIdeRulesAndSkills } from "./ide-CQ9vEsPi.mjs";
3
+ import { a as createPackageResolver, c as writeMcpConfig, i as addClaudeMdReference, n as IDE_CONFIGS, o as detectIdes, s as installIdeRulesAndSkills } from "./ide-DR9i0gbE.mjs";
4
4
  import { defineCommand } from "citty";
5
5
  import { confirm, intro, isCancel, log, multiselect, outro, select, spinner } from "@clack/prompts";
6
6
  import { join } from "node:path";
7
7
  import { writeModel } from "@contentrain/mcp/core/model-manager";
8
8
  import { ensureDir, pathExists, writeJson } from "@contentrain/mcp/util/fs";
9
- import { simpleGit } from "simple-git";
9
+ import { createGit } from "@contentrain/mcp/git/identity";
10
10
  import { buildBranchName, createTransaction } from "@contentrain/mcp/git/transaction";
11
11
  import { detectStackInfo } from "@contentrain/mcp/util/detect";
12
12
  import { getTemplate, listTemplates } from "@contentrain/mcp/templates";
@@ -317,7 +317,7 @@ async function executeInit(projectRoot, opts) {
317
317
  const s = spinner();
318
318
  s.start("Initializing...");
319
319
  if (!await pathExists(join(projectRoot, ".git"))) {
320
- const git = simpleGit(projectRoot);
320
+ const git = createGit(projectRoot);
321
321
  await git.init();
322
322
  await git.add(".");
323
323
  await git.commit("initial commit", { "--allow-empty": null });
@@ -398,7 +398,7 @@ async function installRules(projectRoot) {
398
398
  const essentials = await readFile(resolveRuleFile("essential/contentrain-essentials.md"), "utf-8");
399
399
  const dest = join(projectRoot, "CLAUDE.md");
400
400
  await writeFile(dest, essentials, "utf-8");
401
- const git = simpleGit(projectRoot);
401
+ const git = createGit(projectRoot);
402
402
  await git.add(dest);
403
403
  try {
404
404
  await git.commit("[contentrain] install AI rules");
@@ -418,7 +418,7 @@ async function configureMcp(projectRoot) {
418
418
  }
419
419
  }
420
420
  if (writtenPaths.length > 0) {
421
- const git = simpleGit(projectRoot);
421
+ const git = createGit(projectRoot);
422
422
  await git.add(writtenPaths);
423
423
  try {
424
424
  await git.commit("[contentrain] configure MCP servers");
@@ -2,7 +2,7 @@ import { i as pc } from "./ui-B8l_LC36.mjs";
2
2
  import { r as resolveProjectRoot } from "./context-OskMGy8y.mjs";
3
3
  import { defineCommand } from "citty";
4
4
  import { confirm, intro, isCancel, log, outro } from "@clack/prompts";
5
- import { simpleGit } from "simple-git";
5
+ import { createGit } from "@contentrain/mcp/git/identity";
6
6
  import { CONTENTRAIN_BRANCH } from "@contentrain/types";
7
7
  import { mergeBranch } from "@contentrain/mcp/git/transaction";
8
8
  //#region src/commands/merge.ts
@@ -48,7 +48,7 @@ var merge_default = defineCommand({
48
48
  process.exitCode = 1;
49
49
  return;
50
50
  }
51
- if (!(await simpleGit(projectRoot).branchLocal()).all.includes(branch)) {
51
+ if (!(await createGit(projectRoot).branchLocal()).all.includes(branch)) {
52
52
  log.error(`Branch "${branch}" does not exist locally.`);
53
53
  outro("");
54
54
  process.exitCode = 1;
@@ -1,6 +1,7 @@
1
1
  import { r as resolveProjectRoot } from "./context-OskMGy8y.mjs";
2
2
  import { defineCommand } from "citty";
3
3
  import { createServer } from "@contentrain/mcp/server";
4
+ import { createGit } from "@contentrain/mcp/git/identity";
4
5
  import consola from "consola";
5
6
  //#region src/commands/serve.ts
6
7
  var serve_default = defineCommand({
@@ -54,7 +55,7 @@ var serve_default = defineCommand({
54
55
  let projectRoot = await resolveProjectRoot(args.root);
55
56
  let demoDir;
56
57
  if (args.demo) {
57
- const { createDemoProject, cleanupDemoProject } = await import("./demo-BPbR_r4f.mjs");
58
+ const { createDemoProject, cleanupDemoProject } = await import("./demo-DP9ceYhe.mjs");
58
59
  demoDir = await createDemoProject();
59
60
  projectRoot = demoDir;
60
61
  consola.info(`Demo project created at ${demoDir}`);
@@ -69,8 +70,7 @@ var serve_default = defineCommand({
69
70
  process.env["CONTENTRAIN_PROJECT_ROOT"] = projectRoot;
70
71
  process.env["CONTENTRAIN_SOURCE"] = "mcp-local";
71
72
  try {
72
- const { simpleGit } = await import("simple-git");
73
- const config = await simpleGit(projectRoot).listConfig();
73
+ const config = await createGit(projectRoot).listConfig();
74
74
  const name = config.all["user.name"];
75
75
  const email = config.all["user.email"];
76
76
  if (name && typeof name === "string") process.env["CONTENTRAIN_AUTHOR_NAME"] = name;
@@ -139,7 +139,7 @@ var serve_default = defineCommand({
139
139
  consola.warn("Serve UI not found. Running in API-only mode.");
140
140
  consola.info("UI will be available after building: cd packages/cli/src/serve-ui && pnpm build");
141
141
  }
142
- const { createServeApp } = await import("./server-Dn-zy9bv.mjs");
142
+ const { createServeApp } = await import("./server-Dsv_Afjl.mjs");
143
143
  const { app, handleUpgrade } = await createServeApp({
144
144
  projectRoot,
145
145
  port,
@@ -3,7 +3,7 @@ import { readConfig } from "@contentrain/mcp/core/config";
3
3
  import { createServer } from "@contentrain/mcp/server";
4
4
  import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
5
5
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
6
- import { simpleGit } from "simple-git";
6
+ import { createGit } from "@contentrain/mcp/git/identity";
7
7
  import { CONTENTRAIN_BRANCH, LOCAL_CAPABILITIES } from "@contentrain/types";
8
8
  import { mergeBranch } from "@contentrain/mcp/git/transaction";
9
9
  import { branchDiff, checkBranchHealth, deleteRemoteBranch } from "@contentrain/mcp/git/branch-lifecycle";
@@ -338,7 +338,7 @@ async function createServeApp(options) {
338
338
  });
339
339
  }));
340
340
  router.add("/api/branches", defineEventHandler(async () => {
341
- const branches = await simpleGit(projectRoot).branchLocal();
341
+ const branches = await createGit(projectRoot).branchLocal();
342
342
  const crBranches = branches.all.filter((b) => b.startsWith("cr/")).map((b) => ({
343
343
  name: b,
344
344
  current: b === branches.current,
@@ -370,7 +370,7 @@ async function createServeApp(options) {
370
370
  statusCode: 400,
371
371
  message: "Missing or invalid `branch` query (must start with \"cr/\")"
372
372
  });
373
- const git = simpleGit(projectRoot);
373
+ const git = createGit(projectRoot);
374
374
  if (!(await git.branchLocal()).all.includes(branchName)) throw createError({
375
375
  statusCode: 404,
376
376
  message: `Branch "${branchName}" does not exist locally`
@@ -489,7 +489,7 @@ async function createServeApp(options) {
489
489
  message: "Method not allowed"
490
490
  });
491
491
  const { branch: branchName } = parseOrThrow(BranchActionBodySchema, await readBody(event));
492
- await simpleGit(projectRoot).deleteLocalBranch(branchName, true);
492
+ await createGit(projectRoot).deleteLocalBranch(branchName, true);
493
493
  const remote = await deleteRemoteBranch(projectRoot, branchName);
494
494
  syncWarnings.delete(branchName);
495
495
  broadcast({
@@ -505,7 +505,7 @@ async function createServeApp(options) {
505
505
  router.add("/api/history", defineEventHandler(async (event) => {
506
506
  const query = getQuery(event);
507
507
  const limit = Number(query["limit"]) || 50;
508
- const log = await simpleGit(projectRoot).log({
508
+ const log = await createGit(projectRoot).log({
509
509
  maxCount: limit * 2,
510
510
  format: {
511
511
  hash: "%h",
@@ -649,7 +649,7 @@ async function createServeApp(options) {
649
649
  const op = JSON.parse(raw)?.lastOperation;
650
650
  if (op?.tool === "contentrain_scan" || op?.tool === "contentrain_apply") lastNormalize = op;
651
651
  } catch {}
652
- const branches = (await simpleGit(projectRoot).branchLocal()).all.filter((b) => b.startsWith("cr/normalize/")).map((b) => ({ name: b }));
652
+ const branches = (await createGit(projectRoot).branchLocal()).all.filter((b) => b.startsWith("cr/normalize/")).map((b) => ({ name: b }));
653
653
  return {
654
654
  lastOperation: lastNormalize,
655
655
  pendingBranches: branches
@@ -1,6 +1,6 @@
1
1
  import { i as pc } from "./ui-B8l_LC36.mjs";
2
2
  import { r as resolveProjectRoot, t as loadProjectContext } from "./context-OskMGy8y.mjs";
3
- import { a as createPackageResolver, c as writeMcpConfig, n as IDE_CONFIGS, o as detectIdes, r as MCP_CONFIGS, s as installIdeRulesAndSkills } from "./ide-CQ9vEsPi.mjs";
3
+ import { a as createPackageResolver, c as writeMcpConfig, n as IDE_CONFIGS, o as detectIdes, r as MCP_CONFIGS, s as installIdeRulesAndSkills } from "./ide-DR9i0gbE.mjs";
4
4
  import { defineCommand } from "citty";
5
5
  import { intro, log, outro, spinner } from "@clack/prompts";
6
6
  //#region src/commands/setup.ts
@@ -1,6 +1,6 @@
1
1
  import { i as pc } from "./ui-B8l_LC36.mjs";
2
2
  import { r as resolveProjectRoot } from "./context-OskMGy8y.mjs";
3
- import { a as createPackageResolver, n as IDE_CONFIGS, o as detectIdes, s as installIdeRulesAndSkills, t as AGENT_SKILL_NAMES } from "./ide-CQ9vEsPi.mjs";
3
+ import { a as createPackageResolver, n as IDE_CONFIGS, o as detectIdes, s as installIdeRulesAndSkills, t as AGENT_SKILL_NAMES } from "./ide-DR9i0gbE.mjs";
4
4
  import { defineCommand } from "citty";
5
5
  import { intro, log, outro, spinner } from "@clack/prompts";
6
6
  import { join } from "node:path";
@@ -3,7 +3,7 @@ import { n as requireInitialized, r as resolveProjectRoot, t as loadProjectConte
3
3
  import { defineCommand } from "citty";
4
4
  import { intro, log, outro } from "@clack/prompts";
5
5
  import { countEntries, readModel } from "@contentrain/mcp/core/model-manager";
6
- import { simpleGit } from "simple-git";
6
+ import { createGit } from "@contentrain/mcp/git/identity";
7
7
  import { CONTENTRAIN_BRANCH } from "@contentrain/types";
8
8
  import { checkBranchHealth } from "@contentrain/mcp/git/branch-lifecycle";
9
9
  import { validateProject } from "@contentrain/mcp/core/validator";
@@ -45,7 +45,7 @@ var status_default = defineCommand({
45
45
  };
46
46
  } catch {}
47
47
  try {
48
- const git = simpleGit(projectRoot);
48
+ const git = createGit(projectRoot);
49
49
  const branches = await git.branch(["--list", "cr/*"]);
50
50
  const allLocal = await git.branchLocal();
51
51
  jsonResult["pending_branches"] = branches.all.filter((b) => b !== CONTENTRAIN_BRANCH);
@@ -119,7 +119,7 @@ var status_default = defineCommand({
119
119
  ], rows));
120
120
  } else log.message(" No models yet. Run `contentrain init` with a template or create models.");
121
121
  try {
122
- const git = simpleGit(projectRoot);
122
+ const git = createGit(projectRoot);
123
123
  if ((await git.branchLocal()).all.includes(CONTENTRAIN_BRANCH)) try {
124
124
  const baseBranch = ctx.config?.repository?.default_branch ?? "main";
125
125
  const aheadRaw = await git.raw([
@@ -9,7 +9,7 @@ var studio_default = defineCommand({
9
9
  login: () => import("./login-yLBoeLVM.mjs").then((m) => m.default),
10
10
  logout: () => import("./logout-DBm34b7e.mjs").then((m) => m.default),
11
11
  whoami: () => import("./whoami-D0ZYvnWU.mjs").then((m) => m.default),
12
- connect: () => import("./connect-BTJU6Ud3.mjs").then((m) => m.default),
12
+ connect: () => import("./connect-CKx-SfQ7.mjs").then((m) => m.default),
13
13
  status: () => import("./status-BAQ8GFyN.mjs").then((m) => m.default),
14
14
  activity: () => import("./activity-DP5wjWLV.mjs").then((m) => m.default),
15
15
  usage: () => import("./usage-CC7Chuf6.mjs").then((m) => m.default),
@@ -101,6 +101,7 @@ var validate_default = defineCommand({
101
101
  s?.stop("Validation complete");
102
102
  if (args.json) {
103
103
  process.stdout.write(JSON.stringify(result, null, 2));
104
+ if (!result.valid) process.exitCode = 1;
104
105
  return;
105
106
  }
106
107
  log.info(pc.bold("Summary"));
@@ -170,6 +171,7 @@ var validate_default = defineCommand({
170
171
  else {
171
172
  outro(pc.yellow(`${formatCount(result.summary.errors, "error")}, ${formatCount(result.summary.warnings, "warning")}`));
172
173
  if (!args.fix && !args.interactive) log.message(`Run ${pc.cyan("contentrain validate --fix")} to auto-fix.`);
174
+ process.exitCode = 1;
173
175
  }
174
176
  }
175
177
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "contentrain",
3
- "version": "0.8.1",
3
+ "version": "0.9.0",
4
4
  "license": "MIT",
5
5
  "description": "CLI for Contentrain — AI content governance infrastructure",
6
6
  "type": "module",
@@ -47,11 +47,11 @@
47
47
  "simple-git": "^3.27.0",
48
48
  "ws": "^8.18.0",
49
49
  "zod": "^3.24.0",
50
- "@contentrain/rules": "0.6.0",
51
- "@contentrain/skills": "0.7.0",
52
- "@contentrain/mcp": "2.3.1",
53
- "@contentrain/query": "7.0.1",
54
- "@contentrain/types": "0.9.0"
50
+ "@contentrain/rules": "0.7.0",
51
+ "@contentrain/skills": "0.8.0",
52
+ "@contentrain/mcp": "3.0.0",
53
+ "@contentrain/query": "7.0.2",
54
+ "@contentrain/types": "1.0.0"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@types/ws": "^8.5.0",