@actuate-media/cms-admin 0.56.2 → 0.57.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.
Files changed (72) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/__tests__/views/ai-settings.render.test.js +34 -0
  3. package/dist/__tests__/views/ai-settings.render.test.js.map +1 -1
  4. package/dist/actuate-admin.css +1 -1
  5. package/dist/components/AICoauthorBubbleMenu.d.ts.map +1 -1
  6. package/dist/components/AICoauthorBubbleMenu.js +5 -1
  7. package/dist/components/AICoauthorBubbleMenu.js.map +1 -1
  8. package/dist/components/BrandVoiceAlignmentBadge.d.ts +6 -0
  9. package/dist/components/BrandVoiceAlignmentBadge.d.ts.map +1 -0
  10. package/dist/components/BrandVoiceAlignmentBadge.js +11 -0
  11. package/dist/components/BrandVoiceAlignmentBadge.js.map +1 -0
  12. package/dist/components/CoauthorResultPopover.d.ts +5 -1
  13. package/dist/components/CoauthorResultPopover.d.ts.map +1 -1
  14. package/dist/components/CoauthorResultPopover.js +35 -6
  15. package/dist/components/CoauthorResultPopover.js.map +1 -1
  16. package/dist/components/CommandPalette.d.ts.map +1 -1
  17. package/dist/components/CommandPalette.js +5 -1
  18. package/dist/components/CommandPalette.js.map +1 -1
  19. package/dist/components/seo/SeoEditorDrawer.d.ts.map +1 -1
  20. package/dist/components/seo/SeoEditorDrawer.js +43 -2
  21. package/dist/components/seo/SeoEditorDrawer.js.map +1 -1
  22. package/dist/components/ui/Badge.d.ts +1 -1
  23. package/dist/lib/brand-voice-client.d.ts +21 -0
  24. package/dist/lib/brand-voice-client.d.ts.map +1 -0
  25. package/dist/lib/brand-voice-client.js +27 -0
  26. package/dist/lib/brand-voice-client.js.map +1 -0
  27. package/dist/lib/coauthor-client.d.ts +2 -0
  28. package/dist/lib/coauthor-client.d.ts.map +1 -1
  29. package/dist/lib/coauthor-client.js +1 -0
  30. package/dist/lib/coauthor-client.js.map +1 -1
  31. package/dist/lib/seo-service.d.ts +12 -0
  32. package/dist/lib/seo-service.d.ts.map +1 -1
  33. package/dist/lib/seo-service.js +0 -10
  34. package/dist/lib/seo-service.js.map +1 -1
  35. package/dist/views/Settings.js +1 -1
  36. package/dist/views/Settings.js.map +1 -1
  37. package/dist/views/settings/AISettingsTab.d.ts +3 -1
  38. package/dist/views/settings/AISettingsTab.d.ts.map +1 -1
  39. package/dist/views/settings/AISettingsTab.js +2 -2
  40. package/dist/views/settings/AISettingsTab.js.map +1 -1
  41. package/dist/views/settings/BrandVoiceCard.d.ts +39 -2
  42. package/dist/views/settings/BrandVoiceCard.d.ts.map +1 -1
  43. package/dist/views/settings/BrandVoiceCard.js +215 -3
  44. package/dist/views/settings/BrandVoiceCard.js.map +1 -1
  45. package/dist/views/settings/brand-voice/BrandVoiceAlignmentPanel.d.ts +13 -0
  46. package/dist/views/settings/brand-voice/BrandVoiceAlignmentPanel.d.ts.map +1 -0
  47. package/dist/views/settings/brand-voice/BrandVoiceAlignmentPanel.js +74 -0
  48. package/dist/views/settings/brand-voice/BrandVoiceAlignmentPanel.js.map +1 -0
  49. package/dist/views/settings/brand-voice/BrandVoiceRulesSections.d.ts +7 -0
  50. package/dist/views/settings/brand-voice/BrandVoiceRulesSections.d.ts.map +1 -0
  51. package/dist/views/settings/brand-voice/BrandVoiceRulesSections.js +54 -0
  52. package/dist/views/settings/brand-voice/BrandVoiceRulesSections.js.map +1 -0
  53. package/dist/views/settings/useAiSettings.d.ts +32 -0
  54. package/dist/views/settings/useAiSettings.d.ts.map +1 -1
  55. package/dist/views/settings/useAiSettings.js +85 -3
  56. package/dist/views/settings/useAiSettings.js.map +1 -1
  57. package/package.json +2 -2
  58. package/src/__tests__/views/ai-settings.render.test.tsx +50 -0
  59. package/src/components/AICoauthorBubbleMenu.tsx +12 -0
  60. package/src/components/BrandVoiceAlignmentBadge.tsx +39 -0
  61. package/src/components/CoauthorResultPopover.tsx +62 -4
  62. package/src/components/CommandPalette.tsx +12 -0
  63. package/src/components/seo/SeoEditorDrawer.tsx +65 -1
  64. package/src/lib/brand-voice-client.ts +38 -0
  65. package/src/lib/coauthor-client.ts +4 -0
  66. package/src/lib/seo-service.ts +2 -0
  67. package/src/views/Settings.tsx +1 -1
  68. package/src/views/settings/AISettingsTab.tsx +13 -2
  69. package/src/views/settings/BrandVoiceCard.tsx +592 -76
  70. package/src/views/settings/brand-voice/BrandVoiceAlignmentPanel.tsx +205 -0
  71. package/src/views/settings/brand-voice/BrandVoiceRulesSections.tsx +321 -0
  72. package/src/views/settings/useAiSettings.ts +134 -3
