@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.
Files changed (71) hide show
  1. package/CHANGELOG.md +102 -0
  2. package/README.md +70 -13
  3. package/package.json +2 -2
  4. package/src/cli.js +15 -38
  5. package/src/commands/init.js +41 -44
  6. package/src/commands/update.js +78 -75
  7. package/src/lib/blocos.js +148 -0
  8. package/src/lib/deteccao.js +69 -0
  9. package/src/lib/fsx.js +1 -55
  10. package/src/lib/ides.js +4 -0
  11. package/src/lib/legado.js +142 -0
  12. package/src/lib/manifest.js +67 -26
  13. package/src/lib/mcp.js +131 -0
  14. package/src/lib/migrations.js +77 -74
  15. package/src/lib/node-version.js +43 -0
  16. package/src/lib/prompts.js +25 -2
  17. package/src/lib/resumo.js +125 -0
  18. package/templates/.mcp.json +1 -1
  19. package/templates/AGENTS.md +20 -6
  20. package/templates/_opencrew/.opencrew-version +1 -1
  21. package/templates/_opencrew/core/best-practices/social-networks-publishing.md +14 -14
  22. package/templates/_opencrew/core/escritorio/animacao.js +64 -0
  23. package/templates/_opencrew/core/escritorio/app.js +137 -0
  24. package/templates/_opencrew/core/escritorio/cena.js +132 -0
  25. package/templates/_opencrew/core/escritorio/demo.js +79 -0
  26. package/templates/_opencrew/core/escritorio/escala.js +27 -0
  27. package/templates/_opencrew/core/escritorio/index.html +166 -0
  28. package/templates/_opencrew/core/escritorio/modelo-agentes.js +93 -0
  29. package/templates/_opencrew/core/escritorio/modelo-estado.js +71 -0
  30. package/templates/_opencrew/core/escritorio/modelo-mesas.js +81 -0
  31. package/templates/_opencrew/core/escritorio/modelo-pagina.js +95 -0
  32. package/templates/_opencrew/core/escritorio/modelo-textos.js +65 -0
  33. package/templates/_opencrew/core/escritorio/modelo-visao.js +91 -0
  34. package/templates/_opencrew/core/escritorio/modelo.js +29 -0
  35. package/templates/_opencrew/core/escritorio/painel.js +120 -0
  36. package/templates/_opencrew/core/escritorio/quadro.js +106 -0
  37. package/templates/_opencrew/core/escritorio/rota.js +62 -0
  38. package/templates/_opencrew/core/escritorio/rotulos.js +78 -0
  39. package/templates/_opencrew/core/escritorio/sprites-mesa.js +122 -0
  40. package/templates/_opencrew/core/escritorio/sprites-sala.js +92 -0
  41. package/templates/_opencrew/core/escritorio/sprites.js +187 -0
  42. package/templates/_opencrew/core/prompts/build.prompt.md +3 -3
  43. package/templates/_opencrew/core/prompts/export.prompt.md +1 -1
  44. package/templates/_opencrew/core/prompts/repair.prompt.md +7 -12
  45. package/templates/_opencrew/core/prompts/sherlock-shared.md +5 -5
  46. package/templates/_opencrew/core/runner.pipeline.md +76 -139
  47. package/templates/_opencrew/core/scripts/comum.mjs +49 -4
  48. package/templates/_opencrew/core/scripts/conferir-fontes/busca.mjs +42 -3
  49. package/templates/_opencrew/core/scripts/conferir-fontes/relatorio.mjs +18 -6
  50. package/templates/_opencrew/core/scripts/conferir-fontes.mjs +97 -39
  51. package/templates/_opencrew/core/scripts/escritorio/leitura.mjs +31 -0
  52. package/templates/_opencrew/core/scripts/escritorio/porta.mjs +98 -0
  53. package/templates/_opencrew/core/scripts/escritorio/projeto.mjs +29 -0
  54. package/templates/_opencrew/core/scripts/escritorio/servidor.mjs +78 -0
  55. package/templates/_opencrew/core/scripts/escritorio.mjs +117 -0
  56. package/templates/_opencrew/core/scripts/estado/argumentos.mjs +61 -0
  57. package/templates/_opencrew/core/scripts/estado/arquivo.mjs +53 -0
  58. package/templates/_opencrew/core/scripts/estado/decisao.mjs +56 -0
  59. package/templates/_opencrew/core/scripts/estado/elenco.mjs +58 -0
  60. package/templates/_opencrew/core/scripts/estado/nucleo.mjs +113 -0
  61. package/templates/_opencrew/core/scripts/estado/preferencia.mjs +24 -0
  62. package/templates/_opencrew/core/scripts/estado.mjs +96 -0
  63. package/templates/_opencrew/core/scripts/verificar.mjs +7 -4
  64. package/templates/_opencrew/core/skills.engine.md +7 -3
  65. package/templates/gitignore +1 -0
  66. package/templates/skills/blotato/SKILL.md +39 -10
  67. package/templates/skills/image-ai-generator/SKILL.md +18 -5
  68. package/templates/skills/image-ai-generator/scripts/generate.py +52 -10
  69. package/templates/skills/instagram-publisher/SKILL.md +4 -0
  70. package/templates/skills/opencrew-skill-creator/references/skill-format.md +1 -0
  71. 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 "description" --output "path/to/image.jpg" --mode test
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 "description" --output "path/to/image.jpg" --reference "path/to/logo.png" --mode production
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="Text prompt for single image generation")
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 not args.prompt and not args.batch:
142
- parser.error("Either --prompt or --batch is required")
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(args.prompt, args.output, args.mode, api_key, reference_image=args.reference)
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
- 1. Prepare **from**, **to**, **subject**, and **body** (HTML or plain text).
40
- 2. Call the Resend MCP `send_email` tool.
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
- 1. Build an array of email objects (same fields as single send).
46
- 2. Call the Resend MCP `batch_send_emails` tool.
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