@cmssy/cli 0.12.1 → 0.14.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.
@@ -0,0 +1,178 @@
1
+ import chalk from "chalk";
2
+ import fs from "fs-extra";
3
+ import inquirer from "inquirer";
4
+ import os from "os";
5
+ import path from "path";
6
+ import { fileURLToPath } from "url";
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+ const SKILLS_ROOT = path.resolve(__dirname, "../skills");
10
+ const EDITOR_TARGETS = ["claude"];
11
+ const SKILLS = {
12
+ block: {
13
+ name: "block",
14
+ label: "Block dev (CLI + defineBlock/defineTemplate workflow)",
15
+ sourceBasename: "cmssy-block.md",
16
+ destDir: "cmssy-block",
17
+ examplePrompt: "scaffold a pricing block and publish as patch",
18
+ },
19
+ "mcp-content": {
20
+ name: "mcp-content",
21
+ label: "Content editing via @cmssy/mcp-server",
22
+ sourceBasename: "cmssy-mcp-content.md",
23
+ destDir: "cmssy-mcp-content",
24
+ examplePrompt: "add a new testimonials block to the homepage, in English and Polish",
25
+ },
26
+ };
27
+ function resolveEditorTarget(raw) {
28
+ const target = (raw ?? "claude").trim().toLowerCase();
29
+ if (!EDITOR_TARGETS.includes(target)) {
30
+ // JSON.stringify so whitespace-only / empty raw input is visible in
31
+ // the error (otherwise interpolating `" "` gives a blank message).
32
+ console.error(chalk.red(`✖ Unknown editor target: raw=${JSON.stringify(raw)}, normalized=${JSON.stringify(target)}`) + chalk.gray(`\n Supported: ${EDITOR_TARGETS.join(", ")}`));
33
+ process.exit(1);
34
+ }
35
+ return target;
36
+ }
37
+ function resolveSourcePath(editor, skill) {
38
+ return path.join(SKILLS_ROOT, editor, skill.sourceBasename);
39
+ }
40
+ function resolveInstallDir(editor, skill, opts) {
41
+ // Editor-specific layout. Today only `claude`, whose layout is:
42
+ // ~/.claude/skills/<destDir>/SKILL.md (global)
43
+ // <cwd>/.claude/skills/<destDir>/SKILL.md (local)
44
+ if (editor === "claude") {
45
+ const root = opts.local ? opts.cwd : os.homedir();
46
+ return path.join(root, ".claude", "skills", skill.destDir);
47
+ }
48
+ // Fallback (unreachable today, keeps TS happy for future targets)
49
+ throw new Error(`Unsupported editor target: ${editor}`);
50
+ }
51
+ function postInstallHint(editor, skill, installPath) {
52
+ if (editor === "claude") {
53
+ return [
54
+ chalk.gray("Next step:"),
55
+ chalk.white(" Restart Claude Code (or open a new session) so it picks up the skill."),
56
+ chalk.gray(" Then try something like:"),
57
+ chalk.white(` "${skill.examplePrompt}"`),
58
+ "",
59
+ chalk.gray(`Installed at: ${installPath}`),
60
+ ].join("\n");
61
+ }
62
+ return chalk.gray(`Installed at: ${installPath}`);
63
+ }
64
+ async function installOne(skill, editor, options) {
65
+ const sourcePath = resolveSourcePath(editor, skill);
66
+ if (!(await fs.pathExists(sourcePath))) {
67
+ console.error(chalk.red(`✖ Skill source missing: ${sourcePath}`) +
68
+ chalk.gray("\n This is a packaging bug - please report it at https://github.com/cmssy-io/cmssy-cli/issues"));
69
+ process.exit(1);
70
+ }
71
+ const installDir = resolveInstallDir(editor, skill, {
72
+ local: !!options.local,
73
+ cwd: process.cwd(),
74
+ });
75
+ const installPath = path.join(installDir, "SKILL.md");
76
+ const exists = await fs.pathExists(installPath);
77
+ if (exists && !options.force) {
78
+ if (options.yes) {
79
+ console.error(chalk.red(`✖ ${installPath} already exists`) +
80
+ chalk.gray("\n Pass --force to overwrite."));
81
+ process.exit(1);
82
+ }
83
+ const { overwrite } = await inquirer.prompt([
84
+ {
85
+ type: "confirm",
86
+ name: "overwrite",
87
+ message: `${installPath} already exists. Overwrite?`,
88
+ default: false,
89
+ },
90
+ ]);
91
+ if (!overwrite) {
92
+ console.log(chalk.yellow(`⚠ Skipped ${skill.name} - ${installPath} unchanged.`));
93
+ return "skipped";
94
+ }
95
+ }
96
+ await fs.ensureDir(installDir);
97
+ await fs.copy(sourcePath, installPath, { overwrite: true });
98
+ const scope = options.local ? "local (.claude/)" : "global (~/.claude/)";
99
+ console.log(chalk.green(`✔ Installed ${skill.label} skill`) + chalk.gray(` → ${scope}`));
100
+ console.log();
101
+ console.log(postInstallHint(editor, skill, installPath));
102
+ console.log();
103
+ return "installed";
104
+ }
105
+ export async function skillsInstallCommand(rawSkill, options) {
106
+ const editor = resolveEditorTarget(options.target);
107
+ // Normalize once - whitespace-only or empty input is treated as "no skill"
108
+ // so `cmssy skills install " "` behaves like `cmssy skills install`.
109
+ const skill = rawSkill?.trim().toLowerCase() || undefined;
110
+ // Friendly error if user passes an editor name where a skill name is expected
111
+ // (covers the pre-0.14.0 `cmssy skills install claude` shape).
112
+ if (skill && EDITOR_TARGETS.includes(skill)) {
113
+ console.error(chalk.red(`✖ "${rawSkill}" is an editor target, not a skill name.`) +
114
+ chalk.gray(`\n The first positional argument is now the skill name (e.g. "block", "mcp-content").`) +
115
+ chalk.gray(`\n Pass editor with --target, e.g.: cmssy skills install block --target ${skill}`));
116
+ process.exit(1);
117
+ }
118
+ if (options.all) {
119
+ if (skill) {
120
+ console.error(chalk.red(`✖ Cannot combine --all with a skill name.`) +
121
+ chalk.gray("\n Either pass a skill name or use --all, not both."));
122
+ process.exit(1);
123
+ }
124
+ for (const entry of Object.values(SKILLS)) {
125
+ await installOne(entry, editor, options);
126
+ }
127
+ return;
128
+ }
129
+ let skillName;
130
+ if (skill) {
131
+ if (!Object.hasOwn(SKILLS, skill)) {
132
+ console.error(chalk.red(`✖ Unknown skill: ${rawSkill}`) +
133
+ chalk.gray(`\n Available skills: ${Object.keys(SKILLS).join(", ")}`) +
134
+ chalk.gray(`\n Run 'cmssy skills list' to see all skills.`));
135
+ process.exit(1);
136
+ }
137
+ skillName = skill;
138
+ }
139
+ else {
140
+ // No skill passed (or whitespace-only) → interactive prompt (unless -y)
141
+ if (options.yes) {
142
+ console.error(chalk.red(`✖ No skill specified.`) +
143
+ chalk.gray(`\n Pass a skill name (e.g. 'block', 'mcp-content') or use --all.`) +
144
+ chalk.gray(`\n Run 'cmssy skills list' to see all skills.`));
145
+ process.exit(1);
146
+ }
147
+ const { chosen } = await inquirer.prompt([
148
+ {
149
+ type: "list",
150
+ name: "chosen",
151
+ message: "Which skill to install?",
152
+ choices: Object.values(SKILLS).map((s) => ({
153
+ name: `${s.name} - ${s.label}`,
154
+ value: s.name,
155
+ })),
156
+ },
157
+ ]);
158
+ skillName = chosen;
159
+ }
160
+ await installOne(SKILLS[skillName], editor, options);
161
+ }
162
+ export function skillsListCommand() {
163
+ console.log();
164
+ console.log(chalk.bold("Available skills:"));
165
+ console.log();
166
+ const padName = Math.max(...Object.values(SKILLS).map((s) => s.name.length));
167
+ for (const skill of Object.values(SKILLS)) {
168
+ console.log(` ${chalk.cyan(skill.name.padEnd(padName))} ${skill.label}`);
169
+ }
170
+ console.log();
171
+ console.log(chalk.gray(`Supported editor targets: ${EDITOR_TARGETS.join(", ")}`));
172
+ console.log();
173
+ console.log(chalk.gray("Install with:"));
174
+ console.log(chalk.white(" cmssy skills install <skill>"));
175
+ console.log(chalk.white(" cmssy skills install --all"));
176
+ console.log();
177
+ }
178
+ //# sourceMappingURL=skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/commands/skills.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAE3C,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;AAIzD,MAAM,cAAc,GAA4B,CAAC,QAAQ,CAAU,CAAC;AAiBpE,MAAM,MAAM,GAAuC;IACjD,KAAK,EAAE;QACL,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,uDAAuD;QAC9D,cAAc,EAAE,gBAAgB;QAChC,OAAO,EAAE,aAAa;QACtB,aAAa,EAAE,+CAA+C;KAC/D;IACD,aAAa,EAAE;QACb,IAAI,EAAE,aAAa;QACnB,KAAK,EAAE,uCAAuC;QAC9C,cAAc,EAAE,sBAAsB;QACtC,OAAO,EAAE,mBAAmB;QAC5B,aAAa,EACX,qEAAqE;KACxE;CACF,CAAC;AAUF,SAAS,mBAAmB,CAAC,GAAuB;IAClD,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACtD,IAAI,CAAE,cAAoC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5D,oEAAoE;QACpE,oEAAoE;QACpE,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,GAAG,CACP,gCAAgC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,gBAAgB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAC5F,GAAG,KAAK,CAAC,IAAI,CAAC,kBAAkB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAC9D,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,MAAsB,CAAC;AAChC,CAAC;AAED,SAAS,iBAAiB,CACxB,MAAoB,EACpB,KAAsB;IAEtB,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;AAC9D,CAAC;AAED,SAAS,iBAAiB,CACxB,MAAoB,EACpB,KAAsB,EACtB,IAAqC;IAErC,gEAAgE;IAChE,mDAAmD;IACnD,qDAAqD;IACrD,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC;QAClD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7D,CAAC;IACD,kEAAkE;IAClE,MAAM,IAAI,KAAK,CAAC,8BAA8B,MAAM,EAAE,CAAC,CAAC;AAC1D,CAAC;AAED,SAAS,eAAe,CACtB,MAAoB,EACpB,KAAsB,EACtB,WAAmB;IAEnB,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QACxB,OAAO;YACL,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC;YACxB,KAAK,CAAC,KAAK,CACT,yEAAyE,CAC1E;YACD,KAAK,CAAC,IAAI,CAAC,4BAA4B,CAAC;YACxC,KAAK,CAAC,KAAK,CAAC,QAAQ,KAAK,CAAC,aAAa,GAAG,CAAC;YAC3C,EAAE;YACF,KAAK,CAAC,IAAI,CAAC,iBAAiB,WAAW,EAAE,CAAC;SAC3C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,iBAAiB,WAAW,EAAE,CAAC,CAAC;AACpD,CAAC;AAED,KAAK,UAAU,UAAU,CACvB,KAAsB,EACtB,MAAoB,EACpB,OAA6B;IAE7B,MAAM,UAAU,GAAG,iBAAiB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAEpD,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC;QACvC,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,GAAG,CAAC,2BAA2B,UAAU,EAAE,CAAC;YAChD,KAAK,CAAC,IAAI,CACR,gGAAgG,CACjG,CACJ,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,UAAU,GAAG,iBAAiB,CAAC,MAAM,EAAE,KAAK,EAAE;QAClD,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK;QACtB,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;KACnB,CAAC,CAAC;IACH,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;IAEhD,IAAI,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAC7B,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;YAChB,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,GAAG,CAAC,KAAK,WAAW,iBAAiB,CAAC;gBAC1C,KAAK,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAC/C,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAyB;YAClE;gBACE,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,GAAG,WAAW,6BAA6B;gBACpD,OAAO,EAAE,KAAK;aACf;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,MAAM,CAAC,aAAa,KAAK,CAAC,IAAI,MAAM,WAAW,aAAa,CAAC,CACpE,CAAC;YACF,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IAED,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC/B,MAAM,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE5D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,qBAAqB,CAAC;IACzE,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,KAAK,CAAC,eAAe,KAAK,CAAC,KAAK,QAAQ,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,EAAE,CAAC,CAC5E,CAAC;IACF,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,EAAE,CAAC;IAEd,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,QAA4B,EAC5B,OAA6B;IAE7B,MAAM,MAAM,GAAG,mBAAmB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnD,2EAA2E;IAC3E,uEAAuE;IACvE,MAAM,KAAK,GAAG,QAAQ,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,SAAS,CAAC;IAE1D,8EAA8E;IAC9E,+DAA+D;IAC/D,IAAI,KAAK,IAAK,cAAoC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACnE,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,GAAG,CAAC,MAAM,QAAQ,0CAA0C,CAAC;YACjE,KAAK,CAAC,IAAI,CACR,wFAAwF,CACzF;YACD,KAAK,CAAC,IAAI,CACR,4EAA4E,KAAK,EAAE,CACpF,CACJ,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,GAAG,CAAC,2CAA2C,CAAC;gBACpD,KAAK,CAAC,IAAI,CAAC,sDAAsD,CAAC,CACrE,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1C,MAAM,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QAC3C,CAAC;QACD,OAAO;IACT,CAAC;IAED,IAAI,SAAoB,CAAC;IAEzB,IAAI,KAAK,EAAE,CAAC;QACV,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC;YAClC,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,GAAG,CAAC,oBAAoB,QAAQ,EAAE,CAAC;gBACvC,KAAK,CAAC,IAAI,CACR,yBAAyB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC1D;gBACD,KAAK,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAC/D,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,SAAS,GAAG,KAAkB,CAAC;IACjC,CAAC;SAAM,CAAC;QACN,wEAAwE;QACxE,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;YAChB,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,GAAG,CAAC,uBAAuB,CAAC;gBAChC,KAAK,CAAC,IAAI,CACR,mEAAmE,CACpE;gBACD,KAAK,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAC/D,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAwB;YAC9D;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,yBAAyB;gBAClC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBACzC,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,KAAK,EAAE;oBAC9B,KAAK,EAAE,CAAC,CAAC,IAAI;iBACd,CAAC,CAAC;aACJ;SACF,CAAC,CAAC;QACH,SAAS,GAAG,MAAM,CAAC;IACrB,CAAC;IAED,MAAM,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC;IAC7C,OAAO,CAAC,GAAG,EAAE,CAAC;IAEd,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAE7E,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;IAC7E,CAAC;IAED,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,IAAI,CAAC,6BAA6B,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CACrE,CAAC;IACF,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC;IACzC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC,CAAC;IAC3D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,EAAE,CAAC;AAChB,CAAC"}
@@ -0,0 +1,345 @@
1
+ ---
2
+ name: cmssy-block
3
+ description: "Run the full cmssy CLI lifecycle - init, link, scaffold/edit blocks and templates, dev/build/test, publish, sync. Trigger when the user asks to: initialize a cmssy project, link to a workspace, create/add a new block or template, add a field to a block's schema, edit config.ts, run cmssy dev/build/test/doctor, publish a block, bump a block version, sync a block from the design library, or work with defineBlock/defineTemplate. Trigger on words: cmssy, blok, block, template, publish, opublikuj, workspace, link, sync, defineBlock, defineTemplate, scaffold, zescafoldwac."
4
+ ---
5
+
6
+ # cmssy-block
7
+
8
+ Operates the full cmssy CLI workflow for blocks and templates in a project like `cmssy-marketing`. Covers every command the CLI exposes: `init`, `link`, `create`, `dev`, `test`, `build`, `publish`, `sync`, `doctor`, `workspaces`.
9
+
10
+ ## 0. Orientation
11
+
12
+ ```bash
13
+ cmssy --version # CLI must be installed globally
14
+ cmssy doctor # all-in-one health check
15
+ ```
16
+
17
+ `cmssy doctor` is the canonical precheck. It verifies:
18
+ - Node >= 18, npm, Next.js, React versions
19
+ - `cmssy.config.js` exists
20
+ - `.env` with `CMSSY_API_URL`, `CMSSY_API_TOKEN`, `CMSSY_WORKSPACE_ID`
21
+ - API reachable, token valid, workspace accessible
22
+
23
+ Run it before any non-trivial operation. If something fails, fix that first - don't proceed.
24
+
25
+ The project uses **pnpm**. Never run `npm install` - use `pnpm install`, `pnpm typecheck`, `pnpm lint`.
26
+
27
+ ## 1. Project lifecycle (in order)
28
+
29
+ ### 1.1 `cmssy init` - start a new project or bolt onto an existing one
30
+
31
+ ```bash
32
+ cmssy init <name> # creates ./<name> via create-next-app + cmssy scaffolding
33
+ cmssy init -y <name> # skip prompts, use defaults
34
+ cmssy init # add cmssy to the current Next.js project
35
+ ```
36
+
37
+ Outputs: `cmssy.config.js`, `blocks/`, `templates/`, `styles/main.css`, `components/`, example block.
38
+
39
+ ### 1.2 `cmssy link` - connect the project to a workspace
40
+
41
+ ```bash
42
+ cmssy link # interactive: pick workspace, paste token
43
+ cmssy link --token cs_xxx --workspace <id|slug> # non-interactive, for CI or scripted setup
44
+ cmssy link --api-url https://api.cmssy.io/graphql
45
+ ```
46
+
47
+ Writes credentials and `CMSSY_WORKSPACE_ID` to `.env`. Tokens come from https://cmssy.io/settings/tokens. List existing workspaces with `cmssy workspaces`.
48
+
49
+ ### 1.3 `cmssy workspaces` - show what this machine can publish to
50
+
51
+ ```bash
52
+ cmssy workspaces
53
+ ```
54
+
55
+ Returns name, slug, ID, and role for every accessible workspace. Use this when the user is ambiguous about the publish target.
56
+
57
+ ### 1.4 `cmssy create` - scaffold blocks or templates
58
+
59
+ ```bash
60
+ cmssy create block <kebab-name> [-d "desc"] [-c <category>] [-t "tag1,tag2"] [-y]
61
+ cmssy create template <kebab-name> [-d "desc"] [-y]
62
+ ```
63
+
64
+ Categories: `marketing`, `typography`, `media`, `layout`, `forms`, `navigation`, `other`.
65
+
66
+ Always use `-y` in automated flows unless the user wants to be prompted.
67
+
68
+ ### 1.5 `cmssy dev` - local preview with HMR
69
+
70
+ ```bash
71
+ cmssy dev # port 3000
72
+ cmssy dev -p 8080 # custom port
73
+ ```
74
+
75
+ Watches `config.ts` and auto-regenerates `block.d.ts`. Use for visual verification after edits.
76
+
77
+ ### 1.6 `cmssy test` - vitest runner
78
+
79
+ ```bash
80
+ cmssy test # all blocks/templates
81
+ cmssy test --block hero faq # subset
82
+ cmssy test --watch
83
+ cmssy test --coverage
84
+ ```
85
+
86
+ Test files live at `blocks/*/src/**/*.{test,spec}.{ts,tsx}` (same for templates). If no tests exist yet, this is a no-op.
87
+
88
+ ### 1.7 `cmssy build` - production bundle
89
+
90
+ ```bash
91
+ cmssy build # everything
92
+ cmssy build --block hero pricing # subset
93
+ cmssy build --framework react # override
94
+ ```
95
+
96
+ Outputs `public/@<vendor>/blocks.<name>/<version>/{index.js,index.css,package.json}`. Run before publish if you want to preview the bundle.
97
+
98
+ ### 1.8 `cmssy publish` - upload to workspace
99
+
100
+ ```bash
101
+ cmssy publish <name> --patch # single, patch bump
102
+ cmssy publish --all --patch # everything
103
+ cmssy publish <name> -w <workspaceId> --patch # explicit workspace (otherwise .env)
104
+ cmssy publish <name> --patch --dry-run # preview only, upload nothing
105
+ cmssy publish <name> --patch --with-source # include source for AI Block Builder
106
+ cmssy publish <name> --patch --zip # package and upload ZIP instead of GraphQL
107
+ ```
108
+
109
+ **Exactly one bump flag:** `--patch` | `--minor` | `--major` | `--no-bump`.
110
+
111
+ **Bump semantics:**
112
+ - `--patch` - bug fix, copy tweak, style-only change. No schema change.
113
+ - `--minor` - added optional fields, new variants. Non-breaking schema additions.
114
+ - `--major` - renamed/removed fields, changed field types, breaking component contract.
115
+
116
+ **Content preservation:** republishing preserves `defaultContent` and `schemaFields` on the workspace by default. Pass `--overwrite-content` only when the user explicitly wants to reset them from `config.ts` / `preview.json`.
117
+
118
+ **Breaking changes** trigger a confirmation prompt; pass `--force` only with explicit user approval.
119
+
120
+ ### 1.9 `cmssy sync` - pull blocks down from a workspace
121
+
122
+ ```bash
123
+ cmssy sync @cmssy/blocks.hero # one package from the design library
124
+ cmssy sync --workspace <id> # everything from a workspace
125
+ ```
126
+
127
+ Use when cloning a project's block set to a new repo, or when a block has drifted from its published version.
128
+
129
+ ## 2. Block anatomy (non-negotiable)
130
+
131
+ Every block lives in `blocks/<kebab-name>/`:
132
+
133
+ ```
134
+ blocks/<name>/
135
+ ├── config.ts # defineBlock({ name, description, category, tags, schema })
136
+ ├── package.json # { "name": "@<project>/blocks.<name>", "version": "x.y.z" }
137
+ ├── preview.json # sample content for cmssy dev
138
+ └── src/
139
+ ├── index.tsx # export { default } from "./<Pascal>"; import "./index.css";
140
+ ├── <Pascal>.tsx # the React component
141
+ ├── index.css # @import "../../../styles/main.css";
142
+ └── block.d.ts # AUTO-GENERATED from config.ts - never hand-edit
143
+ ```
144
+
145
+ **Naming (hard rules):**
146
+ - Directory + package `name` suffix: `kebab-case` (`blog-post-hero`).
147
+ - Component file and default export: `PascalCase` matching the directory (`BlogPostHero.tsx`).
148
+ - Package name: `@<projectName>/blocks.<kebab-name>` where `projectName` comes from `cmssy.config.js`.
149
+ - New blocks start at `"version": "1.0.0"`.
150
+
151
+ ## 3. Writing `config.ts`
152
+
153
+ Import from `@cmssy/cli/config`. Available field types:
154
+
155
+ | type | Use for |
156
+ | --- | --- |
157
+ | `singleLine` | Short text (heading, label, badge). |
158
+ | `multiLine` | Paragraph without formatting. |
159
+ | `richText` | HTML body copy. |
160
+ | `link` | URL. |
161
+ | `media` | Image or video (returns URL string). |
162
+ | `boolean` | Toggle. |
163
+ | `numeric` | Number. |
164
+ | `date` | ISO date string. |
165
+ | `color` | Hex color picker. |
166
+ | `select` | Enum with `options: [{ label, value }]`. |
167
+ | `repeater` | Array of sub-objects with nested `schema`. |
168
+ | `form` | Reference to a form-builder form. |
169
+ | `pageSelector` | Pick a page from the workspace. |
170
+
171
+ **Field options:** `label` (required), `defaultValue`, `placeholder`, `required`, `group` (groups fields in the editor UI).
172
+
173
+ ```ts
174
+ import { defineBlock, field } from "@cmssy/cli/config";
175
+
176
+ export default defineBlock({
177
+ name: "Feature Grid",
178
+ description: "Grid of feature cards with icon, title, description",
179
+ category: "marketing",
180
+ tags: ["marketing", "features", "grid"],
181
+
182
+ schema: {
183
+ heading: field({ type: "singleLine", label: "Heading", required: true }),
184
+ headingHighlight: field({ type: "singleLine", label: "Highlight" }),
185
+ description: field({ type: "multiLine", label: "Description" }),
186
+ features: field({
187
+ type: "repeater",
188
+ label: "Features",
189
+ schema: {
190
+ title: field({ type: "singleLine", label: "Title", required: true }),
191
+ description: field({ type: "multiLine", label: "Description" }),
192
+ icon: field({
193
+ type: "select",
194
+ label: "Icon",
195
+ options: [
196
+ { label: "Zap", value: "ZapIcon" },
197
+ { label: "Sparkles", value: "SparklesIcon" },
198
+ ],
199
+ }),
200
+ color: field({ type: "color", label: "Accent color" }),
201
+ },
202
+ }),
203
+ },
204
+ });
205
+ ```
206
+
207
+ After editing `config.ts`, `block.d.ts` regenerates on the next `cmssy dev` or `cmssy build`. Never hand-edit it.
208
+
209
+ ## 4. Writing the component
210
+
211
+ Follow the design system in the repo's `DESIGN.md`:
212
+
213
+ - Import `Container` from `../../../components/container`.
214
+ - Section wrapper: `<section className="py-24">` or `"py-24 bg-slate-50/50 dark:bg-slate-900/50"` for alternating tint.
215
+ - Destructure `content` with defaults: `const { heading = "Default" } = content;`.
216
+ - Gradient-clip highlight phrases: `bg-linear-to-r from-violet-600 to-purple-600 bg-clip-text text-transparent`.
217
+ - Primary CTAs: gradient pill button with `shadow-lg shadow-violet-500/25`. Secondary: outline with `border-input`.
218
+ - Icons: `lucide-react`, default stroke width.
219
+ - Rich text: `dangerouslySetInnerHTML` inside a `prose` wrapper.
220
+
221
+ ```tsx
222
+ import { Container } from "../../../components/container";
223
+ import { BlockContent } from "./block";
224
+
225
+ export default function FeatureGrid({ content }: { content: BlockContent }) {
226
+ const { heading = "", features = [] } = content;
227
+ return (
228
+ <section className="py-24">
229
+ <Container>{/* ... */}</Container>
230
+ </section>
231
+ );
232
+ }
233
+ ```
234
+
235
+ Blocks that read platform data (auth, i18n) accept a second prop:
236
+
237
+ ```tsx
238
+ export default function Header({ content, context }: {
239
+ content: BlockContent;
240
+ context?: PlatformContext;
241
+ }) { ... }
242
+ ```
243
+
244
+ Components that use hooks or browser APIs: `"use client";` at the top.
245
+
246
+ ## 5. `preview.json`
247
+
248
+ Sample content for `cmssy dev`. Keys must match `config.ts` field names. Repeater fields take arrays of objects. Make it realistic - preview is what reviewers see.
249
+
250
+ ## 6. Templates
251
+
252
+ ```
253
+ templates/<name>/
254
+ ├── config.ts # defineTemplate({ name, description, category, tags, pages })
255
+ ├── package.json
256
+ ├── pages.json # layoutPositions (header/footer) + block references
257
+ ├── preview.json
258
+ └── src/ # optional root component
259
+ ```
260
+
261
+ ```ts
262
+ import { defineTemplate, field } from "@cmssy/cli/config";
263
+
264
+ export default defineTemplate({
265
+ name: "Marketing Site",
266
+ description: "...",
267
+ category: "website",
268
+ tags: [...],
269
+ pages: [
270
+ {
271
+ name: "Home",
272
+ slug: "/",
273
+ blocks: [
274
+ { type: "hero", content: { heading: "...", ... } },
275
+ { type: "features", content: { ... } },
276
+ ],
277
+ },
278
+ ],
279
+ });
280
+ ```
281
+
282
+ Publish templates the same way as blocks: `cmssy publish <template-name> --patch`.
283
+
284
+ ## 7. Standard workflows
285
+
286
+ ### Brand-new project
287
+
288
+ ```bash
289
+ cmssy init my-blocks -y
290
+ cd my-blocks
291
+ cmssy link # interactive - pick workspace
292
+ cmssy doctor # confirm green
293
+ cmssy dev
294
+ ```
295
+
296
+ ### Add a new block end-to-end
297
+
298
+ ```bash
299
+ cmssy create block testimonials -c marketing -t "marketing,social-proof" -y
300
+ # edit blocks/testimonials/config.ts, Testimonials.tsx, preview.json
301
+ cmssy dev # visual check
302
+ pnpm typecheck && pnpm lint
303
+ cmssy test --block testimonials # if tests exist
304
+ cmssy publish testimonials --patch --dry-run
305
+ cmssy publish testimonials --patch
306
+ ```
307
+
308
+ ### Extend an existing block with an optional field
309
+
310
+ 1. Add `field({...})` to `config.ts`. Don't set `required: true` - that's breaking.
311
+ 2. Update the component to read and render it with a default.
312
+ 3. Update `preview.json`.
313
+ 4. `cmssy publish <block> --minor`.
314
+
315
+ ### Copy-only fix
316
+
317
+ 1. Edit default strings or JSX in the component.
318
+ 2. `cmssy publish <block> --patch`.
319
+
320
+ ### Pull a block from the design library
321
+
322
+ ```bash
323
+ cmssy sync @cmssy/blocks.hero
324
+ ```
325
+
326
+ ## 8. Safety rules (always)
327
+
328
+ - Run `cmssy doctor` before publishing.
329
+ - Never fabricate a workspace ID. Use `cmssy workspaces` and confirm with the user.
330
+ - Never pass `--force` without explicit user approval (skips breaking-change confirmation).
331
+ - Never pass `--overwrite-content` without explicit user approval (wipes editor content).
332
+ - Use `--dry-run` first when unsure what will change.
333
+ - Confirm with the user before publishing from a branch other than `develop` or `main`.
334
+ - Commit local changes before publishing - publish uploads the working tree.
335
+ - For init and link, never write a token or workspace ID into `.env` without user confirmation.
336
+
337
+ ## 9. Troubleshooting
338
+
339
+ | Symptom | Likely cause | Fix |
340
+ | --- | --- | --- |
341
+ | `doctor` says token invalid | Revoked/expired token | `cmssy link` again with a fresh token from https://cmssy.io/settings/tokens |
342
+ | Publish says "workspace not accessible" | Wrong `CMSSY_WORKSPACE_ID` or no role | `cmssy workspaces`, update `.env` |
343
+ | Schema diff prompts blocking publish | Breaking field change | Bump `--major`, or revert to non-breaking, or `--force` with user approval |
344
+ | `block.d.ts` shows wrong fields | Stale generation | Restart `cmssy dev`, or run `cmssy build` to regenerate |
345
+ | Dev server shows a blank block | `preview.json` missing keys | Match keys to `config.ts` field names |