oxe-cc 0.6.2 → 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/.github/prompts/oxe-loop.prompt.md +12 -12
  2. package/.github/prompts/oxe-project.prompt.md +12 -12
  3. package/.github/prompts/oxe-retro.prompt.md +12 -12
  4. package/.github/prompts/oxe-security.prompt.md +12 -12
  5. package/.github/prompts/oxe.prompt.md +12 -12
  6. package/AGENTS.md +75 -8
  7. package/CHANGELOG.md +74 -0
  8. package/README.md +323 -323
  9. package/bin/banner.txt +1 -1
  10. package/bin/lib/oxe-project-health.cjs +82 -0
  11. package/bin/oxe-cc.js +13 -1
  12. package/commands/oxe/loop.md +17 -17
  13. package/commands/oxe/oxe.md +16 -16
  14. package/commands/oxe/project.md +16 -16
  15. package/commands/oxe/retro.md +16 -16
  16. package/commands/oxe/review-pr.md +16 -0
  17. package/commands/oxe/security.md +16 -16
  18. package/commands/oxe/update.md +16 -0
  19. package/lib/sdk/index.cjs +22 -1
  20. package/lib/sdk/index.d.ts +28 -2
  21. package/oxe/schemas/plan-agents.schema.json +15 -4
  22. package/oxe/templates/CONFIG.md +6 -1
  23. package/oxe/templates/LESSONS.template.md +43 -43
  24. package/oxe/templates/SECURITY.template.md +72 -72
  25. package/oxe/templates/STATE.md +19 -1
  26. package/oxe/templates/config.template.json +2 -0
  27. package/oxe/templates/plan-agents.template.json +1 -0
  28. package/oxe/workflows/loop.md +57 -57
  29. package/oxe/workflows/next.md +4 -1
  30. package/oxe/workflows/obs.md +10 -0
  31. package/oxe/workflows/oxe.md +115 -115
  32. package/oxe/workflows/project.md +50 -50
  33. package/oxe/workflows/quick.md +1 -1
  34. package/oxe/workflows/retro.md +62 -62
  35. package/oxe/workflows/security.md +61 -61
  36. package/oxe/workflows/verify.md +2 -0
  37. package/package.json +2 -2
@@ -12,12 +12,14 @@ const ALLOWED_CONFIG_KEYS = [
12
12
  'default_verify_command',
13
13
  'scan_max_age_days',
14
14
  'compact_max_age_days',
15
+ 'lessons_max_age_days',
15
16
  'scan_focus_globs',
16
17
  'scan_ignore_globs',
17
18
  'spec_required_sections',
18
19
  'plan_max_tasks_per_wave',
19
20
  'profile',
20
21
  'verification_depth',
22
+ 'security_in_verify',
21
23
  'install',
22
24
  'plugins',
23
25
  'workstreams',
@@ -279,6 +281,18 @@ function parseLastCompactDate(stateText) {
279
281
  return null;
280
282
  }
281
283
 
284
+ /**
285
+ * Data do último `/oxe-retro` em STATE.md (campo `last_retro: YYYY-MM-DD`).
286
+ * @param {string} stateText
287
+ * @returns {Date | null}
288
+ */
289
+ function parseLastRetroDate(stateText) {
290
+ const m = stateText.match(/\blast_retro\s*:\s*(\d{4}-\d{2}-\d{2})/i);
291
+ if (!m) return null;
292
+ const iso = Date.parse(m[1]);
293
+ return Number.isNaN(iso) ? null : new Date(iso);
294
+ }
295
+
282
296
  /**
283
297
  * @param {Date | null} scanDate
284
298
  * @param {number} maxAgeDays 0 = desligado
@@ -289,6 +303,16 @@ function isStaleScan(scanDate, maxAgeDays) {
289
303
  return { stale: days > maxAgeDays, days: Math.floor(days) };
290
304
  }
291
305
 
306
+ /**
307
+ * Alias semântico para verificar se LESSONS.md está desatualizado.
308
+ * Reutiliza a lógica de isStaleScan.
309
+ * @param {Date | null} retroDate
310
+ * @param {number} maxAgeDays 0 = desligado
311
+ */
312
+ function isStaleLessons(retroDate, maxAgeDays) {
313
+ return isStaleScan(retroDate, maxAgeDays);
314
+ }
315
+
292
316
  /**
293
317
  * @param {string} target
294
318
  */
@@ -304,9 +328,45 @@ function oxePaths(target) {
304
328
  discuss: path.join(oxe, 'DISCUSS.md'),
305
329
  summary: path.join(oxe, 'SUMMARY.md'),
306
330
  codebase: path.join(oxe, 'codebase'),
331
+ lessons: path.join(oxe, 'LESSONS.md'),
332
+ planAgents: path.join(oxe, 'plan-agents.json'),
307
333
  };
308
334
  }
