@@ -72,11 +72,13 @@ export function createWorkspaceSystemController(options = {}) {
7272 const toolEntry = getToolById ( toolId ) ;
7373 const isReadOnlyTool = toolEntry ?. readOnly === true ;
7474 const skipInitialToolStateApply = options . skipInitialToolStateApply === true ;
75+ const launchHasSourcePreset = options . launchHasSourcePreset === true ;
7576 const launchContext = options . launchContext && typeof options . launchContext === "object"
7677 ? options . launchContext
7778 : { } ;
7879 const launchGameId = safeString ( launchContext . gameId , "" ) ;
7980 const launchGameTitle = safeString ( launchContext . gameTitle , launchGameId ) ;
81+ const strictLaunchMode = Boolean ( launchGameId ) ;
8082 const onChange = typeof options . onChange === "function" ? options . onChange : ( ) => { } ;
8183 const onStatus = typeof options . onStatus === "function" ? options . onStatus : ( ) => { } ;
8284 const adapter = ( ) => getProjectAdapter ( toolId ) ;
@@ -87,7 +89,8 @@ export function createWorkspaceSystemController(options = {}) {
8789 lastObservedHash : "" ,
8890 adapterReady : false ,
8991 appliedInitialState : skipInitialToolStateApply ,
90- launchContextHydrated : false
92+ launchContextHydrated : false ,
93+ toolStateSourceValidated : strictLaunchMode ? launchHasSourcePreset : true
9194 } ;
9295
9396 function isGenericWorkspaceName ( name ) {
@@ -110,7 +113,7 @@ export function createWorkspaceSystemController(options = {}) {
110113
111114 function computeObservedManifest ( ) {
112115 const toolAdapter = adapter ( ) ;
113- const currentManifest = state . manifest
116+ let currentManifest = state . manifest
114117 ? cloneValue ( state . manifest )
115118 : createEmptyProjectManifest ( {
116119 name : toolAdapter . getProjectName ?. ( ) || getToolById ( toolId ) ?. displayName || "Untitled Workspace" ,
@@ -121,6 +124,11 @@ export function createWorkspaceSystemController(options = {}) {
121124 if ( ! state . launchContextHydrated ) {
122125 clearSharedAssetHandoff ( ) ;
123126 clearSharedPaletteHandoff ( ) ;
127+ currentManifest = createEmptyProjectManifest ( {
128+ name : launchGameTitle || launchGameId ,
129+ toolId
130+ } ) ;
131+ state . manifest = cloneValue ( currentManifest ) ;
124132 }
125133 currentManifest . workspace = currentManifest . workspace && typeof currentManifest . workspace === "object"
126134 ? currentManifest . workspace
@@ -142,7 +150,7 @@ export function createWorkspaceSystemController(options = {}) {
142150 ? currentManifest . tools
143151 : { } ;
144152
145- if ( toolAdapter . ready ) {
153+ if ( toolAdapter . ready && ( ! strictLaunchMode || state . toolStateSourceValidated ) ) {
146154 currentManifest . tools [ toolId ] = normalizeToolStateForProjectManifest (
147155 toolId ,
148156 toolAdapter . captureState ( )
@@ -156,6 +164,8 @@ export function createWorkspaceSystemController(options = {}) {
156164 if ( adapterName && ( ! manifestName || manifestName === defaultManifestName ) ) {
157165 currentManifest . name = adapterName ;
158166 }
167+ } else if ( strictLaunchMode && ! state . toolStateSourceValidated && currentManifest . tools ?. [ toolId ] ) {
168+ delete currentManifest . tools [ toolId ] ;
159169 }
160170
161171 currentManifest . toolIntegration = buildProjectToolIntegration ( currentManifest . tools ) ;
@@ -223,7 +233,10 @@ export function createWorkspaceSystemController(options = {}) {
223233 const toolState = manifest . tools ?. [ toolId ] ;
224234 if ( toolState ) {
225235 toolAdapter . applyState ( cloneValue ( unwrapToolStateForAdapter ( toolId , toolState ) ) ) ;
236+ state . toolStateSourceValidated = true ;
226237 onStatus ( buildStatusSummary ( validateProjectManifest ( manifest ) ) ) ;
238+ } else if ( strictLaunchMode ) {
239+ onStatus ( `Workspace launched for ${ launchGameTitle || launchGameId } . Waiting for source tool JSON for ${ toolId } .` ) ;
227240 }
228241 state . appliedInitialState = true ;
229242 markSaved ( "initial-apply" ) ;
@@ -237,16 +250,13 @@ export function createWorkspaceSystemController(options = {}) {
237250 name : nextName ,
238251 toolId
239252 } ) ;
240- if ( toolAdapter . ready ) {
241- const defaultState = normalizeToolStateForProjectManifest ( toolId , toolAdapter . createDefaultState ( nextName ) ) ;
242- nextManifest . tools [ toolId ] = defaultState ;
243- nextManifest . toolIntegration = buildProjectToolIntegration ( nextManifest . tools ) ;
244- toolAdapter . applyState ( cloneValue ( unwrapToolStateForAdapter ( toolId , defaultState ) ) ) ;
245- }
253+ nextManifest . tools = { } ;
254+ nextManifest . toolIntegration = buildProjectToolIntegration ( nextManifest . tools ) ;
246255 clearSharedAssetHandoff ( ) ;
247256 clearSharedPaletteHandoff ( ) ;
248257 state . manifest = nextManifest ;
249258 state . appliedInitialState = true ;
259+ state . toolStateSourceValidated = ! strictLaunchMode ;
250260 markSaved ( "new-project" ) ;
251261 onStatus ( `Started ${ nextName } .` ) ;
252262 }
@@ -270,12 +280,14 @@ export function createWorkspaceSystemController(options = {}) {
270280 state . manifest = nextManifest ;
271281 const toolAdapter = adapter ( ) ;
272282 if ( toolAdapter . ready ) {
273- const nextToolState = nextManifest . tools ?. [ toolId ]
274- ? normalizeToolStateForProjectManifest ( toolId , nextManifest . tools [ toolId ] )
275- : normalizeToolStateForProjectManifest ( toolId , toolAdapter . createDefaultState ( nextManifest . name ) ) ;
283+ if ( ! nextManifest . tools ?. [ toolId ] ) {
284+ throw new Error ( `Workspace manifest is missing required state for ${ toolId } .` ) ;
285+ }
286+ const nextToolState = normalizeToolStateForProjectManifest ( toolId , nextManifest . tools [ toolId ] ) ;
276287 toolAdapter . applyState ( cloneValue ( unwrapToolStateForAdapter ( toolId , nextToolState ) ) ) ;
277288 nextManifest . tools [ toolId ] = cloneValue ( nextToolState ) ;
278289 nextManifest . toolIntegration = buildProjectToolIntegration ( nextManifest . tools ) ;
290+ state . toolStateSourceValidated = true ;
279291 }
280292 state . appliedInitialState = true ;
281293 markSaved ( "open-project" ) ;
@@ -298,26 +310,28 @@ export function createWorkspaceSystemController(options = {}) {
298310 }
299311
300312 function handleCloseWorkspace ( ) {
301- const toolAdapter = adapter ( ) ;
302313 const fallbackName = "No Active Workspace" ;
303314 const nextManifest = createEmptyProjectManifest ( {
304315 name : fallbackName ,
305316 toolId
306317 } ) ;
307318 nextManifest . workspace . notes = "closed" ;
308- if ( toolAdapter . ready ) {
309- const defaultState = normalizeToolStateForProjectManifest ( toolId , toolAdapter . createDefaultState ( fallbackName ) ) ;
310- nextManifest . tools [ toolId ] = defaultState ;
311- nextManifest . toolIntegration = buildProjectToolIntegration ( nextManifest . tools ) ;
312- toolAdapter . applyState ( cloneValue ( unwrapToolStateForAdapter ( toolId , defaultState ) ) ) ;
313- }
319+ nextManifest . tools = { } ;
320+ nextManifest . toolIntegration = buildProjectToolIntegration ( nextManifest . tools ) ;
314321 state . manifest = nextManifest ;
315322 state . appliedInitialState = true ;
323+ state . toolStateSourceValidated = ! strictLaunchMode ;
316324 state . baselineHash = "" ;
325+ state . lastObservedHash = "" ;
317326 clearStorage ( ) ;
318327 clearSharedAssetHandoff ( ) ;
319328 clearSharedPaletteHandoff ( ) ;
320- updateDirtyState ( "close-project" ) ;
329+ onChange ( {
330+ manifest : cloneValue ( state . manifest ) ,
331+ dirty : false ,
332+ ready : adapter ( ) . ready ,
333+ reason : "close-project"
334+ } ) ;
321335 onStatus ( "Workspace closed." ) ;
322336 }
323337
@@ -371,6 +385,7 @@ export function createWorkspaceSystemController(options = {}) {
371385 }
372386
373387 state . appliedInitialState = true ;
388+ state . toolStateSourceValidated = true ;
374389 markSaved ( "external-preset" ) ;
375390 const label = safeString ( payload . label , "external preset" ) ;
376391 if ( applied ) {
0 commit comments