sinapse-ai 1.11.3 → 1.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/.claude/hooks/enforce-architecture-first.cjs +2 -2
  2. package/.claude/hooks/enforce-delegation.cjs +2 -2
  3. package/.claude/hooks/enforce-permission-mode.cjs +12 -12
  4. package/.claude/hooks/enforce-story-gate.cjs +5 -5
  5. package/.claude/hooks/precompact-session-digest.cjs +2 -2
  6. package/.claude/hooks/secret-scanning.cjs +6 -6
  7. package/.claude/hooks/telemetry-post-tool.cjs +0 -1
  8. package/.claude/hooks/write-path-validation.cjs +2 -2
  9. package/.sinapse-ai/core/code-intel/helpers/dev-helper.js +1 -1
  10. package/.sinapse-ai/core/code-intel/helpers/devops-helper.js +0 -1
  11. package/.sinapse-ai/core/code-intel/helpers/planning-helper.js +1 -1
  12. package/.sinapse-ai/core/code-intel/helpers/qa-helper.js +2 -2
  13. package/.sinapse-ai/core/config/template-overrides.js +1 -1
  14. package/.sinapse-ai/core/doctor/checks/git-hooks.js +6 -3
  15. package/.sinapse-ai/core/doctor/checks/npm-packages.js +1 -1
  16. package/.sinapse-ai/core/doctor/checks/rules-files.js +0 -1
  17. package/.sinapse-ai/core/doctor/index.js +0 -1
  18. package/.sinapse-ai/core/graph-dashboard/cli.js +1 -1
  19. package/.sinapse-ai/core/graph-dashboard/data-sources/code-intel-source.js +1 -1
  20. package/.sinapse-ai/core/health-check/checks/project/constitution-consistency.js +0 -1
  21. package/.sinapse-ai/core/ideation/ideation-engine.js +0 -2
  22. package/.sinapse-ai/core/ids/layer-classifier.js +1 -1
  23. package/.sinapse-ai/core/registry/build-registry.js +12 -2
  24. package/.sinapse-ai/core/registry/service-registry.json +178 -55
  25. package/.sinapse-ai/core/registry/squad-agent-resolver.js +6 -0
  26. package/.sinapse-ai/core/synapse/layers/layer-processor.js +1 -1
  27. package/.sinapse-ai/data/capability-detection.js +15 -15
  28. package/.sinapse-ai/data/tok3-token-comparison.js +0 -3
  29. package/.sinapse-ai/data/tool-search-validation.js +1 -1
  30. package/.sinapse-ai/development/agents/snps-orqx.md +109 -0
  31. package/.sinapse-ai/development/scripts/agent-config-loader.js +8 -2
  32. package/.sinapse-ai/development/templates/sinapse-doc-template.md +6 -6
  33. package/.sinapse-ai/git-hooks/lib/framework-guard.js +1 -0
  34. package/.sinapse-ai/git-hooks/lib/staged-protected-files-guard.js +63 -0
  35. package/.sinapse-ai/git-hooks/pre-commit +3 -1
  36. package/.sinapse-ai/index.d.ts +19 -0
  37. package/.sinapse-ai/infrastructure/scripts/validate-agents.js +46 -16
  38. package/.sinapse-ai/install-manifest.yaml +61 -57
  39. package/.sinapse-ai/package.json +0 -1
  40. package/.sinapse-ai/utils/filters/index.js +2 -1
  41. package/CHANGELOG.md +38 -2
  42. package/README.md +132 -132
  43. package/bin/commands/doctor.js +1 -1
  44. package/bin/commands/help.js +3 -4
  45. package/bin/commands/install.js +7 -7
  46. package/bin/commands/status.js +3 -3
  47. package/bin/modules/chrome-brain-installer.js +3 -3
  48. package/bin/postinstall.js +1 -1
  49. package/bin/sinapse-init.js +11 -9
  50. package/bin/sinapse.js +1 -1
  51. package/bin/utils/framework-guard.js +1 -0
  52. package/bin/utils/staged-protected-files-guard.js +63 -0
  53. package/package.json +19 -2
  54. package/packages/installer/src/index.js +1 -1
  55. package/packages/installer/src/installer/brownfield-upgrader.js +1 -1
  56. package/packages/installer/src/installer/git-hooks-installer.js +10 -3
  57. package/packages/installer/src/pro/pro-scaffolder.js +3 -3
  58. package/packages/installer/src/wizard/ide-config-generator.js +1 -1
  59. package/packages/installer/src/wizard/index.js +4 -41
  60. package/scripts/audit-tasks.cjs +1 -1
  61. package/scripts/package-synapse.js +1 -1
  62. package/scripts/sinapse-patch.js +31 -31
  63. package/scripts/sync-squad-yaml-components.js +3 -3
  64. package/scripts/validate-agents-md.js +1 -1
  65. package/scripts/validate-no-external-refs.js +2 -2
  66. package/scripts/validate-no-personal-leaks.js +1 -1
  67. package/scripts/validate-orqx-discipline.js +0 -2
  68. package/scripts/validate-package-completeness.js +7 -7
  69. package/scripts/validate-squad-yaml.js +6 -6
  70. package/sinapse/agents/sinapse-orqx.md +1 -1
  71. package/sinapse/agents/snps-orqx.md +110 -1
  72. package/squads/claude-code-mastery/agents/swarm-orqx.md +12 -11
  73. package/squads/claude-code-mastery/scripts/validate-setup.js +2 -2
  74. package/squads/squad-brand/agents/brand-orqx.md +16 -1
  75. package/squads/squad-cloning/agents/cloning-orqx.md +2 -0
  76. package/squads/squad-commercial/agents/commercial-orqx.md +7 -4
  77. package/squads/squad-council/squad.yaml +67 -11
  78. package/squads/squad-design/agents/design-orqx.md +20 -0
  79. package/squads/squad-finance/agents/finance-orqx.md +6 -0
  80. package/squads/squad-paidmedia/agents/paidmedia-orqx.md +3 -1
