@actuate-media/plugin-ai 0.1.0 → 0.2.1
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 -31
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +36 -35
- 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.map +1 -1
- package/dist/page-builder/generate.js +106 -87
- package/dist/page-builder/generate.js.map +1 -1
- 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 +287 -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 +2 -2
|
@@ -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;AAyND;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC,sBAAsB,CAAC,CAkEjC"}
|
|
@@ -0,0 +1,287 @@
|
|
|
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
|
+
// Media is supplied by the human reviewer.
|
|
108
|
+
// Relations are excluded because the LLM has no view of existing
|
|
109
|
+
// document IDs — guessing would create dangling references that the
|
|
110
|
+
// validator would then reject. Humans / orchestration code wire those
|
|
111
|
+
// in after creation.
|
|
112
|
+
.filter(([, f]) => f.type !== 'media' && f.type !== 'relationship')
|
|
113
|
+
.map(([name, field]) => describeField(name, field))
|
|
114
|
+
.join('\n');
|
|
115
|
+
const lines = [
|
|
116
|
+
`Create a ${collection.labels.singular} matching this brief:`,
|
|
117
|
+
'',
|
|
118
|
+
prompt.trim(),
|
|
119
|
+
'',
|
|
120
|
+
'Field schema:',
|
|
121
|
+
fieldDescriptions,
|
|
122
|
+
'',
|
|
123
|
+
'Output ONLY a JSON object with the field values. No prose. No markdown fences.',
|
|
124
|
+
];
|
|
125
|
+
if (context?.existingContent) {
|
|
126
|
+
lines.push('', 'Existing related content for voice / fact reference:');
|
|
127
|
+
lines.push(context.existingContent.slice(0, 2000));
|
|
128
|
+
}
|
|
129
|
+
return lines.join('\n');
|
|
130
|
+
}
|
|
131
|
+
// ─── Output coercion ──────────────────────────────────────────────────────
|
|
132
|
+
function slugify(title) {
|
|
133
|
+
return (title
|
|
134
|
+
.toLowerCase()
|
|
135
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
136
|
+
.replace(/^-+|-+$/g, '')
|
|
137
|
+
.slice(0, 80) || 'untitled');
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Coerce the LLM output into shapes that match each field's declared type.
|
|
141
|
+
* The LLM occasionally returns numbers as strings, booleans as "true"/"false",
|
|
142
|
+
* etc. We don't try to recover unrecoverable values — we leave bad fields
|
|
143
|
+
* `undefined` so the downstream field validator surfaces the error to the
|
|
144
|
+
* caller instead of silently persisting garbage.
|
|
145
|
+
*/
|
|
146
|
+
function coerceFieldValue(value, field) {
|
|
147
|
+
if (value === null || value === undefined)
|
|
148
|
+
return value;
|
|
149
|
+
switch (field.type) {
|
|
150
|
+
case 'text':
|
|
151
|
+
case 'richText':
|
|
152
|
+
case 'email':
|
|
153
|
+
case 'url':
|
|
154
|
+
case 'slug':
|
|
155
|
+
case 'color':
|
|
156
|
+
return typeof value === 'string' ? value : String(value);
|
|
157
|
+
case 'number':
|
|
158
|
+
if (typeof value === 'number')
|
|
159
|
+
return value;
|
|
160
|
+
if (typeof value === 'string') {
|
|
161
|
+
const n = Number(value);
|
|
162
|
+
return Number.isFinite(n) ? n : undefined;
|
|
163
|
+
}
|
|
164
|
+
return undefined;
|
|
165
|
+
case 'boolean':
|
|
166
|
+
if (typeof value === 'boolean')
|
|
167
|
+
return value;
|
|
168
|
+
if (value === 'true')
|
|
169
|
+
return true;
|
|
170
|
+
if (value === 'false')
|
|
171
|
+
return false;
|
|
172
|
+
return undefined;
|
|
173
|
+
case 'date':
|
|
174
|
+
if (value instanceof Date)
|
|
175
|
+
return value.toISOString();
|
|
176
|
+
if (typeof value === 'string') {
|
|
177
|
+
const d = new Date(value);
|
|
178
|
+
return isNaN(d.getTime()) ? undefined : d.toISOString();
|
|
179
|
+
}
|
|
180
|
+
return undefined;
|
|
181
|
+
case 'select':
|
|
182
|
+
if (typeof value === 'string' && field.options?.some((o) => o.value === value))
|
|
183
|
+
return value;
|
|
184
|
+
return undefined;
|
|
185
|
+
case 'array':
|
|
186
|
+
if (!Array.isArray(value))
|
|
187
|
+
return [];
|
|
188
|
+
if (!field.fields)
|
|
189
|
+
return value;
|
|
190
|
+
return value.map((item) => {
|
|
191
|
+
if (item === null || typeof item !== 'object')
|
|
192
|
+
return item;
|
|
193
|
+
const obj = item;
|
|
194
|
+
const coerced = {};
|
|
195
|
+
for (const [name, sub] of Object.entries(field.fields)) {
|
|
196
|
+
if (obj[name] !== undefined)
|
|
197
|
+
coerced[name] = coerceFieldValue(obj[name], sub);
|
|
198
|
+
}
|
|
199
|
+
return coerced;
|
|
200
|
+
});
|
|
201
|
+
case 'json':
|
|
202
|
+
return value;
|
|
203
|
+
case 'media':
|
|
204
|
+
// The LLM doesn't have asset IDs. Leave for a human to fill.
|
|
205
|
+
return null;
|
|
206
|
+
case 'relationship':
|
|
207
|
+
// Same rationale as media — IDs are out-of-band knowledge. If the
|
|
208
|
+
// model did emit something (e.g. echoed an ID from the prompt) we
|
|
209
|
+
// accept strings and string arrays verbatim; otherwise drop.
|
|
210
|
+
if (typeof value === 'string')
|
|
211
|
+
return value;
|
|
212
|
+
if (Array.isArray(value))
|
|
213
|
+
return value.filter((v) => typeof v === 'string');
|
|
214
|
+
return undefined;
|
|
215
|
+
default:
|
|
216
|
+
return value;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// ─── Main entrypoint ──────────────────────────────────────────────────────
|
|
220
|
+
/**
|
|
221
|
+
* Generate a complete document body for the given collection from a prompt.
|
|
222
|
+
*
|
|
223
|
+
* The result is a flat field-data map that can be passed directly to
|
|
224
|
+
* `createDocument(slug, payload, ctx)` in cms-core.
|
|
225
|
+
*
|
|
226
|
+
* @throws if the AI provider is not configured, the LLM output doesn't parse
|
|
227
|
+
* as JSON, or no title field is present in the response.
|
|
228
|
+
*/
|
|
229
|
+
export async function generateDocumentContent(input) {
|
|
230
|
+
const provider = input.context?.provider ?? requireAIProvider();
|
|
231
|
+
const systemPrompt = buildSystemPrompt(input.collection, input.tone, input.context);
|
|
232
|
+
const userPrompt = buildUserPrompt(input);
|
|
233
|
+
const started = Date.now();
|
|
234
|
+
const result = await provider.generateText(userPrompt, {
|
|
235
|
+
systemPrompt,
|
|
236
|
+
maxTokens: input.maxTokens ?? 3000,
|
|
237
|
+
temperature: input.temperature ?? 0.7,
|
|
238
|
+
});
|
|
239
|
+
const raw = result.text;
|
|
240
|
+
const jsonText = extractJsonObject(raw);
|
|
241
|
+
if (!jsonText) {
|
|
242
|
+
throw new Error('AI content generator returned no JSON object');
|
|
243
|
+
}
|
|
244
|
+
let parsed;
|
|
245
|
+
try {
|
|
246
|
+
parsed = JSON.parse(jsonText);
|
|
247
|
+
}
|
|
248
|
+
catch (err) {
|
|
249
|
+
throw new Error(`AI content generator returned invalid JSON: ${err instanceof Error ? err.message : 'parse failed'}`);
|
|
250
|
+
}
|
|
251
|
+
// Coerce each field according to the schema. Unknown keys (anything the
|
|
252
|
+
// schema doesn't declare) are dropped to keep persisted data clean.
|
|
253
|
+
const data = {};
|
|
254
|
+
for (const [name, field] of Object.entries(input.collection.fields)) {
|
|
255
|
+
const raw = parsed[name];
|
|
256
|
+
if (raw === undefined)
|
|
257
|
+
continue;
|
|
258
|
+
const coerced = coerceFieldValue(raw, field);
|
|
259
|
+
if (coerced !== undefined)
|
|
260
|
+
data[name] = coerced;
|
|
261
|
+
}
|
|
262
|
+
// Derive title + slug.
|
|
263
|
+
const title = (typeof data.title === 'string' && data.title) ||
|
|
264
|
+
(typeof data.question === 'string' && data.question) ||
|
|
265
|
+
(typeof data.name === 'string' && data.name) ||
|
|
266
|
+
'Untitled';
|
|
267
|
+
const slug = (typeof data.slug === 'string' && data.slug.trim()) || slugify(title);
|
|
268
|
+
data.slug = slug;
|
|
269
|
+
const seo = {
|
|
270
|
+
metaTitle: (typeof data.metaTitle === 'string' && data.metaTitle) ||
|
|
271
|
+
(typeof parsed.metaTitle === 'string' && parsed.metaTitle) ||
|
|
272
|
+
title,
|
|
273
|
+
metaDescription: (typeof data.metaDescription === 'string' && data.metaDescription) ||
|
|
274
|
+
(typeof parsed.metaDescription === 'string' && parsed.metaDescription) ||
|
|
275
|
+
undefined,
|
|
276
|
+
schemaType: input.collection.seo?.defaultSchemaType,
|
|
277
|
+
};
|
|
278
|
+
return {
|
|
279
|
+
data,
|
|
280
|
+
title: typeof title === 'string' ? title : 'Untitled',
|
|
281
|
+
slug,
|
|
282
|
+
seo,
|
|
283
|
+
usage: result.usage,
|
|
284
|
+
durationMs: Date.now() - started,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
//# sourceMappingURL=content-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-generator.js","sourceRoot":"","sources":["../../src/writing/content-generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { requireAIProvider } from
|
|
1
|
+
import { requireAIProvider } from '../providers/index.js';
|
|
2
2
|
/** Returns inline writing suggestions for the given text at the cursor position. */
|
|
3
3
|
export async function getSuggestions(text, cursorPosition, context) {
|
|
4
4
|
const ai = context?.provider ?? requireAIProvider();
|
|
@@ -15,18 +15,21 @@ Return a JSON array of objects with:
|
|
|
15
15
|
- "type": one of "completion", "improvement", or "alternative"
|
|
16
16
|
- "confidence": a number between 0 and 1`;
|
|
17
17
|
const result = await ai.generateText(prompt, {
|
|
18
|
-
systemPrompt:
|
|
18
|
+
systemPrompt: 'You are a writing assistant providing inline suggestions. Return valid JSON only, no markdown.',
|
|
19
19
|
maxTokens: 512,
|
|
20
20
|
temperature: 0.6,
|
|
21
21
|
});
|
|
22
22
|
try {
|
|
23
|
-
const cleaned = result.text
|
|
23
|
+
const cleaned = result.text
|
|
24
|
+
.replace(/```json?\n?/g, '')
|
|
25
|
+
.replace(/```/g, '')
|
|
26
|
+
.trim();
|
|
24
27
|
const parsed = JSON.parse(cleaned);
|
|
25
28
|
return parsed.map((s) => ({
|
|
26
29
|
text: s.text,
|
|
27
|
-
type: ([
|
|
30
|
+
type: (['completion', 'improvement', 'alternative'].includes(s.type)
|
|
28
31
|
? s.type
|
|
29
|
-
:
|
|
32
|
+
: 'completion'),
|
|
30
33
|
confidence: Math.max(0, Math.min(1, s.confidence ?? 0.5)),
|
|
31
34
|
range: { start: cursorPosition, end: cursorPosition },
|
|
32
35
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inline-suggestions.js","sourceRoot":"","sources":["../../src/writing/inline-suggestions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,
|
|
1
|
+
{"version":3,"file":"inline-suggestions.js","sourceRoot":"","sources":["../../src/writing/inline-suggestions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAezD,oFAAoF;AACpF,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAAY,EACZ,cAAsB,EACtB,OAA2B;IAE3B,MAAM,EAAE,GAAG,OAAO,EAAE,QAAQ,IAAI,iBAAiB,EAAE,CAAA;IAEnD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,cAAc,GAAG,GAAG,CAAC,EAAE,cAAc,CAAC,CAAA;IAC5E,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,cAAc,GAAG,GAAG,CAAC,CAAA;IAE9D,MAAM,MAAM,GAAG;;uBAEM,MAAM;;sBAEP,KAAK;;;;;yCAKc,CAAA;IAEvC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE;QAC3C,YAAY,EACV,gGAAgG;QAClG,SAAS,EAAE,GAAG;QACd,WAAW,EAAE,GAAG;KACjB,CAAC,CAAA;IAEF,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI;aACxB,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC;aAC3B,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;aACnB,IAAI,EAAE,CAAA;QACT,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAI/B,CAAA;QAEF,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACxB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,IAAI,EAAE,CAAC,CAAC,YAAY,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;gBAClE,CAAC,CAAC,CAAC,CAAC,IAAI;gBACR,CAAC,CAAC,YAAY,CAA6B;YAC7C,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,UAAU,IAAI,GAAG,CAAC,CAAC;YACzD,KAAK,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,cAAc,EAAE;SACtD,CAAC,CAAC,CAAA;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { AIProvider } from
|
|
1
|
+
import type { AIProvider } from '../providers/index.js';
|
|
2
2
|
export interface TitleOptions {
|
|
3
3
|
count?: number;
|
|
4
|
-
style?:
|
|
4
|
+
style?: 'informative' | 'engaging' | 'seo-optimized';
|
|
5
5
|
provider?: AIProvider;
|
|
6
6
|
}
|
|
7
7
|
/** Generates an SEO-friendly meta description from content. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meta-generator.d.ts","sourceRoot":"","sources":["../../src/writing/meta-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,
|
|
1
|
+
{"version":3,"file":"meta-generator.d.ts","sourceRoot":"","sources":["../../src/writing/meta-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAGvD,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,aAAa,GAAG,UAAU,GAAG,eAAe,CAAA;IACpD,QAAQ,CAAC,EAAE,UAAU,CAAA;CACtB;AAED,+DAA+D;AAC/D,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,MAAM,EACf,SAAS,GAAE,MAAY,EACvB,QAAQ,CAAC,EAAE,UAAU,GACpB,OAAO,CAAC,MAAM,CAAC,CAiBjB;AAED,gDAAgD;AAChD,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,SAAS,GAAE,MAAY,EACvB,QAAQ,CAAC,EAAE,UAAU,GACpB,OAAO,CAAC,MAAM,CAAC,CAgBjB;AAED,+DAA+D;AAC/D,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA4B9F"}
|
|
@@ -1,41 +1,53 @@
|
|
|
1
|
-
import { requireAIProvider } from
|
|
1
|
+
import { requireAIProvider } from '../providers/index.js';
|
|
2
2
|
/** Generates an SEO-friendly meta description from content. */
|
|
3
3
|
export async function generateMetaDescription(content, maxLength = 155, provider) {
|
|
4
4
|
const ai = provider ?? requireAIProvider();
|
|
5
5
|
const result = await ai.generateText(`Write a compelling meta description (maximum ${maxLength} characters) for the following content. The description should be informative, include relevant keywords naturally, and encourage clicks from search results.\n\nContent:\n${content.slice(0, 3000)}`, {
|
|
6
|
-
systemPrompt:
|
|
6
|
+
systemPrompt: 'You are an SEO specialist. Write only the meta description text, no quotes or labels. Keep it under the specified character limit.',
|
|
7
7
|
maxTokens: 256,
|
|
8
8
|
temperature: 0.5,
|
|
9
9
|
});
|
|
10
|
-
return result.text
|
|
10
|
+
return result.text
|
|
11
|
+
.replace(/^["']|["']$/g, '')
|
|
12
|
+
.trim()
|
|
13
|
+
.slice(0, maxLength);
|
|
11
14
|
}
|
|
12
15
|
/** Generates a concise excerpt from content. */
|
|
13
16
|
export async function generateExcerpt(content, maxLength = 300, provider) {
|
|
14
17
|
const ai = provider ?? requireAIProvider();
|
|
15
18
|
const result = await ai.generateText(`Write a concise excerpt (maximum ${maxLength} characters) that summarizes the following content. It should capture the essence of the piece and entice readers.\n\nContent:\n${content.slice(0, 3000)}`, {
|
|
16
|
-
systemPrompt:
|
|
19
|
+
systemPrompt: 'You are an editor. Write only the excerpt text, no quotes or labels.',
|
|
17
20
|
maxTokens: 256,
|
|
18
21
|
temperature: 0.4,
|
|
19
22
|
});
|
|
20
|
-
return result.text
|
|
23
|
+
return result.text
|
|
24
|
+
.replace(/^["']|["']$/g, '')
|
|
25
|
+
.trim()
|
|
26
|
+
.slice(0, maxLength);
|
|
21
27
|
}
|
|
22
28
|
/** Generates title options from content in the given style. */
|
|
23
29
|
export async function generateTitle(content, options) {
|
|
24
30
|
const ai = options?.provider ?? requireAIProvider();
|
|
25
31
|
const count = options?.count ?? 5;
|
|
26
|
-
const style = options?.style ??
|
|
32
|
+
const style = options?.style ?? 'informative';
|
|
27
33
|
const result = await ai.generateText(`Generate ${count} ${style} title options for the following content. Return them as a JSON array of strings.\n\nContent:\n${content.slice(0, 3000)}`, {
|
|
28
|
-
systemPrompt:
|
|
34
|
+
systemPrompt: 'You are a headline writer. Return valid JSON only: an array of title strings. No markdown formatting.',
|
|
29
35
|
maxTokens: 512,
|
|
30
36
|
temperature: 0.7,
|
|
31
37
|
});
|
|
32
38
|
try {
|
|
33
|
-
const cleaned = result.text
|
|
39
|
+
const cleaned = result.text
|
|
40
|
+
.replace(/```json?\n?/g, '')
|
|
41
|
+
.replace(/```/g, '')
|
|
42
|
+
.trim();
|
|
34
43
|
const titles = JSON.parse(cleaned);
|
|
35
44
|
if (Array.isArray(titles))
|
|
36
45
|
return titles.map(String);
|
|
37
46
|
}
|
|
38
47
|
catch { }
|
|
39
|
-
return result.text
|
|
48
|
+
return result.text
|
|
49
|
+
.split('\n')
|
|
50
|
+
.filter((line) => line.trim().length > 0)
|
|
51
|
+
.slice(0, count);
|
|
40
52
|
}
|
|
41
53
|
//# sourceMappingURL=meta-generator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meta-generator.js","sourceRoot":"","sources":["../../src/writing/meta-generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,
|
|
1
|
+
{"version":3,"file":"meta-generator.js","sourceRoot":"","sources":["../../src/writing/meta-generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAQzD,+DAA+D;AAC/D,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,OAAe,EACf,YAAoB,GAAG,EACvB,QAAqB;IAErB,MAAM,EAAE,GAAG,QAAQ,IAAI,iBAAiB,EAAE,CAAA;IAE1C,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,YAAY,CAClC,gDAAgD,SAAS,8KAA8K,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAC/P;QACE,YAAY,EACV,oIAAoI;QACtI,SAAS,EAAE,GAAG;QACd,WAAW,EAAE,GAAG;KACjB,CACF,CAAA;IAED,OAAO,MAAM,CAAC,IAAI;SACf,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC;SAC3B,IAAI,EAAE;SACN,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAA;AACxB,CAAC;AAED,gDAAgD;AAChD,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAAe,EACf,YAAoB,GAAG,EACvB,QAAqB;IAErB,MAAM,EAAE,GAAG,QAAQ,IAAI,iBAAiB,EAAE,CAAA;IAE1C,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,YAAY,CAClC,oCAAoC,SAAS,mIAAmI,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EACxM;QACE,YAAY,EAAE,sEAAsE;QACpF,SAAS,EAAE,GAAG;QACd,WAAW,EAAE,GAAG;KACjB,CACF,CAAA;IAED,OAAO,MAAM,CAAC,IAAI;SACf,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC;SAC3B,IAAI,EAAE;SACN,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAA;AACxB,CAAC;AAED,+DAA+D;AAC/D,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAe,EAAE,OAAsB;IACzE,MAAM,EAAE,GAAG,OAAO,EAAE,QAAQ,IAAI,iBAAiB,EAAE,CAAA;IACnD,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,IAAI,CAAC,CAAA;IACjC,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,IAAI,aAAa,CAAA;IAE7C,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,YAAY,CAClC,YAAY,KAAK,IAAI,KAAK,kGAAkG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EACpJ;QACE,YAAY,EACV,uGAAuG;QACzG,SAAS,EAAE,GAAG;QACd,WAAW,EAAE,GAAG;KACjB,CACF,CAAA;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI;aACxB,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC;aAC3B,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;aACnB,IAAI,EAAE,CAAA;QACT,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAClC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;YAAE,OAAO,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IACtD,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IAEV,OAAO,MAAM,CAAC,IAAI;SACf,KAAK,CAAC,IAAI,CAAC;SACX,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;SACxC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;AACpB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@actuate-media/plugin-ai",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/actuatecms/actuatecms.git",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"@types/react": "^19.0.0",
|
|
27
27
|
"typescript": "^5.7.0",
|
|
28
28
|
"vitest": "^3.0.0",
|
|
29
|
-
"@actuate-media/cms-core": "0.
|
|
29
|
+
"@actuate-media/cms-core": "0.18.0"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
32
|
"@actuate-media/cms-core": ">=0.1.0",
|