@@ -67,11 +67,15 @@ function simulateWorkspaceModeExport(activePayload, currentHostContextId, librar
6767 toolSessions [ payloadToolId ] [ sessionId ] = payload ;
6868 } ) ;
6969 const container = {
70- version : "v2" ,
71- toolId : "workspace-v2" ,
72- workspaceSession : {
73- workspaceToolId : "workspace-v2" ,
74- workspaceSessionId : activeHostContextId ,
70+ $schema : "../../tools/schemas/workspace.manifest.schema.json" ,
71+ documentKind : "workspace-manifest" ,
72+ schema : "html-js-gaming.project" ,
73+ version : 1 ,
74+ id : `workspace-v2-${ activeHostContextId || "session" } ` ,
75+ name : "Workspace V2 Session Export" ,
76+ tools : { } ,
77+ workspaceV2Session : {
78+ schema : "html-js-gaming.workspace-v2-session/1" ,
7579 defaultToolId : "palette-manager-v2" ,
7680 activeToolId,
7781 activeHostContextId,
@@ -94,6 +98,9 @@ export function run() {
9498 const workspaceJsExists = fs . existsSync ( workspaceJsPath ) ;
9599 const workspaceHtml = workspaceHtmlExists ? fs . readFileSync ( workspaceHtmlPath , "utf8" ) : "" ;
96100 const workspaceJs = workspaceJsExists ? fs . readFileSync ( workspaceJsPath , "utf8" ) : "" ;
101+ const workspaceManifestSchema = JSON . parse (
102+ fs . readFileSync ( path . join ( repoRoot , "tools" , "schemas" , "workspace.manifest.schema.json" ) , "utf8" )
103+ ) ;
97104 const workspaceJsSyntax = checkSyntax ( workspaceJsPath ) ;
98105 const testSyntax = checkSyntax ( testPath ) ;
99106
@@ -132,17 +139,33 @@ export function run() {
132139 const requiredWorkspaceJsTokens = [
133140 "importWorkspaceSessionJson()" ,
134141 "exportWorkspaceSessionJson()" ,
135- "buildPortableWorkspaceSessionContainer()" ,
142+ "buildWorkspaceManifestDocument()" ,
143+ "validateWorkspaceManifestDocument(" ,
144+ "workspaceV2Session" ,
136145 "runtime-only fields are not allowed in portable workspace payload" ,
137146 "toolSessions" ,
138- "savedSessions"
147+ "savedSessions" ,
148+ "workspaceSession wrapper is not allowed"
139149 ] ;
140150 requiredWorkspaceJsTokens . forEach ( ( token ) => {
141151 if ( ! workspaceJs . includes ( token ) ) {
142152 failures . push ( `Missing required workspace contract JS token: ${ token } ` ) ;
143153 }
144154 } ) ;
145155
156+ const requiredSessionFlowTokens = [
157+ "saveNamedSession(" ,
158+ "loadNamedSession(" ,
159+ "computeSelectedSessionDiff(" ,
160+ "computeSelectedSessionMerge(" ,
161+ "readActiveSessionPayloadForLibraryActions()"
162+ ] ;
163+ requiredSessionFlowTokens . forEach ( ( token ) => {
164+ if ( ! workspaceJs . includes ( token ) ) {
165+ failures . push ( `Missing expected session flow token: ${ token } ` ) ;
166+ }
167+ } ) ;
168+
146169 TOOL_IDS . forEach ( ( toolId ) => {
147170 const toolHtmlPath = path . join ( repoRoot , "tools" , toolId , "index.html" ) ;
148171 const toolHtmlExists = fs . existsSync ( toolHtmlPath ) ;
@@ -181,24 +204,49 @@ export function run() {
181204 if ( ! workspaceExport . ok ) failures . push ( "Workspace export should succeed when active payload exists." ) ;
182205 const workspaceExportParsed = workspaceExport . serialized ? JSON . parse ( workspaceExport . serialized ) : null ;
183206 if ( ! workspaceExportParsed || typeof workspaceExportParsed !== "object" || Array . isArray ( workspaceExportParsed ) ) {
184- failures . push ( "Workspace export should be an object container." ) ;
185- } else if ( ! workspaceExportParsed . workspaceSession || typeof workspaceExportParsed . workspaceSession !== "object" ) {
186- failures . push ( "Workspace export should include workspaceSession container." ) ;
207+ failures . push ( "Workspace export should be an object." ) ;
187208 } else {
188- if ( Object . prototype . hasOwnProperty . call ( workspaceExportParsed . workspaceSession , "sessionHistory" ) ) {
209+ if ( Object . prototype . hasOwnProperty . call ( workspaceExportParsed , "workspaceSession" ) ) {
210+ failures . push ( "Workspace export must not include workspaceSession wrapper." ) ;
211+ }
212+ if ( workspaceExportParsed . documentKind !== "workspace-manifest" ) {
213+ failures . push ( "Workspace export documentKind must be workspace-manifest." ) ;
214+ }
215+ if ( ! workspaceExportParsed . workspaceV2Session || typeof workspaceExportParsed . workspaceV2Session !== "object" ) {
216+ failures . push ( "Workspace export should include workspaceV2Session payload." ) ;
217+ }
218+ if ( ! workspaceExportParsed . tools || typeof workspaceExportParsed . tools !== "object" || Array . isArray ( workspaceExportParsed . tools ) ) {
219+ failures . push ( "Workspace export should include tools object." ) ;
220+ }
221+ const requiredSchemaKeys = Array . isArray ( workspaceManifestSchema . required ) ? workspaceManifestSchema . required : [ ] ;
222+ requiredSchemaKeys . forEach ( ( schemaKey ) => {
223+ if ( ! Object . prototype . hasOwnProperty . call ( workspaceExportParsed , schemaKey ) ) {
224+ failures . push ( `Workspace export is missing required schema key: ${ schemaKey } ` ) ;
225+ }
226+ } ) ;
227+ if ( ! Object . prototype . hasOwnProperty . call ( workspaceManifestSchema . properties || { } , "workspaceV2Session" ) ) {
228+ failures . push ( "workspace.manifest schema should define workspaceV2Session property." ) ;
229+ }
230+ if ( ! workspaceManifestSchema . properties ?. workspaceV2Session ?. properties ?. toolSessions ) {
231+ failures . push ( "workspace.manifest schema should define workspaceV2Session.toolSessions." ) ;
232+ }
233+ if ( ! workspaceManifestSchema . properties ?. workspaceV2Session ?. properties ?. savedSessions ) {
234+ failures . push ( "workspace.manifest schema should define workspaceV2Session.savedSessions." ) ;
235+ }
236+ if ( Object . prototype . hasOwnProperty . call ( workspaceExportParsed . workspaceV2Session , "sessionHistory" ) ) {
189237 failures . push ( "Workspace export must not include sessionHistory runtime field." ) ;
190238 }
191- if ( Object . prototype . hasOwnProperty . call ( workspaceExportParsed . workspaceSession , "sessionSelection" ) ) {
239+ if ( Object . prototype . hasOwnProperty . call ( workspaceExportParsed . workspaceV2Session , "sessionSelection" ) ) {
192240 failures . push ( "Workspace export must not include sessionSelection runtime field." ) ;
193241 }
194- if ( Object . prototype . hasOwnProperty . call ( workspaceExportParsed . workspaceSession , "mergeAuditLog" ) ) {
242+ if ( Object . prototype . hasOwnProperty . call ( workspaceExportParsed . workspaceV2Session , "mergeAuditLog" ) ) {
195243 failures . push ( "Workspace export must not include mergeAuditLog runtime field." ) ;
196244 }
197- if ( Object . prototype . hasOwnProperty . call ( workspaceExportParsed . workspaceSession , "activeSessionPayload" ) ) {
245+ if ( Object . prototype . hasOwnProperty . call ( workspaceExportParsed . workspaceV2Session , "activeSessionPayload" ) ) {
198246 failures . push ( "Workspace export must not include lone activeSessionPayload runtime field." ) ;
199247 }
200248 const activeEntry =
201- workspaceExportParsed . workspaceSession . toolSessions ?. [ "palette-manager-v2" ] ?. [ "palette-manager-v2-1234567890123-abcd1234" ] ;
249+ workspaceExportParsed . workspaceV2Session . toolSessions ?. [ "palette-manager-v2" ] ?. [ "palette-manager-v2-1234567890123-abcd1234" ] ;
202250 if ( JSON . stringify ( activeEntry ) !== JSON . stringify ( activePayload ) ) {
203251 failures . push ( "Workspace export should preserve active payload under toolSessions by tool/session id." ) ;
204252 }
0 commit comments