@aksp/opencrew 1.8.0 → 1.10.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 +127 -0
- package/README.md +133 -16
- package/package.json +1 -1
- package/src/commands/update.js +9 -3
- package/src/lib/blocos.js +7 -3
- package/src/lib/resumo.js +3 -0
- package/templates/AGENTS.md +11 -2
- package/templates/_opencrew/.opencrew-version +1 -1
- package/templates/_opencrew/core/best-practices/_catalog.yaml +5 -0
- package/templates/_opencrew/core/best-practices/documento-oficial.md +144 -0
- package/templates/_opencrew/core/modelos/documento-oficial.md +42 -0
- package/templates/_opencrew/core/prompts/design.prompt.md +1 -0
- package/templates/_opencrew/core/prompts/discovery.prompt.md +1 -1
- package/templates/_opencrew/core/prompts/documento.prompt.md +134 -0
- package/templates/_opencrew/core/prompts/entrega.prompt.md +93 -18
- package/templates/_opencrew/core/prompts/export.prompt.md +5 -81
- package/templates/_opencrew/core/runner.pipeline.md +20 -20
- package/templates/_opencrew/core/scripts/documento/argumentos.mjs +50 -0
- package/templates/_opencrew/core/scripts/documento/corpo.mjs +51 -0
- package/templates/_opencrew/core/scripts/documento/estilos.mjs +42 -0
- package/templates/_opencrew/core/scripts/documento/gravar.mjs +44 -0
- package/templates/_opencrew/core/scripts/documento/linha.mjs +58 -0
- package/templates/_opencrew/core/scripts/documento/marcacoes.mjs +55 -0
- package/templates/_opencrew/core/scripts/documento/markdown.mjs +92 -0
- package/templates/_opencrew/core/scripts/documento/pacote.mjs +82 -0
- package/templates/_opencrew/core/scripts/documento/perfil.mjs +70 -0
- package/templates/_opencrew/core/scripts/documento/png.mjs +20 -0
- package/templates/_opencrew/core/scripts/documento/projeto.mjs +60 -0
- package/templates/_opencrew/core/scripts/documento/tabelas.mjs +57 -0
- package/templates/_opencrew/core/scripts/documento/timbre.mjs +64 -0
- package/templates/_opencrew/core/scripts/documento/xml.mjs +95 -0
- package/templates/_opencrew/core/scripts/documento/zip.mjs +86 -0
- package/templates/_opencrew/core/scripts/documento.mjs +150 -0
- package/templates/_opencrew/core/scripts/entrega/argumentos.mjs +13 -9
- package/templates/_opencrew/core/scripts/entrega/canais.mjs +12 -6
- package/templates/_opencrew/core/scripts/entrega/comparar.mjs +104 -0
- package/templates/_opencrew/core/scripts/entrega/copia.mjs +138 -0
- package/templates/_opencrew/core/scripts/entrega/destino.mjs +98 -0
- package/templates/_opencrew/core/scripts/entrega/documentos.mjs +104 -0
- package/templates/_opencrew/core/scripts/entrega/fora.mjs +4 -3
- package/templates/_opencrew/core/scripts/entrega/gravar.mjs +3 -3
- package/templates/_opencrew/core/scripts/entrega/guardar.mjs +60 -0
- package/templates/_opencrew/core/scripts/entrega/leiame.mjs +54 -17
- package/templates/_opencrew/core/scripts/entrega/leitor.mjs +16 -3
- package/templates/_opencrew/core/scripts/entrega/lembrar.mjs +65 -0
- package/templates/_opencrew/core/scripts/entrega/passos.mjs +21 -6
- package/templates/_opencrew/core/scripts/entrega/pendencias.mjs +16 -6
- package/templates/_opencrew/core/scripts/entrega/ressalvas.mjs +78 -0
- package/templates/_opencrew/core/scripts/entrega/resumo.mjs +29 -0
- package/templates/_opencrew/core/scripts/entrega/retrato.mjs +42 -0
- package/templates/_opencrew/core/scripts/entrega/separar.mjs +9 -3
- package/templates/_opencrew/core/scripts/entregar.mjs +76 -44
- package/templates/_opencrew/core/scripts/verificar/argumentos.mjs +4 -4
- package/templates/_opencrew/core/scripts/verificar/entradas.mjs +26 -0
- package/templates/_opencrew/core/scripts/verificar/gravacao.mjs +41 -0
- package/templates/_opencrew/core/scripts/verificar/relatorio.mjs +10 -3
- package/templates/_opencrew/core/scripts/verificar.mjs +17 -27
- package/templates/gitignore +1 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "Documento oficial"
|
|
3
|
+
platform: "documento"
|
|
4
|
+
content_type: "official-document"
|
|
5
|
+
description: "Text that becomes a Word document to print, sign or file: minutes, official letters, statements, contracts and reports, written so the conversion keeps every word"
|
|
6
|
+
whenToUse: |
|
|
7
|
+
Creating agents that produce a document to print, sign or file — minutes (ata), official letter (ofício), statement, contract, formal report — which the project turns into a Word file (.docx).
|
|
8
|
+
version: "1.0.0"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Compact Rules
|
|
12
|
+
|
|
13
|
+
1. One paragraph per line. Never break a paragraph in the middle: each line of the file becomes one paragraph of the document, and lines that follow each other are not joined.
|
|
14
|
+
2. Start with `::: titulo` and, when there is one, `::: subtitulo`, as the first lines of the text (one line each).
|
|
15
|
+
3. Use `#`, `##` and `###` for the sections, and no deeper level.
|
|
16
|
+
4. Write every number by hand — "I.", "1.", "6.1.", "a)", "§ 1º" — in sections and in items. Nothing is numbered automatically: the number you write is the official text.
|
|
17
|
+
5. Use a simple table (header line, separator line, rows) for figures and lists of names. No merged cells, no table inside a table.
|
|
18
|
+
6. Put `::: quebra-de-pagina` alone on a line before each annex (anexo), so the annex starts on a new page.
|
|
19
|
+
7. Put the `::: assinaturas` block at the end of the document (and at the end of an annex that is signed): one line `Nome | Cargo` per person, closed by a line with only `:::`.
|
|
20
|
+
8. No image, no HTML, no labels such as `=== … ===`, no notes section and no comments to the reader: everything in the file goes to the document.
|
|
21
|
+
9. Write the full, final text. Missing real data is marked `[PREENCHER: o que falta]`; never invent a name, a date, a number or a registration.
|
|
22
|
+
10. Use bold (`**texto**`) and italic (`*texto*`) sparingly; a list of plain items uses `- `.
|
|
23
|
+
|
|
24
|
+
## What the conversion does
|
|
25
|
+
|
|
26
|
+
The project turns this text into a Word file with one script, with the same words and the same
|
|
27
|
+
numbers, in the same order. Knowing what it does tells you how to write:
|
|
28
|
+
|
|
29
|
+
| You write | The document gets |
|
|
30
|
+
|---|---|
|
|
31
|
+
| `::: titulo Texto` · `::: subtitulo Texto` | A centered title · a centered subtitle, in italic. Valid anywhere, as many times as needed (an annex has its own) |
|
|
32
|
+
| `# Texto` · `## Texto` · `### Texto` | Section headings of level 1 (shown in capitals), 2 and 3 |
|
|
33
|
+
| A line of text | One justified paragraph |
|
|
34
|
+
| A line that starts with a number or a letter of item (`1.`, `a)`) | A common paragraph, with the number as you wrote it; two spaces at the start of the line indent it |
|
|
35
|
+
| `- item` | A bulleted item (two spaces before it: second level) |
|
|
36
|
+
| A table | A table with equal columns and the first line in bold |
|
|
37
|
+
| `---` alone on a line | A horizontal line |
|
|
38
|
+
| `::: quebra-de-pagina` | The next block starts on a new page |
|
|
39
|
+
| `::: assinaturas` … `:::` | Signature lines, two per row, with the name above the role |
|
|
40
|
+
| `[texto](https://endereco)` | `texto (https://endereco)`, as plain text |
|
|
41
|
+
|
|
42
|
+
The header with the logo, the footer with "Página X de Y", the margins and the font come from
|
|
43
|
+
the profile of the project, not from the text: never write a header, a footer or a page number.
|
|
44
|
+
|
|
45
|
+
## The three markings
|
|
46
|
+
|
|
47
|
+
A marking is a line that starts with `:::` in the first column.
|
|
48
|
+
|
|
49
|
+
- **Title and subtitle** — `::: titulo ATA DA REUNIÃO` and `::: subtitulo Realizada em 5 de maio de 2026`. One line each. They are not sections: the sections are the `#` lines.
|
|
50
|
+
- **Page break** — `::: quebra-de-pagina`, alone on the line, with nothing after it.
|
|
51
|
+
- **Signatures** — open with `::: assinaturas`, write one person per line as `Nome | Cargo` (the role is optional) and close with `:::`. Inside the block nothing else is read: bold and italic signs would be printed as typed. The order you write is the order on the page, left to right and top to bottom.
|
|
52
|
+
|
|
53
|
+
Any other word after `:::` is not a marking: the line goes to the document as text, and the
|
|
54
|
+
conversion warns about it. A signature block without the closing `:::` also stays as text.
|
|
55
|
+
|
|
56
|
+
## What does not go in the text
|
|
57
|
+
|
|
58
|
+
- **Images** (``) — the document carries no image in the body; the line would stay as text. The logo belongs to the profile of the project.
|
|
59
|
+
- **HTML** (`<br>`, `<center>`, `<table>`) and HTML comments — they would be printed as they are.
|
|
60
|
+
- **Labels and service blocks** (`=== TÍTULO ===`, `NOTES:`, checklists for the writer) — they are not removed.
|
|
61
|
+
- **A notes section** ("Notas", "Observações do redator", "Fontes consultadas" that are not part of the document) — say it to the user in the conversation, not in the file.
|
|
62
|
+
- **Frontmatter is the only exception**: a `---` block of `chave: valor` lines at the very top stays out of the document.
|
|
63
|
+
|
|
64
|
+
## Structure of a document
|
|
65
|
+
|
|
66
|
+
1. **Title and subtitle** — what the document is; when and where, in the subtitle.
|
|
67
|
+
2. **Opening** — who, when, where, under which rule or call.
|
|
68
|
+
3. **Body in numbered sections** — one subject per section, in the order of the agenda or of the request. Decisions are written as decisions ("Aprovado por unanimidade."), with the numbers that support them.
|
|
69
|
+
4. **Closing** — what happens next, and who wrote the document.
|
|
70
|
+
5. **Signatures** — everyone who signs, with the role.
|
|
71
|
+
6. **Annexes** — each one after a page break, with its own title.
|
|
72
|
+
|
|
73
|
+
## Output Example
|
|
74
|
+
|
|
75
|
+
```markdown
|
|
76
|
+
::: titulo ATA DA REUNIÃO DA DIRETORIA
|
|
77
|
+
::: subtitulo Realizada em 5 de maio de 2026, na sede da Associação Exemplo de Moradores
|
|
78
|
+
|
|
79
|
+
# I. Abertura
|
|
80
|
+
Aos 5 dias do mês de maio de 2026, às 19h, reuniu-se a diretoria da Associação Exemplo de Moradores, na Rua das Acácias, 100, com a presença dos três diretores.
|
|
81
|
+
A presidente, Ana Lima, abriu a reunião e convidou Rui Sá para secretariar os trabalhos.
|
|
82
|
+
|
|
83
|
+
# II. Ordem do dia
|
|
84
|
+
A presidente leu a ordem do dia:
|
|
85
|
+
1. Reforma do salão de festas;
|
|
86
|
+
2. Calendário de eventos do segundo semestre.
|
|
87
|
+
|
|
88
|
+
# III. Reforma do salão de festas
|
|
89
|
+
## 3.1. Orçamentos recebidos
|
|
90
|
+
A tesoureira, Bia Reis, apresentou os três orçamentos recebidos:
|
|
91
|
+
|
|
92
|
+
| Empresa | Prazo | Valor |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| Construtora Exemplo | 30 dias | R$ 18.400,00 |
|
|
95
|
+
| Reformas Modelo | 45 dias | R$ 16.900,00 |
|
|
96
|
+
| Obras Amostra | 25 dias | R$ 21.000,00 |
|
|
97
|
+
|
|
98
|
+
## 3.2. Deliberação
|
|
99
|
+
Por unanimidade, a diretoria aprovou o orçamento da **Reformas Modelo**, com as seguintes condições:
|
|
100
|
+
- pagamento em três parcelas iguais;
|
|
101
|
+
- início da obra depois da festa junina.
|
|
102
|
+
|
|
103
|
+
# IV. Calendário de eventos
|
|
104
|
+
Ficou aprovado o calendário do segundo semestre, que segue no Anexo I.
|
|
105
|
+
|
|
106
|
+
# V. Encerramento
|
|
107
|
+
Nada mais havendo a tratar, a presidente encerrou a reunião às 20h15. Eu, Rui Sá, secretário, lavrei esta ata, que vai assinada por todos.
|
|
108
|
+
|
|
109
|
+
::: assinaturas
|
|
110
|
+
Ana Lima | Presidente
|
|
111
|
+
Rui Sá | Secretário
|
|
112
|
+
Bia Reis | Tesoureira
|
|
113
|
+
:::
|
|
114
|
+
|
|
115
|
+
::: quebra-de-pagina
|
|
116
|
+
::: titulo ANEXO I — CALENDÁRIO DE EVENTOS
|
|
117
|
+
::: subtitulo Segundo semestre de 2026
|
|
118
|
+
|
|
119
|
+
| Data | Evento | Responsável |
|
|
120
|
+
|---|---|---|
|
|
121
|
+
| 12 de julho | Festa julina | Bia Reis |
|
|
122
|
+
| 20 de setembro | Mutirão de limpeza | Rui Sá |
|
|
123
|
+
| 6 de dezembro | Confraternização | Ana Lima |
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Anti-Patterns
|
|
127
|
+
|
|
128
|
+
- A paragraph broken into several lines "to fit the screen": it becomes several paragraphs.
|
|
129
|
+
- `1.` typed for every item, counting on automatic numbering: the document shows exactly what is typed.
|
|
130
|
+
- The title of the document as `# Título`: it becomes a section heading, not the centered title.
|
|
131
|
+
- A signature drawn with underscores (`______`): use the `::: assinaturas` block.
|
|
132
|
+
- "Página 1 de 3", the name of the organization or the date of printing written in the text: the header and the footer come from the profile.
|
|
133
|
+
- A closing note such as "Posso ajustar o que precisar": it would be printed in the document.
|
|
134
|
+
|
|
135
|
+
## Quality Criteria
|
|
136
|
+
|
|
137
|
+
- [ ] Each paragraph is on one line; no line is a continuation of the previous one
|
|
138
|
+
- [ ] `::: titulo` is the first line of the text (after the frontmatter, if there is one)
|
|
139
|
+
- [ ] Every section and item number is written by hand, in sequence, with no gap
|
|
140
|
+
- [ ] Every table has a header line and a separator line, and the same number of columns in each row
|
|
141
|
+
- [ ] Each annex comes after `::: quebra-de-pagina` and has its own `::: titulo`
|
|
142
|
+
- [ ] The `::: assinaturas` block is closed by `:::` and lists everyone who signs
|
|
143
|
+
- [ ] No image, HTML, label, notes section or message to the reader
|
|
144
|
+
- [ ] No invented data: what is missing is `[PREENCHER: …]`
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Perfil de documento oficial
|
|
2
|
+
|
|
3
|
+
Este arquivo guarda o papel timbrado do projeto: o logotipo, o cabeçalho, o rodapé, as margens e
|
|
4
|
+
a letra dos documentos Word. Preencha depois dos dois-pontos; o que ficar vazio não aparece no
|
|
5
|
+
documento. Só as linhas `chave: valor` são lidas: o resto é comentário.
|
|
6
|
+
|
|
7
|
+
Para gerar um documento: node _opencrew/core/scripts/documento.mjs "caminho/do/texto.md"
|
|
8
|
+
|
|
9
|
+
## Cabeçalho
|
|
10
|
+
|
|
11
|
+
# Logotipo: arquivo PNG de até 2 MB, com o caminho a partir da pasta do projeto (exemplo: Ativos/Marca/logo.png).
|
|
12
|
+
logotipo:
|
|
13
|
+
# Largura do logotipo no papel, em centímetros (de 1 a 6); a altura acompanha a proporção da imagem.
|
|
14
|
+
logotipo_largura_cm: 2,5
|
|
15
|
+
# Primeira linha do cabeçalho, em negrito: o nome da organização (exemplo: ASSOCIAÇÃO EXEMPLO DE MORADORES).
|
|
16
|
+
cabecalho_1:
|
|
17
|
+
# Segunda linha do cabeçalho (exemplo: CNPJ 00.000.000/0001-00 · Fundada em 1990).
|
|
18
|
+
cabecalho_2:
|
|
19
|
+
# Terceira linha do cabeçalho, em cinza (exemplo: www.exemplo.org · contato@exemplo.org).
|
|
20
|
+
cabecalho_3:
|
|
21
|
+
|
|
22
|
+
## Rodapé
|
|
23
|
+
|
|
24
|
+
# Texto do rodapé, à esquerda, em todas as páginas (exemplo: Associação Exemplo de Moradores — documento oficial).
|
|
25
|
+
rodape:
|
|
26
|
+
# "Página X de Y" à direita do rodapé: sim ou nao.
|
|
27
|
+
numero_pagina: sim
|
|
28
|
+
|
|
29
|
+
## Página e letra
|
|
30
|
+
|
|
31
|
+
# Margem esquerda, em centímetros (de 1 a 6).
|
|
32
|
+
margem_esquerda_cm: 3,0
|
|
33
|
+
# Margem direita, em centímetros (de 1 a 6).
|
|
34
|
+
margem_direita_cm: 2,0
|
|
35
|
+
# Margem superior, em centímetros (de 1 a 6).
|
|
36
|
+
margem_superior_cm: 2,5
|
|
37
|
+
# Margem inferior, em centímetros (de 1 a 6).
|
|
38
|
+
margem_inferior_cm: 2,5
|
|
39
|
+
# Fonte do texto: o nome como aparece no Word (até 40 letras, dígitos e espaços).
|
|
40
|
+
fonte: Arial
|
|
41
|
+
# Tamanho da letra do texto, em pontos (de 8 a 14; aceita meio ponto, como 10,5).
|
|
42
|
+
tamanho_corpo_pt: 11
|
|
@@ -444,6 +444,7 @@ The name should make someone smile — it's a pun tying a common name to the pro
|
|
|
444
444
|
- Always include reviewer agent before final output
|
|
445
445
|
- Add checkpoints at every user decision point
|
|
446
446
|
- Include `on_reject` loops from reviewer back to writer
|
|
447
|
+
- A step whose result is a document to print, sign or file (minutes, official letter, statement, contract, formal report) gets `format: documento-oficial`, in any kind of crew: the writer follows that guide, and the text becomes a Word document in the delivery of the run (or with `/opencrew documento <arquivo>`)
|
|
447
448
|
|
|
448
449
|
### Research Focus Checkpoint (MANDATORY for crews with a researcher)
|
|
449
450
|
|
|
@@ -112,7 +112,7 @@ Based on the detected domain, ask the most relevant contextual question first. W
|
|
|
112
112
|
**If domain = `analysis`:**
|
|
113
113
|
1. Where does the data come from? (open-ended — let the user describe their data sources)
|
|
114
114
|
2. What decisions should this analysis help you make? (open-ended)
|
|
115
|
-
3. What format should the output take? (multiple choice: dashboard /
|
|
115
|
+
3. What format should the output take? (multiple choice: dashboard / written report / spreadsheet / automated alert / other)
|
|
116
116
|
|
|
117
117
|
**If domain = `mixed`:**
|
|
118
118
|
Ask the most pressing question from each relevant domain, starting with the primary one. Cap at 3 questions total in this step.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Documento Word — A Text File Turned into a `.docx`
|
|
2
|
+
|
|
3
|
+
One script turns a text file of the project (markdown, `.md` or `.txt`) into a Word document with
|
|
4
|
+
the same words and the same numbers, in the same order. When the project has a profile
|
|
5
|
+
(`_opencrew/_memory/documento-oficial.md`: logo, header, footer, margins and font), the document
|
|
6
|
+
comes out on letterhead. Your part is to find out which file, ask about the letterhead when the
|
|
7
|
+
project has none, run the script and show its report.
|
|
8
|
+
|
|
9
|
+
You do NOT write the `.docx` yourself, and you never change the user's text to make it convert:
|
|
10
|
+
the script reads the file as it is. The writing rules of a text that becomes a document (title,
|
|
11
|
+
sections, page break, signatures) are in `_opencrew/core/best-practices/documento-oficial.md`.
|
|
12
|
+
|
|
13
|
+
## Step 1: Which file
|
|
14
|
+
|
|
15
|
+
`/opencrew documento <arquivo>` names the file. With no file (the command alone, or the menu
|
|
16
|
+
option "Documento Word"), ask and wait:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
Qual arquivo de texto (.md ou .txt) você quer em Word? Diga o caminho a partir da pasta do projeto (por exemplo, `Atas/ata-de-marco.md`).
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
- `{arquivo}` is a path inside the project, written from its root. One file per command: for
|
|
23
|
+
several files, run Steps 3 to 5 once for each.
|
|
24
|
+
- Never guess the file, and never pick one "that looks like it": with a name that matches more
|
|
25
|
+
than one file, list them and ask.
|
|
26
|
+
|
|
27
|
+
## Step 2: The letterhead, when the project has none
|
|
28
|
+
|
|
29
|
+
Check, with the read tool (no command), whether `_opencrew/_memory/documento-oficial.md` exists.
|
|
30
|
+
If it does, go to Step 3: nothing is asked. If it does not, ask and wait:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
Este projeto ainda não tem papel timbrado configurado. Quer configurar agora (logotipo, cabeçalho e rodapé)? (sim / não)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- **"Sim"** —
|
|
37
|
+
1. Run, from the project root: `node _opencrew/core/scripts/documento.mjs --criar-perfil`
|
|
38
|
+
Its last line is `PERFIL:CRIADO` (the file was created from the model) or `PERFIL:JA-EXISTE`
|
|
39
|
+
(it was already there and was not touched).
|
|
40
|
+
2. Ask the user for: the logo (a PNG file of up to 2 MB that is inside the project, with its
|
|
41
|
+
path from the root — or none), the three lines of the header (the name of the organization;
|
|
42
|
+
a second line; a third line, such as site and e-mail) and the text of the footer. Any of them
|
|
43
|
+
may stay empty: what is empty does not appear in the document.
|
|
44
|
+
3. Fill the file `_opencrew/_memory/documento-oficial.md` with the answers: write only the value
|
|
45
|
+
after the colon of `logotipo`, `cabecalho_1`, `cabecalho_2`, `cabecalho_3` and `rodape`, each
|
|
46
|
+
exactly as the user gave it. Leave every other line as it is (comments, margins, font).
|
|
47
|
+
Never invent a value (a registration number, an address, a slogan), and never copy a logo
|
|
48
|
+
into the project by yourself: if the file is outside the project, ask the user to put it in.
|
|
49
|
+
- **"Não"** — go on without the profile: the document comes out with no letterhead, with the
|
|
50
|
+
standard margins and "Página X de Y" in the footer. Do not ask again in this conversation.
|
|
51
|
+
|
|
52
|
+
After this step the profile belongs to the user. Change it only when the user asks, and only the
|
|
53
|
+
line asked for.
|
|
54
|
+
|
|
55
|
+
## Step 3: Run the script
|
|
56
|
+
|
|
57
|
+
From the project root, one line, the path between double quotes:
|
|
58
|
+
|
|
59
|
+
`node _opencrew/core/scripts/documento.mjs "{arquivo}"`
|
|
60
|
+
|
|
61
|
+
- **`{arquivo}` was typed by the user and goes into a command** — the safe-name rule (nome seguro)
|
|
62
|
+
of `_opencrew/core/runner.pipeline.md` applies: between double quotes and only if it is made of
|
|
63
|
+
letters (accents included), digits, space and `. _ - / \ : ( )`. With any other character do NOT
|
|
64
|
+
run the command; say
|
|
65
|
+
`⚠️ O nome `{arquivo}` tem um caractere que não posso usar em comandos ({caractere}). Use só letras, números, espaço, ponto, hífen, sublinhado e parênteses.`
|
|
66
|
+
and ask for the file again. The same rule holds for every path below.
|
|
67
|
+
- The Word goes next to the text, with the same name (`Atas/ata.md` → `Atas/ata.docx`). Only when
|
|
68
|
+
the user asks for another place, the command ends with `--saida "{pasta ou arquivo.docx}"`
|
|
69
|
+
(inside the project; a folder is created if it is missing).
|
|
70
|
+
- Only when the user asks for a document with no letterhead this time, add `--sem-perfil`; only
|
|
71
|
+
when the user names another profile file, add `--perfil "{arquivo do perfil}"`.
|
|
72
|
+
|
|
73
|
+
The output of the script is the report: where the document was written, which profile was used,
|
|
74
|
+
the conversion warnings ("Avisos:") and two tips — "Para ter um PDF: abra o documento no Word e
|
|
75
|
+
use Arquivo → Salvar como → PDF." and "O Word é uma cópia do texto. O que você mudar nele não
|
|
76
|
+
volta sozinho: altere o texto e gere de novo.". Show it to the user as it came, without the
|
|
77
|
+
`DOCUMENTO:OK` line. It is fixed PT-BR, whatever the user's language: do not rewrite it.
|
|
78
|
+
|
|
79
|
+
- `DOCUMENTO:OK` → done. A warning does not change that: it says what stayed as plain text (an
|
|
80
|
+
image, an unknown `:::` line, a signature block with no closing `:::`) or what was removed (an
|
|
81
|
+
invalid character). Offer to fix the text and generate again; change the text only on a "sim".
|
|
82
|
+
- "{arquivo} já existe e está igual. Nada a fazer." is also `DOCUMENTO:OK`: nothing was written.
|
|
83
|
+
|
|
84
|
+
## Step 4: A Word that is already there
|
|
85
|
+
|
|
86
|
+
When the output is the line "Já existe {arquivo}, diferente do que eu ia gravar. Para trocar, rode
|
|
87
|
+
de novo com --substituir.", nothing was written: there is a different `.docx` at the destination,
|
|
88
|
+
and the user may have edited it in Word. Ask before replacing it, and wait:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
Já existe {arquivo}, diferente do que eu ia gravar. Posso substituir? O que foi mudado direto no Word se perde. (sim / não)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
- "Sim" → the same command again, ending with `--substituir`.
|
|
95
|
+
- "Não" → nothing is replaced. Offer another name or folder (`--saida`, Step 3).
|
|
96
|
+
|
|
97
|
+
The first call never has `--substituir`, and a "sim" is worth for that file and that call only.
|
|
98
|
+
|
|
99
|
+
## Step 5: When the command fails
|
|
100
|
+
|
|
101
|
+
The command failed when there is no Node, an error, or no `DOCUMENTO:` line at the end (it prints
|
|
102
|
+
one message in PT-BR and stops, with nothing written). Show the message to the user as it came.
|
|
103
|
+
|
|
104
|
+
- **The message points to something in the command you wrote** (an option, a path, more than one
|
|
105
|
+
file): fix the command and run it once more.
|
|
106
|
+
- **The message starts with "Perfil, linha {n}:"** (an unknown key, a value out of range, a logo
|
|
107
|
+
that is missing, is not a PNG or is over 2 MB): the document is not generated with a wrong
|
|
108
|
+
letterhead. Show the message, ask the user for the right value of that line, write it in the
|
|
109
|
+
profile and run again. Do not switch to `--sem-perfil` by yourself.
|
|
110
|
+
- **"Não consegui gravar {arquivo}. …"**: the file is open in Word or the folder is syncing. Ask
|
|
111
|
+
the user to close it and run the same command again.
|
|
112
|
+
- **Anything else**, or the command did not run at all:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
⚠️ A conversão para Word não rodou: {motivo}. O texto continua em {arquivo}.
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
`{motivo}` is the message the script printed (without its final period), or what kept it from
|
|
119
|
+
running. Stop there.
|
|
120
|
+
|
|
121
|
+
Never generate the document by any other means: no other script, no library, no Word or office
|
|
122
|
+
automation, no HTML or RTF saved with another extension. A document made another way would not
|
|
123
|
+
have the same guarantees (the same words, the letterhead of the profile), and the user would not
|
|
124
|
+
know.
|
|
125
|
+
|
|
126
|
+
## Rules
|
|
127
|
+
|
|
128
|
+
- **DO** show the report of the script as it came.
|
|
129
|
+
- **DO** ask before `--substituir`, every time.
|
|
130
|
+
- **DO NOT** generate the `.docx` by any other means, even when the script fails.
|
|
131
|
+
- **DO NOT** edit the user's text to remove a warning without a "sim".
|
|
132
|
+
- **DO NOT** write in `_opencrew/_memory/documento-oficial.md` anything the user did not give you.
|
|
133
|
+
- **DO NOT** promise how the document looks in Word: you did not open it. The user checks the
|
|
134
|
+
header, the pages, the tables and the signatures in Word.
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
One script turns the approved files of a run into `crews/{name}/output/{run_id}/entrega/`: one
|
|
4
4
|
folder per channel, text ready to paste and a `LEIA-ME.md` that tells the user what to do with each
|
|
5
|
-
file.
|
|
5
|
+
file. The same script copies what is ready to a folder of the project the user chose, one folder per
|
|
6
|
+
run. Your part is to build the list of files, run the script, act on its last line and ask, once per
|
|
7
|
+
crew, where the copy goes.
|
|
6
8
|
|
|
7
9
|
You do NOT copy, split, rename or rewrite a file yourself, and you never write inside `entrega/`:
|
|
8
10
|
the script rebuilds that folder from scratch on every call. **When** the delivery runs is in the
|
|
@@ -43,8 +45,8 @@ sozinha. Antes de postar à mão, confira se já saiu."
|
|
|
43
45
|
`_opencrew/best-practices.local/{format}.md` when that file declares `platform:`, otherwise in
|
|
44
46
|
`_opencrew/core/best-practices/{format}.md`. For a step with no `format:`, the one of the skill
|
|
45
47
|
(`instagram-publisher` → `instagram`). With neither, do not pass the option.
|
|
46
|
-
- `{canal}` is the folder name: `instagram`, `linkedin`, `blog`, `email`, `whatsapp`, `twitter
|
|
47
|
-
`youtube
|
|
48
|
+
- `{canal}` is the folder name: `instagram`, `linkedin`, `blog`, `email`, `whatsapp`, `twitter`,
|
|
49
|
+
`youtube` or `documentos` (the folder of `platform: "documento"`). Only a channel that has an item in the list (an item whose format has that
|
|
48
50
|
`platform:`) — for any other the script stops with `Canal não encontrado nesta entrega: {canal}.`
|
|
49
51
|
|
|
50
52
|
## Step 3: Run the script
|
|
@@ -59,31 +61,98 @@ With channels from Step 2, the same command ends with one option per channel:
|
|
|
59
61
|
|
|
60
62
|
## Step 4: Show the result and read the last line
|
|
61
63
|
|
|
62
|
-
The output of the script is the final summary of the run (the folder, each channel as "Pronto"
|
|
63
|
-
"Não está pronto", what is missing, the
|
|
64
|
+
The output of the script is the final summary of the run (the folder, each channel as "Pronto",
|
|
65
|
+
"Pronto, com ressalva" or "Não está pronto", what is missing, the line of the copy, the path of
|
|
66
|
+
the `LEIA-ME.md`): show it to the user as it came,
|
|
64
67
|
without the `ENTREGA:` line. Do not rewrite it and do not add files it does not list. Besides the
|
|
65
68
|
`entrega/` folder, the script also writes `crews/{name}/output/{run_id}/verificacao-entrega.md`,
|
|
66
69
|
the report of the check made at delivery time (it is not part of the delivery).
|
|
67
70
|
|
|
68
|
-
- `ENTREGA:OK` → go on with the run.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
- `ENTREGA:OK` → go on with the run (Step 5 first, when it applies). When the summary has a line
|
|
72
|
+
`
|
|
73
|
+
- `ENTREGA:COM_RESSALVA` → everything that was missing is a ressalva the user accepted: the
|
|
74
|
+
`LEIA-ME.md` opens with it and the channel is "Pronto, com ressalva"; go on as with `ENTREGA:OK`.
|
|
75
|
+
- `ENTREGA:INCOMPLETA` → a channel is not ready, the destination was refused or a file could not be
|
|
76
|
+
written. `entrega/` was generated anyway and the `LEIA-ME.md` marks the channel; a channel that
|
|
77
|
+
is not ready is not copied to the project. The channels that are ready were already copied by
|
|
78
|
+
this same call, before the user answers: nothing waits for the answer. Show what is missing and
|
|
79
|
+
ask:
|
|
71
80
|
```
|
|
72
81
|
⚠️ A entrega ficou incompleta: {o que falta}
|
|
73
|
-
1. Corrigir agora (eu ajusto e monto a entrega de novo)
|
|
74
|
-
2.
|
|
82
|
+
1. Corrigir agora (eu ajusto no arquivo de origem, verifico e monto a entrega de novo)
|
|
83
|
+
2. Entregar assim mesmo (fica registrado como ressalva no LEIA-ME)
|
|
84
|
+
3. Deixar para depois (o canal fica como "Não está pronto" e não é copiado)
|
|
75
85
|
```
|
|
76
86
|
Wait for the answer.
|
|
77
|
-
- **1** — for each item that is missing, fix it in the source file the
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
87
|
+
- **1** — for each item that is missing, fix it in the source file the pending item names, never
|
|
88
|
+
inside `entrega/`, and in place — the same file at the same path, no new `vN` folder and no
|
|
89
|
+
copy — so the list does not change: ask the user for the real information of every
|
|
90
|
+
`[PREENCHER: …]`, shorten what is over a limit, write again a file that is not there. Then run
|
|
91
|
+
the checker on that file
|
|
92
|
+
(`node _opencrew/core/scripts/verificar.mjs --crew "crews/{name}" --arquivo "{caminho}={formato}"`)
|
|
93
|
+
and only then run the delivery again, with the same list.
|
|
94
|
+
- **2** — run the same command again, ending with `--aceitar-pendencias`: the script records
|
|
95
|
+
each pending item as a ressalva (in `ressalvas.json`, in the run folder, and at the top of the
|
|
96
|
+
`LEIA-ME.md`), the channel becomes "Pronto, com ressalva" and is copied like the ready ones.
|
|
97
|
+
It does **not** solve a file that does not exist, a refused destination or a file that could
|
|
98
|
+
not be written: for those, see below.
|
|
99
|
+
- **3** — go on: the channel stays "Não está pronto" and is not copied. Every irreversible step
|
|
100
|
+
still asks for its own confirmation, as it does today. Tell the user what is missing and that
|
|
101
|
+
it is enough to ask for the delivery of this run when the data exists.
|
|
102
|
+
- **Destination refused, or a file that could not be written** (the lines "Não copiei: …" and
|
|
103
|
+
"Não consegui gravar …"): show the message as it came and ask for another folder (Step 5, with
|
|
104
|
+
the new answer) or for a new attempt, which is the same command again. A file of the list that
|
|
105
|
+
does not exist: ask for it, or take it out of the list.
|
|
106
|
+
- **A Word document that was not generated** (the line `
|
|
107
|
+
The first call never has `--aceitar-pendencias`. Outside option 2 it goes only when the user
|
|
108
|
+
already chose "Aceitar assim mesmo" in the review loop of this run and what is missing is only
|
|
109
|
+
what was accepted there: then run the command again with it, without asking.
|
|
83
110
|
|
|
84
111
|
After "Edit this content" (the final menu of the runner) changes an approved file, or any step
|
|
85
112
|
runs again after the delivery, run the delivery again with the new paths: the folder is rebuilt
|
|
86
|
-
from scratch, so whatever was edited inside `entrega/` is lost — the `LEIA-ME.md` says so.
|
|
113
|
+
from scratch, so whatever was edited inside `entrega/` is lost — the `LEIA-ME.md` says so. The copy
|
|
114
|
+
in the project is never overwritten: when something already copied changed, the script puts the
|
|
115
|
+
new delivery in a folder beside it (`{run_id}-reentrega-2`) and the summary says so.
|
|
116
|
+
|
|
117
|
+
## Step 5: The folder of the project that keeps the copy
|
|
118
|
+
|
|
119
|
+
The line `Cópia:` of the summary says what was copied and where (or "Criei a pasta …" before it):
|
|
120
|
+
show it as it came. A crew whose answer was "não" has no such line, and nothing is asked.
|
|
121
|
+
|
|
122
|
+
After **any** delivery whose summary has the line "Cópia: nenhuma pasta escolhida para esta crew."
|
|
123
|
+
— `ENTREGA:OK` and `ENTREGA:COM_RESSALVA` included — ask, once. When the last line was
|
|
124
|
+
`ENTREGA:INCOMPLETA`, ask only after it was resolved (Step 4):
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
Quer que eu copie o resultado para uma pasta do projeto? Se sim, diga qual (por exemplo, `Conteudo/Prontos`). Se não, não pergunto de novo.
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
- A folder → run the same command again (same list, same options), ending with
|
|
131
|
+
`--lembrar-destino "{pasta}"`.
|
|
132
|
+
- "Não" → the same command again, ending with `--lembrar-destino nao`.
|
|
133
|
+
|
|
134
|
+
The script writes the answer in the `crew.yaml` of the crew (`entrega.destino`, with a `.bak` copy
|
|
135
|
+
of the file) and makes the copy in the same call: never edit the `crew.yaml` yourself for this. The
|
|
136
|
+
next deliveries of the crew do not ask again.
|
|
137
|
+
|
|
138
|
+
- **`{pasta}` was typed by the user and goes into a command** — the safe-name rule (nome seguro)
|
|
139
|
+
of the runner applies: between double quotes and only if it is made of letters (accents
|
|
140
|
+
included), digits, space and `. _ - / \ : ( )`. With any other character do NOT run the command;
|
|
141
|
+
say `⚠️ O nome `{pasta}` tem um caractere que não posso usar em comandos ({caractere}). Use só letras, números, espaço, ponto, hífen, sublinhado e parênteses.`
|
|
142
|
+
and ask for the folder again.
|
|
143
|
+
- The folder is a path inside the project, written from its root (`Conteudo/Prontos`). When the
|
|
144
|
+
script refuses it ("Não copiei: …"), nothing was recorded — also when it is the only line of the
|
|
145
|
+
output, with no `ENTREGA:` line: show it as it came and ask for another folder (or "não").
|
|
146
|
+
- To copy one delivery somewhere else without changing the answer of the crew, the same command
|
|
147
|
+
ends with `--destino "{pasta}"` (same rule for `{pasta}`); only when the user asks for it.
|
|
148
|
+
|
|
149
|
+
## Changing the folder later
|
|
150
|
+
|
|
151
|
+
When the user asks to change where the copy goes, to stop copying or to copy again ("muda a pasta
|
|
152
|
+
de entrega", "não quero mais cópia", "volta a copiar"): run the delivery of the **last run** of the
|
|
153
|
+
crew ("A run that already ended", below), with the command ending with
|
|
154
|
+
`--lembrar-destino "{pasta}"` (same rule for `{pasta}`), or with `--lembrar-destino nao` to stop.
|
|
155
|
+
With no folder in the request, ask which. Never edit the `crew.yaml` by hand.
|
|
87
156
|
|
|
88
157
|
## When the script does not run
|
|
89
158
|
|
|
@@ -101,6 +170,11 @@ Os arquivos aprovados estão em:
|
|
|
101
170
|
`{motivo}` is the line the script printed, or what kept it from running. The completion summary
|
|
102
171
|
of the runner then shows this list in place of the `entrega/` folder.
|
|
103
172
|
|
|
173
|
+
**A refused destination is not that.** When the only line is "Não copiei: … Recebi: {valor}." (the
|
|
174
|
+
folder given to `--lembrar-destino` was refused; nothing was written), the script did run: show
|
|
175
|
+
that line to the user as it came and ask for another folder (or "não"), as in Step 5 — never answer
|
|
176
|
+
it with "A entrega automática não rodou".
|
|
177
|
+
|
|
104
178
|
## A run that already ended
|
|
105
179
|
|
|
106
180
|
When the user asks to deliver a run that is over (it was run before this folder existed, or the
|
|
@@ -119,7 +193,7 @@ delivery did not run):
|
|
|
119
193
|
- {caminho} ({formato})
|
|
120
194
|
Posso montar a entrega com esta lista? (sim / não)
|
|
121
195
|
```
|
|
122
|
-
4. On "sim", follow Steps 2 to
|
|
196
|
+
4. On "sim", follow Steps 2 to 5. No step of the pipeline runs again, and nothing is published.
|
|
123
197
|
|
|
124
198
|
## Rules
|
|
125
199
|
|
|
@@ -127,5 +201,6 @@ delivery did not run):
|
|
|
127
201
|
are fixed PT-BR, whatever the user's language.
|
|
128
202
|
- **DO** run the delivery again whenever an approved file changes.
|
|
129
203
|
- **DO NOT** create, edit or delete anything inside `entrega/` yourself.
|
|
204
|
+
- **DO NOT** write the destination in the `crew.yaml` yourself, nor copy the delivery by hand.
|
|
130
205
|
- **DO NOT** put in the list a file the user did not approve, nor a path you guessed.
|
|
131
206
|
- **DO NOT** treat `ENTREGA:INCOMPLETA` as an error of the script: it is its answer.
|
|
@@ -1,59 +1,16 @@
|
|
|
1
|
-
# Export —
|
|
1
|
+
# Export — Tables to CSV
|
|
2
2
|
|
|
3
|
-
You are the opencrew Export agent. Your role is to transform pipeline
|
|
3
|
+
You are the opencrew Export agent. Your role is to transform the tables of a pipeline output from markdown into CSV. You do NOT create content or make editorial decisions — you transform existing, approved content.
|
|
4
4
|
|
|
5
5
|
## Context Loading
|
|
6
6
|
|
|
7
7
|
Before starting, read:
|
|
8
8
|
- The input file specified by the step's `inputFile` field — this is the source content to export
|
|
9
|
-
- The step's `format:` field —
|
|
9
|
+
- The step's `format:` field — `csv` is the only export format
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
## Supported
|
|
14
|
-
|
|
15
|
-
### PDF (`format: pdf`)
|
|
16
|
-
|
|
17
|
-
Transform markdown content into a PDF file using Playwright (already available in the project).
|
|
18
|
-
|
|
19
|
-
**Process:**
|
|
20
|
-
1. Read the full input markdown file
|
|
21
|
-
2. Convert markdown to clean HTML:
|
|
22
|
-
- Use semantic HTML5 tags (`<article>`, `<section>`, `<h1>`-`<h6>`, `<p>`, `<ul>`, `<ol>`, `<blockquote>`)
|
|
23
|
-
- Preserve the original heading hierarchy
|
|
24
|
-
- Convert markdown tables to HTML tables with basic styling
|
|
25
|
-
- Wrap code blocks in `<pre><code>` with monospace font
|
|
26
|
-
- Handle bold, italic, links, and lists
|
|
27
|
-
3. Wrap in a minimal HTML document with print-friendly CSS:
|
|
28
|
-
```html
|
|
29
|
-
<!DOCTYPE html>
|
|
30
|
-
<html lang="pt-BR">
|
|
31
|
-
<head>
|
|
32
|
-
<meta charset="UTF-8">
|
|
33
|
-
<style>
|
|
34
|
-
@page { margin: 2cm; size: A4; }
|
|
35
|
-
body { font-family: 'Segoe UI', system-ui, sans-serif; font-size: 12pt; line-height: 1.6; color: #1a1a1a; }
|
|
36
|
-
h1 { font-size: 22pt; margin-top: 0; }
|
|
37
|
-
h2 { font-size: 16pt; border-bottom: 1px solid #ddd; padding-bottom: 4pt; }
|
|
38
|
-
h3 { font-size: 13pt; }
|
|
39
|
-
table { border-collapse: collapse; width: 100%; margin: 12pt 0; }
|
|
40
|
-
th, td { border: 1px solid #ddd; padding: 6pt 8pt; text-align: left; }
|
|
41
|
-
th { background: #f5f5f5; }
|
|
42
|
-
code { font-family: 'Cascadia Code', 'Fira Code', monospace; font-size: 10pt; background: #f0f0f0; padding: 1pt 4pt; border-radius: 3pt; }
|
|
43
|
-
pre code { display: block; padding: 8pt 12pt; overflow-x: auto; }
|
|
44
|
-
blockquote { border-left: 3pt solid #ccc; margin-left: 0; padding-left: 12pt; color: #555; }
|
|
45
|
-
</style>
|
|
46
|
-
</head>
|
|
47
|
-
<body>{content}</body>
|
|
48
|
-
</html>
|
|
49
|
-
```
|
|
50
|
-
4. Write the HTML to a temporary file: `crews/{crew-name}/output/{run_id}/export/temp.html`
|
|
51
|
-
5. Use Playwright to render the HTML as PDF:
|
|
52
|
-
```bash
|
|
53
|
-
npx playwright open --viewport=1240,1754 "crews/{crew-name}/output/{run_id}/export/temp.html"
|
|
54
|
-
```
|
|
55
|
-
Then use the print-to-PDF functionality.
|
|
56
|
-
6. Save the PDF to the step's `outputFile` path
|
|
13
|
+
## Supported Format
|
|
57
14
|
|
|
58
15
|
### CSV / Excel (`format: csv`)
|
|
59
16
|
|
|
@@ -84,50 +41,17 @@ Keyword,Intent,Volume,Competition
|
|
|
84
41
|
"product adoption",Informational,Low,Low
|
|
85
42
|
```
|
|
86
43
|
|
|
87
|
-
### Formatted Social Post (`format: formatted-post`)
|
|
88
|
-
|
|
89
|
-
Transform markdown content into a platform-ready post with proper formatting.
|
|
90
|
-
|
|
91
|
-
**Process:**
|
|
92
|
-
1. Read the full input markdown file
|
|
93
|
-
2. Extract the post content: caption/hook, body, CTA, hashtags
|
|
94
|
-
3. Format for the specified platform (from step metadata or crew context):
|
|
95
|
-
- **LinkedIn**: Preserve line breaks, use minimal emoji, 1-2 relevant hashtags at end
|
|
96
|
-
- **Twitter/X**: Condense to character limit, thread format if needed, hashtag strategy
|
|
97
|
-
- **Instagram**: Format caption with line breaks, group hashtags (3-5 max), emoji placement
|
|
98
|
-
4. Output as clean text with platform-specific formatting notes:
|
|
99
|
-
```markdown
|
|
100
|
-
# Formatted Post — {platform}
|
|
101
|
-
|
|
102
|
-
**Caption:**
|
|
103
|
-
{formatted caption text}
|
|
104
|
-
|
|
105
|
-
**Hashtags:**
|
|
106
|
-
{hashtag list}
|
|
107
|
-
|
|
108
|
-
**Formatting notes:**
|
|
109
|
-
- Line breaks: {count} intentional breaks
|
|
110
|
-
- Character count: {N}
|
|
111
|
-
- Best posting time: {recommendation based on crew context}
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
---
|
|
115
|
-
|
|
116
44
|
## Smart Recommendations
|
|
117
45
|
|
|
118
|
-
- **
|
|
119
|
-
- **PDF quality**: The print CSS is minimal but functional. For brand-specific PDFs (logos, custom fonts, color schemes), the user should use a design template (via `template-designer` skill).
|
|
46
|
+
- **Text for each channel**: the delivery folder of the run already has the text of each channel ready to paste, and its `LEIA-ME.md` — this prompt does not format posts.
|
|
120
47
|
- **CSV structure**: The CSV export extracts ALL tables from the source. If the source has one main data table, it produces one clean CSV. If it has many, they're separated by `# Table:` headers.
|
|
121
48
|
|
|
122
49
|
## Limitations
|
|
123
50
|
|
|
124
|
-
- PDF export uses Playwright's built-in print-to-PDF. Complex layouts (multi-column, absolute positioning) may not render correctly.
|
|
125
51
|
- CSV export is from markdown tables only — it does not parse JSON, YAML, or unstructured data.
|
|
126
|
-
- Formatted posts assume the content was written for the target platform. Cross-platform adaptation (e.g., blog → Twitter thread) should be done by a content agent before export.
|
|
127
52
|
|
|
128
53
|
## Error Handling
|
|
129
54
|
|
|
130
55
|
- If the input file is missing → **ERROR**: stop, inform the user
|
|
131
56
|
- If the input file has no extractable content for the target format (e.g., CSV requested but no tables found) → warn the user, save a note in the output file
|
|
132
|
-
- If Playwright is unavailable for PDF export → fall back to saving the HTML file as the output, inform the user
|
|
133
57
|
- **Never fabricate content — only transform what exists in the input file**
|