@materializecms/server 0.5.0 → 0.6.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/CHANGELOG.md +15 -0
- package/package.json +4 -4
- package/src/ai.d.ts +6 -1
- package/src/ai.js +11 -3
- package/src/app.js +672 -21
- package/src/brief.d.ts +43 -0
- package/src/brief.js +172 -0
- package/src/studio.d.ts +13 -0
- package/src/studio.js +75 -0
- package/src/tools.d.ts +1 -0
- package/src/tools.js +57 -2
- package/src/wordpress.d.ts +2 -0
- package/src/wordpress.js +22 -5
- package/src/wpimport.d.ts +19 -1
- package/src/wpimport.js +112 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,21 @@ Ogni versione, dalla più recente. Le novità in arrivo si scrivono sotto «Pros
|
|
|
4
4
|
|
|
5
5
|
## Prossima versione
|
|
6
6
|
|
|
7
|
+
## 0.6.0 — 2026-11-06
|
|
8
|
+
|
|
9
|
+
- **Panoramica rinnovata**: si apre su quello che c'è da fare (documenti da pubblicare, il rilascio in preparazione, la prossima uscita programmata, i messaggi nuovi), con un riepilogo in una frase, le ultime modifiche e il sito a colpo d'occhio.
|
|
10
|
+
- **Cosa facciamo oggi sul sito?**: in cima alla panoramica chiedi all'AI qualcosa che riguarda tutto il sito, come le descrizioni per Google mancanti o la traduzione delle pagine. Lavora solo in bozza, senza pubblicare né toccare tema e sezioni condivise, e ti elenca le bozze da rivedere.
|
|
11
|
+
- **Barra sopra l'elemento selezionato** nell'editor: AI sul testo, cambia immagine, duplica, sposta su e giù, com'è su mobile, altre azioni ed elimina, senza andare nel pannello a destra.
|
|
12
|
+
- **Import da WordPress con impaginazione AI**: un'opzione in più rifà l'impaginazione di ogni pagina importata con le sezioni della libreria (apertura, colonne, elenchi, inviti all'azione), con gli stessi testi e le stesse immagini, nella bozza. Un controllo confronta parole e immagini prima e dopo: se cambierebbero, la pagina resta com'era.
|
|
13
|
+
- L'import da WordPress conserva le descrizioni (testo alternativo) delle immagini nei contenuti: prima andavano perse.
|
|
14
|
+
- **Tour dell'editor rifatto**: 14 passi invece di 4, e ognuno illumina la zona vera di cui parla (le schede a sinistra si aprono da sole): Contenuto e Design, Livelli, Aggiungi, Stili, Controlli, la tela, le proprietà, i dispositivi, zoom e anteprima, l'assistente AI, cronologia e pubblicazione. Frecce per spostarsi, Esc per uscire, e si rifà da **?** → **Rifai il tour**.
|
|
15
|
+
- **Rilasci**: raccogli più pagine e articoli che devono uscire insieme, per un lancio o una campagna, e pubblicali con un clic o a un'ora stabilita. Nello stesso momento si possono togliere dal sito le pagine vecchie. Tutto o niente: se una pagina non è pronta non esce niente, e il pannello dice quale e perché. Dalla nuova voce **Rilasci** nella barra laterale, o da Altre azioni → Aggiungi a un rilascio.
|
|
16
|
+
- Nelle finestre il cursore va subito nel campo da compilare.
|
|
17
|
+
- Le icone di alcuni pulsanti (Rivedi con l'AI, Ricavala dai testi del sito, Copia, Applica, Crea e copia il link) avevano una misura sbagliata e riempivano il pulsante.
|
|
18
|
+
- **Il sito da un brief**: dalla Panoramica, **Sito da un brief**. Descrivi l'attività in poche righe, se vuoi con un'immagine di riferimento, e l'AI prepara le pagine con le sezioni della libreria, con menu, piè di pagina, testi e descrizioni per Google. Tutto resta in bozza; le pagine esistenti, i menu condivisi e il sito online non vengono toccati. Colori, caratteri e voce del brand arrivano come proposta da applicare con un clic. Dove mancano informazioni (prezzi, indirizzo, telefono) lascia un segnaposto tra parentesi quadre invece di inventare, e puoi rispondere all'AI per chiedere altro.
|
|
19
|
+
- Le risposte dell'assistente mostrano grassetti ed elenchi, invece di asterischi e trattini.
|
|
20
|
+
- **Revisione AI prima di pubblicare**: nella scheda Controlli (e in Altre azioni per gli articoli) **Rivedi con l'AI** rilegge la pagina e segnala refusi, grammatica, frasi fuori dalla voce del brand, incoerenze e link che non portano dove dicono. Ogni segnalazione ha la correzione, da applicare con un clic e annullare con ⌘Z.
|
|
21
|
+
- **Voce del brand per l'AI**: in Impostazioni → Voce del brand scrivi chi siete, il tono, come vi rivolgete a chi legge, le parole da usare ed evitare e un testo d'esempio. L'AI la segue in ogni testo che scrive: pulsante ✨, assistente, traduzioni e client MCP. Il pulsante **Ricavala dai testi del sito** la propone leggendo le pagine pubblicate.
|
|
7
22
|
## 0.5.0 — 2026-11-05
|
|
8
23
|
|
|
9
24
|
- **Nuovo logo**: una M fatta di blocchi che passano da trasparenti a pieni, perché i contenuti prendono forma. Il nome è in Geist. Lo trovi nel pannello, nella favicon, nella pagina di accesso e nel README; i file sono in `docs/assets`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@materializecms/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Il server di Materialize: API, accessi, media, backup, aggiornamenti dal pannello e server MCP.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@anthropic-ai/sdk": "1.3.0",
|
|
22
22
|
"@hono/node-server": "2.1.5",
|
|
23
|
-
"@materializecms/admin": "0.
|
|
24
|
-
"@materializecms/core": "0.
|
|
25
|
-
"@materializecms/db": "0.
|
|
23
|
+
"@materializecms/admin": "0.6.0",
|
|
24
|
+
"@materializecms/core": "0.6.0",
|
|
25
|
+
"@materializecms/db": "0.6.0",
|
|
26
26
|
"@modelcontextprotocol/sdk": "1.32.2",
|
|
27
27
|
"hono": "4.13.14",
|
|
28
28
|
"htmlparser2": "12.0.0",
|
package/src/ai.d.ts
CHANGED
|
@@ -97,10 +97,15 @@ export declare function runTurn(s: AiSettings, conv: Conversation, input: {
|
|
|
97
97
|
tools: SiteTool[];
|
|
98
98
|
onEvent: (e: AiEvent) => void;
|
|
99
99
|
maxSteps?: number;
|
|
100
|
+
/** Stops before the next step (the person closed the panel or pressed stop). */
|
|
101
|
+
signal?: AbortSignal;
|
|
100
102
|
}): Promise<string>;
|
|
101
103
|
export declare const fastModelOf: (s: AiSettings) => string;
|
|
104
|
+
export declare const languageName: (code: string) => string;
|
|
102
105
|
/**
|
|
103
106
|
* Translates a page's texts in batches, keeping their order: each batch goes out as a JSON list
|
|
104
107
|
* and must come back as a list of the same length. Marks like <b>, <i> and <a1> stay in place.
|
|
105
108
|
*/
|
|
106
|
-
export declare function translateTexts(s: AiSettings, texts: string[], from: string, to: string, onProgress?: (done: number) => void
|
|
109
|
+
export declare function translateTexts(s: AiSettings, texts: string[], from: string, to: string, onProgress?: (done: number) => void,
|
|
110
|
+
/** The brand voice (voicePrompt), kept in the other language. */
|
|
111
|
+
voice?: string): Promise<string[]>;
|
package/src/ai.js
CHANGED
|
@@ -70,6 +70,10 @@ export async function complete(s, input) {
|
|
|
70
70
|
* (at most `maxSteps`), then its answer. The conversation keeps everything for the next turn.
|
|
71
71
|
*/
|
|
72
72
|
export async function runTurn(s, conv, input) {
|
|
73
|
+
const stopped = () => {
|
|
74
|
+
if (input.signal?.aborted)
|
|
75
|
+
throw new AiError('Interrotto.');
|
|
76
|
+
};
|
|
73
77
|
const images = input.images ?? [];
|
|
74
78
|
const byName = new Map(input.tools.map((t) => [t.name, t]));
|
|
75
79
|
const runTool = async (name, raw) => {
|
|
@@ -107,6 +111,7 @@ export async function runTurn(s, conv, input) {
|
|
|
107
111
|
: input.text,
|
|
108
112
|
});
|
|
109
113
|
for (let step = 0; step < maxSteps; step++) {
|
|
114
|
+
stopped();
|
|
110
115
|
const reply = await openaiChat(s, { messages: [{ role: 'system', content: input.system }, ...messages], tools });
|
|
111
116
|
messages.push(reply);
|
|
112
117
|
if (!reply.tool_calls?.length)
|
|
@@ -153,6 +158,7 @@ export async function runTurn(s, conv, input) {
|
|
|
153
158
|
// forward step by step.
|
|
154
159
|
const system = [{ type: 'text', text: input.system, cache_control: { type: 'ephemeral' } }];
|
|
155
160
|
for (let step = 0; step < maxSteps; step++) {
|
|
161
|
+
stopped();
|
|
156
162
|
const message = await claude(s, {
|
|
157
163
|
max_tokens: 16000,
|
|
158
164
|
output_config: { effort: 'medium' },
|
|
@@ -278,7 +284,7 @@ async function openaiChat(s, body) {
|
|
|
278
284
|
return { role: 'assistant', content: message.content ?? null, tool_calls: message.tool_calls };
|
|
279
285
|
}
|
|
280
286
|
// ---------- translation ----------
|
|
281
|
-
const languageName = (code) => {
|
|
287
|
+
export const languageName = (code) => {
|
|
282
288
|
try {
|
|
283
289
|
return `${new Intl.DisplayNames(['en'], { type: 'language' }).of(code) ?? code} (${code})`;
|
|
284
290
|
}
|
|
@@ -290,8 +296,10 @@ const languageName = (code) => {
|
|
|
290
296
|
* Translates a page's texts in batches, keeping their order: each batch goes out as a JSON list
|
|
291
297
|
* and must come back as a list of the same length. Marks like <b>, <i> and <a1> stay in place.
|
|
292
298
|
*/
|
|
293
|
-
export async function translateTexts(s, texts, from, to, onProgress
|
|
294
|
-
|
|
299
|
+
export async function translateTexts(s, texts, from, to, onProgress,
|
|
300
|
+
/** The brand voice (voicePrompt), kept in the other language. */
|
|
301
|
+
voice = '') {
|
|
302
|
+
const system = `${voice ? `${voice}\nKeep this voice in ${languageName(to)}: its tone and form of address, with words natural in that language.\n\n` : ''}You translate the texts of a website from ${languageName(from)} to ${languageName(to)}. You receive a JSON array of strings and reply with a JSON array of their translations: same length, same order, nothing else (no code fences, no notes). Keep the tags <b>, </b>, <i>, </i>, <a1>, </a1> and so on around the matching words, keep line breaks, numbers, brand names, e-mail addresses and URLs. Write naturally for native readers, as a professional copywriter would, with the same tone and roughly the same length.`;
|
|
295
303
|
const out = [];
|
|
296
304
|
const BATCH = 60;
|
|
297
305
|
for (let start = 0; start < texts.length; start += BATCH) {
|