Previously I wrote a script for @BryanPagenkopf that groups characters by line, so if we combine that with the script above by @m1b, you can run the reCompound script on multiple lines at a time.
Here's the grouping script in action...

// GroupLinesOfObjects.jsx
// Take a selection of objects that are separated by a unknown vertical gap
// and group the shapes that are in the same "line" together
var doc = app.activeDocument;
groups = groupObjectsByLine(doc.selection);
if (groups) {
alert("Groups Created:\n" + groups.length);
}
/**
* Take an array of Adobe Illustrator pageItems and group them by vertical separation.
* @param {Array} sel Adobe Illustrator pageItems
* @returns {Array} Array of Adobe Illustrator groupItems
*/
function groupObjectsByLine(sel) {
var groups = [];
// sort the selected page items by their height (tallest to shortest)
sel.sort(function (a, b) {
var aHeight = a.geometricBounds[3] - a.geometricBounds[1];
var bHeight = b.geometricBounds[3] - b.geometricBounds[1];
return bHeight - aHeight;
});
// check if each page item shares bounds with others
var item, placed;
while (sel.length > 0) {
item = sel.pop();
placed = false;
for (var i = 0; i < groups.length; i++) {
group = groups[i];
// check if item bounds overlaps a groups bounds
if (
item.geometricBounds[3] <= group.geometricBounds[1] &&
item.geometricBounds[1] >= group.geometricBounds[3]
) {
item.move(group, ElementPlacement.PLACEATEND);
placed = true;
}
}
// if an item didn't fit into any current groups make a new group
if (!placed) {
g = app.activeDocument.groupItems.add();
groups.push(g);
item.move(g, ElementPlacement.PLACEATEND);
}
}
return groups;
}
After combining the scripts here are the results...


