contentrain 0.4.1 → 0.4.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.
Files changed (28) hide show
  1. package/dist/{activity-DMQsYlzz.mjs → activity-CbkxcfDf.mjs} +2 -2
  2. package/dist/{branches-D330IxDO.mjs → branches-D2UWex1N.mjs} +2 -2
  3. package/dist/{cdn-build-D_d3p4OZ.mjs → cdn-build-BzC2QPNi.mjs} +2 -2
  4. package/dist/{cdn-init-Bhnil0F8.mjs → cdn-init-CsmqJIaQ.mjs} +2 -2
  5. package/dist/{connect-DiSYnxFd.mjs → connect-DJo9PSiw.mjs} +2 -2
  6. package/dist/demo-DcBt6fw8.mjs +80 -0
  7. package/dist/ide-Bg-Z8QZk.mjs +227 -0
  8. package/dist/index.mjs +8 -6
  9. package/dist/{init-Q9B0iYtu.mjs → init-DFyQ-l-E.mjs} +22 -152
  10. package/dist/{login-wRBvHDCi.mjs → login-DCXkOrQV.mjs} +2 -2
  11. package/dist/{logout-xPTGu6vx.mjs → logout-nPt2UAeQ.mjs} +1 -1
  12. package/dist/{resolve-context-BwcikcF0.mjs → resolve-context-Cg6JoVZt.mjs} +1 -1
  13. package/dist/{serve-DL4LhWxl.mjs → serve-CNeFIQ1i.mjs} +30 -11
  14. package/dist/setup-DJy-jNEU.mjs +108 -0
  15. package/dist/skills-D-tFY7WA.mjs +92 -0
  16. package/dist/{status-UvjbO4eS.mjs → status-Cyv-jo1y.mjs} +2 -2
  17. package/dist/studio-CJUGiIMd.mjs +24 -0
  18. package/dist/{submissions-Dw0ChFDi.mjs → submissions-bIG-MWvv.mjs} +2 -2
  19. package/dist/{usage-BqriRRqE.mjs → usage-B2xuc2DT.mjs} +2 -2
  20. package/dist/{webhooks-B1OhcCtZ.mjs → webhooks-Dq3zFLP7.mjs} +2 -2
  21. package/dist/{whoami-CWvTYzum.mjs → whoami-Ub5RznbU.mjs} +1 -1
  22. package/package.json +5 -5
  23. package/dist/studio-B8lF0fQx.mjs +0 -24
  24. /package/dist/{client-CLV4XoJz.mjs → client-C400qHcL.mjs} +0 -0
  25. /package/dist/{oauth-server-1p6y1H30.mjs → oauth-server-Beppljfz.mjs} +0 -0
  26. /package/dist/{server-WLDOAZa4.mjs → server-DTdmutjb.mjs} +0 -0
  27. /package/dist/{status-BmQZGdZX.mjs → status-CoHgz6HN.mjs} +0 -0
  28. /package/dist/{validate-DnVamp3p.mjs → validate-B10L7RL7.mjs} +0 -0
@@ -1,6 +1,6 @@
1
1
  import { i as pc } from "./ui-B5mXontH.mjs";
2
- import { n as resolveStudioClient } from "./client-CLV4XoJz.mjs";
3
- import { t as resolveStudioContext } from "./resolve-context-BwcikcF0.mjs";
2
+ import { n as resolveStudioClient } from "./client-C400qHcL.mjs";
3
+ import { t as resolveStudioContext } from "./resolve-context-Cg6JoVZt.mjs";
4
4
  import { defineCommand } from "citty";
5
5
  import { intro, log, outro, spinner } from "@clack/prompts";
6
6
  //#region src/studio/commands/activity.ts
@@ -1,6 +1,6 @@
1
1
  import { i as pc, r as formatTable, t as formatCount } from "./ui-B5mXontH.mjs";
2
- import { n as resolveStudioClient } from "./client-CLV4XoJz.mjs";
3
- import { t as resolveStudioContext } from "./resolve-context-BwcikcF0.mjs";
2
+ import { n as resolveStudioClient } from "./client-C400qHcL.mjs";
3
+ import { t as resolveStudioContext } from "./resolve-context-Cg6JoVZt.mjs";
4
4
  import { defineCommand } from "citty";
5
5
  import { confirm, intro, isCancel, log, outro, select, spinner } from "@clack/prompts";
6
6
  //#region src/studio/commands/branches.ts
@@ -1,6 +1,6 @@
1
1
  import { i as pc, t as formatCount } from "./ui-B5mXontH.mjs";
2
- import { n as resolveStudioClient } from "./client-CLV4XoJz.mjs";
3
- import { t as resolveStudioContext } from "./resolve-context-BwcikcF0.mjs";
2
+ import { n as resolveStudioClient } from "./client-C400qHcL.mjs";
3
+ import { t as resolveStudioContext } from "./resolve-context-Cg6JoVZt.mjs";
4
4
  import { defineCommand } from "citty";
5
5
  import { intro, log, outro, spinner } from "@clack/prompts";
6
6
  //#region src/studio/commands/cdn-build.ts
@@ -1,6 +1,6 @@
1
1
  import { i as pc } from "./ui-B5mXontH.mjs";
2
- import { n as resolveStudioClient } from "./client-CLV4XoJz.mjs";
3
- import { t as resolveStudioContext } from "./resolve-context-BwcikcF0.mjs";
2
+ import { n as resolveStudioClient } from "./client-C400qHcL.mjs";
3
+ import { t as resolveStudioContext } from "./resolve-context-Cg6JoVZt.mjs";
4
4
  import { defineCommand } from "citty";
5
5
  import { confirm, intro, isCancel, log, outro, spinner } from "@clack/prompts";
6
6
  //#region src/studio/commands/cdn-init.ts
@@ -1,6 +1,6 @@
1
1
  import { i as pc } from "./ui-B5mXontH.mjs";
2
- import { c as saveDefaults, n as resolveStudioClient } from "./client-CLV4XoJz.mjs";
3
- import { n as openBrowser, t as startOAuthServer } from "./oauth-server-1p6y1H30.mjs";
2
+ import { c as saveDefaults, n as resolveStudioClient } from "./client-C400qHcL.mjs";
3
+ import { n as openBrowser, t as startOAuthServer } from "./oauth-server-Beppljfz.mjs";
4
4
  import { defineCommand } from "citty";
5
5
  import { confirm, intro, isCancel, log, outro, select, spinner, text } from "@clack/prompts";
6
6
  import { simpleGit } from "simple-git";
