@@ -697,16 +697,21 @@ async function readWorkspaceManifestToolDiagnosticsFromSamplePreset(samplePreset
697697 reason : `fetch-failed(status=${ response . status } )`
698698 }
699699 ] ,
700- schemaContractError : schemaContract ?. schemaContractError || ""
700+ schemaContractError : schemaContract ?. schemaContractError || "" ,
701+ explicitToolPayloadById : new Map ( ) ,
702+ explicitPalettePayload : null
701703 } ;
702704 }
703705 const rawSource = await response . json ( ) ;
704706 const classifications = classifyWorkspaceManifestTools ( rawSource , schemaContract ) ;
707+ const explicitInputs = extractWorkspaceManifestExplicitLaunchInputs ( rawSource ) ;
705708 return {
706709 sourcePath : normalizedPath ,
707710 ...classifications ,
708711 visibleToolIds : [ ] ,
709- schemaContractError : schemaContract ?. schemaContractError || ""
712+ schemaContractError : schemaContract ?. schemaContractError || "" ,
713+ explicitToolPayloadById : explicitInputs . explicitToolPayloadById ,
714+ explicitPalettePayload : explicitInputs . explicitPalettePayload
710715 } ;
711716 } catch ( error ) {
712717 return {
@@ -723,9 +728,49 @@ async function readWorkspaceManifestToolDiagnosticsFromSamplePreset(samplePreset
723728 key : "" ,
724729 reason : `fetch-error(${ error instanceof Error ? error . message : "unknown" } )`
725730 }
726- ]
731+ ] ,
732+ explicitToolPayloadById : new Map ( ) ,
733+ explicitPalettePayload : null
734+ } ;
735+ }
736+ }
737+
738+ function extractWorkspaceManifestExplicitLaunchInputs ( rawSource ) {
739+ const explicitToolPayloadById = new Map ( ) ;
740+ let explicitPalettePayload = null ;
741+ if ( ! isWorkspaceManifestSource ( rawSource ) ) {
742+ return {
743+ explicitToolPayloadById,
744+ explicitPalettePayload
745+ } ;
746+ }
747+ const toolsBlock = rawSource . tools && typeof rawSource . tools === "object" && ! Array . isArray ( rawSource . tools )
748+ ? rawSource . tools
749+ : null ;
750+ if ( ! toolsBlock ) {
751+ return {
752+ explicitToolPayloadById,
753+ explicitPalettePayload
727754 } ;
728755 }
756+
757+ Object . entries ( toolsBlock ) . forEach ( ( [ rawToolKey , rawToolPayload ] ) => {
758+ const toolId = normalizeTextParam ( rawToolKey ) . toLowerCase ( ) ;
759+ if ( ! toolId || ! rawToolPayload || typeof rawToolPayload !== "object" || Array . isArray ( rawToolPayload ) ) {
760+ return ;
761+ }
762+ explicitToolPayloadById . set ( toolId , rawToolPayload ) ;
763+ if ( toolId === "palette-browser"
764+ && rawToolPayload . schema === "html-js-gaming.palette"
765+ && Array . isArray ( rawToolPayload . swatches ) ) {
766+ explicitPalettePayload = rawToolPayload ;
767+ }
768+ } ) ;
769+
770+ return {
771+ explicitToolPayloadById,
772+ explicitPalettePayload
773+ } ;
729774}
730775
731776function logWorkspaceManifestToolDiagnostics ( diagnostics ) {
@@ -746,48 +791,6 @@ function logWorkspaceManifestToolDiagnostics(diagnostics) {
746791 }
747792}
748793
749- function readForwardedToolLaunchParams ( ) {
750- const searchParams = new URL ( window . location . href ) . searchParams ;
751- const forwarded = { } ;
752- const sampleId = normalizeTextParam ( searchParams . get ( "sampleId" ) ) ;
753- const sampleTitle = normalizeTextParam ( searchParams . get ( "sampleTitle" ) ) ;
754- const samplePresetPath = normalizeLocalHrefParam (
755- searchParams . get ( "samplePresetPath" ) ,
756- TOOL_LAUNCH_PARAM_PREFIXES . samplePresetPath
757- ) ;
758- const gameId = normalizeTextParam ( searchParams . get ( "gameId" ) ) ;
759- const gameTitle = normalizeTextParam ( searchParams . get ( "gameTitle" ) ) ;
760- const gameHref = normalizeLocalHrefParam ( searchParams . get ( "gameHref" ) , TOOL_LAUNCH_PARAM_PREFIXES . gameHref ) ;
761- const workspaceHref = normalizeLocalHrefParam ( searchParams . get ( "workspaceHref" ) , TOOL_LAUNCH_PARAM_PREFIXES . workspaceHref ) ;
762- const returnTo = normalizeLocalHrefParam ( searchParams . get ( "returnTo" ) , TOOL_LAUNCH_PARAM_PREFIXES . returnTo ) ;
763-
764- if ( sampleId ) {
765- forwarded . sampleId = sampleId ;
766- }
767- if ( sampleTitle ) {
768- forwarded . sampleTitle = sampleTitle ;
769- }
770- if ( samplePresetPath ) {
771- forwarded . samplePresetPath = samplePresetPath ;
772- }
773- if ( gameId ) {
774- forwarded . gameId = gameId ;
775- }
776- if ( gameTitle ) {
777- forwarded . gameTitle = gameTitle ;
778- }
779- if ( gameHref ) {
780- forwarded . gameHref = gameHref ;
781- }
782- if ( workspaceHref ) {
783- forwarded . workspaceHref = workspaceHref ;
784- }
785- if ( returnTo ) {
786- forwarded . returnTo = returnTo ;
787- }
788- return forwarded ;
789- }
790-
791794function readSelectedToolId ( ) {
792795 return selectedToolId ;
793796}
@@ -1225,38 +1228,29 @@ function mountSelectedTool(source = "manual") {
12251228 ) ;
12261229 return false ;
12271230 }
1228- let optionalState = null ;
1229- if ( refs . stateInput instanceof HTMLTextAreaElement ) {
1230- const rawState = refs . stateInput . value . trim ( ) ;
1231- if ( rawState ) {
1232- try {
1233- optionalState = JSON . parse ( rawState ) ;
1234- } catch {
1235- writeStatus ( "State JSON is invalid. Fix JSON or clear the state field." ) ;
1236- renderMountDiagnostic (
1237- "Tool mount blocked by invalid state JSON." ,
1238- "Clear optional state or provide valid JSON before mounting."
1239- ) ;
1240- return false ;
1241- }
1242- }
1243- }
1231+ const hasStateInput = refs . stateInput instanceof HTMLTextAreaElement
1232+ && Boolean ( refs . stateInput . value . trim ( ) ) ;
12441233 updateSwitchMeta ( ) ;
12451234 updateStandaloneHref ( toolId ) ;
12461235 writeQueryToolId ( toolId , source === "init" ) ;
1247- const previousMount = runtime . getCurrentMount ( ) ;
1248- const launchParams = readForwardedToolLaunchParams ( ) ;
1249- const mountResult = runtime . mountTool ( toolId , {
1250- source,
1251- requestedAt : new Date ( ) . toISOString ( ) ,
1252- sharedContext : {
1253- requestedToolId : toolId ,
1254- previousToolId : previousMount ?. tool ?. id || "" ,
1255- switchPosition : `${ Math . max ( 1 , getSelectedToolIndex ( ) + 1 ) } /${ Math . max ( 1 , toolIds . length ) } `
1256- } ,
1257- state : optionalState ,
1258- launchParams
1259- } ) ;
1236+ const explicitToolPayloadById = workspaceManifestToolDiagnostics ?. explicitToolPayloadById instanceof Map
1237+ ? workspaceManifestToolDiagnostics . explicitToolPayloadById
1238+ : null ;
1239+ const payloadJson = explicitToolPayloadById ? ( explicitToolPayloadById . get ( toolId ) || null ) : null ;
1240+ if ( ! payloadJson || typeof payloadJson !== "object" || Array . isArray ( payloadJson ) ) {
1241+ writeStatus ( `Launch blocked for ${ toolId } : explicit payloadJson is required.` ) ;
1242+ renderMountDiagnostic (
1243+ `Launch blocked for ${ toolId } .` ,
1244+ "Workspace Manager now enforces explicit launch(toolId, payloadJson, paletteJson?) inputs."
1245+ ) ;
1246+ syncControlState ( ) ;
1247+ return false ;
1248+ }
1249+ if ( hasStateInput ) {
1250+ writeStatus ( "State JSON is ignored for explicit launch signature enforcement." ) ;
1251+ }
1252+ const paletteJson = workspaceManifestToolDiagnostics ?. explicitPalettePayload || null ;
1253+ const mountResult = runtime . launch ( toolId , payloadJson , paletteJson ) ;
12601254 if ( ! mountResult || ! ( mountResult . frame instanceof HTMLIFrameElement ) ) {
12611255 const selectedEntry = getToolHostEntryById ( manifest , toolId ) ;
12621256 const displayName = selectedEntry ? selectedEntry . displayName : toolId ;
0 commit comments