@@ -44,9 +44,102 @@ After the greeting, check if the user already provided briefing/context with the
44
44
 
45
45
  If the user asks about SINAPSE, how it works, or how to use it, execute the `*onboard` task from `tasks/onboard-user.md` to provide a guided walkthrough of the ecosystem, available squads, commands, and workflows.
46
46
 
47
+ ## NON-NEGOTIABLE: INITIAL STATE AUDIT (RUNS FIRST OF ALL)
48
+
49
+ > **This step runs BEFORE bootstrap classification, BEFORE routing, BEFORE anything.**
50
+ > Without it, Imperator treats every directory as greenfield and ignores existing partial work (brand assets, half-written PRD, components, abandoned epics, brownfield code without `package.json`).
51
+
52
+ On every briefing that mentions creating, building, or working on a project, run the **Initial State Audit** (full spec in `~/.claude/rules/project-intelligence.md` § Initial State Audit):
53
+
54
+ 1. Silently check the 8 dimensions (Docs, Brand, Design system, Components, Code, Tests, Infra, Git history)
55
+ 2. Compute maturity level: `EMPTY` / `BOOTSTRAPPED` / `PARTIAL` / `MATURE` / `SINAPSE_MANAGED`
56
+ 3. **Present a structured report to the user (PT-BR) BEFORE proposing any plan:**
57
+ ```
58
+ Estado detectado: {maturity_level}
59
+ Já existe: {list of artifacts found}
60
+ Faltando: {list of gaps relative to user's goal}
61
+ Recomendação: {workflow + first step}
62
+ ```
63
+ 4. Only after this report (and any user correction) proceed to bootstrap classification
64
+
65
+ ### Why this exists
66
+
67
+ Caio's runtime test (2026-05-07) showed the framework treating fresh installs as "create from scratch" without ever checking what already lived in the directory. A user often has brand assets, an old PRD, half-finished components, or an abandoned epic — and the framework was overwriting / duplicating that work instead of continuing from it.
68
+
69
+ ### Anti-patterns (FORBIDDEN)
70
+
71
+ - Skipping the audit "because it looks empty"
72
+ - Routing to greenfield workflows without first reporting what already exists
73
+ - Overwriting partial work (brand assets, components, docs) without listing it to the user
74
+ - Ignoring `docs/epics/` or `docs/stories/` from a previous session
75
+ - Treating a directory with brand assets but no code as `EMPTY`
76
+ - Treating a directory with `package.json` as `MATURE` when it's actually just bootstrapped infra
77
+
78
+ ## NON-NEGOTIABLE: PROJECT BOOTSTRAP CLASSIFICATION (RUNS AFTER AUDIT, BEFORE ROUTING)
79
+
80
+ > **This step runs AFTER the Initial State Audit, BEFORE the routing decision. No exceptions.**
81
+ > Without it, Imperator routes large-project requests directly to a domain orchestrator and skips the doc-first pipeline (Article III violation).
82
+
83
+ After the audit reports the maturity level, classify the request **before** consulting the routing table:
84
+
85
+ ### Step 1 — Detect intent
86
+
87
+ | Intent | Trigger keywords (PT/EN) |
88
+ |---|---|
89
+ | `new_project_bootstrap` | criar / novo / build / montar / fazer um(a) [site, plataforma, app, API, ...] |
90
+ | `feature_in_existing_project` | implementa / adiciona / add (with `docs/epics/` already present) |
91
+ | `fix` | corrige / conserta / ajusta / fix / bug |
92
+ | `tweak` | troca / muda / altera (small surface, single file) |
93
+ | `domain_consult` | qualquer pergunta de branding, copy, growth, etc. (no code change implied) |
94
+
95
+ ### Step 2 — If `new_project_bootstrap`, sub-classify project_type
96
+
97
+ | project_type | Triggers | Required workflow |
98
+ |---|---|---|
99
+ | `site` | site, website, institutional, página | `greenfield-ui.yaml` |
100
+ | `lp` | landing page, LP, captura, sales page | `greenfield-ui.yaml` |
101
+ | `app` | app mobile, app nativo, ios, android, react native | `greenfield-ui.yaml` |
102
+ | `platform` | plataforma, dashboard, admin, portal interno | `greenfield-fullstack.yaml` |
103
+ | `saas` | SaaS, software as a service, app web com login | `greenfield-fullstack.yaml` |
104
+ | `api` | API, backend, microservice, serviço REST/GraphQL | `greenfield-service.yaml` |
105
+ | `service` | worker, integration, automation, ETL, cron job | `greenfield-service.yaml` |
106
+
107
+ ### Step 3 — Apply the gate (NON-NEGOTIABLE)
108
+
109
+ ```
110
+ IF intent == new_project_bootstrap
111
+ AND project_type ∈ [site, lp, app, platform, saas, api, service]
112
+ AND no epic exists in docs/epics/
113
+ THEN
114
+ BLOCK any direct routing to domain orchestrators
115
+ INVOKE the required greenfield workflow (see table)
116
+ PRODUCE upstream artifacts FIRST: project-brief.md → prd.md → architecture.md (and front-end-spec.md for UI)
117
+ ONLY AFTER artifacts validated → shard → stories → route to domain orqx for execution
118
+ ```
119
+
120
+ ### Step 4 — Complexity gate
121
+
122
+ If the briefing scores ≥ 16 on the 5 complexity dimensions (scope, integration, infrastructure, knowledge, risk), run the **Spec Pipeline** (`spec-pipeline.yaml`) BEFORE the greenfield workflow:
123
+
124
+ ```
125
+ @project-lead gather → @architect assess → @analyst research →
126
+ @project-lead spec → @quality-gate critique → @architect plan
127
+ ```
128
+
129
+ Only after spec is APPROVED, the greenfield workflow runs.
130
+
131
+ ### Anti-patterns (FORBIDDEN — these violate Article III)
132
+
133
+ - Routing "criar um site" directly to `@design-orqx` / `@brand-orqx` without first running greenfield-ui.yaml
134
+ - Routing "monta uma plataforma SaaS" to a domain orqx without Spec Pipeline + greenfield-fullstack.yaml
135
+ - Skipping Phase 1 Discovery (5-agent: analyst → project-lead → ux-design-expert → architect → product-lead) on a new UI project
136
+ - Treating "rapidinho" / "simples" as a license to skip doc-first when the project type requires it
137
+ - Generating UI without DS grounding (see `~/.claude/rules/design-system-grounding.md`)
138
+
47
139
  ## NON-NEGOTIABLE: ORCHESTRATION PLAN ON EVERY BRIEFING
