const whileUntilBlock = flyoutWorkspace.getAllBlocks().find(block => block.type === "controls_whileUntil") || flyoutWorkspace.newBlock("controls_whileUntil");
whileUntilBlock.getInput("DO").connection.connect(flyoutWorkspace.newBlock("text_print").previousConnection);
Blockly.getMainWorkspace().updateToolbox(Blockly.Xml.workspaceToDom(flyoutWorkspace));
I should mention that I haven't investigated the Blockly toolbox code enough to know if this is the best way to do this, but it works.
If the stack of blocks you use will remain unchanged, it's probably easiest to directly load the toolbox from XML. If you're using built-in blocks, you can generate the desired XML by using the Code application (
https://blockly-demo.appspot.com/static/demos/code/index.html) that appears on the page Monica linked to. For example, if you put a text_print block in the statement input of a controls_whileUntil block, you'll see the following generated XML, which you could then include in the appropriate place in your toolbox XML:
<block type="controls_whileUntil" id="6Ir.qE4b+]8]nAu9zbxr" x="138" y="338">
<field name="MODE">WHILE</field>
<statement name="DO">
<block type="text_print" id="G`c$Hit:809ZXoxuJh5J">
<value name="TEXT">
<shadow type="text" id="zJ:}6k5dD5hr3x,gY9HW">
<field name="TEXT">abc</field>
</shadow>
</value>
</block>
</statement>
</block>
Please feel free to follow up with any additional questions.