309
335
 
336
+ /**
337
+ * Valida o arquivo plan-agents.json (se existir) e retorna avisos.
338
+ * @param {string} target
339
+ * @returns {string[]}
340
+ */
341
+ function planAgentsWarnings(target) {
342
+ const p = oxePaths(target);
343
+ if (!fs.existsSync(p.planAgents)) return [];
344
+ /** @type {string[]} */
345
+ const warns = [];
346
+ let json;
347
+ try {
348
+ json = JSON.parse(fs.readFileSync(p.planAgents, 'utf8'));
349
+ } catch {
350
+ warns.push('plan-agents.json existe mas não é JSON válido');
351
+ return warns;
352
+ }
353
+ const schema = json.oxePlanAgentsSchema;
354
+ if (schema === 1) {
355
+ warns.push('plan-agents.json usa schema 1 (legado) — regere com /oxe-plan-agent para schema 3');
356
+ }
357
+ if (Array.isArray(json.agents)) {
358
+ const VALID_HINTS = new Set(['fast', 'balanced', 'powerful']);
359
+ for (const agent of json.agents) {
360
+ if (agent.model_hint && !VALID_HINTS.has(agent.model_hint)) {
361
+ warns.push(
362
+ `plan-agents.json agente "${agent.id || '?'}": model_hint "${agent.model_hint}" inválido — use fast | balanced | powerful`
363
+ );
364
+ }
365
+ }
366
+ }
367
+ return warns;
368
+ }
369
+
310
370
  /**
311
371
  * @param {string} phase
312
372
  * @param {ReturnType<typeof oxePaths>} p
@@ -537,6 +597,20 @@ function suggestNextStep(target, cfg = {}) {
537
597
  };
538
598
  }
539
599
 
600
+ // Após verify_complete, sugerir retro se LESSONS.md não existe ou last_retro ausente no STATE
601
+ if (phaseLow === 'verify_complete' || /\bverify_complete\b/i.test(stateText)) {
602
+ const lessonsExist = has(path.join(target, '.oxe', 'LESSONS.md'));
603
+ const hasRetroInState = /\blast_retro\s*:/i.test(stateText);
604
+ if (!lessonsExist || !hasRetroInState) {
605
+ return {
606
+ step: 'retro',
607
+ cursorCmd: '/oxe-retro',
608
+ reason: 'Verify completo — capture as lições do ciclo em .oxe/LESSONS.md para orientar o próximo spec/plan',
609
+ artifacts: ['.oxe/LESSONS.md'],
610
+ };
611
+ }
612
+ }
613
+
540
614
  return {
541
615
  step: 'next',
542
616
  cursorCmd: '/oxe-next',
@@ -565,6 +639,8 @@ function buildHealthReport(target) {
565
639
  const stale = isStaleScan(scanDate, Number(config.scan_max_age_days) || 0);
566
640
  const compactDate = parseLastCompactDate(stateText);
567
641
  const staleCompact = isStaleScan(compactDate, Number(config.compact_max_age_days) || 0);
642
+ const retroDate = parseLastRetroDate(stateText);
643
+ const staleLessons = isStaleLessons(retroDate, Number(config.lessons_max_age_days) || 0);
568
644
  const phaseWarn = phase ? phaseCoherenceWarnings(phase, p) : [];
569
645
  const sumWarn = verifyGapsWithoutSummaryWarning(p.verify, p.summary);
570
646
  const specReq = Array.isArray(config.spec_required_sections) ? config.spec_required_sections : [];
@@ -572,6 +648,7 @@ function buildHealthReport(target) {
572
648
  const planWarn = [
573
649
  ...planWaveWarningsFixed(p.plan, Number(config.plan_max_tasks_per_wave) || 0),
574
650
  ...planTaskAceiteWarnings(p.plan),
651
+ ...planAgentsWarnings(target),
575
652
  ];
576
653
  const next = suggestNextStep(target, { discuss_before_plan: config.discuss_before_plan });
577
654
 
@@ -585,6 +662,8 @@ function buildHealthReport(target) {
585
662
  stale,
586
663
  compactDate,
587
664
  staleCompact,
665
+ retroDate,
666
+ staleLessons,
588
667
  phaseWarn,
589
668
  summaryGapWarn: sumWarn,
590
669
  specWarn,
@@ -609,7 +688,10 @@ module.exports = {
609
688
  parseStatePhase,
610
689
  parseLastScanDate,
611
690
  parseLastCompactDate,
691
+ parseLastRetroDate,
612
692
  isStaleScan,
693
+ isStaleLessons,
694
+ planAgentsWarnings,
613
695
  phaseCoherenceWarnings,
614
696
  verifyGapsWithoutSummaryWarning,
615
697
  specSectionWarnings,
package/bin/oxe-cc.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  /**
3
3
  * OXE — CLI em pt-BR: instala workflows no projeto, bootstrap `.oxe/`, doctor, uninstall, update.
4
4
  * Uso: npx oxe-cc, doctor, status, init-oxe, uninstall, update (ver --help).
@@ -1543,6 +1543,13 @@ ${green}Opções da instalação:${reset}
1543
1543
  -h, --help
1544
1544
  -v, --version
1545
1545
 
1546
+ ${green}doctor${reset} (valida estrutura OXE, config e saúde do projeto)
1547
+ --dir <pasta> raiz do projeto (padrão: diretório atual)
1548
+
1549
+ ${green}init-oxe${reset} (bootstrap só de .oxe/ no projeto — STATE.md, codebase/, templates)
1550
+ --dir <pasta> raiz do projeto (padrão: diretório atual)
1551
+ --force, -f sobrescreve arquivos existentes
1552
+
1546
1553
  ${green}status${reset} (coerência .oxe/ + um próximo passo sugerido; não exige pacote de workflows completo)
1547
1554
  --dir <pasta> raiz do projeto (padrão: diretório atual)
1548
1555
  --json imprime um único objeto JSON (próximo passo + diagnósticos) em stdout; adequado a CI
@@ -1625,6 +1632,11 @@ function runInstall(opts) {
1625
1632
  if (fs.existsSync(personasSrc)) {
1626
1633
  copyDir(personasSrc, path.join(nested, 'personas'), copyOpts, false);
1627
1634
  }
1635
+ // Schemas: copiar para .oxe/schemas/ (ex.: plan-agents.schema.json para validação local)
1636
+ const schemasSrc = path.join(PKG_ROOT, 'oxe', 'schemas');
1637
+ if (fs.existsSync(schemasSrc)) {
1638
+ copyDir(schemasSrc, path.join(nested, 'schemas'), copyOpts, false);
1639
+ }
1628
1640
  }
1629
1641
 
1630
1642
  const cursorBase = installCursorBase(opts);
@@ -1,17 +1,17 @@
1
- ---
2
- name: oxe:loop
3
- description: OXE — Execução iterativa de onda com retries automáticos e diagnóstico inline
4
- argument-hint: "onda <N> [max:<tentativas>]"
5
- allowed-tools:
6
- - Read
7
- - Bash
8
- - Glob
9
- - Grep
10
- - Write
11
- - Edit
12
- - Task
13
- ---
14
-
15
- **Workflow canônico:** `oxe/workflows/loop.md`
16
-
17
- Execute integralmente esse ficheiro na raiz do repositório. `$ARGUMENTS` = onda alvo e máximo de tentativas. Pré-requisito: `.oxe/PLAN.md`.
1
+ ---
2
+ name: oxe:loop
3
+ description: OXE — Execução iterativa de onda com retries automáticos e diagnóstico inline
4
+ argument-hint: "onda <N> [max:<tentativas>]"
5
+ allowed-tools:
6
+ - Read
7
+ - Bash
8
+ - Glob
9
+ - Grep
10
+ - Write
11
+ - Edit
12
+ - Task
13
+ ---
14
+
15
+ **Workflow canônico:** `oxe/workflows/loop.md`
16
+
17
+ Execute integralmente esse ficheiro na raiz do repositório. `$ARGUMENTS` = onda alvo e máximo de tentativas. Pré-requisito: `.oxe/PLAN.md`.
@@ -1,16 +1,16 @@
1
- ---
2
- name: oxe
3
- description: OXE — Entrada universal: próximo passo, roteamento de linguagem natural ou help dos 8 comandos essenciais
4
- argument-hint: "[contexto | 'help' | vazio]"
5
- allowed-tools:
6
- - Read
7
- - Bash
8
- - Glob
9
- - Grep
10
- - Write
11
- - Task
12
- ---
13
-
14
- **Workflow canônico:** `oxe/workflows/oxe.md`
15
-
16
- Execute integralmente esse ficheiro. `$ARGUMENTS`: vazio → próximo passo; texto → roteamento inteligente; "help" → 8 comandos essenciais.
1
+ ---
2
+ name: oxe
3
+ description: OXE — Entrada universal: próximo passo, roteamento de linguagem natural ou help dos 8 comandos essenciais
4
+ argument-hint: "[contexto | 'help' | vazio]"
5
+ allowed-tools:
6
+ - Read
7
+ - Bash
8
+ - Glob
9
+ - Grep
10
+ - Write
11
+ - Task
12
+ ---
13
+
14
+ **Workflow canônico:** `oxe/workflows/oxe.md`
15
+
16
+ Execute integralmente esse ficheiro. `$ARGUMENTS`: vazio → próximo passo; texto → roteamento inteligente; "help" → 8 comandos essenciais.
@@ -1,16 +1,16 @@
1
- ---
2
- name: oxe:project
3
- description: OXE — Gestão de projeto: milestone (M-NN), workstream (trilhas paralelas), checkpoint (snapshot)
4
- argument-hint: "milestone new|complete|status|audit | workstream new|switch|list|close <nome> | checkpoint [slug]"
5
- allowed-tools:
6
- - Read
7
- - Bash
8
- - Glob
9
- - Grep
10
- - Write
11
- - Task
12
- ---
13
-
14
- **Workflow canônico:** `oxe/workflows/project.md`
15
-
16
- Execute integralmente esse ficheiro. `$ARGUMENTS` = subcomando. Sem argumento: mostra status atual (milestone ativo, workstreams, último checkpoint).
1
+ ---
2
+ name: oxe:project
3
+ description: OXE — Gestão de projeto: milestone (M-NN), workstream (trilhas paralelas), checkpoint (snapshot)
4
+ argument-hint: "milestone new|complete|status|audit | workstream new|switch|list|close <nome> | checkpoint [slug]"
5
+ allowed-tools:
6
+ - Read
7
+ - Bash
8
+ - Glob
9
+ - Grep
10
+ - Write
11
+ - Task
12
+ ---
13
+
14
+ **Workflow canônico:** `oxe/workflows/project.md`
15
+
16
+ Execute integralmente esse ficheiro. `$ARGUMENTS` = subcomando. Sem argumento: mostra status atual (milestone ativo, workstreams, último checkpoint).
@@ -1,16 +1,16 @@
1
- ---
2
- name: oxe:retro
3
- description: OXE — Retrospectiva de ciclo: sintetiza lições prescritivas em .oxe/LESSONS.md (alimenta ciclos futuros automaticamente)
4
- argument-hint: "[opcional: contexto sobre o ciclo]"
5
- allowed-tools:
6
- - Read
7
- - Bash
8
- - Glob
9
- - Grep
10
- - Write
11
- - Task
12
- ---
13
-
14
- **Workflow canônico:** `oxe/workflows/retro.md`
15
-
16
- Execute integralmente esse ficheiro. Lê VERIFY.md, FORENSICS.md, SUMMARY.md para sintetizar 3–5 lições prescritivas. `$ARGUMENTS` = contexto extra opcional.
1
+ ---
2
+ name: oxe:retro
3
+ description: OXE — Retrospectiva de ciclo: sintetiza lições prescritivas em .oxe/LESSONS.md (alimenta ciclos futuros automaticamente)
4
+ argument-hint: "[opcional: contexto sobre o ciclo]"
5
+ allowed-tools:
6
+ - Read
7
+ - Bash
8
+ - Glob
9
+ - Grep
10
+ - Write
11
+ - Task
12
+ ---
13
+
14
+ **Workflow canônico:** `oxe/workflows/retro.md`
15
+
16
+ Execute integralmente esse ficheiro. Lê VERIFY.md, FORENSICS.md, SUMMARY.md para sintetizar 3–5 lições prescritivas. `$ARGUMENTS` = contexto extra opcional.
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: oxe:review-pr
3
+ description: OXE — Revisão de diff/PR: analisa alterações, riscos, convenções e sugestões acionáveis
4
+ argument-hint: "<URL do PR ou branch:base..head>"
5
+ allowed-tools:
6
+ - Read
7
+ - Bash
8
+ - Glob
9
+ - Grep
10
+ - Write
11
+ - Task
12
+ ---
13
+
14
+ **Workflow canônico:** `oxe/workflows/review-pr.md`
15
+
16
+ Execute integralmente esse ficheiro. Recebe URL de PR do GitHub (`org/repo#N`) ou par de branches/SHAs. `$ARGUMENTS` = referência do diff.
@@ -1,16 +1,16 @@
1
- ---
2
- name: oxe:security
3
- description: OXE — Auditoria de segurança OWASP (.oxe/SECURITY.md): P0 crítico / P1 alto / P2 médio
4
- argument-hint: "[opcional: categoria OWASP, módulo ou arquivo]"
5
- allowed-tools:
6
- - Read
7
- - Bash
8
- - Glob
9
- - Grep
10
- - Write
11
- - Task
12
- ---
13
-
14
- **Workflow canônico:** `oxe/workflows/security.md`
15
-
16
- Execute integralmente esse ficheiro na raiz do repositório. Lê `STACK.md` para determinar categorias OWASP pertinentes. `$ARGUMENTS` = foco opcional.
1
+ ---
2
+ name: oxe:security
3
+ description: OXE — Auditoria de segurança OWASP (.oxe/SECURITY.md): P0 crítico / P1 alto / P2 médio
4
+ argument-hint: "[opcional: categoria OWASP, módulo ou arquivo]"
5
+ allowed-tools:
6
+ - Read
7
+ - Bash
8
+ - Glob
9
+ - Grep
10
+ - Write
11
+ - Task
12
+ ---
13
+
14
+ **Workflow canônico:** `oxe/workflows/security.md`
15
+
16
+ Execute integralmente esse ficheiro na raiz do repositório. Lê `STACK.md` para determinar categorias OWASP pertinentes. `$ARGUMENTS` = foco opcional.
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: oxe:update
3
+ description: OXE — Atualiza workflows e integrações para a versão mais recente do oxe-cc no npm
4
+ argument-hint: "[--force] [--check] [--if-newer]"
5
+ allowed-tools:
6
+ - Read
7
+ - Bash
8
+ - Glob
9
+ - Grep
10
+ - Write
11
+ - Task
12
+ ---
13
+
14
+ **Workflow canônico:** `oxe/workflows/update.md`
15
+
16
+ Execute integralmente esse ficheiro. Verifica versão no npm, reinstala com --force se necessário e valida com doctor. `$ARGUMENTS` = flags opcionais.
package/lib/sdk/index.cjs CHANGED
@@ -205,7 +205,25 @@ function parseState(stateMd) {
205
205
  const msMatch = stateMd.match(/##\s*Milestone ativo\s*\n+[^`]*`([^`]+)`/im);
206
206
  const activeMilestone = msMatch ? msMatch[1] : null;
207
207
 
208
- return { phase, lastScanDate, nextStep, decisions, activeWorkstreams, activeMilestone };
208
+ // Último retro
209
+ const retroDate = health.parseLastRetroDate(stateMd);
210
+ const lastRetroDate = retroDate ? retroDate.toISOString().split('T')[0] : null;
211
+
212
+ // Blueprint de agentes (sessão)
213
+ const runIdMatch = stateMd.match(/^\s*[-*]?\s*\*?\*?run_id:\*?\*?\s*(.+)/im);
214
+ const runIdRaw = runIdMatch ? runIdMatch[1].trim().replace(/^[\(\-—]+|[\)\-—]+$/g, '').trim() : null;
215
+ const runId = runIdRaw && runIdRaw !== '—' && runIdRaw !== '-' ? runIdRaw : null;
216
+
217
+ const lifecycleMatch = stateMd.match(/^\s*[-*]?\s*\*?\*?lifecycle_status:\*?\*?\s*([^\s\n|`(]+)/im);
218
+ const lifecycleStatusRaw = lifecycleMatch ? lifecycleMatch[1].trim() : null;
219
+ const lifecycleStatus = lifecycleStatusRaw && lifecycleStatusRaw !== '—' && lifecycleStatusRaw !== '-' ? lifecycleStatusRaw : null;
220
+
221
+ // Loop (sessão)
222
+ const loopStatusMatch = stateMd.match(/^\s*[-*]?\s*\*?\*?loop_status:\*?\*?\s*([^\s\n|`(]+)/im);
223
+ const loopStatusRaw = loopStatusMatch ? loopStatusMatch[1].trim() : null;
224
+ const loopStatus = loopStatusRaw && loopStatusRaw !== '—' && loopStatusRaw !== '-' ? loopStatusRaw : null;
225
+
226
+ return { phase, lastScanDate, lastRetroDate, nextStep, decisions, activeWorkstreams, activeMilestone, runId, lifecycleStatus, loopStatus };
209
227
  }
210
228
 
211
229
  /**
@@ -456,7 +474,10 @@ module.exports = {
456
474
  parseStatePhase: health.parseStatePhase,
457
475
  parseLastScanDate: health.parseLastScanDate,
458
476
  parseLastCompactDate: health.parseLastCompactDate,
477
+ parseLastRetroDate: health.parseLastRetroDate,
459
478
  isStaleScan: health.isStaleScan,
479
+ isStaleLessons: health.isStaleLessons,
480
+ planAgentsWarnings: health.planAgentsWarnings,
460
481
  phaseCoherenceWarnings: health.phaseCoherenceWarnings,
461
482
  specSectionWarnings: health.specSectionWarnings,
462
483
  planWaveWarningsFixed: health.planWaveWarningsFixed,
@@ -56,6 +56,8 @@ export interface OxeHealthReport {
56
56
  stale: HealthStaleInfo;
57
57
  compactDate: Date | null;
58
58
  staleCompact: HealthStaleInfo;
59
+ retroDate: Date | null;
60
+ staleLessons: HealthStaleInfo;
59
61
  phaseWarn: string[];
60
62
  summaryGapWarn: string | null;
61
63
  specWarn: string[];
@@ -124,10 +126,17 @@ export interface ParsedSpec {
124
126
  export interface ParsedState {
125
127
  phase: string | null;
126
128
  lastScanDate: string | null;
129
+ lastRetroDate: string | null;
127
130
  nextStep: string | null;
128
131
  decisions: string[];
129
132
  activeWorkstreams: string[];
130
133
  activeMilestone: string | null;
134
+ /** run_id do blueprint ativo extraído da seção "Blueprint de agentes" em STATE.md. */
135
+ runId: string | null;
136
+ /** lifecycle_status do blueprint: pending_execute | executing | closed | invalidated. */
137
+ lifecycleStatus: string | null;
138
+ /** loop_status da sessão de loop: retrying | passed | escalated. */
139
+ loopStatus: string | null;
131
140
  }
