1- import { cockpitManifest } from '@threadplane/cockpit-registry' ;
2- import { capabilities } from './scripts/capability-registry' ;
31import {
4- buildNavigationTree ,
52 capabilityModules ,
6- } from './src/lib/route-resolution' ;
3+ cockpitManifest ,
4+ } from '@threadplane/cockpit-registry' ;
5+ import { capabilities } from './scripts/capability-registry' ;
6+ import { buildNavigationTree } from '@threadplane/cockpit-shell' ;
7+ import { existsSync , readFileSync } from 'node:fs' ;
8+ import { resolve } from 'node:path' ;
79
810/**
911 * The cockpit site is assembled from three lists that nothing forced to agree:
1012 *
1113 * - `apps/cockpit/scripts/capability-registry.ts` — what serve/build/deploy know about;
1214 * - `libs/cockpit-registry` `cockpitManifest` — what the Next route can resolve;
13- * - `capabilityModules` in `route-resolution.ts ` — what supplies a page's assets.
15+ * - registry-owned `capabilityModules ` — what supplies a page's assets.
1416 *
1517 * When the `runtimes` product shipped, only the first list learned about it, so
1618 * `/runtimes/core-capabilities/<topic>/overview/<lang>` threw
1719 * "No manifest entry found …" and every runtime page 500'd in production while
1820 * the whole suite stayed green. These assertions are the missing coupling.
1921 */
2022describe ( 'cockpit capability wiring' , ( ) => {
21- const manifestKey = ( e : { product : string ; section : string ; topic : string } ) =>
22- `${ e . product } /${ e . section } /${ e . topic } ` ;
23+ const resolveCockpitConfig = ( fileName : string ) : string => {
24+ const workspaceConfigPath = resolve (
25+ process . cwd ( ) ,
26+ 'apps/cockpit' ,
27+ fileName
28+ ) ;
29+ return existsSync ( workspaceConfigPath )
30+ ? workspaceConfigPath
31+ : resolve ( process . cwd ( ) , fileName ) ;
32+ } ;
33+
34+ const manifestKey = ( e : {
35+ product : string ;
36+ section : string ;
37+ topic : string ;
38+ } ) => `${ e . product } /${ e . section } /${ e . topic } ` ;
2339
2440 it ( 'gives every registered capability a resolvable manifest entry' , ( ) => {
2541 const manifestKeys = new Set ( cockpitManifest . map ( manifestKey ) ) ;
2642
2743 const unroutable = capabilities
28- . map ( ( capability ) => `${ capability . product } /core-capabilities/${ capability . topic } ` )
44+ . map (
45+ ( capability ) =>
46+ `${ capability . product } /core-capabilities/${ capability . topic } `
47+ )
2948 . filter ( ( key ) => ! manifestKeys . has ( key ) ) ;
3049
3150 expect ( unroutable ) . toEqual ( [ ] ) ;
3251 } ) ;
3352
34- it ( 'gives every registered capability a cockpit module in route-resolution ' , ( ) => {
53+ it ( 'gives every registered capability a registry-owned content descriptor ' , ( ) => {
3554 const moduleKeys = new Set (
3655 capabilityModules . map ( ( module ) => manifestKey ( module . manifestIdentity ) )
3756 ) ;
3857
3958 const unwired = capabilities
40- . map ( ( capability ) => `${ capability . product } /core-capabilities/${ capability . topic } ` )
59+ . map (
60+ ( capability ) =>
61+ `${ capability . product } /core-capabilities/${ capability . topic } `
62+ )
4163 . filter ( ( key ) => ! moduleKeys . has ( key ) ) ;
4264
4365 expect ( unwired ) . toEqual ( [ ] ) ;
@@ -46,7 +68,8 @@ describe('cockpit capability wiring', () => {
4668 it ( 'points every cockpit module at a capability that still exists' , ( ) => {
4769 const capabilityKeys = new Set (
4870 capabilities . map (
49- ( capability ) => `${ capability . product } /core-capabilities/${ capability . topic } `
71+ ( capability ) =>
72+ `${ capability . product } /core-capabilities/${ capability . topic } `
5073 )
5174 ) ;
5275
@@ -58,29 +81,74 @@ describe('cockpit capability wiring', () => {
5881 } ) ;
5982
6083 it ( 'surfaces every manifest product in the navigation tree' , ( ) => {
61- const manifestProducts = [ ...new Set ( cockpitManifest . map ( ( entry ) => entry . product ) ) ] ;
84+ const manifestProducts = [
85+ ...new Set ( cockpitManifest . map ( ( entry ) => entry . product ) ) ,
86+ ] ;
6287 const navigationProducts = buildNavigationTree ( cockpitManifest ) . map (
6388 ( product ) => product . product
6489 ) ;
6590
66- expect ( [ ...manifestProducts ] . sort ( ) ) . toEqual ( [ ...navigationProducts ] . sort ( ) ) ;
91+ expect ( [ ...manifestProducts ] . sort ( ) ) . toEqual (
92+ [ ...navigationProducts ] . sort ( )
93+ ) ;
6794
6895 for ( const product of buildNavigationTree ( cockpitManifest ) ) {
6996 const entries = product . sections . flatMap ( ( section ) => section . entries ) ;
70- expect ( { product : product . product , empty : entries . length === 0 } ) . toEqual ( {
71- product : product . product ,
72- empty : false ,
73- } ) ;
97+ expect ( { product : product . product , empty : entries . length === 0 } ) . toEqual (
98+ {
99+ product : product . product ,
100+ empty : false ,
101+ }
102+ ) ;
74103 }
75104 } ) ;
76105
77106 it ( 'keeps every registry product inside the CockpitProduct union' , ( ) => {
78107 // `cockpitManifest` is typed `CockpitManifestEntry[]`, so a product that is
79108 // not in the union cannot appear here — the runtime check is that the
80109 // registry's products are all representable in the manifest.
81- const manifestProducts = new Set < string > ( cockpitManifest . map ( ( entry ) => entry . product ) ) ;
110+ const manifestProducts = new Set < string > (
111+ cockpitManifest . map ( ( entry ) => entry . product )
112+ ) ;
82113 const registryProducts = [ ...new Set ( capabilities . map ( ( c ) => c . product ) ) ] ;
83114
84- expect ( registryProducts . filter ( ( p ) => ! manifestProducts . has ( p ) ) ) . toEqual ( [ ] ) ;
115+ expect ( registryProducts . filter ( ( p ) => ! manifestProducts . has ( p ) ) ) . toEqual (
116+ [ ]
117+ ) ;
118+ } ) ;
119+
120+ it ( 'has no direct project references to capability example lanes' , ( ) => {
121+ const tsconfig = JSON . parse (
122+ readFileSync ( resolveCockpitConfig ( 'tsconfig.json' ) , 'utf8' )
123+ ) as { references ?: Array < { path : string } > } ;
124+
125+ expect (
126+ tsconfig . references ?. filter ( ( reference ) =>
127+ reference . path . startsWith ( '../../cockpit/' )
128+ )
129+ ) . toEqual ( [ ] ) ;
130+ } ) ;
131+
132+ it ( 'includes external capability content assets in the Cockpit build inputs' , ( ) => {
133+ const project = JSON . parse (
134+ readFileSync ( resolveCockpitConfig ( 'project.json' ) , 'utf8' )
135+ ) as {
136+ targets : { build : { inputs : string [ ] } } ;
137+ namedInputs : Record < string , string [ ] > ;
138+ } ;
139+
140+ expect ( project . targets . build . inputs ) . toEqual ( [
141+ 'default' ,
142+ 'deploymentConfig' ,
143+ 'contentAssets' ,
144+ '^default' ,
145+ ] ) ;
146+ expect ( project . namedInputs [ 'contentAssets' ] ) . toEqual ( [
147+ '{workspaceRoot}/cockpit/**/prompts/**' ,
148+ '{workspaceRoot}/cockpit/**/angular/src/**' ,
149+ '{workspaceRoot}/cockpit/**/python/src/**' ,
150+ '{workspaceRoot}/cockpit/**/docs/**' ,
151+ '{workspaceRoot}/deployments/ag-ui-mastra/*.mjs' ,
152+ ] ) ;
85153 } ) ;
86154} ) ;
0 commit comments