48
140
 
49
141
  > **This is an absolute, non-negotiable rule. No exceptions. No waiting to be asked.**
142
+ > **It runs AFTER the bootstrap classification above.** If the gate routed to a greenfield workflow, the orchestration plan describes that workflow (its phases, agents, handoffs) — not a domain-orqx routing.
50
143
 
51
144
  When the user provides ANY briefing, request, or initiative (regardless of complexity), Imperator MUST **immediately and autonomously**:
52
145
 
@@ -610,6 +703,22 @@ framework_compatibility:
610
703
 
611
704
  ## How Imperator Operates
612
705
 
706
+ ### -1. Initial State Audit (ABSOLUTE FIRST)
707
+ Before anything else, Imperator runs the Initial State Audit described above:
708
+ - Silently checks 8 dimensions (Docs, Brand, DS, Components, Code, Tests, Infra, Git)
709
+ - Computes maturity level: `EMPTY` / `BOOTSTRAPPED` / `PARTIAL` / `MATURE` / `SINAPSE_MANAGED`
710
+ - Presents structured PT-BR report to user listing what exists, what's missing, what's recommended
711
+ - Only proceeds when the user has seen what's already there
712
+
713
+ ### 0. Bootstrap Classification (after audit)
714
+ Imperator runs the Project Bootstrap Classification described above:
715
+ - Detects intent: `new_project_bootstrap` / `feature` / `fix` / `tweak` / `domain_consult`
716
+ - Sub-classifies project_type if bootstrap: `site` / `lp` / `app` / `platform` / `saas` / `api` / `service`
717
+ - Applies the gate: large-project bootstrap with no epic → invokes the required greenfield workflow
718
+ - Triggers the Spec Pipeline if complexity score ≥ 16
719
+ - Routes to Continuation Behavior when audit detected `PARTIAL` maturity (never overwrite existing work)
720
+ - Only proceeds to step 1 (routing) when this gate is satisfied
721
+
613
722
  ### 1. Diagnose First
