cmx-sdk 0.2.6 → 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -0
- package/dist/add-studio-YUDYE2OH.js +72 -0
- package/dist/{chunk-XPP5MZKG.js → chunk-7TDMLYBI.js} +17 -45
- package/dist/chunk-EDXXR5BE.js +80 -0
- package/dist/chunk-EZMBZWH7.js +121 -0
- package/dist/chunk-FPQYL5GE.js +128 -0
- package/dist/chunk-NZQ6SBFS.js +35 -0
- package/dist/cli.js +1152 -619
- package/dist/index.d.ts +253 -385
- package/dist/index.js +154 -25
- package/dist/index.js.map +1 -1
- package/dist/{init-NDNG5Q5T.js → init-FLRQXJX4.js} +23 -51
- package/dist/interactive-menu-FYVOQSTL.js +80 -0
- package/dist/studio-HAS6DYLO.js +8 -0
- package/dist/update-sdk-KJZ6VB4M.js +10 -0
- package/dist/update-studio-TWCYSYIS.js +14 -0
- package/package.json +18 -10
- package/templates/AGENTS.md +173 -0
- package/templates/CLAUDE.md +28 -0
- package/templates/claude/commands/check.md +64 -0
- package/templates/claude/commands/next-action.md +66 -0
- package/templates/claude/skills/cmx-cache/SKILL.md +50 -0
- package/templates/claude/skills/cmx-cache/references/cache-patterns.md +153 -0
- package/templates/claude/skills/cmx-component/SKILL.md +108 -0
- package/templates/claude/skills/cmx-component/references/component-schema.md +123 -0
- package/templates/claude/skills/cmx-content/SKILL.md +158 -0
- package/templates/claude/skills/cmx-content/references/migration-patterns.md +120 -0
- package/templates/claude/skills/cmx-content/references/seed-patterns.md +146 -0
- package/templates/claude/skills/cmx-dev/SKILL.md +266 -0
- package/templates/claude/skills/cmx-dev/references/api-patterns.md +220 -0
- package/templates/claude/skills/cmx-dev/references/cli-reference.md +54 -0
- package/templates/claude/skills/cmx-form/SKILL.md +103 -0
- package/templates/claude/skills/cmx-form/references/form-template.md +152 -0
- package/templates/claude/skills/cmx-migrate/SKILL.md +501 -0
- package/templates/claude/skills/cmx-migrate/references/analysis-guide.md +127 -0
- package/templates/claude/skills/cmx-migrate/references/html-to-mdx.md +99 -0
- package/templates/claude/skills/cmx-migrate/references/intermediate-format.md +196 -0
- package/templates/claude/skills/cmx-migrate/references/tool-setup.md +150 -0
- package/templates/claude/skills/cmx-schema/SKILL.md +159 -0
- package/templates/claude/skills/cmx-schema/references/field-types.md +164 -0
- package/templates/claude/skills/cmx-schema/references/migration-scenarios.md +44 -0
- package/templates/claude/skills/cmx-seo/SKILL.md +54 -0
- package/templates/claude/skills/cmx-seo/references/seo-patterns.md +216 -0
- package/templates/claude/skills/cmx-style/SKILL.md +48 -0
- package/templates/claude/skills/cmx-style/references/style-patterns.md +114 -0
- package/dist/add-studio-J7M7KOWM.js +0 -125
- package/dist/interactive-menu-RPPCBCOU.js +0 -66
- package/dist/studio-3YGVKWS4.js +0 -7
package/dist/index.js
CHANGED
|
@@ -22,6 +22,46 @@ var CmxApiError = class extends Error {
|
|
|
22
22
|
|
|
23
23
|
// src/core/sdk-fetcher.ts
|
|
24
24
|
var DEFAULT_API_URL = "https://app.cmx-ai.org";
|
|
25
|
+
function stringifyErrorValue(value) {
|
|
26
|
+
if (typeof value === "string") return value;
|
|
27
|
+
if (value === null || value === void 0) return "";
|
|
28
|
+
if (typeof value === "object") {
|
|
29
|
+
const objectValue = value;
|
|
30
|
+
if (typeof objectValue.message === "string" && objectValue.message.length > 0) {
|
|
31
|
+
return objectValue.message;
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
return JSON.stringify(value);
|
|
35
|
+
} catch {
|
|
36
|
+
return String(value);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return String(value);
|
|
40
|
+
}
|
|
41
|
+
function parseSdkErrorBody(body, status) {
|
|
42
|
+
const fallbackMessage = `API error: ${status}`;
|
|
43
|
+
if (!body) {
|
|
44
|
+
return { message: fallbackMessage };
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
const parsed = JSON.parse(body);
|
|
48
|
+
const main = stringifyErrorValue(parsed.error ?? parsed.message);
|
|
49
|
+
const details = stringifyErrorValue(parsed.details);
|
|
50
|
+
const code = typeof parsed.code === "string" ? parsed.code : void 0;
|
|
51
|
+
const message = [main, details].filter((part, index, parts) => part.length > 0 && parts.indexOf(part) === index).join(" | ");
|
|
52
|
+
return {
|
|
53
|
+
message: message || fallbackMessage,
|
|
54
|
+
code
|
|
55
|
+
};
|
|
56
|
+
} catch {
|
|
57
|
+
return { message: body };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async function toCmxApiError(response) {
|
|
61
|
+
const body = await response.text();
|
|
62
|
+
const { message, code } = parseSdkErrorBody(body, response.status);
|
|
63
|
+
return new CmxApiError(message, response.status, code);
|
|
64
|
+
}
|
|
25
65
|
function getSdkApiBaseUrl() {
|
|
26
66
|
const apiUrl = process.env.CMX_API_URL || DEFAULT_API_URL;
|
|
27
67
|
return `${apiUrl}/api/v1/sdk`;
|
|
@@ -50,8 +90,7 @@ async function sdkFetcher(path, options) {
|
|
|
50
90
|
};
|
|
51
91
|
const response = await fetch(url, fetchOptions);
|
|
52
92
|
if (!response.ok) {
|
|
53
|
-
|
|
54
|
-
throw new CmxApiError(error.error || `API error: ${response.status}`, response.status, error.code);
|
|
93
|
+
throw await toCmxApiError(response);
|
|
55
94
|
}
|
|
56
95
|
return response.json();
|
|
57
96
|
}
|
|
@@ -68,8 +107,7 @@ async function sdkCustomInstance(url, options) {
|
|
|
68
107
|
}
|
|
69
108
|
});
|
|
70
109
|
if (!response.ok) {
|
|
71
|
-
|
|
72
|
-
throw new CmxApiError(error.error || `API error: ${response.status}`, response.status, error.code);
|
|
110
|
+
throw await toCmxApiError(response);
|
|
73
111
|
}
|
|
74
112
|
return response.json();
|
|
75
113
|
}
|
|
@@ -90,8 +128,7 @@ async function sdkFetchWithTags(path, tags, revalidate) {
|
|
|
90
128
|
};
|
|
91
129
|
const response = await fetch(url, fetchOptions);
|
|
92
130
|
if (!response.ok) {
|
|
93
|
-
|
|
94
|
-
throw new CmxApiError(error.error || `API error: ${response.status}`, response.status, error.code);
|
|
131
|
+
throw await toCmxApiError(response);
|
|
95
132
|
}
|
|
96
133
|
return response.json();
|
|
97
134
|
}
|
|
@@ -109,8 +146,7 @@ async function sdkPostFetcher(path, body) {
|
|
|
109
146
|
cache: "no-store"
|
|
110
147
|
});
|
|
111
148
|
if (!response.ok) {
|
|
112
|
-
|
|
113
|
-
throw new CmxApiError(error.error || `API error: ${response.status}`, response.status, error.code);
|
|
149
|
+
throw await toCmxApiError(response);
|
|
114
150
|
}
|
|
115
151
|
return response.json();
|
|
116
152
|
}
|
|
@@ -783,7 +819,7 @@ function getZodTypeName(zodType) {
|
|
|
783
819
|
// src/mdx/validator.ts
|
|
784
820
|
import { compile } from "@mdx-js/mdx";
|
|
785
821
|
var FORBIDDEN_PATTERNS = [
|
|
786
|
-
// import/export statements
|
|
822
|
+
// import/export statements (at MDX level, not inside code blocks)
|
|
787
823
|
{ pattern: /^\s*import\s+/m, message: "import\u6587\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093" },
|
|
788
824
|
{ pattern: /^\s*export\s+/m, message: "export\u6587\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093" },
|
|
789
825
|
// JS expressions in curly braces (except component props)
|
|
@@ -800,21 +836,111 @@ var FORBIDDEN_PATTERNS = [
|
|
|
800
836
|
// data: URLs (for images - can be XSS vector)
|
|
801
837
|
{ pattern: /src\s*=\s*["']?\s*data:/i, message: "data: URL\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093" }
|
|
802
838
|
];
|
|
839
|
+
function stripCodeBlocksForPatternCheck(mdx) {
|
|
840
|
+
let result = mdx.replace(/<CodeBlock[^>]*>([^]*?)<\/CodeBlock>/g, (_match, content) => {
|
|
841
|
+
const newlineCount = (content.match(/\n/g) || []).length;
|
|
842
|
+
return "<CodeBlock>__CODE_PLACEHOLDER__" + "\n".repeat(newlineCount) + "</CodeBlock>";
|
|
843
|
+
});
|
|
844
|
+
result = result.replace(/```[\s\S]*?```/g, (match) => {
|
|
845
|
+
const newlineCount = (match.match(/\n/g) || []).length;
|
|
846
|
+
return "```__CODE_PLACEHOLDER__" + "\n".repeat(Math.max(0, newlineCount - 1)) + "```";
|
|
847
|
+
});
|
|
848
|
+
return result;
|
|
849
|
+
}
|
|
850
|
+
function escapeCodeBlocksForCompile(mdx) {
|
|
851
|
+
let result = mdx.replace(/<CodeBlock([^>]*)>([^]*?)<\/CodeBlock>/g, (_match, attrs, content) => {
|
|
852
|
+
const escapedContent = content.replace(/^(\s*)(import|export)\s/gm, "$1/* $2 */ ").replace(/\{/g, "{").replace(/\}/g, "}").replace(/</g, "<").replace(/>/g, ">");
|
|
853
|
+
return `<CodeBlock${attrs}>${escapedContent}</CodeBlock>`;
|
|
854
|
+
});
|
|
855
|
+
result = result.replace(/```([a-z]*)\n([\s\S]*?)```/g, (_match, lang, content) => {
|
|
856
|
+
const escapedContent = content.replace(/^(\s*)(import|export)\s/gm, "$1/* $2 */ ").replace(/\{/g, "{").replace(/\}/g, "}").replace(/</g, "<").replace(/>/g, ">");
|
|
857
|
+
return "```" + lang + "\n" + escapedContent + "```";
|
|
858
|
+
});
|
|
859
|
+
return result;
|
|
860
|
+
}
|
|
803
861
|
function extractComponents(mdx) {
|
|
804
862
|
const components = [];
|
|
805
863
|
const lines = mdx.split("\n");
|
|
806
|
-
const
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
864
|
+
const lineOffsets = [];
|
|
865
|
+
let offset = 0;
|
|
866
|
+
for (const line of lines) {
|
|
867
|
+
lineOffsets.push(offset);
|
|
868
|
+
offset += line.length + 1;
|
|
869
|
+
}
|
|
870
|
+
function getLineNumber(index) {
|
|
871
|
+
let lo = 0, hi = lineOffsets.length - 1;
|
|
872
|
+
while (lo < hi) {
|
|
873
|
+
const mid = Math.floor((lo + hi + 1) / 2);
|
|
874
|
+
if (lineOffsets[mid] <= index) {
|
|
875
|
+
lo = mid;
|
|
876
|
+
} else {
|
|
877
|
+
hi = mid - 1;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
return lo + 1;
|
|
881
|
+
}
|
|
882
|
+
const stack = [];
|
|
883
|
+
let i = 0;
|
|
884
|
+
while (i < mdx.length) {
|
|
885
|
+
if (mdx[i] !== "<") {
|
|
886
|
+
i++;
|
|
887
|
+
continue;
|
|
888
|
+
}
|
|
889
|
+
const tagStart = i;
|
|
890
|
+
i++;
|
|
891
|
+
if (mdx[i] === "/") {
|
|
892
|
+
i++;
|
|
893
|
+
const closeMatch = mdx.slice(i).match(/^([A-Z][a-zA-Z0-9]*)\s*>/);
|
|
894
|
+
if (closeMatch) {
|
|
895
|
+
const closingName = closeMatch[1];
|
|
896
|
+
i += closeMatch[0].length;
|
|
897
|
+
for (let s = stack.length - 1; s >= 0; s--) {
|
|
898
|
+
if (stack[s].name === closingName) {
|
|
899
|
+
const opening = stack[s];
|
|
900
|
+
const children = mdx.slice(opening.contentStart, tagStart).trim();
|
|
901
|
+
const props = parseProps(opening.propsString);
|
|
902
|
+
if (children) {
|
|
903
|
+
props.children = children;
|
|
904
|
+
}
|
|
905
|
+
components.push({
|
|
906
|
+
name: opening.name,
|
|
907
|
+
props,
|
|
908
|
+
line: opening.line
|
|
909
|
+
});
|
|
910
|
+
stack.splice(s, 1);
|
|
911
|
+
break;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
continue;
|
|
916
|
+
}
|
|
917
|
+
if (mdx[i] === "!" && mdx[i + 1] === "-" && mdx[i + 2] === "-") {
|
|
918
|
+
const commentEnd = mdx.indexOf("-->", i + 3);
|
|
919
|
+
i = commentEnd !== -1 ? commentEnd + 3 : mdx.length;
|
|
920
|
+
continue;
|
|
921
|
+
}
|
|
922
|
+
const tagMatch = mdx.slice(i).match(/^([A-Z][a-zA-Z0-9]*)([\s\S]*?)(\/)?>/);
|
|
923
|
+
if (!tagMatch) {
|
|
924
|
+
continue;
|
|
925
|
+
}
|
|
926
|
+
const name = tagMatch[1];
|
|
927
|
+
const attrsPart = tagMatch[2].trim();
|
|
928
|
+
const isSelfClosing = tagMatch[3] === "/";
|
|
929
|
+
i += tagMatch[0].length;
|
|
930
|
+
if (isSelfClosing) {
|
|
814
931
|
components.push({
|
|
815
932
|
name,
|
|
816
|
-
props,
|
|
817
|
-
line:
|
|
933
|
+
props: parseProps(attrsPart),
|
|
934
|
+
line: getLineNumber(tagStart)
|
|
935
|
+
});
|
|
936
|
+
} else {
|
|
937
|
+
stack.push({
|
|
938
|
+
name,
|
|
939
|
+
propsString: attrsPart,
|
|
940
|
+
tagStart,
|
|
941
|
+
contentStart: tagStart + 1 + tagMatch[0].length,
|
|
942
|
+
// after '>'
|
|
943
|
+
line: getLineNumber(tagStart)
|
|
818
944
|
});
|
|
819
945
|
}
|
|
820
946
|
}
|
|
@@ -879,9 +1005,10 @@ function extractReferences(components) {
|
|
|
879
1005
|
async function validateMdx(mdx) {
|
|
880
1006
|
const errors = [];
|
|
881
1007
|
const warnings = [];
|
|
1008
|
+
const mdxWithoutCodeBlocks = stripCodeBlocksForPatternCheck(mdx);
|
|
882
1009
|
for (const { pattern, message } of FORBIDDEN_PATTERNS) {
|
|
883
|
-
if (pattern.test(
|
|
884
|
-
const lines =
|
|
1010
|
+
if (pattern.test(mdxWithoutCodeBlocks)) {
|
|
1011
|
+
const lines = mdxWithoutCodeBlocks.split("\n");
|
|
885
1012
|
for (let i = 0; i < lines.length; i++) {
|
|
886
1013
|
if (pattern.test(lines[i])) {
|
|
887
1014
|
errors.push({
|
|
@@ -894,10 +1021,10 @@ async function validateMdx(mdx) {
|
|
|
894
1021
|
}
|
|
895
1022
|
}
|
|
896
1023
|
}
|
|
1024
|
+
const escapedMdx = escapeCodeBlocksForCompile(mdx);
|
|
897
1025
|
try {
|
|
898
|
-
await compile(
|
|
1026
|
+
await compile(escapedMdx, {
|
|
899
1027
|
development: false
|
|
900
|
-
// Minimal compilation to check syntax
|
|
901
1028
|
});
|
|
902
1029
|
} catch (error) {
|
|
903
1030
|
const err = error;
|
|
@@ -908,7 +1035,8 @@ async function validateMdx(mdx) {
|
|
|
908
1035
|
column: err.column
|
|
909
1036
|
});
|
|
910
1037
|
}
|
|
911
|
-
const
|
|
1038
|
+
const mdxForComponentExtraction = stripCodeBlocksForPatternCheck(mdx);
|
|
1039
|
+
const components = extractComponents(mdxForComponentExtraction);
|
|
912
1040
|
for (const component of components) {
|
|
913
1041
|
if (!isValidComponent(component.name)) {
|
|
914
1042
|
errors.push({
|
|
@@ -941,8 +1069,9 @@ async function validateMdx(mdx) {
|
|
|
941
1069
|
}
|
|
942
1070
|
function quickValidateMdx(mdx) {
|
|
943
1071
|
const errors = [];
|
|
1072
|
+
const mdxWithoutCodeBlocks = stripCodeBlocksForPatternCheck(mdx);
|
|
944
1073
|
for (const { pattern, message } of FORBIDDEN_PATTERNS) {
|
|
945
|
-
if (pattern.test(
|
|
1074
|
+
if (pattern.test(mdxWithoutCodeBlocks)) {
|
|
946
1075
|
errors.push({
|
|
947
1076
|
type: "forbidden",
|
|
948
1077
|
message
|