And here's the full script with my addition. Basically, I first group all of the lines of items, then group by group, I run @m1b's reCompound script on the group pathItems.
/**
* Script to turn outlined, uncompounded text back
* into normal compoundPathItems.
* @author m1b
* @discussion https://community.adobe.com/t5/illustrator-discussions/how-can-i-do-compoundpaths-with-logic/m-p/13498584
* Script isn't smart, and uses the following algorithm:
* 1. compute a top and bottom boundary for the whole line.
* 2. collect items whose bounds fall inside the top and bottom, and
* also inside the left and right of each item (plus tolerance value)
* 3. choose the collection with the most elements, discarding others
* 4. combine these elements into a new CompoundPathItem.
*/
(function () {
var doc = app.activeDocument;
if (doc.selection.length == 0) {
alert("Please select rows of text outlines and try again.");
return;
}
// group all of the characters by line
var groups = groupObjectsByLine(doc.selection);
var group;
// iterate over each grouped line and reCompound the groups items
for (var i = 0; i < groups.length; i++) {
var lineItems = [];
group = groups[i];
var item;
while (group.pageItems.length > 0) {
item = group.pageItems[0];
item.move(group.layer, ElementPlacement.PLACEATEND);
lineItems.push(item);
}
reCompoundLineOfTextOutlines(doc, lineItems);
}
/**
* Take an array of Adobe Illustrator pageItems and group them by vertical separation.
* @param {Array} sel Adobe Illustrator pageItems
* @returns {Array} Array of Adobe Illustrator groupItems
*/
function groupObjectsByLine(sel) {
var groups = [];
// sort the selected page items by their height (tallest to shortest)
sel.sort(function (a, b) {
var aHeight = a.geometricBounds[3] - a.geometricBounds[1];
var bHeight = b.geometricBounds[3] - b.geometricBounds[1];
return bHeight - aHeight;
});
// check if each page item shares bounds with others
var item, placed;
while (sel.length > 0) {
item = sel.pop();
placed = false;
for (var i = 0; i < groups.length; i++) {
group = groups[i];
// check if item bounds overlaps a groups bounds
if (
item.geometricBounds[3] <= group.geometricBounds[1] &&
item.geometricBounds[1] >= group.geometricBounds[3]
) {
item.move(group, ElementPlacement.PLACEATEND);
placed = true;
}
}
// if an item didn't fit into any current groups make a new group
if (!placed) {
g = app.activeDocument.groupItems.add();
groups.push(g);
item.move(g, ElementPlacement.PLACEATEND);
}
}
return groups;
}
/**
* Attempts to "ReCompound" a line
* of outlined, uncompounded path items.
* @author m1b
* @version 2023-01-18
* @param {Document} doc - an Illustrator Document.
* @param {Array<PathItems>} pathItems - an array or collection of pathItems.
* @param {Number} [tolerance] - the amount that the algorithm will expand each bounding box horizontally (default: height / 20)
* @returns {Array<CompoundPathItem>}
*/
function reCompoundLineOfTextOutlines(doc, pathItems, tolerance) {
var items = [],
compounds = {},
masters = {},
finalCompoundPathItems = [],
top = Infinity,
bottom = -Infinity;
for (var i = 0; i < pathItems.length; i++)
if (pathItems[i].typename == "PathItem") {
var item = pathItems[i],
b = item.geometricBounds;
items.push(item);
if (top > -b[1]) top = -b[1];
if (bottom < -b[3]) bottom = -b[3];
}
if (tolerance == undefined) tolerance = (bottom - top) / 20;
masterLoop1: for (var i = items.length - 1; i >= 0; i--) {
var master = items[i],
mb = [
master.geometricBounds[0] - tolerance,
-top,
master.geometricBounds[2] + tolerance,
-bottom,
];
testingLoop: for (var j = items.length - 1; j >= 0; j--) {
var item = items[j];
if (
master.uuid === item.uuid ||
!boundsAreInsideBounds(item.geometricBounds, mb)
)
continue testingLoop;
if (compounds[master.uuid] == undefined) compounds[master.uuid] = [];
if (masters[item.uuid] == undefined) masters[item.uuid] = [];
compounds[master.uuid].push(item);
masters[item.uuid].push(master);
}
if (compounds[master.uuid] != undefined) compounds[master.uuid].push(master);
}
masterLoop2: for (var key in compounds) {
if (!compounds.hasOwnProperty(key) || compounds[key].length == 0) continue;
var items = compounds[key];
// check to see if any of these items appear as master
// objects having more items themselves, for example,
// an item might fit into another item, but that item
// may, in turn fit into another, and so on. We only
// want the one with the most items inside it.
for (var i = items.length - 1; i >= 0; i--) {
var item = items[i],
itemCount = 0;
if (masters[item.uuid] != undefined)
checkMastersLoop: for (var j = masters[item.uuid].length - 1; j >= 0; j--) {
var masterUUID = masters[item.uuid][j].uuid;
if (masterUUID == key) continue checkMastersLoop;
if (itemCount < compounds[masterUUID].length)
itemCount = compounds[masterUUID].length;
}
if (itemCount > items.length)
// this isn't the best grouping to compound
continue masterLoop2;
}
// create the CompoundPathItem
var newCompoundPathItem = doc.activeLayer.compoundPathItems.add();
finalCompoundPathItems.push(newCompoundPathItem);
// move the path items into it
for (var i = items.length - 1; i >= 0; i--)
items[i].move(newCompoundPathItem, ElementPlacement.PLACEATBEGINNING);
}
return finalCompoundPathItems;
}
/**
* Returns true if `bounds`
* are inside `containerBounds`.
* @param {Array<Number>} bounds - [L, T, R, B]
* @param {Array<Number>} containerBounds - [L, T, R, B]
* @returns {Boolean}
*/
function boundsAreInsideBounds(bounds, containerBounds) {
return (
bounds[0] >= containerBounds[0] &&
bounds[1] <= containerBounds[1] &&
bounds[2] <= containerBounds[2] &&
bounds[3] >= containerBounds[3]
);
}
})();