11import { createToolHostManifest , getToolHostEntryById } from "../../tools/shared/toolHostManifest.js" ;
22import { createToolHostRuntime } from "../../tools/shared/toolHostRuntime.js" ;
3+ import {
4+ removeToolHostSharedContextById ,
5+ writeToolHostSharedContext
6+ } from "../../tools/shared/toolHostSharedContext.js" ;
37
48const GAMES_METADATA_PATH = "/games/metadata/games.index.metadata.json" ;
59
@@ -21,6 +25,7 @@ const manifest = createToolHostManifest();
2125const toolIds = manifest . tools . map ( ( tool ) => tool . id ) ;
2226const hasAvailableTools = toolIds . length > 0 ;
2327let currentGameFrame = null ;
28+ let currentGameHostContextId = "" ;
2429
2530function decodeSamplePresetPayload ( encoded ) {
2631 if ( typeof encoded !== "string" || ! encoded . trim ( ) ) {
@@ -184,13 +189,21 @@ async function readGameEntryById(gameId) {
184189
185190function unmountGameFrame ( ) {
186191 if ( ! currentGameFrame ) {
192+ if ( currentGameHostContextId ) {
193+ removeToolHostSharedContextById ( currentGameHostContextId ) ;
194+ currentGameHostContextId = "" ;
195+ }
187196 return ;
188197 }
189198 if ( currentGameFrame . parentElement === refs . mountContainer ) {
190199 currentGameFrame . removeAttribute ( "src" ) ;
191200 refs . mountContainer . removeChild ( currentGameFrame ) ;
192201 }
193202 currentGameFrame = null ;
203+ if ( currentGameHostContextId ) {
204+ removeToolHostSharedContextById ( currentGameHostContextId ) ;
205+ currentGameHostContextId = "" ;
206+ }
194207}
195208
196209function mountGameFrame ( gameEntry ) {
@@ -201,6 +214,24 @@ function mountGameFrame(gameEntry) {
201214 runtime . unmountCurrentTool ( "switch-to-game" ) ;
202215 unmountGameFrame ( ) ;
203216
217+ const hostContext = writeToolHostSharedContext ( {
218+ toolId : "workspace-manager" ,
219+ source : "game-host" ,
220+ requestedAt : new Date ( ) . toISOString ( ) ,
221+ sharedContext : {
222+ hostMode : "game" ,
223+ gameId : gameEntry . id ,
224+ gameTitle : gameEntry . title
225+ } ,
226+ state : {
227+ game : {
228+ id : gameEntry . id ,
229+ title : gameEntry . title ,
230+ href : gameEntry . href
231+ }
232+ }
233+ } ) ;
234+
204235 const frame = document . createElement ( "iframe" ) ;
205236 frame . setAttribute ( "data-game-host-frame" , gameEntry . id ) ;
206237 frame . setAttribute ( "title" , `${ gameEntry . title } Workspace Frame` ) ;
@@ -209,6 +240,12 @@ function mountGameFrame(gameEntry) {
209240 gameUrl . searchParams . set ( "hosted" , "1" ) ;
210241 gameUrl . searchParams . set ( "hostToolId" , "workspace-manager" ) ;
211242 gameUrl . searchParams . set ( "hostGameId" , gameEntry . id ) ;
243+ if ( hostContext ?. contextId ) {
244+ currentGameHostContextId = hostContext . contextId ;
245+ gameUrl . searchParams . set ( "hostContextId" , hostContext . contextId ) ;
246+ } else {
247+ currentGameHostContextId = "" ;
248+ }
212249 frame . src = gameUrl . toString ( ) ;
213250 refs . mountContainer . replaceChildren ( frame ) ;
214251 currentGameFrame = frame ;
@@ -348,6 +385,17 @@ function bindEvents() {
348385 }
349386
350387 window . addEventListener ( "popstate" , ( ) => {
388+ const gameId = readInitialGameId ( ) ;
389+ if ( gameId ) {
390+ void readGameEntryById ( gameId ) . then ( ( gameEntry ) => {
391+ if ( ! gameEntry ) {
392+ writeStatus ( `Game "${ gameId } " is not available for Workspace Manager launch.` ) ;
393+ return ;
394+ }
395+ mountGameFrame ( gameEntry ) ;
396+ } ) ;
397+ return ;
398+ }
351399 const toolId = readInitialToolId ( ) ;
352400 if ( refs . toolSelect instanceof HTMLSelectElement ) {
353401 refs . toolSelect . value = toolId ;
@@ -357,6 +405,10 @@ function bindEvents() {
357405 mountSelectedTool ( "popstate" ) ;
358406 syncControlState ( ) ;
359407 } ) ;
408+
409+ window . addEventListener ( "beforeunload" , ( ) => {
410+ unmountGameFrame ( ) ;
411+ } ) ;
360412}
361413
362414async function init ( ) {
0 commit comments