@jaimevalasek/aioson 1.21.6 → 1.21.7
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/docs/en/1-understand/glossary.md +1 -1
- package/docs/en/2-start/initial-decisions.md +7 -7
- package/docs/en/5-reference/squad-dashboard.md +5 -5
- package/docs/pt/1-entender/glossario.md +1 -1
- package/docs/pt/1-entender/mapa-do-ecossistema.md +1 -1
- package/docs/pt/2-comecar/decisoes-iniciais.md +6 -6
- package/docs/pt/4-agentes/README.md +5 -4
- package/docs/pt/4-agentes/dev.md +4 -4
- package/docs/pt/4-agentes/squad.md +10 -10
- package/docs/pt/5-referencia/fluxo-artefatos.md +15 -11
- package/docs/pt/5-referencia/squad-dashboard.md +5 -5
- package/docs/pt/README.md +1 -1
- package/docs/pt/agentes.md +8 -7
- package/docs/pt/living-memory/troubleshooting.md +1 -1
- package/package.json +1 -1
- package/src/commands/live.js +115 -26
- package/src/commands/workflow-next.js +70 -28
- package/src/handoff-contract.js +49 -41
- package/template/.aioson/agents/genome.md +9 -9
- package/template/.aioson/rules/agent-structural-contract.md +21 -2
|
@@ -255,7 +255,7 @@ Terms in alphabetical order. Each entry has a **short definition** + **concrete
|
|
|
255
255
|
|
|
256
256
|
**Example:** a "legal compliance" squad with agents `@regulator`, `@attorney`, `@auditor`, under the command of `@squad`.
|
|
257
257
|
|
|
258
|
-
**Commands:** `aioson squad:
|
|
258
|
+
**Commands:** `aioson squad:scaffold`, `squad:agent-create`, `squad:doctor`.
|
|
259
259
|
|
|
260
260
|
---
|
|
261
261
|
|
|
@@ -110,13 +110,13 @@ Adds the squad system — you can create custom squads for domains outside the s
|
|
|
110
110
|
- `@attorney` — interprets clauses
|
|
111
111
|
- `@auditor` — checks conformity
|
|
112
112
|
|
|
113
|
-
```bash
|
|
114
|
-
# Inside the AI client
|
|
115
|
-
> @squad
|
|
116
|
-
|
|
117
|
-
# Or via CLI
|
|
118
|
-
npx @jaimevalasek/aioson squad:
|
|
119
|
-
```
|
|
113
|
+
```bash
|
|
114
|
+
# Inside the AI client
|
|
115
|
+
> @squad scaffold compliance
|
|
116
|
+
|
|
117
|
+
# Or via CLI
|
|
118
|
+
npx @jaimevalasek/aioson squad:scaffold . --slug=compliance --name="Compliance" --mode=mixed
|
|
119
|
+
```
|
|
120
120
|
|
|
121
121
|
**When to activate Squads:**
|
|
122
122
|
- You know you'll need specialization outside the standard
|
|
@@ -9,7 +9,7 @@ No additional installation required. It ships with aioson.
|
|
|
9
9
|
## Prerequisites
|
|
10
10
|
|
|
11
11
|
- aioson installed globally (`npm install -g @jaimevalasek/aioson`)
|
|
12
|
-
- At least one squad created in the project (`aioson squad:
|
|
12
|
+
- At least one squad created in the project (`aioson squad:scaffold . --slug=<slug>`)
|
|
13
13
|
- Node.js ≥ 18 (already required by aioson)
|
|
14
14
|
- A modern browser (Chrome, Firefox, Safari, Edge)
|
|
15
15
|
|
|
@@ -330,10 +330,10 @@ Check that the manifest exists:
|
|
|
330
330
|
ls .aioson/squads/*/squad.manifest.json
|
|
331
331
|
```
|
|
332
332
|
|
|
333
|
-
If not, create the squad first:
|
|
334
|
-
```bash
|
|
335
|
-
aioson squad:
|
|
336
|
-
```
|
|
333
|
+
If not, create the squad first:
|
|
334
|
+
```bash
|
|
335
|
+
aioson squad:scaffold . --slug=my-squad --name="My Squad" --mode=mixed
|
|
336
|
+
```
|
|
337
337
|
|
|
338
338
|
### Panels appear empty
|
|
339
339
|
|
|
@@ -255,7 +255,7 @@ Termos em ordem alfabética. Cada um tem **definição curta** + **exemplo concr
|
|
|
255
255
|
|
|
256
256
|
**Exemplo:** squad "compliance jurídico" com agentes `@regulator`, `@attorney`, `@auditor`, sob comando do `@squad`.
|
|
257
257
|
|
|
258
|
-
**Comandos:** `aioson squad:
|
|
258
|
+
**Comandos:** `aioson squad:scaffold`, `squad:agent-create`, `squad:doctor`.
|
|
259
259
|
|
|
260
260
|
---
|
|
261
261
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> **Para quem é:** quem quer ver o time inteiro de uma vez.
|
|
4
4
|
> **Tempo de leitura:** 8 min.
|
|
5
|
-
> **O que você vai sair sabendo:** quem são os
|
|
5
|
+
> **O que você vai sair sabendo:** quem são os 29 agentes, em que momento cada um entra, e como eles se conversam.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -99,7 +99,7 @@ Você pode marcar **mais de um** no wizard — eles convivem no mesmo projeto.
|
|
|
99
99
|
|
|
100
100
|
### Development (padrão)
|
|
101
101
|
|
|
102
|
-
Inclui os
|
|
102
|
+
Inclui os 29 agentes oficiais (product, analyst, dev, qa, etc.). Suficiente para 95% dos projetos.
|
|
103
103
|
|
|
104
104
|
### Development + Squads
|
|
105
105
|
|
|
@@ -111,11 +111,11 @@ Adiciona o sistema de squads — você pode criar squads customizados para domí
|
|
|
111
111
|
- `@auditor` — checa conformidade
|
|
112
112
|
|
|
113
113
|
```bash
|
|
114
|
-
# Dentro do cliente AI
|
|
115
|
-
> @squad
|
|
116
|
-
|
|
117
|
-
# Ou via CLI
|
|
118
|
-
npx @jaimevalasek/aioson squad:
|
|
114
|
+
# Dentro do cliente AI
|
|
115
|
+
> @squad montar compliance
|
|
116
|
+
|
|
117
|
+
# Ou via CLI
|
|
118
|
+
npx @jaimevalasek/aioson squad:scaffold compliance
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
**Quando ativar Squads:**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Guia de Agentes AIOSON
|
|
2
2
|
|
|
3
|
-
> Índice completo dos
|
|
3
|
+
> Índice completo dos 29 agentes, com situação de uso e saída esperada.
|
|
4
4
|
> Cada agente tem sua ficha — clique no nome para detalhes.
|
|
5
5
|
|
|
6
6
|
---
|
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
|
|
10
10
|
| Agente | Para que serve | Quando invocar | Saída principal |
|
|
11
11
|
|---|---|---|---|
|
|
12
|
-
| [@product](./product.md) | Define visão, PRD e escopo da feature | Início de projeto ou nova feature | `prd.md`, `spec.md` |
|
|
13
|
-
| [@analyst](./analyst.md) | Descobre domínio, entidades, fluxos | Após `@product`, antes de `@architect` | `architecture.md` (domínio) |
|
|
14
|
-
| [@
|
|
12
|
+
| [@product](./product.md) | Define visão, PRD e escopo da feature | Início de projeto ou nova feature | `prd.md`, `spec.md` |
|
|
13
|
+
| [@analyst](./analyst.md) | Descobre domínio, entidades, fluxos | Após `@product`, antes de `@architect` | `architecture.md` (domínio) |
|
|
14
|
+
| [@scope-check](./scope-check.md) | Confronta intenção, plano e artefatos antes do código | Antes de `@dev` e após fixes relevantes | `scope-check.md` |
|
|
15
|
+
| [@architect](./architect.md) | Decide stack, estrutura, integração técnica | Após `@analyst` | `architecture.md` (técnico) |
|
|
15
16
|
| [@ux-ui](./ux-ui.md) | Design system e specs de componentes | MEDIUM, após `@architect` | `design-doc.md`, `discovery.md` |
|
|
16
17
|
| [@pm](./pm.md) | Backlog, user stories, ACs detalhados | MEDIUM, após `@ux-ui` | `tasks.md` |
|
|
17
18
|
| [@orchestrator](./orchestrator.md) | Coordena lanes paralelas de implementação | MEDIUM, após `@pm` | `.aioson/context/parallel/` |
|
package/docs/pt/4-agentes/dev.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
## Para que serve
|
|
12
12
|
|
|
13
|
-
Você passou por `@product`, `@analyst`, `@architect
|
|
13
|
+
Você passou por `@product`, `@analyst`, `@architect` e, nos fluxos SMALL/MEDIUM atuais, por `@scope-check` antes de abrir implementação. A spec existe, as decisões técnicas estão em disco. Agora é hora de escrever código — mas de forma que o próximo agente (`@qa`, `@validator`) consiga verificar o que foi feito sem perguntar "o que você implementou?".
|
|
14
14
|
|
|
15
15
|
`@dev` lê os artefatos, implementa, e grava um `dev-state.md` com o resumo do que foi feito, quais arquivos foram tocados, e qual é o próximo passo. Isso é o que permite continuar de onde parou em outra sessão, sem depender do histórico de chat.
|
|
16
16
|
|
|
@@ -20,7 +20,7 @@ Você passou por `@product`, `@analyst`, `@architect`. A spec existe, as decisõ
|
|
|
20
20
|
|
|
21
21
|
## Quando invocar
|
|
22
22
|
|
|
23
|
-
- Após `@
|
|
23
|
+
- Após `@scope-check` (SMALL/MEDIUM) ou `@product` (MICRO).
|
|
24
24
|
- Para retomar uma feature interrompida — `@dev` lê `dev-state.md` e sabe onde parou.
|
|
25
25
|
- Para correções apontadas pelo `@qa` (ciclo autônomo, até 2 iterações).
|
|
26
26
|
|
|
@@ -43,7 +43,7 @@ Você > @dev
|
|
|
43
43
|
Lendo project.context.md... Node.js, SMALL, checkout-stripe.
|
|
44
44
|
Lendo spec-checkout-stripe.md e implementation-plan-checkout-stripe.md...
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
Scope-check aprovado. Implementando:
|
|
47
47
|
|
|
48
48
|
1. db/migrations/add-payment-table.sql ← Payment schema
|
|
49
49
|
2. src/models/payment.js ← model com validação básica
|
|
@@ -124,7 +124,7 @@ aioson memory:summary . --last=5
|
|
|
124
124
|
|
|
125
125
|
## Handoff típico
|
|
126
126
|
|
|
127
|
-
- **Vem de:** `@
|
|
127
|
+
- **Vem de:** `@scope-check` (SMALL/MEDIUM) ou `@product` (MICRO)
|
|
128
128
|
- **Vai para:** `@qa`
|
|
129
129
|
|
|
130
130
|
---
|
|
@@ -93,16 +93,16 @@ Antes de criar, o `@squad` lê:
|
|
|
93
93
|
|
|
94
94
|
## Comandos CLI relacionados
|
|
95
95
|
|
|
96
|
-
```bash
|
|
97
|
-
# Criar squad via CLI
|
|
98
|
-
aioson squad:
|
|
99
|
-
|
|
100
|
-
#
|
|
101
|
-
aioson squad:
|
|
102
|
-
|
|
103
|
-
# Publicar no aioson.com
|
|
104
|
-
aioson system:publish --type=squad --slug=<slug>
|
|
105
|
-
```
|
|
96
|
+
```bash
|
|
97
|
+
# Criar squad via CLI
|
|
98
|
+
aioson squad:scaffold . --slug=<slug> --name="Meu Squad" --mode=mixed
|
|
99
|
+
|
|
100
|
+
# Diagnosticar squad existente
|
|
101
|
+
aioson squad:doctor . --squad=<slug>
|
|
102
|
+
|
|
103
|
+
# Publicar no aioson.com
|
|
104
|
+
aioson system:publish --type=squad --slug=<slug>
|
|
105
|
+
```
|
|
106
106
|
|
|
107
107
|
---
|
|
108
108
|
|
|
@@ -11,12 +11,15 @@ Cada agente produz arquivos que os agentes subsequentes leem. Nenhum agente lê
|
|
|
11
11
|
```
|
|
12
12
|
@product → prd.md / prd-{slug}.md
|
|
13
13
|
↓
|
|
14
|
-
@sheldon (N rodadas) → enriquece PRD + gera sheldon-enrichment-{slug}.md
|
|
15
|
-
pode criar .aioson/plans/{slug}/manifest.md + plan-{fase}.md
|
|
16
|
-
↓
|
|
17
|
-
@analyst → lê sheldon-enrichment → discovery.md / requirements-{slug}.md + spec-{slug}.md
|
|
18
|
-
↓
|
|
19
|
-
@
|
|
14
|
+
@sheldon (N rodadas) → enriquece PRD + gera sheldon-enrichment-{slug}.md
|
|
15
|
+
pode criar .aioson/plans/{slug}/manifest.md + plan-{fase}.md
|
|
16
|
+
↓
|
|
17
|
+
@analyst → lê sheldon-enrichment → discovery.md / requirements-{slug}.md + spec-{slug}.md
|
|
18
|
+
↓
|
|
19
|
+
@scope-check → confronta intenção, plano e artefatos antes do código
|
|
20
|
+
gera scope-check-{slug}.md quando a feature é nomeada
|
|
21
|
+
↓
|
|
22
|
+
@dev → carrega minimum context package → implementa fase por fase
|
|
20
23
|
```
|
|
21
24
|
|
|
22
25
|
---
|
|
@@ -86,7 +89,7 @@ O `spec-{slug}.md` é o **artefato de handoff para @dev** — ele inclui as deci
|
|
|
86
89
|
| Modo | O que @dev carrega |
|
|
87
90
|
|---|---|
|
|
88
91
|
| Feature MICRO | `project.context.md` + `prd-{slug}.md` |
|
|
89
|
-
| Feature SMALL/MEDIUM | `project.context.md` + `spec-{slug}.md` + `implementation-plan-{slug}.md` |
|
|
92
|
+
| Feature SMALL/MEDIUM | `project.context.md` + `spec-{slug}.md` + `scope-check-{slug}.md` + `implementation-plan-{slug}.md` |
|
|
90
93
|
| Feature com plano do Sheldon | `project.context.md` + `spec-{slug}.md` + `.aioson/plans/{slug}/manifest.md` + arquivo da fase atual |
|
|
91
94
|
| Modo projeto | `project.context.md` + `spec.md` + `skeleton-system.md` |
|
|
92
95
|
|
|
@@ -157,9 +160,10 @@ Esta é a lista completa de arquivos que @dev pode consultar em qualquer sessão
|
|
|
157
160
|
|---|---|
|
|
158
161
|
| `project.context.md` | Sempre |
|
|
159
162
|
| `dev-state.md` | Sempre (se existir — define o restante) |
|
|
160
|
-
| `features.md` | Cold start apenas |
|
|
161
|
-
| `spec-{slug}.md` | Feature ativa |
|
|
162
|
-
| `
|
|
163
|
+
| `features.md` | Cold start apenas |
|
|
164
|
+
| `spec-{slug}.md` | Feature ativa |
|
|
165
|
+
| `scope-check-{slug}.md` | Antes da primeira implementação e após fixes relevantes |
|
|
166
|
+
| `implementation-plan-{slug}.md` | Se plano existe |
|
|
163
167
|
| `.aioson/plans/{slug}/manifest.md` + fase atual | Se plano Sheldon existe |
|
|
164
168
|
| `skeleton-system.md` | Só ao navegar estrutura do projeto |
|
|
165
169
|
| `design-doc.md` | Só se listado no plano |
|
|
@@ -173,7 +177,7 @@ Esta é a lista completa de arquivos que @dev pode consultar em qualquer sessão
|
|
|
173
177
|
|
|
174
178
|
## Veja também
|
|
175
179
|
|
|
176
|
-
- [Fichas dos
|
|
180
|
+
- [Fichas dos 29 agentes](../4-agentes/README.md) — quando usar cada agente e o que ele entrega
|
|
177
181
|
- [Receitas práticas](../3-receitas/README.md) — exemplos end-to-end por cenário
|
|
178
182
|
- [Continuidade entre sessões](../3-receitas/continuidade-entre-sessoes.md) — feature dossier, dev-resume, drift detection
|
|
179
183
|
- [Feature Archive](./feature-archive.md) — o que acontece com os artefatos quando a feature fecha
|
|
@@ -9,7 +9,7 @@ Não requer instalação adicional. Vem incluso quando você instala o aioson.
|
|
|
9
9
|
## Pré-requisitos
|
|
10
10
|
|
|
11
11
|
- aioson instalado globalmente (`npm install -g @jaimevalasek/aioson`)
|
|
12
|
-
- Pelo menos um squad criado no projeto (`aioson squad:
|
|
12
|
+
- Pelo menos um squad criado no projeto (`aioson squad:scaffold . --slug=<slug>`)
|
|
13
13
|
- Node.js ≥ 18 (já exigido pelo aioson)
|
|
14
14
|
- Browser moderno (Chrome, Firefox, Safari, Edge)
|
|
15
15
|
|
|
@@ -331,10 +331,10 @@ Verifique se o manifest existe:
|
|
|
331
331
|
ls .aioson/squads/*/squad.manifest.json
|
|
332
332
|
```
|
|
333
333
|
|
|
334
|
-
Se não existir, crie o squad primeiro:
|
|
335
|
-
```bash
|
|
336
|
-
aioson squad:
|
|
337
|
-
```
|
|
334
|
+
Se não existir, crie o squad primeiro:
|
|
335
|
+
```bash
|
|
336
|
+
aioson squad:scaffold . --slug=meu-squad --name="Meu Squad" --mode=mixed
|
|
337
|
+
```
|
|
338
338
|
|
|
339
339
|
### Painéis aparecem vazios
|
|
340
340
|
|
package/docs/pt/README.md
CHANGED
|
@@ -37,7 +37,7 @@ Esta é a porta de entrada da documentação em português. Não é um índice a
|
|
|
37
37
|
11. [Continuidade entre sessões](./3-receitas/continuidade-entre-sessoes.md) — feature dossier, dev-resume, drift detection
|
|
38
38
|
|
|
39
39
|
### Quero a referência técnica de um agente ou comando
|
|
40
|
-
- **[Fichas dos
|
|
40
|
+
- **[Fichas dos 29 agentes](./4-agentes/README.md)** — uma ficha por agente, com diálogo típico, saídas em disco e handoff
|
|
41
41
|
- **[Referência técnica completa](./5-referencia/README.md)** — 32 docs organizados em 5 categorias (novos 2026, artefatos, CLI/config, agentes/squads, skills/design)
|
|
42
42
|
- [Guia de agentes (legado)](./agentes.md) — visão tabular alternativa
|
|
43
43
|
|
package/docs/pt/agentes.md
CHANGED
|
@@ -13,10 +13,11 @@ O AIOSON tem agentes oficiais de projeto e também pode criar agentes de squad.
|
|
|
13
13
|
```
|
|
14
14
|
@setup ← sempre o primeiro
|
|
15
15
|
@product ← gera o PRD base vivo e roteia o fluxo
|
|
16
|
-
@deyvin ← companheiro tecnico para continuidade e pequenas implementacoes
|
|
17
|
-
@discovery-design-doc ← quando precisa clarear escopo e gerar design doc vivo
|
|
18
|
-
@analyst ← projetos SMALL e MEDIUM
|
|
19
|
-
@
|
|
16
|
+
@deyvin ← companheiro tecnico para continuidade e pequenas implementacoes
|
|
17
|
+
@discovery-design-doc ← quando precisa clarear escopo e gerar design doc vivo
|
|
18
|
+
@analyst ← projetos SMALL e MEDIUM
|
|
19
|
+
@scope-check ← valida alinhamento antes de codar ou depois de fix relevante
|
|
20
|
+
@architect ← projetos SMALL e MEDIUM
|
|
20
21
|
@ux-ui ← UI/UX quando há interfaces (SMALL e MEDIUM)
|
|
21
22
|
@pm ← apenas MEDIUM
|
|
22
23
|
@orchestrator ← apenas MEDIUM
|
|
@@ -52,9 +53,9 @@ O AIOSON tem agentes oficiais de projeto e também pode criar agentes de squad.
|
|
|
52
53
|
|
|
53
54
|
Quando o projeto ja existe e voce roda `scan:project`, o handoff correto agora e:
|
|
54
55
|
|
|
55
|
-
```text
|
|
56
|
-
scan:project -> @analyst -> @architect -> @dev
|
|
57
|
-
```
|
|
56
|
+
```text
|
|
57
|
+
scan:project -> @analyst -> @scope-check -> @architect -> @dev
|
|
58
|
+
```
|
|
58
59
|
|
|
59
60
|
Regras do fluxo:
|
|
60
61
|
- os artefatos locais do scan (`scan-index.md`, `scan-folders.md`, `scan-<pasta>.md`, `scan-aioson.md`) servem como mapas brutos do codigo
|
|
@@ -44,7 +44,7 @@ aioson memory:status .
|
|
|
44
44
|
|
|
45
45
|
```
|
|
46
46
|
[FAIL] Bootstrap coverage: 4/4
|
|
47
|
-
Hint: Run /discover to refresh the bootstrap files (or `aioson memory:
|
|
47
|
+
Hint: Run /discover to refresh the bootstrap files (or `aioson memory:reflect-prepare . --agent=dev` for manual reflection).
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
(Repare: cobertura 4/4 mas advisório por estar antigo — a hint detecta via `generated_at`.)
|
package/package.json
CHANGED
package/src/commands/live.js
CHANGED
|
@@ -1569,30 +1569,58 @@ async function runLiveStart({ args, options = {}, logger, t }) {
|
|
|
1569
1569
|
}
|
|
1570
1570
|
}
|
|
1571
1571
|
|
|
1572
|
-
async function runRuntimeEmit({ args, options = {}, logger, t }) {
|
|
1573
|
-
const targetDir = resolveTargetDir(args);
|
|
1574
|
-
const agentName = normalizeAgentHandle(requireOption(options, 'agent', t));
|
|
1575
|
-
const eventType = String(options.type || 'note').trim() || 'note';
|
|
1576
|
-
|
|
1577
|
-
const
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1572
|
+
async function runRuntimeEmit({ args, options = {}, logger, t }) {
|
|
1573
|
+
const targetDir = resolveTargetDir(args);
|
|
1574
|
+
const agentName = normalizeAgentHandle(requireOption(options, 'agent', t));
|
|
1575
|
+
const eventType = String(options.type || 'note').trim() || 'note';
|
|
1576
|
+
const now = new Date().toISOString();
|
|
1577
|
+
const refs = parseRefs(options.refs);
|
|
1578
|
+
const planStep = options['plan-step'] ? String(options['plan-step']).trim() : null;
|
|
1579
|
+
const summary = truncateMessage(
|
|
1580
|
+
options.summary || options.message || options.title || `${eventType} emitted by ${agentName}`
|
|
1581
|
+
);
|
|
1582
|
+
const meta = parseJsonOption(options.meta);
|
|
1583
|
+
const payload = meta && typeof meta === 'object' ? { ...meta } : {};
|
|
1584
|
+
if (refs.length > 0) payload.refs = refs;
|
|
1585
|
+
if (planStep) payload.plan_step = planStep;
|
|
1586
|
+
|
|
1587
|
+
let liveHandle;
|
|
1588
|
+
if (await runtimeStoreExists(targetDir)) {
|
|
1589
|
+
try {
|
|
1590
|
+
liveHandle = await requireActiveLiveContext(targetDir, agentName, t, {
|
|
1591
|
+
limit: options.limit
|
|
1592
|
+
});
|
|
1593
|
+
} catch (err) {
|
|
1594
|
+
const noActive = t('live.no_active_session', { agent: agentName });
|
|
1595
|
+
const notActive = t('live.session_not_active', { agent: agentName });
|
|
1596
|
+
if (err && !(err.message === noActive || err.message === notActive)) {
|
|
1597
|
+
throw err;
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
if (!liveHandle) {
|
|
1603
|
+
const standalone = await emitStandaloneRuntimeEvent({
|
|
1604
|
+
targetDir,
|
|
1605
|
+
agentName,
|
|
1606
|
+
eventType,
|
|
1607
|
+
summary,
|
|
1608
|
+
payload,
|
|
1609
|
+
options,
|
|
1610
|
+
now
|
|
1611
|
+
});
|
|
1612
|
+
if (!options.json) {
|
|
1613
|
+
logger.log(`runtime:emit — ${agentName} | standalone event logged | run: ${standalone.runKey} (${standalone.dbPath})`);
|
|
1614
|
+
}
|
|
1615
|
+
return standalone;
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
const { db, dbPath, runtimeDir, context } = liveHandle;
|
|
1619
|
+
|
|
1620
|
+
try {
|
|
1621
|
+
const state = context.state || createLiveState(targetDir, context.run, context.task, {
|
|
1622
|
+
sessionKey: context.sessionKey,
|
|
1623
|
+
activeAgent: context.agentName,
|
|
1596
1624
|
projectPath: targetDir
|
|
1597
1625
|
});
|
|
1598
1626
|
|
|
@@ -1730,8 +1758,69 @@ async function runRuntimeEmit({ args, options = {}, logger, t }) {
|
|
|
1730
1758
|
};
|
|
1731
1759
|
} finally {
|
|
1732
1760
|
db.close();
|
|
1733
|
-
}
|
|
1734
|
-
}
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
async function emitStandaloneRuntimeEvent({
|
|
1765
|
+
targetDir,
|
|
1766
|
+
agentName,
|
|
1767
|
+
eventType,
|
|
1768
|
+
summary,
|
|
1769
|
+
payload,
|
|
1770
|
+
options = {},
|
|
1771
|
+
now
|
|
1772
|
+
}) {
|
|
1773
|
+
const { db, dbPath } = await openRuntimeDb(targetDir);
|
|
1774
|
+
try {
|
|
1775
|
+
const taskKey = startTask(db, {
|
|
1776
|
+
title: options.title ? String(options.title).trim() : `runtime:emit ${agentName}`,
|
|
1777
|
+
goal: summary,
|
|
1778
|
+
status: 'completed',
|
|
1779
|
+
createdBy: agentName,
|
|
1780
|
+
taskKind: 'runtime_event',
|
|
1781
|
+
metaJson: {
|
|
1782
|
+
mode: 'standalone',
|
|
1783
|
+
reason: 'no_active_live_session'
|
|
1784
|
+
}
|
|
1785
|
+
});
|
|
1786
|
+
const runKey = startRun(db, {
|
|
1787
|
+
taskKey,
|
|
1788
|
+
agentName,
|
|
1789
|
+
agentKind: 'official',
|
|
1790
|
+
source: 'direct',
|
|
1791
|
+
title: options.title ? String(options.title).trim() : `runtime:emit ${agentName}`,
|
|
1792
|
+
status: 'completed',
|
|
1793
|
+
summary,
|
|
1794
|
+
eventType,
|
|
1795
|
+
phase: 'direct',
|
|
1796
|
+
message: summary,
|
|
1797
|
+
payload: Object.keys(payload).length > 0 ? {
|
|
1798
|
+
...payload,
|
|
1799
|
+
standalone: true,
|
|
1800
|
+
reason: 'no_active_live_session'
|
|
1801
|
+
} : {
|
|
1802
|
+
standalone: true,
|
|
1803
|
+
reason: 'no_active_live_session'
|
|
1804
|
+
}
|
|
1805
|
+
});
|
|
1806
|
+
|
|
1807
|
+
return {
|
|
1808
|
+
ok: true,
|
|
1809
|
+
targetDir,
|
|
1810
|
+
dbPath,
|
|
1811
|
+
agent: agentName,
|
|
1812
|
+
eventType,
|
|
1813
|
+
sessionKey: null,
|
|
1814
|
+
runKey,
|
|
1815
|
+
taskKey,
|
|
1816
|
+
currentTask: null,
|
|
1817
|
+
open: false,
|
|
1818
|
+
standalone: true
|
|
1819
|
+
};
|
|
1820
|
+
} finally {
|
|
1821
|
+
db.close();
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1735
1824
|
|
|
1736
1825
|
|
|
1737
1826
|
async function runLiveHandoff({ args, options = {}, logger, t }) {
|
|
@@ -465,22 +465,58 @@ function buildQaSecurityAuditBriefing(result, targetDir) {
|
|
|
465
465
|
].join('\n');
|
|
466
466
|
}
|
|
467
467
|
|
|
468
|
-
async function inferCompletedStages(targetDir, draftState) {
|
|
469
|
-
const completed = [];
|
|
470
|
-
for (const stage of draftState.sequence) {
|
|
471
|
-
if (!isInferableStage(stage)) break;
|
|
472
|
-
const valid = await validateStageArtifacts(targetDir, draftState, stage);
|
|
473
|
-
if (!valid) break;
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
468
|
+
async function inferCompletedStages(targetDir, draftState) {
|
|
469
|
+
const completed = [];
|
|
470
|
+
for (const stage of draftState.sequence) {
|
|
471
|
+
if (!isInferableStage(stage)) break;
|
|
472
|
+
const valid = await validateStageArtifacts(targetDir, draftState, stage);
|
|
473
|
+
if (!valid) break;
|
|
474
|
+
const contractCheck = await validateHandoffContract(targetDir, draftState, normalizeAgentName(stage));
|
|
475
|
+
if (!contractCheck.ok) break;
|
|
476
|
+
completed.push(normalizeAgentName(stage));
|
|
477
|
+
}
|
|
478
|
+
return completed;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function mergeInferredCompletedStages(state, inferredCompleted) {
|
|
482
|
+
if (!state || !Array.isArray(state.sequence) || !Array.isArray(inferredCompleted)) {
|
|
483
|
+
return { state, changed: false };
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
const sequence = state.sequence.map(normalizeAgentName);
|
|
487
|
+
const completedSet = new Set((state.completed || []).map(normalizeAgentName).filter(Boolean));
|
|
488
|
+
const skippedSet = new Set((state.skipped || []).map(normalizeAgentName).filter(Boolean));
|
|
489
|
+
let changed = false;
|
|
490
|
+
|
|
491
|
+
for (const stage of inferredCompleted.map(normalizeAgentName).filter(Boolean)) {
|
|
492
|
+
if (!sequence.includes(stage)) continue;
|
|
493
|
+
if (!completedSet.has(stage)) {
|
|
494
|
+
completedSet.add(stage);
|
|
495
|
+
changed = true;
|
|
496
|
+
}
|
|
497
|
+
if (skippedSet.delete(stage)) {
|
|
498
|
+
changed = true;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
if (!changed) return { state, changed: false };
|
|
503
|
+
|
|
504
|
+
return {
|
|
505
|
+
changed: true,
|
|
506
|
+
state: buildStatePayload({
|
|
507
|
+
...state,
|
|
508
|
+
sequence,
|
|
509
|
+
completed: sequence.filter((stage) => completedSet.has(stage)),
|
|
510
|
+
skipped: sequence.filter((stage) => skippedSet.has(stage))
|
|
511
|
+
})
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// SF-project-18: cross-check workflow.state.json#completed against runtime
|
|
516
|
+
// telemetry. Stages claimed as completed without a corresponding agent_done
|
|
517
|
+
// event in .aioson/runtime/aios.sqlite are surfaced as a warning. Detection
|
|
518
|
+
// is best-effort — if the runtime DB is unavailable, the check is silently
|
|
519
|
+
// skipped (the framework still works in environments without telemetry).
|
|
484
520
|
async function detectUnsubstantiatedCompletions(targetDir, completedStages, logger = null) {
|
|
485
521
|
if (!Array.isArray(completedStages) || completedStages.length === 0) return [];
|
|
486
522
|
let runtimeStore;
|
|
@@ -553,18 +589,24 @@ async function loadOrCreateState(targetDir, options = {}) {
|
|
|
553
589
|
}
|
|
554
590
|
}
|
|
555
591
|
|
|
556
|
-
if (existing && typeof existing === 'object' && Array.isArray(existing.sequence)) {
|
|
557
|
-
// SF-project-18: warn-on-mismatch only, never refuse — preserves
|
|
558
|
-
// backwards-compat with environments that lack runtime telemetry.
|
|
559
|
-
if (Array.isArray(existing.completed) && existing.completed.length > 0 && options.logger) {
|
|
560
|
-
await detectUnsubstantiatedCompletions(targetDir, existing.completed, options.logger);
|
|
561
|
-
}
|
|
562
|
-
const reconciled = reconcileWorkflowState(existing);
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
592
|
+
if (existing && typeof existing === 'object' && Array.isArray(existing.sequence)) {
|
|
593
|
+
// SF-project-18: warn-on-mismatch only, never refuse — preserves
|
|
594
|
+
// backwards-compat with environments that lack runtime telemetry.
|
|
595
|
+
if (Array.isArray(existing.completed) && existing.completed.length > 0 && options.logger) {
|
|
596
|
+
await detectUnsubstantiatedCompletions(targetDir, existing.completed, options.logger);
|
|
597
|
+
}
|
|
598
|
+
const reconciled = reconcileWorkflowState(existing);
|
|
599
|
+
const inferredCompleted = (reconciled.state.current || (reconciled.state.detour && reconciled.state.detour.active))
|
|
600
|
+
? []
|
|
601
|
+
: await inferCompletedStages(targetDir, reconciled.state);
|
|
602
|
+
const merged = mergeInferredCompletedStages(reconciled.state, inferredCompleted);
|
|
603
|
+
const finalReconciled = merged.changed ? reconcileWorkflowState(merged.state) : reconciled;
|
|
604
|
+
const changed = reconciled.changed || merged.changed || finalReconciled.changed;
|
|
605
|
+
if (changed) {
|
|
606
|
+
await writeJson(statePath, finalReconciled.state);
|
|
607
|
+
}
|
|
608
|
+
return { statePath, state: finalReconciled.state, created: false };
|
|
609
|
+
}
|
|
568
610
|
|
|
569
611
|
const context = await validateProjectContextFile(targetDir);
|
|
570
612
|
const modeInfo = await detectWorkflowMode(targetDir);
|
package/src/handoff-contract.js
CHANGED
|
@@ -287,41 +287,49 @@ async function checkGateApproval(targetDir, gateLetter, slug, classification, pr
|
|
|
287
287
|
return { ok: false, reason: 'spec_missing' };
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
-
const gateNames = { A: 'requirements', B: 'design', C: 'plan', D: 'execution' };
|
|
291
|
-
const gateName = gateNames[gateLetter];
|
|
292
|
-
|
|
293
|
-
// Parse frontmatter
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
const
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
290
|
+
const gateNames = { A: 'requirements', B: 'design', C: 'plan', D: 'execution' };
|
|
291
|
+
const gateName = gateNames[gateLetter];
|
|
292
|
+
|
|
293
|
+
// Parse frontmatter when present. Explicit gate fields take precedence over
|
|
294
|
+
// free-text gate lines so `gate_requirements: pending` cannot be overridden
|
|
295
|
+
// accidentally by stale prose elsewhere in the spec.
|
|
296
|
+
const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
297
|
+
if (fmMatch) {
|
|
298
|
+
const fm = {};
|
|
299
|
+
for (const line of fmMatch[1].split(/\r?\n/)) {
|
|
300
|
+
const idx = line.indexOf(':');
|
|
301
|
+
if (idx === -1) continue;
|
|
302
|
+
const key = line.slice(0, idx).trim();
|
|
303
|
+
const val = line.slice(idx + 1).trim().replace(/^["']|["']$/g, '');
|
|
304
|
+
if (key) fm[key] = val;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Check explicit gate field
|
|
308
|
+
const gateVal = fm[`gate_${gateName}`] || fm[`gate${gateLetter}`] || fm[`gate_${gateLetter}`];
|
|
309
|
+
if (gateVal) {
|
|
310
|
+
return gateVal.toLowerCase() === 'approved'
|
|
311
|
+
? { ok: true }
|
|
312
|
+
: { ok: false, reason: `gate_${gateName}_not_approved` };
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Check phase_gates JSON
|
|
316
|
+
if (fm.phase_gates) {
|
|
317
|
+
try {
|
|
318
|
+
const parsed = JSON.parse(fm.phase_gates.replace(/'/g, '"'));
|
|
319
|
+
if (parsed[gateName]) {
|
|
320
|
+
return parsed[gateName] === 'approved'
|
|
321
|
+
? { ok: true }
|
|
322
|
+
: { ok: false, reason: `gate_${gateName}_not_approved` };
|
|
323
|
+
}
|
|
324
|
+
} catch {
|
|
325
|
+
// ignore
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Check content for gate approval lines
|
|
331
|
+
const gateLineRe = new RegExp(`gate\\s+${gateLetter}[^:]*:\\s*approved`, 'i');
|
|
332
|
+
if (gateLineRe.test(content)) {
|
|
325
333
|
return { ok: true };
|
|
326
334
|
}
|
|
327
335
|
|
|
@@ -331,12 +339,12 @@ async function checkGateApproval(targetDir, gateLetter, slug, classification, pr
|
|
|
331
339
|
const passMatch = content.match(/\*\*Verdict:\*\*\s*(PASS)/i);
|
|
332
340
|
if (passMatch) {
|
|
333
341
|
return { ok: true };
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
return { ok: false, reason: `gate_${gateName}_not_approved` };
|
|
339
|
-
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return { ok: false, reason: fmMatch ? `gate_${gateName}_not_approved` : 'no_frontmatter' };
|
|
347
|
+
}
|
|
340
348
|
|
|
341
349
|
async function validateHandoffContract(targetDir, state, stageName) {
|
|
342
350
|
const contract = CONTRACTS[stageName];
|
|
@@ -1878,15 +1878,15 @@ The CLI auto-detects format from response (`format` field, OR presence of `files
|
|
|
1878
1878
|
- **DB schema** — should track `format: "folder" | "single-file"` per genome to route response correctly
|
|
1879
1879
|
- **Migration** — backend may store folder format internally and convert to single-file on legacy installs (out of scope here)
|
|
1880
1880
|
|
|
1881
|
-
### Future CLI
|
|
1882
|
-
|
|
1883
|
-
|
|
|
1884
|
-
|
|
1885
|
-
| `
|
|
1886
|
-
| `
|
|
1887
|
-
| `
|
|
1888
|
-
|
|
1889
|
-
These are documented for future implementation. For now, the agent (`@genome`) handles them in-conversation.
|
|
1881
|
+
### Future CLI subcommands (not implemented — do not run)
|
|
1882
|
+
|
|
1883
|
+
| Future subcommand | Status | Function |
|
|
1884
|
+
|-------------------|--------|----------|
|
|
1885
|
+
| `genome:enrich` | not implemented | Enrichment Round (currently runs via `@genome` agent conversation only) |
|
|
1886
|
+
| `genome:export` | not implemented | Export Track 4.3 system-prompt.md (currently runs via `@genome` agent only) |
|
|
1887
|
+
| `genome:viability` | not implemented | Standalone Viability Gate scoring (currently part of `@genome` Step 0.5) |
|
|
1888
|
+
|
|
1889
|
+
These are documented for future implementation only. Do not run them as CLI commands until they are registered in `src/cli.js`. For now, the agent (`@genome`) handles them in-conversation.
|
|
1890
1890
|
|
|
1891
1891
|
## Continuation Protocol
|
|
1892
1892
|
|
|
@@ -84,13 +84,32 @@ Rules:
|
|
|
84
84
|
|
|
85
85
|
## 5. CLI error handling
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
Best-effort `aioson` CLI commands in agent files MUST end with `2>/dev/null || true` to prevent optional telemetry or context helpers from breaking the session when the CLI is unavailable.
|
|
88
88
|
|
|
89
89
|
```
|
|
90
90
|
aioson <command> . --flag=value 2>/dev/null || true
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
Do not silence blocking commands whose result controls safety, routing, or user action. These commands must run normally, and the agent must inspect their result before continuing.
|
|
94
|
+
|
|
95
|
+
Blocking examples:
|
|
96
|
+
- `aioson git:guard`
|
|
97
|
+
- `aioson commit:prepare`
|
|
98
|
+
- `aioson gate:check`
|
|
99
|
+
- `aioson preflight`
|
|
100
|
+
- `aioson workflow:status`
|
|
101
|
+
- `aioson context:validate`
|
|
102
|
+
|
|
103
|
+
Best-effort examples:
|
|
104
|
+
- `aioson runtime:emit`
|
|
105
|
+
- `aioson pulse:update`
|
|
106
|
+
- `aioson agent:done`
|
|
107
|
+
- `aioson dossier:*`
|
|
108
|
+
- `aioson memory:search`
|
|
109
|
+
- `aioson context:search`
|
|
110
|
+
- `aioson context:pack`
|
|
111
|
+
|
|
112
|
+
Commands inside "Quick start" or "Prerequisites" sections are user-run examples and do not need the best-effort suffix.
|
|
94
113
|
|
|
95
114
|
## 6. CLI flag integrity
|
|
96
115
|
|