@aksp/opencrew 1.6.3 → 1.7.1
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 +86 -0
- package/README.md +50 -5
- package/package.json +1 -1
- package/templates/AGENTS.md +20 -6
- package/templates/_opencrew/.opencrew-version +1 -1
- package/templates/_opencrew/core/architect.agent.yaml +1 -1
- 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/discovery.prompt.md +1 -1
- package/templates/_opencrew/core/prompts/repair.prompt.md +7 -12
- package/templates/_opencrew/core/runner.pipeline.md +124 -223
- package/templates/_opencrew/core/scripts/caminho/argumentos.mjs +49 -0
- package/templates/_opencrew/core/scripts/caminho/disco.mjs +36 -0
- package/templates/_opencrew/core/scripts/caminho/nucleo.mjs +61 -0
- package/templates/_opencrew/core/scripts/caminho.mjs +124 -0
- 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
|
@@ -33,18 +33,7 @@ Before starting execution:
|
|
|
33
33
|
- Crew memory from `crews/{name}/_memory/memories.md`
|
|
34
34
|
- User preferences from `_opencrew/_memory/preferences.md`
|
|
35
35
|
|
|
36
|
-
1a. **
|
|
37
|
-
optional, opt-in feature that most installs never use (it requires running the
|
|
38
|
-
separate dashboard app from source — see README). Scan the already-loaded
|
|
39
|
-
`preferences.md` for a `Dashboard:` field:
|
|
40
|
-
- If its value is `enabled` (as written by onboarding: `- **Dashboard:** enabled`, or the
|
|
41
|
-
plain form `Dashboard: enabled`) → set `dashboard_enabled = true` for this run.
|
|
42
|
-
- Otherwise (`disabled`, missing, or preferences.md not configured yet) →
|
|
43
|
-
set `dashboard_enabled = false`. This is the default.
|
|
44
|
-
Store `dashboard_enabled` in working memory for the rest of this run. Every
|
|
45
|
-
`state.json` read/write instruction in this document is conditional on it —
|
|
46
|
-
when `false`, skip ALL of them; never create, update, or delete
|
|
47
|
-
`crews/{name}/state.json`.
|
|
36
|
+
1a. **Escritório toggle** — the optional live view is off unless `preferences.md` turns it on (see "Escritório" below).
|
|
48
37
|
|
|
49
38
|
> **Note on language**: The structural labels listed below are **fixed PT-BR** and must
|
|
50
39
|
> never be translated — opencrew's primary supported audience is PT-BR (see AGENTS.md →
|
|
@@ -64,12 +53,9 @@ Before starting execution:
|
|
|
64
53
|
> unless the user base expands beyond PT-BR — at that point, discuss a migration strategy
|
|
65
54
|
> (e.g. i18n key mapping) rather than mixing languages in a single file.
|
|
66
55
|
|
|
67
|
-
1b. **Memory format migration** — After loading `memories.md`, check whether it uses the new format
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
```
|
|
71
|
-
- If `NEW_FORMAT` → proceed normally.
|
|
72
|
-
- If `OLD_FORMAT` (or file is empty / does not exist) → migrate before proceeding:
|
|
56
|
+
1b. **Memory format migration** — After loading `memories.md`, check whether it uses the new format: it does when it has the `## Estilo de Escrita` section header (read the file with the read tool — no command).
|
|
57
|
+
- If it has the header → proceed normally.
|
|
58
|
+
- If it does not (or the file is empty / does not exist) → migrate before proceeding:
|
|
73
59
|
a0. If the file exists and is not empty, FIRST copy it to `crews/{name}/_memory/memories.md.bak`
|
|
74
60
|
(never lose what the crew learned), then tell the user in one line:
|
|
75
61
|
"Atualizei o formato da memória da crew; a versão anterior está em `memories.md.bak`."
|
|
@@ -89,11 +75,8 @@ Before starting execution:
|
|
|
89
75
|
## Técnico (específico do crew)
|
|
90
76
|
```
|
|
91
77
|
(Use the crew's display name for `{crew-name}`, and the crew code for `{name}` in file paths — they refer to the same crew.)
|
|
92
|
-
b. Check if `crews/{name}/_memory/runs.md` exists
|
|
93
|
-
|
|
94
|
-
test -f "crews/{name}/_memory/runs.md" && echo "EXISTS" || echo "MISSING"
|
|
95
|
-
```
|
|
96
|
-
If `MISSING`, create it with:
|
|
78
|
+
b. Check if `crews/{name}/_memory/runs.md` exists (read tool — no command).
|
|
79
|
+
If it does not exist, create it with:
|
|
97
80
|
```markdown
|
|
98
81
|
# Run History: {crew-name}
|
|
99
82
|
|
|
@@ -240,45 +223,47 @@ Before starting execution:
|
|
|
240
223
|
identical to today: all agents listed, no Skipped line.
|
|
241
224
|
5b. **Initialize run folder**: Generate a unique run ID for this execution:
|
|
242
225
|
- Format: `YYYY-MM-DD-HHmmss` using the current timestamp (e.g. `2026-03-03-143022`)
|
|
243
|
-
- Check if `crews/{name}/output/{run_id}/` already exists
|
|
226
|
+
- Check (folder-listing tool, no command) if `crews/{name}/output/{run_id}/` already exists
|
|
244
227
|
- If it does (sub-second collision), append `-2`, `-3`, etc. until the folder does not exist
|
|
245
|
-
- Create the folder
|
|
228
|
+
- Create the folder: run the `pasta` command (see "Output Path Transformation" below) — never create a folder by command yourself
|
|
246
229
|
- Store `run_id` in working memory for this run — it will be used for ALL output paths
|
|
247
|
-
6. **
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
230
|
+
6. **Escritório** — if it is on, run `iniciar`, then one `pular` per deselected agent, one after the other (see "Escritório" below).
|
|
231
|
+
|
|
232
|
+
## Escritório (optional live view)
|
|
233
|
+
|
|
234
|
+
A local page that shows the crew at work, off by default. Follow this section only when the
|
|
235
|
+
already-loaded `preferences.md` has `Dashboard: enabled` (written `- **Dashboard:** enabled` or
|
|
236
|
+
plain `Dashboard: enabled`, any letter case); otherwise run none of these commands. When it is on,
|
|
237
|
+
run via Bash, from the project root, the one-line command of each moment:
|
|
238
|
+
|
|
239
|
+
| Moment | Command |
|
|
240
|
+
|---|---|
|
|
241
|
+
| Start of the run (Initialization, step 6) | `node _opencrew/core/scripts/estado.mjs "{name}" iniciar --passos {N}` |
|
|
242
|
+
| Right after `iniciar`, once per deselected agent | `node _opencrew/core/scripts/estado.mjs "{name}" pular --agente {id}` |
|
|
243
|
+
| Before each step, each time it starts | `node _opencrew/core/scripts/estado.mjs "{name}" passo --n {K} --agente {id} --rotulo "{rótulo}" --mensagem "{frase}"` |
|
|
244
|
+
| Before asking the question of a checkpoint (instead of `passo`) | `node _opencrew/core/scripts/estado.mjs "{name}" checkpoint --n {K} --agente {id} --rotulo "{rótulo}"` |
|
|
245
|
+
| End of the run (After Pipeline Completion) | `node _opencrew/core/scripts/estado.mjs "{name}" concluir` |
|
|
246
|
+
| Run aborted after `iniciar`, by the user or by an error | `node _opencrew/core/scripts/estado.mjs "{name}" falhar --motivo "{motivo}"` |
|
|
247
|
+
|
|
248
|
+
- **One at a time** — Run these commands one at a time, waiting for the `ESTADO:` line of each
|
|
249
|
+
before the next — never in parallel or in the background (each one reads and rewrites the same file).
|
|
250
|
+
- **Values** — `{name}`: the crew code. `{N}`: how many steps will run, checkpoints included (a
|
|
251
|
+
deselected agent's steps do not count). `{K}`: the step's position among them, from 1. `{id}`: the agent's `id` column in
|
|
252
|
+
`crew-party.csv`; a step or checkpoint with no `agent:` goes without `--agente`
|
|
253
|
+
(the table shows the full form). `{rótulo}`: the step's name, in
|
|
254
|
+
a few words. `--mensagem` goes only when the agent changed since the last `passo` (so never on the first
|
|
255
|
+
one): one sentence on what the previous agent delivered — never look at the next step. `{motivo}`: why the run stopped.
|
|
256
|
+
- **Text on the command line** — `--rotulo`, `--mensagem` and `--motivo` go between double quotes,
|
|
257
|
+
on one line, starting with a letter or a digit, with only letters (accents included), digits,
|
|
258
|
+
spaces and `. , : ; - ( ) / ?`. Drop every other sign (quotes of any kind, `$`, backtick, `\`,
|
|
259
|
+
`%`, `!`, emoji). If no text is left, omit the option. Write them in the user's language.
|
|
260
|
+
- **After `iniciar`**, when it answers `ESTADO:OK`, show the user once:
|
|
261
|
+
`Escritório ligado. Se a página não estiver aberta, rode em outro terminal: node _opencrew/core/scripts/escritorio.mjs`
|
|
262
|
+
- **The Escritório never stops the run.** A command that fails, does not run or answers
|
|
263
|
+
`ESTADO:IGNORADO`: go on, do not repeat that event, ask nothing, and tell the user once per run,
|
|
264
|
+
in one line: `O escritório não foi atualizado nesta execução; o trabalho segue normalmente.` With
|
|
265
|
+
the reason "escritório desligado", say nothing and stop calling the script for the rest of this run.
|
|
266
|
+
- The script is the only writer: never read, write or describe `crews/{name}/state.json` yourself.
|
|
282
267
|
|
|
283
268
|
## Execution Rules
|
|
284
269
|
|
|
@@ -388,11 +373,9 @@ Before executing any step that references an agent:
|
|
|
388
373
|
To prevent linear token growth across multi-agent pipelines, apply context compression
|
|
389
374
|
when passing prior agents' outputs as context:
|
|
390
375
|
|
|
391
|
-
1. **TL;DR extraction**: After each agent completes, check if its output contains a `## TL;DR` section
|
|
376
|
+
1. **TL;DR extraction**: After each agent completes, check if its output contains a `## TL;DR` section
|
|
377
|
+
(a line starting with `## TL;DR` — you have the output, no command is needed).
|
|
392
378
|
If present, extract and store it separately as the agent's summary.
|
|
393
|
-
```bash
|
|
394
|
-
grep -q "^## TL;DR" "{outputFile}" && echo "HAS_TLDR" || echo "NO_TLDR"
|
|
395
|
-
```
|
|
396
379
|
|
|
397
380
|
2. **Compressed context assembly**: When preparing context for Agent N:
|
|
398
381
|
- Include **TL;DR summaries** from Agents 1 through N-2 (all agents except the direct predecessor)
|
|
@@ -450,7 +433,7 @@ When an agent's `.agent.md` frontmatter contains a `tasks:` field:
|
|
|
450
433
|
e. Check task veto conditions (same enforcement as step veto conditions below)
|
|
451
434
|
|
|
452
435
|
3. **Final output**: The output of the LAST task in the chain becomes the step's output
|
|
453
|
-
-
|
|
436
|
+
- Resolve the `outputFile` path with the `saida` command (Output Path Transformation) before saving — this applies regardless of whether the step runs as `execution: inline` or `execution: subagent`
|
|
454
437
|
- Save to the **transformed** outputFile path
|
|
455
438
|
- This is what the next step (or checkpoint) receives
|
|
456
439
|
|
|
@@ -464,86 +447,63 @@ When an agent's `.agent.md` frontmatter contains a `tasks:` field:
|
|
|
464
447
|
|
|
465
448
|
### Output Path Transformation
|
|
466
449
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
450
|
+
The path of every file of the run comes from one script (`caminho.mjs`), the same on every system —
|
|
451
|
+
never from a path you put together, never from a shell command of your own. Run from the project
|
|
452
|
+
root the one-line command of each moment and read the last line (`CAMINHO:OK {path}`,
|
|
453
|
+
`CAMINHO:FALTA {path}` or `CAMINHO:REPROVADO {motivo}`):
|
|
454
|
+
|
|
455
|
+
| Moment | Command |
|
|
456
|
+
|---|---|
|
|
457
|
+
| Start of the run (Initialization, step 5b) | `node _opencrew/core/scripts/caminho.mjs "{name}" pasta --run "{run_id}"` |
|
|
458
|
+
| Before a step, for its `inputFile` | `node _opencrew/core/scripts/caminho.mjs "{name}" entrada --run "{run_id}" --arquivo "{inputFile}"` |
|
|
459
|
+
| Before a step writes, for the first `outputFile` of each group | `node _opencrew/core/scripts/caminho.mjs "{name}" saida --run "{run_id}" --arquivo "{outputFile}"` |
|
|
460
|
+
| After a step wrote, for each output file | `node _opencrew/core/scripts/caminho.mjs "{name}" conferir --arquivo "{path}"` |
|
|
461
|
+
|
|
462
|
+
- **Values** — `{name}`: the crew code. `{inputFile}` / `{outputFile}`: the path as the step
|
|
463
|
+
declares it (raw, without the run_id). `{path}`: the path `saida` returned. The safe-name rule
|
|
464
|
+
(nome seguro) applies: the crew and every path between double quotes.
|
|
465
|
+
- **`saida`** answers with the **transformed** path and creates its folder: write the file there,
|
|
466
|
+
never to the raw path. Run it once per group in a step — the other `outputFile`s of the same
|
|
467
|
+
group reuse the version folder it returned, and a file written twice in a step goes to the same path.
|
|
468
|
+
- **`entrada`** answers with the newest output of that file: use the path it returns, whatever
|
|
469
|
+
its version folder.
|
|
470
|
+
- **The rule the script applies** (apply it yourself only when the script does not run):
|
|
471
|
+
1. A declared path that starts with `crews/{name}/output/` gets `{run_id}/` right after
|
|
472
|
+
`output/`; any other path stays as declared, with no version folder.
|
|
473
|
+
2. The **group** is the folder of the file, run_id included (`…/output/{run_id}/`, or
|
|
474
|
+
`…/output/{run_id}/slides/`). A step writes to the group's next version folder: the highest
|
|
475
|
+
`vN` there plus 1, or `v1` when there is none — numeric order (`v10` comes after `v9`), gaps
|
|
476
|
+
not filled (`v1` and `v3` → `v4`).
|
|
477
|
+
3. A step reads the newest version that has the file: from the highest `vN` down, the first
|
|
478
|
+
where the file exists and is not empty; then the group itself, with no version folder (where
|
|
479
|
+
checkpoint answers live).
|
|
480
|
+
|
|
481
|
+
Example, one group: the researcher writes `…/v1/pesquisa.md`, the writer writes `…/v2/post.md`
|
|
482
|
+
and reads `…/v1/pesquisa.md`. Never assume `v1`.
|
|
483
|
+
- **Script that does not run** (no Node, an error, or no `CAMINHO:` line): tell the user once per
|
|
484
|
+
run `Não consegui rodar a conferência de caminhos; sigo pela regra escrita e marco os arquivos como não verificados.`,
|
|
485
|
+
build the path by the rule above (the Write tool creates the folder) and continue. A file handled
|
|
486
|
+
this way skips its gate and is listed at the final approval:
|
|
487
|
+
`{arquivo} — não verificado: a conferência de caminhos não rodou`.
|
|
501
488
|
|
|
502
489
|
### For each pipeline step:
|
|
503
490
|
|
|
504
491
|
0. **Agent deselection check** — Read the step's `agent:` frontmatter field.
|
|
505
492
|
- If the step has an `agent:` value present AND it is in `skipped_agents` →
|
|
506
493
|
announce `⏭️ Skipping {Agent Name} (deselected for this run)` and skip this
|
|
507
|
-
step ENTIRELY: no
|
|
508
|
-
validation, no veto, no output file
|
|
494
|
+
step ENTIRELY: no Escritório command, no input validation, no execution, no output
|
|
495
|
+
validation, no veto, no output file. Advance to the next step in
|
|
509
496
|
`filtered_steps`.
|
|
510
497
|
- Checkpoints that declare `agent:` and whose agent was deselected are skipped the
|
|
511
498
|
same way. Checkpoints with no `agent:` field always run (backward compatible).
|
|
512
499
|
- When the selection step was skipped (no `agent_dependencies:`), `skipped_agents`
|
|
513
500
|
is empty → this check never fires (legacy behavior).
|
|
514
501
|
|
|
515
|
-
0b. **
|
|
516
|
-
```json
|
|
517
|
-
{
|
|
518
|
-
"crew": "{crew code from crew.yaml}",
|
|
519
|
-
"status": "running",
|
|
520
|
-
"step": {
|
|
521
|
-
"current": {1-based index of this step},
|
|
522
|
-
"total": {total steps in pipeline},
|
|
523
|
-
"label": "{step id or label}"
|
|
524
|
-
},
|
|
525
|
-
"agents": [
|
|
526
|
-
{
|
|
527
|
-
"id": "{agent id}",
|
|
528
|
-
"name": "{agent displayName}",
|
|
529
|
-
"icon": "{agent icon}",
|
|
530
|
-
"status": "{working if this is the current step's agent, done if already completed, skipped if in skipped_agents, idle otherwise}",
|
|
531
|
-
"desk": {preserve existing desk positions from state.json — do not change col/row}
|
|
532
|
-
}
|
|
533
|
-
],
|
|
534
|
-
"handoff": {preserve existing handoff object, or null if this is the first step},
|
|
535
|
-
"startedAt": "{ISO timestamp — set on the first step only, then preserve from existing state.json on subsequent steps}",
|
|
536
|
-
"updatedAt": "{ISO timestamp now}"
|
|
537
|
-
}
|
|
538
|
-
```
|
|
502
|
+
0b. **Escritório** — if it is on, run `passo`, or `checkpoint` when the step is a checkpoint (see "Escritório" above).
|
|
539
503
|
|
|
540
|
-
1. **Pre-Step Input Validation** — MANDATORY. If the step's frontmatter declares an `inputFile`, validate that the input exists before executing the step. Run
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
```
|
|
544
|
-
- Apply the Output Path Transformation (Step 1: run_id injection) to the `inputFile` path before running the check.
|
|
545
|
-
- If the Bash output contains `VALIDATION:PASS` → proceed to execute the step.
|
|
546
|
-
- If the Bash output contains `VALIDATION:FAIL` → do NOT execute the step. Present to user:
|
|
504
|
+
1. **Pre-Step Input Validation** — MANDATORY. If the step's frontmatter declares an `inputFile`, the input comes from the `entrada` action, never from a path you build: validate that the input exists before executing the step. Run the `entrada` command (Output Path Transformation) with the `inputFile` as declared:
|
|
505
|
+
- `CAMINHO:OK {path}` → that path is the step's input (the newest version that has the file): read the input from it and execute the step.
|
|
506
|
+
- `CAMINHO:FALTA {path}` → do NOT execute the step. Present to user:
|
|
547
507
|
```
|
|
548
508
|
⚠️ Input for {Agent Name} not found: {path}
|
|
549
509
|
The previous step may have failed to produce output.
|
|
@@ -562,7 +522,7 @@ Apply this transformation consistently for every write in this step.
|
|
|
562
522
|
- Inform user: `🔍 {Agent Name} is working in the background...`
|
|
563
523
|
- Read the step's `model_tier` frontmatter field (if present).
|
|
564
524
|
Valid values: `fast` or `powerful`. If absent or any other value: default to `powerful`.
|
|
565
|
-
- **Before building the subagent prompt**:
|
|
525
|
+
- **Before building the subagent prompt**: Resolve all output paths referenced in the step file with the `saida` command (Output Path Transformation, once per group). Store the transformed path(s) in working memory — they will be used both in the prompt and in post-completion verification. Never pass raw paths from the step file to the subagent.
|
|
566
526
|
- Use the Task tool to dispatch the step as a subagent:
|
|
567
527
|
- If `model_tier: fast`: use the fastest/lightest model available in your current IDE.
|
|
568
528
|
- If `model_tier: powerful` or absent/invalid: use the default model (no model override needed)
|
|
@@ -574,7 +534,7 @@ Apply this transformation consistently for every write in this step.
|
|
|
574
534
|
- The veto conditions from the step file (agent should self-check before completing)
|
|
575
535
|
- The company context
|
|
576
536
|
- The crew memory
|
|
577
|
-
- The **transformed** path to save output (e.g
|
|
537
|
+
- The **transformed** path to save output (the one `saida` returned, e.g. `crews/{name}/output/2026-03-20-140736/slides/v2/draft.md`)
|
|
578
538
|
- Wait for the subagent to complete
|
|
579
539
|
- Inform user: `✓ {Agent Name} completed`
|
|
580
540
|
- Proceed to Post-Step Output Validation (below) before advancing.
|
|
@@ -584,13 +544,13 @@ Apply this transformation consistently for every write in this step.
|
|
|
584
544
|
- Announce: `{icon} {Agent Name} is working...`
|
|
585
545
|
- Follow the step instructions
|
|
586
546
|
- Present output directly in the conversation
|
|
587
|
-
- Save output to the specified output file —
|
|
547
|
+
- Save output to the specified output file — resolve the path with the `saida` command (Output Path Transformation) before writing. Do not write to the raw path from the step file.
|
|
588
548
|
- Proceed to Post-Step Output Validation (below) before advancing.
|
|
589
549
|
|
|
590
550
|
#### If `type: checkpoint`
|
|
591
551
|
- Present the checkpoint message to the user
|
|
592
552
|
- If the checkpoint requires a choice (numbered list), present options as a numbered list
|
|
593
|
-
- **Always include the file path** of any generated content the user needs to review. Example: "Review the content at `crews/{name}/output/{run_id}/
|
|
553
|
+
- **Always include the file path** of any generated content the user needs to review. Example: "Review the content at `crews/{name}/output/{run_id}/v2/content.md` and let me know if it looks good." (the path the script returned)
|
|
594
554
|
- Wait for user input before proceeding
|
|
595
555
|
- Save the user's choice/response for the next step
|
|
596
556
|
- **Correction → memory, right away**: if the answer corrects something (tone, audience, a term,
|
|
@@ -603,7 +563,7 @@ Apply this transformation consistently for every write in this step.
|
|
|
603
563
|
(e.g. the organization's name, the main audience), ask: "Isso vale para todas as crews?
|
|
604
564
|
Atualizo o perfil da empresa?" — change `company.md` only after a yes.
|
|
605
565
|
- **If the step frontmatter contains `outputFile`**: after collecting the user's full response,
|
|
606
|
-
|
|
566
|
+
insert only the run_id in the `outputFile` path (item 1 of the rule in Output Path Transformation — no version folder, no `saida` command), then write the response to that path using the Write tool (it creates the folder) before moving to the next step. Checkpoint files are user input captures, not versioned output: they live in the group itself, where `entrada` finds them.
|
|
607
567
|
Use this format:
|
|
608
568
|
```
|
|
609
569
|
# Research Focus
|
|
@@ -616,28 +576,22 @@ Apply this transformation consistently for every write in this step.
|
|
|
616
576
|
|
|
617
577
|
### Post-Step Output Validation
|
|
618
578
|
|
|
619
|
-
After a step produces output (subagent or inline) and BEFORE Veto Condition Enforcement, the runner MUST validate that the declared output files exist and are non-empty. This is a binary, non-negotiable gate — the runner does NOT proceed on memory or assumption, only on
|
|
620
|
-
|
|
621
|
-
**If the step declares an `outputFile`** (single or multiple), run via Bash tool for EACH output file:
|
|
579
|
+
After a step produces output (subagent or inline) and BEFORE Veto Condition Enforcement, the runner MUST validate that the declared output files exist and are non-empty. This is a binary, non-negotiable gate — the runner does NOT proceed on memory or assumption, only on the script's `CAMINHO:` line.
|
|
622
580
|
|
|
623
|
-
|
|
624
|
-
test -s "{transformed outputFile path}" && echo "VALIDATION:PASS" || echo "VALIDATION:FAIL"
|
|
625
|
-
```
|
|
581
|
+
**If the step declares an `outputFile`** (single or multiple), run the `conferir` command (Output Path Transformation) for EACH output file, with the **stored transformed path** (the one `saida` returned), not the raw path from the step file. A step with an `output_contract:` adds its options to this same call (see Output Contract Validation): one command per file.
|
|
626
582
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
**Rules:**
|
|
630
|
-
- If ALL output files return `VALIDATION:PASS` → proceed to Veto Condition Enforcement.
|
|
583
|
+
**Rules** (`FAIL` below = the last line is `CAMINHO:REPROVADO arquivo ausente ou vazio`):
|
|
584
|
+
- If ALL output files return `CAMINHO:OK` → proceed to Veto Condition Enforcement.
|
|
631
585
|
- **Irreversible step** (`side_effects: irreversible` — publish, post, send) with ANY
|
|
632
|
-
`
|
|
586
|
+
`FAIL` → NEVER re-execute it. Tell the user: "⚠️ {Agent Name} did not save its
|
|
633
587
|
output, but the action may already have happened (post published / email sent). Check
|
|
634
588
|
before retrying." Then offer: 1. Retry step (only after the user checked) · 2. Mark as done
|
|
635
589
|
and continue · 3. Abort pipeline.
|
|
636
|
-
- If ANY output file returns `
|
|
590
|
+
- If ANY output file returns `FAIL` (any other step):
|
|
637
591
|
1. **Retry once**: re-execute the entire step with the same input and context.
|
|
638
592
|
2. After re-execution, run the validation again for all output files.
|
|
639
|
-
3. If second attempt returns `
|
|
640
|
-
4. If second attempt still has ANY `
|
|
593
|
+
3. If second attempt returns `CAMINHO:OK` for all files → proceed normally.
|
|
594
|
+
4. If second attempt still has ANY `FAIL` → present to user:
|
|
641
595
|
```
|
|
642
596
|
⚠️ {Agent Name}'s output was not generated: {path}
|
|
643
597
|
|
|
@@ -649,26 +603,23 @@ Use the **stored transformed path** (after Output Path Transformation Steps 1 an
|
|
|
649
603
|
- If the step does not declare an `outputFile` (e.g., steps that only produce inline console output) → skip output validation.
|
|
650
604
|
- Checkpoint steps (`type: checkpoint`) are exempt — their output is the user's response, not a file.
|
|
651
605
|
|
|
652
|
-
**IMPORTANT**: Do NOT rely on reading the file with the Read tool to "verify" output. The Read tool returns content that can be misinterpreted. Use ONLY the
|
|
606
|
+
**IMPORTANT**: Do NOT rely on reading the file with the Read tool to "verify" output. The Read tool returns content that can be misinterpreted. Use ONLY the `conferir` command — its last line is binary and cannot be hallucinated.
|
|
653
607
|
|
|
654
608
|
### Output Contract Validation
|
|
655
609
|
|
|
656
610
|
If the step's frontmatter declares an `output_contract:` field, apply structured validation
|
|
657
|
-
|
|
611
|
+
in the same call as the basic file existence check (Post-Step Output Validation):
|
|
658
612
|
|
|
659
|
-
1. **Required sections check**: If `output_contract.required_sections` is defined,
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
grep -c "^## " "{transformed outputFile path}" | xargs -I {} test {} -ge {min_sections} && echo "SECTIONS:PASS" || echo "SECTIONS:FAIL"
|
|
663
|
-
```
|
|
613
|
+
1. **Required sections check**: If `output_contract.required_sections` is defined, add
|
|
614
|
+
`--secoes {min_sections}` to the same `conferir` command: the file needs at least that many
|
|
615
|
+
lines starting with `## `.
|
|
664
616
|
|
|
665
|
-
2. **TL;DR check**: If the output contract requires a TL;DR section
|
|
666
|
-
|
|
667
|
-
grep -q "^## TL;DR" "{transformed outputFile path}" && echo "TLDR:PASS" || echo "TLDR:FAIL"
|
|
668
|
-
```
|
|
617
|
+
2. **TL;DR check**: If the output contract requires a TL;DR section, add `--tldr` to the same
|
|
618
|
+
`conferir` command.
|
|
669
619
|
|
|
670
|
-
3. **If
|
|
671
|
-
|
|
620
|
+
3. **If a check fails** (the last line is `CAMINHO:REPROVADO {motivo}`, with a motivo other than
|
|
621
|
+
`arquivo ausente ou vazio`; the script reports the first one):
|
|
622
|
+
- Present to user: "⚠️ Output from {Agent Name} is incomplete: {motivo}"
|
|
672
623
|
- Options as numbered list:
|
|
673
624
|
1. Accept anyway and continue
|
|
674
625
|
2. Retry step (re-execute the agent)
|
|
@@ -752,85 +703,34 @@ When a step has `on_reject: {step-id}` (a review step):
|
|
|
752
703
|
lines under each file, not the "não é texto" line of **Notas**), one per line as
|
|
753
704
|
`{arquivo} — {motivo}`, then the lines under `**Notas:**` in that report, as they are written,
|
|
754
705
|
and repeat every "não rodou" warning of this run (checker and source check) and the line of
|
|
755
|
-
every file left unchecked by the safe-name rule.
|
|
706
|
+
every file left unchecked by the safe-name rule. List the same way every file the path script
|
|
707
|
+
did not check (see Output Path Transformation). If the approved
|
|
756
708
|
text still contains `[PREENCHER: …]`, ask the user for each missing piece of real information
|
|
757
709
|
and write it into the text before approving.
|
|
758
710
|
|
|
759
|
-
### Dashboard Handoff (between steps)
|
|
760
|
-
|
|
761
|
-
Only if `dashboard_enabled` (otherwise skip this entire section). After a step
|
|
762
|
-
completes output and there IS a next step:
|
|
763
|
-
|
|
764
|
-
1. **Write delivering state** — Write `crews/{name}/state.json` with:
|
|
765
|
-
- Current step's agent: `"status": "delivering"`
|
|
766
|
-
- Next step's agent: `"status": "idle"`
|
|
767
|
-
- All other agents unchanged
|
|
768
|
-
- Pipeline `"status": "running"`
|
|
769
|
-
- Add or update `"handoff"`:
|
|
770
|
-
```json
|
|
771
|
-
"handoff": {
|
|
772
|
-
"from": "{current agent id}",
|
|
773
|
-
"to": "{next agent id}",
|
|
774
|
-
"message": "{one-sentence summary of what was produced, written in the user's language}",
|
|
775
|
-
"completedAt": "{ISO timestamp now}"
|
|
776
|
-
}
|
|
777
|
-
```
|
|
778
|
-
- `"updatedAt"`: now
|
|
779
|
-
|
|
780
|
-
2. _(No delay — proceed immediately to working state)_
|
|
781
|
-
|
|
782
|
-
2. **Write working state** — Write `crews/{name}/state.json` again with:
|
|
783
|
-
- Current agent: `"status": "done"`
|
|
784
|
-
- Next agent: `"status": "working"`
|
|
785
|
-
- Keep the `"handoff"` object from step 1 unchanged
|
|
786
|
-
- `"updatedAt"`: now
|
|
787
|
-
|
|
788
711
|
### Step Execution Order (Summary)
|
|
789
712
|
|
|
790
713
|
For reference, the complete execution order for each pipeline step is:
|
|
791
714
|
|
|
792
715
|
```
|
|
793
716
|
0. Agent deselection check (skip step if its agent was deselected)
|
|
794
|
-
0b.
|
|
795
|
-
1. Pre-Step Input Validation (
|
|
717
|
+
0b. Escritório command (passo or checkpoint) — only if it is on
|
|
718
|
+
1. Pre-Step Input Validation (script gate: `entrada`)
|
|
796
719
|
2. Read step file
|
|
797
720
|
3. Check execution mode and execute (subagent / inline / checkpoint)
|
|
798
|
-
4. Post-Step Output Validation (
|
|
721
|
+
4. Post-Step Output Validation (script gate: `conferir`)
|
|
799
722
|
5. Veto Condition Enforcement
|
|
800
|
-
6. Dashboard Handoff (to next step) — only if dashboard_enabled
|
|
801
723
|
```
|
|
802
724
|
|
|
803
|
-
Steps 1 and 4 are binary
|
|
725
|
+
Steps 1 and 4 are binary script gates. If either fails, the pipeline does NOT advance — the user is consulted.
|
|
804
726
|
|
|
805
727
|
### After Pipeline Completion
|
|
806
728
|
|
|
807
729
|
1. Save final output to `crews/{name}/output/{run_id}/{filename}.md`
|
|
808
730
|
(The run folder was created during initialization — no separate date subfolder needed)
|
|
809
|
-
1b. **
|
|
810
|
-
- `"status": "completed"`
|
|
811
|
-
- All agents: `"status": "done"`
|
|
812
|
-
- `"updatedAt"`: now
|
|
813
|
-
- `"completedAt"`: now
|
|
814
|
-
- `"startedAt"`: preserve from existing `state.json`
|
|
815
|
-
- Keep existing `"handoff"` object
|
|
816
|
-
|
|
817
|
-
### Post-Completion Cleanup (only if `dashboard_enabled`)
|
|
818
|
-
|
|
819
|
-
After writing the final "completed" state to `crews/{name}/state.json`:
|
|
820
|
-
|
|
821
|
-
1. Add the `completedAt` field (or `failedAt` if status is `failed`) with the current ISO timestamp
|
|
822
|
-
2. Copy `state.json` to the run output folder for permanent history:
|
|
823
|
-
```bash
|
|
824
|
-
cp "crews/{name}/state.json" "crews/{name}/output/{run_id}/state.json"
|
|
825
|
-
```
|
|
826
|
-
3. Leave the working copy of `crews/{name}/state.json` in place — do not delete it and
|
|
827
|
-
do not add an artificial delay. A dashboard watching the file already sees the
|
|
828
|
-
"completed" status the moment it's written; the next run's initialization (step 6)
|
|
829
|
-
overwrites this file from scratch. There is nothing to clean up.
|
|
830
|
-
|
|
831
|
-
This archives the run state for the `runs` command while keeping crew history available.
|
|
731
|
+
1b. **Escritório** — if it is on, run `concluir` (see "Escritório" above).
|
|
832
732
|
|
|
833
|
-
2. **Update crew memory** — write to BOTH files
|
|
733
|
+
2. **Update crew memory** — write to BOTH files:
|
|
834
734
|
|
|
835
735
|
### 2a. Update `memories.md` (living preferences)
|
|
836
736
|
|
|
@@ -947,6 +847,7 @@ This archives the run state for the `runs` command while keeping crew history av
|
|
|
947
847
|
- If a step file is missing, inform the user and suggest running `/opencrew edit {crew}` to fix.
|
|
948
848
|
- If company.md is empty, stop and redirect to onboarding.
|
|
949
849
|
- Never continue past a checkpoint without user input.
|
|
850
|
+
- When the run is aborted: if the Escritório is on, run `falhar` (see "Escritório" above).
|
|
950
851
|
|
|
951
852
|
## Pipeline State
|
|
952
853
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Linha de comando do `caminho.mjs`: a crew, a ação, as opções e a linha de uso.
|
|
2
|
+
// Spec: fase-r3-runner-em-uso-real.md, §3 e §6 (repositório do OpenCrew).
|
|
3
|
+
import { MSG } from '../comum.mjs';
|
|
4
|
+
import { ACOES } from './nucleo.mjs';
|
|
5
|
+
|
|
6
|
+
export const USO = 'Uso: node _opencrew/core/scripts/caminho.mjs <crew> <ação> --run <id> [opções]';
|
|
7
|
+
|
|
8
|
+
const LISTA = ACOES.join(', ');
|
|
9
|
+
const OPCAO = /^--(run|arquivo|secoes|tldr)(?:=(.*))?$/s;
|
|
10
|
+
const RUN = /^(?!\.+$)[A-Za-z0-9._-]+$/;
|
|
11
|
+
const INTEIRO = /^[1-9]\d{0,8}$/;
|
|
12
|
+
|
|
13
|
+
/** Texto que veio da linha de comando e volta numa mensagem: uma linha só, até 200 caracteres. */
|
|
14
|
+
export const limpar = (valor) => String(valor).replace(/\s+/g, ' ').trim().slice(0, 200);
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* `argv` → `{ crew, acao, run, arquivo, secoes, tldr }`. Os dois primeiros argumentos soltos são
|
|
18
|
+
* a crew e a ação. Opção vale como `--nome valor` e `--nome=valor`; `--tldr` não leva valor.
|
|
19
|
+
* Opção ausente fica `undefined`.
|
|
20
|
+
*/
|
|
21
|
+
export function lerArgs(argv) {
|
|
22
|
+
const soltos = [];
|
|
23
|
+
const opcoes = {};
|
|
24
|
+
for (let i = 0; i < argv.length; i++) {
|
|
25
|
+
const [, nome, colado] = argv[i].match(OPCAO) ?? [];
|
|
26
|
+
if (!nome) soltos.push(argv[i]);
|
|
27
|
+
else if (nome === 'tldr') opcoes.tldr = true;
|
|
28
|
+
else if (colado !== undefined) opcoes[nome] = colado;
|
|
29
|
+
else opcoes[nome] = i + 1 < argv.length && !OPCAO.test(argv[i + 1]) ? argv[++i] : '';
|
|
30
|
+
}
|
|
31
|
+
const [crew, acao] = soltos.filter((s) => !s.startsWith('--'));
|
|
32
|
+
return { crew, acao, tldr: false, ...opcoes };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* O que falta ou está errado na linha de comando, antes de olhar o disco. `conferir` recebe um
|
|
37
|
+
* caminho já resolvido: é a única ação que não precisa de `--run`.
|
|
38
|
+
* @returns {string|null} o motivo em PT-BR, ou `null`
|
|
39
|
+
*/
|
|
40
|
+
export function erroDeArgumentos({ crew, acao, run, arquivo, secoes }) {
|
|
41
|
+
if (!crew) return 'Falta o nome da crew.';
|
|
42
|
+
if (!acao) return `Falta a ação. Ações: ${LISTA}.`;
|
|
43
|
+
if (!ACOES.includes(acao)) return `Ação desconhecida: ${limpar(acao)}. Ações: ${LISTA}.`;
|
|
44
|
+
if (acao !== 'conferir' && !run) return MSG.faltaOpcao('--run');
|
|
45
|
+
if (run !== undefined && !RUN.test(run)) return 'O --run só aceita letras, dígitos, ponto, sublinhado e hífen.';
|
|
46
|
+
if (acao !== 'pasta' && !arquivo) return MSG.faltaOpcao('--arquivo');
|
|
47
|
+
if (secoes !== undefined && !INTEIRO.test(secoes)) return 'O --secoes é um número inteiro a partir de 1.';
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// O que o `caminho.mjs` faz no disco: lê nomes de pastas, confere se um arquivo tem conteúdo, lê
|
|
2
|
+
// um arquivo e cria pastas. Nunca cria, altera nem apaga arquivo.
|
|
3
|
+
// Spec: fase-r3-runner-em-uso-real.md, regra 6 (repositório do OpenCrew).
|
|
4
|
+
import { mkdirSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
5
|
+
|
|
6
|
+
/** Os nomes das pastas que ficam direto em `pasta`; pasta que não existe não tem nenhuma. */
|
|
7
|
+
export function pastasDe(pasta) {
|
|
8
|
+
try {
|
|
9
|
+
return readdirSync(pasta, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
10
|
+
} catch {
|
|
11
|
+
return [];
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function ehPasta(caminho) {
|
|
16
|
+
try {
|
|
17
|
+
return statSync(caminho).isDirectory();
|
|
18
|
+
} catch {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** É um arquivo, existe e não está vazio? */
|
|
24
|
+
export function temConteudo(arquivo) {
|
|
25
|
+
try {
|
|
26
|
+
const info = statSync(arquivo);
|
|
27
|
+
return info.isFile() && info.size > 0;
|
|
28
|
+
} catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const lerTexto = (arquivo) => readFileSync(arquivo, 'utf8');
|
|
34
|
+
|
|
35
|
+
/** Cria a pasta com as pastas-mãe; pasta que já existe não é erro. */
|
|
36
|
+
export const criarPasta = (pasta) => { mkdirSync(pasta, { recursive: true }); };
|