1- import chalk from 'chalk' ;
21import type { TeamCastManifest } from '../types/manifest.js' ;
32import { applyDefaults } from '../manifest/defaults.js' ;
3+ import { getManifestTargetConfig , isManifestTargetName } from '../manifest/targets.js' ;
44import { validateSchema } from '../manifest/schema-validator.js' ;
55import { normalizeManifest } from '../manifest/normalize.js' ;
66import { runValidation } from '../validator/index.js' ;
7- import { hasErrors } from '../validator/reporter.js' ;
7+ import {
8+ hasErrors ,
9+ printManifestValidationSummary ,
10+ } from '../validator/reporter.js' ;
811import type { ValidationResult } from '../validator/types.js' ;
912import { getTarget , getRegisteredTargetNames } from '../renderers/registry.js' ;
13+ import { injectEnvironmentPolicies } from '../plugins/inject.js' ;
1014
1115export interface TeamValidationSummary {
1216 schemaErrors : Array < { path : string ; message : string } > ;
1317 validationResults : ValidationResult [ ] ;
1418 policyAssertionCount ?: number ;
1519}
1620
17- export function evaluateTeam ( manifest : TeamCastManifest ) : TeamValidationSummary {
21+ export function evaluateTeam (
22+ manifest : TeamCastManifest ,
23+ options ?: { cwd ?: string } ,
24+ ) : TeamValidationSummary {
1825 const schemaResult = validateSchema ( manifest ) ;
1926
2027 if ( ! schemaResult . valid ) {
@@ -25,15 +32,21 @@ export function evaluateTeam(manifest: TeamCastManifest): TeamValidationSummary
2532 }
2633
2734 const rawManifest = applyDefaults ( schemaResult . data ) ;
28- const rawManifestRecord = rawManifest as unknown as Record < string , unknown > ;
29- const activeTargets = getRegisteredTargetNames ( ) . filter ( ( targetName ) => rawManifestRecord [ targetName ] ) ;
35+ const resolvedManifest = options ?. cwd ? injectEnvironmentPolicies ( rawManifest , options . cwd ) : rawManifest ;
36+ const activeTargets = getRegisteredTargetNames ( ) . filter (
37+ ( targetName ) =>
38+ isManifestTargetName ( targetName ) &&
39+ Boolean ( getManifestTargetConfig ( resolvedManifest , targetName ) ) ,
40+ ) ;
3041 const validationResults : ValidationResult [ ] = [ ] ;
42+ let policyAssertionCount = 0 ;
3143
3244 for ( const targetName of activeTargets ) {
3345 const targetContext = getTarget ( targetName ) ;
34- const team = normalizeManifest ( rawManifest , targetContext ) ;
46+ const team = normalizeManifest ( resolvedManifest , targetContext ) ;
3547 const targetResults = runValidation ( team , targetContext ) ;
3648 const prefix = activeTargets . length > 1 ? `[${ targetName } ] ` : '' ;
49+ policyAssertionCount += team . policies ?. assertions ?. length ?? 0 ;
3750 validationResults . push (
3851 ...targetResults . map ( ( result ) => ( {
3952 ...result ,
@@ -45,7 +58,7 @@ export function evaluateTeam(manifest: TeamCastManifest): TeamValidationSummary
4558 return {
4659 schemaErrors : [ ] ,
4760 validationResults,
48- policyAssertionCount : rawManifest . policies ?. assertions ?. length ?? 0 ,
61+ policyAssertionCount,
4962 } ;
5063}
5164
@@ -54,90 +67,5 @@ export function teamHasBlockingIssues(summary: TeamValidationSummary): boolean {
5467}
5568
5669export function printManifestValidation ( summary : TeamValidationSummary ) : void {
57- if ( summary . schemaErrors . length > 0 ) {
58- console . log ( '' ) ;
59- console . log ( ` ${ chalk . red ( '[!!]' ) } ${ chalk . bold ( 'Schema' ) } ${ chalk . dim ( '—' ) } ${ chalk . red ( 'manifest structure invalid' ) } ` ) ;
60- for ( const error of summary . schemaErrors ) {
61- console . log ( ` ${ chalk . red ( '[error]' ) } ${ error . path } : ${ error . message } ` ) ;
62- }
63- console . log ( '' ) ;
64- return ;
65- }
66-
67- console . log ( '' ) ;
68- console . log ( chalk . bold ( 'Validation results:' ) ) ;
69- console . log ( ` ${ chalk . green ( '[ok]' ) } ${ chalk . bold ( 'Schema' ) } ${ chalk . dim ( '—' ) } ${ chalk . dim ( 'manifest structure valid' ) } ` ) ;
70-
71- printCategoryRows ( summary . validationResults , summary . policyAssertionCount ) ;
72- }
73-
74- function printCategoryRows ( results : ValidationResult [ ] , policyAssertionCount ?: number ) : void {
75- const categoryOrder = [
76- { label : 'Handoff graph' , okDescription : 'delegation paths verified' } ,
77- { label : 'Tool conflicts' , okDescription : 'no allow/deny overlaps' } ,
78- { label : 'Role separation' , okDescription : 'roles match capabilities' } ,
79- { label : 'Security' , okDescription : 'sandbox and permissions checked' } ,
80- { label : 'Instruction blocks' , okDescription : 'all blocks valid' } ,
81- { label : 'policy' , okDescription : 'all assertions passed' } ,
82- ] ;
83-
84- const byCategory = new Map < string , ValidationResult [ ] > ( ) ;
85- for ( const result of results ) {
86- const existing = byCategory . get ( result . category ) ?? [ ] ;
87- byCategory . set ( result . category , [ ...existing , result ] ) ;
88- }
89-
90- for ( const meta of categoryOrder ) {
91- const categoryResults = byCategory . get ( meta . label ) ?? [ ] ;
92- const errors = categoryResults . filter ( ( result ) => result . severity === 'error' ) ;
93- const warnings = categoryResults . filter ( ( result ) => result . severity === 'warning' ) ;
94-
95- if ( errors . length > 0 ) {
96- const desc = chalk . red ( `${ errors . length } error${ errors . length !== 1 ? 's' : '' } ` ) ;
97- const extra =
98- warnings . length > 0
99- ? `, ${ chalk . yellow ( `${ warnings . length } warning${ warnings . length !== 1 ? 's' : '' } ` ) } `
100- : '' ;
101- console . log ( ` ${ chalk . red ( '[!!]' ) } ${ chalk . bold ( meta . label ) } ${ chalk . dim ( '—' ) } ${ desc } ${ extra } ` ) ;
102- for ( const result of [ ...errors , ...warnings ] ) {
103- const prefix = result . severity === 'error' ? chalk . red ( ' [error]' ) : chalk . yellow ( ' [warn]' ) ;
104- console . log ( ` ${ prefix } ${ result . message } ` ) ;
105- }
106- } else if ( warnings . length > 0 ) {
107- const desc = chalk . yellow ( `${ warnings . length } warning${ warnings . length !== 1 ? 's' : '' } ` ) ;
108- console . log ( ` ${ chalk . yellow ( '[--]' ) } ${ chalk . bold ( meta . label ) } ${ chalk . dim ( '—' ) } ${ desc } ` ) ;
109- for ( const result of warnings ) {
110- console . log ( ` ${ chalk . yellow ( ' [warn]' ) } ${ result . message } ` ) ;
111- }
112- } else {
113- let okDesc : string ;
114- if ( meta . label === 'policy' && policyAssertionCount !== undefined ) {
115- okDesc =
116- policyAssertionCount === 0
117- ? chalk . dim ( 'no assertions defined' )
118- : chalk . dim ( `${ policyAssertionCount } rule${ policyAssertionCount !== 1 ? 's' : '' } passed` ) ;
119- } else {
120- okDesc = chalk . dim ( meta . okDescription ) ;
121- }
122- console . log ( ` ${ chalk . green ( '[ok]' ) } ${ chalk . bold ( meta . label ) } ${ chalk . dim ( '—' ) } ${ okDesc } ` ) ;
123- }
124- }
125-
126- console . log ( '' ) ;
127-
128- const totalErrors = results . filter ( ( result ) => result . severity === 'error' ) . length ;
129- const totalWarnings = results . filter ( ( result ) => result . severity === 'warning' ) . length ;
130-
131- if ( totalErrors === 0 && totalWarnings === 0 ) {
132- console . log ( chalk . green ( 'All checks passed.' ) ) ;
133- } else {
134- const parts : string [ ] = [ ] ;
135- if ( totalErrors > 0 ) parts . push ( chalk . red ( `${ totalErrors } error${ totalErrors !== 1 ? 's' : '' } ` ) ) ;
136- if ( totalWarnings > 0 ) {
137- parts . push ( chalk . yellow ( `${ totalWarnings } warning${ totalWarnings !== 1 ? 's' : '' } ` ) ) ;
138- }
139- console . log ( `${ parts . join ( ', ' ) } found.` ) ;
140- }
141-
142- console . log ( '' ) ;
70+ printManifestValidationSummary ( summary ) ;
14371}
0 commit comments