From 89bb93520065a6938e3bb46d41667d80789bb180 Mon Sep 17 00:00:00 2001 From: GiovaneLaurencio <210858529+GiovaneLaurencio@users.noreply.github.com> Date: Sun, 26 Jul 2026 18:50:14 -0300 Subject: [PATCH 1/3] fix: standardize greenfield guard across claude-code-mastery squad agents MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The squad's 8 agents carried the same GREENFIELD GUARD as the core agents, with the same two defects plus a consistency problem of their own. Agent Authority (Constitution Article II): 4 of the 8 recommended `*environment-bootstrap`, a @devops-exclusive command none of them owns (hooks-architect, mcp-integrator, skill-craftsman, swarm-orchestrator). They now delegate: `@devops *environment-bootstrap`. The 3 agents that recommend a command they actually own keep it unchanged — `*configure` (config-engineer), `*integrate-project` (project-integrator), `*check-updates` (roadmap-sentinel); each was verified to exist in its own `commands` block. False positive in non-project directories: the guard fired wherever there was no git repo, including a user home directory, and labelled it a "Greenfield project". It now decides from the working directory path already present in the system prompt (zero extra I/O): a home or non-project directory gets a tip to activate from inside the project instead of a command recommendation. claude-mastery-chief, which never recommended anything, gets the tip branch only. Typographic consistency: the three guard lines existed in 4 different variants across the 8 files (`--` vs `—`, with and without bold, with and without emoji). All 8 now carry byte-identical lines, matching the core agents. Note: `npm run validate:agents` covers only the 12 core agents, not squads. A manual YAML parse of all 8 found swarm-orchestrator.md invalid at its `lexicon:` block — pre-existing (fails identically at HEAD, before this change) and left untouched here. Co-Authored-By: Claude Opus 5 (1M context) --- squads/claude-code-mastery/agents/claude-mastery-chief.md | 5 +++-- squads/claude-code-mastery/agents/config-engineer.md | 8 +++++--- squads/claude-code-mastery/agents/hooks-architect.md | 8 +++++--- squads/claude-code-mastery/agents/mcp-integrator.md | 8 +++++--- squads/claude-code-mastery/agents/project-integrator.md | 8 +++++--- squads/claude-code-mastery/agents/roadmap-sentinel.md | 8 +++++--- squads/claude-code-mastery/agents/skill-craftsman.md | 8 +++++--- squads/claude-code-mastery/agents/swarm-orchestrator.md | 6 ++++-- 8 files changed, 37 insertions(+), 22 deletions(-) diff --git a/squads/claude-code-mastery/agents/claude-mastery-chief.md b/squads/claude-code-mastery/agents/claude-mastery-chief.md index 66bfa8fbd7..64b35e7189 100644 --- a/squads/claude-code-mastery/agents/claude-mastery-chief.md +++ b/squads/claude-code-mastery/agents/claude-mastery-chief.md @@ -20,8 +20,9 @@ activation-instructions: Display greeting using native context (zero JS execution): 0. GREENFIELD GUARD: If gitStatus in system prompt says "Is a git repository: false" OR git commands return "not a git repository": - For substep 2: skip the "Branch:" append - - For substep 3: show "Project Status: Greenfield project — no git repository detected" instead of git narrative - - Do NOT run any git commands during activation + - For substep 3: show "📊 **Project Status:** No git repository detected in the working directory" instead of git narrative + - After substep 6, if the working directory is a user home directory (e.g. `C:\Users\{name}`, `/home/{name}`, `/Users/{name}`) or any other non-project directory — decided from the path already in the system prompt, zero I/O: show "💡 **Tip:** Activate agents from inside the project directory — never run `git init` in a home directory." + - Do NOT run any git commands during activation — they will fail and produce errors 1. Show: "{icon} {persona_profile.communication.greeting_levels.archetypal}" + permission badge from current permission mode 2. Show: "**Role:** {persona.role}" - Append: "Story: {active story from docs/stories/}" if detected + "Branch: `{branch}`" if not main/master diff --git a/squads/claude-code-mastery/agents/config-engineer.md b/squads/claude-code-mastery/agents/config-engineer.md index 86e52b9e5d..a36839ed0a 100644 --- a/squads/claude-code-mastery/agents/config-engineer.md +++ b/squads/claude-code-mastery/agents/config-engineer.md @@ -21,9 +21,11 @@ activation-instructions: Display greeting using native context (zero JS execution): 0. GREENFIELD GUARD: If gitStatus in system prompt says "Is a git repository: false" OR git commands return "not a git repository": - For substep 2: skip the "Branch:" append - - For substep 3: show "**Project Status:** Greenfield project -- no git repository detected" instead of git narrative - - After substep 6: show "**Recommended:** Run `*configure` to bootstrap Claude Code settings for this project" - - Do NOT run any git commands during activation -- they will fail and produce errors + - For substep 3: show "📊 **Project Status:** No git repository detected in the working directory" instead of git narrative + - After substep 6, decide from the working directory path already in the system prompt (zero I/O): + - If it is a user home directory (e.g. `C:\Users\{name}`, `/home/{name}`, `/Users/{name}`) or any other non-project directory: show "💡 **Tip:** Activate agents from inside the project directory — never run `git init` in a home directory." and do NOT recommend a project command + - Otherwise (an actual project directory): show "💡 **Recommended:** Run `*configure` to bootstrap Claude Code settings for this project" + - Do NOT run any git commands during activation — they will fail and produce errors 1. Show: "{icon} {persona_profile.communication.greeting_levels.archetypal}" + permission badge from current permission mode (e.g., [Ask], [Auto], [Explore]) 2. Show: "**Role:** {persona.role}" - Append: "Story: {active story from docs/stories/}" if detected + "Branch: `{branch from gitStatus}`" if not main/master diff --git a/squads/claude-code-mastery/agents/hooks-architect.md b/squads/claude-code-mastery/agents/hooks-architect.md index b715e5bf03..932df5b98c 100644 --- a/squads/claude-code-mastery/agents/hooks-architect.md +++ b/squads/claude-code-mastery/agents/hooks-architect.md @@ -21,9 +21,11 @@ activation-instructions: Display greeting using native context (zero JS execution): 0. GREENFIELD GUARD: If gitStatus in system prompt says "Is a git repository: false" OR git commands return "not a git repository": - For substep 2: skip the "Branch:" append - - For substep 3: show "**Project Status:** Greenfield project -- no git repository detected" instead of git narrative - - After substep 6: show "**Recommended:** Run `*environment-bootstrap` to initialize git, GitHub remote, and CI/CD" - - Do NOT run any git commands during activation -- they will fail and produce errors + - For substep 3: show "📊 **Project Status:** No git repository detected in the working directory" instead of git narrative + - After substep 6, decide from the working directory path already in the system prompt (zero I/O): + - If it is a user home directory (e.g. `C:\Users\{name}`, `/home/{name}`, `/Users/{name}`) or any other non-project directory: show "💡 **Tip:** Activate agents from inside the project directory — never run `git init` in a home directory." and do NOT recommend a project command + - Otherwise (an actual project directory): show "💡 **Recommended:** Run `@devops *environment-bootstrap` to initialize git, GitHub remote, and CI/CD" + - Do NOT run any git commands during activation — they will fail and produce errors 1. Show: "{icon} {persona_profile.communication.greeting_levels.archetypal}" + permission badge from current permission mode (e.g., [Ask], [Auto], [Explore]) 2. Show: "**Role:** {persona.role}" - Append: "Story: {active story from docs/stories/}" if detected + "Branch: `{branch from gitStatus}`" if not main/master diff --git a/squads/claude-code-mastery/agents/mcp-integrator.md b/squads/claude-code-mastery/agents/mcp-integrator.md index 7ce483d90e..8416f4f5f4 100644 --- a/squads/claude-code-mastery/agents/mcp-integrator.md +++ b/squads/claude-code-mastery/agents/mcp-integrator.md @@ -21,9 +21,11 @@ activation-instructions: Display greeting using native context (zero JS execution): 0. GREENFIELD GUARD: If gitStatus in system prompt says "Is a git repository: false" OR git commands return "not a git repository": - For substep 2: skip the "Branch:" append - - For substep 3: show "Project Status: Greenfield project -- no git repository detected" instead of git narrative - - After substep 6: show "Recommended: Run `*environment-bootstrap` to initialize git, GitHub remote, and CI/CD" - - Do NOT run any git commands during activation -- they will fail and produce errors + - For substep 3: show "📊 **Project Status:** No git repository detected in the working directory" instead of git narrative + - After substep 6, decide from the working directory path already in the system prompt (zero I/O): + - If it is a user home directory (e.g. `C:\Users\{name}`, `/home/{name}`, `/Users/{name}`) or any other non-project directory: show "💡 **Tip:** Activate agents from inside the project directory — never run `git init` in a home directory." and do NOT recommend a project command + - Otherwise (an actual project directory): show "💡 **Recommended:** Run `@devops *environment-bootstrap` to initialize git, GitHub remote, and CI/CD" + - Do NOT run any git commands during activation — they will fail and produce errors 1. Show: "{icon} {persona_profile.communication.greeting_levels.archetypal}" + permission badge from current permission mode (e.g., [Ask], [Auto], [Explore]) 2. Show: "**Role:** {persona.role}" - Append: "Story: {active story from docs/stories/}" if detected + "Branch: `{branch from gitStatus}`" if not main/master diff --git a/squads/claude-code-mastery/agents/project-integrator.md b/squads/claude-code-mastery/agents/project-integrator.md index 9e320321cc..55c1826bc7 100644 --- a/squads/claude-code-mastery/agents/project-integrator.md +++ b/squads/claude-code-mastery/agents/project-integrator.md @@ -21,9 +21,11 @@ activation-instructions: Display greeting using native context (zero JS execution): 0. GREENFIELD GUARD: If gitStatus in system prompt says "Is a git repository: false" OR git commands return "not a git repository": - For substep 2: skip the "Branch:" append - - For substep 3: show "Project Status: Greenfield project -- no git repository detected" instead of git narrative - - After substep 6: show "Recommended: Run `*integrate-project` to scaffold the full AI-assisted development infrastructure" - - Do NOT run any git commands during activation -- they will fail and produce errors + - For substep 3: show "📊 **Project Status:** No git repository detected in the working directory" instead of git narrative + - After substep 6, decide from the working directory path already in the system prompt (zero I/O): + - If it is a user home directory (e.g. `C:\Users\{name}`, `/home/{name}`, `/Users/{name}`) or any other non-project directory: show "💡 **Tip:** Activate agents from inside the project directory — never run `git init` in a home directory." and do NOT recommend a project command + - Otherwise (an actual project directory): show "💡 **Recommended:** Run `*integrate-project` to scaffold the full AI-assisted development infrastructure" + - Do NOT run any git commands during activation — they will fail and produce errors 1. Show: "{icon} {persona_profile.communication.greeting_levels.archetypal}" + permission badge from current permission mode (e.g., [Ask], [Auto], [Explore]) 2. Show: "**Role:** {persona.role}" - Append: "Story: {active story from docs/stories/}" if detected + "Branch: `{branch from gitStatus}`" if not main/master diff --git a/squads/claude-code-mastery/agents/roadmap-sentinel.md b/squads/claude-code-mastery/agents/roadmap-sentinel.md index 28296e3907..c4c310d952 100644 --- a/squads/claude-code-mastery/agents/roadmap-sentinel.md +++ b/squads/claude-code-mastery/agents/roadmap-sentinel.md @@ -21,9 +21,11 @@ activation-instructions: Display greeting using native context (zero JS execution): 0. GREENFIELD GUARD: If gitStatus in system prompt says "Is a git repository: false" OR git commands return "not a git repository": - For substep 2: skip the "Branch:" append - - For substep 3: show "**Project Status:** Greenfield project -- no git repository detected" instead of git narrative - - After substep 6: show "**Recommended:** Run `*check-updates` to assess your Claude Code version and feature readiness" - - Do NOT run any git commands during activation -- they will fail and produce errors + - For substep 3: show "📊 **Project Status:** No git repository detected in the working directory" instead of git narrative + - After substep 6, decide from the working directory path already in the system prompt (zero I/O): + - If it is a user home directory (e.g. `C:\Users\{name}`, `/home/{name}`, `/Users/{name}`) or any other non-project directory: show "💡 **Tip:** Activate agents from inside the project directory — never run `git init` in a home directory." and do NOT recommend a project command + - Otherwise (an actual project directory): show "💡 **Recommended:** Run `*check-updates` to assess your Claude Code version and feature readiness" + - Do NOT run any git commands during activation — they will fail and produce errors 1. Show: "{icon} {persona_profile.communication.greeting_levels.archetypal}" + permission badge from current permission mode (e.g., [Ask], [Auto], [Explore]) 2. Show: "**Role:** {persona.role}" - Append: "Story: {active story from docs/stories/}" if detected + "Branch: `{branch from gitStatus}`" if not main/master diff --git a/squads/claude-code-mastery/agents/skill-craftsman.md b/squads/claude-code-mastery/agents/skill-craftsman.md index d20636686b..043e7ddc80 100644 --- a/squads/claude-code-mastery/agents/skill-craftsman.md +++ b/squads/claude-code-mastery/agents/skill-craftsman.md @@ -21,9 +21,11 @@ activation-instructions: Display greeting using native context (zero JS execution): 0. GREENFIELD GUARD: If gitStatus in system prompt says "Is a git repository: false" OR git commands return "not a git repository": - For substep 2: skip the "Branch:" append - - For substep 3: show "Project Status: Greenfield project -- no git repository detected" instead of git narrative - - After substep 6: show "Recommended: Run `*environment-bootstrap` to initialize git, GitHub remote, and CI/CD" - - Do NOT run any git commands during activation -- they will fail and produce errors + - For substep 3: show "📊 **Project Status:** No git repository detected in the working directory" instead of git narrative + - After substep 6, decide from the working directory path already in the system prompt (zero I/O): + - If it is a user home directory (e.g. `C:\Users\{name}`, `/home/{name}`, `/Users/{name}`) or any other non-project directory: show "💡 **Tip:** Activate agents from inside the project directory — never run `git init` in a home directory." and do NOT recommend a project command + - Otherwise (an actual project directory): show "💡 **Recommended:** Run `@devops *environment-bootstrap` to initialize git, GitHub remote, and CI/CD" + - Do NOT run any git commands during activation — they will fail and produce errors 1. Show: "{icon} {persona_profile.communication.greeting_levels.archetypal}" + permission badge from current permission mode (e.g., [Ask], [Auto], [Explore]) 2. Show: "**Role:** {persona.role}" - Append: "Story: {active story from docs/stories/}" if detected + "Branch: `{branch from gitStatus}`" if not main/master diff --git a/squads/claude-code-mastery/agents/swarm-orchestrator.md b/squads/claude-code-mastery/agents/swarm-orchestrator.md index 59bffd1da8..89f913dcd8 100644 --- a/squads/claude-code-mastery/agents/swarm-orchestrator.md +++ b/squads/claude-code-mastery/agents/swarm-orchestrator.md @@ -21,8 +21,10 @@ activation-instructions: Display greeting using native context (zero JS execution): 0. GREENFIELD GUARD: If gitStatus in system prompt says "Is a git repository: false" OR git commands return "not a git repository": - For substep 2: skip the "Branch:" append - - For substep 3: show "📊 **Project Status:** Greenfield project — no git repository detected" instead of git narrative - - After substep 6: show "💡 **Recommended:** Run `*environment-bootstrap` to initialize git, GitHub remote, and CI/CD" + - For substep 3: show "📊 **Project Status:** No git repository detected in the working directory" instead of git narrative + - After substep 6, decide from the working directory path already in the system prompt (zero I/O): + - If it is a user home directory (e.g. `C:\Users\{name}`, `/home/{name}`, `/Users/{name}`) or any other non-project directory: show "💡 **Tip:** Activate agents from inside the project directory — never run `git init` in a home directory." and do NOT recommend a project command + - Otherwise (an actual project directory): show "💡 **Recommended:** Run `@devops *environment-bootstrap` to initialize git, GitHub remote, and CI/CD" - Do NOT run any git commands during activation — they will fail and produce errors 1. Show: "{icon} {persona_profile.communication.greeting_levels.archetypal}" + permission badge from current permission mode (e.g., [⚠️ Ask], [🟢 Auto], [🔍 Explore]) 2. Show: "**Role:** {persona.role}" From b349e97a1a58225660395c6bff26e373816585fa Mon Sep 17 00:00:00 2001 From: GiovaneLaurencio <210858529+GiovaneLaurencio@users.noreply.github.com> Date: Sun, 26 Jul 2026 18:56:13 -0300 Subject: [PATCH 2/3] fix: repair invalid YAML sequence entries in swarm-orchestrator lexicon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 8 entries under `voice_dna.lexicon` had the shape: - "topology" (preferred over "structure" for agent arrangements) YAML closes the scalar at the second quote, leaving ` (preferred ...)` as a stray token — js-yaml rejected the whole embedded block with "bad indentation of a sequence entry", so the agent definition was unparseable by any tooling. Each entry is now wrapped in single quotes, which keeps the inner double quotes verbatim and keeps the parenthetical part of the value rather than turning it into a comment: - '"topology" (preferred over "structure" for agent arrangements)' Verified: all 8 squad agents now parse, and lexicon still yields 8 entries with their text unchanged. Entries elsewhere in the squad of the form `- "text" # comment` were left alone — the `#` makes those valid already. Co-Authored-By: Claude Opus 5 (1M context) --- .../agents/swarm-orchestrator.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/squads/claude-code-mastery/agents/swarm-orchestrator.md b/squads/claude-code-mastery/agents/swarm-orchestrator.md index 89f913dcd8..0c4f55c791 100644 --- a/squads/claude-code-mastery/agents/swarm-orchestrator.md +++ b/squads/claude-code-mastery/agents/swarm-orchestrator.md @@ -548,14 +548,14 @@ voice_dna: (not structure), fan-out/fan-in (not split/merge). Prefers diagrams and decision trees over prose. Every recommendation includes the cost implication. lexicon: - - "topology" (preferred over "structure" or "architecture" for agent arrangements) - - "spawn" (preferred over "create" for agent instantiation) - - "converge" (preferred over "combine" for result synthesis) - - "fan-out / fan-in" (preferred over "split / merge" for parallel patterns) - - "isolation boundary" (preferred over "separation" for context/file boundaries) - - "heartbeat" (for health monitoring of long-running teammates) - - "claim" (for task acquisition in swarm patterns) - - "unblock" (for dependency resolution in task pipelines) + - '"topology" (preferred over "structure" or "architecture" for agent arrangements)' + - '"spawn" (preferred over "create" for agent instantiation)' + - '"converge" (preferred over "combine" for result synthesis)' + - '"fan-out / fan-in" (preferred over "split / merge" for parallel patterns)' + - '"isolation boundary" (preferred over "separation" for context/file boundaries)' + - '"heartbeat" (for health monitoring of long-running teammates)' + - '"claim" (for task acquisition in swarm patterns)' + - '"unblock" (for dependency resolution in task pipelines)' # ────────────────────────────────────────────────────── # OUTPUT EXAMPLES From 04a05a845f23c362c3d6b7fe4d1595adcb8528b9 Mon Sep 17 00:00:00 2001 From: GiovaneLaurencio <210858529+GiovaneLaurencio@users.noreply.github.com> Date: Mon, 27 Jul 2026 10:49:03 -0300 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20validate-agents=20cobre=20squads=20?= =?UTF-8?q?e=20reporta=20YAML=20inv=C3=A1lido=20em=20vez=20de=20engolir?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `npm run validate:agents` validava só os 12 agentes core. Squads não tinham gate nenhum — foi por isso que 4 variantes tipográficas do mesmo guard e um bloco YAML que nenhum parser aceita conviveram sem ninguém notar (ver #815). Pior: o loader tinha um try/catch em volta do loop INTEIRO. Um YAML quebrado abortava a leitura de todos os agentes seguintes, imprimia a falha como console.error e o run ainda terminava com "All validations passed". O gate existia no papel. O que muda: - descobre `squads//agents/` além do core. Sumário por escopo: 20 agentes = core 12 + squad:claude-code-mastery 8. - NOVO check "YAML Parse": bloco que não parseia é ERRO (exit 1) com o motivo e uma sugestão. try/catch agora é POR ARQUIVO — um quebrado não esconde os outros. Verificado com um agente propositalmente inválido: acusou, saiu 1, e seguiu validando os 20. - unicidade de comando passa a ser POR ESCOPO. Core disputa com core, cada squad com ele mesmo — mesmo comando em dois squads diferentes não é colisão. Sem isso, ligar squads geraria falso-positivo em massa. - dependências de squad resolvem em `squads///`; `reference_files` (que guardam caminho relativo à raiz) passam a ser checados contra o repo em vez de virar "unknown dependency type". - `--core-only` restringe ao comportamento antigo. - removida uma função morta que o refactor deixou referenciando variáveis inexistentes. `loadAllAgents()` mantém a assinatura antiga (só a lista) para não quebrar consumidor; `loadAgents()` é o novo, com parseErrors e escopos. Estado atual do repo: 0 erros, 121 warnings — todas dependências ausentes pré-existentes no core, nenhuma introduzida aqui. Co-Authored-By: Claude Opus 5 (1M context) --- .../development/tasks/validate-agents.md | 21 +- .../infrastructure/scripts/validate-agents.js | 315 ++++++++++++++---- .aiox-core/install-manifest.yaml | 110 +++--- 3 files changed, 314 insertions(+), 132 deletions(-) diff --git a/.aiox-core/development/tasks/validate-agents.md b/.aiox-core/development/tasks/validate-agents.md index 672d94a10f..f5fc4f8598 100644 --- a/.aiox-core/development/tasks/validate-agents.md +++ b/.aiox-core/development/tasks/validate-agents.md @@ -28,6 +28,18 @@ Story ACT-6: Framework integrity checking via `*validate-agents` command. Scan `.aiox-core/development/agents/` for all `.md` files. Expected agents: dev, qa, architect, pm, po, sm, analyst, data-engineer, ux-design-expert, devops, aiox-master, squad-creator +Also scan `squads//agents/` for every squad that ships agents. Squad scope +differs in two ways: + +- **Command uniqueness is per scope.** Core agents share one namespace and each squad + has its own — the same command name in two different squads is not a collision. +- **Dependencies resolve inside the squad** (`squads///`), not in the core + development directories. `reference_files` are repo-relative instead. + +Use `--core-only` to restrict the run to the 12 core agents. + +Files starting with `_` are skipped by design (partials, drafts). + ### Step 2: Parse YAML Block For each agent file: @@ -77,8 +89,11 @@ For each command in `commands` array: ### Step 7: Cross-Agent Validation 1. Verify no duplicate agent IDs across files -2. Verify all 12 expected agents are present +2. Verify all 12 expected core agents are present (squad agents are additional) 3. Verify `*yolo` command exists (universal command) +4. Verify every agent's YAML block PARSES. An unparseable block is an ERROR, not a + silent skip: before this check existed, one broken file aborted the whole scan and + the run still reported success. ### Step 8: Generate Report @@ -110,8 +125,8 @@ Summary: 11 passed, 1 warning, 0 failed - `js-yaml` - YAML parsing - `fs` - File system access -- Agent files in `.aiox-core/development/agents/` -- Task files in `.aiox-core/development/tasks/` +- Agent files in `.aiox-core/development/agents/` and `squads//agents/` +- Task files in `.aiox-core/development/tasks/` and `squads//tasks/` - `unified-activation-pipeline.js` - Pipeline reference check --- diff --git a/.aiox-core/infrastructure/scripts/validate-agents.js b/.aiox-core/infrastructure/scripts/validate-agents.js index 29c0e940fe..187a4ec27a 100644 --- a/.aiox-core/infrastructure/scripts/validate-agents.js +++ b/.aiox-core/infrastructure/scripts/validate-agents.js @@ -6,13 +6,21 @@ * Validates all agent definitions for consistency according to the * Agent Consistency Refactor PRD requirements: * - * 1. Command uniqueness across agents (1 command = 1 owner) - * 2. Dependency existence verification - * 3. Format schema validation - * 4. Cross-agent reference validation + * 1. YAML parseability (a broken block is reported, not swallowed) + * 2. Command uniqueness within each scope (1 command = 1 owner) + * 3. Dependency existence verification + * 4. Format schema validation + * 5. Cross-agent reference validation + * + * Scope: core agents in .aiox-core/development/agents/ AND squad agents in + * squads//agents/. Command uniqueness is checked per scope — core agents + * share one namespace and each squad has its own, so the same command name in + * two different squads is not a conflict. Squad dependencies resolve against + * squads/// rather than the core development directories. * * Usage: - * node validate-agents.js Validate all agents + * node validate-agents.js Validate core + squad agents + * node validate-agents.js --core-only Validate only core agents * node validate-agents.js --json Output as JSON * node validate-agents.js --fix-suggestions Show fix suggestions * @@ -26,7 +34,9 @@ const path = require('path'); const yaml = require('js-yaml'); // Paths -const ROOT_DIR = path.join(__dirname, '..', '..'); +const ROOT_DIR = path.join(__dirname, '..', '..'); // .aiox-core +const REPO_ROOT = path.join(ROOT_DIR, '..'); // repository root +const SQUADS_DIR = path.join(REPO_ROOT, 'squads'); const AGENTS_DIR = path.join(ROOT_DIR, 'development', 'agents'); const TASKS_DIR = path.join(ROOT_DIR, 'development', 'tasks'); const TEMPLATES_DIR = path.join(ROOT_DIR, 'development', 'templates'); @@ -36,6 +46,26 @@ const UTILS_DIR = path.join(ROOT_DIR, 'development', 'utils'); const WORKFLOWS_DIR = path.join(ROOT_DIR, 'development', 'workflows'); const SCRIPTS_DIR = path.join(ROOT_DIR, 'development', 'scripts'); +const CORE_SCOPE = 'core'; + +// Where each file-based dependency type lives, for core agents. +const CORE_DEP_DIRS = { + tasks: TASKS_DIR, + templates: TEMPLATES_DIR, + checklists: CHECKLISTS_DIR, + data: DATA_DIR, + utils: UTILS_DIR, + workflows: WORKFLOWS_DIR, + scripts: SCRIPTS_DIR, +}; + +// Same types, resolved inside a squad directory (squads///). +function squadDepDirs(squadRoot) { + return Object.fromEntries( + Object.keys(CORE_DEP_DIRS).map((type) => [type, path.join(squadRoot, type)]) + ); +} + // Commands that are allowed to be shared by multiple agents // These are utility/infrastructure commands, not domain-specific const SHARED_COMMANDS = new Set([ @@ -81,36 +111,109 @@ function extractYamlFromMarkdown(content) { } /** - * Load all agent files + * Load agent files from a single directory. + * + * A file whose YAML does not parse is recorded in parseErrors instead of + * aborting the scan — previously one broken block stopped every remaining + * agent from being loaded at all, and the failure surfaced only as a console + * message while the run still reported success. */ -async function loadAllAgents() { +async function loadAgentsFromDir(dir, scope, depDirs) { const agents = []; + const parseErrors = []; + let files; try { - const files = await fs.readdir(AGENTS_DIR); - for (const file of files) { - if (file.endsWith('.md') && !file.startsWith('_')) { - const filePath = path.join(AGENTS_DIR, file); - const content = await fs.readFile(filePath, 'utf-8'); - const parsed = extractYamlFromMarkdown(content); - - if (parsed?.agent) { - agents.push({ - file, - path: filePath, - id: parsed.agent.id || file.replace('.md', ''), - name: parsed.agent.name, - commands: parsed.commands || [], - dependencies: parsed.dependencies || {}, - parsed, - }); - } + files = await fs.readdir(dir); + } catch { + return { agents, parseErrors }; // directory absent — nothing to validate + } + + for (const file of files) { + if (!file.endsWith('.md') || file.startsWith('_')) continue; + + const filePath = path.join(dir, file); + try { + const content = await fs.readFile(filePath, 'utf-8'); + const parsed = extractYamlFromMarkdown(content); + + if (parsed?.agent) { + agents.push({ + file, + path: filePath, + scope, + depDirs, + id: parsed.agent.id || file.replace('.md', ''), + name: parsed.agent.name, + commands: parsed.commands || [], + dependencies: parsed.dependencies || {}, + parsed, + }); } + } catch (error) { + parseErrors.push({ + type: 'INVALID_YAML', + scope, + agent: file.replace('.md', ''), + file, + path: filePath, + message: `Unparseable YAML in ${scope}/${file}: ${String(error.message).split('\n')[0]}`, + suggestion: + 'Fix the embedded YAML block. A common cause is a sequence entry like `- "term" (note)`, where the text after the closing quote is a stray token — wrap the whole entry in single quotes.', + }); } - } catch (error) { - console.error(`Error reading agents directory: ${error.message}`); } + return { agents, parseErrors }; +} + +/** + * Discover squads that ship agents (squads//agents/). + */ +async function discoverSquads() { + try { + const entries = await fs.readdir(SQUADS_DIR, { withFileTypes: true }); + return entries + .filter((e) => e.isDirectory()) + .map((e) => ({ + name: e.name, + root: path.join(SQUADS_DIR, e.name), + agentsDir: path.join(SQUADS_DIR, e.name, 'agents'), + })); + } catch { + return []; // no squads/ directory (e.g. project-mode install) + } +} + +/** + * Load core agents plus, unless disabled, every squad's agents. + * Returns { agents, parseErrors, scopes }. + */ +async function loadAgents({ includeSquads = true } = {}) { + const core = await loadAgentsFromDir(AGENTS_DIR, CORE_SCOPE, CORE_DEP_DIRS); + const agents = [...core.agents]; + const parseErrors = [...core.parseErrors]; + const scopes = [{ scope: CORE_SCOPE, count: core.agents.length }]; + + if (includeSquads) { + for (const squad of await discoverSquads()) { + const scope = `squad:${squad.name}`; + const loaded = await loadAgentsFromDir(squad.agentsDir, scope, squadDepDirs(squad.root)); + if (loaded.agents.length === 0 && loaded.parseErrors.length === 0) continue; + agents.push(...loaded.agents); + parseErrors.push(...loaded.parseErrors); + scopes.push({ scope, count: loaded.agents.length }); + } + } + + return { agents, parseErrors, scopes }; +} + +/** + * Backwards-compatible wrapper: returns just the agent list. + */ +async function loadAllAgents(options = {}) { + const { agents } = await loadAgents(options); return agents; } @@ -127,35 +230,50 @@ async function fileExists(filePath) { } /** - * Validate command uniqueness across agents - * Returns: { errors: [], warnings: [], commandOwners: Map } + * Extract a command name from any of the three accepted command shapes. + */ +function commandName(cmd) { + if (typeof cmd === 'string') { + // String format: 'command: description' + return cmd.split(':')[0].trim(); + } + if (cmd && cmd.name) { + // Explicit format: { name: 'command', ... } + return cmd.name; + } + if (typeof cmd === 'object' && cmd !== null) { + // Shorthand format: { command: 'description' } - take first key + return Object.keys(cmd)[0]?.split(' ')[0]; // Handle 'command {args}' format + } + return undefined; +} + +/** + * Validate command uniqueness within each scope. + * + * Scopes are separate namespaces: core agents are checked against each other, + * and each squad against itself. A command named the same in two different + * squads is not a collision, so cross-scope pairs are never reported. + * + * Returns: { errors: [], warnings: [], commandOwners: Map> } */ function validateCommandUniqueness(agents) { - const commandOwners = new Map(); // command -> [{ agent, hasVisibility }] + const commandOwners = new Map(); // scope -> Map(command -> [{ agent, file, hasVisibility }]) const errors = []; const warnings = []; for (const agent of agents) { if (!Array.isArray(agent.commands)) continue; + const scope = agent.scope || CORE_SCOPE; + if (!commandOwners.has(scope)) commandOwners.set(scope, new Map()); + const scopeOwners = commandOwners.get(scope); + for (const cmd of agent.commands) { - let cmdName; - if (typeof cmd === 'string') { - // String format: 'command: description' - cmdName = cmd.split(':')[0].trim(); - } else if (cmd.name) { - // Explicit format: { name: 'command', ... } - cmdName = cmd.name; - } else if (typeof cmd === 'object') { - // Shorthand format: { command: 'description' } - take first key - const keys = Object.keys(cmd); - cmdName = keys[0]?.split(' ')[0]; // Handle 'command {args}' format - } + const cmdName = commandName(cmd); if (!cmdName) continue; - if (!commandOwners.has(cmdName)) { - commandOwners.set(cmdName, []); - } - commandOwners.get(cmdName).push({ + if (!scopeOwners.has(cmdName)) scopeOwners.set(cmdName, []); + scopeOwners.get(cmdName).push({ agent: agent.id, file: agent.file, hasVisibility: cmd.visibility !== undefined, @@ -163,17 +281,20 @@ function validateCommandUniqueness(agents) { } } - // Check for duplicates - for (const [cmd, owners] of commandOwners) { - if (owners.length > 1 && !SHARED_COMMANDS.has(cmd)) { - const ownerList = owners.map((o) => `@${o.agent}`).join(', '); - errors.push({ - type: 'DUPLICATE_COMMAND', - command: cmd, - owners: owners.map((o) => o.agent), - message: `Command "*${cmd}" has multiple owners: ${ownerList}`, - suggestion: `Keep "*${cmd}" only in the primary owner agent and remove from others, or add to SHARED_COMMANDS if intentionally shared.`, - }); + // Check for duplicates, one scope at a time + for (const [scope, scopeOwners] of commandOwners) { + for (const [cmd, owners] of scopeOwners) { + if (owners.length > 1 && !SHARED_COMMANDS.has(cmd)) { + const ownerList = owners.map((o) => `@${o.agent}`).join(', '); + errors.push({ + type: 'DUPLICATE_COMMAND', + scope, + command: cmd, + owners: owners.map((o) => o.agent), + message: `[${scope}] Command "*${cmd}" has multiple owners: ${ownerList}`, + suggestion: `Keep "*${cmd}" only in the primary owner agent and remove from others, or add to SHARED_COMMANDS if intentionally shared.`, + }); + } } } @@ -187,31 +308,45 @@ async function validateDependencies(agents) { const errors = []; const warnings = []; - const depDirs = { - tasks: TASKS_DIR, - templates: TEMPLATES_DIR, - checklists: CHECKLISTS_DIR, - data: DATA_DIR, - utils: UTILS_DIR, - workflows: WORKFLOWS_DIR, - scripts: SCRIPTS_DIR, - }; - // Dependency types that are not file-based (external tools, integrations) const skipDepTypes = new Set(['tools', 'coderabbit_integration', 'pr_automation', 'repository_agnostic_design', 'git_authority', 'workflow_examples']); for (const agent of agents) { const deps = agent.dependencies; + // Squad agents resolve dependencies inside their own squad directory. + const depDirs = agent.depDirs || CORE_DEP_DIRS; for (const [depType, depList] of Object.entries(deps)) { // Skip non-file-based dependency types if (skipDepTypes.has(depType)) continue; if (!Array.isArray(depList)) continue; + // reference_files hold repo-relative paths, not / entries. + if (depType === 'reference_files') { + for (const refFile of depList) { + if (typeof refFile !== 'string') continue; + const refPath = path.join(REPO_ROOT, refFile); + if (!(await fileExists(refPath))) { + warnings.push({ + type: 'MISSING_REFERENCE_FILE', + scope: agent.scope, + agent: agent.id, + depType, + depFile: refFile, + expectedPath: refPath, + message: `Missing reference file: @${agent.id} → ${refFile}`, + suggestion: `Create ${refFile} or remove it from the agent's reference_files.`, + }); + } + } + continue; + } + const depDir = depDirs[depType]; if (!depDir) { warnings.push({ type: 'UNKNOWN_DEP_TYPE', + scope: agent.scope, agent: agent.id, depType, message: `Unknown dependency type "${depType}" in @${agent.id}`, @@ -227,6 +362,7 @@ async function validateDependencies(agents) { // Missing dependencies are warnings, not errors (pre-existing technical debt) warnings.push({ type: 'MISSING_DEPENDENCY', + scope: agent.scope, agent: agent.id, depType, depFile, @@ -342,7 +478,7 @@ function validateAgentFormat(agents) { */ function formatResults(results, showSuggestions = false) { const lines = []; - const { commandValidation, dependencyValidation, formatValidation, summary } = results; + const { parseValidation, commandValidation, dependencyValidation, formatValidation, summary } = results; lines.push(''); lines.push('━'.repeat(60)); @@ -350,6 +486,21 @@ function formatResults(results, showSuggestions = false) { lines.push('━'.repeat(60)); lines.push(''); + // YAML parseability — must come first: an unparseable agent cannot be checked at all + lines.push('🔍 YAML Parse Check'); + lines.push('─'.repeat(40)); + if (parseValidation.errors.length === 0) { + lines.push(' ✅ All agent definitions parse as YAML'); + } else { + for (const err of parseValidation.errors) { + lines.push(` ❌ ${err.message}`); + if (showSuggestions && err.suggestion) { + lines.push(` 💡 ${err.suggestion}`); + } + } + } + lines.push(''); + // Command Uniqueness lines.push('📋 Command Uniqueness Check'); lines.push('─'.repeat(40)); @@ -413,6 +564,9 @@ function formatResults(results, showSuggestions = false) { lines.push(' Summary'); lines.push('━'.repeat(60)); lines.push(` Agents validated: ${summary.totalAgents}`); + for (const { scope, count } of summary.scopes || []) { + lines.push(` • ${scope}: ${count}`); + } lines.push(` Errors: ${summary.totalErrors}`); lines.push(` Warnings: ${summary.totalWarnings}`); lines.push(''); @@ -431,38 +585,43 @@ function formatResults(results, showSuggestions = false) { * Main validation function */ async function validateAgents(options = {}) { - const { json = false, fixSuggestions = false } = options; + const { json = false, fixSuggestions = false, coreOnly = false } = options; - // Load all agents - const agents = await loadAllAgents(); + // Load core agents and, unless restricted, every squad's agents + const { agents, parseErrors, scopes } = await loadAgents({ includeSquads: !coreOnly }); - if (agents.length === 0) { + if (agents.length === 0 && parseErrors.length === 0) { console.error('No agents found in', AGENTS_DIR); process.exit(1); } // Run validations + const parseValidation = { errors: parseErrors, warnings: [] }; const commandValidation = validateCommandUniqueness(agents); const dependencyValidation = await validateDependencies(agents); const formatValidation = validateAgentFormat(agents); - // Calculate summary + // Calculate summary — an unparseable definition is an error, not a silent skip const totalErrors = + parseValidation.errors.length + commandValidation.errors.length + dependencyValidation.errors.length + formatValidation.errors.length; const totalWarnings = + parseValidation.warnings.length + commandValidation.warnings.length + dependencyValidation.warnings.length + formatValidation.warnings.length; const results = { + parseValidation, commandValidation, dependencyValidation, formatValidation, summary: { totalAgents: agents.length, + scopes, totalErrors, totalWarnings, valid: totalErrors === 0, @@ -502,6 +661,7 @@ Exit codes: const options = { json: args.includes('--json'), fixSuggestions: args.includes('--fix-suggestions') || args.includes('--fix'), + coreOnly: args.includes('--core-only'), }; const results = await validateAgents(options); @@ -514,7 +674,14 @@ module.exports = { validateCommandUniqueness, validateDependencies, validateAgentFormat, + // loadAllAgents mantém a assinatura antiga (devolve só a lista) para não quebrar + // quem já consome; loadAgents é o novo, com parseErrors e escopos. loadAllAgents, + loadAgents, + loadAgentsFromDir, + discoverSquads, + commandName, + CORE_SCOPE, }; // Run CLI if called directly diff --git a/.aiox-core/install-manifest.yaml b/.aiox-core/install-manifest.yaml index 0bd15989eb..c9fbfe350f 100644 --- a/.aiox-core/install-manifest.yaml +++ b/.aiox-core/install-manifest.yaml @@ -8,7 +8,7 @@ # - File types for categorization # version: 5.2.9 -generated_at: "2026-05-21T13:48:41.292Z" +generated_at: "2026-07-27T13:49:10.653Z" generator: scripts/generate-install-manifest.js file_count: 1129 files: @@ -2661,9 +2661,9 @@ files: type: task size: 13275 - path: development/tasks/validate-agents.md - hash: sha256:b278ba27cf8171d143aba30bd2f708b9226526dae70e9b881f52b5e1e908525f + hash: sha256:66200c9ce5fce7086f7982af8cff13b12bfbd506714a01d334c58f8d45d04107 type: task - size: 3595 + size: 4455 - path: development/tasks/validate-next-story.md hash: sha256:277faba94cba30ac3773159d641fc2b8a345efd70dcfef6bae15f8a6280128ea type: task @@ -2719,19 +2719,19 @@ files: - path: development/templates/service-template/__tests__/index.test.ts.hbs hash: sha256:4617c189e75ab362d4ef2cabcc3ccce3480f914fd915af550469c17d1b68a4fe type: template - size: 9573 + size: 9810 - path: development/templates/service-template/client.ts.hbs hash: sha256:f342c60695fe611192002bdb8c04b3a0dbce6345b7fa39834ea1898f71689198 type: template - size: 11810 + size: 12213 - path: development/templates/service-template/errors.ts.hbs hash: sha256:e0be40d8be19b71b26e35778eadffb20198e7ca88e9d140db9da1bfe12de01ec type: template - size: 5213 + size: 5395 - path: development/templates/service-template/index.ts.hbs hash: sha256:d44012d54b76ab98356c7163d257ca939f7fed122f10fecf896fe1e7e206d10a type: template - size: 3086 + size: 3206 - path: development/templates/service-template/jest.config.js hash: sha256:1681bfd7fbc0d330d3487d3427515847c4d57ef300833f573af59e0ad69ed159 type: template @@ -2739,11 +2739,11 @@ files: - path: development/templates/service-template/package.json.hbs hash: sha256:d89d35f56992ee95c2ceddf17fa1d455c18007a4d24af914ba83cf4abc38bca9 type: template - size: 2227 + size: 2314 - path: development/templates/service-template/README.md.hbs hash: sha256:2c3dd4c2bf6df56b9b6db439977be7e1cc35820438c0e023140eccf6ccd227a0 type: template - size: 3426 + size: 3584 - path: development/templates/service-template/tsconfig.json hash: sha256:8b465fcbdd45c4d6821ba99aea62f2bd7998b1bca8de80486a1525e77d43c9a1 type: template @@ -2751,7 +2751,7 @@ files: - path: development/templates/service-template/types.ts.hbs hash: sha256:3e52e0195003be8cd1225a3f27f4d040686c8b8c7762f71b41055f04cd1b841b type: template - size: 2516 + size: 2661 - path: development/templates/squad-template/agents/example-agent.yaml hash: sha256:824a1b349965e5d4ae85458c231b78260dc65497da75dada25b271f2cabbbe67 type: agent @@ -2759,7 +2759,7 @@ files: - path: development/templates/squad-template/LICENSE hash: sha256:ff7017aa403270cf2c440f5ccb4240d0b08e54d8bf8a0424d34166e8f3e10138 type: template - size: 1071 + size: 1092 - path: development/templates/squad-template/package.json hash: sha256:8f68627a0d74e49f94ae382d0c2b56ecb5889d00f3095966c742fb5afaf363db type: template @@ -3477,9 +3477,9 @@ files: type: script size: 18245 - path: infrastructure/scripts/validate-agents.js - hash: sha256:5f5f89a1fcf02ba340772ed30ade56fc346114d7a4d43e6d69af40858c64b180 + hash: sha256:708c52b9c80dae897878a345dc5079cc6b6567050a301fd2b2020672dd8314ea type: script - size: 14900 + size: 21246 - path: infrastructure/scripts/validate-claude-integration.js hash: sha256:e9d6776b9af9e9233e50aa7664eef7c67937af0ebabca1a3aa26c518debf8178 type: script @@ -3523,11 +3523,11 @@ files: - path: infrastructure/templates/aiox-sync.yaml.template hash: sha256:0040ad8a9e25716a28631b102c9448b72fd72e84f992c3926eb97e9e514744bb type: template - size: 8385 + size: 8567 - path: infrastructure/templates/coderabbit.yaml.template hash: sha256:91a4a76bbc40767a4072fb6a87c480902bb800cfb0a11e9fc1b3183d8f7f3a80 type: template - size: 8042 + size: 8321 - path: infrastructure/templates/core-config/core-config-brownfield.tmpl.yaml hash: sha256:9bdb0c0e09c765c991f9f142921f7f8e2c0d0ada717f41254161465dc0622d02 type: template @@ -3539,11 +3539,11 @@ files: - path: infrastructure/templates/github-workflows/ci.yml.template hash: sha256:acbfa2a8a84141fd6a6b205eac74719772f01c221c0afe22ce951356f06a605d type: template - size: 4920 + size: 5089 - path: infrastructure/templates/github-workflows/pr-automation.yml.template hash: sha256:c236077b4567965a917e48df9a91cc42153ff97b00a9021c41a7e28179be9d0f type: template - size: 10609 + size: 10939 - path: infrastructure/templates/github-workflows/README.md hash: sha256:6b7b5cb32c28b3e562c81a96e2573ea61849b138c93ccac6e93c3adac26cadb5 type: template @@ -3551,23 +3551,23 @@ files: - path: infrastructure/templates/github-workflows/release.yml.template hash: sha256:b771145e61a254a88dc6cca07869e4ece8229ce18be87132f59489cdf9a66ec6 type: template - size: 6595 + size: 6791 - path: infrastructure/templates/gitignore/gitignore-aiox-base.tmpl hash: sha256:9088975ee2bf4d88e23db6ac3ea5d27cccdc72b03db44450300e2f872b02e935 type: template - size: 788 + size: 851 - path: infrastructure/templates/gitignore/gitignore-brownfield-merge.tmpl hash: sha256:ce4291a3cf5677050c9dafa320809e6b0ca5db7e7f7da0382d2396e32016a989 type: template - size: 488 + size: 506 - path: infrastructure/templates/gitignore/gitignore-node.tmpl hash: sha256:5179f78de7483274f5d7182569229088c71934db1fd37a63a40b3c6b815c9c8e type: template - size: 951 + size: 1036 - path: infrastructure/templates/gitignore/gitignore-python.tmpl hash: sha256:d7aac0b1e6e340b774a372a9102b4379722588449ca82ac468cf77804bbc1e55 type: template - size: 1580 + size: 1725 - path: infrastructure/templates/project-docs/coding-standards-tmpl.md hash: sha256:377acf85463df8ac9923fc59d7cfeba68a82f8353b99948ea1d28688e88bc4a9 type: template @@ -3663,43 +3663,43 @@ files: - path: monitor/hooks/lib/__init__.py hash: sha256:bfab6ee249c52f412c02502479da649b69d044938acaa6ab0aa39dafe6dee9bf type: monitor - size: 29 + size: 30 - path: monitor/hooks/lib/enrich.py hash: sha256:20dfa73b4b20d7a767e52c3ec90919709c4447c6e230902ba797833fc6ddc22c type: monitor - size: 1644 + size: 1702 - path: monitor/hooks/lib/send_event.py hash: sha256:59d61311f718fb373a5cf85fd7a01c23a4fd727e8e022ad6930bba533ef4615d type: monitor - size: 1190 + size: 1237 - path: monitor/hooks/notification.py hash: sha256:8a1a6ce0ff2b542014de177006093b9caec9b594e938a343dc6bd62df2504f22 type: monitor - size: 499 + size: 528 - path: monitor/hooks/post_tool_use.py hash: sha256:47dbe37073d432c55657647fc5b907ddb56efa859d5c3205e8362aa916d55434 type: monitor - size: 1140 + size: 1185 - path: monitor/hooks/pre_compact.py hash: sha256:f287cf45e83deed6f1bc0e30bd9348dfa1bf08ad770c5e58bb34e3feb210b30b type: monitor - size: 500 + size: 529 - path: monitor/hooks/pre_tool_use.py hash: sha256:a4d1d3ffdae9349e26a383c67c9137effff7d164ac45b2c87eea9fa1ab0d6d98 type: monitor - size: 981 + size: 1021 - path: monitor/hooks/stop.py hash: sha256:edb382f0cf46281a11a8588bc20eafa7aa2b5cc3f4ad775d71b3d20a7cfab385 type: monitor - size: 490 + size: 519 - path: monitor/hooks/subagent_stop.py hash: sha256:fa5357309247c71551dba0a19f28dd09bebde749db033d6657203b50929c0a42 type: monitor - size: 512 + size: 541 - path: monitor/hooks/user_prompt_submit.py hash: sha256:af57dca79ef55cdf274432f4abb4c20a9778b95e107ca148f47ace14782c5828 type: monitor - size: 818 + size: 856 - path: package.json hash: sha256:d8dbe037240a366d545ca4259d2059e705b709706dcf2a18a5a52d9b543b7ed9 type: other @@ -3847,7 +3847,7 @@ files: - path: product/templates/adr.hbs hash: sha256:d68653cae9e64414ad4f58ea941b6c6e337c5324c2c7247043eca1461a652d10 type: template - size: 2212 + size: 2337 - path: product/templates/agent-template.yaml hash: sha256:98676fcc493c0d5f09264dcc52fcc2cf1129f9a195824ecb4c2ec035c2515121 type: template @@ -3899,7 +3899,7 @@ files: - path: product/templates/dbdr.hbs hash: sha256:5a2781ffaa3da9fc663667b5a63a70b7edfc478ed14cad02fc6ed237ff216315 type: template - size: 4139 + size: 4380 - path: product/templates/design-story-tmpl.yaml hash: sha256:2bfefc11ae2bcfc679dbd924c58f8b764fa23538c14cb25344d6edef41968f29 type: template @@ -3963,7 +3963,7 @@ files: - path: product/templates/epic.hbs hash: sha256:dcbcc26f6dd8f3782b3ef17aee049b689f1d6d92931615c3df9513eca0de2ef7 type: template - size: 3868 + size: 4080 - path: product/templates/eslintrc-security.json hash: sha256:657d40117261d6a52083984d29f9f88e79040926a64aa4c2058a602bfe91e0d5 type: template @@ -4071,7 +4071,7 @@ files: - path: product/templates/pmdr.hbs hash: sha256:d529cebbb562faa82c70477ece70de7cda871eaa6896f2962b48b2a8b67b1cbe type: template - size: 3239 + size: 3425 - path: product/templates/prd-tmpl.yaml hash: sha256:25c239f40e05f24aee1986601a98865188dbe3ea00a705028efc3adad6d420f3 type: template @@ -4079,11 +4079,11 @@ files: - path: product/templates/prd-v2.0.hbs hash: sha256:21a20ef5333a85a11f5326d35714e7939b51bab22bd6e28d49bacab755763bea type: template - size: 4512 + size: 4728 - path: product/templates/prd.hbs hash: sha256:4a1a030a5388c6a8bf2ce6ea85e54cae6cf1fe64f1bb2af7f17d349d3c24bf1d type: template - size: 3425 + size: 3626 - path: product/templates/project-brief-tmpl.yaml hash: sha256:b8d388268c24dc5018f48a87036d591b11cb122fafe9b59c17809b06ea5d9d58 type: template @@ -4131,7 +4131,7 @@ files: - path: product/templates/story.hbs hash: sha256:3f0ac8b39907634a2b53f43079afc33663eee76f46e680d318ff253e0befc2c4 type: template - size: 5583 + size: 5846 - path: product/templates/task-execution-report.md hash: sha256:e0f08a3e199234f3d2207ba8f435786b7d8e1b36174f46cb82fc3666b9a9309e type: template @@ -4143,67 +4143,67 @@ files: - path: product/templates/task.hbs hash: sha256:621e987e142c455cd290dc85d990ab860faa0221f66cf1f57ac296b076889ea5 type: template - size: 2705 + size: 2875 - path: product/templates/tmpl-comment-on-examples.sql hash: sha256:254002c3fbc63cfcc5848b1d4b15822ce240bf5f57e6a1c8bb984e797edc2691 type: template - size: 6215 + size: 6373 - path: product/templates/tmpl-migration-script.sql hash: sha256:44ef63ea475526d21a11e3c667c9fdb78a9fddace80fdbaa2312b7f2724fbbb5 type: template - size: 2947 + size: 3038 - path: product/templates/tmpl-rls-granular-policies.sql hash: sha256:36c2fd8c6d9eebb5d164acb0fb0c87bc384d389264b4429ce21e77e06318f5f3 type: template - size: 3322 + size: 3426 - path: product/templates/tmpl-rls-kiss-policy.sql hash: sha256:5210d37fce62e5a9a00e8d5366f5f75653cd518be73fbf96333ed8a6712453c7 type: template - size: 299 + size: 309 - path: product/templates/tmpl-rls-roles.sql hash: sha256:2d032a608a8e87440c3a430c7d69ddf9393d8813d8d4129270f640dd847425c3 type: template - size: 4592 + size: 4727 - path: product/templates/tmpl-rls-simple.sql hash: sha256:f67af0fa1cdd2f2af9eab31575ac3656d82457421208fd9ccb8b57ca9785275e type: template - size: 2915 + size: 2992 - path: product/templates/tmpl-rls-tenant.sql hash: sha256:36629ed87a2c72311809cc3fb96298b6f38716bba35bc56c550ac39d3321757a type: template - size: 4978 + size: 5130 - path: product/templates/tmpl-rollback-script.sql hash: sha256:8b84046a98f1163faf7350322f43831447617c5a63a94c88c1a71b49804e022b type: template - size: 2657 + size: 2734 - path: product/templates/tmpl-seed-data.sql hash: sha256:a65e73298f46cd6a8e700f29b9d8d26e769e12a57751a943a63fd0fe15768615 type: template - size: 5576 + size: 5716 - path: product/templates/tmpl-smoke-test.sql hash: sha256:aee7e48bb6d9c093769dee215cacc9769939501914e20e5ea8435b25fad10f3c type: template - size: 723 + size: 739 - path: product/templates/tmpl-staging-copy-merge.sql hash: sha256:55988caeb47cc04261665ba7a37f4caa2aa5fac2e776fdbc5964e0587af24450 type: template - size: 4081 + size: 4220 - path: product/templates/tmpl-stored-proc.sql hash: sha256:2b205ff99dc0adfade6047a4d79f5b50109e50ceb45386e5c886437692c7a2a3 type: template - size: 3839 + size: 3979 - path: product/templates/tmpl-trigger.sql hash: sha256:93abdc92e1b475d1370094e69a9d1b18afd804da6acb768b878355c798bd8e0e type: template - size: 5272 + size: 5424 - path: product/templates/tmpl-view-materialized.sql hash: sha256:47935510f03d4ad9b2200748e65441ce6c2d6a7c74750395eca6831d77c48e91 type: template - size: 4363 + size: 4496 - path: product/templates/tmpl-view.sql hash: sha256:22557b076003a856b32397f05fa44245a126521de907058a95e14dd02da67aff type: template - size: 4916 + size: 5093 - path: product/templates/token-exports-css-tmpl.css hash: sha256:d937b8d61cdc9e5b10fdff871c6cb41c9f756004d060d671e0ae26624a047f62 type: template