@@ -0,0 +1,38 @@
1
+ import type { BrandAlignmentScoreResult } from '@actuate-media/cms-core/brand-voice'
2
+ import { cmsApi } from './api.js'
3
+
4
+ export type { BrandAlignmentScoreResult }
5
+
6
+ export interface BrandVoiceFixResult {
7
+ text: string
8
+ deterministicFixes: string[]
9
+ beforeScore: BrandAlignmentScoreResult
10
+ afterScore: BrandAlignmentScoreResult
11
+ usedAi: boolean
12
+ }
13
+
14
+ export async function fixBrandVoiceContent(input: {
15
+ content: string
16
+ channel?: string
17
+ useAi?: boolean
18
+ }): Promise<{ ok: boolean; result?: BrandVoiceFixResult; error?: string }> {
19
+ const res = await cmsApi<BrandVoiceFixResult>('/ai/brand-voice/fix', {
20
+ method: 'POST',
21
+ body: JSON.stringify(input),
22
+ })
23
+ if (res.error) return { ok: false, error: res.error }
24
+ if (!res.data?.text) return { ok: false, error: 'No fixed copy was returned.' }
25
+ return { ok: true, result: res.data }
26
+ }
27
+
28
+ export function brandAlignmentLabel(score: number): string {
29
+ if (score >= 85) return 'On brand'
30
+ if (score >= 65) return 'Mostly on brand'
31
+ return 'Off brand'
32
+ }
33
+
34
+ export function brandAlignmentTone(score: number): string {
35
+ if (score >= 85) return 'text-success'
36
+ if (score >= 65) return 'text-warning'
37
+ return 'text-destructive'
38
+ }
@@ -1,4 +1,5 @@
1
1
  import { cmsApi } from './api.js'
2
+ import type { BrandAlignmentScoreResult } from '@actuate-media/cms-core/brand-voice'
2
3
 
3
4
  /**
4
5
  * Inline AI co-author client — thin, typed wrapper around the
@@ -68,6 +69,7 @@ export interface CoauthorResult {
68
69
  text: string
69
70
  /** Populated only when `action === 'proofread'`. */
70
71
  changes?: ProofreadChange[]
72
+ brandAlignment?: BrandAlignmentScoreResult
71
73
  }
72
74
 
73
75
  export type CoauthorOutcome =
@@ -125,6 +127,7 @@ export async function coauthorText(
125
127
  action?: CoauthorAction
126
128
  text?: unknown
127
129
  changes?: unknown
130
+ brandAlignment?: BrandAlignmentScoreResult
128
131
  }>('/ai/coauthor', {
129
132
  method: 'POST',
130
133
  body: JSON.stringify(body),
@@ -155,6 +158,7 @@ export async function coauthorText(
155
158
  action === 'proofread' && Array.isArray(res.data.changes)
156
159
  ? (res.data.changes as ProofreadChange[])
157
160
  : undefined,
161
+ brandAlignment: res.data.brandAlignment,
158
162
  },
159
163
  }
160
164
  }
@@ -8,6 +8,7 @@
8
8
  * Endpoint paths here are the contract implemented by cms-core
9
9
  * `packages/cms-core/src/api/handlers.ts` across phases 2-3 and 6.
10
10
  */
11
+ import type { BrandAlignmentScoreResult } from '@actuate-media/cms-core/brand-voice'
11
12
  import { cmsApi } from './api.js'
12
13
 
13
14
  /**
@@ -643,6 +644,7 @@ export interface SeoAiResult {
643
644
  text?: string
644
645
  alternatives?: string[]
645
646
  structuredData?: Record<string, unknown>
647
+ brandAlignment?: BrandAlignmentScoreResult
646
648
  /** True when the AI provider is not configured (graceful fallback). */
647
649
  unavailable?: boolean
648
650
  }
@@ -325,7 +325,7 @@ export function Settings({
325
325
  </Tabs.Content>
326
326
 
327
327
  <Tabs.Content value="ai" className="space-y-4">
328
- <AISettingsTab role={session?.user?.role} />
328
+ <AISettingsTab role={session?.user?.role} config={config} />
329
329
  </Tabs.Content>
330
330
 
331
331
  <Tabs.Content value="users">
@@ -30,9 +30,11 @@ const PROVIDER_OPTIONS: Array<{ value: AiProviderKey; label: string }> = [
30
30
  export interface AISettingsTabProps {
31
31
  /** Current user's role. Only ADMIN can persist changes. */
32
32
  role?: string
33
+ /** Resolved CMS config — used to list content collections for brand voice analysis. */
34
+ config?: unknown
33
35
  }
34
36
 
35
- export function AISettingsTab({ role }: AISettingsTabProps) {
37
+ export function AISettingsTab({ role, config }: AISettingsTabProps) {
36
38
  const canEdit = role === 'ADMIN'
37
39
  const ai = useAiSettings(canEdit)
38
40
 
@@ -89,7 +91,16 @@ export function AISettingsTab({ role }: AISettingsTabProps) {
89
91
  onToggle={ai.toggleFeature}
90
92
  onSetFeatureModel={ai.setFeatureModel}
91
93
  />
92
- <BrandVoiceCard value={ai.form.brandVoice} canEdit={canEdit} onChange={ai.setBrandVoice} />
94
+ <BrandVoiceCard
95
+ value={ai.form.brandVoice}
96
+ canEdit={canEdit}
97
+ onChange={ai.setBrandVoice}
98
+ config={config}
99
+ onAnalyze={canEdit ? ai.analyzeBrandVoice : undefined}
100
+ onScore={canEdit ? ai.scoreBrandVoice : undefined}
101
+ editMode={ai.brandVoiceEditMode}
102
+ onEditModeChange={ai.setBrandVoiceEditMode}
103
+ />
93
104
  <MonthlyUsageCard
94
105
  usage={ai.usage}
95
106
  monthlyTokenLimit={ai.form.monthlyTokenLimit}