@aksp/opencrew 1.6.2 → 1.7.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 +102 -0
- package/README.md +70 -13
- package/package.json +2 -2
- package/src/cli.js +15 -38
- package/src/commands/init.js +41 -44
- package/src/commands/update.js +78 -75
- package/src/lib/blocos.js +148 -0
- package/src/lib/deteccao.js +69 -0
- package/src/lib/fsx.js +1 -55
- package/src/lib/ides.js +4 -0
- package/src/lib/legado.js +142 -0
- package/src/lib/manifest.js +67 -26
- package/src/lib/mcp.js +131 -0
- package/src/lib/migrations.js +77 -74
- package/src/lib/node-version.js +43 -0
- package/src/lib/prompts.js +25 -2
- package/src/lib/resumo.js +125 -0
- package/templates/.mcp.json +1 -1
- package/templates/AGENTS.md +20 -6
- package/templates/_opencrew/.opencrew-version +1 -1
- package/templates/_opencrew/core/best-practices/social-networks-publishing.md +14 -14
- package/templates/_opencrew/core/escritorio/animacao.js +64 -0
- package/templates/_opencrew/core/escritorio/app.js +137 -0
- package/templates/_opencrew/core/escritorio/cena.js +132 -0
- package/templates/_opencrew/core/escritorio/demo.js +79 -0
- package/templates/_opencrew/core/escritorio/escala.js +27 -0
- package/templates/_opencrew/core/escritorio/index.html +166 -0
- package/templates/_opencrew/core/escritorio/modelo-agentes.js +93 -0
- package/templates/_opencrew/core/escritorio/modelo-estado.js +71 -0
- package/templates/_opencrew/core/escritorio/modelo-mesas.js +81 -0
- package/templates/_opencrew/core/escritorio/modelo-pagina.js +95 -0
- package/templates/_opencrew/core/escritorio/modelo-textos.js +65 -0
- package/templates/_opencrew/core/escritorio/modelo-visao.js +91 -0
- package/templates/_opencrew/core/escritorio/modelo.js +29 -0
- package/templates/_opencrew/core/escritorio/painel.js +120 -0
- package/templates/_opencrew/core/escritorio/quadro.js +106 -0
- package/templates/_opencrew/core/escritorio/rota.js +62 -0
- package/templates/_opencrew/core/escritorio/rotulos.js +78 -0
- package/templates/_opencrew/core/escritorio/sprites-mesa.js +122 -0
- package/templates/_opencrew/core/escritorio/sprites-sala.js +92 -0
- package/templates/_opencrew/core/escritorio/sprites.js +187 -0
- package/templates/_opencrew/core/prompts/build.prompt.md +3 -3
- package/templates/_opencrew/core/prompts/export.prompt.md +1 -1
- package/templates/_opencrew/core/prompts/repair.prompt.md +7 -12
- package/templates/_opencrew/core/prompts/sherlock-shared.md +5 -5
- package/templates/_opencrew/core/runner.pipeline.md +76 -139
- package/templates/_opencrew/core/scripts/comum.mjs +49 -4
- package/templates/_opencrew/core/scripts/conferir-fontes/busca.mjs +42 -3
- package/templates/_opencrew/core/scripts/conferir-fontes/relatorio.mjs +18 -6
- package/templates/_opencrew/core/scripts/conferir-fontes.mjs +97 -39
- package/templates/_opencrew/core/scripts/escritorio/leitura.mjs +31 -0
- package/templates/_opencrew/core/scripts/escritorio/porta.mjs +98 -0
- package/templates/_opencrew/core/scripts/escritorio/projeto.mjs +29 -0
- package/templates/_opencrew/core/scripts/escritorio/servidor.mjs +78 -0
- package/templates/_opencrew/core/scripts/escritorio.mjs +117 -0
- package/templates/_opencrew/core/scripts/estado/argumentos.mjs +61 -0
- package/templates/_opencrew/core/scripts/estado/arquivo.mjs +53 -0
- package/templates/_opencrew/core/scripts/estado/decisao.mjs +56 -0
- package/templates/_opencrew/core/scripts/estado/elenco.mjs +58 -0
- package/templates/_opencrew/core/scripts/estado/nucleo.mjs +113 -0
- package/templates/_opencrew/core/scripts/estado/preferencia.mjs +24 -0
- package/templates/_opencrew/core/scripts/estado.mjs +96 -0
- package/templates/_opencrew/core/scripts/verificar.mjs +7 -4
- package/templates/_opencrew/core/skills.engine.md +7 -3
- package/templates/gitignore +1 -0
- package/templates/skills/blotato/SKILL.md +39 -10
- package/templates/skills/image-ai-generator/SKILL.md +18 -5
- package/templates/skills/image-ai-generator/scripts/generate.py +52 -10
- package/templates/skills/instagram-publisher/SKILL.md +4 -0
- package/templates/skills/opencrew-skill-creator/references/skill-format.md +1 -0
- package/templates/skills/resend/SKILL.md +52 -13
|
@@ -4,14 +4,16 @@ Image Generator — opencrew Skill
|
|
|
4
4
|
Generates images via Openrouter API using AI image models.
|
|
5
5
|
|
|
6
6
|
Usage:
|
|
7
|
-
# Single image
|
|
8
|
-
python3 generate.py --prompt "
|
|
7
|
+
# Single image (the prompt is read from a UTF-8 text file, never typed in the command)
|
|
8
|
+
python3 generate.py --prompt-file "path/to/prompt.txt" --output "path/to/image.jpg" --mode test
|
|
9
9
|
|
|
10
10
|
# Single image with reference (logo/mascot)
|
|
11
|
-
python3 generate.py --prompt "
|
|
11
|
+
python3 generate.py --prompt-file "path/to/prompt.txt" --output "path/to/image.jpg" --reference "path/to/logo.png" --mode production
|
|
12
12
|
|
|
13
|
-
# Batch (JSON file with list of {prompt, output} objects)
|
|
13
|
+
# Batch (UTF-8 JSON file with list of {prompt, output} objects)
|
|
14
14
|
python3 generate.py --batch "path/to/batch.json" --mode production
|
|
15
|
+
|
|
16
|
+
--prompt "text" is still accepted (legacy): the shell may rewrite $, quotes and backticks in it.
|
|
15
17
|
"""
|
|
16
18
|
|
|
17
19
|
import argparse
|
|
@@ -32,6 +34,42 @@ MODELS = {
|
|
|
32
34
|
API_URL = "https://openrouter.ai/api/v1/chat/completions"
|
|
33
35
|
|
|
34
36
|
|
|
37
|
+
def fail(message):
|
|
38
|
+
"""Tell the user what went wrong and exit with code 1, without a traceback."""
|
|
39
|
+
print(message, file=sys.stderr)
|
|
40
|
+
sys.exit(1)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def read_prompt_file(path):
|
|
44
|
+
"""Read the prompt from a UTF-8 text file (BOM accepted); it never goes through the shell."""
|
|
45
|
+
if not os.path.isfile(path):
|
|
46
|
+
fail(f"Arquivo de prompt não encontrado: {path}")
|
|
47
|
+
try:
|
|
48
|
+
with open(path, "r", encoding="utf-8-sig") as f:
|
|
49
|
+
prompt = f.read().strip()
|
|
50
|
+
except (OSError, ValueError) as e:
|
|
51
|
+
fail(f"Não consegui ler o arquivo de prompt {path}: {e}. Grave o arquivo em UTF-8.")
|
|
52
|
+
if not prompt:
|
|
53
|
+
fail(f"O arquivo de prompt está vazio: {path}")
|
|
54
|
+
return prompt
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def read_batch(path):
|
|
58
|
+
"""Read the batch list from a UTF-8 JSON file (BOM accepted)."""
|
|
59
|
+
try:
|
|
60
|
+
with open(path, "r", encoding="utf-8-sig") as f:
|
|
61
|
+
batch = json.load(f)
|
|
62
|
+
except (OSError, ValueError) as e:
|
|
63
|
+
fail(f"Não consegui ler o lote {path}: {e}. Grave o arquivo em UTF-8.")
|
|
64
|
+
ok = isinstance(batch, list) and all(
|
|
65
|
+
isinstance(i, dict) and all(isinstance(i.get(k), str) and i[k].strip() for k in ("prompt", "output"))
|
|
66
|
+
for i in batch
|
|
67
|
+
)
|
|
68
|
+
if not ok:
|
|
69
|
+
fail(f'O lote {path} tem de ser uma lista de itens com "prompt" e "output". Nada foi gerado.')
|
|
70
|
+
return batch
|
|
71
|
+
|
|
72
|
+
|
|
35
73
|
def load_api_key():
|
|
36
74
|
"""Load OPENROUTER_API_KEY from environment."""
|
|
37
75
|
key = os.environ.get("OPENROUTER_API_KEY")
|
|
@@ -130,7 +168,8 @@ def generate_image(prompt, output_path, mode, api_key, reference_image=None):
|
|
|
130
168
|
|
|
131
169
|
def main():
|
|
132
170
|
parser = argparse.ArgumentParser(description="Generate images via Openrouter API")
|
|
133
|
-
parser.add_argument("--prompt", help="
|
|
171
|
+
parser.add_argument("--prompt-file", help="UTF-8 text file with the prompt for single image generation")
|
|
172
|
+
parser.add_argument("--prompt", help="Legacy: prompt typed in the command (use --prompt-file)")
|
|
134
173
|
parser.add_argument("--output", help="Output file path for single image")
|
|
135
174
|
parser.add_argument("--batch", help="Path to JSON batch file")
|
|
136
175
|
parser.add_argument("--mode", choices=["test", "production"], default="test",
|
|
@@ -138,8 +177,13 @@ def main():
|
|
|
138
177
|
parser.add_argument("--reference", help="Path to reference image to include in the prompt")
|
|
139
178
|
args = parser.parse_args()
|
|
140
179
|
|
|
141
|
-
if
|
|
142
|
-
|
|
180
|
+
if args.prompt_file and args.batch:
|
|
181
|
+
fail("Use só um: --prompt-file ou --batch.")
|
|
182
|
+
if not (args.prompt_file or args.prompt or args.batch):
|
|
183
|
+
parser.error("Either --prompt-file or --batch is required")
|
|
184
|
+
# The input files are read first: a bad file stops here, before the key and any API call.
|
|
185
|
+
items = read_batch(args.batch) if args.batch else None
|
|
186
|
+
prompt = read_prompt_file(args.prompt_file) if args.prompt_file else args.prompt
|
|
143
187
|
|
|
144
188
|
api_key = load_api_key()
|
|
145
189
|
model = MODELS[args.mode]
|
|
@@ -147,8 +191,6 @@ def main():
|
|
|
147
191
|
|
|
148
192
|
if args.batch:
|
|
149
193
|
# Batch mode
|
|
150
|
-
with open(args.batch, "r") as f:
|
|
151
|
-
items = json.load(f)
|
|
152
194
|
print(f"Generating {len(items)} images...\n")
|
|
153
195
|
success = 0
|
|
154
196
|
for i, item in enumerate(items, 1):
|
|
@@ -167,7 +209,7 @@ def main():
|
|
|
167
209
|
if not args.output:
|
|
168
210
|
parser.error("--output is required for single image generation")
|
|
169
211
|
print(f"Generating: {os.path.basename(args.output)}...")
|
|
170
|
-
ok = generate_image(
|
|
212
|
+
ok = generate_image(prompt, args.output, args.mode, api_key, reference_image=args.reference)
|
|
171
213
|
sys.exit(0 if ok else 1)
|
|
172
214
|
|
|
173
215
|
|
|
@@ -74,6 +74,10 @@ and is **never** retried automatically.
|
|
|
74
74
|
|
|
75
75
|
- Images: JPEG only (`.jpg`/`.jpeg`), 2-10 per carousel, inside `crews/*/output/` — the
|
|
76
76
|
script refuses anything else before uploading
|
|
77
|
+
- File names: the image paths and the caption file follow the safe-name rule (nome seguro) of
|
|
78
|
+
`_opencrew/core/runner.pipeline.md` — letters, digits, space and `. _ - / \ : ( )`. With any
|
|
79
|
+
other character (a comma included: it splits the `--images` list) do not run the command: ask
|
|
80
|
+
the user to rename the file
|
|
77
81
|
- Images are hosted on imgBB for 24h only (enough for Instagram to fetch them)
|
|
78
82
|
- Caption: max 2200 characters
|
|
79
83
|
- Requires Instagram Business account (not Personal or Creator)
|
|
@@ -14,6 +14,7 @@ Every opencrew skill consists of a `SKILL.md` file with YAML frontmatter and a M
|
|
|
14
14
|
| `version` | Yes | Semver version string (e.g., `1.0.0`) |
|
|
15
15
|
| `categories` | No | Classification tags array (e.g., `["social-media", "content"]`) |
|
|
16
16
|
| `env` | No | Required environment variable names array |
|
|
17
|
+
| `side_effects` | No | `irreversible` for a skill that publishes or sends (a post, an e-mail). Its body must then show a preview, wait for a confirmation word and make one single call, never repeated after a failure. A skill that only costs money does not use it |
|
|
17
18
|
|
|
18
19
|
### Type: mcp
|
|
19
20
|
|
|
@@ -19,6 +19,7 @@ mcp:
|
|
|
19
19
|
command: npx
|
|
20
20
|
args: ["-y", "resend-mcp"]
|
|
21
21
|
transport: stdio
|
|
22
|
+
side_effects: irreversible
|
|
22
23
|
env:
|
|
23
24
|
- RESEND_API_KEY
|
|
24
25
|
categories: [email, automation, communication]
|
|
@@ -34,17 +35,53 @@ so the crew only needs to compose the content and call the MCP tools.
|
|
|
34
35
|
|
|
35
36
|
## Instructions
|
|
36
37
|
|
|
38
|
+
### Confirmation (before any send, schedule or delete)
|
|
39
|
+
|
|
40
|
+
Sending is **irreversible**: an e-mail cannot be taken back once it leaves. The rule below is
|
|
41
|
+
about the **action**, whatever the tool is called on the server: before ANY call that sends,
|
|
42
|
+
schedules or deletes, follow this order. The messages to the user are in PT-BR, as written here.
|
|
43
|
+
|
|
44
|
+
1. Prepare **from**, **to**, **subject**, **body** (HTML or plain text) and attachments. Call no
|
|
45
|
+
sending tool yet.
|
|
46
|
+
2. **Preview (prévia)** — show the user exactly this, filled in:
|
|
47
|
+
```
|
|
48
|
+
Vou enviar este e-mail:
|
|
49
|
+
De: {remetente}
|
|
50
|
+
Para: {N} destinatário(s): {até 10 endereços}… e mais {N-10}
|
|
51
|
+
Assunto: {assunto}
|
|
52
|
+
Início do texto: {3 primeiras linhas}
|
|
53
|
+
Anexos: {nomes}, ou nenhum
|
|
54
|
+
Quando: agora, ou agendado para {data e hora}
|
|
55
|
+
Para enviar, responda com a palavra enviar. Qualquer outra resposta cancela.
|
|
56
|
+
```
|
|
57
|
+
(`{N}` is the total of recipients — to, CC and BCC; in a batch, of all the e-mails together.
|
|
58
|
+
List at most 10 addresses; "… e mais {N-10}" only when there are more. `Quando`: write `agora`
|
|
59
|
+
or `agendado para …`. `Anexos`: the file names, or `nenhum`.)
|
|
60
|
+
3. Wait for the word **enviar**. Any other answer — including silence, "ok" or "sim" — cancels:
|
|
61
|
+
say "Nenhum e-mail foi enviado." and stop.
|
|
62
|
+
4. Only after the word: make **one single call** — `send_email` for one e-mail,
|
|
63
|
+
`batch_send_emails` for a batch.
|
|
64
|
+
5. On success: check the response for the `id` (one per item in a batch) and save it to the step
|
|
65
|
+
output file immediately.
|
|
66
|
+
6. On failure, timeout or missing answer: do NOT repeat the call again, in this step or in a retry.
|
|
67
|
+
Tell the user: "⚠️ Não recebi a confirmação do Resend. O e-mail pode já ter sido enviado.
|
|
68
|
+
Confira no painel antes de tentar de novo. Não vou repetir sozinho."
|
|
69
|
+
7. One confirmation is worth one send. If this step runs again in the same run (a retry, or back
|
|
70
|
+
from a rejected review), show the preview again, after this line: "Este passo já tentou enviar
|
|
71
|
+
nesta execução. Confira se saiu antes de confirmar de novo." — and wait for the word.
|
|
72
|
+
8. A call that **deletes** (removing a contact or a domain) follows the same order with its own
|
|
73
|
+
word: "Vou apagar isto: {o que será apagado}. Para apagar, responda com a palavra apagar.
|
|
74
|
+
Qualquer outra resposta cancela." Any other answer: "Nada foi apagado."
|
|
75
|
+
|
|
37
76
|
### Sending a single email
|
|
38
77
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
3. Check the response for a successful `id` — that confirms the email was queued.
|
|
78
|
+
Fields: **from**, **to**, **subject** and **body**; a successful `id` in the response confirms the
|
|
79
|
+
e-mail was queued.
|
|
42
80
|
|
|
43
81
|
### Sending a batch
|
|
44
82
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
3. Each item in the response will have its own `id` or error.
|
|
83
|
+
Build an array of email objects (same fields as single send). Each item in the response has its
|
|
84
|
+
own `id` or error — report both; never send the failed ones again on your own.
|
|
48
85
|
|
|
49
86
|
### Attachments
|
|
50
87
|
|
|
@@ -52,25 +89,27 @@ Pass attachments as an array with `filename`, `path` (local file), `url`, or `co
|
|
|
52
89
|
|
|
53
90
|
### Scheduling
|
|
54
91
|
|
|
55
|
-
Include a `scheduled_at` field (ISO 8601 datetime) to schedule future delivery.
|
|
92
|
+
Include a `scheduled_at` field (ISO 8601 datetime) to schedule future delivery. A scheduled e-mail
|
|
93
|
+
asks for the same preview and the same word, with the date and time on the `Quando` line.
|
|
56
94
|
|
|
57
95
|
## Best practices
|
|
58
96
|
|
|
59
97
|
- Validate **from** against a verified domain before sending — Resend rejects unverified senders.
|
|
60
98
|
- Keep subject lines under 80 characters for better deliverability.
|
|
61
99
|
- For batch sends, group by shared content to reduce payload size.
|
|
62
|
-
- Always check the response for errors and surface them to the user rather than silently failing
|
|
100
|
+
- Always check the response for errors and surface them to the user rather than silently failing
|
|
101
|
+
— and never by sending again.
|
|
63
102
|
- When composing HTML emails, keep the markup simple — most email clients ignore complex CSS.
|
|
64
103
|
|
|
65
104
|
## Available operations
|
|
66
105
|
|
|
67
|
-
- **Send Email** — Single email with HTML/text body, attachments, CC/BCC, reply-to
|
|
68
|
-
- **Batch Send** — Multiple emails in one call
|
|
69
|
-
- **Schedule Email** — Queue an email for future delivery
|
|
106
|
+
- **Send Email** — Single email with HTML/text body, attachments, CC/BCC, reply-to (only after the word)
|
|
107
|
+
- **Batch Send** — Multiple emails in one call (only after the word)
|
|
108
|
+
- **Schedule Email** — Queue an email for future delivery (only after the word)
|
|
70
109
|
- **List/Get Emails** — Check delivery status of sent emails
|
|
71
110
|
- **Cancel Email** — Cancel a scheduled email before it sends
|
|
72
|
-
- **Manage Contacts** — Create, list, update, and remove contacts from audiences
|
|
73
|
-
- **Manage Domains** — Add and verify sender domains
|
|
111
|
+
- **Manage Contacts** — Create, list, update, and remove contacts from audiences (removing asks for the word `apagar`)
|
|
112
|
+
- **Manage Domains** — Add and verify sender domains (removing asks for the word `apagar`)
|
|
74
113
|
|
|
75
114
|
## Setup
|
|
76
115
|
|