@@ -0,0 +1,80 @@
1
+ import { simpleGit } from "simple-git";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { writeModel } from "@contentrain/mcp/core/model-manager";
5
+ import { ensureDir, writeJson } from "@contentrain/mcp/util/fs";
6
+ import { mkdtemp, rm, writeFile } from "node:fs/promises";
7
+ import { getTemplate } from "@contentrain/mcp/templates";
8
+ //#region src/utils/demo.ts
9
+ /**
10
+ * Creates a temporary demo project with a blog template.
11
+ * Returns the project root path.
12
+ */
13
+ async function createDemoProject() {
14
+ const dir = await mkdtemp(join(tmpdir(), "contentrain-demo-"));
15
+ const git = simpleGit(dir);
16
+ await git.init();
17
+ await git.addConfig("user.email", "demo@contentrain.io");
18
+ await git.addConfig("user.name", "Contentrain Demo");
19
+ const crDir = join(dir, ".contentrain");
20
+ await Promise.all([
21
+ "models",
22
+ "content",
23
+ "meta"
24
+ ].map(async (sub) => {
25
+ await ensureDir(join(crDir, sub));
26
+ await writeFile(join(crDir, sub, ".gitkeep"), "", "utf-8");
27
+ }));
28
+ await writeJson(join(crDir, "config.json"), {
29
+ version: 1,
30
+ stack: "other",
31
+ workflow: "auto-merge",
32
+ locales: {
33
+ default: "en",
34
+ supported: ["en"]
35
+ },
36
+ domains: [
37
+ "marketing",
38
+ "blog",
39
+ "system"
40
+ ]
41
+ });
42
+ await writeJson(join(crDir, "vocabulary.json"), {
43
+ version: 1,
44
+ terms: {}
45
+ });
46
+ await writeJson(join(crDir, "context.json"), {
47
+ version: "1",
48
+ lastOperation: {
49
+ tool: "contentrain_init",
50
+ model: "",
51
+ locale: "en",
52
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
53
+ source: "demo"
54
+ },
55
+ stats: {
56
+ models: 0,
57
+ entries: 0,
58
+ locales: ["en"],
59
+ lastSync: (/* @__PURE__ */ new Date()).toISOString()
60
+ }
61
+ });
62
+ const tmpl = getTemplate("blog");
63
+ if (tmpl) for (const model of tmpl.models) await writeModel(dir, model);
64
+ await git.add(".");
65
+ await git.commit("[contentrain] demo project");
66
+ return dir;
67
+ }
68
+ /**
69
+ * Clean up a demo project directory.
70
+ */
71
+ async function cleanupDemoProject(dir) {
72
+ try {
73
+ await rm(dir, {
74
+ recursive: true,
75
+ force: true
76
+ });
77
+ } catch {}
78
+ }
79
+ //#endregion
80
+ export { cleanupDemoProject, createDemoProject };
@@ -0,0 +1,227 @@
1
+ import { simpleGit } from "simple-git";
2
+ import { join } from "node:path";
3
+ import { ensureDir, pathExists } from "@contentrain/mcp/util/fs";
4
+ import { appendFile, readFile, writeFile } from "node:fs/promises";
5
+ //#region src/utils/ide.ts
6
+ const AGENT_SKILL_NAMES = [
7
+ "contentrain",
8
+ "contentrain-normalize",
9
+ "contentrain-quality",
10
+ "contentrain-sdk",
11
+ "contentrain-content",
12
+ "contentrain-model",
13
+ "contentrain-init",
14
+ "contentrain-bulk",
15
+ "contentrain-validate-fix",
16
+ "contentrain-review",
17
+ "contentrain-translate",
18
+ "contentrain-generate",
19
+ "contentrain-serve",
20
+ "contentrain-diff",
21
+ "contentrain-doctor"
22
+ ];
23
+ const OLD_RULE_FILES = [
24
+ "contentrain-content-quality.md",
25
+ "contentrain-seo-rules.md",
26
+ "contentrain-i18n-quality.md",
27
+ "contentrain-accessibility-rules.md",
28
+ "contentrain-security-rules.md",
29
+ "contentrain-media-rules.md",
30
+ "contentrain-content-conventions.md",
31
+ "contentrain-schema-rules.md",
32
+ "contentrain-mcp-usage.md",
33
+ "contentrain-workflow-rules.md",
34
+ "contentrain-normalize-rules.md"
35
+ ];
36
+ const IDE_CONFIGS = {
37
+ "claude-code": {
38
+ name: "Claude Code",
39
+ rulesDir: ".claude/rules",
40
+ skillsDir: ".claude/skills",
41
+ guardrailsFileName: "contentrain-essentials.md"
42
+ },
43
+ cursor: {
44
+ name: "Cursor",
45
+ rulesDir: ".cursor/rules",
46
+ skillsDir: ".cursor/skills",
47
+ guardrailsFileName: "contentrain-essentials.mdc",
48
+ guardrailsFrontmatter: "---\ndescription: Contentrain essential content governance rules\nalwaysApply: true\n---\n\n"
49
+ },
50
+ windsurf: {
51
+ name: "Windsurf",
52
+ rulesDir: ".windsurf/rules",
53
+ skillsDir: ".windsurf/skills",
54
+ guardrailsFileName: "contentrain-essentials.md",
55
+ guardrailsFrontmatter: "---\ndescription: Contentrain essential content governance rules\ntrigger: always_on\n---\n\n"
56
+ },
57
+ copilot: {
58
+ name: "GitHub Copilot",
59
+ rulesDir: ".github",
60
+ skillsDir: ".agents/skills",
61
+ guardrailsFileName: "copilot-instructions.md"
62
+ }
63
+ };
64
+ const MCP_CONFIGS = {
65
+ "claude-code": ".mcp.json",
66
+ cursor: ".cursor/mcp.json",
67
+ windsurf: ".windsurf/mcp.json",
68
+ vscode: ".vscode/mcp.json",
69
+ copilot: ".vscode/mcp.json"
70
+ };
71
+ const STANDARD_MCP_CONFIG = { mcpServers: { contentrain: {
72
+ command: "npx",
73
+ args: [
74
+ "contentrain",
75
+ "serve",
76
+ "--stdio"
77
+ ]
78
+ } } };
79
+ async function detectIdes(projectRoot) {
80
+ const ides = [];
81
+ if (await pathExists(join(projectRoot, "CLAUDE.md")) || await pathExists(join(projectRoot, ".claude"))) ides.push("claude-code");
82
+ if (await pathExists(join(projectRoot, ".cursor"))) ides.push("cursor");
83
+ if (await pathExists(join(projectRoot, ".windsurf"))) ides.push("windsurf");
84
+ if (await pathExists(join(projectRoot, ".github"))) ides.push("copilot");
85
+ return ides;
86
+ }
87
+ async function writeMcpConfig(projectRoot, agent) {
88
+ const relativePath = MCP_CONFIGS[agent];
89
+ if (!relativePath) return {
90
+ written: false,
91
+ path: "",
92
+ skipped: `Unknown agent: "${agent}"`
93
+ };
94
+ const configPath = join(projectRoot, relativePath);
95
+ if (await pathExists(configPath)) try {
96
+ const existing = JSON.parse(await readFile(configPath, "utf-8"));
97
+ if (existing?.mcpServers?.contentrain) return {
98
+ written: false,
99
+ path: relativePath,
100
+ skipped: "Already configured"
101
+ };
102
+ existing.mcpServers = {
103
+ ...existing.mcpServers,
104
+ ...STANDARD_MCP_CONFIG.mcpServers
105
+ };
106
+ await ensureDir(join(configPath, ".."));
107
+ await writeFile(configPath, JSON.stringify(existing, null, 2) + "\n", "utf-8");
108
+ return {
109
+ written: true,
110
+ path: relativePath
111
+ };
112
+ } catch {}
113
+ await ensureDir(join(configPath, ".."));
114
+ await writeFile(configPath, JSON.stringify(STANDARD_MCP_CONFIG, null, 2) + "\n", "utf-8");
115
+ return {
116
+ written: true,
117
+ path: relativePath
118
+ };
119
+ }
120
+ async function installIdeRulesAndSkills(projectRoot, ide, resolveRuleFile, resolveSkillFile, forceUpdate = false) {
121
+ let installed = 0;
122
+ let updated = 0;
123
+ const rulesDir = join(projectRoot, ide.rulesDir);
124
+ const git = simpleGit(projectRoot);
125
+ const filesToAdd = [];
126
+ await ensureDir(rulesDir);
127
+ const guardrailsDest = join(rulesDir, ide.guardrailsFileName);
128
+ try {
129
+ let content = await readFile(resolveRuleFile("essential/contentrain-essentials.md"), "utf-8");
130
+ if (ide.guardrailsFrontmatter) content = ide.guardrailsFrontmatter + content;
131
+ if (await pathExists(guardrailsDest)) {
132
+ if (forceUpdate) {
133
+ await writeFile(guardrailsDest, content, "utf-8");
134
+ updated++;
135
+ }
136
+ } else {
137
+ if (ide.name === "GitHub Copilot" && await pathExists(guardrailsDest)) {
138
+ if (!(await readFile(guardrailsDest, "utf-8")).includes("# Contentrain")) await appendFile(guardrailsDest, `\n\n${content}`);
139
+ } else await writeFile(guardrailsDest, content, "utf-8");
140
+ installed++;
141
+ }
142
+ filesToAdd.push(guardrailsDest);
143
+ } catch {}
144
+ for (const oldFile of OLD_RULE_FILES) {
145
+ const oldPath = join(rulesDir, oldFile);
146
+ if (await pathExists(oldPath)) {
147
+ const { unlink } = await import("node:fs/promises");
148
+ await unlink(oldPath);
149
+ }
150
+ }
151
+ if (resolveSkillFile) {
152
+ const skillsDir = join(projectRoot, ide.skillsDir);
153
+ await ensureDir(skillsDir);
154
+ for (const skillName of AGENT_SKILL_NAMES) {
155
+ const skillDir = join(skillsDir, skillName);
156
+ const skillMd = join(skillDir, "SKILL.md");
157
+ try {
158
+ const src = resolveSkillFile(`skills/${skillName}/SKILL.md`);
159
+ const srcContent = await readFile(src, "utf-8");
160
+ await ensureDir(skillDir);
161
+ if (await pathExists(skillMd)) {
162
+ if (forceUpdate) {
163
+ await writeFile(skillMd, srcContent, "utf-8");
164
+ updated++;
165
+ }
166
+ } else {
167
+ await writeFile(skillMd, srcContent, "utf-8");
168
+ installed++;
169
+ }
170
+ const { readdirSync } = await import("node:fs");
171
+ try {
172
+ const refsDir = join(src, "..", "references");
173
+ const refs = readdirSync(refsDir);
174
+ if (refs.length > 0) {
175
+ const destRefsDir = join(skillDir, "references");
176
+ await ensureDir(destRefsDir);
177
+ for (const ref of refs) {
178
+ const refDest = join(destRefsDir, ref);
179
+ if (forceUpdate || !await pathExists(refDest)) await writeFile(refDest, await readFile(join(refsDir, ref), "utf-8"), "utf-8");
180
+ }
181
+ }
182
+ } catch {}
183
+ } catch {}
184
+ }
185
+ }
186
+ if (filesToAdd.length > 0) {
187
+ await git.add(filesToAdd);
188
+ try {
189
+ await git.commit(`[contentrain] install ${ide.name} rules and skills`);
190
+ } catch {}
191
+ }
192
+ return {
193
+ installed,
194
+ updated
195
+ };
196
+ }
197
+ async function addClaudeMdReference(projectRoot) {
198
+ const claudeMdPath = join(projectRoot, "CLAUDE.md");
199
+ const marker = "# Contentrain AI Rules";
200
+ const reference = [
201
+ "# Contentrain AI Rules",
202
+ "",
203
+ "This project uses [Contentrain](https://ai.contentrain.io) for AI-driven content management.",
204
+ "",
205
+ "- **Rules** are in `.claude/rules/contentrain-essentials.md` — auto-loaded each conversation",
206
+ "- **Skills** are in `.claude/skills/` — loaded on demand by the agent",
207
+ "- **Docs:** https://ai.contentrain.io"
208
+ ].join("\n");
209
+ const git = simpleGit(projectRoot);
210
+ if (await pathExists(claudeMdPath)) {
211
+ if (!(await readFile(claudeMdPath, "utf-8")).includes(marker)) {
212
+ await appendFile(claudeMdPath, `\n\n${reference}\n`);
213
+ await git.add(claudeMdPath);
214
+ try {
215
+ await git.commit("[contentrain] add CLAUDE.md reference");
216
+ } catch {}
217
+ }
218
+ } else {
219
+ await writeFile(claudeMdPath, `${reference}\n`, "utf-8");
220
+ await git.add(claudeMdPath);
221
+ try {
222
+ await git.commit("[contentrain] add CLAUDE.md reference");
223
+ } catch {}
224
+ }
225
+ }
226
+ //#endregion
227
+ export { detectIdes as a, addClaudeMdReference as i, IDE_CONFIGS as n, installIdeRulesAndSkills as o, MCP_CONFIGS as r, writeMcpConfig as s, AGENT_SKILL_NAMES as t };
package/dist/index.mjs CHANGED
@@ -5,18 +5,20 @@ import { defineCommand, runMain } from "citty";
5
5
  runMain(defineCommand({
6
6
  meta: {
7
7
  name: "contentrain",
8
- version: "0.4.1",
8
+ version: "0.4.2",
9
9
  description: "Contentrain CLI — AI content governance infrastructure"
10
10
  },
11
11
  subCommands: {
12
- init: () => import("./init-Q9B0iYtu.mjs").then((m) => m.default),
13
- status: () => import("./status-BmQZGdZX.mjs").then((m) => m.default),
12
+ init: () => import("./init-DFyQ-l-E.mjs").then((m) => m.default),
13
+ status: () => import("./status-CoHgz6HN.mjs").then((m) => m.default),
14
14
  doctor: () => import("./doctor-DyKjAIKH.mjs").then((m) => m.default),
15
- validate: () => import("./validate-DnVamp3p.mjs").then((m) => m.default),
16
- serve: () => import("./serve-DL4LhWxl.mjs").then((m) => m.default),
15
+ validate: () => import("./validate-B10L7RL7.mjs").then((m) => m.default),
16
+ serve: () => import("./serve-CNeFIQ1i.mjs").then((m) => m.default),
17
17
  generate: () => import("./generate-DrUojrk8.mjs").then((m) => m.default),
18
18
  diff: () => import("./diff--halNUpG.mjs").then((m) => m.default),
19
- studio: () => import("./studio-B8lF0fQx.mjs").then((m) => m.default)
19
+ setup: () => import("./setup-DJy-jNEU.mjs").then((m) => m.default),
20
+ skills: () => import("./skills-D-tFY7WA.mjs").then((m) => m.default),
21
+ studio: () => import("./studio-CJUGiIMd.mjs").then((m) => m.default)
20
22
  }
21
23
  }));