132
141
 
133
142
  export interface DecisionFidelityResult {
@@ -173,6 +182,20 @@ export interface PluginValidationResult {
173
182
  issues: Array<{ file: string; issue: string }>;
174
183
  }
175
184
 
185
+ export interface ManifestAPI {
186
+ loadFileManifest: (home: string) => Record<string, unknown>;
187
+ writeFileManifest: (home: string, manifest: Record<string, unknown>) => void;
188
+ sha256File: (filePath: string) => string;
189
+ collectFilesRecursive: (dir: string) => string[];
190
+ MANIFEST_DIR: string;
191
+ PATCHES_DIR: string;
192
+ }
193
+
194
+ export interface AgentsAPI {
195
+ adjustWorkflowPathsForNestedLayout: (content: string, layout?: string) => string;
196
+ parseCursorCommandFrontmatter: (mdContent: string) => Record<string, unknown>;
197
+ }
198
+
176
199
  export interface OxeSdk {
177
200
  version: string;
178
201
  name: string;
@@ -195,7 +218,10 @@ export interface OxeSdk {
195
218
  parseStatePhase: (stateText: string) => string | null;
196
219
  parseLastScanDate: (stateText: string) => Date | null;
197
220
  parseLastCompactDate: (stateText: string) => Date | null;
221
+ parseLastRetroDate: (stateText: string) => Date | null;
198
222
  isStaleScan: (scanDate: Date | null, maxAgeDays: number) => HealthStaleInfo;
223
+ isStaleLessons: (retroDate: Date | null, maxAgeDays: number) => HealthStaleInfo;
224
+ planAgentsWarnings: (target: string) => string[];
199
225
  phaseCoherenceWarnings: (phase: string, paths: Record<string, string>) => string[];
200
226
  specSectionWarnings: (specPath: string, requiredHeadings: string[]) => string[];
201
227
  planWaveWarningsFixed: (planPath: string, maxPerWave: number) => string[];
@@ -230,8 +256,8 @@ export interface OxeSdk {
230
256
  ) => { options: Record<string, unknown>; warnings: string[] };
231
257
  };
232
258
 
233
- manifest: Record<string, unknown>;
234
- agents: Record<string, unknown>;
259
+ manifest: ManifestAPI;
260
+ agents: AgentsAPI;
235
261
 
236
262
  security: {
237
263
  checkPathSafety: (filePath: string, projectRoot: string, options?: {
@@ -8,14 +8,15 @@
8
8
  "properties": {
9
9
  "oxePlanAgentsSchema": {
10
10
  "type": "integer",
11
- "enum": [1, 2]
11
+ "enum": [2, 3],
12
+ "description": "Schema 3 = atual (com model_hint). Schema 2 = aceito (sem model_hint). Schema 1 = legado (não recomendado)."
12
13
  },
13
14
  "goal": { "type": "string", "minLength": 1 },
14
15
  "specRef": { "type": "string" },
15
16
  "runId": {
16
17
  "type": "string",
17
18
  "minLength": 8,
18
- "description": "Obrigatório quando oxePlanAgentsSchema === 2"
19
+ "description": "Obrigatório quando oxePlanAgentsSchema >= 2"
19
20
  },
20
21
  "lifecycle": {
21
22
  "type": "object",
@@ -33,7 +34,7 @@
33
34
  "enum": ["quick", "out_of_scope", "new_plan", "manual"]
34
35
  }
35
36
  },
36
- "description": "Obrigatório quando oxePlanAgentsSchema === 2"
37
+ "description": "Obrigatório quando oxePlanAgentsSchema >= 2"
37
38
  },
38
39
  "agents": {
39
40
  "type": "array",
@@ -48,6 +49,11 @@
48
49
  "pattern": "^[a-z0-9][a-z0-9-]*$"
49
50
  },
50
51
  "role": { "type": "string", "minLength": 1 },
52
+ "persona": {
53
+ "type": "string",
54
+ "minLength": 1,
55
+ "description": "ID de persona em oxe/personas/ (ex.: executor, architect). Opcional."
56
+ },
51
57
  "scope": {
52
58
  "type": "array",
53
59
  "items": { "type": "string" },
@@ -72,6 +78,11 @@
72
78
  "outputs": {
73
79
  "type": "array",
74
80
  "items": { "type": "string" }
81
+ },
82
+ "model_hint": {
83
+ "type": "string",
84
+ "enum": ["fast", "balanced", "powerful"],
85
+ "description": "Tier de modelo sugerido para este agente (schema v3). Opcional."
75
86
  }
76
87
  }
77
88
  }
@@ -100,7 +111,7 @@
100
111
  "allOf": [
101
112
  {
102
113
  "if": {
103
- "properties": { "oxePlanAgentsSchema": { "const": 2 } },
114
+ "properties": { "oxePlanAgentsSchema": { "enum": [2, 3] } },
104
115
  "required": ["oxePlanAgentsSchema"]
105
116
  },
106
117
  "then": {
@@ -8,18 +8,23 @@ Copie `oxe/templates/config.template.json` para **`.oxe/config.json`** no seu pr
8
8
  |-------|------|-------------|
9
9
  | `profile` | string | Profile de execução: `balanced` (padrão) \| `strict` \| `fast` \| `legacy`. Expande automaticamente outras keys — keys explícitas prevalecem. Ver tabela abaixo. |
10
10
  | `discuss_before_plan` | boolean | Se `true`, o fluxo recomenda **`oxe:discuss`** entre spec e plan. |
11
- | `verification_depth` | string | Profundidade da verificação: `standard` (padrão) \| `thorough` (4 camadas) \| `quick` (skip camadas 3–4 e UAT). |
11
+ | `verification_depth` | string | Profundidade da verificação: `standard` (padrão) \| `thorough` (ativa Camada 5 — validate-gaps automático) \| `quick` (skip camadas 3–4 e UAT). |
12
+ | `security_in_verify` | boolean | Se `true`, executa auditoria OWASP automaticamente no **verify** como **Camada 6** (produz `.oxe/SECURITY.md`). Achados P0 bloqueiam `verify_complete`. Padrão: `false`. |
12
13
  | `after_verify_suggest_pr` | boolean | Se `true`, o workflow **verify** inclui checklist de PR no fim. |
13
14
  | `after_verify_draft_commit` | boolean | Se `true`, o **verify** propõe rascunho de mensagem de commit alinhado aos critérios de aceite. |
14
15
  | `after_verify_suggest_uat` | boolean | Se `true`, o **verify** gera checklist UAT (Camada 4). Ativo automaticamente com `profile: strict`. |
15
16
  | `default_verify_command` | string | Comando guarda-chuva opcional (ex.: `npm test`) sugerido em **plan**/**verify** quando o projeto não define outro. |
16
17
  | `scan_max_age_days` | number | Se **> 0**, `oxe-cc doctor` / `status` avisam quando a **Data** do último scan em `STATE.md` é mais antiga que esse número de dias. Use **0** para desligar. |
17
18
  | `compact_max_age_days` | number | Se **> 0**, `oxe-cc doctor` / `status` avisam quando a **Data** em **Último compact** em `STATE.md` é mais antiga que esse número de dias. Use **0** para desligar. |
19
+ | `lessons_max_age_days` | number | Se **> 0**, `oxe-cc doctor` / `status` avisam quando o campo `last_retro` em `STATE.md` é mais antigo que esse número de dias (ciclos sem retrospectiva). Use **0** para desligar (padrão). |
18
20
  | `scale_adaptive` | boolean | Se `true` (padrão), o workflow **scan** sugere automaticamente um `profile` baseado no tamanho do projeto. |
19
21
  | `scan_focus_globs` | string[] | Padrões (ex.: `src/api/**`) que o workflow **scan** deve priorizar; só orientação para o agente. |
20
22
  | `scan_ignore_globs` | string[] | Padrões a tratar como baixa prioridade ou omitir no scan (ex.: `**/dist/**`). |
21
23
  | `spec_required_sections` | string[] | Cabeçalhos que **devem** existir em `SPEC.md` (ex.: `"## Critérios de aceite"`). `doctor` / `status` emitem aviso se faltar. |
22
24
  | `plan_max_tasks_per_wave` | number | Se **> 0**, `doctor` / `status` avisam se alguma **Onda** no `PLAN.md` tiver mais tarefas `T1…` que esse limite. **0** desliga. |
25
+ | `plugins` | array | Caminhos de plugins customizados em `.oxe/plugins/` (strings relativas). Padrão: `[]`. Ver [`PLUGINS.md`](PLUGINS.md). |
26
+ | `workstreams` | array | Lista de nomes de workstreams ativos (strings). Usado como referência pelo agente em **`/oxe-workstream`**. Padrão: `[]`. |
27
+ | `milestones` | array | Lista de milestones ativos (objetos `{ "id": "M-01", "name": "..." }`). Usado como referência pelo agente em **`/oxe-milestone`**. Padrão: `[]`. |
23
28
  | `install` | object | Opcional. Preferências de **instalação** quando corre `npx oxe-cc` **sem** flags de CLI. Ver tabela abaixo. |
24
29
 
25
30
  ## Profiles de execução (`profile`)