614
723
  Every request gets classified before routing. Imperator identifies:
615
724
  - **Domain(s):** Which squad(s) own this work?
@@ -12,6 +12,10 @@ const path = require('path');
12
12
  const yaml = require('js-yaml');
13
13
  const { globalConfigCache } = require('../../core/config/config-cache');
14
14
  const { trackConfigLoad } = require('../../infrastructure/scripts/performance-tracker');
15
+ // Canonical short-form → file-id alias map (single source of truth). Without this,
16
+ // short ids like 'dev'/'qa'/'sinapse-orqx' resolve to '<id>.md' which does not exist
17
+ // (files are developer.md / quality-gate.md / snps-orqx.md), degrading the greeting.
18
+ const { ALIASES: AGENT_ID_ALIASES } = require('../../core/registry/squad-agent-resolver');
15
19
 
16
20
  /**
17
21
  * Agent configuration requirements cache
@@ -317,8 +321,10 @@ class AgentConfigLoader {
317
321
  }
318
322
  }
319
323
 
320
- // Load from file
321
- const agentPath = path.join(process.cwd(), '.sinapse-ai', 'development', 'agents', `${this.agentId}.md`);
324
+ // Load from file. Resolve short-form aliases (dev→developer, qa→quality-gate,
325
+ // sinapse-orqx→snps-orqx, ...) to the canonical file id before building the path.
326
+ const fileId = AGENT_ID_ALIASES[this.agentId] || this.agentId;
327
+ const agentPath = path.join(process.cwd(), '.sinapse-ai', 'development', 'agents', `${fileId}.md`);
322
328
 
323
329
  try {
324
330
  const content = await fs.readFile(agentPath, 'utf8');
@@ -65,7 +65,7 @@ _Last Updated: {{DATE}} | SINAPSE Framework Team_
65
65
  ```markdown
66
66
  # {{TITLE}}
67
67
 
68
- > **EN** | [PT](../pt/path/{{FILENAME}}) | [ES](../es/path/{{FILENAME}})
68
+ > **EN** | [PT](../pt/path/{{FILENAME}})
69
69
 
70
70
  ---
71
71
 
@@ -169,7 +169,7 @@ _Last Updated: {{DATE}} | SINAPSE Framework Team_
169
169
  ```markdown
170
170
  # ADR-{{NUMBER}}: {{TITLE}}
171
171
 
172
- > **EN** | [PT](../../pt/architecture/adr/{{FILENAME}}) | [ES](../../es/architecture/adr/{{FILENAME}})
172
+ > **EN** | [PT](../../pt/architecture/adr/{{FILENAME}})
173
173
 
174
174
  ---
175
175
 
@@ -224,7 +224,7 @@ _Decision made as part of {{STORY_ID}}._
224
224
  ```markdown
225
225
  # {{TITLE}} Guide
226
226
 
227
- > **EN** | [PT](../pt/guides/{{FILENAME}}) | [ES](../es/guides/{{FILENAME}})
227
+ > **EN** | [PT](../pt/guides/{{FILENAME}})
228
228
 
229
229
  ---
230
230
 
@@ -311,7 +311,7 @@ _Last Updated: {{DATE}} | SINAPSE Framework Team_
311
311
  ```markdown
312
312
  # {{COMPONENT}} Reference
313
313
 
314
- > **EN** | [PT](../pt/reference/{{FILENAME}}) | [ES](../es/reference/{{FILENAME}})
314
+ > **EN** | [PT](../pt/reference/{{FILENAME}})
315
315
 
316
316
  ---
317
317
 
@@ -396,7 +396,7 @@ docs/
396
396
  Always include the language navigation header:
397
397
 
398
398
  ```markdown
399
- > **EN** | [PT](../pt/path/file.md) | [ES](../es/path/file.md)
399
+ > **EN** | [PT](../pt/path/file.md)
400
400
  ```
401
401
 
402
402
  ### Translation Notes
@@ -445,7 +445,7 @@ Always include the language navigation header:
445
445
  ```markdown
446
446
  # Creating Custom Agents
447
447
 
448
- > **EN** | [PT](../pt/guides/creating-agents.md) | [ES](../es/guides/creating-agents.md)
448
+ > **EN** | [PT](../pt/guides/creating-agents.md)
449
449
 
450
450
  ---
451
451
 
@@ -54,6 +54,7 @@ function globToRegex(glob) {
54
54
  pattern = pattern.replace(/\*/g, '[^/]+');