22
24
  //#endregion
@@ -1,5 +1,6 @@
1
1
  import { r as resolveProjectRoot, t as loadProjectContext } from "./context-An3xrvcP.mjs";
2
2
  import { i as pc } from "./ui-B5mXontH.mjs";
3
+ import { a as detectIdes, i as addClaudeMdReference, n as IDE_CONFIGS, o as installIdeRulesAndSkills, s as writeMcpConfig } from "./ide-Bg-Z8QZk.mjs";
3
4
  import { defineCommand } from "citty";
4
5
  import { confirm, intro, isCancel, log, multiselect, outro, select, spinner } from "@clack/prompts";
5
6
  import { simpleGit } from "simple-git";
@@ -346,6 +347,7 @@ async function executeInit(projectRoot, opts) {
346
347
  await tx.complete();
347
348
  s.stop("Initialized");
348
349
  await installRules(projectRoot);
350
+ await configureMcp(projectRoot);
349
351
  } catch (error) {
350
352
  s.stop("Failed");
351
353
  throw error;
@@ -353,64 +355,6 @@ async function executeInit(projectRoot, opts) {
353
355
  await tx.cleanup();
354
356
  }
355
357
  }
356
- const AGENT_SKILL_NAMES = [
357
- "contentrain",
358
- "contentrain-normalize",
359
- "contentrain-quality",
360
- "contentrain-sdk",
361
- "contentrain-content",
362
- "contentrain-model",
363
- "contentrain-init",
364
- "contentrain-bulk",
365
- "contentrain-validate-fix",
366
- "contentrain-review",
367
- "contentrain-translate",
368
- "contentrain-generate",
369
- "contentrain-serve",
370
- "contentrain-diff",
371
- "contentrain-doctor"
372
- ];
373
- const OLD_RULE_FILES = [
374
- "contentrain-content-quality.md",
375
- "contentrain-seo-rules.md",
376
- "contentrain-i18n-quality.md",
377
- "contentrain-accessibility-rules.md",
378
- "contentrain-security-rules.md",
379
- "contentrain-media-rules.md",
380
- "contentrain-content-conventions.md",
381
- "contentrain-schema-rules.md",
382
- "contentrain-mcp-usage.md",
383
- "contentrain-workflow-rules.md",
384
- "contentrain-normalize-rules.md"
385
- ];
386
- const IDE_CONFIGS = {
387
- "claude-code": {
388
- name: "Claude Code",
389
- rulesDir: ".claude/rules",
390
- skillsDir: ".claude/skills",
391
- guardrailsFileName: "contentrain-essentials.md"
392
- },
393
- cursor: {
394
- name: "Cursor",
395
- rulesDir: ".cursor/rules",
396
- skillsDir: ".cursor/skills",
397
- guardrailsFileName: "contentrain-essentials.mdc",
398
- guardrailsFrontmatter: "---\ndescription: Contentrain essential content governance rules\nalwaysApply: true\n---\n\n"
399
- },
400
- windsurf: {
401
- name: "Windsurf",
402
- rulesDir: ".windsurf/rules",
403
- skillsDir: ".windsurf/skills",
404
- guardrailsFileName: "contentrain-essentials.md",
405
- guardrailsFrontmatter: "---\ndescription: Contentrain essential content governance rules\ntrigger: always_on\n---\n\n"
406
- },
407
- copilot: {
408
- name: "GitHub Copilot",
409
- rulesDir: ".github",
410
- skillsDir: ".agents/skills",
411
- guardrailsFileName: "copilot-instructions.md"
412
- }
413
- };
414
358
  async function installRules(projectRoot) {
415
359
  try {
416
360
  const { createRequire } = await import("node:module");
@@ -421,21 +365,13 @@ async function installRules(projectRoot) {
421
365
  const requireSkills = createRequire(import.meta.url);
422
366
  resolveSkillFile = (p) => requireSkills.resolve(`@contentrain/skills/${p}`);
423
367
  } catch {}
424
- const hasClaudeCode = await pathExists(join(projectRoot, "CLAUDE.md")) || await pathExists(join(projectRoot, ".claude"));
425
- const hasCursor = await pathExists(join(projectRoot, ".cursor"));
426
- const hasWindsurf = await pathExists(join(projectRoot, ".windsurf"));
427
- const hasCopilot = await pathExists(join(projectRoot, ".github"));
428
- const noIDEDetected = !hasClaudeCode && !hasCursor && !hasWindsurf && !hasCopilot;
429
- const detectedIdes = [];
430
- if (hasClaudeCode) detectedIdes.push("claude-code");
431
- if (hasCursor) detectedIdes.push("cursor");
432
- if (hasWindsurf) detectedIdes.push("windsurf");
433
- if (hasCopilot) detectedIdes.push("copilot");
434
- for (const ideKey of detectedIdes) {
368
+ const detectedIdeKeys = await detectIdes(projectRoot);
369
+ const noIDEDetected = detectedIdeKeys.length === 0;
370
+ for (const ideKey of detectedIdeKeys) {
435
371
  const ide = IDE_CONFIGS[ideKey];
436
372
  await installIdeRulesAndSkills(projectRoot, ide, resolveRuleFile, resolveSkillFile);
437
373
  }
438
- if (hasClaudeCode) await addClaudeMdReference(projectRoot);
374
+ if (detectedIdeKeys.includes("claude-code")) await addClaudeMdReference(projectRoot);
439
375
  if (noIDEDetected) {
440
376
  const essentials = await readFile(resolveRuleFile("essential/contentrain-essentials.md"), "utf-8");
441
377
  const dest = join(projectRoot, "CLAUDE.md");
@@ -448,92 +384,26 @@ async function installRules(projectRoot) {
448
384
  }
449
385
  } catch {}
450
386
  }
451
- async function installIdeRulesAndSkills(projectRoot, ide, resolveRuleFile, resolveSkillFile) {
452
- const rulesDir = join(projectRoot, ide.rulesDir);
453
- const skillsDir = join(projectRoot, ide.skillsDir);
454
- const git = simpleGit(projectRoot);
455
- const filesToAdd = [];
456
- await ensureDir(rulesDir);
457
- const guardrailsDest = join(rulesDir, ide.guardrailsFileName);
458
- if (!await pathExists(guardrailsDest)) try {
459
- let content = await readFile(resolveRuleFile("essential/contentrain-essentials.md"), "utf-8");
460
- if (ide.guardrailsFrontmatter) content = ide.guardrailsFrontmatter + content;
461
- if (ide.name === "GitHub Copilot" && await pathExists(guardrailsDest)) {
462
- if (!(await readFile(guardrailsDest, "utf-8")).includes("# Contentrain")) await appendFile(guardrailsDest, `\n\n${content}`);
463
- } else await writeFile(guardrailsDest, content, "utf-8");
464
- filesToAdd.push(guardrailsDest);
465
- } catch {}
466
- for (const oldFile of OLD_RULE_FILES) {
467
- const oldPath = join(rulesDir, oldFile);
468
- if (await pathExists(oldPath)) {
469
- const { unlink } = await import("node:fs/promises");
470
- await unlink(oldPath);
471
- }
472
- }
473
- if (resolveSkillFile) {
474
- await ensureDir(skillsDir);
475
- for (const skillName of AGENT_SKILL_NAMES) {
476
- const skillDir = join(skillsDir, skillName);
477
- const skillMd = join(skillDir, "SKILL.md");
478
- if (await pathExists(skillMd)) continue;
479
- try {
480
- const src = resolveSkillFile(`skills/${skillName}/SKILL.md`);
481
- await ensureDir(skillDir);
482
- await writeFile(skillMd, await readFile(src, "utf-8"), "utf-8");
483
- filesToAdd.push(skillMd);
484
- const { readdirSync } = await import("node:fs");
485
- try {
486
- const refsDir = join(resolveSkillFile(`skills/${skillName}/SKILL.md`), "..", "references");
487
- const refs = readdirSync(refsDir);
488
- if (refs.length > 0) {
489
- const destRefsDir = join(skillDir, "references");
490
- await ensureDir(destRefsDir);
491
- for (const ref of refs) {
492
- const refSrc = join(refsDir, ref);
493
- const refDest = join(destRefsDir, ref);
494
- await writeFile(refDest, await readFile(refSrc, "utf-8"), "utf-8");
495
- filesToAdd.push(refDest);
496
- }
497
- }
498
- } catch {}
499
- } catch {}
387
+ async function configureMcp(projectRoot) {
388
+ try {
389
+ const detectedIdeKeys = await detectIdes(projectRoot);
390
+ if (detectedIdeKeys.length === 0) detectedIdeKeys.push("claude-code");
391
+ const writtenPaths = [];
392
+ for (const ideKey of detectedIdeKeys) {
393
+ const result = await writeMcpConfig(projectRoot, ideKey);
394
+ if (result.written) {
395
+ log.info(`MCP configured: ${pc.cyan(result.path)}`);
396
+ writtenPaths.push(join(projectRoot, result.path));
397
+ }
500
398
  }
501
- }
502
- if (filesToAdd.length > 0) {
503
- await git.add(filesToAdd);
504
- try {
505
- await git.commit(`[contentrain] install ${ide.name} rules and skills`);
506
- } catch {}
507
- }
508
- }
509
- async function addClaudeMdReference(projectRoot) {
510
- const claudeMdPath = join(projectRoot, "CLAUDE.md");
511
- const marker = "# Contentrain AI Rules";
512
- const reference = [
513
- "# Contentrain AI Rules",
514
- "",
515
- "This project uses [Contentrain](https://ai.contentrain.io) for AI-driven content management.",
516
- "",
517
- "- **Rules** are in `.claude/rules/contentrain-essentials.md` — auto-loaded each conversation",
518
- "- **Skills** are in `.claude/skills/` — loaded on demand by the agent",
519
- "- **Docs:** https://ai.contentrain.io"
520
- ].join("\n");
521
- const git = simpleGit(projectRoot);
522
- if (await pathExists(claudeMdPath)) {
523
- if (!(await readFile(claudeMdPath, "utf-8")).includes(marker)) {
524
- await appendFile(claudeMdPath, `\n\n${reference}\n`);
525
- await git.add(claudeMdPath);
399
+ if (writtenPaths.length > 0) {
400
+ const git = simpleGit(projectRoot);
401
+ await git.add(writtenPaths);
526
402
  try {
527
- await git.commit("[contentrain] add CLAUDE.md reference");
403
+ await git.commit("[contentrain] configure MCP servers");
528
404
  } catch {}
529
405
  }
530
- } else {
531
- await writeFile(claudeMdPath, `${reference}\n`, "utf-8");
532
- await git.add(claudeMdPath);
533
- try {
534
- await git.commit("[contentrain] add CLAUDE.md reference");
535
- } catch {}
536
- }
406
+ } catch {}
537
407
  }
538
408
  async function updateGitignore(projectRoot) {
539
409
  const gitignorePath = join(projectRoot, ".gitignore");
@@ -1,6 +1,6 @@
1
1
  import { i as pc } from "./ui-B5mXontH.mjs";
2
- import { i as checkPermissions, o as loadCredentials, s as saveCredentials, t as StudioApiClient } from "./client-CLV4XoJz.mjs";
3
- import { n as openBrowser, t as startOAuthServer } from "./oauth-server-1p6y1H30.mjs";
2
+ import { i as checkPermissions, o as loadCredentials, s as saveCredentials, t as StudioApiClient } from "./client-C400qHcL.mjs";
3
+ import { n as openBrowser, t as startOAuthServer } from "./oauth-server-Beppljfz.mjs";
4
4
  import { defineCommand } from "citty";
5
5
  import { confirm, intro, isCancel, log, outro, select, spinner } from "@clack/prompts";
6
6
  //#region src/studio/commands/login.ts
@@ -1,5 +1,5 @@
1
1
  import { i as pc } from "./ui-B5mXontH.mjs";
2
- import { a as clearCredentials, o as loadCredentials, t as StudioApiClient } from "./client-CLV4XoJz.mjs";
2
+ import { a as clearCredentials, o as loadCredentials, t as StudioApiClient } from "./client-C400qHcL.mjs";
3
3
  import { defineCommand } from "citty";
4
4
  import { intro, log, outro } from "@clack/prompts";
5
5
  //#region src/studio/commands/logout.ts
@@ -1,4 +1,4 @@
1
- import { c as saveDefaults, o as loadCredentials } from "./client-CLV4XoJz.mjs";
1
+ import { c as saveDefaults, o as loadCredentials } from "./client-C400qHcL.mjs";
2
2
  import { confirm, isCancel, select } from "@clack/prompts";
3
3
  //#region src/studio/resolve-context.ts
4
4
  /**
@@ -11,32 +11,51 @@ var serve_default = defineCommand({
11
11
  args: {
12
12
  root: {
13
13
  type: "string",
14
- description: "Project root path",
14
+ description: "Project root path (env: CONTENTRAIN_PROJECT_ROOT)",
15
15
  required: false
16
16
  },
17
17
  stdio: {
18
18
  type: "boolean",
19
- description: "Use stdio MCP transport (for IDE integration)",
19
+ description: "Use stdio MCP transport for IDE integration (env: CONTENTRAIN_STDIO=true)",
20
20
  required: false
21
21
  },
22
22
  port: {
23
23
  type: "string",
24
- description: "HTTP server port (default: 3333)",
24
+ description: "HTTP server port, default: 3333 (env: CONTENTRAIN_PORT)",
25
25
  required: false
26
26
  },
27
27
  open: {
28
28
  type: "boolean",
29
- description: "Open browser automatically",
29
+ description: "Open browser automatically (env: CONTENTRAIN_NO_OPEN=true to disable)",
30
30
  required: false
31
31
  },
32
32
  host: {
33
33
  type: "string",
34
- description: "Bind address (default: localhost)",
34
+ description: "Bind address, default: localhost (env: CONTENTRAIN_HOST)",
35
+ required: false
36
+ },
37
+ demo: {
38
+ type: "boolean",
39
+ description: "Start with a temporary demo project (no setup needed)",
35
40
  required: false
36
41
  }
37
42
  },
38
43
  async run({ args }) {
39
- const projectRoot = await resolveProjectRoot(args.root);
44
+ let projectRoot = await resolveProjectRoot(args.root);
45
+ let demoDir;
46
+ if (args.demo) {
47
+ const { createDemoProject, cleanupDemoProject } = await import("./demo-DcBt6fw8.mjs");
48
+ demoDir = await createDemoProject();
49
+ projectRoot = demoDir;
50
+ consola.info(`Demo project created at ${demoDir}`);
51
+ process.on("exit", () => {
52
+ cleanupDemoProject(demoDir);
53
+ });
54
+ process.on("SIGINT", () => {
55
+ cleanupDemoProject(demoDir);
56
+ process.exit(0);
57
+ });
58
+ }
40
59
  process.env["CONTENTRAIN_PROJECT_ROOT"] = projectRoot;
41
60
  process.env["CONTENTRAIN_SOURCE"] = "mcp-local";
42
61
  try {
@@ -47,7 +66,7 @@ var serve_default = defineCommand({
47
66
  if (name && typeof name === "string") process.env["CONTENTRAIN_AUTHOR_NAME"] = name;
48
67
  if (email && typeof email === "string") process.env["CONTENTRAIN_AUTHOR_EMAIL"] = email;
49
68
  } catch {}
50
- if (args.stdio) {
69
+ if (args.stdio || process.env["CONTENTRAIN_STDIO"] === "true" || process.env["CONTENTRAIN_STDIO"] === "1") {
51
70
  const server = createServer(projectRoot);
52
71
  const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
53
72
  const transport = new StdioServerTransport();
@@ -55,9 +74,9 @@ var serve_default = defineCommand({
55
74
  await server.connect(transport);
56
75
  return;
57
76
  }
58
- const port = Number(args.port) || 3333;
59
- const host = args.host ?? "localhost";
60
- const shouldOpen = args.open !== false;
77
+ const port = Number(args.port) || Number(process.env["CONTENTRAIN_PORT"]) || 3333;
78
+ const host = args.host ?? process.env["CONTENTRAIN_HOST"] ?? "localhost";
79
+ const shouldOpen = args.open !== false && process.env["CONTENTRAIN_NO_OPEN"] !== "true";
61
80
  const { join, dirname } = await import("node:path");
62
81
  const { existsSync } = await import("node:fs");
63
82
  const { fileURLToPath } = await import("node:url");
@@ -66,7 +85,7 @@ var serve_default = defineCommand({
66
85
  consola.warn("Serve UI not found. Running in API-only mode.");
67
86
  consola.info("UI will be available after building: cd packages/cli/src/serve-ui && pnpm build");
68
87
  }
69
- const { createServeApp } = await import("./server-WLDOAZa4.mjs");
88
+ const { createServeApp } = await import("./server-DTdmutjb.mjs");
70
89
  const { app, handleUpgrade } = await createServeApp({
71
90
  projectRoot,
72
91
  port,
@@ -0,0 +1,108 @@
1
+ import { r as resolveProjectRoot, t as loadProjectContext } from "./context-An3xrvcP.mjs";
2
+ import { i as pc } from "./ui-B5mXontH.mjs";
3
+ import { a as detectIdes, n as IDE_CONFIGS, o as installIdeRulesAndSkills, r as MCP_CONFIGS, s as writeMcpConfig } from "./ide-Bg-Z8QZk.mjs";
4
+ import { defineCommand } from "citty";
5
+ import { intro, log, outro, spinner } from "@clack/prompts";
6
+ //#region src/commands/setup.ts
7
+ const SUPPORTED_AGENTS = Object.keys(MCP_CONFIGS);
8
+ var setup_default = defineCommand({
9
+ meta: {
10
+ name: "setup",
11
+ description: "Configure MCP server and AI rules for your IDE"
12
+ },
13
+ args: {
14
+ agent: {
15
+ type: "positional",
16
+ description: `IDE agent: ${SUPPORTED_AGENTS.join(", ")}`,
17
+ required: false
18
+ },
19
+ root: {
20
+ type: "string",
21
+ description: "Project root path",
22
+ required: false
23
+ },
24
+ all: {
25
+ type: "boolean",
26
+ description: "Configure all detected IDEs",
27
+ required: false
28
+ }
29
+ },
30
+ async run({ args }) {
31
+ const projectRoot = await resolveProjectRoot(args.root);
32
+ intro(pc.bold("contentrain setup"));
33
+ const agent = args.agent;
34
+ if (!agent && !args.all) {
35
+ log.error("Please specify an agent or use --all:");
36
+ log.message("");
37
+ log.message(` ${pc.cyan("contentrain setup claude-code")}`);
38
+ log.message(` ${pc.cyan("contentrain setup cursor")}`);
39
+ log.message(` ${pc.cyan("contentrain setup vscode")}`);
40
+ log.message(` ${pc.cyan("contentrain setup windsurf")}`);
41
+ log.message(` ${pc.cyan("contentrain setup copilot")}`);
42
+ log.message(` ${pc.cyan("contentrain setup --all")}`);
43
+ outro("");
44
+ return;
45
+ }
46
+ if (agent && !SUPPORTED_AGENTS.includes(agent)) {
47
+ log.error(`Unknown agent: "${agent}"`);
48
+ log.message(`Supported agents: ${SUPPORTED_AGENTS.join(", ")}`);
49
+ outro("");
50
+ return;
51
+ }
52
+ if (!(await loadProjectContext(projectRoot)).initialized) {
53
+ log.warning("Project not initialized. Run `contentrain init` first.");
54
+ outro("");
55
+ return;
56
+ }
57
+ const s = spinner();
58
+ let agents;
59
+ if (args.all) {
60
+ agents = await detectIdes(projectRoot);
61
+ if (agents.length === 0) agents = ["claude-code"];
62
+ s.start(`Configuring MCP for ${agents.map((a) => MCP_CONFIGS[a] ? a : "").filter(Boolean).join(", ")}...`);
63
+ } else {
64
+ agents = [agent];
65
+ s.start(`Configuring MCP for ${agent}...`);
66
+ }
67
+ const results = [];
68
+ for (const agentKey of agents) {
69
+ const mcpResult = await writeMcpConfig(projectRoot, agentKey);
70
+ let rulesStatus = "skipped";
71
+ const ideConfig = IDE_CONFIGS[agentKey];
72
+ if (ideConfig) try {
73
+ const { createRequire } = await import("node:module");
74
+ const req = createRequire(import.meta.url);
75
+ const resolveRuleFile = (p) => req.resolve(`@contentrain/rules/${p}`);
76
+ let resolveSkillFile = null;
77
+ try {
78
+ resolveSkillFile = (p) => req.resolve(`@contentrain/skills/${p}`);
79
+ } catch {}
80
+ const result = await installIdeRulesAndSkills(projectRoot, ideConfig, resolveRuleFile, resolveSkillFile);
81
+ if (result.installed > 0) rulesStatus = `${result.installed} installed`;
82
+ else rulesStatus = "up to date";
83
+ } catch {
84
+ rulesStatus = "failed (packages not installed)";
85
+ }
86
+ results.push({
87
+ agent: agentKey,
88
+ mcp: mcpResult.written ? `${pc.green("✓")} ${mcpResult.path}` : `${pc.dim("–")} ${mcpResult.skipped ?? mcpResult.path}`,
89
+ rules: rulesStatus
90
+ });
91
+ }
92
+ s.stop("Done");
93
+ for (const r of results) {
94
+ log.info(`${pc.bold(r.agent)}`);
95
+ log.message(` MCP config: ${r.mcp}`);
96
+ log.message(` Rules/skills: ${r.rules}`);
97
+ }
98
+ log.message("");
99
+ log.info(pc.bold("Next steps:"));
100
+ log.message(` 1. Restart your IDE to pick up the MCP config`);
101
+ log.message(` 2. Ask your agent: ${pc.cyan("\"Create a hero section model\"")}`);
102
+ log.message("");
103
+ log.message(pc.dim(` Tip: Run ${pc.cyan("contentrain serve")} to open the local review UI`));
104
+ outro("");
105
+ }
106
+ });
107
+ //#endregion
108
+ export { setup_default as default };
@@ -0,0 +1,92 @@
1
+ import { r as resolveProjectRoot } from "./context-An3xrvcP.mjs";
2
+ import { i as pc } from "./ui-B5mXontH.mjs";
3
+ import { a as detectIdes, n as IDE_CONFIGS, o as installIdeRulesAndSkills, t as AGENT_SKILL_NAMES } from "./ide-Bg-Z8QZk.mjs";
4
+ import { defineCommand } from "citty";
5
+ import { intro, log, outro, spinner } from "@clack/prompts";
6
+ import { join } from "node:path";
7
+ import { pathExists } from "@contentrain/mcp/util/fs";
8
+ //#region src/commands/skills.ts
9
+ var skills_default = defineCommand({
10
+ meta: {
11
+ name: "skills",
12
+ description: "Install, update, or list Contentrain AI skills and rules for your IDE"
13
+ },
14
+ args: {
15
+ root: {
16
+ type: "string",
17
+ description: "Project root path",
18
+ required: false
19
+ },
20
+ update: {
21
+ type: "boolean",
22
+ description: "Force update all skills and rules",
23
+ required: false
24
+ },
25
+ list: {
26
+ type: "boolean",
27
+ description: "List installed skills and their status",
28
+ required: false
29
+ }
30
+ },
31
+ async run({ args }) {
32
+ const projectRoot = await resolveProjectRoot(args.root);
33
+ intro(pc.bold("contentrain skills"));
34
+ if (args.list) {
35
+ await listInstalledSkills(projectRoot);
36
+ return;
37
+ }
38
+ const s = spinner();
39
+ s.start("Installing skills and rules...");
40
+ try {
41
+ const { createRequire } = await import("node:module");
42
+ const require = createRequire(import.meta.url);
43
+ const resolveRuleFile = (p) => require.resolve(`@contentrain/rules/${p}`);
44
+ let resolveSkillFile = null;
45
+ try {
46
+ const requireSkills = createRequire(import.meta.url);
47
+ resolveSkillFile = (p) => requireSkills.resolve(`@contentrain/skills/${p}`);
48
+ } catch {
49
+ s.stop("Failed");
50
+ log.error("@contentrain/skills package not found. Install it:");
51
+ log.message(pc.cyan(" pnpm add -D @contentrain/skills @contentrain/rules"));
52
+ outro("");
53
+ return;
54
+ }
55
+ const detectedIdes = await detectIdes(projectRoot);
56
+ if (detectedIdes.length === 0) detectedIdes.push("claude-code");
57
+ let totalInstalled = 0;
58
+ let totalUpdated = 0;
59
+ for (const ideKey of detectedIdes) {
60
+ const ide = IDE_CONFIGS[ideKey];
61
+ const result = await installIdeRulesAndSkills(projectRoot, ide, resolveRuleFile, resolveSkillFile, args.update ?? false);
62
+ totalInstalled += result.installed;
63
+ totalUpdated += result.updated;
64
+ }
65
+ s.stop(`Done — ${detectedIdes.map((k) => IDE_CONFIGS[k].name).join(", ")}`);
66
+ if (totalUpdated > 0) log.success(`Updated ${totalUpdated} skill(s)`);
67
+ if (totalInstalled > 0) log.success(`Installed ${totalInstalled} new skill(s)`);
68
+ if (totalInstalled === 0 && totalUpdated === 0) log.info("All skills are up to date");
69
+ outro("");
70
+ } catch (error) {
71
+ s.stop("Failed");
72
+ throw error;
73
+ }
74
+ }
75
+ });
76
+ async function listInstalledSkills(projectRoot) {
77
+ let found = false;
78
+ for (const [, ide] of Object.entries(IDE_CONFIGS)) {
79
+ const skillsDir = join(projectRoot, ide.skillsDir);
80
+ if (!await pathExists(skillsDir)) continue;
81
+ found = true;
82
+ log.info(`${pc.bold(ide.name)} (${ide.skillsDir}/):`);
83
+ for (const skillName of AGENT_SKILL_NAMES) if (await pathExists(join(skillsDir, skillName, "SKILL.md"))) log.message(` ${pc.green("✓")} ${skillName}`);
84
+ else log.message(` ${pc.red("✗")} ${skillName} ${pc.dim("(missing)")}`);
85
+ if (await pathExists(join(projectRoot, ide.rulesDir, ide.guardrailsFileName))) log.message(` ${pc.green("✓")} essential rules`);
86
+ else log.message(` ${pc.red("✗")} essential rules ${pc.dim("(missing)")}`);
87
+ }
88
+ if (!found) log.warning("No IDE skills directories found. Run `contentrain skills` to install.");
89
+ outro("");
90
+ }
91
+ //#endregion
92
+ export { skills_default as default };
@@ -1,6 +1,6 @@
1
1
  import { i as pc, r as formatTable, t as formatCount } from "./ui-B5mXontH.mjs";
2
- import { n as resolveStudioClient } from "./client-CLV4XoJz.mjs";
3
- import { t as resolveStudioContext } from "./resolve-context-BwcikcF0.mjs";
2
+ import { n as resolveStudioClient } from "./client-C400qHcL.mjs";
3
+ import { t as resolveStudioContext } from "./resolve-context-Cg6JoVZt.mjs";
4
4
  import { defineCommand } from "citty";
5
5
  import { intro, log, outro, spinner } from "@clack/prompts";
6
6
  //#region src/studio/commands/status.ts
@@ -0,0 +1,24 @@
1
+ import { defineCommand } from "citty";
2
+ //#region src/studio/index.ts
3
+ var studio_default = defineCommand({
4
+ meta: {
5
+ name: "studio",
6
+ description: "Interact with Contentrain Studio"
7
+ },
8
+ subCommands: {
9
+ login: () => import("./login-DCXkOrQV.mjs").then((m) => m.default),
10
+ logout: () => import("./logout-nPt2UAeQ.mjs").then((m) => m.default),
11
+ whoami: () => import("./whoami-Ub5RznbU.mjs").then((m) => m.default),
12
+ connect: () => import("./connect-DJo9PSiw.mjs").then((m) => m.default),
13
+ status: () => import("./status-Cyv-jo1y.mjs").then((m) => m.default),
14
+ activity: () => import("./activity-CbkxcfDf.mjs").then((m) => m.default),
15
+ usage: () => import("./usage-B2xuc2DT.mjs").then((m) => m.default),
16
+ branches: () => import("./branches-D2UWex1N.mjs").then((m) => m.default),
17
+ "cdn-init": () => import("./cdn-init-CsmqJIaQ.mjs").then((m) => m.default),
18
+ "cdn-build": () => import("./cdn-build-BzC2QPNi.mjs").then((m) => m.default),
19
+ webhooks: () => import("./webhooks-Dq3zFLP7.mjs").then((m) => m.default),
20
+ submissions: () => import("./submissions-bIG-MWvv.mjs").then((m) => m.default)
21
+ }
22
+ });
23
+ //#endregion
24
+ export { studio_default as default };
@@ -1,6 +1,6 @@
1
1
  import { i as pc, r as formatTable, t as formatCount } from "./ui-B5mXontH.mjs";
2
- import { n as resolveStudioClient } from "./client-CLV4XoJz.mjs";
3
- import { t as resolveStudioContext } from "./resolve-context-BwcikcF0.mjs";
2
+ import { n as resolveStudioClient } from "./client-C400qHcL.mjs";
3
+ import { t as resolveStudioContext } from "./resolve-context-Cg6JoVZt.mjs";
4
4
  import { defineCommand } from "citty";
5
5
  import { confirm, intro, isCancel, log, outro, select, spinner } from "@clack/prompts";
6
6
  //#region src/studio/commands/submissions.ts
@@ -1,6 +1,6 @@
1
1
  import { i as pc, n as formatPercent, r as formatTable } from "./ui-B5mXontH.mjs";
2
- import { n as resolveStudioClient } from "./client-CLV4XoJz.mjs";
3
- import { t as resolveStudioContext } from "./resolve-context-BwcikcF0.mjs";
2
+ import { n as resolveStudioClient } from "./client-C400qHcL.mjs";
3
+ import { t as resolveStudioContext } from "./resolve-context-Cg6JoVZt.mjs";
4
4
  import { defineCommand } from "citty";
5
5
  import { intro, log, outro, spinner } from "@clack/prompts";
6
6
  //#region src/studio/commands/usage.ts
@@ -1,6 +1,6 @@
1
1
  import { i as pc, o as statusIcon, r as formatTable } from "./ui-B5mXontH.mjs";
2
- import { n as resolveStudioClient } from "./client-CLV4XoJz.mjs";
3
- import { t as resolveStudioContext } from "./resolve-context-BwcikcF0.mjs";
2
+ import { n as resolveStudioClient } from "./client-C400qHcL.mjs";
3
+ import { t as resolveStudioContext } from "./resolve-context-Cg6JoVZt.mjs";
4
4
  import { defineCommand } from "citty";
5
5
  import { confirm, intro, isCancel, log, multiselect, outro, select, spinner, text } from "@clack/prompts";
6
6
  //#region src/studio/commands/webhooks.ts
@@ -1,5 +1,5 @@
1
1
  import { i as pc } from "./ui-B5mXontH.mjs";
2
- import { i as checkPermissions, n as resolveStudioClient, r as AuthExpiredError } from "./client-CLV4XoJz.mjs";
2
+ import { i as checkPermissions, n as resolveStudioClient, r as AuthExpiredError } from "./client-C400qHcL.mjs";
3
3
  import { defineCommand } from "citty";
4
4
  import { intro, log, outro } from "@clack/prompts";
5
5
  //#region src/studio/commands/whoami.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "contentrain",
3
- "version": "0.4.1",
3
+ "version": "0.4.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.1",
50
- "@contentrain/query": "5.1.3",
51
- "@contentrain/types": "0.4.1",
52
- "@contentrain/mcp": "1.1.2"
49
+ "@contentrain/rules": "0.3.2",
50
+ "@contentrain/mcp": "1.2.0",
51
+ "@contentrain/query": "5.1.4",
52
+ "@contentrain/types": "0.4.2"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@types/ws": "^8.5.0",
@@ -1,24 +0,0 @@
1
- import { defineCommand } from "citty";
2
- //#region src/studio/index.ts
3
- var studio_default = defineCommand({
4
- meta: {
5
- name: "studio",
6
- description: "Interact with Contentrain Studio"
7
- },
8
- subCommands: {
9
- login: () => import("./login-wRBvHDCi.mjs").then((m) => m.default),
10
- logout: () => import("./logout-xPTGu6vx.mjs").then((m) => m.default),
11
- whoami: () => import("./whoami-CWvTYzum.mjs").then((m) => m.default),
12
- connect: () => import("./connect-DiSYnxFd.mjs").then((m) => m.default),
13
- status: () => import("./status-UvjbO4eS.mjs").then((m) => m.default),
14
- activity: () => import("./activity-DMQsYlzz.mjs").then((m) => m.default),
15
- usage: () => import("./usage-BqriRRqE.mjs").then((m) => m.default),
16
- branches: () => import("./branches-D330IxDO.mjs").then((m) => m.default),
17
- "cdn-init": () => import("./cdn-init-Bhnil0F8.mjs").then((m) => m.default),
18
- "cdn-build": () => import("./cdn-build-D_d3p4OZ.mjs").then((m) => m.default),
19
- webhooks: () => import("./webhooks-B1OhcCtZ.mjs").then((m) => m.default),
20
- submissions: () => import("./submissions-Dw0ChFDi.mjs").then((m) => m.default)
21
- }
22
- });
23
- //#endregion
24
- export { studio_default as default };