         output_n.execution_count = exec_count
     else if output_n.name?
         output_n.output_type = 'stream'
+        if output_n.name == 'input'
+            process_stdin_output(output_n)
     else if output_n.ename?
         output_n.output_type = 'error'
     return
+
+process_stdin_output = (output) ->
+    output.cocalc = misc.deep_copy(output)
+    output.name = 'stdout'
+    output.text = output.opts.prompt + ' ' + (output.value ? '')
+    delete output.opts
+    delete output.value

# Return ipynb version of the given cell as Python object
cell_to_ipynb = (id, opts) ->
    cell = opts.cells.get(id)
    obj =
        cell_type : cell.get('cell_type') ? 'code'
        source    : cell.get('input')
        metadata  : {}
    if cell.get('collapsed')
        obj.metadata.collapsed = true
    if cell.get('scrolled')
        obj.metadata.scrolled = true

    exec_count = cell.get('exec_count') ? 0
    if obj.cell_type == 'code'

        obj.outputs = ipynb_outputs(output, exec_count, opts.more_output?[id], opts.blob_store)
    else if not obj.outputs? and obj.cell_type == 'code'
        obj.outputs = [] # annoying requirement of ipynb file format.
    for n, x of obj.outputs
        if x.cocalc?
            # alternative version of cell that official Jupyter doesn' support can only
            # stored in the **cell-level** metadata, not output.
            metadata.cocalc ?= {outputs:{}}
            metadata.cocalc.outputs[n] = x.cocalc
            delete x.cocalc
    return obj

ipynb_outputs = (output, exec_count, more_output, blob_store) ->