55
55
 
56
56
  // 4. Restore ** placeholder to any-depth matcher
57
+ // eslint-disable-next-line no-control-regex -- internal placeholder char (set above), never user input
57
58
  pattern = pattern.replace(/\u0000/g, '.+');
58
59
 
59
60
  // If pattern ends with .+ (was **), match prefix
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * staged-protected-files-guard — blocks a commit that DELETES (or untracks) a
6
+ * protected, committed-but-critical framework file.
7
+ *
8
+ * Why: on 2026-06-20 a "snapshot migracao notebook" sweep (`git add -A`) untracked
9
+ * `.sinapse-ai/core/registry/service-registry.json` (the committed registry drift
10
+ * detector, ~12k lines), bundled it with unrelated work, and pushed it. The
11
+ * framework-boundary guard is a no-op in contributor mode
12
+ * (boundary.frameworkProtection=false), so nothing stopped the deletion. This guard
13
+ * is ALWAYS on and narrowly targets that class of damage — it never touches normal
14
+ * edits, only the removal of a curated set of protected paths.
15
+ *
16
+ * Intentional removal (done in a story) bypasses with: git commit --no-verify
17
+ *
18
+ * Self-contained: Node built-ins + `git` only (matches the other lib guards so it
19
+ * bundles into <hooksDir>/lib/ with no extra deps).
20
+ */
21
+
22
+ const { spawnSync } = require('child_process');
23
+
24
+ // Curated, high-signal list. Keep small to guarantee zero false positives on
25
+ // normal work. These files are committed on purpose and must never be removed by
26
+ // an automated sweep without an explicit story.
27
+ const PROTECTED = ['.sinapse-ai/core/registry/service-registry.json'];
28
+
29
+ function stagedDeletions() {
30
+ // --no-renames forces a rename-away of a protected file to surface as a real
31
+ // deletion (D) of the old path, so moving the file out also trips the guard.
32
+ const res = spawnSync('git', ['diff', '--cached', '--name-status', '--no-renames'], {
33
+ encoding: 'utf8',
34
+ });
35
+ if (!res || res.status !== 0 || typeof res.stdout !== 'string') return [];
36
+ const deleted = [];
37
+ for (const line of res.stdout.split('\n')) {
38
+ if (!line) continue;
39
+ const parts = line.split('\t');
40
+ const status = parts[0];
41
+ const file = (parts[parts.length - 1] || '').replace(/\\/g, '/');
42
+ if (status === 'D') deleted.push(file);
43
+ }
44
+ return deleted;
45
+ }
46
+
47
+ const offenders = stagedDeletions().filter((f) => PROTECTED.includes(f));
48
+
49
+ if (offenders.length > 0) {
50
+ process.stderr.write(
51
+ 'SINAPSE Protected Files: blocking commit — it deletes/untracks a protected file:\n',
52
+ );
53
+ for (const f of offenders) process.stderr.write(' - ' + f + '\n');
54
+ process.stderr.write(
55
+ '\nThese files are committed on purpose (e.g. service-registry.json is the registry\n' +
56
+ 'drift detector). They must not be removed by an automated sweep (git add -A) or a\n' +
57
+ 'machine-migration snapshot. If this removal is intentional, do it in a story and\n' +
58
+ 'bypass once with: git commit --no-verify\n',
59
+ );
60
+ process.exit(1);
61
+ }
62
+
63
+ process.exit(0);
@@ -11,12 +11,14 @@ const projectRoot = process.cwd();
11
11
  const libDir = path.join(__dirname, 'lib');
