@actuate-media/plugin-ai 0.0.11 → 0.2.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.
- package/LICENSE +21 -21
- package/dist/__tests__/content-generator.test.d.ts +2 -0
- package/dist/__tests__/content-generator.test.d.ts.map +1 -0
- package/dist/__tests__/content-generator.test.js +200 -0
- package/dist/__tests__/content-generator.test.js.map +1 -0
- package/dist/__tests__/index.test.js.map +1 -1
- package/dist/admin/AIScorePanel.d.ts +1 -1
- package/dist/admin/AIScorePanel.d.ts.map +1 -1
- package/dist/admin/AIScorePanel.js +34 -17
- package/dist/admin/AIScorePanel.js.map +1 -1
- package/dist/admin/BrandVoiceSettings.d.ts +2 -2
- package/dist/admin/BrandVoiceSettings.d.ts.map +1 -1
- package/dist/admin/BrandVoiceSettings.js +123 -34
- package/dist/admin/BrandVoiceSettings.js.map +1 -1
- package/dist/admin/ContentScoreDashboard.d.ts +1 -1
- package/dist/admin/ContentScoreDashboard.d.ts.map +1 -1
- package/dist/admin/ContentScoreDashboard.js +50 -16
- package/dist/admin/ContentScoreDashboard.js.map +1 -1
- package/dist/admin/WritingAssistantToolbar.d.ts.map +1 -1
- package/dist/admin/WritingAssistantToolbar.js +21 -21
- package/dist/admin/WritingAssistantToolbar.js.map +1 -1
- package/dist/brand/consistency-checker.d.ts +3 -3
- package/dist/brand/consistency-checker.d.ts.map +1 -1
- package/dist/brand/consistency-checker.js +7 -7
- package/dist/brand/consistency-checker.js.map +1 -1
- package/dist/brand/profile-builder.d.ts +2 -2
- package/dist/brand/profile-builder.d.ts.map +1 -1
- package/dist/brand/profile-builder.js +20 -19
- package/dist/brand/profile-builder.js.map +1 -1
- package/dist/brand/voice-profile.d.ts +4 -4
- package/dist/brand/voice-profile.d.ts.map +1 -1
- package/dist/collections.d.ts +1 -1
- package/dist/collections.d.ts.map +1 -1
- package/dist/collections.js.map +1 -1
- package/dist/fields.d.ts +1 -1
- package/dist/fields.d.ts.map +1 -1
- package/dist/fields.js.map +1 -1
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +16 -14
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +33 -29
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +36 -34
- package/dist/index.js.map +1 -1
- package/dist/links/smart-links.d.ts.map +1 -1
- package/dist/links/smart-links.js +2 -2
- package/dist/links/smart-links.js.map +1 -1
- package/dist/media/alt-text-generator.d.ts +2 -2
- package/dist/media/alt-text-generator.d.ts.map +1 -1
- package/dist/media/alt-text-generator.js +14 -9
- package/dist/media/alt-text-generator.js.map +1 -1
- package/dist/media/auto-tagger.d.ts +1 -1
- package/dist/media/auto-tagger.d.ts.map +1 -1
- package/dist/media/auto-tagger.js +8 -5
- package/dist/media/auto-tagger.js.map +1 -1
- package/dist/page-builder/generate.d.ts +23 -0
- package/dist/page-builder/generate.d.ts.map +1 -0
- package/dist/page-builder/generate.js +422 -0
- package/dist/page-builder/generate.js.map +1 -0
- package/dist/page-builder/index.d.ts +3 -0
- package/dist/page-builder/index.d.ts.map +1 -0
- package/dist/page-builder/index.js +2 -0
- package/dist/page-builder/index.js.map +1 -0
- package/dist/providers/anthropic.d.ts +1 -1
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +32 -32
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/index.d.ts +1 -1
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +6 -6
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +24 -24
- package/dist/providers/openai.js.map +1 -1
- package/dist/scoring/accessibility.d.ts +1 -1
- package/dist/scoring/accessibility.d.ts.map +1 -1
- package/dist/scoring/accessibility.js +22 -22
- package/dist/scoring/accessibility.js.map +1 -1
- package/dist/scoring/brand-alignment.d.ts +1 -1
- package/dist/scoring/brand-alignment.d.ts.map +1 -1
- package/dist/scoring/brand-alignment.js +14 -12
- package/dist/scoring/brand-alignment.js.map +1 -1
- package/dist/scoring/composite.d.ts +1 -1
- package/dist/scoring/composite.d.ts.map +1 -1
- package/dist/scoring/composite.js +5 -5
- package/dist/scoring/composite.js.map +1 -1
- package/dist/scoring/freshness.d.ts +1 -1
- package/dist/scoring/freshness.d.ts.map +1 -1
- package/dist/scoring/freshness.js +5 -7
- package/dist/scoring/freshness.js.map +1 -1
- package/dist/scoring/readability.d.ts +1 -1
- package/dist/scoring/readability.d.ts.map +1 -1
- package/dist/scoring/readability.js +8 -8
- package/dist/scoring/readability.js.map +1 -1
- package/dist/scoring/seo-score.d.ts.map +1 -1
- package/dist/scoring/seo-score.js +82 -16
- package/dist/scoring/seo-score.js.map +1 -1
- package/dist/search/clustering.d.ts +1 -1
- package/dist/search/clustering.d.ts.map +1 -1
- package/dist/search/clustering.js +7 -9
- package/dist/search/clustering.js.map +1 -1
- package/dist/search/embeddings.d.ts +1 -1
- package/dist/search/embeddings.d.ts.map +1 -1
- package/dist/search/embeddings.js +3 -3
- package/dist/search/embeddings.js.map +1 -1
- package/dist/search/semantic-search.d.ts +1 -1
- package/dist/search/semantic-search.d.ts.map +1 -1
- package/dist/search/semantic-search.js +5 -5
- package/dist/search/semantic-search.js.map +1 -1
- package/dist/translation/translator.d.ts +2 -2
- package/dist/translation/translator.d.ts.map +1 -1
- package/dist/translation/translator.js +8 -8
- package/dist/translation/translator.js.map +1 -1
- package/dist/writing/assistant.d.ts +3 -3
- package/dist/writing/assistant.d.ts.map +1 -1
- package/dist/writing/assistant.js +19 -16
- package/dist/writing/assistant.js.map +1 -1
- package/dist/writing/content-generator.d.ts +107 -0
- package/dist/writing/content-generator.d.ts.map +1 -0
- package/dist/writing/content-generator.js +273 -0
- package/dist/writing/content-generator.js.map +1 -0
- package/dist/writing/inline-suggestions.d.ts +2 -2
- package/dist/writing/inline-suggestions.d.ts.map +1 -1
- package/dist/writing/inline-suggestions.js +8 -5
- package/dist/writing/inline-suggestions.js.map +1 -1
- package/dist/writing/meta-generator.d.ts +2 -2
- package/dist/writing/meta-generator.d.ts.map +1 -1
- package/dist/writing/meta-generator.js +21 -9
- package/dist/writing/meta-generator.js.map +1 -1
- package/package.json +3 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { requireAIProvider } from
|
|
1
|
+
import { requireAIProvider } from '../providers/index.js';
|
|
2
2
|
/** Translates content between languages while preserving brand voice and glossary terms. */
|
|
3
3
|
export async function translateContent(content, options) {
|
|
4
4
|
const ai = options.provider ?? requireAIProvider();
|
|
@@ -11,20 +11,20 @@ export async function translateContent(content, options) {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
const glossaryInstruction = glossaryMatches.length > 0
|
|
14
|
-
? `\n\nGlossary (use these exact translations):\n${glossaryMatches.map((g) => `- "${g.original}" → "${g.translated}"`).join(
|
|
15
|
-
:
|
|
14
|
+
? `\n\nGlossary (use these exact translations):\n${glossaryMatches.map((g) => `- "${g.original}" → "${g.translated}"`).join('\n')}`
|
|
15
|
+
: '';
|
|
16
16
|
const brandInstruction = options.brandProfile
|
|
17
|
-
? `\nMaintain a ${options.brandProfile.tone.map((t) => t.dimension).join(
|
|
18
|
-
:
|
|
17
|
+
? `\nMaintain a ${options.brandProfile.tone.map((t) => t.dimension).join('/')} tone.`
|
|
18
|
+
: '';
|
|
19
19
|
const formatInstruction = options.preserveFormatting !== false
|
|
20
|
-
?
|
|
21
|
-
:
|
|
20
|
+
? '\nPreserve all HTML tags, markdown formatting, and line breaks exactly.'
|
|
21
|
+
: '';
|
|
22
22
|
const prompt = `Translate the following content from ${options.sourceLanguage} to ${options.targetLanguage}.${formatInstruction}${brandInstruction}${glossaryInstruction}
|
|
23
23
|
|
|
24
24
|
Content to translate:
|
|
25
25
|
${content}`;
|
|
26
26
|
const result = await ai.generateText(prompt, {
|
|
27
|
-
systemPrompt:
|
|
27
|
+
systemPrompt: 'You are a professional translator. Translate accurately while preserving meaning, tone, and formatting. Return only the translated text, no explanations.',
|
|
28
28
|
maxTokens: Math.max(2048, Math.ceil(content.length * 1.5)),
|
|
29
29
|
temperature: 0.3,
|
|
30
30
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"translator.js","sourceRoot":"","sources":["../../src/translation/translator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,
|
|
1
|
+
{"version":3,"file":"translator.js","sourceRoot":"","sources":["../../src/translation/translator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAoBzD,4FAA4F;AAC5F,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAAe,EACf,OAA2B;IAE3B,MAAM,EAAE,GAAG,OAAO,CAAC,QAAQ,IAAI,iBAAiB,EAAE,CAAA;IAElD,MAAM,eAAe,GAAyC,EAAE,CAAA;IAEhE,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,KAAK,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YACtE,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;gBAC3D,eAAe,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAA;YAChD,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,mBAAmB,GACvB,eAAe,CAAC,MAAM,GAAG,CAAC;QACxB,CAAC,CAAC,iDAAiD,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,QAAQ,QAAQ,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QACnI,CAAC,CAAC,EAAE,CAAA;IAER,MAAM,gBAAgB,GAAG,OAAO,CAAC,YAAY;QAC3C,CAAC,CAAC,gBAAgB,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ;QACrF,CAAC,CAAC,EAAE,CAAA;IAEN,MAAM,iBAAiB,GACrB,OAAO,CAAC,kBAAkB,KAAK,KAAK;QAClC,CAAC,CAAC,yEAAyE;QAC3E,CAAC,CAAC,EAAE,CAAA;IAER,MAAM,MAAM,GAAG,wCAAwC,OAAO,CAAC,cAAc,OAAO,OAAO,CAAC,cAAc,IAAI,iBAAiB,GAAG,gBAAgB,GAAG,mBAAmB;;;EAGxK,OAAO,EAAE,CAAA;IAET,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE;QAC3C,YAAY,EACV,2JAA2J;QAC7J,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;QAC1D,WAAW,EAAE,GAAG;KACjB,CAAC,CAAA;IAEF,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAA;IACrC,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAA;IAEhE,OAAO;QACL,UAAU;QACV,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,SAAS;QACT,UAAU,EAAE,IAAI;QAChB,eAAe;KAChB,CAAA;AACH,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { BrandVoiceProfile } from
|
|
2
|
-
import type { AIProvider } from
|
|
1
|
+
import type { BrandVoiceProfile } from '../brand/voice-profile.js';
|
|
2
|
+
import type { AIProvider } from '../providers/index.js';
|
|
3
3
|
export interface WritingContext {
|
|
4
4
|
collectionSlug?: string;
|
|
5
5
|
existingContent?: string;
|
|
@@ -12,7 +12,7 @@ export interface ProofreadResult {
|
|
|
12
12
|
changes: Array<{
|
|
13
13
|
original: string;
|
|
14
14
|
corrected: string;
|
|
15
|
-
type:
|
|
15
|
+
type: 'grammar' | 'spelling' | 'style' | 'clarity';
|
|
16
16
|
}>;
|
|
17
17
|
}
|
|
18
18
|
/** Generates content from a prompt with optional context. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assistant.d.ts","sourceRoot":"","sources":["../../src/writing/assistant.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,
|
|
1
|
+
{"version":3,"file":"assistant.d.ts","sourceRoot":"","sources":["../../src/writing/assistant.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAGvD,MAAM,WAAW,cAAc;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,YAAY,CAAC,EAAE,iBAAiB,CAAA;IAChC,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,EAAE,UAAU,CAAA;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,KAAK,CAAC;QACb,QAAQ,EAAE,MAAM,CAAA;QAChB,SAAS,EAAE,MAAM,CAAA;QACjB,IAAI,EAAE,SAAS,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,CAAA;KACnD,CAAC,CAAA;CACH;AAkCD,6DAA6D;AAC7D,wBAAsB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBxF;AAED,iEAAiE;AACjE,wBAAsB,MAAM,CAC1B,IAAI,EAAE,MAAM,EACZ,YAAY,CAAC,EAAE,MAAM,EACrB,QAAQ,CAAC,EAAE,UAAU,GACpB,OAAO,CAAC,MAAM,CAAC,CAYjB;AAED,+EAA+E;AAC/E,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,MAAM,EACZ,YAAY,CAAC,EAAE,MAAM,EACrB,QAAQ,CAAC,EAAE,UAAU,GACpB,OAAO,CAAC,MAAM,CAAC,CAgBjB;AAED,4DAA4D;AAC5D,wBAAsB,OAAO,CAC3B,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,MAAM,EACb,QAAQ,CAAC,EAAE,UAAU,GACpB,OAAO,CAAC,MAAM,CAAC,CAajB;AAED,2EAA2E;AAC3E,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,eAAe,CAAC,CA+B7F"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { requireAIProvider } from
|
|
1
|
+
import { requireAIProvider } from '../providers/index.js';
|
|
2
2
|
function resolveProvider(context) {
|
|
3
3
|
return context?.provider ?? requireAIProvider();
|
|
4
4
|
}
|
|
5
5
|
function buildSystemPrompt(context) {
|
|
6
6
|
const parts = [
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
'You are an expert content writer for a CMS.',
|
|
8
|
+
'Do not include passwords, API keys, personal data, or other sensitive information in your output.',
|
|
9
9
|
];
|
|
10
10
|
if (context?.collectionSlug) {
|
|
11
11
|
parts.push(`Content type: ${context.collectionSlug}.`);
|
|
@@ -16,16 +16,16 @@ function buildSystemPrompt(context) {
|
|
|
16
16
|
if (context?.brandProfile) {
|
|
17
17
|
const tone = context.brandProfile.tone
|
|
18
18
|
.map((t) => `${t.dimension}: ${Math.round(t.value * 100)}%`)
|
|
19
|
-
.join(
|
|
19
|
+
.join(', ');
|
|
20
20
|
parts.push(`Brand tone: ${tone}.`);
|
|
21
21
|
if (context.brandProfile.vocabulary.preferred.length > 0) {
|
|
22
|
-
parts.push(`Preferred terms: ${context.brandProfile.vocabulary.preferred.join(
|
|
22
|
+
parts.push(`Preferred terms: ${context.brandProfile.vocabulary.preferred.join(', ')}.`);
|
|
23
23
|
}
|
|
24
24
|
if (context.brandProfile.vocabulary.avoided.length > 0) {
|
|
25
|
-
parts.push(`Avoid these terms: ${context.brandProfile.vocabulary.avoided.join(
|
|
25
|
+
parts.push(`Avoid these terms: ${context.brandProfile.vocabulary.avoided.join(', ')}.`);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
-
return parts.join(
|
|
28
|
+
return parts.join(' ');
|
|
29
29
|
}
|
|
30
30
|
/** Generates content from a prompt with optional context. */
|
|
31
31
|
export async function generate(prompt, context) {
|
|
@@ -45,9 +45,9 @@ export async function generate(prompt, context) {
|
|
|
45
45
|
/** Expands the given text with additional detail and context. */
|
|
46
46
|
export async function expand(text, instructions, provider) {
|
|
47
47
|
const ai = provider ?? requireAIProvider();
|
|
48
|
-
const prompt = `Expand the following text with additional detail and context${instructions ? `. Instructions: ${instructions}` :
|
|
48
|
+
const prompt = `Expand the following text with additional detail and context${instructions ? `. Instructions: ${instructions}` : ''}. Maintain the same voice and style.\n\n${text}`;
|
|
49
49
|
const result = await ai.generateText(prompt, {
|
|
50
|
-
systemPrompt:
|
|
50
|
+
systemPrompt: 'You are a content writer. Expand the text while maintaining its voice, style, and accuracy.',
|
|
51
51
|
maxTokens: 2048,
|
|
52
52
|
temperature: 0.7,
|
|
53
53
|
});
|
|
@@ -58,10 +58,10 @@ export async function compress(text, targetLength, provider) {
|
|
|
58
58
|
const ai = provider ?? requireAIProvider();
|
|
59
59
|
const lengthInstruction = targetLength
|
|
60
60
|
? `Target approximately ${targetLength} characters.`
|
|
61
|
-
:
|
|
61
|
+
: 'Make it significantly shorter.';
|
|
62
62
|
const prompt = `Compress the following text while preserving all key information. ${lengthInstruction}\n\n${text}`;
|
|
63
63
|
const result = await ai.generateText(prompt, {
|
|
64
|
-
systemPrompt:
|
|
64
|
+
systemPrompt: 'You are an editor. Compress text while preserving meaning, key points, and readability.',
|
|
65
65
|
maxTokens: 1024,
|
|
66
66
|
temperature: 0.3,
|
|
67
67
|
});
|
|
@@ -70,10 +70,10 @@ export async function compress(text, targetLength, provider) {
|
|
|
70
70
|
/** Rewrites the given text in a different style or tone. */
|
|
71
71
|
export async function rewrite(text, style, tone, provider) {
|
|
72
72
|
const ai = provider ?? requireAIProvider();
|
|
73
|
-
const modifiers = [style && `style: ${style}`, tone && `tone: ${tone}`].filter(Boolean).join(
|
|
74
|
-
const prompt = `Rewrite the following text${modifiers ? ` with ${modifiers}` :
|
|
73
|
+
const modifiers = [style && `style: ${style}`, tone && `tone: ${tone}`].filter(Boolean).join(', ');
|
|
74
|
+
const prompt = `Rewrite the following text${modifiers ? ` with ${modifiers}` : ' to improve clarity and engagement'}:\n\n${text}`;
|
|
75
75
|
const result = await ai.generateText(prompt, {
|
|
76
|
-
systemPrompt:
|
|
76
|
+
systemPrompt: 'You are a content editor. Rewrite text as requested while preserving the core message.',
|
|
77
77
|
maxTokens: 2048,
|
|
78
78
|
temperature: 0.7,
|
|
79
79
|
});
|
|
@@ -91,12 +91,15 @@ Only include actual errors. If the text is correct, return an empty changes arra
|
|
|
91
91
|
Text to proofread:
|
|
92
92
|
${text}`;
|
|
93
93
|
const result = await ai.generateText(prompt, {
|
|
94
|
-
systemPrompt:
|
|
94
|
+
systemPrompt: 'You are a professional proofreader. Return valid JSON only, no markdown formatting.',
|
|
95
95
|
maxTokens: 2048,
|
|
96
96
|
temperature: 0.2,
|
|
97
97
|
});
|
|
98
98
|
try {
|
|
99
|
-
const cleaned = result.text
|
|
99
|
+
const cleaned = result.text
|
|
100
|
+
.replace(/```json?\n?/g, '')
|
|
101
|
+
.replace(/```/g, '')
|
|
102
|
+
.trim();
|
|
100
103
|
const parsed = JSON.parse(cleaned);
|
|
101
104
|
return {
|
|
102
105
|
corrected: parsed.corrected ?? text,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assistant.js","sourceRoot":"","sources":["../../src/writing/assistant.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,
|
|
1
|
+
{"version":3,"file":"assistant.js","sourceRoot":"","sources":["../../src/writing/assistant.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic AI content authoring for any CMS collection.
|
|
3
|
+
*
|
|
4
|
+
* Given a prompt + a minimal collection schema (slug, labels, fields), the
|
|
5
|
+
* generator asks the LLM to return JSON matching the field names and types,
|
|
6
|
+
* parses + validates, and returns the structured data ready to be persisted
|
|
7
|
+
* via the standard `createDocument` action.
|
|
8
|
+
*
|
|
9
|
+
* Why this lives in plugin-ai (not cms-core):
|
|
10
|
+
* - It depends on the configured AI provider (Anthropic / OpenAI).
|
|
11
|
+
* - cms-core stays runtime-free of any LLM SDK so the package builds without
|
|
12
|
+
* pulling AI deps when the integrator doesn't use AI features.
|
|
13
|
+
*
|
|
14
|
+
* The generator is intentionally pragmatic — it does *not* attempt to render
|
|
15
|
+
* page-builder layout trees. For that, use `generatePage()` from the page
|
|
16
|
+
* builder module. This function is for non-page collections (blog posts,
|
|
17
|
+
* case studies, services, locations, team members, etc.) where the "content"
|
|
18
|
+
* is structured field data, not a visual layout.
|
|
19
|
+
*/
|
|
20
|
+
import type { AIProvider, GenerateResult } from '../providers/index.js';
|
|
21
|
+
import type { BrandVoiceProfile } from '../brand/voice-profile.js';
|
|
22
|
+
/**
|
|
23
|
+
* Minimal field shape we accept. Matches the relevant subset of
|
|
24
|
+
* `@actuate-media/cms-core` `FieldDefinition` without forcing a build-time
|
|
25
|
+
* dependency on the core types.
|
|
26
|
+
*/
|
|
27
|
+
export interface FieldShape {
|
|
28
|
+
type: string;
|
|
29
|
+
label?: string;
|
|
30
|
+
required?: boolean;
|
|
31
|
+
maxLength?: number;
|
|
32
|
+
options?: Array<{
|
|
33
|
+
label: string;
|
|
34
|
+
value: string;
|
|
35
|
+
}>;
|
|
36
|
+
min?: number;
|
|
37
|
+
max?: number;
|
|
38
|
+
step?: number;
|
|
39
|
+
fields?: Record<string, FieldShape>;
|
|
40
|
+
admin?: {
|
|
41
|
+
description?: string;
|
|
42
|
+
};
|
|
43
|
+
features?: string[];
|
|
44
|
+
}
|
|
45
|
+
export interface CollectionShape {
|
|
46
|
+
slug: string;
|
|
47
|
+
labels: {
|
|
48
|
+
singular: string;
|
|
49
|
+
plural: string;
|
|
50
|
+
};
|
|
51
|
+
type?: 'page' | 'post';
|
|
52
|
+
fields: Record<string, FieldShape>;
|
|
53
|
+
seo?: {
|
|
54
|
+
defaultSchemaType?: string;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export interface DocumentGenerationContext {
|
|
58
|
+
/** Existing site content the agent can reference for voice / facts. */
|
|
59
|
+
existingContent?: string;
|
|
60
|
+
/** Brand voice profile (tone, vocabulary). */
|
|
61
|
+
brandProfile?: BrandVoiceProfile;
|
|
62
|
+
/** Audience description (`"small business owners"`). */
|
|
63
|
+
targetAudience?: string;
|
|
64
|
+
/** Override the global provider — used in tests. */
|
|
65
|
+
provider?: AIProvider;
|
|
66
|
+
}
|
|
67
|
+
export interface GenerateDocumentInput {
|
|
68
|
+
prompt: string;
|
|
69
|
+
collection: CollectionShape;
|
|
70
|
+
/** Optional context object — brand voice, target audience, existing content. */
|
|
71
|
+
context?: DocumentGenerationContext;
|
|
72
|
+
/** Free-form tone modifier ("conversational", "expert", "playful"). */
|
|
73
|
+
tone?: string;
|
|
74
|
+
/** Cap output tokens; defaults to 3000 (enough for ~2000-word posts). */
|
|
75
|
+
maxTokens?: number;
|
|
76
|
+
/** LLM temperature; defaults to 0.7. */
|
|
77
|
+
temperature?: number;
|
|
78
|
+
}
|
|
79
|
+
export interface GenerateDocumentResult {
|
|
80
|
+
/** Field data ready to merge into a `data` payload. */
|
|
81
|
+
data: Record<string, unknown>;
|
|
82
|
+
/** Suggested document title (separate from data.title because it's also used as the doc record's `title` column). */
|
|
83
|
+
title: string;
|
|
84
|
+
/** URL-safe slug derived from the title. */
|
|
85
|
+
slug: string;
|
|
86
|
+
/** SEO bundle the generator extracted from the output (or synthesized). */
|
|
87
|
+
seo: {
|
|
88
|
+
metaTitle?: string;
|
|
89
|
+
metaDescription?: string;
|
|
90
|
+
schemaType?: string;
|
|
91
|
+
};
|
|
92
|
+
/** Raw LLM provider usage stats. */
|
|
93
|
+
usage: GenerateResult['usage'];
|
|
94
|
+
/** Total wall-clock time for the call in ms. */
|
|
95
|
+
durationMs: number;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Generate a complete document body for the given collection from a prompt.
|
|
99
|
+
*
|
|
100
|
+
* The result is a flat field-data map that can be passed directly to
|
|
101
|
+
* `createDocument(slug, payload, ctx)` in cms-core.
|
|
102
|
+
*
|
|
103
|
+
* @throws if the AI provider is not configured, the LLM output doesn't parse
|
|
104
|
+
* as JSON, or no title field is present in the response.
|
|
105
|
+
*/
|
|
106
|
+
export declare function generateDocumentContent(input: GenerateDocumentInput): Promise<GenerateDocumentResult>;
|
|
107
|
+
//# sourceMappingURL=content-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-generator.d.ts","sourceRoot":"","sources":["../../src/writing/content-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAEvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAElE;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACjD,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IACnC,KAAK,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAChC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IAC5C,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACtB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IAClC,GAAG,CAAC,EAAE;QAAE,iBAAiB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CACrC;AAED,MAAM,WAAW,yBAAyB;IACxC,uEAAuE;IACvE,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,8CAA8C;IAC9C,YAAY,CAAC,EAAE,iBAAiB,CAAA;IAChC,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,UAAU,CAAA;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,eAAe,CAAA;IAC3B,gFAAgF;IAChF,OAAO,CAAC,EAAE,yBAAyB,CAAA;IACnC,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,wCAAwC;IACxC,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,qHAAqH;IACrH,KAAK,EAAE,MAAM,CAAA;IACb,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAA;IACZ,2EAA2E;IAC3E,GAAG,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC1E,oCAAoC;IACpC,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,CAAA;IAC9B,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAA;CACnB;AA6MD;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC,sBAAsB,CAAC,CAkEjC"}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import { requireAIProvider } from '../providers/index.js';
|
|
2
|
+
// ─── JSON extraction ──────────────────────────────────────────────────────
|
|
3
|
+
/**
|
|
4
|
+
* Locate and parse the first complete JSON object in a string by scanning for
|
|
5
|
+
* a balanced pair of braces, ignoring braces inside string literals. Same
|
|
6
|
+
* algorithm used by the page builder generator — handles LLM outputs that
|
|
7
|
+
* include leading commentary or trailing junk.
|
|
8
|
+
*/
|
|
9
|
+
function extractJsonObject(text) {
|
|
10
|
+
let depth = 0;
|
|
11
|
+
let start = -1;
|
|
12
|
+
let inString = false;
|
|
13
|
+
let escape = false;
|
|
14
|
+
for (let i = 0; i < text.length; i++) {
|
|
15
|
+
const ch = text[i];
|
|
16
|
+
if (escape) {
|
|
17
|
+
escape = false;
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (ch === '\\') {
|
|
21
|
+
escape = true;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (ch === '"') {
|
|
25
|
+
inString = !inString;
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (inString)
|
|
29
|
+
continue;
|
|
30
|
+
if (ch === '{') {
|
|
31
|
+
if (depth === 0)
|
|
32
|
+
start = i;
|
|
33
|
+
depth++;
|
|
34
|
+
}
|
|
35
|
+
else if (ch === '}') {
|
|
36
|
+
depth--;
|
|
37
|
+
if (depth === 0 && start !== -1) {
|
|
38
|
+
return text.slice(start, i + 1);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
// ─── Prompt construction ──────────────────────────────────────────────────
|
|
45
|
+
function describeField(name, field) {
|
|
46
|
+
const parts = [` "${name}"`];
|
|
47
|
+
parts.push(`(${field.type}${field.required ? ', required' : ''})`);
|
|
48
|
+
if (field.label && field.label !== name)
|
|
49
|
+
parts.push(`label: ${field.label}`);
|
|
50
|
+
if (field.maxLength)
|
|
51
|
+
parts.push(`max ${field.maxLength} chars`);
|
|
52
|
+
if (typeof field.min === 'number' || typeof field.max === 'number') {
|
|
53
|
+
parts.push(`range ${field.min ?? '∞'}…${field.max ?? '∞'}`);
|
|
54
|
+
}
|
|
55
|
+
if (field.options && field.options.length) {
|
|
56
|
+
parts.push(`one of: ${field.options.map((o) => o.value).join(', ')}`);
|
|
57
|
+
}
|
|
58
|
+
if (field.type === 'array' && field.fields) {
|
|
59
|
+
const subFields = Object.entries(field.fields)
|
|
60
|
+
.map(([n, f]) => `${n}:${f.type}`)
|
|
61
|
+
.join(', ');
|
|
62
|
+
parts.push(`array of { ${subFields} }`);
|
|
63
|
+
}
|
|
64
|
+
if (field.admin?.description) {
|
|
65
|
+
parts.push(`— ${field.admin.description}`);
|
|
66
|
+
}
|
|
67
|
+
return parts.join(' ');
|
|
68
|
+
}
|
|
69
|
+
function buildSystemPrompt(collection, tone, ctx) {
|
|
70
|
+
const lines = [
|
|
71
|
+
`You are an expert content writer creating a "${collection.labels.singular}" document for a CMS.`,
|
|
72
|
+
'You generate valid JSON matching the requested field schema. NEVER include markdown, code fences, or commentary.',
|
|
73
|
+
'',
|
|
74
|
+
'Rules:',
|
|
75
|
+
'- Output a single JSON object whose top-level keys exactly match the field names below.',
|
|
76
|
+
'- Match field types: text/richText/email/url are strings; number is a number; boolean is a boolean; date is an ISO-8601 string; array is a JSON array of objects; select must use one of the listed option values; media fields should be left as null (a human will upload the asset).',
|
|
77
|
+
'- Respect maxLength constraints. Quality over quantity — never pad.',
|
|
78
|
+
'- For slug fields, generate a URL-safe lowercase string with words joined by hyphens.',
|
|
79
|
+
'- For richText fields, return well-structured prose with paragraph breaks, but no HTML tags.',
|
|
80
|
+
'- For seo fields (metaTitle, metaDescription) compose SEO-optimised copy distinct from the page title.',
|
|
81
|
+
"- Never invent facts. If you don't know something the prompt didn't supply, leave the field blank or null.",
|
|
82
|
+
];
|
|
83
|
+
if (collection.seo?.defaultSchemaType) {
|
|
84
|
+
lines.push(`- This collection maps to Schema.org "${collection.seo.defaultSchemaType}".`);
|
|
85
|
+
}
|
|
86
|
+
if (tone)
|
|
87
|
+
lines.push(`- Tone: ${tone}.`);
|
|
88
|
+
if (ctx?.targetAudience)
|
|
89
|
+
lines.push(`- Audience: ${ctx.targetAudience}.`);
|
|
90
|
+
if (ctx?.brandProfile) {
|
|
91
|
+
const top = ctx.brandProfile.tone
|
|
92
|
+
.map((t) => `${t.dimension} ${Math.round(t.value * 100)}%`)
|
|
93
|
+
.join(', ');
|
|
94
|
+
lines.push(`- Brand tone: ${top}.`);
|
|
95
|
+
if (ctx.brandProfile.vocabulary?.preferred?.length) {
|
|
96
|
+
lines.push(`- Preferred terms: ${ctx.brandProfile.vocabulary.preferred.join(', ')}.`);
|
|
97
|
+
}
|
|
98
|
+
if (ctx.brandProfile.vocabulary?.avoided?.length) {
|
|
99
|
+
lines.push(`- Avoid: ${ctx.brandProfile.vocabulary.avoided.join(', ')}.`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return lines.join('\n');
|
|
103
|
+
}
|
|
104
|
+
function buildUserPrompt(input) {
|
|
105
|
+
const { collection, prompt, context } = input;
|
|
106
|
+
const fieldDescriptions = Object.entries(collection.fields)
|
|
107
|
+
.filter(([, f]) => f.type !== 'media') // Media is supplied by the human reviewer.
|
|
108
|
+
.map(([name, field]) => describeField(name, field))
|
|
109
|
+
.join('\n');
|
|
110
|
+
const lines = [
|
|
111
|
+
`Create a ${collection.labels.singular} matching this brief:`,
|
|
112
|
+
'',
|
|
113
|
+
prompt.trim(),
|
|
114
|
+
'',
|
|
115
|
+
'Field schema:',
|
|
116
|
+
fieldDescriptions,
|
|
117
|
+
'',
|
|
118
|
+
'Output ONLY a JSON object with the field values. No prose. No markdown fences.',
|
|
119
|
+
];
|
|
120
|
+
if (context?.existingContent) {
|
|
121
|
+
lines.push('', 'Existing related content for voice / fact reference:');
|
|
122
|
+
lines.push(context.existingContent.slice(0, 2000));
|
|
123
|
+
}
|
|
124
|
+
return lines.join('\n');
|
|
125
|
+
}
|
|
126
|
+
// ─── Output coercion ──────────────────────────────────────────────────────
|
|
127
|
+
function slugify(title) {
|
|
128
|
+
return (title
|
|
129
|
+
.toLowerCase()
|
|
130
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
131
|
+
.replace(/^-+|-+$/g, '')
|
|
132
|
+
.slice(0, 80) || 'untitled');
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Coerce the LLM output into shapes that match each field's declared type.
|
|
136
|
+
* The LLM occasionally returns numbers as strings, booleans as "true"/"false",
|
|
137
|
+
* etc. We don't try to recover unrecoverable values — we leave bad fields
|
|
138
|
+
* `undefined` so the downstream field validator surfaces the error to the
|
|
139
|
+
* caller instead of silently persisting garbage.
|
|
140
|
+
*/
|
|
141
|
+
function coerceFieldValue(value, field) {
|
|
142
|
+
if (value === null || value === undefined)
|
|
143
|
+
return value;
|
|
144
|
+
switch (field.type) {
|
|
145
|
+
case 'text':
|
|
146
|
+
case 'richText':
|
|
147
|
+
case 'email':
|
|
148
|
+
case 'url':
|
|
149
|
+
case 'slug':
|
|
150
|
+
case 'color':
|
|
151
|
+
return typeof value === 'string' ? value : String(value);
|
|
152
|
+
case 'number':
|
|
153
|
+
if (typeof value === 'number')
|
|
154
|
+
return value;
|
|
155
|
+
if (typeof value === 'string') {
|
|
156
|
+
const n = Number(value);
|
|
157
|
+
return Number.isFinite(n) ? n : undefined;
|
|
158
|
+
}
|
|
159
|
+
return undefined;
|
|
160
|
+
case 'boolean':
|
|
161
|
+
if (typeof value === 'boolean')
|
|
162
|
+
return value;
|
|
163
|
+
if (value === 'true')
|
|
164
|
+
return true;
|
|
165
|
+
if (value === 'false')
|
|
166
|
+
return false;
|
|
167
|
+
return undefined;
|
|
168
|
+
case 'date':
|
|
169
|
+
if (value instanceof Date)
|
|
170
|
+
return value.toISOString();
|
|
171
|
+
if (typeof value === 'string') {
|
|
172
|
+
const d = new Date(value);
|
|
173
|
+
return isNaN(d.getTime()) ? undefined : d.toISOString();
|
|
174
|
+
}
|
|
175
|
+
return undefined;
|
|
176
|
+
case 'select':
|
|
177
|
+
if (typeof value === 'string' && field.options?.some((o) => o.value === value))
|
|
178
|
+
return value;
|
|
179
|
+
return undefined;
|
|
180
|
+
case 'array':
|
|
181
|
+
if (!Array.isArray(value))
|
|
182
|
+
return [];
|
|
183
|
+
if (!field.fields)
|
|
184
|
+
return value;
|
|
185
|
+
return value.map((item) => {
|
|
186
|
+
if (item === null || typeof item !== 'object')
|
|
187
|
+
return item;
|
|
188
|
+
const obj = item;
|
|
189
|
+
const coerced = {};
|
|
190
|
+
for (const [name, sub] of Object.entries(field.fields)) {
|
|
191
|
+
if (obj[name] !== undefined)
|
|
192
|
+
coerced[name] = coerceFieldValue(obj[name], sub);
|
|
193
|
+
}
|
|
194
|
+
return coerced;
|
|
195
|
+
});
|
|
196
|
+
case 'json':
|
|
197
|
+
return value;
|
|
198
|
+
case 'media':
|
|
199
|
+
// The LLM doesn't have asset IDs. Leave for a human to fill.
|
|
200
|
+
return null;
|
|
201
|
+
default:
|
|
202
|
+
return value;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// ─── Main entrypoint ──────────────────────────────────────────────────────
|
|
206
|
+
/**
|
|
207
|
+
* Generate a complete document body for the given collection from a prompt.
|
|
208
|
+
*
|
|
209
|
+
* The result is a flat field-data map that can be passed directly to
|
|
210
|
+
* `createDocument(slug, payload, ctx)` in cms-core.
|
|
211
|
+
*
|
|
212
|
+
* @throws if the AI provider is not configured, the LLM output doesn't parse
|
|
213
|
+
* as JSON, or no title field is present in the response.
|
|
214
|
+
*/
|
|
215
|
+
export async function generateDocumentContent(input) {
|
|
216
|
+
const provider = input.context?.provider ?? requireAIProvider();
|
|
217
|
+
const systemPrompt = buildSystemPrompt(input.collection, input.tone, input.context);
|
|
218
|
+
const userPrompt = buildUserPrompt(input);
|
|
219
|
+
const started = Date.now();
|
|
220
|
+
const result = await provider.generateText(userPrompt, {
|
|
221
|
+
systemPrompt,
|
|
222
|
+
maxTokens: input.maxTokens ?? 3000,
|
|
223
|
+
temperature: input.temperature ?? 0.7,
|
|
224
|
+
});
|
|
225
|
+
const raw = result.text;
|
|
226
|
+
const jsonText = extractJsonObject(raw);
|
|
227
|
+
if (!jsonText) {
|
|
228
|
+
throw new Error('AI content generator returned no JSON object');
|
|
229
|
+
}
|
|
230
|
+
let parsed;
|
|
231
|
+
try {
|
|
232
|
+
parsed = JSON.parse(jsonText);
|
|
233
|
+
}
|
|
234
|
+
catch (err) {
|
|
235
|
+
throw new Error(`AI content generator returned invalid JSON: ${err instanceof Error ? err.message : 'parse failed'}`);
|
|
236
|
+
}
|
|
237
|
+
// Coerce each field according to the schema. Unknown keys (anything the
|
|
238
|
+
// schema doesn't declare) are dropped to keep persisted data clean.
|
|
239
|
+
const data = {};
|
|
240
|
+
for (const [name, field] of Object.entries(input.collection.fields)) {
|
|
241
|
+
const raw = parsed[name];
|
|
242
|
+
if (raw === undefined)
|
|
243
|
+
continue;
|
|
244
|
+
const coerced = coerceFieldValue(raw, field);
|
|
245
|
+
if (coerced !== undefined)
|
|
246
|
+
data[name] = coerced;
|
|
247
|
+
}
|
|
248
|
+
// Derive title + slug.
|
|
249
|
+
const title = (typeof data.title === 'string' && data.title) ||
|
|
250
|
+
(typeof data.question === 'string' && data.question) ||
|
|
251
|
+
(typeof data.name === 'string' && data.name) ||
|
|
252
|
+
'Untitled';
|
|
253
|
+
const slug = (typeof data.slug === 'string' && data.slug.trim()) || slugify(title);
|
|
254
|
+
data.slug = slug;
|
|
255
|
+
const seo = {
|
|
256
|
+
metaTitle: (typeof data.metaTitle === 'string' && data.metaTitle) ||
|
|
257
|
+
(typeof parsed.metaTitle === 'string' && parsed.metaTitle) ||
|
|
258
|
+
title,
|
|
259
|
+
metaDescription: (typeof data.metaDescription === 'string' && data.metaDescription) ||
|
|
260
|
+
(typeof parsed.metaDescription === 'string' && parsed.metaDescription) ||
|
|
261
|
+
undefined,
|
|
262
|
+
schemaType: input.collection.seo?.defaultSchemaType,
|
|
263
|
+
};
|
|
264
|
+
return {
|
|
265
|
+
data,
|
|
266
|
+
title: typeof title === 'string' ? title : 'Untitled',
|
|
267
|
+
slug,
|
|
268
|
+
seo,
|
|
269
|
+
usage: result.usage,
|
|
270
|
+
durationMs: Date.now() - started,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=content-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-generator.js","sourceRoot":"","sources":["../../src/writing/content-generator.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAqEzD,6EAA6E;AAE7E;;;;;GAKG;AACH,SAAS,iBAAiB,CAAC,IAAY;IACrC,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,IAAI,KAAK,GAAG,CAAC,CAAC,CAAA;IACd,IAAI,QAAQ,GAAG,KAAK,CAAA;IACpB,IAAI,MAAM,GAAG,KAAK,CAAA;IAClB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAE,CAAA;QACnB,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,GAAG,KAAK,CAAA;YACd,SAAQ;QACV,CAAC;QACD,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YAChB,MAAM,GAAG,IAAI,CAAA;YACb,SAAQ;QACV,CAAC;QACD,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,QAAQ,GAAG,CAAC,QAAQ,CAAA;YACpB,SAAQ;QACV,CAAC;QACD,IAAI,QAAQ;YAAE,SAAQ;QACtB,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,IAAI,KAAK,KAAK,CAAC;gBAAE,KAAK,GAAG,CAAC,CAAA;YAC1B,KAAK,EAAE,CAAA;QACT,CAAC;aAAM,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACtB,KAAK,EAAE,CAAA;YACP,IAAI,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;gBAChC,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;YACjC,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,6EAA6E;AAE7E,SAAS,aAAa,CAAC,IAAY,EAAE,KAAiB;IACpD,MAAM,KAAK,GAAa,CAAC,MAAM,IAAI,GAAG,CAAC,CAAA;IACvC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;IAClE,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,KAAK,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,UAAU,KAAK,CAAC,KAAK,EAAE,CAAC,CAAA;IAC5E,IAAI,KAAK,CAAC,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,OAAO,KAAK,CAAC,SAAS,QAAQ,CAAC,CAAA;IAC/D,IAAI,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;QACnE,KAAK,CAAC,IAAI,CAAC,SAAS,KAAK,CAAC,GAAG,IAAI,GAAG,IAAI,KAAK,CAAC,GAAG,IAAI,GAAG,EAAE,CAAC,CAAA;IAC7D,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QAC1C,KAAK,CAAC,IAAI,CAAC,WAAW,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACvE,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QAC3C,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC;aAC3C,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;aACjC,IAAI,CAAC,IAAI,CAAC,CAAA;QACb,KAAK,CAAC,IAAI,CAAC,cAAc,SAAS,IAAI,CAAC,CAAA;IACzC,CAAC;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAA;IAC5C,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACxB,CAAC;AAED,SAAS,iBAAiB,CACxB,UAA2B,EAC3B,IAAa,EACb,GAA+B;IAE/B,MAAM,KAAK,GAAa;QACtB,gDAAgD,UAAU,CAAC,MAAM,CAAC,QAAQ,uBAAuB;QACjG,kHAAkH;QAClH,EAAE;QACF,QAAQ;QACR,yFAAyF;QACzF,yRAAyR;QACzR,qEAAqE;QACrE,uFAAuF;QACvF,8FAA8F;QAC9F,wGAAwG;QACxG,4GAA4G;KAC7G,CAAA;IACD,IAAI,UAAU,CAAC,GAAG,EAAE,iBAAiB,EAAE,CAAC;QACtC,KAAK,CAAC,IAAI,CAAC,yCAAyC,UAAU,CAAC,GAAG,CAAC,iBAAiB,IAAI,CAAC,CAAA;IAC3F,CAAC;IACD,IAAI,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,WAAW,IAAI,GAAG,CAAC,CAAA;IACxC,IAAI,GAAG,EAAE,cAAc;QAAE,KAAK,CAAC,IAAI,CAAC,eAAe,GAAG,CAAC,cAAc,GAAG,CAAC,CAAA;IACzE,IAAI,GAAG,EAAE,YAAY,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,GAAG,CAAC,YAAY,CAAC,IAAI;aAC9B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC;aAC1D,IAAI,CAAC,IAAI,CAAC,CAAA;QACb,KAAK,CAAC,IAAI,CAAC,iBAAiB,GAAG,GAAG,CAAC,CAAA;QACnC,IAAI,GAAG,CAAC,YAAY,CAAC,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;YACnD,KAAK,CAAC,IAAI,CAAC,sBAAsB,GAAG,CAAC,YAAY,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACvF,CAAC;QACD,IAAI,GAAG,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;YACjD,KAAK,CAAC,IAAI,CAAC,YAAY,GAAG,CAAC,YAAY,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAC3E,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC;AAED,SAAS,eAAe,CAAC,KAA4B;IACnD,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAA;IAC7C,MAAM,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC;SACxD,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,2CAA2C;SACjF,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;SAClD,IAAI,CAAC,IAAI,CAAC,CAAA;IAEb,MAAM,KAAK,GAAa;QACtB,YAAY,UAAU,CAAC,MAAM,CAAC,QAAQ,uBAAuB;QAC7D,EAAE;QACF,MAAM,CAAC,IAAI,EAAE;QACb,EAAE;QACF,eAAe;QACf,iBAAiB;QACjB,EAAE;QACF,gFAAgF;KACjF,CAAA;IACD,IAAI,OAAO,EAAE,eAAe,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,sDAAsD,CAAC,CAAA;QACtE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAA;IACpD,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC;AAED,6EAA6E;AAE7E,SAAS,OAAO,CAAC,KAAa;IAC5B,OAAO,CACL,KAAK;SACF,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,UAAU,CAC9B,CAAA;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAS,gBAAgB,CAAC,KAAc,EAAE,KAAiB;IACzD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAA;IACvD,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,MAAM,CAAC;QACZ,KAAK,UAAU,CAAC;QAChB,KAAK,OAAO,CAAC;QACb,KAAK,KAAK,CAAC;QACX,KAAK,MAAM,CAAC;QACZ,KAAK,OAAO;YACV,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAC1D,KAAK,QAAQ;YACX,IAAI,OAAO,KAAK,KAAK,QAAQ;gBAAE,OAAO,KAAK,CAAA;YAC3C,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC9B,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;gBACvB,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;YAC3C,CAAC;YACD,OAAO,SAAS,CAAA;QAClB,KAAK,SAAS;YACZ,IAAI,OAAO,KAAK,KAAK,SAAS;gBAAE,OAAO,KAAK,CAAA;YAC5C,IAAI,KAAK,KAAK,MAAM;gBAAE,OAAO,IAAI,CAAA;YACjC,IAAI,KAAK,KAAK,OAAO;gBAAE,OAAO,KAAK,CAAA;YACnC,OAAO,SAAS,CAAA;QAClB,KAAK,MAAM;YACT,IAAI,KAAK,YAAY,IAAI;gBAAE,OAAO,KAAK,CAAC,WAAW,EAAE,CAAA;YACrD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC9B,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAA;gBACzB,OAAO,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAA;YACzD,CAAC;YACD,OAAO,SAAS,CAAA;QAClB,KAAK,QAAQ;YACX,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAA;YAC5F,OAAO,SAAS,CAAA;QAClB,KAAK,OAAO;YACV,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;gBAAE,OAAO,EAAE,CAAA;YACpC,IAAI,CAAC,KAAK,CAAC,MAAM;gBAAE,OAAO,KAAK,CAAA;YAC/B,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;gBACxB,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;oBAAE,OAAO,IAAI,CAAA;gBAC1D,MAAM,GAAG,GAAG,IAA+B,CAAA;gBAC3C,MAAM,OAAO,GAA4B,EAAE,CAAA;gBAC3C,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,MAAO,CAAC,EAAE,CAAC;oBACxD,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,SAAS;wBAAE,OAAO,CAAC,IAAI,CAAC,GAAG,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAA;gBAC/E,CAAC;gBACD,OAAO,OAAO,CAAA;YAChB,CAAC,CAAC,CAAA;QACJ,KAAK,MAAM;YACT,OAAO,KAAK,CAAA;QACd,KAAK,OAAO;YACV,6DAA6D;YAC7D,OAAO,IAAI,CAAA;QACb;YACE,OAAO,KAAK,CAAA;IAChB,CAAC;AACH,CAAC;AAED,6EAA6E;AAE7E;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,KAA4B;IAE5B,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,EAAE,QAAQ,IAAI,iBAAiB,EAAE,CAAA;IAC/D,MAAM,YAAY,GAAG,iBAAiB,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;IACnF,MAAM,UAAU,GAAG,eAAe,CAAC,KAAK,CAAC,CAAA;IAEzC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IAC1B,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,YAAY,CAAC,UAAU,EAAE;QACrD,YAAY;QACZ,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI;QAClC,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,GAAG;KACtC,CAAC,CAAA;IAEF,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAA;IACvB,MAAM,QAAQ,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAA;IACvC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAA;IACjE,CAAC;IAED,IAAI,MAA+B,CAAA;IACnC,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAA4B,CAAA;IAC1D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,+CAA+C,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,EAAE,CACrG,CAAA;IACH,CAAC;IAED,wEAAwE;IACxE,oEAAoE;IACpE,MAAM,IAAI,GAA4B,EAAE,CAAA;IACxC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACpE,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAA;QACxB,IAAI,GAAG,KAAK,SAAS;YAAE,SAAQ;QAC/B,MAAM,OAAO,GAAG,gBAAgB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QAC5C,IAAI,OAAO,KAAK,SAAS;YAAE,IAAI,CAAC,IAAI,CAAC,GAAG,OAAO,CAAA;IACjD,CAAC;IAED,uBAAuB;IACvB,MAAM,KAAK,GACT,CAAC,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC;QAC9C,CAAC,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC;QACpD,CAAC,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC;QAC5C,UAAU,CAAA;IACZ,MAAM,IAAI,GAAG,CAAC,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,CAAA;IAClF,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;IAEhB,MAAM,GAAG,GAAG;QACV,SAAS,EACP,CAAC,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC;YACtD,CAAC,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC;YAC1D,KAAK;QACP,eAAe,EACb,CAAC,OAAO,IAAI,CAAC,eAAe,KAAK,QAAQ,IAAI,IAAI,CAAC,eAAe,CAAC;YAClE,CAAC,OAAO,MAAM,CAAC,eAAe,KAAK,QAAQ,IAAI,MAAM,CAAC,eAAe,CAAC;YACtE,SAAS;QACX,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,iBAAiB;KACpD,CAAA;IAED,OAAO;QACL,IAAI;QACJ,KAAK,EAAE,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU;QACrD,IAAI;QACJ,GAAG;QACH,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO;KACjC,CAAA;AACH,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AIProvider } from
|
|
1
|
+
import type { AIProvider } from '../providers/index.js';
|
|
2
2
|
export interface SuggestionContext {
|
|
3
3
|
documentContent?: string;
|
|
4
4
|
collectionSlug?: string;
|
|
@@ -6,7 +6,7 @@ export interface SuggestionContext {
|
|
|
6
6
|
}
|
|
7
7
|
export interface InlineSuggestion {
|
|
8
8
|
text: string;
|
|
9
|
-
type:
|
|
9
|
+
type: 'completion' | 'improvement' | 'alternative';
|
|
10
10
|
confidence: number;
|
|
11
11
|
range: {
|
|
12
12
|
start: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inline-suggestions.d.ts","sourceRoot":"","sources":["../../src/writing/inline-suggestions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,
|
|
1
|
+
{"version":3,"file":"inline-suggestions.d.ts","sourceRoot":"","sources":["../../src/writing/inline-suggestions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAGvD,MAAM,WAAW,iBAAiB;IAChC,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,EAAE,UAAU,CAAA;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,YAAY,GAAG,aAAa,GAAG,aAAa,CAAA;IAClD,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CACtC;AAED,oFAAoF;AACpF,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA8C7B"}
|