@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.
@@ -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:assemble`, `squad:agent-create`, `squad:refresh`.
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 assemble compliance
116
-
117
- # Or via CLI
118
- npx @jaimevalasek/aioson squad:assemble compliance
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:create`)
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:create . --squad=my-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:assemble`, `squad:agent-create`, `squad:refresh`.
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 28 agentes, em que momento cada um entra, e como eles se conversam.
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 28 agentes oficiais (product, analyst, dev, qa, etc.). Suficiente para 95% dos projetos.
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 assemble compliance
116
-
117
- # Ou via CLI
118
- npx @jaimevalasek/aioson squad:assemble compliance
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 28 agentes, com situação de uso e saída esperada.
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
- | [@architect](./architect.md) | Decide stack, estrutura, integração técnica | Após `@analyst` | `architecture.md` (técnico) |
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/` |
@@ -10,7 +10,7 @@
10
10
 
11
11
  ## Para que serve
12
12
 
13
- Você passou por `@product`, `@analyst`, `@architect`. 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?".
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 `@architect` (SMALL/MEDIUM) ou `@product` (MICRO).
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
- Plano aprovado. Implementando:
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:** `@architect` (SMALL/MEDIUM) ou `@product` (MICRO)
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:assemble <slug>
99
-
100
- # Atualizar squad existente (breadth-aware)
101
- aioson squad:refresh <slug>
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
- @devcarrega minimum context package implementa fase por fase
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-checkconfronta 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
- | `implementation-plan-{slug}.md` | Se plano existe |
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 28 agentes](../4-agentes/README.md) — quando usar cada agente e o que ele entrega
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:create`)
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:create . --squad=meu-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 28 agentes](./4-agentes/README.md)** — uma ficha por agente, com diálogo típico, saídas em disco e handoff
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
 
@@ -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
- @architect projetos SMALL e MEDIUM
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:refresh` if implemented).
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jaimevalasek/aioson",
3
- "version": "1.21.6",
3
+ "version": "1.21.7",
4
4
  "description": "AI operating framework for hyper-personalized software.",
5
5
  "keywords": [
6
6
  "ai",
@@ -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 { db, dbPath, runtimeDir, context } = await requireActiveLiveContext(targetDir, agentName, t, {
1578
- limit: options.limit
1579
- });
1580
-
1581
- try {
1582
- const now = new Date().toISOString();
1583
- const refs = parseRefs(options.refs);
1584
- const planStep = options['plan-step'] ? String(options['plan-step']).trim() : null;
1585
- const summary = truncateMessage(
1586
- options.summary || options.message || options.title || `${eventType} emitted by ${agentName}`
1587
- );
1588
- const meta = parseJsonOption(options.meta);
1589
- const payload = meta && typeof meta === 'object' ? { ...meta } : {};
1590
- if (refs.length > 0) payload.refs = refs;
1591
- if (planStep) payload.plan_step = planStep;
1592
-
1593
- const state = context.state || createLiveState(targetDir, context.run, context.task, {
1594
- sessionKey: context.sessionKey,
1595
- activeAgent: context.agentName,
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
- completed.push(normalizeAgentName(stage));
475
- }
476
- return completed;
477
- }
478
-
479
- // SF-project-18: cross-check workflow.state.json#completed against runtime
480
- // telemetry. Stages claimed as completed without a corresponding agent_done
481
- // event in .aioson/runtime/aios.sqlite are surfaced as a warning. Detection
482
- // is best-effort — if the runtime DB is unavailable, the check is silently
483
- // skipped (the framework still works in environments without telemetry).
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
- if (reconciled.changed) {
564
- await writeJson(statePath, reconciled.state);
565
- }
566
- return { statePath, state: reconciled.state, created: false };
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);
@@ -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
- const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
295
- if (!fmMatch) return { ok: false, reason: 'no_frontmatter' };
296
-
297
- const fm = {};
298
- for (const line of fmMatch[1].split(/\r?\n/)) {
299
- const idx = line.indexOf(':');
300
- if (idx === -1) continue;
301
- const key = line.slice(0, idx).trim();
302
- const val = line.slice(idx + 1).trim().replace(/^["']|["']$/g, '');
303
- if (key) fm[key] = val;
304
- }
305
-
306
- // Check explicit gate field
307
- const gateVal = fm[`gate_${gateName}`] || fm[`gate${gateLetter}`] || fm[`gate_${gateLetter}`];
308
- if (gateVal && gateVal.toLowerCase() === 'approved') {
309
- return { ok: true };
310
- }
311
-
312
- // Check phase_gates JSON
313
- if (fm.phase_gates) {
314
- try {
315
- const parsed = JSON.parse(fm.phase_gates.replace(/'/g, '"'));
316
- if (parsed[gateName] === 'approved') return { ok: true };
317
- } catch {
318
- // ignore
319
- }
320
- }
321
-
322
- // Check content for gate approval lines
323
- const gateLineRe = new RegExp(`gate\\s+${gateLetter}[^:]*:\\s*approved`, 'i');
324
- if (gateLineRe.test(content)) {
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 commands (not yet implemented — placeholders)
1882
-
1883
- | Command | Status | Function |
1884
- |---------|--------|----------|
1885
- | `aioson genome:enrich --slug=<slug> --source=<file>` | not implemented | Enrichment Round (currently runs via `@genome` agent conversation only) |
1886
- | `aioson genome:export --slug=<slug> --as=system-prompt` | not implemented | Export Track 4.3 system-prompt.md (currently runs via `@genome` agent only) |
1887
- | `aioson genome:viability --slug=<slug>` | not implemented | Standalone Viability Gate scoring (currently part of `@genome` Step 0.5) |
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
- Every `aioson` CLI command in an agent file MUST end with `2>/dev/null || true` to prevent silent failures from breaking the session.
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
- The ONLY exception is commands inside "Quick start" or "Prerequisites" sections where the user runs them manually (not the agent).
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