12
12
 
13
13
  // --- 1-3. SINAPSE staged guards (each fail-CLOSED) ---------------------------
14
- // Order: secret scan, then destructive-SQL guard, then framework-boundary guard.
14
+ // Order: secret scan, destructive-SQL guard, framework-boundary guard, then
15
+ // protected-files guard (always-on anti-sweep; does NOT respect frameworkProtection).
15
16
  // framework-guard self-disables when boundary.frameworkProtection is false.
16
17
  const GUARDS = [
17
18
  { file: 'staged-secret-scan.js', label: 'Secret Scan' },
18
19
  { file: 'staged-sql-guard.js', label: 'SQL Guard' },
19
20
  { file: 'framework-guard.js', label: 'Framework Boundary' },
21
+ { file: 'staged-protected-files-guard.js', label: 'Protected Files' },
20
22
  ];
21
23
 
22
24
  for (const guard of GUARDS) {
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Type declarations for the SINAPSE programmatic API (CommonJS + ESM entry points).
3
+ *
4
+ * The underlying modules are authored in JavaScript, so these declarations expose
5
+ * the public constructors only — enough for `import { MetaAgent } from 'sinapse-ai'`
6
+ * to resolve. Member signatures are intentionally permissive (the JS implementation
7
+ * is the source of truth); this file does NOT fabricate detailed types it cannot
8
+ * guarantee. The framework is CLI-first; the programmatic API is a secondary surface.
9
+ */
10
+
11
+ /** A JS class/constructor exposed by the framework, with an unconstrained surface. */
12
+ type FrameworkConstructor = new (...args: unknown[]) => unknown;
13
+
14
+ export const MetaAgent: FrameworkConstructor;
15
+ export const TaskManager: FrameworkConstructor;
16
+ export const ElicitationEngine: FrameworkConstructor;
17
+ export const TemplateEngine: FrameworkConstructor;
18
+ export const ComponentSearch: FrameworkConstructor;
19
+ export const DependencyAnalyzer: FrameworkConstructor;
@@ -35,6 +35,18 @@ const DATA_DIR = path.join(ROOT_DIR, 'development', 'data');
35
35
  const UTILS_DIR = path.join(ROOT_DIR, 'development', 'utils');
36
36
  const WORKFLOWS_DIR = path.join(ROOT_DIR, 'development', 'workflows');
37
37
  const SCRIPTS_DIR = path.join(ROOT_DIR, 'development', 'scripts');
38
+ // Additional canonical homes — the framework stores agent artifacts across
39
+ // development/, product/, data/ and infrastructure/, not only development/.
40
+ const KNOWLEDGE_BASE_DIR = path.join(ROOT_DIR, 'development', 'knowledge-base');
41
+ const PRODUCT_TEMPLATES_DIR = path.join(ROOT_DIR, 'product', 'templates');
42
+ const PRODUCT_CHECKLISTS_DIR = path.join(ROOT_DIR, 'product', 'checklists');
43
+ const PRODUCT_DATA_DIR = path.join(ROOT_DIR, 'product', 'data');
44
+ const ROOT_DATA_DIR = path.join(ROOT_DIR, 'data');
45
+ const INFRA_SCRIPTS_DIR = path.join(ROOT_DIR, 'infrastructure', 'scripts');
46
+ const INFRA_SCHEMAS_DIR = path.join(ROOT_DIR, 'infrastructure', 'schemas');
47
+ const SCHEMAS_DIR = path.join(ROOT_DIR, 'schemas');
48
+ const CORE_EXECUTION_DIR = path.join(ROOT_DIR, 'core', 'execution');
49
+ const CORE_MEMORY_DIR = path.join(ROOT_DIR, 'core', 'memory');
38
50
 
39
51
  // Commands that are allowed to be shared by multiple agents
40
52
  // These are utility/infrastructure commands, not domain-specific
@@ -187,14 +199,18 @@ async function validateDependencies(agents) {
187
199
  const errors = [];
188
200
  const warnings = [];
189
201
 
202
+ // Each dependency type resolves against one or more candidate directories —
203
+ // an artifact is considered present if it exists in ANY of them.
190
204
  const depDirs = {
191
- tasks: TASKS_DIR,
192
- templates: TEMPLATES_DIR,
193
- checklists: CHECKLISTS_DIR,
194
- data: DATA_DIR,
195
- utils: UTILS_DIR,
196
- workflows: WORKFLOWS_DIR,
197
- scripts: SCRIPTS_DIR,
205
+ tasks: [TASKS_DIR],
206
+ templates: [TEMPLATES_DIR, PRODUCT_TEMPLATES_DIR],
207
+ checklists: [CHECKLISTS_DIR, PRODUCT_CHECKLISTS_DIR],
208
+ data: [DATA_DIR, ROOT_DATA_DIR, PRODUCT_DATA_DIR],
209
+ utils: [UTILS_DIR, SCRIPTS_DIR, INFRA_SCRIPTS_DIR, CORE_EXECUTION_DIR, CORE_MEMORY_DIR],
210
+ workflows: [WORKFLOWS_DIR],
211
+ scripts: [SCRIPTS_DIR, INFRA_SCRIPTS_DIR, CORE_EXECUTION_DIR, CORE_MEMORY_DIR],
212
+ knowledge_bases: [KNOWLEDGE_BASE_DIR],
213
+ schemas: [SCHEMAS_DIR, INFRA_SCHEMAS_DIR],
198
214
  };
199
215
 
200
216
  // Dependency types that are not file-based (external tools, integrations)
@@ -208,8 +224,8 @@ async function validateDependencies(agents) {
208
224
  if (skipDepTypes.has(depType)) continue;
209
225
  if (!Array.isArray(depList)) continue;
210
226
 
211
- const depDir = depDirs[depType];
212
- if (!depDir) {
227
+ const candidateDirs = depDirs[depType];
228
+ if (!candidateDirs) {
213
229
  warnings.push({
214
230
  type: 'UNKNOWN_DEP_TYPE',
215
231
  agent: agent.id,
@@ -219,9 +235,23 @@ async function validateDependencies(agents) {
219
235
  continue;
220
236
  }
221
237
 
222
- for (const depFile of depList) {
223
- const depPath = path.join(depDir, depFile);
224
- const exists = await fileExists(depPath);
238
+ for (const depFile2 of depList) {
239
+ // Bare references (no extension) may be listed without their suffix —
240
+ // try the common framework extensions before declaring them missing.
241
+ const extCandidates = path.extname(depFile2)
242
+ ? ['']
243
+ : ['', '.js', '.cjs', '.md', '.yaml', '.yml'];
244
+
245
+ let exists = false;
246
+ for (const dir of candidateDirs) {
247
+ for (const ext of extCandidates) {
248
+ if (await fileExists(path.join(dir, depFile2 + ext))) {
249
+ exists = true;
250
+ break;
251
+ }
252
+ }
253
+ if (exists) break;
254
+ }
225
255
 
226
256
  if (!exists) {
227
257
  // Missing dependencies are warnings, not errors (pre-existing technical debt)
@@ -229,10 +259,10 @@ async function validateDependencies(agents) {
229
259
  type: 'MISSING_DEPENDENCY',
230
260
  agent: agent.id,
231
261
  depType,
232
- depFile,
233
- expectedPath: depPath,
234
- message: `Missing dependency: @${agent.id} → ${depType}/${depFile}`,
235
- suggestion: `Create the file at ${depPath} or remove from agent dependencies.`,
262
+ depFile: depFile2,
263
+ expectedPath: path.join(candidateDirs[0], depFile2),
264
+ message: `Missing dependency: @${agent.id} → ${depType}/${depFile2}`,
265
+ suggestion: `Create the file under one of [${candidateDirs.join(', ')}] or remove from agent dependencies.`,
236
266
  });
237
267
  }
238
268
  }