sagadeck 1.9.0 → 1.11.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/README.md +9 -2
- package/SKILL.md +1 -1
- package/bin/sagadeck.js +1 -1
- package/docs/ANDAMENTO.md +302 -0
- package/docs/REFERENCIA.md +72 -4
- package/package.json +4 -4
- package/src/ai/context.js +7 -2
- package/src/ai/critique.js +8 -1
- package/src/ai/deck-ai.js +36 -12
- package/src/ai/document-visuals.js +6 -2
- package/src/ai/ia-check.js +13 -4
- package/src/ai/ia-config.js +4 -2
- package/src/ai/llm.js +12 -7
- package/src/ai/math-check.js +318 -0
- package/src/ai/quality.js +3 -3
- package/src/ai/units.js +85 -0
- package/src/api-client.js +42 -10
- package/src/build.js +1 -0
- package/src/code-highlight.js +19 -2
- package/src/code-language.js +13 -0
- package/src/fs-retry.js +2 -2
- package/src/lessons.js +72 -11
- package/src/mcp/server.js +1 -1
- package/src/package.js +4 -0
- package/src/runtime/api-core.js +122 -11
- package/src/runtime/api-ui.js +2 -1
- package/src/runtime/base.css +3 -0
- package/src/runtime/skins/aurora-dev.css +39 -0
- package/src/runtime/skins/terminal-pro.css +33 -0
- package/src/runtime/solution.js +131 -0
- package/src/studio/ai-chat-route.js +69 -7
- package/src/studio/conference-routes.js +44 -0
- package/src/studio/conference.js +144 -0
- package/src/studio/developer-starters.js +46 -0
- package/src/studio/generation-report.js +61 -1
- package/src/studio/generation-request.js +80 -0
- package/src/studio/ia-routes.js +1 -1
- package/src/studio/layout-samples.js +1 -1
- package/src/studio/library-routes.js +7 -0
- package/src/studio/public/about.js +68 -0
- package/src/studio/public/ai-settings.js +4 -4
- package/src/studio/public/app.js +14 -2
- package/src/studio/public/chat.js +11 -3
- package/src/studio/public/conference-ui.js +91 -0
- package/src/studio/public/developer-authoring.css +12 -0
- package/src/studio/public/developer-authoring.js +306 -0
- package/src/studio/public/generation-guide.js +42 -0
- package/src/studio/public/index.html +21 -0
- package/src/studio/public/library.css +36 -0
- package/src/studio/public/library.html +4 -1
- package/src/studio/public/library.js +118 -28
- package/src/studio/public/slide-form.js +17 -17
- package/src/studio/public/style.css +25 -0
- package/src/studio/public/ui-icons.js +1 -1
- package/src/studio/server.js +20 -8
- package/src/themes.js +48 -0
package/src/studio/server.js
CHANGED
|
@@ -37,8 +37,9 @@ import { openLibrary, defaultLibraryRoot, safeName } from "../library.js";
|
|
|
37
37
|
import { ApiEnvironments, defaultEnvFile, readRecordings, writeRecording, mimeOf } from "../api-client.js";
|
|
38
38
|
import { startMockApi, demoEnv, DEMO_FILES } from "../api-demo.js";
|
|
39
39
|
import { slideSnapshots, diagramCheck } from "./snapshot.js";
|
|
40
|
-
import { saveGenReport } from './generation-report.js';
|
|
40
|
+
import { saveGenReport, generationNotice } from './generation-report.js';
|
|
41
41
|
import { generateForStudio } from "./generate.js";
|
|
42
|
+
import { saveGenerationRequest } from "./generation-request.js";
|
|
42
43
|
import { runCommand, logCommand } from "../ai/commands.js";
|
|
43
44
|
import { needsApproval, approvalLabel, awaitApproval, commandEnv, estimateSubmitCost } from "./command-approval.js";
|
|
44
45
|
import { demoDeck, demoAssets, demoProjectFiles } from "./demo-decks.js";
|
|
@@ -51,6 +52,7 @@ import { styleRoutes, styleAction } from "./style-routes.js";
|
|
|
51
52
|
import { shareRoutes } from "./share-routes.js";
|
|
52
53
|
import { apiRoutes } from "./api-routes.js";
|
|
53
54
|
import { aiChatRoutes } from "./ai-chat-route.js";
|
|
55
|
+
import { conferenceRoutes } from "./conference-routes.js";
|
|
54
56
|
import { libraryRoutes } from "./library-routes.js";
|
|
55
57
|
export { lightVariant };
|
|
56
58
|
import { VERSION, buildInfo } from "./instance.js";
|
|
@@ -320,16 +322,19 @@ export function createStudioServer(deckPath = null, opts = {}) {
|
|
|
320
322
|
// Gerar com IA (editor ou biblioteca): a IA trabalha numa pasta oculta do tópico (invisível na biblioteca)
|
|
321
323
|
// e a apresentação só aparece quando pronta, publicada com o título final. Falhou ou a IA perguntou algo:
|
|
322
324
|
// a pasta vai para a lixeira (recuperável). Minutos, estilo, anexos.
|
|
323
|
-
async function generateIntoLibrary(W, topic, b, emit) {
|
|
325
|
+
async function generateIntoLibrary(W, topic, b, emit, origin = "biblioteca") {
|
|
324
326
|
const L = W.library;
|
|
325
327
|
const { dir, file } = L.createStagingDeck(topic);
|
|
326
328
|
try {
|
|
327
|
-
const
|
|
329
|
+
const materials = takeMaterials(W, b.materials);
|
|
330
|
+
const gen = await generateForStudio(b, { dir, materials, emit });
|
|
328
331
|
if (gen.question) { L.discardStaging(topic, dir); return { question: gen.question }; } // a IA quer saber para que serve o material
|
|
329
332
|
// estilo padrão da biblioteca (Brand Kit), se a pessoa não escolheu um tema para esta
|
|
330
333
|
if (!b.theme) gen.spec = L.withDefaultStyle(gen.spec, dir);
|
|
331
334
|
fs.writeFileSync(file, toYaml(gen.spec), "utf8");
|
|
332
335
|
saveGenReport(dir, gen);
|
|
336
|
+
// o pedido que originou a apresentação, para auditar depois (.sagadeck/geracao.json)
|
|
337
|
+
try { saveGenerationRequest(dir, { origem: origin, pedido: b, materials, spec: gen.spec, research: gen.research }); } catch { /* o registro não derruba a criação */ }
|
|
333
338
|
const finalId = L.publishStagedDeck(topic, dir, gen.spec.title || "Nova apresentação");
|
|
334
339
|
return { id: finalId, file: L.resolveId(finalId), images: gen.images, research: gen.research, quality: gen.quality, variety: gen.variety };
|
|
335
340
|
} catch (e) {
|
|
@@ -464,7 +469,7 @@ export function createStudioServer(deckPath = null, opts = {}) {
|
|
|
464
469
|
res.end(html);
|
|
465
470
|
return;
|
|
466
471
|
}
|
|
467
|
-
if (["/style.css", "/library.css", "/studio-next.css"].includes(pathname)) {
|
|
472
|
+
if (["/style.css", "/library.css", "/studio-next.css", "/developer-authoring.css"].includes(pathname)) {
|
|
468
473
|
const css = fs.readFileSync(path.join(PUBLIC_DIR, pathname.slice(1)), "utf8");
|
|
469
474
|
res.writeHead(200, { "Content-Type": "text/css; charset=utf-8" });
|
|
470
475
|
res.end(css);
|
|
@@ -496,7 +501,7 @@ export function createStudioServer(deckPath = null, opts = {}) {
|
|
|
496
501
|
res.end(fs.readFileSync(path.join(RUNTIME_DIR, ["/map.js", "/map-background.js"].includes(pathname) ? pathname.slice(1) : `vendor${pathname}`)));
|
|
497
502
|
return;
|
|
498
503
|
}
|
|
499
|
-
if (["/science.js", "/formula.js", "/calc.js", "/plotly.min.js"].includes(pathname)) {
|
|
504
|
+
if (["/science.js", "/formula.js", "/calc.js", "/solution.js", "/plotly.min.js"].includes(pathname)) {
|
|
500
505
|
res.writeHead(200, {"Content-Type":"application/javascript; charset=utf-8"});
|
|
501
506
|
res.end(fs.readFileSync(path.join(RUNTIME_DIR, pathname === "/plotly.min.js" ? "vendor/plotly.min.js" : pathname.slice(1))));
|
|
502
507
|
return;
|
|
@@ -590,7 +595,7 @@ export function createStudioServer(deckPath = null, opts = {}) {
|
|
|
590
595
|
// quem é esta instância (o CLI confere antes de abrir outra na mesma porta)
|
|
591
596
|
if (pathname === "/api/instance" && req.method === "GET") {
|
|
592
597
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
593
|
-
res.end(JSON.stringify({ app: "sagadeck-studio", ...BUILD, library: libraryRoot, started: STARTED, multiuser: !!opts.multiuser }));
|
|
598
|
+
res.end(JSON.stringify({ app: "sagadeck-studio", ...BUILD, node: process.version, platform: process.platform, library: libraryRoot, started: STARTED, multiuser: !!opts.multiuser }));
|
|
594
599
|
return;
|
|
595
600
|
}
|
|
596
601
|
if (pathname === "/api/deck" && req.method === "GET") {
|
|
@@ -707,6 +712,7 @@ export function createStudioServer(deckPath = null, opts = {}) {
|
|
|
707
712
|
if (await versionRoutes({req,res,pathname,W,readJSON})) return;
|
|
708
713
|
if (await meetingRoutes({req,res,pathname,W,readJSON,persist})) return;
|
|
709
714
|
if (await styleRoutes({ req, res, pathname, W, persist, readJSON })) return;
|
|
715
|
+
if (await conferenceRoutes({ req, res, pathname, W, readJSON, isBundledTemplate })) return;
|
|
710
716
|
if (await shares.api({ req, res, pathname, W, readJSON })) return;
|
|
711
717
|
if (pathname === "/api/aspect" && req.method === "POST") {
|
|
712
718
|
const b = await readJSON(req);
|
|
@@ -954,7 +960,7 @@ export function createStudioServer(deckPath = null, opts = {}) {
|
|
|
954
960
|
}
|
|
955
961
|
// O deck novo vai para uma pasta própria na biblioteca (regra do CLAUDE.md), no tópico do deck aberto
|
|
956
962
|
await respond(res, body.stream, async (emit) => {
|
|
957
|
-
const r = await generateIntoLibrary(W, topicOfOpen(W), body, emit);
|
|
963
|
+
const r = await generateIntoLibrary(W, topicOfOpen(W), body, emit, "editor");
|
|
958
964
|
if (r.question) return { ok: true, question: r.question }; // a IA perguntou para que serve o material
|
|
959
965
|
W.file = r.file;
|
|
960
966
|
W.spec = loadSpec(r.file);
|
|
@@ -1064,8 +1070,14 @@ Responda só com JSON: {"colunas": [{"nome": "…", "tipo": "tempo|categoria|num
|
|
|
1064
1070
|
if (req.method === "GET") {
|
|
1065
1071
|
let history = W.chatHistory || [];
|
|
1066
1072
|
if (file) try { history = JSON.parse(fs.readFileSync(file, "utf8")).history || []; } catch { history = []; }
|
|
1073
|
+
// avisos que a criação com IA deixou sem resolver: viram mensagem do chat na primeira abertura
|
|
1074
|
+
const notice = file ? generationNotice(path.dirname(W.file)) : null;
|
|
1075
|
+
if (notice) {
|
|
1076
|
+
history = [...history, { role: "assistant", text: notice, talk: true }];
|
|
1077
|
+
try { const tmp = `${file}.tmp-${process.pid}`; fs.mkdirSync(path.dirname(file), { recursive: true }); fs.writeFileSync(tmp, JSON.stringify({ history }, null, 1)); renameRetry(tmp, file); } catch (e) { console.error("[Studio] conversa:", e.message); }
|
|
1078
|
+
}
|
|
1067
1079
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1068
|
-
res.end(JSON.stringify({ history }));
|
|
1080
|
+
res.end(JSON.stringify({ history, notice: !!notice }));
|
|
1069
1081
|
return;
|
|
1070
1082
|
}
|
|
1071
1083
|
if (req.method === "POST") {
|
package/src/themes.js
CHANGED
|
@@ -25,6 +25,16 @@ const MUSGO_FACES = {
|
|
|
25
25
|
quote: { css: "font-family: 'Fraunces', Georgia, serif; font-style: italic; font-weight: 400; letter-spacing: -0.01em; line-height: 1.14;", pptx: { face: "Georgia", italic: true } },
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
+
// Desenvolvimento: fontes já embutidas, com corpo de leitura e código sem ligaduras que mudem a pontuação.
|
|
29
|
+
const DEV_FACES = {
|
|
30
|
+
display: { css: "font-family: 'Space Grotesk', 'Segoe UI', sans-serif; font-weight: 700; letter-spacing: -0.045em; line-height: 1.02;", pptx: { face: "Segoe UI", bold: true } },
|
|
31
|
+
heading: { css: "font-family: 'Space Grotesk', 'Segoe UI', sans-serif; font-weight: 600; letter-spacing: -0.025em; line-height: 1.1;", pptx: { face: "Segoe UI Semibold" } },
|
|
32
|
+
body: { css: "font-family: 'Space Grotesk', 'Segoe UI', sans-serif; font-weight: 400; line-height: 1.45;", pptx: { face: "Segoe UI" }, pptxBold: { face: "Segoe UI Semibold" } },
|
|
33
|
+
label: { css: `font-family: 'IBM Plex Mono', ${SYS_MONO}; font-weight: 500; letter-spacing: 0.1em; text-transform: uppercase; line-height: 1.25;`, pptx: { face: "Cascadia Mono" } },
|
|
34
|
+
mono: { css: `font-family: 'IBM Plex Mono', ${SYS_MONO}; font-weight: 400; font-variant-ligatures: none; line-height: 1.5;`, pptx: { face: "Cascadia Mono" }, pptxBold: { face: "Cascadia Mono SemiBold" } },
|
|
35
|
+
quote: { css: "font-family: 'Space Grotesk', 'Segoe UI', sans-serif; font-weight: 400; letter-spacing: -0.02em; line-height: 1.2;", pptx: { face: "Segoe UI" } },
|
|
36
|
+
};
|
|
37
|
+
|
|
28
38
|
export const THEMES = {
|
|
29
39
|
sinal: {
|
|
30
40
|
label: "Sinal — sinalização/segurança: DIN condensada, amarelo de aviso, pictogramas",
|
|
@@ -153,6 +163,44 @@ export const THEMES = {
|
|
|
153
163
|
radius: 6, deco: "grid",
|
|
154
164
|
},
|
|
155
165
|
|
|
166
|
+
"terminal-pro": {
|
|
167
|
+
label: "Terminal Pro — programação e APIs: grafite, verde menta, janelas de código e rede viva discreta",
|
|
168
|
+
dark: true,
|
|
169
|
+
colors: {
|
|
170
|
+
paper: "0B1118", ink: "EAF5F1", accent: "74E8B4", alert: "FF9C97",
|
|
171
|
+
muted: "A4B8B4", line: "2B4145", surface: "131E28", surfaceDark: "0D1720",
|
|
172
|
+
c1: "74E8B4", c2: "83CCF8", c3: "FFCB8A", c4: "CEB4FF", c5: "FF9C97",
|
|
173
|
+
},
|
|
174
|
+
tones: {
|
|
175
|
+
light: { bg: "paper", fg: "ink", muted: "muted", line: "line", surface: "surface", hi: "accent", em: "accent", onHi: "0B1118" },
|
|
176
|
+
dark: { bg: "070D13", fg: "ink", muted: "muted", line: "line", surface: "surfaceDark", hi: "accent", em: "accent", onHi: "0B1118" },
|
|
177
|
+
accent: { bg: "0D211D", fg: "ink", muted: "B2C8BF", line: "31534A", surface: "152F28", hi: "accent", em: "accent", onHi: "0B1118" },
|
|
178
|
+
alert: { bg: "27151B", fg: "FFF0EC", muted: "DDB9BD", line: "65404A", surface: "382029", hi: "alert", em: "alert", onHi: "0B1118" },
|
|
179
|
+
},
|
|
180
|
+
fontFaces: [],
|
|
181
|
+
faces: DEV_FACES,
|
|
182
|
+
radius: 12, deco: "none", coverAmbient: "rede",
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
"aurora-dev": {
|
|
186
|
+
label: "Aurora Dev — desenvolvimento criativo: azul noite, lilás e ciano, painéis luminosos e rede viva",
|
|
187
|
+
dark: true,
|
|
188
|
+
colors: {
|
|
189
|
+
paper: "101329", ink: "F1F2FF", accent: "C4ADFF", alert: "FFADCA",
|
|
190
|
+
muted: "B5BBD9", line: "394266", surface: "1B2240", surfaceDark: "151B35",
|
|
191
|
+
c1: "C4ADFF", c2: "83E7EF", c3: "FFADCA", c4: "A9C8FF", c5: "FFDCA2",
|
|
192
|
+
},
|
|
193
|
+
tones: {
|
|
194
|
+
light: { bg: "paper", fg: "ink", muted: "muted", line: "line", surface: "surface", hi: "accent", em: "83E7EF", onHi: "101329" },
|
|
195
|
+
dark: { bg: "090D20", fg: "ink", muted: "muted", line: "line", surface: "surfaceDark", hi: "accent", em: "83E7EF", onHi: "101329" },
|
|
196
|
+
accent: { bg: "211737", fg: "ink", muted: "CCC0E5", line: "594572", surface: "302349", hi: "accent", em: "83E7EF", onHi: "101329" },
|
|
197
|
+
alert: { bg: "301A32", fg: "FFF1F8", muted: "DEC0D4", line: "684C65", surface: "43273F", hi: "alert", em: "alert", onHi: "101329" },
|
|
198
|
+
},
|
|
199
|
+
fontFaces: [],
|
|
200
|
+
faces: DEV_FACES,
|
|
201
|
+
radius: 24, deco: "none", coverAmbient: "rede",
|
|
202
|
+
},
|
|
203
|
+
|
|
156
204
|
jornal: {
|
|
157
205
|
label: "Jornal — manchete: Franklin Gothic pesada, papel-jornal, azul-tinta",
|
|
158
206
|
colors: {
|