@mu-crew/mu 3.13.0 → 3.13.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../node_modules/cli-table3/src/debug.js","../node_modules/cli-table3/node_modules/ansi-regex/index.js","../node_modules/cli-table3/node_modules/strip-ansi/index.js","../node_modules/cli-table3/node_modules/is-fullwidth-code-point/index.js","../node_modules/emoji-regex/index.js","../node_modules/cli-table3/node_modules/string-width/index.js","../node_modules/cli-table3/src/utils.js","../node_modules/@colors/colors/lib/styles.js","../node_modules/@colors/colors/lib/system/has-flag.js","../node_modules/@colors/colors/lib/system/supports-colors.js","../node_modules/@colors/colors/lib/custom/trap.js","../node_modules/@colors/colors/lib/custom/zalgo.js","../node_modules/@colors/colors/lib/maps/america.js","../node_modules/@colors/colors/lib/maps/zebra.js","../node_modules/@colors/colors/lib/maps/rainbow.js","../node_modules/@colors/colors/lib/maps/random.js","../node_modules/@colors/colors/lib/colors.js","../node_modules/@colors/colors/safe.js","../node_modules/cli-table3/src/cell.js","../node_modules/cli-table3/src/layout-manager.js","../node_modules/cli-table3/src/table.js","../node_modules/cli-table3/index.js","../node_modules/picocolors/picocolors.js","../src/logs.ts","../src/mux/types.ts","../src/exec-file.ts","../node_modules/signal-exit/src/signals.ts","../node_modules/signal-exit/src/index.ts","../src/mux/input-timing.ts","../src/mux/tmux.ts","../src/mux/herdr.ts","../src/mux/detect.ts","../src/mux.ts","../src/glyphs.ts","../src/agents.ts","../src/agent-state.ts","../src/agents/transport.ts","../src/ctl/client.ts","../src/ctl/protocol.ts","../src/ctl/path.ts","../src/agents/spawn.ts","../src/output.ts","../src/staleness.ts","../src/workspace/core.ts","../src/workspace/crud.ts","../src/vcs/git.ts","../src/vcs/helpers.ts","../src/vcs/types.ts","../src/vcs/jj.ts","../src/vcs/none.ts","../src/vcs/sl.ts","../src/vcs/index.ts","../src/workspace/decorate.ts","../src/workspace/orphans.ts","../src/tasks/core.ts","../src/tasks/queries.ts","../src/tasks/id.ts","../src/tasks/errors.ts","../src/tasks/edges.ts","../src/workstream.ts","../src/tasks/edit.ts","../src/tasks/lifecycle.ts","../src/tasks/claim.ts","../src/tmux.ts","../src/agents/spawn-lock.ts","../src/agents/errors.ts","../src/tasks/wait.ts","../src/agents/abort.ts","../src/agents/adopt.ts","../src/agents/delegate.ts","../src/agents/kick.ts","../src/agents/wait.ts","../src/reconcile.ts","../src/dag.ts","../src/rebuild.ts","../src/drift.ts","../src/fleet-hazards.ts","../src/link.ts","../src/doctor-summary.ts","../src/log-render.ts","../src/tracks.ts","../src/state.ts"],"sourcesContent":["let messages = [];\nlet level = 0;\n\nconst debug = (msg, min) => {\n if (level >= min) {\n messages.push(msg);\n }\n};\n\ndebug.WARN = 1;\ndebug.INFO = 2;\ndebug.DEBUG = 3;\n\ndebug.reset = () => {\n messages = [];\n};\n\ndebug.setDebugLevel = (v) => {\n level = v;\n};\n\ndebug.warn = (msg) => debug(msg, debug.WARN);\ndebug.info = (msg) => debug(msg, debug.INFO);\ndebug.debug = (msg) => debug(msg, debug.DEBUG);\n\ndebug.debugMessages = () => messages;\n\nmodule.exports = debug;\n","'use strict';\n\nmodule.exports = ({onlyFirst = false} = {}) => {\n\tconst pattern = [\n\t\t'[\\\\u001B\\\\u009B][[\\\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]+)*|[a-zA-Z\\\\d]+(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]*)*)?\\\\u0007)',\n\t\t'(?:(?:\\\\d{1,4}(?:;\\\\d{0,4})*)?[\\\\dA-PR-TZcf-ntqry=><~]))'\n\t].join('|');\n\n\treturn new RegExp(pattern, onlyFirst ? undefined : 'g');\n};\n","'use strict';\nconst ansiRegex = require('ansi-regex');\n\nmodule.exports = string => typeof string === 'string' ? string.replace(ansiRegex(), '') : string;\n","/* eslint-disable yoda */\n'use strict';\n\nconst isFullwidthCodePoint = codePoint => {\n\tif (Number.isNaN(codePoint)) {\n\t\treturn false;\n\t}\n\n\t// Code points are derived from:\n\t// http://www.unix.org/Public/UNIDATA/EastAsianWidth.txt\n\tif (\n\t\tcodePoint >= 0x1100 && (\n\t\t\tcodePoint <= 0x115F || // Hangul Jamo\n\t\t\tcodePoint === 0x2329 || // LEFT-POINTING ANGLE BRACKET\n\t\t\tcodePoint === 0x232A || // RIGHT-POINTING ANGLE BRACKET\n\t\t\t// CJK Radicals Supplement .. Enclosed CJK Letters and Months\n\t\t\t(0x2E80 <= codePoint && codePoint <= 0x3247 && codePoint !== 0x303F) ||\n\t\t\t// Enclosed CJK Letters and Months .. CJK Unified Ideographs Extension A\n\t\t\t(0x3250 <= codePoint && codePoint <= 0x4DBF) ||\n\t\t\t// CJK Unified Ideographs .. Yi Radicals\n\t\t\t(0x4E00 <= codePoint && codePoint <= 0xA4C6) ||\n\t\t\t// Hangul Jamo Extended-A\n\t\t\t(0xA960 <= codePoint && codePoint <= 0xA97C) ||\n\t\t\t// Hangul Syllables\n\t\t\t(0xAC00 <= codePoint && codePoint <= 0xD7A3) ||\n\t\t\t// CJK Compatibility Ideographs\n\t\t\t(0xF900 <= codePoint && codePoint <= 0xFAFF) ||\n\t\t\t// Vertical Forms\n\t\t\t(0xFE10 <= codePoint && codePoint <= 0xFE19) ||\n\t\t\t// CJK Compatibility Forms .. Small Form Variants\n\t\t\t(0xFE30 <= codePoint && codePoint <= 0xFE6B) ||\n\t\t\t// Halfwidth and Fullwidth Forms\n\t\t\t(0xFF01 <= codePoint && codePoint <= 0xFF60) ||\n\t\t\t(0xFFE0 <= codePoint && codePoint <= 0xFFE6) ||\n\t\t\t// Kana Supplement\n\t\t\t(0x1B000 <= codePoint && codePoint <= 0x1B001) ||\n\t\t\t// Enclosed Ideographic Supplement\n\t\t\t(0x1F200 <= codePoint && codePoint <= 0x1F251) ||\n\t\t\t// CJK Unified Ideographs Extension B .. Tertiary Ideographic Plane\n\t\t\t(0x20000 <= codePoint && codePoint <= 0x3FFFD)\n\t\t)\n\t) {\n\t\treturn true;\n\t}\n\n\treturn false;\n};\n\nmodule.exports = isFullwidthCodePoint;\nmodule.exports.default = isFullwidthCodePoint;\n","\"use strict\";\n\nmodule.exports = function () {\n // https://mths.be/emoji\n return /\\uD83C\\uDFF4\\uDB40\\uDC67\\uDB40\\uDC62(?:\\uDB40\\uDC65\\uDB40\\uDC6E\\uDB40\\uDC67|\\uDB40\\uDC73\\uDB40\\uDC63\\uDB40\\uDC74|\\uDB40\\uDC77\\uDB40\\uDC6C\\uDB40\\uDC73)\\uDB40\\uDC7F|\\uD83D\\uDC68(?:\\uD83C\\uDFFC\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68\\uD83C\\uDFFB|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFF\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB-\\uDFFE])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFE\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB-\\uDFFD])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFD\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB\\uDFFC])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\u200D(?:\\u2764\\uFE0F\\u200D(?:\\uD83D\\uDC8B\\u200D)?\\uD83D\\uDC68|(?:\\uD83D[\\uDC68\\uDC69])\\u200D(?:\\uD83D\\uDC66\\u200D\\uD83D\\uDC66|\\uD83D\\uDC67\\u200D(?:\\uD83D[\\uDC66\\uDC67]))|\\uD83D\\uDC66\\u200D\\uD83D\\uDC66|\\uD83D\\uDC67\\u200D(?:\\uD83D[\\uDC66\\uDC67])|(?:\\uD83D[\\uDC68\\uDC69])\\u200D(?:\\uD83D[\\uDC66\\uDC67])|[\\u2695\\u2696\\u2708]\\uFE0F|\\uD83D[\\uDC66\\uDC67]|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|(?:\\uD83C\\uDFFB\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFF\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFE\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFD\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFC\\u200D[\\u2695\\u2696\\u2708])\\uFE0F|\\uD83C\\uDFFB\\u200D(?:\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C[\\uDFFB-\\uDFFF])|(?:\\uD83E\\uDDD1\\uD83C\\uDFFB\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1|\\uD83D\\uDC69\\uD83C\\uDFFC\\u200D\\uD83E\\uDD1D\\u200D\\uD83D\\uDC69)\\uD83C\\uDFFB|\\uD83E\\uDDD1(?:\\uD83C\\uDFFF\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1(?:\\uD83C[\\uDFFB-\\uDFFF])|\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1)|(?:\\uD83E\\uDDD1\\uD83C\\uDFFE\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1|\\uD83D\\uDC69\\uD83C\\uDFFF\\u200D\\uD83E\\uDD1D\\u200D(?:\\uD83D[\\uDC68\\uDC69]))(?:\\uD83C[\\uDFFB-\\uDFFE])|(?:\\uD83E\\uDDD1\\uD83C\\uDFFC\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1|\\uD83D\\uDC69\\uD83C\\uDFFD\\u200D\\uD83E\\uDD1D\\u200D\\uD83D\\uDC69)(?:\\uD83C[\\uDFFB\\uDFFC])|\\uD83D\\uDC69(?:\\uD83C\\uDFFE\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB-\\uDFFD\\uDFFF])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFC\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB\\uDFFD-\\uDFFF])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFB\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFC-\\uDFFF])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFD\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB\\uDFFC\\uDFFE\\uDFFF])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\u200D(?:\\u2764\\uFE0F\\u200D(?:\\uD83D\\uDC8B\\u200D(?:\\uD83D[\\uDC68\\uDC69])|\\uD83D[\\uDC68\\uDC69])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFF\\u200D(?:\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD]))|\\uD83D\\uDC69\\u200D\\uD83D\\uDC69\\u200D(?:\\uD83D\\uDC66\\u200D\\uD83D\\uDC66|\\uD83D\\uDC67\\u200D(?:\\uD83D[\\uDC66\\uDC67]))|(?:\\uD83E\\uDDD1\\uD83C\\uDFFD\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1|\\uD83D\\uDC69\\uD83C\\uDFFE\\u200D\\uD83E\\uDD1D\\u200D\\uD83D\\uDC69)(?:\\uD83C[\\uDFFB-\\uDFFD])|\\uD83D\\uDC69\\u200D\\uD83D\\uDC66\\u200D\\uD83D\\uDC66|\\uD83D\\uDC69\\u200D\\uD83D\\uDC69\\u200D(?:\\uD83D[\\uDC66\\uDC67])|(?:\\uD83D\\uDC41\\uFE0F\\u200D\\uD83D\\uDDE8|\\uD83D\\uDC69(?:\\uD83C\\uDFFF\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFE\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFC\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFB\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFD\\u200D[\\u2695\\u2696\\u2708]|\\u200D[\\u2695\\u2696\\u2708])|(?:(?:\\u26F9|\\uD83C[\\uDFCB\\uDFCC]|\\uD83D\\uDD75)\\uFE0F|\\uD83D\\uDC6F|\\uD83E[\\uDD3C\\uDDDE\\uDDDF])\\u200D[\\u2640\\u2642]|(?:\\u26F9|\\uD83C[\\uDFCB\\uDFCC]|\\uD83D\\uDD75)(?:\\uD83C[\\uDFFB-\\uDFFF])\\u200D[\\u2640\\u2642]|(?:\\uD83C[\\uDFC3\\uDFC4\\uDFCA]|\\uD83D[\\uDC6E\\uDC71\\uDC73\\uDC77\\uDC81\\uDC82\\uDC86\\uDC87\\uDE45-\\uDE47\\uDE4B\\uDE4D\\uDE4E\\uDEA3\\uDEB4-\\uDEB6]|\\uD83E[\\uDD26\\uDD37-\\uDD39\\uDD3D\\uDD3E\\uDDB8\\uDDB9\\uDDCD-\\uDDCF\\uDDD6-\\uDDDD])(?:(?:\\uD83C[\\uDFFB-\\uDFFF])\\u200D[\\u2640\\u2642]|\\u200D[\\u2640\\u2642])|\\uD83C\\uDFF4\\u200D\\u2620)\\uFE0F|\\uD83D\\uDC69\\u200D\\uD83D\\uDC67\\u200D(?:\\uD83D[\\uDC66\\uDC67])|\\uD83C\\uDFF3\\uFE0F\\u200D\\uD83C\\uDF08|\\uD83D\\uDC15\\u200D\\uD83E\\uDDBA|\\uD83D\\uDC69\\u200D\\uD83D\\uDC66|\\uD83D\\uDC69\\u200D\\uD83D\\uDC67|\\uD83C\\uDDFD\\uD83C\\uDDF0|\\uD83C\\uDDF4\\uD83C\\uDDF2|\\uD83C\\uDDF6\\uD83C\\uDDE6|[#\\*0-9]\\uFE0F\\u20E3|\\uD83C\\uDDE7(?:\\uD83C[\\uDDE6\\uDDE7\\uDDE9-\\uDDEF\\uDDF1-\\uDDF4\\uDDF6-\\uDDF9\\uDDFB\\uDDFC\\uDDFE\\uDDFF])|\\uD83C\\uDDF9(?:\\uD83C[\\uDDE6\\uDDE8\\uDDE9\\uDDEB-\\uDDED\\uDDEF-\\uDDF4\\uDDF7\\uDDF9\\uDDFB\\uDDFC\\uDDFF])|\\uD83C\\uDDEA(?:\\uD83C[\\uDDE6\\uDDE8\\uDDEA\\uDDEC\\uDDED\\uDDF7-\\uDDFA])|\\uD83E\\uDDD1(?:\\uD83C[\\uDFFB-\\uDFFF])|\\uD83C\\uDDF7(?:\\uD83C[\\uDDEA\\uDDF4\\uDDF8\\uDDFA\\uDDFC])|\\uD83D\\uDC69(?:\\uD83C[\\uDFFB-\\uDFFF])|\\uD83C\\uDDF2(?:\\uD83C[\\uDDE6\\uDDE8-\\uDDED\\uDDF0-\\uDDFF])|\\uD83C\\uDDE6(?:\\uD83C[\\uDDE8-\\uDDEC\\uDDEE\\uDDF1\\uDDF2\\uDDF4\\uDDF6-\\uDDFA\\uDDFC\\uDDFD\\uDDFF])|\\uD83C\\uDDF0(?:\\uD83C[\\uDDEA\\uDDEC-\\uDDEE\\uDDF2\\uDDF3\\uDDF5\\uDDF7\\uDDFC\\uDDFE\\uDDFF])|\\uD83C\\uDDED(?:\\uD83C[\\uDDF0\\uDDF2\\uDDF3\\uDDF7\\uDDF9\\uDDFA])|\\uD83C\\uDDE9(?:\\uD83C[\\uDDEA\\uDDEC\\uDDEF\\uDDF0\\uDDF2\\uDDF4\\uDDFF])|\\uD83C\\uDDFE(?:\\uD83C[\\uDDEA\\uDDF9])|\\uD83C\\uDDEC(?:\\uD83C[\\uDDE6\\uDDE7\\uDDE9-\\uDDEE\\uDDF1-\\uDDF3\\uDDF5-\\uDDFA\\uDDFC\\uDDFE])|\\uD83C\\uDDF8(?:\\uD83C[\\uDDE6-\\uDDEA\\uDDEC-\\uDDF4\\uDDF7-\\uDDF9\\uDDFB\\uDDFD-\\uDDFF])|\\uD83C\\uDDEB(?:\\uD83C[\\uDDEE-\\uDDF0\\uDDF2\\uDDF4\\uDDF7])|\\uD83C\\uDDF5(?:\\uD83C[\\uDDE6\\uDDEA-\\uDDED\\uDDF0-\\uDDF3\\uDDF7-\\uDDF9\\uDDFC\\uDDFE])|\\uD83C\\uDDFB(?:\\uD83C[\\uDDE6\\uDDE8\\uDDEA\\uDDEC\\uDDEE\\uDDF3\\uDDFA])|\\uD83C\\uDDF3(?:\\uD83C[\\uDDE6\\uDDE8\\uDDEA-\\uDDEC\\uDDEE\\uDDF1\\uDDF4\\uDDF5\\uDDF7\\uDDFA\\uDDFF])|\\uD83C\\uDDE8(?:\\uD83C[\\uDDE6\\uDDE8\\uDDE9\\uDDEB-\\uDDEE\\uDDF0-\\uDDF5\\uDDF7\\uDDFA-\\uDDFF])|\\uD83C\\uDDF1(?:\\uD83C[\\uDDE6-\\uDDE8\\uDDEE\\uDDF0\\uDDF7-\\uDDFB\\uDDFE])|\\uD83C\\uDDFF(?:\\uD83C[\\uDDE6\\uDDF2\\uDDFC])|\\uD83C\\uDDFC(?:\\uD83C[\\uDDEB\\uDDF8])|\\uD83C\\uDDFA(?:\\uD83C[\\uDDE6\\uDDEC\\uDDF2\\uDDF3\\uDDF8\\uDDFE\\uDDFF])|\\uD83C\\uDDEE(?:\\uD83C[\\uDDE8-\\uDDEA\\uDDF1-\\uDDF4\\uDDF6-\\uDDF9])|\\uD83C\\uDDEF(?:\\uD83C[\\uDDEA\\uDDF2\\uDDF4\\uDDF5])|(?:\\uD83C[\\uDFC3\\uDFC4\\uDFCA]|\\uD83D[\\uDC6E\\uDC71\\uDC73\\uDC77\\uDC81\\uDC82\\uDC86\\uDC87\\uDE45-\\uDE47\\uDE4B\\uDE4D\\uDE4E\\uDEA3\\uDEB4-\\uDEB6]|\\uD83E[\\uDD26\\uDD37-\\uDD39\\uDD3D\\uDD3E\\uDDB8\\uDDB9\\uDDCD-\\uDDCF\\uDDD6-\\uDDDD])(?:\\uD83C[\\uDFFB-\\uDFFF])|(?:\\u26F9|\\uD83C[\\uDFCB\\uDFCC]|\\uD83D\\uDD75)(?:\\uD83C[\\uDFFB-\\uDFFF])|(?:[\\u261D\\u270A-\\u270D]|\\uD83C[\\uDF85\\uDFC2\\uDFC7]|\\uD83D[\\uDC42\\uDC43\\uDC46-\\uDC50\\uDC66\\uDC67\\uDC6B-\\uDC6D\\uDC70\\uDC72\\uDC74-\\uDC76\\uDC78\\uDC7C\\uDC83\\uDC85\\uDCAA\\uDD74\\uDD7A\\uDD90\\uDD95\\uDD96\\uDE4C\\uDE4F\\uDEC0\\uDECC]|\\uD83E[\\uDD0F\\uDD18-\\uDD1C\\uDD1E\\uDD1F\\uDD30-\\uDD36\\uDDB5\\uDDB6\\uDDBB\\uDDD2-\\uDDD5])(?:\\uD83C[\\uDFFB-\\uDFFF])|(?:[\\u231A\\u231B\\u23E9-\\u23EC\\u23F0\\u23F3\\u25FD\\u25FE\\u2614\\u2615\\u2648-\\u2653\\u267F\\u2693\\u26A1\\u26AA\\u26AB\\u26BD\\u26BE\\u26C4\\u26C5\\u26CE\\u26D4\\u26EA\\u26F2\\u26F3\\u26F5\\u26FA\\u26FD\\u2705\\u270A\\u270B\\u2728\\u274C\\u274E\\u2753-\\u2755\\u2757\\u2795-\\u2797\\u27B0\\u27BF\\u2B1B\\u2B1C\\u2B50\\u2B55]|\\uD83C[\\uDC04\\uDCCF\\uDD8E\\uDD91-\\uDD9A\\uDDE6-\\uDDFF\\uDE01\\uDE1A\\uDE2F\\uDE32-\\uDE36\\uDE38-\\uDE3A\\uDE50\\uDE51\\uDF00-\\uDF20\\uDF2D-\\uDF35\\uDF37-\\uDF7C\\uDF7E-\\uDF93\\uDFA0-\\uDFCA\\uDFCF-\\uDFD3\\uDFE0-\\uDFF0\\uDFF4\\uDFF8-\\uDFFF]|\\uD83D[\\uDC00-\\uDC3E\\uDC40\\uDC42-\\uDCFC\\uDCFF-\\uDD3D\\uDD4B-\\uDD4E\\uDD50-\\uDD67\\uDD7A\\uDD95\\uDD96\\uDDA4\\uDDFB-\\uDE4F\\uDE80-\\uDEC5\\uDECC\\uDED0-\\uDED2\\uDED5\\uDEEB\\uDEEC\\uDEF4-\\uDEFA\\uDFE0-\\uDFEB]|\\uD83E[\\uDD0D-\\uDD3A\\uDD3C-\\uDD45\\uDD47-\\uDD71\\uDD73-\\uDD76\\uDD7A-\\uDDA2\\uDDA5-\\uDDAA\\uDDAE-\\uDDCA\\uDDCD-\\uDDFF\\uDE70-\\uDE73\\uDE78-\\uDE7A\\uDE80-\\uDE82\\uDE90-\\uDE95])|(?:[#\\*0-9\\xA9\\xAE\\u203C\\u2049\\u2122\\u2139\\u2194-\\u2199\\u21A9\\u21AA\\u231A\\u231B\\u2328\\u23CF\\u23E9-\\u23F3\\u23F8-\\u23FA\\u24C2\\u25AA\\u25AB\\u25B6\\u25C0\\u25FB-\\u25FE\\u2600-\\u2604\\u260E\\u2611\\u2614\\u2615\\u2618\\u261D\\u2620\\u2622\\u2623\\u2626\\u262A\\u262E\\u262F\\u2638-\\u263A\\u2640\\u2642\\u2648-\\u2653\\u265F\\u2660\\u2663\\u2665\\u2666\\u2668\\u267B\\u267E\\u267F\\u2692-\\u2697\\u2699\\u269B\\u269C\\u26A0\\u26A1\\u26AA\\u26AB\\u26B0\\u26B1\\u26BD\\u26BE\\u26C4\\u26C5\\u26C8\\u26CE\\u26CF\\u26D1\\u26D3\\u26D4\\u26E9\\u26EA\\u26F0-\\u26F5\\u26F7-\\u26FA\\u26FD\\u2702\\u2705\\u2708-\\u270D\\u270F\\u2712\\u2714\\u2716\\u271D\\u2721\\u2728\\u2733\\u2734\\u2744\\u2747\\u274C\\u274E\\u2753-\\u2755\\u2757\\u2763\\u2764\\u2795-\\u2797\\u27A1\\u27B0\\u27BF\\u2934\\u2935\\u2B05-\\u2B07\\u2B1B\\u2B1C\\u2B50\\u2B55\\u3030\\u303D\\u3297\\u3299]|\\uD83C[\\uDC04\\uDCCF\\uDD70\\uDD71\\uDD7E\\uDD7F\\uDD8E\\uDD91-\\uDD9A\\uDDE6-\\uDDFF\\uDE01\\uDE02\\uDE1A\\uDE2F\\uDE32-\\uDE3A\\uDE50\\uDE51\\uDF00-\\uDF21\\uDF24-\\uDF93\\uDF96\\uDF97\\uDF99-\\uDF9B\\uDF9E-\\uDFF0\\uDFF3-\\uDFF5\\uDFF7-\\uDFFF]|\\uD83D[\\uDC00-\\uDCFD\\uDCFF-\\uDD3D\\uDD49-\\uDD4E\\uDD50-\\uDD67\\uDD6F\\uDD70\\uDD73-\\uDD7A\\uDD87\\uDD8A-\\uDD8D\\uDD90\\uDD95\\uDD96\\uDDA4\\uDDA5\\uDDA8\\uDDB1\\uDDB2\\uDDBC\\uDDC2-\\uDDC4\\uDDD1-\\uDDD3\\uDDDC-\\uDDDE\\uDDE1\\uDDE3\\uDDE8\\uDDEF\\uDDF3\\uDDFA-\\uDE4F\\uDE80-\\uDEC5\\uDECB-\\uDED2\\uDED5\\uDEE0-\\uDEE5\\uDEE9\\uDEEB\\uDEEC\\uDEF0\\uDEF3-\\uDEFA\\uDFE0-\\uDFEB]|\\uD83E[\\uDD0D-\\uDD3A\\uDD3C-\\uDD45\\uDD47-\\uDD71\\uDD73-\\uDD76\\uDD7A-\\uDDA2\\uDDA5-\\uDDAA\\uDDAE-\\uDDCA\\uDDCD-\\uDDFF\\uDE70-\\uDE73\\uDE78-\\uDE7A\\uDE80-\\uDE82\\uDE90-\\uDE95])\\uFE0F|(?:[\\u261D\\u26F9\\u270A-\\u270D]|\\uD83C[\\uDF85\\uDFC2-\\uDFC4\\uDFC7\\uDFCA-\\uDFCC]|\\uD83D[\\uDC42\\uDC43\\uDC46-\\uDC50\\uDC66-\\uDC78\\uDC7C\\uDC81-\\uDC83\\uDC85-\\uDC87\\uDC8F\\uDC91\\uDCAA\\uDD74\\uDD75\\uDD7A\\uDD90\\uDD95\\uDD96\\uDE45-\\uDE47\\uDE4B-\\uDE4F\\uDEA3\\uDEB4-\\uDEB6\\uDEC0\\uDECC]|\\uD83E[\\uDD0F\\uDD18-\\uDD1F\\uDD26\\uDD30-\\uDD39\\uDD3C-\\uDD3E\\uDDB5\\uDDB6\\uDDB8\\uDDB9\\uDDBB\\uDDCD-\\uDDCF\\uDDD1-\\uDDDD])/g;\n};\n","'use strict';\nconst stripAnsi = require('strip-ansi');\nconst isFullwidthCodePoint = require('is-fullwidth-code-point');\nconst emojiRegex = require('emoji-regex');\n\nconst stringWidth = string => {\n\tif (typeof string !== 'string' || string.length === 0) {\n\t\treturn 0;\n\t}\n\n\tstring = stripAnsi(string);\n\n\tif (string.length === 0) {\n\t\treturn 0;\n\t}\n\n\tstring = string.replace(emojiRegex(), ' ');\n\n\tlet width = 0;\n\n\tfor (let i = 0; i < string.length; i++) {\n\t\tconst code = string.codePointAt(i);\n\n\t\t// Ignore control characters\n\t\tif (code <= 0x1F || (code >= 0x7F && code <= 0x9F)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Ignore combining characters\n\t\tif (code >= 0x300 && code <= 0x36F) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Surrogates\n\t\tif (code > 0xFFFF) {\n\t\t\ti++;\n\t\t}\n\n\t\twidth += isFullwidthCodePoint(code) ? 2 : 1;\n\t}\n\n\treturn width;\n};\n\nmodule.exports = stringWidth;\n// TODO: remove this in the next major version\nmodule.exports.default = stringWidth;\n","const stringWidth = require('string-width');\n\nfunction codeRegex(capture) {\n return capture ? /\\u001b\\[((?:\\d*;){0,5}\\d*)m/g : /\\u001b\\[(?:\\d*;){0,5}\\d*m/g;\n}\n\nfunction strlen(str) {\n let code = codeRegex();\n let stripped = ('' + str).replace(code, '');\n let split = stripped.split('\\n');\n return split.reduce(function (memo, s) {\n return stringWidth(s) > memo ? stringWidth(s) : memo;\n }, 0);\n}\n\nfunction repeat(str, times) {\n return Array(times + 1).join(str);\n}\n\nfunction pad(str, len, pad, dir) {\n let length = strlen(str);\n if (len + 1 >= length) {\n let padlen = len - length;\n switch (dir) {\n case 'right': {\n str = repeat(pad, padlen) + str;\n break;\n }\n case 'center': {\n let right = Math.ceil(padlen / 2);\n let left = padlen - right;\n str = repeat(pad, left) + str + repeat(pad, right);\n break;\n }\n default: {\n str = str + repeat(pad, padlen);\n break;\n }\n }\n }\n return str;\n}\n\nlet codeCache = {};\n\nfunction addToCodeCache(name, on, off) {\n on = '\\u001b[' + on + 'm';\n off = '\\u001b[' + off + 'm';\n codeCache[on] = { set: name, to: true };\n codeCache[off] = { set: name, to: false };\n codeCache[name] = { on: on, off: off };\n}\n\n//https://github.com/Marak/colors.js/blob/master/lib/styles.js\naddToCodeCache('bold', 1, 22);\naddToCodeCache('italics', 3, 23);\naddToCodeCache('underline', 4, 24);\naddToCodeCache('inverse', 7, 27);\naddToCodeCache('strikethrough', 9, 29);\n\nfunction updateState(state, controlChars) {\n let controlCode = controlChars[1] ? parseInt(controlChars[1].split(';')[0]) : 0;\n if ((controlCode >= 30 && controlCode <= 39) || (controlCode >= 90 && controlCode <= 97)) {\n state.lastForegroundAdded = controlChars[0];\n return;\n }\n if ((controlCode >= 40 && controlCode <= 49) || (controlCode >= 100 && controlCode <= 107)) {\n state.lastBackgroundAdded = controlChars[0];\n return;\n }\n if (controlCode === 0) {\n for (let i in state) {\n /* istanbul ignore else */\n if (Object.prototype.hasOwnProperty.call(state, i)) {\n delete state[i];\n }\n }\n return;\n }\n let info = codeCache[controlChars[0]];\n if (info) {\n state[info.set] = info.to;\n }\n}\n\nfunction readState(line) {\n let code = codeRegex(true);\n let controlChars = code.exec(line);\n let state = {};\n while (controlChars !== null) {\n updateState(state, controlChars);\n controlChars = code.exec(line);\n }\n return state;\n}\n\nfunction unwindState(state, ret) {\n let lastBackgroundAdded = state.lastBackgroundAdded;\n let lastForegroundAdded = state.lastForegroundAdded;\n\n delete state.lastBackgroundAdded;\n delete state.lastForegroundAdded;\n\n Object.keys(state).forEach(function (key) {\n if (state[key]) {\n ret += codeCache[key].off;\n }\n });\n\n if (lastBackgroundAdded && lastBackgroundAdded != '\\u001b[49m') {\n ret += '\\u001b[49m';\n }\n if (lastForegroundAdded && lastForegroundAdded != '\\u001b[39m') {\n ret += '\\u001b[39m';\n }\n\n return ret;\n}\n\nfunction rewindState(state, ret) {\n let lastBackgroundAdded = state.lastBackgroundAdded;\n let lastForegroundAdded = state.lastForegroundAdded;\n\n delete state.lastBackgroundAdded;\n delete state.lastForegroundAdded;\n\n Object.keys(state).forEach(function (key) {\n if (state[key]) {\n ret = codeCache[key].on + ret;\n }\n });\n\n if (lastBackgroundAdded && lastBackgroundAdded != '\\u001b[49m') {\n ret = lastBackgroundAdded + ret;\n }\n if (lastForegroundAdded && lastForegroundAdded != '\\u001b[39m') {\n ret = lastForegroundAdded + ret;\n }\n\n return ret;\n}\n\nfunction truncateWidth(str, desiredLength) {\n if (str.length === strlen(str)) {\n return str.substr(0, desiredLength);\n }\n\n while (strlen(str) > desiredLength) {\n str = str.slice(0, -1);\n }\n\n return str;\n}\n\nfunction truncateWidthWithAnsi(str, desiredLength) {\n let code = codeRegex(true);\n let split = str.split(codeRegex());\n let splitIndex = 0;\n let retLen = 0;\n let ret = '';\n let myArray;\n let state = {};\n\n while (retLen < desiredLength) {\n myArray = code.exec(str);\n let toAdd = split[splitIndex];\n splitIndex++;\n if (retLen + strlen(toAdd) > desiredLength) {\n toAdd = truncateWidth(toAdd, desiredLength - retLen);\n }\n ret += toAdd;\n retLen += strlen(toAdd);\n\n if (retLen < desiredLength) {\n if (!myArray) {\n break;\n } // full-width chars may cause a whitespace which cannot be filled\n ret += myArray[0];\n updateState(state, myArray);\n }\n }\n\n return unwindState(state, ret);\n}\n\nfunction truncate(str, desiredLength, truncateChar) {\n truncateChar = truncateChar || '…';\n let lengthOfStr = strlen(str);\n if (lengthOfStr <= desiredLength) {\n return str;\n }\n desiredLength -= strlen(truncateChar);\n\n let ret = truncateWidthWithAnsi(str, desiredLength);\n\n ret += truncateChar;\n\n const hrefTag = '\\x1B]8;;\\x07';\n\n if (str.includes(hrefTag) && !ret.includes(hrefTag)) {\n ret += hrefTag;\n }\n\n return ret;\n}\n\nfunction defaultOptions() {\n return {\n chars: {\n top: '─',\n 'top-mid': '┬',\n 'top-left': '┌',\n 'top-right': '┐',\n bottom: '─',\n 'bottom-mid': '┴',\n 'bottom-left': '└',\n 'bottom-right': '┘',\n left: '│',\n 'left-mid': '├',\n mid: '─',\n 'mid-mid': '┼',\n right: '│',\n 'right-mid': '┤',\n middle: '│',\n },\n truncate: '…',\n colWidths: [],\n rowHeights: [],\n colAligns: [],\n rowAligns: [],\n style: {\n 'padding-left': 1,\n 'padding-right': 1,\n head: ['red'],\n border: ['grey'],\n compact: false,\n },\n head: [],\n };\n}\n\nfunction mergeOptions(options, defaults) {\n options = options || {};\n defaults = defaults || defaultOptions();\n let ret = Object.assign({}, defaults, options);\n ret.chars = Object.assign({}, defaults.chars, options.chars);\n ret.style = Object.assign({}, defaults.style, options.style);\n return ret;\n}\n\n// Wrap on word boundary\nfunction wordWrap(maxLength, input) {\n let lines = [];\n let split = input.split(/(\\s+)/g);\n let line = [];\n let lineLength = 0;\n let whitespace;\n for (let i = 0; i < split.length; i += 2) {\n let word = split[i];\n let newLength = lineLength + strlen(word);\n if (lineLength > 0 && whitespace) {\n newLength += whitespace.length;\n }\n if (newLength > maxLength) {\n if (lineLength !== 0) {\n lines.push(line.join(''));\n }\n line = [word];\n lineLength = strlen(word);\n } else {\n line.push(whitespace || '', word);\n lineLength = newLength;\n }\n whitespace = split[i + 1];\n }\n if (lineLength) {\n lines.push(line.join(''));\n }\n return lines;\n}\n\n// Wrap text (ignoring word boundaries)\nfunction textWrap(maxLength, input) {\n let lines = [];\n let line = '';\n function pushLine(str, ws) {\n if (line.length && ws) line += ws;\n line += str;\n while (line.length > maxLength) {\n lines.push(line.slice(0, maxLength));\n line = line.slice(maxLength);\n }\n }\n let split = input.split(/(\\s+)/g);\n for (let i = 0; i < split.length; i += 2) {\n pushLine(split[i], i && split[i - 1]);\n }\n if (line.length) lines.push(line);\n return lines;\n}\n\nfunction multiLineWordWrap(maxLength, input, wrapOnWordBoundary = true) {\n let output = [];\n input = input.split('\\n');\n const handler = wrapOnWordBoundary ? wordWrap : textWrap;\n for (let i = 0; i < input.length; i++) {\n output.push.apply(output, handler(maxLength, input[i]));\n }\n return output;\n}\n\nfunction colorizeLines(input) {\n let state = {};\n let output = [];\n for (let i = 0; i < input.length; i++) {\n let line = rewindState(state, input[i]);\n state = readState(line);\n let temp = Object.assign({}, state);\n output.push(unwindState(temp, line));\n }\n return output;\n}\n\n/**\n * Credit: Matheus Sampaio https://github.com/matheussampaio\n */\nfunction hyperlink(url, text) {\n const OSC = '\\u001B]';\n const BEL = '\\u0007';\n const SEP = ';';\n\n return [OSC, '8', SEP, SEP, url || text, BEL, text, OSC, '8', SEP, SEP, BEL].join('');\n}\n\nmodule.exports = {\n strlen: strlen,\n repeat: repeat,\n pad: pad,\n truncate: truncate,\n mergeOptions: mergeOptions,\n wordWrap: multiLineWordWrap,\n colorizeLines: colorizeLines,\n hyperlink,\n};\n","/*\nThe MIT License (MIT)\n\nCopyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n*/\n\nvar styles = {};\nmodule['exports'] = styles;\n\nvar codes = {\n reset: [0, 0],\n\n bold: [1, 22],\n dim: [2, 22],\n italic: [3, 23],\n underline: [4, 24],\n inverse: [7, 27],\n hidden: [8, 28],\n strikethrough: [9, 29],\n\n black: [30, 39],\n red: [31, 39],\n green: [32, 39],\n yellow: [33, 39],\n blue: [34, 39],\n magenta: [35, 39],\n cyan: [36, 39],\n white: [37, 39],\n gray: [90, 39],\n grey: [90, 39],\n\n brightRed: [91, 39],\n brightGreen: [92, 39],\n brightYellow: [93, 39],\n brightBlue: [94, 39],\n brightMagenta: [95, 39],\n brightCyan: [96, 39],\n brightWhite: [97, 39],\n\n bgBlack: [40, 49],\n bgRed: [41, 49],\n bgGreen: [42, 49],\n bgYellow: [43, 49],\n bgBlue: [44, 49],\n bgMagenta: [45, 49],\n bgCyan: [46, 49],\n bgWhite: [47, 49],\n bgGray: [100, 49],\n bgGrey: [100, 49],\n\n bgBrightRed: [101, 49],\n bgBrightGreen: [102, 49],\n bgBrightYellow: [103, 49],\n bgBrightBlue: [104, 49],\n bgBrightMagenta: [105, 49],\n bgBrightCyan: [106, 49],\n bgBrightWhite: [107, 49],\n\n // legacy styles for colors pre v1.0.0\n blackBG: [40, 49],\n redBG: [41, 49],\n greenBG: [42, 49],\n yellowBG: [43, 49],\n blueBG: [44, 49],\n magentaBG: [45, 49],\n cyanBG: [46, 49],\n whiteBG: [47, 49],\n\n};\n\nObject.keys(codes).forEach(function(key) {\n var val = codes[key];\n var style = styles[key] = [];\n style.open = '\\u001b[' + val[0] + 'm';\n style.close = '\\u001b[' + val[1] + 'm';\n});\n","/*\nMIT License\n\nCopyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n'use strict';\n\nmodule.exports = function(flag, argv) {\n argv = argv || process.argv;\n\n var terminatorPos = argv.indexOf('--');\n var prefix = /^-{1,2}/.test(flag) ? '' : '--';\n var pos = argv.indexOf(prefix + flag);\n\n return pos !== -1 && (terminatorPos === -1 ? true : pos < terminatorPos);\n};\n","/*\nThe MIT License (MIT)\n\nCopyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n*/\n\n'use strict';\n\nvar os = require('os');\nvar hasFlag = require('./has-flag.js');\n\nvar env = process.env;\n\nvar forceColor = void 0;\nif (hasFlag('no-color') || hasFlag('no-colors') || hasFlag('color=false')) {\n forceColor = false;\n} else if (hasFlag('color') || hasFlag('colors') || hasFlag('color=true')\n || hasFlag('color=always')) {\n forceColor = true;\n}\nif ('FORCE_COLOR' in env) {\n forceColor = env.FORCE_COLOR.length === 0\n || parseInt(env.FORCE_COLOR, 10) !== 0;\n}\n\nfunction translateLevel(level) {\n if (level === 0) {\n return false;\n }\n\n return {\n level: level,\n hasBasic: true,\n has256: level >= 2,\n has16m: level >= 3,\n };\n}\n\nfunction supportsColor(stream) {\n if (forceColor === false) {\n return 0;\n }\n\n if (hasFlag('color=16m') || hasFlag('color=full')\n || hasFlag('color=truecolor')) {\n return 3;\n }\n\n if (hasFlag('color=256')) {\n return 2;\n }\n\n if (stream && !stream.isTTY && forceColor !== true) {\n return 0;\n }\n\n var min = forceColor ? 1 : 0;\n\n if (process.platform === 'win32') {\n // Node.js 7.5.0 is the first version of Node.js to include a patch to\n // libuv that enables 256 color output on Windows. Anything earlier and it\n // won't work. However, here we target Node.js 8 at minimum as it is an LTS\n // release, and Node.js 7 is not. Windows 10 build 10586 is the first\n // Windows release that supports 256 colors. Windows 10 build 14931 is the\n // first release that supports 16m/TrueColor.\n var osRelease = os.release().split('.');\n if (Number(process.versions.node.split('.')[0]) >= 8\n && Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {\n return Number(osRelease[2]) >= 14931 ? 3 : 2;\n }\n\n return 1;\n }\n\n if ('CI' in env) {\n if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI'].some(function(sign) {\n return sign in env;\n }) || env.CI_NAME === 'codeship') {\n return 1;\n }\n\n return min;\n }\n\n if ('TEAMCITY_VERSION' in env) {\n return (/^(9\\.(0*[1-9]\\d*)\\.|\\d{2,}\\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0\n );\n }\n\n if ('TERM_PROGRAM' in env) {\n var version = parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10);\n\n switch (env.TERM_PROGRAM) {\n case 'iTerm.app':\n return version >= 3 ? 3 : 2;\n case 'Hyper':\n return 3;\n case 'Apple_Terminal':\n return 2;\n // No default\n }\n }\n\n if (/-256(color)?$/i.test(env.TERM)) {\n return 2;\n }\n\n if (/^screen|^xterm|^vt100|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {\n return 1;\n }\n\n if ('COLORTERM' in env) {\n return 1;\n }\n\n if (env.TERM === 'dumb') {\n return min;\n }\n\n return min;\n}\n\nfunction getSupportLevel(stream) {\n var level = supportsColor(stream);\n return translateLevel(level);\n}\n\nmodule.exports = {\n supportsColor: getSupportLevel,\n stdout: getSupportLevel(process.stdout),\n stderr: getSupportLevel(process.stderr),\n};\n","module['exports'] = function runTheTrap(text, options) {\n var result = '';\n text = text || 'Run the trap, drop the bass';\n text = text.split('');\n var trap = {\n a: ['\\u0040', '\\u0104', '\\u023a', '\\u0245', '\\u0394', '\\u039b', '\\u0414'],\n b: ['\\u00df', '\\u0181', '\\u0243', '\\u026e', '\\u03b2', '\\u0e3f'],\n c: ['\\u00a9', '\\u023b', '\\u03fe'],\n d: ['\\u00d0', '\\u018a', '\\u0500', '\\u0501', '\\u0502', '\\u0503'],\n e: ['\\u00cb', '\\u0115', '\\u018e', '\\u0258', '\\u03a3', '\\u03be', '\\u04bc',\n '\\u0a6c'],\n f: ['\\u04fa'],\n g: ['\\u0262'],\n h: ['\\u0126', '\\u0195', '\\u04a2', '\\u04ba', '\\u04c7', '\\u050a'],\n i: ['\\u0f0f'],\n j: ['\\u0134'],\n k: ['\\u0138', '\\u04a0', '\\u04c3', '\\u051e'],\n l: ['\\u0139'],\n m: ['\\u028d', '\\u04cd', '\\u04ce', '\\u0520', '\\u0521', '\\u0d69'],\n n: ['\\u00d1', '\\u014b', '\\u019d', '\\u0376', '\\u03a0', '\\u048a'],\n o: ['\\u00d8', '\\u00f5', '\\u00f8', '\\u01fe', '\\u0298', '\\u047a', '\\u05dd',\n '\\u06dd', '\\u0e4f'],\n p: ['\\u01f7', '\\u048e'],\n q: ['\\u09cd'],\n r: ['\\u00ae', '\\u01a6', '\\u0210', '\\u024c', '\\u0280', '\\u042f'],\n s: ['\\u00a7', '\\u03de', '\\u03df', '\\u03e8'],\n t: ['\\u0141', '\\u0166', '\\u0373'],\n u: ['\\u01b1', '\\u054d'],\n v: ['\\u05d8'],\n w: ['\\u0428', '\\u0460', '\\u047c', '\\u0d70'],\n x: ['\\u04b2', '\\u04fe', '\\u04fc', '\\u04fd'],\n y: ['\\u00a5', '\\u04b0', '\\u04cb'],\n z: ['\\u01b5', '\\u0240'],\n };\n text.forEach(function(c) {\n c = c.toLowerCase();\n var chars = trap[c] || [' '];\n var rand = Math.floor(Math.random() * chars.length);\n if (typeof trap[c] !== 'undefined') {\n result += trap[c][rand];\n } else {\n result += c;\n }\n });\n return result;\n};\n","// please no\nmodule['exports'] = function zalgo(text, options) {\n text = text || ' he is here ';\n var soul = {\n 'up': [\n '̍', '̎', '̄', '̅',\n '̿', '̑', '̆', '̐',\n '͒', '͗', '͑', '̇',\n '̈', '̊', '͂', '̓',\n '̈', '͊', '͋', '͌',\n '̃', '̂', '̌', '͐',\n '̀', '́', '̋', '̏',\n '̒', '̓', '̔', '̽',\n '̉', 'ͣ', 'ͤ', 'ͥ',\n 'ͦ', 'ͧ', 'ͨ', 'ͩ',\n 'ͪ', 'ͫ', 'ͬ', 'ͭ',\n 'ͮ', 'ͯ', '̾', '͛',\n '͆', '̚',\n ],\n 'down': [\n '̖', '̗', '̘', '̙',\n '̜', '̝', '̞', '̟',\n '̠', '̤', '̥', '̦',\n '̩', '̪', '̫', '̬',\n '̭', '̮', '̯', '̰',\n '̱', '̲', '̳', '̹',\n '̺', '̻', '̼', 'ͅ',\n '͇', '͈', '͉', '͍',\n '͎', '͓', '͔', '͕',\n '͖', '͙', '͚', '̣',\n ],\n 'mid': [\n '̕', '̛', '̀', '́',\n '͘', '̡', '̢', '̧',\n '̨', '̴', '̵', '̶',\n '͜', '͝', '͞',\n '͟', '͠', '͢', '̸',\n '̷', '͡', ' ҉',\n ],\n };\n var all = [].concat(soul.up, soul.down, soul.mid);\n\n function randomNumber(range) {\n var r = Math.floor(Math.random() * range);\n return r;\n }\n\n function isChar(character) {\n var bool = false;\n all.filter(function(i) {\n bool = (i === character);\n });\n return bool;\n }\n\n\n function heComes(text, options) {\n var result = '';\n var counts;\n var l;\n options = options || {};\n options['up'] =\n typeof options['up'] !== 'undefined' ? options['up'] : true;\n options['mid'] =\n typeof options['mid'] !== 'undefined' ? options['mid'] : true;\n options['down'] =\n typeof options['down'] !== 'undefined' ? options['down'] : true;\n options['size'] =\n typeof options['size'] !== 'undefined' ? options['size'] : 'maxi';\n text = text.split('');\n for (l in text) {\n if (isChar(l)) {\n continue;\n }\n result = result + text[l];\n counts = {'up': 0, 'down': 0, 'mid': 0};\n switch (options.size) {\n case 'mini':\n counts.up = randomNumber(8);\n counts.mid = randomNumber(2);\n counts.down = randomNumber(8);\n break;\n case 'maxi':\n counts.up = randomNumber(16) + 3;\n counts.mid = randomNumber(4) + 1;\n counts.down = randomNumber(64) + 3;\n break;\n default:\n counts.up = randomNumber(8) + 1;\n counts.mid = randomNumber(6) / 2;\n counts.down = randomNumber(8) + 1;\n break;\n }\n\n var arr = ['up', 'mid', 'down'];\n for (var d in arr) {\n var index = arr[d];\n for (var i = 0; i <= counts[index]; i++) {\n if (options[index]) {\n result = result + soul[index][randomNumber(soul[index].length)];\n }\n }\n }\n }\n return result;\n }\n // don't summon him\n return heComes(text, options);\n};\n\n","module['exports'] = function(colors) {\n return function(letter, i, exploded) {\n if (letter === ' ') return letter;\n switch (i%3) {\n case 0: return colors.red(letter);\n case 1: return colors.white(letter);\n case 2: return colors.blue(letter);\n }\n };\n};\n","module['exports'] = function(colors) {\n return function(letter, i, exploded) {\n return i % 2 === 0 ? letter : colors.inverse(letter);\n };\n};\n","module['exports'] = function(colors) {\n // RoY G BiV\n var rainbowColors = ['red', 'yellow', 'green', 'blue', 'magenta'];\n return function(letter, i, exploded) {\n if (letter === ' ') {\n return letter;\n } else {\n return colors[rainbowColors[i++ % rainbowColors.length]](letter);\n }\n };\n};\n\n","module['exports'] = function(colors) {\n var available = ['underline', 'inverse', 'grey', 'yellow', 'red', 'green',\n 'blue', 'white', 'cyan', 'magenta', 'brightYellow', 'brightRed',\n 'brightGreen', 'brightBlue', 'brightWhite', 'brightCyan', 'brightMagenta'];\n return function(letter, i, exploded) {\n return letter === ' ' ? letter :\n colors[\n available[Math.round(Math.random() * (available.length - 2))]\n ](letter);\n };\n};\n","/*\n\nThe MIT License (MIT)\n\nOriginal Library\n - Copyright (c) Marak Squires\n\nAdditional functionality\n - Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n*/\n\nvar colors = {};\nmodule['exports'] = colors;\n\ncolors.themes = {};\n\nvar util = require('util');\nvar ansiStyles = colors.styles = require('./styles');\nvar defineProps = Object.defineProperties;\nvar newLineRegex = new RegExp(/[\\r\\n]+/g);\n\ncolors.supportsColor = require('./system/supports-colors').supportsColor;\n\nif (typeof colors.enabled === 'undefined') {\n colors.enabled = colors.supportsColor() !== false;\n}\n\ncolors.enable = function() {\n colors.enabled = true;\n};\n\ncolors.disable = function() {\n colors.enabled = false;\n};\n\ncolors.stripColors = colors.strip = function(str) {\n return ('' + str).replace(/\\x1B\\[\\d+m/g, '');\n};\n\n// eslint-disable-next-line no-unused-vars\nvar stylize = colors.stylize = function stylize(str, style) {\n if (!colors.enabled) {\n return str+'';\n }\n\n var styleMap = ansiStyles[style];\n\n // Stylize should work for non-ANSI styles, too\n if (!styleMap && style in colors) {\n // Style maps like trap operate as functions on strings;\n // they don't have properties like open or close.\n return colors[style](str);\n }\n\n return styleMap.open + str + styleMap.close;\n};\n\nvar matchOperatorsRe = /[|\\\\{}()[\\]^$+*?.]/g;\nvar escapeStringRegexp = function(str) {\n if (typeof str !== 'string') {\n throw new TypeError('Expected a string');\n }\n return str.replace(matchOperatorsRe, '\\\\$&');\n};\n\nfunction build(_styles) {\n var builder = function builder() {\n return applyStyle.apply(builder, arguments);\n };\n builder._styles = _styles;\n // __proto__ is used because we must return a function, but there is\n // no way to create a function with a different prototype.\n builder.__proto__ = proto;\n return builder;\n}\n\nvar styles = (function() {\n var ret = {};\n ansiStyles.grey = ansiStyles.gray;\n Object.keys(ansiStyles).forEach(function(key) {\n ansiStyles[key].closeRe =\n new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g');\n ret[key] = {\n get: function() {\n return build(this._styles.concat(key));\n },\n };\n });\n return ret;\n})();\n\nvar proto = defineProps(function colors() {}, styles);\n\nfunction applyStyle() {\n var args = Array.prototype.slice.call(arguments);\n\n var str = args.map(function(arg) {\n // Use weak equality check so we can colorize null/undefined in safe mode\n if (arg != null && arg.constructor === String) {\n return arg;\n } else {\n return util.inspect(arg);\n }\n }).join(' ');\n\n if (!colors.enabled || !str) {\n return str;\n }\n\n var newLinesPresent = str.indexOf('\\n') != -1;\n\n var nestedStyles = this._styles;\n\n var i = nestedStyles.length;\n while (i--) {\n var code = ansiStyles[nestedStyles[i]];\n str = code.open + str.replace(code.closeRe, code.open) + code.close;\n if (newLinesPresent) {\n str = str.replace(newLineRegex, function(match) {\n return code.close + match + code.open;\n });\n }\n }\n\n return str;\n}\n\ncolors.setTheme = function(theme) {\n if (typeof theme === 'string') {\n console.log('colors.setTheme now only accepts an object, not a string. ' +\n 'If you are trying to set a theme from a file, it is now your (the ' +\n 'caller\\'s) responsibility to require the file. The old syntax ' +\n 'looked like colors.setTheme(__dirname + ' +\n '\\'/../themes/generic-logging.js\\'); The new syntax looks like '+\n 'colors.setTheme(require(__dirname + ' +\n '\\'/../themes/generic-logging.js\\'));');\n return;\n }\n for (var style in theme) {\n (function(style) {\n colors[style] = function(str) {\n if (typeof theme[style] === 'object') {\n var out = str;\n for (var i in theme[style]) {\n out = colors[theme[style][i]](out);\n }\n return out;\n }\n return colors[theme[style]](str);\n };\n })(style);\n }\n};\n\nfunction init() {\n var ret = {};\n Object.keys(styles).forEach(function(name) {\n ret[name] = {\n get: function() {\n return build([name]);\n },\n };\n });\n return ret;\n}\n\nvar sequencer = function sequencer(map, str) {\n var exploded = str.split('');\n exploded = exploded.map(map);\n return exploded.join('');\n};\n\n// custom formatter methods\ncolors.trap = require('./custom/trap');\ncolors.zalgo = require('./custom/zalgo');\n\n// maps\ncolors.maps = {};\ncolors.maps.america = require('./maps/america')(colors);\ncolors.maps.zebra = require('./maps/zebra')(colors);\ncolors.maps.rainbow = require('./maps/rainbow')(colors);\ncolors.maps.random = require('./maps/random')(colors);\n\nfor (var map in colors.maps) {\n (function(map) {\n colors[map] = function(str) {\n return sequencer(colors.maps[map], str);\n };\n })(map);\n}\n\ndefineProps(colors, init());\n","//\n// Remark: Requiring this file will use the \"safe\" colors API,\n// which will not touch String.prototype.\n//\n// var colors = require('colors/safe');\n// colors.red(\"foo\")\n//\n//\nvar colors = require('./lib/colors');\nmodule['exports'] = colors;\n","const { info, debug } = require('./debug');\nconst utils = require('./utils');\n\nclass Cell {\n /**\n * A representation of a cell within the table.\n * Implementations must have `init` and `draw` methods,\n * as well as `colSpan`, `rowSpan`, `desiredHeight` and `desiredWidth` properties.\n * @param options\n * @constructor\n */\n constructor(options) {\n this.setOptions(options);\n\n /**\n * Each cell will have it's `x` and `y` values set by the `layout-manager` prior to\n * `init` being called;\n * @type {Number}\n */\n this.x = null;\n this.y = null;\n }\n\n setOptions(options) {\n if (['boolean', 'number', 'bigint', 'string'].indexOf(typeof options) !== -1) {\n options = { content: '' + options };\n }\n options = options || {};\n this.options = options;\n let content = options.content;\n if (['boolean', 'number', 'bigint', 'string'].indexOf(typeof content) !== -1) {\n this.content = String(content);\n } else if (!content) {\n this.content = this.options.href || '';\n } else {\n throw new Error('Content needs to be a primitive, got: ' + typeof content);\n }\n this.colSpan = options.colSpan || 1;\n this.rowSpan = options.rowSpan || 1;\n if (this.options.href) {\n Object.defineProperty(this, 'href', {\n get() {\n return this.options.href;\n },\n });\n }\n }\n\n mergeTableOptions(tableOptions, cells) {\n this.cells = cells;\n\n let optionsChars = this.options.chars || {};\n let tableChars = tableOptions.chars;\n let chars = (this.chars = {});\n CHAR_NAMES.forEach(function (name) {\n setOption(optionsChars, tableChars, name, chars);\n });\n\n this.truncate = this.options.truncate || tableOptions.truncate;\n\n let style = (this.options.style = this.options.style || {});\n let tableStyle = tableOptions.style;\n setOption(style, tableStyle, 'padding-left', this);\n setOption(style, tableStyle, 'padding-right', this);\n this.head = style.head || tableStyle.head;\n this.border = style.border || tableStyle.border;\n\n this.fixedWidth = tableOptions.colWidths[this.x];\n this.lines = this.computeLines(tableOptions);\n\n this.desiredWidth = utils.strlen(this.content) + this.paddingLeft + this.paddingRight;\n this.desiredHeight = this.lines.length;\n }\n\n computeLines(tableOptions) {\n const tableWordWrap = tableOptions.wordWrap || tableOptions.textWrap;\n const { wordWrap = tableWordWrap } = this.options;\n if (this.fixedWidth && wordWrap) {\n this.fixedWidth -= this.paddingLeft + this.paddingRight;\n if (this.colSpan) {\n let i = 1;\n while (i < this.colSpan) {\n this.fixedWidth += tableOptions.colWidths[this.x + i];\n i++;\n }\n }\n const { wrapOnWordBoundary: tableWrapOnWordBoundary = true } = tableOptions;\n const { wrapOnWordBoundary = tableWrapOnWordBoundary } = this.options;\n return this.wrapLines(utils.wordWrap(this.fixedWidth, this.content, wrapOnWordBoundary));\n }\n return this.wrapLines(this.content.split('\\n'));\n }\n\n wrapLines(computedLines) {\n const lines = utils.colorizeLines(computedLines);\n if (this.href) {\n return lines.map((line) => utils.hyperlink(this.href, line));\n }\n return lines;\n }\n\n /**\n * Initializes the Cells data structure.\n *\n * @param tableOptions - A fully populated set of tableOptions.\n * In addition to the standard default values, tableOptions must have fully populated the\n * `colWidths` and `rowWidths` arrays. Those arrays must have lengths equal to the number\n * of columns or rows (respectively) in this table, and each array item must be a Number.\n *\n */\n init(tableOptions) {\n let x = this.x;\n let y = this.y;\n this.widths = tableOptions.colWidths.slice(x, x + this.colSpan);\n this.heights = tableOptions.rowHeights.slice(y, y + this.rowSpan);\n this.width = this.widths.reduce(sumPlusOne, -1);\n this.height = this.heights.reduce(sumPlusOne, -1);\n\n this.hAlign = this.options.hAlign || tableOptions.colAligns[x];\n this.vAlign = this.options.vAlign || tableOptions.rowAligns[y];\n\n this.drawRight = x + this.colSpan == tableOptions.colWidths.length;\n }\n\n /**\n * Draws the given line of the cell.\n * This default implementation defers to methods `drawTop`, `drawBottom`, `drawLine` and `drawEmpty`.\n * @param lineNum - can be `top`, `bottom` or a numerical line number.\n * @param spanningCell - will be a number if being called from a RowSpanCell, and will represent how\n * many rows below it's being called from. Otherwise it's undefined.\n * @returns {String} The representation of this line.\n */\n draw(lineNum, spanningCell) {\n if (lineNum == 'top') return this.drawTop(this.drawRight);\n if (lineNum == 'bottom') return this.drawBottom(this.drawRight);\n let content = utils.truncate(this.content, 10, this.truncate);\n if (!lineNum) {\n info(`${this.y}-${this.x}: ${this.rowSpan - lineNum}x${this.colSpan} Cell ${content}`);\n } else {\n // debug(`${lineNum}-${this.x}: 1x${this.colSpan} RowSpanCell ${content}`);\n }\n let padLen = Math.max(this.height - this.lines.length, 0);\n let padTop;\n switch (this.vAlign) {\n case 'center':\n padTop = Math.ceil(padLen / 2);\n break;\n case 'bottom':\n padTop = padLen;\n break;\n default:\n padTop = 0;\n }\n if (lineNum < padTop || lineNum >= padTop + this.lines.length) {\n return this.drawEmpty(this.drawRight, spanningCell);\n }\n let forceTruncation = this.lines.length > this.height && lineNum + 1 >= this.height;\n return this.drawLine(lineNum - padTop, this.drawRight, forceTruncation, spanningCell);\n }\n\n /**\n * Renders the top line of the cell.\n * @param drawRight - true if this method should render the right edge of the cell.\n * @returns {String}\n */\n drawTop(drawRight) {\n let content = [];\n if (this.cells) {\n //TODO: cells should always exist - some tests don't fill it in though\n this.widths.forEach(function (width, index) {\n content.push(this._topLeftChar(index));\n content.push(utils.repeat(this.chars[this.y == 0 ? 'top' : 'mid'], width));\n }, this);\n } else {\n content.push(this._topLeftChar(0));\n content.push(utils.repeat(this.chars[this.y == 0 ? 'top' : 'mid'], this.width));\n }\n if (drawRight) {\n content.push(this.chars[this.y == 0 ? 'topRight' : 'rightMid']);\n }\n return this.wrapWithStyleColors('border', content.join(''));\n }\n\n _topLeftChar(offset) {\n let x = this.x + offset;\n let leftChar;\n if (this.y == 0) {\n leftChar = x == 0 ? 'topLeft' : offset == 0 ? 'topMid' : 'top';\n } else {\n if (x == 0) {\n leftChar = 'leftMid';\n } else {\n leftChar = offset == 0 ? 'midMid' : 'bottomMid';\n if (this.cells) {\n //TODO: cells should always exist - some tests don't fill it in though\n let spanAbove = this.cells[this.y - 1][x] instanceof Cell.ColSpanCell;\n if (spanAbove) {\n leftChar = offset == 0 ? 'topMid' : 'mid';\n }\n if (offset == 0) {\n let i = 1;\n while (this.cells[this.y][x - i] instanceof Cell.ColSpanCell) {\n i++;\n }\n if (this.cells[this.y][x - i] instanceof Cell.RowSpanCell) {\n leftChar = 'leftMid';\n }\n }\n }\n }\n }\n return this.chars[leftChar];\n }\n\n wrapWithStyleColors(styleProperty, content) {\n if (this[styleProperty] && this[styleProperty].length) {\n try {\n let colors = require('@colors/colors/safe');\n for (let i = this[styleProperty].length - 1; i >= 0; i--) {\n colors = colors[this[styleProperty][i]];\n }\n return colors(content);\n } catch (e) {\n return content;\n }\n } else {\n return content;\n }\n }\n\n /**\n * Renders a line of text.\n * @param lineNum - Which line of text to render. This is not necessarily the line within the cell.\n * There may be top-padding above the first line of text.\n * @param drawRight - true if this method should render the right edge of the cell.\n * @param forceTruncationSymbol - `true` if the rendered text should end with the truncation symbol even\n * if the text fits. This is used when the cell is vertically truncated. If `false` the text should\n * only include the truncation symbol if the text will not fit horizontally within the cell width.\n * @param spanningCell - a number of if being called from a RowSpanCell. (how many rows below). otherwise undefined.\n * @returns {String}\n */\n drawLine(lineNum, drawRight, forceTruncationSymbol, spanningCell) {\n let left = this.chars[this.x == 0 ? 'left' : 'middle'];\n if (this.x && spanningCell && this.cells) {\n let cellLeft = this.cells[this.y + spanningCell][this.x - 1];\n while (cellLeft instanceof ColSpanCell) {\n cellLeft = this.cells[cellLeft.y][cellLeft.x - 1];\n }\n if (!(cellLeft instanceof RowSpanCell)) {\n left = this.chars['rightMid'];\n }\n }\n let leftPadding = utils.repeat(' ', this.paddingLeft);\n let right = drawRight ? this.chars['right'] : '';\n let rightPadding = utils.repeat(' ', this.paddingRight);\n let line = this.lines[lineNum];\n let len = this.width - (this.paddingLeft + this.paddingRight);\n if (forceTruncationSymbol) line += this.truncate || '…';\n let content = utils.truncate(line, len, this.truncate);\n content = utils.pad(content, len, ' ', this.hAlign);\n content = leftPadding + content + rightPadding;\n return this.stylizeLine(left, content, right);\n }\n\n stylizeLine(left, content, right) {\n left = this.wrapWithStyleColors('border', left);\n right = this.wrapWithStyleColors('border', right);\n if (this.y === 0) {\n content = this.wrapWithStyleColors('head', content);\n }\n return left + content + right;\n }\n\n /**\n * Renders the bottom line of the cell.\n * @param drawRight - true if this method should render the right edge of the cell.\n * @returns {String}\n */\n drawBottom(drawRight) {\n let left = this.chars[this.x == 0 ? 'bottomLeft' : 'bottomMid'];\n let content = utils.repeat(this.chars.bottom, this.width);\n let right = drawRight ? this.chars['bottomRight'] : '';\n return this.wrapWithStyleColors('border', left + content + right);\n }\n\n /**\n * Renders a blank line of text within the cell. Used for top and/or bottom padding.\n * @param drawRight - true if this method should render the right edge of the cell.\n * @param spanningCell - a number of if being called from a RowSpanCell. (how many rows below). otherwise undefined.\n * @returns {String}\n */\n drawEmpty(drawRight, spanningCell) {\n let left = this.chars[this.x == 0 ? 'left' : 'middle'];\n if (this.x && spanningCell && this.cells) {\n let cellLeft = this.cells[this.y + spanningCell][this.x - 1];\n while (cellLeft instanceof ColSpanCell) {\n cellLeft = this.cells[cellLeft.y][cellLeft.x - 1];\n }\n if (!(cellLeft instanceof RowSpanCell)) {\n left = this.chars['rightMid'];\n }\n }\n let right = drawRight ? this.chars['right'] : '';\n let content = utils.repeat(' ', this.width);\n return this.stylizeLine(left, content, right);\n }\n}\n\nclass ColSpanCell {\n /**\n * A Cell that doesn't do anything. It just draws empty lines.\n * Used as a placeholder in column spanning.\n * @constructor\n */\n constructor() {}\n\n draw(lineNum) {\n if (typeof lineNum === 'number') {\n debug(`${this.y}-${this.x}: 1x1 ColSpanCell`);\n }\n return '';\n }\n\n init() {}\n\n mergeTableOptions() {}\n}\n\nclass RowSpanCell {\n /**\n * A placeholder Cell for a Cell that spans multiple rows.\n * It delegates rendering to the original cell, but adds the appropriate offset.\n * @param originalCell\n * @constructor\n */\n constructor(originalCell) {\n this.originalCell = originalCell;\n }\n\n init(tableOptions) {\n let y = this.y;\n let originalY = this.originalCell.y;\n this.cellOffset = y - originalY;\n this.offset = findDimension(tableOptions.rowHeights, originalY, this.cellOffset);\n }\n\n draw(lineNum) {\n if (lineNum == 'top') {\n return this.originalCell.draw(this.offset, this.cellOffset);\n }\n if (lineNum == 'bottom') {\n return this.originalCell.draw('bottom');\n }\n debug(`${this.y}-${this.x}: 1x${this.colSpan} RowSpanCell for ${this.originalCell.content}`);\n return this.originalCell.draw(this.offset + 1 + lineNum);\n }\n\n mergeTableOptions() {}\n}\n\nfunction firstDefined(...args) {\n return args.filter((v) => v !== undefined && v !== null).shift();\n}\n\n// HELPER FUNCTIONS\nfunction setOption(objA, objB, nameB, targetObj) {\n let nameA = nameB.split('-');\n if (nameA.length > 1) {\n nameA[1] = nameA[1].charAt(0).toUpperCase() + nameA[1].substr(1);\n nameA = nameA.join('');\n targetObj[nameA] = firstDefined(objA[nameA], objA[nameB], objB[nameA], objB[nameB]);\n } else {\n targetObj[nameB] = firstDefined(objA[nameB], objB[nameB]);\n }\n}\n\nfunction findDimension(dimensionTable, startingIndex, span) {\n let ret = dimensionTable[startingIndex];\n for (let i = 1; i < span; i++) {\n ret += 1 + dimensionTable[startingIndex + i];\n }\n return ret;\n}\n\nfunction sumPlusOne(a, b) {\n return a + b + 1;\n}\n\nlet CHAR_NAMES = [\n 'top',\n 'top-mid',\n 'top-left',\n 'top-right',\n 'bottom',\n 'bottom-mid',\n 'bottom-left',\n 'bottom-right',\n 'left',\n 'left-mid',\n 'mid',\n 'mid-mid',\n 'right',\n 'right-mid',\n 'middle',\n];\n\nmodule.exports = Cell;\nmodule.exports.ColSpanCell = ColSpanCell;\nmodule.exports.RowSpanCell = RowSpanCell;\n","const { warn, debug } = require('./debug');\nconst Cell = require('./cell');\nconst { ColSpanCell, RowSpanCell } = Cell;\n\n(function () {\n function next(alloc, col) {\n if (alloc[col] > 0) {\n return next(alloc, col + 1);\n }\n return col;\n }\n\n function layoutTable(table) {\n let alloc = {};\n table.forEach(function (row, rowIndex) {\n let col = 0;\n row.forEach(function (cell) {\n cell.y = rowIndex;\n // Avoid erroneous call to next() on first row\n cell.x = rowIndex ? next(alloc, col) : col;\n const rowSpan = cell.rowSpan || 1;\n const colSpan = cell.colSpan || 1;\n if (rowSpan > 1) {\n for (let cs = 0; cs < colSpan; cs++) {\n alloc[cell.x + cs] = rowSpan;\n }\n }\n col = cell.x + colSpan;\n });\n Object.keys(alloc).forEach((idx) => {\n alloc[idx]--;\n if (alloc[idx] < 1) delete alloc[idx];\n });\n });\n }\n\n function maxWidth(table) {\n let mw = 0;\n table.forEach(function (row) {\n row.forEach(function (cell) {\n mw = Math.max(mw, cell.x + (cell.colSpan || 1));\n });\n });\n return mw;\n }\n\n function maxHeight(table) {\n return table.length;\n }\n\n function cellsConflict(cell1, cell2) {\n let yMin1 = cell1.y;\n let yMax1 = cell1.y - 1 + (cell1.rowSpan || 1);\n let yMin2 = cell2.y;\n let yMax2 = cell2.y - 1 + (cell2.rowSpan || 1);\n let yConflict = !(yMin1 > yMax2 || yMin2 > yMax1);\n\n let xMin1 = cell1.x;\n let xMax1 = cell1.x - 1 + (cell1.colSpan || 1);\n let xMin2 = cell2.x;\n let xMax2 = cell2.x - 1 + (cell2.colSpan || 1);\n let xConflict = !(xMin1 > xMax2 || xMin2 > xMax1);\n\n return yConflict && xConflict;\n }\n\n function conflictExists(rows, x, y) {\n let i_max = Math.min(rows.length - 1, y);\n let cell = { x: x, y: y };\n for (let i = 0; i <= i_max; i++) {\n let row = rows[i];\n for (let j = 0; j < row.length; j++) {\n if (cellsConflict(cell, row[j])) {\n return true;\n }\n }\n }\n return false;\n }\n\n function allBlank(rows, y, xMin, xMax) {\n for (let x = xMin; x < xMax; x++) {\n if (conflictExists(rows, x, y)) {\n return false;\n }\n }\n return true;\n }\n\n function addRowSpanCells(table) {\n table.forEach(function (row, rowIndex) {\n row.forEach(function (cell) {\n for (let i = 1; i < cell.rowSpan; i++) {\n let rowSpanCell = new RowSpanCell(cell);\n rowSpanCell.x = cell.x;\n rowSpanCell.y = cell.y + i;\n rowSpanCell.colSpan = cell.colSpan;\n insertCell(rowSpanCell, table[rowIndex + i]);\n }\n });\n });\n }\n\n function addColSpanCells(cellRows) {\n for (let rowIndex = cellRows.length - 1; rowIndex >= 0; rowIndex--) {\n let cellColumns = cellRows[rowIndex];\n for (let columnIndex = 0; columnIndex < cellColumns.length; columnIndex++) {\n let cell = cellColumns[columnIndex];\n for (let k = 1; k < cell.colSpan; k++) {\n let colSpanCell = new ColSpanCell();\n colSpanCell.x = cell.x + k;\n colSpanCell.y = cell.y;\n cellColumns.splice(columnIndex + 1, 0, colSpanCell);\n }\n }\n }\n }\n\n function insertCell(cell, row) {\n let x = 0;\n while (x < row.length && row[x].x < cell.x) {\n x++;\n }\n row.splice(x, 0, cell);\n }\n\n function fillInTable(table) {\n let h_max = maxHeight(table);\n let w_max = maxWidth(table);\n debug(`Max rows: ${h_max}; Max cols: ${w_max}`);\n for (let y = 0; y < h_max; y++) {\n for (let x = 0; x < w_max; x++) {\n if (!conflictExists(table, x, y)) {\n let opts = { x: x, y: y, colSpan: 1, rowSpan: 1 };\n x++;\n while (x < w_max && !conflictExists(table, x, y)) {\n opts.colSpan++;\n x++;\n }\n let y2 = y + 1;\n while (y2 < h_max && allBlank(table, y2, opts.x, opts.x + opts.colSpan)) {\n opts.rowSpan++;\n y2++;\n }\n let cell = new Cell(opts);\n cell.x = opts.x;\n cell.y = opts.y;\n warn(`Missing cell at ${cell.y}-${cell.x}.`);\n insertCell(cell, table[y]);\n }\n }\n }\n }\n\n function generateCells(rows) {\n return rows.map(function (row) {\n if (!Array.isArray(row)) {\n let key = Object.keys(row)[0];\n row = row[key];\n if (Array.isArray(row)) {\n row = row.slice();\n row.unshift(key);\n } else {\n row = [key, row];\n }\n }\n return row.map(function (cell) {\n return new Cell(cell);\n });\n });\n }\n\n function makeTableLayout(rows) {\n let cellRows = generateCells(rows);\n layoutTable(cellRows);\n fillInTable(cellRows);\n addRowSpanCells(cellRows);\n addColSpanCells(cellRows);\n return cellRows;\n }\n\n module.exports = {\n makeTableLayout: makeTableLayout,\n layoutTable: layoutTable,\n addRowSpanCells: addRowSpanCells,\n maxWidth: maxWidth,\n fillInTable: fillInTable,\n computeWidths: makeComputeWidths('colSpan', 'desiredWidth', 'x', 1),\n computeHeights: makeComputeWidths('rowSpan', 'desiredHeight', 'y', 1),\n };\n})();\n\nfunction makeComputeWidths(colSpan, desiredWidth, x, forcedMin) {\n return function (vals, table) {\n let result = [];\n let spanners = [];\n let auto = {};\n table.forEach(function (row) {\n row.forEach(function (cell) {\n if ((cell[colSpan] || 1) > 1) {\n spanners.push(cell);\n } else {\n result[cell[x]] = Math.max(result[cell[x]] || 0, cell[desiredWidth] || 0, forcedMin);\n }\n });\n });\n\n vals.forEach(function (val, index) {\n if (typeof val === 'number') {\n result[index] = val;\n }\n });\n\n //spanners.forEach(function(cell){\n for (let k = spanners.length - 1; k >= 0; k--) {\n let cell = spanners[k];\n let span = cell[colSpan];\n let col = cell[x];\n let existingWidth = result[col];\n let editableCols = typeof vals[col] === 'number' ? 0 : 1;\n if (typeof existingWidth === 'number') {\n for (let i = 1; i < span; i++) {\n existingWidth += 1 + result[col + i];\n if (typeof vals[col + i] !== 'number') {\n editableCols++;\n }\n }\n } else {\n existingWidth = desiredWidth === 'desiredWidth' ? cell.desiredWidth - 1 : 1;\n if (!auto[col] || auto[col] < existingWidth) {\n auto[col] = existingWidth;\n }\n }\n\n if (cell[desiredWidth] > existingWidth) {\n let i = 0;\n while (editableCols > 0 && cell[desiredWidth] > existingWidth) {\n if (typeof vals[col + i] !== 'number') {\n let dif = Math.round((cell[desiredWidth] - existingWidth) / editableCols);\n existingWidth += dif;\n result[col + i] += dif;\n editableCols--;\n }\n i++;\n }\n }\n }\n\n Object.assign(vals, result, auto);\n for (let j = 0; j < vals.length; j++) {\n vals[j] = Math.max(forcedMin, vals[j] || 0);\n }\n };\n}\n","const debug = require('./debug');\nconst utils = require('./utils');\nconst tableLayout = require('./layout-manager');\n\nclass Table extends Array {\n constructor(opts) {\n super();\n\n const options = utils.mergeOptions(opts);\n Object.defineProperty(this, 'options', {\n value: options,\n enumerable: options.debug,\n });\n\n if (options.debug) {\n switch (typeof options.debug) {\n case 'boolean':\n debug.setDebugLevel(debug.WARN);\n break;\n case 'number':\n debug.setDebugLevel(options.debug);\n break;\n case 'string':\n debug.setDebugLevel(parseInt(options.debug, 10));\n break;\n default:\n debug.setDebugLevel(debug.WARN);\n debug.warn(`Debug option is expected to be boolean, number, or string. Received a ${typeof options.debug}`);\n }\n Object.defineProperty(this, 'messages', {\n get() {\n return debug.debugMessages();\n },\n });\n }\n }\n\n toString() {\n let array = this;\n let headersPresent = this.options.head && this.options.head.length;\n if (headersPresent) {\n array = [this.options.head];\n if (this.length) {\n array.push.apply(array, this);\n }\n } else {\n this.options.style.head = [];\n }\n\n let cells = tableLayout.makeTableLayout(array);\n\n cells.forEach(function (row) {\n row.forEach(function (cell) {\n cell.mergeTableOptions(this.options, cells);\n }, this);\n }, this);\n\n tableLayout.computeWidths(this.options.colWidths, cells);\n tableLayout.computeHeights(this.options.rowHeights, cells);\n\n cells.forEach(function (row) {\n row.forEach(function (cell) {\n cell.init(this.options);\n }, this);\n }, this);\n\n let result = [];\n\n for (let rowIndex = 0; rowIndex < cells.length; rowIndex++) {\n let row = cells[rowIndex];\n let heightOfRow = this.options.rowHeights[rowIndex];\n\n if (rowIndex === 0 || !this.options.style.compact || (rowIndex == 1 && headersPresent)) {\n doDraw(row, 'top', result);\n }\n\n for (let lineNum = 0; lineNum < heightOfRow; lineNum++) {\n doDraw(row, lineNum, result);\n }\n\n if (rowIndex + 1 == cells.length) {\n doDraw(row, 'bottom', result);\n }\n }\n\n return result.join('\\n');\n }\n\n get width() {\n let str = this.toString().split('\\n');\n return str[0].length;\n }\n}\n\nTable.reset = () => debug.reset();\n\nfunction doDraw(row, lineNum, result) {\n let line = [];\n row.forEach(function (cell) {\n line.push(cell.draw(lineNum));\n });\n let str = line.join('');\n if (str.length) result.push(str);\n}\n\nmodule.exports = Table;\n","module.exports = require('./src/table');","let p = process || {}, argv = p.argv || [], env = p.env || {}\nlet isColorSupported =\n\t!(!!env.NO_COLOR || argv.includes(\"--no-color\")) &&\n\t(!!env.FORCE_COLOR || argv.includes(\"--color\") || p.platform === \"win32\" || ((p.stdout || {}).isTTY && env.TERM !== \"dumb\") || !!env.CI)\n\nlet formatter = (open, close, replace = open) =>\n\tinput => {\n\t\tlet string = \"\" + input, index = string.indexOf(close, open.length)\n\t\treturn ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close\n\t}\n\nlet replaceClose = (string, close, replace, index) => {\n\tlet result = \"\", cursor = 0\n\tdo {\n\t\tresult += string.substring(cursor, index) + replace\n\t\tcursor = index + close.length\n\t\tindex = string.indexOf(close, cursor)\n\t} while (~index)\n\treturn result + string.substring(cursor)\n}\n\nlet createColors = (enabled = isColorSupported) => {\n\tlet f = enabled ? formatter : () => String\n\treturn {\n\t\tisColorSupported: enabled,\n\t\treset: f(\"\\x1b[0m\", \"\\x1b[0m\"),\n\t\tbold: f(\"\\x1b[1m\", \"\\x1b[22m\", \"\\x1b[22m\\x1b[1m\"),\n\t\tdim: f(\"\\x1b[2m\", \"\\x1b[22m\", \"\\x1b[22m\\x1b[2m\"),\n\t\titalic: f(\"\\x1b[3m\", \"\\x1b[23m\"),\n\t\tunderline: f(\"\\x1b[4m\", \"\\x1b[24m\"),\n\t\tinverse: f(\"\\x1b[7m\", \"\\x1b[27m\"),\n\t\thidden: f(\"\\x1b[8m\", \"\\x1b[28m\"),\n\t\tstrikethrough: f(\"\\x1b[9m\", \"\\x1b[29m\"),\n\n\t\tblack: f(\"\\x1b[30m\", \"\\x1b[39m\"),\n\t\tred: f(\"\\x1b[31m\", \"\\x1b[39m\"),\n\t\tgreen: f(\"\\x1b[32m\", \"\\x1b[39m\"),\n\t\tyellow: f(\"\\x1b[33m\", \"\\x1b[39m\"),\n\t\tblue: f(\"\\x1b[34m\", \"\\x1b[39m\"),\n\t\tmagenta: f(\"\\x1b[35m\", \"\\x1b[39m\"),\n\t\tcyan: f(\"\\x1b[36m\", \"\\x1b[39m\"),\n\t\twhite: f(\"\\x1b[37m\", \"\\x1b[39m\"),\n\t\tgray: f(\"\\x1b[90m\", \"\\x1b[39m\"),\n\n\t\tbgBlack: f(\"\\x1b[40m\", \"\\x1b[49m\"),\n\t\tbgRed: f(\"\\x1b[41m\", \"\\x1b[49m\"),\n\t\tbgGreen: f(\"\\x1b[42m\", \"\\x1b[49m\"),\n\t\tbgYellow: f(\"\\x1b[43m\", \"\\x1b[49m\"),\n\t\tbgBlue: f(\"\\x1b[44m\", \"\\x1b[49m\"),\n\t\tbgMagenta: f(\"\\x1b[45m\", \"\\x1b[49m\"),\n\t\tbgCyan: f(\"\\x1b[46m\", \"\\x1b[49m\"),\n\t\tbgWhite: f(\"\\x1b[47m\", \"\\x1b[49m\"),\n\n\t\tblackBright: f(\"\\x1b[90m\", \"\\x1b[39m\"),\n\t\tredBright: f(\"\\x1b[91m\", \"\\x1b[39m\"),\n\t\tgreenBright: f(\"\\x1b[92m\", \"\\x1b[39m\"),\n\t\tyellowBright: f(\"\\x1b[93m\", \"\\x1b[39m\"),\n\t\tblueBright: f(\"\\x1b[94m\", \"\\x1b[39m\"),\n\t\tmagentaBright: f(\"\\x1b[95m\", \"\\x1b[39m\"),\n\t\tcyanBright: f(\"\\x1b[96m\", \"\\x1b[39m\"),\n\t\twhiteBright: f(\"\\x1b[97m\", \"\\x1b[39m\"),\n\n\t\tbgBlackBright: f(\"\\x1b[100m\", \"\\x1b[49m\"),\n\t\tbgRedBright: f(\"\\x1b[101m\", \"\\x1b[49m\"),\n\t\tbgGreenBright: f(\"\\x1b[102m\", \"\\x1b[49m\"),\n\t\tbgYellowBright: f(\"\\x1b[103m\", \"\\x1b[49m\"),\n\t\tbgBlueBright: f(\"\\x1b[104m\", \"\\x1b[49m\"),\n\t\tbgMagentaBright: f(\"\\x1b[105m\", \"\\x1b[49m\"),\n\t\tbgCyanBright: f(\"\\x1b[106m\", \"\\x1b[49m\"),\n\t\tbgWhiteBright: f(\"\\x1b[107m\", \"\\x1b[49m\"),\n\t}\n}\n\nmodule.exports = createColors()\nmodule.exports.createColors = createColors\n","// mu — the log surface, as a thin shim over the **ops log**.\n//\n// @deprecated — v2-log-verb replaces this module. v9 dropped the\n// `agent_logs` table; `ops` is now the single append-only record of\n// every change (VISION.md § 2b). Rather than rewrite ~25 consumers in\n// the schema commit, this module keeps its legacy signatures\n// (appendLog / listLogs / latestSeq / emitEvent) and reads and writes\n// `ops` rows underneath. v2-capture makes triggers the real writers\n// and v2-log-verb re-renders `mu log` from intents; both delete\n// chunks of this file.\n//\n// Shim mapping (legacy log row -> op):\n// kind -> ops.entity ('message' | 'event' | ...)\n// source -> ops.actor\n// workstream -> ops.key (natural key; '' = machine-wide)\n// payload -> ops.payload (raw text, not JSON, until v2-capture)\n// seq -> ops.seq (same AUTOINCREMENT cursor semantics)\n//\n// `ops.hlc` is now a REAL HLC minted by `nextHlc` (src/hlc.ts). The old\n// placeholder `<iso>|<uuid>` is gone: `parseHlc` deliberately rejects\n// that shape as a tripwire, so leaving it would have failed loudly the\n// moment anything downstream read the log in HLC order.\n//\n// `group_id` is still a fresh uuid per entry rather than the ambient\n// **op context** group. That is correct for this module's remaining\n// callers, which are log APPENDS (`mu log \"<text>\"`, event breadcrumbs) —\n// each is its own user-visible action, not part of a row-mutation\n// group. Rows written through the capture triggers get the ambient\n// group; these are hand-written log lines, not captured mutations.\n\nimport { randomUUID } from \"node:crypto\";\nimport { type Db, SYNCED_ENTITIES } from \"./db.js\";\nimport { nextHlc } from \"./hlc.js\";\nimport { intentSpellings } from \"./legacy-ops.js\";\nimport type { HasNextSteps, NextStep } from \"./output.js\";\n\nexport type LogKind = \"message\" | \"event\" | \"broadcast\" | string;\n\nexport interface LogRow {\n /** Monotonic AUTOINCREMENT id. Use as the cursor for `--since`. */\n seq: number;\n /** Workstream this entry belongs to, or `null` for machine-wide. */\n workstreamName: string | null;\n /** Free TEXT: agent name, \"system\", \"user\", or anything a caller picks.\n * Captured ops that ran outside any actor context have no actor, and\n * render as \"system\" rather than the string \"null\". */\n source: string;\n /** Structured intent ('task.close', 'agent.spawn', ...). Null only for\n * operator-authored prose lines (`mu log \"<text>\"` / a `--kind` ledger),\n * which name no state change. The formatter in src/log-render.ts\n * renders from this — never from the payload text. */\n intent: string | null;\n /** Undo group: every op of one operator action shares it. Surfaced so\n * `mu log` can print it and `mu log --group <id>` can filter to it\n * (undo discoverability). */\n group: string;\n /** 'put' (semantic partial update) or 'del' (tombstone). The formatter\n * needs it to tell \"edge removed\" from \"row touched\". */\n op: string;\n /** Free TEXT: \"message\" (default), \"event\" (auto state changes),\n * \"broadcast\" (explicit cross-agent), or any caller-defined value. */\n kind: LogKind;\n /** Free utf-8 string. May be JSON if the kind suggests structure. */\n payload: string;\n /** ISO 8601 timestamp set at insert time. */\n createdAt: string;\n}\n\ninterface RawLogRow {\n seq: number;\n /** `ops.key` verbatim (the natural key). '' means machine-wide. */\n workstream: string | null;\n /** `ops.actor`, which IS nullable: a captured op outside any actor\n * context has none. Normalised in `rowFromDb`. */\n source: string | null;\n intent: string | null;\n group_id: string;\n op: string;\n kind: string;\n payload: string;\n created_at: string;\n}\n\n/** SELECT clause mapping op columns back onto the legacy log row shape.\n * `ops.key` already holds the operator-facing workstream name (the\n * natural key), so there is no join to do; '' means machine-wide and\n * is normalised back to NULL in `rowFromDb`. */\nconst SELECT_LOG_COLS = `\n l.seq AS seq,\n l.key AS workstream,\n l.actor AS source,\n l.intent AS intent,\n l.group_id AS group_id,\n l.op AS op,\n l.entity AS kind,\n l.payload AS payload,\n l.created_at AS created_at\n`;\n\nconst LOG_FROM_JOIN = \"FROM ops l\";\n\n// WHY THERE IS NO LONGER AN ENTITY FILTER (v2-retire-log-shim)\n//\n// v2-capture briefly left `ops` holding the SAME change twice: once as\n// a typed op from the trigger (intent='task.update', key='demo/t1',\n// JSON payload) and once as a prose breadcrumb from `emitEvent`\n// (intent=NULL, key='demo', free text). A filter pinning `mu log` to\n// the prose entities was needed so a single `task add` did not surface\n// twice.\n//\n// The duplicate prose emits are gone, so the filter's reason to exist\n// went with them. `mu log` now reads EVERY op, which is what\n// docs/VOCABULARY.md § log entry has always claimed (\"a rendered op...\n// not a distinct table\"). Payloads for captured ops are still raw JSON;\n// v2-log-verb renders prose from `intent`. Uglier for now, honest, and\n// no longer lossy: a peer's synced ops appear in `mu log` too, which\n// prose events could never do (they were machine-local by accident of\n// entity='event' not being in SYNCED_ENTITIES).\n//\n// `latestSeq` deliberately shares this same \"no filter\" shape. When the\n// two disagreed, `mu log --tail` started its cursor past rows the\n// non-tail view had shown and silently skipped them.\n\n/** Scope a log query to one workstream.\n *\n * `ops.key` is the NATURAL key, so it is the bare workstream name for\n * workstream-scoped rows ('demo') and a qualified ref for everything\n * inside it ('demo/t1', 'demo/t1#1', 'demo/t2->demo/t1'). Matching\n * only `key = 'demo'` would therefore hide every task, note, and edge\n * op in the workstream — which is most of them. Exact-or-prefix is the\n * smallest predicate that reads \"belongs to this workstream\". */\nexport function workstreamScopeSql(column = \"l.key\"): string {\n return `(${column} = ? OR ${column} LIKE ? ESCAPE '\\\\')`;\n}\n\n/** Bind params for `workstreamScopeSql`. The LIKE pattern escapes the\n * operator-supplied name so a workstream containing '%' or '_' cannot\n * widen the match. */\nexport function workstreamScopeParams(workstream: string): [string, string] {\n const escaped = workstream.replace(/[\\\\%_]/g, (c) => `\\\\${c}`);\n return [workstream, `${escaped}/%`];\n}\n\n/** Every distinct `ops.entity`, read by skip-scanning idx_ops_entity_key\n * (one seek per entity, ~a dozen). `entity IN (…) AND key …` lets SQLite\n * seek (entity, key) without knowing the entity: the only index on key\n * leads with entity, and a bare `key` predicate scans all of ops. */\nexport const OPS_ENTITIES_SQL = `WITH RECURSIVE e(entity) AS (\n SELECT MIN(entity) FROM ops\n UNION ALL\n SELECT (SELECT MIN(entity) FROM ops WHERE entity > e.entity) FROM e WHERE e.entity IS NOT NULL\n ) SELECT entity FROM e WHERE entity IS NOT NULL`;\n\n/** Index-seekable superset of `workstreamScopeSql`: keys from '<ws>' up\n * to (not including) '<ws>0', '0' being the byte after '/'. AND it with\n * the exact-or-LIKE scope, never use it alone. */\nconst INDEXED_SCOPE_SQL = `l.entity IN (${OPS_ENTITIES_SQL}) AND l.key >= ? AND l.key < ?`;\n\n/** Above this many ops a workstream is \"busy\": its newest rows are\n * near the end of ops, so walking seq backwards finds them fast, while\n * the index seek would read and sort every one of its ops. Below it the\n * seek wins, and a quiet or unknown workstream no longer scans all of\n * ops looking for rows that are not there (f_ops_key_scan). */\nconst SMALL_SCOPE_OPS = 2000;\n\n/** Extra predicate + params that make a workstream-scoped ops read an\n * index seek, or null when the workstream is busy and the seq walk is\n * already cheap. The predicate only narrows to rows the scope already\n * matches, so the row set is unchanged. */\nfunction indexedScope(db: Db, workstream: string): { sql: string; params: string[] } | null {\n const params = [workstream, `${workstream}0`];\n const { n } = db\n .prepare(`SELECT COUNT(*) AS n FROM (SELECT 1 FROM ops l WHERE ${INDEXED_SCOPE_SQL} LIMIT ?)`)\n .get(...params, SMALL_SCOPE_OPS) as { n: number };\n return n < SMALL_SCOPE_OPS ? { sql: INDEXED_SCOPE_SQL, params } : null;\n}\n\n/** `workstreamScopeSql` (column `l.key`) plus, for a small workstream,\n * the indexed bound. Same row set, fewer rows visited. */\nexport function scopeFor(db: Db, workstream: string): { sql: string; params: string[] } {\n const scope = { sql: workstreamScopeSql(), params: workstreamScopeParams(workstream) };\n const indexed = indexedScope(db, workstream);\n if (indexed === null) return scope;\n return {\n sql: `${scope.sql} AND ${indexed.sql}`,\n params: [...scope.params, ...indexed.params],\n };\n}\n\n/** `workstreamScopeSql` limited to the newest SMALL_SCOPE_OPS ops: a\n * bounded seq-range read, enough for an active workstream's latest\n * rows. Callers that find too few fall back to `scopeFor`. */\nfunction recentScope(workstream: string): { sql: string; params: unknown[] } {\n return {\n sql: `${workstreamScopeSql()} AND l.seq > (SELECT COALESCE(MAX(seq), 0) FROM ops) - ?`,\n params: [...workstreamScopeParams(workstream), SMALL_SCOPE_OPS],\n };\n}\n\n/**\n * Hide parent-row TOUCH ops from the log surface.\n *\n * Adding a note or an edge bumps its task's `updated_at` so\n * `--sort recency` works. That UPDATE fires the tasks capture trigger,\n * producing a second op in the same group whose payload is ONLY\n * `updated_at` — no new information, and it renders as a duplicate of\n * the note/edge line the operator actually cares about. A `task note`\n * therefore appeared twice in `mu log`.\n *\n * These rows stay in `ops` (they are real state changes, and per-field\n * merge needs them); they are just not LOG LINES. The predicate is\n * shared by `listLogs` and `latestSeq` — those two MUST return the same\n * row set, or `--tail` starts its cursor past rows the non-tail view\n * already showed (hit in R4 and again in R7).\n *\n * `json_extract` is not used: SQLite's JSON1 is compiled in by default\n * for better-sqlite3, but a plain LENGTH test needs no extension and is\n * cheaper. A payload with only `updated_at` is always short.\n */\nconst TOUCH_OP_FILTER = `NOT (\n l.intent IS NOT NULL\n AND l.op = 'put'\n AND l.payload LIKE '{\"updated_at\":%'\n AND LENGTH(l.payload) < 45\n)`;\n\n/** Sentinel stored in `ops.key` for machine-wide entries (ops.key is\n * NOT NULL). Exported so the few call sites that query `ops` directly\n * agree with the shim. */\nexport const MACHINE_WIDE_KEY = \"\";\n\n// ─── group-id prefix resolution (shared) ──────────────────────────\n//\n// Group ids are uuids, which nobody types. `mu undo` prints 8-char\n// prefixes and accepts them, so `mu log --group` must too — otherwise the\n// documented workflow (`mu undo` to see the id → `mu log --group <id>` to\n// inspect it → `mu undo <id> --yes`) breaks in the middle, and it breaks\n// SILENTLY: an unmatched prefix returns zero rows, which reads as \"this\n// group did nothing\" rather than \"you gave me a prefix I ignored\".\n// (bug_group_id_prefix_asymmetry — found by following the workflow across\n// R9 and R10; each verb was self-consistent on its own.)\n//\n// This lives HERE, next to the ops reader, so both verbs share ONE\n// resolution rule. `src/undo.ts` delegates to it rather than keeping a\n// second copy. Same affordance git gives for abbreviated shas, and the\n// same shape as `src/tasks/id.ts`'s resolve-or-raise helpers.\n\n/** Raised when a group-id prefix matches more than one group.\n * Astronomically unlikely with uuids, but silently picking one of two\n * candidate groups to UNDO is not an acceptable failure mode. */\nexport class GroupIdAmbiguousError extends Error implements HasNextSteps {\n constructor(\n readonly prefix: string,\n readonly candidates: readonly string[],\n ) {\n super(\n `group id ${JSON.stringify(prefix)} is ambiguous: matches ${candidates.length} groups (${candidates\n .slice(0, 4)\n .map((c) => c.slice(0, 12))\n .join(\", \")}${candidates.length > 4 ? \", …\" : \"\"})`,\n );\n this.name = \"GroupIdAmbiguousError\";\n }\n\n errorNextSteps(): NextStep[] {\n return [\n { intent: \"List recent groups with their ids\", command: \"mu undo\" },\n {\n intent: \"Retry with more characters\",\n command: `mu log --group ${this.candidates[0] ?? \"<full-id>\"}`,\n },\n ];\n }\n}\n\n/**\n * Resolve a possibly-abbreviated group id to the full one.\n *\n * Returns null when nothing matches, so callers choose their own\n * not-found error (undo raises `UndoGroupNotFoundError`; `mu log`\n * filters to nothing but says so). Throws `GroupIdAmbiguousError` when a\n * prefix matches several groups — that is a genuine conflict the\n * operator must resolve, not something to guess at.\n *\n * An EXACT match always wins over prefix matching, so a full uuid can\n * never be shadowed by a longer id that happens to start with it.\n */\nexport function groupIdFromPrefix(db: Db, prefix: string): string | null {\n if (prefix === \"\") return null;\n const rows = db\n .prepare(\n // The range lets idx_ops_group seek; LIKE alone scanned it all.\n // char(0x10FFFF) sorts after any continuation of the prefix.\n `SELECT DISTINCT group_id AS groupId FROM ops\n WHERE group_id = @exact\n OR (group_id >= @exact AND group_id < @exact || char(1114111)\n AND group_id LIKE @prefix || '%' ESCAPE '\\\\')`,\n )\n .all({ exact: prefix, prefix: prefix.replace(/[\\\\%_]/g, (c) => `\\\\${c}`) }) as {\n groupId: string;\n }[];\n const exact = rows.find((r) => r.groupId === prefix);\n if (exact !== undefined) return exact.groupId;\n const first = rows[0];\n if (rows.length === 1 && first !== undefined) return first.groupId;\n if (rows.length === 0) return null;\n throw new GroupIdAmbiguousError(\n prefix,\n rows.map((r) => r.groupId),\n );\n}\n\n/** This machine's identity — the peer id every op is stamped with. */\nfunction machineId(db: Db): string {\n const row = db.prepare(\"SELECT machine_id FROM machine_identity WHERE id = 1\").get() as\n | { machine_id: string }\n | undefined;\n return row?.machine_id ?? \"unknown\";\n}\n\nfunction rowFromDb(row: RawLogRow): LogRow {\n return {\n seq: row.seq,\n workstreamName: row.workstream === MACHINE_WIDE_KEY ? null : row.workstream,\n source: row.source ?? \"system\",\n intent: row.intent,\n group: row.group_id,\n op: row.op,\n kind: row.kind,\n payload: row.payload,\n createdAt: row.created_at,\n };\n}\n\nexport interface AppendLogOptions {\n /** Workstream this entry belongs to. `null` for machine-wide. */\n workstream: string | null;\n /** Who emitted this. Agent name, \"system\", \"user\", or arbitrary. */\n source: string;\n /** Defaults to \"message\". */\n kind?: LogKind;\n /** Free utf-8. Multi-line allowed. */\n payload: string;\n /** Structured intent. Set by `emitEvent` for the local-only changes\n * no trigger can see. Stays null for operator-authored `mu log\n * write` lines, which are prose by nature and have no state change\n * to name. */\n intent?: string;\n}\n\n/** Kinds a log line may not use: the entities that sync AND project\n * into a portable table. A log line's kind is stored as `ops.entity`,\n * so `mu log \"x\" --kind task` wrote a prose op that sync, rebuild and\n * apply then read as a real task op (\"malformed task key\"), wedging\n * `mu rebuild` and every peer's ingest. 'message' syncs but projects\n * nowhere, so it stays allowed (it is the default). */\nconst RESERVED_LOG_KINDS: ReadonlySet<string> = new Set(\n SYNCED_ENTITIES.filter((e) => e !== \"message\"),\n);\n\n/** Raised by `appendLog` for a kind in RESERVED_LOG_KINDS. Usage lane\n * (exit 2): the operator picked a tag that names a projectable entity. */\nexport class LogKindReservedError extends Error implements HasNextSteps {\n override readonly name = \"LogKindReservedError\";\n constructor(readonly kind: string) {\n super(\n `--kind ${JSON.stringify(kind)} is reserved: ${[...RESERVED_LOG_KINDS].join(\", \")} name projectable op entities, and a log line under one would be synced and replayed as a real ${kind} change`,\n );\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Use a channel tag that names your ledger\",\n command: `mu log --kind ${this.kind}-log '<text>'`,\n },\n ];\n }\n}\n\n/**\n * Append a log entry. Returns the inserted row (with assigned `seq`).\n * Constant-time. Single INSERT; safe to call from any state-changing\n * verb without a transaction wrapper.\n */\nexport function appendLog(db: Db, opts: AppendLogOptions): LogRow {\n const kind = opts.kind ?? \"message\";\n if (RESERVED_LOG_KINDS.has(kind)) throw new LogKindReservedError(kind);\n const createdAt = new Date().toISOString();\n // `ops.key` is the NATURAL key, so the workstream NAME goes in\n // verbatim — no resolution, and the op stays readable after the\n // workstream is destroyed (which is the point of an ops log).\n const key = opts.workstream ?? MACHINE_WIDE_KEY;\n const group = randomUUID();\n const result = db\n .prepare(\n `INSERT INTO ops (hlc, machine_id, group_id, actor, intent, entity, key, op, payload, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, 'put', ?, ?)`,\n )\n .run(\n nextHlc(db),\n machineId(db),\n group,\n opts.source,\n opts.intent ?? null,\n kind,\n key,\n opts.payload,\n createdAt,\n );\n return {\n seq: Number(result.lastInsertRowid),\n workstreamName: opts.workstream,\n source: opts.source,\n intent: opts.intent ?? null,\n group,\n op: \"put\",\n kind,\n payload: opts.payload,\n createdAt,\n };\n}\n\nexport interface ListLogsOptions {\n /** Filter by workstream. `undefined` = every workstream + machine-wide.\n * `null` = ONLY machine-wide entries. */\n workstream?: string | null;\n /** Strictly > this seq. Use to resume a tail. */\n since?: number;\n /** Cap the result. With `since`, returns the FIRST N matching (oldest\n * first). Without `since`, returns the LAST N (most recent),\n * re-sorted oldest-first. */\n limit?: number;\n source?: string;\n /** Filter by `ops.entity` (the legacy `kind` column). */\n kind?: string;\n /** Filter by structured `ops.intent`, e.g. 'task.close'. */\n intent?: string;\n /** Filter to one undo group (`ops.group_id`). */\n group?: string;\n}\n\n/**\n * List log entries. Always returns oldest-first. Use `since` for\n * cursor-based reads (the canonical tail pattern); use `limit` alone\n * for \"show me the most recent N\" reads.\n */\nexport function listLogs(db: Db, opts: ListLogsOptions = {}): LogRow[] {\n const conditions: string[] = [];\n const params: unknown[] = [];\n\n if (opts.workstream === null) {\n conditions.push(\"l.key = ?\");\n params.push(MACHINE_WIDE_KEY);\n }\n if (opts.since !== undefined) {\n conditions.push(\"l.seq > ?\");\n params.push(opts.since);\n }\n if (opts.source === \"system\") {\n // rowFromDb renders a NULL actor as \"system\", so the filter must\n // match what the listing shows.\n conditions.push(\"(l.actor = ? OR l.actor IS NULL)\");\n params.push(opts.source);\n } else if (opts.source !== undefined) {\n conditions.push(\"l.actor = ?\");\n params.push(opts.source);\n }\n if (opts.kind !== undefined) {\n conditions.push(\"l.entity = ?\");\n params.push(opts.kind);\n }\n if (opts.intent !== undefined) {\n // Accept every historical spelling, so a renamed intent does not\n // truncate the user's history at the release boundary.\n const spellings = intentSpellings(opts.intent);\n conditions.push(`l.intent IN (${spellings.map(() => \"?\").join(\", \")})`);\n params.push(...spellings);\n }\n if (opts.group !== undefined) {\n conditions.push(\"l.group_id = ?\");\n params.push(opts.group);\n }\n // Same predicate as latestSeq — see TOUCH_OP_FILTER.\n conditions.push(TOUCH_OP_FILTER);\n const ws = opts.workstream ?? null;\n\n // Two query shapes:\n // - When `since` is set, ascending order is what we want directly.\n // - When `limit` is set without `since`, fetch the most-recent N\n // (descending) then reverse so the caller still sees oldest-first.\n if (opts.limit !== undefined && opts.since === undefined) {\n const limit = opts.limit;\n const newest = (scope: { sql: string; params: unknown[] }) =>\n db\n .prepare(\n `SELECT ${SELECT_LOG_COLS} ${LOG_FROM_JOIN} WHERE ${[scope.sql, ...conditions].join(\" AND \")} ORDER BY l.seq DESC LIMIT ?`,\n )\n .all(...scope.params, ...params, limit) as RawLogRow[];\n // An active workstream fills the limit from the newest ops; try\n // that cheap seq range first and fall back to scopeFor only when the\n // workstream is quiet. The first `limit` rows by seq DESC are the\n // same either way.\n let rowsDesc = newest(ws === null ? { sql: \"1\", params: [] } : recentScope(ws));\n if (ws !== null && rowsDesc.length < limit) rowsDesc = newest(scopeFor(db, ws));\n return rowsDesc.reverse().map(rowFromDb);\n }\n\n if (ws !== null) {\n const scope = scopeFor(db, ws);\n conditions.unshift(scope.sql);\n params.unshift(...scope.params);\n }\n const where = `WHERE ${conditions.join(\" AND \")}`;\n\n let sql = `SELECT ${SELECT_LOG_COLS} ${LOG_FROM_JOIN} ${where} ORDER BY l.seq ASC`;\n if (opts.limit !== undefined) {\n sql += \" LIMIT ?\";\n params.push(opts.limit);\n }\n const rows = db.prepare(sql).all(...params) as RawLogRow[];\n return rows.map(rowFromDb);\n}\n\n/**\n * Return the latest seq currently in the table (or 0 if empty). Used\n * by `mu log --tail` to start the cursor at \"now\" so the subscriber\n * only sees NEW entries unless they explicitly pass `--since 0`.\n */\nexport function latestSeq(db: Db, workstream?: string): number {\n // MUST stay consistent with listLogs' row set — this is the cursor\n // INTO it. When the two disagreed (a filter here that listLogs did\n // not apply, or vice versa) `--tail` started past rows the non-tail\n // view had already shown and silently skipped them.\n if (workstream === undefined) {\n const row = db.prepare(`SELECT MAX(seq) AS s FROM ops l WHERE ${TOUCH_OP_FILTER}`).get() as {\n s: number | null;\n };\n return row.s ?? 0;\n }\n const max = (scope: { sql: string; params: unknown[] }) =>\n (\n db\n .prepare(`SELECT MAX(seq) AS s FROM ops l WHERE ${scope.sql} AND ${TOUCH_OP_FILTER}`)\n .get(...scope.params) as { s: number | null }\n ).s;\n return max(recentScope(workstream)) ?? max(scopeFor(db, workstream)) ?? 0;\n}\n\n/**\n * Record a change that NO capture trigger can see.\n *\n * The triggers in src/capture.ts cover the four **portable** tables\n * (workstreams, tasks, task_edges, task_notes), so every task and\n * workstream mutation is already an op with a real `intent` and a real\n * natural key. Anything that mutates one of those tables must NOT call\n * this — that was the duplication v2-retire-log-shim deleted: 13 call\n * sites each writing a second, prose, intent-less copy of a change the\n * trigger had already captured properly.\n *\n * What legitimately remains is state that lives OUTSIDE those tables:\n *\n * agent.* spawn / close / free / adopt / kick — `agents` is\n * machine-local (it holds `pane_id`), so there is no\n * trigger and never will be.\n * workspace.* create / free / refresh — `vcs_workspaces`\n * is machine-local (absolute paths).\n * agent.stall a pure observation; nothing is mutated.\n *\n * `intent` is REQUIRED (and typed), not optional, because the whole\n * point is that these rows render through the same formatter as\n * captured ops. An intent-less op cannot be rendered without\n * prefix-matching prose, which is the brittleness\n * (`classifyEventVerb`, `CLAIM_EVENT_PREFIX`) the ops log deletes.\n *\n * These entities are deliberately NOT in SYNCED_ENTITIES: every one of\n * them describes something about THIS machine (a pane id, a filesystem\n * path) that is meaningless on a peer. They are still recorded, so\n * `mu log` and the TUI show them locally.\n */\nexport function emitEvent(\n db: Db,\n workstream: string | null,\n intent: LocalIntent,\n payload: string,\n source = \"system\",\n): void {\n appendLog(db, { workstream, source, kind: entityForIntent(intent), payload, intent });\n}\n\n/**\n * Intents for changes no trigger can capture. Closed union rather than\n * `string` so a typo is a compile error and the set stays auditable —\n * `mu log`'s formatter (v2-log-verb) switches on exactly these.\n */\nexport type LocalIntent =\n | \"agent.spawn\"\n | \"agent.spawn_failed\"\n | \"agent.close\"\n | \"agent.adopt\"\n | \"agent.kick\"\n | \"agent.send\"\n | \"agent.abort\"\n | \"agent.stall\"\n | \"workspace.create\"\n | \"workspace.free\"\n | \"workspace.refresh\";\n\n/** Entity for a local intent: the token before the dot. Keeps\n * `entity`/`intent` consistent by construction instead of asking each\n * call site to pass both and agree. */\nfunction entityForIntent(intent: LocalIntent): string {\n const dot = intent.indexOf(\".\");\n return dot === -1 ? intent : intent.slice(0, dot);\n}\n\n// ─── claim attribution ─────────────────────────────────────────────\n//\n// mu once stored claim attribution as PROSE and re-parsed it: a\n// tab-delimited `task.claim<TAB><id><TAB>actor=<a><TAB>...` prefix was\n// bolted onto the payload precisely because prefix-matching the prose\n// was brittle (review_code_last_claim_actor_brittle). Two helpers then\n// existed only to put that prefix on and take it back off.\n//\n// The ops log makes all of it unnecessary. `withOpContext` seeds\n// _op_ctx.actor, the capture trigger copies it into `ops.actor`, and\n// the intent is `task.claim`. So attribution is two indexed columns,\n// not a string to parse — including on the `--self` path, where\n// tasks.owner_id stays NULL by design and the payload therefore\n// CANNOT name the actor. Reading ops.actor is the whole fix.\n\n/** The most recent `task.claim` op for a task: its actor and when.\n *\n * `ops.key` is the natural key, so the task's own ops are keyed\n * '<ws>/<localId>' exactly — no LIKE, no wildcard escaping, and no\n * way for `foo` to cross-match `foo_2`. Unbounded by design: the old\n * limit=100 ceiling silently dropped attribution on long-lived\n * workstreams. */\nfunction lastClaimOp(\n db: Db,\n workstream: string,\n localId: string,\n): { actor: string | null; created_at: string } | null {\n const row = db\n .prepare(\n `SELECT actor, created_at FROM ops\n WHERE entity = 'task' AND key = ? AND intent = 'task.claim'\n ORDER BY seq DESC LIMIT 1`,\n )\n .get(`${workstream}/${localId}`) as { actor: string | null; created_at: string } | undefined;\n return row ?? null;\n}\n\n/**\n * Actor of the most recent claim of this task. Surfaces \"who is working\n * on this\" when `tasks.owner_id IS NULL` — the `--self` anonymous-claim\n * path. Null when the task was never claimed.\n */\nexport function lastClaimActor(db: Db, workstream: string, localId: string): string | null {\n return lastClaimOp(db, workstream, localId)?.actor ?? null;\n}\n\n/**\n * Find the `created_at` timestamp of the most recent claim of a task.\n *\n * Used by `mu task notes --since-claim` to slice the note timeline at\n * the most recent claim, so an operator dispatching a worker sees only\n * the post-claim notes (the spec was written before the claim; the\n * worker's progress lands after).\n *\n * Returns null when the task was never claimed — `--since-claim` then\n * degrades gracefully to no filter.\n */\nexport function lastClaimEventAt(db: Db, workstream: string, localId: string): string | null {\n return lastClaimOp(db, workstream, localId)?.created_at ?? null;\n}\n\n// ─── retired: prose verb classification ───────────────────────────────\n//\n// The old renderer needed EVENT_VERB_PREFIXES + classifyEventVerb + ClassifiedEvent +\n// logRowSubject to render a log line: every consumer prefix-matched a\n// payload's leading two words to find its verb, and CLAIM_EVENT_PREFIX\n// was bolted on because that matching kept breaking.\n//\n// v2-log-verb deletes all four. Rendering now reads `intent` (+ `key` +\n// named payload fields) in src/log-render.ts, which cannot be broken by\n// rewording a payload. If you find yourself wanting to string-match a\n// payload to decide what an op IS, that is the bug this removed.\n","// mu — shared multiplexer backend contracts and typed errors.\n//\n// A \"mux\" is the terminal multiplexer that owns panes. mu supports one\n// active backend per invocation, chosen by `detectMux()` in ./detect.js.\n// Everything backend-specific lives behind `MuxBackend`:\n//\n// - session / window / pane topology\n// - the send protocol (bracketed paste on tmux)\n// - scrollback capture\n// - PANE ID VALIDATION — tmux `%15` vs herdr `w1:p1`, which is why\n// there is no global pane-id regex\n// - ACTOR IDENTITY fallback — how to ask \"which agent is this pane?\"\n//\n// Same shape as src/vcs/: a types module, one file per impl, and an\n// index that dispatches. See docs/VOCABULARY.md § \"mux backend\".\n\nimport type { HasNextSteps, NextStep } from \"../output.js\";\n\n/** The multiplexers mu can drive. */\nexport type MuxBackendName = \"herdr\" | \"tmux\";\n\n/** Runtime states a mux backend can report directly for one pane. */\nexport type MuxPaneStatus = \"busy\" | \"needs_input\" | \"needs_permission\";\n\n// ─── Domain types ──────────────────────────────────────────────────────\n//\n// Deliberately narrow: these carry only the fields mu actually reads.\n// A backend that knows more about a pane keeps that to itself.\n\nexport interface MuxSession {\n name: string;\n}\n\nexport interface MuxWindow {\n /** Backend-specific window handle (tmux `@1`). */\n id: string;\n name: string;\n /** Session this window belongs to (only set by cross-session listings). */\n sessionName?: string;\n}\n\nexport interface MuxPane {\n /** Backend-specific stable pane id (tmux `%15`). Never a volatile index. */\n paneId: string;\n /** The agent's name, in mu's convention. */\n title: string;\n /** Current foreground command (e.g. \"claude\", \"node\", \"bash\"). */\n command: string;\n /** Window this pane lives in. Only set by cross-window listings. */\n windowId?: string;\n /** Session this pane lives in. Only set by cross-session listings. */\n sessionName?: string;\n}\n\nexport interface NewSessionOptions {\n detached?: boolean;\n windowName?: string;\n command?: string;\n /** Initial working directory for the first pane (`-c <path>`). */\n cwd?: string;\n /** Extra env vars to set in the new pane. On tmux this is `-e KEY=VALUE`\n * (tmux 3.0+), which sets the variable in the new pane's environment\n * without polluting the server's global env. */\n env?: Record<string, string>;\n}\n\nexport interface NewSessionWithPaneOptions {\n windowName: string;\n command: string;\n cwd?: string;\n detached?: boolean;\n /** Extra env vars to set in the new pane. */\n env?: Record<string, string>;\n}\n\nexport interface NewWindowOptions {\n /** Target session. Required if invoking outside an existing client. */\n session?: string;\n /** Window name. Maps to the agent's `tab:` value (or its name if no tab). */\n name: string;\n /** Command to run in the first pane. */\n command: string;\n /** If true, do not switch focus. Defaults to true. */\n detached?: boolean;\n /** Initial working directory (`-c <path>`). */\n cwd?: string;\n /** Extra env vars to set in the new pane. */\n env?: Record<string, string>;\n}\n\nexport interface SplitWindowOptions {\n /** Target window or pane (e.g. \":Backend\" or \"%15\"). */\n target: string;\n command: string;\n /** Horizontal split (side-by-side). Default true. */\n horizontal?: boolean;\n detached?: boolean;\n /** Initial working directory for the new pane (`-c <path>`). */\n cwd?: string;\n /** Extra env vars to set in the new pane. */\n env?: Record<string, string>;\n}\n\n/** Where an attach should land the user. */\nexport interface AttachTarget {\n /** Mux session name, e.g. `mu-auth`. */\n session: string;\n /** Window inside that session (the agent's `tab`, or its name). */\n window?: string;\n /** True when the caller is already inside a client of this mux, which\n * on tmux means `switch-client` rather than `attach-session`. */\n inside?: boolean;\n}\n\n/** One argv the caller may execute to hand the terminal to the mux. */\nexport interface MuxCommand {\n command: string;\n args: readonly string[];\n /** Best-effort step: a non-zero exit is not a failure of the attach\n * as a whole (tmux's post-attach `select-window`, for instance). */\n optional?: boolean;\n}\n\n/** What a backend can say about its own health. Deliberately DATA, not\n * prose: `mu doctor` owns all rendering (human and --json). */\nexport interface MuxHealth {\n /** Backend name, echoed so doctor can label the row. */\n name: MuxBackendName;\n /** True iff the backend answered a version probe. */\n ok: boolean;\n /** Version string as the backend reports it, or null when unreachable. */\n version: string | null;\n /** Ambient env facts this backend cares about, in display order\n * (tmux: $TMUX / $TMUX_PANE). Values are null when unset. */\n env: readonly { name: string; value: string | null }[];\n /** Remediation line shown when `ok` is false. */\n remediation: string;\n}\n\nexport interface SendOptions {\n /** Override the default delay between paste and Enter, in ms. */\n delayMs?: number;\n /**\n * Override the pre-send readiness budget, in ms. 0 disables the wait\n * AND the post-send submit verification.\n */\n readinessMs?: number;\n /** Called when the send could not be confirmed as submitted. */\n onUndelivered?: (warning: SendWarning) => void;\n}\n\n/** Why a send could not be confirmed as submitted. */\nexport interface SendWarning {\n paneId: string;\n /** 'paste-vanished' — pane looked calm, but the text stayed stranded\n * in the input box. 'busy-at-deadline' — pane never quiesced within\n * the budget and the text stayed stranded. */\n reason: \"busy-at-deadline\" | \"paste-vanished\";\n message: string;\n}\n\n/**\n * What `startAgentInPane` needs to know. mu has already resolved the\n * command it WOULD have run in a create-and-run backend; a backend that\n * starts agents itself needs both that string and the `--cli` key it came\n * from, because those select different routes (see the herdr impl).\n */\nexport interface StartAgentInPaneOptions {\n /** An existing pane, sitting at its interactive shell prompt. */\n paneId: string;\n /** mu's agent name. Backends with their own agent registry use it as\n * the mux-level handle too. */\n name: string;\n /** mu's `--cli` key, e.g. \"pi\". A backend that classifies agent kinds\n * natively maps this onto its own kind vocabulary. */\n cli: string;\n /** Fully resolved command string mu would otherwise have spawned. */\n command: string;\n /**\n * Where `command` came from. A backend that resolves the executable\n * ITSELF (rather than running the string mu hands it) must not silently\n * discard an operator's explicit choice, and needs to know which one it\n * is so the diagnostic can name the right thing to change:\n *\n * \"cli-key\" — just the `--cli` value; nothing to honour, proceed.\n * \"env\" — a `MU_<UPPER_CLI>_COMMAND` override.\n * \"explicit\" — an explicit `--command \"…\"`.\n */\n commandSource: \"cli-key\" | \"env\" | \"explicit\";\n}\n\nexport interface CaptureOptions {\n /**\n * Number of trailing lines to capture. Omitted = full scrollback.\n * 0 = visible pane only.\n */\n lines?: number;\n}\n\n// ─── Title parsing ───────────────────────────────────────────────\n\n/**\n * Extract the agent-name token from a (possibly composed) pane title.\n * mu's `composeAgentTitle` renders titles as `name · task_id`;\n * the agent name is always the first ' · '-separated token. Adopted\n * panes mu never re-titled have just the name — still parses.\n *\n * Backend-INDEPENDENT: the format is mu's, not any multiplexer's, so\n * every backend that can read a pane title parses it the same way.\n * Lives here rather than in an impl so migrated call sites can use it\n * without importing tmux.\n */\nexport function parseAgentNameFromTitle(title: string): string {\n const idx = title.indexOf(\" · \");\n return idx === -1 ? title.trim() : title.slice(0, idx).trim();\n}\n\n// ─── Errors ────────────────────────────────────────────────────────────\n\n/**\n * Base class for \"the multiplexer itself failed\". Each backend\n * subclasses it (tmux → `TmuxError`) so `handle()` can map the whole\n * family to exit code 5 (substrate unavailable) with one `instanceof`.\n */\nexport class MuxError extends Error implements HasNextSteps {\n override name: string = \"MuxError\";\n errorNextSteps(): NextStep[] {\n return [{ intent: \"Run health check\", command: \"mu doctor\" }];\n }\n}\n\n/**\n * Thrown when a verb references a pane id that doesn't exist on the\n * running multiplexer. Distinct from `MuxError` (which wraps any mux\n * command failure) so callers can map it to a specific exit code\n * (`mu` maps it to 5 alongside other mux issues, but the message is\n * more actionable than raw backend stderr).\n *\n * The backend-specific half of the remediation comes from the backend\n * that raised it: showing a herdr user `tmux info | head` would be\n * worse than showing no hint at all. Callers that construct this error\n * already hold the active backend, so passing it is free; the\n * no-backend form degrades to mu's own verbs only.\n */\nexport class PaneNotFoundError extends Error implements HasNextSteps {\n override readonly name = \"PaneNotFoundError\";\n constructor(\n public readonly paneId: string,\n private readonly backend?: MuxDiagnostics,\n ) {\n super(`${backend?.name ?? \"mux\"} pane not found: ${paneId}`);\n }\n errorNextSteps(): NextStep[] {\n return [\n ...(this.backend?.paneNotFoundNextSteps(this.paneId) ?? []),\n {\n intent: \"List workstreams to choose the right scope\",\n command: \"mu workstream list\",\n },\n {\n intent: \"List registered agents and orphan panes in that scope\",\n command: \"mu agent list -w <workstream>\",\n },\n ];\n }\n}\n\n/** The slice of a backend `PaneNotFoundError` needs. Structural so the\n * error type doesn't depend on the whole backend contract. */\nexport interface MuxDiagnostics {\n readonly name: MuxBackendName;\n paneNotFoundNextSteps(paneId: string): NextStep[];\n}\n\n/**\n * Thrown by `detectMux()` when no supported multiplexer is available.\n * Maps to exit 5 (substrate unavailable) — the same bucket as \"tmux is\n * installed but the server is unreachable\", because from the caller's\n * point of view both mean \"mu cannot reach a pane right now\".\n */\nexport class NoMultiplexerError extends Error implements HasNextSteps {\n override readonly name = \"NoMultiplexerError\";\n constructor(public readonly tried: readonly string[]) {\n super(\n `no supported multiplexer found (tried: ${tried.join(\", \")}). mu drives agents through tmux panes.`,\n );\n }\n errorNextSteps(): NextStep[] {\n return [\n { intent: \"Run health check\", command: \"mu doctor\" },\n { intent: \"Verify tmux is installed\", command: \"tmux -V\" },\n { intent: \"Force a specific backend\", command: \"MU_MUX=tmux mu <verb>\" },\n ];\n }\n}\n\n// ─── The backend contract ──────────────────────────────────────────────\n\n/**\n * One multiplexer implementation. Methods mirror the operations mu\n * actually performs; nothing is here speculatively.\n *\n * Implementations must be stateless value objects (a frozen record of\n * functions), so swapping the active backend is a pointer assignment\n * and tests can install a fake without teardown ordering hazards.\n */\nexport interface MuxBackend {\n readonly name: MuxBackendName;\n\n /** True iff this backend can drive panes on this machine right now.\n * Consulted by `detectMux()` in precedence order. */\n available(): Promise<boolean>;\n\n // — pane id validation (shape is backend-specific) —\n isValidPaneId(s: string): boolean;\n assertValidPaneId(s: string): void;\n\n // — sessions —\n listSessions(): Promise<MuxSession[]>;\n sessionExists(name: string): Promise<boolean>;\n newSession(name: string, opts?: NewSessionOptions): Promise<void>;\n newSessionWithPane(name: string, opts?: NewSessionWithPaneOptions): Promise<string>;\n killSession(name: string): Promise<void>;\n\n // — windows —\n listWindows(session?: string): Promise<MuxWindow[]>;\n newWindow(opts: NewWindowOptions): Promise<string>;\n selectLayout(window: string, layout: string): Promise<void>;\n\n // — panes —\n listPanes(target?: string): Promise<MuxPane[]>;\n listPanesInSession(session: string): Promise<MuxPane[]>;\n splitWindow(opts: SplitWindowOptions): Promise<string>;\n killPane(paneId: string): Promise<void>;\n /** False only when the mux reports the pane (or server) gone; throws\n * when the probe itself fails, so liveness gates fail closed. */\n paneExists(paneId: string): Promise<boolean>;\n paneTTY(paneId: string): Promise<string>;\n\n // — identity —\n //\n // The FALLBACK rung of actor resolution. `$MU_AGENT_NAME` is checked\n // first by the caller (src/tasks/claim.ts) and is backend-independent;\n // this exists because adopted panes predate that env injection.\n setPaneTitle(paneId: string, title: string): Promise<void>;\n /** Stop the pane's program from retitling it (tmux `allow-set-title off`;\n * pi emits OSC \"π - <cwd>\"). No-op where the backend has no equivalent. */\n lockPaneTitle(paneId: string): Promise<void>;\n getPaneTitle(paneId: string): Promise<string | undefined>;\n currentAgentName(): Promise<string | undefined>;\n /** Name of the session the CALLER is running inside, or undefined\n * when outside one. Backs the `mu-<name>` rung of workstream\n * auto-detection, which is why it is identity and not topology. */\n currentSessionName(): Promise<string | undefined>;\n\n // — spawn —\n //\n // OPTIONAL, and its absence is the DEFAULT shape: tmux creates a pane\n // and runs a command in one atomic call, so `NewWindowOptions.command`\n // et al. carry the command and there is nothing left to do.\n //\n // A backend that has no create-and-run form implements this instead.\n // mu then creates the pane bare, calls `startAgentInPane`, and — because\n // such a backend only returns once IT considers the agent ready for\n // input — SKIPS its own liveness/readiness polling. This is a capability\n // flag, not a backend name check: `src/agents/spawn.ts` branches on the\n // method being present, never on `mux.name`.\n startAgentInPane?(opts: StartAgentInPaneOptions): Promise<void>;\n\n // — io —\n sendToPane(paneId: string, text: string, opts?: SendOptions): Promise<void>;\n capturePane(paneId: string, opts?: CaptureOptions): Promise<string>;\n\n /**\n * The pane's runtime state as the mux itself reports it, or undefined\n * when the pane is gone or unclassified. tmux omits this capability;\n * herdr reports it directly.\n */\n paneStatus?(paneId: string): Promise<MuxPaneStatus | undefined>;\n\n // — chrome (decorative; a backend with no equivalent no-ops) —\n enableMuPaneBordersForSession(session: string): Promise<number>;\n enableMuPaneBordersForPane(paneId: string): Promise<void>;\n\n // — attach —\n //\n // Two shapes for the same intent because mu prints attach hints after\n // workstream creation while the TUI's `a` key executes the steps.\n // Neither may hardcode a tmux string. Sync or async: tmux builds the\n // line from the target alone, herdr must first resolve the session\n // name to an opaque workspace id. Callers always `await` the result.\n\n /** Copy-pasteable shell line that lands the user on `target`. */\n attachHint(target: AttachTarget): string | Promise<string>;\n /** The same attach, as argv steps to spawn in order. */\n attachCommands(target: AttachTarget): readonly MuxCommand[] | Promise<readonly MuxCommand[]>;\n\n // — diagnostics —\n\n /** Backend-specific `PaneNotFoundError` remediation. */\n paneNotFoundNextSteps(paneId: string): NextStep[];\n /** Version + ambient facts for `mu doctor`. Never throws: an\n * unreachable backend reports `ok: false`. */\n healthCheck(): Promise<MuxHealth>;\n}\n","// Run a binary and capture its output, never rejecting on a non-zero exit.\n// Shared by the tmux, herdr, kick and murmur-status executors. Uses\n// node:child_process rather than execa: execa's ~110 modules cost 25-40 ms\n// of import time on every process that touches a multiplexer.\n\nimport { type ChildProcess, execFile } from \"node:child_process\";\nimport { onExit } from \"signal-exit\";\n\nexport interface ExecFileResult {\n stdout: string;\n stderr: string;\n /** Numeric exit code; null on spawn failure (ENOENT), signal, or timeout. */\n exitCode: number | null;\n}\n\n/** execa's default `maxBuffer` (100 MiB); execFile's own default is 1 MiB. */\nconst MAX_BUFFER = 100 * 1024 * 1024;\n\n/** Drop one trailing LF or CRLF (what execa does), not all trailing whitespace. */\nfunction stripFinalNewline(s: string): string {\n if (s.endsWith(\"\\r\\n\")) return s.slice(0, -2);\n if (s.endsWith(\"\\n\")) return s.slice(0, -1);\n return s;\n}\n\n// execa killed in-flight children when the parent exited or was signalled\n// (`cleanup: true`, via signal-exit); a bare execFile does not, so an orphaned\n// tmux client or murmur process would outlive mu and its timeout timer. Reuse\n// signal-exit (what execa used) so every catchable signal is covered and the\n// parent still terminates correctly next to other signal-exit users such as\n// Ink. The hook is installed only while a child is live.\nconst live = new Set<ChildProcess>();\nlet removeExitHook: (() => void) | undefined;\n\nfunction killLive(): void {\n for (const c of live) c.kill(\"SIGKILL\");\n}\n\nfunction install(): void {\n removeExitHook = onExit(killLive);\n}\n\nfunction uninstall(): void {\n removeExitHook?.();\n removeExitHook = undefined;\n}\n\nfunction track(child: ChildProcess): void {\n if (live.size === 0) install();\n live.add(child);\n const done = (): void => {\n if (!live.delete(child)) return;\n if (live.size === 0) uninstall();\n };\n child.once(\"close\", done);\n child.once(\"error\", done);\n}\n\nexport function execFileCapture(\n cmd: string,\n args: readonly string[],\n opts: { timeoutMs?: number } = {},\n): Promise<ExecFileResult> {\n return new Promise((resolve) => {\n const child = execFile(\n cmd,\n [...args],\n {\n encoding: \"utf8\",\n maxBuffer: MAX_BUFFER,\n ...(opts.timeoutMs !== undefined ? { timeout: opts.timeoutMs, killSignal: \"SIGKILL\" } : {}),\n },\n (err, stdout, stderr) => {\n const code = err && \"code\" in err && typeof err.code === \"number\" ? err.code : null;\n resolve({\n stdout: stripFinalNewline(stdout ?? \"\"),\n stderr: stripFinalNewline(stderr ?? \"\"),\n exitCode: err ? code : 0,\n });\n },\n );\n // execa closes stdin when no input is given; do the same so children\n // that read stdin see EOF instead of hanging.\n child.stdin?.end();\n track(child);\n });\n}\n","/**\n * This is not the set of all possible signals.\n *\n * It IS, however, the set of all signals that trigger\n * an exit on either Linux or BSD systems. Linux is a\n * superset of the signal names supported on BSD, and\n * the unknown signals just fail to register, so we can\n * catch that easily enough.\n *\n * Windows signals are a different set, since there are\n * signals that terminate Windows processes, but don't\n * terminate (or don't even exist) on Posix systems.\n *\n * Don't bother with SIGKILL. It's uncatchable, which\n * means that we can't fire any callbacks anyway.\n *\n * If a user does happen to register a handler on a non-\n * fatal signal like SIGWINCH or something, and then\n * exit, it'll end up firing `process.emit('exit')`, so\n * the handler will be fired anyway.\n *\n * SIGBUS, SIGFPE, SIGSEGV and SIGILL, when not raised\n * artificially, inherently leave the process in a\n * state from which it is not safe to try and enter JS\n * listeners.\n */\nexport const signals: NodeJS.Signals[] = []\nsignals.push('SIGHUP', 'SIGINT', 'SIGTERM')\n\nif (process.platform !== 'win32') {\n signals.push(\n 'SIGALRM',\n 'SIGABRT',\n 'SIGVTALRM',\n 'SIGXCPU',\n 'SIGXFSZ',\n 'SIGUSR2',\n 'SIGTRAP',\n 'SIGSYS',\n 'SIGQUIT',\n 'SIGIOT'\n // should detect profiler and enable/disable accordingly.\n // see #21\n // 'SIGPROF'\n )\n}\n\nif (process.platform === 'linux') {\n signals.push('SIGIO', 'SIGPOLL', 'SIGPWR', 'SIGSTKFLT')\n}\n","// Note: since nyc uses this module to output coverage, any lines\n// that are in the direct sync flow of nyc's outputCoverage are\n// ignored, since we can never get coverage for them.\n// grab a reference to node's real process object right away\nimport { signals } from './signals.js'\nexport { signals }\n\n// just a loosened process type so we can do some evil things\ntype ProcessRE = NodeJS.Process & {\n reallyExit: (code?: number | undefined | null) => any\n emit: (ev: string, ...a: any[]) => any\n}\n\nconst processOk = (process: any): process is ProcessRE =>\n !!process &&\n typeof process === 'object' &&\n typeof process.removeListener === 'function' &&\n typeof process.emit === 'function' &&\n typeof process.reallyExit === 'function' &&\n typeof process.listeners === 'function' &&\n typeof process.kill === 'function' &&\n typeof process.pid === 'number' &&\n typeof process.on === 'function'\n\nconst kExitEmitter = Symbol.for('signal-exit emitter')\nconst global: typeof globalThis & { [kExitEmitter]?: Emitter } = globalThis\nconst ObjectDefineProperty = Object.defineProperty.bind(Object)\n\n/**\n * A function that takes an exit code and signal as arguments\n *\n * In the case of signal exits *only*, a return value of true\n * will indicate that the signal is being handled, and we should\n * not synthetically exit with the signal we received. Regardless\n * of the handler return value, the handler is unloaded when an\n * otherwise fatal signal is received, so you get exactly 1 shot\n * at it, unless you add another onExit handler at that point.\n *\n * In the case of numeric code exits, we may already have committed\n * to exiting the process, for example via a fatal exception or\n * unhandled promise rejection, so it is impossible to stop safely.\n */\nexport type Handler = (\n code: number | null | undefined,\n signal: NodeJS.Signals | null\n) => true | void\ntype ExitEvent = 'afterExit' | 'exit'\ntype Emitted = { [k in ExitEvent]: boolean }\ntype Listeners = { [k in ExitEvent]: Handler[] }\n\n// teeny special purpose ee\nclass Emitter {\n emitted: Emitted = {\n afterExit: false,\n exit: false,\n }\n\n listeners: Listeners = {\n afterExit: [],\n exit: [],\n }\n\n count: number = 0\n id: number = Math.random()\n\n constructor() {\n if (global[kExitEmitter]) {\n return global[kExitEmitter]\n }\n ObjectDefineProperty(global, kExitEmitter, {\n value: this,\n writable: false,\n enumerable: false,\n configurable: false,\n })\n }\n\n on(ev: ExitEvent, fn: Handler) {\n this.listeners[ev].push(fn)\n }\n\n removeListener(ev: ExitEvent, fn: Handler) {\n const list = this.listeners[ev]\n const i = list.indexOf(fn)\n /* c8 ignore start */\n if (i === -1) {\n return\n }\n /* c8 ignore stop */\n if (i === 0 && list.length === 1) {\n list.length = 0\n } else {\n list.splice(i, 1)\n }\n }\n\n emit(\n ev: ExitEvent,\n code: number | null | undefined,\n signal: NodeJS.Signals | null\n ): boolean {\n if (this.emitted[ev]) {\n return false\n }\n this.emitted[ev] = true\n let ret: boolean = false\n for (const fn of this.listeners[ev]) {\n ret = fn(code, signal) === true || ret\n }\n if (ev === 'exit') {\n ret = this.emit('afterExit', code, signal) || ret\n }\n return ret\n }\n}\n\nabstract class SignalExitBase {\n abstract onExit(cb: Handler, opts?: { alwaysLast?: boolean }): () => void\n abstract load(): void\n abstract unload(): void\n}\n\nconst signalExitWrap = <T extends SignalExitBase>(handler: T) => {\n return {\n onExit(cb: Handler, opts?: { alwaysLast?: boolean }) {\n return handler.onExit(cb, opts)\n },\n load() {\n return handler.load()\n },\n unload() {\n return handler.unload()\n },\n }\n}\n\nclass SignalExitFallback extends SignalExitBase {\n onExit() {\n return () => {}\n }\n load() {}\n unload() {}\n}\n\nclass SignalExit extends SignalExitBase {\n // \"SIGHUP\" throws an `ENOSYS` error on Windows,\n // so use a supported signal instead\n /* c8 ignore start */\n #hupSig = process.platform === 'win32' ? 'SIGINT' : 'SIGHUP'\n /* c8 ignore stop */\n #emitter = new Emitter()\n #process: ProcessRE\n #originalProcessEmit: ProcessRE['emit']\n #originalProcessReallyExit: ProcessRE['reallyExit']\n\n #sigListeners: { [k in NodeJS.Signals]?: () => void } = {}\n #loaded: boolean = false\n\n constructor(process: ProcessRE) {\n super()\n this.#process = process\n // { <signal>: <listener fn>, ... }\n this.#sigListeners = {}\n for (const sig of signals) {\n this.#sigListeners[sig] = () => {\n // If there are no other listeners, an exit is coming!\n // Simplest way: remove us and then re-send the signal.\n // We know that this will kill the process, so we can\n // safely emit now.\n const listeners = this.#process.listeners(sig)\n let { count } = this.#emitter\n // This is a workaround for the fact that signal-exit v3 and signal\n // exit v4 are not aware of each other, and each will attempt to let\n // the other handle it, so neither of them do. To correct this, we\n // detect if we're the only handler *except* for previous versions\n // of signal-exit, and increment by the count of listeners it has\n // created.\n /* c8 ignore start */\n const p = process as unknown as {\n __signal_exit_emitter__?: { count: number }\n }\n if (\n typeof p.__signal_exit_emitter__ === 'object' &&\n typeof p.__signal_exit_emitter__.count === 'number'\n ) {\n count += p.__signal_exit_emitter__.count\n }\n /* c8 ignore stop */\n if (listeners.length === count) {\n this.unload()\n const ret = this.#emitter.emit('exit', null, sig)\n /* c8 ignore start */\n const s = sig === 'SIGHUP' ? this.#hupSig : sig\n if (!ret) process.kill(process.pid, s)\n /* c8 ignore stop */\n }\n }\n }\n\n this.#originalProcessReallyExit = process.reallyExit\n this.#originalProcessEmit = process.emit\n }\n\n onExit(cb: Handler, opts?: { alwaysLast?: boolean }) {\n /* c8 ignore start */\n if (!processOk(this.#process)) {\n return () => {}\n }\n /* c8 ignore stop */\n\n if (this.#loaded === false) {\n this.load()\n }\n\n const ev = opts?.alwaysLast ? 'afterExit' : 'exit'\n this.#emitter.on(ev, cb)\n return () => {\n this.#emitter.removeListener(ev, cb)\n if (\n this.#emitter.listeners['exit'].length === 0 &&\n this.#emitter.listeners['afterExit'].length === 0\n ) {\n this.unload()\n }\n }\n }\n\n load() {\n if (this.#loaded) {\n return\n }\n this.#loaded = true\n\n // This is the number of onSignalExit's that are in play.\n // It's important so that we can count the correct number of\n // listeners on signals, and don't wait for the other one to\n // handle it instead of us.\n this.#emitter.count += 1\n\n for (const sig of signals) {\n try {\n const fn = this.#sigListeners[sig]\n if (fn) this.#process.on(sig, fn)\n } catch (_) {}\n }\n\n this.#process.emit = (ev: string, ...a: any[]) => {\n return this.#processEmit(ev, ...a)\n }\n this.#process.reallyExit = (code?: number | null | undefined) => {\n return this.#processReallyExit(code)\n }\n }\n\n unload() {\n if (!this.#loaded) {\n return\n }\n this.#loaded = false\n\n signals.forEach(sig => {\n const listener = this.#sigListeners[sig]\n /* c8 ignore start */\n if (!listener) {\n throw new Error('Listener not defined for signal: ' + sig)\n }\n /* c8 ignore stop */\n try {\n this.#process.removeListener(sig, listener)\n /* c8 ignore start */\n } catch (_) {}\n /* c8 ignore stop */\n })\n this.#process.emit = this.#originalProcessEmit\n this.#process.reallyExit = this.#originalProcessReallyExit\n this.#emitter.count -= 1\n }\n\n #processReallyExit(code?: number | null | undefined) {\n /* c8 ignore start */\n if (!processOk(this.#process)) {\n return 0\n }\n this.#process.exitCode = code || 0\n /* c8 ignore stop */\n\n this.#emitter.emit('exit', this.#process.exitCode, null)\n return this.#originalProcessReallyExit.call(\n this.#process,\n this.#process.exitCode\n )\n }\n\n #processEmit(ev: string, ...args: any[]): any {\n const og = this.#originalProcessEmit\n if (ev === 'exit' && processOk(this.#process)) {\n if (typeof args[0] === 'number') {\n this.#process.exitCode = args[0]\n /* c8 ignore start */\n }\n /* c8 ignore start */\n const ret = og.call(this.#process, ev, ...args)\n /* c8 ignore start */\n this.#emitter.emit('exit', this.#process.exitCode, null)\n /* c8 ignore stop */\n return ret\n } else {\n return og.call(this.#process, ev, ...args)\n }\n }\n}\n\nconst process = globalThis.process\n// wrap so that we call the method on the actual handler, without\n// exporting it directly.\nexport const {\n /**\n * Called when the process is exiting, whether via signal, explicit\n * exit, or running out of stuff to do.\n *\n * If the global process object is not suitable for instrumentation,\n * then this will be a no-op.\n *\n * Returns a function that may be used to unload signal-exit.\n */\n onExit,\n\n /**\n * Load the listeners. Likely you never need to call this, unless\n * doing a rather deep integration with signal-exit functionality.\n * Mostly exposed for the benefit of testing.\n *\n * @internal\n */\n load,\n\n /**\n * Unload the listeners. Likely you never need to call this, unless\n * doing a rather deep integration with signal-exit functionality.\n * Mostly exposed for the benefit of testing.\n *\n * @internal\n */\n unload,\n} = signalExitWrap(\n processOk(process) ? new SignalExit(process) : new SignalExitFallback()\n)\n","// tmux paste path for non-pi agents; pi agents use the control socket.\n//\n// Private pane-text checks used by tmux's send protocol. These answer whether\n// input can be delivered, not what state an agent is in.\n\nconst TAIL_WINDOW_LINES = 100;\nconst TAIL_LINES = 20;\n// \"model: loading\" is Codex's boot screen: it has no spinner, so without\n// the marker a booting Codex looks calm. This only covers the text being\n// visible in the captured tail, not a blank startup screen or the readiness\n// deadline expiring (sendToPane still pastes then).\nconst BUSY_MARKERS: readonly string[] = [\"to interrupt)\", \"model: loading\"];\nconst BRAILLE_SPINNER_RE = /[\\u2800-\\u28ff]/;\n\n/** Take the recent non-blank pane tail used by the input-timing checks. */\nexport function extractTail(scrollback: string): string {\n const lines = scrollback.split(\"\\n\");\n const window = lines.slice(-TAIL_WINDOW_LINES);\n let end = window.length;\n while (end > 0 && (window[end - 1] ?? \"\").trim() === \"\") end--;\n return window.slice(Math.max(0, end - TAIL_LINES), end).join(\"\\n\");\n}\n\n/** True when recent pane text shows input is temporarily unsafe to submit. */\nexport function paneLooksBusy(scrollback: string): boolean {\n const tail = extractTail(scrollback);\n return BUSY_MARKERS.some((marker) => tail.includes(marker)) || BRAILLE_SPINNER_RE.test(tail);\n}\n","// mu — tmux substrate.\n//\n// Single source of truth for all tmux interactions. Every tmux invocation\n// goes through `tmux(args)`, which wraps child_process and produces structured\n// `TmuxError`s carrying args + stderr.\n//\n// The send protocol is the bracketed-paste sequence for NON-pi agents\n// (claude-code, codex, adopted panes) and an explicit `--via mux`. pi\n// agents never reach it: they use the control socket\n// (src/agents/transport.ts). Canonical implementation in `sendToPane`:\n// 0. await pane quiescence (MU_SEND_READINESS_MS, default 15s)\n// 1. copy-mode -q (silent if not in copy mode)\n// 2. set-buffer (load text into a uniquely named buffer)\n// 3. paste-buffer -p -d -r (bracketed paste, delete buffer, preserve LF)\n// 4. delay (MU_SEND_DELAY_MS, default 500)\n// 5. send-keys Enter\n// 6. confirm the Enter took; re-send it, then warn loudly if not\n//\n// Naive `tmux send-keys \"<text>\"` is broken: characters like /, ?, f get\n// interpreted by the agent's TUI (Claude, Codex, less, vim) or by tmux's\n// copy mode if the user has scrolled up. Use `sendToPane()`.\n//\n// Steps 0 and 6 exist because of dogfood_send_after_new_dropped: a TUI\n// rendering a modal SWALLOWS the Enter, stranding the pasted text in the\n// input box while `mu agent send` reported exit 0. See\n// `awaitPaneQuiescence`.\n\nimport { execFileCapture } from \"../exec-file.js\";\nimport type { NextStep } from \"../output.js\";\nimport { extractTail, paneLooksBusy } from \"./input-timing.js\";\nimport {\n type AttachTarget,\n type CaptureOptions,\n type MuxBackend,\n type MuxCommand,\n MuxError,\n type MuxHealth,\n type MuxPane,\n type MuxSession,\n type MuxWindow,\n type NewSessionOptions,\n type NewSessionWithPaneOptions,\n type NewWindowOptions,\n PaneNotFoundError,\n parseAgentNameFromTitle,\n type SendOptions,\n type SendWarning,\n type SplitWindowOptions,\n} from \"./types.js\";\n\n// Re-exported so the historical `import { ... } from \"./tmux.js\"` surface\n// keeps resolving these names (47 test files and 12 src modules use it).\nexport {\n type AttachTarget,\n type CaptureOptions,\n type MuxCommand,\n MuxError,\n type MuxHealth,\n type NewSessionOptions,\n type NewSessionWithPaneOptions,\n type NewWindowOptions,\n PaneNotFoundError,\n parseAgentNameFromTitle,\n type SendOptions,\n type SendWarning,\n type SplitWindowOptions,\n};\n\n/** Back-compat aliases: tmux-specific names predating the MuxBackend\n * extraction. Same shapes, now owned by ./types.js. */\nexport type TmuxSession = MuxSession;\nexport type TmuxWindow = MuxWindow;\nexport type TmuxPane = MuxPane;\n\n// ─── Error type ────────────────────────────────────────────────────────\n\nexport class TmuxError extends MuxError {\n constructor(\n public readonly args: readonly string[],\n public readonly stderr: string,\n public readonly stdout: string,\n public readonly exitCode: number | null,\n ) {\n const detail = stderr.trim() || stdout.trim() || \"no output\";\n super(`tmux ${args.join(\" \")} failed (exit ${exitCode}): ${detail}`);\n this.name = \"TmuxError\";\n }\n override errorNextSteps(): NextStep[] {\n return [\n { intent: \"Run health check\", command: \"mu doctor\" },\n {\n intent: \"Verify tmux is running and reachable\",\n command: \"tmux info | head\",\n },\n {\n intent: \"Check the failing tmux command in isolation\",\n command: `tmux ${this.args.join(\" \")}`,\n },\n ];\n }\n}\n\n// ─── Pane ID validation ────────────────────────────────────────────────\n\n/**\n * Stable tmux pane IDs are of the form `%N` (e.g. \"%15\"). They never change\n * for the lifetime of the pane. **Pane indexes** (0, 1, 2…) are volatile and\n * shift when other panes close — never store or pass them.\n */\nexport const PANE_ID_RE = /^%\\d+$/;\n\nexport function isValidPaneId(s: string): boolean {\n return PANE_ID_RE.test(s);\n}\n\nexport function assertValidPaneId(s: string): void {\n if (!isValidPaneId(s)) {\n throw new TypeError(`invalid tmux pane id: ${JSON.stringify(s)} (expected /^%\\\\d+$/)`);\n }\n}\n\n// ─── Configurable delay ────────────────────────────────────────────────\n\n/**\n * Delay between bracketed-paste and Enter, in milliseconds. Claude/Codex/pi\n * process pasted text asynchronously; without this delay, Enter can arrive\n * before the agent has ingested the text. Defaults to 500; lower for tests,\n * raise for slow remotes via `MU_SEND_DELAY_MS`.\n */\nexport function defaultSendDelayMs(): number {\n const raw = process.env.MU_SEND_DELAY_MS;\n if (raw === undefined) return 500;\n const parsed = Number.parseInt(raw, 10);\n if (Number.isNaN(parsed) || parsed < 0) return 500;\n return parsed;\n}\n\n// ─── Executor (swappable for tests) ────────────────────────────────────\n\nexport interface TmuxExecResult {\n stdout: string;\n stderr: string;\n exitCode: number | null;\n}\n\nexport type TmuxExecutor = (args: readonly string[]) => Promise<TmuxExecResult>;\n\n/**\n * Optional global-flag prefix to splice in front of every tmux args\n * vector. When `MU_TMUX_SOCKET=<name>` is set, this returns\n * `[\"-L\", name, \"-f\", \"/dev/null\"]`:\n *\n * `-L <name>` routes every call through a private tmux server with\n * the given socket name (Linux: `/tmp/tmux-<uid>/<name>`,\n * macOS: `$TMPDIR/tmux-<uid>/<name>`) instead of the user's default\n * `/tmp/tmux-<uid>/default`. Set by the test harness in Layer 3 of\n * bug_test_suite_flake_leaks_isolation so the integration suite\n * can never observe — or contaminate — the user's interactive\n * tmux server.\n *\n * `-f /dev/null` skips the user's `~/.tmux.conf`. This matters\n * because tmux auto-starts the server on the first client call if\n * none is running (e.g. after a test’s last `kill-session`\n * shuts the server down). A typical user config uses `run-shell`\n * for status-bar plugins (TPM, hostname/network probes), and each\n * such hook adds ~1–4s to that auto-start. Without `-f /dev/null`\n * a single integration test grows from 3s to 48s on a configured\n * dev box. The suite drives tmux through the documented protocol,\n * not through bound keys, so the user's config is irrelevant.\n *\n * Read fresh on every call so a setupFiles hook that mutates\n * `process.env.MU_TMUX_SOCKET` mid-run takes effect immediately.\n *\n * Production code never sets this; it's a test-isolation seam.\n */\nfunction tmuxGlobalFlags(): readonly string[] {\n const socket = process.env.MU_TMUX_SOCKET;\n if (socket === undefined || socket.length === 0) return [];\n return [\"-L\", socket, \"-f\", \"/dev/null\"];\n}\n\nconst realExecutor: TmuxExecutor = (args) =>\n execFileCapture(\"tmux\", [...tmuxGlobalFlags(), ...args]);\n\nlet currentExecutor: TmuxExecutor = realExecutor;\n\n/**\n * Install a custom executor (for tests). Returns the previous executor so\n * tests can restore it cleanly. Production code should never call this.\n */\nexport function setTmuxExecutor(executor: TmuxExecutor): TmuxExecutor {\n const previous = currentExecutor;\n currentExecutor = executor;\n return previous;\n}\n\n/** Restore the real (child_process-backed) executor. */\nexport function resetTmuxExecutor(): void {\n currentExecutor = realExecutor;\n}\n\n/**\n * Run an arbitrary tmux command. The single point of contact with the\n * tmux binary; every higher-level operation in this module goes through it.\n *\n * Throws `TmuxError` on non-zero exit. Returns stdout on success.\n */\nexport async function tmux(args: readonly string[]): Promise<string> {\n const result = await currentExecutor(args);\n if (result.exitCode !== 0) {\n throw new TmuxError([...args], result.stderr, result.stdout, result.exitCode);\n }\n return result.stdout;\n}\n\n// ─── Sleep helper (testable) ──────────────────────────────────────────\n\nlet currentSleep: (ms: number) => Promise<void> = (ms) =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\nexport function setSleepForTests(\n impl: (ms: number) => Promise<void>,\n): (ms: number) => Promise<void> {\n const previous = currentSleep;\n currentSleep = impl;\n return previous;\n}\n\nexport function resetSleep(): void {\n currentSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** Test-aware sleep — honours `setSleepForTests`. Public so other modules\n * (notably `agents.ts` for spawn liveness polling) get free no-op-ing in\n * tests without re-implementing the swap. */\nexport function sleep(ms: number): Promise<void> {\n return currentSleep(ms);\n}\n\n// ─── Domain types ──────────────────────────────────────────────────────\n\n// ─── Sessions ──────────────────────────────────────────────────────────\n\n/**\n * The `-t` form that names session `name` EXACTLY. A bare `-t mu-auth`\n * falls back to prefix matching, so it resolves to `mu-auth-refactor`\n * when `mu-auth` does not exist, and a teardown of workstream `auth`\n * kills another workstream's session. `=` disables the prefix and\n * pattern fallback. The trailing `:` makes it a session target for\n * pane- and window-scoped verbs too: `list-panes -s -t =mu-auth`\n * still prefix-matches through the pane lookup, but\n * `-t =mu-auth:` does not (verified on tmux 3.7c).\n */\nfunction exactSessionTarget(name: string): string {\n return `=${name}:`;\n}\n\n/**\n * stderr shapes that mean \"no tmux server is running\", so there is no\n * session, window or pane to find. tmux prints \"no server running on\n * <path>\" when the socket file exists but nothing listens, and \"error\n * connecting to <path> (No such file or directory)\" when the socket file\n * does not exist at all (fresh boot, cleared /tmp, new TMUX_TMPDIR).\n * Other \"error connecting\" causes, such as permission denied, stay\n * real errors.\n */\nconst NO_SERVER_RE = /no server running|error connecting to .*\\(No such file or directory\\)/i;\n\n/** True when a tmux call failed because the pane (or the whole server)\n * is gone, rather than for a transient reason. \"no current target\" is\n * what a server with zero sessions (`exit-empty off`) says about a dead\n * pane, as in killSession and sendToPane's copy-mode check. */\nfunction isPaneGoneError(err: unknown): boolean {\n return (\n err instanceof TmuxError &&\n (/can't find pane|pane not found|no current target/i.test(err.stderr) ||\n NO_SERVER_RE.test(err.stderr))\n );\n}\n\nexport async function listSessions(): Promise<TmuxSession[]> {\n // `list-sessions` exits 1 when no sessions exist; treat as empty.\n try {\n const out = await tmux([\"list-sessions\", \"-F\", \"#{session_name}\"]);\n return out\n .split(\"\\n\")\n .filter((line) => line.length > 0)\n .map((name) => ({ name }));\n } catch (err) {\n if (\n err instanceof TmuxError &&\n (NO_SERVER_RE.test(err.stderr) || /no sessions/i.test(err.stderr))\n ) {\n return [];\n }\n throw err;\n }\n}\n\nexport async function sessionExists(name: string): Promise<boolean> {\n const result = await currentExecutor([\"has-session\", \"-t\", exactSessionTarget(name)]);\n return result.exitCode === 0;\n}\n\n/**\n * A detached session otherwise gets tmux's default-size (80x24), so\n * `mu agent read` captures wrap at 80. Never resize-window: it pins\n * window-size to manual.\n */\nconst DETACHED_SIZE = [\"-x\", \"200\", \"-y\", \"50\"];\n\nexport async function newSession(name: string, opts: NewSessionOptions = {}): Promise<void> {\n const args = [\"new-session\"];\n if (opts.detached !== false) args.push(\"-d\", ...DETACHED_SIZE);\n args.push(\"-s\", name);\n if (opts.windowName) args.push(\"-n\", opts.windowName);\n if (opts.cwd) args.push(\"-c\", opts.cwd);\n appendEnvFlags(args, opts.env);\n if (opts.command) args.push(opts.command);\n await tmux(args);\n}\n\n/**\n * Create a tmux session AND its first window+pane in one atomic call.\n * Returns the new pane's stable id. Used by mu when spawning the first\n * agent in a workstream so we never end up with an empty `mu-<workstream>`\n * session left behind by a failed spawn.\n */\nexport async function newSessionWithPane(\n name: string,\n opts: NewSessionWithPaneOptions,\n): Promise<string> {\n const args = [\"new-session\"];\n if (opts.detached !== false) args.push(\"-d\", ...DETACHED_SIZE);\n args.push(\"-s\", name, \"-n\", opts.windowName);\n if (opts.cwd) args.push(\"-c\", opts.cwd);\n appendEnvFlags(args, opts.env);\n args.push(\"-P\", \"-F\", \"#{pane_id}\", opts.command);\n const out = (await tmux(args)).trim();\n assertValidPaneId(out);\n return out;\n}\n\n/**\n * Idempotent: succeeds even if the session is already gone.\n *\n * Four swallowed shapes:\n * - \"can't find session: <name>\" — session never existed.\n * - \"session not found\" — alternate phrasing on some tmux builds.\n * - \"no server running on <path>\" (or \"error connecting to <path> (No\n * such file or directory)\", see NO_SERVER_RE) — the tmux server itself has exited\n * (typical when the test suite runs against a private `tmux -L\n * <socket>` server and the just-killed session was its last; tmux\n * quietly shuts the server down). Without this, killSession would\n * throw on the very next idempotent call — only visible under\n * Layer 3 of bug_test_suite_flake_leaks_isolation.\n * - \"no current target\" — the server is UP but has zero\n * sessions, so `-t <name>` has no session list to resolve against\n * and tmux never gets as far as \"can't find session\". Reachable\n * whenever the server outlives its last session: the suite's\n * private server (`exit-empty off`, see test/_global-teardown.ts)\n * and any user whose ~/.tmux.conf sets `exit-empty off`. Same\n * meaning as \"can't find session\" for our purposes — the session\n * we were asked to kill is gone.\n */\nexport async function killSession(name: string): Promise<void> {\n const args = [\"kill-session\", \"-t\", exactSessionTarget(name)];\n const result = await currentExecutor(args);\n if (\n result.exitCode !== 0 &&\n !/can't find session|session not found|no current target/i.test(result.stderr) &&\n !NO_SERVER_RE.test(result.stderr)\n ) {\n throw new TmuxError(args, result.stderr, result.stdout, result.exitCode);\n }\n}\n\n// ─── Windows ───────────────────────────────────────────────────────────\n\nexport async function listWindows(session?: string): Promise<TmuxWindow[]> {\n if (session) {\n const out = await tmux([\n \"list-windows\",\n \"-t\",\n exactSessionTarget(session),\n \"-F\",\n \"#{window_id}\\t#{window_name}\",\n ]);\n return parseWindows(out);\n }\n // Cross-session: include the session name.\n const out = await tmux([\n \"list-windows\",\n \"-a\",\n \"-F\",\n \"#{session_name}\\t#{window_id}\\t#{window_name}\",\n ]);\n const windows: TmuxWindow[] = [];\n for (const line of out.split(\"\\n\")) {\n if (line.length === 0) continue;\n const [sessionName, id, name] = line.split(\"\\t\");\n if (!sessionName || !id || name === undefined) continue;\n windows.push({ id, name, sessionName });\n }\n return windows;\n}\n\nfunction parseWindows(output: string): TmuxWindow[] {\n const windows: TmuxWindow[] = [];\n for (const line of output.split(\"\\n\")) {\n if (line.length === 0) continue;\n const [id, name] = line.split(\"\\t\");\n if (!id || name === undefined) continue;\n windows.push({ id, name });\n }\n return windows;\n}\n\n/**\n * Create a new tmux window with one pane. Returns the new pane's stable\n * pane id (e.g. `%15`).\n */\nexport async function newWindow(opts: NewWindowOptions): Promise<string> {\n const args = [\"new-window\"];\n if (opts.detached !== false) args.push(\"-d\");\n if (opts.session) args.push(\"-t\", exactSessionTarget(opts.session));\n args.push(\"-n\", opts.name);\n if (opts.cwd) args.push(\"-c\", opts.cwd);\n appendEnvFlags(args, opts.env);\n args.push(\"-P\", \"-F\", \"#{pane_id}\", opts.command);\n const out = (await tmux(args)).trim();\n assertValidPaneId(out);\n return out;\n}\n\n// ─── Panes ─────────────────────────────────────────────────────────────\n\n/**\n * List ALL panes in a tmux session (across every window). Used by\n * reconciliation to find every pane in the workstream's session.\n *\n * Note `list-panes -t <session>` (no -s) lists panes in the current\n * *window* of that session, not the whole session — a common gotcha.\n * `-s` is the flag that says \"all panes in this session.\"\n *\n * Returns `[]` (not throws) when the session doesn't exist or has no\n * panes. tmux destroys a session as soon as its last pane closes, so the\n * \"session was just here a moment ago\" case is normal during reconcile.\n * tmux's error wording in this case varies (\"can't find session\",\n * \"can't find window\", or \"no current target\" when the server is up\n * with zero sessions), so we match any of them.\n */\nexport async function listPanesInSession(session: string): Promise<TmuxPane[]> {\n const args = [\n \"list-panes\",\n \"-s\",\n \"-t\",\n exactSessionTarget(session),\n \"-F\",\n \"#{window_id}\\t#{pane_id}\\t#{pane_title}\\t#{pane_current_command}\",\n ];\n const result = await currentExecutor(args);\n if (result.exitCode !== 0) {\n if (\n /can't find (session|window)|no sessions|no current target/i.test(result.stderr) ||\n NO_SERVER_RE.test(result.stderr)\n ) {\n return [];\n }\n throw new TmuxError(args, result.stderr, result.stdout, result.exitCode);\n }\n const panes: TmuxPane[] = [];\n for (const line of result.stdout.split(\"\\n\")) {\n if (line.length === 0) continue;\n const [windowId, paneId, title, command] = line.split(\"\\t\");\n if (!windowId || !paneId || command === undefined) continue;\n panes.push({ paneId, title: title ?? \"\", command, windowId });\n }\n return panes;\n}\n\n/**\n * List panes in the current session, a specific window/session target, or\n * all panes across all sessions when `target` is the literal \"*\".\n */\nexport async function listPanes(target?: string): Promise<TmuxPane[]> {\n if (target === \"*\") {\n const out = await tmux([\n \"list-panes\",\n \"-a\",\n \"-F\",\n \"#{session_name}\\t#{window_id}\\t#{pane_id}\\t#{pane_title}\\t#{pane_current_command}\",\n ]);\n const panes: TmuxPane[] = [];\n for (const line of out.split(\"\\n\")) {\n if (line.length === 0) continue;\n const [sessionName, windowId, paneId, title, command] = line.split(\"\\t\");\n if (!sessionName || !windowId || !paneId || command === undefined) continue;\n panes.push({ paneId, title: title ?? \"\", command, windowId, sessionName });\n }\n return panes;\n }\n\n const args = [\"list-panes\"];\n if (target !== undefined) args.push(\"-t\", target);\n args.push(\"-F\", \"#{pane_id}\\t#{pane_title}\\t#{pane_current_command}\");\n const out = await tmux(args);\n const panes: TmuxPane[] = [];\n for (const line of out.split(\"\\n\")) {\n if (line.length === 0) continue;\n const [paneId, title, command] = line.split(\"\\t\");\n if (!paneId || command === undefined) continue;\n panes.push({ paneId, title: title ?? \"\", command });\n }\n return panes;\n}\n\n/**\n * Split a window and run a command in the new pane. Returns the new pane's\n * stable pane id.\n */\nexport async function splitWindow(opts: SplitWindowOptions): Promise<string> {\n const args = [\"split-window\"];\n if (opts.horizontal !== false) args.push(\"-h\");\n if (opts.detached !== false) args.push(\"-d\");\n args.push(\"-t\", opts.target);\n if (opts.cwd) args.push(\"-c\", opts.cwd);\n appendEnvFlags(args, opts.env);\n args.push(\"-P\", \"-F\", \"#{pane_id}\", opts.command);\n const out = (await tmux(args)).trim();\n assertValidPaneId(out);\n return out;\n}\n\n/**\n * Push one `-e KEY=VALUE` flag per entry into `args`, validating that\n * keys are non-empty and contain no `=` (tmux would error obscurely\n * otherwise; throwing TypeError keeps the failure at the call site).\n * No-op when `env` is undefined or empty.\n *\n * Iteration order follows Object.entries (insertion order); tests\n * shouldn't depend on a specific ordering, only on the presence of\n * each `-e KEY=VALUE` pair in the captured args.\n */\nfunction appendEnvFlags(args: string[], env: Record<string, string> | undefined): void {\n if (!env) return;\n for (const [k, v] of Object.entries(env)) {\n if (k.length === 0) {\n throw new TypeError(\"tmux env key must be non-empty\");\n }\n if (k.includes(\"=\")) {\n throw new TypeError(`tmux env key must not contain '=': ${JSON.stringify(k)}`);\n }\n args.push(\"-e\", `${k}=${v}`);\n }\n}\n\n/** Idempotent: succeeds even if the pane is already gone. */\nexport async function killPane(paneId: string): Promise<void> {\n assertValidPaneId(paneId);\n const result = await currentExecutor([\"kill-pane\", \"-t\", paneId]);\n if (\n result.exitCode !== 0 &&\n !/can't find pane/i.test(result.stderr) &&\n !NO_SERVER_RE.test(result.stderr)\n ) {\n throw new TmuxError([\"kill-pane\", \"-t\", paneId], result.stderr, result.stdout, result.exitCode);\n }\n}\n\nexport async function paneExists(paneId: string): Promise<boolean> {\n if (!isValidPaneId(paneId)) return false;\n // tmux's `display-message -t <bogus>` exits 0 but emits empty output; we\n // must check that the echoed pane id matches what we asked for.\n const args = [\"display-message\", \"-t\", paneId, \"-p\", \"#{pane_id}\"];\n const result = await currentExecutor(args);\n if (result.exitCode !== 0) {\n // Only \"the pane or server is gone\" means false. Any other failure\n // (permission denied, a broken socket) is unknown, not dead: callers\n // that gate destructive work on liveness must not read it as gone.\n if (/can't find pane|pane not found|no current target/i.test(result.stderr)) return false;\n if (NO_SERVER_RE.test(result.stderr)) return false;\n throw new TmuxError(args, result.stderr, result.stdout, result.exitCode);\n }\n return result.stdout.trim() === paneId;\n}\n\nexport async function setPaneTitle(paneId: string, title: string): Promise<void> {\n assertValidPaneId(paneId);\n await tmux([\"select-pane\", \"-t\", paneId, \"-T\", title]);\n}\n\n/** Pane-scoped `allow-set-title off`: OSC title escapes from the app no longer overwrite the mu title. */\nexport async function lockPaneTitle(paneId: string): Promise<void> {\n assertValidPaneId(paneId);\n await tmux([\"set-option\", \"-p\", \"-t\", paneId, \"allow-set-title\", \"off\"]);\n}\n\n/**\n * Look up the window id (e.g. `@42`) that contains a given pane id\n * (e.g. `%15`). Used by spawn so we can apply window-scoped options\n * (`pane-border-status`) to the freshly created window.\n *\n * Returns undefined if the pane no longer exists.\n */\nexport async function getWindowIdForPane(paneId: string): Promise<string | undefined> {\n if (!isValidPaneId(paneId)) return undefined;\n const result = await currentExecutor([\"display-message\", \"-t\", paneId, \"-p\", \"#{window_id}\"]);\n if (result.exitCode !== 0) return undefined;\n const id = result.stdout.trim();\n return id.length > 0 ? id : undefined;\n}\n\n/**\n * Single source of truth for the operator opt-out from the mu pane\n * banner / border decorations. Set `MU_BANNER_QUIET=1` to disable.\n * All `enableMuPaneBorders*` helpers self-check this so callers\n * don't have to wrap them in env guards (a footgun: forget the\n * guard and you set the border even when the operator wanted\n * quiet).\n */\nfunction muBannersDisabled(): boolean {\n return process.env.MU_BANNER_QUIET === \"1\";\n}\n\n/**\n * Enable the mu pane border on EVERY window currently in `session`\n * without overriding the user's pane-border format. Idempotent. Best-effort:\n * windows that have vanished mid-iteration are silently skipped. Used\n * by `mu workstream init` (covers the placeholder `_mu` window plus\n * any windows that already exist, e.g. on re-init of an upgraded\n * mu-pre-border session) and by `mu agent spawn` (covers the\n * just-created window so the border shows immediately on attach).\n *\n * No-op (returns 0) when `MU_BANNER_QUIET=1`.\n *\n * Returns the number of windows that received the option.\n */\nexport async function enableMuPaneBordersForSession(session: string): Promise<number> {\n if (muBannersDisabled()) return 0;\n const windows = await listWindows(session).catch(() => []);\n let n = 0;\n for (const w of windows) {\n try {\n await enableMuPaneBorders(w.id);\n n += 1;\n } catch {\n // Window vanished; skip silently. Border is decorative.\n }\n }\n return n;\n}\n\n/**\n * Apply the mu pane border to the window containing `paneId`. This is\n * the spawn/adopt shape: callers have a pane id (from `new-window` or\n * from an adopt target), and need to resolve the enclosing window\n * before calling `enableMuPaneBorders` (a window-scoped option).\n *\n * Self-checks `MU_BANNER_QUIET` and swallows tmux errors — the border\n * is decorative; failing to set it is never load-bearing.\n */\nexport async function enableMuPaneBordersForPane(paneId: string): Promise<void> {\n if (muBannersDisabled()) return;\n if (!isValidPaneId(paneId)) return;\n // Target the pane directly: `set-option -w` resolves a pane target to\n // its window, so no `display-message #{window_id}` round-trip needed.\n await enableMuPaneBorders(paneId).catch(() => {});\n}\n\n/**\n * Enable a one-line top pane border on a specific window/session target.\n * The user's inherited `pane-border-format` is left intact; mu owns the\n * title's durable context, not border presentation. Idempotent\n * (`set-option` is a write, not a toggle).\n *\n * IMPORTANT: tmux's `pane-border-status` is a **window** option, not a\n * session option. `set-option -t <session>`\n * only updates the active window at call time — windows created later\n * inherit from the GLOBAL value (which is `off` by default and which\n * we deliberately do NOT touch, since changing the global would\n * affect every other tmux session on the user's machine, including\n * dotfile-curated ones).\n *\n * Therefore mu must call this twice:\n * 1. At `mu workstream init` time on the placeholder `_mu` window\n * (so an attached operator sees a border immediately).\n * 2. On every `mu agent spawn` (which calls `tmux new-window`),\n * against the new window's id.\n *\n * The border is tmux chrome, not pane content: it doesn't scroll, it\n * survives copy-mode, and the inner CLI never sees it.\n *\n * Designed as the pane-border visual cue for mu-managed panes.\n */\nexport async function enableMuPaneBorders(target: string): Promise<void> {\n if (muBannersDisabled()) return;\n // One tmux invocation (`;`-chained) instead of four: each spawn of the\n // tmux client costs ~10 ms. tmux aborts the chain at the first error.\n // Bottom + sides: heavy box-drawing lines so a mu-managed pane is\n // visually distinct even when not the active pane (top carries the\n // labeled status text; the rest of the frame carries the visual\n // \"this is mu\" cue). Cyan-bold for the active pane, dim brightblack\n // for inactive ones, so the operator's eye lands on the pane that\n // currently has focus.\n await tmux([\n ...[\"set-option\", \"-w\", \"-t\", target, \"pane-border-status\", \"top\"],\n \";\",\n ...[\"set-option\", \"-w\", \"-t\", target, \"pane-border-lines\", \"heavy\"],\n \";\",\n ...[\"set-option\", \"-w\", \"-t\", target, \"pane-active-border-style\", \"fg=cyan,bold\"],\n \";\",\n ...[\"set-option\", \"-w\", \"-t\", target, \"pane-border-style\", \"fg=brightblack\"],\n ]);\n}\n\n/**\n * Look up the TTY device path for a pane (e.g. `/dev/ttys012` on macOS,\n * `/dev/pts/3` on Linux). Used by `mu agent kick` to find the\n * foreground process group on the pane's TTY so it can be signalled\n * directly — `tmux send-keys C-c` does NOT propagate to wrapped\n * subprocesses inside a CLI like pi/claude/codex (the CLI catches it\n * itself and treats it as a UI input). The escape hatch is signalling\n * the foreground pgid of the underlying TTY from outside the pane.\n *\n * Throws `PaneNotFoundError` when the pane id is invalid or the pane\n * has vanished. Throws `TmuxError` on any other tmux failure.\n */\nexport async function paneTTY(paneId: string): Promise<string> {\n assertValidPaneId(paneId);\n const result = await currentExecutor([\"display-message\", \"-t\", paneId, \"-p\", \"#{pane_tty}\"]);\n if (result.exitCode !== 0) {\n if (/can't find pane|pane not found/i.test(result.stderr) || NO_SERVER_RE.test(result.stderr)) {\n throw new PaneNotFoundError(paneId, tmuxBackend);\n }\n throw new TmuxError(\n [\"display-message\", \"-t\", paneId, \"-p\", \"#{pane_tty}\"],\n result.stderr,\n result.stdout,\n result.exitCode,\n );\n }\n const tty = result.stdout.trim();\n if (tty === \"\") throw new PaneNotFoundError(paneId, tmuxBackend);\n return tty;\n}\n\nexport async function getPaneTitle(paneId: string): Promise<string | undefined> {\n if (!isValidPaneId(paneId)) return undefined;\n const result = await currentExecutor([\"display-message\", \"-t\", paneId, \"-p\", \"#{pane_title}\"]);\n if (result.exitCode !== 0) return undefined;\n return result.stdout.trimEnd();\n}\n\n/**\n * Read the title of the *current* pane (the one whose shell is running this\n * process), via $TMUX_PANE. Returns undefined when not inside tmux. Used by\n * `mu claim` to derive the agent identity from the pane title — the claim\n * protocol's zero-config identity step.\n */\nexport async function currentPaneTitle(): Promise<string | undefined> {\n const paneId = process.env.TMUX_PANE;\n if (!paneId || !isValidPaneId(paneId)) return undefined;\n return getPaneTitle(paneId);\n}\n\n/**\n * Convenience: read the current pane's title and extract the agent name.\n */\nexport async function currentAgentName(): Promise<string | undefined> {\n const title = await currentPaneTitle();\n if (title === undefined) return undefined;\n return parseAgentNameFromTitle(title);\n}\n\n/**\n * Name of the tmux session this process is running inside, or\n * undefined outside tmux. Gated on `$TMUX` so a call from a plain\n * shell doesn't get whatever session the server happens to consider\n * current.\n */\nexport async function currentSessionName(): Promise<string | undefined> {\n if (!process.env.TMUX) return undefined;\n const result = await currentExecutor([\"display-message\", \"-p\", \"#S\"]);\n if (result.exitCode !== 0) return undefined;\n const name = result.stdout.trim();\n return name === \"\" ? undefined : name;\n}\n\nexport async function selectLayout(window: string, layout: string): Promise<void> {\n await tmux([\"select-layout\", \"-t\", window, layout]);\n}\n\n// ─── Send protocol (the canonical bracketed-paste sequence) ────────────\n\n/**\n * Default pre-send readiness budget in ms. Override with\n * MU_SEND_READINESS_MS; 0 disables the wait entirely.\n *\n * 15s (vs spawn's 10s) because the blocking operation here is an LLM\n * round-trip inside the target TUI, not a process cold-start. pi's\n * post-`/new` \"Naming session before closing…\" step measured ~1.5s on a\n * warm session but is a model call, so it has no useful upper bound.\n */\nexport function defaultSendReadinessMs(): number {\n const raw = process.env.MU_SEND_READINESS_MS;\n if (raw === undefined) return 15_000;\n const parsed = Number.parseInt(raw, 10);\n if (Number.isNaN(parsed) || parsed < 0) return 15_000;\n return parsed;\n}\n\n/** Interval between quiescence polls (ms). */\nconst SEND_READINESS_POLL_MS = 250;\n\n/**\n * How many CONSECUTIVE non-busy polls count as quiescent.\n *\n * One is not enough, and that is the subtle half of this bug. A TUI\n * does not render its modal synchronously: `mu agent send W \"/new\"`\n * returns as soon as tmux delivers Enter, and pi needs ~200-400ms more\n * before the \"Naming session…\" spinner appears. A single poll in that\n * window sees the PREVIOUS frame — still `needs_input` — declares the\n * pane ready, and pastes straight into the modal that is about to\n * appear. Measured directly: with a single poll, quiescence returned\n * true while naming was still running on 2 of 3 attempts.\n *\n * Three polls at 250ms means the pane must look idle for ~500ms of\n * wall-clock before we believe it, which covers the render gap without\n * adding meaningful latency to the common already-idle case.\n */\nconst QUIESCENCE_CONFIRMATIONS = 3;\n\n/** How many times to re-send Enter for text stranded in the input box.\n * One swallowed Enter is the observed failure; a second retry costs\n * nothing when it is not needed. */\nconst SUBMIT_RETRIES = 2;\n\n/** Pause after a retry Enter so the TUI can accept it and repaint\n * before we re-inspect. */\nconst SUBMIT_SETTLE_MS = 600;\n\n/** Samples that must ALL agree before calling a send stranded, and the\n * gap between them. 4 x 700ms ≈ 2.1s, which covers the observed\n * repaint lag during which a delivered prompt still reads as count==1. */\nconst SUBMIT_VERIFY_SAMPLES = 4;\nconst SUBMIT_VERIFY_INTERVAL_MS = 700;\n\n/**\n * Markers that mean \"the agent is mid-turn\", as opposed to \"a modal is\n * up\". Both render a spinner, so the spinner alone cannot tell them\n * apart. `to interrupt)` is the same literal the status detector keys\n * on for busy; `Working` covers pi's plain progress line.\n */\nconst WORK_MARKERS: readonly string[] = [\"to interrupt)\", \"Working\"];\n\n/** True when the pane tail shows the agent working on a turn (rather\n * than a modal / re-init spinner). Only the last 40 lines count, so a\n * work marker scrolled far above cannot make a live modal look like an\n * in-flight turn. See awaitPaneQuiescence. */\nexport function hasWorkMarker(scrollback: string): boolean {\n const tail = scrollback.split(\"\\n\").slice(-40).join(\"\\n\");\n // A visible Codex boot marker wins: a cwd like ~/Working must not\n // bypass readiness while \"model: loading\" is still on screen.\n if (extractTail(scrollback).includes(\"model: loading\")) return false;\n return WORK_MARKERS.some((m) => tail.includes(m));\n}\n\n/**\n * Block until the pane is ready to ACCEPT input, or the budget expires.\n * Returns true if the pane quiesced, false on timeout. Throws the\n * capture's TmuxError at once when the pane or the server is gone:\n * a dead pane never quiesces, so polling it would only burn the whole\n * budget before the send fails anyway.\n *\n * WHY THIS EXISTS (dogfood_send_after_new_dropped, reproduced 3/6 at\n * sleep=0.3s and 1/5 at sleep=2s against a real pi pane):\n *\n * `mu agent send W \"/new\"` makes pi run an ASYNC \"Naming session before\n * closing…\" step — an LLM call — before the new session exists. A\n * bracketed paste that arrives while that modal is up is ACCEPTED, but\n * the Enter that follows it is SWALLOWED. The text is therefore left\n * sitting in the new session's input box, typed but never submitted —\n * exactly the reported symptom: pane at needs_input, context 0.0%, no\n * error anywhere, and an orchestrator waiting on a task the agent never\n * started.\n *\n * (Verified rather than assumed: pasting during the modal and capturing\n * afterwards shows the probe string exactly ONCE, in the input box, on\n * 3 of 3 attempts. Re-sending Enter afterwards took it to 2 and moved\n * context 0.0% -> 2.4%, which is what makes recovery possible.)\n *\n * Because the blocker is a model call, no fixed sleep can be correct —\n * `sleep 2` is a coin flip, not a fix. The signal already existed: pi's\n * spinner is a Braille glyph, so the private input-timing helper can wait\n * for it to clear before sending.\n *\n * `needs_permission` counts as ready: a pane sitting on a confirm\n * dialog is waiting for a keystroke, and refusing to send would break\n * the documented \"answer the prompt with `mu agent send`\" flow.\n *\n * IMPORTANT — what this does NOT wait for: an agent that is BUSY doing\n * the work you gave it. Queuing a follow-up into a working agent is a\n * legitimate, documented pattern, and pi accepts it. Waiting on that\n * made every send into a working agent pay the full budget — measured\n * at 14.5s of 15s, versus milliseconds before. The two cases are told\n * apart by WHAT is busy, not by when:\n *\n * agent working — tail carries a work marker (`to interrupt)`,\n * `Working`). Send immediately; pi queues it.\n * modal / re-init — spinner with NO work marker, which is what pi's\n * \"Naming session before closing…\" looks like.\n * Wait it out; this is the one that eats the Enter.\n */\nexport async function awaitPaneQuiescence(paneId: string, budgetMs: number): Promise<boolean> {\n if (budgetMs <= 0) return true;\n const deadline = Date.now() + budgetMs;\n let calm = 0;\n for (;;) {\n // A transient capture failure counts as busy; a vanished pane is fatal.\n const scrollback = await capturePane(paneId, { lines: 50 }).catch((err: unknown) => {\n if (isPaneGoneError(err)) throw err;\n return undefined;\n });\n const busy = scrollback === undefined || paneLooksBusy(scrollback);\n // Busy BECAUSE the agent is working a turn: not a re-init modal.\n // Send now and let the TUI queue it behind the current turn.\n if (busy && scrollback !== undefined && hasWorkMarker(scrollback)) return true;\n if (!busy) {\n calm++;\n if (calm >= QUIESCENCE_CONFIRMATIONS) return true;\n } else {\n // Went busy after looking idle: a modal rendered late. Reset the\n // streak so it cannot sneak in behind that early idle reading.\n calm = 0;\n }\n const remaining = deadline - Date.now();\n if (remaining <= 0) return false;\n await currentSleep(Math.min(SEND_READINESS_POLL_MS, remaining));\n }\n}\n\n/**\n * Longest prefix of `text` that is safe to look for in a pane capture.\n * The TUI soft-wraps its input box, so only the first line survives\n * intact. 24 chars is comfortably under any sane terminal width while\n * still being specific enough not to false-positive on chrome.\n */\nfunction pasteProbe(text: string): string {\n const firstLine = (text.split(\"\\n\")[0] ?? \"\").trim();\n return firstLine.slice(0, 24);\n}\n\n/**\n * True when `probe` looks SUSTAINED-unsubmitted: visible exactly once,\n * on a pane that is not working, across every sample in a short window.\n *\n * Why all three conditions, each learned from a false positive on a\n * real pane:\n *\n * - EXACTLY ONCE. Text sitting in the input box appears once. A\n * submitted prompt ends up appearing twice (the TUI echoes it into\n * the transcript above its response) or zero times (it scrolled\n * past). Zero therefore counts as delivered — treating \"cannot see\n * it\" as failure would warn on every long send.\n * - NOT BUSY. A busy pane is working on something, which is what a\n * delivered prompt looks like.\n * - SUSTAINED. This is the one that matters most. A successful submit\n * legitimately passes THROUGH count==1 for up to ~2s while the TUI\n * repaints, before the echo makes it 2. Sampling once inside that\n * window reports a strand that has already gone through, which was\n * a real false warning during development. Requiring every sample\n * to agree removes it.\n *\n * Cost when all is well: the first sample usually shows 0 or 2 and the\n * function returns immediately.\n */\nasync function isTextStranded(paneId: string, probe: string): Promise<boolean> {\n for (let i = 0; i < SUBMIT_VERIFY_SAMPLES; i++) {\n if (i > 0) await currentSleep(SUBMIT_VERIFY_INTERVAL_MS);\n const capture = await capturePane(paneId, { lines: 50 }).catch(() => undefined);\n if (capture === undefined) return false;\n if (paneLooksBusy(capture)) return false;\n let count = 0;\n let idx = capture.indexOf(probe);\n while (idx !== -1 && count < 2) {\n count++;\n idx = capture.indexOf(probe, idx + probe.length);\n }\n if (count !== 1) return false;\n }\n return true;\n}\n\n/** Default handler for an unconfirmed send: warn on stderr. Loud by\n * design — the whole bug was that this case was silent. */\nfunction defaultUndeliveredWarning(warning: SendWarning): void {\n console.warn(`warning: ${warning.message}`);\n}\n\n/**\n * Send a single line of text to a pane and submit it.\n *\n * Sequence:\n * 0. wait until the pane is not mid-modal (see awaitPaneQuiescence)\n * 1. exit copy mode (silent if not in copy mode)\n * 2. load text into a uniquely-named tmux buffer\n * 3. paste with bracketed-paste mode (-p) so apps treat as literal text;\n * delete buffer after paste (-d); preserve LF (-r)\n * 4. wait MU_SEND_DELAY_MS (default 500) so the agent ingests the text\n * 5. send Enter as a real key event\n * 6. confirm the Enter took; re-send it if the text is stranded\n *\n * DELIVERY CONTRACT (dogfood_send_after_new_dropped): exit 0 must not\n * be able to mean \"silently dropped\". After Enter, the pane is checked\n * for text left STRANDED in the input box — typed but unsubmitted,\n * which is what a swallowed Enter looks like. If found, Enter is\n * re-sent (up to SUBMIT_RETRIES times), which recovers the prompt.\n * `onUndelivered` fires only if it is STILL stranded afterwards.\n *\n * Not a throw, deliberately: by then the text is in the agent's input\n * box, so the operator's next `mu agent read` shows it and a bare Enter\n * finishes the job. Failing the command would also break every existing\n * caller for a usually-recoverable condition. The warning is loud and\n * names the recovery step.\n *\n * Naive `send-keys \"<text>\"` would let characters like /, ?, f, : be\n * interpreted by the agent's TUI or by tmux's copy mode. Always use this.\n */\nexport async function sendToPane(\n paneId: string,\n text: string,\n opts: SendOptions = {},\n): Promise<void> {\n assertValidPaneId(paneId);\n\n // 0. Wait out an in-flight modal / re-init. A TUI rendering one\n // swallows the Enter, stranding the paste in the input box.\n const readinessMs = opts.readinessMs ?? defaultSendReadinessMs();\n const quiesced = await awaitPaneQuiescence(paneId, readinessMs);\n\n // 1. Exit copy mode silently. -q suppresses errors when not in copy mode.\n const copyResult = await currentExecutor([\"copy-mode\", \"-q\", \"-t\", paneId]);\n // Even with -q, some tmux versions report errors. Swallow non-fatal.\n if (copyResult.exitCode !== 0 && /can't find pane|no current target/i.test(copyResult.stderr)) {\n throw new TmuxError(\n [\"copy-mode\", \"-q\", \"-t\", paneId],\n copyResult.stderr,\n copyResult.stdout,\n copyResult.exitCode,\n );\n }\n\n // Empty text: tmux refuses to paste an empty buffer (\"no buffer\"), so\n // press a bare Enter instead (dismisses a \"Press Enter\" prompt).\n if (text === \"\") {\n await tmux([\"send-keys\", \"-t\", paneId, \"Enter\"]);\n return;\n }\n\n // 2. Load text into a uniquely-named buffer.\n const bufferName = `mu-send-${process.pid}-${Date.now()}-${Math.floor(Math.random() * 1e6)}`;\n await tmux([\"set-buffer\", \"-b\", bufferName, text]);\n\n // 3. Bracketed paste: -p wraps in \\e[200~...\\e[201~ so apps see literal\n // text; -d deletes buffer after paste; -r preserves LF (no CR conversion).\n try {\n await tmux([\"paste-buffer\", \"-p\", \"-d\", \"-r\", \"-b\", bufferName, \"-t\", paneId]);\n } catch (err) {\n // Best-effort buffer cleanup if paste failed before -d took effect.\n await currentExecutor([\"delete-buffer\", \"-b\", bufferName]).catch(() => {});\n throw err;\n }\n\n // 4. Wait for the agent CLI to ingest the pasted text.\n const delay = opts.delayMs ?? defaultSendDelayMs();\n if (delay > 0) await currentSleep(delay);\n\n // 5. Submit. Enter must be a real key event, not part of the paste.\n await tmux([\"send-keys\", \"-t\", paneId, \"Enter\"]);\n\n // 6. Confirm the Enter took. readinessMs: 0 opts out of the whole\n // wrapper (bare 4-command protocol; unit tests mock captures away).\n if (readinessMs <= 0) return;\n\n const probe = pasteProbe(text);\n if (probe.length === 0) return; // nothing observable to verify\n\n for (let attempt = 0; attempt <= SUBMIT_RETRIES; attempt++) {\n if (!(await isTextStranded(paneId, probe))) return;\n if (attempt === SUBMIT_RETRIES) break;\n // Sustained strand on a calm pane: the Enter was swallowed. Re-send.\n await tmux([\"send-keys\", \"-t\", paneId, \"Enter\"]);\n await currentSleep(SUBMIT_SETTLE_MS);\n }\n\n const warn = opts.onUndelivered ?? defaultUndeliveredWarning;\n warn({\n paneId,\n reason: quiesced ? \"paste-vanished\" : \"busy-at-deadline\",\n message: `send to ${paneId} was NOT submitted: the text is still sitting unsubmitted in the pane's input box after ${SUBMIT_RETRIES + 1} Enter attempts. The agent has NOT seen it. Press Enter in the pane, or re-send.`,\n });\n}\n\n// ─── Capture ───────────────────────────────────────────────────────────\n\n/**\n * Read pane scrollback as plain text (no ANSI escapes).\n *\n * - No options: full scrollback (`-S - -E -`)\n * - `lines: 0`: visible pane only\n * - `lines: N`: last N lines, ending at the last non-blank row\n *\n * `-S -N` counts from the TOP of the visible screen, so tmux returns the\n * N rows above the screen plus every visible row, blank rows below the\n * cursor included. That range always holds the last N non-blank-ended\n * lines, so drop the trailing blank rows and keep the last N.\n */\nexport async function capturePane(paneId: string, opts: CaptureOptions = {}): Promise<string> {\n assertValidPaneId(paneId);\n const args = [\"capture-pane\", \"-t\", paneId, \"-p\"];\n if (opts.lines === undefined) {\n args.push(\"-S\", \"-\", \"-E\", \"-\");\n } else if (opts.lines > 0) {\n args.push(\"-S\", `-${opts.lines}`);\n return lastLines(await tmux(args), opts.lines);\n }\n return tmux(args);\n}\n\n/** The last `n` lines of `text` after dropping trailing blank lines.\n * Keeps a trailing newline when `text` had one (tmux prints one). */\nfunction lastLines(text: string, n: number): string {\n const lines = text.split(\"\\n\");\n let end = lines.length;\n while (end > 0 && (lines[end - 1] ?? \"\").trim() === \"\") end--;\n if (end === 0) return \"\";\n const kept = lines.slice(Math.max(0, end - n), end).join(\"\\n\");\n return text.endsWith(\"\\n\") ? `${kept}\\n` : kept;\n}\n\n// ─── Backend record ────────────────────────────────────────────────────\n\n/**\n * True iff tmux can be reached right now. `tmux -V` rather than a PATH\n * probe: a tmux binary that cannot execute (broken install, missing\n * libtinfo) is not an available backend, and the version call is the\n * cheapest thing that proves the binary actually runs.\n *\n * Deliberately does NOT require `$TMUX` — mu creates its own detached\n * sessions, so a usable tmux server is enough. `$TMUX` only tells us\n * whether the CALLER is inside a pane, which is a detection-precedence\n * signal (see ./detect.ts), not an availability one.\n */\nasync function tmuxAvailable(): Promise<boolean> {\n try {\n await tmux([\"-V\"]);\n return true;\n } catch {\n return false;\n }\n}\n\n// ─── Attach ────────────────────────────────────────────────────\n//\n// From INSIDE a tmux client the right verb is `switch-client`, which\n// repoints the existing client and returns immediately. From outside\n// it is `attach-session` followed by a separate `select-window`: `tmux\n// attach -t session:window` does not reliably select the window across\n// tmux versions, and the select must run after the attach detaches.\n\nfunction attachTargetSpec(target: AttachTarget): string {\n return target.window === undefined ? target.session : `${target.session}:${target.window}`;\n}\n\nexport function attachHint(target: AttachTarget): string {\n const spec = attachTargetSpec(target);\n if (target.inside === true) return `tmux switch-client -t ${spec}`;\n if (target.window === undefined) return `tmux attach -t ${target.session}`;\n return `tmux attach -t ${target.session} && tmux select-window -t ${spec}`;\n}\n\nexport function attachCommands(target: AttachTarget): readonly MuxCommand[] {\n const spec = attachTargetSpec(target);\n if (target.inside === true) {\n return [{ command: \"tmux\", args: [\"switch-client\", \"-t\", spec] }];\n }\n const steps: MuxCommand[] = [{ command: \"tmux\", args: [\"attach-session\", \"-t\", target.session] }];\n if (target.window !== undefined) {\n // Best-effort: if it fails the user is at least in the right session.\n steps.push({ command: \"tmux\", args: [\"select-window\", \"-t\", spec], optional: true });\n }\n return steps;\n}\n\n// ─── Diagnostics ────────────────────────────────────────────────\n\nexport function paneNotFoundNextSteps(paneId: string): NextStep[] {\n return [\n {\n intent: `Verify the pane id ${paneId} actually exists`,\n command: `tmux display-message -t ${paneId} -p '#{pane_id} #{pane_title}'`,\n },\n {\n intent: \"List all live panes across all sessions\",\n command:\n \"tmux list-panes -a -F '#{session_name}:#{window_id}.#{pane_id}\\\\t#{pane_title}\\\\t#{pane_current_command}'\",\n },\n ];\n}\n\n/**\n * Version probe + the two ambient env facts tmux exposes. Returns DATA;\n * `mu doctor` owns every string the user sees, so a second backend\n * reporting different env vars needs no doctor change.\n */\nexport async function healthCheck(): Promise<MuxHealth> {\n let version: string | null = null;\n try {\n version = (await tmux([\"-V\"])).trim();\n } catch {\n version = null;\n }\n return {\n name: \"tmux\",\n ok: version !== null,\n version,\n env: [\n { name: \"$TMUX\", value: process.env.TMUX ?? null },\n { name: \"$TMUX_PANE\", value: process.env.TMUX_PANE ?? null },\n ],\n remediation: \"install tmux ≥ 3.0\",\n };\n}\n\n/** `MuxBackend` with tmux's synchronous attach methods: SDK callers of\n * `tmuxBackend.attachHint()` keep getting a string, not a Promise. */\nexport interface TmuxBackend extends MuxBackend {\n attachHint(target: AttachTarget): string;\n attachCommands(target: AttachTarget): readonly MuxCommand[];\n}\n\n/**\n * The tmux implementation of `MuxBackend`. A frozen record of the\n * module's functions — no state of its own, so swapping backends is a\n * pointer assignment (see ./detect.ts).\n */\nexport const tmuxBackend: TmuxBackend = Object.freeze({\n name: \"tmux\" as const,\n available: tmuxAvailable,\n\n isValidPaneId,\n assertValidPaneId,\n\n listSessions,\n sessionExists,\n newSession,\n newSessionWithPane,\n killSession,\n\n listWindows,\n newWindow,\n selectLayout,\n\n listPanes,\n listPanesInSession,\n splitWindow,\n killPane,\n paneExists,\n paneTTY,\n\n setPaneTitle,\n lockPaneTitle,\n getPaneTitle,\n currentAgentName,\n currentSessionName,\n\n sendToPane,\n capturePane,\n\n enableMuPaneBordersForSession,\n enableMuPaneBordersForPane,\n\n attachHint,\n attachCommands,\n\n paneNotFoundNextSteps,\n healthCheck,\n});\n","// mu — herdr substrate (TOPOLOGY half).\n//\n// Single source of truth for all herdr interactions. Every herdr\n// invocation goes through `herdr(args)`, which wraps child_process and produces\n// structured `HerdrError`s carrying args + the server's JSON error.\n//\n// ─── The mapping ──────────────────────────────────────────────────────\n//\n// herdr's own \"session\" is SERVER-level (one socket per named session),\n// so it is NOT the workstream unit. The locked mapping (see\n// docs/architecture/mux.md § \"One mux session per workstream\") is:\n//\n// mu workstream = herdr WORKSPACE, labelled `mu-<name>`\n// mu window = herdr TAB\n// mu agent = herdr PANE\n//\n// mu addresses workspaces BY LABEL (`MuxSession.name`), because that is\n// the only handle mu persists. herdr addresses them by opaque id (`w1`).\n// Every session-taking method therefore resolves label → id first; see\n// `resolveWorkspaceId`.\n//\n// ─── Protocol notes ───────────────────────────────────────────────────\n//\n// - Every command emits JSON on stdout under `.result`. IDs are READ\n// from creation responses, never predicted or constructed. herdr's\n// skill doc is explicit about this and closed ids are not reused.\n// - `--no-focus` on EVERY mutating call. mu must never steal the\n// user's focus out from under them.\n// - Server errors are JSON on STDERR with exit 1 → `HerdrError`\n// (a `MuxError`, exit 5: the substrate said no).\n// - SYNTAX errors exit 2 → `HerdrSyntaxError`, which is deliberately\n// NOT a `MuxError`. A herdr CLI that renamed a flag under us is a\n// BUG IN MU, and must not masquerade as \"herdr is down\".\n//\n// ─── Scope ────────────────────────────────────────────────────────────\n//\n// This module implements ALL of `MuxBackend` for herdr: sessions,\n// windows, panes, pane-id validation, availability, identity, send,\n// capture, native pane status, and the two-step spawn\n// (`startAgentInPane`).\n//\n// ─── Two exceptions to \"everything is JSON\" ───────────────────────────\n//\n// `herdr status` and `herdr pane read` both emit PLAIN TEXT. They go\n// through `currentExecutor` directly rather than `herdr()`, which would\n// reject their unparseable stdout as CLI drift.\n//\n// ─── Why spawn is two steps ───────────────────────────────────────────\n//\n// herdr has NO create-and-run form: `workspace create` / `tab create` /\n// `pane split` always start a plain shell, and `agent start` never\n// creates, splits or moves layout — it requires an ALREADY-EXISTING\n// pane sitting at its interactive prompt. So the creation verbs below\n// REFUSE a non-empty `opts.command` (silently dropping it would leave\n// an empty shell mu believes hosts an agent — the worst failure mode),\n// and `startAgentInPane` is the second step mu calls afterwards.\n// See `MuxBackend.startAgentInPane` for how spawn.ts branches on it.\n\nimport { execFileCapture } from \"../exec-file.js\";\nimport type { NextStep } from \"../output.js\";\nimport { sleep } from \"./tmux.js\";\nimport {\n type AttachTarget,\n type CaptureOptions,\n type MuxBackend,\n type MuxCommand,\n MuxError,\n type MuxHealth,\n type MuxPane,\n type MuxPaneStatus,\n type MuxSession,\n type MuxWindow,\n type NewSessionOptions,\n type NewSessionWithPaneOptions,\n type NewWindowOptions,\n PaneNotFoundError,\n type SendOptions,\n type SendWarning,\n type SplitWindowOptions,\n type StartAgentInPaneOptions,\n} from \"./types.js\";\n\n// ─── Error types ───────────────────────────────────────────────────────\n\n/**\n * \"herdr itself failed\" — the server returned a JSON error, or the\n * binary could not be reached. A `MuxError`, so `handle()` maps the\n * whole family to exit 5 with one `instanceof`. Mirrors `TmuxError`.\n */\nexport class HerdrError extends MuxError {\n constructor(\n public readonly args: readonly string[],\n public readonly stderr: string,\n public readonly stdout: string,\n public readonly exitCode: number | null,\n /** herdr's machine-readable error code (e.g. `pane_not_found`), when\n * the stderr payload parsed as the documented JSON envelope. */\n public readonly code?: string,\n ) {\n const detail = parseErrorEnvelope(stderr)?.message ?? (stderr.trim() || stdout.trim());\n super(`herdr ${args.join(\" \")} failed (exit ${exitCode}): ${detail || \"no output\"}`);\n this.name = \"HerdrError\";\n }\n override errorNextSteps(): NextStep[] {\n return [\n { intent: \"Run health check\", command: \"mu doctor\" },\n { intent: \"Verify the herdr server is running\", command: \"herdr status\" },\n {\n intent: \"Check the failing herdr command in isolation\",\n command: `herdr ${this.args.join(\" \")}`,\n },\n ];\n }\n}\n\n/**\n * herdr rejected our ARGUMENTS (exit 2). Deliberately not a `MuxError`:\n * the substrate is healthy and mu asked it something ungrammatical.\n * That is a bug in this file — most likely CLI drift after a herdr\n * upgrade — and must surface as one instead of being swallowed into\n * the \"herdr is down\" bucket, where it would waste hours.\n */\nexport class HerdrSyntaxError extends Error {\n override readonly name = \"HerdrSyntaxError\";\n constructor(\n public readonly args: readonly string[],\n public readonly output: string,\n ) {\n super(\n `herdr rejected the command line (exit 2) — this is a bug in mu, not a herdr outage. ` +\n `Ran: herdr ${args.join(\" \")}. herdr said: ${output.trim().split(\"\\n\")[0] ?? \"(no output)\"}`,\n );\n }\n}\n\n/**\n * `mu agent spawn --cli <key>` named something herdr does not recognise\n * as an interactive agent kind.\n *\n * A REFUSAL, not a fallback. herdr's `pane run <command>` would happily\n * start the binary, but herdr would then never classify that pane, and\n * on this backend herdr's report is mu's runtime state source. A pane\n * mu can start but never observe is the same family of failure as a pane mu records\n * with nothing running in it: it looks fine and lies forever.\n *\n * Not a `MuxError`: the substrate is healthy and answered precisely.\n * This is an operator asking for something the active backend cannot\n * do, which `handle()` maps to exit 2 alongside the usage family.\n *\n * herdr is the AUTHORITY on the kind list — mu does not hardcode one,\n * it forwards `--cli` and translates herdr's rejection. A herdr release\n * that adds a kind therefore works without a mu change.\n */\nexport class HerdrUnsupportedCliError extends Error {\n override readonly name = \"HerdrUnsupportedCliError\";\n constructor(\n public readonly cli: string,\n public readonly detail: string,\n ) {\n super(\n `herdr does not recognise --cli ${cli} as an interactive agent kind, so it cannot classify that pane's status. herdr said: ${detail}`,\n );\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"List the agent kinds this herdr knows\",\n command: \"herdr agent start --help\",\n },\n {\n intent: \"Spawn with a kind herdr supports\",\n command: \"mu agent spawn <name> --cli pi -w <workstream>\",\n },\n {\n intent: \"Or spawn this cli under tmux, which runs any command\",\n command: `MU_MUX=tmux mu agent spawn <name> --cli ${this.cli}`,\n },\n ];\n }\n}\n\n/**\n * The operator pinned an exact command line — `--command \"…\"` or\n * `MU_<UPPER_CLI>_COMMAND` — and herdr cannot honour it.\n *\n * `herdr agent start --kind <k>` resolves the canonical executable\n * ITSELF; there is no \"use this binary instead\" flag. Args after `--`\n * are passed to the agent, NOT used to choose it (verified against\n * 0.8.0: `agent start x --kind pi -- --model m` reports `argv:[\"pi\"]`;\n * 0.9.0 still exposes no override flag), so forwarding an override\n * there would append a binary\n * NAME as an argument and start the wrong thing while reporting success.\n *\n * Accepting the override and not honouring it is the one outcome ruled\n * out, so mu refuses and names the variable.\n */\nexport class HerdrCommandOverrideError extends Error {\n override readonly name = \"HerdrCommandOverrideError\";\n constructor(\n public readonly cli: string,\n public readonly command: string,\n /** The `MU_<UPPER_CLI>_COMMAND` var, when that is where the override\n * came from; undefined for an explicit `--command`. */\n public readonly envVar?: string,\n ) {\n super(\n (envVar === undefined\n ? `--command ${JSON.stringify(command)} cannot be honoured on the herdr backend`\n : `${envVar}=${command} cannot be honoured on the herdr backend`) +\n `: 'herdr agent start --kind ${cli}' resolves the executable itself and has no override flag. ` +\n `mu refuses rather than starting a different binary than you asked for.`,\n );\n }\n errorNextSteps(): NextStep[] {\n return [\n ...(this.envVar === undefined\n ? [\n {\n intent: \"Spawn without --command so herdr resolves the agent itself\",\n command: `mu agent spawn <name> --cli ${this.cli} -w <workstream>`,\n },\n ]\n : [\n {\n intent: `Unset the override so herdr resolves ${this.cli} itself`,\n command: `unset ${this.envVar}`,\n },\n ]),\n {\n intent: \"Or spawn under tmux, which runs the command you name\",\n command: `MU_MUX=tmux mu agent spawn <name> --cli ${this.cli}`,\n },\n ];\n }\n}\n\n/** herdr's refusal (0.9.0+) to close a workspace that has linked\n * worktree workspaces without explicit group intent. */\nconst GROUP_CLOSE_REQUIRED_CODE = \"workspace_group_close_required\";\n\n/**\n * `mu workstream destroy` asked herdr to close the workstream's\n * workspace, and herdr refused because worktree workspaces are linked\n * to it (herdr 0.9.0+).\n *\n * mu does NOT retry with `--group`. Those sibling workspaces are not\n * mu's: they were created by `herdr worktree`, they host panes mu never\n * spawned, and mu has no way to know whether the user still wants them.\n * Closing them to satisfy a teardown would destroy unsaved work with no\n * undo, which is the one outcome ruled out.\n *\n * Not a `MuxError`: the substrate is healthy and answered precisely.\n * This is a decision only the operator can make, so it lands in the\n * usage lane (exit 2) beside the other herdr refusals. Thrown BEFORE\n * any DB rows are deleted — `teardownWorkstream` kills the mux session\n * first for exactly this reason — so the workstream is left intact and\n * the command is safe to re-run.\n */\nexport class HerdrWorkspaceGroupCloseError extends Error {\n override readonly name = \"HerdrWorkspaceGroupCloseError\";\n constructor(\n public readonly session: string,\n public readonly workspaceId: string,\n public readonly detail: string,\n ) {\n super(\n `herdr refused to close workspace ${workspaceId} (${session}): it has linked worktree workspaces, ` +\n `which mu did not create and will not close on your behalf. herdr said: ${detail}`,\n );\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"See which workspaces are linked as a group\",\n command: \"herdr workspace list\",\n },\n {\n intent: \"Remove the worktree workspaces you no longer want\",\n command: \"herdr worktree remove <workspace-id>\",\n },\n {\n intent: \"Or close the whole group yourself, then re-run the teardown\",\n command: `herdr workspace close ${this.workspaceId} --group`,\n },\n ];\n }\n}\n\n/** A creation verb was handed a command to run. herdr cannot do that\n * in one step (see `rejectCommand`), so this is a bug in the caller:\n * spawn passes no command on herdr and calls `startAgentInPane`. */\nexport class HerdrNotImplementedError extends Error {\n override readonly name = \"HerdrNotImplementedError\";\n constructor(method: string) {\n super(\n `herdr backend: ${method} is not supported: herdr creation verbs always start a plain shell; ` +\n \"create the pane without a command, then start the agent with startAgentInPane\",\n );\n }\n}\n\n// ─── Pane / workspace / tab ID validation ──────────────────────────────\n//\n// herdr's public ids are opaque stable handles with a documented shape:\n// workspace `w1`, tab `w1:t1`, pane `w1:p1`. Pane ids are workspace-\n// qualified, so a pane MOVED between workspaces gets a NEW id — mu must\n// re-read it from `.result.move_result.pane.pane_id`, never reuse the old.\n//\n// This is exactly why `isValidPaneId` is a backend method: a tmux `%15`\n// must be rejected here, and a herdr `w1:p1` must be rejected by tmux.\n//\n// The ORDINALS ARE NOT DECIMAL. Verified on herdr 0.8.0 by opening 38\n// panes: the sequence runs `p1 … p9, pA, pB, … pH, pJ, pK, pM, pN, pP …\n// pZ, p10, p11 …` — Crockford base32 (digits plus A-Z minus I, L, O, U).\n// Workspace and tab ordinals use the same alphabet (`wA` after `w9`).\n// A decimal-only pattern therefore works for exactly nine panes and then\n// starts rejecting live ids, which on the spawn path is a TypeError on\n// the 10th agent in a workstream. Matched as an opaque `[0-9A-Z]+` run\n// rather than by spelling out the alphabet: mu's job is to tell a herdr\n// id from a tmux one, not to re-derive herdr's numbering.\n\nconst HERDR_ORDINAL = \"[0-9A-Z]+\";\nexport const PANE_ID_RE = new RegExp(`^w${HERDR_ORDINAL}:p${HERDR_ORDINAL}$`);\nconst WORKSPACE_ID_RE = new RegExp(`^w${HERDR_ORDINAL}$`);\nconst TAB_ID_RE = new RegExp(`^w${HERDR_ORDINAL}:t${HERDR_ORDINAL}$`);\n\nexport function isValidPaneId(s: string): boolean {\n return PANE_ID_RE.test(s);\n}\n\nexport function assertValidPaneId(s: string): void {\n if (!isValidPaneId(s)) {\n throw new TypeError(\n `invalid herdr pane id: ${JSON.stringify(s)} (expected ${PANE_ID_RE.source})`,\n );\n }\n}\n\n// ─── Executor (swappable for tests) ────────────────────────────────────\n\nexport interface HerdrExecResult {\n stdout: string;\n stderr: string;\n exitCode: number | null;\n}\n\nexport type HerdrExecutor = (args: readonly string[]) => Promise<HerdrExecResult>;\n\n/**\n * Optional `--session <name>` prefix spliced in front of every args\n * vector. When `MU_HERDR_SESSION=<name>` is set, mu drives a NAMED\n * herdr server (its own socket under\n * `~/.config/herdr/sessions/<name>/herdr.sock`) instead of the user's\n * default one. Mirrors `MU_TMUX_SOCKET`: it is the isolation seam any\n * integration test must use so the suite can never observe — or\n * destroy — the user's real panes.\n *\n * Read fresh on every call so a setup hook mutating the env mid-run\n * takes effect immediately.\n */\nfunction herdrGlobalFlags(): readonly string[] {\n const session = process.env.MU_HERDR_SESSION;\n if (session === undefined || session.length === 0) return [];\n return [\"--session\", session];\n}\n\nconst realExecutor: HerdrExecutor = (args) =>\n execFileCapture(\"herdr\", [...herdrGlobalFlags(), ...args]);\n\nlet currentExecutor: HerdrExecutor = realExecutor;\n\n/**\n * Install a custom executor (for tests). Returns the previous executor\n * so tests can restore it cleanly. Production code never calls this.\n * Required: the fast test tier may not shell out.\n */\nexport function setHerdrExecutor(executor: HerdrExecutor): HerdrExecutor {\n const previous = currentExecutor;\n currentExecutor = executor;\n return previous;\n}\n\n/** Restore the real (child_process-backed) executor. */\nexport function resetHerdrExecutor(): void {\n currentExecutor = realExecutor;\n}\n\n// ─── JSON envelope ─────────────────────────────────────────────────────\n\n/** herdr's error payload: `{\"error\":{\"code\":\"…\",\"message\":\"…\"},\"id\":\"…\"}`. */\ninterface HerdrErrorEnvelope {\n code: string;\n message: string;\n}\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\nfunction asString(v: unknown): string | undefined {\n return typeof v === \"string\" ? v : undefined;\n}\n\nfunction parseErrorEnvelope(stderr: string): HerdrErrorEnvelope | undefined {\n const trimmed = stderr.trim();\n if (trimmed.length === 0) return undefined;\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed);\n } catch {\n return undefined;\n }\n if (!isRecord(parsed)) return undefined;\n const err = parsed.error;\n if (!isRecord(err)) return undefined;\n const code = asString(err.code);\n const message = asString(err.message);\n if (code === undefined) return undefined;\n return { code, message: message ?? code };\n}\n\n/**\n * Run a herdr command and return the parsed `.result` object.\n *\n * The single point of contact with the herdr binary; every higher-level\n * operation in this module goes through it.\n *\n * Throws `HerdrSyntaxError` on exit 2 (mu bug), `HerdrError` on any\n * other non-zero exit (substrate failure).\n */\nexport async function herdr(args: readonly string[]): Promise<Record<string, unknown>> {\n const result = await currentExecutor(args);\n if (result.exitCode === 2) {\n throw new HerdrSyntaxError([...args], result.stderr || result.stdout);\n }\n if (result.exitCode !== 0) {\n throw new HerdrError(\n [...args],\n result.stderr,\n result.stdout,\n result.exitCode,\n parseErrorEnvelope(result.stderr)?.code,\n );\n }\n const trimmed = result.stdout.trim();\n if (trimmed.length === 0) return {};\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed);\n } catch {\n // A zero exit with unparseable stdout means the CLI stopped speaking\n // JSON — same class of problem as exit 2, but we cannot prove it is\n // ours, so keep it in the substrate bucket.\n throw new HerdrError([...args], result.stderr, result.stdout, result.exitCode);\n }\n if (!isRecord(parsed)) return {};\n const inner = parsed.result;\n return isRecord(inner) ? inner : {};\n}\n\n/** Like `herdr()` but returns undefined instead of throwing when the\n * server's error code is one of `tolerate`. Used for the idempotent\n * destructive verbs (\"succeeds even if it is already gone\"). */\nasync function herdrTolerating(\n args: readonly string[],\n tolerate: readonly string[],\n): Promise<Record<string, unknown> | undefined> {\n try {\n return await herdr(args);\n } catch (err) {\n if (err instanceof HerdrError && err.code !== undefined && tolerate.includes(err.code)) {\n return undefined;\n }\n throw err;\n }\n}\n\n// ─── Response shapes ───────────────────────────────────────────────────\n//\n// Narrow readers over herdr's JSON: they pull only the fields mu uses\n// and drop anything malformed, so one odd row never poisons a listing.\n\ninterface HerdrWorkspace {\n workspaceId: string;\n label: string;\n}\n\nfunction readWorkspace(v: unknown): HerdrWorkspace | undefined {\n if (!isRecord(v)) return undefined;\n const workspaceId = asString(v.workspace_id);\n if (workspaceId === undefined) return undefined;\n return { workspaceId, label: asString(v.label) ?? \"\" };\n}\n\nfunction readTab(v: unknown): MuxWindow | undefined {\n if (!isRecord(v)) return undefined;\n const id = asString(v.tab_id);\n if (id === undefined) return undefined;\n // herdr auto-labels a tab with its ordinal (\"1\"), which is the closest\n // analogue to a tmux window name; mu labels every tab it creates.\n return { id, name: asString(v.label) ?? \"\" };\n}\n\nfunction readPane(v: unknown): MuxPane | undefined {\n if (!isRecord(v)) return undefined;\n const paneId = asString(v.pane_id);\n if (paneId === undefined) return undefined;\n return {\n paneId,\n // herdr's optional `label` is what `pane rename` writes and is\n // therefore mu's pane-title equivalent.\n title: asString(v.label) ?? \"\",\n // herdr reports no foreground command on `pane list` (that costs a\n // `pane process-info` round trip per pane), but it does report the\n // agent kind it detected (`pi`, `claude`, `codex`, ...). That is\n // what `command` is used for: reconcile's orphan recogniser matches\n // it against the agent CLIs. Empty for a plain shell.\n command: asString(v.agent) ?? \"\",\n windowId: asString(v.tab_id),\n };\n}\n\nfunction readArray(result: Record<string, unknown>, key: string): unknown[] {\n const v = result[key];\n return Array.isArray(v) ? v : [];\n}\n\n// ─── Workspaces (= mu sessions) ────────────────────────────────────────\n\nasync function listWorkspaces(): Promise<HerdrWorkspace[]> {\n const result = await herdr([\"workspace\", \"list\"]);\n const out: HerdrWorkspace[] = [];\n for (const raw of readArray(result, \"workspaces\")) {\n const ws = readWorkspace(raw);\n if (ws) out.push(ws);\n }\n return out;\n}\n\nexport async function listSessions(): Promise<MuxSession[]> {\n return (await listWorkspaces()).map((ws) => ({ name: ws.label }));\n}\n\n/**\n * Resolve a mu session name (= herdr workspace LABEL) to herdr's opaque\n * workspace id. Returns undefined when no workspace carries that label.\n *\n * Labels are not unique in herdr — an unlabelled `workspace create`\n * defaults the label to the cwd's basename, so a user could plausibly\n * have two. mu only ever creates `mu-<workstream>` labels and refuses\n * duplicate workstream names, so the first match is the right one; the\n * ambiguity is inherent to addressing by label and is why every mutating\n * path resolves once and then works in ids.\n */\nasync function resolveWorkspaceId(name: string): Promise<string | undefined> {\n for (const ws of await listWorkspaces()) {\n if (ws.label === name) return ws.workspaceId;\n }\n return undefined;\n}\n\n/** Resolve or throw. Used by paths where a missing workspace is a real\n * substrate failure rather than an expected \"already gone\". */\nasync function requireWorkspaceId(name: string): Promise<string> {\n const id = await resolveWorkspaceId(name);\n if (id === undefined) {\n throw new HerdrError(\n [\"workspace\", \"list\"],\n `{\"error\":{\"code\":\"workspace_not_found\",\"message\":\"no herdr workspace labelled ${name}\"}}`,\n \"\",\n 1,\n \"workspace_not_found\",\n );\n }\n return id;\n}\n\nexport async function sessionExists(name: string): Promise<boolean> {\n return (await resolveWorkspaceId(name)) !== undefined;\n}\n\n/**\n * Create a herdr workspace labelled `name`.\n *\n * `opts.detached` is not a knob on herdr: mu ALWAYS passes `--no-focus`,\n * because stealing the user's focus is the one thing a background agent\n * manager must never do. A caller asking for `detached: false` gets a\n * detached workspace anyway; use `workspace focus` explicitly if you\n * really mean to move the user.\n *\n * `opts.windowName` labels the implicit first tab (see `labelRootTab`).\n */\nexport async function newSession(name: string, opts: NewSessionOptions = {}): Promise<void> {\n rejectCommand(\"newSession\", opts.command);\n const args = [\"workspace\", \"create\", \"--label\", name, \"--no-focus\"];\n if (opts.cwd) args.push(\"--cwd\", opts.cwd);\n appendEnvFlags(args, opts.env);\n await labelRootTab(await herdr(args), opts.windowName);\n}\n\n/**\n * Create a workspace and return its root pane's id.\n *\n * `opts.command` cannot be honoured here: `workspace create` always\n * starts a plain shell. Spawn runs the agent afterwards with\n * `startAgentInPane` (see `rejectCommand`).\n */\nexport async function newSessionWithPane(\n name: string,\n opts: NewSessionWithPaneOptions,\n): Promise<string> {\n rejectCommand(\"newSessionWithPane\", opts.command);\n const args = [\"workspace\", \"create\", \"--label\", name, \"--no-focus\"];\n if (opts.cwd) args.push(\"--cwd\", opts.cwd);\n appendEnvFlags(args, opts.env);\n const result = await herdr(args);\n const paneId = readCreatedPaneId(result, \"root_pane\", args);\n await labelRootTab(result, opts.windowName);\n return paneId;\n}\n\n/**\n * herdr labels a new workspace's implicit first tab \"1\". mu finds tabs\n * by window name (attach focuses the agent's tab, spawn reuses a tab by\n * `--tab`, init checks for `_mu`), so rename it to `windowName`, the\n * label `newWindow` gives every later tab. Load-bearing: an unlabelled\n * first tab is invisible to all three lookups. On failure the new\n * workspace is closed before the error propagates.\n */\nasync function labelRootTab(\n created: Record<string, unknown>,\n windowName: string | undefined,\n): Promise<void> {\n if (windowName === undefined || windowName.length === 0) return;\n const root = created.root_pane;\n const tab = created.tab;\n const tabId =\n (isRecord(root) ? asString(root.tab_id) : undefined) ??\n (isRecord(tab) ? asString(tab.tab_id) : undefined);\n try {\n if (tabId === undefined) {\n throw new HerdrError(\n [\"workspace\", \"create\"],\n `herdr response had no root tab id: ${JSON.stringify(created)}`,\n \"\",\n 0,\n );\n }\n await herdr([\"tab\", \"rename\", tabId, windowName]);\n } catch (err) {\n await closeCreatedWorkspace(created);\n throw err;\n }\n}\n\n/**\n * Best-effort rollback for a workspace this call just created: the caller\n * never got a pane id, so spawn's rollback cannot reach it. The original\n * error is what the caller must see, so a failed close is swallowed.\n */\nasync function closeCreatedWorkspace(created: Record<string, unknown>): Promise<void> {\n const ws = created.workspace;\n const root = created.root_pane;\n const id =\n (isRecord(ws) ? asString(ws.workspace_id) : undefined) ??\n (isRecord(root) ? asString(root.workspace_id) : undefined);\n if (id === undefined) return;\n try {\n await herdrTolerating([\"workspace\", \"close\", id], [\"workspace_not_found\"]);\n } catch {\n // Best effort; the rename error propagates.\n }\n}\n\n/**\n * Idempotent: succeeds even if the workspace is already gone.\n *\n * REFUSES, and does not retry with `--group`, when herdr reports\n * `workspace_group_close_required` (0.9.0+): the workspace has linked\n * worktree workspaces mu did not create, and closing the whole group\n * would take down panes outside this workstream. herdr's own skill doc\n * calls adding `--group` to bypass that error out by name. The operator\n * decides; mu names the command.\n */\nexport async function killSession(name: string): Promise<void> {\n const id = await resolveWorkspaceId(name);\n if (id === undefined) return;\n try {\n await herdrTolerating([\"workspace\", \"close\", id], [\"workspace_not_found\"]);\n } catch (err) {\n if (err instanceof HerdrError && err.code === GROUP_CLOSE_REQUIRED_CODE) {\n throw new HerdrWorkspaceGroupCloseError(name, id, err.message);\n }\n throw err;\n }\n}\n\n// ─── Tabs (= mu windows) ───────────────────────────────────────────────\n\nexport async function listWindows(session?: string): Promise<MuxWindow[]> {\n if (session !== undefined) {\n const id = await resolveWorkspaceId(session);\n // A workspace that vanished mid-reconcile lists as empty, matching\n // the tmux backend's behaviour for a dead session.\n if (id === undefined) return [];\n return readTabs(await herdr([\"tab\", \"list\", \"--workspace\", id]));\n }\n // Cross-workspace: herdr has no `--all`, so fan out and tag each row\n // with the workspace LABEL, which is what MuxWindow.sessionName means.\n const windows: MuxWindow[] = [];\n for (const ws of await listWorkspaces()) {\n for (const tab of readTabs(await herdr([\"tab\", \"list\", \"--workspace\", ws.workspaceId]))) {\n windows.push({ ...tab, sessionName: ws.label });\n }\n }\n return windows;\n}\n\nfunction readTabs(result: Record<string, unknown>): MuxWindow[] {\n const out: MuxWindow[] = [];\n for (const raw of readArray(result, \"tabs\")) {\n const tab = readTab(raw);\n if (tab) out.push(tab);\n }\n return out;\n}\n\n/**\n * Create a tab in `opts.session`'s workspace and return its root pane id.\n * `opts.command` is refused (see `rejectCommand`).\n */\nexport async function newWindow(opts: NewWindowOptions): Promise<string> {\n rejectCommand(\"newWindow\", opts.command);\n const args = [\"tab\", \"create\"];\n if (opts.session !== undefined) {\n args.push(\"--workspace\", await requireWorkspaceId(opts.session));\n }\n args.push(\"--label\", opts.name, \"--no-focus\");\n if (opts.cwd) args.push(\"--cwd\", opts.cwd);\n appendEnvFlags(args, opts.env);\n return readCreatedPaneId(await herdr(args), \"root_pane\", args);\n}\n\n/**\n * NO-OP. herdr has no layout-algorithm concept: splits are explicit and\n * geometry is the user's, not mu's. Kept so the contract is total.\n */\nexport async function selectLayout(_window: string, _layout: string): Promise<void> {\n // Intentionally empty.\n}\n\n// ─── Panes (= mu agents) ───────────────────────────────────────────────\n\n/**\n * List every pane in a workspace, addressed by mu session name (= label).\n *\n * Returns `[]` rather than throwing when the workspace is gone: herdr\n * closes a workspace when its last pane exits, so \"it was here a moment\n * ago\" is normal during reconciliation. Same contract as the tmux backend.\n */\nexport async function listPanesInSession(session: string): Promise<MuxPane[]> {\n const id = await resolveWorkspaceId(session);\n if (id === undefined) return [];\n const result = await herdrTolerating(\n [\"pane\", \"list\", \"--workspace\", id],\n [\"workspace_not_found\"],\n );\n if (result === undefined) return [];\n return readPanes(result).map((p) => ({ ...p, sessionName: session }));\n}\n\n/**\n * List panes.\n *\n * - `\"*\"` or omitted → every pane in every workspace, tagged with its\n * workspace label. (tmux's default target is \"the current session\";\n * herdr has no ambient current workspace outside a managed pane, so\n * `$HERDR_WORKSPACE_ID` is consulted first and \"everything\" is the\n * fallback.)\n * - a workspace id (`w1`) → that workspace.\n * - a tab id (`w1:t2`) → that tab's panes.\n * - a mu session name → that workspace, by label.\n */\nexport async function listPanes(target?: string): Promise<MuxPane[]> {\n if (target !== undefined && target !== \"*\") {\n if (TAB_ID_RE.test(target)) {\n const workspaceId = target.split(\":\")[0] ?? target;\n const panes = readPanes(await herdr([\"pane\", \"list\", \"--workspace\", workspaceId]));\n return panes.filter((p) => p.windowId === target);\n }\n if (WORKSPACE_ID_RE.test(target)) {\n return readPanes(await herdr([\"pane\", \"list\", \"--workspace\", target]));\n }\n return listPanesInSession(target);\n }\n const ambient = process.env.HERDR_WORKSPACE_ID;\n if (target === undefined && ambient !== undefined && WORKSPACE_ID_RE.test(ambient)) {\n return readPanes(await herdr([\"pane\", \"list\", \"--workspace\", ambient]));\n }\n const panes: MuxPane[] = [];\n for (const ws of await listWorkspaces()) {\n for (const pane of readPanes(await herdr([\"pane\", \"list\", \"--workspace\", ws.workspaceId]))) {\n panes.push({ ...pane, sessionName: ws.label });\n }\n }\n return panes;\n}\n\nfunction readPanes(result: Record<string, unknown>): MuxPane[] {\n const out: MuxPane[] = [];\n for (const raw of readArray(result, \"panes\")) {\n const pane = readPane(raw);\n if (pane) out.push(pane);\n }\n return out;\n}\n\n/**\n * Split a pane and return the new pane's id.\n *\n * `opts.horizontal` maps to herdr's `--direction`: horizontal (mu's\n * default, side-by-side) is `right`; a vertical split is `down`.\n * `opts.target` must be a herdr pane id — herdr splits panes, not\n * windows, so there is no \":WindowName\" form to accept.\n */\nexport async function splitWindow(opts: SplitWindowOptions): Promise<string> {\n rejectCommand(\"splitWindow\", opts.command);\n assertValidPaneId(opts.target);\n const args = [\n \"pane\",\n \"split\",\n opts.target,\n \"--direction\",\n opts.horizontal === false ? \"down\" : \"right\",\n \"--no-focus\",\n ];\n if (opts.cwd) args.push(\"--cwd\", opts.cwd);\n appendEnvFlags(args, opts.env);\n return readCreatedPaneId(await herdr(args), \"pane\", args);\n}\n\n/** Idempotent: succeeds even if the pane is already gone. */\nexport async function killPane(paneId: string): Promise<void> {\n assertValidPaneId(paneId);\n await herdrTolerating([\"pane\", \"close\", paneId], [\"pane_not_found\", \"workspace_not_found\"]);\n}\n\nexport async function paneExists(paneId: string): Promise<boolean> {\n if (!isValidPaneId(paneId)) return false;\n const pane = await getPane(paneId);\n return pane !== undefined;\n}\n\n/** `pane get`, or undefined when the pane (or its workspace) is gone. */\nasync function getPane(paneId: string): Promise<MuxPane | undefined> {\n const result = await herdrTolerating(\n [\"pane\", \"get\", paneId],\n [\"pane_not_found\", \"workspace_not_found\"],\n );\n if (result === undefined) return undefined;\n return readPane(result.pane);\n}\n\n/**\n * Look up the TTY device path backing a pane (e.g. `/dev/pts/3`). Used\n * by `mu agent kick` to signal the foreground process group directly.\n *\n * herdr reports the pane's `shell_pid` rather than a TTY, so mu resolves\n * the device through `/proc/<pid>/fd/0`. That is Linux-only by\n * construction; on a kernel without procfs this throws a `HerdrError`\n * naming the limitation rather than returning a plausible-looking lie.\n *\n * Throws `PaneNotFoundError` when the pane has vanished.\n */\nexport async function paneTTY(paneId: string): Promise<string> {\n assertValidPaneId(paneId);\n const result = await herdrTolerating(\n [\"pane\", \"process-info\", \"--pane\", paneId],\n [\"pane_not_found\", \"workspace_not_found\"],\n );\n if (result === undefined) throw new PaneNotFoundError(paneId, herdrBackend);\n const info = result.process_info;\n const pid = isRecord(info) ? info.shell_pid : undefined;\n if (typeof pid !== \"number\") throw new PaneNotFoundError(paneId, herdrBackend);\n const { readlink } = await import(\"node:fs/promises\");\n try {\n return await readlink(`/proc/${pid}/fd/0`);\n } catch (err) {\n throw new HerdrError(\n [\"pane\", \"process-info\", \"--pane\", paneId],\n `cannot resolve the TTY for herdr pane ${paneId} (shell pid ${pid}) via /proc: ${String(err)}`,\n \"\",\n 1,\n );\n }\n}\n\n// ─── Identity ──────────────────────────────────────────────────────────\n\n/** herdr's pane `label` is mu's pane title. */\n/** herdr labels are not rewritten by OSC titles: nothing to lock. */\nexport async function lockPaneTitle(_paneId: string): Promise<void> {}\n\nexport async function setPaneTitle(paneId: string, title: string): Promise<void> {\n assertValidPaneId(paneId);\n await herdr([\"pane\", \"rename\", paneId, title]);\n}\n\nexport async function getPaneTitle(paneId: string): Promise<string | undefined> {\n if (!isValidPaneId(paneId)) return undefined;\n const pane = await getPane(paneId).catch(() => undefined);\n if (pane === undefined) return undefined;\n return pane.title.length > 0 ? pane.title : undefined;\n}\n\n/**\n * The agent name of the pane this process is running in, read from the\n * `$HERDR_PANE_ID` that herdr injects into every managed pane.\n *\n * Fallback rung only: `$MU_AGENT_NAME` is checked first by\n * `src/tasks/claim.ts` and is backend-independent. Titles are composed\n * as `name · task_id · <glyph>`, so the name is the first token.\n */\nexport async function currentAgentName(): Promise<string | undefined> {\n const paneId = process.env.HERDR_PANE_ID;\n if (paneId === undefined || !isValidPaneId(paneId)) return undefined;\n const title = await getPaneTitle(paneId);\n if (title === undefined) return undefined;\n const idx = title.indexOf(\" · \");\n return idx === -1 ? title.trim() : title.slice(0, idx).trim();\n}\n\n/**\n * Label of the workspace the CALLER is running inside, or undefined\n * outside a managed pane. Backs the `mu-<name>` rung of workstream\n * auto-detection.\n *\n * herdr injects `$HERDR_WORKSPACE_ID` into every pane it manages, so\n * this is one lookup rather than tmux's `display-message -p '#S'`. The\n * env var carries the opaque id; mu keys on the LABEL, so resolve it.\n */\nexport async function currentSessionName(): Promise<string | undefined> {\n const workspaceId = process.env.HERDR_WORKSPACE_ID;\n if (workspaceId === undefined || !WORKSPACE_ID_RE.test(workspaceId)) return undefined;\n for (const ws of await listWorkspaces()) {\n if (ws.workspaceId === workspaceId) return ws.label;\n }\n return undefined;\n}\n\n// ─── IO ────────────────────────────────────────────────────────────────\n//\n// THE SEND PROTOCOL IS ONE CALL. Read the header of ./tmux.ts for what\n// that replaces: six steps, of which THREE (awaitPaneQuiescence,\n// the MU_SEND_DELAY_MS gap, and the confirm-the-Enter-took retry loop)\n// exist purely because a TUI rendering a modal SWALLOWS a `send-keys\n// Enter`, stranding the pasted text while `mu agent send` reports exit 0\n// (dogfood_send_after_new_dropped).\n//\n// `herdr agent prompt` submits the text AND an encoded Enter atomically,\n// honouring the pane's live bracketed-paste mode, so the Enter cannot be\n// separated from the paste and cannot be swallowed. There is nothing\n// left for a quiescence poll to protect against — porting one here would\n// re-add latency to work around a bug this substrate does not have.\n//\n// Do not add a scrollback poll to this file. If a send ever looks\n// unconfirmed on herdr, that is a herdr bug, and the `agent_prompt_\n// stalled` guard below is how it surfaces.\n\n// ─── Spawn, step 2 ─────────────────────────────────────────────────────\n//\n// The creation verbs above make a BARE pane; this turns it into a running\n// agent. Both halves exist because herdr has no create-and-run form.\n\n/**\n * Retry budget for `agent start` while herdr reports the target pane is\n * not yet an available shell.\n *\n * VERIFIED RACE (0.8.0): `agent start` immediately after `pane split`\n * fails `agent_pane_busy` ~100% of the time; with a 200ms gap it\n * succeeded every time. The pane exists the moment split returns, but its\n * shell has not drawn a prompt yet, and `agent start` requires an\n * interactive prompt with nothing in the foreground.\n *\n * A retry rather than a fixed pre-sleep: the condition is observable, so\n * mu polls instead of guessing a constant that is simultaneously too long\n * for a fast box and too short for a loaded one. ~3s nominal, because\n * losing the race means a rolled-back spawn while a pane that never frees\n * up is a real failure and must not be spun on forever. Counted in\n * ATTEMPTS not wall-clock, so `setSleepForTests` alone makes the loop\n * instant and deterministic in the fast tier.\n */\nconst PANE_READY_RETRY_INTERVAL_MS = 50;\nconst PANE_READY_MAX_ATTEMPTS = 60;\n\n/**\n * Turn an existing bare pane into a running agent, and return only once\n * herdr considers that agent ready for input.\n *\n * `herdr agent start <name> --kind <cli> --pane <id>` blocks until herdr\n * has DETECTED the expected agent in that terminal and it is\n * interactive-ready (30s default timeout, herdr's own). That subsumes\n * mu's tmux-side `awaitSpawnLiveness` scrollback polling completely,\n * which is why `src/agents/spawn.ts` skips it when a backend implements\n * this method. Nothing here re-implements it.\n *\n * Three refusals, all deliberate (see each error class):\n * - an operator-pinned command → `HerdrCommandOverrideError`\n * - a `--cli` herdr does not know → `HerdrUnsupportedCliError`\n * - an agent name herdr rejects → the raw `HerdrError`\n * On any of them nothing has started, and the caller's rollback kills the\n * bare pane. No path leaves mu holding an agent row for a pane with\n * nothing running in it.\n *\n * Addressed BY PANE ID: the herdr-level agent NAME is cleared when the\n * occupant exits, so the pane id is the only durable handle (and the\n * only one mu persists). Matching `sendToPane`'s choice.\n */\nexport async function startAgentInPane(opts: StartAgentInPaneOptions): Promise<void> {\n assertValidPaneId(opts.paneId);\n // Refuse BEFORE touching the server: an override we cannot honour is\n // decidable locally, and failing fast keeps the pane pristine for the\n // caller's rollback.\n if (opts.commandSource !== \"cli-key\") {\n throw new HerdrCommandOverrideError(\n opts.cli,\n opts.command,\n // Name the env var only when that is actually where the override\n // came from; \"unset MU_PI_COMMAND\" is useless advice to someone who\n // typed --command.\n opts.commandSource === \"env\" ? envVarNameForCli(opts.cli) : undefined,\n );\n }\n const args = [\"agent\", \"start\", opts.name, \"--kind\", opts.cli, \"--pane\", opts.paneId];\n for (let attempt = 1; ; attempt += 1) {\n try {\n await herdr(args);\n return;\n } catch (err) {\n // An unknown --kind is a SYNTAX error to herdr's arg parser (exit\n // 2), because `--kind` is a closed enum. Everywhere else exit 2\n // means mu drifted from the CLI, so translate it here — an\n // operator typo must not read as \"bug in mu\".\n if (err instanceof HerdrSyntaxError) {\n throw new HerdrUnsupportedCliError(opts.cli, err.output.trim().split(\"\\n\")[0] ?? \"\");\n }\n const busy = err instanceof HerdrError && err.code === \"agent_pane_busy\";\n if (!busy || attempt >= PANE_READY_MAX_ATTEMPTS) throw err;\n await sleep(PANE_READY_RETRY_INTERVAL_MS);\n }\n }\n}\n\n/**\n * `MU_<UPPER_CLI>_COMMAND`, mirroring `envVarNameForCli` in\n * src/agents/spawn.ts. Duplicated rather than imported because the mux\n * cluster may not depend on the agent layer (imports run cluster →\n * root, never sideways into another feature); it is one string join and\n * `test/mux-herdr-spawn.test.ts` asserts the two stay identical.\n */\nfunction envVarNameForCli(cli: string): string {\n return `MU_${cli.toUpperCase().replace(/-/g, \"_\")}_COMMAND`;\n}\n\n// ─── IO (owned by mux-herdr-io) ────────────────────────────────────────\n\n/** herdr's error code for \"submitted, but the agent's lifecycle never\n * moved within its 5s guard\". Not an outage — a suspicious send. */\nconst PROMPT_STALLED_CODE = \"agent_prompt_stalled\";\n\n/** Codes meaning \"the pane hosts no RECOGNIZED agent\", so the `agent`\n * surface cannot address it and we fall back to the `pane` surface. */\nconst NO_AGENT_CODES: readonly string[] = [\"agent_not_found\", \"agent_not_recognized\"];\n\n/** Default handler for an unconfirmed send: warn on stderr. Loud by\n * design, exactly as on tmux — silence is the failure mode. */\nfunction defaultUndeliveredWarning(warning: SendWarning): void {\n console.warn(`warning: ${warning.message}`);\n}\n\n/**\n * Submit `text` to a pane and press Enter, atomically.\n *\n * WHICH SURFACE (topology note 9): `agent prompt` only accepts targets\n * herdr has RECOGNIZED as an agent — a plain shell pane is\n * `agent_not_found` there. mu therefore tries the agent surface FIRST\n * (the overwhelmingly common case: every mu-managed pane runs a coding\n * CLI, and it is the only surface that understands lifecycle state) and\n * falls back to `pane run`, herdr's atomic text+Enter for raw shells,\n * only when herdr says there is no agent. The happy path is one call;\n * the fallback path is two, and never polls.\n *\n * `opts.readinessMs === 0` drops `--wait`, the herdr analogue of tmux's\n * \"bare protocol\" opt-out: submit and return without waiting for a\n * settled state. Any other value is ignored — there is no readiness to\n * budget for. `opts.delayMs` is likewise meaningless here: the gap it\n * sizes does not exist. Neither is an error; the tmux-shaped knobs stay\n * accepted so callers need no backend branch.\n *\n * No `--until`: `--wait` already defaults to the first settled idle /\n * done / blocked, which is precisely what mu's callers want, and herdr's\n * skill doc calls repeating those defaults a bug.\n *\n * DELIVERY CONTRACT, same as tmux: an unconfirmed send WARNS and keeps\n * going, never throws. herdr returns `agent_prompt_stalled` when a\n * prompt from a non-working state produces no lifecycle change within\n * 5s — the same observable as tmux's stranded paste, so it maps onto the\n * existing `paste-vanished` reason: the pane was calm, we submitted, and\n * nothing happened.\n */\nexport async function sendToPane(\n paneId: string,\n text: string,\n opts: SendOptions = {},\n): Promise<void> {\n assertValidPaneId(paneId);\n // Unverified: herdr has no key-send primitive mu knows of, and an empty\n // `agent prompt` is untested. Refuse rather than guess.\n if (text === \"\") {\n throw new MuxError(\n \"herdr backend cannot send an empty message (no bare-Enter primitive); press Enter in the pane instead\",\n );\n }\n const wait = opts.readinessMs === 0 ? [] : [\"--wait\"];\n try {\n await herdr([\"agent\", \"prompt\", paneId, text, ...wait]);\n return;\n } catch (err) {\n if (!(err instanceof HerdrError) || err.code === undefined) throw err;\n if (err.code === PROMPT_STALLED_CODE) {\n const warn = opts.onUndelivered ?? defaultUndeliveredWarning;\n warn({\n paneId,\n reason: \"paste-vanished\",\n message: `send to ${paneId} was submitted but the agent's state never changed (herdr: ${PROMPT_STALLED_CODE}). The agent may NOT have seen it. Read the pane, or re-send.`,\n });\n return;\n }\n if (!NO_AGENT_CODES.includes(err.code)) throw err;\n }\n // No recognized agent in this pane: raw shell. `pane run` is herdr's\n // atomic text+Enter for that case. It has no lifecycle to wait on, so\n // there is nothing to confirm and nothing to warn about.\n await herdr([\"pane\", \"run\", paneId, text]);\n}\n\n/**\n * Read pane output as plain text.\n *\n * - no options → everything herdr has available, soft wraps joined\n * - `lines: 0` → the rendered viewport only (`--source visible`)\n * - `lines: N` → the last N rows, soft wraps joined\n *\n * `recent-unwrapped` is the source herdr recommends for logs and\n * transcripts: it joins soft wraps, so a wrapped line reads as one line\n * rather than as terminal-width fragments.\n *\n * KNOWN LIMIT — do not paper over this: a pane running its agent on the\n * terminal's ALTERNATE screen does not spill rows into herdr's host\n * scrollback. Rows that have left the alternate screen are GONE, so a\n * bigger `--lines` cannot recover them. If a read looks truncated, that\n * is why, and the fix is to ask the agent to write its output to a file\n * — not to raise the line count.\n *\n * `pane read` emits PLAIN TEXT, so it bypasses `herdr()` (which would\n * treat unparseable stdout as CLI drift) and reads the executor result\n * directly, mapping herdr's JSON error envelope by hand.\n */\nexport async function capturePane(paneId: string, opts: CaptureOptions = {}): Promise<string> {\n assertValidPaneId(paneId);\n const args = [\"pane\", \"read\", paneId];\n if (opts.lines === 0) {\n args.push(\"--source\", \"visible\");\n } else {\n args.push(\"--source\", \"recent-unwrapped\");\n if (opts.lines !== undefined) args.push(\"--lines\", String(opts.lines));\n }\n const result = await currentExecutor(args);\n if (result.exitCode === 2) throw new HerdrSyntaxError(args, result.stderr || result.stdout);\n if (result.exitCode !== 0) {\n throw new HerdrError(\n args,\n result.stderr,\n result.stdout,\n result.exitCode,\n parseErrorEnvelope(result.stderr)?.code,\n );\n }\n return result.stdout;\n}\n\n// ─── Native status ─────────────────────────────────────────────────────\n\n/**\n * herdr's five agent lifecycle states, mapped onto mu's.\n *\n * working → busy\n * blocked → needs_permission (herdr recognized an approval/question UI)\n * idle → needs_input\n * done → needs_input\n * unknown → needs_input\n *\n * `unknown` MUST NOT become `free`. herdr's skill doc is explicit that\n * unknown \"does not prove completion\"; a false `free` makes mu hand the\n * worker a second task while the first is still running. `needs_input`\n * is the safe reading of \"an agent is there and we cannot classify it\".\n * (`free` is not a detected status at all — it is set by `mu agent\n * free`, i.e. by the user, and no detector may mint it.)\n *\n * `done` is herdr's idle-after-UNSEEN-background-work, and CLI reads\n * deliberately do NOT mark a tab seen. mu polling therefore never clears\n * the user's done badge — which is the point, and why no read path in\n * this file calls a focus or seen-marking verb (only the attach steps\n * the user asks for name one).\n */\nexport function mapAgentStatus(agentStatus: string): MuxPaneStatus {\n switch (agentStatus) {\n case \"working\":\n return \"busy\";\n case \"blocked\":\n return \"needs_permission\";\n default:\n // idle / done / unknown, and any state a future herdr adds: the\n // conservative reading is \"waiting on a human\", never \"free\".\n return \"needs_input\";\n }\n}\n\n/**\n * The pane's status as HERDR classifies it, or undefined when the pane\n * is gone (or reports no state at all).\n *\n * herdr watches the terminal continuously across every agent kind it\n * knows; mu takes that report rather than reading pane text.\n */\nexport async function paneStatus(paneId: string): Promise<MuxPaneStatus | undefined> {\n if (!isValidPaneId(paneId)) return undefined;\n const result = await herdrTolerating(\n [\"pane\", \"get\", paneId],\n [\"pane_not_found\", \"workspace_not_found\"],\n );\n if (result === undefined) return undefined;\n const pane = result.pane;\n const status = isRecord(pane) ? asString(pane.agent_status) : undefined;\n if (status === undefined) return undefined;\n return mapAgentStatus(status);\n}\n\n// ─── Chrome ────────────────────────────────────────────────────────────\n\n/**\n * NO-OP. herdr owns its own pane chrome and exposes no border knobs;\n * mu-managed panes are distinguished by their label instead. Returns 0\n * (windows decorated) to keep the contract total.\n */\nexport async function enableMuPaneBordersForSession(_session: string): Promise<number> {\n return 0;\n}\n\n/** NO-OP. See `enableMuPaneBordersForSession`. */\nexport async function enableMuPaneBordersForPane(_paneId: string): Promise<void> {\n // Intentionally empty.\n}\n\n// ─── Helpers ───────────────────────────────────────────────────────────\n\n/**\n * Push one `--env KEY=VALUE` flag per entry. Keys must be non-empty and\n * free of `=`; throwing a TypeError keeps the failure at the call site\n * instead of letting herdr reject the line as a syntax error (exit 2),\n * which would look like CLI drift.\n */\nfunction appendEnvFlags(args: string[], env: Record<string, string> | undefined): void {\n if (!env) return;\n for (const [k, v] of Object.entries(env)) {\n if (k.length === 0) throw new TypeError(\"herdr env key must be non-empty\");\n if (k.includes(\"=\")) {\n throw new TypeError(`herdr env key must not contain '=': ${JSON.stringify(k)}`);\n }\n args.push(\"--env\", `${k}=${v}`);\n }\n}\n\n/**\n * herdr's creation verbs start a plain shell; there is no\n * create-and-run-this form. Running the agent CLI in the new pane is a\n * separate `agent start` step (`startAgentInPane`), which spawn calls\n * after creating the bare pane. Refuse loudly rather than silently\n * dropping the command on the floor.\n */\nfunction rejectCommand(method: string, command: string | undefined): void {\n if (command === undefined || command.trim().length === 0) return;\n throw new HerdrNotImplementedError(`${method} with a command`);\n}\n\n/**\n * Read a pane id out of a creation response. Never predict an id: herdr\n * does not reuse closed ids and a moved pane is renumbered, so the\n * response is the only trustworthy source.\n */\nfunction readCreatedPaneId(\n result: Record<string, unknown>,\n key: string,\n args: readonly string[],\n): string {\n const pane = readPane(result[key]);\n if (pane === undefined) {\n throw new HerdrError(\n args,\n `herdr response had no ${key}.pane_id: ${JSON.stringify(result)}`,\n \"\",\n 0,\n );\n }\n assertValidPaneId(pane.paneId);\n return pane.paneId;\n}\n\n// ─── Backend record ────────────────────────────────────────────────────\n\n/**\n * True iff a `herdr status` payload describes a server mu can drive.\n *\n * Pure, and EXPORTED because test/_mux.ts gates the real-herdr\n * integration tier on the same question — one parser, not two that\n * drift (they already had, across the 0.8 → 0.9 rename below).\n *\n * WHICH COMPATIBILITY LINE. herdr 0.9.0 split the old single\n * `compatible: yes|no` into two, and they do NOT mean the same thing:\n *\n * endpoint_compatible — the stable public API generation.\n * `no` means the server predates\n * endpoint generation 1 and needs a\n * one-time upgrade before ANY verb\n * works. Load-bearing.\n * private_protocol_compatible — the internal client↔server protocol.\n * Since 0.9.0 a mismatch here only\n * disables the affected action and\n * leaves running agents untouched, so\n * it must NOT gate availability: a\n * client one release ahead of its\n * server still drives panes fine.\n *\n * The bare `compatible:` line is herdr ≤0.8.x and is still honoured, so\n * mu does not silently start trusting an old incompatible server. It\n * cannot collide with the two 0.9 lines: `^\\s*` will not consume the\n * `endpoint_` / `private_protocol_` prefixes.\n *\n * A MISSING line is fine in every case — absence of evidence is not\n * incompatibility, and herdr omits these entirely when no server runs\n * (which the `status: running` check has already rejected).\n */\nexport function isHerdrStatusUsable(stdout: string): boolean {\n if (!/^\\s*status:\\s*running\\s*$/m.test(stdout)) return false;\n if (/^\\s*endpoint_compatible:\\s*no\\s*$/m.test(stdout)) return false;\n return !/^\\s*compatible:\\s*no\\s*$/m.test(stdout);\n}\n\n/**\n * True iff herdr can be reached right now. `herdr status` rather than a\n * PATH probe, and it must report a RUNNING, COMPATIBLE server: a herdr\n * binary whose server is down cannot drive a single pane, so it is not\n * an available backend.\n *\n * Note `herdr status` is plain text, not JSON — the one exception to the\n * \"everything is JSON\" rule, so it is parsed here rather than through\n * `herdr()`.\n */\nasync function herdrAvailable(): Promise<boolean> {\n const result = await currentExecutor([\"status\"]).catch(() => undefined);\n if (result === undefined || result.exitCode !== 0) return false;\n return isHerdrStatusUsable(result.stdout);\n}\n\n// ─── Attach ─────────────────────────────────────────────────────────────\n//\n// The mu session name is a workspace LABEL inside one herdr server, so\n// attaching means FOCUSING that workspace (or the agent's tab), and\n// herdr addresses both by opaque id: resolve label → id first.\n// `herdr session attach <name>` is NOT the analogue: it attaches a\n// whole named SERVER, and pointing it at a workspace label starts a\n// new, empty server under that name.\n//\n// `MU_HERDR_SESSION` picks the server mu drives, and the user's shell\n// does not read it, so every emitted line carries the same\n// `--session <name>` prefix as `herdrGlobalFlags()`.\n//\n// Focus moves the server's view; the user only sees it through a\n// client. Inside a herdr pane (`$HERDR_ENV=1`, the signal detect.ts\n// uses) the caller's client already shows it. Outside, a second step\n// opens a client. `target.inside` is tmux's evidence (`$TMUX`) and is\n// ignored here.\n\n/** The focus argv for `target` in workspace `workspaceId`. Prefers the\n * agent's tab (`tab focus` also switches the workspace) and falls back\n * to the workspace when no tab carries that label. */\nasync function attachFocusArgs(workspaceId: string, target: AttachTarget): Promise<string[]> {\n if (target.window !== undefined) {\n const tabs = readTabs(await herdr([\"tab\", \"list\", \"--workspace\", workspaceId]));\n const tab = tabs.find((t) => t.name === target.window);\n if (tab !== undefined) return [\"tab\", \"focus\", tab.id];\n }\n return [\"workspace\", \"focus\", workspaceId];\n}\n\nfunction insideHerdrClient(): boolean {\n return process.env.HERDR_ENV === \"1\";\n}\n\n/**\n * Copy-pasteable line landing the user on `target`. Never throws: it is\n * a hint, so an unresolvable label degrades to the manual recipe.\n */\nexport async function attachHint(target: AttachTarget): Promise<string> {\n const base = [\"herdr\", ...herdrGlobalFlags()].join(\" \");\n const focus = await resolveWorkspaceId(target.session)\n .then((id) => (id === undefined ? undefined : attachFocusArgs(id, target)))\n .catch(() => undefined);\n if (focus === undefined) {\n return `${base} workspace list # then: ${base} workspace focus <id of ${target.session}>`;\n }\n const line = `${base} ${focus.join(\" \")}`;\n return insideHerdrClient() ? line : `${line} && ${base}`;\n}\n\n/** The same attach as argv steps. Throws `HerdrError` when no workspace\n * carries the label (the TUI shows it in the footer). */\nexport async function attachCommands(target: AttachTarget): Promise<readonly MuxCommand[]> {\n const flags = herdrGlobalFlags();\n const focus = await attachFocusArgs(await requireWorkspaceId(target.session), target);\n const steps: MuxCommand[] = [{ command: \"herdr\", args: [...flags, ...focus] }];\n // Bare `herdr` launches a client attached to the (named) server.\n if (!insideHerdrClient()) steps.push({ command: \"herdr\", args: [...flags] });\n return steps;\n}\n\n// ─── Diagnostics ────────────────────────────────────────────────────────\n\nexport function paneNotFoundNextSteps(paneId: string): NextStep[] {\n return [\n {\n intent: `Verify the pane id ${paneId} actually exists`,\n command: `herdr pane get ${paneId}`,\n },\n {\n intent: \"List panes in the current workspace\",\n command: 'herdr pane list --workspace \"$HERDR_WORKSPACE_ID\"',\n },\n ];\n}\n\n/**\n * Version probe plus the ambient facts herdr injects into every managed\n * pane. Returns DATA; `mu doctor` owns the strings.\n *\n * `herdr status` is the one command that is NOT JSON (see the task note\n * on mux-herdr-topology), so this parses the plain-text `version:` line\n * from the CLIENT block rather than routing through `herdr()`.\n */\nexport async function healthCheck(): Promise<MuxHealth> {\n let version: string | null = null;\n try {\n const result = await currentExecutor([\"status\"]);\n if (result.exitCode === 0) {\n const match = /^\\s*version:\\s*(\\S+)\\s*$/m.exec(result.stdout);\n version = match?.[1] ?? null;\n }\n } catch {\n version = null;\n }\n return {\n name: \"herdr\",\n ok: version !== null,\n version,\n env: [\n { name: \"$HERDR_ENV\", value: process.env.HERDR_ENV ?? null },\n { name: \"$HERDR_WORKSPACE_ID\", value: process.env.HERDR_WORKSPACE_ID ?? null },\n { name: \"$HERDR_PANE_ID\", value: process.env.HERDR_PANE_ID ?? null },\n ],\n remediation: \"start the herdr server (herdr status) or install herdr\",\n };\n}\n\n/**\n * The herdr implementation of `MuxBackend`. A frozen record of the\n * module's functions — no state of its own, so swapping backends is a\n * pointer assignment (see ./detect.ts).\n */\nexport const herdrBackend: MuxBackend = Object.freeze({\n name: \"herdr\" as const,\n available: herdrAvailable,\n\n isValidPaneId,\n assertValidPaneId,\n\n listSessions,\n sessionExists,\n newSession,\n newSessionWithPane,\n killSession,\n\n listWindows,\n newWindow,\n selectLayout,\n\n listPanes,\n listPanesInSession,\n splitWindow,\n killPane,\n paneExists,\n paneTTY,\n\n setPaneTitle,\n lockPaneTitle,\n getPaneTitle,\n currentAgentName,\n currentSessionName,\n\n startAgentInPane,\n\n sendToPane,\n capturePane,\n paneStatus,\n\n enableMuPaneBordersForSession,\n enableMuPaneBordersForPane,\n\n attachHint,\n attachCommands,\n paneNotFoundNextSteps,\n healthCheck,\n});\n","// mu — multiplexer backend detection.\n//\n// Picks the ONE backend a given mu invocation drives. Mirrors\n// detectBackend() in src/vcs/index.ts, with one difference: the VCS\n// backend is a property of a directory, so it is re-detected per call;\n// the mux backend is a property of the PROCESS, so it is resolved once\n// and cached (see `activeMux`).\n\nimport { herdrBackend } from \"./herdr.js\";\nimport { tmuxBackend } from \"./tmux.js\";\nimport { type MuxBackend, type MuxBackendName, NoMultiplexerError } from \"./types.js\";\n\n/** Every backend mu knows about, in detection-precedence order. tmux is\n * the incumbent and wins pure availability ties; herdr is selected by\n * the narrower `$HERDR_ENV` ambient signal (see `detectMux`). */\nconst BACKENDS: readonly MuxBackend[] = [tmuxBackend, herdrBackend];\n\n/** Look up a backend by name. Throws on unknown name. Backs `MU_MUX`. */\nexport function muxByName(name: MuxBackendName): MuxBackend {\n for (const backend of BACKENDS) {\n if (backend.name === name) return backend;\n }\n throw new Error(`unknown mux backend: ${name}`);\n}\n\n/** Valid `MU_MUX` values, for error messages. */\nconst KNOWN_NAMES: readonly string[] = BACKENDS.map((b) => b.name);\n\n/**\n * Resolve the active multiplexer backend.\n *\n * The ladder, in order:\n *\n * 1. `MU_MUX=<name>` — explicit override. Also the test seam. An\n * unknown value throws rather than silently falling through: a\n * typo'd backend name should fail loud, not quietly run on tmux.\n * 2. Ambient signal — an env var proving the CALLER is already\n * inside a managed pane of that mux ($HERDR_ENV for herdr, $TMUX\n * or $TMUX_PANE for tmux). The most specific signal wins, since a\n * mux can run nested inside another: herdr panes routinely host a\n * tmux server, so BOTH sets of vars can be present at once and\n * $HERDR_ENV — the narrower claim — is checked first.\n * 3. Availability — whichever backend's binary actually runs.\n * Ties break in BACKENDS order (tmux is the incumbent).\n * 4. Throw `NoMultiplexerError`.\n *\n * Note rungs 2 and 3 are separate on purpose. `$TMUX` says \"the caller\n * is in a tmux pane\"; `tmux -V` says \"tmux works here\". mu can spawn a\n * detached session from a plain shell, so rung 3 alone is sufficient to\n * operate — rung 2 exists only to pick the RIGHT mux when several are\n * installed.\n */\nexport async function detectMux(): Promise<MuxBackend> {\n const override = process.env.MU_MUX;\n if (override !== undefined && override.length > 0) {\n return muxByName(override as MuxBackendName);\n }\n\n // herdr FIRST. herdr can run inside tmux and vice versa, so both\n // signals can be live simultaneously; `$HERDR_ENV=1` is the narrower\n // one (herdr sets it only in panes IT manages) and must win. The\n // exact-\"1\" comparison is what `herdr --skill` mandates: any other\n // value, including \"0\" or \"true\", is not the documented contract.\n if (process.env.HERDR_ENV === \"1\") return herdrBackend;\n\n // Both vars, not just $TMUX: tmux sets $TMUX_PANE in every pane too,\n // and some setups (sudo -E, direnv, ssh with a restrictive SendEnv)\n // pass one through but not the other. Either one proves we are in a\n // tmux pane, which is what this rung is asking.\n if (process.env.TMUX || process.env.TMUX_PANE) return tmuxBackend;\n\n for (const backend of BACKENDS) {\n if (await backend.available()) return backend;\n }\n\n throw new NoMultiplexerError(KNOWN_NAMES);\n}\n\n// ─── Process-wide active backend ───────────────────────────────────────\n\nlet cached: MuxBackend | undefined;\n\n/**\n * The active backend, resolved once per process and memoized.\n *\n * Memoized because detection can shell out (`tmux -V`) and mu is a\n * short-lived CLI that touches the mux many times per invocation; the\n * answer cannot change mid-process in any way that mu should react to.\n */\nexport async function activeMux(): Promise<MuxBackend> {\n if (cached === undefined) cached = await detectMux();\n return cached;\n}\n\n/**\n * Install a backend directly, bypassing detection. Returns the previous\n * value so tests can restore it. Mirrors `setTmuxExecutor`.\n *\n * Production code never calls this — use `activeMux()`.\n */\nexport function setMuxForTests(backend: MuxBackend | undefined): MuxBackend | undefined {\n const previous = cached;\n cached = backend;\n return previous;\n}\n\n/** Drop the memoized backend so the next `activeMux()` re-detects. */\nexport function resetMux(): void {\n cached = undefined;\n}\n","// mu — multiplexer backend hub.\n//\n// Concrete backends live in the cohesive src/mux/ cluster: one file per\n// backend plus shared types and detection. This root file is the public\n// `import { ... } from \"./mux.js\"` surface, mirroring src/vcs.ts.\n//\n// A \"mux\" is the terminal multiplexer that owns panes. Exactly one is\n// active per mu invocation, resolved by `activeMux()`. Everything\n// backend-specific — topology, the send protocol, capture, pane-id\n// validation, identity fallback — lives behind `MuxBackend`.\n//\n// See docs/VOCABULARY.md § \"mux backend\" and docs/architecture/mux.md\n// § \"One mux session per workstream\".\n\nexport {\n type AttachTarget,\n activeMux,\n type CaptureOptions,\n detectMux,\n HerdrCommandOverrideError,\n HerdrError,\n HerdrNotImplementedError,\n HerdrSyntaxError,\n HerdrUnsupportedCliError,\n HerdrWorkspaceGroupCloseError,\n herdrBackend,\n isHerdrStatusUsable,\n type MuxBackend,\n type MuxBackendName,\n type MuxCommand,\n type MuxDiagnostics,\n MuxError,\n type MuxHealth,\n type MuxPane,\n type MuxPaneStatus,\n type MuxSession,\n type MuxWindow,\n muxByName,\n type NewSessionOptions,\n type NewSessionWithPaneOptions,\n type NewWindowOptions,\n NoMultiplexerError,\n PaneNotFoundError,\n parseAgentNameFromTitle,\n resetHerdrExecutor,\n resetMux,\n type SendOptions,\n type SendWarning,\n type SplitWindowOptions,\n type StartAgentInPaneOptions,\n setHerdrExecutor,\n setMuxForTests,\n tmuxBackend,\n} from \"./mux/index.js\";\n","// The one glyph vocabulary. Every symbol mu paints as *state* is\n// defined here and nowhere else.\n//\n// WHY ONE FILE\n// Glyphs were previously inlined at each render site: \"✓\" in the\n// Recent card, \"✓\" again in the Workspaces card, \"✓\" a third time in\n// the doctor card, \"⛓\" in Blocked, \"⚠\" in two CLI formatters. Three\n// spellings of \"ok\" drifted apart once already (the busy gear vs\n// murmur's play glyph), and each inline literal is a place the next\n// drift can start. One meaning, one constant.\n//\n// WHY ONE FAMILY\n// All state glyphs are classic Nerd Font `nf-fa-*` (Font Awesome 4)\n// codepoints. Two properties matter:\n//\n// 1. SINGLE CODEPOINT, SINGLE CELL. Unicode emoji like ⚙️ are two\n// codepoints (base + variation selector) that terminals draw one\n// cell wide. cli-table3 sizes columns by string length, so a\n// table mixing 1- and 2-codepoint glyphs misaligns. nf-fa slots\n// are private-use, all length-1, all one cell.\n// 2. STABLE SLOTS. Avoid `nf-md-*`: those PUA codepoints move\n// between Nerd Font releases and silently render as the wrong\n// icon (mu's `idle` once looked like a red shield under md-sleep).\n//\n// This matches murmur's dash (`src/dash-paint.ts` in ../murmur), which\n// drives the same tmux panes from the other side. `busy` here and\n// `running` there are both nf-fa-play on purpose: one symbol, one\n// meaning, across both surfaces.\n//\n// Requires a Nerd Font on the operator's terminal. mu's substrate is\n// pi, which assumes one. Without it every glyph renders as a\n// placeholder box — and the columns still line up, which is the bug\n// the family rule exists to prevent.\n//\n// NOT IN HERE\n// Typographic punctuation that carries no state: the `•` list bullet,\n// the `—` empty-cell dash, `…` truncation, box-drawing borders. Those\n// are text, not vocabulary, and stay at their call sites.\n\nimport type { RuntimeState } from \"./agent-state.js\";\n\nexport const AGENT_STATE_GLYPH: Record<RuntimeState, string> = {\n busy: \"\\uf04b\", // nf-fa-play\n needs_input: \"\\uf186\", // nf-fa-moon_o\n needs_permission: \"\\uf023\", // nf-fa-lock\n unknown: \"\\uf059\", // nf-fa-question_circle\n};\n\nexport function agentStateGlyph(state: RuntimeState): string {\n return AGENT_STATE_GLYPH[state] ?? GLYPH.unknown;\n}\n\n/**\n * Non-agent state glyphs, keyed by what they MEAN rather than what\n * they look like. A call site asks for `GLYPH.stale`, never for a\n * clock — so re-pointing the clock is a one-line edit here.\n *\n * `ok` / `fail` / `warn` deliberately reuse the same codepoints as the\n * agent statuses they rhyme with (`free`, `terminated`): a check-circle\n * means \"fine\" whether the row is an agent, a workspace or a doctor\n * check.\n */\nexport const GLYPH = {\n /** Healthy, clean, passing, closed-successfully. */\n ok: \"\\uf058\", // nf-fa-check_circle\n /** Failed check. */\n fail: \"\\uf057\", // nf-fa-times_circle\n /** Needs attention but not broken (idle-but-assigned, stale warning). */\n warn: \"\\uf071\", // nf-fa-warning\n /** Workspace has uncommitted edits. */\n dirty: \"\\uf005\", // nf-fa-star\n /** Workspace is ≥ WORKSPACE_STALE_THRESHOLD commits behind main. */\n stale: \"\\uf017\", // nf-fa-clock_o\n /** Task is blocked by an incoming edge. */\n blocked: \"\\uf0c1\", // nf-fa-link (chain)\n /** Task is parked (OPEN/parked): open, but set aside on purpose. */\n parked: \"\\uf04c\", // nf-fa-pause\n /** Track whose roots merged (diamond dependency). */\n merge: \"\\uf074\", // nf-fa-random\n /** Agent owns more than one task (pane-title multi-count slot). */\n multi: \"\\uf055\", // nf-fa-plus_circle\n /** Filter toggle: enabled / disabled. */\n on: \"\\uf111\", // nf-fa-circle\n off: \"\\uf10c\", // nf-fa-circle_o\n /** Status outside the known enum. */\n unknown: \"\\uf059\", // nf-fa-question_circle\n} as const;\n\n// ─── Card-header digits ────────────────────────────────────────────\n//\n// Not state, but the same question (\"which codepoint?\") asked of the\n// same file. Superscript digits prefix a TUI card's title with its\n// toggle key (`╭─ ¹ Agents · 3 free ─...─╮`, the btop convention);\n// the help overlay renders the same glyphs so the dashboard and the\n// keymap speak one visual language.\n\nconst SUPERSCRIPT = [\"⁰\", \"¹\", \"²\", \"³\", \"⁴\", \"⁵\", \"⁶\", \"⁷\", \"⁸\", \"⁹\"] as const;\n\n/**\n * Map a single decimal digit (0..9) to its Unicode superscript form.\n * Throws on out-of-range inputs so callers can't silently drop a key.\n */\nexport function superscriptDigit(n: number): string {\n if (!Number.isInteger(n) || n < 0 || n > 9) {\n throw new RangeError(`superscriptDigit: expected integer 0..9, got ${n}`);\n }\n const g = SUPERSCRIPT[n];\n // Defensive narrow for noUncheckedIndexedAccess; bounds checked above.\n if (g === undefined) {\n throw new RangeError(`superscriptDigit: unreachable for n=${n}`);\n }\n return g;\n}\n","// mu — agent registry CRUD primitives + the five high-level verbs\n// (spawn, send, read, list, close) that the CLI in step 7 will wrap.\n//\n// Layering inside this file:\n//\n// - Types & raw-row mapping (RawAgentRow / rowFromDb)\n// - CRUD primitives (insertAgent, getAgent, listAgents,\n// deleteAgent)\n// - Verbs (spawnAgent, sendToAgent, readAgent,\n// closeAgent, listLiveAgents)\n//\n// The verbs compose the CRUD primitives with the mux and reconciliation\n// layers. They are deliberately thin.\n\nimport { dirname } from \"node:path\";\nimport {\n agentKey,\n type CtlLink,\n type RuntimeState,\n readAgentStates,\n type StateSource,\n} from \"./agent-state.js\";\nimport { type Db, resolveWorkstreamId, tryResolveWorkstreamId } from \"./db.js\";\nimport { GLYPH } from \"./glyphs.js\";\nimport { emitEvent } from \"./logs.js\";\nimport { withOpContext } from \"./op-context.js\";\nimport { type ReconcileMode, type ReconcileReport, reconcile } from \"./reconcile.js\";\nimport { addNote, listTasksByOwner } from \"./tasks.js\";\n\n// Re-export the cluster modules so external callers continue to\n// `import { AgentNotFoundError, spawnAgent, ... } from \"./agents.js\"`.\nexport {\n type AbortAgentOptions,\n type AbortResult,\n abortAgent,\n DEFAULT_ABORT_TIMEOUT_MS,\n type InterruptResult,\n interruptAgent,\n} from \"./agents/abort.js\";\nexport {\n type AdoptAgentOptions,\n type AdoptAgentResult,\n adoptAgent,\n} from \"./agents/adopt.js\";\nexport { type DelegateOutcome, delegateOutcome } from \"./agents/delegate.js\";\nexport {\n AgentAbortNeedsCtlError,\n AgentAbortTimeoutError,\n AgentBusyError,\n AgentCtlUnreachableError,\n AgentDiedOnSpawnError,\n AgentEmptySendError,\n AgentExistsError,\n AgentExtensionOutdatedError,\n AgentFreshNeedsCtlError,\n AgentNameExhaustedError,\n AgentNotFoundError,\n AgentNotInWorkstreamError,\n AgentPaneDeadError,\n AgentSendIndeterminateError,\n AgentSlashCommandUnsupportedError,\n AgentSpawnCliNotFoundError,\n AgentSpawnStartupError,\n PaneNotInSessionError,\n WorkspaceOwnerBusyError,\n WorkspacePreservedError,\n} from \"./agents/errors.js\";\nexport {\n foregroundPgid,\n isKickSignal,\n type KickAgentOptions,\n type KickAgentResult,\n type KickProcessExecutor,\n type KickSignal,\n kickAgent,\n NoForegroundProcessError,\n parsePsTtyOutput,\n resetKickProcessExecutor,\n setKickProcessExecutor,\n} from \"./agents/kick.js\";\nexport {\n type CommandResolutionResult,\n type CommandResolver,\n checkCommandResolvable,\n defaultSpawnCtlMs,\n defaultSpawnLivenessMs,\n envVarNameForCli,\n nextFreeAgentName,\n resetCommandResolverForTests,\n resolveCliCommand,\n resolveCliCommandWithSource,\n type SpawnAgentOptions,\n type SpawnCtl,\n type SpawnedAgent,\n setCommandResolverForTests,\n spawnAgent,\n speaksMuCtl,\n} from \"./agents/spawn.js\";\nexport {\n agentCtlSocket,\n CTL_SLASH_COMMANDS,\n chooseTransport,\n expectsCtl,\n isSlashCommand,\n parseSessionCommand,\n type SendResult,\n sendViaTransport,\n type Transport,\n type TransportSendOptions,\n} from \"./agents/transport.js\";\nexport {\n type AgentStatusSnapshot,\n type AgentWaitAgentState,\n type AgentWaitOptions,\n type AgentWaitRef,\n type AgentWaitResult,\n type AgentWatch,\n setAgentWaitSleepForTests,\n waitForAgents,\n} from \"./agents/wait.js\";\n\nimport { AgentExistsError, AgentNotFoundError, WorkspacePreservedError } from \"./agents/errors.js\";\nimport {\n agentCtlSocket,\n recordSend,\n type SendResult,\n sendViaTransport,\n type TransportSendOptions,\n} from \"./agents/transport.js\";\nimport { unlinkCtlSocket } from \"./ctl/path.js\";\nimport { activeMux, type CaptureOptions, type MuxPane } from \"./mux.js\";\nimport { resolveActorIdentity } from \"./tasks/claim.js\";\nimport { freeWorkspace, getWorkspaceForAgent, isWorkspaceClean } from \"./workspace.js\";\n// (freeWorkspace is used by the spawn rollback paths below, not by closeAgent.\n// Closing an agent is intentionally a separate concern from freeing its workspace;\n// see the closeAgent docstring.)\nimport { ensureWorkstream, isScratchWorkstream } from \"./workstream.js\";\n\nexport interface AgentRow {\n name: string;\n /** Foreign-name reference to the owning workstream. */\n workstreamName: string;\n cli: string;\n paneId: string;\n role: string;\n /** Window name; null when the agent has its own window named after itself. */\n tab: string | null;\n /** ISO 8601 timestamp. */\n createdAt: string;\n /** ISO 8601 timestamp. */\n updatedAt: string;\n}\n\nexport interface LiveAgent extends AgentRow {\n state: RuntimeState;\n source: StateSource;\n /** Control-socket link: ok / missing / refused for pi agents, n/a otherwise. */\n ctl?: CtlLink;\n /** ISO 8601 time when the source entered this state. */\n since: string | null;\n reason?: string;\n idle?: boolean;\n}\n\n/** Default idle threshold for the derived `idle` flag (`mu state`, TUI).\n * Deliberately looser than `mu task wait --stuck-after` (2 min), which\n * acts on the stall rather than just displaying it. */\nconst DEFAULT_IDLE_THRESHOLD_MS = 300_000;\n\n/**\n * Read the operator-tunable idle threshold (`MU_IDLE_THRESHOLD_MS`).\n * Returns the default on any unparsable / negative value rather than\n * throwing — env-var typos shouldn't crash `mu state`.\n */\nexport function idleThresholdMs(): number {\n const env = process.env.MU_IDLE_THRESHOLD_MS;\n if (env === undefined || env === \"\") return DEFAULT_IDLE_THRESHOLD_MS;\n const n = Number.parseInt(env, 10);\n if (!Number.isFinite(n) || n < 0) return DEFAULT_IDLE_THRESHOLD_MS;\n return n;\n}\n\n/**\n * Decide whether an agent is in the 'idle but assigned' state. Pure\n * read on (agents, tasks); no side effects. Exported so `listLiveAgents`,\n * the renderers, and tests can share one source of truth.\n *\n * Scratch agents own no task, so for them idle past the threshold is\n * enough: a leftover delegate pane is then flagged in `mu state -w\n * scratch` / `mu agent list` instead of piling up unseen.\n */\nexport function computeAgentIdle(db: Db, agent: LiveAgent, now: number = Date.now()): boolean {\n if (agent.state !== \"needs_input\" || agent.since === null) return false;\n const threshold = idleThresholdMs();\n if (threshold <= 0) return false;\n const since = Date.parse(agent.since);\n if (!Number.isFinite(since)) return false;\n if (now - since < threshold) return false;\n if (isScratchWorkstream(agent.workstreamName)) return true;\n const wsId = tryResolveWorkstreamId(db, agent.workstreamName);\n if (wsId === null) return false;\n const row = db\n .prepare(\n `SELECT COUNT(*) AS n\n FROM tasks t\n JOIN agents a ON a.id = t.owner_id\n WHERE a.name = ? AND a.workstream_id = ? AND t.status = 'IN_PROGRESS'`,\n )\n .get(agent.name, wsId) as { n: number };\n return row.n > 0;\n}\n\nexport interface InsertAgentInput {\n name: string;\n workstream: string;\n paneId: string;\n /** Defaults to \"pi\" via schema DEFAULT. */\n cli?: string;\n /** Defaults to \"full-access\" via schema DEFAULT. */\n role?: string;\n tab?: string | null;\n}\n\ninterface RawAgentRow {\n name: string;\n /** Joined from workstreams.name. */\n workstream: string;\n cli: string;\n pane_id: string;\n role: string;\n tab: string | null;\n created_at: string;\n updated_at: string;\n}\n\n/** SELECT clause that joins agents to workstreams, exposing the\n * operator-facing workstream name as `workstream`. Used by every\n * read path. */\nconst SELECT_AGENT_COLS = `\n a.name AS name,\n ws.name AS workstream,\n a.cli AS cli,\n a.pane_id AS pane_id,\n a.role AS role,\n a.tab AS tab,\n a.created_at AS created_at,\n a.updated_at AS updated_at\n`;\n\nconst AGENT_FROM_JOIN = \"FROM agents a JOIN workstreams ws ON ws.id = a.workstream_id\";\n\nfunction rowFromDb(row: RawAgentRow): AgentRow {\n return {\n name: row.name,\n workstreamName: row.workstream,\n cli: row.cli,\n paneId: row.pane_id,\n role: row.role,\n tab: row.tab,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n };\n}\n\n/** Resolve an agent's surrogate id by (workstream, name). Returns\n * null on miss. */\nfunction agentIdByName(db: Db, name: string, workstream: string): number | null {\n const wsId = tryResolveWorkstreamId(db, workstream);\n if (wsId === null) return null;\n const row = db\n .prepare(\"SELECT id FROM agents WHERE name = ? AND workstream_id = ?\")\n .get(name, wsId) as { id: number } | undefined;\n return row ? row.id : null;\n}\n\nexport function insertAgent(db: Db, input: InsertAgentInput): AgentRow {\n // Auto-create the workstreams row if missing so the FK on\n // agents.workstream_id is always satisfied. Preserves the ergonomics\n // where you could spawn without explicit `mu init`.\n ensureWorkstream(db, input.workstream);\n const workstreamId = resolveWorkstreamId(db, input.workstream);\n const now = new Date().toISOString();\n try {\n db.prepare(\n `INSERT INTO agents (name, workstream_id, cli, pane_id, status, role, tab, created_at, updated_at)\n VALUES (@name, @workstreamId, COALESCE(@cli, 'pi'), @paneId, 'spawning',\n COALESCE(@role, 'full-access'), @tab, @now, @now)`,\n ).run({\n name: input.name,\n workstreamId,\n cli: input.cli ?? null,\n paneId: input.paneId,\n role: input.role ?? null,\n tab: input.tab ?? null,\n now,\n });\n } catch (err) {\n // UNIQUE (workstream_id, name): a concurrent spawn/adopt took the\n // name between the caller's existence check and this insert.\n if ((err as { code?: unknown }).code === \"SQLITE_CONSTRAINT_UNIQUE\") {\n throw new AgentExistsError(input.name);\n }\n throw err;\n }\n const row = getAgent(db, input.name, input.workstream);\n if (!row) throw new Error(`agents.insertAgent: row not found after insert: ${input.name}`);\n return row;\n}\n\n/**\n * Look up an agent by its tmux pane id (e.g. `%4`). Returns undefined if\n * no agent currently owns that pane. Used by `mu me` and friends to\n * answer \"which agent am I?\" from `$TMUX_PANE` without the LLM having to\n * remember its own name.\n *\n * Note: `pane_id` is not declared UNIQUE in the schema (a managed agent\n * could in theory be re-spawned into the same recycled pane id) but in\n * practice tmux pane ids are unique within a server's lifetime, and\n * reconcile prunes ghosts. We return the first match.\n */\nexport function getAgentByPane(db: Db, paneId: string): AgentRow | undefined {\n const row = db\n .prepare(`SELECT ${SELECT_AGENT_COLS} ${AGENT_FROM_JOIN} WHERE a.pane_id = ? LIMIT 1`)\n .get(paneId) as RawAgentRow | undefined;\n return row ? rowFromDb(row) : undefined;\n}\n\nexport function getAgent(db: Db, name: string, workstream: string): AgentRow | undefined {\n // v5: agents.name is per-workstream unique, not globally unique.\n // Workstream is required so the same name in two workstreams\n // resolves unambiguously.\n const wsId = tryResolveWorkstreamId(db, workstream);\n if (wsId === null) return undefined;\n const row = db\n .prepare(\n `SELECT ${SELECT_AGENT_COLS} ${AGENT_FROM_JOIN} WHERE a.name = ? AND a.workstream_id = ?`,\n )\n .get(name, wsId) as RawAgentRow | undefined;\n return row ? rowFromDb(row) : undefined;\n}\n\nexport function listAgents(db: Db, opts: { workstream?: string } = {}): AgentRow[] {\n if (opts.workstream === undefined) {\n const rows = db\n .prepare(`SELECT ${SELECT_AGENT_COLS} ${AGENT_FROM_JOIN} ORDER BY ws.name, a.name`)\n .all() as RawAgentRow[];\n return rows.map(rowFromDb);\n }\n const wsId = tryResolveWorkstreamId(db, opts.workstream);\n if (wsId === null) return [];\n const rows = db\n .prepare(\n `SELECT ${SELECT_AGENT_COLS} ${AGENT_FROM_JOIN} WHERE a.workstream_id = ? ORDER BY a.name`,\n )\n .all(wsId) as RawAgentRow[];\n return rows.map(rowFromDb);\n}\n\n// ─── Pane title composition (mu's durable context) ───────────────────\n//\n// mu owns the pane title as identity plus task context. Runtime status is\n// sampled only when a mu process reconciles, so putting it here leaves a stale\n// glyph after the agent stops. A continuously updated observer may append live\n// status in tmux chrome without competing with mu for the title.\n//\n// worker-a\n// worker-a · build_x\n// worker-a · <glyph multi>2 tasks\n//\n// The agent name MUST remain the first ' · '-separated token so the\n// claim protocol's pane-title-as-identity fallback (currentPaneTitle\n// in src/tmux.ts) keeps working. Adopted panes that haven't been\n// re-titled by mu just have the name (one token) — still parses.\n\n/** Maximum total length for a composed pane title. tmux truncates\n * silently in some chrome positions; we truncate the task id\n * ourselves so the suffix is predictable. */\nconst MAX_TITLE_LEN = 64;\n\n/**\n * Placeholder pane-id prefix used during the `--workspace` pre-stage in\n * spawnAgent (src/agents/spawn.ts).\n *\n * The placeholder unblocks the FK-ordering cycle:\n * - vcs_workspaces.agent FK requires an agents row\n * - agents.pane_id is NOT NULL\n * - pane creation needs the workspace path as cwd\n * So we insert the agent with a placeholder pane_id, then create the\n * workspace, then the real pane, then patch pane_id.\n *\n * Because no real tmux pane has this prefix, a naive mutating reconcile\n * pass would treat the placeholder row as a ghost and prune it\n * (→ FK-failure on the workspace insert mid-spawn). Reconcile now guards\n * against it explicitly via isPendingPaneId(), and refreshAgentTitle skips\n * placeholders for the same reason.\n *\n * Bug surfaced as bug_agent_spawn_workspace_fk_failure.\n */\nexport const PENDING_PANE_PREFIX = \"%pending-\";\n\n/** Build the placeholder pane id for an agent during workspace pre-stage. */\nexport function pendingPaneIdFor(agentName: string): string {\n return `${PENDING_PANE_PREFIX}${agentName}`;\n}\n\n/** True iff `paneId` is a `--workspace` pre-stage placeholder (not yet patched\n * to the real tmux pane id). */\nexport function isPendingPaneId(paneId: string): boolean {\n return paneId.startsWith(PENDING_PANE_PREFIX);\n}\n\n/** Build the pane title for `agent` based on current DB state.\n * Pure (no tmux side effect; no DB write). Read-only on the DB. */\nexport function composeAgentTitle(db: Db, agent: AgentRow): string {\n // Scope by the agent's workstream so a same-named worker in another\n // workstream can't pollute this title's task list.\n const tasks = listTasksByOwner(db, agent.workstreamName, agent.name);\n let title = agent.name;\n if (tasks.length === 1) {\n title += ` · ${tasks[0]?.name}`;\n } else if (tasks.length > 1) {\n title += ` · ${GLYPH.multi}${tasks.length} tasks`;\n }\n if (title.length > MAX_TITLE_LEN) title = `${title.slice(0, MAX_TITLE_LEN - 1)}…`;\n return title;\n}\n\n/** Push a fresh pane title for `agentName`. Best-effort — a missing\n * agent, a placeholder pane id, or a tmux failure are all swallowed\n * silently (titles are decorative; never block the calling verb).\n * `currentTitle` is the pane's live title when the caller already read\n * it (reconcile); the write is skipped when it equals the new title,\n * since each retitle is a mux server write plus a status redraw. */\nexport async function refreshAgentTitle(\n db: Db,\n agentName: string,\n workstream: string,\n currentTitle?: string,\n): Promise<void> {\n const agent = getAgent(db, agentName, workstream);\n if (!agent) return;\n if (isPendingPaneId(agent.paneId)) return; // workspace pre-stage placeholder; see PENDING_PANE_PREFIX\n const title = composeAgentTitle(db, agent);\n if (title === currentTitle) return;\n // Best-effort all the way down, including \"no mux reachable at all\":\n // pane titles are decorative and must never fail the calling verb.\n await activeMux()\n .then((mux) => mux.setPaneTitle(agent.paneId, title))\n .catch(() => {});\n}\n\n/**\n * Delete an agent row. Returns true if a row was matched. Idempotent;\n * deleting an agent that doesn't exist returns false without throwing.\n *\n * Reaper side-effect: any task that was IN_PROGRESS owned by this\n * agent gets flipped back to OPEN with a `[reaper]` task_note and a\n * `task reap` event in `agent_logs`. The FK on `tasks.owner` is\n * `ON DELETE SET NULL` so the owner column resets automatically; the\n * extra step here is the status revert. Without this an agent that\n * crashed (or was explicitly closed mid-task) leaves the task graph\n * in a wrong state — IN_PROGRESS forever, with no owner to release.\n */\nexport function deleteAgent(\n db: Db,\n name: string,\n workstream: string,\n /** When set, delete only if the row still has this pane id (checked inside the reaper transaction). */\n expectedPaneId?: string,\n): boolean {\n const deleted = deleteAgentRow(db, name, workstream, expectedPaneId);\n if (deleted) unlinkCtlSocket(db, name, workstream);\n return deleted;\n}\n\nfunction deleteAgentRow(\n db: Db,\n name: string,\n workstream: string,\n expectedPaneId?: string,\n): boolean {\n // Wrap the whole reaper sequence (snapshot stuck tasks → DELETE\n // agent → per-task UPDATE + addNote + emitEvent) in a single\n // synchronous better-sqlite3 transaction. Without this, a throw\n // mid-loop (FK race after workstream teardown, addNote/emitEvent\n // regression, OOM, …) would leave the agent row deleted (FK\n // CASCADE already SET NULL on tasks.owner_id) but only PART of\n // the reaper trail written: leftover IN_PROGRESS tasks with no\n // owner and no `[reaper]` note explaining how they got there.\n // Reconcile / `mu task wait --stuck-after` would then surface\n // them as ownerless zombies with no breadcrumb.\n // `task.reap` intent so the tasks-trigger ops this produces are\n // attributable. Without it the reaper's status revert landed as\n // intent=NULL typed ops (measured), unrenderable by the one formatter\n // v2-log-verb builds — the same defect as the prose events, in the\n // other direction.\n return withOpContext(db, { intent: \"task.reap\", actor: \"reaper\", group: \"new\" }, () =>\n db\n .transaction(() => {\n // Snapshot the stuck tasks BEFORE the DELETE; the FK CASCADE\n // (SET NULL on owner_id) makes the post-delete query\n // indistinguishable from \"never owned by this agent.\"\n const agentId = agentIdByName(db, name, workstream);\n if (agentId === null) {\n // Already gone — idempotent return. (Could happen if reconcile\n // pruned a ghost concurrently.) The DELETE is a no-op.\n return false;\n }\n if (expectedPaneId !== undefined) {\n const cur = db.prepare(\"SELECT pane_id FROM agents WHERE id = ?\").get(agentId) as\n | { pane_id: string }\n | undefined;\n // Same name, different pane: the agent was replaced; keep it.\n if (cur?.pane_id !== expectedPaneId) return false;\n }\n const stuck = db\n .prepare(\n `SELECT t.id AS taskId, t.local_id AS localId, ws.name AS workstream\n FROM tasks t\n JOIN workstreams ws ON ws.id = t.workstream_id\n WHERE t.owner_id = ? AND t.status = 'IN_PROGRESS'`,\n )\n .all(agentId) as Array<{ taskId: number; localId: string; workstream: string }>;\n\n const result = db.prepare(\"DELETE FROM agents WHERE id = ?\").run(agentId);\n if (result.changes === 0) return false;\n\n for (const t of stuck) {\n db.prepare(\n \"UPDATE tasks SET status = 'OPEN', substate = 'todo', updated_at = ? WHERE id = ?\",\n ).run(new Date().toISOString(), t.taskId);\n addNote(\n db,\n t.localId,\n `[reaper] previous owner ${name} gone (agent removed); status reverted IN_PROGRESS → OPEN, owner cleared`,\n { author: \"reaper\", workstream: t.workstream },\n );\n // No emitEvent: the UPDATE above fired the tasks capture\n // trigger. Reap is the one site the orchestrator's split did not\n // predict — it DOES mutate a portable table, so a trigger sees\n // it, but it ran outside any withOpContext and so produced\n // intent=NULL typed ops. The fix is the intent above, not a\n // second prose row. The `[reaper]` task_note is the\n // human-readable breadcrumb, and it is itself a captured op.\n }\n return true;\n })\n .immediate(),\n );\n}\n\n// ────────────────────────────────────────────────────────────────────────\n// High-level verbs (spawn, send, read, list, close)\n// ────────────────────────────────────────────────────────────────────────\n\n/** Allowed agent name shape: lowercase alpha first, then alnum/underscore/\n * hyphen. Mirrors docs/reference/naming.md. */\nconst AGENT_NAME_RE = /^[a-z][a-z0-9_-]{0,31}$/;\n/** Longest name AGENT_NAME_RE accepts. */\nexport const MAX_AGENT_NAME_LEN = 32;\n\nexport function isValidAgentName(name: string): boolean {\n return AGENT_NAME_RE.test(name);\n}\n\n/**\n * Send text to an agent and submit it. A pi agent gets it through its\n * control socket (AgentCtlUnreachableError when that does not answer —\n * never a silent paste), `/new` / `/reload` / `/compact` included; a\n * non-pi CLI or `via: \"mux\"` goes through the mux paste path. See\n * src/agents/transport.ts.\n */\nexport async function sendToAgent(\n db: Db,\n name: string,\n text: string,\n opts: TransportSendOptions & { workstream: string },\n): Promise<SendResult> {\n const agent = getAgent(db, name, opts.workstream);\n if (!agent) throw new AgentNotFoundError(name);\n const sent = await sendViaTransport(agent, text, {\n ...opts,\n socket: opts.socket ?? agentCtlSocket(db, agent),\n });\n const source = await resolveActorIdentity();\n recordSend(\n db,\n agent,\n opts.fresh ? \"fresh\" : opts.mode === \"steer\" ? \"steer\" : \"plain\",\n Buffer.byteLength(text),\n {\n transport: sent.transport,\n command: sent.command,\n state: sent.state,\n since: sent.since,\n },\n source,\n );\n return sent;\n}\n\n/**\n * Read scrollback from an agent's pane. With no options, returns the full\n * scrollback (`-S - -E -`); with `lines: N`, returns only the last N lines.\n */\nexport async function readAgent(\n db: Db,\n name: string,\n opts: CaptureOptions & { workstream: string },\n): Promise<string> {\n const agent = getAgent(db, name, opts.workstream);\n if (!agent) throw new AgentNotFoundError(name);\n // Load-bearing: the scrollback IS the output of this verb.\n return (await activeMux()).capturePane(agent.paneId, opts);\n}\n\nexport interface CloseAgentOptions {\n /**\n * Lossy override: when true, free the agent's workspace BEFORE\n * deleting the agent regardless of whether it's clean. (We control\n * the order rather than relying on FK cascade, which leaves the\n * on-disk dir orphaned.) Any pending changes / commits since fork\n * are gone unless the caller frees with `--commit` separately first.\n *\n * When false (default), behaviour depends on workspace state:\n * - clean (no uncommitted changes AND no commits since fork):\n * silently auto-free. allow_mu_agent_close_without_discard.\n * - dirty (uncommitted changes OR commits since fork): throw\n * WorkspacePreservedError so the caller decides explicitly.\n * Surfaced as a real bug in the multi-agent dogfood teardown.\n */\n discardWorkspace?: boolean;\n}\n\nexport interface CloseAgentResult {\n killedPane: boolean;\n deletedRow: boolean;\n /** True iff the agent had an associated workspace AND we proactively\n * freed it — either because the caller passed `discardWorkspace:\n * true` (lossy) or because the workspace was clean and we\n * auto-freed (allow_mu_agent_close_without_discard). False on the\n * no-workspace path (nothing to free) and on the refused path (we\n * threw before doing anything). */\n workspaceFreed: boolean;\n /** True iff `workspaceFreed` was triggered by the clean-workspace\n * auto-free path (no uncommitted changes AND no commits since\n * fork) rather than the explicit `discardWorkspace: true` override.\n * Lets the CLI render an accurate message (\"auto-freed (clean)\"\n * vs \"workspace discarded\") and gives JSON consumers a stable\n * signal. False on every other path. */\n workspaceAutoFreedClean: boolean;\n}\n\n/**\n * Close an agent: kill its tmux pane and remove its DB row. Idempotent:\n * - if the agent doesn't exist in the DB, returns a no-op result\n * - if the tmux pane is already gone, killPane swallows the error\n *\n * Workspace handling: closing an agent and freeing its workspace are\n * separate concerns (agent lifecycle vs disk artifacts). Three cases:\n *\n * - No workspace: close proceeds normally.\n * - Workspace exists AND is CLEAN (no uncommitted changes, no\n * commits since fork): silently auto-free (so a workspace that\n * contains nothing worth preserving doesn't make the operator\n * type --discard-workspace just to clean it up). Surfaced by\n * allow_mu_agent_close_without_discard — a misconfigured-spawn\n * teardown was needlessly forced through the lossy flag.\n * - Workspace exists AND has either uncommitted changes OR commits\n * since fork: REFUSE with WorkspacePreservedError so the operator\n * decides explicitly. Two resolutions:\n * 1. `freeWorkspace(db, name)` first, then `closeAgent(db, name)`.\n * Preserves the option to `--commit` pending changes.\n * 2. `closeAgent(db, name, { discardWorkspace: true })`.\n * One-shot; lossy.\n *\n * The CLI surfaces these as the two actionable nextSteps on the\n * `WorkspacePreservedError` thrown by the refuse path.\n */\nexport async function closeAgent(\n db: Db,\n name: string,\n opts: CloseAgentOptions & { workstream: string },\n): Promise<CloseAgentResult> {\n const agent = getAgent(db, name, opts.workstream);\n if (!agent) {\n return {\n killedPane: false,\n deletedRow: false,\n workspaceFreed: false,\n workspaceAutoFreedClean: false,\n };\n }\n const ws = getWorkspaceForAgent(db, name, agent.workstreamName);\n // allow_mu_agent_close_without_discard: silently auto-free a clean\n // workspace (no uncommitted changes AND no commits since fork) so\n // the user doesn't have to type --discard-workspace for a workspace\n // that contains nothing worth preserving. Only refuse when there's\n // actually something to lose. The flag stays as the lossy override\n // for non-clean workspaces.\n let autoFreeClean = false;\n if (ws !== undefined && opts.discardWorkspace !== true) {\n autoFreeClean = await isWorkspaceClean(ws);\n if (!autoFreeClean) {\n throw new WorkspacePreservedError(name, ws.path);\n }\n }\n // No pre-mutation snapshot: v9 dropped the `snapshots` table and\n // rollback is inverse ops over the ops log (`mu undo`).\n // Free the workspace BEFORE the agent (so the on-disk dir is\n // removed cleanly, not orphaned by FK cascade). freeWorkspace is\n // idempotent on missing rows.\n let workspaceFreed = false;\n if (ws !== undefined && (opts.discardWorkspace === true || autoFreeClean)) {\n await freeWorkspace(db, name, { commit: false, workstream: agent.workstreamName });\n workspaceFreed = true;\n }\n await activeMux()\n .then((mux) => mux.killPane(agent.paneId))\n .catch(() => {\n /* idempotent — pane may already be gone, or the mux with it */\n });\n const deletedRow = deleteAgent(db, name, agent.workstreamName);\n // Machine-local table (`agents`): no trigger, so this emit is the\n // only record.\n emitEvent(\n db,\n agent.workstreamName,\n \"agent.close\",\n `agent close ${name} (pane=${agent.paneId}${\n workspaceFreed\n ? autoFreeClean\n ? \", workspace auto-freed (clean)\"\n : \", workspace discarded\"\n : \"\"\n })`,\n );\n return {\n killedPane: true,\n deletedRow,\n workspaceFreed,\n workspaceAutoFreedClean: workspaceFreed && autoFreeClean,\n };\n}\n\nexport interface ListLiveAgentsOptions {\n workstream: string;\n tmuxSession?: string;\n /**\n * Which kind of reconciliation pass to run. Forwarded to\n * `reconcile()`'s same-name option. Default `\"full\"` (the\n * documented mutating behaviour `mu agent list` has always had,\n * now also used by `mu state`).\n *\n * `mu doctor` passes `\"report-only\"`: count drift, mutate nothing.\n *\n * Mid-spawn placeholders (pane id `%pending-<name>`) are protected\n * directly in reconcile's prune loop, independent of mode\n * (bug_agent_spawn_workspace_fk_failure).\n *\n * BREAKING: this replaces the previous `dryRun?: boolean`\n * option. Migration: `dryRun: true` → `mode: \"report-only\"`;\n * default (`dryRun: false` / unset) → `mode: \"full\"`.\n */\n mode?: ReconcileMode;\n}\n\nexport interface LiveAgentsView {\n /** All registered agents in the workstream, post-reconcile. */\n agents: LiveAgent[];\n /** Panes in the tmux session that look like agents but aren't registered. */\n orphans: MuxPane[];\n /** Diagnostic numbers from the reconcile pass; useful for `mu doctor`. */\n report: ReconcileReport;\n}\n\n/**\n * Return the live, reality-reconciled view of agents in a workstream.\n * `mu state` and `mu agent list` call this with the default `mode: \"full\"`\n * (mutating); the read-only diagnostic (`mu doctor`) calls it with\n * `mode: \"report-only\"` to mutate nothing at all.\n */\nexport async function listLiveAgents(db: Db, opts: ListLiveAgentsOptions): Promise<LiveAgentsView> {\n const report = await reconcile(db, {\n workstream: opts.workstream,\n ...(opts.tmuxSession !== undefined ? { tmuxSession: opts.tmuxSession } : {}),\n ...(opts.mode !== undefined ? { mode: opts.mode } : {}),\n });\n const baseAgents = listAgents(db, { workstream: opts.workstream });\n const readings = await readAgentStates(baseAgents, { stateDir: dirname(db.name) });\n const now = Date.now();\n const agents: LiveAgent[] = baseAgents.map((agent) => {\n const reading = readings.get(agentKey(agent)) ?? {\n state: \"unknown\" as const,\n source: \"none\" as const,\n since: null,\n alive: true,\n reason: \"state unavailable\",\n };\n const live: LiveAgent = {\n ...agent,\n state: reading.state,\n source: reading.source,\n ctl: reading.ctl ?? \"n/a\",\n since: reading.since === null ? null : new Date(reading.since).toISOString(),\n ...(reading.reason !== undefined ? { reason: reading.reason } : {}),\n };\n return computeAgentIdle(db, live, now) ? { ...live, idle: true } : live;\n });\n return { agents, orphans: report.orphans, report };\n}\n","import { accessSync, constants, existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { delimiter, join } from \"node:path\";\nimport { expectsCtl } from \"./agents/transport.js\";\nimport { ctlProbe } from \"./ctl/client.js\";\nimport { ctlSocketPath } from \"./ctl/path.js\";\nimport type { CtlBlocked, CtlState } from \"./ctl/protocol.js\";\nimport { execFileCapture } from \"./exec-file.js\";\nimport { activeMux } from \"./mux/detect.js\";\nimport { tmux } from \"./tmux.js\";\n\nexport type RuntimeState = \"busy\" | \"needs_input\" | \"needs_permission\" | \"unknown\";\nexport type StateSource = \"murmur\" | \"herdr\" | \"ctl\" | \"none\";\n/** How a pi agent's control socket answered; \"n/a\" for non-pi agents. */\nexport type CtlLink = \"ok\" | \"missing\" | \"refused\" | \"n/a\";\n\nexport interface StateReading {\n state: RuntimeState;\n source: StateSource;\n since: number | null;\n alive: boolean;\n reason?: string;\n /** Set for agents that expect a control socket. */\n ctl?: Exclude<CtlLink, \"n/a\">;\n /** ctl only: pi holds queued messages, so an idle reading is about to\n * turn busy. */\n pending?: boolean;\n /** ctl only: pi's settled-run count (`mu agent wait --after-runs`). */\n runs?: number;\n /** ctl only: the extension dialog pi is waiting on (state needs_permission). */\n blocked?: CtlBlocked;\n}\n\nexport interface StateAgentRef {\n name: string;\n workstreamName: string;\n paneId: string;\n /** When set and it names pi, the control socket is the state source. */\n cli?: string;\n}\n\n/** Per-agent budget for the control-socket status read (one connection). */\nconst CTL_STATE_PROBE_MS = 1000;\n\n/** ctl's idle maps to needs_input, the same as murmur's idle; an open\n * extension dialog (`blocked`) maps to needs_permission. */\nexport function ctlRuntimeState(state: CtlState, blocked?: CtlBlocked): RuntimeState {\n if (blocked !== undefined) return \"needs_permission\";\n return state === \"busy\" ? \"busy\" : \"needs_input\";\n}\n\n/** The reason line for a dialog-blocked pi: `dialog <kind>: <title>`. */\nexport function blockedReason(blocked: CtlBlocked): string {\n return `dialog ${blocked.kind}${blocked.title !== undefined ? `: ${blocked.title}` : \"\"}`;\n}\n\nexport const UNKNOWN_REASON = {\n murmurMissing: \"murmur not installed\",\n extensionMissing: \"murmur pi extension not linked\",\n noRow: \"murmur has no row\",\n stale: \"remote snapshot stale\",\n herdrNone: \"herdr reports no state\",\n paneGone: \"pane gone\",\n ctlMissing: \"ctl missing\",\n ctlRefused: \"ctl refused\",\n} as const;\n\nexport type MurmurRunner = () => Promise<string | null>;\n\nconst MURMUR_CACHE_MS = 10_000;\nlet murmurRunnerForTests: MurmurRunner | null = null;\nlet murmurCache: { at: number; stdout: string | null } | undefined;\n\nexport function agentKey(a: { name: string; workstreamName: string }): string {\n return `${a.workstreamName}/${a.name}`;\n}\n\nexport function ambiguousReason(n: number): string {\n return `ambiguous: ${n} hosts`;\n}\n\nfunction murmurOnPath(): boolean {\n for (const dir of (process.env.PATH ?? \"\").split(delimiter)) {\n if (dir.length === 0) continue;\n try {\n accessSync(join(dir, \"murmur\"), constants.X_OK);\n return true;\n } catch {\n // Keep scanning PATH.\n }\n }\n return false;\n}\n\nfunction murmurExtensionLinked(): boolean {\n const piDir = process.env.PI_CODING_AGENT_DIR ?? join(homedir(), \".pi\", \"agent\");\n return existsSync(join(piDir, \"extensions\", \"murmur.ts\"));\n}\n\nexport function murmurAvailable(): boolean {\n return murmurOnPath() && murmurExtensionLinked();\n}\n\nconst defaultMurmurRunner: MurmurRunner = async () => {\n try {\n const result = await execFileCapture(\"murmur\", [\"status\", \"--json\"], { timeoutMs: 5_000 });\n return result.exitCode === 0 ? result.stdout : null;\n } catch {\n return null;\n }\n};\n\nexport function setMurmurRunnerForTests(run: MurmurRunner | null): void {\n murmurRunnerForTests = run;\n}\n\nexport function resetAgentStateCacheForTests(): void {\n murmurCache = undefined;\n}\n\nfunction unknown(reason: string, alive = true, source: StateSource = \"none\"): StateReading {\n return { state: \"unknown\", source, since: null, alive, reason };\n}\n\nfunction mapMurmurState(token: string, since: number | null): StateReading {\n let state: RuntimeState;\n switch (token) {\n case \"working\":\n state = \"busy\";\n break;\n case \"blocked\":\n state = \"needs_permission\";\n break;\n case \"idle\":\n case \"done\":\n case \"error\":\n case \"crashed\":\n state = \"needs_input\";\n break;\n default:\n return unknown(`unrecognised murmur state ${token}`, true, \"murmur\");\n }\n return { state, source: \"murmur\", since, alive: true };\n}\n\nfunction parseSince(value: string | undefined): number | null {\n return value !== undefined && /^\\d+$/.test(value) ? Number(value) : null;\n}\n\nasync function readMurmur(now: number): Promise<string | null> {\n if (murmurCache !== undefined && now - murmurCache.at < MURMUR_CACHE_MS) {\n return murmurCache.stdout;\n }\n let stdout: string | null;\n try {\n stdout = await (murmurRunnerForTests ?? defaultMurmurRunner)();\n } catch {\n stdout = null;\n }\n murmurCache = { at: now, stdout };\n return stdout;\n}\n\ninterface MurmurPane {\n local?: unknown;\n agent_name?: unknown;\n workstream?: unknown;\n activity?: unknown;\n attention?: unknown;\n freshness?: unknown;\n updated_at?: unknown;\n}\n\nfunction remotePanes(stdout: string): MurmurPane[] {\n try {\n const parsed: unknown = JSON.parse(stdout);\n if (typeof parsed !== \"object\" || parsed === null || !(\"panes\" in parsed)) return [];\n const panes = parsed.panes;\n if (!Array.isArray(panes)) return [];\n return panes.filter((pane): pane is MurmurPane => typeof pane === \"object\" && pane !== null);\n } catch {\n return [];\n }\n}\n\nfunction remoteReading(agent: StateAgentRef, panes: readonly MurmurPane[]): StateReading {\n const matches = panes.filter(\n (pane) =>\n pane.local === false &&\n pane.agent_name === agent.name &&\n pane.workstream === agent.workstreamName,\n );\n if (matches.length === 0) {\n return unknown(\n murmurExtensionLinked() ? UNKNOWN_REASON.noRow : UNKNOWN_REASON.extensionMissing,\n );\n }\n if (matches.length > 1) return unknown(ambiguousReason(matches.length));\n const row = matches[0];\n if (row === undefined) return unknown(UNKNOWN_REASON.noRow);\n if (row.freshness !== \"fresh\") return unknown(UNKNOWN_REASON.stale);\n\n const kinds = Array.isArray(row.attention)\n ? new Set(\n row.attention.flatMap((entry) =>\n typeof entry === \"object\" &&\n entry !== null &&\n \"kind\" in entry &&\n typeof entry.kind === \"string\"\n ? [entry.kind]\n : [],\n ),\n )\n : new Set<string>();\n const state: RuntimeState =\n kinds.has(\"crashed\") || kinds.has(\"error\")\n ? \"needs_input\"\n : kinds.has(\"blocked\")\n ? \"needs_permission\"\n : kinds.has(\"done\")\n ? \"needs_input\"\n : row.activity === \"running\"\n ? \"busy\"\n : \"needs_input\";\n return {\n state,\n source: \"murmur\",\n since: typeof row.updated_at === \"number\" ? row.updated_at : null,\n alive: true,\n };\n}\n\nasync function readHerdrStates(\n agents: readonly StateAgentRef[],\n mux: Awaited<ReturnType<typeof activeMux>>,\n): Promise<Map<string, StateReading>> {\n const readings = new Map<string, StateReading>();\n for (const agent of agents) {\n try {\n const status = await mux.paneStatus?.(agent.paneId);\n if (status !== undefined) {\n readings.set(agentKey(agent), {\n state: status,\n source: \"herdr\",\n since: null,\n alive: true,\n });\n continue;\n }\n const alive = await mux.paneExists(agent.paneId);\n readings.set(\n agentKey(agent),\n alive\n ? unknown(UNKNOWN_REASON.herdrNone, true, \"herdr\")\n : unknown(UNKNOWN_REASON.paneGone, false),\n );\n } catch (error) {\n readings.set(\n agentKey(agent),\n unknown(`herdr: ${error instanceof Error ? error.message : String(error)}`),\n );\n }\n }\n return readings;\n}\n\n/**\n * Read the runtime state of each agent. Order per agent: control socket\n * (pi agents) → murmur pane option → murmur remote → herdr. A pi agent\n * whose socket does not answer reads `unknown` with reason `ctl missing`\n * or `ctl refused`, never a murmur reading, so the gap stays visible.\n * `stateDir` roots the derived socket path (spawn uses the DB's directory).\n */\nexport async function readAgentStates(\n agents: readonly StateAgentRef[],\n opts: { now?: number; stateDir?: string } = {},\n): Promise<Map<string, StateReading>> {\n const ctlAgents = agents.filter(\n (a) =>\n a.cli !== undefined &&\n expectsCtl(\n { cli: a.cli, name: a.name, workstreamName: a.workstreamName },\n ctlSocketPath(a.workstreamName, a.name, opts.stateDir),\n ),\n );\n const probes = await Promise.all(\n ctlAgents.map((a) =>\n ctlProbe(ctlSocketPath(a.workstreamName, a.name, opts.stateDir), CTL_STATE_PROBE_MS, {\n hello: false,\n }),\n ),\n );\n const readings = new Map<string, StateReading>();\n const failed = new Map<string, \"missing\" | \"refused\">();\n ctlAgents.forEach((agent, i) => {\n const probe = probes[i];\n if (probe?.kind === \"ok\") {\n const { blocked } = probe.status;\n readings.set(agentKey(agent), {\n state: ctlRuntimeState(probe.status.state, blocked),\n source: \"ctl\",\n since: blocked?.since ?? probe.status.since,\n alive: true,\n ...(blocked !== undefined ? { reason: blockedReason(blocked), blocked } : {}),\n ctl: \"ok\",\n pending: probe.status.pending,\n runs: probe.status.runs,\n });\n } else {\n failed.set(agentKey(agent), probe?.kind === \"missing\" ? \"missing\" : \"refused\");\n }\n });\n const rest = agents.filter((a) => !readings.has(agentKey(a)));\n if (rest.length === 0) return readings;\n // A ctl-failed agent keeps only the base reading's liveness, so it never\n // needs the murmur remote read (whose rows are always alive).\n for (const [key, reading] of await readBaseStates(rest, opts, new Set(failed.keys()))) {\n const ctl = failed.get(key);\n if (ctl === undefined) readings.set(key, reading);\n else if (!reading.alive) readings.set(key, { ...reading, ctl });\n else {\n const reason = ctl === \"missing\" ? UNKNOWN_REASON.ctlMissing : UNKNOWN_REASON.ctlRefused;\n readings.set(key, { ...unknown(reason), ctl });\n }\n }\n return readings;\n}\n\nasync function readBaseStates(\n agents: readonly StateAgentRef[],\n opts: { now?: number },\n livenessOnly: ReadonlySet<string> = new Set(),\n): Promise<Map<string, StateReading>> {\n const readings = new Map<string, StateReading>();\n let mux: Awaited<ReturnType<typeof activeMux>>;\n try {\n mux = await activeMux();\n } catch (error) {\n const reason = `mux: ${error instanceof Error ? error.message : String(error)}`;\n for (const agent of agents) readings.set(agentKey(agent), unknown(reason));\n return readings;\n }\n if (mux.paneStatus !== undefined) return await readHerdrStates(agents, mux);\n\n let stdout: string;\n try {\n stdout = await tmux([\n \"list-panes\",\n \"-a\",\n \"-F\",\n \"#{pane_id}\\t#{@murmur_pane_state}\\t#{@murmur_pane_since}\",\n ]);\n } catch (error) {\n const reason = `tmux: ${error instanceof Error ? error.message : String(error)}`;\n for (const agent of agents) readings.set(agentKey(agent), unknown(reason));\n return readings;\n }\n\n const local = new Map<string, { token: string; since: number | null }>();\n for (const line of stdout.split(\"\\n\")) {\n if (line.length === 0) continue;\n const [paneId, token = \"\", since] = line.split(\"\\t\");\n if (paneId !== undefined) local.set(paneId, { token, since: parseSince(since) });\n }\n\n const remoteCandidates: StateAgentRef[] = [];\n for (const agent of agents) {\n const pane = local.get(agent.paneId);\n if (pane === undefined) {\n readings.set(agentKey(agent), unknown(UNKNOWN_REASON.paneGone, false));\n } else if (livenessOnly.has(agentKey(agent))) {\n readings.set(agentKey(agent), unknown(UNKNOWN_REASON.noRow));\n } else if (pane.token.length > 0) {\n readings.set(agentKey(agent), mapMurmurState(pane.token, pane.since));\n } else {\n remoteCandidates.push(agent);\n }\n }\n\n if (remoteCandidates.length === 0) return readings;\n const remoteStdout = await readMurmur(opts.now ?? Date.now());\n if (remoteStdout === null) {\n const reason = murmurAvailable()\n ? UNKNOWN_REASON.noRow\n : murmurOnPath()\n ? UNKNOWN_REASON.extensionMissing\n : UNKNOWN_REASON.murmurMissing;\n for (const agent of remoteCandidates) readings.set(agentKey(agent), unknown(reason));\n return readings;\n }\n\n const panes = remotePanes(remoteStdout);\n for (const agent of remoteCandidates) readings.set(agentKey(agent), remoteReading(agent, panes));\n return readings;\n}\n","// mu — send transport: how `mu agent send` reaches an agent.\n//\n// A pi agent (speaksMuCtl) is reached through its control socket, served\n// by the mu pi extension inside the pane's own pi. `/new`, `/reload` and\n// `/compact` become the ctl `command` op; any other slash command is\n// refused (pi.sendUserMessage would hand it to the model as text). Only\n// non-pi agents and an explicit `--via mux` reach the mux paste path. No\n// silent fallback: a pi agent whose socket does not answer is an\n// AgentCtlUnreachableError, never a paste.\n\nimport { existsSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport type { AgentRow } from \"../agents.js\";\nimport {\n CtlDeliveryUnknownError,\n CtlUnknownOpError,\n CtlVersionError,\n ctlRequest,\n errCode,\n} from \"../ctl/client.js\";\nimport { ctlSocketPath } from \"../ctl/path.js\";\nimport {\n CTL_COMMANDS,\n type CtlCommandName,\n type CtlReply,\n type CtlRequest,\n type CtlState,\n} from \"../ctl/protocol.js\";\nimport type { Db } from \"../db.js\";\nimport { emitEvent } from \"../logs.js\";\nimport { activeMux, type SendOptions } from \"../mux.js\";\nimport {\n AgentBusyError,\n AgentCtlUnreachableError,\n AgentEmptySendError,\n AgentExtensionOutdatedError,\n AgentFreshNeedsCtlError,\n AgentPaneDeadError,\n AgentSendIndeterminateError,\n AgentSlashCommandUnsupportedError,\n} from \"./errors.js\";\nimport { resolveCliCommand, speaksMuCtl } from \"./spawn.js\";\n\nexport type Transport = \"ctl\" | \"mux\";\n\nexport type SendResult = {\n transport: Transport;\n state?: CtlState;\n /**\n * ctl only: pi's completed-run count. For a plain send it is measured\n * before dispatch (the `mu agent wait --after-runs` baseline); for\n * `--fresh` it is the new session's count once its run started.\n * Absent from an extension that predates it.\n */\n runs?: number;\n /** ctl only: when pi entered `state` (epoch ms), from the same status. */\n since?: number;\n /** ctl only: pi's session file, from the same status. */\n sessionFile?: string;\n /** Set when the text ran as a pi session command over ctl. */\n command?: CtlCommandName;\n};\n\nexport type TransportSendOptions = SendOptions & {\n /** How a busy pi queues the message. Default followUp. ctl only. */\n mode?: \"steer\" | \"followUp\";\n /** Force a transport instead of choosing by agent and text. */\n via?: Transport;\n /** Control socket path. Default: agentCtlSocket(db, agent). */\n socket?: string;\n /** Start a new pi session and send the text into it, as one ctl op. */\n fresh?: boolean;\n /** With fresh or a session command: abandon a running turn instead of refusing. */\n force?: boolean;\n};\n\n/** The agent's derived control socket, rooted at the DB's directory (as spawn does). */\nexport function agentCtlSocket(db: Db, agent: AgentRow): string {\n return ctlSocketPath(agent.workstreamName, agent.name, dirname(db.name));\n}\n\n/**\n * True when the agent runs pi, so sends go through its control socket.\n * The cli key decides when it names pi (or MU_<KEY>_COMMAND here runs\n * pi). Otherwise the agent's own socket file decides: spawn removes any\n * stale file before the pane starts, so a file at the derived path was\n * bound by this agent's extension (or its ssh forward). That covers\n * `--cli helper --command \"pi-meta ...\"`, whose command is not stored,\n * without a schema change. `sock` defaults to the derived path; pass\n * agentCtlSocket(db, agent) when a DB is at hand.\n */\nexport function expectsCtl(\n agent: Pick<AgentRow, \"cli\" | \"name\" | \"workstreamName\">,\n sock: string = ctlSocketPath(agent.workstreamName, agent.name),\n): boolean {\n return speaksMuCtl(agent.cli, resolveCliCommand(agent.cli)) || existsSync(sock);\n}\n\n/** The transport a send to `agent` uses when not forced. */\nexport function chooseTransport(agent: AgentRow, sock?: string): Transport {\n return expectsCtl(agent, sock) ? \"ctl\" : \"mux\";\n}\n\n/** The slash commands a pi agent runs over ctl, as typed. */\nexport const CTL_SLASH_COMMANDS = CTL_COMMANDS.map((n) => `/${n}`);\n\n/**\n * `text` as a pi session command: `/new`, `/reload`, or `/compact` with\n * optional instructions. undefined for anything else (a plain prompt, or\n * another slash command: see isSlashCommand).\n */\nexport function parseSessionCommand(\n text: string,\n): { name: CtlCommandName; instructions?: string } | undefined {\n const t = text.trim();\n if (t === \"/new\") return { name: \"new\" };\n if (t === \"/reload\") return { name: \"reload\" };\n const m = /^\\/compact(?:\\s+([\\s\\S]*))?$/.exec(t);\n if (!m) return undefined;\n const instructions = m[1]?.trim();\n return instructions ? { name: \"compact\", instructions } : { name: \"compact\" };\n}\n\n/** True when `text` reads as a TUI slash command (`/word ...`), not a path or prose. */\nexport function isSlashCommand(text: string): boolean {\n return /^\\/[A-Za-z][\\w:-]*(?:\\s|$)/.test(text.trimStart());\n}\n\n/**\n * Map a CtlUnknownOpError to AgentExtensionOutdatedError, asking the\n * socket's `hello` (best effort) for the extension's build version.\n * Checked after the refusal rather than before every op: an unknown op\n * is a no-op in the extension, so the happy path pays no extra trip.\n */\nexport async function extensionOutdated(\n agent: Pick<AgentRow, \"name\" | \"workstreamName\">,\n sock: string,\n e: CtlUnknownOpError,\n): Promise<AgentExtensionOutdatedError> {\n let extVersion: string | undefined;\n try {\n const hello = await ctlRequest(sock, { op: \"hello\" });\n if (hello.ok) extVersion = hello.extVersion;\n } catch {\n // The refusal already proved the socket answers; the version is a nicety.\n }\n return new AgentExtensionOutdatedError(agent.name, agent.workstreamName, e.op, extVersion, e.ops);\n}\n\n/**\n * One ctl request to `agent`, with the failure mapping every ctl verb\n * shares: a version mismatch rethrows, an unknown op becomes\n * AgentExtensionOutdatedError, anything else AgentCtlUnreachableError\n * (missing on ENOENT, else refused).\n */\nexport async function ctlRequestFor(\n agent: Pick<AgentRow, \"name\" | \"workstreamName\" | \"paneId\">,\n sock: string,\n req: CtlRequest,\n): Promise<CtlReply> {\n try {\n return await ctlRequest(sock, req);\n } catch (e) {\n throw await ctlFailure(agent, sock, e);\n }\n}\n\n/** The error ctlRequestFor raises for a failed ctl request (see there). */\nexport async function ctlFailure(\n agent: Pick<AgentRow, \"name\" | \"workstreamName\" | \"paneId\">,\n sock: string,\n e: unknown,\n): Promise<unknown> {\n if (e instanceof CtlVersionError) return e;\n if (e instanceof CtlUnknownOpError) return extensionOutdated(agent, sock, e);\n // A silent socket on a vanished pane is a dead agent, not a link problem.\n if (await paneGone(agent.paneId)) {\n return new AgentPaneDeadError(agent.name, agent.workstreamName, agent.paneId);\n }\n if (e instanceof CtlDeliveryUnknownError) {\n return new AgentSendIndeterminateError(agent.name, agent.workstreamName, e.op, e.cause.message);\n }\n return new AgentCtlUnreachableError(\n agent.name,\n agent.workstreamName,\n sock,\n errCode(e) === \"ENOENT\" ? \"missing\" : \"refused\",\n );\n}\n\n/** True only when the mux positively reports the pane gone (a mux error is \"unknown\"). */\nasync function paneGone(paneId: string): Promise<boolean> {\n try {\n return !(await (await activeMux()).paneExists(paneId));\n } catch {\n return false;\n }\n}\n\n/** How `mu agent send` delivered: the `mode=` of an `agent.send` op. */\nexport type SendMode = \"plain\" | \"steer\" | \"interrupt\" | \"fresh\";\n\n/**\n * Record a delivered send as an `agent.send` op. `agents` is machine-local\n * and a send mutates no table, so this emit is the only record that a\n * running worker was told something, and when. `fields` carries pi's\n * pre-send state (`since` as ISO) so an audit can see a worker stuck in\n * one long turn when a plain/steer send queued behind it.\n */\nexport function recordSend(\n db: Db,\n agent: Pick<AgentRow, \"name\" | \"workstreamName\">,\n mode: SendMode,\n bytes: number,\n fields: Record<string, string | number | boolean | undefined>,\n /** Who sent it (resolveActorIdentity); lands in `ops.actor`. */\n source = \"system\",\n): void {\n const detail = Object.entries({ mode, ...fields })\n .filter(([, v]) => v !== undefined)\n .map(([k, v]) => `${k}=${k === \"since\" ? new Date(Number(v)).toISOString() : v}`)\n .join(\" \");\n emitEvent(\n db,\n agent.workstreamName,\n \"agent.send\",\n `agent send ${agent.name} (${detail}, ${bytes} bytes)`,\n source,\n );\n}\n\nexport async function sendViaTransport(\n agent: AgentRow,\n text: string,\n // Required: only the caller knows the DB whose directory roots the socket.\n opts: TransportSendOptions & { socket: string },\n): Promise<SendResult> {\n const sock = opts.socket;\n if (opts.fresh && (opts.via === \"mux\" || !expectsCtl(agent, sock))) {\n throw new AgentFreshNeedsCtlError(agent.name, agent.workstreamName, agent.cli);\n }\n const transport = opts.fresh ? \"ctl\" : (opts.via ?? chooseTransport(agent, sock));\n if (transport === \"mux\") {\n // The paste path: non-pi CLIs, adopted panes, and an explicit --via mux.\n // Load-bearing: a send that cannot reach a pane is a failed send.\n await (await activeMux()).sendToPane(agent.paneId, text, opts);\n return { transport };\n }\n if (text === \"\") throw new AgentEmptySendError(agent.name, agent.workstreamName);\n if (!opts.fresh) {\n const cmd = parseSessionCommand(text);\n if (cmd) return runSessionCommand(agent, sock, cmd, opts.force === true);\n if (isSlashCommand(text)) {\n throw new AgentSlashCommandUnsupportedError(\n agent.name,\n agent.workstreamName,\n text,\n CTL_SLASH_COMMANDS,\n );\n }\n }\n const reply = await ctlRequestFor(\n agent,\n sock,\n opts.fresh\n ? { op: \"fresh\", text, ...(opts.force ? { force: true } : {}) }\n : { op: \"send\", text, mode: opts.mode ?? \"followUp\" },\n );\n if (!reply.ok) {\n if (opts.fresh && reply.error === \"busy\") {\n throw new AgentBusyError(agent.name, agent.workstreamName);\n }\n throw new Error(`control socket refused the send: ${reply.error}`);\n }\n return {\n transport,\n ...(reply.state !== undefined ? { state: reply.state } : {}),\n ...(reply.runs !== undefined ? { runs: reply.runs } : {}),\n ...(reply.since !== undefined ? { since: reply.since } : {}),\n ...(reply.sessionFile !== undefined ? { sessionFile: reply.sessionFile } : {}),\n };\n}\n\n/** `/new`, `/reload` or `/compact` inside pi, through the ctl `command` op. */\nasync function runSessionCommand(\n agent: AgentRow,\n sock: string,\n cmd: { name: CtlCommandName; instructions?: string },\n force: boolean,\n): Promise<SendResult> {\n const reply = await ctlRequestFor(agent, sock, {\n op: \"command\",\n name: cmd.name,\n ...(cmd.instructions !== undefined ? { instructions: cmd.instructions } : {}),\n ...(force ? { force: true } : {}),\n });\n if (!reply.ok) {\n if (reply.error === \"busy\") {\n throw new AgentBusyError(agent.name, agent.workstreamName, `/${cmd.name}`);\n }\n throw new Error(`pi refused /${cmd.name}: ${reply.error}`);\n }\n return {\n transport: \"ctl\",\n command: cmd.name,\n ...(reply.state !== undefined ? { state: reply.state } : {}),\n };\n}\n","/**\n * Client for the per-agent control socket served by the mu pi extension.\n * One request per connection: connect, write one line, read one line, end.\n */\nimport { createConnection } from \"node:net\";\nimport {\n CTL_PROTOCOL_VERSION,\n type CtlReply,\n type CtlRequest,\n type CtlStatus,\n encode,\n LineDecoder,\n UNKNOWN_OP_PREFIX,\n} from \"./protocol.js\";\n\n/** Default client timeout for non-`wait` requests. */\nexport const CTL_DEFAULT_TIMEOUT_MS = 5000;\n/** Client timeout for `fresh` and `command`: the new session must start its run, or pi reload. */\nexport const CTL_FRESH_TIMEOUT_MS = 60_000;\n/** Slack added to a `wait` request's own timeoutMs for the client timeout. */\nexport const CTL_WAIT_SLACK_MS = 5000;\n\nexport type CtlProbe =\n | {\n kind: \"ok\";\n status: CtlStatus;\n /** From hello: the ops the extension serves. Absent: it predates reporting them. */\n ops?: string[];\n /** From hello: the mu version the extension was built from. */\n extVersion?: string;\n }\n | { kind: \"missing\" }\n | { kind: \"refused\"; error: string }\n | { kind: \"version\"; got: unknown };\n\nexport class CtlVersionError extends Error {\n constructor(readonly got: unknown) {\n super(`control socket speaks protocol v${String(got)}; mu expects v${CTL_PROTOCOL_VERSION}`);\n this.name = \"CtlVersionError\";\n }\n}\n\nexport class CtlTimeoutError extends Error {\n constructor(readonly timeoutMs: number) {\n super(`control socket did not reply within ${timeoutMs}ms`);\n this.name = \"CtlTimeoutError\";\n }\n}\n\n/**\n * A side-effecting request (send, fresh, interrupt, command) was written\n * to the socket, then the connection timed out, errored or closed with no\n * reply. pi may or may not have acted on it. `cause` is the raw failure.\n */\nexport class CtlDeliveryUnknownError extends Error {\n constructor(\n readonly op: string,\n override readonly cause: Error,\n ) {\n super(`control socket ${op} request was written but no reply arrived: ${cause.message}`);\n this.name = \"CtlDeliveryUnknownError\";\n }\n}\n\n/** Ops that change pi's state: a failure after the write is ambiguous. */\nconst SIDE_EFFECT_OPS: ReadonlySet<string> = new Set([\"send\", \"fresh\", \"interrupt\", \"command\"]);\n\n/**\n * The extension answered \"unknown op\": it was loaded before mu learned\n * `op`. `ops` lists what it serves (absent from extensions that predate\n * reporting them).\n */\nexport class CtlUnknownOpError extends Error {\n constructor(\n readonly op: string,\n readonly ops?: readonly string[],\n ) {\n super(`control socket does not serve op ${op}`);\n this.name = \"CtlUnknownOpError\";\n }\n}\n\nfunction clientTimeout(req: CtlRequest, override?: number): number | undefined {\n if (override !== undefined) return override;\n if (req.op === \"fresh\" || req.op === \"command\") return CTL_FRESH_TIMEOUT_MS;\n if (req.op !== \"wait\" && req.op !== \"interrupt\") return CTL_DEFAULT_TIMEOUT_MS;\n // An unbounded wait (or interrupt) is held until pi settles.\n return req.timeoutMs === undefined ? undefined : req.timeoutMs + CTL_WAIT_SLACK_MS;\n}\n\nfunction parseReply(line: string): CtlReply {\n const msg: unknown = JSON.parse(line);\n const v = typeof msg === \"object\" && msg !== null ? (msg as { v?: unknown }).v : undefined;\n if (v !== CTL_PROTOCOL_VERSION) throw new CtlVersionError(v);\n return msg as CtlReply;\n}\n\n/**\n * Send one request and resolve with its reply. Rejects with the socket\n * error (its `code` intact), CtlTimeoutError, CtlDeliveryUnknownError\n * (side-effecting op failed after the write), CtlVersionError, or\n * CtlUnknownOpError (an ok:false \"unknown op\" reply).\n * Aborting `signal` closes the connection and rejects.\n */\nexport function ctlRequest(\n sock: string,\n req: CtlRequest,\n opts?: { timeoutMs?: number; signal?: AbortSignal },\n): Promise<CtlReply> {\n const timeoutMs = clientTimeout(req, opts?.timeoutMs);\n return new Promise((resolve, reject) => {\n const conn = createConnection(sock);\n // Set when conn.write is called. A write callback is not a delivery ack, so never cleared.\n let written = false;\n const ambiguous = (err: Error): Error =>\n written && SIDE_EFFECT_OPS.has(req.op) ? new CtlDeliveryUnknownError(req.op, err) : err;\n const dec = new LineDecoder();\n let done = false;\n const finish = (err: Error | null, reply?: CtlReply): void => {\n if (done) return;\n done = true;\n if (timer) clearTimeout(timer);\n conn.destroy();\n if (err) reject(err);\n else if (reply) resolve(reply);\n };\n const timer =\n timeoutMs === undefined\n ? undefined\n : setTimeout(() => finish(ambiguous(new CtlTimeoutError(timeoutMs))), timeoutMs);\n const signal = opts?.signal;\n if (signal?.aborted) finish(new Error(\"control socket request aborted\"));\n signal?.addEventListener(\"abort\", () => finish(new Error(\"control socket request aborted\")), {\n once: true,\n });\n conn.setEncoding(\"utf8\");\n conn.on(\"connect\", () => {\n written = true;\n conn.write(encode(req));\n });\n conn.on(\"data\", (chunk: string) => {\n const line = dec.push(chunk)[0];\n if (line === undefined) return;\n try {\n const reply = parseReply(line);\n if (!reply.ok && reply.error.startsWith(UNKNOWN_OP_PREFIX)) {\n finish(new CtlUnknownOpError(req.op, reply.ops));\n } else finish(null, reply);\n } catch (e) {\n finish(e instanceof Error ? e : new Error(String(e)));\n }\n });\n conn.on(\"error\", (e) => finish(ambiguous(e)));\n conn.on(\"close\", () => finish(ambiguous(new Error(\"control socket closed without a reply\"))));\n });\n}\n\n/** A Node system error's `code` (ENOENT, ECONNREFUSED, ...), if any. */\nexport function errCode(e: unknown): string | undefined {\n const code = typeof e === \"object\" && e !== null ? (e as { code?: unknown }).code : undefined;\n return typeof code === \"string\" ? code : undefined;\n}\n\n/**\n * hello + status (status only with `hello: false`, one connection).\n * `timeoutMs` bounds the whole probe, not each request. ENOENT → missing;\n * a version mismatch → version; any other failure (ECONNREFUSED,\n * ENOTSOCK, timeout, bad reply) → refused.\n */\nexport async function ctlProbe(\n sock: string,\n timeoutMs = CTL_DEFAULT_TIMEOUT_MS,\n opts: { hello?: boolean } = {},\n): Promise<CtlProbe> {\n const deadline = Date.now() + timeoutMs;\n try {\n let hello: CtlReply | undefined;\n if (opts.hello !== false) {\n hello = await ctlRequest(sock, { op: \"hello\" }, { timeoutMs });\n if (!hello.ok) return { kind: \"refused\", error: hello.error };\n }\n const left = Math.max(1, deadline - Date.now());\n const st = await ctlRequest(sock, { op: \"status\" }, { timeoutMs: left });\n if (!st.ok) return { kind: \"refused\", error: st.error };\n const { state, since, runs, pending, blocked } = st;\n if (state === undefined || since === undefined || runs === undefined || pending === undefined) {\n return { kind: \"refused\", error: \"status reply is missing fields\" };\n }\n return {\n kind: \"ok\",\n status: { state, since, runs, pending, ...(blocked !== undefined ? { blocked } : {}) },\n ...(hello?.ok && hello.ops !== undefined ? { ops: hello.ops } : {}),\n ...(hello?.ok && hello.extVersion !== undefined ? { extVersion: hello.extVersion } : {}),\n };\n } catch (e) {\n if (e instanceof CtlVersionError) return { kind: \"version\", got: e.got };\n if (errCode(e) === \"ENOENT\") return { kind: \"missing\" };\n return { kind: \"refused\", error: e instanceof Error ? e.message : String(e) };\n }\n}\n","/**\n * mu control socket protocol: JSON lines over a unix socket, one request\n * per connection. Shared by mu's client and the mu pi extension, so this\n * file imports nothing from mu — the extension loads it standalone.\n */\n\nexport const CTL_PROTOCOL_VERSION = 1;\n\nexport type CtlState = \"busy\" | \"idle\";\n\n/**\n * pi is waiting on a blocking extension dialog (ui_prompt_start without\n * its ui_prompt_end): a confirm, select, input, editor or custom prompt.\n * `kind` and `title` are the innermost open dialog's; `since` is when the\n * first one opened (ms epoch).\n */\nexport type CtlBlocked = { kind: string; title?: string; since: number };\n\nexport type CtlRequest =\n | { op: \"hello\" }\n | { op: \"status\" }\n | { op: \"send\"; text: string; mode?: \"steer\" | \"followUp\" }\n /**\n * Resolve once a run past afterRuns settles. With returnOnBlocked, also\n * resolve (ended \"blocked\", runs unchanged) when a dialog is open or\n * opens. Older extensions ignore the flag and hold until the settle.\n */\n | { op: \"wait\"; afterRuns?: number; timeoutMs?: number; returnOnBlocked?: boolean }\n | { op: \"abort\" }\n /**\n * Make a busy pi act on `text` now: abort the running turn, wait for\n * agent_settled (up to timeoutMs), then send `text` as a new run. Idle:\n * just send. Replies `timeout` and sends nothing when pi does not settle.\n */\n | { op: \"interrupt\"; text: string; timeoutMs?: number }\n /** New session + prompt as one operation. Refused with error \"busy\" unless force. */\n | { op: \"fresh\"; text: string; force?: boolean }\n /**\n * Run one of pi's session commands inside pi (sendUserMessage cannot run\n * built-in slash commands). Refused with error \"busy\" unless force.\n */\n | { op: \"command\"; name: CtlCommandName; instructions?: string; force?: boolean };\n\n/** Session commands the `command` op runs: `/new`, `/reload`, `/compact`. */\nexport const CTL_COMMANDS = [\"new\", \"reload\", \"compact\"] as const;\nexport type CtlCommandName = (typeof CTL_COMMANDS)[number];\n\n/**\n * Every op this protocol defines. The extension reports the ops it serves\n * in its `hello` reply (and in an unknown-op error), so mu can tell an\n * extension loaded by an older pi process from a broken one.\n */\nexport const CTL_OPS = [\n \"hello\",\n \"status\",\n \"send\",\n \"wait\",\n \"abort\",\n \"interrupt\",\n \"fresh\",\n \"command\",\n] as const satisfies readonly CtlRequest[\"op\"][];\n\nexport type CtlStatus = {\n state: CtlState;\n since: number;\n runs: number;\n pending: boolean;\n /** The pi session file (where the transcript is written); absent for an ephemeral pi or an older extension. */\n sessionFile?: string;\n /** Set while pi waits on an extension dialog; absent from older extensions. */\n blocked?: CtlBlocked;\n};\n\nexport type CtlReply =\n | ({ v: 1; ok: true } & Partial<CtlStatus> & {\n agent?: string;\n workstream?: string;\n piVersion?: string;\n /** hello only: the ops this extension serves. Absent: predates reporting. */\n ops?: string[];\n /** hello only: the mu package version the extension was built from. */\n extVersion?: string;\n /** wait only: \"blocked\" when a dialog ended the wait before a settle (returnOnBlocked). */\n ended?: \"settled\" | \"blocked\";\n /** wait only: text of the settled run's final assistant message (\"\" when none). */\n lastText?: string;\n /** wait only: the error that ended the settled run (retries exhausted). */\n lastError?: string;\n /** wait only: the settled pi's session file, where its full transcript lives. */\n sessionFile?: string;\n /**\n * abort, interrupt: pi was busy, so a turn was aborted. For abort,\n * absent from older extensions (which always call abort).\n */\n wasBusy?: boolean;\n })\n | { v: 1; ok: false; error: string; ops?: string[] };\n\n/** Error text of a reply to an op the extension does not serve. */\nexport const UNKNOWN_OP_PREFIX = \"unknown op: \";\n\n/** One frame. JSON.stringify escapes \"\\n\" inside strings, so the frame is one line. */\nexport function encode(msg: object): string {\n return `${JSON.stringify(msg)}\\n`;\n}\n\n/** Splits a stream into lines on \"\\n\" only (never U+2028/U+2029). */\nexport class LineDecoder {\n private buf = \"\";\n\n push(chunk: string): string[] {\n this.buf += chunk;\n const parts = this.buf.split(\"\\n\");\n this.buf = parts.pop() ?? \"\";\n return parts;\n }\n}\n","/**\n * Per-agent control socket path. Derived from (state dir, workstream,\n * agent) on every call; never stored. The mu pi extension serves the\n * socket at `$MU_CTL_SOCK`, and mu connects to the same derived path.\n */\nimport { createHash } from \"node:crypto\";\nimport { rmSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { type Db, defaultStateDir } from \"../db.js\";\n\n/** Env var spawn injects so the pi extension knows where to listen. */\nexport const CTL_SOCK_ENV = \"MU_CTL_SOCK\";\n\n/** macOS sun_path is 104 bytes including the trailing NUL. */\nexport const MAX_SOCK_PATH = 103;\n\n/** `<dir>/<ws>/<agent>.sock`, or `<dir>/h/<hash>.sock` past MAX_SOCK_PATH. */\nfunction sockPathUnder(dir: string, workstream: string, agent: string): string {\n const readable = join(dir, workstream, `${agent}.sock`);\n if (Buffer.byteLength(readable) <= MAX_SOCK_PATH) return readable;\n const h = createHash(\"sha1\").update(`${workstream}/${agent}`).digest(\"hex\").slice(0, 16);\n return join(dir, \"h\", `${h}.sock`);\n}\n\nexport function ctlSocketPath(workstream: string, agent: string, stateDir?: string): string {\n const dbPath = process.env.MU_DB_PATH;\n const base = stateDir ?? (dbPath ? dirname(dbPath) : defaultStateDir());\n return sockPathUnder(join(base, \"sock\"), workstream, agent);\n}\n\n/**\n * Remove an agent's local control socket file. For a remote agent ssh's\n * `-L` forward leaves that file behind when the connection dies; it\n * probes as `refused`, never `ok`, but it is litter. A local pi removes\n * its own on quit. Best-effort: callers have already deleted the row.\n */\nexport function unlinkCtlSocket(db: Db, name: string, workstream: string): void {\n if (db.memory) return;\n try {\n rmSync(ctlSocketPath(workstream, name, dirname(db.name)), { force: true });\n } catch {\n /* best-effort */\n }\n}\n\n/**\n * Default socket path ON THE REMOTE HOST for a remote pi agent:\n * `/tmp/mu-<uid>/<ws>/<agent>.sock`, shortened by the same rule. `uid`\n * is the local one (mu cannot know the remote's); the extension creates\n * the directory, and `mu agent remote-env --remote-sock` overrides it.\n */\nexport function remoteCtlSocketPath(workstream: string, agent: string, uid: number): string {\n return sockPathUnder(`/tmp/mu-${uid}`, workstream, agent);\n}\n","// mu — spawnAgent + supporting helpers (resolveCliCommand,\n// awaitSpawnLiveness, createOrReusePane, defaultSpawnLivenessMs,\n// prestageWorkspace, finalizeAgentRow, rollbackSpawn).\n//\n// spawnAgent's flow is documented inline. The interesting bit is the\n// `--workspace` cycle (workspace row FKs agent.name; agent row needs\n// pane_id which needs workspace path as cwd) — see prestageWorkspace.\n//\n// Extracted from src/agents.ts as part of refactor_split_large_src_files.\n\nimport { execFile } from \"node:child_process\";\nimport { existsSync, mkdirSync, rmSync, statSync } from \"node:fs\";\nimport { basename, dirname, resolve } from \"node:path\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport { promisify } from \"node:util\";\nimport {\n type AgentRow,\n deleteAgent,\n getAgent,\n insertAgent,\n isValidAgentName,\n MAX_AGENT_NAME_LEN,\n pendingPaneIdFor,\n} from \"../agents.js\";\nimport { type CtlProbe, ctlProbe } from \"../ctl/client.js\";\nimport { CTL_SOCK_ENV, ctlSocketPath } from \"../ctl/path.js\";\nimport type { Db } from \"../db.js\";\nimport { emitEvent } from \"../logs.js\";\nimport { activeMux, type MuxBackend } from \"../mux.js\";\nimport { isJsonMode, type NextStep } from \"../output.js\";\nimport { resolveActorIdentity } from \"../tasks/claim.js\";\n// `sleep` is the shared poll-sleep TEST SEAM (setSleepForTests), not a\n// multiplexer operation, so it stays on the tmux module rather than\n// joining the MuxBackend contract.\nimport { sleep } from \"../tmux.js\";\nimport type { VcsBackendName } from \"../vcs.js\";\nimport { createWorkspace, freeWorkspace, workspacePath } from \"../workspace.js\";\nimport { ensureWorkstreamSession, isScratchWorkstream } from \"../workstream.js\";\nimport {\n AgentDiedOnSpawnError,\n AgentExistsError,\n AgentNameExhaustedError,\n AgentSpawnCliNotFoundError,\n AgentSpawnStartupError,\n} from \"./errors.js\";\nimport { withSpawnLock } from \"./spawn-lock.js\";\n\n/**\n * Smallest-unused-suffix naming convention for agent names: a role\n * (lowercase alpha + digits) followed by `-<n>` where `<n>` is one or\n * more digits. Examples that pass: `worker-1`, `reviewer-2`, `scout-12`.\n * Examples that warn: `worker-tests`, `alice`, `db-leader`, `x-y-1`.\n *\n * Source: feedback ws task fb_agent_naming_convention. The dogfood report\n * was operators (LLMs included) drifting to descriptive names like\n * `worker-tests` after a few spawns, breaking the convention silently.\n * The hint surfaced by `maybeWarnNonConventionalAgentName` is a lint, not\n * a rule — `isValidAgentName` still accepts the broader\n * `^[a-z][a-z0-9_-]{0,31}$` shape.\n */\nconst AGENT_NAME_CONVENTION_RE = /^[a-z][a-z0-9]*(?:-[0-9]+)$/;\n\n/**\n * Stderr lint when an agent name doesn't match the smallest-unused-suffix\n * convention. Mirrors the slugify-truncation stderr hint in cmdTaskAdd\n * (commit 28a13af): stderr-only, exit 0, suppressed under --json so\n * machine consumers stay clean. The spawn already succeeded by the time\n * this runs — we're just nudging the operator toward `<role>-<n>`.\n */\nfunction maybeWarnNonConventionalAgentName(name: string): void {\n if (AGENT_NAME_CONVENTION_RE.test(name)) return;\n if (isJsonMode()) return;\n process.stderr.write(\n `hint: agent name \"${name}\" does not match the smallest-unused-suffix convention (<role>-<n>; e.g. worker-1, reviewer-2). Accepted; consider renaming if you spawn additional workers.\\n`,\n );\n}\n\n/**\n * Resolve the actual executable to launch in an agent's pane for a given\n * `cli`. Honours the env var `MU_<UPPER_CLI>_COMMAND` (e.g. `MU_PI_COMMAND=\n * pi-alt` makes `--cli pi` actually exec `pi-alt`). Falls back to the cli\n * name itself, which is what users expect when their `pi` binary is on\n * `$PATH` under that exact name.\n *\n * Used by `spawnAgent` to pick the spawned command, and by reconcile's\n * orphan detector so externally-spawned panes running the resolved binary\n * are still recognised as agents.\n */\nexport function resolveCliCommand(cli: string): string {\n const envName = envVarNameForCli(cli);\n const override = process.env[envName];\n return override && override.trim() !== \"\" ? override : cli;\n}\n\n/**\n * Compute the `MU_<UPPER_CLI>_COMMAND` env var name mu consults when\n * resolving `--cli <key>`. Hyphens in the cli key become underscores\n * (env var names can't contain `-`); this matches the operator-aliases\n * convention documented in the mu skill (e.g. `--cli pi-meta` →\n * `MU_PI_META_COMMAND`).\n */\nexport function envVarNameForCli(cli: string): string {\n return `MU_${cli.toUpperCase().replace(/-/g, \"_\")}_COMMAND`;\n}\n\n/**\n * Resolve `--cli <key>` to its actual command string AND tell the\n * caller whether the resolution came from a `MU_<UPPER_CLI>_COMMAND`\n * env var or fell through to the bare cli name. The CLI uses this to\n * surface env-var attribution in the spawn-success line so config\n * issues are visible without `mu agent show`\n * (fb_agent_spawn_no_validation, part C).\n */\nexport function resolveCliCommandWithSource(cli: string): {\n command: string;\n envVar: string;\n resolvedFromEnv: boolean;\n} {\n const envVar = envVarNameForCli(cli);\n const override = process.env[envVar];\n if (override !== undefined && override.trim() !== \"\") {\n return { command: override, envVar, resolvedFromEnv: true };\n }\n return { command: cli, envVar, resolvedFromEnv: false };\n}\n\n// ─── Pre-flight PATH check (fb_agent_spawn_no_validation, part A) ──\n//\n// Operator typo'd `mu agent spawn worker-1 --cli pi-meta` on a host\n// where `pi-meta` wasn't on PATH; the spawn appeared to succeed but\n// the pane died with `command not found` and the existing 1.5s\n// liveness check sometimes missed it (shells stay alive past a failed\n// exec). Pre-flight the PATH resolution so a typo never:\n// 1. creates an orphan workspace dir\n// 2. creates an orphan tmux pane\n// 3. inserts a half-spawned DB row\n// The check fires AFTER `resolveCliCommand` so `MU_<UPPER>_COMMAND`\n// overrides are honoured AND the diagnostic mentions the env var by\n// name. Hookable via `setCommandResolverForTests` so the test suite\n// can simulate \"binary present\" / \"binary absent\" without polluting\n// the real PATH.\n\nexport interface CommandResolutionResult {\n ok: boolean;\n /** First whitespace-separated token of the command — the binary\n * whose presence on PATH we checked. */\n binary: string;\n /** Absolute path of the resolved binary on PATH, when ok=true. */\n resolvedPath?: string;\n}\n\nexport type CommandResolver = (command: string) => Promise<CommandResolutionResult>;\n\nconst execFileP = promisify(execFile);\n\n/** Default resolver: shell-out to `command -v <binary>` (POSIX-portable\n * equivalent of `which`). Returns ok=false when the lookup exits\n * non-zero. Always returns the parsed `binary` field so the typed\n * error can quote what we actually searched for. */\nasync function defaultCommandResolver(command: string): Promise<CommandResolutionResult> {\n const binary = parseFirstToken(command);\n if (binary === \"\") return { ok: false, binary };\n try {\n // `command -v` is the POSIX builtin lookup. Spawned via /bin/sh\n // -c so the builtin is available (it's not an external program).\n const { stdout } = await execFileP(\"/bin/sh\", [\"-c\", `command -v -- ${shellQuote(binary)}`], {\n env: process.env,\n });\n const resolvedPath = stdout.trim();\n if (resolvedPath === \"\") return { ok: false, binary };\n return { ok: true, binary, resolvedPath };\n } catch {\n return { ok: false, binary };\n }\n}\n\n/** Single-quote a token for /bin/sh -c. Only used on the binary name,\n * which `parseFirstToken` already restricted to a non-whitespace run\n * — no embedded single-quotes expected. Escape defensively anyway. */\nfunction shellQuote(s: string): string {\n return `'${s.replace(/'/g, \"'\\\\''\")}'`;\n}\n\n/** First whitespace-separated token of a command string (\"pi-meta\n * --no-solo\" → \"pi-meta\"). Returns \"\" on an empty / whitespace-only\n * input. */\nfunction parseFirstToken(command: string): string {\n const trimmed = command.trim();\n if (trimmed === \"\") return \"\";\n const match = trimmed.match(/^\\S+/);\n return match ? match[0] : \"\";\n}\n\nlet activeCommandResolver: CommandResolver = defaultCommandResolver;\n\n/** Override the PATH resolver. Tests use this to simulate \"binary\n * absent\" / \"binary present\" without depending on what's actually\n * installed. Production callers should never touch this. */\nexport function setCommandResolverForTests(resolver: CommandResolver): void {\n activeCommandResolver = resolver;\n}\n\n/** Restore the default PATH resolver. */\nexport function resetCommandResolverForTests(): void {\n activeCommandResolver = defaultCommandResolver;\n}\n\n/**\n * Verify the first token of `command` resolves to a binary on PATH.\n * Public so tests can call it directly; spawnAgent calls it before\n * prestageWorkspace so a bad --cli never creates an orphan workspace.\n */\nexport async function checkCommandResolvable(command: string): Promise<CommandResolutionResult> {\n return activeCommandResolver(command);\n}\n\nexport interface SpawnAgentOptions {\n name: string;\n workstream: string;\n /** Defaults to \"pi\". Any CLI is accepted: pi is driven over its control\n * socket; others run `MU_<CLI>_COMMAND` (or the cli name) and get\n * text by mux paste. */\n cli?: string;\n /** The actual command to run in the pane. Defaults to the cli value. */\n command?: string;\n /** Window name to group this agent under. Defaults to the agent's name\n * (so each agent gets its own window). Multiple agents sharing a `tab`\n * share a window with multiple panes. */\n tab?: string;\n /** \"full-access\" (default) or \"read-only\". The schema stores it; today\n * the role isn't enforced (deferred to a future capabilities pass). */\n role?: string;\n /** Initial working directory for the spawned pane (`tmux -c <path>`).\n * When `workspace: true` is passed, this is ignored — the workspace\n * path is used instead. */\n cwd?: string;\n /** Override the tmux session name. Defaults to `mu-<workstream>`. */\n tmuxSession?: string;\n /** Auto-create a VCS workspace for this agent before spawning the\n * pane and use the workspace path as cwd. Backend defaults to\n * detection (jj > sl > git > none). */\n workspace?: boolean;\n /** Force a specific VCS backend (only meaningful with `workspace: true`). */\n workspaceBackend?: VcsBackendName;\n /** Optional ref to base the workspace on (only meaningful with\n * `workspace: true`). Backend-specific. */\n workspaceFrom?: string;\n /** Project root the workspace branches from (only meaningful with\n * `workspace: true`). Defaults to `process.cwd()`. */\n workspaceProjectRoot?: string;\n /** Run the control-socket handshake for pi agents (default true).\n * `false` skips it and reports `ctl: \"skipped\"`. */\n ctl?: boolean;\n /** When `name` is taken in the workstream, take the next free one\n * (see `nextFreeAgentName`) instead of failing with AgentExistsError. */\n nextFree?: boolean;\n}\n\n/** How many taken names a `nextFree` spawn skips past before it gives up. */\nconst NEXT_FREE_ATTEMPTS = 32;\n\n/** How many names `nextFreeAgentName` looks up before it gives up. */\nconst NEXT_FREE_LOOKUPS = 1000;\n\n/**\n * `name` when it is free in `workstream`, else the next free name: a\n * trailing `-<n>` counts up (`delegate-1` → `delegate-2`), and a name\n * without one gets `-2`, `-3`, … (`delegate-review` → `delegate-review-2`).\n * The stem is cut so a candidate stays within the 32-char name limit.\n * A name whose workspace dir is still on disk counts as taken: a dead\n * agent's checkout outlives its row (kept as evidence), and spawning\n * that name with --workspace would fail on the dir instead of moving on.\n * Throws AgentNameExhaustedError after NEXT_FREE_LOOKUPS taken names,\n * or when no valid candidate is left (the suffix alone outgrows it).\n */\nexport function nextFreeAgentName(db: Db, name: string, workstream: string): string {\n const free = (n: string) =>\n getAgent(db, n, workstream) === undefined && !existsSync(workspacePath(workstream, n));\n if (free(name)) return name;\n const m = /^(.*)-(\\d+)$/.exec(name);\n const [stem, first] = m ? [m[1] ?? \"\", BigInt(m[2] ?? \"1\")] : [name, 1n];\n for (let i = 1n; i <= BigInt(NEXT_FREE_LOOKUPS); i++) {\n const suffix = `-${first + i}`;\n const candidate = `${stem.slice(0, MAX_AGENT_NAME_LEN - suffix.length)}${suffix}`;\n if (!isValidAgentName(candidate)) {\n throw new AgentNameExhaustedError(name, `no valid name left (tried ${candidate})`);\n }\n if (free(candidate)) return candidate;\n }\n throw new AgentNameExhaustedError(name, `the next ${NEXT_FREE_LOOKUPS} names are taken`);\n}\n\n/** Outcome of the spawn-time control-socket handshake. */\nexport type SpawnCtl = \"ok\" | \"missing\" | \"refused\" | \"skipped\";\n\n/** A ctl probe's outcome as spawn and adopt report it. */\nexport function probeToSpawnCtl(kind: CtlProbe[\"kind\"]): Exclude<SpawnCtl, \"skipped\"> {\n return kind === \"ok\" ? \"ok\" : kind === \"missing\" ? \"missing\" : \"refused\";\n}\n\n/** What spawnAgent returns: the registered row plus the handshake outcome. */\nexport type SpawnedAgent = AgentRow & {\n ctl: SpawnCtl;\n ctlSocket: string;\n /** Set when the startup scan saw a Claude trust dialog parked in the pane. */\n trustDialog?: true;\n};\n\n/**\n * True when the agent runs pi, so the mu pi extension should answer on\n * its control socket: `cli` is \"pi\", or the command's argv0 basename is\n * `pi` / `pi-meta`.\n */\nexport function speaksMuCtl(cli: string, command: string): boolean {\n if (cli === \"pi\") return true;\n const argv0 = basename(parseFirstToken(command));\n return argv0 === \"pi\" || argv0 === \"pi-meta\";\n}\n\n/**\n * Handshake budget in ms after the agent is live. 0 disables. Override\n * via `MU_SPAWN_CTL_MS`.\n */\nexport function defaultSpawnCtlMs(): number {\n const raw = process.env.MU_SPAWN_CTL_MS;\n if (raw === undefined) return 30_000;\n const parsed = Number.parseInt(raw, 10);\n if (Number.isNaN(parsed) || parsed < 0) return 30_000;\n return parsed;\n}\n\n/** Cadence of `onMiss` (pane-alive check + capture: ~2 forks per call). */\nconst CTL_POLL_INTERVAL_MS = 250;\n/** Cadence of the socket-path stat, which costs no fork. */\nconst CTL_STAT_INTERVAL_MS = 50;\n\n/**\n * Poll the control socket until the extension answers or the budget\n * runs out. Returns the last probe outcome. The socket path is stat'd\n * every ~50 ms and probed as soon as it exists, so readiness is seen\n * within ~50 ms of pi binding it. `onMiss` (the pane-alive check) keeps\n * its 250 ms cadence plus one final check at the deadline, and may\n * throw to abort (the pane died); otherwise this never throws. Uses real\n * timers, not the `sleep` seam: tests stub that to a no-op, which would\n * turn this into a busy loop.\n */\nasync function awaitCtlHandshake(\n sock: string,\n onMiss?: () => Promise<void>,\n): Promise<Exclude<SpawnCtl, \"skipped\">> {\n const budgetMs = defaultSpawnCtlMs();\n const deadline = Date.now() + budgetMs;\n let last: Exclude<SpawnCtl, \"skipped\"> = \"missing\";\n let lastMissAt = Number.NEGATIVE_INFINITY;\n let first = true;\n for (;;) {\n if (first || existsSync(sock)) {\n first = false;\n const remaining = deadline - Date.now();\n const probe = await ctlProbe(\n sock,\n Math.max(1, Math.min(remaining, CTL_POLL_INTERVAL_MS * 4)),\n );\n if (probe.kind === \"ok\") return \"ok\";\n last = probeToSpawnCtl(probe.kind);\n }\n // The final check at the deadline always runs, throttle or not: a pane\n // that dies in the last <250 ms keeps the scrollback onMiss captured.\n const atDeadline = Date.now() >= deadline;\n if (onMiss && (atDeadline || Date.now() - lastMissAt >= CTL_POLL_INTERVAL_MS)) {\n lastMissAt = Date.now();\n await onMiss();\n }\n const left = deadline - Date.now();\n if (left <= 0) return last;\n await delay(Math.min(CTL_STAT_INTERVAL_MS, left));\n }\n}\n\n/**\n * Spawn a new agent in its tmux pane and register it in the DB.\n *\n * Phases:\n * 1. Validate name + uniqueness.\n * 2. If --workspace: prestageWorkspace() (placeholder agent row +\n * workspace dir + workspace row).\n * 3. createOrReusePane() in the workspace path (or opts.cwd).\n * 4. setPaneTitle + enableMuPaneBordersForPane.\n * 5. finalizeAgentRow() — patch placeholder pane_id to real (workspace\n * path), or insert a fresh agent row (no-workspace path).\n * 6. Liveness: awaitSpawnLiveness() (fixed sleep, then pane + scan\n * check), or for a tmux pi agent the ctl handshake with a pane\n * check per tick and the scan at the end. herdr: startAgentInPane.\n * 7. ctl handshake for herdr pi agents (outside the rollback).\n *\n * Failure between any of (3)–(6) calls rollbackSpawn() to undo the\n * pane + row + workspace. The caller-visible error is preserved.\n */\nexport async function spawnAgent(db: Db, opts: SpawnAgentOptions): Promise<SpawnedAgent> {\n if (opts.nextFree === true) {\n // A parallel spawn can take the picked name between the pick and the\n // insert (the in-lock re-check throws before any side effect): pick again.\n for (let attempt = 1; ; attempt++) {\n const name = nextFreeAgentName(db, opts.name, opts.workstream);\n try {\n return await spawnAgent(db, { ...opts, name, nextFree: false });\n } catch (err) {\n if (!(err instanceof AgentExistsError) || attempt >= NEXT_FREE_ATTEMPTS) throw err;\n }\n }\n }\n if (!isValidAgentName(opts.name)) {\n throw new TypeError(\n `invalid agent name: ${JSON.stringify(opts.name)} (expected /^[a-z][a-z0-9_-]{0,31}$/)`,\n );\n }\n // Per-workstream uniqueness check: v5 allows the same agent name in\n // different workstreams. Scope the existence check to the spawn's\n // workstream so two operators spawning 'worker-1' in wsA and wsB\n // both succeed (bug_v5_name_clash_silent_misroute). A fast path only:\n // a parallel spawn of the same name can pass it too, so the check is\n // repeated inside the spawn lock, and insertAgent maps the UNIQUE\n // violation to AgentExistsError as the last line.\n if (getAgent(db, opts.name, opts.workstream) !== undefined) {\n throw new AgentExistsError(opts.name);\n }\n\n const session = opts.tmuxSession ?? `mu-${opts.workstream}`;\n const windowName = opts.tab ?? opts.name;\n const cli = opts.cli ?? \"pi\";\n const resolved = resolveCliCommandWithSource(cli);\n const command = opts.command ?? resolved.command;\n // Where `command` came from. Backends that resolve the executable\n // themselves may not silently ignore an operator's choice, and need to\n // know WHICH knob to name (see `StartAgentInPaneOptions.commandSource`).\n const commandSource =\n opts.command !== undefined ? \"explicit\" : resolved.resolvedFromEnv ? \"env\" : \"cli-key\";\n\n // Pre-flight PATH resolution. Catches `--cli does-not-exist` (and\n // typos in `MU_<UPPER>_COMMAND` overrides) before any side effect.\n // See `checkCommandResolvable` / `AgentSpawnCliNotFoundError` for\n // the rationale; in short: prevents orphan workspace dirs + orphan\n // panes + half-spawned DB rows on a typo.\n //\n // We do NOT pre-flight an explicit `--command \"...\"` value: the\n // operator who passed --command gave us the literal string they\n // want spawned (often a wrapper like `pi-meta --no-solo` whose\n // first token IS on PATH but with arg-quoting that the resolver\n // would mis-parse; or a shell snippet like `bash -lc '...'`). For\n // those, the existing post-spawn liveness check is the safety net.\n if (opts.command === undefined) {\n const check = await checkCommandResolvable(command);\n if (!check.ok) {\n throw new AgentSpawnCliNotFoundError(cli, check.binary, envVarNameForCli(cli));\n }\n }\n\n // Workspace pre-stage. See `prestageWorkspace` for the FK-ordering\n // rationale. Returns the workspace path (used as the pane's cwd) or\n // undefined when --workspace wasn't requested.\n let workspacePathStr: string | undefined;\n if (opts.workspace) {\n try {\n workspacePathStr = await prestageWorkspace(db, opts, cli);\n } catch (err) {\n emitSpawnFailed(db, opts, \"workspace\", err);\n throw err;\n }\n }\n\n // Inject identity env vars into the pane so anything running inside\n // (pi extensions, claim-protocol scripts, status segments) can branch\n // on 'I am a mu-managed worker' without scraping pane titles or DB\n // lookups. Set via tmux `-e KEY=VALUE` (per-pane; doesn't pollute the\n // tmux server's global env).\n //\n // These are NOT exposed via SpawnAgentOptions — mu identity is not\n // user-tunable. Adding more keys here means every spawned pane sees\n // them automatically.\n //\n // MU_CTL_SOCK goes to every CLI (harmless for non-pi). Its directory\n // must exist before the pane starts: for a remote agent, ssh's\n // `-L <local>:<remote>` binds the LOCAL path and does not mkdir. A\n // socket file left by a previous agent of this name is removed inside\n // the spawn lock below, once this spawn owns the name, since ssh\n // refuses to bind over it.\n //\n // The base is the DB's directory: in production that is exactly\n // ctlSocketPath's own default (MU_DB_PATH dir or the state dir), and\n // a test DB in a temp dir keeps its sockets there too.\n const ctlSocket = ctlSocketPath(opts.workstream, opts.name, dirname(db.name));\n mkdirSync(dirname(ctlSocket), { recursive: true, mode: 0o700 });\n const paneEnv: Record<string, string> = {\n MU_MANAGED_AGENT: \"1\",\n MU_AGENT_NAME: opts.name,\n MU_WORKSTREAM: opts.workstream,\n [CTL_SOCK_ENV]: ctlSocket,\n };\n // tmux panes inherit the tmux server's env, not ours: pin the DB (and\n // state dir) this spawn used, resolved against our cwd, so the worker's\n // `mu` hits the same taskgraph. Local spawns only.\n if (db.name !== \"\" && db.name !== \":memory:\") paneEnv.MU_DB_PATH = resolve(db.name);\n if (process.env.MU_STATE_DIR) paneEnv.MU_STATE_DIR = resolve(process.env.MU_STATE_DIR);\n // mu sessions are created detached and may never be attached, so tmux's\n // update-environment never refreshes them and a pane would inherit a\n // stale SSH_AUTH_SOCK. Forward the caller's. File-type check only (is it\n // a socket?), not a liveness probe: mu stays ssh-free. Best-effort.\n const sshSock = process.env.SSH_AUTH_SOCK;\n if (sshSock) {\n try {\n if (statSync(sshSock).isSocket()) paneEnv.SSH_AUTH_SOCK = sshSock;\n } catch {\n // missing or unreadable: skip forwarding\n }\n }\n\n const hasWorkspace = workspacePathStr !== undefined;\n\n // Single outer try wrapping every step that can throw AFTER the\n // workspace has been prestaged: pane create/reuse, pane title +\n // borders, agent-row finalize, liveness check. Earlier shape had\n // createOrReusePane outside the try, so a tmux failure (e.g. no\n // workstream session and tmux refusing to create one) left the\n // prestaged workspace dir + placeholder agent row behind as an\n // orphan — task agent_spawn_abort_leaves_orphan_workspace.\n //\n // paneId is undefined until createOrReusePane returns; rollbackSpawn\n // skips killPane in that case. The inner try/catches that previously\n // wrapped finalize and liveness were folded into this single catch\n // (clarity > belt-and-suspenders; rollbackSpawn is idempotent and\n // best-effort regardless).\n let paneId: string | undefined;\n let agent: AgentRow;\n // Whether the agent row is this spawn's to delete on rollback. A\n // spawn that lost a same-name race must not delete the winner's row.\n let ownsRow = hasWorkspace;\n const wantsCtl = opts.ctl !== false && speaksMuCtl(cli, command) && defaultSpawnCtlMs() !== 0;\n let ctl: SpawnCtl | undefined;\n // Last phase entered, recorded in agent.spawn_failed if we roll back.\n let phase: SpawnPhase = \"pane\";\n let trustDialog = false;\n try {\n // Cross-process critical section: the tmux topology check-then-act\n // (`sessionExists` → `new-session` / `new-window` / `split-window`)\n // plus the agent-row finalize. Serialised per tmux SESSION so a\n // parallel fan-out (`for n in …; do mu agent spawn … & done`) can't\n // race six `new-session -d -s mu-scratch` calls into\n // five-rolled-back-losers. Keyed on the session name: spawns into\n // different sessions never contend. See spawn-lock.ts.\n //\n // The liveness wait is deliberately OUTSIDE the lock: it is the slow\n // part (1.5s+), and holding the lock across it would serialise the\n // very parallelism the operator asked for. Once the row is inserted\n // and the lock released, the next spawn can build its own window\n // while this one waits.\n const created = await withSpawnLock(session, async () => {\n // Re-check under the lock: a parallel spawn of the same name may\n // have inserted its row since the fast-path check. (With a\n // workspace, the placeholder row already claimed the name.)\n if (!hasWorkspace && getAgent(db, opts.name, opts.workstream) !== undefined) {\n throw new AgentExistsError(opts.name);\n }\n // The name is ours: no live agent owns a socket at this path.\n rmSync(ctlSocket, { force: true });\n const pid = await createOrReusePane({\n session,\n keepSessionAlive: isScratchWorkstream(opts.workstream),\n windowName,\n command,\n cwd: workspacePathStr ?? opts.cwd,\n env: paneEnv,\n });\n // Capture the pane id on the OUTER scope as soon as it exists so a\n // throw later in the lock (setPaneTitle / finalizeAgentRow INSERT\n // failure) still routes through rollbackSpawn -> killPane. Assigning\n // only via the returned object meant a finalize failure left paneId\n // undefined and rollbackSpawn skipped killPane, leaking the pane\n // (finding_verbs_spawn_rolls_back_pane).\n paneId = pid;\n const mux = await activeMux();\n // Lock first so an early OSC title cannot be frozen in; best-effort\n // (identity prefers $MU_AGENT_NAME, reconcile repairs titles).\n await mux.lockPaneTitle(pid).catch(() => {});\n await mux.setPaneTitle(pid, opts.name);\n // Apply the mu pane border to the new window. Window-scoped option;\n // see enableMuPaneBorders docstring for why this is required per\n // window (and not just per session). Self-checks MU_BANNER_QUIET\n // and is best-effort — the border is decorative.\n await mux.enableMuPaneBordersForPane(pid);\n phase = \"finalize\";\n const row = finalizeAgentRow(db, { opts, cli, paneId: pid, hasWorkspace });\n ownsRow = true;\n return { pid, row };\n });\n paneId = created.pid;\n agent = created.row;\n phase = \"liveness\";\n // Liveness check: wait briefly, then verify the pane is still alive.\n // Catches the silent-spawn-failure class of bugs where the CLI dies\n // immediately (lock conflict, bad credentials, etc.). On failure,\n // surface a typed error with whatever scrollback tmux still has.\n //\n // On a backend with no create-and-run form the pane above is a BARE\n // SHELL and this is where the agent actually starts. Both branches\n // live outside the spawn lock on purpose — they are the slow part\n // (1.5s+ here, up to herdr's 30s there) and holding the lock across\n // either would serialise the very fan-out the operator asked for.\n // Either branch throwing routes through the same `rollbackSpawn`,\n // so a pane that never became an agent never keeps its agent row.\n //\n // A tmux pi agent skips the fixed sleep: the ctl handshake is the\n // readiness signal, so the pane check rides on each handshake tick\n // and the startup-error scan runs once the handshake ends. A\n // handshake timeout with a live, clean pane is still NOT a\n // rollback (see below). MU_SPAWN_LIVENESS_MS=0 disables the checks\n // here too.\n const startAgent = (await activeMux()).startAgentInPane;\n if (startAgent === undefined) {\n if (wantsCtl) {\n const pid = paneId;\n const check = defaultSpawnLivenessMs() !== 0;\n const when = `during the ctl handshake (up to ${defaultSpawnCtlMs()}ms after spawn)`;\n // Capture every tick and keep the last good buffer: on real tmux\n // capture-pane fails once the pane is gone, so a capture taken\n // after the death check would always come back empty.\n let lastScrollback: string | undefined;\n const assertPaneAlive = async (): Promise<void> => {\n const mux = await activeMux();\n const sb = await mux.capturePane(pid, { lines: 50 }).catch(() => undefined);\n lastScrollback = sb ?? lastScrollback;\n if (await mux.paneExists(pid)) return;\n throw new AgentDiedOnSpawnError(opts.name, pid, lastScrollback, command, when);\n };\n ctl = await awaitCtlHandshake(ctlSocket, check ? assertPaneAlive : undefined);\n // Known gap: pi binds the socket in session_start (init), before\n // it renders startup diagnostics, so an ok on the first tick can\n // scan a pane that has not printed its error yet.\n //\n // An ok handshake proves the CLI started, so only provider/auth\n // patterns apply: a shell exec-failure line in the tail is then\n // transcript text (a resumed `--session` re-renders old tool\n // output such as `grep: x: No such file or directory`).\n if (check)\n trustDialog = await checkSpawnHealth(pid, opts.name, command, when, ctl === \"ok\");\n } else {\n trustDialog = await awaitSpawnLiveness(paneId, opts.name, command);\n }\n } else {\n // `startAgentInPane` returns only once the MUX has detected the\n // agent in that pane and considers it ready for input — strictly\n // stronger than what awaitSpawnLiveness's scrollback poll can\n // prove, so MU_SPAWN_LIVENESS_MS is\n // subsumed and deliberately not consulted. Branching on the\n // CAPABILITY, never on `mux.name`.\n await startAgent({ paneId, name: opts.name, cli, command, commandSource });\n }\n } catch (err) {\n // Record first: a throwing cleanup must neither skip the record nor\n // mask the original error.\n emitSpawnFailed(db, opts, phase, err);\n try {\n await rollbackSpawn(db, opts.name, paneId, hasWorkspace, ownsRow, opts.workstream);\n } catch (cleanupErr) {\n if (err instanceof Error && err.cause === undefined) {\n try {\n err.cause = cleanupErr;\n } catch {\n // frozen error: keep original as-is\n }\n }\n }\n if (hasWorkspace) attachOrphanCleanupHint(err, opts.name, opts.workstream);\n throw err;\n }\n // Control-socket handshake when the tmux path above did not run it.\n // Outside the rollback: a timeout means only control is missing; the\n // pane and pi are fine. The caller reports it (see\n // AgentCtlUnreachableError).\n ctl ??= wantsCtl ? await awaitCtlHandshake(ctlSocket) : \"skipped\";\n // `agents` is machine-local (it holds pane_id), so no capture trigger\n // covers it and this emit is the ONLY record. Typed intent so it\n // renders through the same formatter as captured ops.\n emitEvent(\n db,\n opts.workstream,\n \"agent.spawn\",\n `agent spawn ${opts.name} (cli=${cli}, role=${opts.role ?? \"full-access\"}, pane=${paneId}, ctl=${ctl})`,\n await resolveActorIdentity(),\n );\n // Lint-grade stderr nudge when the operator picked a name that\n // doesn't fit the <role>-<n> smallest-unused-suffix convention. The\n // spawn already succeeded; this is advice, not an error. Done LAST\n // so the hint trails the spawn's own stdout output and so a partial\n // failure (rolled back above) never emits it.\n maybeWarnNonConventionalAgentName(opts.name);\n return { ...agent, ctl, ctlSocket, ...(trustDialog ? { trustDialog: true as const } : {}) };\n}\n\n/**\n * Stage 1 of `--workspace` spawn: insert the agent row with a placeholder\n * pane id, then create the VCS workspace (whose row FKs the agent name).\n *\n * Why placeholder-first? `vcs_workspaces.agent` FK + ON DELETE CASCADE\n * means the workspace row needs an agents row to exist before we insert\n * it; but we can't insert agents without a pane_id (NOT NULL), and we\n * can't create the pane until we know the workspace's on-disk path\n * (used as cwd). The placeholder unblocks the cycle.\n *\n * The placeholder is a publicly-visible quirk — see `PENDING_PANE_PREFIX`\n * and the consumers it documents (refreshAgentTitle and reconcile's\n * pending-pane prune skip). The deeper fix (eliminate the placeholder\n * by reordering ws-dir → pane → atomic dual-insert) is filed as a\n * separate refactor; this shape is the established equilibrium.\n *\n * Throws after best-effort rollback (deleteAgent) if workspace creation\n * fails. Returns the workspace's on-disk path.\n */\nasync function prestageWorkspace(db: Db, opts: SpawnAgentOptions, cli: string): Promise<string> {\n insertAgent(db, {\n name: opts.name,\n workstream: opts.workstream,\n cli,\n paneId: pendingPaneIdFor(opts.name),\n role: opts.role,\n tab: opts.tab ?? null,\n });\n try {\n const wsOpts: Parameters<typeof createWorkspace>[1] = {\n agent: opts.name,\n workstream: opts.workstream,\n };\n if (opts.workspaceBackend !== undefined) wsOpts.backend = opts.workspaceBackend;\n if (opts.workspaceFrom !== undefined) wsOpts.parentRef = opts.workspaceFrom;\n if (opts.workspaceProjectRoot !== undefined) wsOpts.projectRoot = opts.workspaceProjectRoot;\n const ws = await createWorkspace(db, wsOpts);\n return ws.path;\n } catch (err) {\n try {\n deleteAgent(db, opts.name, opts.workstream);\n } catch {\n // best-effort: never mask the workspace error\n }\n throw err;\n }\n}\n\n/**\n * Stage 2 of spawn (after the real pane exists): either patch the\n * placeholder row to the real pane id (workspace path), or insert a\n * fresh agent row (no-workspace path). Throws if the patch UPDATE\n * silently affects no row (the placeholder row vanished mid-spawn —\n * historically the bug_agent_spawn_workspace_fk_failure class, now\n * patched by reconcile's pending-pane prune skip).\n */\nfunction finalizeAgentRow(\n db: Db,\n args: { opts: SpawnAgentOptions; cli: string; paneId: string; hasWorkspace: boolean },\n): AgentRow {\n const { opts, cli, paneId, hasWorkspace } = args;\n if (!hasWorkspace) {\n return insertAgent(db, {\n name: opts.name,\n workstream: opts.workstream,\n cli,\n paneId,\n role: opts.role,\n tab: opts.tab ?? null,\n });\n }\n // Scope the patch to the spawn's workstream so a same-named worker\n // in another workstream isn't repointed at this pane\n // (bug_v5_name_clash_silent_misroute).\n db.prepare(\n `UPDATE agents SET pane_id = ?, updated_at = ?\n WHERE name = ?\n AND workstream_id = (SELECT id FROM workstreams WHERE name = ?)`,\n ).run(paneId, new Date().toISOString(), opts.name, opts.workstream);\n const row = getAgent(db, opts.name, opts.workstream);\n if (!row) throw new Error(`spawnAgent: agent vanished after workspace stage: ${opts.name}`);\n return row;\n}\n\n/**\n * Roll back a failed spawn. Idempotent and best-effort: every step\n * swallows its own errors so a partial-cleanup substrate (already-killed\n * pane, no agent row) never masks the original failure.\n *\n * `paneId` is `undefined` when createOrReusePane itself threw before\n * returning a pane id — there's nothing to kill. `hasWorkspace` is\n * `true` when prestageWorkspace succeeded; freeWorkspace is idempotent\n * on a missing workspace so calling it after a same-cycle failure is\n * safe. deleteAgent is also idempotent (no-op on a missing row).\n *\n * `ownsRow` is false when the spawn failed before inserting its own row\n * (e.g. it lost a same-name race); the row then belongs to another\n * agent and is left alone.\n */\ntype SpawnPhase = \"workspace\" | \"pane\" | \"finalize\" | \"liveness\";\n\n/** Terminal record for a failed spawn. Best-effort; never throws. */\nfunction emitSpawnFailed(db: Db, opts: SpawnAgentOptions, phase: SpawnPhase, err: unknown): void {\n try {\n const errName = err instanceof Error ? err.constructor.name : typeof err;\n emitEvent(\n db,\n opts.workstream,\n \"agent.spawn_failed\",\n `agent spawn failed ${opts.name} (phase=${phase}, error=${errName})`,\n );\n } catch {\n // logging is best-effort\n }\n}\n\nasync function rollbackSpawn(\n db: Db,\n name: string,\n paneId: string | undefined,\n hasWorkspace: boolean,\n ownsRow: boolean,\n workstream: string,\n): Promise<void> {\n if (paneId !== undefined) {\n // Best-effort: rollback runs on an already-failing path and must not\n // mask the original error, even if the mux itself went away.\n await activeMux()\n .then((mux) => mux.killPane(paneId))\n .catch(() => {});\n }\n if (hasWorkspace) {\n // Scope cleanup to the spawn's workstream so a same-named worker\n // elsewhere isn't torn down by accident\n // (bug_v5_name_clash_silent_misroute).\n await freeWorkspace(db, name, { workstream }).catch(() => {});\n }\n if (ownsRow) deleteAgent(db, name, workstream);\n}\n\n/**\n * After a failed spawn that prestaged a workspace, augment the thrown\n * error with orphan-cleanup hints (`mu workspace orphans` +\n * `mu workspace free`). rollbackSpawn is best-effort — if the\n * freeWorkspace call inside it failed (rmdir blocked, vcs backend\n * refusing to remove a workspace with uncommitted state, etc.), the\n * dir survives and the operator needs to know how to clean it up.\n *\n * Uses the duck-typed `errorNextSteps()` convention (see\n * `hasNextSteps()` in src/output.ts) so this works whether the inner\n * error is a typed mu error already exposing nextSteps\n * (AgentDiedOnSpawnError) or a bare TmuxError / Error from\n * createOrReusePane that has none. Existing hints (if any) are\n * preserved and listed first; the orphan-cleanup hints are appended\n * so the diagnostic-first ordering of typed errors is kept.\n */\nfunction attachOrphanCleanupHint(err: unknown, agent: string, workstream: string): void {\n if (typeof err !== \"object\" || err === null) return;\n const target = err as { errorNextSteps?: () => NextStep[] };\n const existing =\n typeof target.errorNextSteps === \"function\" ? target.errorNextSteps.bind(target) : null;\n const orphanHints: NextStep[] = [\n {\n intent: \"Check for an orphan workspace dir (rollback is best-effort; may have failed)\",\n command: `mu workspace orphans -w ${workstream}`,\n },\n {\n intent: \"Free the workspace if it survived the rollback (idempotent on missing)\",\n command: `mu workspace free ${agent} -w ${workstream}`,\n },\n ];\n // Best-effort: a frozen or non-extensible error must still reach the\n // caller as itself, just without the extra hints.\n try {\n target.errorNextSteps = () => [...(existing ? existing() : []), ...orphanHints];\n } catch {}\n}\n\n/**\n * Default liveness window in milliseconds. 0 disables the check (useful\n * for fast tests that don't want to wait). Override via env var\n * `MU_SPAWN_LIVENESS_MS`.\n */\nexport function defaultSpawnLivenessMs(): number {\n const raw = process.env.MU_SPAWN_LIVENESS_MS;\n if (raw === undefined) return 1500;\n const parsed = Number.parseInt(raw, 10);\n if (Number.isNaN(parsed) || parsed < 0) return 1500;\n return parsed;\n}\n\n/**\n * Curated list of patterns that indicate the spawned CLI hit a fatal\n * provider/auth error during startup and is now parked at an error\n * prompt instead of becoming a working agent. Source:\n * `agent_spawn_model_auth_failure_counts_as_live` in the feedback ws.\n *\n * Kept short and case-insensitive on purpose: every entry must match a\n * real, observed dogfood failure mode. Don't add patterns speculatively\n * — the false-positive cost is to roll back a healthy spawn, which the\n * operator then has to re-attempt without the scan (`MU_SPAWN_LIVENESS_MS=0`).\n *\n * Mitigation against scrollback noise from harmless prior-session text:\n * `checkSpawnHealth` only scans the LAST `STARTUP_ERROR_TAIL_LINES`\n * lines of the capture, and after an ok ctl handshake it skips\n * `EXEC_FAILURE_PATTERN` (a resumed pi session re-renders old tool\n * output, which often ends in `No such file or directory`).\n */\nconst AUTH_ERROR_PATTERNS: readonly RegExp[] = [\n /No API key found for [\\w-]+/i,\n /Error: invalid API key/i,\n /Authentication failed/i,\n /401 Unauthorized/i,\n /Could not authenticate/i,\n];\n\n/**\n * The spawned command failed to exec (fb_agent_spawn_no_validation\n * part B): post-spawn detection of the\n * \"binary not found at exec time\" failure mode. The pre-flight check\n * above catches the common typo BEFORE any side effect, but a few\n * edge cases still slip through and only surface in the pane:\n * - `--command \"...\"` skips the pre-flight (operator opt-out).\n * - PATH inside the spawned shell differs from PATH in mu's\n * process (login shell rc files, /etc/paths.d, etc.).\n * - Race: binary on PATH at spawn time, gone 1.5s later.\n *\n * Anchored to lines that LOOK like a shell error rather than prose\n * mentioning the marker (review_substrate_startup_err_patterns_too_broad):\n * require the marker at end-of-line, optionally followed by a single\n * `: <name>` token (the zsh form: `zsh: command not found: pi-meta`).\n * This still trips the canonical cases —\n * `bash: pi-meta: command not found`\n * `zsh: command not found: pi-meta`\n * `sh: pi-meta: No such file or directory`\n * — but rejects banner prose like\n * `I noticed earlier you saw 'command not found'`\n * `type \\`mu\\` — command not found? install with …`\n * that previously triggered a full spawn rollback. The pre-flight\n * PATH check remains the deterministic safety net for typo'd `--cli`.\n */\nconst EXEC_FAILURE_PATTERN =\n /^(?:.*: )?(?:command not found|No such file or directory)(?::\\s*\\S+)?$/i;\n\n/** True when `line` reads as a shell exec failure, not a provider/auth error. */\nexport function isExecFailureLine(line: string): boolean {\n return EXEC_FAILURE_PATTERN.test(line);\n}\n\n/**\n * Number of trailing lines of the post-liveness scrollback to scan for\n * the startup-error patterns. The capture is `lines: 50`; tailing the last\n * 30 keeps the scan focused on the spawned CLI's own startup output\n * (the pane is brand-new, so anything earlier than that is the shell\n * banner / our own command-line, both safe).\n */\nconst STARTUP_ERROR_TAIL_LINES = 30;\n\n/**\n * Scan the tail of a freshly-captured pane buffer for known startup-\n * failure patterns. Returns the matched line on first hit, or undefined\n * if the buffer is clean. `cliStarted` (the CLI answered the ctl\n * handshake) drops the exec-failure pattern: the CLI demonstrably ran.\n *\n * Exported for the test suite; not part of the SDK surface.\n */\nexport function detectSpawnStartupError(\n scrollback: string,\n cliStarted = false,\n): string | undefined {\n const patterns = cliStarted\n ? AUTH_ERROR_PATTERNS\n : [...AUTH_ERROR_PATTERNS, EXEC_FAILURE_PATTERN];\n const lines = scrollback.split(/\\r?\\n/);\n const tail = lines.slice(Math.max(0, lines.length - STARTUP_ERROR_TAIL_LINES));\n for (const line of tail) {\n for (const pattern of patterns) {\n if (pattern.test(line)) return line;\n }\n }\n return undefined;\n}\n\nasync function awaitSpawnLiveness(\n paneId: string,\n agentName: string,\n command: string,\n): Promise<boolean> {\n const ms = defaultSpawnLivenessMs();\n if (ms === 0) return false;\n await sleep(ms);\n return checkSpawnHealth(paneId, agentName, command);\n}\n\n/**\n * Claude's \"Is this a project you trust?\" dialog, recorded from claude\n * 2.1.x (test/fixtures/claude-trust-dialog.txt). It is unnumbered and\n * defaults to \"No, exit\", so the Enter that ends a send makes claude\n * quit. Matched on the short option line, which survives line wraps.\n *\n * NOT an error: the pane and agent are kept, so this is a warning that\n * spawn reports and that skips the initial --send. Startup scan only: it\n * does not protect a later `mu agent send`, and the herdr spawn path\n * never runs this scan. No keypress is ever sent for the operator.\n */\nconst CLAUDE_TRUST_DIALOG = /Yes, I trust this folder/i;\n\n/** True when the tail of `scrollback` shows Claude's folder-trust dialog. */\nexport function detectClaudeTrustDialog(scrollback: string): boolean {\n const lines = scrollback.split(/\\r?\\n/);\n const tail = lines.slice(Math.max(0, lines.length - STARTUP_ERROR_TAIL_LINES));\n return tail.some((line) => CLAUDE_TRUST_DIALOG.test(line));\n}\n\n/**\n * One liveness verdict: throw AgentDiedOnSpawnError when the pane is\n * gone, AgentSpawnStartupError when its scrollback tail shows a known\n * startup failure. Returns true (non-fatal) when Claude's trust dialog is\n * showing.\n */\nasync function checkSpawnHealth(\n paneId: string,\n agentName: string,\n command: string,\n /** When the failure happened, for the error text; default: the liveness window. */\n when?: string,\n /** The CLI answered the ctl handshake; see detectSpawnStartupError. */\n cliStarted = false,\n): Promise<boolean> {\n // Capture-pane first so we have something to attach to the error if the\n // pane is in the process of being torn down (the buffer survives a beat\n // longer than the pane's existence in some tmux builds).\n const mux = await activeMux();\n const scrollback = await mux.capturePane(paneId, { lines: 50 }).catch(() => undefined);\n if (!(await mux.paneExists(paneId))) {\n throw new AgentDiedOnSpawnError(agentName, paneId, scrollback, command, when);\n }\n // Pane is alive — but \"alive\" doesn't mean \"working\". Scan the tail of\n // the capture for known provider/auth startup errors\n // (agent_spawn_model_auth_failure_counts_as_live). The pane stays at\n // an error prompt forever otherwise, and the orchestrator only\n // discovers the dud minutes later when `mu task wait` stalls.\n if (scrollback !== undefined) {\n const matchedLine = detectSpawnStartupError(scrollback, cliStarted);\n if (matchedLine !== undefined) {\n throw new AgentSpawnStartupError(agentName, paneId, matchedLine, scrollback, when);\n }\n return detectClaudeTrustDialog(scrollback);\n }\n return false;\n}\n\n/**\n * Three cases, all returning a stable pane id:\n * - session doesn't exist → create session+window+pane in one shot\n * (with `keepSessionAlive`: create the\n * session with its placeholder `_mu`\n * window first, then a window here)\n * - session exists, no such window → create a new window for this agent\n * - session and window both exist → split the window to add a pane\n *\n * BARE-PANE MODE. A backend implementing `startAgentInPane` has no\n * create-and-run form, so passing a command to the creation verbs is a\n * hard error there (deliberately, so it can never be dropped silently).\n * For those backends this creates the pane EMPTY and the caller starts\n * the agent in it as a second step. Keyed on the capability, never on\n * the backend name; on tmux the command still rides along exactly as\n * before and this function is byte-for-byte equivalent to its previous\n * behaviour.\n */\nasync function createOrReusePane(opts: {\n session: string;\n /** Ensure the placeholder `_mu` window (creating or repairing it) so\n * the session outlives its last agent. Set for `scratch`, which is\n * never `workstream init`-ed; other workstreams get `_mu` at init. */\n keepSessionAlive: boolean;\n windowName: string;\n command: string;\n cwd?: string;\n env?: Record<string, string>;\n}): Promise<string> {\n // Load-bearing from top to bottom: this IS the pane creation.\n const mux = await activeMux();\n const command = mux.startAgentInPane === undefined ? opts.command : \"\";\n if (opts.keepSessionAlive) await ensureWorkstreamSession(opts.session);\n else if (!(await mux.sessionExists(opts.session))) {\n return mux.newSessionWithPane(opts.session, {\n windowName: opts.windowName,\n command,\n cwd: opts.cwd,\n env: opts.env,\n });\n }\n\n const windows = await mux.listWindows(opts.session);\n const matching = windows.find((w) => w.name === opts.windowName);\n\n if (matching) {\n return mux.splitWindow({\n // tmux splits a WINDOW: target it as `=<session>:<window_id>`.\n // A bare `<session>:<name>` falls back to tmux's session prefix\n // match, so if `mu-auth` vanishes between listWindows and here,\n // `mu-auth:Backend` splits `mu-auth-refactor`'s Backend window.\n // `=` makes the session exact and the stable window id (from\n // the listing above) must live in that session, so a vanished\n // session or window fails instead of landing elsewhere.\n // herdr splits a PANE and has no window-target form at all. Ask\n // the backend for a concrete pane in that window when it needs\n // one — cheaper than a `target` union type for two backends.\n target:\n mux.startAgentInPane === undefined\n ? `=${opts.session}:${matching.id}`\n : await firstPaneInWindow(mux, opts.session, matching.id),\n command,\n cwd: opts.cwd,\n env: opts.env,\n });\n }\n\n return mux.newWindow({\n session: opts.session,\n name: opts.windowName,\n command,\n cwd: opts.cwd,\n env: opts.env,\n });\n}\n\n/**\n * A concrete pane id inside `windowId`, for backends that split panes\n * rather than windows. Any pane in the window is a correct split target\n * — the new pane lands in the same window either way, which is all mu\n * cares about; geometry is the user's business.\n *\n * Throws rather than guessing when the window is empty: an empty window\n * cannot exist on either backend (a window IS its panes), so seeing one\n * means the window vanished between `listWindows` and here, and the\n * caller must roll back rather than create a pane somewhere else.\n */\nasync function firstPaneInWindow(\n mux: MuxBackend,\n session: string,\n windowId: string,\n): Promise<string> {\n const panes = await mux.listPanesInSession(session);\n const pane = panes.find((p) => p.windowId === windowId);\n if (pane === undefined) {\n throw new Error(\n `spawnAgent: window ${windowId} in session ${session} has no panes to split (it vanished mid-spawn?)`,\n );\n }\n return pane.paneId;\n}\n","// mu — self-documenting output helpers.\n//\n// Every successful verb output should answer \"what changed AND what's\n// the natural next step?\". Every error should answer \"why AND what are\n// the actionable resolutions?\". The same data shape feeds both human\n// (dim text) and JSON (`nextSteps` array) consumers.\n//\n// Why a separate module: this is shared by cli.ts (success-path\n// rendering), the typed errors in src/agents.ts / src/tasks.ts /\n// src/workstream.ts (error nextSteps), and tests. Keeping the type +\n// helpers in one place avoids circular imports.\n\nimport Table from \"cli-table3\";\nimport tableUtils from \"cli-table3/src/utils.js\";\nimport type { Command } from \"commander\";\nimport picocolors from \"picocolors\";\n\n/**\n * Should we emit ANSI color escapes from this process?\n *\n * picocolors ships an `isColorSupported` flag, but it bakes its env\n * inspection (NO_COLOR / FORCE_COLOR / isTTY) ONCE at module-load\n * time. That makes the function untestable without dynamic re-imports\n * — and worse, it loses colors whenever stdout is a pipe, most\n * painfully under `watch --color mu state` and `tmux display-popup -E\n * 'mu state' | cat`, where the surrounding pane is a real terminal but\n * our own stdout is a pipe.\n *\n * We therefore re-implement the decision from scratch at call time,\n * reading every signal directly from `process.env` / `process.stdout`\n * so tests can flip env vars and observe the result without the\n * vi.resetModules + vi.doMock dance (per task\n * review_test_color_enabled_no_color_module_load_caveat).\n *\n * Order of precedence (first match wins):\n * - `NO_COLOR` set (cross-tool opt-out, https://no-color.org/) →\n * OFF, even when TMUX/MU_FORCE_COLOR/FORCE_COLOR are set. We\n * treat any defined value (including \"\") as set, matching the\n * no-color.org convention and picocolors' own behavior.\n * - `MU_FORCE_COLOR` truthy → ON (mu-specific override). Values\n * \"\", \"0\", and \"false\" are explicit opt-outs, matching chalk's\n * FORCE_COLOR convention.\n * - `FORCE_COLOR` truthy → ON (the standard env var picocolors /\n * chalk consult). Values \"\", \"0\", and \"false\" opt out.\n * - `TMUX` set → ON (the load-bearing fix for `watch` inside tmux:\n * the surrounding pane is a real terminal even though our stdout\n * is a pipe).\n * - Fall back to the standard TTY heuristic: stdout is a TTY AND\n * TERM !== \"dumb\". This mirrors what picocolors itself does in\n * `isColorSupported` for the happy-path case.\n *\n * See task hud_colors_stripped_under_watch_and for the original repro.\n */\nfunction envForceTrue(key: string): boolean {\n const v = process.env[key];\n if (v === undefined) return false;\n if (v === \"\" || v === \"0\" || v.toLowerCase() === \"false\") return false;\n return true;\n}\n\nexport function colorEnabled(): boolean {\n if (process.env.NO_COLOR !== undefined) return false;\n if (envForceTrue(\"MU_FORCE_COLOR\")) return true;\n if (envForceTrue(\"FORCE_COLOR\")) return true;\n if (process.env.TMUX !== undefined) return true;\n return Boolean(process.stdout.isTTY) && process.env.TERM !== \"dumb\";\n}\n\n/**\n * The single picocolors instance the rest of the codebase imports.\n * Built once at module load with `colorEnabled()` baked in, so every\n * caller (cli.ts, src/cli/*.ts) renders consistently regardless of\n * isTTY heuristics. Any other module that needs `pc` should import\n * this one rather than reaching for `picocolors` directly.\n */\n// picocolors is still used as the renderer (createColors honors the\n// flag we pass), but the *decision* of whether to render is ours.\nexport const pc = picocolors.createColors(colorEnabled());\n\n/**\n * One actionable next step. The `intent` is human-prose (\"Drop notes\n * as you work\"); the `command` is a literal shell command the user (or\n * an LLM) can copy-paste or `eval` directly.\n *\n * Used both for success-path hints (post-verb) and for typed-error\n * resolutions (in the error message + JSON output).\n */\nexport interface NextStep {\n /** Short human-prose label, e.g. \"Drop notes as you work\". */\n intent: string;\n /** Literal shell command, e.g. `mu task note foo \"...\"`. */\n command: string;\n}\n\n/**\n * Print a block of next-step hints to stdout, dimmed so humans can\n * skim past them but agents reading the captured output still get\n * them. No-op when the array is empty.\n *\n * Format:\n *\n * Next:\n * <intent padded>: <command>\n * <intent padded>: <command>\n *\n * The padding aligns the colons so visual scanning is easy.\n */\nexport function printNextSteps(steps: readonly NextStep[]): void {\n printNextStepsTo(steps, \"stdout\");\n}\n\n/** Same as `printNextSteps` but routes to either stdout or stderr.\n * Errors emit nextSteps to stderr (so success vs failure paths\n * capture cleanly when scripts redirect them separately); success\n * paths emit to stdout. Single source of truth for the formatting\n * (review_code_print_next_steps_duplicated). */\nexport function printNextStepsTo(steps: readonly NextStep[], sink: \"stdout\" | \"stderr\"): void {\n if (steps.length === 0) return;\n const labelWidth = Math.max(...steps.map((s) => s.intent.length));\n const out = sink === \"stderr\" ? console.error : console.log;\n out(pc.dim(\"Next:\"));\n for (const step of steps) {\n const label = step.intent.padEnd(labelWidth);\n out(pc.dim(` ${label} : ${step.command}`));\n }\n}\n\n// Printable ASCII plus the width-1 punctuation mu prints (dashes,\n// quotes, \"…\", \"∞\"), after stripping picocolors' SGR codes. Such a line\n// renders as itself with width = stripped length, skipping per-grapheme\n// segmentation (~95 ms on 1901 rows). Anything else (unbalanced SGR,\n// zero-width/format characters, wide text, tabs, CR, other escapes) goes\n// through cli-table3's own strlen and colorizeLines, so it is\n// byte-identical by construction: cli-table3 bundles an older\n// string-width that measures soft hyphen and U+200B differently, and\n// closes SGR left open at each line end.\nconst NARROW = /^[\\x20-\\x7e\\u2010-\\u2027\\u221e]*$/;\n// biome-ignore lint/suspicious/noControlCharactersInRegex: matching SGR escapes is the point\nconst SGR = /\\u001b\\[(?:\\d*;){0,5}\\d*m/g;\ninterface BoxCell {\n lines: string[];\n widths: number[];\n width: number;\n}\n// Mirrors cli-table3's Cell: lines = colorizeLines(content.split(\"\\n\")),\n// width = widest line. Splitting on \"\\n\" only (not CR) is what it does.\nfunction boxCell(c: string): BoxCell {\n if (NARROW.test(c)) return { lines: [c], widths: [c.length], width: c.length };\n const raw = c.split(\"\\n\");\n const lines = tableUtils.colorizeLines(raw);\n const widths = raw.map((l) => {\n const plain = l.replace(SGR, \"\"); // cli-table3's strlen strip regex\n return NARROW.test(plain) ? plain.length : tableUtils.strlen(l);\n });\n return { lines, widths, width: Math.max(...widths) };\n}\n\n/**\n * Render a bordered table byte-identical to `muTable({ head }).toString()`\n * (default style, auto widths), in linear time.\n *\n * cli-table3's layout pass (`fillInTable` → `conflictExists`) scans\n * every earlier row for every cell, so a 1901-row `mu task list` spent\n * ~1.5 s there. Plain cells take a fast path; the rest use cli-table3's\n * own width and SGR-closing helpers (see boxCell). A row is as tall as\n * its tallest cell; shorter cells get blank lines below, as in cli-table3.\n */\nexport function renderBoxTable(\n head: readonly string[],\n rows: readonly (readonly string[])[],\n): string {\n const all = [head, ...rows];\n const widths = head.map(() => 0);\n const cells = all.map((r) =>\n r.map((c, i) => {\n const cell = boxCell(c);\n if (cell.width > (widths[i] ?? 0)) widths[i] = cell.width;\n return cell;\n }),\n );\n const rule = (l: string, m: string, r: string) =>\n l + widths.map((w) => \"─\".repeat(w + 2)).join(m) + r;\n const sep = rule(\"├\", \"┼\", \"┤\");\n const out: string[] = [rule(\"┌\", \"┬\", \"┐\")];\n for (let y = 0; y < all.length; y++) {\n if (y > 0) out.push(sep);\n const r = cells[y] ?? [];\n let height = 1;\n for (const cell of r) if (cell.lines.length > height) height = cell.lines.length;\n for (let n = 0; n < height; n++) {\n let line = \"│\";\n for (let x = 0; x < widths.length; x++) {\n const cell = r[x];\n const pad = (widths[x] ?? 0) - (cell?.widths[n] ?? 0);\n line += ` ${cell?.lines[n] ?? \"\"}${\" \".repeat(pad)} │`;\n }\n out.push(line);\n }\n }\n out.push(rule(\"└\", \"┴\", \"┘\"));\n return out.join(\"\\n\");\n}\n\n/**\n * Build a cli-table3 Table with the mu-standard safety belt:\n * `wordWrap: false` (cells wider than their column truncate with `…`\n * instead of wrapping to a second visual row), per-column max widths\n * applied only where the caller asks (`null` = auto), and a default\n * borderless style mirroring the state/workspace/workstream tables.\n *\n * Callers should pre-truncate values they care about via the\n * `truncate()` / `truncateFront()` helpers in cli.ts (the proactive\n * path); `wordWrap: false` is the safety belt for the cells they\n * miss. This is load-bearing for renderers with fixed row budgets:\n * a single wrapped cell silently blows out the promised section height.\n *\n * Surfaced live by `mu workspace list` blowing the terminal width on\n * the `path` column (tables_truncate_long_cols_audit). Don't try to\n * cap every column — apply `colWidths` only on the column(s) the\n * operator is least likely to read in full and most likely to be\n * long. Don't add a `--full` / `--no-truncate` flag per verb either;\n * `--json` already emits the full value.\n */\nexport function muTable(opts: {\n head: string[];\n /** Per-column max widths in cells (`null` = auto width). When\n * supplied, the array length must match `head`. cli-table3\n * truncates with `…` because we set `wordWrap: false`. */\n colWidths?: (number | null)[];\n /** Style override; defaults to `{ head: [], border: [] }` (mu's\n * borderless look). Pass `{ head: [] }` to keep cli-table3's\n * default border styling. */\n style?: { head?: string[]; border?: string[] };\n}): InstanceType<typeof Table> {\n return new Table({\n head: opts.head,\n ...(opts.colWidths !== undefined ? { colWidths: opts.colWidths } : {}),\n style: opts.style ?? { head: [], border: [] },\n wordWrap: false,\n });\n}\n\n/**\n * The typed-error wire format for `--json` output. Errors that carry\n * actionable resolutions (most of them) implement `errorNextSteps()`;\n * the handler in cli.ts wraps them in this shape and emits to stderr.\n */\nexport interface ErrorJson {\n /** Class name (e.g. \"ClaimerNotRegisteredError\"). */\n error: string;\n /** Human-readable message (the same one printed to stderr in non-JSON mode). */\n message: string;\n /** Actionable resolutions. May be empty. */\n nextSteps: NextStep[];\n /** Process exit code that will follow. */\n exitCode: number;\n}\n\n/**\n * Marker interface for typed errors that carry actionable resolutions.\n * The handler checks this with a duck-typed `typeof err.errorNextSteps\n * === \"function\"` rather than instanceof so cross-realm errors (e.g.\n * thrown from a different module instance after a hot-reload) still\n * surface their nextSteps.\n */\nexport interface HasNextSteps {\n errorNextSteps(): NextStep[];\n}\n\n/**\n * Detect whether the current invocation requested `--json`. Used by the\n * error handler to decide between human-prose stderr and structured\n * JSON stderr. Reads `process.argv` directly because commander has\n * already consumed it by the time the handler runs, and threading it\n * through every verb wrapper would be invasive.\n *\n * Tolerates `--json=...` form (commander supports both) but mu's verbs\n * only use the bare `--json` flag.\n */\nexport function isJsonMode(): boolean {\n return process.argv.some((a) => a === \"--json\" || a.startsWith(\"--json=\"));\n}\n\n/**\n * Has the current err object produced its own actionable nextSteps?\n * Encapsulates the duck-type check so the handler stays readable.\n */\nexport function hasNextSteps(err: unknown): err is HasNextSteps {\n return (\n typeof err === \"object\" &&\n err !== null &&\n typeof (err as { errorNextSteps?: unknown }).errorNextSteps === \"function\"\n );\n}\n\n// ─── Usage rendering for the validation-error contract ──────────────\n//\n// Every operator-error path (commander-thrown CommanderError, handler-\n// thrown UsageError, typed *Invalid* errors) gets the same surface:\n// (1) the error line, (2) the failing subcommand's --help. The human\n// path prints commander's own helpInformation() (so future commander\n// version bumps automatically pick up any rendering improvements);\n// the --json path renders a structured shape so a script orchestrator\n// can introspect the verb without re-shelling for --help.\n//\n// Why structured-not-string for JSON: the entire point of --json is\n// that consumers never have to free-text-parse mu output. Embedding a\n// multi-kilobyte rendered help blob in the JSON envelope defeats that\n// — every option is already structured on the Command object.\n\n/** Structured rendition of a verb's --help, for JSON error envelopes. */\nexport interface UsageJson {\n /** Full canonical name including parent commands (e.g. \"mu task add\"). */\n command: string;\n /** The single-line synopsis (e.g. \"mu task add [options] [id]\"). */\n synopsis: string;\n /** Verb description (the one-paragraph prose under the synopsis). */\n description: string;\n /** Positional arguments in declared order. */\n args: Array<{ name: string; required: boolean; variadic: boolean; description: string }>;\n /** Options in declared order. `mandatory: true` iff the option was\n * declared via `.requiredOption()` (i.e. the operator MUST pass it).\n * `valueRequired: true` for `<value>`-style options whose value is\n * required when the flag IS passed. The two are independent. */\n options: Array<{\n flags: string;\n description: string;\n mandatory: boolean;\n valueRequired: boolean;\n }>;\n}\n\n/** Walk parent chain so subcommand renderings include the full path\n * (\"mu task add\" not just \"add\"). */\nfunction commandFullName(cmd: Command): string {\n const parts: string[] = [];\n let cur: Command | null = cmd;\n while (cur) {\n parts.unshift(cur.name());\n cur = cur.parent;\n }\n return parts.join(\" \");\n}\n\n/** Extract the structured usage shape for `--json` error envelopes. */\nexport function renderUsageJson(cmd: Command): UsageJson {\n return {\n command: commandFullName(cmd),\n synopsis: `${commandFullName(cmd)} ${cmd.usage()}`,\n description: cmd.description(),\n args: cmd.registeredArguments.map((a) => ({\n name: a.name(),\n required: a.required,\n variadic: a.variadic,\n description: a.description ?? \"\",\n })),\n options: cmd.options.map((o) => ({\n flags: o.flags,\n description: o.description ?? \"\",\n mandatory: o.mandatory ?? false,\n valueRequired: o.required ?? false,\n })),\n };\n}\n\n/** Render the human --help block (commander's own `helpInformation()`)\n * to stderr. Single source of truth for the post-error help dump. */\nexport function printUsageHuman(cmd: Command): void {\n // helpInformation() returns the full \"Usage: ...\\n\\n<desc>\\n\\nOptions:\\n ...\" block.\n // Print to stderr (errors only) so success-path stdout is never polluted.\n process.stderr.write(`\\n${cmd.helpInformation()}`);\n}\n","// Shared workspace staleness threshold + predicate.\n//\n// The TUI Workspaces card originally owned the magic number (red bucket\n// at ≥10 commits behind main). Dispatch-time warnings need the same\n// definition without importing ink/react code, so the threshold lives here.\n\nexport const WORKSPACE_STALE_THRESHOLD = 10;\n\nexport function isWorkspaceStale(behind: number | null | undefined): boolean {\n return behind !== null && behind !== undefined && behind >= WORKSPACE_STALE_THRESHOLD;\n}\n","// mu — shared workspace row shapes, path helpers, and typed errors.\n\nimport { join } from \"node:path\";\nimport { defaultStateDir } from \"../db.js\";\nimport type { HasNextSteps, NextStep } from \"../output.js\";\nimport type { VcsBackendName } from \"../vcs.js\";\n\nexport interface WorkspaceRow {\n agentName: string;\n workstreamName: string;\n backend: VcsBackendName;\n path: string;\n parentRef: string | null;\n createdAt: string;\n /** How many commits the workspace's parent_ref is behind the project's\n * default branch HEAD, as of the last time the workspace's local refs\n * cache was updated. Undefined when not yet computed (the listWorkspaces\n * fast path leaves it unset; call decorateWithStaleness to populate).\n * Null when staleness was queried but cannot be computed (no main found,\n * none-backend, missing parent_ref, command failure). */\n commitsBehindMain?: number | null;\n /** True when the workspace has uncommitted / unstaged / untracked-not-\n * ignored files, as observed by the backend's `listDirtyFiles`.\n * Undefined when not yet computed (the listWorkspaces fast path leaves\n * it unset; call decorateWithDirty to populate). Null when the dirty\n * check could not be performed (backend command failure). For jj /\n * none backends — which have no operator-visible \"dirty\" concept —\n * this is always false (their listDirtyFiles returns []). */\n dirty?: boolean | null;\n}\n\nexport interface RawWorkspaceRow {\n /** Joined from agents.name. */\n agent: string;\n /** Joined from workstreams.name. */\n workstream: string;\n backend: string;\n path: string;\n parent_ref: string | null;\n created_at: string;\n}\n\n// SELECT clause that joins vcs_workspaces back to operator-facing\n// agent + workstream names (v5 stores surrogate ids; the JS row shape\n// is operator-facing TEXT names).\nexport const SELECT_WS_COLS = `\n ag.name AS agent,\n ws.name AS workstream,\n v.backend AS backend,\n v.path AS path,\n v.parent_ref AS parent_ref,\n v.created_at AS created_at\n`;\n\nexport const WS_FROM_JOIN = `FROM vcs_workspaces v\n JOIN agents ag ON ag.id = v.agent_id\n JOIN workstreams ws ON ws.id = v.workstream_id`;\n\nexport function rowFromDb(row: RawWorkspaceRow): WorkspaceRow {\n return {\n agentName: row.agent,\n workstreamName: row.workstream,\n backend: row.backend as VcsBackendName,\n path: row.path,\n parentRef: row.parent_ref,\n createdAt: row.created_at,\n };\n}\n\nexport class WorkspaceExistsError extends Error implements HasNextSteps {\n override readonly name = \"WorkspaceExistsError\";\n constructor(public readonly agent: string) {\n super(`workspace already exists for agent: ${agent}`);\n }\n errorNextSteps(): NextStep[] {\n return [\n { intent: \"Show its on-disk path\", command: `mu workspace path ${this.agent}` },\n {\n intent: \"Free it (optionally --commit pending changes first)\",\n command: `mu workspace free ${this.agent} (--commit to commit pending changes first)`,\n },\n {\n intent: \"Then re-spawn the agent with a fresh workspace\",\n command: `mu agent spawn ${this.agent} --workspace --workspace-backend <jj|sl|git|none> --workspace-from <ref>`,\n },\n ];\n }\n}\n\nexport class WorkspaceNotFoundError extends Error implements HasNextSteps {\n override readonly name = \"WorkspaceNotFoundError\";\n constructor(public readonly agent: string) {\n super(`no workspace for agent: ${agent}`);\n }\n errorNextSteps(): NextStep[] {\n return [\n { intent: \"List workspaces in current workstream\", command: \"mu workspace list\" },\n { intent: \"List workspaces across all workstreams\", command: \"mu workspace list --all\" },\n {\n intent: \"Spawn the agent with a workspace (creation happens at spawn)\",\n command: `mu agent spawn ${this.agent} --workspace`,\n },\n ];\n }\n}\n\n/**\n * Thrown by createWorkspace when the on-disk path it would create is\n * already occupied. Distinct from WorkspaceExistsError (which is about\n * the DB row) so the recovery is clear: the dir is orphaned (no DB\n * row points at it) and needs cleanup.\n *\n * Maps to exit code 4 (conflict).\n */\nexport class WorkspacePathNotEmptyError extends Error implements HasNextSteps {\n override readonly name = \"WorkspacePathNotEmptyError\";\n constructor(\n public readonly agent: string,\n public readonly workstream: string,\n public readonly workspacePath: string,\n ) {\n super(\n `workspace dir already on disk for agent ${agent} (${workspacePath}); refusing to overwrite`,\n );\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"List every orphan workspace dir in this workstream\",\n command: `mu workspace orphans -w ${this.workstream}`,\n },\n {\n // No row points at the dir (createWorkspace throws\n // WorkspaceExistsError first when one does), so `mu workspace\n // free` has nothing to free. Same recipe as `mu workspace orphans`.\n intent: \"Inspect it, then remove it by hand (git: also drops the worktree registration)\",\n command: `(cd <project-root> && git worktree remove --force ${this.workspacePath}) || rm -rf ${this.workspacePath}`,\n },\n ];\n }\n}\n\n/**\n * Thrown by createWorkspace when the resolved projectRoot is the\n * user's $HOME.\n *\n * Maps to exit code 4 (conflict).\n */\nexport class HomeDirAsProjectRootError extends Error implements HasNextSteps {\n override readonly name = \"HomeDirAsProjectRootError\";\n constructor(\n public readonly agent: string,\n public readonly workstream: string,\n public readonly homeDir: string,\n ) {\n super(\n `refusing to create workspace with projectRoot=$HOME (${homeDir}); a recursive copy/clone of your home directory is almost never what you want`,\n );\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Re-run from inside a real project directory\",\n command: `cd <your-project> && mu agent spawn ${this.agent} -w ${this.workstream} --workspace`,\n },\n {\n intent: \"Or pass --workspace-project-root explicitly\",\n command: `mu agent spawn ${this.agent} -w ${this.workstream} --workspace --workspace-project-root <your-project>`,\n },\n ];\n }\n}\n\n/**\n * Compose the canonical on-disk path for an agent's workspace. Used by\n * createWorkspace and reachable from `mu workspace path` so the user\n * can `cd $(mu workspace path foo)` even before the directory exists.\n */\nexport function workspacePath(workstream: string, agent: string): string {\n return join(defaultStateDir(), \"workspaces\", workstream, agent);\n}\n\n/** Root dir for a workstream's workspaces — the parent of all\n * per-agent workspace dirs. Used by listWorkspaceOrphans to scan\n * the filesystem. */\nexport function workspacesRoot(workstream: string): string {\n return join(defaultStateDir(), \"workspaces\", workstream);\n}\n\nexport interface WorkspaceStaleness {\n agentName: string;\n workstreamName: string;\n commitsBehindMain: number | null;\n isStale: boolean;\n}\n","// mu — workspace registry CRUD and free/list/commits helpers.\n\nimport { existsSync, rmSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { resolve } from \"node:path\";\nimport { AgentNotFoundError } from \"../agents/errors.js\";\nimport { type Db, tryResolveWorkstreamId } from \"../db.js\";\nimport { emitEvent } from \"../logs.js\";\nimport {\n backendByName,\n type CommitSummary,\n detectBackend,\n type RebaseResult,\n type VcsBackend,\n type VcsBackendName,\n} from \"../vcs.js\";\nimport {\n HomeDirAsProjectRootError,\n type RawWorkspaceRow,\n rowFromDb,\n SELECT_WS_COLS,\n WorkspaceExistsError,\n WorkspaceNotFoundError,\n WorkspacePathNotEmptyError,\n type WorkspaceRow,\n WS_FROM_JOIN,\n workspacePath,\n} from \"./core.js\";\n\nexport interface CreateWorkspaceOptions {\n agent: string;\n workstream: string;\n /** Project root to branch from. Defaults to the current working\n * directory (the `mu` invocation site, which is normally what the\n * user wants). */\n projectRoot?: string;\n /** Override backend detection. Default: walk `detectBackend`.\n * Accepts either a name (\"jj\" / \"sl\" / \"git\" / \"none\") OR a\n * pre-built `VcsBackend` object — the object form lets tests inject\n * a fresh fake backend without mutating the exported singletons. */\n backend?: VcsBackendName | VcsBackend;\n /** Optional ref to base the workspace on. Backend-specific. */\n parentRef?: string;\n}\n\n/**\n * Create a fresh workspace for an agent. Allocates the on-disk\n * directory, records the row, emits a system event. Idempotent ONLY\n * to the extent that the row check is up-front; if the row exists\n * we throw `WorkspaceExistsError` rather than silently re-using a\n * possibly-stale on-disk state. Callers should `freeWorkspace` first.\n */\nexport async function createWorkspace(db: Db, opts: CreateWorkspaceOptions): Promise<WorkspaceRow> {\n if (getWorkspaceForAgent(db, opts.agent, opts.workstream) !== undefined) {\n throw new WorkspaceExistsError(opts.agent);\n }\n\n const projectRoot = opts.projectRoot ?? process.cwd();\n\n // Footgun guard: refuse projectRoot=$HOME. resolve() normalises a\n // trailing slash, `.`, symlinks-in-name, etc., so `cd && mu agent spawn\n // --workspace ...` and `--workspace-project-root ~/` are all blocked\n // the same way.\n // Direct children of $HOME (e.g. ~/Documents) are NOT blocked —\n // that would be overreach. See snap_dogfood Finding 4.\n if (resolve(projectRoot) === resolve(homedir())) {\n throw new HomeDirAsProjectRootError(opts.agent, opts.workstream, homedir());\n }\n\n const backend =\n opts.backend === undefined\n ? await detectBackend(projectRoot)\n : typeof opts.backend === \"string\"\n ? backendByName(opts.backend)\n : opts.backend;\n const path = workspacePath(opts.workstream, opts.agent);\n\n // Surface the dir-already-exists case as a typed error WITH actionable\n // nextSteps before we delegate to the backend (which throws a bare\n // Error). This is the orphan-from-older-mu case: a workspace dir from\n // before the cccba88 close-refuses fix landed; it has no DB row.\n if (existsSync(path)) {\n throw new WorkspacePathNotEmptyError(opts.agent, opts.workstream, path);\n }\n\n const createOpts: { projectRoot: string; workspacePath: string; parentRef?: string } = {\n projectRoot,\n workspacePath: path,\n };\n if (opts.parentRef !== undefined) createOpts.parentRef = opts.parentRef;\n\n // Wrap the backend's on-disk side effect in a cleanup guard. If the\n // backend throws mid-way (cp -a hits a DRM-protected file, git\n // worktree add fails after creating the dir, an interrupt during a\n // long copy), the partial dir would otherwise be left behind with\n // no DB row — exactly the failure mode from snap_dogfood Finding 4,\n // which then blocked subsequent `--workspace` spawns with\n // WorkspacePathNotEmptyError. Best-effort: if the rm itself fails,\n // surface the original error and let the user clean up via\n // `mu workspace orphans`.\n let created: Awaited<ReturnType<typeof backend.createWorkspace>>;\n try {\n created = await backend.createWorkspace(createOpts);\n } catch (err) {\n try {\n rmSync(path, { recursive: true, force: true });\n } catch {\n // best-effort; original error wins\n }\n throw err;\n }\n\n // Roll back the on-disk + VCS-registry side effect if the DB row\n // insert fails (FK violation, schema constraint, sqlite_busy timeout).\n const now = new Date().toISOString();\n try {\n const wsId = tryResolveWorkstreamId(db, opts.workstream);\n if (wsId === null) {\n throw new Error(\n `createWorkspace: workstream not found: ${opts.workstream} (insertAgent should have ensured this)`,\n );\n }\n const agentRow = db\n .prepare(\"SELECT id FROM agents WHERE name = ? AND workstream_id = ? LIMIT 1\")\n .get(opts.agent, wsId) as { id: number } | undefined;\n if (!agentRow) {\n throw new AgentNotFoundError(opts.agent, opts.workstream);\n }\n db.prepare(\n `INSERT INTO vcs_workspaces (agent_id, workstream_id, backend, path, parent_ref, created_at)\n VALUES (?, ?, ?, ?, ?, ?)`,\n ).run(agentRow.id, wsId, backend.name, path, created.parentRef, now);\n } catch (err) {\n await backend.freeWorkspace({ workspacePath: path, commit: false }).catch(() => {});\n throw err;\n }\n\n // `vcs_workspaces` is machine-local (absolute paths), so no trigger\n // covers it and this emit is the only record.\n emitEvent(\n db,\n opts.workstream,\n \"workspace.create\",\n `workspace create ${opts.agent} (backend=${backend.name}, path=${path}${created.parentRef ? `, parent=${created.parentRef.slice(0, 12)}` : \"\"})`,\n );\n\n return {\n agentName: opts.agent,\n workstreamName: opts.workstream,\n backend: backend.name,\n path,\n parentRef: created.parentRef,\n createdAt: now,\n };\n}\n\nexport function getWorkspaceForAgent(\n db: Db,\n agent: string,\n workstream: string,\n): WorkspaceRow | undefined {\n // v5: agents.name is per-workstream unique — the lookup must scope\n // by (workstream, agent) so a same-named worker elsewhere can't be\n // resolved instead.\n const wsId = tryResolveWorkstreamId(db, workstream);\n if (wsId === null) return undefined;\n const row = db\n .prepare(`SELECT ${SELECT_WS_COLS} ${WS_FROM_JOIN} WHERE ag.name = ? AND v.workstream_id = ?`)\n .get(agent, wsId) as RawWorkspaceRow | undefined;\n return row ? rowFromDb(row) : undefined;\n}\n\nexport function listWorkspaces(db: Db, workstream?: string): WorkspaceRow[] {\n if (workstream === undefined) {\n const rows = db\n .prepare(`SELECT ${SELECT_WS_COLS} ${WS_FROM_JOIN} ORDER BY ws.name, ag.name`)\n .all() as RawWorkspaceRow[];\n return rows.map(rowFromDb);\n }\n const wsId = tryResolveWorkstreamId(db, workstream);\n if (wsId === null) return [];\n const rows = db\n .prepare(`SELECT ${SELECT_WS_COLS} ${WS_FROM_JOIN} WHERE v.workstream_id = ? ORDER BY ag.name`)\n .all(wsId) as RawWorkspaceRow[];\n return rows.map(rowFromDb);\n}\n\nexport interface FreeWorkspaceOptions {\n /** If true, attempt to commit pending changes before tearing down.\n * Backend-specific; see VcsBackend.freeWorkspace. */\n commit?: boolean;\n}\n\nexport interface FreeWorkspaceResult {\n /** The committed ref, when `commit` was true and there was something\n * to commit. */\n committedRef?: string;\n /** Branch mu created to keep the workspace's commits reachable after\n * removal (git `--commit` on a detached HEAD). */\n branch?: string;\n /** True iff the on-disk path was actually removed. */\n removed: boolean;\n /** True iff the DB row was actually deleted. */\n rowDeleted: boolean;\n}\n\n/**\n * Tear down an agent's workspace. Calls the backend to remove the\n * on-disk directory (with optional auto-commit), then DELETEs the row.\n * Idempotent on a missing workspace (returns all-false).\n */\nexport async function freeWorkspace(\n db: Db,\n agent: string,\n opts: FreeWorkspaceOptions & { workstream: string },\n): Promise<FreeWorkspaceResult> {\n const row = getWorkspaceForAgent(db, agent, opts.workstream);\n if (!row) return { removed: false, rowDeleted: false };\n\n // No pre-mutation snapshot: v9 dropped the `snapshots` table and\n // rollback is inverse ops over the ops log (`mu undo`).\n\n const backend = backendByName(row.backend);\n const result = await backend.freeWorkspace({\n workspacePath: row.path,\n commit: opts.commit ?? false,\n });\n\n // Resolve to surrogate ids scoped by the row's workstream.\n const wsIdForDel = tryResolveWorkstreamId(db, row.workstreamName);\n const del =\n wsIdForDel === null\n ? { changes: 0 }\n : db\n .prepare(\n `DELETE FROM vcs_workspaces\n WHERE agent_id = (SELECT id FROM agents WHERE name = ? AND workstream_id = ?)\n AND workstream_id = ?`,\n )\n .run(agent, wsIdForDel, wsIdForDel);\n // Machine-local table: no trigger, only record.\n emitEvent(\n db,\n row.workstreamName,\n \"workspace.free\",\n `workspace free ${agent} (backend=${row.backend}, path=${row.path}${result.committedRef ? `, committed=${result.committedRef.slice(0, 12)}` : \"\"}${result.branch ? `, branch=${result.branch}` : \"\"})`,\n );\n\n return {\n removed: result.removed,\n rowDeleted: del.changes > 0,\n ...(result.committedRef !== undefined ? { committedRef: result.committedRef } : {}),\n ...(result.branch !== undefined ? { branch: result.branch } : {}),\n };\n}\n\nexport interface RefreshWorkspaceOptions {\n agent: string;\n workstream: string;\n /** Optional override of the rebase target. When undefined, the\n * backend resolves its own default (origin/HEAD for git,\n * `trunk()` for jj/sl). */\n fromRef?: string;\n}\n\nexport interface RefreshWorkspaceResult extends RebaseResult {\n /** Backend name (mirrors the row) so a JSON consumer doesn't have\n * to look up the workspace separately to know what kind of rebase\n * it just got. */\n vcs: VcsBackendName;\n /** The workspace's on-disk path (so the JSON shape is self-contained\n * for piping to a downstream `jq` script). */\n workspacePath: string;\n}\n\n/**\n * Refresh an agent's workspace by rebasing it onto `fromRef` (or the\n * backend's default base). The agent / pane are NOT touched — only\n * the on-disk working copy moves. Writes the backend's new fork point\n * to the row's `parent_ref` so staleness, `mu workspace commits` and\n * the close-time clean check measure from the new base. Only a\n * conflict-free rebase writes it: on WorkspaceConflictError the row\n * keeps the old base, and a refresh after the conflicts are resolved\n * records the new one.\n */\nexport async function refreshWorkspace(\n db: Db,\n opts: RefreshWorkspaceOptions,\n): Promise<RefreshWorkspaceResult> {\n const row = getWorkspaceForAgent(db, opts.agent, opts.workstream);\n if (!row) throw new WorkspaceNotFoundError(opts.agent);\n const backend = backendByName(row.backend);\n const result = await backend.rebaseTo(row.path, opts.fromRef, row.parentRef || undefined);\n if (result.parentRef !== undefined) setWorkspaceParentRef(db, row, result.parentRef);\n // vcs_workspaces is machine-local, so this event is the only record.\n emitEvent(\n db,\n row.workstreamName,\n \"workspace.refresh\",\n `workspace refresh ${opts.agent} (backend=${row.backend}, fromRef=${result.fromRef}, replayed=${result.replayed.length})`,\n );\n return { ...result, vcs: row.backend, workspacePath: row.path };\n}\n\nfunction setWorkspaceParentRef(db: Db, row: WorkspaceRow, parentRef: string): void {\n const wsId = tryResolveWorkstreamId(db, row.workstreamName);\n if (wsId === null) return;\n db.prepare(\n `UPDATE vcs_workspaces SET parent_ref = ?\n WHERE agent_id = (SELECT id FROM agents WHERE name = ? AND workstream_id = ?)\n AND workstream_id = ?`,\n ).run(parentRef, row.agentName, wsId, wsId);\n}\n\nexport interface ListCommitsOptions {\n workstream: string;\n /** Optional override of the base ref (default: the workspace row's\n * parent_ref). Useful when the operator wants to ask \"what's on\n * top of an arbitrary ref\" without re-creating the workspace. */\n since?: string;\n}\n\nexport interface ListCommitsResult {\n /** Backend name (mirrors the row). */\n vcs: VcsBackendName;\n /** The base ref actually used. */\n baseRef: string;\n /** The commits, oldest-first. Empty when the workspace is exactly\n * at baseRef. */\n commits: CommitSummary[];\n /** The workspace's on-disk path (so JSON consumers don't have to\n * call `mu workspace path` separately). */\n workspacePath: string;\n}\n\n/**\n * List commits the workspace has on top of its `parent_ref` (or the\n * `--since` override), oldest-first. Promotes the dogfood-painful\n * cd $(mu workspace path X) && git log <base>..HEAD\n * incantation into a typed verb that knows the workspace's\n * recorded fork point.\n */\nexport async function listCommitsForWorkspace(\n db: Db,\n agent: string,\n opts: ListCommitsOptions,\n): Promise<ListCommitsResult> {\n const row = getWorkspaceForAgent(db, agent, opts.workstream);\n if (!row) throw new WorkspaceNotFoundError(agent);\n const backend = backendByName(row.backend);\n const baseRef = opts.since ?? row.parentRef;\n if (baseRef === null || baseRef.length === 0) {\n if (row.backend === \"none\") {\n await backend.commitsSinceBase(row.path, \"\");\n }\n throw new Error(`workspace ${agent} has no recorded parent_ref; pass --since <ref> explicitly`);\n }\n const commits = await backend.commitsSinceBase(row.path, baseRef);\n return { vcs: row.backend, baseRef, commits, workspacePath: row.path };\n}\n\n/**\n * \"Is this workspace safe to silently free on agent close?\" — i.e.\n * does it have ZERO uncommitted changes AND ZERO commits since its\n * fork point. Used by closeAgent to auto-free clean workspaces.\n */\nexport async function isWorkspaceClean(row: WorkspaceRow): Promise<boolean> {\n // A `cp -a` copy has no history to prove it is unchanged: never clean.\n if (row.backend === \"none\") return false;\n const backend = backendByName(row.backend);\n let clean: boolean;\n try {\n clean = await backend.isClean(row.path);\n } catch {\n return false;\n }\n if (!clean) return false;\n if (row.parentRef === null || row.parentRef.length === 0) return false;\n try {\n const commits = await backend.commitsSinceBase(row.path, row.parentRef);\n return commits.length === 0;\n } catch {\n return false;\n }\n}\n","// mu — git VCS backend.\n\nimport { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport {\n commitSummary,\n ensureParent,\n exec,\n probeVcsRoot,\n rmDirSync,\n run,\n runShow,\n saneLimit,\n} from \"./helpers.js\";\nimport {\n type CommitSummary,\n type FreeWorkspaceResult,\n type VcsBackend,\n WorkspaceConflictError,\n WorkspaceDirtyError,\n} from \"./types.js\";\n\n// Uses `git worktree` so the new workspace shares the .git store with\n// the project root. Cheap (no copy), fast, and integrates with the rest\n// of the agent's git workflow (push, log, etc) trivially.\n\nexport const gitBackend: VcsBackend = {\n name: \"git\",\n\n async detect(projectRoot, report) {\n return probeVcsRoot(\"git\", [\"rev-parse\", \"--show-toplevel\"], projectRoot, report);\n },\n\n async createWorkspace(opts) {\n if (existsSync(opts.workspacePath)) {\n throw new Error(`vcs git: workspacePath already exists: ${opts.workspacePath}`);\n }\n await ensureParent(opts.workspacePath);\n // Defensive prune: if a previous workspace at the same path was\n // freed by `rm -rf` (or otherwise lost its dir without proper\n // teardown), git's worktree registry still points at it. Then\n // `git worktree add` fails with 'missing but already registered\n // worktree'. `git worktree prune` is idempotent and cheap; running\n // it BEFORE every add costs ~10ms and immunises us against the\n // mufeedback workspace_free_cleanup_leaves_git case.\n await run(\"git\", [\"worktree\", \"prune\"], opts.projectRoot).catch(() => {\n /* prune is best-effort; if it fails we'll get a clear error from `add` next */\n });\n // `git worktree add <path> [<ref>]`. Without a ref, the new worktree\n // checks out a detached HEAD at the project's current HEAD, which\n // matches the \"fresh per-agent workspace\" semantics we want. Use a\n // detached HEAD by default so two agents from the same parent ref\n // don't collide on a branch name.\n const args = [\"worktree\", \"add\", \"--detach\", opts.workspacePath];\n if (opts.parentRef) args.push(opts.parentRef);\n await run(\"git\", args, opts.projectRoot);\n // Resolve the actual SHA we ended up on for the parentRef record.\n const sha = await run(\"git\", [\"rev-parse\", \"HEAD\"], opts.workspacePath);\n return { parentRef: sha };\n },\n\n // Working-copy clean check: empty `git status --porcelain` output\n // means no working-tree, staged, or untracked-not-ignored changes.\n // Returns false on any failure (workspace path missing, git\n // explodes) — be conservative; auto-free should never \"silently\n // succeed\" because we couldn't check.\n async isClean(workspacePath) {\n if (!existsSync(workspacePath)) return false;\n try {\n const files = await listGitDirtyFiles(workspacePath);\n return files.length === 0;\n } catch {\n return false;\n }\n },\n\n // Compute commits-behind as: count of commits reachable from main\n // but not from `ref`. Resolves \"main\" via origin/HEAD (the symbolic\n // ref the remote advertises), falling back to origin/main and then\n // origin/master. Returns null when none of those resolve, or when\n // the rev-list call fails (e.g. ref unknown locally).\n //\n // Pure observation: NO `git fetch`. The number is as fresh as the\n // last time the user (or some other process) updated the local\n // remote-tracking refs.\n async commitsBehind(workspacePath, ref, mainRefCache) {\n if (!existsSync(workspacePath)) return null;\n let main: string | undefined;\n if (mainRefCache === undefined) {\n main = await resolveGitMainRef(workspacePath);\n } else {\n // Worktrees of one repo share refs: key on the common git dir.\n const key = gitCommonDir(workspacePath);\n let p = mainRefCache.get(key);\n if (p === undefined) {\n p = resolveGitMainRef(workspacePath);\n mainRefCache.set(key, p);\n }\n main = await p;\n }\n if (main === undefined) return null;\n try {\n const out = await run(\"git\", [\"rev-list\", \"--count\", `${ref}..${main}`], workspacePath);\n const n = Number.parseInt(out.trim(), 10);\n return Number.isFinite(n) ? n : null;\n } catch {\n return null;\n }\n },\n\n // Rebase the worktree onto `fromRef` (default = origin/HEAD via\n // resolveGitMainRef). Refuses on a dirty WC; returns the replayed\n // commit subjects oldest-first and the new fork point (parentRef);\n // on conflict aborts the rebase and throws WorkspaceConflictError so\n // the operator never inherits a half-rebased worktree from us.\n //\n // We DO `git fetch` first — otherwise the rebase target would only\n // be as fresh as the local refs cache, and the operator running\n // `mu workspace refresh` is explicitly asking for the latest. This\n // is the one-and-only place mu fetches; commitsBehind() stays pure.\n async rebaseTo(workspacePath, fromRef, previousParentRef) {\n if (!existsSync(workspacePath)) {\n throw new Error(`vcs git: workspace path missing: ${workspacePath}`);\n }\n // Dirty-check first: refuse before any side effect.\n const dirtyFiles = await listGitDirtyFiles(workspacePath);\n if (dirtyFiles.length > 0) {\n throw new WorkspaceDirtyError(workspacePath, dirtyFiles);\n }\n // Best-effort fetch so the resolved main ref is fresh. Failure is\n // ignored (offline / no remote) — we still attempt the rebase\n // against whatever the local refs cache holds.\n await run(\"git\", [\"fetch\", \"--quiet\"], workspacePath).catch(() => {});\n let resolvedRef: string;\n if (fromRef !== undefined) {\n resolvedRef = fromRef;\n } else {\n const main = await resolveGitMainRef(workspacePath);\n if (main === undefined) {\n throw new Error(\n `vcs git: cannot resolve default branch (no origin/HEAD, origin/main, or origin/master) in ${workspacePath}; pass --from <ref>`,\n );\n }\n resolvedRef = main;\n }\n // HEAD before the rebase: when the rebase leaves it unchanged,\n // nothing was replayed, whatever sits above the fork point.\n const headBefore = await run(\"git\", [\"rev-parse\", \"HEAD\"], workspacePath);\n try {\n await run(\n \"git\",\n [\"-c\", \"user.email=mu@local\", \"-c\", \"user.name=mu\", \"rebase\", resolvedRef],\n workspacePath,\n );\n } catch (err) {\n // Capture the conflicting paths BEFORE aborting (the abort\n // resets the index and the unmerged paths disappear).\n const conflicts = await listGitUnmergedPaths(workspacePath);\n await run(\"git\", [\"rebase\", \"--abort\"], workspacePath).catch(() => {});\n if (conflicts.length > 0) {\n throw new WorkspaceConflictError(workspacePath, resolvedRef, conflicts);\n }\n // Non-conflict rebase failure (e.g. unknown ref). Surface it raw.\n throw err;\n }\n // After a successful `git rebase <ref>`, HEAD descends from <ref>,\n // so <ref>'s commit is the new fork point, unless the old fork\n // point already descends from <ref> (a no-op refresh onto an older\n // base): moving parent_ref back would relabel the commits between\n // them as the worker's. HEAD's history above it is the replayed set,\n // or nothing when the rebase left HEAD where it was (a no-op).\n const target = await run(\n \"git\",\n [\"rev-parse\", \"--verify\", `${resolvedRef}^{commit}`],\n workspacePath,\n );\n const keepPrevious =\n previousParentRef !== undefined &&\n (await gitIsAncestor(workspacePath, target, previousParentRef)) &&\n (await gitIsAncestor(workspacePath, previousParentRef, \"HEAD\"));\n const parentRef = keepPrevious ? previousParentRef : target;\n const headAfter = await run(\"git\", [\"rev-parse\", \"HEAD\"], workspacePath);\n const logOut =\n headAfter === headBefore\n ? \"\"\n : await run(\n \"git\",\n [\"log\", \"--reverse\", \"--format=%s\", `${parentRef}..HEAD`],\n workspacePath,\n );\n const replayed = logOut.length === 0 ? [] : logOut.split(\"\\n\");\n return { fromRef: resolvedRef, parentRef, replayed, conflicts: [] };\n },\n\n // List commits in (baseRef..HEAD), oldest-first. The format string\n // packs four NUL-delimited fields per record, then a record\n // separator '\\x1e' (RECORD-SEPARATOR control char) so subjects /\n // bodies with embedded newlines or NULs survive parsing. We don't\n // use a JSON template because git's `--format` is field-oriented;\n // %x00 (NUL) and %x1e (RS) are git's portable escape sequences.\n async commitsSinceBase(workspacePath, baseRef) {\n if (!existsSync(workspacePath)) {\n throw new Error(`vcs git: workspace path missing: ${workspacePath}`);\n }\n const out = await run(\n \"git\",\n [\"log\", \"--reverse\", \"-z\", \"--format=%H%x00%s%x00%b%x00%aI\", `${baseRef}..HEAD`],\n workspacePath,\n );\n if (out.length === 0) return [];\n // -z makes git use NUL as the record separator; combined with our\n // %x00 field separators each commit looks like:\n // <sha>\\0<subject>\\0<body>\\0<authorDate>\\0\n // i.e. four fields followed by the record-terminating NUL git\n // injects with -z. Splitting on NUL leaves us with 4N fields plus\n // a trailing empty string we drop.\n const fields = out.split(\"\\x00\");\n const records: CommitSummary[] = [];\n for (let i = 0; i + 3 < fields.length; i += 4) {\n const sha = fields[i] ?? \"\";\n const subject = fields[i + 1] ?? \"\";\n const body = fields[i + 2] ?? \"\";\n const authorDate = fields[i + 3] ?? \"\";\n if (sha.length === 0) continue;\n records.push(commitSummary(sha, subject, body, authorDate));\n }\n return records;\n },\n\n async recentCommits(projectRoot, limit) {\n if (!existsSync(projectRoot)) {\n throw new Error(`vcs git: project root missing: ${projectRoot}`);\n }\n const n = saneLimit(limit);\n if (n === 0) return [];\n const out = await run(\n \"git\",\n [\"log\", `--max-count=${n}`, \"-z\", \"--format=%H%x00%s%x00%b%x00%aI%x00%an\"],\n projectRoot,\n );\n return parseGitZRecords(out);\n },\n\n async showCommit(projectRoot, sha) {\n return runShow(\"git\", [\"show\", sha, \"--stat\", \"-p\", \"--color=always\"], projectRoot);\n },\n\n async freeWorkspace(opts) {\n // Disk-missing case: a previous caller (or the user) ran `rm -rf`\n // out from under us, but the git worktree registry STILL has an\n // entry pointing here. Without a prune, the next `git worktree\n // add` at this path errors out (the mufeedback case). We can't\n // reach the project root via the workspace itself (the .git\n // pointer file is gone with the dir), and we can't reliably guess\n // WHICH project root, so we return { removed: false } without\n // pruning; createWorkspace's defensive prune (above) reaps the\n // dead registry entry on next use.\n if (!existsSync(opts.workspacePath)) {\n return { removed: false };\n }\n let committedRef: string | undefined;\n let branch: string | undefined;\n if (opts.commit) {\n // Commit only if there's anything to commit. Reuse the same\n // dirty-file semantics as isClean() and rebaseTo(): `git status\n // --porcelain` includes working-tree, staged, and untracked-not-\n // ignored changes.\n const dirty = (await listGitDirtyFiles(opts.workspacePath)).length > 0;\n if (dirty) {\n await run(\"git\", [\"add\", \"-A\"], opts.workspacePath);\n await run(\n \"git\",\n [\n \"-c\",\n \"user.email=mu@local\",\n \"-c\",\n \"user.name=mu\",\n \"commit\",\n \"-m\",\n \"mu workspace free auto-commit\",\n ],\n opts.workspacePath,\n );\n committedRef = await run(\"git\", [\"rev-parse\", \"HEAD\"], opts.workspacePath);\n }\n // The worktree's HEAD is detached (createWorkspace uses --detach),\n // so removing the worktree would leave the auto-commit, and any\n // commit the agent made, reachable from no ref: git gc deletes\n // them. Pin HEAD with a branch unless a branch, remote or tag\n // already contains it.\n branch = await keepGitHeadReachable(opts.workspacePath);\n }\n // Tear down: git worktree remove --force <path> cleans both the\n // on-disk directory AND the git/worktrees/<name>/ admin entry. We\n // can't easily run it from the project root (we don't store it on\n // the workspace row), but git accepts the worktree's own path from\n // anywhere with --force, so we resolve a usable cwd via git's own\n // pointer back to the project's .git dir.\n const projectRoot = await resolveGitProjectRoot(opts.workspacePath);\n if (projectRoot) {\n await run(\"git\", [\"worktree\", \"remove\", \"--force\", opts.workspacePath], projectRoot);\n } else {\n // Lost the link — just rm the directory. git's admin entry will\n // be cleaned by the next `git worktree prune` invocation.\n rmDirSync(opts.workspacePath);\n }\n const result: FreeWorkspaceResult = { removed: true };\n if (committedRef !== undefined) result.committedRef = committedRef;\n if (branch !== undefined) result.branch = branch;\n return result;\n },\n\n async listDirtyFiles(workspacePath) {\n if (!existsSync(workspacePath)) return [];\n return listGitDirtyFiles(workspacePath);\n },\n};\n\n/**\n * Resolve the workspace's notion of \"main\". Tries, in order:\n * 1. `origin/HEAD` — the symbolic ref the remote published\n * (e.g. \"refs/remotes/origin/main\"). The most accurate signal.\n * 2. `refs/remotes/origin/main` — the convention.\n * 3. `refs/remotes/origin/master` — pre-rename convention.\n * Returns the resolved ref string (suitable for `git rev-list`) or\n * undefined if none of the three resolve.\n */\n/** `git merge-base --is-ancestor`: exit 0 = yes; exit 1 or any failure = no. */\nasync function gitIsAncestor(cwd: string, ancestor: string, descendant: string): Promise<boolean> {\n try {\n await run(\"git\", [\"merge-base\", \"--is-ancestor\", ancestor, descendant], cwd);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * The repo's common git dir, read from the filesystem (no subprocess):\n * `<ws>/.git` when it is a directory, else the `gitdir:` its `.git` file\n * names, followed through that dir's `commondir` pointer (a worktree).\n * Falls back to the workspace path, which only costs a cache miss.\n */\nexport function gitCommonDir(workspacePath: string): string {\n const dotGit = join(workspacePath, \".git\");\n try {\n if (statSync(dotGit).isDirectory()) return resolve(dotGit);\n const m = /^gitdir:\\s*(.+?)\\s*$/m.exec(readFileSync(dotGit, \"utf8\"));\n if (m?.[1] === undefined) return resolve(workspacePath);\n const gitDir = resolve(workspacePath, m[1]);\n try {\n return resolve(gitDir, readFileSync(join(gitDir, \"commondir\"), \"utf8\").trim());\n } catch {\n return gitDir;\n }\n } catch {\n return resolve(workspacePath);\n }\n}\n\nasync function resolveGitMainRef(workspacePath: string): Promise<string | undefined> {\n for (const candidate of [\n \"refs/remotes/origin/HEAD\",\n \"refs/remotes/origin/main\",\n \"refs/remotes/origin/master\",\n ]) {\n try {\n await exec(\"git\", [\"rev-parse\", \"--verify\", \"--quiet\", candidate], { cwd: workspacePath });\n return candidate;\n } catch {\n /* try next */\n }\n }\n return undefined;\n}\n\n/**\n * Return the list of dirty paths (working-tree modifications + staged\n * + untracked-not-ignored), one entry per file. Empty when clean.\n * Used by `rebaseTo` to refuse with WorkspaceDirtyError carrying the\n * file list — one error message tells the operator both that the\n * workspace is dirty and which files to deal with.\n */\nasync function listGitDirtyFiles(workspacePath: string): Promise<string[]> {\n // `git status --porcelain` prints one line per changed file with\n // a 2-char status prefix; trim the prefix to get the path. Untracked\n // files appear as `?? path` and are included by default.\n const { stdout } = await exec(\"git\", [\"status\", \"--porcelain\"], { cwd: workspacePath });\n const lines = stdout.split(\"\\n\").filter((l) => l.length > 0);\n return lines.map((l) => l.slice(3));\n}\n\n/**\n * Return the unmerged paths after a failed `git rebase`. Used to\n * enrich WorkspaceConflictError before we abort. Empty list means the\n * rebase failed for a non-conflict reason (unknown ref, etc).\n */\nasync function listGitUnmergedPaths(workspacePath: string): Promise<string[]> {\n try {\n const out = await run(\"git\", [\"diff\", \"--name-only\", \"--diff-filter=U\"], workspacePath);\n return out.length === 0 ? [] : out.split(\"\\n\").filter((l) => l.length > 0);\n } catch {\n return [];\n }\n}\n\n/**\n * Create a branch at the worktree's HEAD when no branch, remote-tracking\n * ref or tag contains it, so the commits survive `git worktree remove`.\n * The name is `mu/<workstream>/<agent>-<sha12>`, taken from the\n * workspace path (`<state>/workspaces/<workstream>/<agent>`); the sha\n * suffix keeps a re-spawned agent's later free from colliding. Returns\n * the branch name, or undefined when HEAD was already reachable.\n */\nasync function keepGitHeadReachable(workspacePath: string): Promise<string | undefined> {\n const containing = await run(\n \"git\",\n [\"for-each-ref\", \"--count=1\", \"--contains\", \"HEAD\", \"refs/heads\", \"refs/remotes\", \"refs/tags\"],\n workspacePath,\n );\n if (containing.length > 0) return undefined;\n const sha = await run(\"git\", [\"rev-parse\", \"HEAD\"], workspacePath);\n const parts = workspacePath.replace(/\\/+$/, \"\").split(\"/\");\n const agent = parts.at(-1) ?? \"workspace\";\n const workstream = parts.at(-2) ?? \"mu\";\n const branch = `mu/${workstream}/${agent}-${sha.slice(0, 12)}`;\n await run(\"git\", [\"branch\", branch, sha], workspacePath);\n return branch;\n}\n\n/**\n * Resolve the project root that owns this worktree. Returns undefined\n * if the link is broken (e.g. project root deleted). git rev-parse\n * --git-common-dir gives us the parent project's .git dir; the worktree's\n * project root is its parent.\n */\nasync function resolveGitProjectRoot(workspacePath: string): Promise<string | undefined> {\n try {\n const { stdout } = await exec(\n \"git\",\n [\"rev-parse\", \"--path-format=absolute\", \"--git-common-dir\"],\n { cwd: workspacePath },\n );\n return resolve(stdout.trim(), \"..\");\n } catch {\n return undefined;\n }\n}\n\nfunction parseGitZRecords(raw: string): CommitSummary[] {\n if (raw.length === 0) return [];\n const fields = raw.split(\"\\x00\");\n const records: CommitSummary[] = [];\n for (let i = 0; i + 4 < fields.length; i += 5) {\n const sha = fields[i] ?? \"\";\n if (sha.length === 0) continue;\n records.push(\n commitSummary(\n sha,\n fields[i + 1] ?? \"\",\n fields[i + 2] ?? \"\",\n fields[i + 3] ?? \"\",\n fields[i + 4] ?? \"\",\n ),\n );\n }\n return records;\n}\n","// mu — shared helpers for concrete VCS backends.\n\nimport { execFile } from \"node:child_process\";\nimport { existsSync, rmSync } from \"node:fs\";\nimport { mkdir } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport {\n type CommitSummary,\n type ProbeReport,\n SHOW_COMMIT_MAX_CHARS,\n type ShowCommitResult,\n} from \"./types.js\";\n\nexport const exec = promisify(execFile);\n\n/** What each tool prints when cwd is simply not in its kind of repo. */\nconst NOT_A_REPO = /no jj repo|not inside a repository|not a git repository/i;\n\n/** True when `err` is the tool answering \"not this VCS\": it is not installed\n * (ENOENT), or it exited non-zero with its own not-a-repo message. Anything\n * else (a config or repo-state error that also exits 1, EAGAIN, EMFILE,\n * signal kill, timeout, maxBuffer) is an indeterminate probe failure. */\nfunction isCleanProbeNo(err: unknown): boolean {\n const cause = err instanceof Error ? err.cause : undefined;\n const { code, stderr } = (cause ?? {}) as { code?: unknown; stderr?: unknown };\n if (code === \"ENOENT\") return true;\n return typeof code === \"number\" && typeof stderr === \"string\" && NOT_A_REPO.test(stderr);\n}\n\nexport async function probeVcsRootPath(\n cmd: string,\n args: string[],\n cwd: string,\n report?: ProbeReport,\n): Promise<string | null> {\n try {\n const stdout = await run(cmd, args, cwd);\n const root = stdout.trim();\n return root.length > 0 ? root : null;\n } catch (err) {\n // Tool not installed, or tool exited non-zero because cwd is not\n // in that backend's repo type. Both mean \"not this backend\". Other\n // failures also read as \"no\" but are flagged in `report`.\n if (report !== undefined && !isCleanProbeNo(err)) report.failed = true;\n return null;\n }\n}\n\nexport async function probeVcsRoot(\n cmd: string,\n args: string[],\n cwd: string,\n report?: ProbeReport,\n): Promise<boolean> {\n return (await probeVcsRootPath(cmd, args, cwd, report)) !== null;\n}\n\nexport function isSaplingDotdir(dotdir: string): boolean {\n return /(?:^|[\\\\/])\\.(?:sl|hg)$/.test(dotdir);\n}\n\nexport async function ensureParent(path: string): Promise<void> {\n await mkdir(dirname(path), { recursive: true });\n}\n\nexport function rmDirSync(path: string): boolean {\n if (!existsSync(path)) return false;\n rmSync(path, { recursive: true, force: true });\n return true;\n}\n\n/**\n * Run a binary with args. Throws a typed Error on non-zero exit. Stdout\n * is returned trimmed; stderr is appended to the Error message.\n */\nexport async function run(bin: string, args: readonly string[], cwd?: string): Promise<string> {\n try {\n const { stdout } = await exec(bin, [...args], { cwd, maxBuffer: 16 * 1024 * 1024 });\n return stdout.trim();\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`vcs ${bin} ${args.join(\" \")} failed: ${msg}`, { cause: err });\n }\n}\n\n/**\n * Run a VCS `show` and cap its text at SHOW_COMMIT_MAX_CHARS. Output\n * past the exec buffer (2x the cap, in bytes) kills the child with\n * ERR_CHILD_PROCESS_STDIO_MAXBUFFER. A stdout overflow keeps the stdout\n * read so far and is always reported as truncated, even when multi-byte\n * text decodes to fewer characters than the cap. A stderr overflow is a\n * failure and surfaces as an error.\n */\nexport async function runShow(\n bin: string,\n args: readonly string[],\n cwd?: string,\n): Promise<ShowCommitResult> {\n let stdout: string;\n let overflowed = false;\n try {\n ({ stdout } = await exec(bin, [...args], { cwd, maxBuffer: SHOW_COMMIT_MAX_CHARS * 2 }));\n } catch (err) {\n const partial = stdoutOverflow(err);\n if (partial === undefined) {\n return {\n text: \"\",\n truncated: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n stdout = partial;\n overflowed = true;\n }\n if (overflowed || stdout.length > SHOW_COMMIT_MAX_CHARS) {\n return {\n text: `${stdout.slice(0, SHOW_COMMIT_MAX_CHARS)}\\n…(truncated at ${SHOW_COMMIT_MAX_CHARS} chars)`,\n truncated: true,\n };\n }\n return { text: stdout, truncated: false };\n}\n\n/** The partial stdout of a stdout maxBuffer overflow; undefined for any\n * other failure (a stderr overflow included). Node names the stream\n * only in the message: \"stdout maxBuffer length exceeded\". */\nfunction stdoutOverflow(err: unknown): string | undefined {\n if (!(err instanceof Error)) return undefined;\n const e = err as Error & { code?: unknown; stdout?: unknown };\n if (e.code !== \"ERR_CHILD_PROCESS_STDIO_MAXBUFFER\" || typeof e.stdout !== \"string\") {\n return undefined;\n }\n return e.message.startsWith(\"stdout \") ? e.stdout : undefined;\n}\n\nfunction relTimeFromIso(iso: string): string {\n const t = Date.parse(iso);\n if (!Number.isFinite(t)) return \"—\";\n const sec = Math.max(0, Math.floor((Date.now() - t) / 1000));\n if (sec < 60) return `${sec}s`;\n const min = Math.floor(sec / 60);\n if (min < 60) return `${min}m`;\n const hr = Math.floor(min / 60);\n if (hr < 24) return `${hr}h`;\n const day = Math.floor(hr / 24);\n if (day < 7) return `${day}d`;\n return `${Math.floor(day / 7)}w`;\n}\n\nexport function commitSummary(\n sha: string,\n subject: string,\n body: string,\n authorDate: string,\n author = \"\",\n): CommitSummary {\n return { sha, subject, body, author, authorDate, relTime: relTimeFromIso(authorDate) };\n}\n\nexport function saneLimit(limit: number): number {\n if (!Number.isFinite(limit)) return 25;\n return Math.max(0, Math.min(200, Math.floor(limit)));\n}\n\n/**\n * Parse the NUL-field / \\x1e-record format used by the jj/sl\n * commitsSinceBase impls. Each record is `sha\\0subject\\0body\\0date`\n * terminated by \\x1e. Empty input → [].\n */\nexport function parseNulRecords(raw: string): CommitSummary[] {\n if (raw.length === 0) return [];\n const records: CommitSummary[] = [];\n for (const rec of raw.split(\"\\x1e\")) {\n if (rec.length === 0) continue;\n const fields = rec.split(\"\\x00\");\n const sha = fields[0] ?? \"\";\n if (sha.length === 0) continue;\n records.push(\n commitSummary(sha, fields[1] ?? \"\", fields[2] ?? \"\", fields[3] ?? \"\", fields[4] ?? \"\"),\n );\n }\n return records;\n}\n","// mu — shared VCS backend contracts and typed errors.\n\nimport type { HasNextSteps, NextStep } from \"../output.js\";\n\nexport type VcsBackendName = \"jj\" | \"sl\" | \"git\" | \"none\";\n\n/** Out-parameter for `detect()`: set `failed` when a root probe could not\n * answer (spawn error, signal, timeout) as opposed to cleanly saying \"not\n * this VCS\". A caller that caches the detected backend must not cache\n * when `failed` is set: the probe may have hidden a higher-precedence\n * backend. */\nexport interface ProbeReport {\n failed: boolean;\n}\n\n// ─── Refresh / rebase result + typed errors ──────────────────────────\n//\n// rebaseTo is the backend-side of `mu workspace refresh`. The errors\n// live in this module (not src/workspace.ts) because they're thrown\n// from inside the backend impls; workspace.ts imports vcs.ts, and the\n// root vcs hub re-exports these concrete definitions.\n\nexport interface RebaseResult {\n /** The ref the workspace was actually rebased onto (resolved\n * symbolic-or-revset → concrete name). For git that is the\n * resolveGitMainRef() symbolic ref; for jj/sl it's the literal\n * `trunk()` revset (or whatever the operator passed via fromRef). */\n fromRef: string;\n /** Concrete commit id of the workspace's new fork point: fromRef's\n * commit, or the previous fork point when that already descends from\n * it (parent_ref never moves backward). The caller writes it to\n * `vcs_workspaces.parent_ref` so staleness, `mu workspace commits`\n * and the close-time clean check measure from the new base. Omitted\n * when the backend cannot resolve a single commit (e.g. a jj revset\n * naming several); the caller then keeps the old value. */\n parentRef?: string;\n /** Commit subjects (or descriptions) that got replayed, oldest-first.\n * Empty when the workspace was already at fromRef (no-op). */\n replayed: string[];\n /** Files / commits that conflicted during the rebase. Always\n * empty for a successful rebase — a non-empty conflicts list\n * means we threw WorkspaceConflictError before returning. The\n * field exists so the error's serialised payload can carry it. */\n conflicts: string[];\n}\n\nexport interface CommitSummary {\n /** Full commit / change id. */\n sha: string;\n /** First-line description / subject. */\n subject: string;\n /** Remainder of the commit message (may be empty). */\n body: string;\n /** Author display name, when the backend exposes one. */\n author: string;\n /** ISO-8601 author / commit timestamp. */\n authorDate: string;\n /** Compact relative author time (e.g. \"3m\", \"2d\"). */\n relTime: string;\n}\n\nexport interface ShowCommitResult {\n /** Captured VCS show output (possibly truncated). Empty string on error. */\n text: string;\n /** True when stdout exceeded SHOW_COMMIT_MAX_CHARS and was clipped. */\n truncated: boolean;\n /** Human-readable error message; omitted on success. */\n error?: string;\n}\n\n/** Cap captured `show` output so giant merge commits can't eat the TUI. */\nexport const SHOW_COMMIT_MAX_CHARS = 100_000;\n\n/**\n * Thrown by `rebaseTo` / `commitsSinceBase` on the `none` backend\n * (cp -a snapshots have no notion of a rebase target / fork point).\n * Maps to exit code 4.\n */\nexport class WorkspaceVcsRequiredError extends Error implements HasNextSteps {\n override readonly name = \"WorkspaceVcsRequiredError\";\n constructor(\n public readonly verb: string,\n public readonly workspacePath: string,\n ) {\n super(\n `vcs none: \\`mu workspace ${verb}\\` requires a real VCS (jj/sl/git); ${workspacePath} is a cp -a snapshot`,\n );\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Free the snapshot and re-spawn with a real VCS backend\",\n command:\n \"mu workspace free <agent> && mu agent spawn <agent> --workspace --workspace-backend <jj|sl|git>\",\n },\n ];\n }\n}\n\n/**\n * Thrown by `rebaseTo` when the workspace has uncommitted changes\n * the rebase would clobber. Carries the dirty file list so the operator\n * can decide between commit/stash/--force. Maps to exit code 4.\n */\nexport class WorkspaceDirtyError extends Error implements HasNextSteps {\n override readonly name = \"WorkspaceDirtyError\";\n /** The verb that refused. Only `rebaseTo` refuses this way today,\n * but the field keeps the message + nextSteps self-describing. */\n public readonly verb: string;\n constructor(\n public readonly workspacePath: string,\n public readonly files: readonly string[],\n verb = \"rebase\",\n ) {\n super(\n `workspace dirty (${files.length} uncommitted file(s)): ${workspacePath}; refusing to ${verb}`,\n );\n this.verb = verb;\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Inspect the dirty files\",\n command: `(cd ${this.workspacePath} && git status -s) # or jj st / sl st`,\n },\n {\n intent: `Commit them first, then retry ${this.verb}`,\n command: `(cd ${this.workspacePath} && git add -A && git commit -m WIP)`,\n },\n {\n intent: \"Or stash them first (git only)\",\n command: `(cd ${this.workspacePath} && git stash)`,\n },\n {\n intent: \"Or DISCARD the workspace entirely (the lossy escape)\",\n command: \"mu workspace free <agent>\",\n },\n ];\n }\n}\n\n/**\n * Thrown by `rebaseTo` when the rebase produced conflicts. Carries the\n * conflicting paths (git/sl) or commits (jj). Maps to exit code 5.\n *\n * git and sl abort the rebase before throwing, so the workspace is back\n * at its pre-rebase state (`aborted` is true). jj cannot abort: the\n * rebase is done and the conflicts are committed in place (`aborted` is\n * false). Either way the row's parent_ref is unchanged, so the hint\n * ends with re-running refresh: once the conflicts are resolved, that\n * rebase is clean and records the base the disk is on.\n */\nexport class WorkspaceConflictError extends Error implements HasNextSteps {\n override readonly name = \"WorkspaceConflictError\";\n constructor(\n public readonly workspacePath: string,\n public readonly fromRef: string,\n public readonly conflicts: readonly string[],\n /** True when the backend aborted the rebase and the workspace is unchanged. */\n public readonly aborted = true,\n ) {\n super(\n `rebase onto ${fromRef} produced ${conflicts.length} conflict(s)${aborted ? \"; rebase aborted, workspace unchanged\" : \"; conflicts left in place\"}: ${workspacePath}`,\n );\n }\n errorNextSteps(): NextStep[] {\n const resync = {\n intent: \"After resolving, record the new base (a clean refresh updates the fork point)\",\n command: `mu workspace refresh <agent> --from '${this.fromRef}'`,\n };\n if (this.aborted) {\n return [\n {\n intent: \"The rebase was aborted. Rebase by hand in the workspace and resolve\",\n command: `cd ${this.workspacePath} # then: git rebase ${this.fromRef} (sl: sl rebase -d '${this.fromRef}')`,\n },\n resync,\n {\n intent: \"Or DISCARD the workspace entirely (the lossy escape)\",\n command: \"mu workspace free <agent>\",\n },\n ];\n }\n return [\n {\n intent: \"Resolve the conflicted commits in place\",\n command: `cd ${this.workspacePath} # then: jj resolve; or undo the rebase: jj op undo`,\n },\n resync,\n ];\n }\n}\n\nexport interface CreateWorkspaceOptions {\n /** The repository being branched from. Absolute path. */\n projectRoot: string;\n /** Where to place the new workspace. Absolute path; must NOT exist. */\n workspacePath: string;\n /** Optional commit / branch / changeset id to base off. Backend-specific:\n * git uses it as a `git worktree add`'s ref, jj as a revset, sl as a\n * rev. Undefined = current head. */\n parentRef?: string;\n}\n\nexport interface CreateWorkspaceResult {\n /** The actual ref the workspace points at (resolved to a stable id\n * when possible). Stored on the row; useful for `mu workspace list`\n * and for `--commit` flows. May be null for backends that don't\n * expose a meaningful parent (e.g. `none`). */\n parentRef: string | null;\n}\n\nexport interface FreeWorkspaceOptions {\n workspacePath: string;\n /** If true, attempt to commit any pending changes BEFORE removal.\n * Backend-specific: jj auto-commits via `jj describe + jj new`, git\n * needs an explicit commit on the worktree, sl needs `sl commit`,\n * none has nothing to commit. If pending changes exist and `commit`\n * is false, the on-disk directory still gets removed and changes are\n * lost — the verb prints a clear warning. */\n commit: boolean;\n}\n\nexport interface FreeWorkspaceResult {\n /** The commit id that captured the pending changes, when `commit` was\n * true and there was something to commit. Otherwise undefined. */\n committedRef?: string;\n /** Branch created to keep the workspace's commits reachable after the\n * worktree is removed (git with `commit`, when HEAD was on no branch,\n * remote or tag). Otherwise undefined. */\n branch?: string;\n /** True iff the on-disk path was actually removed (vs. already gone). */\n removed: boolean;\n}\n\nexport interface VcsBackend {\n readonly name: VcsBackendName;\n\n /** True iff this backend should handle `projectRoot`. Implementations\n * check for the relevant marker dir (`.jj`, `.sl`, `.git`); `none`\n * always returns true and is consulted last. `report.failed` is set\n * when a root probe was indeterminate (see `ProbeReport`). */\n detect(projectRoot: string, report?: ProbeReport): Promise<boolean>;\n\n createWorkspace(opts: CreateWorkspaceOptions): Promise<CreateWorkspaceResult>;\n\n freeWorkspace(opts: FreeWorkspaceOptions): Promise<FreeWorkspaceResult>;\n\n /**\n * Count commits that the project's default branch (\"main\") has but\n * `ref` does not — i.e. how many commits `ref` is BEHIND main.\n *\n * Used by `mu workspace list` and `mu state` to surface staleness\n * (bug_workspace_stale_parent_silent_drift). Cheap, pure-observation:\n * NO automatic fetch. We compare against whatever main resolves to in\n * the workspace's LOCAL refs cache. The user can `git fetch` (or\n * equivalent) themselves if they want a fresher number.\n *\n * Returns null when:\n * - main / trunk cannot be resolved (no origin/HEAD, no origin/main,\n * no origin/master, no trunk() bookmark, etc.)\n * - the underlying VCS command fails for any reason (detached worktree,\n * missing refs, the `none` backend which has no notion of \"main\")\n *\n * Callers treat null as \"unknown — render — — and don't warn\".\n *\n * `mainRefCache`, when given, is shared across the rows of one\n * decorate call so a backend that must resolve \"main\" per repo (git's\n * origin/HEAD probe) does it once per repo, not once per workspace.\n * Backends that resolve main inside the count command ignore it.\n */\n commitsBehind(\n workspacePath: string,\n ref: string,\n mainRefCache?: Map<string, Promise<string | undefined>>,\n ): Promise<number | null>;\n\n /**\n * Rebase the workspace onto `fromRef` (or the backend's tracked\n * base when undefined: `origin/HEAD` for git, `trunk()` for jj/sl).\n * Returns the resolved ref + replayed commits + conflicts list.\n *\n * Backend-specific behaviour:\n * - git: refuses on dirty WC (WorkspaceDirtyError); fetches first;\n * `git rebase <ref>`. On conflict, aborts the rebase and throws\n * WorkspaceConflictError (aborted); the workspace is unchanged.\n * Any other rebase failure is rethrown.\n * - jj: always-snapshotted, so dirty is never an issue. After\n * `jj rebase -d <ref>` the conflict-set is queried via\n * `jj log -r 'conflict()'`. Conflicts surface as\n * WorkspaceConflictError without an abort (jj's conflict markers\n * persist as commits; the operator resolves in-place).\n * - sl: like git. Refuses on dirty WC (WorkspaceDirtyError);\n * `sl rebase -d <ref>`; conflicts via `sl resolve --list`, then\n * aborts and throws WorkspaceConflictError (aborted). Any other\n * rebase failure is rethrown.\n * - none: throws WorkspaceVcsRequiredError unconditionally.\n *\n * Surfaced by fb_workspace_recycle_verb: dogfood between waves\n * needed `close → free → spawn` to refresh a worker against new\n * main; that killed the worker's LLM context. `refresh` updates\n * the on-disk dir without touching the agent or pane.\n */\n rebaseTo(\n workspacePath: string,\n fromRef?: string,\n /** The row's current parent_ref. Kept as the result's parentRef\n * when it already descends from fromRef and is under the head. */\n previousParentRef?: string,\n ): Promise<RebaseResult>;\n\n /**\n * Cheap \"is the working copy clean?\" probe used by close-auto-free\n * (allow_mu_agent_close_without_discard). Definition: ZERO uncommitted\n * changes (no working-tree modifications, no staged changes, no\n * untracked-not-ignored files). Pure observation; no fetch, no commit.\n *\n * Backend-specific:\n * - git: empty `git status --porcelain` output.\n * - jj: jj is auto-snapshotted, so the @ commit IS the WC; clean\n * here means @ has no diff from its parent (empty `jj diff\n * -r @ --summary`). A description-only difference still\n * counts as clean.\n * - sl: empty `sl status` output.\n * - none: meaningless (cp -a snapshot has no notion of\n * \"committed\" vs \"uncommitted\"); always returns true so the\n * close-auto-free path treats every none-workspace as\n * eligible for silent free (no commits can be lost; the only\n * loss is local file edits, which the operator implicitly\n * accepts by closing the agent).\n *\n * Returns false on any backend command failure — be conservative\n * (we'd rather refuse a close than auto-free a workspace whose\n * cleanliness we couldn't verify).\n */\n isClean(workspacePath: string): Promise<boolean>;\n\n /**\n * List commits the workspace has on top of `baseRef`, oldest-first.\n * Used by `mu workspace commits` (fb_workspace_commits_verb) to\n * promote the dogfood-painful\n * cd $(mu workspace path X) && git log <base>..HEAD\n * incantation into a typed verb that knows the workspace's\n * parent_ref. The CommitSummary fields survive subjects/bodies with\n * embedded newlines (NUL-delimited record format on the wire).\n *\n * `none` throws WorkspaceVcsRequiredError. Returns `[]` when the\n * workspace is exactly at baseRef (no commits since fork). Throws\n * on backend command failure (unknown ref, missing repo).\n */\n commitsSinceBase(workspacePath: string, baseRef: string): Promise<CommitSummary[]>;\n\n /** Last N commits on the project root, newest-first. Used by the\n * TUI Commits card / popup. Unlike commitsSinceBase, this is NOT\n * a per-workspace since-fork query. */\n recentCommits(projectRoot: string, limit: number): Promise<CommitSummary[]>;\n\n /** Show one commit / change from the project root, capped for TUI\n * rendering. Backend-specific equivalent of `git show <sha>`. */\n showCommit(projectRoot: string, sha: string): Promise<ShowCommitResult>;\n\n /**\n * Return the list of dirty (uncommitted / unstaged / untracked-not-\n * ignored) paths in the workspace. Empty array = clean.\n *\n * Used by `mu workspace list`'s dirty decoration and by the\n * dirty-check `rebaseTo` does internally before a refresh.\n *\n * Backend semantics:\n * - git: `git status --porcelain` (working-tree + staged +\n * untracked-not-ignored, mirroring the rebaseTo path).\n * - sl: `sl status` parsed for non-empty output.\n * - jj: always-snapshotted, so no concept of \"dirty\" — returns [].\n * - none: cp -a snapshots have no VCS, so we can't decide \"dirty\";\n * returns [] so the caller doesn't refuse for an unanswerable\n * question.\n *\n * Throws on backend command failure (the operator should see a\n * real error, not a silent \"clean\").\n */\n listDirtyFiles(workspacePath: string): Promise<string[]>;\n}\n","// mu — jj VCS backend.\n\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n ensureParent,\n parseNulRecords,\n probeVcsRoot,\n rmDirSync,\n run,\n runShow,\n saneLimit,\n} from \"./helpers.js\";\nimport { type FreeWorkspaceResult, type VcsBackend, WorkspaceConflictError } from \"./types.js\";\n\n// `jj workspace add --name <name> <path>` shares the .jj/repo store\n// while giving each agent its own working copy. Workspaces are named\n// per repo; we use `<workstream>/<agent>` (the last two segments of\n// our on-disk layout) because agent names are unique only per\n// workstream.\n//\n// Free is two-step: `jj workspace forget` (no name: the current\n// workspace) from the workspace itself unregisters; then we rm the dir\n// since jj leaves the files behind. A dir that is already gone cannot\n// be forgotten from here (free has no project root), so createWorkspace\n// forgets a same-named registration whose root is missing, as git's\n// `worktree prune` does.\n//\n// --commit semantics for jj: jj's working copy is always automatically\n// snapshotted, so \"commit\" is really \"capture the current change_id\n// as the result.\" Nothing is ever lost; jj keeps all operations in\n// its op log indefinitely. We additionally call `jj describe` to set\n// a description IF the current commit's description is empty so the\n// captured ref is human-discoverable.\n\nexport const jjBackend: VcsBackend = {\n name: \"jj\",\n\n async detect(projectRoot, report) {\n return probeVcsRoot(\"jj\", [\"root\"], projectRoot, report);\n },\n\n async createWorkspace(opts) {\n if (existsSync(opts.workspacePath)) {\n throw new Error(`vcs jj: workspacePath already exists: ${opts.workspacePath}`);\n }\n await ensureParent(opts.workspacePath);\n const name = jjWorkspaceName(opts.workspacePath);\n await forgetIfRootMissing(name, opts.projectRoot);\n const args = [\"workspace\", \"add\", \"--name\", name];\n if (opts.parentRef) args.push(\"--revision\", opts.parentRef);\n args.push(opts.workspacePath);\n await run(\"jj\", args, opts.projectRoot);\n const commitId = await jjCommitId(opts.workspacePath);\n return { parentRef: commitId };\n },\n\n async freeWorkspace(opts) {\n if (!existsSync(opts.workspacePath)) {\n return { removed: false };\n }\n let committedRef: string | undefined;\n if (opts.commit) {\n const desc = await run(\n \"jj\",\n [\n \"log\",\n \"-r\",\n \"@\",\n \"--no-graph\",\n \"--no-pager\",\n \"--color\",\n \"never\",\n \"--template\",\n \"description\",\n ],\n opts.workspacePath,\n );\n if (desc.trim().length === 0) {\n await run(\"jj\", [\"describe\", \"-m\", \"mu workspace free auto-commit\"], opts.workspacePath);\n }\n committedRef = await jjCommitId(opts.workspacePath);\n }\n // Bare `jj workspace forget` forgets the workspace it runs in, so\n // free never depends on how the name was derived (older mu used\n // the agent name alone). jj prints a hint about the working copy\n // becoming orphaned; we resolve that immediately by rm-ing the dir.\n await run(\"jj\", [\"workspace\", \"forget\"], opts.workspacePath);\n rmDirSync(opts.workspacePath);\n const result: FreeWorkspaceResult = { removed: true };\n if (committedRef !== undefined) result.committedRef = committedRef;\n return result;\n },\n\n // jj working-copy clean: @ has no diff from its parent.\n // `jj diff -r @ --summary` prints one line per changed file; empty\n // stdout = clean. jj's auto-snapshotting means there's no separate\n // \"untracked\" bucket — every working-tree change is already in @.\n async isClean(workspacePath) {\n if (!existsSync(workspacePath)) return false;\n try {\n const out = await run(\n \"jj\",\n [\"diff\", \"-r\", \"@\", \"--summary\", \"--no-pager\", \"--color\", \"never\"],\n workspacePath,\n );\n return out.length === 0;\n } catch {\n return false;\n }\n },\n\n // Compute commits-behind via jj's `trunk()` revset, which resolves\n // to the project's configured trunk (default-branch heuristic).\n // Returns null when trunk() is unresolvable (e.g. fresh repo with\n // no configured trunk) or when the log call fails.\n //\n // Pure observation: NO `jj git fetch`, and `--ignore-working-copy`\n // so the probe neither snapshots the working copy (a full tree stat\n // per workspace on every `mu state` / TUI slow tick) nor writes a jj\n // operation. `<ref>..trunk()` never involves `@`, so the count is the\n // same either way. But the flag also skips the automatic Git import a\n // colocated workspace (`.git` beside `.jj`) does, so a plain `git\n // fetch` would go unseen; import explicitly there first. The import\n // writes an op only when Git refs moved, as the implicit one did.\n // Non-colocated workspaces never auto-imported, so they skip it.\n async commitsBehind(workspacePath, ref) {\n if (!existsSync(workspacePath)) return null;\n try {\n if (existsSync(join(workspacePath, \".git\"))) {\n await run(\"jj\", [\"git\", \"import\", \"--ignore-working-copy\", \"--quiet\"], workspacePath);\n }\n // `<ref>..trunk()` is the set of commits reachable from trunk\n // but not from ref — exactly the staleness number. Template `\"x\\n\"`\n // gives one line per commit, which we count.\n const out = await run(\n \"jj\",\n [\n \"log\",\n \"--ignore-working-copy\",\n \"-r\",\n `${ref}..trunk()`,\n \"--no-graph\",\n \"--no-pager\",\n \"--color\",\n \"never\",\n \"--template\",\n '\"x\\\\n\"',\n ],\n workspacePath,\n );\n if (out.length === 0) return 0;\n return out.split(\"\\n\").filter((l) => l.length > 0).length;\n } catch {\n return null;\n }\n },\n\n // Rebase the workspace's @ onto `fromRef` (default = `trunk()`).\n // jj is always-snapshotted so dirty WC is never an issue — the auto-\n // snapshot becomes part of the rebase. After the rebase we query\n // `conflict()` to surface any commits that ended up conflicted; jj\n // doesn't auto-abort on conflicts (they materialise as commits with\n // conflict markers), so the workspace is left in a state the\n // operator can resolve in-place.\n async rebaseTo(workspacePath, fromRef, previousParentRef) {\n if (!existsSync(workspacePath)) {\n throw new Error(`vcs jj: workspace path missing: ${workspacePath}`);\n }\n const target = fromRef ?? \"trunk()\";\n // @'s commit id before the rebase (reading it snapshots the WC\n // first). jj skips commits already in place, so an unchanged id\n // after the rebase means a no-op: nothing was replayed.\n const headBefore = await jjCommitId(workspacePath);\n await run(\"jj\", [\"rebase\", \"-d\", target], workspacePath);\n const moved = (await jjCommitId(workspacePath)) !== headBefore;\n // Replayed = first-line descriptions of commits in (target..@),\n // oldest-first, one per line; empty when the rebase was a no-op.\n const replayedRaw = moved\n ? await run(\n \"jj\",\n [\n \"log\",\n \"-r\",\n `${target}..@`,\n \"--no-graph\",\n \"--no-pager\",\n \"--color\",\n \"never\",\n \"--reversed\",\n \"--template\",\n 'description.first_line() ++ \"\\\\n\"',\n ],\n workspacePath,\n ).catch(() => \"\")\n : \"\";\n const replayed = replayedRaw\n .split(\"\\n\")\n .map((l) => l.trim())\n .filter((l) => l.length > 0);\n // Conflict surface: list change_ids of commits in the rebased\n // range that are conflicted. Empty = clean rebase.\n const conflictRaw = await run(\n \"jj\",\n [\n \"log\",\n \"-r\",\n `(${target}..@) & conflict()`,\n \"--no-graph\",\n \"--no-pager\",\n \"--color\",\n \"never\",\n \"--template\",\n 'change_id.short() ++ \"\\\\n\"',\n ],\n workspacePath,\n ).catch(() => \"\");\n const conflicts = conflictRaw\n .split(\"\\n\")\n .map((l) => l.trim())\n .filter((l) => l.length > 0);\n if (conflicts.length > 0) {\n // jj has no abort: the rebase stays with the conflicts. The row's\n // parent_ref is left alone; the operator resolves (or `jj op\n // undo`es) and re-runs refresh, whose clean no-op rebase records\n // the base the disk is on.\n throw new WorkspaceConflictError(workspacePath, target, conflicts, false);\n }\n // After `jj rebase -d <target>` the chain sits on <target>, so its\n // commit is the new fork point (the row's parent_ref), unless the\n // old fork point already descends from it and is still under @\n // (no-op refresh onto an older base): parent_ref never moves\n // backward. Omitted when the revset names zero or several commits.\n const targetId = await jjSingleCommitId(workspacePath, target);\n if (targetId === undefined) return { fromRef: target, replayed, conflicts: [] };\n const keepPrevious =\n previousParentRef !== undefined &&\n (await jjSingleCommitId(workspacePath, `${previousParentRef} & ${targetId}:: & ::@`)) !==\n undefined;\n const parentRef = keepPrevious ? previousParentRef : targetId;\n return { fromRef: target, parentRef, replayed, conflicts: [] };\n },\n\n // List jj commits in (baseRef..@), oldest-first, minus @ itself when\n // it is the empty, undescribed working-copy commit jj snapshots on\n // every command: that is \"no work yet\", not a commit. jj's templating\n // gives us per-field strings; we glue them with NUL field-separators\n // and \\x1e record-separators so multi-line descriptions/bodies\n // round-trip cleanly. The author timestamp template is\n // `author.timestamp().format(\"%Y-%m-%dT%H:%M:%S%:z\")` which is\n // ISO-8601 (matches git's --aiso strict / --aI).\n async commitsSinceBase(workspacePath, baseRef) {\n if (!existsSync(workspacePath)) {\n throw new Error(`vcs jj: workspace path missing: ${workspacePath}`);\n }\n const out = await run(\n \"jj\",\n [\n \"log\",\n \"-r\",\n `(${baseRef}..@) ~ (@ & empty() & description(exact:\"\"))`,\n \"--no-graph\",\n \"--no-pager\",\n \"--color\",\n \"never\",\n \"--reversed\",\n \"--template\",\n jjCommitSummaryTemplate,\n ],\n workspacePath,\n );\n return parseNulRecords(out);\n },\n\n async recentCommits(projectRoot, limit) {\n if (!existsSync(projectRoot)) {\n throw new Error(`vcs jj: project root missing: ${projectRoot}`);\n }\n const n = saneLimit(limit);\n if (n === 0) return [];\n const out = await run(\n \"jj\",\n [\n \"log\",\n \"--no-graph\",\n \"--no-pager\",\n \"--color\",\n \"never\",\n \"-r\",\n \"::@\",\n \"--limit\",\n String(n),\n \"--template\",\n jjCommitSummaryTemplate,\n ],\n projectRoot,\n );\n return parseNulRecords(out);\n },\n\n async showCommit(projectRoot, sha) {\n return runShow(\"jj\", [\"show\", sha, \"--color\", \"always\"], projectRoot);\n },\n\n // jj is always-snapshotted: there is no \"uncommitted\" state. The\n // working copy is itself a commit; the next snapshot folds any\n // edits in. Surface that by returning [] so dirty-checking callers\n // never refuse a jj workspace as \"dirty\".\n async listDirtyFiles(_workspacePath) {\n return [];\n },\n};\n\nconst jjCommitSummaryTemplate =\n 'commit_id ++ \"\\\\x00\" ++ description.first_line() ++ \"\\\\x00\" ++ description ++ \"\\\\x00\" ++ author.timestamp().format(\"%Y-%m-%dT%H:%M:%S%:z\") ++ \"\\\\x00\" ++ author.name() ++ \"\\\\x1e\"';\n\n/** jj workspace name for a mu workspace path:\n * <state>/workspaces/auth/worker-1 → auth/worker-1. Workstream and\n * agent names cannot contain \"/\", so the name is unique per repo. */\nexport function jjWorkspaceName(workspacePath: string): string {\n const parts = workspacePath.split(\"/\").filter((p) => p.length > 0);\n return parts.slice(-2).join(\"/\") || workspacePath;\n}\n\n// Forget `name` if jj still registers it but its root dir is gone (the\n// dir was rm -rf'd, or freed while already missing). jj reports such a\n// workspace's root as \"\". Best-effort: on a jj without the\n// `WorkspaceRef.root()` template, `workspace add` reports the clash.\nasync function forgetIfRootMissing(name: string, projectRoot: string): Promise<void> {\n try {\n const out = await run(\n \"jj\",\n [\n \"workspace\",\n \"list\",\n \"--color\",\n \"never\",\n \"--template\",\n 'name ++ \"\\\\x00\" ++ self.root() ++ \"\\\\x1e\"',\n ],\n projectRoot,\n );\n const stale = out\n .split(\"\\x1e\")\n .map((r) => r.trim().split(\"\\x00\"))\n .some(([n, root]) => n === name && root === \"\");\n if (stale) await run(\"jj\", [\"workspace\", \"forget\", name], projectRoot);\n } catch {\n // best-effort; `workspace add` surfaces any remaining conflict\n }\n}\n\nasync function jjSingleCommitId(\n workspacePath: string,\n revset: string,\n): Promise<string | undefined> {\n const out = await run(\n \"jj\",\n [\n \"log\",\n \"-r\",\n revset,\n \"--no-graph\",\n \"--no-pager\",\n \"--color\",\n \"never\",\n \"--template\",\n 'commit_id ++ \"\\\\n\"',\n ],\n workspacePath,\n ).catch(() => \"\");\n const ids = out.split(\"\\n\").filter((l) => l.length > 0);\n return ids.length === 1 ? ids[0] : undefined;\n}\n\nasync function jjCommitId(workspacePath: string): Promise<string> {\n return run(\n \"jj\",\n [\"log\", \"-r\", \"@\", \"--no-graph\", \"--no-pager\", \"--color\", \"never\", \"--template\", \"commit_id\"],\n workspacePath,\n );\n}\n","// mu — non-VCS fallback backend.\n\nimport { existsSync } from \"node:fs\";\nimport { ensureParent, rmDirSync, run } from \"./helpers.js\";\nimport { type VcsBackend, WorkspaceVcsRequiredError } from \"./types.js\";\n\n// The fallback for projects that aren't under any VCS we recognise.\n// `cp -a` is heavy but correct; the workspace is a full snapshot.\n// Free deletes the snapshot. No commit semantics (no VCS to commit\n// against), so `--commit` is silently ignored.\n\nexport const noneBackend: VcsBackend = {\n name: \"none\",\n\n async detect(_projectRoot) {\n return true;\n },\n\n async createWorkspace(opts) {\n if (existsSync(opts.workspacePath)) {\n throw new Error(`vcs none: workspacePath already exists: ${opts.workspacePath}`);\n }\n await ensureParent(opts.workspacePath);\n // `cp -a` is GNU/BSD-portable for \"preserve everything, recursive\".\n await run(\"cp\", [\"-a\", `${opts.projectRoot}/.`, opts.workspacePath]);\n return { parentRef: null };\n },\n\n async freeWorkspace(opts) {\n const removed = rmDirSync(opts.workspacePath);\n return { removed };\n },\n\n // The `none` backend has no VCS to compare against — there's no\n // notion of \"main\" for a `cp -a` snapshot. Always null.\n async commitsBehind(_workspacePath, _ref) {\n return null;\n },\n\n // none has no notion of clean — a cp -a snapshot doesn't track\n // committed vs uncommitted state. Returning true makes the\n // close-auto-free path silently free a none-workspace (consistent\n // with the fact that there are no commits to lose).\n async isClean(_workspacePath) {\n return true;\n },\n\n // none has no upstream to rebase onto. Throw a typed error so the\n // CLI's handle() maps it to exit 4 with a clean Next: hint.\n async rebaseTo(workspacePath, _fromRef) {\n throw new WorkspaceVcsRequiredError(\"refresh\", workspacePath);\n },\n\n // none has no notion of a fork point either — a cp -a snapshot\n // doesn't track history. Same typed error as rebaseTo.\n async commitsSinceBase(workspacePath, _baseRef) {\n throw new WorkspaceVcsRequiredError(\"commits\", workspacePath);\n },\n\n async recentCommits(_projectRoot, _limit) {\n return [];\n },\n\n async showCommit(_projectRoot, _sha) {\n return { text: \"\", truncated: false, error: \"vcs none: no commits to show\" };\n },\n\n // No VCS → nothing to compare against; \"dirty\" is unanswerable.\n // Callers treat [] as \"clean\" and proceed.\n async listDirtyFiles(_workspacePath) {\n return [];\n },\n};\n","// mu — Sapling VCS backend.\n\nimport { existsSync } from \"node:fs\";\nimport {\n ensureParent,\n isSaplingDotdir,\n parseNulRecords,\n probeVcsRootPath,\n rmDirSync,\n run,\n runShow,\n saneLimit,\n} from \"./helpers.js\";\nimport {\n type FreeWorkspaceResult,\n type VcsBackend,\n WorkspaceConflictError,\n WorkspaceDirtyError,\n} from \"./types.js\";\n\n// `sl worktree` exists in Sapling but only for EdenFS-backed repos.\n// For portability we use `sl clone` instead, which works on any\n// sapling install. The trade-off is heavier (history copy) vs lighter\n// (shared store), but the workspace is fully isolated either way —\n// which is what we care about. EdenFS-specific worktree optimization\n// can layer on later if anyone hits the friction.\n//\n// Free is just rm -rf: sapling has no formal \"unclone\" because each\n// clone is a self-contained repo.\n\nexport const slBackend: VcsBackend = {\n name: \"sl\",\n\n async detect(projectRoot, report) {\n const root = await probeVcsRootPath(\"sl\", [\"root\"], projectRoot, report);\n if (root === null) return false;\n // Meta's Sapling build can transparently operate in plain git repos\n // by creating `.git/sl`. That should not beat git in BACKENDS order.\n // `--dotdir` keeps true sl / hg-compat repos (`.sl` / `.hg`) distinct.\n const dotdir = await probeVcsRootPath(\"sl\", [\"root\", \"--dotdir\"], projectRoot, report);\n return dotdir !== null && isSaplingDotdir(dotdir);\n },\n\n async createWorkspace(opts) {\n if (existsSync(opts.workspacePath)) {\n throw new Error(`vcs sl: workspacePath already exists: ${opts.workspacePath}`);\n }\n await ensureParent(opts.workspacePath);\n const args = [\"clone\"];\n if (opts.parentRef) args.push(\"-r\", opts.parentRef);\n args.push(opts.projectRoot, opts.workspacePath);\n await run(\"sl\", args);\n const commitId = await slCommitId(opts.workspacePath);\n return { parentRef: commitId };\n },\n\n async freeWorkspace(opts) {\n if (!existsSync(opts.workspacePath)) {\n return { removed: false };\n }\n let committedRef: string | undefined;\n if (opts.commit && (await slIsDirty(opts.workspacePath))) {\n // sl commit -A: stage all (including untracked), commit. Exits\n // non-zero if nothing changed, but we just guarded above.\n await run(\n \"sl\",\n [\n \"--config\",\n \"ui.username=mu <mu@local>\",\n \"commit\",\n \"-A\",\n \"-m\",\n \"mu workspace free auto-commit\",\n ],\n opts.workspacePath,\n );\n committedRef = await slCommitId(opts.workspacePath);\n }\n rmDirSync(opts.workspacePath);\n const result: FreeWorkspaceResult = { removed: true };\n if (committedRef !== undefined) result.committedRef = committedRef;\n return result;\n },\n\n // sl working-copy clean: empty `sl status` output. Same shape as\n // listSlDirtyFiles below but inlined to keep the failure-mode\n // boundary tight (any throw → not clean).\n async isClean(workspacePath) {\n if (!existsSync(workspacePath)) return false;\n try {\n const out = await run(\"sl\", [\"status\"], workspacePath);\n return out.length === 0;\n } catch {\n return false;\n }\n },\n\n // Same shape as the jj impl: count commits in trunk() not reachable\n // from ref. Sapling's revset language is close enough to jj's that\n // the same idiom works. Returns null when trunk() is unresolvable\n // (fresh repo, missing remote bookmark, etc.) or the log fails.\n //\n // Pure observation: NO `sl pull`.\n async commitsBehind(workspacePath, ref) {\n if (!existsSync(workspacePath)) return null;\n try {\n const out = await run(\n \"sl\",\n [\"log\", \"-r\", `${ref}::trunk() - ${ref}`, \"--template\", \"x\\\\n\"],\n workspacePath,\n );\n if (out.length === 0) return 0;\n return out.split(\"\\n\").filter((l) => l.length > 0).length;\n } catch {\n return null;\n }\n },\n\n // Rebase the active draft chain onto `fromRef` (default = `trunk()`).\n // We pre-check the WC and refuse with the typed WorkspaceDirtyError.\n // `sl rebase` exits 0 on success (also when there is nothing to\n // rebase) and 1 on unresolved conflicts. Conflict surface via\n // `sl resolve --list --tool=internal:dumpjson` is brittle across\n // versions, so on failure we read the textual `sl resolve --list`\n // and keep the U-prefixed (unresolved) lines. A failure with no\n // unresolved files (bad ref, unresolvable trunk()) is rethrown, as\n // the git impl does.\n async rebaseTo(workspacePath, fromRef, previousParentRef) {\n if (!existsSync(workspacePath)) {\n throw new Error(`vcs sl: workspace path missing: ${workspacePath}`);\n }\n const target = fromRef ?? \"trunk()\";\n const dirtyFiles = await listSlDirtyFiles(workspacePath);\n if (dirtyFiles.length > 0) {\n throw new WorkspaceDirtyError(workspacePath, dirtyFiles);\n }\n // `.`'s node before the rebase: unchanged afterwards means sl had\n // nothing to rebase, so nothing was replayed.\n const headBefore = await slCommitId(workspacePath);\n try {\n await run(\n \"sl\",\n [\"--config\", \"ui.username=mu <mu@local>\", \"rebase\", \"-d\", target],\n workspacePath,\n );\n } catch (err) {\n const conflicts = await listSlUnresolved(workspacePath);\n // Best-effort abort so the workspace returns to its pre-rebase\n // state, mirroring the git impl's never-leave-half-rebased policy.\n await run(\"sl\", [\"rebase\", \"--abort\"], workspacePath).catch(() => {});\n if (conflicts.length > 0) {\n throw new WorkspaceConflictError(workspacePath, target, conflicts);\n }\n throw err;\n }\n // After the rebase the draft chain sits on `target`, so `target`'s\n // node is the new fork point (recorded as the row's parent_ref),\n // unless the old fork point already descends from it and is still\n // under `.` (no-op refresh onto an older base): parent_ref never\n // moves backward.\n const targetNode = await run(\n \"sl\",\n [\"log\", \"-r\", `last(${target})`, \"--template\", \"{node}\"],\n workspacePath,\n ).catch(() => \"\");\n const keepPrevious =\n previousParentRef !== undefined &&\n targetNode.length > 0 &&\n (await run(\n \"sl\",\n [\"log\", \"-r\", `${previousParentRef} & ${targetNode}:: & ::.`, \"--template\", \"{node}\"],\n workspacePath,\n ).catch(() => \"\")) !== \"\";\n const parentRef = keepPrevious ? previousParentRef : targetNode;\n // Replayed = log of `target..` post-rebase, oldest-first. Single-\n // line subjects via `{desc|firstline}`. Empty when nothing replayed.\n const moved = (await slCommitId(workspacePath)) !== headBefore;\n const replayedRaw = moved\n ? await run(\n \"sl\",\n [\"log\", \"-r\", `${target}::. - ${target}`, \"--template\", \"{desc|firstline}\\\\n\"],\n workspacePath,\n ).catch(() => \"\")\n : \"\";\n const replayed = replayedRaw\n .split(\"\\n\")\n .map((l) => l.trim())\n .filter((l) => l.length > 0);\n return parentRef.length > 0\n ? { fromRef: target, parentRef, replayed, conflicts: [] }\n : { fromRef: target, replayed, conflicts: [] };\n },\n\n // List sl commits in (baseRef..., minus baseRef itself), oldest-\n // first. Same NUL-field / \\x1e-record format as the jj impl;\n // sl's templating uses {field} braces (not jj's `++` operator) but\n // the field set is equivalent ({node}, {desc|firstline}, {desc},\n // {date|isodate}).\n async commitsSinceBase(workspacePath, baseRef) {\n if (!existsSync(workspacePath)) {\n throw new Error(`vcs sl: workspace path missing: ${workspacePath}`);\n }\n const out = await run(\n \"sl\",\n [\"log\", \"-r\", `${baseRef}::. - ${baseRef}`, \"--template\", slCommitSummaryTemplate],\n workspacePath,\n );\n // sl emits oldest-last by default; reverse to oldest-first to match\n // the git/jj contract.\n return parseNulRecords(out).reverse();\n },\n\n async recentCommits(projectRoot, limit) {\n if (!existsSync(projectRoot)) {\n throw new Error(`vcs sl: project root missing: ${projectRoot}`);\n }\n const n = saneLimit(limit);\n if (n === 0) return [];\n const out = await run(\n \"sl\",\n [\"log\", \"-l\", String(n), \"--template\", slCommitSummaryTemplate],\n projectRoot,\n );\n return parseNulRecords(out);\n },\n\n async showCommit(projectRoot, sha) {\n return runShow(\"sl\", [\"show\", sha, \"--color=always\"], projectRoot);\n },\n\n async listDirtyFiles(workspacePath) {\n if (!existsSync(workspacePath)) return [];\n return listSlDirtyFiles(workspacePath);\n },\n};\n\n/**\n * List dirty paths for a sapling workspace. `sl status` prints one\n * line per changed file: `<status> <path>`. Empty = clean.\n */\nasync function listSlDirtyFiles(workspacePath: string): Promise<string[]> {\n const out = await run(\"sl\", [\"status\"], workspacePath);\n if (out.length === 0) return [];\n return out\n .split(\"\\n\")\n .filter((l) => l.length > 0)\n .map((l) => l.slice(2));\n}\n\n/**\n * List unresolved (conflicting) paths after an `sl rebase`. `sl resolve\n * --list` prints `<U|R> <path>` per file; U = unresolved.\n */\nasync function listSlUnresolved(workspacePath: string): Promise<string[]> {\n try {\n const out = await run(\"sl\", [\"resolve\", \"--list\"], workspacePath);\n if (out.length === 0) return [];\n return out\n .split(\"\\n\")\n .filter((l) => l.startsWith(\"U \"))\n .map((l) => l.slice(2));\n } catch {\n return [];\n }\n}\n\nconst slCommitSummaryTemplate =\n \"{node}\\\\0{desc|firstline}\\\\0{desc}\\\\0{date|isodatesec}\\\\0{author|user}\\\\x1e\";\n\nasync function slCommitId(workspacePath: string): Promise<string> {\n return run(\"sl\", [\"log\", \"-r\", \".\", \"--template\", \"{node}\"], workspacePath);\n}\n\nasync function slIsDirty(workspacePath: string): Promise<boolean> {\n // sl status prints one line per changed file; empty stdout = clean.\n const out = await run(\"sl\", [\"status\"], workspacePath);\n return out.length > 0;\n}\n","// mu — VCS backend dispatcher.\n\nimport { gitBackend } from \"./git.js\";\nimport { jjBackend } from \"./jj.js\";\nimport { noneBackend } from \"./none.js\";\nimport { slBackend } from \"./sl.js\";\nimport type { ProbeReport, VcsBackend, VcsBackendName } from \"./types.js\";\n\nexport { gitBackend } from \"./git.js\";\nexport { jjBackend } from \"./jj.js\";\nexport { noneBackend } from \"./none.js\";\nexport { slBackend } from \"./sl.js\";\nexport {\n type CommitSummary,\n type CreateWorkspaceOptions,\n type CreateWorkspaceResult,\n type FreeWorkspaceOptions,\n type FreeWorkspaceResult,\n type ProbeReport,\n type RebaseResult,\n SHOW_COMMIT_MAX_CHARS,\n type ShowCommitResult,\n type VcsBackend,\n type VcsBackendName,\n WorkspaceConflictError,\n WorkspaceDirtyError,\n WorkspaceVcsRequiredError,\n} from \"./types.js\";\n\n/**\n * Detection precedence: jj > sl > git > none. The first backend whose\n * detect() returns true wins. `none` is always last. Detection shells\n * out to each VCS's canonical root probe (`jj root`, `sl root`, `git\n * rev-parse --show-toplevel`) so worktrees and gitdir-pointer files are\n * handled by the owning tool instead of a brittle marker-dir heuristic.\n */\nconst BACKENDS: readonly VcsBackend[] = [jjBackend, slBackend, gitBackend, noneBackend];\n\n/** Return the backend that should handle projectRoot. Walks BACKENDS\n * in precedence order; never returns undefined because noneBackend\n * always claims. */\nexport async function detectBackend(\n projectRoot: string,\n report?: ProbeReport,\n): Promise<VcsBackend> {\n for (const backend of BACKENDS) {\n if (await backend.detect(projectRoot, report)) return backend;\n }\n return noneBackend;\n}\n\n/** Look up a backend by name. Throws on unknown name. Used by\n * `mu agent spawn --workspace-backend ...` to honour an explicit\n * override. */\nexport function backendByName(name: VcsBackendName): VcsBackend {\n for (const backend of BACKENDS) {\n if (backend.name === name) return backend;\n }\n throw new Error(`unknown vcs backend: ${name}`);\n}\n","// mu — workspace staleness and dirty decorators.\n\nimport type { Db } from \"../db.js\";\nimport { isWorkspaceStale } from \"../staleness.js\";\nimport { backendByName } from \"../vcs.js\";\nimport type { WorkspaceRow, WorkspaceStaleness } from \"./core.js\";\nimport { getWorkspaceForAgent } from \"./crud.js\";\n\nconst DECORATE_CONCURRENCY = 4;\n\nexport async function getWorkspaceStaleness(\n db: Db,\n agentName: string,\n workstreamName: string,\n): Promise<WorkspaceStaleness | null> {\n const row = getWorkspaceForAgent(db, agentName, workstreamName);\n if (row === undefined) return null;\n const [decorated] = await decorateWithStaleness([row]);\n const commitsBehindMain = decorated?.commitsBehindMain ?? null;\n return {\n agentName,\n workstreamName,\n commitsBehindMain,\n isStale: isWorkspaceStale(commitsBehindMain),\n };\n}\n\n/**\n * Decorate each row with `commitsBehindMain` by asking the row's backend\n * how far the parent_ref is behind the project's default branch HEAD.\n * Cheap, pure observation: NO automatic `git fetch` / `jj git fetch` /\n * `sl pull`. The number is as fresh as the workspace's local refs cache.\n *\n * Returns a NEW array; does not mutate the input. Rows whose parent_ref\n * is missing, or whose backend's commitsBehind throws / returns null,\n * get `commitsBehindMain: null`.\n */\nexport async function decorateWithStaleness(\n rows: readonly WorkspaceRow[],\n): Promise<WorkspaceRow[]> {\n const cache = new Map<string, Promise<number | null>>();\n const mainRefCache = new Map<string, Promise<string | undefined>>();\n const fetchBehind = (r: WorkspaceRow): Promise<number | null> => {\n const parentRef = r.parentRef;\n if (parentRef === null) return Promise.resolve(null);\n const key = `${r.backend}\\x00${parentRef}`;\n const cached = cache.get(key);\n if (cached !== undefined) return cached;\n const p = (async (): Promise<number | null> => {\n try {\n const backend = backendByName(r.backend);\n return await backend.commitsBehind(r.path, parentRef, mainRefCache);\n } catch {\n return null;\n }\n })();\n cache.set(key, p);\n return p;\n };\n return mapWithConcurrency(rows, DECORATE_CONCURRENCY, async (r) => ({\n ...r,\n commitsBehindMain: await fetchBehind(r),\n }));\n}\n\n/**\n * Decorate every row with a `dirty` marker — true when the backend's\n * `listDirtyFiles` reports any uncommitted / unstaged / untracked-not-\n * ignored files; false when clean; null on backend-command failure.\n *\n * Returns a NEW array; does not mutate the input.\n */\nexport async function decorateWithDirty(rows: readonly WorkspaceRow[]): Promise<WorkspaceRow[]> {\n return mapWithConcurrency(rows, DECORATE_CONCURRENCY, async (r) => {\n let dirty: boolean | null;\n try {\n const backend = backendByName(r.backend);\n const files = await backend.listDirtyFiles(r.path);\n dirty = files.length > 0;\n } catch {\n dirty = null;\n }\n return { ...r, dirty };\n });\n}\n\n/**\n * Tiny p-limit-style helper. Keeps at most `limit` callbacks in flight\n * at once and preserves input order in the result. Stays in this file\n * because it has exactly two local decorator callers; promote out only\n * when a second cluster needs it.\n */\nasync function mapWithConcurrency<T, R>(\n items: readonly T[],\n limit: number,\n fn: (item: T, index: number) => Promise<R>,\n): Promise<R[]> {\n const results = new Array<R>(items.length);\n let next = 0;\n const worker = async (): Promise<void> => {\n while (true) {\n const i = next++;\n if (i >= items.length) return;\n const item = items[i] as T;\n results[i] = await fn(item, i);\n }\n };\n const workerCount = Math.min(Math.max(1, limit), items.length);\n await Promise.all(Array.from({ length: workerCount }, () => worker()));\n return results;\n}\n","// mu — workspace orphan directory detection.\n\nimport { readdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { type Db, defaultStateDir, tryResolveWorkstreamId } from \"../db.js\";\nimport { workspacesRoot } from \"./core.js\";\nimport { listWorkspaces } from \"./crud.js\";\n\nexport interface WorkspaceOrphan {\n /** The on-disk dir name (the agent name it WOULD be for, if mu had\n * registered it). */\n agentName: string;\n /** Workstream the dir is filed under. */\n workstreamName: string;\n /** Absolute path to the orphan dir. */\n path: string;\n}\n\n/**\n * Like WorkspaceOrphan but additionally flags whether the parent\n * workstream itself is gone (no row in `workstreams`). Returned by\n * listAllOrphanWorkspaces; the per-workstream listWorkspaceOrphans\n * doesn't carry this since by construction it only runs against an\n * existing workstream.\n */\nexport interface StrandedWorkspaceOrphan extends WorkspaceOrphan {\n /** True iff the parent workstream has no DB row (the dir was left\n * behind by a `mu workstream teardown` or a manual DELETE). */\n stranded: boolean;\n}\n\n/**\n * Scan `<state-dir>/workspaces/<workstream>/` for directories that\n * have no row in `vcs_workspaces`.\n *\n * Returns `[]` when the workstream's workspaces dir doesn't exist,\n * or when every dir on disk has a corresponding DB row. Filesystem\n * read is best-effort: a missing/inaccessible dir returns `[]`.\n */\nexport function listWorkspaceOrphans(db: Db, workstream: string): WorkspaceOrphan[] {\n const root = workspacesRoot(workstream);\n let dirs: string[];\n try {\n dirs = readdirSync(root, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => d.name);\n } catch {\n return [];\n }\n const registered = new Set(listWorkspaces(db, workstream).map((w) => w.path));\n const orphans: WorkspaceOrphan[] = [];\n for (const agentDir of dirs) {\n const fullPath = join(root, agentDir);\n if (!registered.has(fullPath)) {\n orphans.push({ agentName: agentDir, workstreamName: workstream, path: fullPath });\n }\n }\n return orphans;\n}\n\n/**\n * Cross-workstream variant of listWorkspaceOrphans. Reads\n * `<state-dir>/workspaces/`, recurses one level (per-ws subdir →\n * per-agent subdir), and surfaces every dir with no row in\n * `vcs_workspaces`.\n */\nexport function listAllOrphanWorkspaces(db: Db): StrandedWorkspaceOrphan[] {\n const root = join(defaultStateDir(), \"workspaces\");\n let wsDirs: string[];\n try {\n wsDirs = readdirSync(root, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => d.name);\n } catch {\n return [];\n }\n const registered = new Set(listWorkspaces(db).map((w) => w.path));\n const orphans: StrandedWorkspaceOrphan[] = [];\n for (const wsName of wsDirs) {\n const wsRoot = join(root, wsName);\n let agentDirs: string[];\n try {\n agentDirs = readdirSync(wsRoot, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => d.name);\n } catch {\n continue;\n }\n const stranded = tryResolveWorkstreamId(db, wsName) === null;\n for (const agentDir of agentDirs) {\n const fullPath = join(wsRoot, agentDir);\n if (!registered.has(fullPath)) {\n orphans.push({\n agentName: agentDir,\n workstreamName: wsName,\n path: fullPath,\n stranded,\n });\n }\n }\n }\n return orphans;\n}\n","// mu — task graph shared row-shape helpers.\n//\n// This module owns the snake_case → camelCase task/note mappings and\n// surrogate-id resolution helpers consumed by the task SDK cluster.\n// It stays below the public hub (`src/tasks.ts`): cluster files import\n// from this file or sibling files, never from the hub they're re-exported\n// through.\n\nimport { type Db, tryResolveWorkstreamId } from \"../db.js\";\nimport type { TaskStatus, TaskSubstate } from \"./status.js\";\n\nexport interface TaskRow {\n /** Per-workstream-unique TEXT name. The operator-facing identifier. */\n name: string;\n /** Foreign-name reference to the owning workstream. */\n workstreamName: string;\n title: string;\n status: TaskStatus;\n /** Qualifies status (e.g. OPEN/parked, CLOSED/wontfix). Never null. */\n substate: TaskSubstate;\n impact: number;\n effortDays: number;\n /** Foreign-name reference to the owning agent (NULL when unowned). */\n ownerName: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface TaskNoteRow {\n author: string | null;\n content: string;\n createdAt: string;\n}\n\nexport interface RawTaskRow {\n /** Surrogate id (v5). */\n id: number;\n local_id: string;\n /** Joined from workstreams.name. */\n workstream: string;\n title: string;\n status: string;\n substate: string;\n impact: number;\n effort_days: number;\n /** Joined from agents.name via owner_id. NULL when unowned. */\n owner: string | null;\n created_at: string;\n updated_at: string;\n}\n\nexport interface RawTaskNoteRow {\n author: string | null;\n content: string;\n created_at: string;\n}\n\n// SELECT clause for v5 task reads. Joins workstreams + agents to expose\n// the operator-facing names as `workstream` and `owner`. Used by every\n// read path so callers don't see surrogate ids.\nexport const SELECT_TASK_COLS = `\n t.id AS id,\n t.local_id AS local_id,\n ws.name AS workstream,\n t.title AS title,\n t.status AS status,\n t.substate AS substate,\n t.impact AS impact,\n t.effort_days AS effort_days,\n ag.name AS owner,\n t.created_at AS created_at,\n t.updated_at AS updated_at\n`;\n\nexport const TASK_FROM_JOIN = `\n FROM tasks t\n JOIN workstreams ws ON ws.id = t.workstream_id\n LEFT JOIN agents ag ON ag.id = t.owner_id\n`;\n\nexport const SELECT_NOTE_COLS = `\n n.author AS author,\n n.content AS content,\n n.created_at AS created_at\n`;\n\nexport function rowFromDb(row: RawTaskRow): TaskRow {\n return {\n name: row.local_id,\n workstreamName: row.workstream,\n title: row.title,\n status: row.status as TaskStatus,\n substate: row.substate as TaskSubstate,\n impact: row.impact,\n effortDays: row.effort_days,\n ownerName: row.owner,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n };\n}\n\nexport function noteFromDb(row: RawTaskNoteRow): TaskNoteRow {\n return {\n author: row.author,\n content: row.content,\n createdAt: row.created_at,\n };\n}\n\n/** Look up a task by local_id across every workstream. Task ids are\n * unique per workstream only, so a row in `preferWorkstream` wins;\n * otherwise the first match sorted by workstream name (deterministic).\n * Used by edge verbs (addBlockEdge / reparentTask) to resolve a\n * blocker so a cross-workstream blocker can surface\n * `CrossWorkstreamEdgeError` rather than the less-actionable\n * `TaskNotFoundError`. NOT for operator-facing reads — use\n * `getTask(db, localId, workstream)` for those. */\nexport function lookupTaskAnyWorkstream(\n db: Db,\n localId: string,\n preferWorkstream?: string,\n): TaskRow | undefined {\n const row = db\n .prepare(\n `SELECT ${SELECT_TASK_COLS} ${TASK_FROM_JOIN} WHERE t.local_id = ?\n ORDER BY (ws.name = ?) DESC, ws.name LIMIT 1`,\n )\n .get(localId, preferWorkstream ?? null) as RawTaskRow | undefined;\n return row ? rowFromDb(row) : undefined;\n}\n\n/** Resolve a (workstream, localId) pair to the surrogate task id.\n * Returns null on miss. */\nexport function taskIdFor(db: Db, localId: string, workstream: string): number | null {\n const wsId = tryResolveWorkstreamId(db, workstream);\n if (wsId === null) return null;\n const row = db\n .prepare(\"SELECT id FROM tasks WHERE workstream_id = ? AND local_id = ?\")\n .get(wsId, localId) as { id: number } | undefined;\n return row ? row.id : null;\n}\n\n/**\n * Bump `tasks.updated_at` on a surrogate task id. Used by every write\n * that mutates a child row (notes, edges) without touching the task\n * row itself, so `mu task list --sort recency` reflects 'last write of\n * any kind' rather than only 'last status/field change'\n * (task_updatedat_not_bumped_by_reparent). Status changes, field\n * updates, and claim/release already update `updated_at` directly in\n * their own UPDATE statements; don't double-bump from here.\n *\n * Always called inside the same transaction as the child-row mutation\n * so the bump rolls back together with the mutation on error.\n */\nexport function touchTask(db: Db, taskId: number, now?: string): void {\n db.prepare(\"UPDATE tasks SET updated_at = ? WHERE id = ?\").run(\n now ?? new Date().toISOString(),\n taskId,\n );\n}\n","// mu — task read/query primitives.\n\nimport type { Db } from \"../db.js\";\nimport { tryResolveWorkstreamId } from \"../db.js\";\nimport { lastClaimEventAt } from \"../logs.js\";\nimport {\n noteFromDb,\n type RawTaskNoteRow,\n type RawTaskRow,\n rowFromDb,\n SELECT_NOTE_COLS,\n SELECT_TASK_COLS,\n TASK_FROM_JOIN,\n type TaskNoteRow,\n type TaskRow,\n taskIdFor,\n} from \"./core.js\";\nimport type { TaskStatus, TaskSubstate } from \"./status.js\";\n\nexport function getTask(db: Db, localId: string, workstream: string): TaskRow | undefined {\n const wsId = tryResolveWorkstreamId(db, workstream);\n if (wsId === null) return undefined;\n const row = db\n .prepare(\n `SELECT ${SELECT_TASK_COLS} ${TASK_FROM_JOIN} WHERE t.workstream_id = ? AND t.local_id = ?`,\n )\n .get(wsId, localId) as RawTaskRow | undefined;\n return row ? rowFromDb(row) : undefined;\n}\n\n/**\n * The task's owner as (name, workstream), resolved through\n * `tasks.owner_id`. The owner's workstream can differ from the task's:\n * `task claim --for <ws>/<agent>` assigns an owner from another\n * workstream, and `TaskRow.ownerName` alone cannot say which.\n * Undefined when the task does not exist or has no owner.\n */\nexport function getTaskOwner(\n db: Db,\n localId: string,\n workstream: string,\n): { name: string; workstreamName: string } | undefined {\n return db\n .prepare(\n `SELECT a.name AS name, aws.name AS workstreamName\n FROM tasks t\n JOIN workstreams tws ON tws.id = t.workstream_id\n JOIN agents a ON a.id = t.owner_id\n JOIN workstreams aws ON aws.id = a.workstream_id\n WHERE t.local_id = ? AND tws.name = ?`,\n )\n .get(localId, workstream) as { name: string; workstreamName: string } | undefined;\n}\n\n/**\n * List tasks. With no `workstream` arg returns every row — used by `mu sql`\n * and by tests; CLI surfaces always pass a workstream so users only see\n * their own.\n */\nexport interface ListTasksOptions {\n /** Filter to one or more lifecycle statuses. Omitted = all statuses. */\n status?: TaskStatus | readonly TaskStatus[];\n /** Filter to one or more substates (ANDed with `status`). */\n substate?: TaskSubstate | readonly TaskSubstate[];\n}\n\n/** Normalise a one-or-many filter option to an array (undefined = no filter). */\nfunction asList<T extends string>(v: T | readonly T[] | undefined): readonly T[] | undefined {\n if (v === undefined) return undefined;\n return typeof v === \"string\" ? [v] : (v as readonly T[]);\n}\n\nexport function listTasks(db: Db, workstream?: string, opts: ListTasksOptions = {}): TaskRow[] {\n const statuses =\n opts.status === undefined\n ? undefined\n : Array.isArray(opts.status)\n ? (opts.status as TaskStatus[])\n : [opts.status as TaskStatus];\n\n const where: string[] = [];\n const params: unknown[] = [];\n if (workstream !== undefined) {\n const wsId = tryResolveWorkstreamId(db, workstream);\n if (wsId === null) return [];\n where.push(\"t.workstream_id = ?\");\n params.push(wsId);\n }\n if (statuses !== undefined) {\n where.push(`t.status IN (${statuses.map(() => \"?\").join(\", \")})`);\n params.push(...statuses);\n }\n const substates = asList(opts.substate);\n if (substates !== undefined && substates.length > 0) {\n where.push(`t.substate IN (${substates.map(() => \"?\").join(\", \")})`);\n params.push(...substates);\n }\n const sql =\n where.length === 0\n ? `SELECT ${SELECT_TASK_COLS} ${TASK_FROM_JOIN} ORDER BY t.local_id`\n : `SELECT ${SELECT_TASK_COLS} ${TASK_FROM_JOIN} WHERE ${where.join(\" AND \")} ORDER BY t.local_id`;\n const rows = db.prepare(sql).all(...params) as RawTaskRow[];\n return rows.map(rowFromDb);\n}\n\n// The three views (ready, blocked, goals) project tasks.* directly,\n// so they expose v5 columns (id, workstream_id, owner_id). We wrap\n// them with the same JOINs as TASK_FROM_JOIN to translate back to the\n// operator-facing TaskRow shape (workstream + owner as TEXT names).\nconst VIEW_FROM_JOIN = (view: string) => `\n FROM ${view} v\n JOIN workstreams ws ON ws.id = v.workstream_id\n LEFT JOIN agents ag ON ag.id = v.owner_id\n`;\nconst SELECT_VIEW_COLS = `\n v.id AS id,\n v.local_id AS local_id,\n ws.name AS workstream,\n v.title AS title,\n v.status AS status,\n v.substate AS substate,\n v.impact AS impact,\n v.effort_days AS effort_days,\n ag.name AS owner,\n v.created_at AS created_at,\n v.updated_at AS updated_at\n`;\n\n/** Options for listReady. The optional `statuses` filter composes\n * on top of the `ready` view (which itself constrains to\n * `status='OPEN'`); passing only OPEN is identical to today's no-\n * filter shape, passing only non-OPEN values returns []. Exists so\n * `mu task next --status` can mirror the multi-status flag shape\n * shipped on `mu task list` (task_list_multi_status_union). */\nexport interface ListReadyOptions {\n status?: TaskStatus | readonly TaskStatus[];\n /** Substate filter; the `ready` view already excludes OPEN/parked. */\n substate?: TaskSubstate | readonly TaskSubstate[];\n}\n\nexport function listReady(db: Db, workstream: string, opts: ListReadyOptions = {}): TaskRow[] {\n const wsId = tryResolveWorkstreamId(db, workstream);\n if (wsId === null) return [];\n const statuses =\n opts.status === undefined\n ? undefined\n : Array.isArray(opts.status)\n ? (opts.status as TaskStatus[])\n : [opts.status as TaskStatus];\n const where: string[] = [\"v.workstream_id = ?\"];\n const params: unknown[] = [wsId];\n if (statuses !== undefined && statuses.length > 0) {\n where.push(`v.status IN (${statuses.map(() => \"?\").join(\", \")})`);\n params.push(...statuses);\n }\n const substates = asList(opts.substate);\n if (substates !== undefined && substates.length > 0) {\n where.push(`v.substate IN (${substates.map(() => \"?\").join(\", \")})`);\n params.push(...substates);\n }\n const rows = db\n .prepare(\n `SELECT ${SELECT_VIEW_COLS} ${VIEW_FROM_JOIN(\"ready\")} WHERE ${where.join(\" AND \")} ORDER BY v.local_id`,\n )\n .all(...params) as RawTaskRow[];\n return rows.map(rowFromDb);\n}\n\nexport function listBlocked(db: Db, workstream: string): TaskRow[] {\n const wsId = tryResolveWorkstreamId(db, workstream);\n if (wsId === null) return [];\n const rows = db\n .prepare(\n `SELECT ${SELECT_VIEW_COLS} ${VIEW_FROM_JOIN(\"blocked\")} WHERE v.workstream_id = ? ORDER BY v.local_id`,\n )\n .all(wsId) as RawTaskRow[];\n return rows.map(rowFromDb);\n}\n\nexport function listGoals(db: Db, workstream: string): TaskRow[] {\n const wsId = tryResolveWorkstreamId(db, workstream);\n if (wsId === null) return [];\n const rows = db\n .prepare(\n `SELECT ${SELECT_VIEW_COLS} ${VIEW_FROM_JOIN(\"goals\")} WHERE v.workstream_id = ? ORDER BY v.local_id`,\n )\n .all(wsId) as RawTaskRow[];\n return rows.map(rowFromDb);\n}\n\n/** All IN_PROGRESS tasks in a workstream, most-recently-touched first.\n * Used by `mu state` to populate its in-progress slice; exposed as a\n * named SDK helper so CLI renderers don't re-derive the row-shape\n * conversion (review_code_raw_task_state_duplicate). */\nexport function listInProgress(db: Db, workstream: string): TaskRow[] {\n const wsId = tryResolveWorkstreamId(db, workstream);\n if (wsId === null) return [];\n const rows = db\n .prepare(\n `SELECT ${SELECT_TASK_COLS} ${TASK_FROM_JOIN} WHERE t.workstream_id = ? AND t.status = 'IN_PROGRESS' ORDER BY t.updated_at DESC`,\n )\n .all(wsId) as RawTaskRow[];\n return rows.map(rowFromDb);\n}\n\n/** CLOSED tasks in a workstream, most recently updated first, capped at\n * `limit` (default 5). `updated_at` is a proxy for close time: there is\n * no `closed_at` column, and a later note or edge change on a CLOSED\n * task bumps `updated_at` (touchTask), moving it up. Used by `mu state`\n * for its 'recent closed'\n * slice; exposed as a named SDK helper so the CLI no longer needs the\n * raw-row type that was duplicating RawTaskRow\n * (review_code_raw_task_state_duplicate). */\nexport function listRecentClosed(db: Db, workstream: string, limit = 5): TaskRow[] {\n const wsId = tryResolveWorkstreamId(db, workstream);\n if (wsId === null) return [];\n const rows = db\n .prepare(\n `SELECT ${SELECT_TASK_COLS} ${TASK_FROM_JOIN} WHERE t.workstream_id = ? AND t.status = 'CLOSED' ORDER BY t.updated_at DESC LIMIT ?`,\n )\n .all(wsId, limit) as RawTaskRow[];\n return rows.map(rowFromDb);\n}\n\n/** Optional filter knobs for `listNotes`. Default-everything-undefined\n * preserves the historical \"return every note, oldest-first\" shape so\n * every existing caller (cmdTaskShow's notes block, agents.test.ts)\n * keeps working unchanged.\n *\n * Filters compose multiplicatively when both apply (`since` AND\n * `tail`): the timestamp filter is applied first, then `tail` slices\n * the last N of what survived. The CLI surface (`mu task notes\n * --tail / --since / --since-claim`) lives in src/cli/tasks/edit.ts;\n * the mutex between `--since` and `--since-claim` is a CLI concern,\n * not enforced here — if both arrive at the SDK, `since` wins (it's\n * the explicit one) and `sinceClaim` is ignored. The auto-resolve\n * for `sinceClaim` (look up the most recent `task claim` event in\n * agent_logs) happens here so the SDK is self-contained for scripted\n * callers. */\nexport interface ListNotesOptions {\n /** Print only the last N notes (after any timestamp filter). Must\n * be a positive integer; a value of 0 returns no rows but is not\n * an error here — CLI-side validation rejects `--tail 0`. */\n tail?: number;\n /** ISO-8601 cutoff: only notes with `created_at > since` survive.\n * Any `Date.parse`-able value; it is normalised to `toISOString()`\n * form (the stored shape) before the text comparison, so offsets\n * and second-precision cutoffs compare as instants. */\n since?: string;\n /** When true and `since` is unset, look up the `created_at` of the\n * most recent `task claim` event for this task and use it as the\n * cutoff. Falls back to no filter when no claim event exists\n * (equivalent to `--since-beginning`). */\n sinceClaim?: boolean;\n}\n\n/** List notes for a task. Operator-facing local_id; resolves to the\n * surrogate task id via taskIdFor (with optional workstream scope).\n *\n * Optional filters: see {@link ListNotesOptions}. Default behaviour\n * (no opts) is unchanged — every note, oldest-first. */\nexport function listNotes(\n db: Db,\n taskLocalId: string,\n workstream: string,\n opts: ListNotesOptions = {},\n): TaskNoteRow[] {\n const taskId = taskIdFor(db, taskLocalId, workstream);\n if (taskId === null) return [];\n // Resolve the cutoff once: explicit `since` wins; otherwise\n // `sinceClaim` resolves via lastClaimEventAt (null → no filter).\n // created_at is always `toISOString()` (UTC, millis, `Z`) and the\n // filter compares text, so normalise `since` to that same shape: a\n // raw `10:07:00Z` sorts after `10:07:00.411Z` ('Z' > '.') and an\n // offset like `+02:00` compares as local time. An unparseable value\n // passes through unchanged (the CLI rejects it before here).\n let cutoff: string | undefined = opts.since;\n if (cutoff !== undefined) {\n const ms = Date.parse(cutoff);\n if (!Number.isNaN(ms)) cutoff = new Date(ms).toISOString();\n }\n if (cutoff === undefined && opts.sinceClaim === true) {\n const at = lastClaimEventAt(db, workstream, taskLocalId);\n if (at !== null) cutoff = at;\n }\n const rows =\n cutoff !== undefined\n ? (db\n .prepare(\n `SELECT ${SELECT_NOTE_COLS} FROM task_notes n JOIN tasks t ON t.id = n.task_id\n WHERE n.task_id = ? AND n.created_at > ? ORDER BY n.id`,\n )\n .all(taskId, cutoff) as RawTaskNoteRow[])\n : (db\n .prepare(\n `SELECT ${SELECT_NOTE_COLS} FROM task_notes n JOIN tasks t ON t.id = n.task_id\n WHERE n.task_id = ? ORDER BY n.id`,\n )\n .all(taskId) as RawTaskNoteRow[]);\n const mapped = rows.map(noteFromDb);\n if (opts.tail !== undefined && opts.tail >= 0) {\n return opts.tail === 0 ? [] : mapped.slice(-opts.tail);\n }\n return mapped;\n}\n\n/**\n * All tasks currently owned by `agent` in a given workstream\n * (v5: agents.name is per-workstream unique). Sorted by local_id.\n *\n * Defaults to **excluding CLOSED** since the verb's purpose is \"what\n * is X currently working on?\" and a closed task is no longer being\n * worked on. closeTask intentionally preserves `owner` as a\n * historical record (so audit/notes can attribute decisions); pass\n * `{ includeClosed: true }` to surface that history.\n */\nexport function listTasksByOwner(\n db: Db,\n workstream: string,\n owner: string,\n opts: { includeClosed?: boolean } = {},\n): TaskRow[] {\n // 'Live work' = not CLOSED. includeClosed re-includes CLOSED tasks\n // so historical attribution is recoverable.\n // Filter on the joined ag.name so the operator-facing owner string\n // still drives the lookup; FK is now via owner_id.\n const filter = opts.includeClosed ? \"\" : \"AND t.status <> 'CLOSED'\";\n const wsId = tryResolveWorkstreamId(db, workstream);\n if (wsId === null) return [];\n const sql = `SELECT ${SELECT_TASK_COLS} ${TASK_FROM_JOIN}\n WHERE ag.name = ? AND t.workstream_id = ? ${filter}\n ORDER BY t.local_id`;\n return (db.prepare(sql).all(owner, wsId) as RawTaskRow[]).map(rowFromDb);\n}\n\n/**\n * Cross-workstream variant of `listTasksByOwner`. Returns tasks owned\n * by ANY agent of the given name across every workstream. Used by\n * `mu task owned-by --all` for the genuine cross-workstream view\n * (audit / dashboards). The bare name is the join key, so two\n * distinct same-named agents in different workstreams contribute\n * their tasks to the same result list.\n */\nexport function listTasksByOwnerCrossWorkstream(\n db: Db,\n owner: string,\n opts: { includeClosed?: boolean } = {},\n): TaskRow[] {\n const filter = opts.includeClosed ? \"\" : \"AND t.status <> 'CLOSED'\";\n const sql = `SELECT ${SELECT_TASK_COLS} ${TASK_FROM_JOIN}\n WHERE ag.name = ? ${filter}\n ORDER BY ws.name, t.local_id`;\n return (db.prepare(sql).all(owner) as RawTaskRow[]).map(rowFromDb);\n}\n","// mu — task id validation and title slug helpers.\n\nimport type { Db } from \"../db.js\";\nimport type { HasNextSteps, NextStep } from \"../output.js\";\nimport { getTask } from \"./queries.js\";\n\n/** Thrown when a title has no ASCII letter or digit, so no id can be\n * derived from it (any non-ASCII script, or pure punctuation). Exit 2\n * (usage) with the verb's --help; the fix is the `<id>` positional.\n * Lives here, not in errors.ts, because errors.ts imports this file. */\nexport class TaskTitleSlugEmptyError extends Error implements HasNextSteps {\n override readonly name = \"TaskTitleSlugEmptyError\";\n constructor(public readonly title: string) {\n super(\n `title yields empty slug: ${JSON.stringify(title)} (no ASCII letter or digit to derive an id from)`,\n );\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Pass the id explicitly as the positional\",\n command: 'mu task add <id> --title \"...\" --impact <n> --effort-days <n>',\n },\n ];\n }\n}\n\n/** Lowercase alpha first, then alnum / underscore / hyphen, ≤64 chars. */\nconst TASK_ID_RE = /^[a-z][a-z0-9_-]{0,63}$/;\n\nexport function isValidTaskId(id: string): boolean {\n return TASK_ID_RE.test(id);\n}\n\n/**\n * Derive a task id from a free-form title.\n *\n * \"Build the auth module\" → \"build_the_auth_module\"\n * \"FILES: foo.ts (refactor)\" → \"files_foo_ts_refactor\"\n */\n\n/**\n * Soft cap for auto-generated slugs. The collision-suffix loop in\n * idFromTitle can push past this (`_2`, `_3`, ...) without going past\n * the hard ceiling. 40 chars hits the sweet spot of 'short enough to\n * type and to look reasonable in mu task tree' without losing too\n * much of the title's meaning.\n */\nconst SLUG_SOFT_CAP = 40;\n\n/**\n * Hard ceiling for any generated id. Schema has no length limit, but\n * 64 keeps ids comfortable in tables, JSON, and tmux pane titles.\n */\nconst SLUG_HARD_CAP = 64;\n\n/**\n * Lowercase title; collapse non-alnum runs into single `_`; trim\n * leading/trailing `_`; prefix `t_` if the result starts with a digit\n * (schema requires first char letter); apply the soft cap with\n * word-boundary trim (cut at the last `_` at-or-before SLUG_SOFT_CAP\n * when one exists, else hard-truncate). Mirrors `tg`'s `id_from_title`\n * but adds the soft cap.\n *\n * Throws `TaskTitleSlugEmptyError` if `title` yields an empty slug.\n */\nexport function slugifyTitle(title: string): string {\n return slugifyTitleVerbose(title).slug;\n}\n\n/**\n * Result of `slugifyTitleVerbose`: the slug plus enough metadata for\n * the CLI to decide whether to warn the user that meaning was lost.\n *\n * slug — the same string `slugifyTitle` returns.\n * strippedLength — length of the post-strip pre-cap slug. When this\n * exceeds the SLUG_SOFT_CAP the verbose form had to\n * cut at a word boundary (or hard-truncate); the\n * cut clauses are gone with no in-band signal.\n * originalSlug — what the slug WOULD have been without the\n * SLUG_SOFT_CAP cut: full stripped slug with the\n * same `t_` digit-prefix correction and the same\n * SLUG_HARD_CAP ceiling, but no word-boundary\n * truncation. Equal to `slug` when nothing was\n * cut. The CLI surfaces this in `mu task add\n * --json` so scripted callers can detect the\n * truncation without grepping stderr.\n * truncated — true iff `slug.length < strippedLength` AFTER the\n * `t_` digit-prefix correction, i.e. real bytes were\n * dropped. False for any title that fits under the\n * soft cap or whose only diff vs the stripped slug\n * is the `t_` prefix.\n *\n * The CLI's `mu task add` uses `truncated` to print a one-line stderr\n * hint pointing at the `<id>` positional override and (under --json)\n * to surface `originalSlug` alongside `truncated:true`\n * (slugifytitle_silently_drops_clauses; task_add_slugify_silently_truncates_ids).\n */\nexport interface SlugifyResult {\n slug: string;\n strippedLength: number;\n originalSlug: string;\n truncated: boolean;\n}\n\n/**\n * Verbose sibling of `slugifyTitle`: returns the slug AND a\n * `truncated` flag so the CLI can hint to the user when the soft cap\n * dropped clauses (the meaning-shift hazard documented in\n * slugifytitle_silently_drops_clauses).\n *\n * Algorithm is byte-for-byte identical to `slugifyTitle`; this just\n * surfaces the metadata that the plain form throws away.\n */\nexport function slugifyTitleVerbose(title: string): SlugifyResult {\n const stripped = title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\");\n if (stripped.length === 0) {\n throw new TaskTitleSlugEmptyError(title);\n }\n // Soft cap with word-boundary preference: if the slug exceeds the\n // soft cap, look for the last `_` at-or-before the cap and cut there\n // (so we never break a word). If no underscore is in the cap window\n // (ie the title is one giant word), fall back to a hard truncate at\n // the soft cap. The result is always <= SLUG_SOFT_CAP after this.\n let trimmed: string;\n if (stripped.length <= SLUG_SOFT_CAP) {\n trimmed = stripped;\n } else {\n // lastIndexOf's fromIndex is inclusive, so an `_` AT index\n // SLUG_SOFT_CAP (a word ending exactly at the cap) is found too.\n const lastSep = stripped.lastIndexOf(\"_\", SLUG_SOFT_CAP);\n trimmed = lastSep > 0 ? stripped.slice(0, lastSep) : stripped.slice(0, SLUG_SOFT_CAP);\n }\n // First char must be a letter → prefix `t_` if it isn't. v5 has no\n // global namespace and no reserved prefix; `mu_foo` is a perfectly\n // valid local_id (per-workstream unique).\n const applyPrefix = (s: string): string =>\n /^[a-z]/.test(s) ? s.slice(0, SLUG_HARD_CAP) : `t_${s}`.slice(0, SLUG_HARD_CAP);\n const slug = applyPrefix(trimmed);\n // `originalSlug` is what the slug would have been without the\n // soft-cap word-boundary cut: same prefix correction, same hard\n // cap, no word-boundary trim. Used by `mu task add --json` so\n // scripted callers can detect truncation programmatically.\n const originalSlug = applyPrefix(stripped);\n // `truncated` reflects whether real characters were dropped — the\n // `t_` prefix doesn't count as truncation. We compare the trimmed\n // length against the stripped length (both pre-prefix) so a digit-\n // led title that fit under the cap still reports truncated=false.\n return {\n slug,\n strippedLength: stripped.length,\n originalSlug,\n truncated: trimmed.length < stripped.length,\n };\n}\n\n/**\n * Generate a unique task id from a title. v5: tasks.local_id is\n * per-workstream unique, so the collision check scopes to one\n * workstream. On collision, appends `_2`, `_3`, … until unique.\n */\nexport function idFromTitle(db: Db, workstream: string, title: string): string {\n return idFromTitleVerbose(db, workstream, title).id;\n}\n\n/**\n * Result of `idFromTitleVerbose`: the unique-in-workstream id plus the\n * truncated flag from the underlying slugify pass. Used by `mu task\n * add` to decide whether to surface the stderr hint about lost clauses\n * (slugifytitle_silently_drops_clauses) and to surface the un-truncated\n * slug in `--json` (task_add_slugify_silently_truncates_ids).\n *\n * id — the unique-in-workstream task id.\n * truncated — true iff the underlying slugify pass cut real\n * characters (collision-suffixing does NOT flip\n * this).\n * originalSlug — what the slug would have been without the\n * SLUG_SOFT_CAP cut. Equal to `id` when nothing was\n * cut AND no collision suffix was appended; for\n * the truncation-detection use case the only thing\n * the CLI cares about is the lossy-vs-not\n * comparison surfaced via `truncated`.\n */\nexport interface IdFromTitleResult {\n id: string;\n truncated: boolean;\n originalSlug: string;\n}\n\n/**\n * Verbose sibling of `idFromTitle`: returns the unique id, the\n * `truncated` flag from the slugify pass, and the un-truncated\n * `originalSlug` for `--json` consumers. Collision-suffixing (`_2`,\n * `_3`, …) does not flip `truncated` — the underlying slug's lossiness\n * is what the CLI hint cares about.\n */\nexport function idFromTitleVerbose(db: Db, workstream: string, title: string): IdFromTitleResult {\n const { slug: base, truncated, originalSlug } = slugifyTitleVerbose(title);\n if (getTask(db, base, workstream) === undefined) return { id: base, truncated, originalSlug };\n for (let i = 2; i < 1000; i++) {\n const candidate = `${base}_${i}`.slice(0, SLUG_HARD_CAP);\n if (getTask(db, candidate, workstream) === undefined)\n return { id: candidate, truncated, originalSlug };\n }\n throw new Error(`could not derive a unique id from title in workstream ${workstream}: ${title}`);\n}\n\n/**\n * Sanitise a free-form string into a candidate task id.\n *\n * Lowercases, replaces every non-`[a-z0-9_-]` char with `_`, trims any\n * leading non-letter (the schema requires the first char to be a\n * letter), truncates to 64 chars. Returns `\"task\"` when the input has\n * no usable letters at all so the suggestion in\n * `TaskIdInvalidError.errorNextSteps()` is always a runnable command.\n *\n * Mirrors `slugifyTitle`'s prefix corrections so suggested ids will\n * pass `isValidTaskId` if the user runs them verbatim. Lives next to\n * `slugifyTitle` rather than in `tasks/errors.ts` because it's a slug\n * helper, not an error helper — the only caller happens to be\n * `TaskIdInvalidError.errorNextSteps()`.\n */\nexport function sanitiseTaskId(input: string): string {\n const s = input\n .toLowerCase()\n .replace(/[^a-z0-9_-]/g, \"_\")\n .replace(/^[^a-z]+/, \"\")\n .slice(0, SLUG_HARD_CAP);\n return s.length === 0 ? \"task\" : s;\n}\n","// mu — task error classes.\n//\n// Every task verb that can fail in a typed way has its own error class\n// here. The CLI's `classifyError()` (src/cli.ts) maps them to exit codes:\n// not found → 3 (TaskNotFoundError)\n// conflict → 4 (TaskExistsError, TaskNotInWorkstreamError,\n// TaskAlreadyOwnedError, ClaimerNotRegisteredError,\n// CrossWorkstreamEdgeError,\n// SubstateReasonRequiredError, TaskParkStateError,\n// TaskParkedError, TaskInTriageError,\n// InvalidSubstateError)\n// cycle → 4 (CycleError — also a conflict)\n// usage → 2 (TaskIdInvalidError; TaskTitleSlugEmptyError in id.ts)\n//\n// Each error implements HasNextSteps so the CLI can render a per-error\n// `Next:` block with the most useful follow-up commands.\n//\n// Extracted from src/tasks.ts as part of refactor_split_large_src_files.\n\nimport type { HasNextSteps, NextStep } from \"../output.js\";\nimport { WORKSPACE_STALE_THRESHOLD, type WorkspaceStaleness } from \"../workspace.js\";\nimport { sanitiseTaskId } from \"./id.js\";\nimport { TASK_SUBSTATES, type TaskStatus, type TaskSubstate } from \"./status.js\";\n\nexport class TaskNotFoundError extends Error implements HasNextSteps {\n override readonly name = \"TaskNotFoundError\";\n constructor(public readonly taskId: string) {\n super(`no such task: ${taskId}`);\n }\n errorNextSteps(): NextStep[] {\n // v5: tasks.workstream (TEXT) was replaced by tasks.workstream_id\n // (FK → workstreams.id). The pre-v5 recipe SELECTed a column that\n // no longer exists and crashed at runtime — and this is THE first\n // hint a user sees on a missed-task lookup, so the breakage was\n // high-traffic. Mirror the join pattern used by AgentExistsError.\n const idLit = this.taskId.replace(/'/g, \"''\").toLowerCase();\n const recipe = `mu sql \"SELECT ws.name AS workstream, t.local_id, t.status, t.title FROM tasks t JOIN workstreams ws ON ws.id = t.workstream_id WHERE LOWER(t.local_id) LIKE '%${idLit}%' OR LOWER(t.title) LIKE '%${idLit}%'\"`;\n return [\n { intent: \"List tasks in workstream\", command: \"mu task list -w <workstream>\" },\n { intent: \"Search every workstream by substring (id + title)\", command: recipe },\n ];\n }\n}\n\n/**\n * Thrown by `addTask` when `localId` violates the schema regex\n * `/^[a-z][a-z0-9_-]{0,63}$/`. Replaces a bare `TypeError` so the\n * CLI's `handle()` wrapper can map it to exit code 2 (usage, with the\n * verb's --help, like WorkstreamNameInvalidError) and surface a `--json` `nextSteps` block pointing at\n * the auto-derived-id workflow and a sanitised candidate.\n */\nexport class TaskIdInvalidError extends Error implements HasNextSteps {\n override readonly name = \"TaskIdInvalidError\";\n constructor(public readonly attempted: string) {\n super(`invalid task id: ${JSON.stringify(attempted)} (expected /^[a-z][a-z0-9_-]{0,63}$/)`);\n }\n errorNextSteps(): NextStep[] {\n const sanitised = sanitiseTaskId(this.attempted);\n return [\n {\n intent: \"Use the auto-derived id (drop the <id> positional; --title derives it)\",\n command: 'mu task add --title \"...\" --impact <n> --effort-days <n>',\n },\n {\n intent: \"Sanitise to a valid id\",\n command: `mu task add ${sanitised} --title \"...\" --impact <n> --effort-days <n>`,\n },\n ];\n }\n}\n\nexport class TaskExistsError extends Error implements HasNextSteps {\n override readonly name = \"TaskExistsError\";\n constructor(public readonly taskId: string) {\n super(`task already exists: ${taskId}`);\n }\n errorNextSteps(): NextStep[] {\n return [\n { intent: \"Show the existing task\", command: `mu task show ${this.taskId}` },\n {\n intent: \"Update fields on the existing task\",\n command: `mu task update ${this.taskId} --title \"...\" --impact <n> --effort-days <n>`,\n },\n {\n intent: \"Pick a different id\",\n command: 'mu task add <new-id> --title \"...\" --impact <n> --effort-days <n>',\n },\n ];\n }\n}\n\n/**\n * Thrown when a verb is invoked with `-w/--workstream <name>` but the\n * named task lives in a different workstream. Distinguishes \"the user\n * typo'd the workstream\" from \"the task doesn't exist anywhere\"\n * (which surfaces as `TaskNotFoundError`). Maps to exit code 4\n * (conflict / wrong scope).\n */\nexport class TaskNotInWorkstreamError extends Error implements HasNextSteps {\n override readonly name = \"TaskNotInWorkstreamError\";\n constructor(\n public readonly taskId: string,\n public readonly expectedWorkstream: string,\n public readonly actualWorkstream: string,\n ) {\n super(`task ${taskId} is in workstream ${actualWorkstream}, not ${expectedWorkstream}`);\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Use the correct workstream\",\n command: `mu task show ${this.taskId} -w ${this.actualWorkstream}`,\n },\n {\n intent: \"List tasks in the requested workstream\",\n command: `mu task list -w ${this.expectedWorkstream}`,\n },\n ];\n }\n}\n\nexport class TaskAlreadyOwnedError extends Error implements HasNextSteps {\n override readonly name = \"TaskAlreadyOwnedError\";\n constructor(\n public readonly taskId: string,\n public readonly currentOwner: string,\n ) {\n super(`task ${taskId} is already owned by ${currentOwner}`);\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"See the current owner's task list\",\n command: `mu task owned-by ${this.currentOwner}`,\n },\n {\n intent: \"Release the current claim (if you ARE the owner)\",\n command: `mu task release ${this.taskId}`,\n },\n { intent: \"Show full task state\", command: `mu task show ${this.taskId}` },\n ];\n }\n}\n\n/**\n * Thrown when `mu task claim` resolves a claimer agent name (from the\n * pane title or --for) that has no matching row in the agents table.\n *\n * The FK on `tasks.owner_id` references `agents.id`; without this guard\n * the claim attempt would fail with the unhelpful 'FOREIGN KEY constraint\n * failed' from SQLite. This typed error gives the user actionable next\n * steps (run `mu agent adopt <pane-id>` to register, or use --for to pick a\n * different agent).\n *\n * Maps to exit code 4 (conflict) via the cli.ts handler.\n */\nexport class ClaimerNotRegisteredError extends Error implements HasNextSteps {\n override readonly name = \"ClaimerNotRegisteredError\";\n constructor(\n public readonly agentName: string,\n public readonly paneId: string | null,\n ) {\n const paneHint = paneId !== null ? ` (pane ${paneId})` : \"\";\n super(\n `claimer '${agentName}'${paneHint} is not a registered mu agent (no row in agents table)`,\n );\n }\n\n /**\n * Three actionable resolutions in expected-frequency order:\n * 1. --self : orchestrator pattern (working directly)\n * 2. --for : dispatcher pattern (assigning to a worker)\n * 3. mu agent adopt: registration pattern (promote pane to worker)\n */\n errorNextSteps(): NextStep[] {\n const steps: NextStep[] = [\n { intent: \"Work directly (anonymous)\", command: \"mu task claim <id> --self\" },\n { intent: \"Dispatch to a worker\", command: \"mu task claim <id> --for <worker>\" },\n ];\n steps.push(\n this.paneId !== null\n ? { intent: \"Register this pane\", command: `mu agent adopt ${this.paneId}` }\n : {\n intent: \"Register a pane\",\n command: \"mu agent adopt <pane-id> (must be in mu-<workstream> tmux session)\",\n },\n );\n return steps;\n }\n}\n\nexport class TaskClaimStaleWorkspaceError extends Error implements HasNextSteps {\n override readonly name = \"TaskClaimStaleWorkspaceError\";\n constructor(public readonly staleness: WorkspaceStaleness) {\n super(\n `${staleness.agentName} workspace is ${staleness.commitsBehindMain} commits behind main (≥${WORKSPACE_STALE_THRESHOLD} = stale); refresh before dispatch or rerun without --strict-staleness`,\n );\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Refresh first\",\n command: `mu workspace refresh ${this.staleness.agentName} -w ${this.staleness.workstreamName}`,\n },\n ];\n }\n}\n\nexport class CycleError extends Error implements HasNextSteps {\n override readonly name = \"CycleError\";\n constructor(\n public readonly from: string,\n public readonly to: string,\n /** Existing path `to -> … -> from` (task names) that the new edge would close. */\n public readonly path: readonly string[] = [],\n public readonly workstream?: string,\n ) {\n super(\n path.length > 1\n ? `adding edge ${from} -> ${to} would create a cycle: ${[from, ...path].join(\" -> \")}`\n : `adding edge ${from} -> ${to} would create a cycle`,\n );\n }\n errorNextSteps(): NextStep[] {\n const a = this.path[0];\n const b = this.path[1];\n const ws = this.workstream ? ` -w ${this.workstream}` : \"\";\n const concrete: NextStep[] =\n a !== undefined && b !== undefined\n ? [\n {\n intent: `Break the cycle by removing existing edge ${a} -> ${b}`,\n command: `mu task unblock ${b} --by ${a}${ws}`,\n },\n ]\n : [];\n return [\n ...concrete,\n {\n intent: \"Show the dependency tree\",\n command: `mu task tree ${this.to} --down`,\n },\n {\n intent: \"Show the prereq tree (what blocks the from-task)\",\n command: `mu task tree ${this.from}`,\n },\n {\n intent: \"Remove an edge in the path to break the cycle\",\n command: \"mu task unblock <blocked> --by <blocker>\",\n },\n ];\n }\n}\n\n/**\n * Thrown by the `mu task wait` CLI wrapper when the per-poll\n * reconciler detects that a watched task transitioned\n * `IN_PROGRESS → OPEN` between polls (the reaper saw the owner's\n * pane was gone and flipped the task back). With `--status CLOSED`\n * (the default) the wait can never satisfy by progress — the worker\n * is dead — so we abort fast instead of running out the operator's\n * `--timeout`.\n *\n * Maps to exit code 6 (REAPER_DETECTED) via the cli.ts handler. The\n * suppression rule (only fire when target=CLOSED) lives in the\n * caller; this error type is a pure data carrier.\n *\n * Surfaced live by task_wait_reconcile_dead_panes (twice in one\n * v0.3 dispatch wave: tmux restart killed worker panes; `mu task\n * wait --timeout 1800` blocked silently for 25 min instead of\n * failing in seconds).\n */\nexport class ReaperDetectedDuringWaitError extends Error implements HasNextSteps {\n override readonly name = \"ReaperDetectedDuringWaitError\";\n constructor(\n public readonly taskId: string,\n public readonly previousOwner: string | null,\n public readonly workstream: string,\n ) {\n const ownerBit = previousOwner !== null ? `owner=${previousOwner}` : \"owner=<unknown>\";\n super(\n `task ${taskId} was IN_PROGRESS ${ownerBit} until just now; reaper detected dead pane and flipped to OPEN. wait abandoned. Re-dispatch a worker and retry.`,\n );\n }\n errorNextSteps(): NextStep[] {\n const ws = this.workstream;\n return [\n {\n intent: \"Inspect the task's current state\",\n command: `mu task show ${this.taskId} -w ${ws}`,\n },\n {\n intent: \"List live agents in the workstream (post-reap)\",\n command: `mu agent list -w ${ws}`,\n },\n {\n intent: \"Re-dispatch a fresh worker, then re-run the wait\",\n command: `mu agent spawn <name> -w ${ws} && mu task claim ${this.taskId} --for <name> -w ${ws}`,\n },\n ];\n }\n}\n\n/**\n * Thrown by the `mu task wait` CLI wrapper when `--on-stall exit` is\n * in effect and the existing `--stuck-after` predicate fires on a\n * watched task — the task is IN_PROGRESS, owned by a registered\n * agent whose detected status is `needs_input` for `>= stuckAfterMs`.\n *\n * Pairs with `ReaperDetectedDuringWaitError` (exit 6, dead pane).\n * Stall is the AMBIGUOUS sibling: the worker is alive but not\n * progressing — the operator decides whether it's transient (poke +\n * retry) or terminal (release + reopen). Exit code 7 = STALL_DETECTED\n * via classifyError, distinct from 6 so consumer scripts can branch.\n *\n * Carve-out (lives at the call site, not here): only fires when the\n * wait target is CLOSED — same logic as exit-6's reaper-flip\n * suppression. With `--status OPEN`/etc the worker reaching\n * needs_input might BE the success path.\n *\n * Surfaced by task_wait_stall_action_flag (the warn-only behaviour\n * pre-dates this; the typed-throw path is the new escape hatch for\n * unattended orchestrators).\n */\n/**\n * A stalled pi owner's last answer, read exactly: `--after-runs <runs-1>`\n * returns the last settled run's lastText at once. Empty unless the\n * owner's socket reported at least one settled run. The pane read stays\n * next to it: dialogs and crashes show in the pane, not the session.\n */\nexport function stallWaitHint(owner: string, ws: string, runs: number | undefined): NextStep[] {\n if (runs === undefined || runs < 1) return [];\n return [\n {\n intent: \"Read the worker's last answer (its final text, at once)\",\n command: `mu agent wait ${owner} --after-runs ${runs - 1} --json -w ${ws}`,\n },\n ];\n}\n\nexport class StallDetectedDuringWaitError extends Error implements HasNextSteps {\n override readonly name = \"StallDetectedDuringWaitError\";\n constructor(\n public readonly taskName: string,\n public readonly owner: string | null,\n public readonly workstream: string,\n public readonly ageSecs: number,\n /** The owner runs pi (control socket): `mu agent abort` stops its turn. */\n public readonly ownerExpectsCtl = false,\n /** The owner's ctl run count at the stall, when its socket answered. */\n public readonly ownerRuns?: number,\n /** The owner's workstream when it differs from the task's\n * (`task claim --for <ws>/<agent>`). Agent commands use it. */\n public readonly ownerWorkstream: string = workstream,\n ) {\n const ownerBit = owner !== null ? owner : \"<unknown>\";\n super(\n `task ${taskName} owned by ${ownerBit} has been needs_input for ${ageSecs}s; exiting per --on-stall exit. Read the pane to see which it is — finished without closing, waiting on an answer, or sitting at a prompt.`,\n );\n }\n /**\n * Diagnose before acting. `mu agent read` comes FIRST because the\n * predicate that threw cannot tell the three causes of needs_input\n * apart, and the evidence is in the pane rather than the task row.\n * The earlier order led with \"poke the worker\", which is the right\n * move for only one of the three and actively wrong for a worker\n * waiting on an answer — a poke with no answer in it just restates\n * the question.\n */\n errorNextSteps(): NextStep[] {\n const ws = this.workstream;\n const ownerWs = this.ownerWorkstream;\n const ownerBit = this.owner !== null ? this.owner : \"<owner>\";\n return [\n ...stallWaitHint(ownerBit, ownerWs, this.ownerRuns),\n {\n intent: \"Read the worker's pane to see what it is waiting on\",\n command: `mu agent read ${ownerBit} -w ${ownerWs} --lines 60`,\n },\n {\n intent: \"Answer a question, or poke a worker that stalled mid-step\",\n command: `mu agent send ${ownerBit} '<answer-or-retry-instruction>' -w ${ownerWs}`,\n },\n ...(this.ownerExpectsCtl\n ? [\n {\n intent: \"Stuck mid-turn? Stop it through the control socket before kick or close\",\n command: `mu agent abort ${ownerBit} -w ${ownerWs}`,\n },\n ]\n : []),\n {\n intent: \"Close the task if the worker finished but skipped it\",\n command: `mu task close ${this.taskName} -w ${ws}`,\n },\n {\n intent: \"Release the task back to OPEN (declare the stall terminal)\",\n command: `mu task release ${this.taskName} --reopen -w ${ws}`,\n },\n ];\n }\n}\n\nexport class CrossWorkstreamEdgeError extends Error implements HasNextSteps {\n override readonly name = \"CrossWorkstreamEdgeError\";\n constructor(\n public readonly blocker: string,\n public readonly blockerWorkstream: string,\n public readonly dependent: string,\n public readonly dependentWorkstream: string,\n ) {\n super(\n `cross-workstream edge: blocker '${blocker}' is in workstream '${blockerWorkstream}', dependent '${dependent}' is in workstream '${dependentWorkstream}'`,\n );\n }\n errorNextSteps(): NextStep[] {\n // No \"move the blocker\" recipe. A task's workstream is part of its\n // natural key (`<ws>/<local_id>`), which every op is filed under, so\n // a raw `UPDATE tasks SET workstream_id=...` re-keys the row with no\n // op for either key: sync, undo and `mu doctor` then disagree with\n // the table. The capture layer refuses that UPDATE (src/capture.ts\n // KEY_COLUMNS). The \"rename one workstream to the other\" hint went\n // earlier for the same reason, and because it moved every task.\n return [\n {\n intent: \"Duplicate the blocker into the dependent's workstream\",\n command: `mu task add <new-id> -w ${this.dependentWorkstream} --title \"<copy of ${this.blocker}>\" --impact <n> --effort-days <n>`,\n },\n {\n intent: \"Or wait on the blocker across workstreams instead of an edge\",\n command: `mu task wait ${this.blockerWorkstream}/${this.blocker}`,\n },\n ];\n }\n}\n\n/**\n * Thrown by `closeTask` (non-`done` `--as`) and `parkTask` when no\n * non-empty `--why` was given. The reason is stored as a note, so a\n * classification with no rationale is refused before any write.\n */\nexport class SubstateReasonRequiredError extends Error implements HasNextSteps {\n override readonly name = \"SubstateReasonRequiredError\";\n constructor(\n public readonly verb: \"close\" | \"park\",\n public readonly substate: TaskSubstate,\n public readonly taskId: string,\n ) {\n super(\n verb === \"close\"\n ? `closing ${taskId} as ${substate} needs a reason (--why \"...\")`\n : `parking ${taskId} needs a reason (--why \"...\")`,\n );\n }\n errorNextSteps(): NextStep[] {\n const cmd =\n this.verb === \"close\"\n ? `mu task close ${this.taskId} --as ${this.substate} --why \"<reason>\"`\n : `mu task park ${this.taskId} --why \"<reason>\"`;\n return [{ intent: \"Retry with a reason\", command: cmd }];\n }\n}\n\n/**\n * Thrown by `parkTask` on an IN_PROGRESS or CLOSED task. Park is one\n * transition (OPEN/todo → OPEN/parked); the owner releases, or the task\n * is reopened, first.\n */\nexport class TaskParkStateError extends Error implements HasNextSteps {\n override readonly name = \"TaskParkStateError\";\n constructor(\n public readonly taskId: string,\n public readonly status: \"IN_PROGRESS\" | \"CLOSED\",\n public readonly workstream: string,\n ) {\n super(\n status === \"IN_PROGRESS\"\n ? `cannot park ${taskId}: it is IN_PROGRESS (release it first)`\n : `cannot park ${taskId}: it is CLOSED (open it first)`,\n );\n }\n errorNextSteps(): NextStep[] {\n const ws = this.workstream;\n const first: NextStep =\n this.status === \"IN_PROGRESS\"\n ? { intent: \"Release the claim first\", command: `mu task release ${this.taskId} -w ${ws}` }\n : { intent: \"Reopen the task first\", command: `mu task open ${this.taskId} -w ${ws}` };\n return [\n first,\n {\n intent: \"Then park it\",\n command: `mu task park ${this.taskId} --why \"<reason>\" -w ${ws}`,\n },\n ];\n }\n}\n\n/**\n * Thrown by `claimTask` on an OPEN/triage task without `force`. A triage\n * task is a proposal (often a review finding) nobody has accepted as\n * work yet; accept it, or close it rejected / duplicate.\n */\nexport class TaskInTriageError extends Error implements HasNextSteps {\n override readonly name = \"TaskInTriageError\";\n constructor(\n public readonly taskId: string,\n public readonly workstream: string,\n ) {\n super(`task ${taskId} is in triage (OPEN/triage); accept it or claim with --force`);\n }\n errorNextSteps(): NextStep[] {\n const ws = this.workstream;\n return [\n {\n intent: \"Accept it as work, then claim\",\n command: `mu task accept ${this.taskId} -w ${ws}`,\n },\n {\n intent: \"Decline it\",\n command: `mu task close ${this.taskId} --as rejected --why \"<reason>\" -w ${ws}`,\n },\n { intent: \"Claim it anyway\", command: `mu task claim ${this.taskId} --force -w ${ws}` },\n ];\n }\n}\n\n/**\n * Thrown by `claimTask` on an OPEN/parked task without `force`. Parked\n * means \"keep out of the scheduler\"; claiming it anyway is explicit.\n */\nexport class TaskParkedError extends Error implements HasNextSteps {\n override readonly name = \"TaskParkedError\";\n constructor(\n public readonly taskId: string,\n public readonly workstream: string,\n ) {\n super(`task ${taskId} is parked (OPEN/parked); unpark it or claim with --force`);\n }\n errorNextSteps(): NextStep[] {\n const ws = this.workstream;\n return [\n { intent: \"Unpark it, then claim\", command: `mu task unpark ${this.taskId} -w ${ws}` },\n { intent: \"Claim it anyway\", command: `mu task claim ${this.taskId} --force -w ${ws}` },\n ];\n }\n}\n\n/**\n * Thrown when a verb is asked for a (status, substate) pair that the\n * task_substates table does not allow, e.g. `close --as parked`.\n * Caught here rather than by the deferred FK, which would fail only at\n * commit with an opaque constraint message.\n */\nexport class InvalidSubstateError extends Error implements HasNextSteps {\n override readonly name = \"InvalidSubstateError\";\n constructor(\n public readonly status: TaskStatus,\n public readonly substate: string,\n ) {\n super(\n `invalid substate for ${status}: ${JSON.stringify(substate)} (expected one of: ${TASK_SUBSTATES[status].join(\", \")})`,\n );\n }\n errorNextSteps(): NextStep[] {\n return TASK_SUBSTATES[this.status].map((s) => ({\n intent: `Use ${this.status}/${s}`,\n command:\n this.status === \"CLOSED\" ? `mu task close <id> --as ${s}` : `mu task list --substate ${s}`,\n }));\n }\n}\n","// mu — task edge reads and mutations.\n\nimport type { Db } from \"../db.js\";\nimport { withOpContext } from \"../op-context.js\";\nimport { lookupTaskAnyWorkstream, taskIdFor, touchTask } from \"./core.js\";\nimport { CrossWorkstreamEdgeError, CycleError, TaskNotFoundError } from \"./errors.js\";\nimport { getTask } from \"./queries.js\";\nimport type { TaskStatus, TaskSubstate } from \"./status.js\";\n\nexport interface TaskEdges {\n /** Tasks that must close before this one can start (blockers). */\n blockers: string[];\n /** Tasks that this one blocks (dependents). */\n dependents: string[];\n}\n\nexport interface CanonicalBlocker {\n localId: string;\n id: number;\n}\n\nexport function dedupeBlockersById(blockers: readonly CanonicalBlocker[]): CanonicalBlocker[] {\n const seen = new Set<number>();\n const canonical: CanonicalBlocker[] = [];\n for (const blocker of blockers) {\n if (seen.has(blocker.id)) continue;\n seen.add(blocker.id);\n canonical.push(blocker);\n }\n return canonical;\n}\n\nfunction sameNumberSet(left: readonly number[], right: readonly number[]): boolean {\n if (left.length !== right.length) return false;\n const rightSet = new Set(right);\n if (rightSet.size !== right.length) return false;\n return left.every((value) => rightSet.has(value));\n}\n\n/** One end of an edge with the neighbour's current status attached.\n * Used by `mu task show` to group blockers/dependents into\n * \"still gating\" vs \"satisfied\" buckets without making the renderer\n * do a second round-trip to the DB per neighbour. */\nexport interface TaskEdgeWithStatus {\n name: string;\n status: TaskStatus;\n substate: TaskSubstate;\n}\n\nexport interface TaskEdgesWithStatus {\n /** Tasks that must close before this one can start (blockers),\n * carrying each blocker's current status. */\n blockers: TaskEdgeWithStatus[];\n /** Tasks that this one blocks (dependents), carrying each\n * dependent's current status. */\n dependents: TaskEdgeWithStatus[];\n}\n\n/**\n * Direct (one-hop) edges for a task. For transitive prerequisites, use\n * `getPrerequisites()`; this helper is the immediate-neighbour view used\n * by `mu task show`.\n */\nexport function getTaskEdges(db: Db, taskLocalId: string, workstream: string): TaskEdges {\n const taskId = taskIdFor(db, taskLocalId, workstream);\n if (taskId === null) return { blockers: [], dependents: [] };\n const blockers = (\n db\n .prepare(\n `SELECT t.local_id AS id FROM task_edges e\n JOIN tasks t ON t.id = e.from_task_id\n WHERE e.to_task_id = ? ORDER BY t.local_id`,\n )\n .all(taskId) as { id: string }[]\n ).map((r) => r.id);\n const dependents = (\n db\n .prepare(\n `SELECT t.local_id AS id FROM task_edges e\n JOIN tasks t ON t.id = e.to_task_id\n WHERE e.from_task_id = ? ORDER BY t.local_id`,\n )\n .all(taskId) as { id: string }[]\n ).map((r) => r.id);\n return { blockers, dependents };\n}\n\n/**\n * Same one-hop edge view as `getTaskEdges`, but each neighbour is\n * returned as `{ name, status }` so callers can group / colour by\n * status without an N+1 round-trip. Used by `mu task show` to split\n * \"blocked by\" (still-gating) from \"satisfied\" (already-CLOSED)\n * blockers, and the symmetric split on the dependents side\n * (task_show_blocked_by_renders_closed). OPEN and IN_PROGRESS stay in\n * the still-gating bucket; CLOSED is satisfied.\n */\nexport function getTaskEdgesWithStatus(\n db: Db,\n taskLocalId: string,\n workstream: string,\n): TaskEdgesWithStatus {\n const taskId = taskIdFor(db, taskLocalId, workstream);\n if (taskId === null) return { blockers: [], dependents: [] };\n const blockers = db\n .prepare(\n `SELECT t.local_id AS name, t.status AS status, t.substate AS substate FROM task_edges e\n JOIN tasks t ON t.id = e.from_task_id\n WHERE e.to_task_id = ? ORDER BY t.local_id`,\n )\n .all(taskId) as TaskEdgeWithStatus[];\n const dependents = db\n .prepare(\n `SELECT t.local_id AS name, t.status AS status, t.substate AS substate FROM task_edges e\n JOIN tasks t ON t.id = e.to_task_id\n WHERE e.from_task_id = ? ORDER BY t.local_id`,\n )\n .all(taskId) as TaskEdgeWithStatus[];\n return { blockers, dependents };\n}\n\n/**\n * All tasks transitively reachable from `taskId` via reverse-edge\n * traversal (i.e. the set of tasks that block this one), including the\n * task itself.\n */\nexport function getPrerequisites(db: Db, taskLocalId: string, workstream: string): Set<string> {\n const taskId = taskIdFor(db, taskLocalId, workstream);\n if (taskId === null) return new Set([taskLocalId]);\n // Walk reverse edges in surrogate-id space, then translate back to\n // local_id strings. The seed must be the surrogate id; the result\n // includes the seed task itself (callers like the tracks union-find\n // rely on the inclusive set).\n const rows = db\n .prepare(\n `WITH RECURSIVE reach(node) AS (\n SELECT ?\n UNION\n SELECT from_task_id FROM task_edges, reach WHERE to_task_id = reach.node\n )\n SELECT t.local_id AS local_id FROM reach r JOIN tasks t ON t.id = r.node`,\n )\n .all(taskId) as { local_id: string }[];\n return new Set(rows.map((r) => r.local_id));\n}\n\n/**\n * Adding edge `from -> to` creates a cycle iff there's already a path\n * `to -> ... -> from`. SQL recursive CTE expresses this exactly.\n */\nexport function wouldCreateCycle(db: Db, fromId: number, toId: number): boolean {\n if (fromId === toId) return true;\n const result = db\n .prepare(\n `WITH RECURSIVE forward(node) AS (\n SELECT ?\n UNION\n SELECT to_task_id FROM task_edges, forward WHERE from_task_id = forward.node\n )\n SELECT 1 AS hit FROM forward WHERE node = ? LIMIT 1`,\n )\n .get(toId, fromId) as { hit: number } | undefined;\n return result !== undefined;\n}\n\n/**\n * Shortest existing path `toId -> … -> fromId` (task local ids, both ends\n * included), i.e. what adding edge `fromId -> toId` would close into a\n * cycle. Null when there is none. Tracks visited nodes per path, so it\n * terminates even on cycles already present (e.g. created by sync).\n */\nexport function findCyclePath(db: Db, fromId: number, toId: number): string[] | null {\n if (fromId === toId) {\n const t = db.prepare(\"SELECT local_id FROM tasks WHERE id = ?\").get(fromId) as\n | { local_id: string }\n | undefined;\n return t ? [t.local_id] : null;\n }\n // BFS with parent pointers: linear in edges, shortest by construction,\n // and terminates on cycles already present (each node is visited once).\n // A per-path recursive CTE is exponential on wide DAGs.\n const next = db.prepare(\"SELECT to_task_id AS id FROM task_edges WHERE from_task_id = ?\");\n const parent = new Map<number, number>([[toId, toId]]);\n let frontier = [toId];\n while (frontier.length > 0 && !parent.has(fromId)) {\n const nextFrontier: number[] = [];\n for (const node of frontier) {\n for (const { id } of next.all(node) as { id: number }[]) {\n if (parent.has(id)) continue;\n parent.set(id, node);\n nextFrontier.push(id);\n }\n }\n frontier = nextFrontier;\n }\n if (!parent.has(fromId)) return null;\n const ids: number[] = [];\n for (let n = fromId; ; ) {\n ids.unshift(n);\n if (n === toId) break;\n const p = parent.get(n);\n if (p === undefined) return null;\n n = p;\n }\n const name = db.prepare(\"SELECT local_id FROM tasks WHERE id = ?\");\n return ids.map(\n (id) => (name.get(id) as { local_id: string } | undefined)?.local_id ?? String(id),\n );\n}\n\n/** Build a CycleError for edge `blocker -> blocked`, with the closing path. */\nexport function cycleErrorFor(\n db: Db,\n blocker: string,\n blocked: string,\n blockerId: number,\n blockedId: number,\n workstream?: string,\n): CycleError {\n return new CycleError(\n blocker,\n blocked,\n findCyclePath(db, blockerId, blockedId) ?? [],\n workstream,\n );\n}\n\nexport interface BlockEdgeResult {\n /** True iff a row was actually inserted (vs. already present). */\n added: boolean;\n}\n\n/**\n * Add the edge `blocker → blocked` ('blocker blocks blocked').\n * Idempotent (existing edge → `added: false`). Validates:\n *\n * - both tasks exist\n * - same workstream (cross-workstream edges forbidden)\n * - no cycle (the new edge wouldn't form a path blocked → ... → blocker)\n * - blocker ≠ blocked (no self-reference)\n */\nexport function addBlockEdge(\n db: Db,\n workstream: string,\n blocked: string,\n blocker: string,\n): BlockEdgeResult {\n return withOpContext(db, { intent: \"task.block\", group: \"new\" }, () =>\n addBlockEdgeImpl(db, workstream, blocked, blocker),\n );\n}\n\nfunction addBlockEdgeImpl(\n db: Db,\n workstream: string,\n blocked: string,\n blocker: string,\n): BlockEdgeResult {\n if (blocked === blocker) {\n // Surface as a typed CycleError so the CLI maps it to exit 4 (conflict)\n // rather than letting the schema CHECK fire as a generic SQL error.\n throw new CycleError(blocker, blocked);\n }\n const blockedRow = getTask(db, blocked, workstream);\n if (!blockedRow) throw new TaskNotFoundError(blocked);\n // Resolve the blocker in the dependent's workstream first, then\n // globally so a cross-workstream blocker surfaces\n // CrossWorkstreamEdgeError (clearer than TaskNotFoundError). Cycle\n // check + same-workstream guard run after.\n const blockerRow = lookupTaskAnyWorkstream(db, blocker, blockedRow.workstreamName);\n if (!blockerRow) throw new TaskNotFoundError(blocker);\n if (blockedRow.workstreamName !== blockerRow.workstreamName) {\n throw new CrossWorkstreamEdgeError(\n blocker,\n blockerRow.workstreamName,\n blocked,\n blockedRow.workstreamName,\n );\n }\n const blockedId = taskIdFor(db, blocked, blockedRow.workstreamName);\n const blockerId = taskIdFor(db, blocker, blockerRow.workstreamName);\n if (blockedId === null || blockerId === null) throw new TaskNotFoundError(blocked);\n if (wouldCreateCycle(db, blockerId, blockedId)) {\n throw cycleErrorFor(db, blocker, blocked, blockerId, blockedId, blockedRow.workstreamName);\n }\n const now = new Date().toISOString();\n const added = db\n .transaction(() => {\n const result = db\n .prepare(\n \"INSERT OR IGNORE INTO task_edges (from_task_id, to_task_id, created_at) VALUES (?, ?, ?)\",\n )\n .run(blockerId, blockedId, now);\n if (result.changes > 0) {\n // Bump the BLOCKED task — its blocker set changed. The blocker\n // itself is unaffected. Aligned with reparentTask, which also\n // bumps the FROM_TASK side (the task whose blockers shifted).\n touchTask(db, blockedId, now);\n return true;\n }\n return false;\n })\n .immediate();\n // No emitEvent: the task_edges INSERT fired the capture trigger\n // (intent='task.block', key='<ws>/<blocker>-><ws>/<blocked>').\n return { added };\n}\n\nexport interface RemoveBlockEdgeResult {\n /** True iff a row was actually deleted (vs. no such edge). */\n removed: boolean;\n}\n\n/**\n * Remove the edge `blocker → blocked`. Idempotent (no edge →\n * `removed: false`). Does NOT validate task existence — if the\n * edge is gone there's nothing to do, regardless of whether the\n * tasks are gone too.\n */\nexport function removeBlockEdge(\n db: Db,\n workstream: string,\n blocked: string,\n blocker: string,\n): RemoveBlockEdgeResult {\n return withOpContext(db, { intent: \"task.unblock\", group: \"new\" }, () =>\n removeBlockEdgeImpl(db, workstream, blocked, blocker),\n );\n}\n\nfunction removeBlockEdgeImpl(\n db: Db,\n workstream: string,\n blocked: string,\n blocker: string,\n): RemoveBlockEdgeResult {\n const blockedRow = getTask(db, blocked, workstream);\n if (!blockedRow) return { removed: false };\n const blockerRow = getTask(db, blocker, workstream);\n if (!blockerRow) return { removed: false };\n const blockedId = taskIdFor(db, blocked, blockedRow.workstreamName);\n const blockerId = taskIdFor(db, blocker, blockerRow.workstreamName);\n if (blockedId === null || blockerId === null) return { removed: false };\n const removed = db\n .transaction(() => {\n const result = db\n .prepare(\"DELETE FROM task_edges WHERE from_task_id = ? AND to_task_id = ?\")\n .run(blockerId, blockedId);\n if (result.changes > 0) {\n // Bump the BLOCKED task — its blocker set just shrank.\n touchTask(db, blockedId);\n return true;\n }\n return false;\n })\n .immediate();\n if (removed) {\n // No emitEvent: the DELETE fired the capture trigger, writing an\n // edge tombstone with intent='task.unblock'.\n }\n return { removed };\n}\n\nexport interface ReparentTaskResult {\n /** Edges removed (i.e. all incoming `to_task = taskId` edges). */\n removedEdges: number;\n /** Edges added (after duplicate blockers are canonicalised). */\n addedEdges: number;\n}\n\n/**\n * Atomically replace every incoming edge of `taskId` with new ones\n * `blocker[i] → taskId`. Pass an empty `blockers` array to clear all\n * incoming edges (the task becomes ready iff its status allows).\n *\n * Validates ALL new blockers up-front (existence + same workstream +\n * cycle check); if any fails, no DELETE happens — the call is fully\n * atomic via a single transaction.\n *\n * Cycle reasoning: removing the existing incoming edges to `taskId`\n * doesn't change `taskId`'s OUTGOING reachability, so\n * `wouldCreateCycle(db, blocker, taskId)` evaluated against the\n * pre-state gives the right answer for each new edge.\n */\nexport function reparentTask(\n db: Db,\n taskLocalId: string,\n blockers: readonly string[],\n scope: { workstream: string },\n): ReparentTaskResult {\n // One group for the whole reparent: it DELETEs the old blocker edges\n // and INSERTs the new ones, which is one operator action and must\n // undo as one.\n return withOpContext(db, { intent: \"task.reparent\", group: \"new\" }, () =>\n reparentTaskImpl(db, taskLocalId, blockers, scope),\n );\n}\n\nfunction reparentTaskImpl(\n db: Db,\n taskLocalId: string,\n blockers: readonly string[],\n scope: { workstream: string },\n): ReparentTaskResult {\n const task = getTask(db, taskLocalId, scope.workstream);\n if (!task) throw new TaskNotFoundError(taskLocalId);\n const taskSurrogateId = taskIdFor(db, task.name, task.workstreamName);\n if (taskSurrogateId === null) throw new TaskNotFoundError(taskLocalId);\n\n // Resolve every blocker up-front to its surrogate id; do all\n // existence + same-workstream + cycle checks before any DELETE.\n // Look up blockers in the task's workstream first, then across all\n // workstreams so a blocker that exists only in a DIFFERENT workstream surfaces CrossWorkstreamEdgeError (clearer\n // than TaskNotFoundError). Duplicate blockers are an ergonomic input\n // accident from repeat/CSV forms, so silently canonicalise by\n // surrogate id while preserving first-seen order.\n const requestedBlockers: CanonicalBlocker[] = [];\n for (const blockerLocalId of blockers) {\n if (blockerLocalId === taskLocalId) {\n throw new CycleError(blockerLocalId, taskLocalId);\n }\n const blocker = lookupTaskAnyWorkstream(db, blockerLocalId, task.workstreamName);\n if (!blocker) throw new TaskNotFoundError(blockerLocalId);\n if (blocker.workstreamName !== task.workstreamName) {\n throw new CrossWorkstreamEdgeError(\n blockerLocalId,\n blocker.workstreamName,\n taskLocalId,\n task.workstreamName,\n );\n }\n const blockerId = taskIdFor(db, blocker.name, blocker.workstreamName);\n if (blockerId === null) throw new TaskNotFoundError(blockerLocalId);\n if (wouldCreateCycle(db, blockerId, taskSurrogateId)) {\n throw cycleErrorFor(\n db,\n blockerLocalId,\n taskLocalId,\n blockerId,\n taskSurrogateId,\n task.workstreamName,\n );\n }\n requestedBlockers.push({ localId: blockerLocalId, id: blockerId });\n }\n const canonicalBlockers = dedupeBlockersById(requestedBlockers);\n const blockerIds = canonicalBlockers.map((blocker) => blocker.id);\n const currentBlockerIds = (\n db\n .prepare(\"SELECT from_task_id AS id FROM task_edges WHERE to_task_id = ?\")\n .all(taskSurrogateId) as { id: number }[]\n ).map((row) => row.id);\n\n if (sameNumberSet(currentBlockerIds, blockerIds)) {\n return { removedEdges: 0, addedEdges: 0 };\n }\n\n return db\n .transaction(() => {\n const removed = db\n .prepare(\"DELETE FROM task_edges WHERE to_task_id = ?\")\n .run(taskSurrogateId);\n const insertEdge = db.prepare(\n \"INSERT INTO task_edges (from_task_id, to_task_id, created_at) VALUES (?, ?, ?)\",\n );\n const now = new Date().toISOString();\n for (const blockerId of blockerIds) {\n insertEdge.run(blockerId, taskSurrogateId, now);\n }\n // Bump the reparented task itself — its blocker set just changed.\n touchTask(db, taskSurrogateId, now);\n // No emitEvent: every edge DELETE and INSERT in this transaction\n // fired the capture trigger under intent='task.reparent'.\n return { removedEdges: removed.changes, addedEdges: blockerIds.length };\n })\n .immediate();\n}\n\nexport interface EdgeCycle {\n workstream: string;\n /** Local ids around the cycle, `a -> b -> … -> a` (first id not repeated). */\n path: string[];\n /** Local ids of an edge on it: `blocker` blocks `blocked`. Removing it breaks this cycle. */\n blocker: string;\n blocked: string;\n}\n\n/**\n * Cycles already present in task_edges. addBlockEdge refuses to make one,\n * but sync can merge two locally valid edges into one (apply never\n * rejects a peer's edge). Members block each other until one closes.\n * Returns one cycle per suggested fix; applying every fix together\n * leaves the graph acyclic.\n */\nexport function findEdgeCycles(db: Db): EdgeCycle[] {\n const rows = db\n .prepare(\n `SELECT e.from_task_id AS f, e.to_task_id AS t, w.name AS ws\n FROM task_edges e\n JOIN tasks a ON a.id = e.from_task_id\n JOIN workstreams w ON w.id = a.workstream_id\n ORDER BY w.name, e.from_task_id, e.to_task_id`,\n )\n .all() as { f: number; t: number; ws: string }[];\n // Peel nodes with no in-edges or no out-edges until stable: what is\n // left lies on, or between, cycles.\n let live = rows;\n for (;;) {\n const ins = new Set(live.map((r) => r.t));\n const outs = new Set(live.map((r) => r.f));\n const kept = live.filter((r) => ins.has(r.f) && outs.has(r.t));\n if (kept.length === live.length) break;\n live = kept;\n }\n const name = db.prepare(\"SELECT local_id FROM tasks WHERE id = ?\");\n const local = (id: number): string =>\n (name.get(id) as { local_id: string } | undefined)?.local_id ?? String(id);\n // Break cycles on an in-memory copy: find one, report it with its\n // closing edge, drop that edge, repeat. Applying every reported fix\n // therefore leaves the graph acyclic (a graph can hold exponentially\n // many cycles, so \"every cycle\" is not the contract; \"every fix\n // together breaks them all\" is). Each round is a BFS, at most one\n // round per edge.\n const out = new Map<number, Set<number>>();\n for (const r of live) {\n const set = out.get(r.f) ?? new Set<number>();\n set.add(r.t);\n out.set(r.f, set);\n }\n const wsOf = new Map(live.map((r) => [r.f, r.ws] as const));\n const shortestPath = (from: number, to: number): number[] | null => {\n const parent = new Map<number, number>([[from, from]]);\n let frontier = [from];\n while (frontier.length > 0 && !parent.has(to)) {\n const next: number[] = [];\n for (const n of frontier)\n for (const m of out.get(n) ?? []) {\n if (parent.has(m)) continue;\n parent.set(m, n);\n next.push(m);\n }\n frontier = next;\n }\n if (!parent.has(to)) return null;\n const ids: number[] = [];\n for (let n = to; ; ) {\n ids.unshift(n);\n if (n === from) return ids;\n const p = parent.get(n);\n if (p === undefined) return null;\n n = p;\n }\n };\n const cycles: EdgeCycle[] = [];\n for (const r of live) {\n for (;;) {\n if (!out.get(r.f)?.has(r.t)) break;\n const back = shortestPath(r.t, r.f); // r.t -> … -> r.f closes via r.f -> r.t\n if (back === null) break;\n cycles.push({\n workstream: wsOf.get(r.f) ?? r.ws,\n path: [r.f, ...back.slice(0, -1)].map(local),\n blocker: local(r.f),\n blocked: local(r.t),\n });\n out.get(r.f)?.delete(r.t);\n }\n }\n return cycles;\n}\n","// mu — workstream-level operations.\n//\n// One workstream = one mux session + N agents + M tasks (and their\n// edges/notes) all sharing the workstream column. 0.1.0 ships `mu init`\n// (create the mux session) and `mu workstream teardown` (this module: nuke the\n// mux session and every DB row tagged with the workstream name).\n//\n// `teardownWorkstream` is idempotent on every leg:\n// - mux session already gone → killSession swallows the error\n// - no agents/tasks for this name → DELETE returns zero changes\n// - workstream never existed at all → returns all-zero counts\n//\n// Both summarize and teardown take an optional `muxSession` override so\n// tests (and the rare workstream whose mux session was created with a\n// non-default name) work without env-var gymnastics.\n\nimport { existsSync, readdirSync, rmdirSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { unlinkCtlSocket } from \"./ctl/path.js\";\nimport { type Db, defaultStateDir } from \"./db.js\";\nimport { intentSpellings } from \"./legacy-ops.js\";\nimport { activeMux } from \"./mux.js\";\nimport { withOpContext } from \"./op-context.js\";\nimport type { HasNextSteps, NextStep } from \"./output.js\";\nimport { backendByName, type VcsBackend, type VcsBackendName } from \"./vcs.js\";\nimport { listWorkspaces } from \"./workspace.js\";\n\n/**\n * Allowed workstream-name shape: lowercase alpha first, then alnum,\n * underscore, or hyphen, up to 32 chars total. Mirrors the agent-name\n * rule in docs/reference/naming.md.\n *\n * Critically, this rule excludes `.` and `:` — tmux silently rewrites\n * `.` to `_` in session names (because `.` is the window/pane separator\n * in tmux's `session:window.pane` target syntax) and `:` is reserved\n * outright. A workstream name with `.` would create a session that mu\n * couldn't subsequently look up, breaking every downstream verb. We\n * fail loud at init time instead.\n */\nconst WORKSTREAM_NAME_RE = /^[a-z][a-z0-9_-]{0,31}$/;\n\n/** Reserved prefix — mu auto-prepends `mu-` to derive the tmux session\n * name (so workstream `auth` lives in tmux session `mu-auth`). A\n * workstream named `mu-auth` would produce session `mu-mu-auth`,\n * which the user almost certainly didn't intend. Fail loud rather\n * than silently double-prefix. */\nexport const RESERVED_WORKSTREAM_PREFIX = \"mu-\";\n\n/** Reserved workstream names that may only be auto-created on spawn,\n * never via `mu workstream init`. `scratch` is the off-the-cuff bucket\n * for ad-hoc agents you'll keep talking to without crew/DAG ceremony;\n * it auto-creates on first `mu agent spawn <name> -w scratch` (via\n * `ensureWorkstream`, which stays permissive) but `init` is rejected\n * loud so the operator doesn't treat it as a durable crew workstream.\n * See docs/VOCABULARY.md \"scratch workstream\". */\nexport const RESERVED_WORKSTREAM_NAMES = new Set([\"scratch\"]);\n\n// ─── Best-effort mux reads ─────────────────────────────────────────\n//\n// Every workstream READ decorates DB truth with mux liveness. The DB\n// half always works, so an unreachable mux must degrade the decoration\n// (\"no sessions\", \"not alive\") rather than fail `mu workstream list`\n// on a box where nobody is running a multiplexer right now.\n\n/** Live session names, or undefined when the mux could not be listed\n * (callers fall back to per-session `sessionExists` probes, since an\n * empty answer from a failed list would mark every session dead). */\nasync function tryListMuxSessions(): Promise<readonly { name: string }[] | undefined> {\n try {\n return await (await activeMux()).listSessions();\n } catch {\n return undefined;\n }\n}\n\nasync function listMuxSessions(): Promise<readonly { name: string }[]> {\n return (await tryListMuxSessions()) ?? [];\n}\n\nasync function sessionAlive(session: string): Promise<boolean> {\n try {\n return await (await activeMux()).sessionExists(session);\n } catch {\n return false;\n }\n}\n\n/** True iff `name` is a scratch/ephemeral workstream (special-cased by\n * the staleness nudge, the TUI ephemeral marker, the kept-alive\n * session on spawn, and the `teardown --empty` exemption). */\nexport function isScratchWorkstream(name: string): boolean {\n return RESERVED_WORKSTREAM_NAMES.has(name);\n}\n\n/** Name of the placeholder shell window every `mu-<ws>` session keeps,\n * so the session outlives its last agent pane. */\nexport const MU_PLACEHOLDER_WINDOW = \"_mu\";\n\n/**\n * Make sure mux session `session` exists and holds the placeholder\n * `_mu` window: create the session with it when missing, and add the\n * window when the session exists without it (the operator killed it,\n * or the session predates it). Load-bearing: mux errors propagate.\n *\n * Used by `mu workstream init` and by the first spawn into `scratch`\n * (never init-ed). Without `_mu`, closing the last agent kills the\n * last window and tmux destroys the session.\n */\nexport async function ensureWorkstreamSession(\n session: string,\n): Promise<{ created: boolean; muWindowRepaired: boolean }> {\n const mux = await activeMux();\n if (!(await mux.sessionExists(session))) {\n await mux.newSession(session, { detached: true, windowName: MU_PLACEHOLDER_WINDOW });\n return { created: true, muWindowRepaired: false };\n }\n const windows = await mux.listWindows(session).catch(() => []);\n if (windows.some((w) => w.name === MU_PLACEHOLDER_WINDOW)) {\n return { created: false, muWindowRepaired: false };\n }\n await mux.newWindow({\n session,\n name: MU_PLACEHOLDER_WINDOW,\n // A backend with no create-and-run form rejects a command and\n // starts a shell anyway (see createOrReusePane in agents/spawn.ts).\n command: mux.startAgentInPane === undefined ? (process.env.SHELL ?? \"/bin/sh\") : \"\",\n detached: true,\n });\n return { created: false, muWindowRepaired: true };\n}\n\n/**\n * The workstream implied by the mux session the caller sits in, or\n * null. Best-effort: this is one rung of the -w resolution ladder, so\n * an unreachable mux means \"no ambient answer\", never a thrown verb.\n */\nexport async function resolveMuxSessionWorkstreamName(): Promise<string | null> {\n try {\n const name = await (await activeMux()).currentSessionName();\n if (name?.startsWith(RESERVED_WORKSTREAM_PREFIX)) {\n return name.slice(RESERVED_WORKSTREAM_PREFIX.length);\n }\n } catch {\n // fall through: mux context is best-effort for workstream resolution\n }\n return null;\n}\n\nexport function isValidWorkstreamName(name: string): boolean {\n if (!WORKSTREAM_NAME_RE.test(name)) return false;\n if (name.startsWith(RESERVED_WORKSTREAM_PREFIX)) return false;\n return true;\n}\n\n/** A workstream name collision. Exported SDK error class mapped to exit\n * 4 (conflict) by `classifyError`; no mu verb throws it today\n * (`ensureWorkstream` is idempotent). Invalid names throw\n * `WorkstreamNameInvalidError`. */\nexport class WorkstreamExistsError extends Error implements HasNextSteps {\n override readonly name: string = \"WorkstreamExistsError\";\n constructor(public readonly workstream: string) {\n super(`workstream already exists: ${workstream}`);\n }\n errorNextSteps(): NextStep[] {\n return [\n { intent: \"List existing workstreams\", command: \"mu workstream list\" },\n {\n intent: \"Tear down the existing workstream first\",\n command: `mu workstream teardown -w ${this.workstream} --yes`,\n },\n ];\n }\n}\n\nexport class WorkstreamNameInvalidError extends Error implements HasNextSteps {\n override readonly name = \"WorkstreamNameInvalidError\";\n constructor(public readonly attempted: string) {\n const reason = attempted.startsWith(RESERVED_WORKSTREAM_PREFIX)\n ? `the 'mu-' prefix is reserved (mu auto-prepends 'mu-' to derive the tmux session name; '${attempted}' would produce session 'mu-${attempted}', which is double-prefixed and almost never what you want). Drop the 'mu-' from the workstream name.`\n : `must match /^[a-z][a-z0-9_-]{0,31}$/. tmux silently rewrites '.' to '_' and reserves ':' as a target separator, so workstream names containing those characters would create tmux sessions mu couldn't look up afterwards. Use letters, digits, '_', and '-' only.`;\n super(`invalid workstream name ${JSON.stringify(attempted)}: ${reason}`);\n }\n errorNextSteps(): NextStep[] {\n // Suggest a sanitized form: lowercase; strip the mu- prefix; map\n // every char outside [a-z0-9_-] (dots, colons, slashes, spaces) to\n // '_'; drop leading non-letters; cap at 32. A result that still\n // fails validation becomes the `<name>` placeholder, so the hint\n // never suggests a command that fails the same check.\n const candidate = this.attempted\n .toLowerCase()\n .replace(/^mu-/, \"\")\n .replace(/[^a-z0-9_-]/g, \"_\")\n .replace(/^[^a-z]+/, \"\")\n .slice(0, 32);\n const sanitized = isValidWorkstreamName(candidate) ? candidate : \"<name>\";\n // Branch the intent label on the failure class. For the mu-prefix\n // case the correction is unambiguous (drop the prefix), so phrase\n // the next-step as a direct action — \"Try a … (best guess)\" reads\n // as a hedge and dogfooding showed agents skip past the rationale\n // line entirely (workstream_init_name_rejected_mu in feedback ws).\n // For the regex/mangle branch the sanitiser really is guessing\n // (`.`/`:`/case all collapse), so the hedge stays honest there.\n const isPrefixCase = this.attempted.toLowerCase().startsWith(RESERVED_WORKSTREAM_PREFIX);\n const intent = isPrefixCase\n ? \"Retry without the 'mu-' prefix\"\n : \"Try a sanitized name (best guess)\";\n return [\n { intent, command: `mu workstream init ${sanitized}` },\n { intent: \"List existing workstreams\", command: \"mu workstream list\" },\n ];\n }\n}\n\nfunction assertValidWorkstreamName(name: string): void {\n if (!isValidWorkstreamName(name)) throw new WorkstreamNameInvalidError(name);\n}\n\n/** Thrown by `mu workstream init` when the operator tries to create a\n * reserved workstream (e.g. `scratch`) explicitly. The name is not\n * invalid — it auto-creates on spawn — it just can't be `init`ed. */\nexport class WorkstreamNameReservedError extends Error implements HasNextSteps {\n override readonly name = \"WorkstreamNameReservedError\";\n constructor(public readonly attempted: string) {\n super(\n `workstream name ${JSON.stringify(attempted)} is reserved: it is the off-the-cuff bucket and auto-creates on first spawn. Don't 'init' it.`,\n );\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Just spawn into it (auto-creates)\",\n command: `mu agent spawn <name> -w ${this.attempted}`,\n },\n { intent: \"Use a durable workstream instead\", command: \"mu workstream init <name>\" },\n ];\n }\n}\n\n/** Reject reserved names for the explicit `mu workstream init` path.\n * `ensureWorkstream` (the auto-create-on-spawn path) deliberately does\n * NOT call this — spawning into `scratch` must Just Work. */\nexport function assertWorkstreamInitable(name: string): void {\n if (RESERVED_WORKSTREAM_NAMES.has(name)) throw new WorkstreamNameReservedError(name);\n}\n\n/**\n * Ensure a row exists in the `workstreams` table for `name`. Idempotent;\n * INSERT OR IGNORE so concurrent callers race safely. Called by\n * `insertAgent` and `addTask` so callers don't need to remember to call\n * `mu init` before adding a task / spawning an agent (preserves the\n * spawn-without-init ergonomics now that agents.workstream and\n * tasks.workstream are real FKs into this table).\n *\n * Validates the name before inserting; throws `WorkstreamNameInvalidError`\n * for names tmux would silently mangle (containing '.' or ':') or that\n * exceed 32 chars / start with a non-letter.\n *\n * Returns true iff a row was actually inserted (vs. already present).\n */\nexport function ensureWorkstream(db: Db, name: string): boolean {\n assertValidWorkstreamName(name);\n return withOpContext(db, { intent: \"workstream.init\", group: \"new\" }, () =>\n ensureWorkstreamImpl(db, name),\n );\n}\n\nfunction ensureWorkstreamImpl(db: Db, name: string): boolean {\n const result = db\n .prepare(\"INSERT OR IGNORE INTO workstreams (name, created_at) VALUES (?, ?)\")\n .run(name, new Date().toISOString());\n const created = result.changes > 0;\n // No emitEvent: the workstreams INSERT fired the capture trigger\n // (intent='workstream.init', key=<name>).\n return created;\n}\n\nexport interface WorkstreamSummary {\n /** The workstream's own name. */\n name: string;\n /** Mux session name, defaults to `mu-<name>`. */\n muxSession: string;\n /** True iff the mux session `<muxSession>` is alive right now. */\n muxAlive: boolean;\n /** Rows in `agents` for this workstream. */\n agentCount: number;\n /** Rows in `tasks` for this workstream. */\n taskCount: number;\n /** Rows in `task_notes` whose task is in this workstream. */\n noteCount: number;\n /** Rows in `task_edges` whose `from_task` is in this workstream. */\n edgeCount: number;\n /** Rows in `vcs_workspaces` for this workstream. Surfaced so the\n * teardown dry-run can warn about per-agent worktrees that need\n * cleanup before the FK cascade silently nukes their rows. */\n workspaceCount: number;\n /** True iff a row exists in the `workstreams` table itself. False\n * for tmux-only `mu-*` sessions that mu never observed via\n * `mu workstream init`. Surfaced so teardown can clean up bare\n * registry rows (workstream row exists, no agents/tasks/etc.) —\n * otherwise such rows are orphaned forever (the previous\n * `nothingToDo` heuristic short-circuited on them). */\n registered: boolean;\n}\n\nexport interface TeardownResult {\n /** True iff killing the mux session actually killed something. */\n killedMux: boolean;\n /** Number of `agents` rows deleted. */\n deletedAgents: number;\n /** Number of `tasks` rows deleted (edges/notes cascade via FK). */\n deletedTasks: number;\n /** Number of `task_notes` deleted by the cascade — informational. */\n deletedNotes: number;\n /** Number of `task_edges` deleted by the cascade — informational. */\n deletedEdges: number;\n /** Number of vcs_workspaces whose on-disk path was actually\n * removed by the backend on this teardown. Excludes\n * `alreadyGoneWorkspaces` (those were no-ops on disk). */\n freedWorkspaces: number;\n /** Number of vcs_workspaces whose registry row existed but\n * whose on-disk path was already gone (manual rm -rf or a prior\n * interrupted teardown). The DB row was cascade-deleted; the\n * backend did no filesystem work. Tracked separately so the\n * teardown report doesn't lie about how much cleanup it actually\n * performed. */\n alreadyGoneWorkspaces: number;\n /** Workspaces whose backend cleanup failed (e.g. `git worktree\n * remove` refused because of uncommitted changes). The DB row\n * was still cascade-deleted; the on-disk path remains and needs\n * manual cleanup. */\n failedWorkspaces: WorkspaceFailure[];\n}\n\nexport interface WorkspaceFailure {\n agent: string;\n backend: string;\n path: string;\n error: string;\n}\n\nexport interface WorkstreamOptions {\n workstream: string;\n /** Override the mux session name. Defaults to `mu-<workstream>`. */\n muxSession?: string;\n /** Override the per-name VcsBackend resolver. Defaults to\n * `backendByName`. Lets tests inject a fake backend (e.g. one whose\n * `freeWorkspace` throws) without mutating the exported singletons —\n * same pattern as `createWorkspace`'s `opts.backend` accepting a\n * pre-built `VcsBackend` object. Production callers leave this\n * unset. */\n resolveBackend?: (name: VcsBackendName) => VcsBackend;\n}\n\nexport interface TeardownWorkstreamOptions extends WorkstreamOptions {}\n\n/** One past **teardown**, reconstructed from the ops log. */\nexport interface TornDownWorkstream {\n /** The workstream's name. Not unique across the list: a name can be\n * torn down, recreated and torn down again, and each is its own\n * entry (the group id is the identity). */\n name: string;\n /** The op group to pass to `mu undo`. */\n group: string;\n /** ISO timestamp of the teardown. */\n at: string;\n /** Rows the teardown removed, so the entry conveys what is at stake\n * without a second query per row. */\n tasks: number;\n notes: number;\n edges: number;\n /** True when a LATER put recreated this workstream, i.e. the\n * teardown was already undone or the name was reused. Kept in the\n * list rather than filtered out: \"I tore this down, then undid it\"\n * is history the operator may be looking for, and silently hiding\n * it would make the list disagree with `mu log`. */\n recreated: boolean;\n}\n\n/**\n * Every **teardown** the ops log remembers, newest first.\n *\n * The list exists because a teardown is REVERSIBLE and that is useless\n * if the group id cannot be found: `mu undo` lists only recent groups,\n * so a teardown from last month was effectively unreachable without\n * hand-written SQL over `ops`.\n *\n * Read straight from the log rather than from a side table — the log\n * already holds it, and a projection would be one more thing that can\n * disagree with the log (see the `provenance` reasoning in\n * docs/VOCABULARY.md).\n *\n * Accepts both intent spellings, so teardowns predating the 1.2.0\n * rename are included.\n */\nexport function listTornDownWorkstreams(db: Db): TornDownWorkstream[] {\n const spellings = intentSpellings(\"workstream.teardown\");\n const placeholders = spellings.map(() => \"?\").join(\", \");\n return db\n .prepare(\n `SELECT o.key AS name,\n o.group_id AS \"group\",\n o.created_at AS at,\n (SELECT COUNT(*) FROM ops t\n WHERE t.group_id = o.group_id AND t.entity = 'task' AND t.op = 'del') AS tasks,\n (SELECT COUNT(*) FROM ops n\n WHERE n.group_id = o.group_id AND n.entity = 'note' AND n.op = 'del') AS notes,\n (SELECT COUNT(*) FROM ops e\n WHERE e.group_id = o.group_id AND e.entity = 'edge' AND e.op = 'del') AS edges,\n EXISTS (SELECT 1 FROM ops p\n WHERE p.entity = 'workstream' AND p.key = o.key\n AND p.op = 'put' AND p.hlc > o.hlc) AS recreated\n FROM ops o\n WHERE o.entity = 'workstream'\n AND o.op = 'del'\n AND o.intent IN (${placeholders})\n ORDER BY o.created_at DESC, o.hlc DESC`,\n )\n .all(...spellings)\n .map((r) => {\n const row = r as Omit<TornDownWorkstream, \"recreated\"> & { recreated: number };\n return { ...row, recreated: row.recreated === 1 };\n });\n}\n\n/**\n * Discover every workstream visible on this machine. The union of:\n * - rows in the `workstreams` table (canonical DB source; populated by\n * `mu init` and auto-created by insertAgent / addTask)\n * - mux sessions named `mu-*` (with the prefix stripped) — catches\n * externally-created sessions (e.g. `tmux new-session -s mu-foo`)\n * that mu hasn't observed yet\n *\n * Returns one `WorkstreamSummary` per workstream, sorted by name.\n * Useful as a pre-flight before `mu init` (\"is this name taken?\") and\n * for `mu doctor`-style diagnostics.\n */\nexport async function listWorkstreams(db: Db): Promise<WorkstreamSummary[]> {\n const dbNames = new Set<string>(\n (db.prepare(\"SELECT name FROM workstreams\").all() as { name: string }[]).map((r) => r.name),\n );\n\n // Best-effort: the DB half of the union is always answerable, so a\n // missing mux degrades to \"registered workstreams only\" rather than\n // failing a read-only listing.\n const muxNames = new Set<string>();\n const sessions = await tryListMuxSessions();\n for (const session of sessions ?? []) {\n if (session.name.startsWith(RESERVED_WORKSTREAM_PREFIX))\n muxNames.add(session.name.slice(RESERVED_WORKSTREAM_PREFIX.length));\n }\n\n // Reuse the one list-sessions answer for liveness instead of a\n // has-session spawn per workstream; on a failed list, each summary\n // probes its own session.\n const live = sessions && new Set(sessions.map((s) => s.name));\n const allNames = Array.from(new Set([...dbNames, ...muxNames])).sort();\n return Promise.all(allNames.map((name) => summarize(db, { workstream: name }, live)));\n}\n\n/**\n * Discover every REGISTERED workstream that has no user-meaningful\n * state attached: a row in `workstreams` with zero tasks, zero\n * agents, zero vcs_workspaces. Mux session presence and agent_logs\n * entries do NOT disqualify — the session itself was created at\n * init time and contains no agent panes; the events are audit, not\n * state.\n *\n * Unregistered `mu-*` mux sessions (no `workstreams` row) are NEVER\n * returned. \"No DB row\" only means THIS DB does not know the\n * session: a run against a throwaway `MU_DB_PATH` sees every real\n * workstream as unregistered, and sweeping them killed a live crew's\n * agent panes. Nothing the mux reports proves such a session idle\n * either: `pane_current_command` is `bash` for a `bash -c` script or\n * loop, and herdr reports no command at all. See\n * listUnregisteredMuxWorkstreams for the names the sweep leaves to an\n * explicit `mu workstream teardown <name> --yes`.\n *\n * The `scratch` workstream is NEVER returned: its idle session is kept\n * alive on purpose (see ensureWorkstreamSession), so the next delegate\n * does not pay for creating it. `mu workstream teardown scratch --yes`\n * still removes it.\n *\n * Used by `mu workstream teardown --empty` to sweep empty\n * workstreams in one command (instead of the per-name jq incantation\n * over `mu workstream list --json`). Returns one `WorkstreamSummary`\n * per match, sorted by name.\n */\nexport async function listEmptyWorkstreams(db: Db): Promise<WorkstreamSummary[]> {\n const registeredRows = db\n .prepare(\n `SELECT ws.name AS name\n FROM workstreams ws\n LEFT JOIN tasks t ON t.workstream_id = ws.id\n LEFT JOIN agents a ON a.workstream_id = ws.id\n LEFT JOIN vcs_workspaces v ON v.workstream_id = ws.id\n GROUP BY ws.id, ws.name\n HAVING COUNT(DISTINCT t.id) = 0\n AND COUNT(DISTINCT a.id) = 0\n AND COUNT(DISTINCT v.id) = 0\n ORDER BY ws.name`,\n )\n .all() as { name: string }[];\n return Promise.all(\n registeredRows\n .filter((r) => !isScratchWorkstream(r.name))\n .map((r) => summarizeWorkstream(db, { workstream: r.name })),\n );\n}\n\n/** Workstream names of live `mu-*` mux sessions with no row in\n * `workstreams`, sorted. `teardown --empty` never sweeps these (see\n * listEmptyWorkstreams); it lists them so the operator can tear one\n * down by name. An unreachable mux yields []. */\nexport async function listUnregisteredMuxWorkstreams(db: Db): Promise<string[]> {\n const dbNames = new Set<string>(\n (db.prepare(\"SELECT name FROM workstreams\").all() as { name: string }[]).map((r) => r.name),\n );\n const names: string[] = [];\n for (const session of await listMuxSessions()) {\n if (!session.name.startsWith(RESERVED_WORKSTREAM_PREFIX)) continue;\n const name = session.name.slice(RESERVED_WORKSTREAM_PREFIX.length);\n if (!dbNames.has(name)) names.push(name);\n }\n return names.sort();\n}\n\nexport async function summarizeWorkstream(\n db: Db,\n opts: WorkstreamOptions,\n): Promise<WorkstreamSummary> {\n return summarize(db, opts, undefined);\n}\n\n/** `liveSessions`: the caller's already-fetched session names; when\n * undefined, probe this workstream's session itself. */\nasync function summarize(\n db: Db,\n opts: WorkstreamOptions,\n liveSessions: ReadonlySet<string> | undefined,\n): Promise<WorkstreamSummary> {\n const muxSession = opts.muxSession ?? `mu-${opts.workstream}`;\n return {\n name: opts.workstream,\n muxSession,\n muxAlive: liveSessions ? liveSessions.has(muxSession) : await sessionAlive(muxSession),\n agentCount: countAgents(db, opts.workstream),\n taskCount: countTasks(db, opts.workstream),\n noteCount: countNotes(db, opts.workstream),\n edgeCount: countEdges(db, opts.workstream),\n workspaceCount: listWorkspaces(db, opts.workstream).length,\n registered: isRegistered(db, opts.workstream),\n };\n}\n\nfunction isRegistered(db: Db, workstream: string): boolean {\n const row = db.prepare(\"SELECT 1 AS x FROM workstreams WHERE name = ?\").get(workstream) as\n | { x: number }\n | undefined;\n return row !== undefined;\n}\n\n/**\n * Tear down a workstream: kill its mux session and delete every DB row\n * tagged with its name. Cascades on `tasks` clean up `task_edges` and\n * `task_notes` automatically (FK ON DELETE CASCADE in the schema).\n *\n * Idempotent: safe to call against a workstream that never existed; safe\n * to call repeatedly. Returns counts so the caller can print a useful\n * summary.\n */\nexport async function teardownWorkstream(\n db: Db,\n opts: TeardownWorkstreamOptions,\n): Promise<TeardownResult> {\n const muxSession = opts.muxSession ?? `mu-${opts.workstream}`;\n\n // Teardown does not snapshot. v9 dropped the `snapshots` table; the\n // teardown writes tombstone ops instead and `mu undo` replays the\n // inverses (VISION.md § 2b).\n\n // Pre-count the cascade victims so we can report them — SQLite's\n // changes() only reports rows directly affected by the last statement,\n // not cascade victims.\n const agentsBefore = countAgents(db, opts.workstream);\n const tasksBefore = countTasks(db, opts.workstream);\n const notesBefore = countNotes(db, opts.workstream);\n const edgesBefore = countEdges(db, opts.workstream);\n const workspacesBefore = listWorkspaces(db, opts.workstream);\n const agentNames = listAgentNames(db, opts.workstream);\n\n // Mux session first: if killSession throws we don't want the DB rows\n // already gone with no way to recover. (killSession is itself\n // idempotent on missing sessions — a real throw here is an\n // unexpected mux error.) Load-bearing: teardown must actually kill\n // the session, not silently report success while leaving panes\n // running.\n const mux = await activeMux();\n const muxAliveBefore = await mux.sessionExists(muxSession);\n if (muxAliveBefore) {\n await mux.killSession(muxSession);\n }\n\n // Workspaces SECOND, before the FK cascade. The cascade silently\n // deletes vcs_workspaces rows but leaves the on-disk worktrees\n // (and the git worktree registry entries) behind — the bug from\n // mufeedback note #195. Per backend, the right cleanup is\n // 'git worktree remove --force' / 'jj workspace forget' / etc.,\n // not 'rm -rf'. We surface failures so the user can recover; we\n // do NOT abort the teardown on workspace failure (the workstream\n // semantics are 'tear it all down', not 'partial cleanup').\n let freedWorkspaces = 0;\n let alreadyGoneWorkspaces = 0;\n const failedWorkspaces: WorkspaceFailure[] = [];\n const resolveBackend = opts.resolveBackend ?? backendByName;\n for (const ws of workspacesBefore) {\n try {\n const backend = resolveBackend(ws.backend);\n const result = await backend.freeWorkspace({\n workspacePath: ws.path,\n commit: false,\n });\n if (result.removed) {\n // Backend actually removed the on-disk path. This is the\n // only case that counts as 'work done by teardown'.\n freedWorkspaces += 1;\n } else {\n // Path was already gone (manual rm -rf or interrupted prior\n // teardown). The DB row is cascade-deleted below either way,\n // but we don't claim to have freed anything on disk — it was\n // already in the desired state. Tracked separately so the\n // user can spot stale registry rows from past mishaps.\n alreadyGoneWorkspaces += 1;\n }\n } catch (err) {\n failedWorkspaces.push({\n agent: ws.agentName,\n backend: ws.backend,\n path: ws.path,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n // After every per-agent worktree is freed, the parent\n // <state>/workspaces/<workstream>/ directory is empty — reap it\n // too. Best-effort: rmdir refuses if non-empty (e.g. backend\n // removal failed and left files behind), which is the right\n // outcome (don't silently rm -rf user data). Skipped if the\n // parent doesn't exist (workstream never had any workspaces).\n const parentDir = join(defaultStateDir(), \"workspaces\", opts.workstream);\n if (existsSync(parentDir)) {\n try {\n if (readdirSync(parentDir).length === 0) rmdirSync(parentDir);\n } catch {\n // Non-empty or otherwise unreapable. The failed-workspaces\n // list above already tells the user what to clean.\n }\n }\n\n // The cascade skips deleteAgent, so unlink each agent's control\n // socket here (ssh -L forwards leave theirs behind). Do it BEFORE the\n // DELETE: the agent rows are how a retry finds the sockets, so an\n // interrupted unlink must leave them in place. Then reap\n // sock/<ws>/ only if empty, never recursively: hashed long paths\n // share sock/h/ across workstreams, so a workstream named \"h\" must\n // not take the others' sockets with it.\n for (const name of agentNames) unlinkCtlSocket(db, name, opts.workstream);\n if (!db.memory) {\n const sockDir = join(dirname(db.name), \"sock\", opts.workstream);\n try {\n if (readdirSync(sockDir).length === 0) rmdirSync(sockDir);\n } catch {\n // Missing or non-empty: nothing of ours left to reap.\n }\n }\n\n // One DELETE: the FK CASCADE chain (workstreams → agents,\n // workstreams → tasks → task_edges + task_notes, workstreams →\n // agent_logs, workstreams → vcs_workspaces) cleans every row in\n // one shot, atomically. If the workstream was never registered\n // (e.g. an orphan mux session that mu never observed),\n // changes() = 0 and we still report the killed mux session\n // honestly.\n // One group for the entire teardown: the DELETE cascades to tasks,\n // edges and notes, and each cascaded row gets its own tombstone op\n // (SQLite FK CASCADE DOES fire triggers — verified empirically, see\n // src/capture.ts). They all share this group so the whole teardown is\n // one unit for `mu undo`.\n withOpContext(db, { intent: \"workstream.teardown\", group: \"new\" }, () =>\n db.prepare(\"DELETE FROM workstreams WHERE name = ?\").run(opts.workstream),\n );\n // No emitEvent: the DELETE cascade fired the capture triggers, which\n // wrote tombstone ops (op='del', intent='workstream.teardown') for the\n // workstream AND for every task/edge/note that cascaded with it —\n // strictly more information than the prose counts, and it survives the\n // cascade because ops is FK-free.\n\n return {\n killedMux: muxAliveBefore,\n deletedAgents: agentsBefore,\n deletedTasks: tasksBefore,\n deletedNotes: notesBefore,\n deletedEdges: edgesBefore,\n freedWorkspaces,\n alreadyGoneWorkspaces,\n failedWorkspaces,\n };\n}\n\n// ─── Counts ────────────────────────────────────────────────────────────\n\nfunction listAgentNames(db: Db, workstream: string): string[] {\n const rows = db\n .prepare(\n `SELECT a.name FROM agents a\n JOIN workstreams ws ON ws.id = a.workstream_id\n WHERE ws.name = ?`,\n )\n .all(workstream) as { name: string }[];\n return rows.map((r) => r.name);\n}\n\nfunction countAgents(db: Db, workstream: string): number {\n const row = db\n .prepare(\n `SELECT COUNT(*) AS n FROM agents a\n JOIN workstreams ws ON ws.id = a.workstream_id\n WHERE ws.name = ?`,\n )\n .get(workstream) as { n: number };\n return row.n;\n}\n\nfunction countTasks(db: Db, workstream: string): number {\n const row = db\n .prepare(\n `SELECT COUNT(*) AS n FROM tasks t\n JOIN workstreams ws ON ws.id = t.workstream_id\n WHERE ws.name = ?`,\n )\n .get(workstream) as { n: number };\n return row.n;\n}\n\nfunction countNotes(db: Db, workstream: string): number {\n const row = db\n .prepare(\n `SELECT COUNT(*) AS n\n FROM task_notes n\n JOIN tasks t ON t.id = n.task_id\n JOIN workstreams ws ON ws.id = t.workstream_id\n WHERE ws.name = ?`,\n )\n .get(workstream) as { n: number };\n return row.n;\n}\n\nfunction countEdges(db: Db, workstream: string): number {\n // Count edges whose blocker (from_task) is in the workstream. Since\n // cross-workstream edges are forbidden by addTask, this equals the\n // edge count for the workstream subgraph.\n const row = db\n .prepare(\n `SELECT COUNT(*) AS n\n FROM task_edges e\n JOIN tasks t ON t.id = e.from_task_id\n JOIN workstreams ws ON ws.id = t.workstream_id\n WHERE ws.name = ?`,\n )\n .get(workstream) as { n: number };\n return row.n;\n}\n","// mu — task edit/write verbs: add task, add note, update, delete.\n\nimport { type Db, resolveWorkstreamId } from \"../db.js\";\nimport { currentOpContext, withOpContext } from \"../op-context.js\";\nimport { ensureWorkstream } from \"../workstream.js\";\nimport { taskIdFor, touchTask } from \"./core.js\";\nimport { dedupeBlockersById, wouldCreateCycle } from \"./edges.js\";\nimport {\n CrossWorkstreamEdgeError,\n CycleError,\n TaskExistsError,\n TaskIdInvalidError,\n TaskNotFoundError,\n} from \"./errors.js\";\nimport { isValidTaskId } from \"./id.js\";\nimport { getTask } from \"./queries.js\";\n\nexport interface AddTaskOptions {\n localId: string;\n workstream: string;\n title: string;\n /** 1..100; enforced by schema CHECK. */\n impact: number;\n /** > 0; enforced by schema CHECK. */\n effortDays: number;\n /**\n * Tasks that block this one. Edges inserted as `blocker -> newTask`.\n * Each blocker must already exist AND share this task's workstream\n * (cross-workstream edges are forbidden); cycle check guards each\n * edge. The CLI surfaces this as `--blocked-by`; the SDK key matches.\n */\n blockedBy?: string[];\n /** Start as OPEN/triage (a proposal, e.g. a review finding) instead of OPEN/todo. */\n triage?: boolean;\n}\n\n/**\n * Atomically create a task and (optionally) its incoming blocked-by\n * edges.\n *\n * The task insert + every edge insert + cycle check happen inside one\n * SQLite transaction. If any blocker is missing or any edge would\n * create a cycle, the entire add rolls back.\n *\n * Cycle check for `addTask` is structurally trivial (a fresh task has\n * no outgoing edges, so `to -> ... -> from` is impossible). It's still\n * called here so the same primitive is exercised by tests.\n */\nexport function addTask(db: Db, opts: AddTaskOptions) {\n return withOpContext(db, { intent: \"task.add\", group: \"new\" }, () => addTaskImpl(db, opts));\n}\n\nfunction addTaskImpl(db: Db, opts: AddTaskOptions) {\n if (!isValidTaskId(opts.localId)) {\n throw new TaskIdInvalidError(opts.localId);\n }\n\n return db\n .transaction(() => {\n // Auto-create the workstream row so tasks.workstream_id FK is\n // satisfied (preserves spawn-without-init ergonomics).\n ensureWorkstream(db, opts.workstream);\n const wsId = resolveWorkstreamId(db, opts.workstream);\n\n // Per-workstream uniqueness: a duplicate local_id within the same\n // workstream throws TaskExistsError. Different workstreams may\n // legitimately share local_ids in v5.\n const existing = db\n .prepare(\"SELECT id FROM tasks WHERE workstream_id = ? AND local_id = ?\")\n .get(wsId, opts.localId) as { id: number } | undefined;\n if (existing) {\n throw new TaskExistsError(opts.localId);\n }\n\n const now = new Date().toISOString();\n const insertResult = db\n .prepare(\n `INSERT INTO tasks (workstream_id, local_id, title, status, substate, impact, effort_days, created_at, updated_at)\n VALUES (?, ?, ?, 'OPEN', ?, ?, ?, ?, ?)`,\n )\n .run(\n wsId,\n opts.localId,\n opts.title,\n opts.triage === true ? \"triage\" : \"todo\",\n opts.impact,\n opts.effortDays,\n now,\n now,\n );\n const newTaskId = Number(insertResult.lastInsertRowid);\n\n if (opts.blockedBy && opts.blockedBy.length > 0) {\n // Prefer the same-workstream blocker first (v5 per-workstream\n // local_id), then fall back to a global lookup so a cross-ws\n // blocker still surfaces CrossWorkstreamEdgeError (not\n // TaskNotFoundError). Without the same-ws preference, two\n // blockers of the same local_id (one in this ws, one elsewhere)\n // could silently bind to the wrong row\n // (bug_v5_name_clash_silent_misroute).\n const blockerLookupSameWs = db.prepare(\n `SELECT t.id AS id, ws.name AS workstream FROM tasks t\n JOIN workstreams ws ON ws.id = t.workstream_id\n WHERE t.local_id = ? AND t.workstream_id = ?`,\n );\n const blockerLookupAnyWs = db.prepare(\n `SELECT t.id AS id, ws.name AS workstream FROM tasks t\n JOIN workstreams ws ON ws.id = t.workstream_id\n WHERE t.local_id = ? LIMIT 1`,\n );\n const requestedBlockers = opts.blockedBy.map((blocker) => {\n const row = (blockerLookupSameWs.get(blocker, wsId) ?? blockerLookupAnyWs.get(blocker)) as\n | { id: number; workstream: string }\n | undefined;\n if (!row) {\n throw new TaskNotFoundError(blocker);\n }\n if (row.workstream !== opts.workstream) {\n throw new CrossWorkstreamEdgeError(\n blocker,\n row.workstream,\n opts.localId,\n opts.workstream,\n );\n }\n if (wouldCreateCycle(db, row.id, newTaskId)) {\n throw new CycleError(blocker, opts.localId);\n }\n return { localId: blocker, id: row.id };\n });\n const canonicalBlockers = dedupeBlockersById(requestedBlockers);\n const insertEdge = db.prepare(\n \"INSERT INTO task_edges (from_task_id, to_task_id, created_at) VALUES (?, ?, ?)\",\n );\n for (const blocker of canonicalBlockers) {\n insertEdge.run(blocker.id, newTaskId, now);\n }\n }\n\n const row = getTask(db, opts.localId, opts.workstream);\n if (!row) throw new Error(`addTask: row missing after insert: ${opts.localId}`);\n // No emitEvent: the INSERT above fired the tasks capture trigger,\n // which already wrote intent='task.add' key='<ws>/<id>' with the\n // full row as payload (v2-retire-log-shim).\n return row;\n })\n .immediate();\n}\n\nexport interface AddNoteOptions {\n /** Free-form author label. Convention: agent name, \"user\", or \"orchestrator\". */\n author?: string;\n /** Workstream context (operator-facing name). v5: tasks.local_id is\n * per-workstream unique, so this is required to disambiguate. */\n workstream: string;\n}\n\nexport function addNote(db: Db, taskLocalId: string, content: string, opts: AddNoteOptions) {\n return withOpContext(db, { intent: \"task.note\", actor: opts.author, group: \"new\" }, () =>\n insertNote(db, taskLocalId, content, opts),\n );\n}\n\n/** addNote without its own op context: the note joins the CALLER's\n * group and intent. For verbs whose note is part of one action (the\n * `--why` of `close --as` / `park`), so `mu undo` reverts both together.\n * Internal — not re-exported from src/tasks.ts. */\nexport function insertNote(db: Db, taskLocalId: string, content: string, opts: AddNoteOptions) {\n const task = getTask(db, taskLocalId, opts.workstream);\n if (!task) {\n throw new TaskNotFoundError(taskLocalId);\n }\n const taskId = taskIdFor(db, task.name, task.workstreamName);\n if (taskId === null) throw new TaskNotFoundError(taskLocalId);\n const now = new Date().toISOString();\n db.transaction(() => {\n const r = db\n .prepare(\"INSERT INTO task_notes (task_id, author, content, created_at) VALUES (?, ?, ?, ?)\")\n .run(taskId, opts.author ?? null, content, now);\n // Bump the parent task so `mu task list --sort recency` surfaces\n // freshly-noted tasks (task_updatedat_not_bumped_by_reparent).\n touchTask(db, taskId, now);\n return r;\n }).immediate();\n // No emitEvent: the task_notes INSERT fired the capture trigger\n // (intent='task.note', key='<ws>/<id>#<n>').\n return {\n author: opts.author ?? null,\n content,\n createdAt: now,\n };\n}\n\nexport interface DeleteTaskResult {\n /** True iff the row existed and was deleted. False on a dry-run\n * (preview) AND on the idempotent missing-row case. */\n deleted: boolean;\n /** Number of `task_edges` rows cascaded out (informational). On a\n * dry-run, this is the would-be count. */\n deletedEdges: number;\n /** Number of `task_notes` rows cascaded out (informational). On a\n * dry-run, this is the would-be count. */\n deletedNotes: number;\n /** True iff this was a dry-run (`opts.dryRun: true`). On a\n * dry-run `deleted` is false and the counts are the would-be\n * counts; the DB is unchanged. Always false on a commit / on a\n * missing-row idempotent no-op. */\n dryRun: boolean;\n /** True iff a matching task row was found at the time of the\n * call. Discriminator for the CLI: a dry-run that found nothing\n * (`present: false`) renders differently from a dry-run that\n * found an existing task with zero edges and zero notes\n * (`present: true, deletedEdges: 0, deletedNotes: 0`). */\n present: boolean;\n /** The op group the delete wrote, for `mu undo <group> --yes`. Null\n * when nothing was deleted (dry-run or missing row). */\n group: string | null;\n}\n\nexport interface DeleteTaskOptions {\n /** When true, return the cascade preview (would-be edge / note\n * counts) without mutating. The CLI uses this to power the bare\n * `mu task delete <id>` two-phase pattern (mirrors\n * `mu workstream teardown` / `mu undo`). Surfaced\n * by feedback ws task\n * fb_task_delete_no_yes (impact=30): a dogfood report typed\n * `mu task delete X --yes` (mirroring workstream teardown) and got\n * 'unknown option --yes' — the verb took no confirmation flag at\n * all. Two failed deletes left long-named tasks lingering. */\n dryRun?: boolean;\n}\n\n/**\n * Delete a task. FK CASCADE on `task_edges` (from + to) and\n * `task_notes` cleans the joined rows automatically. Idempotent on\n * a missing task (returns `deleted: false`).\n *\n * Pre-counts the cascade victims for reporting because SQLite's\n * `changes()` only reports rows directly affected by the DELETE.\n *\n * With `opts.dryRun: true`, returns the would-be counts without\n * touching the DB (no mutation, so no op is written). The CLI bare\n * `mu task delete <id>` form uses this; `--yes` calls through with\n * `dryRun: false`.\n */\nexport function deleteTask(\n db: Db,\n localId: string,\n workstream: string,\n opts: DeleteTaskOptions = {},\n): DeleteTaskResult {\n return withOpContext(db, { intent: \"task.delete\", group: \"new\" }, () =>\n deleteTaskImpl(db, localId, workstream, opts),\n );\n}\n\nfunction deleteTaskImpl(\n db: Db,\n localId: string,\n workstream: string,\n opts: DeleteTaskOptions,\n): DeleteTaskResult {\n const dryRun = opts.dryRun === true;\n const before = getTask(db, localId, workstream);\n if (!before) {\n // Idempotent on a missing row regardless of dryRun.\n return {\n deleted: false,\n deletedEdges: 0,\n deletedNotes: 0,\n dryRun,\n present: false,\n group: null,\n };\n }\n const taskId = taskIdFor(db, localId, before.workstreamName);\n if (taskId === null) {\n return {\n deleted: false,\n deletedEdges: 0,\n deletedNotes: 0,\n dryRun,\n present: false,\n group: null,\n };\n }\n const edgesBefore = (\n db\n .prepare(\"SELECT COUNT(*) AS n FROM task_edges WHERE from_task_id = ? OR to_task_id = ?\")\n .get(taskId, taskId) as { n: number }\n ).n;\n const notesBefore = (\n db.prepare(\"SELECT COUNT(*) AS n FROM task_notes WHERE task_id = ?\").get(taskId) as {\n n: number;\n }\n ).n;\n if (dryRun) {\n return {\n deleted: false,\n deletedEdges: edgesBefore,\n deletedNotes: notesBefore,\n dryRun: true,\n present: true,\n group: null,\n };\n }\n // No pre-mutation snapshot: v9 dropped the `snapshots` table and\n // rollback is inverse ops over the ops log (`mu undo`).\n const result = db.prepare(\"DELETE FROM tasks WHERE id = ?\").run(taskId);\n // No emitEvent: the DELETE fired the capture trigger, which wrote a\n // tombstone op (op='del', intent='task.delete').\n const deleted = result.changes > 0;\n return {\n deleted,\n deletedEdges: edgesBefore,\n deletedNotes: notesBefore,\n dryRun: false,\n present: true,\n // deleteTask opened a fresh group around this call.\n group: deleted ? currentOpContext(db).groupId : null,\n };\n}\n\nexport interface UpdateTaskOptions {\n title?: string;\n /** 1..100; enforced by schema CHECK. */\n impact?: number;\n /** > 0; enforced by schema CHECK. */\n effortDays?: number;\n}\n\nexport interface UpdateTaskResult {\n /** True iff at least one field actually changed. */\n updated: boolean;\n /** The fields whose values differ post-update (in `UpdateTaskOptions`'s\n * camelCase shape). Empty when `updated: false`. */\n changedFields: string[];\n}\n\n/**\n * Update scalar fields on a task. Each option is independently optional;\n * passing none is a typed no-op (returns `updated: false, changedFields: []`).\n * Fields whose new value equals the current value are skipped (no row change).\n *\n * NOT for status (use `closeTask` / `openTask` / `setTaskStatus`), owner\n * (use `claimTask` / `releaseTask`), local_id (rename is deferred), or\n * workstream (cross-workstream moves are deferred).\n */\nexport interface UpdateTaskScopeOption {\n workstream: string;\n}\n\nexport function updateTask(\n db: Db,\n localId: string,\n opts: UpdateTaskOptions,\n scope: UpdateTaskScopeOption,\n): UpdateTaskResult {\n return withOpContext(db, { intent: \"task.update\", group: \"new\" }, () =>\n updateTaskImpl(db, localId, opts, scope),\n );\n}\n\nfunction updateTaskImpl(\n db: Db,\n localId: string,\n opts: UpdateTaskOptions,\n scope: UpdateTaskScopeOption,\n): UpdateTaskResult {\n const before = getTask(db, localId, scope.workstream);\n if (!before) throw new TaskNotFoundError(localId);\n const taskId = taskIdFor(db, before.name, before.workstreamName);\n if (taskId === null) throw new TaskNotFoundError(localId);\n\n const setters: string[] = [];\n const params: unknown[] = [];\n const changedFields: string[] = [];\n\n if (opts.title !== undefined && opts.title !== before.title) {\n setters.push(\"title = ?\");\n params.push(opts.title);\n changedFields.push(\"title\");\n }\n if (opts.impact !== undefined && opts.impact !== before.impact) {\n setters.push(\"impact = ?\");\n params.push(opts.impact);\n changedFields.push(\"impact\");\n }\n if (opts.effortDays !== undefined && opts.effortDays !== before.effortDays) {\n setters.push(\"effort_days = ?\");\n params.push(opts.effortDays);\n changedFields.push(\"effortDays\");\n }\n\n if (setters.length === 0) {\n return { updated: false, changedFields: [] };\n }\n\n setters.push(\"updated_at = ?\");\n params.push(new Date().toISOString());\n params.push(taskId);\n\n // No emitEvent: the UPDATE fired the capture trigger, whose payload is\n // a semantic partial update naming exactly the changed columns —\n // strictly more useful than the prose \"(changed: a, b)\" it replaces.\n db.prepare(`UPDATE tasks SET ${setters.join(\", \")} WHERE id = ?`).run(...params);\n return { updated: true, changedFields };\n}\n","// mu — task lifecycle verbs: setTaskStatus, closeTask, openTask.\n//\n// Lifecycle = \"transition a task from one status to another, with\n// the right captured-op and evidence-note side effects\".\n//\n// EvidenceOption is shared with claim/release (in tasks/claim.ts) and\n// re-exported here as the canonical home; claim.ts imports from this\n// file.\n//\n// Extracted from src/tasks.ts as part of refactor_split_large_src_files.\n\nimport type { Db } from \"../db.js\";\nimport { withOpContext } from \"../op-context.js\";\nimport { taskIdFor } from \"./core.js\";\nimport { getTaskEdgesWithStatus } from \"./edges.js\";\nimport { addNote, insertNote } from \"./edit.js\";\nimport {\n InvalidSubstateError,\n SubstateReasonRequiredError,\n TaskNotFoundError,\n TaskParkStateError,\n} from \"./errors.js\";\nimport { getTask, listNotes } from \"./queries.js\";\nimport {\n DEFAULT_SUBSTATE,\n isValidPair,\n type TASK_SUBSTATES,\n type TaskStatus,\n type TaskSubstate,\n} from \"./status.js\";\n\nexport interface SetStatusResult {\n /** Status before the call. */\n previousStatus: TaskStatus;\n /** Status after the call (== requested status). */\n status: TaskStatus;\n /** Substate before the call. */\n previousSubstate: TaskSubstate;\n /** Substate after the call (== requested substate, or the status default). */\n substate: TaskSubstate;\n /** True iff status OR substate changed. False on idempotent no-op. */\n changed: boolean;\n}\n\n/** The substates a task can be closed as (`mu task close --as`). */\nexport type CloseSubstate = (typeof TASK_SUBSTATES)[\"CLOSED\"][number];\n\n/**\n * Optional evidence string carried on lifecycle verbs (close / open /\n * claim / release). Lands in the auto-emitted `kind='event'` payload\n * verbatim, prefixed with `evidence=`. The first inch of distinguishing\n * \"observed\" from \"claimed\" state per an internal critique: the\n * verb still trusts the caller (it's not a verifier), but the audit\n * trail records what the caller said it relied on.\n */\nexport interface EvidenceOption {\n evidence?: string;\n}\n\n/** Evidence plus the actor its note is attributed to. The CLI passes\n * `resolveActorIdentity()`; without it the note has no author and\n * renders as `<orchestrator>`. */\nexport interface AttributedEvidence extends EvidenceOption {\n author?: string;\n}\n\n/**\n * Persist `--evidence` as a task note, so it survives as a captured op.\n *\n * mu once put evidence in the prose event payload AND (for close only) in a\n * synthetic note. v2-retire-log-shim deleted the prose events, which\n * would have silently dropped evidence on open/release. The note is now\n * the single home for it: notes are portable and sync, whereas the prose\n * event was machine-local and unparseable.\n *\n * Only fires when the verb actually changed something (an idempotent\n * re-close attests nothing new) and the evidence is a non-empty string.\n */\nexport function recordEvidenceNote(\n db: Db,\n localId: string,\n workstream: string,\n label: string,\n opts: AttributedEvidence | undefined,\n): void {\n if (!opts || opts.evidence === undefined || opts.evidence === \"\") return;\n const noteOpts: { author?: string; workstream: string } = { workstream };\n if (opts.author !== undefined && opts.author !== \"\") noteOpts.author = opts.author;\n addNote(db, localId, `${label}: ${opts.evidence}`, noteOpts);\n}\n\n/** Render the optional `--evidence \"<text>\"` payload as the trailing\n * ' evidence=\"...\"' on every state-changing event. Exported because\n * claimTask/releaseTask in src/tasks/claim.ts also use it. */\nexport function evidenceSuffix(opts: EvidenceOption | undefined): string {\n if (!opts || opts.evidence === undefined) return \"\";\n return ` evidence=${JSON.stringify(opts.evidence)}`;\n}\n\nexport interface SetStatusOptions extends EvidenceOption {\n workstream: string;\n /** Substate to land on; defaults to DEFAULT_SUBSTATE[status]. A pair\n * outside TASK_SUBSTATES throws InvalidSubstateError before any write. */\n substate?: TaskSubstate;\n}\n\n/**\n * Flip a task's status to any of OPEN / IN_PROGRESS / CLOSED, writing\n * status and substate in ONE UPDATE (one op, one HLC — spec D7).\n * Idempotent: setting a task to its current pair is a no-op (returns\n * `changed: false`) rather than throwing. Owner is unchanged.\n */\nexport function setTaskStatus(\n db: Db,\n localId: string,\n status: TaskStatus,\n opts: SetStatusOptions,\n): SetStatusResult {\n // NOTE: no `group` here, so a nested call inherits the enclosing\n // group. A direct call with no enclosing context still gets its own\n // group (withOpContext mints one).\n //\n // `intentIfUnset` (not `intent`): when reached via closeTask, the\n // outer verb is the label the operator recognises, so it must win.\n // Only a direct setTaskStatus call labels itself.\n return withOpContext(db, { intentIfUnset: `task.set-${status.toLowerCase()}` }, () =>\n setTaskStatusImpl(db, localId, status, opts),\n );\n}\n\nfunction setTaskStatusImpl(\n db: Db,\n localId: string,\n status: TaskStatus,\n opts: SetStatusOptions,\n): SetStatusResult {\n const substate = opts.substate ?? DEFAULT_SUBSTATE[status];\n if (!isValidPair(status, substate)) throw new InvalidSubstateError(status, substate);\n const before = getTask(db, localId, opts.workstream);\n if (!before) throw new TaskNotFoundError(localId);\n const base = {\n previousStatus: before.status,\n status,\n previousSubstate: before.substate,\n substate,\n };\n if (before.status === status && before.substate === substate) {\n return { ...base, changed: false };\n }\n // v5: tasks.local_id is per-workstream unique. Scope to the row's\n // workstream so the UPDATE doesn't accidentally touch a same-named\n // task in another workstream.\n db.prepare(\n `UPDATE tasks SET status = ?, substate = ?, updated_at = ?\n WHERE local_id = ?\n AND workstream_id = (SELECT id FROM workstreams WHERE name = ?)`,\n ).run(status, substate, new Date().toISOString(), localId, before.workstreamName);\n // No emitEvent: the UPDATE fired the capture trigger, whose intent is\n // the specific verb (task.close / task.open, or task.set-<status> for\n // a bare status set) and whose payload names the new status. Evidence,\n // when passed, lands as a task note — itself a captured op.\n return { ...base, changed: true };\n}\n\n/** Result of `closeTask` when called with `ifReady: true` and the\n * task is NOT yet ready to close (still has at least one OPEN /\n * IN_PROGRESS blocker). Distinguished from a regular `SetStatusResult`\n * by the literal `skipped` field; the CLI keys on it to switch\n * between the \"closed\" and \"waiting\" rendering paths.\n *\n * Surfaced in `fb_umbrella_no_auto_close` (impact=60): a wave umbrella\n * with N blockers stayed OPEN after every blocker reached a terminal\n * status. `--if-ready` is the cheap fix: bare `mu task close` is\n * unchanged (closes regardless), `--if-ready` is a no-op unless every\n * blocker is CLOSED. */\nexport interface CloseSkippedResult {\n /** Always 'not_ready' when set; future cause-codes can extend this\n * without reshaping the JSON payload (the literal-union narrows\n * safely in the CLI rendering path). */\n skipped: \"not_ready\";\n /** Status before the call (always the current status, no change). */\n previousStatus: TaskStatus;\n /** Status after the call (== previousStatus, since we no-op). */\n status: TaskStatus;\n /** Substate before (and after) the call. */\n previousSubstate: TaskSubstate;\n substate: TaskSubstate;\n /** Always false on a skip (no row mutated). */\n changed: false;\n /** Local ids of every blocker still in OPEN or IN_PROGRESS, sorted\n * alphabetically for deterministic rendering. Empty list is\n * impossible on this branch — the no-op only fires when ≥1\n * blocker is non-terminal. */\n blockingIds: string[];\n}\n\nexport interface CloseTaskOptions extends EvidenceOption {\n workstream: string;\n /** When true, no-op the close unless every blocker is CLOSED.\n * Returns a `CloseSkippedResult` carrying the still-blocking ids;\n * the CLI renders the skip with a Next: hint pointing at\n * `mu task wait`. When false / omitted, behaves as bare `closeTask`\n * (closes regardless of blocker status). */\n ifReady?: boolean;\n /** Optional actor identity attributed to the synthetic `CLOSE: …`\n * note auto-inserted when `evidence` is non-empty (see closeTask\n * body). The CLI resolves this via `resolveActorIdentity()` so the\n * note carries the closing worker's name; SDK callers (tests,\n * internal use) may omit it (the note then carries no author, same\n * as a bare `addNote` without `--author`). Surfaced in mufeedback\n * task_close_evidence_does_not_append_the. */\n author?: string;\n /** Closing substate; default \"done\" (or, for an already-CLOSED task,\n * its current substate). Any CLOSED/* satisfies edges. */\n as?: CloseSubstate;\n /** Required (non-empty) unless `as` is \"done\"; stored as a\n * `<AS>: <why>` note in the same op group. */\n why?: string;\n}\n\n/** Result of a close that ran (not skipped). */\nexport interface CloseTaskResult extends SetStatusResult {\n /** Direct same-workstream dependents that entered the `ready` view\n * because of this close, sorted. Computed only when `as` is not\n * \"done\" (spec D3: a non-done close must show what it released);\n * always [] for a done close. */\n unblocked: string[];\n}\n\n/** Convenience: setTaskStatus(db, id, \"CLOSED\"). Accepts evidence.\n * Notes are skipped for the idempotent no-op (already CLOSED with the\n * same substate; a bare close without `as` keeps the current one) so\n * retry loops don't accumulate duplicates.\n *\n * With `ifReady: true`, returns a `CloseSkippedResult` (no mutation,\n * no snapshot) when any blocker is still OPEN / IN_PROGRESS. Used by\n * `mu task close --if-ready` so an orchestrator can fire-and-forget\n * the umbrella close after every blocker resolves without first\n * re-querying the graph. */\nexport function closeTask(\n db: Db,\n localId: string,\n opts: CloseTaskOptions,\n): CloseTaskResult | CloseSkippedResult {\n // Validate before any write (and before withOpContext mints a group).\n const as = opts.as ?? \"done\";\n if (!isValidPair(\"CLOSED\", as)) throw new InvalidSubstateError(\"CLOSED\", as);\n if (as !== \"done\" && (opts.why === undefined || opts.why.trim() === \"\")) {\n throw new SubstateReasonRequiredError(\"close\", as, localId);\n }\n return withOpContext(db, { intent: \"task.close\", actor: opts.author, group: \"new\" }, () =>\n closeTaskImpl(db, localId, opts),\n );\n}\n\nfunction closeTaskImpl(\n db: Db,\n localId: string,\n opts: CloseTaskOptions,\n): CloseTaskResult | CloseSkippedResult {\n const before = getTask(db, localId, opts.workstream);\n // A bare re-close (no --as) of an already-CLOSED task keeps its\n // substate, so it stays the idempotent no-op the help promises\n // instead of rewriting wontfix/rejected/duplicate to done.\n const as: CloseSubstate =\n opts.as ?? (before?.status === \"CLOSED\" ? (before.substate as CloseSubstate) : \"done\");\n if (opts.ifReady && before) {\n // Inspect direct blockers only — the umbrella convention is one\n // hop (umbrella -[blocked-by]→ each wave task). If any direct\n // blocker is not CLOSED, the umbrella isn't ready.\n const edges = getTaskEdgesWithStatus(db, localId, before.workstreamName);\n const blocking = edges.blockers\n .filter((e) => e.status !== \"CLOSED\")\n .map((e) => e.name)\n .sort();\n if (blocking.length > 0) {\n return {\n skipped: \"not_ready\",\n previousStatus: before.status,\n status: before.status,\n previousSubstate: before.substate,\n substate: before.substate,\n changed: false,\n blockingIds: blocking,\n };\n }\n }\n // No pre-mutation snapshot: v9 dropped the `snapshots` table and\n // rollback is inverse ops over the ops log (`mu undo`).\n return db\n .transaction((): CloseTaskResult => {\n const track = as !== \"done\" && before !== undefined;\n const readyBefore = track ? readyDependents(db, localId, before.workstreamName) : [];\n const r = setTaskStatus(db, localId, \"CLOSED\", {\n workstream: opts.workstream,\n substate: as,\n ...(opts.evidence !== undefined ? { evidence: opts.evidence } : {}),\n });\n if (!r.changed || !before) return { ...r, unblocked: [] };\n recordReasonNote(db, localId, before.workstreamName, as, opts.why, opts.author);\n // mufeedback task_close_evidence_does_not_append_the: evidence must\n // reach `mu task notes <id>` / `mu task show <id>`, not just the log.\n // Since v2-retire-log-shim the note is the ONLY home for it.\n recordEvidenceNote(db, localId, before.workstreamName, \"CLOSE\", opts);\n const unblocked = track\n ? readyDependents(db, localId, before.workstreamName).filter(\n (n) => !readyBefore.includes(n),\n )\n : [];\n return { ...r, unblocked };\n })\n .immediate();\n}\n\n/** Direct dependents of `localId` currently in the `ready` view, sorted.\n * Edges never cross workstreams, so these are all in `workstream`. */\nfunction readyDependents(db: Db, localId: string, workstream: string): string[] {\n const id = taskIdFor(db, localId, workstream);\n if (id === null) return [];\n const rows = db\n .prepare(\n `SELECT r.local_id AS name FROM task_edges e\n JOIN ready r ON r.id = e.to_task_id\n WHERE e.from_task_id = ? ORDER BY r.local_id`,\n )\n .all(id) as { name: string }[];\n return rows.map((r) => r.name);\n}\n\n/** Store a classification's `--why` as a `<SUBSTATE>: <why>` note\n * (e.g. `WONTFIX: out of scope`). Notes are captured, so it syncs,\n * and it lands in the enclosing verb's op group. No-op for an empty\n * reason (a done close needs none). */\nfunction recordReasonNote(\n db: Db,\n localId: string,\n workstream: string,\n substate: TaskSubstate,\n why: string | undefined,\n author: string | undefined,\n): void {\n if (why === undefined || why.trim() === \"\") return;\n const noteOpts: { author?: string; workstream: string } = { workstream };\n if (author !== undefined && author !== \"\") noteOpts.author = author;\n const text =\n substate === \"rejected\" || substate === \"superseded\"\n ? withTitles(db, why, workstream, localId)\n : why;\n // insertNote, not addNote: the note joins the verb's group and\n // intent instead of minting its own, so one undo reverts both.\n insertNote(db, localId, `${substate.toUpperCase()}: ${text}`, noteOpts);\n}\n\n/** A token shaped like a task id, not inside a word, path, or file\n * name: never preceded by a word char, `.`, `/` or `-`, and never\n * followed by an extension (`fix.ts`) or a line number (`fix:12`). */\nconst TASK_ID_TOKEN = /(?<![\\w./-])[a-z][a-z0-9_-]{0,63}(?![\\w-]|\\.\\w|:\\d)/g;\n\n/** {@link TASK_ID_TOKEN}, plus an optional parenthetical opener right\n * after it (group 1), so the title can merge into it. */\nconst TASK_ID_WITH_PAREN = new RegExp(`(?:${TASK_ID_TOKEN.source})(\\\\s*\\\\()?`, \"g\");\n\n/** Ids in `text` naming another task in `workstream`. */\nfunction namedTaskIds(db: Db, text: string, workstream: string, self: string): string[] {\n const ids = (text.match(TASK_ID_TOKEN) ?? []).filter((t) => t !== self);\n return [...new Set(ids)].filter((t) => getTask(db, t, workstream) !== undefined);\n}\n\n/** Append each named task's title after its id, so a REJECTED /\n * SUPERSEDED note reads without looking the ids up: `f2 (title)`.\n * An id already followed by a parenthetical (the skill's REJECT form\n * `<id> (<why it fails>)`) gets one merged parenthetical instead:\n * `f2 (title; why it fails)`. Text that names no task in the\n * workstream is left as is. */\nfunction withTitles(db: Db, why: string, workstream: string, self: string): string {\n const named = new Set(namedTaskIds(db, why, workstream, self));\n if (named.size === 0) return why;\n return why.replace(TASK_ID_WITH_PAREN, (match: string, paren: string | undefined) => {\n const id = paren === undefined ? match : match.slice(0, -paren.length);\n if (!named.has(id)) return match;\n const title = getTask(db, id, workstream)?.title ?? \"\";\n return paren === undefined ? `${id} (${title})` : `${id} (${title}; `;\n });\n}\n\n/** Below this many characters a decision reason names no check. */\nexport const WEAK_REASON_CHARS = 40;\n\n/** A note line recording a verdict: `VERDICT: …`, or the header\n * `REFUTER <label> (...)` a recorded delegate answer starts with. */\nconst VERDICT_LINE = /^\\s*(VERDICT:|REFUTER\\s)/m;\n\n/**\n * Decision-time guardrail for a finding. Returns one warning (or\n * none) for accepting a task in triage (`kind: \"accept\"`, reason =\n * `--evidence`) or closing it as rejected / wontfix / duplicate\n * (reason = `--why`). Warns only when the task is OPEN/triage, the\n * reason is missing or under {@link WEAK_REASON_CHARS} chars, and no\n * note records a verdict. A duplicate whose reason names an existing\n * task is fine. Read-only: call it before the verb writes.\n */\nexport function weakDecisionWarning(\n db: Db,\n localId: string,\n workstream: string,\n kind: \"accept\" | CloseSubstate,\n reason: string | undefined,\n): string | undefined {\n if (kind === \"done\" || kind === \"superseded\") return undefined;\n const task = getTask(db, localId, workstream);\n if (task?.status !== \"OPEN\" || task.substate !== \"triage\") return undefined;\n const trimmed = (reason ?? \"\").trim();\n if (trimmed.length >= WEAK_REASON_CHARS) return undefined;\n if (kind === \"duplicate\" && namedTaskIds(db, trimmed, workstream, localId).length > 0) {\n return undefined;\n }\n if (listNotes(db, localId, workstream).some((n) => VERDICT_LINE.test(n.content))) {\n return undefined;\n }\n const flag = kind === \"accept\" ? \"--evidence\" : \"--why\";\n const what = trimmed === \"\" ? `no ${flag}` : `${flag} is ${trimmed.length} chars`;\n return `${localId}: ${kind === \"accept\" ? \"accepting\" : `closing as ${kind}`} a finding with ${what} and no verdict recorded (no VERDICT: line or REFUTER note); record what confirmed it`;\n}\n\n/** Convenience: setTaskStatus(db, id, \"OPEN\"). Owner intentionally NOT\n * cleared — use `releaseTask` for that. Accepts evidence. */\nexport function openTask(\n db: Db,\n localId: string,\n opts: AttributedEvidence & { workstream: string },\n): SetStatusResult {\n return withOpContext(db, { intent: \"task.open\", actor: opts.author, group: \"new\" }, () => {\n const before = getTask(db, localId, opts.workstream);\n const r = setTaskStatus(db, localId, \"OPEN\", {\n workstream: opts.workstream,\n ...(opts.evidence !== undefined ? { evidence: opts.evidence } : {}),\n });\n if (r.changed && before) recordEvidenceNote(db, localId, before.workstreamName, \"OPEN\", opts);\n return r;\n });\n}\n\nexport interface ParkTaskOptions extends EvidenceOption {\n workstream: string;\n /** Required, non-empty; stored as a `PARKED: <why>` note. */\n why: string;\n author?: string;\n}\n\n/**\n * OPEN/todo → OPEN/parked: keep the task out of `ready` / `next` and\n * make `claim` refuse it without `--force`. Its dependents stay blocked\n * (parked is still OPEN). Idempotent on OPEN/parked (no second note).\n * Refuses IN_PROGRESS (release first) and CLOSED (open first) — one\n * verb, one transition.\n */\nexport function parkTask(db: Db, localId: string, opts: ParkTaskOptions): SetStatusResult {\n if (opts.why.trim() === \"\") throw new SubstateReasonRequiredError(\"park\", \"parked\", localId);\n return withOpContext(db, { intent: \"task.park\", actor: opts.author, group: \"new\" }, () =>\n db\n .transaction((): SetStatusResult => {\n const before = getTask(db, localId, opts.workstream);\n if (!before) throw new TaskNotFoundError(localId);\n if (before.status !== \"OPEN\") {\n throw new TaskParkStateError(localId, before.status, before.workstreamName);\n }\n const r = setTaskStatus(db, localId, \"OPEN\", {\n workstream: opts.workstream,\n substate: \"parked\",\n });\n if (r.changed) {\n recordReasonNote(db, localId, before.workstreamName, \"parked\", opts.why, opts.author);\n recordEvidenceNote(db, localId, before.workstreamName, \"PARK\", opts);\n }\n return r;\n })\n .immediate(),\n );\n}\n\n/**\n * OPEN/triage → OPEN/todo: accept a proposed task (a review finding) as\n * real work, back in `ready` / `next`. A no-op (`changed: false`) on any\n * other pair. Declining is `close --as rejected | duplicate --why`.\n */\nexport function acceptTask(\n db: Db,\n localId: string,\n opts: AttributedEvidence & { workstream: string },\n): SetStatusResult {\n return withOpContext(db, { intent: \"task.accept\", actor: opts.author, group: \"new\" }, () =>\n db\n .transaction((): SetStatusResult => {\n const before = getTask(db, localId, opts.workstream);\n if (!before) throw new TaskNotFoundError(localId);\n if (before.status !== \"OPEN\" || before.substate !== \"triage\") {\n return {\n previousStatus: before.status,\n status: before.status,\n previousSubstate: before.substate,\n substate: before.substate,\n changed: false,\n };\n }\n const r = setTaskStatus(db, localId, \"OPEN\", { workstream: opts.workstream });\n recordEvidenceNote(db, localId, before.workstreamName, \"ACCEPT\", opts);\n return r;\n })\n .immediate(),\n );\n}\n\n/** OPEN/parked → OPEN/todo. A no-op (`changed: false`) on any other pair. */\nexport function unparkTask(\n db: Db,\n localId: string,\n opts: AttributedEvidence & { workstream: string },\n): SetStatusResult {\n return withOpContext(db, { intent: \"task.unpark\", actor: opts.author, group: \"new\" }, () =>\n db\n .transaction((): SetStatusResult => {\n const before = getTask(db, localId, opts.workstream);\n if (!before) throw new TaskNotFoundError(localId);\n if (before.status !== \"OPEN\" || before.substate !== \"parked\") {\n return {\n previousStatus: before.status,\n status: before.status,\n previousSubstate: before.substate,\n substate: before.substate,\n changed: false,\n };\n }\n const r = setTaskStatus(db, localId, \"OPEN\", { workstream: opts.workstream });\n recordEvidenceNote(db, localId, before.workstreamName, \"UNPARK\", opts);\n return r;\n })\n .immediate(),\n );\n}\n","// mu — claim/release/resolveActorIdentity verbs.\n//\n// claimTask is the heart of mu's coordination protocol: an atomic\n// CAS via a single SQL UPDATE, with two flavours:\n//\n// \"worker claim\" : --for <name> sets owner_id to that agent (FK to agents.id)\n// \"anonymous claim\": --self keeps owner_id=NULL but flips status to\n// IN_PROGRESS and records the actor\n// in agent_logs\n//\n// resolveActorIdentity is the env-aware identity helper:\n// $MU_AGENT_NAME > pane title > $USER > 'orchestrator'. Used by --self\n// AND by the bare worker-claim path, so both flavours answer \"who am\n// I?\" identically.\n//\n// Extracted from src/tasks.ts as part of refactor_split_large_src_files.\n\nimport type { Db } from \"../db.js\";\nimport { activeMux } from \"../mux.js\";\nimport { withOpContext } from \"../op-context.js\";\nimport {\n ClaimerNotRegisteredError,\n TaskAlreadyOwnedError,\n TaskInTriageError,\n TaskNotFoundError,\n TaskParkedError,\n} from \"./errors.js\";\nimport { type AttributedEvidence, recordEvidenceNote } from \"./lifecycle.js\";\nimport { getTask } from \"./queries.js\";\nimport { DEFAULT_SUBSTATE, type TaskStatus } from \"./status.js\";\n\nexport interface ReleaseResult {\n /** The previous owner (null if the task was already unowned). */\n previousOwnerName: string | null;\n /** Status before the release. */\n previousStatus: TaskStatus;\n /** Status after the release. */\n status: TaskStatus;\n /** True iff owner OR status actually changed. */\n changed: boolean;\n}\n\nexport interface ReleaseTaskOptions extends AttributedEvidence {\n /** Workstream context for the task (v5: tasks.local_id is\n * per-workstream unique). */\n workstream: string;\n /** Force `status = OPEN` regardless of the current status. Without\n * this flag, `IN_PROGRESS` is also flipped to `OPEN` automatically\n * (so a released task isn't left structurally stranded with\n * `owner=NULL, status=IN_PROGRESS`); CLOSED is preserved.\n * `--reopen` is the override for the rarer \"un-close and hand\n * back to the pool\" workflow. */\n reopen?: boolean;\n}\n\n/**\n * Release a task: clear `tasks.owner`.\n *\n * Status side-effects (review_release_open_in_progress_inconsistency):\n * - IN_PROGRESS → OPEN automatically (without it, the task is\n * stranded: no owner to drive it forward, but `mu task next`\n * skips it because it's not OPEN).\n * - OPEN / CLOSED preserved.\n * - `--reopen` forces OPEN regardless of current status — the\n * escape hatch for un-closing a CLOSED owned task in one verb.\n *\n * Idempotent: releasing an already-unowned task with no `--reopen` and\n * no IN_PROGRESS status is a no-op (returns `changed: false`).\n * Throws TaskNotFoundError on missing.\n */\nexport function releaseTask(db: Db, localId: string, opts: ReleaseTaskOptions): ReleaseResult {\n return withOpContext(db, { intent: \"task.release\", actor: opts.author, group: \"new\" }, () =>\n releaseTaskImpl(db, localId, opts),\n );\n}\n\nfunction releaseTaskImpl(db: Db, localId: string, opts: ReleaseTaskOptions): ReleaseResult {\n const before = getTask(db, localId, opts.workstream);\n if (!before) throw new TaskNotFoundError(localId);\n\n // Default: auto-flip IN_PROGRESS → OPEN so the released task isn't\n // left in the structurally weird owner=NULL/IN_PROGRESS limbo.\n // --reopen still wins for any status (including CLOSED).\n const newStatus: TaskStatus = opts.reopen\n ? \"OPEN\"\n : before.status === \"IN_PROGRESS\"\n ? \"OPEN\"\n : before.status;\n const ownerChanges = before.ownerName !== null;\n const statusChanges = newStatus !== before.status;\n\n if (!ownerChanges && !statusChanges) {\n return {\n previousOwnerName: before.ownerName,\n previousStatus: before.status,\n status: before.status,\n changed: false,\n };\n }\n\n // No pre-mutation snapshot: v9 dropped the `snapshots` table and\n // rollback is inverse ops over the ops log (`mu undo`).\n\n db.prepare(\n `UPDATE tasks SET owner_id = NULL, status = ?, substate = ?, updated_at = ?\n WHERE local_id = ?\n AND workstream_id = (SELECT id FROM workstreams WHERE name = ?)`,\n ).run(\n newStatus,\n statusChanges ? DEFAULT_SUBSTATE[newStatus] : before.substate,\n new Date().toISOString(),\n localId,\n before.workstreamName,\n );\n // No emitEvent: the UPDATE fired the capture trigger\n // (intent='task.release'), whose payload names owner_id and status —\n // the same facts the prose spelled out. Evidence goes to a note,\n // since the prose payload that used to carry it is gone.\n recordEvidenceNote(db, localId, before.workstreamName, \"RELEASE\", opts);\n return {\n previousOwnerName: before.ownerName,\n previousStatus: before.status,\n status: newStatus,\n changed: true,\n };\n}\n\n// ─── claimTask (verb) ──────────────────────────────────────────────────\n\nexport interface ClaimTaskOptions extends AttributedEvidence {\n /** Workstream context for both the task and the claiming agent.\n * v5: agents.name and tasks.local_id are per-workstream unique;\n * the task lookup AND the agent FK lookup scope to this\n * workstream so a same-named task or worker elsewhere can't be\n * silently picked. The CLI always passes this from the resolved\n * -w / $MU_SESSION. */\n workstream: string;\n /**\n * Override the agent name. If omitted, resolved from the ambient\n * environment via `resolveWorkerIdentity()`: `$MU_AGENT_NAME` first,\n * then the current pane's title.\n *\n * Mutually exclusive with `self: true`.\n */\n agentName?: string;\n /**\n * Workstream that the claimer agent lives in. When omitted, defaults\n * to `opts.workstream` (today's same-workstream behaviour). Set by\n * the CLI when `mu task claim X -w A --for B/worker-1` qualifies the\n * `--for` ref with a different workstream prefix\n * (`task_claim_for_cross_workstream`).\n *\n * Cross-workstream ownership is structurally allowed by the schema:\n * `tasks.owner_id` is an INTEGER FK to `agents.id` with no\n * workstream qualifier on the agent side. The per-workstream UNIQUE\n * on `agents(workstream_id, name)` is what previously made the\n * SDK's name → id lookup scope to one workstream; this option\n * widens that lookup to a different workstream when the operator\n * dispatches across a workstream boundary. The agent's own\n * workstream remains unchanged — only the task's `owner_id` points\n * out-of-workstream.\n */\n agentWorkstream?: string;\n /**\n * Anonymous claim: write `owner_id = NULL` instead of resolving an agent\n * name and checking the FK. Use when the actor is the orchestrator\n * (or a script, or a human) doing direct work in a workstream they\n * aren't a registered worker in.\n *\n * The actor name is still recorded — it ends up in `agent_logs.source`\n * for the auto-emitted `task claim` event — so provenance is preserved.\n * Just not in the FK column.\n *\n * Resolution order for the actor name (used as the log source):\n * 1. `actor` if explicitly passed.\n * 2. `$MU_AGENT_NAME`.\n * 3. The mux's current agent name (pane title on tmux).\n * 4. `$USER`.\n * 5. The literal string 'orchestrator'.\n *\n * Mutually exclusive with `agentName` (the two are alternative\n * answers to \"who's the actor for this claim?\"). Passing both is a\n * usage error.\n */\n self?: boolean;\n /**\n * Override the actor name used for the log source when `self: true`.\n * Ignored when `self: false`. Useful when the orchestrator wants to\n * attribute the work to a meaningful name rather than the pane\n * title (e.g. \"deploy-bot\" rather than \"pi-mu\").\n */\n actor?: string;\n /**\n * Claim an OPEN/parked task anyway. Without it, a parked task throws\n * TaskParkedError before any write: parking means \"keep out of the\n * scheduler\", so overriding it must be explicit.\n */\n force?: boolean;\n}\n\nexport interface ClaimResult {\n /** The agent now owning the task, or null when the claim was anonymous (--self). */\n ownerName: string | null;\n /** The actor recorded in the agent_logs event — the agent name for a\n * registered-worker claim, or the resolved actor for --self. */\n actorName: string;\n /** The previous owner (null if it was unowned). */\n previousOwnerName: string | null;\n /** The status BEFORE the claim; post-claim is IN_PROGRESS unless was CLOSED. */\n previousStatus: TaskStatus;\n /** The status AFTER the claim. */\n status: TaskStatus;\n}\n\n/**\n * Claim a task. Two modes:\n *\n * Worker claim (default):\n * Resolve an agent name from `opts.agentName`, else $MU_AGENT_NAME,\n * else the mux's current agent name (pane title on tmux). The name\n * MUST exist in the agents table (`tasks.owner_id` is an FK to\n * `agents.id`). Sets `owner_id` to that agent. This is what mu-spawned\n * workers do, and what `mu task claim --for <worker>` does for\n * orchestrator dispatch.\n *\n * Anonymous claim (--self):\n * Skip the name -> agents FK lookup entirely. Sets `owner_id = NULL`.\n * Records the actor in `agent_logs.source` instead. This is the\n * orchestrator-doing-direct-work path — the actor is logged but\n * not registered as a worker pane.\n *\n * Status side-effect: OPEN -> IN_PROGRESS; IN_PROGRESS / CLOSED unchanged.\n *\n * Concurrency: the worker-claim path uses a single-statement CAS UPDATE\n * with `WHERE owner IS NULL OR owner = ?` so two workers racing to\n * claim the same task can't both win. The anonymous path uses\n * `WHERE owner IS NULL` (anonymous claims don't 'own' the task in any\n * exclusive sense; if it's already owned by anyone, the anonymous claim\n * is a TaskAlreadyOwnedError just like a worker claim would be).\n */\nexport async function claimTask(\n db: Db,\n localId: string,\n opts: ClaimTaskOptions,\n): Promise<ClaimResult> {\n // claimTask is async (it shells out to tmux to resolve the caller's\n // identity), and withOpContext is deliberately sync — see its doc\n // comment. So set the context around the SYNCHRONOUS mutation legs\n // inside, not around the whole async function.\n return claimTaskImpl(db, localId, opts);\n}\n\nasync function claimTaskImpl(\n db: Db,\n localId: string,\n opts: ClaimTaskOptions,\n): Promise<ClaimResult> {\n if (opts.self === true && opts.agentName !== undefined) {\n throw new Error(\"claimTask: --self and --for are mutually exclusive\");\n }\n\n if (opts.self === true) {\n return claimSelf(db, localId, opts);\n }\n\n // ── Worker claim path (registered agent owns the task) ──\n const agentName = opts.agentName ?? (await resolveWorkerIdentity());\n if (!agentName) {\n throw new Error(\n \"claimTask: no agent name (pass opts.agentName, run inside an mu-spawned pane with $MU_AGENT_NAME or $TMUX_PANE set, or pass --self for an anonymous claim)\",\n );\n }\n\n // Resolve the claiming agent to its surrogate id within the agent's\n // workstream — defaults to opts.workstream (today's same-ws path),\n // or opts.agentWorkstream when the CLI dispatched across a\n // workstream boundary via a qualified `--for <ws>/<name>` ref\n // (task_claim_for_cross_workstream).\n //\n // The schema permits cross-workstream owner_id assignment (FK to\n // agents.id only); the per-workstream UNIQUE on agents.name is the\n // only reason this SELECT was scoped narrowly before. Bare-name\n // dispatch keeps that scope to honour today's behaviour; qualified\n // dispatch widens it to the named workstream so the agent resolves\n // there.\n const claimerWorkstream = opts.agentWorkstream ?? opts.workstream;\n const claimerRow = db\n .prepare(\n `SELECT a.id AS id\n FROM agents a JOIN workstreams ws ON ws.id = a.workstream_id\n WHERE a.name = ? AND ws.name = ?`,\n )\n .get(agentName, claimerWorkstream) as { id: number } | undefined;\n if (!claimerRow) {\n const paneIdFromEnv = opts.agentName === undefined ? (process.env.TMUX_PANE ?? null) : null;\n throw new ClaimerNotRegisteredError(agentName, paneIdFromEnv);\n }\n\n return withOpContext(db, { intent: \"task.claim\", actor: agentName, group: \"new\" }, () =>\n db\n .transaction(() => {\n // Resolve the task within opts.workstream. This locks the\n // (workstream, local_id) pair for the rest of the transaction.\n const before = getTask(db, localId, opts.workstream);\n if (!before) throw new TaskNotFoundError(localId);\n assertNotParked(before, opts);\n\n const now = new Date().toISOString();\n const result = db\n .prepare(\n `UPDATE tasks\n SET owner_id = ?,\n status = CASE WHEN status = 'OPEN' THEN 'IN_PROGRESS' ELSE status END,\n -- SQLite evaluates every SET expression against the OLD\n -- row, so this CASE still sees the pre-claim status.\n substate = CASE WHEN status = 'OPEN' THEN 'active' ELSE substate END,\n updated_at = ?\n WHERE local_id = ?\n AND workstream_id = (SELECT id FROM workstreams WHERE name = ?)\n AND (owner_id IS NULL OR owner_id = ?)`,\n )\n .run(claimerRow.id, now, localId, opts.workstream, claimerRow.id);\n\n if (result.changes === 0) {\n throw new TaskAlreadyOwnedError(localId, before.ownerName ?? \"<unknown>\");\n }\n\n const after = getTask(db, localId, opts.workstream);\n if (!after) throw new Error(`claimTask: row missing after update: ${localId}`);\n // The CLAIM note's author: the dispatcher when the CLI passed one\n // (`--for`), else the claiming agent.\n recordEvidenceNote(db, localId, opts.workstream, \"CLAIM\", {\n ...opts,\n author: opts.author ?? agentName,\n });\n // No emitEvent: the UPDATE fired the capture trigger under\n // intent='task.claim' with actor=agentName (withOpContext above\n // put it in _op_ctx, and the trigger copies it into ops.actor).\n // The op payload carries the new owner_id, so the prose\n // `formatClaimEvent` breadcrumb — and the tab-delimited prefix\n // that existed only because prose had to be re-parsed — are both\n // redundant. `lastClaimActor` now reads ops.actor directly.\n return {\n ownerName: agentName,\n actorName: agentName,\n previousOwnerName: before.ownerName,\n previousStatus: before.status,\n status: after.status,\n };\n })\n .immediate(),\n );\n}\n\n/** The parked-claim guard shared by the worker and --self paths. The\n * UPDATE's `status = 'OPEN'` CASE already maps parked → active, so a\n * forced claim needs nothing else. */\nfunction assertNotParked(\n task: { name: string; status: TaskStatus; substate: string; workstreamName: string },\n opts: ClaimTaskOptions,\n): void {\n if (task.status === \"OPEN\" && task.substate === \"parked\" && opts.force !== true) {\n throw new TaskParkedError(task.name, task.workstreamName);\n }\n if (task.status === \"OPEN\" && task.substate === \"triage\" && opts.force !== true) {\n throw new TaskInTriageError(task.name, task.workstreamName);\n }\n}\n\n/**\n * Resolve the current actor's identity for attribution in task notes,\n * --self claims, and any other write that wants 'who did this?'.\n *\n * Resolution order:\n * 1. $MU_AGENT_NAME env var (set by mu spawnAgent on every managed\n * pane; surfaced from the f3d4bdd commit). Authoritative when\n * present — you're inside a mu-spawned worker, no ambiguity.\n * 2. tmux pane title (the pane-title identity step). Works\n * when running inside any pane mu manages OR adopted.\n * 3. $USER (when running outside tmux entirely).\n * 4. The literal 'orchestrator' as a last-resort default.\n *\n * Why prefer env over pane title: pane titles are a tmux-server-wide\n * resource that anything can rewrite. The env var is set per-pane at\n * spawn time and is unforgeable from outside without explicit\n * `--actor` override. Pane title is the only identity available for\n * adopted panes that didn't go through mu's spawn path.\n */\nexport async function resolveActorIdentity(): Promise<string> {\n const worker = await resolveWorkerIdentity();\n if (worker !== undefined) return worker;\n const user = process.env.USER;\n if (user !== undefined && user !== \"\") return user;\n return \"orchestrator\";\n}\n\n/**\n * The AGENT-identity half of the ladder, shared by `resolveActorIdentity`\n * and the bare worker-claim path. Returns undefined when the caller\n * isn't identifiable as a specific agent — the two callers disagree\n * about what to do then, which is why this stops short rather than\n * falling through to `$USER`:\n *\n * - `resolveActorIdentity` continues to `$USER` / 'orchestrator',\n * because an anonymous claim only needs an attribution string.\n * - the worker-claim path THROWS, because `tasks.owner_id` is a real\n * FK to `agents.id` and '$USER' is not an agent. Falling back there\n * would turn a clear \"who are you?\" error into a confusing\n * ClaimerNotRegisteredError naming the operator's unix login.\n *\n * Rungs:\n * 1. `$MU_AGENT_NAME` — injected into every pane by spawnAgent.\n * Backend-independent, and the only rung that works on a mux with\n * no mu-writable pane title.\n * 2. The mux backend's `currentAgentName()` — pane title on tmux.\n * Parses 'name · status · task' back to the name token, which\n * matters because composeAgentTitle decorates titles and the FK is\n * keyed on the bare `agents.name`.\n *\n * Why env before title: a pane title is a mux-server-wide resource that\n * any process can rewrite, while the env var is set once at spawn and\n * is unforgeable from outside the pane. The title rung survives only\n * because ADOPTED panes never went through spawn and have nothing else.\n */\nexport async function resolveWorkerIdentity(): Promise<string | undefined> {\n const muAgent = process.env.MU_AGENT_NAME;\n if (muAgent !== undefined && muAgent !== \"\") return muAgent;\n // Best-effort: identity resolution must never be the thing that fails\n // a verb. A non-interactive command on a box with no multiplexer wants an\n // attribution string, not a NoMultiplexerError — and the caller\n // already has $USER / 'orchestrator' rungs below this one.\n try {\n const paneTitle = await (await activeMux()).currentAgentName();\n if (paneTitle !== undefined && paneTitle !== \"\") return paneTitle;\n } catch {\n // No reachable mux, or it could not answer. Fall through.\n }\n return undefined;\n}\n\nasync function claimSelf(db: Db, localId: string, opts: ClaimTaskOptions): Promise<ClaimResult> {\n const actor =\n opts.actor !== undefined && opts.actor !== \"\" ? opts.actor : await resolveActorIdentity();\n return withOpContext(db, { intent: \"task.claim\", actor, group: \"new\" }, () =>\n db\n .transaction(() => {\n // Scope by the operator's workstream so a same-named task\n // elsewhere can't be self-claimed by accident.\n const before = getTask(db, localId, opts.workstream);\n if (!before) throw new TaskNotFoundError(localId);\n assertNotParked(before, opts);\n\n // Anonymous claim: owner stays NULL, status flips OPEN -> IN_PROGRESS.\n // Gate on `owner_id IS NULL` so an in-flight worker claim can't be\n // silently overwritten.\n const now = new Date().toISOString();\n const result = db\n .prepare(\n `UPDATE tasks\n SET status = CASE WHEN status = 'OPEN' THEN 'IN_PROGRESS' ELSE status END,\n substate = CASE WHEN status = 'OPEN' THEN 'active' ELSE substate END,\n updated_at = ?\n WHERE local_id = ?\n AND workstream_id = (SELECT id FROM workstreams WHERE name = ?)\n AND owner_id IS NULL`,\n )\n .run(now, localId, before.workstreamName);\n\n if (result.changes === 0) {\n // Task exists but is already owned (by someone). Mirror the\n // worker-path error so callers can pattern-match consistently.\n throw new TaskAlreadyOwnedError(localId, before.ownerName ?? \"<unknown>\");\n }\n\n const after = getTask(db, localId, before.workstreamName);\n if (!after) throw new Error(`claimTask: row missing after update: ${localId}`);\n recordEvidenceNote(db, localId, before.workstreamName, \"CLAIM\", {\n ...opts,\n author: opts.author ?? actor,\n });\n // No emitEvent. This is the interesting case: the `--self` path\n // leaves tasks.owner_id NULL deliberately, so the op PAYLOAD\n // cannot name the actor — but ops.actor can and does, because\n // withOpContext seeded _op_ctx with it. That is precisely what\n // `lastClaimActor` needs, and reading a column beats\n // prefix-matching prose (review_code_last_claim_actor_brittle).\n return {\n ownerName: null,\n actorName: actor,\n previousOwnerName: before.ownerName,\n previousStatus: before.status,\n status: after.status,\n };\n })\n .immediate(),\n );\n}\n","// mu — tmux substrate (back-compat re-export hub).\n//\n// The tmux implementation moved to src/mux/tmux.ts when the MuxBackend\n// interface was extracted, so mu could grow a second multiplexer. This\n// file preserves the historical `import { ... } from \"./tmux.js\"`\n// surface — 12 src modules and 47 test files import it directly, and\n// churning them in the same commit as the extraction would have made\n// the diff unreviewable.\n//\n// NEW CODE SHOULD IMPORT `./mux.js` and go through `activeMux()`.\n// Importing this module pins you to tmux specifically, which is correct\n// only for genuinely tmux-only concerns (the `MU_TMUX_SOCKET` test\n// isolation seam, `mu doctor`'s tmux version probe).\n//\n// Migrating the call sites is tracked by mux-callsite-migration.\n\nexport * from \"./mux/tmux.js\";\n","// Cross-process advisory lock for the tmux-topology critical section of\n// a spawn.\n//\n// Why this exists: every `mu` invocation is a separate short-lived\n// process, so there is no in-process mutex to lean on. When an operator\n// (or the model) fires several spawns in parallel —\n//\n// for n in 1 2 3; do mu agent spawn scout-$n -w scratch & done; wait\n//\n// — each process runs the check-then-act in `createOrReusePane`:\n// `sessionExists(mu-scratch)` → all see \"no\" → all call\n// `tmux new-session -d -s mu-scratch`. Exactly one wins; the losers get\n// \"duplicate session\", throw, and `rollbackSpawn` removes their agent\n// row. Net effect: agents silently dropped (and sometimes duplicated as\n// windows race). bug_parallel_spawn_races_drop_agents.\n//\n// The fix is a filesystem advisory lock keyed on the tmux SESSION name\n// (the shared resource — two spawns into different sessions never\n// contend). It wraps ONLY the fast topology + DB-insert section, NOT the\n// slow liveness/readiness wait, so genuine parallelism (the whole point\n// of `&`) is preserved: process A creates the session and inserts its\n// row, releases, then waits for liveness while process B is already\n// creating its own window.\n//\n// Mechanism: `fs.mkdir` is atomic and fails with EEXIST if the directory\n// exists — the classic lockfile primitive, no extra dependency (honors\n// the ROADMAP anti-feature pledge). A `meta.json` inside records pid +\n// acquisition time for stale-lock diagnostics and breaking.\n\nimport { join } from \"node:path\";\nimport { type FileLockOptions, locksDir, withFileLock } from \"../file-lock.js\";\n\n/** Lock directory path for a given tmux session name. The session name\n * is already validated ([a-z0-9_-] plus the `mu-` prefix), so it is a\n * safe path segment. Exported for tests that need to read the lock's\n * metadata directly via readFileLockMeta. */\nexport function lockPathForSession(session: string): string {\n return join(locksDir(), `spawn-${session}.lock`);\n}\n\n/** Max time to wait to acquire the lock before giving up (ms). A spawn's\n * critical section is sub-second; this is generous headroom for a deep\n * parallel fan-out queued behind one slow tmux server. */\nconst DEFAULT_ACQUIRE_TIMEOUT_MS = 15_000;\n\n/** A held lock older than this is presumed abandoned (a crashed `mu`\n * process that never released) and force-broken. Must comfortably\n * exceed the critical section's real duration. */\nconst STALE_LOCK_MS = 30_000;\n\nexport interface SpawnLockOptions {\n acquireTimeoutMs?: number;\n staleLockMs?: number;\n}\n\n/**\n * Run `fn` while holding the per-session spawn lock.\n *\n * The mechanism (atomic mkdir, stale-lock breaking, release-in-finally,\n * proceed-unlocked-on-non-contention) lives in src/file-lock.ts so\n * segments can reuse it without a second copy. This wrapper owns the\n * session-keyed path and the spawn-specific timeouts.\n */\nexport async function withSpawnLock<T>(\n session: string,\n fn: () => Promise<T>,\n opts?: SpawnLockOptions,\n): Promise<T> {\n const lockOpts: FileLockOptions<T> = {\n acquireTimeoutMs: opts?.acquireTimeoutMs ?? DEFAULT_ACQUIRE_TIMEOUT_MS,\n staleLockMs: opts?.staleLockMs ?? STALE_LOCK_MS,\n timeoutEnvVar: \"MU_SPAWN_LOCK_TIMEOUT_MS\",\n };\n return withFileLock(lockPathForSession(session), session, fn, lockOpts);\n}\n","// mu — agent error classes.\n//\n// Every agent verb that can fail in a typed way has its own error class\n// here. The CLI's classifyError() (src/cli/handle.ts) maps them to exit\n// codes:\n// usage → 2 (AgentAbortNeedsCtlError, AgentFreshNeedsCtlError,\n// AgentSlashCommandUnsupportedError)\n// not found → 3 (AgentNotFoundError)\n// conflict → 4 (AgentExistsError, AgentNameExhaustedError,\n// AgentNotInWorkstreamError,\n// PaneNotInSessionError, WorkspacePreservedError,\n// AgentExtensionOutdatedError, AgentBusyError,\n// WorkspaceOwnerBusyError)\n// timeout → 5 (AgentAbortTimeoutError)\n// failure → 1 (AgentSpawnCliNotFoundError, AgentDiedOnSpawnError,\n// AgentSpawnStartupError, AgentCtlUnreachableError)\n//\n// AgentDiedOnSpawnError + AgentSpawnStartupError reach into spawn.ts for\n// defaultSpawnLivenessMs — a single, narrow cross-cluster import that\n// documents itself in the error message (\"agent died within Nms of\n// spawn\" / \"agent reported a startup error within Nms of spawn\") —\n// and AgentSpawnStartupError for isExecFailureLine, to pick hints that\n// fit the matched line.\n//\n// AgentSpawnCliNotFoundError is the pre-flight cousin of the two\n// post-spawn-detect errors above: thrown BEFORE prestageWorkspace when\n// the resolved `--cli` command's first token doesn't exist on PATH.\n// Distinct from AgentSpawnStartupError so the operator can tell\n// 'I never had a working CLI' from 'CLI started but parked at an error'.\n//\n// Extracted from src/agents.ts as part of refactor_split_large_src_files.\n\nimport type { HasNextSteps, NextStep } from \"../output.js\";\nimport { defaultSpawnLivenessMs, isExecFailureLine } from \"./spawn.js\";\n\n/**\n * Pre-flight failure: the command mu would have spawned in the new\n * pane doesn't resolve to a binary on PATH (and isn't an absolute /\n * relative path that exists + is executable). Thrown by `spawnAgent`\n * BEFORE `prestageWorkspace` so a typo in `--cli` never leaves an\n * orphan workspace dir behind.\n *\n * Source: feedback ws task `fb_agent_spawn_no_validation`. Live\n * dogfood report: `mu agent spawn worker-1 --cli pi-meta` on a host\n * where the `pi-meta` binary wasn't on PATH printed `Spawned worker-1\n * (pi-meta)` and the pane immediately died with `command not found`;\n * the existing 1.5s liveness check sometimes missed it (the shell\n * stays alive after the failed exec). Pre-flighting the PATH lookup\n * surfaces the typo before any side effects (workspace, pane, DB row).\n *\n * Distinct from `AgentSpawnStartupError` (pane alive but parked at an\n * error prompt) and `AgentDiedOnSpawnError` (pane vanished within the\n * liveness window). All three carry different remediation hints, so\n * they're separate types.\n */\nexport class AgentSpawnCliNotFoundError extends Error implements HasNextSteps {\n override readonly name = \"AgentSpawnCliNotFoundError\";\n constructor(\n public readonly cli: string,\n /** First whitespace-separated token of the resolved command — the\n * thing actually missing on PATH. Surfaced verbatim in the\n * message so the operator sees what mu searched for (which may\n * differ from `cli` when `$MU_<UPPER_CLI>_COMMAND` rewrites it). */\n public readonly binary: string,\n /** Name of the env var that mu consulted before falling back to\n * the bare `cli` value (e.g. `MU_PI_META_COMMAND`). Always set\n * to the conventional name so the nextSteps hint can recommend\n * exporting it. */\n public readonly envVarChecked: string,\n ) {\n super(\n `--cli ${cli} resolved to binary \"${binary}\" which is not on PATH (and not an executable absolute/relative path). Refusing to spawn — would create a pane that dies immediately on \"command not found\".`,\n );\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Try the default CLI (the one mu's substrate ships against)\",\n command: \"mu agent spawn <name> --cli pi\",\n },\n {\n intent: \"If you meant a custom alias, set the env var to its real path\",\n command: `export ${this.envVarChecked}=\"<absolute-path-to-binary> [args...]\"`,\n },\n {\n intent: \"List installed CLIs typically supported by mu\",\n command: \"which pi pi-meta claude codex\",\n },\n ];\n }\n}\n\nexport class AgentExistsError extends Error implements HasNextSteps {\n override readonly name = \"AgentExistsError\";\n constructor(public readonly agentName: string) {\n // v5: agent names are UNIQUE per (workstream, name) — the same\n // name can legitimately exist in two different workstreams. The\n // pre-v5 message claimed global uniqueness, which (a) lied about\n // the schema and (b) misled operators into closing the existing\n // agent when the actual fix is `-w <other-ws>`.\n super(`agent already exists in this workstream: ${agentName}`);\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n // v5: agents.workstream_id → workstreams.id; there is no\n // `agents.workstream` column. Use the join so this hint\n // actually runs against a v5 DB.\n intent: \"List which workstream(s) already have an agent by this name\",\n command: `mu sql \"SELECT a.name, ws.name AS workstream FROM agents a JOIN workstreams ws ON ws.id = a.workstream_id WHERE a.name = '${this.agentName}'\"`,\n },\n {\n intent: \"Spawn it in a different workstream (per-workstream unique → no clash)\",\n command: `mu agent spawn ${this.agentName} -w <other-workstream>`,\n },\n {\n intent: \"Or close the existing agent in this workstream and re-spawn\",\n command: `mu agent close ${this.agentName} && mu agent spawn ${this.agentName}`,\n },\n { intent: \"Or pick a different name\", command: \"mu agent spawn <new-name>\" },\n ];\n }\n}\n\n/** `spawn --next-free` found no free valid name near the asked one. */\nexport class AgentNameExhaustedError extends Error implements HasNextSteps {\n override readonly name = \"AgentNameExhaustedError\";\n constructor(\n public readonly agentName: string,\n reason: string,\n ) {\n super(`no free agent name after ${agentName}: ${reason}`);\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Pick a shorter or different name\",\n command: \"mu agent spawn <new-name> --next-free\",\n },\n { intent: \"Or close agents you no longer need\", command: \"mu agent list\" },\n ];\n }\n}\n\nexport class AgentNotFoundError extends Error implements HasNextSteps {\n override readonly name = \"AgentNotFoundError\";\n constructor(\n public readonly agentName: string,\n /** Optional workstream context. When set, the message is enriched\n * with `(in workstream <ws>)` so the verb that hit the miss\n * (e.g. `mu workspace path <agent> -w <ws>`) doesn't leave the\n * operator guessing which scope was searched. Optional so existing\n * call sites that only know the agent name keep their original\n * one-line message. */\n public readonly workstream?: string,\n ) {\n super(\n workstream === undefined\n ? `no such agent: ${agentName}`\n : `no such agent: ${agentName} (in workstream ${workstream})`,\n );\n }\n errorNextSteps(): NextStep[] {\n return [\n { intent: \"List agents in current workstream\", command: \"mu agent list\" },\n { intent: \"List workstreams to choose the right scope\", command: \"mu workstream list\" },\n {\n intent: \"Spawn it now\",\n command: `mu agent spawn ${this.agentName} -w <workstream>`,\n },\n ];\n }\n}\n\n/**\n * Thrown when an entity-targeted verb is invoked with `-w/--workstream\n * <name>` but the named agent lives in a different workstream.\n * Mirrors `TaskNotInWorkstreamError`. Maps to exit code 4 (conflict /\n * wrong scope). Distinguishes \"the user typo'd the workstream\" from\n * \"the agent doesn't exist anywhere\" (which surfaces as\n * `AgentNotFoundError`).\n */\nexport class AgentNotInWorkstreamError extends Error implements HasNextSteps {\n override readonly name = \"AgentNotInWorkstreamError\";\n constructor(\n public readonly agentName: string,\n public readonly expectedWorkstream: string,\n public readonly actualWorkstream: string,\n ) {\n super(`agent ${agentName} is in workstream ${actualWorkstream}, not ${expectedWorkstream}`);\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Use the agent's actual workstream\",\n command: `mu agent show ${this.agentName} -w ${this.actualWorkstream}`,\n },\n {\n intent: \"List agents in the requested workstream\",\n command: `mu agent list -w ${this.expectedWorkstream}`,\n },\n ];\n }\n}\n\n/**\n * `mu agent adopt` of a pane that exists but is not in the workstream's\n * mux session. Distinct from AgentNotInWorkstreamError: the subject is a\n * pane, not an agent, and its owning session is not known without\n * another mux query. Maps to exit code 4 (conflict).\n */\nexport class PaneNotInSessionError extends Error implements HasNextSteps {\n override readonly name = \"PaneNotInSessionError\";\n constructor(\n public readonly paneId: string,\n public readonly workstream: string,\n public readonly expectedSession: string,\n ) {\n super(\n `pane ${paneId} is not in session ${expectedSession}; adopt only takes panes from workstream ${workstream}'s own session`,\n );\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"List the workstream's agents and orphan panes to pick one\",\n command: `mu agent list -w ${this.workstream}`,\n },\n {\n intent: \"Or adopt it into the workstream whose session holds the pane\",\n command: `mu agent adopt ${this.paneId} -w <workstream>`,\n },\n ];\n }\n}\n\n/**\n * Thrown when an agent's pane is created and titled successfully but the\n * spawned process exits within the liveness window (default 1500ms;\n * configurable via `MU_SPAWN_LIVENESS_MS`). The most common cause is the\n * underlying CLI failing fast: a wrapper CLI blocking on a single-instance\n * lock, `claude` rejecting an invalid API key, etc. The agent's last\n * scrollback (when capturable) is attached to help diagnose.\n */\nexport class AgentDiedOnSpawnError extends Error implements HasNextSteps {\n override readonly name = \"AgentDiedOnSpawnError\";\n /** The spawned command is an ssh hop: remote causes, not wrapper locks. */\n readonly remote: boolean;\n constructor(\n public readonly agentName: string,\n public readonly paneId: string,\n public readonly scrollback: string | undefined,\n /** The command the pane ran; an `ssh ...` command gets remote hints. */\n public readonly command?: string,\n /** When it died; default `within <MU_SPAWN_LIVENESS_MS>ms of spawn`. */\n when = `within ${defaultSpawnLivenessMs()}ms of spawn`,\n ) {\n const tail = scrollback?.trim();\n const detail = tail ? `\\n\\n--- pane scrollback ---\\n${tail}\\n--- end scrollback ---` : \"\";\n const remote = /^\\s*ssh\\s/.test(command ?? \"\");\n const cause = remote\n ? 'The command is an ssh hop, so the likely causes are remote: the remote binary is missing, or its env (PATH, provider keys) is absent because ssh runs a non-interactive shell that skips ~/.zshrc / ~/.bashrc (wrap it: $SHELL -ilc \"pi --approve\"); or sshd refused the socket forward (ExitOnForwardFailure=yes kills the connection; check AllowStreamLocalForwarding).'\n : \"Most common cause: the spawned CLI exited immediately (e.g. a wrapper CLI blocking on its instance lock; set MU_<UPPER_CLI>_COMMAND to a non-blocking variant to bypass).\";\n super(`agent ${agentName} died ${when} (pane ${paneId}). ${cause}${detail}`);\n this.remote = remote;\n }\n errorNextSteps(): NextStep[] {\n if (this.remote) {\n return [\n {\n intent: \"See the ssh pieces and the interactive-login-shell recipe\",\n command: \"mu agent remote-env --help\",\n },\n {\n intent: \"Check the remote binary resolves in a login shell\",\n command: \"ssh <host> '$SHELL -ilc \\\"command -v pi\\\"'\",\n },\n {\n intent: \"Keep the pane open to read the remote error (one-off)\",\n command: \"export MU_SPAWN_LIVENESS_MS=0\",\n },\n { intent: \"Run health check\", command: \"mu doctor\" },\n ];\n }\n return [\n {\n intent: \"Inspect the dead pane's scrollback for the underlying error\",\n command: `mu agent read ${this.agentName} -n 100`,\n },\n {\n // agent_spawn_liveness_check_trips_on: per-spawn override is\n // the right scope for one-offs (e.g. wrapper CLIs blocking\n // on a per-project solo lock). Listed first so operators\n // reach for it before exporting an env var that leaks into\n // every subsequent spawn in the shell.\n intent: \"Override per spawn (one-off; no env-var leak)\",\n command: `mu agent spawn ${this.agentName} --command \"<cli> <bypass-flag>\" (e.g. pi-meta --no-solo)`,\n },\n {\n intent:\n \"Make the override the default for this CLI (applies to every subsequent spawn in this shell)\",\n command: 'export MU_PI_COMMAND=\"pi-alt --some-flag\"',\n },\n {\n intent: \"Disable the liveness check (CI / known long-lived sh subprocess)\",\n command: \"export MU_SPAWN_LIVENESS_MS=0\",\n },\n { intent: \"Run health check\", command: \"mu doctor\" },\n ];\n }\n}\n\n/**\n * Thrown when an agent's pane is alive AND staying alive after the\n * liveness window, but its first burst of output matches a known\n * provider-startup-failure pattern (missing API key, auth rejected, …).\n * Source: feedback ws task `agent_spawn_model_auth_failure_counts_as_live`.\n * Live dogfood report: `pi-meta --no-solo --model sonnet:high` printed\n * `Error: No API key found for amazon-bedrock` and parked at a prompt.\n * The pane stayed alive (1.5s liveness check passed) but the worker\n * could never do work — the orchestrator only discovered this when\n * `mu task wait` stalled minutes later.\n *\n * Distinct from `AgentDiedOnSpawnError`:\n * - `AgentDiedOnSpawnError` → pane vanished within the liveness window\n * (CLI exited fast).\n * - `AgentSpawnStartupError` → pane alive, but the captured scrollback\n * tail contains a curated provider-auth-failure pattern.\n * The two carry different remediation hints (CLI override vs. fix the\n * env var), so they're separate types instead of one with a flag.\n *\n * The pattern list is curated and short to keep false-positive risk low\n * — the scan only looks at the last ~30 lines of the 50-line capture\n * taken right after the liveness sleep, so matches naturally come from\n * the CLI's first ~1.5s of output (not arbitrary later prompts the\n * agent might type into).\n */\nexport class AgentSpawnStartupError extends Error implements HasNextSteps {\n override readonly name = \"AgentSpawnStartupError\";\n constructor(\n public readonly agentName: string,\n public readonly paneId: string,\n /** The single scrollback line that matched a known startup-error\n * pattern. Surfaced verbatim in the message so the operator sees\n * what mu saw. */\n public readonly matchedLine: string,\n /** Full captured scrollback (tail-trimmed already by\n * awaitSpawnLiveness). Attached to the message for context. */\n public readonly scrollback: string,\n /** When it was seen; default `within <MU_SPAWN_LIVENESS_MS>ms of spawn`. */\n when = `within ${defaultSpawnLivenessMs()}ms of spawn`,\n ) {\n super(\n `agent ${agentName} reported a startup error ${when} (pane ${paneId}). The pane is alive but the spawned CLI parked at an error prompt instead of becoming a working agent.\\n\\nMatched line: ${matchedLine.trim()}\\n\\n--- pane scrollback ---\\n${scrollback.trim()}\\n--- end scrollback ---`,\n );\n }\n errorNextSteps(): NextStep[] {\n const inspect: NextStep = {\n intent: \"Inspect the parked pane's scrollback for the full error\",\n command: `mu agent read ${this.agentName} -n 100`,\n };\n const disable: NextStep = {\n intent:\n \"Disable the startup-error scan if you actually wanted that prompt (CI / scripted recovery)\",\n command: \"export MU_SPAWN_LIVENESS_MS=0\",\n };\n if (isExecFailureLine(this.matchedLine.trim())) {\n // A shell exec failure, not a provider error: the API-key hints\n // below would point the operator at the wrong problem.\n return [\n inspect,\n {\n intent: \"Check the spawned command resolves in the pane's shell (PATH, typo)\",\n command: `mu agent spawn ${this.agentName} --command \"<full path to the CLI>\"`,\n },\n disable,\n ];\n }\n return [\n inspect,\n {\n // Most common today: the operator picked a model whose\n // provider has no credentials in this env. Default Anthropic\n // is the safe fallback for pi-meta.\n intent: \"Re-spawn with a CLI command whose provider credentials are present\",\n command: `mu agent spawn ${this.agentName} --command \"pi-meta --no-solo\" # default Anthropic`,\n },\n {\n intent: \"Or set the missing API key env var for the provider you wanted, then re-spawn\",\n command:\n \"export ANTHROPIC_API_KEY=... # or AWS_BEARER_TOKEN_BEDROCK, OPENAI_API_KEY, ...\",\n },\n disable,\n ];\n }\n}\n\n/**\n * Thrown when `closeAgent` is called on an agent that has an associated\n * workspace AND the caller didn't explicitly opt into discarding it.\n *\n * Background: the FK on `vcs_workspaces.agent` cascades on agent\n * delete, so a naive `closeAgent` drops the workspace registry row\n * but leaves the on-disk dir orphaned (mu can't see it via\n * `mu workspace list / free / path` afterwards). Surfaced during\n * the multi-agent dogfood teardown when three workspaces went\n * orphaned silently.\n *\n * The fix: refuse close if a workspace exists; force the caller to\n * decide. Two actionable resolutions:\n * - `mu workspace free <agent>` first, then close cleanly.\n * - `mu agent close <agent> --discard-workspace` to free the\n * workspace AND close the agent in one shot (lossy: pending\n * changes in the workspace are gone).\n *\n * Maps to exit code 4 (conflict) via the cli.ts handler.\n */\nexport class WorkspacePreservedError extends Error implements HasNextSteps {\n override readonly name = \"WorkspacePreservedError\";\n constructor(\n public readonly agentName: string,\n public readonly workspacePath: string,\n ) {\n super(\n `agent ${agentName} has a workspace at ${workspacePath}; refusing to close (would orphan the on-disk dir)`,\n );\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Free the workspace first (preserves agent for next step)\",\n command: `mu workspace free ${this.agentName} (--commit to commit pending changes first)`,\n },\n {\n intent: \"Or close + discard the workspace in one shot (lossy)\",\n command: `mu agent close ${this.agentName} --discard-workspace`,\n },\n {\n intent: \"Or just inspect what's in the workspace\",\n command: `cd ${this.workspacePath}`,\n },\n ];\n }\n}\n\n/**\n * The agent's pane and pi are up, but nothing answers on its control\n * socket (`MU_CTL_SOCK`): the mu pi extension is not loaded, or, for a\n * remote agent, the ssh command lacks the `-L` forward. Spawn does not\n * throw it — the agent is usable by hand — but prints it as a warning;\n * verbs that need the socket throw it.\n */\nexport class AgentCtlUnreachableError extends Error implements HasNextSteps {\n override readonly name = \"AgentCtlUnreachableError\";\n constructor(\n public readonly agentName: string,\n public readonly workstream: string,\n public readonly socket: string,\n public readonly kind: \"missing\" | \"refused\",\n ) {\n super(\n `agent ${agentName} has no control socket (ctl: ${kind}) at ${socket}; mu cannot send to or wait on it exactly`,\n );\n }\n errorNextSteps(): NextStep[] {\n // A pi at its trust prompt has not bound the socket yet, so it reads\n // \"missing\"; a \"refused\" socket exists, so trust is not the cause.\n const trust: NextStep[] =\n this.kind === \"missing\"\n ? [\n {\n intent:\n \"Just spawned? pi may sit at its project trust prompt: answer /trust in the pane, or respawn with --command 'pi --approve'\",\n command: `mu agent read ${this.agentName} -w ${this.workstream}`,\n },\n ]\n : [];\n return [\n ...trust,\n { intent: \"Check whether the mu pi extension is linked\", command: \"mu doctor\" },\n {\n intent: \"Stop a runaway tool without the socket\",\n command: `mu agent kick ${this.agentName} -w ${this.workstream}`,\n },\n { intent: \"Link the extension, then re-spawn\", command: \"mu link pi\" },\n {\n intent: \"Remote agent: forward the socket in your ssh command\",\n command: `ssh -L ${this.socket}:<remote sock> ... (see mu agent remote-env)`,\n },\n ];\n }\n}\n\n/**\n * A side-effecting ctl request (send, fresh, interrupt, command) was\n * written to a live agent's socket, then no reply arrived (timeout or\n * close). pi may have queued the prompt, so a blind resend can duplicate it.\n */\nexport class AgentSendIndeterminateError extends Error implements HasNextSteps {\n override readonly name = \"AgentSendIndeterminateError\";\n constructor(\n public readonly agentName: string,\n public readonly workstream: string,\n public readonly op: string,\n public readonly reason: string,\n ) {\n super(\n `agent ${agentName}: ${op} was written to its control socket but no reply arrived (${reason}); delivery unknown`,\n );\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Precaution before resending: pi may already have received it, so check first\",\n command: `mu agent read ${this.agentName} -w ${this.workstream} -n 20`,\n },\n ];\n }\n}\n\n/**\n * A ctl verb (send, abort, ...) found the agent's control socket silent\n * AND its pane gone: the process exited (or the pane was closed behind\n * mu's back), so there is nothing to link, kick or forward. Raised\n * instead of AgentCtlUnreachableError, which is for a live pane.\n */\nexport class AgentPaneDeadError extends Error implements HasNextSteps {\n override readonly name = \"AgentPaneDeadError\";\n constructor(\n public readonly agentName: string,\n public readonly workstream: string,\n public readonly paneId: string,\n ) {\n super(\n `agent ${agentName} is dead: its pane ${paneId} no longer exists, so its control socket is gone`,\n );\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Read the log for why it exited (a bad model or missing API key is common)\",\n command: `mu log -w ${this.workstream}`,\n },\n {\n intent: \"Drop the dead registry row, then respawn\",\n command: `mu agent close ${this.agentName} -w ${this.workstream}`,\n },\n {\n intent: \"Respawn it\",\n command: `mu agent spawn ${this.agentName} -w ${this.workstream}`,\n },\n ];\n }\n}\n\n/**\n * `mu agent abort` on an agent that does not run pi: there is no control\n * socket to carry the abort, and mu does not silently signal the pane.\n */\nexport class AgentAbortNeedsCtlError extends Error implements HasNextSteps {\n override readonly name = \"AgentAbortNeedsCtlError\";\n constructor(\n public readonly agentName: string,\n public readonly workstream: string,\n public readonly cli: string,\n ) {\n super(\n `agent ${agentName} runs ${cli}, not pi: abort needs the mu pi extension; use mu agent kick`,\n );\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Signal the pane's foreground process instead\",\n command: `mu agent kick ${this.agentName} -w ${this.workstream}`,\n },\n ];\n }\n}\n\n/** The abort was delivered but pi did not settle within the timeout. */\nexport class AgentAbortTimeoutError extends Error implements HasNextSteps {\n override readonly name = \"AgentAbortTimeoutError\";\n constructor(\n public readonly agentName: string,\n public readonly workstream: string,\n public readonly timeoutMs: number,\n ) {\n super(`agent ${agentName} was still busy ${timeoutMs}ms after the abort`);\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Signal the pane's foreground process group\",\n command: `mu agent kick ${this.agentName} -w ${this.workstream}`,\n },\n {\n intent: \"Read the pane to see what it is stuck on\",\n command: `mu agent read ${this.agentName} -n 30 -w ${this.workstream}`,\n },\n ];\n }\n}\n\n/**\n * `mu agent send --fresh` on an agent without a control socket (non-pi\n * CLI, or forced `--via mux`): there is no one-operation new session.\n */\nexport class AgentFreshNeedsCtlError extends Error implements HasNextSteps {\n override readonly name = \"AgentFreshNeedsCtlError\";\n constructor(\n public readonly agentName: string,\n public readonly workstream: string,\n public readonly cli: string,\n ) {\n super(\n `agent ${agentName} runs ${cli} without a control socket: --fresh needs the mu pi extension`,\n );\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Reset the session through the pane, then send (verify it landed)\",\n command: `mu agent send ${this.agentName} '/new' -w ${this.workstream}`,\n },\n ];\n }\n}\n\n/**\n * The agent's pi serves the control socket with an extension it loaded\n * before mu learned `op` (e.g. `fresh`): running pi processes keep the\n * extension code they started with. pi's `/reload` re-imports the\n * extension through the `mu link pi` shim and keeps the socket; a\n * respawn always works. An extension that serves op `command` takes\n * `/reload` over ctl; an older one needs it typed (`--via mux`).\n */\nexport class AgentExtensionOutdatedError extends Error implements HasNextSteps {\n override readonly name = \"AgentExtensionOutdatedError\";\n constructor(\n public readonly agentName: string,\n public readonly workstream: string,\n public readonly op: string,\n public readonly extVersion?: string,\n /** Ops the extension serves (from its \"unknown op\" reply); absent from old extensions. */\n public readonly ops?: readonly string[],\n ) {\n super(\n `agent ${agentName}'s mu pi extension (${extVersion ?? \"version unknown\"}) predates op ${op}: its pi loaded an older mu build; reload or respawn it`,\n );\n }\n errorNextSteps(): NextStep[] {\n const w = `-w ${this.workstream}`;\n // An extension that serves op command runs /reload over ctl itself;\n // an older one only reloads when /reload is typed into the pane.\n const via = this.ops?.includes(\"command\") ? \"\" : \" --via mux\";\n return [\n {\n intent: \"Reload pi's extensions (keeps the session and context)\",\n command: `mu agent send ${this.agentName} '/reload'${via} ${w}`,\n },\n {\n intent: \"Or respawn the agent (loses its context)\",\n command: `mu agent close ${this.agentName} ${w} && mu agent spawn ${this.agentName} ${w} ...`,\n },\n ];\n }\n}\n\n/**\n * `send --fresh` or a session command (`/new`, `/reload`, `/compact`)\n * refused: pi is mid-turn, and running it would abandon the turn.\n */\nexport class AgentBusyError extends Error implements HasNextSteps {\n override readonly name = \"AgentBusyError\";\n constructor(\n public readonly agentName: string,\n public readonly workstream: string,\n /** The session command refused, e.g. \"/new\". Absent: `--fresh`. */\n public readonly command?: string,\n ) {\n super(`agent ${agentName} is busy: ${command ?? \"--fresh\"} would abandon its running turn`);\n }\n errorNextSteps(): NextStep[] {\n const retry =\n this.command === undefined\n ? `mu agent send ${this.agentName} --fresh --force '...' -w ${this.workstream}`\n : `mu agent send ${this.agentName} '${this.command}' --force -w ${this.workstream}`;\n return [\n {\n intent: \"Stop the turn first, then retry\",\n command: `mu agent abort ${this.agentName} -w ${this.workstream}`,\n },\n { intent: \"Or abandon the turn in one step\", command: retry },\n ];\n }\n}\n\n/**\n * `mu workspace free` refused: the owning agent is mid-turn, waiting on\n * a permission, or unreadable with a live pane. Freeing would pull the\n * checkout out from under it. CLI-only guard; `agent close` and spawn\n * rollback call the SDK directly and are unaffected.\n */\nexport class WorkspaceOwnerBusyError extends Error implements HasNextSteps {\n override readonly name = \"WorkspaceOwnerBusyError\";\n constructor(\n public readonly agentName: string,\n public readonly workstream: string,\n public readonly state: string,\n public readonly detail?: string,\n ) {\n super(\n detail\n ? `agent ${agentName} is ${state} (${detail}): refusing to free its workspace`\n : `agent ${agentName} is ${state}: freeing its workspace would pull it out from under it`,\n );\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Stop the turn first, then retry\",\n command: `mu agent abort ${this.agentName} -w ${this.workstream}`,\n },\n {\n intent: \"Or wait until the agent is idle\",\n command: `mu agent wait ${this.agentName} -w ${this.workstream}`,\n },\n {\n intent: \"Or free anyway (pending changes are lost without --commit)\",\n command: `mu workspace free ${this.agentName} --force -w ${this.workstream}`,\n },\n ];\n }\n}\n\n/**\n * A slash command other than `/new`, `/reload`, `/compact` sent to a pi\n * agent. The control socket cannot run it (pi.sendUserMessage would\n * hand it to the model as text), and mu does not silently paste into a\n * pi pane: `--via mux` is the explicit way to type it there.\n */\nexport class AgentSlashCommandUnsupportedError extends Error implements HasNextSteps {\n override readonly name = \"AgentSlashCommandUnsupportedError\";\n constructor(\n public readonly agentName: string,\n public readonly workstream: string,\n public readonly text: string,\n public readonly supported: readonly string[],\n ) {\n super(\n `agent ${agentName} runs pi: over the control socket mu runs only ${supported.join(\", \")}; ${JSON.stringify(text.split(\"\\n\")[0])} is not one of them. Pass --via mux to type it into the pane`,\n );\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Type it into the pane on purpose (tmux paste; unconfirmed)\",\n command: `mu agent send ${this.agentName} '${this.text.split(\"\\n\")[0]}' --via mux -w ${this.workstream}`,\n },\n ];\n }\n}\n\n/**\n * An empty message sent to a pi agent over the control socket.\n * pi.sendUserMessage(\"\") is meaningless; a bare Enter is a pane\n * keystroke, so `--via mux` is the explicit way to press it.\n */\nexport class AgentEmptySendError extends Error implements HasNextSteps {\n override readonly name = \"AgentEmptySendError\";\n constructor(\n public readonly agentName: string,\n public readonly workstream: string,\n ) {\n super(\n `agent ${agentName} runs pi: an empty message cannot go over the control socket. Pass --via mux to press Enter in the pane`,\n );\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Press Enter in the pane\",\n command: `mu agent send ${this.agentName} '' --via mux -w ${this.workstream}`,\n },\n ];\n }\n}\n","// mu — waitForTasks: block until tasks reach a target status.\n//\n// The orchestrator pattern: dispatch N workers via mu task claim --for,\n// then wait until they're all done before reviewing/merging.\n//\n// Pre-existing alternatives + why this verb exists:\n//\n// awk pipe over `mu log --tail`: works for ONE event but the\n// awk script becomes stateful (tracking 'which of N have closed?')\n// for multi-task waits. Bad shape for SKILL examples.\n//\n// Implementation:\n//\n// 1. Initial check — if the wait condition is already satisfied,\n// exit immediately. No subscription needed.\n// 2. Otherwise, poll the tasks table every pollMs. Same cadence as\n// mu log --tail (default 1000ms). We don't subscribe to\n// agent_logs because (a) we'd still need to re-query tasks to\n// learn the current status, (b) some status changes happen via\n// mu sql which doesn't emit events, and (c) the polling cost is\n// one indexed SELECT every second — cheaper than parsing the\n// log stream.\n// 3. Exit on success (all/any reached) OR timeout. Caller maps\n// timeout to exit code 5.\n//\n// Extracted from src/tasks.ts as part of refactor_split_large_src_files.\n\nimport type { StateReading } from \"../agent-state.js\";\nimport type { Db } from \"../db.js\";\nimport { emitEvent } from \"../logs.js\";\nimport { StallDetectedDuringWaitError, stallWaitHint, TaskNotFoundError } from \"./errors.js\";\nimport { getTask, getTaskOwner } from \"./queries.js\";\nimport { DEFAULT_SUBSTATE, type TaskStatus, type TaskSubstate } from \"./status.js\";\n\n// ─── Test seams: poll-sleep + poll counter + stuck-warn writer ─────────\n//\n// Mirror src/tmux.ts's setSleepForTests pattern. Default sleep is a real\n// setTimeout; tests can swap in an instant + counted version to assert\n// poll cadence (the bug fixed alongside this hook silently sleeps a full\n// pollMs past the deadline when pollMs > timeoutMs — see\n// test/tasks-wait.integration.test.ts 'clamped sleep' regression case).\n//\n// The stuck-warn writer is the second seam: agent_attention_required\n// (named agent_close_discipline_gap until it was found to presume one\n// of three causes) added a per-poll \"this task is IN_PROGRESS but its\n// owner is needs_input for too long\" warning emitted to stderr; tests\n// intercept it via setWaitStuckWarnForTests so they can assert\n// exactly-once dedupe without scraping process.stderr.\n\nlet currentWaitSleep: (ms: number) => Promise<void> = (ms) =>\n new Promise((resolve) => setTimeout(resolve, ms));\nlet pollCount = 0;\n\n/** Default `--stuck-after`: how long an IN_PROGRESS task's owner may sit\n * in needs_input before the wait reports it. Short because a pi worker\n * that settles still owning a task is already nudged once to close it;\n * still waiting after that means it needs the orchestrator. */\nexport const DEFAULT_STUCK_AFTER_MS = 120_000;\n\n/** Default `--stuck-after` for an owner read over its control socket.\n * ctl's idle is exact (pi's agent_settled) and arrives only after the\n * close nudge's continuation has run (the nudge fires in\n * agent_before_settle, before the settle), so an idle owner still\n * holding the task has already declined to close it. The grace only\n * covers an orchestrator `send` racing the settle. */\nexport const DEFAULT_CTL_STUCK_AFTER_MS = 5_000;\nconst defaultStuckWarn: (msg: string) => void = (msg) => {\n process.stderr.write(msg);\n};\nlet currentStuckWarn: (msg: string) => void = defaultStuckWarn;\n\nexport function setWaitSleepForTests(\n impl: ((ms: number) => Promise<void>) | undefined,\n): (ms: number) => Promise<void> {\n const previous = currentWaitSleep;\n currentWaitSleep = impl ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));\n return previous;\n}\n\n/** Test seam: swap the stderr writer used by the stuck-task warning so\n * unit tests can capture warnings without spying on process.stderr. */\nexport function setWaitStuckWarnForTests(\n impl: ((msg: string) => void) | undefined,\n): (msg: string) => void {\n const previous = currentStuckWarn;\n currentStuckWarn = impl ?? defaultStuckWarn;\n return previous;\n}\n\n/** Total number of polls performed across all `waitForTasks` calls in this\n * process. Tests typically reset before exercising and read after. */\nexport function getWaitPollCount(): number {\n return pollCount;\n}\n\nexport function resetWaitPollCount(): void {\n pollCount = 0;\n}\n\n/**\n * Human-readable age for the attention warning: `45s`, `5m`, `2h`.\n *\n * Deliberately NOT `relTime` from src/cli/format.ts — that module\n * pulls picocolors and cli-table3, and this one stays dep-free so the\n * SDK can be imported without the CLI's render layer. The duplication\n * is three lines of arithmetic against a shared import that would\n * invert the layering.\n *\n * Raw milliseconds were the old wording and read badly: a worker five\n * minutes into a question got \"(>= 1000ms ...)\" because the message\n * quoted the THRESHOLD, not the age.\n */\nexport function formatStallAge(ms: number): string {\n const sec = Math.max(0, Math.round(ms / 1000));\n if (sec < 60) return `${sec}s`;\n const min = Math.floor(sec / 60);\n if (min < 60) return `${min}m`;\n return `${Math.floor(min / 60)}h`;\n}\n\n/** A single task ref the wait verb is watching. Cross-workstream\n * waits arrive as a heterogeneous list of (workstream, name) pairs;\n * the legacy single-workstream call passes the same workstream on\n * every ref. task_wait_cross_workstream. */\nexport interface TaskWaitRef {\n /** The workstream the task lives in. Each ref carries its own so\n * the SDK doesn't need a single \"the workstream\" — cross-ws waits\n * pass refs from multiple workstreams in one call. */\n workstreamName: string;\n /** The task's per-workstream-unique local id. */\n name: string;\n}\n\nexport interface TaskWaitOptions {\n /** Target status. Default 'CLOSED'. */\n status?: TaskStatus;\n /** When true, succeed as soon as ONE listed task reaches the target.\n * Default false: every listed task must reach the target. */\n any?: boolean;\n /** Maximum time to wait, in milliseconds. Default 600_000 (10 min).\n * Pass 0 to wait forever. */\n timeoutMs?: number;\n /** Polling interval. Default 1000ms; overridable for tests. */\n pollMs?: number;\n /** Workstream context applied to bare-string ids. Required when the\n * caller passes `string[]`; ignored when the caller passes\n * `TaskWaitRef[]` (each ref carries its own ws). The legacy\n * single-ws SDK call site keeps its today's shape; the cross-ws\n * callers (CLI verb) pass `TaskWaitRef[]` and omit `workstream`.\n * task_wait_cross_workstream. */\n workstream?: string;\n /** Emit a yellow STUCK warning to stderr (once per task per wait call)\n * when an IN_PROGRESS task's owner has been in `needs_input` for at\n * least this many milliseconds since the agent row's last update.\n * Default `DEFAULT_STUCK_AFTER_MS` (2 min). Pass 0 to disable.\n *\n * Surfaced by agent_attention_required: a worker sitting in\n * needs_input leaves wait blocked indefinitely. The cause may be a\n * finish-without-close, a question awaiting an answer, or a prompt\n * — the predicate cannot tell them apart, so the warning reports\n * the observation and points at `mu agent read`. Default action is\n * observation-only (wait keeps polling); `onStall: 'exit'` makes it\n * terminal. */\n stuckAfterMs?: number;\n /** `stuckAfterMs` for an owner whose reading came from a working\n * control socket (source ctl, ctl ok). Default\n * `DEFAULT_CTL_STUCK_AFTER_MS`. `stuckAfterMs: 0` disables both. */\n ctlStuckAfterMs?: number;\n /** What to do when the `--stuck-after` predicate fires on a watched\n * task. `'warn'` (default) = today's behaviour: yellow STUCK line\n * to stderr (deduped per task per wait call) + corroborating\n * `kind='event'` agent_logs row; wait keeps polling. `'exit'` =\n * same emit + persist, but THEN throw `StallDetectedDuringWaitError`\n * so the CLI wrapper exits 7 (STALL_DETECTED). The exit-action is\n * the unattended-orchestrator escape: a wrapping policy can branch\n * on 7 (idle, ambiguous — operator decides poke vs release) vs 6\n * (dead pane, unambiguous — re-dispatch).\n *\n * Carve-out (lives at the call site, not here): the CLI passes\n * `'exit'` only when the wait target is CLOSED — mirrors exit-6's\n * reaper-flip suppression. With `--status OPEN` the worker reaching\n * needs_input might BE the success path. See\n * task_wait_stall_action_flag. */\n onStall?: \"warn\" | \"exit\";\n /** Read an owner's current runtime state for attention detection.\n * Without this hook, SDK waits never infer a stall from stored data. */\n readOwnerState?: (owner: {\n name: string;\n workstreamName: string;\n }) => Promise<StateReading | null>;\n /** Optional async hook run BEFORE every snapshot (initial + each\n * poll iteration). The CLI uses this to reconcile the workstream\n * each tick (reaper flips IN_PROGRESS → OPEN for dead-pane\n * workers) and to throw a typed error when a reaper-flip on a\n * watched task should abandon the wait — see\n * task_wait_reconcile_dead_panes. Throwing from `beforePoll`\n * propagates out of `waitForTasks` unchanged.\n *\n * Kept as a generic seam (not a `--reconcile`-shaped option) so\n * the SDK module stays free of tmux/reconcile imports — that\n * layering belongs above the SDK in the CLI wrapper. */\n beforePoll?: () => Promise<void>;\n}\n\nexport interface TaskWaitTaskState {\n /** The workstream this task lives in. Cross-workstream waits\n * return a mixed list; the workstream is part of identity.\n * task_wait_cross_workstream. */\n workstreamName: string;\n /** The task's per-workstream-unique name. */\n name: string;\n /** Current status (at the moment we exit). */\n status: TaskStatus;\n /** Current substate. A CLOSED ref that is not `done` has no deliverable. */\n substate: TaskSubstate;\n /** Owner at exit time (NULL when unowned, after release, or after\n * the reaper flipped IN_PROGRESS → OPEN due to a dead pane). */\n owner: string | null;\n /** True when this task's status equals the target. */\n reachedTarget: boolean;\n /** True when the task is IN_PROGRESS, owned by a registered agent\n * whose detected status is `needs_input` for >= `stuckAfterMs`.\n * Surfaces agent_attention_required: the worker may have finished\n * without closing, be waiting on an answer, or be sitting at a\n * prompt — this flag does not distinguish them, so a consumer\n * should read the pane. Backwards-compatible signal — callers\n * ignoring it see no behaviour change. */\n stuck: boolean;\n}\n\nexport interface TaskWaitResult {\n /** Per-task state at exit time. Same length and order as the input\n * list. The caller derives all-reached / any-reached / elapsed\n * from this list (count `r.reachedTarget`) and from its own\n * startedAt clock — keeping the SDK return minimal. */\n refs: TaskWaitTaskState[];\n /** True when we exited because of the timeout, not because the wait\n * condition was met. Refs that did reach the target are still\n * reflected in `refs[i].reachedTarget` on partial-progress timeout. */\n timedOut: boolean;\n}\n\n/**\n * Block until a set of tasks reaches `opts.status` (default CLOSED).\n * Returns a result describing the final state — the caller decides\n * whether to treat partial-progress timeouts as success or failure\n * (the CLI maps a clean exit to 0, a timeout to 5).\n *\n * Pre-flight: every task in `localIds` MUST exist; missing ones throw\n * TaskNotFoundError before any waiting begins. This is loud-fail by\n * design — a typo'd id silently waiting forever is the worst-case UX.\n */\nexport async function waitForTasks(\n db: Db,\n input: readonly TaskWaitRef[] | readonly string[],\n opts: TaskWaitOptions,\n): Promise<TaskWaitResult> {\n if (input.length === 0) {\n throw new Error(\"waitForTasks: refs must be non-empty\");\n }\n // Normalise to TaskWaitRef[]. The string[] shape preserves today's\n // single-workstream SDK contract (callers pass `workstream` on\n // opts); the TaskWaitRef[] shape carries its own ws per ref so\n // cross-workstream waits don't need a sentinel.\n const refs: readonly TaskWaitRef[] = input.map((entry) => {\n if (typeof entry === \"string\") {\n if (opts.workstream === undefined)\n throw new Error(\n \"waitForTasks: string ids require opts.workstream; pass TaskWaitRef[] for cross-workstream waits\",\n );\n return { workstreamName: opts.workstream, name: entry };\n }\n return entry;\n });\n const target: TaskStatus = opts.status ?? \"CLOSED\";\n const wantAny = opts.any === true;\n const timeoutMs = opts.timeoutMs ?? 600_000;\n const pollMs = opts.pollMs ?? 1000;\n const stuckAfterMs = opts.stuckAfterMs ?? DEFAULT_STUCK_AFTER_MS;\n const ctlStuckAfterMs = opts.ctlStuckAfterMs ?? DEFAULT_CTL_STUCK_AFTER_MS;\n const onStall: \"warn\" | \"exit\" = opts.onStall ?? \"warn\";\n const deadline = timeoutMs > 0 ? Date.now() + timeoutMs : Number.POSITIVE_INFINITY;\n\n // Pre-flight: every ref must exist in its own workstream scope.\n // Cross-workstream waits validate each ref against its declared ws\n // — a typo in the workstream half of `<ws>/<name>` should land here\n // with a clear TaskNotFoundError, not silently wait forever.\n for (const ref of refs) {\n if (getTask(db, ref.name, ref.workstreamName) === undefined)\n throw new TaskNotFoundError(`${ref.workstreamName}/${ref.name}`);\n }\n\n // Per-(ws,name) dedupe: emit the STUCK warning at most ONCE per wait\n // call, not once per poll cycle. Operators don't want their stderr\n // filled with the same yellow line every second; one nudge is enough.\n const stuckWarned = new Set<string>();\n const refKey = (ref: TaskWaitRef): string => `${ref.workstreamName}/${ref.name}`;\n // Owners whose control socket is broken: first-seen time + reason.\n const ctlBrokenSince = new Map<string, number>();\n const stuckLabel = new Map<string, string>();\n // Owners whose reading carried a ctl link: they run pi, so the stall\n // error can point at `mu agent abort`.\n const ctlOwners = new Set<string>();\n // The latest ctl run count per owner, for the stall hints.\n const ownerRuns = new Map<string, number>();\n\n const stuckAgeMs = async (\n status: TaskStatus,\n owner: { name: string; workstreamName: string } | undefined,\n ): Promise<number | null> => {\n if (\n stuckAfterMs <= 0 ||\n status !== \"IN_PROGRESS\" ||\n owner === undefined ||\n opts.readOwnerState === undefined\n )\n return null;\n const reading = await opts.readOwnerState(owner);\n const ownerKey = `${owner.workstreamName}/${owner.name}`;\n if (reading?.ctl !== undefined) ctlOwners.add(ownerKey);\n if (reading?.runs !== undefined) ownerRuns.set(ownerKey, reading.runs);\n else ownerRuns.delete(ownerKey);\n // A pi owner whose control socket does not answer (pane still\n // alive) needs attention too: nothing will report it settling.\n // Its age runs from when this wait first saw the socket broken.\n if (reading?.alive === true && (reading.ctl === \"missing\" || reading.ctl === \"refused\")) {\n const firstSeen = ctlBrokenSince.get(ownerKey) ?? Date.now();\n ctlBrokenSince.set(ownerKey, firstSeen);\n stuckLabel.set(ownerKey, reading.reason ?? `ctl ${reading.ctl}`);\n const ageMs = Date.now() - firstSeen;\n return ageMs >= stuckAfterMs ? ageMs : null;\n }\n ctlBrokenSince.delete(ownerKey);\n stuckLabel.delete(ownerKey);\n if (reading?.state !== \"needs_input\" || reading.since === null) return null;\n const viaCtl = reading.source === \"ctl\" && reading.ctl === \"ok\";\n if (viaCtl && reading.pending === true) return null;\n const ageMs = Date.now() - reading.since;\n return ageMs >= (viaCtl ? ctlStuckAfterMs : stuckAfterMs) ? ageMs : null;\n };\n\n /** Read current state of all tasks; returns the result shape. */\n const snapshot = async (): Promise<TaskWaitResult> => {\n const refStates: TaskWaitTaskState[] = [];\n for (const ref of refs) {\n const row = getTask(db, ref.name, ref.workstreamName);\n // Defensive: if a task was deleted mid-wait, treat as 'never\n // reached' for EVERY target, OPEN included (reachedTarget below\n // requires the row). Not the same as TaskNotFoundError pre-flight:\n // deletion mid-wait shouldn't crash the wait; it's a legitimate\n // state change.\n const status = (row?.status ?? \"OPEN\") as TaskStatus;\n const substate = row?.substate ?? DEFAULT_SUBSTATE[status];\n // The owner's own workstream, not the task's: a cross-workstream\n // owner (`task claim --for <ws>/<agent>`) is read, keyed and\n // named under the workstream it lives in.\n const ownerRef =\n row === undefined ? undefined : getTaskOwner(db, ref.name, ref.workstreamName);\n const owner = ownerRef?.name ?? row?.ownerName ?? null;\n const ownerWs = ownerRef?.workstreamName ?? ref.workstreamName;\n const ageMs = await stuckAgeMs(status, ownerRef);\n const stuck = ageMs !== null;\n const key = refKey(ref);\n if (ageMs !== null && !stuckWarned.has(key)) {\n stuckWarned.add(key);\n const ageSecs = Math.round(ageMs / 1000);\n // State the OBSERVATION, not a cause. The predicate above only\n // knows \"needs_input for >= N\" — it cannot tell a worker that\n // finished without closing from one waiting on an answer from\n // one sitting at a prompt, and those need opposite responses.\n // The old text asserted the first (\"likely committed but\n // skipped mu task close\"), which sent at least one operator\n // hunting for a commit to merge while the worker was waiting\n // on a design decision. Workers asking questions is DESIRABLE;\n // the tooling must not frame it as negligence.\n //\n // The indented lines are the remedy: a pi owner's last answer\n // (wait --after-runs) when its socket reported runs, then\n // `mu agent read`, the next move in all three cases, because a\n // question, dialog, or crash is in the pane, not in the task row.\n //\n // Yellow ANSI escape inline (no picocolors import — keeps the\n // SDK module dep-free; the CLI layer already pulls picocolors).\n // Prefixed `mu task wait:` so log greppers can target it, and\n // cross-ws waits carry the qualified `<ws>/<name>`.\n // A pi owner with a settled run also gets its last answer\n // exactly (wait --after-runs), ahead of the pane read.\n const ownerBit = owner ?? \"<none>\";\n const runs = ownerRuns.get(`${ownerWs}/${ownerBit}`);\n const stateBit = stuckLabel.get(`${ownerWs}/${ownerBit}`) ?? \"needs_input\";\n const waitLine = stallWaitHint(ownerBit, ownerWs, runs)\n .map((s) => ` ${s.command}\\n`)\n .join(\"\");\n currentStuckWarn(\n `\\x1b[33mmu task wait: ${key} needs attention — owner=${ownerBit} has been in ` +\n `${stateBit} for ${formatStallAge(ageMs)}. It may have finished without closing, ` +\n `be waiting on an answer, or be sitting at a prompt.\\x1b[0m\\n` +\n waitLine +\n ` mu agent read ${ownerBit} -w ${ownerWs} --lines 60\\n`,\n );\n // Persist a corroborating kind='event' row so other consumers\n // (mu state, mu log --kind event, dashboards) see the same\n // signal that the new derived `idle` flag surfaces in the\n // agents table. The stderr warning stays — observation-only,\n // operator decides recovery. See idle_assigned_agent_detection.\n // Pure OBSERVATION: nothing is mutated, so no trigger could\n // ever see this. The emit is the only record.\n emitEvent(\n db,\n ref.workstreamName,\n \"agent.stall\",\n `agent stalled ${owner ?? \"<none>\"} owns ${ref.name} for ${ageSecs}s`,\n owner ?? \"system\",\n );\n // task_wait_stall_action_flag: with `--on-stall exit` (the\n // unattended-orchestrator escape), the same emit + persist\n // happens but we then throw — the CLI's classifyError maps\n // this to exit code 7 (STALL_DETECTED). The carve-out\n // (target=CLOSED only) lives at the call site: the CLI\n // wrapper passes `onStall: 'exit'` only when target=CLOSED.\n // Precedence vs exit-6 (dead pane): the reaper-flip check\n // throws inside `beforePoll` BEFORE snapshot() runs, so a\n // watched task that's both reaper-flipped AND stale never\n // reaches this branch (status would already be OPEN).\n if (onStall === \"exit\") {\n throw new StallDetectedDuringWaitError(\n ref.name,\n owner,\n ref.workstreamName,\n ageSecs,\n ctlOwners.has(`${ownerWs}/${owner ?? \"\"}`),\n runs,\n ownerWs,\n );\n }\n }\n refStates.push({\n workstreamName: ref.workstreamName,\n name: ref.name,\n status,\n substate,\n owner,\n reachedTarget: row !== undefined && status === target,\n stuck,\n });\n }\n return {\n refs: refStates,\n timedOut: false,\n };\n };\n\n /** Has the wait condition been met? */\n const isDone = (snap: TaskWaitResult): boolean => {\n const reached = snap.refs.filter((r) => r.reachedTarget).length;\n return wantAny ? reached > 0 : reached === snap.refs.length;\n };\n\n // Initial check: maybe we're already done. Run beforePoll first so\n // the CLI's per-poll reconcile (task_wait_reconcile_dead_panes) runs\n // even on the immediate-exit path — a dead-pane worker that died\n // BEFORE the operator typed `mu task wait` should still fail fast.\n if (opts.beforePoll) await opts.beforePoll();\n let snap = await snapshot();\n if (isDone(snap)) return snap;\n\n // Poll loop.\n //\n // Sleep is clamped to `min(pollMs, deadline - now)` so the function\n // returns within `timeoutMs + small slack`, never `pollMs` later.\n // Without the clamp, `pollMs=10000, timeoutMs=100` sleeps a full 10s\n // before noticing the deadline expired. When the clamp goes <= 0 we\n // skip the sleep entirely and re-snapshot before bailing on the\n // timeout — gives the wait one last chance at a winning state right\n // at the deadline boundary, and avoids passing 0 / negatives to\n // setTimeout (which has implementation-defined behaviour).\n for (;;) {\n const now = Date.now();\n if (now >= deadline) {\n return { ...snap, timedOut: true };\n }\n const sleepMs =\n deadline === Number.POSITIVE_INFINITY ? pollMs : Math.min(pollMs, deadline - now);\n if (sleepMs > 0) {\n await currentWaitSleep(sleepMs);\n }\n pollCount += 1;\n if (opts.beforePoll) await opts.beforePoll();\n snap = await snapshot();\n if (isDone(snap)) return snap;\n }\n}\n","// mu — abort: stop a pi agent's current turn through its control socket.\n//\n// status → abort → wait(afterRuns). The wait keys on the run counter the\n// extension bumps on agent_settled, so an abort that settles before the\n// wait connects still resolves at once. An agent that is not busy gets no\n// abort at all: the verb is idempotent.\n//\n// interruptAgent (`mu agent send --interrupt`) is abort + send as one\n// ctl op; against an extension that predates it, abortAgent then send.\n\nimport { getAgent } from \"../agents.js\";\nimport { CtlUnknownOpError, ctlRequest } from \"../ctl/client.js\";\nimport type { CtlState } from \"../ctl/protocol.js\";\nimport type { Db } from \"../db.js\";\nimport { emitEvent } from \"../logs.js\";\nimport { resolveActorIdentity } from \"../tasks/claim.js\";\nimport {\n AgentAbortNeedsCtlError,\n AgentAbortTimeoutError,\n AgentEmptySendError,\n AgentNotFoundError,\n} from \"./errors.js\";\nimport {\n agentCtlSocket,\n ctlFailure,\n expectsCtl,\n recordSend,\n ctlRequestFor as request,\n} from \"./transport.js\";\n\nexport const DEFAULT_ABORT_TIMEOUT_MS = 30_000;\n\nexport type AbortResult = {\n agent: string;\n workstream: string;\n before: CtlState;\n after: CtlState;\n /** True when pi settled (or was never busy). */\n settled: boolean;\n /** False when the agent was not busy, so no abort was sent. */\n aborted: boolean;\n /** pi had queued messages before the abort (pi returns them to the editor). */\n pending: boolean;\n elapsedMs: number;\n};\n\nexport type AbortAgentOptions = {\n workstream: string;\n timeoutMs?: number;\n /** Control socket path. Default: derived from the agent's identity. */\n socket?: string;\n};\n\nexport async function abortAgent(\n db: Db,\n name: string,\n opts: AbortAgentOptions,\n): Promise<AbortResult> {\n const agent = getAgent(db, name, opts.workstream);\n if (!agent) throw new AgentNotFoundError(name, opts.workstream);\n const sock = opts.socket ?? agentCtlSocket(db, agent);\n if (!expectsCtl(agent, sock)) throw new AgentAbortNeedsCtlError(name, opts.workstream, agent.cli);\n const timeoutMs = opts.timeoutMs ?? DEFAULT_ABORT_TIMEOUT_MS;\n const started = Date.now();\n const base = { agent: name, workstream: opts.workstream };\n\n const st = await request(agent, sock, { op: \"status\" });\n if (!st.ok) throw new Error(`control socket refused status: ${st.error}`);\n const before = st.state ?? \"idle\";\n const pending = st.pending ?? false;\n if (before !== \"busy\") {\n return {\n ...base,\n before,\n after: before,\n settled: true,\n aborted: false,\n pending,\n elapsedMs: Date.now() - started,\n };\n }\n\n const ab = await request(agent, sock, { op: \"abort\" });\n if (!ab.ok) throw new Error(`control socket refused the abort: ${ab.error}`);\n // Only a real abort is logged. wasBusy=false: the run settled between the\n // status probe and the abort, so pi did nothing. Absent: older extension.\n const aborted = ab.wasBusy !== false;\n if (aborted) {\n emitEvent(\n db,\n opts.workstream,\n \"agent.abort\",\n `agent abort ${name} (state=${before}, pending=${pending})`,\n await resolveActorIdentity(),\n );\n }\n\n const w = await request(agent, sock, { op: \"wait\", afterRuns: st.runs ?? 0, timeoutMs });\n if (!w.ok) {\n if (w.error === \"timeout\") throw new AgentAbortTimeoutError(name, opts.workstream, timeoutMs);\n throw new Error(`control socket refused the wait: ${w.error}`);\n }\n return {\n ...base,\n before,\n after: w.state ?? \"idle\",\n settled: true,\n aborted,\n pending,\n elapsedMs: Date.now() - started,\n };\n}\n\nexport type InterruptResult = {\n /** pi was busy, so its turn was aborted before the send. */\n wasBusy: boolean;\n /** pi had queued messages before the abort; pi put them back in the pane's editor. */\n pending: boolean;\n /**\n * pi's run count after the aborted run settled and before the send: the\n * `mu agent wait --after-runs` baseline for the run the text starts.\n */\n runs?: number;\n /** The extension predates the interrupt op: mu ran abort, then send. */\n fallback: boolean;\n};\n\n/**\n * Make a pi agent act on `text` now: abort a running turn, wait for pi to\n * settle (AgentAbortTimeoutError after timeoutMs, text not sent), then\n * send `text` as a new run. Never pastes: non-pi agents get\n * AgentAbortNeedsCtlError.\n */\nexport async function interruptAgent(\n db: Db,\n name: string,\n text: string,\n opts: AbortAgentOptions,\n): Promise<InterruptResult> {\n const r = await interruptAgentImpl(db, name, text, opts);\n recordSend(\n db,\n { name, workstreamName: opts.workstream },\n \"interrupt\",\n Buffer.byteLength(text),\n { transport: \"ctl\", wasBusy: r.wasBusy },\n await resolveActorIdentity(),\n );\n return r;\n}\n\nasync function interruptAgentImpl(\n db: Db,\n name: string,\n text: string,\n opts: AbortAgentOptions,\n): Promise<InterruptResult> {\n const agent = getAgent(db, name, opts.workstream);\n if (!agent) throw new AgentNotFoundError(name, opts.workstream);\n // Refuse before the abort: an empty prompt would kill the running turn\n // and then send nothing. Here, not only in the CLI, so SDK callers get it.\n if (text === \"\") throw new AgentEmptySendError(name, opts.workstream);\n const sock = opts.socket ?? agentCtlSocket(db, agent);\n if (!expectsCtl(agent, sock)) throw new AgentAbortNeedsCtlError(name, opts.workstream, agent.cli);\n const timeoutMs = opts.timeoutMs ?? DEFAULT_ABORT_TIMEOUT_MS;\n let r: Awaited<ReturnType<typeof ctlRequest>>;\n try {\n r = await ctlRequest(sock, { op: \"interrupt\", text, timeoutMs });\n } catch (e) {\n if (!(e instanceof CtlUnknownOpError)) throw await ctlFailure(agent, sock, e);\n // An extension loaded before the op: same steps, composed here.\n const ab = await abortAgent(db, name, { ...opts, socket: sock });\n const sent = await request(agent, sock, { op: \"send\", text });\n if (!sent.ok) throw new Error(`control socket refused the send: ${sent.error}`);\n return {\n wasBusy: ab.aborted,\n pending: ab.pending,\n ...(sent.runs !== undefined ? { runs: sent.runs } : {}),\n fallback: true,\n };\n }\n if (!r.ok) {\n if (r.error === \"timeout\") throw new AgentAbortTimeoutError(name, opts.workstream, timeoutMs);\n throw new Error(`control socket refused the interrupt: ${r.error}`);\n }\n return {\n wasBusy: r.wasBusy ?? false,\n pending: r.pending ?? false,\n ...(r.runs !== undefined ? { runs: r.runs } : {}),\n fallback: false,\n };\n}\n","// mu — adoptAgent: register an existing tmux pane as a managed agent.\n//\n// The inverse of `mu agent spawn` — instead of creating the pane,\n// adoptAgent hooks an already-existing pane into mu's registry.\n//\n// Two flavours of resolution:\n// - by paneId ('%15', 'w1:p2') : look up directly via the mux\n// - by paneTitle ('worker-1') : scan the session's panes for that title\n//\n// Common cases for adopt:\n// - operator manually started a CLI in a pane before installing mu\n// - mu agent close was followed by re-attaching the pane via tmux\n// - migrating from a previous orchestrator\n//\n// Extracted from src/agents.ts as part of refactor_split_large_src_files.\n\nimport {\n type AgentRow,\n getAgent,\n getAgentByPane,\n insertAgent,\n isValidAgentName,\n} from \"../agents.js\";\nimport { ctlProbe } from \"../ctl/client.js\";\nimport type { Db } from \"../db.js\";\nimport { emitEvent } from \"../logs.js\";\nimport { activeMux, type MuxPane, PaneNotFoundError, parseAgentNameFromTitle } from \"../mux.js\";\nimport { AgentExistsError, PaneNotInSessionError } from \"./errors.js\";\nimport { probeToSpawnCtl, type SpawnCtl } from \"./spawn.js\";\nimport { agentCtlSocket, expectsCtl } from \"./transport.js\";\n\n/** Budget for adopt's one-shot control-socket probe. */\nconst ADOPT_CTL_PROBE_MS = 1000;\n\nexport interface AdoptAgentOptions {\n /** Mux pane id (tmux '%15', herdr 'w1:p2'). Must already exist. */\n paneId: string;\n /** Workstream to adopt the pane into. The pane MUST be in the\n * matching tmux session (`mu-<workstream>`); cross-session adopt is\n * rejected. */\n workstream: string;\n /** Override the pane's title with this name. When omitted, the pane's\n * current title becomes the agent name (zero-config adoption). */\n name?: string;\n /** Defaults to 'pi' via the schema DEFAULT. */\n cli?: string;\n /** 'full-access' (default) or 'read-only'. */\n role?: string;\n /** Override the tmux session lookup. Defaults to `mu-<workstream>`. */\n tmuxSession?: string;\n}\n\nexport interface AdoptAgentResult {\n agent: AgentRow;\n /** True when the pane already had a matching agents row — the call\n * was a no-op (idempotent). */\n alreadyAdopted: boolean;\n /** The pane title before adopt, or null if the pane had no title. */\n previousTitle: string | null;\n /** The title the pane was set to (== agent.name post-adopt). Equal to\n * previousTitle when no retitle happened. */\n paneTitleSetTo: string;\n /** One probe of the derived control socket; \"skipped\" for non-pi CLIs.\n * An adopted pi pane usually lacks MU_CTL_SOCK, so this is \"missing\". */\n ctl: SpawnCtl;\n ctlSocket: string;\n}\n\nasync function probeAdopted(\n db: Db,\n agent: AgentRow,\n): Promise<Pick<AdoptAgentResult, \"ctl\" | \"ctlSocket\">> {\n const ctlSocket = agentCtlSocket(db, agent);\n if (!expectsCtl(agent, ctlSocket)) return { ctl: \"skipped\", ctlSocket };\n const probe = await ctlProbe(ctlSocket, ADOPT_CTL_PROBE_MS);\n return { ctl: probeToSpawnCtl(probe.kind), ctlSocket };\n}\n\n/**\n * Register an existing tmux pane as a managed mu agent. Inverse of the\n * 'orphan' state surfaced by `mu agent list`: a pane that looks like an\n * agent (running pi/claude/codex) but has no DB row.\n *\n * Identity contract (matches the claim protocol invariant):\n * - Post-adopt, the pane's title equals the agent's name.\n * - When `name` is omitted, the pane's existing title becomes the\n * agent name verbatim. Adopting a pane titled 'pi' would fail name\n * validation — caller must supply --name in that case.\n *\n * Idempotent: adopting the same pane twice with the same name is a\n * no-op (returns alreadyAdopted=true). Adopting a different pane under\n * an existing agent name throws AgentExistsError.\n *\n * Validation order (matches the design in note #100):\n * 1. Pane id format -> assertValidPaneId via paneExists / setPaneTitle\n * 2. Pane exists -> PaneNotFoundError\n * 3. Pane is in session -> PaneNotInSessionError (cross-session)\n * 4. Resolved name OK -> isValidAgentName / Error('agent name invalid')\n * 5. Idempotent check -> if pane already owned by an agent of this\n * name, return alreadyAdopted=true\n * 6. Name not taken -> AgentExistsError (else)\n * 7. Insert + retitle.\n *\n * The row's `status` column is the deprecated constant 'spawning' (see\n * insertAgent); runtime state is read at display time by\n * src/agent-state.ts (control socket, murmur, or herdr), never from\n * pane text. Adoption runs no state probe, so it does not depend on\n * the agent's control socket or a captured pane answering.\n */\nexport async function adoptAgent(db: Db, opts: AdoptAgentOptions): Promise<AdoptAgentResult> {\n // Load-bearing throughout: adopting a pane requires reading a pane.\n const mux = await activeMux();\n\n // Step 1+2: pane format + existence.\n if (!(await mux.paneExists(opts.paneId))) {\n throw new PaneNotFoundError(opts.paneId, mux);\n }\n\n // Step 3: pane must be in the workstream's mux session.\n const expectedSession = opts.tmuxSession ?? `mu-${opts.workstream}`;\n const panesInSession: MuxPane[] = await mux.listPanesInSession(expectedSession);\n const matchingPane = panesInSession.find((p) => p.paneId === opts.paneId);\n if (!matchingPane) {\n // Pane exists (passed step 2) but isn't in the expected session.\n throw new PaneNotInSessionError(opts.paneId, opts.workstream, expectedSession);\n }\n\n // Step 4: resolved name. Default to the pane's current title —\n // unwrapping a possibly-composed mu title ('name · task')\n // back to just the name token. Re-adoption of a pane that mu previously\n // owned must work; without parseAgentNameFromTitle the ' · <glyph>'\n // suffix would fail isValidAgentName.\n const previousTitle = matchingPane.title.length > 0 ? matchingPane.title : null;\n const candidate =\n opts.name ?? (previousTitle !== null ? parseAgentNameFromTitle(previousTitle) : \"\");\n const resolvedName = candidate;\n if (!isValidAgentName(resolvedName)) {\n if (opts.name === undefined) {\n throw new Error(\n `pane ${opts.paneId} title '${previousTitle ?? \"(empty)\"}' is not a valid agent name; pass --name <name>`,\n );\n }\n throw new Error(`agent name invalid: '${resolvedName}'`);\n }\n\n // Step 5: idempotency. If an agent already owns this pane id, check\n // whether it's the same name; same name == no-op, different name ==\n // conflict (we don't move agents between pane ids silently).\n const existingByPane = getAgentByPane(db, opts.paneId);\n if (existingByPane) {\n if (existingByPane.name === resolvedName) {\n // Already registered: lock only. The title is left as main left it\n // (it may be reconcile's composed \"name · task\"); reconcile repairs\n // a wrong one. The lock is best-effort, so re-adopt never fails on it.\n await mux.lockPaneTitle(opts.paneId).catch(() => {});\n return {\n agent: existingByPane,\n alreadyAdopted: true,\n previousTitle,\n paneTitleSetTo: resolvedName,\n ...(await probeAdopted(db, existingByPane)),\n };\n }\n throw new AgentExistsError(existingByPane.name);\n }\n\n // Step 6: name not taken in THIS workstream. v5 makes agent names\n // per-workstream unique — 'worker-1' may legally exist in another\n // workstream; only refuse when it collides in the workstream we're\n // adopting into (bug_v5_name_clash_silent_misroute).\n const existingByName = getAgent(db, resolvedName, opts.workstream);\n if (existingByName) {\n throw new AgentExistsError(resolvedName);\n }\n\n // Step 7: insert, then lock + retitle. The insert stays synchronous\n // right after the existence checks above (no await in between), so two\n // concurrent adopts cannot both register this pane. Locking before the\n // title write means an OSC title that arrived earlier is overwritten,\n // not frozen in.\n const inserted = insertAgent(db, {\n name: resolvedName,\n workstream: opts.workstream,\n paneId: opts.paneId,\n cli: opts.cli,\n role: opts.role,\n });\n // Machine-local table (`agents`): no trigger, so this emit is the\n // only record. It follows the insert directly so a later mux failure\n // cannot leave a registered agent without its adoption op.\n emitEvent(\n db,\n opts.workstream,\n \"agent.adopt\",\n `agent adopt ${resolvedName} (pane ${opts.paneId}, was title='${previousTitle ?? \"\"}')`,\n );\n await lockThenTitle(mux, opts.paneId, resolvedName, previousTitle === resolvedName);\n return {\n agent: inserted,\n alreadyAdopted: false,\n previousTitle,\n paneTitleSetTo: resolvedName,\n ...(await probeAdopted(db, inserted)),\n };\n}\n\n/**\n * Lock the pane title against OSC rewrites, then write the mu title, so\n * an OSC title that landed before the lock is overwritten. The lock is\n * best-effort ($MU_AGENT_NAME and reconcile still cover identity). The\n * write is best-effort too when the title already matched (`matched`):\n * it only repairs a race, and must not fail an adoption that needed no\n * retitle.\n */\nasync function lockThenTitle(\n mux: Awaited<ReturnType<typeof activeMux>>,\n paneId: string,\n title: string,\n matched: boolean,\n): Promise<void> {\n await mux.lockPaneTitle(paneId).catch(() => {});\n const write = mux.setPaneTitle(paneId, title);\n await (matched ? write.catch(() => {}) : write);\n}\n","// mu — delegate outcome: what one finished `mu agent wait` means for a\n// delegate (a scratch agent started for one task).\n//\n// The classification lives here, not in the pi extension, so the\n// `mu_delegate` tool has no logic the CLI lacks (VISION § 1, The CLI\n// is the product, rule 2): `mu agent wait --json` reports it per\n// agent as `outcome`, and the extension only formats it.\n\nimport type { AgentWaitAgentState } from \"./wait.js\";\n\n/**\n * - `done`: the run settled with a final assistant text (`lastText`).\n * - `empty`: the run settled without one (or the agent has no\n * control socket to supply it); read the pane instead.\n * - `error`: the run stopped on an API error after pi's own retries\n * (`lastError`); the agent is alive and idle.\n * - `died`: the pane or its control socket went away mid-wait.\n * - `timeout`: still working when the wait gave up; the pane is untouched.\n * - `blocked`: not finished; pi is waiting on an extension dialog\n * (`blocked` holds its kind and title). The pane is untouched and needs\n * a human (or an attach) to answer it.\n * - `pending`: not finished, and the wait ended for another reason\n * (`--any` fired on a sibling).\n */\nexport type DelegateOutcome =\n | \"done\"\n | \"empty\"\n | \"error\"\n | \"died\"\n | \"blocked\"\n | \"timeout\"\n | \"pending\";\n\nexport function delegateOutcome(\n agent: Pick<AgentWaitAgentState, \"fired\" | \"dead\" | \"lastText\" | \"lastError\" | \"blocked\">,\n timedOut: boolean,\n): DelegateOutcome {\n if (agent.dead) return \"died\";\n if (agent.blocked !== undefined) return \"blocked\";\n if (agent.fired) {\n if (agent.lastError !== undefined) return \"error\";\n return agent.lastText ? \"done\" : \"empty\";\n }\n return timedOut ? \"timeout\" : \"pending\";\n}\n","// mu — kickAgent: signal a wedged worker pane's foreground process\n// group from outside the pane.\n//\n// Why this verb exists: pi/claude/codex CLIs catch SIGINT themselves\n// (Ctrl-C is a UI input, not a process signal). When a worker is\n// wedged on a long-running tool subprocess (an unbounded `find /`,\n// a busy-wait loop, ...) the orchestrator's options were:\n//\n// - `mu agent send` — queues; the message is read after the tool\n// subprocess returns, which is exactly the wait we're trying to\n// shortcut.\n// - `tmux send-keys C-c` against the pane — the wrapping CLI eats\n// the signal as TUI input; doesn't reach the tool subprocess.\n// - drop out of mu, `pgrep -af \"find /\"`, `kill <pid>` — works,\n// but breaks the orchestrator's mental model and is fiddly.\n//\n// `mu agent kick` looks up the pane's TTY via tmux, asks `ps -t <tty>`\n// for the foreground process group (the pgid whose `stat` field\n// contains a `+`), and kills(2) that pgid directly. Default signal\n// is SIGINT (graceful, matches what Ctrl-C would do if it\n// propagated); --signal SIGTERM / SIGKILL escalate.\n//\n// Source feedback: workers_commonly_attempt_unbounded_find. The\n// PART A spec.\n\nimport { type AgentRow, getAgent } from \"../agents.js\";\nimport type { Db } from \"../db.js\";\nimport { execFileCapture } from \"../exec-file.js\";\nimport { emitEvent } from \"../logs.js\";\nimport { activeMux } from \"../mux.js\";\nimport type { HasNextSteps, NextStep } from \"../output.js\";\nimport { AgentNotFoundError } from \"./errors.js\";\n\n// ─── Allowed signals ─────────────────────────────────────────────────\n\n/** The signal set kick supports. SIGINT is graceful (matches Ctrl-C\n * semantics — what the operator probably wanted in the first place);\n * SIGTERM is the polite escalation; SIGKILL is the unblockable\n * hammer. We deliberately don't expose arbitrary signals — the\n * three above are the actionable ones for \"interrupt a wedged\n * foreground tool subprocess.\" */\nexport type KickSignal = \"SIGINT\" | \"SIGTERM\" | \"SIGKILL\";\n\nconst ALLOWED_SIGNALS: readonly KickSignal[] = [\"SIGINT\", \"SIGTERM\", \"SIGKILL\"];\n\nexport function isKickSignal(s: string): s is KickSignal {\n return (ALLOWED_SIGNALS as readonly string[]).includes(s);\n}\n\n// ─── Errors ──────────────────────────────────────────────────────────\n\n/**\n * Thrown when the foreground pgid lookup on a pane's TTY yields\n * either no rows at all (the pane is sitting at an idle shell with\n * no foreground job) or only the wrapping shell itself (the LLM CLI\n * — pi/claude/codex — is the foreground; signalling it would close\n * the agent, which is what `mu agent close` is for).\n *\n * Maps to the generic exit code 1 in handle.ts (this is a\n * runtime-state condition, not a typed not-found / conflict).\n */\nexport class NoForegroundProcessError extends Error implements HasNextSteps {\n override readonly name = \"NoForegroundProcessError\";\n constructor(\n public readonly agentName: string,\n public readonly tty: string,\n public readonly reason: \"no-foreground\" | \"shell-only\",\n ) {\n const detail =\n reason === \"no-foreground\"\n ? `no foreground process group on tty ${tty} (pane is idle)`\n : `the only foreground process on tty ${tty} is the agent's wrapping CLI itself; refusing to signal it (use \\`mu agent close ${agentName}\\` to close the agent)`;\n super(`agent ${agentName}: ${detail}`);\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Inspect what's running in the pane\",\n command: `mu agent show ${this.agentName} -n 50`,\n },\n {\n intent: \"Close the agent (kills the wrapping CLI + pane)\",\n command: `mu agent close ${this.agentName}`,\n },\n ];\n }\n}\n\n// ─── Process executor (swappable for tests) ──────────────────────────\n//\n// Mirrors the `setTmuxExecutor` pattern in src/tmux.ts so unit tests\n// can mock `ps -t <tty>` and `kill -<sig> -<pgid>` without touching\n// real processes.\n\nexport interface KickProcessExecResult {\n stdout: string;\n stderr: string;\n exitCode: number | null;\n}\n\nexport type KickProcessExecutor = (\n cmd: string,\n args: readonly string[],\n) => Promise<KickProcessExecResult>;\n\nconst realExecutor: KickProcessExecutor = (cmd, args) => execFileCapture(cmd, args);\n\nlet currentExecutor: KickProcessExecutor = realExecutor;\n\n/** Install a custom executor (for tests). Returns the previous one so\n * tests can restore cleanly. */\nexport function setKickProcessExecutor(executor: KickProcessExecutor): KickProcessExecutor {\n const previous = currentExecutor;\n currentExecutor = executor;\n return previous;\n}\n\n/** Restore the real executor. */\nexport function resetKickProcessExecutor(): void {\n currentExecutor = realExecutor;\n}\n\n// ─── Foreground pgid lookup ──────────────────────────────────────────\n\ninterface PsRow {\n pid: number;\n pgid: number;\n /** ps's `stat` (or `state`) field. The presence of `+` means\n * \"foreground process group on its controlling tty\". */\n stat: string;\n /** Process command (just the comm; truncated, used for diagnostics). */\n comm: string;\n}\n\n/**\n * Parse `ps -t <tty> -o pid=,pgid=,stat=,comm=` output. Each non-blank\n * line is one process: four whitespace-separated fields. Defensive\n * about leading whitespace and command names with embedded spaces\n * (the comm is the LAST field — join the tail).\n */\nexport function parsePsTtyOutput(output: string): PsRow[] {\n const rows: PsRow[] = [];\n for (const raw of output.split(\"\\n\")) {\n const line = raw.trim();\n if (line === \"\") continue;\n const parts = line.split(/\\s+/);\n if (parts.length < 4) continue;\n const [pidStr, pgidStr, stat, ...commParts] = parts;\n if (pidStr === undefined || pgidStr === undefined || stat === undefined) continue;\n const pid = Number.parseInt(pidStr, 10);\n const pgid = Number.parseInt(pgidStr, 10);\n if (!Number.isFinite(pid) || !Number.isFinite(pgid)) continue;\n rows.push({ pid, pgid, stat, comm: commParts.join(\" \") });\n }\n return rows;\n}\n\n/**\n * Resolve the foreground process group id for a TTY device path. The\n * canonical signal `ps`'s `stat` field uses is `+` (BSD/Darwin AND\n * Linux procps). We pick the first row whose stat contains `+`; its\n * `pgid` is the foreground pgid of that controlling terminal.\n *\n * Returns:\n * - `{ kind: \"ok\", pgid, fgRow }` on success\n * - `{ kind: \"no-foreground\" }` when no row carries `+` AND there\n * are no candidate rows at all\n * - `{ kind: \"shell-only\", pgid, fgRow }` when the foreground pgid\n * resolves to a shell whose comm is the agent's wrapping CLI\n * (caller decides whether to refuse — kick refuses)\n *\n * The wrapping-CLI guard is intentionally narrow: we only refuse\n * when the foreground process command matches one of the known\n * pi/claude/codex/zsh/bash shapes. Anything else (a `find`, a\n * `cargo build`, a `python script.py`) is exactly what we want to\n * signal — that's the unbounded-tool case the verb was built for.\n */\nexport interface ForegroundLookup {\n kind: \"ok\" | \"shell-only\" | \"no-foreground\";\n pgid?: number;\n fgRow?: PsRow;\n /** All rows ps returned for the tty, for diagnostics / tests. */\n rows: PsRow[];\n}\n\n/** Comm names we treat as the agent's wrapping CLI / shell. Signalling\n * these via kick would just terminate the agent itself; that's\n * `mu agent close`'s job. The match is loose (suffix on basename)\n * so paths like `/usr/local/bin/pi` and aliases like `pi-meta` match\n * the right family. */\nconst WRAPPER_COMM_PREFIXES: readonly string[] = [\n \"pi\",\n \"claude\",\n \"codex\",\n \"bash\",\n \"zsh\",\n \"sh\",\n \"fish\",\n \"dash\",\n];\n\nfunction isWrapperComm(comm: string): boolean {\n // ps -o comm= returns the basename of the executable, possibly with\n // a leading `-` (login shell). Strip both.\n const cleaned = comm.replace(/^-/, \"\").trim();\n if (cleaned === \"\") return false;\n // Match exactly OR with a `-suffix` (e.g. `pi-meta`, `bash-3.2`).\n for (const prefix of WRAPPER_COMM_PREFIXES) {\n if (cleaned === prefix) return true;\n if (cleaned.startsWith(`${prefix}-`)) return true;\n }\n return false;\n}\n\nexport async function foregroundPgid(tty: string): Promise<ForegroundLookup> {\n // Strip the `/dev/` prefix because some `ps` implementations want\n // the tty as e.g. `ttys012` rather than `/dev/ttys012`. macOS's\n // ps accepts both; Linux's procps wants the short form. Pass the\n // short form everywhere for portability.\n const ttyShort = tty.startsWith(\"/dev/\") ? tty.slice(\"/dev/\".length) : tty;\n const result = await currentExecutor(\"ps\", [\"-t\", ttyShort, \"-o\", \"pid=,pgid=,stat=,comm=\"]);\n // ps exits 1 with empty output when no process is attached to the\n // tty; treat as no-foreground rather than throw.\n if (result.exitCode !== 0 && result.stdout.trim() === \"\") {\n return { kind: \"no-foreground\", rows: [] };\n }\n const rows = parsePsTtyOutput(result.stdout);\n if (rows.length === 0) return { kind: \"no-foreground\", rows };\n // Find the foreground row: stat contains `+`.\n const fg = rows.find((r) => r.stat.includes(\"+\"));\n if (!fg) {\n // ps returned rows but none is foreground. Treat as no-foreground.\n return { kind: \"no-foreground\", rows };\n }\n if (isWrapperComm(fg.comm)) {\n return { kind: \"shell-only\", pgid: fg.pgid, fgRow: fg, rows };\n }\n return { kind: \"ok\", pgid: fg.pgid, fgRow: fg, rows };\n}\n\n// ─── kill(2) the process group ────────────────────────────────────────\n\n/**\n * Send `signal` to process group `pgid`. The `kill -SIG -<pgid>` form\n * (negative pid) targets the whole pgrp, which is what we want — a\n * single `find` invocation may have spawned helpers; we want to take\n * the whole tree down with one signal.\n */\nasync function killPgrp(pgid: number, signal: KickSignal): Promise<void> {\n const result = await currentExecutor(\"kill\", [`-${signal}`, `-${pgid}`]);\n if (result.exitCode !== 0) {\n // ESRCH (pgid already gone) is benign — the process completed\n // between our ps and our kill. Treat as success.\n if (/no such process/i.test(result.stderr)) return;\n throw new Error(\n `kill -${signal} -${pgid} failed (exit ${result.exitCode}): ${result.stderr.trim() || \"no stderr\"}`,\n );\n }\n}\n\n// ─── Public verb ──────────────────────────────────────────────────────\n\nexport interface KickAgentOptions {\n workstream: string;\n /** Defaults to SIGINT (matches Ctrl-C semantics). */\n signal?: KickSignal;\n}\n\nexport interface KickAgentResult {\n agentName: string;\n paneId: string;\n /** TTY device path the foreground pgid was resolved against. */\n tty: string;\n /** The pgid we signalled. */\n signaledPgid: number;\n signal: KickSignal;\n /** The comm of the foreground process at the time of signal — useful\n * diagnostic in the event log (\"we kicked a `find`, not a `cargo`\"). */\n foregroundComm: string;\n}\n\n/**\n * Send `signal` to the foreground process group of an agent's pane\n * TTY. Default signal is SIGINT.\n *\n * Errors:\n * - `AgentNotFoundError` — the agent doesn't exist in this workstream.\n * - `PaneNotFoundError` (from paneTTY) — the agent's pane has vanished.\n * - `NoForegroundProcessError` — pane has no foreground job, OR the\n * foreground is the wrapping CLI itself (refuse; use `mu agent close`).\n *\n * Emits an `agent kick <name> (signal=..., pgid=..., comm=...)` event\n * on success.\n */\nexport async function kickAgent(\n db: Db,\n name: string,\n opts: KickAgentOptions,\n): Promise<KickAgentResult> {\n const signal: KickSignal = opts.signal ?? \"SIGINT\";\n const agent: AgentRow | undefined = getAgent(db, name, opts.workstream);\n if (!agent) throw new AgentNotFoundError(name, opts.workstream);\n // Load-bearing: no pane TTY, no process to signal.\n const tty = await (await activeMux()).paneTTY(agent.paneId);\n const lookup = await foregroundPgid(tty);\n if (lookup.kind === \"no-foreground\") {\n throw new NoForegroundProcessError(name, tty, \"no-foreground\");\n }\n if (lookup.kind === \"shell-only\") {\n throw new NoForegroundProcessError(name, tty, \"shell-only\");\n }\n // kind === \"ok\"\n const pgid = lookup.pgid;\n const fgRow = lookup.fgRow;\n if (pgid === undefined || fgRow === undefined) {\n // Should be unreachable given the discriminator; defensive throw\n // satisfies noUncheckedIndexedAccess + future-refactor safety.\n throw new NoForegroundProcessError(name, tty, \"no-foreground\");\n }\n await killPgrp(pgid, signal);\n // Signals a process; mutates no table at all, so there is nothing for\n // a trigger to see and this emit is the only record.\n emitEvent(\n db,\n agent.workstreamName,\n \"agent.kick\",\n `agent kick ${name} (signal=${signal}, pgid=${pgid}, comm=${fgRow.comm})`,\n );\n return {\n agentName: name,\n paneId: agent.paneId,\n tty,\n signaledPgid: pgid,\n signal,\n foregroundComm: fgRow.comm,\n };\n}\n","// mu — waitForAgents: block until agents finish working.\n//\n// The off-the-cuff / scratch pattern: spawn one or more task-less\n// helpers, send them work, then wait until they're done before reading\n// their output. Unlike `mu task wait` (which watches the task DAG),\n// scratch/subagent flows have NO task to wait on — the only signal is\n// the agent's own runtime status. This is that primitive.\n//\n// \"Done\" semantics (chosen in dogfood): an agent fires when it\n// transitions **busy → any other state**. The agent MUST have been\n// observed `busy` first, so a helper that is already idle when the wait\n// starts does NOT instantly fire — the caller is waiting for *this*\n// piece of work to finish, not for \"is idle right now\". An agent that\n// never goes busy (e.g. the prompt didn't land) just keeps the wait\n// pending until timeout, which is the honest outcome.\n//\n// Mirrors waitForTasks' shape: poll cadence + sleep test-seam, a\n// beforePoll hook so the CLI can re-detect live status each tick\n// without this SDK module importing tmux, --any/--all, and a timeout.\n// The CLI wrapper maps the result to task-wait-symmetric exit codes.\n\nimport type { RuntimeState } from \"../agent-state.js\";\nimport type { CtlBlocked } from \"../ctl/protocol.js\";\nimport type { Db } from \"../db.js\";\nimport { AgentNotFoundError } from \"./errors.js\";\n\n// ─── Test seam: poll-sleep (mirrors waitForTasks / tmux setSleepForTests)\nlet currentWaitSleep: (ms: number) => Promise<void> = (ms) =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\nexport function setAgentWaitSleepForTests(\n impl: ((ms: number) => Promise<void>) | undefined,\n): (ms: number) => Promise<void> {\n const previous = currentWaitSleep;\n currentWaitSleep = impl ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));\n return previous;\n}\n\n/** A single agent the wait verb is watching. Each ref carries its own\n * workstream so a cross-workstream wait can span sessions, mirroring\n * TaskWaitRef. */\nexport interface AgentWaitRef {\n workstreamName: string;\n name: string;\n}\n\n/** Snapshot of one watched agent at a poll tick. Supplied by the\n * caller's state-reader hook so this SDK stays free of mux imports. */\nexport interface AgentStatusSnapshot {\n /** Current runtime state, or null when the pane is gone (dead). */\n status: RuntimeState | null;\n /** Why the state is unknown, when the source supplied a reason. */\n unknownReason?: string;\n /** Final assistant text of the settled run (control-socket watches only). */\n lastText?: string;\n /** Error that ended the settled run (control-socket watches only). */\n lastError?: string;\n /** The pi session file holding the run's transcript (control-socket watches only). */\n sessionFile?: string;\n /** The watch ended because pi opened an extension dialog, not on a\n * settle (control-socket watches only). */\n blocked?: CtlBlocked;\n}\n\nexport interface AgentWaitOptions {\n /** When true, succeed as soon as ONE agent fires. Default false:\n * every listed agent must fire. */\n any?: boolean;\n /** Maximum time to wait, in ms. Default 600_000 (10 min). 0 = forever. */\n timeoutMs?: number;\n /** Poll interval. Default 1000ms; overridable for tests. */\n pollMs?: number;\n /** Preferred batch reader, called once per tick. Map keys are\n * `<workstream>/<name>`. */\n readStatuses?: (\n refs: readonly AgentWaitRef[],\n ) => Promise<ReadonlyMap<string, AgentStatusSnapshot>>;\n /** Legacy per-agent reader. Used only when `readStatuses` is absent. */\n readStatus?: (ref: AgentWaitRef) => Promise<AgentStatusSnapshot>;\n /**\n * Event-driven watcher, consulted once per agent before the first tick.\n * Returning a watch takes the agent out of polling: `initial` is its\n * state now, and `settled` resolves when its current or next run ends\n * (`status: null` = it died; `unknown` = no settle seen, poll it\n * instead). Returning undefined keeps it polled. The\n * signal aborts outstanding watches when the wait returns.\n */\n watch?: (ref: AgentWaitRef, signal: AbortSignal) => Promise<AgentWatch | undefined>;\n /** Called once when every watched agent is unknown on the first tick. */\n onInitialUnknown?: (agents: readonly AgentWaitAgentState[]) => void;\n}\n\nexport interface AgentWatch {\n initial: AgentStatusSnapshot;\n /** The run count the watch waits past (ctl `afterRuns`): a re-wait with\n * `--after-runs <this>` still catches a run that settles in between. */\n afterRuns?: number;\n settled: Promise<AgentStatusSnapshot>;\n}\n\nexport interface AgentWaitAgentState {\n workstreamName: string;\n name: string;\n /** State at exit time (null = pane gone / dead). */\n status: RuntimeState | null;\n /** True once we observed this agent `busy` at any tick. */\n wasBusy: boolean;\n /** True when the agent fired: was busy, then moved to a non-busy\n * live status. */\n fired: boolean;\n /** Why the current state is unknown, when supplied by its source. */\n unknownReason?: string;\n /** Final assistant text of the settled run; set only for control-socket\n * (pi) agents, absent for polled ones. */\n lastText?: string;\n /** Error that ended the settled run (API error after pi's retries). */\n lastError?: string;\n /** The pi session file holding the run's transcript; control-socket agents only. */\n sessionFile?: string;\n /** Set when the wait ended on an extension dialog pi is waiting on: the\n * run is not finished (`fired` stays false). Control-socket agents only. */\n blocked?: CtlBlocked;\n /** The run baseline this wait counted from (control-socket agents only):\n * re-wait with `--after-runs <afterRuns>` so a run that settles before\n * the re-wait starts is still returned. */\n afterRuns?: number;\n /** True when the agent's pane vanished mid-wait. Surfaced separately\n * so the CLI can exit non-zero rather than treating a crash as a\n * clean finish. */\n dead: boolean;\n}\n\nexport interface AgentWaitResult {\n /** Per-agent state at exit, same order as input. */\n agents: AgentWaitAgentState[];\n /** True when we exited on the timeout, not because the condition met. */\n timedOut: boolean;\n}\n\n/**\n * Block until watched agents finish (busy → any other state).\n *\n * Pre-flight: every agent in `input` MUST exist; missing ones throw\n * AgentNotFoundError before any waiting begins (loud-fail; a typo'd\n * name silently waiting forever is the worst UX, mirrors waitForTasks).\n *\n * Returns the final per-agent state; the CLI decides exit codes\n * (0 met / 5 timeout / 6 a watched agent died).\n */\nexport async function waitForAgents(\n db: Db,\n input: readonly AgentWaitRef[],\n opts: AgentWaitOptions,\n): Promise<AgentWaitResult> {\n if (input.length === 0) throw new Error(\"waitForAgents: refs must be non-empty\");\n\n // Pre-flight existence check.\n for (const ref of input) {\n const row = db\n .prepare(\n `SELECT 1 FROM agents a JOIN workstreams ws ON ws.id = a.workstream_id\n WHERE a.name = ? AND ws.name = ?`,\n )\n .get(ref.name, ref.workstreamName);\n if (row === undefined) throw new AgentNotFoundError(ref.name);\n }\n\n const pollMs = opts.pollMs ?? 1000;\n const timeoutMs = opts.timeoutMs ?? 600_000;\n const any = opts.any === true;\n const startedAt = Date.now();\n\n // Mutable per-agent tracking.\n const state: AgentWaitAgentState[] = input.map((ref) => ({\n workstreamName: ref.workstreamName,\n name: ref.name,\n status: null,\n wasBusy: false,\n fired: false,\n dead: false,\n }));\n\n const conditionMet = (): boolean => {\n // A dialog-blocked agent needs a human now: it ends the wait, like a\n // stall ends `mu task wait`, whatever --any / --all says.\n if (state.some((s) => s.blocked !== undefined)) return true;\n const done = state.filter((s) => s.fired || s.dead);\n return any ? done.length > 0 : done.length === state.length;\n };\n\n const refKey = (ref: AgentWaitRef): string => `${ref.workstreamName}/${ref.name}`;\n\n // Event-driven agents: their settle wakes the loop instead of a poll.\n const abort = new AbortController();\n const watched = new Set<number>();\n let wake: () => void = () => {};\n let woken = new Promise<void>((resolve) => {\n wake = resolve;\n });\n const rearm = (): void => {\n woken = new Promise<void>((resolve) => {\n wake = resolve;\n });\n };\n if (opts.watch) {\n const watches = await Promise.all(input.map((ref) => opts.watch?.(ref, abort.signal)));\n watches.forEach((w, i) => {\n const st = state[i];\n if (w === undefined || st === undefined) return;\n watched.add(i);\n st.status = w.initial.status;\n if (w.afterRuns !== undefined) st.afterRuns = w.afterRuns;\n if (w.initial.status === \"busy\") st.wasBusy = true;\n void w.settled.then(\n (snap) => {\n if (snap.status === null) {\n st.dead = true;\n st.status = null;\n } else if (snap.blocked !== undefined) {\n // A dialog ended the watch: the run is still open, not settled.\n st.status = snap.status;\n st.blocked = snap.blocked;\n } else if (snap.status === \"unknown\") {\n // No settle observed: hand the agent back to polling.\n watched.delete(i);\n } else {\n st.status = snap.status;\n st.wasBusy = true;\n st.fired = true;\n if (snap.lastText !== undefined) st.lastText = snap.lastText;\n if (snap.lastError !== undefined) st.lastError = snap.lastError;\n if (snap.sessionFile !== undefined) st.sessionFile = snap.sessionFile;\n }\n wake();\n },\n () => {},\n );\n });\n }\n const finish = (timedOut: boolean): AgentWaitResult => {\n abort.abort();\n return { agents: state, timedOut };\n };\n\n // One state read over all not-yet-settled polled agents.\n const tick = async (): Promise<void> => {\n const pending = input.filter((_, i) => {\n const st = state[i];\n return st !== undefined && !st.fired && !st.dead && !watched.has(i);\n });\n if (pending.length === 0) return;\n const snapshots = opts.readStatuses ? await opts.readStatuses(pending) : undefined;\n if (snapshots === undefined && opts.readStatus === undefined) {\n throw new Error(\"waitForAgents: readStatuses or readStatus is required\");\n }\n for (let i = 0; i < input.length; i++) {\n const st = state[i];\n const ref = input[i];\n if (st === undefined || ref === undefined) continue;\n if (st.fired || st.dead || watched.has(i)) continue;\n const snap = snapshots?.get(refKey(ref)) ?? (await opts.readStatus?.(ref));\n if (snap === undefined) {\n st.status = \"unknown\";\n st.unknownReason = \"state reader returned no row\";\n continue;\n }\n if (snap.status === null) {\n st.dead = true;\n st.status = null;\n continue;\n }\n st.status = snap.status;\n st.unknownReason = snap.status === \"unknown\" ? snap.unknownReason : undefined;\n if (snap.blocked !== undefined) {\n // An open extension dialog: the run is not finished, whatever the\n // busy history says. Reached when a ctl watch dropped back to polling.\n st.blocked = snap.blocked;\n } else if (snap.status === \"busy\") {\n st.wasBusy = true;\n } else if (snap.status !== \"unknown\" && st.wasBusy) {\n // Unknown is absence of a reading, not evidence that work ended.\n st.fired = true;\n }\n }\n };\n\n // Initial pass — seeds wasBusy for agents already busy; an agent that\n // is already idle here just sits pending (it must go busy first).\n await tick();\n if (state.every((agent) => agent.status === \"unknown\")) opts.onInitialUnknown?.(state);\n if (conditionMet()) return finish(false);\n\n while (true) {\n const elapsed = Date.now() - startedAt;\n if (timeoutMs > 0 && elapsed >= timeoutMs) return finish(true);\n const remaining = timeoutMs > 0 ? timeoutMs - elapsed : undefined;\n const polled = input.some((_, i) => {\n const st = state[i];\n return st !== undefined && !st.fired && !st.dead && !watched.has(i);\n });\n // Sleep, but never past the deadline (mirrors waitForTasks' clamp).\n // A settle ends the sleep early; with nothing left to poll, only a\n // settle or the deadline does.\n const sleeps: Promise<unknown>[] = [woken];\n let timer: ReturnType<typeof setTimeout> | undefined;\n if (polled) sleeps.push(currentWaitSleep(Math.min(pollMs, remaining ?? pollMs)));\n else if (remaining !== undefined) {\n sleeps.push(new Promise((resolve) => (timer = setTimeout(resolve, remaining))));\n }\n await Promise.race(sleeps);\n if (timer) clearTimeout(timer);\n rearm();\n await tick();\n if (conditionMet()) return finish(false);\n }\n}\n","// mu — the canonical \"reality wins\" reconciliation routine.\n//\n// Three steps, in order:\n//\n// 1. Prune ghost rows whose pane no longer exists in the mux.\n// 2. Refresh pane titles for surviving agents.\n// 3. Surface orphan panes that look like agents but have no DB row.\n// Do NOT auto-adopt — `mu agent list` shows orphans under a separate\n// section and the user runs `mu agent adopt` to formally claim.\n//\n// `mu state`, `mu agent list`, and `mu doctor` all call this. It's the only\n// place where the registry's view of the world is reconciled against tmux's\n// view.\n\nimport * as agentSdk from \"./agents.js\";\nimport type { Db } from \"./db.js\";\nimport { activeMux, type MuxPane } from \"./mux.js\";\n\n/**\n * What kind of reconciliation pass to run.\n *\n * \"full\" Default for `mu state` and `mu agent list`. Prunes\n * ghosts (deleting the registry row, which fires the\n * deleteAgent reaper that flips IN_PROGRESS tasks back\n * to OPEN with [reaper] notes), refreshes pane titles\n * of surviving agents, surfaces orphans.\n *\n * \"report-only\" Pure observation. Counts would-be-pruned ghosts\n * without deleting; skips the title refresh (no DB\n * writes, no tmux title writes); surfaces orphans\n * (pure read). Used by `mu doctor` (read-only\n * diagnostic).\n *\n * Mid-spawn placeholders are protected directly in the prune loop, so read\n * paths no longer need a separate mode just to avoid racing spawn's workspace\n * pre-stage.\n */\nexport type ReconcileMode = \"full\" | \"report-only\";\n\nexport interface ReconcileOptions {\n /** The workstream whose registry rows we're reconciling. */\n workstream: string;\n /**\n * Override the tmux session name. Defaults to `mu-<workstream>`. Useful\n * for tests and for the rare case where a workstream's tmux session was\n * created with a non-default name.\n */\n tmuxSession?: string;\n /**\n * Which kind of pass to run. Default is `\"full\"` (the documented\n * mutating behaviour `mu agent list` has always had). See\n * `ReconcileMode` for the full per-mode contract.\n *\n * BREAKING: this replaces the previous `dryRun?: boolean` flag.\n * Migration: `dryRun: true` → `mode: \"report-only\"`; default\n * (`dryRun: false` / unset) → `mode: \"full\"`.\n */\n mode?: ReconcileMode;\n}\n\nexport interface ReconcileReport {\n /** Number of registry rows whose pane was gone. In `report-only` mode\n * this is the count of rows that WOULD have been pruned; in `full`\n * mode it's the count actually deleted. */\n prunedGhosts: number;\n /** Panes in the workstream's tmux session that look like agents but\n * aren't in the registry. NOT auto-adopted. */\n orphans: MuxPane[];\n /** Which mode this report was generated in. Lets callers switch their\n * output text (\"agents pruned\" vs \"would-be-pruned (suppressed)\")\n * without re-deriving from options. */\n mode: ReconcileMode;\n}\n\n/**\n * Pane commands that suggest \"this is an agent, surface it as an orphan.\"\n * 0.1.0 scope: pi only is detected, but the orphan list will surface\n * claude/codex panes too so the user can adopt them later.\n *\n * Also includes any env-overridden binary names (e.g. `MU_PI_COMMAND=pi-alt`\n * makes \"pi-alt\" agent-worthy) so externally-spawned panes running the\n * user's actual pi binary are still surfaced as orphans.\n */\nconst BASE_AGENT_CLIS: readonly string[] = [\"pi\", \"claude\", \"codex\"];\n\nfunction knownAgentCommands(): ReadonlySet<string> {\n const names = new Set<string>(BASE_AGENT_CLIS);\n for (const cli of BASE_AGENT_CLIS) {\n names.add(agentSdk.resolveCliCommand(cli));\n }\n return names;\n}\n\n/**\n * Build a recogniser closure that captures one snapshot of\n * knownAgentCommands() (which itself reads MU_<CLI>_COMMAND env vars).\n * Hoisted out of the orphan-surface loop so reconcile() reads each env\n * var at most once per pass instead of once per pane: dozens of panes\n * × three env vars per call = needless syscalls in a `mu state` poll\n * tick. Also pins the env-var snapshot for the loop, so test suites\n * that twiddle MU_PI_COMMAND in afterEach can't race the inner check.\n */\nfunction buildAgentPaneRecogniser(): (pane: MuxPane) => boolean {\n const known = knownAgentCommands();\n return (pane) => known.has(pane.command);\n}\n\nexport async function reconcile(db: Db, opts: ReconcileOptions): Promise<ReconcileReport> {\n const sessionName = opts.tmuxSession ?? `mu-${opts.workstream}`;\n const mode: ReconcileMode = opts.mode ?? \"full\";\n const dbAgents = agentSdk.listAgents(db, { workstream: opts.workstream });\n // Load-bearing: reconcile IS the mux read. With no reachable mux there\n // is no reality to reconcile against, and silently reporting \"zero\n // panes\" would prune every registered agent as a ghost.\n const mux = await activeMux();\n const muxPanes = await mux.listPanesInSession(sessionName);\n const paneById = new Map(muxPanes.map((p) => [p.paneId, p]));\n\n let prunedGhosts = 0;\n const orphans: MuxPane[] = [];\n\n // 1. Prune ghosts (DB row references a pane that no longer exists).\n // `full` mode deletes (and therefore reaps); `report-only` counts\n // the would-be-prunes so callers can surface drift, but leaves the\n // row in place. Mid-spawn placeholder pane ids are protected by\n // the defensive skip that lets read paths use full mode safely.\n // Placeholder rows survive this step, but are split out so the title\n // refresh and orphan exclusion only reason about real tmux panes.\n const survivors: agentSdk.AgentRow[] = [];\n const pendingSurvivors: agentSdk.AgentRow[] = [];\n for (const agent of dbAgents) {\n if (agentSdk.isPendingPaneId(agent.paneId)) {\n pendingSurvivors.push(agent);\n } else if (paneById.has(agent.paneId)) {\n survivors.push(agent);\n } else {\n if (mode !== \"full\") {\n prunedGhosts++;\n } else if (agentSdk.deleteAgent(db, agent.name, agent.workstreamName, agent.paneId)) {\n prunedGhosts++;\n }\n }\n }\n\n // 2. Refresh durable pane titles in mutating mode. Runtime state is\n // resolved separately and is never written to the registry. Pass\n // the live title so unchanged panes are not rewritten every tick.\n if (mode === \"full\") {\n for (const agent of survivors) {\n const currentTitle = paneById.get(agent.paneId)?.title;\n await agentSdk.refreshAgentTitle(db, agent.name, agent.workstreamName, currentTitle);\n }\n }\n\n // 3. Surface orphan panes. `looksLikeAgentPane` is conservative:\n // pane.command must be one we recognise as an agent CLI. A bash\n // pane the user spawned for their own use is never an orphan.\n // Pure read; runs in every mode.\n const dbPaneIds = new Set(survivors.map((a) => a.paneId));\n const looksLikeAgentPane = buildAgentPaneRecogniser();\n for (const pane of muxPanes) {\n if (dbPaneIds.has(pane.paneId)) continue;\n if (looksLikeAgentPane(pane)) orphans.push(pane);\n }\n\n return { prunedGhosts, orphans, mode };\n}\n","// mu — task-DAG read + ASCII forest rendering helpers.\n//\n// Shared by the static `mu task tree` command and the read-only TUI DAG\n// popup. Pure rendering lives here so the box-drawing characters and\n// diamond-collapse semantics have one implementation.\n\nimport pc from \"picocolors\";\nimport type { Db } from \"./db.js\";\nimport type { TaskStatus } from \"./tasks/status.js\";\nimport { listTasks, type TaskRow } from \"./tasks.js\";\n\n// One-line marker appended to a tree node when its subtree was already\n// rendered earlier in the forest (DAG diamond collapse). Symbol-only\n// + dimmed: the ↻ glyph carries the recurrence semantics, the dim\n// keeps it from competing with the task title for the eye.\nconst RECURRENCE_MARKER = ` ${pc.dim(\"(↻)\")}`;\n\nexport interface FullDag {\n /** Root tasks: no incoming `blocks` edge (no blockers). */\n roots: TaskRow[];\n /** Edges map parent task name → child task names (what parent blocks). */\n edges: Map<string, string[]>;\n /** All tasks in the workstream, keyed by operator-facing name. */\n tasks: Map<string, TaskRow>;\n}\n\nexport type TaskStatusLabelFn = (task: TaskRow) => string;\n\nexport interface RenderTreeOptions {\n /** Include the task title after the name + status label. Default: true. */\n includeTitle?: boolean;\n}\n\nexport interface LoadFullDagOptions {\n /** Optional visible-status filter. Omitted = every task status. */\n statuses?: ReadonlySet<TaskStatus>;\n /** Optional row predicate, applied after `statuses` (e.g. the TUI's\n * substate toggles). Omitted = keep every row. */\n include?: (task: TaskRow) => boolean;\n}\n\nexport function loadFullDag(db: Db, workstream: string, opts: LoadFullDagOptions = {}): FullDag {\n const tasks = listTasks(db, workstream).filter(\n (t) =>\n (opts.statuses === undefined || opts.statuses.has(t.status)) &&\n (opts.include === undefined || opts.include(t)),\n );\n const byName = new Map(tasks.map((t) => [t.name, t]));\n const incoming = new Set<string>();\n const edges = new Map<string, string[]>();\n\n for (const task of tasks) {\n edges.set(task.name, []);\n }\n\n // Start from task_edges deliberately. With ordinary JOINs plus the\n // same-workstream guard below, SQLite chose tasks(src) × tasks(dst)\n // before probing the edge PK — quadratic in workstream size. CROSS JOIN\n // fixes the loop order at edges → two INTEGER-PK lookups while retaining\n // the guard against malformed cross-workstream rows.\n const rows = db\n .prepare(\n `SELECT src.local_id AS parent, dst.local_id AS child\n FROM task_edges e\n CROSS JOIN tasks src\n CROSS JOIN tasks dst\n WHERE src.id = e.from_task_id\n AND dst.id = e.to_task_id\n AND src.workstream_id = (SELECT id FROM workstreams WHERE name = ?)\n AND dst.workstream_id = src.workstream_id\n ORDER BY src.local_id, dst.local_id`,\n )\n .all(workstream) as { parent: string; child: string }[];\n\n for (const row of rows) {\n if (!byName.has(row.parent) || !byName.has(row.child)) continue;\n incoming.add(row.child);\n const children = edges.get(row.parent) ?? [];\n children.push(row.child);\n edges.set(row.parent, children);\n }\n\n const roots = tasks.filter((t) => !incoming.has(t.name));\n return { roots, edges, tasks: byName };\n}\n\n/**\n * Render a DAG forest in the same ASCII shape as `mu task tree --down`:\n * each root is printed as a header node, dependents are below it, and\n * DAG diamonds collapse after the first full subtree render with a\n * one-line recurrence marker.\n */\nexport function renderForest(\n roots: readonly TaskRow[],\n edges: ReadonlyMap<string, readonly string[]>,\n statusFn: TaskStatusLabelFn,\n tasksByName?: ReadonlyMap<string, TaskRow>,\n opts: RenderTreeOptions = {},\n): string {\n const byName = new Map(tasksByName ?? roots.map((t) => [t.name, t]));\n const seen = new Set<string>();\n const sections: string[] = [];\n\n for (const root of roots) {\n if (!byName.has(root.name)) byName.set(root.name, root);\n const lines = [formatTreeNodeLabel(root, statusFn, opts)];\n if (seen.has(root.name)) {\n lines[0] = `${lines[0]}${RECURRENCE_MARKER}`;\n } else {\n seen.add(root.name);\n renderForestChildren(root.name, \"\", edges, byName, statusFn, seen, lines, opts);\n }\n sections.push(lines.join(\"\\n\"));\n }\n\n return sections.join(\"\\n\\n\");\n}\n\nexport function renderTaskTree(\n db: Db,\n workstream: string,\n root: TaskRow,\n direction: \"blockers\" | \"dependents\",\n statusFn: TaskStatusLabelFn,\n opts: RenderTreeOptions = {},\n): string {\n const dag = loadFullDag(db, workstream);\n if (direction === \"dependents\") {\n return renderForest([root], dag.edges, statusFn, dag.tasks, opts);\n }\n\n const blockers = new Map<string, string[]>([...dag.tasks.keys()].map((name) => [name, []]));\n for (const [blocker, dependents] of dag.edges) {\n for (const dependent of dependents) blockers.get(dependent)?.push(blocker);\n }\n for (const names of blockers.values()) names.sort();\n return renderForest([root], blockers, statusFn, dag.tasks, opts);\n}\n\nfunction renderForestChildren(\n taskName: string,\n prefix: string,\n edges: ReadonlyMap<string, readonly string[]>,\n byName: Map<string, TaskRow>,\n statusFn: TaskStatusLabelFn,\n seen: Set<string>,\n lines: string[],\n opts: RenderTreeOptions,\n): void {\n const children = edges.get(taskName) ?? [];\n for (let i = 0; i < children.length; i++) {\n const childName = children[i];\n if (childName === undefined) continue;\n const isLast = i === children.length - 1;\n const branch = isLast ? \"└── \" : \"├── \";\n const childPrefix = prefix + (isLast ? \" \" : \"│ \");\n const child = byName.get(childName);\n\n if (!child) {\n lines.push(`${prefix}${branch}${childName} (missing!)`);\n continue;\n }\n\n if (seen.has(childName)) {\n lines.push(\n `${prefix}${branch}${formatTreeNodeLabel(child, statusFn, opts)}${RECURRENCE_MARKER}`,\n );\n continue;\n }\n\n lines.push(`${prefix}${branch}${formatTreeNodeLabel(child, statusFn, opts)}`);\n seen.add(childName);\n renderForestChildren(childName, childPrefix, edges, byName, statusFn, seen, lines, opts);\n }\n}\n\nexport function formatTreeNodeLabel(\n t: TaskRow,\n statusFn: TaskStatusLabelFn,\n opts: RenderTreeOptions = {},\n): string {\n const base = `${t.name} ${statusFn(t)}`;\n if (opts.includeTitle === false) return base;\n return `${base} ${t.title}`;\n}\n","// mu — rebuild: materialize a fresh DB by replaying the ops log.\n//\n// The third leg of the ops-log substrate, after capture (write side) and\n// apply (read side). This is the DISASTER-RECOVERY story that replaces\n// the snapshot files mu no longer keeps: given an intact `ops` table, every\n// portable row is reconstructable, because the log is the canonical\n// record and the tables are a projection of it.\n//\n// It is also the foundation the doctor drift check stands on. \"Is the\n// projection still faithful to the log?\" is answered by rebuilding into\n// a temp DB and diffing — which is why `rebuildInto` takes the target\n// path as a PARAMETER and prints nothing. All human output lives in the\n// CLI layer (src/cli/rebuild.ts).\n//\n// REBUILD INTO A NEW FILE, NEVER IN PLACE\n// ---------------------------------------\n// Locked decision. A rebuild that overwrote the live DB would be a\n// destructive operation whose failure mode is \"no database at all\", and\n// it would have to hold a write lock over the whole replay. Writing a\n// new file and PRINTING THE SWAP COMMAND keeps the operator in control:\n// they can diff, inspect, and swap when ready. It also means a rebuild\n// is safe to run at any time, including from the drift check, with no\n// risk to live state.\n//\n// REBUILD IS NOT INGEST\n// ---------------------\n// The distinction is load-bearing and easy to get backwards.\n//\n// ingest = \"absorb a PEER's ops\". Only SYNCED_ENTITIES may cross a\n// machine boundary, so ingest filters. A peer's agent rows\n// are meaningless here (`pane_id` '%17' names a pane on\n// their box), so they must never arrive.\n// rebuild = \"reconstruct MY OWN database\". A local recovery\n// operation, so it must replay EVERYTHING the log knows,\n// including machine-local ops. Dropping them would silently\n// discard this machine's own log history — `mu log` would\n// come back empty after a recovery.\n//\n// So this module deliberately does NOT filter by SYNCED_ENTITIES. It\n// copies every op verbatim and projects the ones that have a portable\n// table to project into.\n//\n// WHAT A REBUILT DB LEGITIMATELY LOSES\n// ------------------------------------\n// The ops log only contains what capture recorded, and capture has\n// triggers on the PORTABLE tables only. `agents` and `vcs_workspaces`\n// have no triggers, so they leave no ops and cannot be reconstructed.\n//\n// That is CORRECT, not a gap. Both tables hold values that are\n// meaningless after recovery: `agents.pane_id` names a tmux pane in a\n// server that no longer has it, and `vcs_workspaces.path` is an absolute\n// path whose working copy may be gone. Resurrecting either would produce\n// rows that lie about reality, and `mu doctor` would immediately flag\n// them as ghosts.\n//\n// But it must be REPORTED, never silent. An operator who rebuilds and\n// does not realise their agent registry is empty will wonder why\n// `mu agent list` is blank. `RebuildReport.machineLocalLost` carries the\n// per-table counts so the CLI can say so explicitly and tell them to\n// re-spawn.\n\nimport { existsSync, mkdirSync, rmSync, statSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { applyOp, type Op } from \"./apply.js\";\nimport { type Db, openDb, SYNCED_ENTITIES } from \"./db.js\";\nimport { compareHlc } from \"./hlc.js\";\nimport { isLegacyLogOnlyIntent } from \"./legacy-ops.js\";\nimport { withCaptureSuppressed } from \"./op-context.js\";\nimport type { HasNextSteps, NextStep } from \"./output.js\";\n\n/** Raised when the rebuild target already exists. Never overwrite: the\n * operator may have pointed at their live DB by mistake, and a rebuild\n * is supposed to be the SAFE recovery path. */\nexport class RebuildTargetExistsError extends Error implements HasNextSteps {\n constructor(readonly path: string) {\n super(`rebuild target already exists: ${path}`);\n this.name = \"RebuildTargetExistsError\";\n }\n\n errorNextSteps(): NextStep[] {\n return [\n { intent: \"Pick a path that does not exist\", command: \"mu rebuild /tmp/mu-rebuilt.db\" },\n { intent: \"Or remove the stale target first\", command: `rm -f ${this.path}` },\n ];\n }\n}\n\n/** Raised when the target path resolves to the source DB. Rebuilding a\n * DB onto itself would truncate the very log being replayed. */\nexport class RebuildTargetIsSourceError extends Error implements HasNextSteps {\n constructor(readonly path: string) {\n super(`rebuild target is the source DB: ${path}`);\n this.name = \"RebuildTargetIsSourceError\";\n }\n\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Rebuild writes a NEW file; pick a different path\",\n command: \"mu rebuild /tmp/mu-rebuilt.db\",\n },\n ];\n }\n}\n\n/** Per-table counts of rows a rebuild cannot reconstruct, because the\n * table has no capture triggers and therefore leaves no ops. */\nexport interface MachineLocalLoss {\n table: string;\n /** Rows present in the SOURCE that will be absent from the rebuild. */\n rows: number;\n}\n\n/** What a rebuild did. Returned rather than printed so the drift check\n * can consume it programmatically. */\nexport interface RebuildReport {\n /** Absolute-ish path written (as given by the caller). */\n targetPath: string;\n /** Ops copied into the target's log. Every op, not just synced ones. */\n opsCopied: number;\n /** Ops that projected into a portable table. Always <= opsCopied:\n * log-only entities (message / event / broadcast), machine-local\n * agent / workspace ops and legacy log-only intents are copied but\n * have no table to land in. */\n opsProjected: number;\n /** Ops that changed a row when applied. Lower than opsProjected\n * whenever later ops superseded earlier ones — which is normal and\n * is exactly what makes the rebuild a merge rather than a diff. */\n opsChangedRows: number;\n /** Ops skipped as non-projectable, by entity. Diagnostic only. */\n logOnlyByEntity: Record<string, number>;\n /** Row counts per portable table in the rebuilt DB. */\n rebuiltRows: Record<string, number>;\n /** Tables that cannot be rebuilt, with the row counts being lost. */\n machineLocalLost: MachineLocalLoss[];\n /** The machine identity carried across, so the rebuilt DB remains the\n * SAME peer rather than becoming a new one. */\n machineId: string;\n}\n\n/** Tables that hold real state but leave no ops, so a rebuild cannot\n * reconstruct them. Both are machine-local by nature — see the module\n * comment for why resurrecting them would be wrong even if we could. */\nconst UNREBUILDABLE_TABLES = [\"agents\", \"vcs_workspaces\"] as const;\n\n/** Entities that exist only in the log: there is no portable table to\n * project them into, so copying the op IS applying it.\n *\n * 'message' / 'event' / 'broadcast' are log lines (src/logs.ts writes\n * them). All three are copied verbatim and deliberately not passed to\n * applyOp, which would reject the log kinds as non-synced. */\nconst LOG_ONLY_ENTITIES = new Set([\"message\", \"event\", \"broadcast\"]);\n\n/** Ops that `applyOp` knows how to project into a portable table. This\n * is the intersection of \"synced\" and \"has a table\", which excludes\n * 'message' even though it is in SYNCED_ENTITIES.\n *\n * Historical log-only intents can name a synced entity, so intent is\n * also part of the classification even after its command is removed. */\nfunction isProjectable(entity: string, intent: string | null): boolean {\n if (isLegacyLogOnlyIntent(intent)) return false;\n if (LOG_ONLY_ENTITIES.has(entity)) return false;\n return (SYNCED_ENTITIES as readonly string[]).includes(entity);\n}\n\ninterface RawOpRow {\n hlc: string;\n machine_id: string;\n group_id: string;\n actor: string | null;\n intent: string | null;\n entity: string;\n key: string;\n op: string;\n payload: string;\n created_at: string;\n}\n\nfunction opFromRow(row: RawOpRow): Op {\n return {\n hlc: row.hlc,\n machineId: row.machine_id,\n groupId: row.group_id,\n actor: row.actor,\n intent: row.intent,\n entity: row.entity,\n key: row.key,\n op: row.op === \"del\" ? \"del\" : \"put\",\n payload: row.payload,\n };\n}\n\nexport interface RebuildOptions {\n /** Path for the new DB. Must not exist. */\n targetPath: string;\n /** Overwrite an existing target. Off by default so a mistyped path\n * cannot clobber a real file; the drift check sets it because it\n * owns a temp path it just created. */\n force?: boolean;\n}\n\n/**\n * Replay `source`'s ops log into a brand-new DB at `opts.targetPath`.\n *\n * Prints nothing and returns a report, so both `mu rebuild` and the\n * (forthcoming) doctor drift check can use it — the latter rebuilds into\n * a temp path and diffs rather than showing a human anything.\n *\n * SYNCHRONOUS, matching applyOp and withOpContext: the op context is a\n * per-connection temp table, so interleaved async scopes would clobber\n * each other's suppression flag.\n */\nexport function rebuildInto(source: Db, opts: RebuildOptions): RebuildReport {\n const { targetPath } = opts;\n\n // Refuse to touch the source. `sqlite_master`-level identity is not\n // enough — the caller may pass a different string for the same file —\n // so compare the resolved filename SQLite itself reports.\n const sourceFile = (source.pragma(\"database_list\") as Array<{ name: string; file: string }>).find(\n (row) => row.name === \"main\",\n )?.file;\n if (sourceFile !== undefined && sourceFile.length > 0) {\n const sameFile =\n sourceFile === targetPath ||\n (existsSync(targetPath) && existsSync(sourceFile) && sameInode(sourceFile, targetPath));\n if (sameFile) throw new RebuildTargetIsSourceError(targetPath);\n }\n if (existsSync(targetPath) && opts.force !== true) {\n throw new RebuildTargetExistsError(targetPath);\n }\n\n mkdirSync(dirname(targetPath), { recursive: true });\n\n // Read everything we need from the source FIRST, so the target is only\n // opened once we know the replay can proceed.\n const identity = source\n .prepare(\n \"SELECT machine_id, hostname, created_at, last_wall, last_counter FROM machine_identity WHERE id = 1\",\n )\n .get() as\n | {\n machine_id: string;\n hostname: string | null;\n created_at: string;\n last_wall: number;\n last_counter: number;\n }\n | undefined;\n if (!identity) throw new Error(\"source DB has no machine_identity row; not a mu DB\");\n\n const opRows = source\n .prepare(\n `SELECT hlc, machine_id, group_id, actor, intent, entity, key, op, payload, created_at\n FROM ops`,\n )\n .all() as RawOpRow[];\n\n // HLC ORDER, not seq order. seq is a local append cursor, so it\n // reflects the order ops were RECORDED, which for ingested peer ops is\n // arrival order rather than causal order. Replaying in HLC order is\n // what makes per-field LWW resolve correctly (see src/apply.ts), and\n // it is why the rebuild converges to the same state regardless of how\n // the log happened to be assembled.\n opRows.sort((a, b) => compareHlc(a.hlc, b.hlc));\n\n const peerRows = source\n .prepare(\"SELECT machine_id, last_applied_seq, last_seen_at FROM sync_peers\")\n .all() as Array<{\n machine_id: string;\n last_applied_seq: number;\n last_seen_at: string | null;\n }>;\n\n const machineLocalLost: MachineLocalLoss[] = [];\n for (const table of UNREBUILDABLE_TABLES) {\n const row = source.prepare(`SELECT COUNT(*) AS n FROM ${table}`).get() as { n: number };\n if (row.n > 0) machineLocalLost.push({ table, rows: row.n });\n }\n\n // `force` replaces the target, never merges into it: replaying over an\n // existing DB would keep its foreign rows and ops under our identity.\n if (opts.force === true) {\n for (const suffix of [\"\", \"-wal\", \"-shm\"]) rmSync(`${targetPath}${suffix}`, { force: true });\n }\n const target = openDb({ path: targetPath });\n try {\n // Carry the machine identity across BEFORE replaying.\n //\n // A fresh openDb seeds a NEW uuid, which would make the rebuilt DB a\n // DIFFERENT PEER: its own historical ops would look foreign to it,\n // the UNIQUE (machine_id, hlc) identity of every op would no longer\n // match its author, and peers tracking watermarks against the old id\n // would treat it as an unknown machine. Recovery must preserve who\n // this machine IS.\n //\n // The HLC clock (last_wall / last_counter) comes too. Without it the\n // rebuilt DB starts at 0 and the next local edit would mint an HLC\n // BELOW every op already in its log — so a brand-new change would\n // sort as older than history and lose every LWW comparison against\n // it. Monotonicity is a property of the machine, not of the file.\n target\n .prepare(\n `UPDATE machine_identity\n SET machine_id = @machineId, hostname = @hostname, created_at = @createdAt,\n last_wall = @lastWall, last_counter = @lastCounter\n WHERE id = 1`,\n )\n .run({\n machineId: identity.machine_id,\n hostname: identity.hostname,\n createdAt: identity.created_at,\n lastWall: identity.last_wall,\n lastCounter: identity.last_counter,\n });\n\n const insertOp = target.prepare(\n `INSERT OR IGNORE INTO ops\n (hlc, machine_id, group_id, actor, intent, entity, key, op, payload, created_at)\n VALUES (@hlc, @machineId, @groupId, @actor, @intent, @entity, @key, @op, @payload, @createdAt)`,\n );\n const insertPeer = target.prepare(\n `INSERT OR REPLACE INTO sync_peers (machine_id, last_applied_seq, last_seen_at)\n VALUES (@machineId, @lastAppliedSeq, @lastSeenAt)`,\n );\n\n const logOnlyByEntity: Record<string, number> = {};\n let opsProjected = 0;\n let opsChangedRows = 0;\n\n // ONE transaction for the whole replay. A rebuild is all-or-nothing:\n // a half-replayed DB is worse than no DB, because it looks usable.\n const replay = target.transaction(() => {\n // Capture-suppressed for the entire replay. Without this, applying\n // each op would fire the capture triggers and mint a SECOND op per\n // row, so the rebuilt log would be roughly double the original and\n // full of ops with fresh HLCs that never happened. The suppression\n // wraps the op INSERTs too, so nothing here can mint.\n withCaptureSuppressed(target, () => {\n for (const row of opRows) {\n // Copy the op verbatim, whatever its entity. This is the\n // rebuild-is-not-ingest rule: the log is this machine's own\n // history and every row of it survives recovery, including\n // machine-local entities that would never cross a peer\n // boundary.\n insertOp.run({\n hlc: row.hlc,\n machineId: row.machine_id,\n groupId: row.group_id,\n actor: row.actor,\n intent: row.intent,\n entity: row.entity,\n key: row.key,\n op: row.op,\n payload: row.payload,\n createdAt: row.created_at,\n });\n\n if (!isProjectable(row.entity, row.intent)) {\n logOnlyByEntity[row.entity] = (logOnlyByEntity[row.entity] ?? 0) + 1;\n continue;\n }\n // Project through the SAME apply path sync ingest uses. Not a\n // second implementation of the merge rules: tombstone\n // ordering, per-field LWW and grow-only sets all come from\n // src/apply.ts, so a rebuild and an ingest can never disagree.\n opsProjected += 1;\n if (applyOp(target, opFromRow(row)).changed) opsChangedRows += 1;\n }\n\n // sync_fingerprints is NOT copied: it is a cache that vouches for\n // the old DB's last reads, and without it the next ingest of\n // each peer simply reads its segment in full once.\n for (const peer of peerRows) {\n insertPeer.run({\n machineId: peer.machine_id,\n lastAppliedSeq: peer.last_applied_seq,\n lastSeenAt: peer.last_seen_at,\n });\n }\n });\n });\n replay.immediate();\n\n const rebuiltRows: Record<string, number> = {};\n for (const table of [\"workstreams\", \"tasks\", \"task_edges\", \"task_notes\", \"ops\"]) {\n const row = target.prepare(`SELECT COUNT(*) AS n FROM ${table}`).get() as { n: number };\n rebuiltRows[table] = row.n;\n }\n\n return {\n targetPath,\n opsCopied: rebuiltRows.ops ?? 0,\n opsProjected,\n opsChangedRows,\n logOnlyByEntity,\n rebuiltRows,\n machineLocalLost,\n machineId: identity.machine_id,\n };\n } finally {\n target.close();\n }\n}\n\n/** True iff both paths name the same file on disk. Guards the\n * rebuild-onto-itself case when the caller passes a different string\n * for the same file (a symlink, or ./x vs x). */\nfunction sameInode(a: string, b: string): boolean {\n try {\n const sa = statSync(a);\n const sb = statSync(b);\n return sa.ino === sb.ino && sa.dev === sb.dev;\n } catch {\n // A path we cannot stat is not the source by definition.\n return false;\n }\n}\n","// mu — drift detection: is the projection still faithful to the ops log?\n//\n// WHY THIS IS LOAD-BEARING, NOT DIAGNOSTICS GARNISH\n// ------------------------------------------------\n// mu collapsed four independent change-recording mechanisms into ONE\n// ops log. The upside is coherence. The cost, stated plainly in\n// docs/VISION.md § 2b, is that a capture bug is no longer \"sync is\n// broken\" — it is undo AND sync AND history broken,\n// simultaneously and silently, because all four are projections of the\n// same table.\n//\n// This module is what converts that from a hazard into a DETECTABLE\n// CONDITION. It is the reason the consolidation was defensible at all,\n// so it is production code: it must name what diverged precisely enough\n// to act on at 3am, and it must not cry wolf on shapes that are\n// legitimately asymmetric.\n//\n// HOW IT WORKS\n// ------------\n// Rebuild the log into a throwaway DB (src/rebuild.ts, whose target path\n// is a parameter precisely so this can point it at a temp file), then\n// diff the rebuilt tables against the live ones. The log is canonical by\n// definition, so any divergence means either capture missed a mutation\n// or apply is lossy. Both are bugs; neither is recoverable by guessing.\n//\n// TWO TIERS, AND WHY\n// ------------------\n// Measured on this machine (better-sqlite3 3.49, NVMe):\n//\n// tasks ops rebuild\n// 100 353 258ms\n// 500 1742 1146ms\n// 1000 3461 2178ms\n//\n// Linear in ops, ~0.6ms per op. `mu doctor` is expected to be fast and\n// is run reflexively, so a 2s+ hit on a realistic DB is not acceptable\n// as a default. Hence:\n//\n// DEFAULT (`mu doctor`) — `checkCheapDriftInvariant`, ~1ms: every\n// live row must have at least one op naming\n// its key. Catches an uncaptured INSERT or a\n// row that exists with no history at all,\n// which is the most common shape of a\n// capture bug (a new mutation path that\n// bypassed the triggers).\n// DEEP (`mu doctor --deep`) — full rebuild + field-level diff. Catches\n// everything, including an uncaptured UPDATE,\n// which the cheap check is structurally blind\n// to because the key still has ops.\n//\n// That blindness is real and measured, not assumed: an uncaptured UPDATE\n// leaves the cheap invariant reporting zero orphans. So the cheap check\n// is a smoke alarm, not a proof, and the default run says so by pointing\n// at --deep.\n\nimport { mkdtempSync, rmSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { type Db, openDb } from \"./db.js\";\nimport type { HasNextSteps, NextStep } from \"./output.js\";\nimport { rebuildInto } from \"./rebuild.js\";\n\n/** One field-level divergence between the live tables and the rebuild. */\nexport interface DriftRecord {\n /** Portable table the divergence is in. */\n table: string;\n /** NATURAL key of the row (never a surrogate id), so the report is\n * meaningful to an operator and stable across machines. */\n key: string;\n /** Field that differs, or a marker for whole-row presence:\n * '<row>' means the row exists on one side only. */\n field: string;\n /** Value in the LIVE tables — what mu is currently showing. */\n live: string | null;\n /** Value the ops log says it should be. The log is canonical. */\n expected: string | null;\n /** Which side is missing the row entirely, when field is '<row>'. */\n presence?: \"missing-in-live\" | \"missing-in-rebuild\";\n}\n\nexport interface DriftReport {\n /** True iff the projection matches the log exactly. */\n clean: boolean;\n /** Every divergence found, capped (see DRIFT_REPORT_CAP). */\n records: readonly DriftRecord[];\n /** Total divergences found, which may exceed records.length. */\n totalDrift: number;\n /** Rows compared, per table. Context for \"clean\" — a clean report on\n * an empty DB proves less than one on 900 rows. */\n rowsCompared: Record<string, number>;\n /** Wall-clock cost, so `mu doctor --deep` can be honest about it. */\n elapsedMs: number;\n}\n\n/** Cap on reported records. A systematic capture bug can diverge every\n * row; printing 900 lines buries the signal. The count is always exact\n * (`totalDrift`) even when the list is truncated. */\nexport const DRIFT_REPORT_CAP = 20;\n\n/** Result of the cheap invariant that runs in the DEFAULT doctor. */\nexport interface CheapDriftReport {\n clean: boolean;\n /** Live rows with NO op naming their key — i.e. rows whose existence\n * the log cannot explain. */\n unexplainedRows: readonly { table: string; key: string }[];\n totalUnexplained: number;\n elapsedMs: number;\n}\n\n// ─── the cheap invariant (default doctor) ─────────────────────────────\n\n/**\n * Every live row must have at least one op naming its natural key.\n *\n * Four indexed NOT EXISTS scans, no rebuild, no temp file: ~10 ms on a\n * 2.3k-task, 10.7k-note, 67k-op DB. Cheap enough to run on every `mu\n * doctor` and the TUI slow tick.\n *\n * WHAT IT CATCHES: a row that exists with no history — an uncaptured\n * INSERT, or a mutation path that bypassed the triggers entirely.\n *\n * WHAT IT CANNOT CATCH, by construction: an uncaptured UPDATE. The key\n * still has ops from the original insert, so the invariant holds while\n * the field value has silently diverged. Verified empirically. Only the\n * full rebuild-diff finds that, which is exactly why `--deep` exists and\n * why the default run points at it rather than claiming to be a proof.\n */\nexport function checkCheapDriftInvariant(db: Db): CheapDriftReport {\n const started = Date.now();\n const unexplained: { table: string; key: string }[] = [];\n\n // One query per portable table, each resolving the row to its natural\n // key so the report is actionable.\n const probes: Array<{ table: string; sql: string }> = [\n {\n table: \"workstreams\",\n sql: `SELECT w.name AS key FROM workstreams w\n WHERE NOT EXISTS (\n SELECT 1 FROM ops o WHERE o.entity = 'workstream' AND o.key = w.name)`,\n },\n {\n table: \"tasks\",\n sql: `SELECT w.name || '/' || t.local_id AS key\n FROM tasks t JOIN workstreams w ON w.id = t.workstream_id\n WHERE NOT EXISTS (\n SELECT 1 FROM ops o\n WHERE o.entity = 'task' AND o.key = w.name || '/' || t.local_id)`,\n },\n {\n table: \"task_edges\",\n sql: `SELECT wf.name || '/' || f.local_id || '->' || wt.name || '/' || t.local_id AS key\n FROM task_edges e\n JOIN tasks f ON f.id = e.from_task_id\n JOIN tasks t ON t.id = e.to_task_id\n JOIN workstreams wf ON wf.id = f.workstream_id\n JOIN workstreams wt ON wt.id = t.workstream_id\n WHERE NOT EXISTS (\n SELECT 1 FROM ops o\n WHERE o.entity = 'edge'\n AND o.key = wf.name || '/' || f.local_id || '->' || wt.name || '/' || t.local_id)`,\n },\n {\n // Notes are keyed <task-key>#<origin-id> and the origin id is the\n // AUTHORING machine's surrogate id, which need not match ours (see\n // src/apply.ts § applyNotePut). So match on the task-key PREFIX\n // rather than the exact key: the question here is \"does the log\n // know about a note on this task at all\", not \"which note\".\n //\n // Express the prefix as an indexed half-open range. A correlated\n // `LIKE task_key || '#%'` made SQLite scan every note op for every\n // live note (seconds on the dogfood DB); '#'..'$' contains exactly\n // the strings beginning with `task_key || '#'` because task ids\n // cannot contain either delimiter.\n //\n // The answer is per TASK, so probe each task that has notes once\n // (2.3k probes, not 10.7k on the dogfood DB), then list the notes\n // of the tasks that fail. MATERIALIZED stops SQLite flattening the\n // probe back into a per-note subquery.\n table: \"task_notes\",\n sql: `WITH bare AS MATERIALIZED (\n SELECT t.id AS task_id, w.name || '/' || t.local_id AS task_key\n FROM tasks t\n JOIN workstreams w ON w.id = t.workstream_id\n WHERE t.id IN (SELECT task_id FROM task_notes)\n AND NOT EXISTS (\n SELECT 1 FROM ops o\n WHERE o.entity = 'note'\n AND o.key >= w.name || '/' || t.local_id || '#'\n AND o.key < w.name || '/' || t.local_id || '$'))\n SELECT b.task_key || '#' || n.id AS key\n FROM bare b\n JOIN task_notes n ON n.task_id = b.task_id\n ORDER BY n.task_id, n.id`,\n },\n ];\n\n for (const probe of probes) {\n const rows = db.prepare(probe.sql).all() as { key: string }[];\n for (const row of rows) unexplained.push({ table: probe.table, key: row.key });\n }\n\n return {\n clean: unexplained.length === 0,\n unexplainedRows: unexplained.slice(0, DRIFT_REPORT_CAP),\n totalUnexplained: unexplained.length,\n elapsedMs: Date.now() - started,\n };\n}\n\n// ─── the deep check (rebuild + diff) ──────────────────────────────────\n\n/** Columns compared per table, keyed by natural key.\n *\n * DELIBERATE OMISSIONS, each of which would otherwise be a false\n * positive:\n *\n * surrogate ids (`tasks.id`, `task_notes.id`) — assigned by\n * AUTOINCREMENT in replay order, which need not\n * match the original insert order. The natural key\n * is the identity; the rowid is an implementation\n * detail.\n * owner_id — an FK into machine-local `agents`, so it is\n * captured but never APPLIED (src/apply.ts strips\n * it: a peer's value would violate the FK). A\n * rebuild therefore legitimately has NULL owners\n * while the live DB has claims. Comparing it would\n * make every claimed task report drift.\n * created_at on\n * task_notes/edges — kept, since capture records it and apply\n * replays it verbatim.\n */\nconst COMPARED: Record<string, readonly string[]> = {\n workstreams: [\"created_at\"],\n tasks: [\"title\", \"status\", \"substate\", \"impact\", \"effort_days\", \"created_at\", \"updated_at\"],\n task_notes: [\"author\", \"content\", \"created_at\"],\n task_edges: [\"created_at\"],\n};\n\n/** SELECTs that project each portable table to (key, ...COMPARED) so\n * both sides can be compared by natural key. */\nconst SNAPSHOT_SQL: Record<string, string> = {\n workstreams: `SELECT w.name AS key, w.created_at\n FROM workstreams w`,\n tasks: `SELECT w.name || '/' || t.local_id AS key,\n t.title, t.status, t.substate, t.impact, t.effort_days, t.created_at, t.updated_at\n FROM tasks t JOIN workstreams w ON w.id = t.workstream_id`,\n // Notes are a GROW-ONLY SET whose local surrogate id is not portable,\n // so identity for diffing is (task, author, content, created_at) —\n // exactly the identity applyNotePut uses for its insert-if-absent check. Using the\n // '#<id>' key here would report drift on every note that replayed to a\n // different rowid, which is normal and not drift.\n //\n // char(31) (ASCII Unit Separator) joins the parts: it cannot occur in a\n // workstream/task id and is vanishingly unlikely in note prose, so two\n // distinct notes cannot collide into one composite key. A literal NUL\n // would be the textbook choice but SQLite truncates TEXT at NUL.\n task_notes: `SELECT w.name || '/' || t.local_id || char(31) ||\n COALESCE(n.author, '') || char(31) || n.content || char(31) ||\n n.created_at AS key,\n n.author, n.content, n.created_at\n FROM task_notes n\n JOIN tasks t ON t.id = n.task_id\n JOIN workstreams w ON w.id = t.workstream_id`,\n task_edges: `SELECT wf.name || '/' || f.local_id || '->' || wt.name || '/' || t.local_id AS key,\n e.created_at\n FROM task_edges e\n JOIN tasks f ON f.id = e.from_task_id\n JOIN tasks t ON t.id = e.to_task_id\n JOIN workstreams wf ON wf.id = f.workstream_id\n JOIN workstreams wt ON wt.id = t.workstream_id`,\n};\n\ntype Row = Record<string, string | number | null>;\n\nfunction snapshot(db: Db, table: string): Map<string, Row> {\n const sql = SNAPSHOT_SQL[table];\n if (sql === undefined) throw new Error(`no drift snapshot defined for table ${table}`);\n const out = new Map<string, Row>();\n for (const row of db.prepare(sql).all() as Row[]) {\n const key = row.key;\n if (typeof key !== \"string\") continue;\n out.set(key, row);\n }\n return out;\n}\n\n/** Render a value for the report. Distinguishes SQL NULL from the string\n * \"null\", which matters when the drift IS a set-to-NULL. */\nfunction show(v: string | number | null | undefined): string | null {\n if (v === null || v === undefined) return null;\n return String(v);\n}\n\n/**\n * Rebuild the log into a temp DB and diff it against the live tables.\n *\n * Any divergence is a bug in capture (a mutation that left no op) or in\n * apply (an op that does not reproduce its mutation). The log is\n * canonical, so `expected` is always the rebuilt value.\n *\n * SYNCHRONOUS, matching rebuildInto / applyOp: the op context is a\n * per-connection temp table, so interleaved async scopes would clobber\n * each other's capture-suppression flag.\n *\n * Cleans up its temp directory even on throw — a doctor run that leaked\n * a DB copy per invocation into /tmp would be its own bug.\n */\nexport function checkDrift(db: Db): DriftReport {\n const started = Date.now();\n const dir = mkdtempSync(join(tmpdir(), \"mu-drift-\"));\n const target = join(dir, \"rebuilt.db\");\n\n try {\n rebuildInto(db, { targetPath: target });\n const rebuilt = openDb({ path: target });\n try {\n const records: DriftRecord[] = [];\n const rowsCompared: Record<string, number> = {};\n let total = 0;\n\n const push = (record: DriftRecord): void => {\n total += 1;\n if (records.length < DRIFT_REPORT_CAP) records.push(record);\n };\n\n for (const table of Object.keys(SNAPSHOT_SQL)) {\n const live = snapshot(db, table);\n const expected = snapshot(rebuilt, table);\n rowsCompared[table] = live.size;\n\n for (const [key, liveRow] of live) {\n const expectedRow = expected.get(key);\n if (expectedRow === undefined) {\n // Live has a row the log cannot account for: capture missed\n // its creation, or a tombstone that should not have applied.\n push({\n table,\n key,\n field: \"<row>\",\n live: \"present\",\n expected: null,\n presence: \"missing-in-rebuild\",\n });\n continue;\n }\n for (const field of COMPARED[table] ?? []) {\n const a = liveRow[field];\n const b = expectedRow[field];\n // Compare rendered values so 1 and 1.0 (INTEGER vs REAL\n // affinity across a replay) do not read as drift.\n if (show(a) !== show(b)) {\n push({ table, key, field, live: show(a), expected: show(b) });\n }\n }\n }\n\n for (const key of expected.keys()) {\n if (live.has(key)) continue;\n // The log says this row should exist but it is gone from live:\n // a delete that left no tombstone.\n push({\n table,\n key,\n field: \"<row>\",\n live: null,\n expected: \"present\",\n presence: \"missing-in-live\",\n });\n }\n }\n\n return {\n clean: total === 0,\n records,\n totalDrift: total,\n rowsCompared,\n elapsedMs: Date.now() - started,\n };\n } finally {\n rebuilt.close();\n }\n } finally {\n rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 25 });\n }\n}\n\n/** One-line-per-record rendering shared by the CLI and the TUI popup, so\n * the wording of a drift report lives in exactly one place. */\nexport function formatDriftRecord(record: DriftRecord): string {\n if (record.field === \"<row>\") {\n return record.presence === \"missing-in-live\"\n ? `${record.table} ${record.key}: row MISSING from live tables (the log says it exists)`\n : `${record.table} ${record.key}: row present in live tables but the log cannot explain it`;\n }\n const live = record.live === null ? \"NULL\" : record.live;\n const expected = record.expected === null ? \"NULL\" : record.expected;\n return `${record.table} ${record.key}.${record.field}: live=${live} log=${expected}`;\n}\n\n/** What an operator should DO about drift. Detection without remediation\n * is just an alarm; this is the part that matters at 3am.\n *\n * Deliberately does NOT tell them to swap the rebuild in blindly. Drift\n * means one of the two sides is wrong and we cannot know which from\n * here: if capture missed a mutation, the LIVE tables hold the truth and\n * the log is incomplete, so rebuilding would DISCARD real work. If apply\n * is lossy, the log is right. So the guidance is: capture the evidence,\n * then choose deliberately. */\nexport function driftRemediation(): readonly string[] {\n return [\n \"Drift means the ops log and the live tables disagree. One of them is wrong.\",\n \"\",\n \" * If CAPTURE missed a mutation, the LIVE tables hold work the log never\",\n \" recorded. Rebuilding would DISCARD it. Do not rebuild reflexively.\",\n \" * If APPLY is lossy, the log is authoritative and a rebuild is the fix.\",\n \"\",\n \"Do this, in order:\",\n \" 1. Back up first, before anything else: mu db backup /tmp/mu-drift-evidence.db\",\n \" 2. Materialize what the log believes: mu rebuild /tmp/mu-rebuilt.db\",\n \" 3. Compare the two by hand for the keys named above, and decide which\",\n \" side is correct. `mu sql` against both files is the fastest way.\",\n \" 4. Report it: drift is a capture/apply BUG, not operator error. The\",\n \" named table/key/field above is the reproduction.\",\n ];\n}\n\n// ─── the typed error ──────────────────────────────────────────────────\n\n/**\n * Thrown by `mu doctor` when drift is found, so the verb exits non-zero\n * and a CI job or a wrapper script notices.\n *\n * Drift is not operator error and not a transient condition: it means the\n * ops log and the tables disagree, which is a capture or apply BUG. An\n * exit code is how that reaches automation; the printed report is how it\n * reaches a human.\n */\nexport class DriftDetectedError extends Error implements HasNextSteps {\n constructor(\n readonly totalDrift: number,\n readonly records: readonly DriftRecord[],\n ) {\n super(\n `ops-log drift: ${totalDrift} divergence${totalDrift === 1 ? \"\" : \"s\"} between the live tables and the ops log`,\n );\n this.name = \"DriftDetectedError\";\n }\n\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Back up the current state FIRST\",\n command: \"mu db backup /tmp/mu-drift-evidence.db\",\n },\n { intent: \"Materialize what the log believes\", command: \"mu rebuild /tmp/mu-rebuilt.db\" },\n {\n intent: \"Compare the named keys by hand before choosing a side\",\n command: 'mu sql \"SELECT local_id, title, status, impact FROM tasks\"',\n },\n ];\n }\n}\n","// mu — mixed-fleet hazard detection.\n//\n// Three environment conditions that silently corrupt or diverge state on\n// a multi-machine fleet. All three are cheap, pure-ish checks that run in\n// the DEFAULT `mu doctor`, because unlike drift they cost microseconds\n// and unlike drift they are PREVENTABLE — the operator can fix each one\n// before it costs them data.\n//\n// (a) DB inside the sync dir -> corruption. THE footgun of the design.\n// (b) DB on a network mount -> broken WAL locking.\n// (c) case-colliding names -> collide on macOS, coexist on Linux.\n//\n// The checks that need MU_SYNC_DIR read it if set and no-op otherwise,\n// so a single-machine install pays nothing.\n\nimport { existsSync, statfsSync } from \"node:fs\";\nimport { resolve, sep } from \"node:path\";\nimport type { Db } from \"./db.js\";\n\nexport type HazardSeverity = \"ok\" | \"warn\" | \"fail\";\n\nexport interface FleetHazard {\n /** Stable token, used as the doctor row label. */\n name: string;\n severity: HazardSeverity;\n /** One-line summary for the row. */\n detail: string;\n /** Multi-line explanation + remediation, shown when non-ok. */\n remediation?: readonly string[];\n}\n\n/**\n * `mu doctor` found at least one `fail`-severity row. Thrown after the\n * whole report is printed (or the --json payload emitted) so scripts and\n * CI see a non-zero exit; maps to exit 5 like drift, because a `fail`\n * row means the substrate is unsafe, not that a hint is pending.\n */\nexport class HazardFailError extends Error {\n override readonly name = \"HazardFailError\";\n constructor(readonly failedRows: readonly string[]) {\n super(\n `doctor: ${failedRows.length} row${failedRows.length === 1 ? \"\" : \"s\"} failed (${failedRows.join(\", \")}); see the remediation above`,\n );\n }\n}\n\n// ─── (a) DB inside the sync dir ───────────────────────────────────────\n\n/**\n * True iff `child` is inside `parent` (or is `parent`).\n *\n * Path-based, deliberately: the check must fire even when the DB file\n * does not exist yet, so it cannot rely on stat/inode identity. Both\n * sides are resolved to absolute form first, and a separator is appended\n * so `/sync-data` does not read as the parent of `/sync-database`.\n */\nexport function isPathInside(child: string, parent: string): boolean {\n const c = resolve(child);\n const p = resolve(parent);\n if (c === p) return true;\n return c.startsWith(p.endsWith(sep) ? p : p + sep);\n}\n\n/**\n * THE footgun of the whole sync design, and the reason it is `fail` rather\n * than `warn`.\n *\n * Sync tools (Syncthing, Dropbox, iCloud, rsync loops) copy files\n * whole-file and out of order. A live SQLite DB in WAL mode is THREE\n * files — `mu.db`, `mu.db-wal`, `mu.db-shm` — whose mutual consistency is\n * the entire basis of durability. A sync daemon that copies the main file\n * while the WAL is mid-checkpoint, or that resurrects a stale `-wal` from\n * another machine, produces a DB that opens fine and is silently corrupt.\n * Two machines writing the same synced file is worse still: last-writer\n * wins on the FILE, so an entire machine's history vanishes.\n *\n * mu's sync design specifically avoids this by shipping append-only\n * per-machine SEGMENTS (one writer per file, never contended) rather than\n * the DB itself. Putting the DB inside the sync dir defeats that on\n * purpose-built-to-be-safe transport, so it is a hard failure.\n */\nexport function checkDbInsideSyncDir(dbPath: string, syncDir: string | undefined): FleetHazard {\n if (syncDir === undefined || syncDir.trim() === \"\") {\n return {\n name: \"db-vs-sync\",\n severity: \"ok\",\n detail: \"MU_SYNC_DIR not set (no sync configured)\",\n };\n }\n if (!isPathInside(dbPath, syncDir)) {\n return { name: \"db-vs-sync\", severity: \"ok\", detail: \"DB is outside the sync dir\" };\n }\n return {\n name: \"db-vs-sync\",\n severity: \"fail\",\n detail: `DB is INSIDE MU_SYNC_DIR — this WILL corrupt it (${dbPath})`,\n remediation: [\n \"The mu database must never live inside the synced folder.\",\n \"\",\n \"A live WAL-mode SQLite DB is three files (mu.db, -wal, -shm) whose mutual\",\n \"consistency is the basis of durability. File-sync tools copy whole files,\",\n \"out of order, and across machines: a stale -wal resurrected from a peer, or\",\n \"a main file copied mid-checkpoint, yields a DB that OPENS FINE and is\",\n \"silently corrupt. Two machines writing the same synced file is worse — last\",\n \"writer wins on the whole FILE, so one machine's entire history disappears.\",\n \"\",\n \"mu syncs append-only per-machine SEGMENTS precisely to avoid this: one\",\n \"writer per file, never contended, so any file-mover is adequate transport.\",\n \"\",\n \"Fix: move the DB out of the sync dir, e.g.\",\n \" export MU_DB_PATH=$HOME/.local/state/mu/mu.db\",\n \"and keep MU_SYNC_DIR pointing at the shared folder for segments only.\",\n ],\n };\n}\n\n// ─── (b) DB on a network mount ────────────────────────────────────────\n\n/** Linux `statfs.f_type` magic numbers for filesystems where POSIX\n * advisory locking is unreliable or absent. SQLite's WAL mode needs\n * working locks AND shared memory; neither is dependable here.\n *\n * Values from linux/magic.h. Kept as a table rather than inline so the\n * list is auditable and extendable. */\nconst NETWORK_FS_MAGIC = new Map<number, string>([\n // Every value here is transcribed from linux/magic.h, not recalled.\n // An invented magic is worse than a missing one: it would either never\n // match (silent no-op) or match the wrong filesystem and warn falsely.\n [0x6969, \"NFS\"], // NFS_SUPER_MAGIC\n [0xff534d42, \"CIFS/SMB\"], // CIFS_SUPER_MAGIC\n [0xfe534d42, \"SMB2\"], // SMB2_SUPER_MAGIC\n [0x517b, \"SMBFS\"], // SMB_SUPER_MAGIC\n [0x65735546, \"FUSE (may be sshfs/rclone/cloud drive)\"], // FUSE_SUPER_MAGIC\n [0x00c36400, \"Ceph\"], // CEPH_SUPER_MAGIC\n]);\n\n/** Result of a filesystem probe. `unknown` is a first-class outcome:\n * telling the operator \"cannot determine\" is honest, whereas claiming\n * \"ok\" on a platform we cannot inspect would be a false assurance. */\nexport interface FsProbe {\n kind: \"local\" | \"network\" | \"unknown\";\n /** Human label for the detected fs, when known. */\n label: string;\n}\n\n/**\n * Classify the filesystem a path lives on.\n *\n * PORTABILITY, and why this degrades rather than guesses:\n *\n * Linux — `statfsSync().type` is a documented magic number, so the\n * classification is exact.\n * macOS — `f_type` is a small driver INDEX, not a stable magic, so\n * the same number means different things across releases.\n * Comparing it would produce confident nonsense, so we do\n * not; macOS falls through to `unknown`.\n * Other — `unknown`.\n *\n * Exported separately from the check so it can be unit-tested against\n * SYNTHETIC input: mounting NFS in a test suite is not feasible, so the\n * tests exercise `classifyFsType` (pure, takes the magic number) rather\n * than the syscall. Stated plainly because an untested detector is worse\n * than no detector.\n */\nexport function classifyFsType(magic: number, platform: string = process.platform): FsProbe {\n if (platform !== \"linux\") {\n // See above: f_type is not a portable magic off Linux.\n return { kind: \"unknown\", label: `unrecognised (${platform})` };\n }\n const network = NETWORK_FS_MAGIC.get(magic);\n if (network !== undefined) return { kind: \"network\", label: network };\n return { kind: \"local\", label: `local (0x${magic.toString(16)})` };\n}\n\n/** Probe the real filesystem for a path, falling back to `unknown` when\n * the syscall is unavailable or the path does not exist yet. */\nexport function probeFilesystem(path: string): FsProbe {\n try {\n // Probe the nearest existing ancestor: the DB file may not exist on a\n // first run, but its directory tells us the same thing.\n let probeTarget = resolve(path);\n while (!existsSync(probeTarget)) {\n const parent = resolve(probeTarget, \"..\");\n if (parent === probeTarget) break;\n probeTarget = parent;\n }\n const stats = statfsSync(probeTarget);\n return classifyFsType(Number(stats.type));\n } catch {\n return { kind: \"unknown\", label: \"probe failed\" };\n }\n}\n\n/**\n * WARN rather than fail on a network mount.\n *\n * Warn, not fail, because it is not always fatal: a single machine using\n * an NFS home with no concurrent access often works, and refusing\n * outright would lock such an operator out of their own tool. But it IS\n * the second-most-common corruption cause after (a), because WAL needs\n * both advisory locking and a shared-memory file, and NFS/SMB/sshfs\n * deliver neither reliably. Symptoms are 'database is locked' under no\n * contention, or silent corruption under real contention.\n */\nexport function checkNetworkMount(\n dbPath: string,\n probe: FsProbe = probeFilesystem(dbPath),\n): FleetHazard {\n if (probe.kind === \"network\") {\n return {\n name: \"db-filesystem\",\n severity: \"warn\",\n detail: `DB is on a network mount (${probe.label}) — WAL locking is unreliable there`,\n remediation: [\n `The DB appears to live on ${probe.label}.`,\n \"\",\n \"SQLite's WAL mode needs working POSIX advisory locks AND a shared-memory\",\n \"file. NFS, SMB/CIFS and FUSE mounts (sshfs, rclone, cloud drives) provide\",\n \"neither dependably. Expect 'database is locked' with no contention, or\",\n \"silent corruption with real contention from parallel mu invocations.\",\n \"\",\n \"Fix: keep the DB on local disk and sync SEGMENTS instead —\",\n \" export MU_DB_PATH=$HOME/.local/state/mu/mu.db\",\n \"That is what the segment design is for: append-only, single-writer files\",\n \"that any file-mover can carry safely.\",\n ],\n };\n }\n if (probe.kind === \"unknown\") {\n return {\n name: \"db-filesystem\",\n severity: \"ok\",\n detail: `filesystem not classifiable on this platform (${probe.label}); assuming local`,\n };\n }\n return { name: \"db-filesystem\", severity: \"ok\", detail: `DB is on ${probe.label}` };\n}\n\n// ─── (c) case-colliding workstream names ──────────────────────────────\n\nexport interface CaseCollision {\n /** The names, as stored, that fold to the same lowercase form. */\n names: readonly string[];\n /** The shared case-folded form. */\n folded: string;\n}\n\n/**\n * Workstream names differing only by case.\n *\n * On ext4 these coexist happily. On APFS (macOS default,\n * case-INSENSITIVE though case-preserving) and on NTFS they collide, so\n * the same fleet reaches different states depending on which machine\n * applies an op first. Concretely: `workstreams.name` is UNIQUE and IS\n * the tmux session name, so on a Mac 'Foo' and 'foo' are one session and\n * one directory but two DB rows — and every workspace path derived from\n * the name aliases onto one directory.\n *\n * Detected in the DB rather than at write time on purpose: the rows may\n * have been created on Linux and only become a hazard when the fleet\n * gains a Mac, so this must be a standing check rather than a validation.\n *\n * SQL-side `LOWER()` is ASCII-only in SQLite, which is the right\n * comparison here: workstream names are already constrained to\n * `[a-z0-9_-]` by `isValidWorkstreamName`, so any collision within the\n * legal charset is ASCII. Names that predate the rule (or were inserted\n * via `mu sql`) still get caught because we fold in JS too.\n */\nexport function findCaseCollisions(db: Db): CaseCollision[] {\n const rows = db.prepare(\"SELECT name FROM workstreams ORDER BY name\").all() as {\n name: string;\n }[];\n const byFolded = new Map<string, string[]>();\n for (const row of rows) {\n // toLocaleLowerCase would be locale-dependent (Turkish dotless i);\n // toLowerCase is stable, which is what a cross-machine check needs.\n const folded = row.name.toLowerCase();\n const bucket = byFolded.get(folded);\n if (bucket === undefined) byFolded.set(folded, [row.name]);\n else bucket.push(row.name);\n }\n const collisions: CaseCollision[] = [];\n for (const [folded, names] of byFolded) {\n if (names.length > 1) collisions.push({ folded, names });\n }\n return collisions;\n}\n\nexport function checkCaseCollisions(db: Db): FleetHazard {\n const collisions = findCaseCollisions(db);\n if (collisions.length === 0) {\n return {\n name: \"name-case\",\n severity: \"ok\",\n detail: \"no case-colliding workstream names\",\n };\n }\n const shown = collisions\n .slice(0, 5)\n .map((c) => c.names.join(\" / \"))\n .join(\", \");\n return {\n name: \"name-case\",\n severity: \"warn\",\n detail: `${collisions.length} case-colliding workstream name(s): ${shown}`,\n remediation: [\n \"These workstream names differ only by letter case:\",\n ...collisions.map((c) => ` ${c.names.join(\" / \")}`),\n \"\",\n \"They coexist on Linux (ext4 is case-sensitive) but COLLIDE on macOS (APFS\",\n \"is case-insensitive) and on Windows (NTFS). Because a workstream name IS a\",\n \"tmux session name and seeds every workspace path, a Mac in the fleet sees\",\n \"one session and one directory where Linux sees two — so the fleet reaches\",\n \"different states depending on which machine applies an op first.\",\n \"\",\n \"Fix: rename one side to a distinct name before adding a Mac to the fleet.\",\n \"There is no in-place rename verb; back the DB up, re-init under the new\",\n \"name, and tear down the old one:\",\n \" mu db backup <file>\",\n \" mu workstream init <new-name>\",\n \" mu workstream teardown <old-name> --yes\",\n ],\n };\n}\n\n// ─── the aggregate ────────────────────────────────────────────────────\n\n/**\n * Run all three mixed-fleet checks. Cheap enough for the default doctor:\n * two path/string comparisons, one statfs, one indexed table scan.\n */\nexport function checkFleetHazards(\n db: Db,\n opts: { dbPath: string; syncDir?: string | undefined } = { dbPath: \"\" },\n): FleetHazard[] {\n const syncDir = opts.syncDir !== undefined ? opts.syncDir : process.env.MU_SYNC_DIR;\n return [\n checkDbInsideSyncDir(opts.dbPath, syncDir),\n checkNetworkMount(opts.dbPath),\n checkCaseCollisions(db),\n ];\n}\n","// mu — `mu link pi`: install the mu pi extension and the mu skill.\n//\n// Modelled on murmur's `link pi` (~/hacking/crew/murmur/src/cli/link.ts):\n// the extension is installed as a re-export SHIM, not a copy, so\n// upgrading mu upgrades the extension with no relink. The skill is a\n// SYMLINK to the package's `skills/mu`, for the same reason.\n//\n// Destinations live under `MU_PI_HOME ?? homedir()`; tests point\n// MU_PI_HOME (or the `home` option) at a temp dir. Never writes into\n// pi-meta's PI_CODING_AGENT_DIR instance dirs: pi-meta copies/links from\n// ~/.pi/agent and ~/.agents at launch.\n\nimport {\n existsSync,\n lstatSync,\n mkdirSync,\n readFileSync,\n readlinkSync,\n realpathSync,\n rmSync,\n symlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport type { HasNextSteps, NextStep } from \"./output.js\";\n\n/**\n * Identifies a generated shim on its own line, so re-linking (and\n * `inspectLinks`) can tell it from an older inlined copy without\n * depending on the import statement's exact shape.\n */\nexport const MU_SHIM_MARKER = \"// mu:shim\";\n\nexport type LinkState = \"ok\" | \"missing\" | \"stale-copy\" | \"foreign\" | \"dangling\";\n\nexport interface LinkStatus {\n path: string;\n state: LinkState;\n target?: string;\n}\n\nexport interface LinkOptions {\n /** Root under which `.pi/` and `.agents/` live. Default `MU_PI_HOME ?? homedir()`. */\n home?: string;\n}\n\n/** Raised when the destination holds something mu did not put there\n * (a real directory, or a symlink to another checkout without\n * `--force`). mu never deletes user files to make room. */\nexport class LinkConflictError extends Error implements HasNextSteps {\n constructor(\n readonly path: string,\n readonly reason: \"not-a-symlink\" | \"foreign-symlink\",\n readonly current?: string,\n ) {\n super(\n reason === \"not-a-symlink\"\n ? `${path} exists and is not a symlink; refusing to replace it`\n : `${path} already links to ${current ?? \"?\"}; pass --force to replace it`,\n );\n this.name = \"LinkConflictError\";\n }\n\n errorNextSteps(): NextStep[] {\n if (this.reason === \"foreign-symlink\") {\n return [{ intent: \"Replace the existing link\", command: \"mu link pi --force\" }];\n }\n return [\n { intent: \"Inspect what is there\", command: `ls -la ${this.path}` },\n { intent: \"Move it aside, then relink\", command: `mv ${this.path} ${this.path}.bak` },\n ];\n }\n}\n\nfunction resolveHome(opts?: LinkOptions): string {\n return opts?.home ?? process.env.MU_PI_HOME ?? homedir();\n}\n\n/** Package root. src/link.ts and the bundled dist/*.js both sit exactly\n * one directory below it. */\nfunction packageRoot(): string {\n return resolve(dirname(fileURLToPath(import.meta.url)), \"..\");\n}\n\n/** The built extension the shim imports. `MU_EXTENSION_ENTRY` overrides\n * it (tests point it at a fixture so they need no prior build). */\nexport function extensionEntry(): string {\n return process.env.MU_EXTENSION_ENTRY ?? join(packageRoot(), \"dist\", \"extension\", \"mu-pi.js\");\n}\n\n/** The skill directory the symlink points at. */\nexport function skillSource(): string {\n return join(packageRoot(), \"skills\", \"mu\");\n}\n\nexport function extensionPath(opts?: LinkOptions): string {\n return join(resolveHome(opts), \".pi\", \"agent\", \"extensions\", \"mu.ts\");\n}\n\nexport function skillPath(opts?: LinkOptions): string {\n return join(resolveHome(opts), \".agents\", \"skills\", \"mu\");\n}\n\n/**\n * The installed extension as a re-export of this installation. One\n * statement on purpose: any logic here is logic that cannot be upgraded.\n * A dynamic import, not `export ... from`, matching murmur's shim (ESM\n * hoisting bit it once).\n */\nfunction shim(entry: string): string {\n return `${MU_SHIM_MARKER}\n// Generated by \\`mu link pi\\`. Do not edit.\n//\n// A re-export, not a copy: the extension code lives in the mu install, so\n// upgrading mu upgrades the extension. Re-run \\`mu link pi\\` only if the\n// install path itself moves.\nconst { default: extension } = await import(${JSON.stringify(pathToFileURL(entry).href)});\nexport default extension;\n`;\n}\n\n/** Install the extension shim (or, with `copy`, an inlined copy pinned\n * to this version). `replacedCopy` is true when an existing file without\n * the shim marker was overwritten. A symlink at the destination (e.g. to\n * a dev checkout) is never written through: a live one needs `force`,\n * which replaces the link itself, never its target. */\nexport function linkPi(opts?: LinkOptions & { copy?: boolean; force?: boolean }): {\n path: string;\n replacedCopy: boolean;\n} {\n const path = extensionPath(opts);\n const entry = extensionEntry();\n if (!existsSync(entry)) {\n throw new Error(`mu pi extension not built: ${entry} is missing (run npm run build)`);\n }\n if (lstatOrUndefined(path)?.isSymbolicLink() === true) {\n const current = resolve(dirname(path), readlinkSync(path));\n if (existsSync(current) && opts?.force !== true) {\n throw new LinkConflictError(path, \"foreign-symlink\", current);\n }\n rmSync(path);\n }\n let replacedCopy = false;\n try {\n replacedCopy = !readFileSync(path, \"utf8\").includes(MU_SHIM_MARKER);\n } catch {\n // No previous install.\n }\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, opts?.copy === true ? readFileSync(entry, \"utf8\") : shim(entry));\n return { path, replacedCopy };\n}\n\n/** Symlink `<home>/.agents/skills/mu` to the package's `skills/mu`.\n * `previous` is the old link target when one was replaced. */\nexport function linkSkill(opts?: LinkOptions & { force?: boolean }): {\n path: string;\n target: string;\n previous?: string;\n} {\n const path = skillPath(opts);\n const target = skillSource();\n let previous: string | undefined;\n const st = lstatOrUndefined(path);\n if (st) {\n if (!st.isSymbolicLink()) throw new LinkConflictError(path, \"not-a-symlink\");\n const current = resolve(dirname(path), readlinkSync(path));\n if (current === target) return { path, target };\n // A dangling link holds nothing worth protecting; anything live\n // (e.g. a dev checkout) is replaced only on request.\n if (existsSync(current) && opts?.force !== true) {\n throw new LinkConflictError(path, \"foreign-symlink\", current);\n }\n previous = current;\n rmSync(path);\n }\n mkdirSync(dirname(path), { recursive: true });\n symlinkSync(target, path, \"dir\");\n return previous === undefined ? { path, target } : { path, target, previous };\n}\n\nfunction lstatOrUndefined(path: string): ReturnType<typeof lstatSync> | undefined {\n try {\n return lstatSync(path);\n } catch {\n return undefined;\n }\n}\n\nfunction inspectExtension(path: string): LinkStatus {\n let content: string;\n try {\n content = readFileSync(path, \"utf8\");\n } catch {\n return { path, state: \"missing\" };\n }\n if (!content.includes(MU_SHIM_MARKER)) return { path, state: \"stale-copy\" };\n const m = /await import\\((\".*?\")\\)/.exec(content);\n const spec = m?.[1];\n if (!spec) return { path, state: \"dangling\" };\n const raw = JSON.parse(spec) as string;\n const target = raw.startsWith(\"file:\") ? fileURLToPath(raw) : raw;\n return { path, state: existsSync(target) ? \"ok\" : \"dangling\", target };\n}\n\nfunction inspectSkill(path: string): LinkStatus {\n const st = lstatOrUndefined(path);\n if (!st) return { path, state: \"missing\" };\n if (!st.isSymbolicLink()) return { path, state: \"foreign\" };\n let target: string;\n try {\n target = realpathSync(path);\n } catch {\n return { path, state: \"dangling\", target: resolve(dirname(path), readlinkSync(path)) };\n }\n let skillMd: string;\n try {\n skillMd = readFileSync(join(target, \"SKILL.md\"), \"utf8\");\n } catch {\n return { path, state: \"foreign\", target };\n }\n const front = /^---\\n([\\s\\S]*?)\\n---/.exec(skillMd)?.[1] ?? \"\";\n const isMu = /^name:\\s*[\"']?mu[\"']?\\s*$/m.test(front);\n return { path, state: isMu ? \"ok\" : \"foreign\", target };\n}\n\n/** Report the state of both installs without changing anything. */\nexport function inspectLinks(opts?: LinkOptions): { extension: LinkStatus; skill: LinkStatus } {\n return {\n extension: inspectExtension(extensionPath(opts)),\n skill: inspectSkill(skillPath(opts)),\n };\n}\n","// Doctor summary — a TUI-friendly slice of `mu doctor`'s checks.\n//\n// The full `mu doctor` verb (src/cli/doctor.ts) renders a textual card\n// with: tmux/env presence, DB schema integrity, schema_version,\n// journal_mode, foreign_keys, per-workstream agent/task/log counts,\n// and reconcile drift (would-be-pruned ghosts + orphan panes). The\n// TUI's slot-9 Doctor card needs the same SIGNAL but at poll-tick\n// cost: an array of checks the card can render row-by-row.\n//\n// Per feat_card_9_doctor (workstream `tui-impl`), promoted from the\n// last reserved slot in design_global_keymap.\n//\n// CHEAPNESS RULES (so this is safe to run on every snapshot tick):\n// - Synchronous DB pragmas + COUNT(*)-shape SELECTs only.\n// - Reads `view.report.prunedGhosts` and `view.orphans` straight\n// out of the WorkstreamSnapshot — `loadWorkstreamSnapshot`\n// already runs `listLiveAgents(...)` once per tick, which populates\n// `report.prunedGhosts`.\n// - Reads `workspaceOrphans` straight out of the snapshot too.\n// - NO subprocess shellouts. The `tmux -V` check from the textual\n// `mu doctor` is intentionally OMITTED here — the TUI is\n// already running inside a terminal so tmux's binary presence\n// is implicit, and adding a per-tick subprocess fork to a\n// polled dashboard is the wrong tradeoff. If a future task\n// wants tmux-presence on the dashboard, add it as a\n// once-per-session probe in <App> (mirrors probeClipboardBackend),\n// not as a per-tick check here.\n//\n// CHECK SHAPE (matches the textual doctor's per-row vocabulary):\n// { name, status: \"ok\" | \"warn\" | \"fail\", detail }\n//\n// The card filters to non-OK rows for its body; subtitle counts\n// warn+fail. When everything is OK the card renders a quiet\n// \"all healthy\" line so the operator's eye learns to read the\n// presence of rows as \"something needs attention.\"\n\nimport { accessSync, constants, existsSync, readFileSync, realpathSync } from \"node:fs\";\nimport { delimiter, dirname, join, parse } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { murmurAvailable, UNKNOWN_REASON } from \"./agent-state.js\";\nimport { type AgentRow, expectsCtl } from \"./agents.js\";\nimport { type CtlProbe, ctlProbe } from \"./ctl/client.js\";\nimport { ctlSocketPath } from \"./ctl/path.js\";\nimport { CTL_OPS } from \"./ctl/protocol.js\";\nimport { CURRENT_SCHEMA_VERSION, type Db, defaultDbPath, EXPECTED_TABLES } from \"./db.js\";\nimport { checkCheapDriftInvariant } from \"./drift.js\";\nimport { checkFleetHazards } from \"./fleet-hazards.js\";\nimport { inspectLinks, type LinkOptions } from \"./link.js\";\nimport type { WorkstreamSnapshot } from \"./state.js\";\n\nexport type DoctorStatus = \"ok\" | \"warn\" | \"fail\";\n\nexport interface DoctorCheck {\n /** Short, stable identifier — used as the row label. Lowercase\n * one-word tokens so the column-aligned card layout looks tidy. */\n name: string;\n status: DoctorStatus;\n /** Free-form prose for the row's right-hand column. Kept short so\n * the card's CLIP column doesn't truncate it on common widths. */\n detail: string;\n}\n\nexport interface DoctorSummary {\n /** Every check that ran, in stable display order. The card filters\n * to non-OK rows for its body but keeps the OK rows so the popup\n * (when it ships under feat_more_cards_umbrella) can render the\n * full list. */\n checks: readonly DoctorCheck[];\n /** Convenience: how many rows are warn or fail. Card subtitle\n * reads this directly. Pure derivation from `checks`. */\n problemCount: number;\n /** Where the murmur row read agent state from. The slot-9 popup\n * re-derives the full check list and passes this back, so its\n * murmur row matches the card's (herdr on herdr). */\n agentStateSource?: \"murmur\" | \"herdr\";\n}\n\n/**\n * Compute the doctor summary for a workstream. Pure-ish: runs cheap\n * synchronous DB queries + reads from the supplied snapshot. Callers\n * that don't want to compute a snapshot first (or are running inside\n * `loadWorkstreamSnapshot` mid-build) can omit `snapshot` — the\n * snapshot-derived checks (ghosts / orphans / workspace-orphans) are\n * skipped in that case.\n */\nexport function loadDoctorSummary(\n db: Db,\n snapshot: WorkstreamSnapshot | null,\n agentStateSource: \"murmur\" | \"herdr\" = \"murmur\",\n): DoctorSummary {\n const checks: DoctorCheck[] = [];\n\n // ─ schema (table presence) ──────────────────────────────────────\n try {\n const tables = (\n db\n .prepare(\n \"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name\",\n )\n .all() as { name: string }[]\n ).map((r) => r.name);\n const missing = EXPECTED_TABLES.filter((t) => !tables.includes(t));\n if (missing.length === 0) {\n checks.push({\n name: \"schema\",\n status: \"ok\",\n detail: `${EXPECTED_TABLES.length} tables`,\n });\n } else {\n checks.push({\n name: \"schema\",\n status: \"fail\",\n detail: `missing: ${missing.join(\", \")}`,\n });\n }\n } catch (err) {\n checks.push({\n name: \"schema\",\n status: \"fail\",\n detail: err instanceof Error ? err.message : String(err),\n });\n }\n\n // ─ schema_version ────────────────────────────────────────────────\n try {\n const row = db.prepare(\"SELECT version FROM schema_version WHERE id = 1\").get() as\n | { version: number }\n | undefined;\n const v = row?.version;\n if (v === undefined) {\n checks.push({\n name: \"schema_version\",\n status: \"fail\",\n detail: `missing row (expected ${CURRENT_SCHEMA_VERSION})`,\n });\n } else if (v === CURRENT_SCHEMA_VERSION) {\n checks.push({ name: \"schema_version\", status: \"ok\", detail: String(v) });\n } else if (v < CURRENT_SCHEMA_VERSION) {\n checks.push({\n name: \"schema_version\",\n status: \"warn\",\n detail: `${v} (code expects ${CURRENT_SCHEMA_VERSION})`,\n });\n } else {\n checks.push({\n name: \"schema_version\",\n status: \"fail\",\n detail: `${v} (code expects ${CURRENT_SCHEMA_VERSION}; downgrade?)`,\n });\n }\n } catch {\n checks.push({\n name: \"schema_version\",\n status: \"fail\",\n detail: \"unreadable\",\n });\n }\n\n // ─ journal_mode ─────────────────────────────────────────────────\n try {\n const journal = db.pragma(\"journal_mode\", { simple: true });\n if (journal === \"wal\") {\n checks.push({ name: \"journal_mode\", status: \"ok\", detail: String(journal) });\n } else {\n checks.push({\n name: \"journal_mode\",\n status: \"warn\",\n detail: `${journal} (expected wal)`,\n });\n }\n } catch (err) {\n checks.push({\n name: \"journal_mode\",\n status: \"warn\",\n detail: err instanceof Error ? err.message : String(err),\n });\n }\n\n // ─ foreign_keys ─────────────────────────────────────────────────\n try {\n const fk = db.pragma(\"foreign_keys\", { simple: true });\n if (fk === 1) {\n checks.push({ name: \"foreign_keys\", status: \"ok\", detail: \"on\" });\n } else {\n checks.push({\n name: \"foreign_keys\",\n status: \"fail\",\n detail: `off (${fk})`,\n });\n }\n } catch (err) {\n checks.push({\n name: \"foreign_keys\",\n status: \"fail\",\n detail: err instanceof Error ? err.message : String(err),\n });\n }\n\n // ─ snapshot-derived checks (ghosts / orphans) ───────────────────\n if (snapshot !== null) {\n const ghosts = snapshot.view.report.prunedGhosts;\n if (ghosts === 0) {\n checks.push({ name: \"agents\", status: \"ok\", detail: \"no ghost panes\" });\n } else {\n checks.push({\n name: \"agents\",\n status: \"warn\",\n detail: `${ghosts} ghost pane${ghosts === 1 ? \"\" : \"s\"}; run \\`mu state\\` or \\`mu agent list\\` to reap`,\n });\n }\n const orphanPanes = snapshot.view.orphans.length;\n if (orphanPanes === 0) {\n checks.push({ name: \"panes\", status: \"ok\", detail: \"no orphan panes\" });\n } else {\n checks.push({\n name: \"panes\",\n status: \"warn\",\n detail: `${orphanPanes} orphan pane${orphanPanes === 1 ? \"\" : \"s\"}; run \\`mu agent adopt\\``,\n });\n }\n const orphanWorkspaces = snapshot.workspaceOrphans.length;\n if (orphanWorkspaces === 0) {\n checks.push({ name: \"workspaces\", status: \"ok\", detail: \"no orphan dirs\" });\n } else {\n checks.push({\n name: \"workspaces\",\n status: \"warn\",\n detail: `${orphanWorkspaces} orphan dir${orphanWorkspaces === 1 ? \"\" : \"s\"}; run \\`mu workspace orphans\\``,\n });\n }\n }\n\n const muExt = ctlExtensionDoctorCheck();\n checks.push(murmurDoctorCheck(agentStateSource, { muExtOk: muExt.status === \"ok\" }));\n checks.push(muExt, skillDoctorCheck());\n\n // ─ Mixed-fleet hazards + the SHALLOW drift invariant.\n //\n // Both obey this file's cheapness rules: the fleet checks are two path\n // comparisons, one statfs and one indexed scan; the drift invariant is\n // four indexed NOT EXISTS queries (~1ms on a 200-task DB). NO rebuild\n // here — `checkDrift` is ~0.6ms per op and would make the TUI's poll\n // tick take seconds. The deep check belongs to `mu doctor --deep`, and\n // the row below says so when it is clean, so the operator knows the\n // dashboard is showing a smoke alarm rather than a proof.\n for (const hazard of checkFleetHazards(db, { dbPath: defaultDbPath() })) {\n // Skip the inert \"no sync configured\" row: on a single-machine setup\n // it would be permanent noise in a dashboard whose whole design is\n // \"rows appearing means something needs attention\".\n if (hazard.severity === \"ok\" && hazard.name === \"db-vs-sync\") continue;\n checks.push({ name: hazard.name, status: hazard.severity, detail: hazard.detail });\n }\n\n const cheapDrift = checkCheapDriftInvariant(db);\n checks.push(\n cheapDrift.clean\n ? {\n name: \"drift\",\n status: \"ok\",\n detail: \"every row has ops; `mu doctor --deep` for full diff\",\n }\n : {\n name: \"drift\",\n status: \"fail\",\n detail: `${cheapDrift.totalUnexplained} row(s) with no ops; run \\`mu doctor --deep\\``,\n },\n );\n\n return { checks, problemCount: countProblems(checks), agentStateSource };\n}\n\nfunction resolveExecutable(name: string): string | null {\n for (const dir of (process.env.PATH ?? \"\").split(delimiter).filter(Boolean)) {\n const candidate = join(dir, name);\n try {\n accessSync(candidate, constants.X_OK);\n return realpathSync(candidate);\n } catch {\n // Keep scanning PATH.\n }\n }\n return null;\n}\n\nfunction murmurVersion(executable: string): string | null {\n let dir = dirname(executable);\n const root = parse(dir).root;\n while (dir !== root) {\n const packagePath = join(dir, \"package.json\");\n if (existsSync(packagePath)) {\n try {\n const pkg: unknown = JSON.parse(readFileSync(packagePath, \"utf8\"));\n if (\n typeof pkg === \"object\" &&\n pkg !== null &&\n \"name\" in pkg &&\n pkg.name === \"@mu-crew/murmur\" &&\n \"version\" in pkg &&\n typeof pkg.version === \"string\"\n ) {\n return pkg.version;\n }\n } catch {\n // An unrelated or unreadable package.json does not end the walk.\n }\n }\n dir = dirname(dir);\n }\n return null;\n}\n\nfunction olderThanMurmurOne(version: string): boolean {\n const match = /^(\\d+)\\.(\\d+)\\.(\\d+)/.exec(version);\n return match !== null && Number(match[1]) < 1;\n}\n\n/** Detail of the murmur row when murmur is absent but pi agents are\n * covered by the mu extension's control socket. */\nexport const MURMUR_NOT_NEEDED_DETAIL =\n \"not needed for pi agents (mu extension); used for other CLIs\";\n\n/**\n * The agent-state source row. Shared by the TUI card and `mu doctor`.\n * `muExtOk`: the mu pi extension is linked, so pi agents report state\n * over their control socket and a missing murmur only affects other CLIs.\n */\nexport function murmurDoctorCheck(\n agentStateSource: \"murmur\" | \"herdr\",\n opts: { muExtOk?: boolean } = {},\n): DoctorCheck {\n if (agentStateSource === \"herdr\") {\n return { name: \"murmur\", status: \"ok\", detail: \"agent state from herdr\" };\n }\n\n const executable = resolveExecutable(\"murmur\");\n if (opts.muExtOk === true && (executable === null || !murmurAvailable())) {\n return { name: \"murmur\", status: \"ok\", detail: MURMUR_NOT_NEEDED_DETAIL };\n }\n if (executable === null) {\n return {\n name: \"murmur\",\n status: \"warn\",\n detail: `${UNKNOWN_REASON.murmurMissing}: agent state shows unknown`,\n };\n }\n if (!murmurAvailable()) {\n return {\n name: \"murmur\",\n status: \"warn\",\n detail: `${UNKNOWN_REASON.extensionMissing}: run murmur link pi`,\n };\n }\n\n const version = murmurVersion(executable);\n if (version !== null && olderThanMurmurOne(version)) {\n return {\n name: \"murmur\",\n status: \"warn\",\n detail:\n opts.muExtOk === true\n ? `murmur ${version} is older than 1.0.0; idle/stall timing unknown for non-pi CLIs (pi agents use ctl)`\n : `murmur ${version} is older than 1.0.0; @murmur_pane_since missing, idle/stall timing unknown`,\n };\n }\n return {\n name: \"murmur\",\n status: \"ok\",\n detail: version === null ? \"agent state from murmur\" : `agent state from murmur ${version}`,\n };\n}\n\nconst RELINK = \"run mu link pi\";\n\n/** The \"mu ext\" row's feature list; a feature an env var switched off is named with it. */\nexport function extFeatures(env: NodeJS.ProcessEnv): string {\n const features: [string, string][] = [\n [\"mu_delegate\", \"MU_DELEGATE\"],\n [\"nudge\", \"MU_NUDGE\"],\n ];\n const on = [\"ctl\", ...features.filter(([, v]) => env[v] !== \"0\").map(([f]) => f)];\n const off = features.filter(([, v]) => env[v] === \"0\").map(([f, v]) => `${f} disabled by ${v}=0`);\n return `(${on.join(\", \")}${off.length ? `; ${off.join(\"; \")}` : \"\"})`;\n}\n\n/** The \"mu ext\" row: is the mu pi extension shim installed and live? */\nexport function ctlExtensionDoctorCheck(opts?: LinkOptions): DoctorCheck {\n const { extension } = inspectLinks(opts);\n switch (extension.state) {\n case \"ok\":\n return {\n name: \"mu ext\",\n status: \"ok\",\n detail: extFeatures(process.env),\n };\n case \"stale-copy\":\n return { name: \"mu ext\", status: \"warn\", detail: `stale copy: ${RELINK}` };\n case \"dangling\":\n return { name: \"mu ext\", status: \"warn\", detail: `dangling: ${RELINK}` };\n default:\n return { name: \"mu ext\", status: \"warn\", detail: `not linked: ${RELINK}` };\n }\n}\n\n/** The \"mu skill\" row: is `~/.agents/skills/mu` this package's skill? */\nexport function skillDoctorCheck(opts?: LinkOptions): DoctorCheck {\n const { skill } = inspectLinks(opts);\n switch (skill.state) {\n case \"ok\":\n return { name: \"mu skill\", status: \"ok\", detail: skill.target ?? skill.path };\n case \"foreign\":\n return {\n name: \"mu skill\",\n status: \"warn\",\n detail: `foreign skill at ~/.agents/skills/mu (${skill.target ?? \"not a symlink\"})`,\n };\n case \"dangling\":\n return { name: \"mu skill\", status: \"warn\", detail: `dangling: ${RELINK}` };\n default:\n return { name: \"mu skill\", status: \"warn\", detail: `not linked: ${RELINK}` };\n }\n}\n\n/** Per-agent probe budget for the doctor \"ctl\" row. */\nexport const DOCTOR_CTL_TIMEOUT_MS = 500;\n\nexport interface AgentCtlReport {\n workstream: string;\n agent: string;\n socket: string;\n probe: CtlProbe[\"kind\"];\n /** ok probes: the mu version the agent's extension was built from. */\n extVersion?: string;\n /** ok probes whose extension is older than the installed mu, or lacks ops. */\n outdated?: boolean;\n /** ok probes: protocol ops (CTL_OPS) the extension's hello does not list. */\n missingOps?: string[];\n /** Outdated probes: how `/reload` reaches it. \"ctl\" when the extension\n * serves op command, else \"mux\" (`--via mux`, typed into the pane). */\n reloadVia?: \"ctl\" | \"mux\";\n}\n\n/**\n * The installed mu version, from the package.json one directory above\n * this module (src/ in source mode, dist/ when bundled). Null if unreadable.\n */\nexport function installedMuVersion(): string | null {\n try {\n const pkgPath = join(dirname(fileURLToPath(import.meta.url)), \"..\", \"package.json\");\n const pkg: unknown = JSON.parse(readFileSync(pkgPath, \"utf8\"));\n const v =\n typeof pkg === \"object\" && pkg !== null ? (pkg as { version?: unknown }).version : null;\n return typeof v === \"string\" ? v : null;\n } catch {\n return null;\n }\n}\n\n/** a < b on the numeric major.minor.patch prefix; false when either is unparsable. */\nexport function versionOlder(a: string, b: string): boolean {\n const pa = /^(\\d+)\\.(\\d+)\\.(\\d+)/.exec(a);\n const pb = /^(\\d+)\\.(\\d+)\\.(\\d+)/.exec(b);\n if (!pa || !pb) return false;\n for (let i = 1; i <= 3; i++) {\n const d = Number(pa[i]) - Number(pb[i]);\n if (d !== 0) return d < 0;\n }\n return false;\n}\n\n/**\n * Is an ok probe's extension older than the installed mu? An extension\n * without `ops` in hello predates version reporting, so it is older. One\n * with ops but no extVersion runs from source (tests, dev): not flagged.\n * Missing ops are checked separately (`probeMissingOps`), because a pi that\n * loaded the extension before an op landed reports the SAME version.\n */\nfunction probeOutdated(probe: CtlProbe, installed: string | null): boolean {\n if (probe.kind !== \"ok\") return false;\n if (probe.ops === undefined) return true;\n if (probe.extVersion === undefined || installed === null) return false;\n return versionOlder(probe.extVersion, installed);\n}\n\n/** CTL_OPS entries an ok probe's hello does not list; [] when it predates ops. */\nfunction probeMissingOps(probe: CtlProbe): string[] {\n if (probe.kind !== \"ok\" || probe.ops === undefined) return [];\n const served = new Set<string>(probe.ops);\n return CTL_OPS.filter((op) => !served.has(op));\n}\n\n/**\n * The \"ctl\" row: probe the control socket of every agent that runs pi\n * (per `expectsCtl`, the rule send, state and abort use). `stateDir`\n * roots the derived socket path like spawn's (the DB's directory); it\n * defaults to ctlSocketPath's env-derived base. Probes run in\n * parallel, each bounded by `timeoutMs`. Async, so `mu doctor` only:\n * the TUI's per-tick summary stays synchronous and socket-free.\n */\nexport async function ctlSocketsDoctorCheck(\n agents: readonly AgentRow[],\n opts: { timeoutMs?: number; installedVersion?: string | null; stateDir?: string } = {},\n): Promise<{ check: DoctorCheck; agents: AgentCtlReport[] }> {\n const timeoutMs = opts.timeoutMs ?? DOCTOR_CTL_TIMEOUT_MS;\n const installed =\n opts.installedVersion !== undefined ? opts.installedVersion : installedMuVersion();\n const piAgents = agents\n .map((a) => ({ a, socket: ctlSocketPath(a.workstreamName, a.name, opts.stateDir) }))\n .filter(({ a, socket }) => expectsCtl(a, socket));\n const reports = await Promise.all(\n piAgents.map(async ({ a, socket }): Promise<AgentCtlReport> => {\n const probe = await ctlProbe(socket, timeoutMs);\n const older = probeOutdated(probe, installed);\n const missingOps = probeMissingOps(probe);\n return {\n workstream: a.workstreamName,\n agent: a.name,\n socket,\n probe: probe.kind,\n ...(probe.kind === \"ok\" && probe.extVersion !== undefined\n ? { extVersion: probe.extVersion }\n : {}),\n ...(older || missingOps.length > 0\n ? {\n outdated: true,\n reloadVia: probe.kind === \"ok\" && probe.ops?.includes(\"command\") ? \"ctl\" : \"mux\",\n }\n : {}),\n ...(missingOps.length > 0 ? { missingOps } : {}),\n };\n }),\n );\n const bad = reports.filter((r) => r.probe !== \"ok\" || r.outdated);\n const describe = (r: AgentCtlReport): string => {\n const who = `${r.workstream}/${r.agent}`;\n if (!r.outdated) return `${who}: ${r.probe}`;\n if (r.missingOps && !(r.extVersion && installed && versionOlder(r.extVersion, installed)))\n return `${who}: extension lacks ops: ${r.missingOps.join(\", \")}`;\n return `${who}: extension ${r.extVersion ?? \"(unknown)\"} older than installed ${installed ?? \"mu\"}`;\n };\n let check: DoctorCheck;\n if (reports.length === 0) check = { name: \"ctl\", status: \"ok\", detail: \"no pi agents\" };\n else if (bad.length === 0) {\n check = {\n name: \"ctl\",\n status: \"ok\",\n detail: `${reports.length}/${reports.length} pi agents reachable`,\n };\n } else {\n check = {\n name: \"ctl\",\n status: \"warn\",\n detail: bad.map(describe).join(\", \"),\n };\n }\n return { check, agents: reports };\n}\n\n/** Count of warn + fail rows. Pure; exported for unit tests. */\nexport function countProblems(checks: readonly DoctorCheck[]): number {\n let n = 0;\n for (const c of checks) if (c.status !== \"ok\") n++;\n return n;\n}\n\n/**\n * Return the full check array (OK + warn + fail) in stable display\n * order. Used by the TUI's slot-9 Doctor popup\n * (feat_popup_9_doctor, workstream `tui-impl`) which renders every\n * row — not just the non-OK subset Card 9 surfaces.\n *\n * Thin wrapper over `loadDoctorSummary` so the SDK seam stays\n * single: `loadDoctorSummary` is the source of truth for the\n * check vocabulary, and the popup's `loadDoctorChecks` view is\n * just `.checks`. Pure-ish (same cheap synchronous DB reads as\n * `loadDoctorSummary`).\n */\nexport function loadDoctorChecks(\n db: Db,\n snapshot: WorkstreamSnapshot | null,\n agentStateSource: \"murmur\" | \"herdr\" = \"murmur\",\n): readonly DoctorCheck[] {\n return loadDoctorSummary(db, snapshot, agentStateSource).checks;\n}\n\n// ─── pure helpers (per-check remediation hints) ────────────────────\n//\n// These map a `DoctorCheck.name` to either (a) a single-line\n// informational shell command suitable for yank/paste, or (b) a\n// short multi-line paragraph explaining the failure shape. They\n// originally lived next to the slot-9 Doctor popup\n// (src/cli/tui/popups/doctor.tsx) but moved here per\n// review_tui_doctor_remediation_lives_in_popup: neither function\n// has any rendering concern (both return plain strings) and the\n// popup's `renderDrillBody` was the only render-layer caller.\n// Living here keeps every per-check fact in one file so adding a\n// new check is a single touchpoint, and lets future SDK consumers\n// (e.g. a `mu doctor --remediation` flag) reach the same data\n// without depending on the TUI render layer.\n//\n// READ-ONLY by construction. Even when a check is `fail`, the yank\n// recipe is the diagnostic verb the operator should RUN MANUALLY,\n// never a mutating fix. Schema-shape checks (no actionable\n// mutation) yank a `# ...` comment line so the muscle-memory of\n// `y` still gives feedback.\n\n/**\n * Map a check row to the most useful informational command the\n * operator might paste. Read-only by construction: `mu agent list`,\n * `mu workspace orphans`, `mu doctor` are all SELECT-shape verbs;\n * `# ...` lines are visibly inert. Per the slot-9 popup spec KEY\n * MAP block this is INFORMATIONAL, never a mutating recipe — so\n * even when the check is `fail`, we yank the diagnostic verb the\n * operator should RUN MANUALLY, not a fix command.\n *\n * Pure; exported for unit tests + SDK reuse.\n */\nexport function yankCommandForCheck(check: Pick<DoctorCheck, \"name\" | \"status\">): string {\n switch (check.name) {\n case \"murmur\":\n return \"murmur link pi\";\n case \"mu ext\":\n case \"mu skill\":\n return \"mu link pi\";\n case \"ctl\":\n return \"mu agent list\";\n case \"agents\":\n // Diagnostic/reaping read: `mu state` and `mu agent list` both\n // reconcile missing panes. Prefer the canonical state card; the\n // detailed agent list remains in the doctor detail text.\n return \"mu state\";\n case \"panes\":\n // Orphan tmux panes — the standard adoption recipe.\n return \"mu agent adopt\";\n case \"workspaces\":\n // Diagnostic: list orphan workspace dirs with their cleanup\n // command. An orphan has no row, so `mu workspace free` cannot\n // remove it; the operator deletes it by hand.\n return \"mu workspace orphans\";\n case \"drift\":\n // The full rebuild-and-diff. Read-only: it writes only to a temp\n // DB and never touches live state.\n return \"mu doctor --deep\";\n case \"db-vs-sync\":\n case \"db-filesystem\":\n // Environment hazards: the fix is an env-var change the operator\n // must make deliberately, so yank the inspection, not a mutation.\n return \"# check MU_DB_PATH / MU_SYNC_DIR; see `mu doctor` for the full explanation\";\n case \"name-case\":\n return 'mu sql \"SELECT name FROM workstreams ORDER BY LOWER(name)\"';\n case \"schema\":\n case \"schema_version\":\n case \"journal_mode\":\n case \"foreign_keys\":\n // No actionable mutation an operator should yank for\n // schema-shape checks (the migration runner is the SDK seam,\n // not a CLI verb). Yank a no-op comment so the muscle memory\n // of `y` still gives feedback. When fail, the textual\n // `mu doctor` carries the full diagnostic.\n return `# ${check.name}: see \\`mu doctor\\` for full diagnostic`;\n default:\n // Forward-compat: any future check name falls back to the\n // textual `mu doctor` verb. Read-only.\n return \"mu doctor\";\n }\n}\n\n/**\n * A short paragraph (one paragraph per check name) explaining the\n * shape of the failure / warning. Returned as a `readonly string[]`\n * so the popup's drill body can interleave the lines with other\n * content; CLI consumers can `.join(\"\\n\")` themselves.\n *\n * Pure; exported for unit tests + SDK reuse.\n */\nexport function remediationParagraph(check: DoctorCheck): readonly string[] {\n switch (check.name) {\n case \"murmur\":\n return [\n \"Install murmur with `npm i -g @mu-crew/murmur`, then run\",\n \"`murmur init` and `murmur link pi`. Restart running pi sessions.\",\n ];\n case \"mu ext\":\n case \"mu skill\":\n return [\n \"Run `mu link pi` to install the mu pi extension shim and the mu\",\n \"skill symlink, then restart running pi sessions so they load it.\",\n ];\n case \"ctl\":\n return [\n \"mu talks to pi agents over a per-agent control socket served by\",\n \"the mu pi extension. `missing`: no socket (extension not loaded,\",\n \"the agent predates `mu link pi`, or a new pi still waits at its\",\n \"project trust prompt: answer /trust in the pane, or spawn with\",\n \"--command 'pi --approve'). `refused`: socket present but not\",\n \"answering. `version`: protocol mismatch; upgrade mu or pi.\",\n \"Run `mu link pi`, then respawn the agent. `extension X older than\",\n \"installed Y` or `lacks ops`: the agent's pi loaded an older mu\",\n \"build; reload it with `mu agent send <a> '/reload'` (add\",\n \"`--via mux` when the extension lacks op command) or respawn it.\",\n ];\n case \"agents\":\n return [\n \"A 'ghost pane' is a registered agent whose tmux pane is gone.\",\n \"Doctor only reports the count. Run `mu state` or `mu agent list`\",\n \"to reap ghost agents and return their IN_PROGRESS tasks to OPEN.\",\n \"The TUI is read-only, but its slow tick uses the same state reap.\",\n ];\n case \"panes\":\n return [\n \"An 'orphan pane' is a live tmux pane in the workstream's\",\n \"session that mu doesn't know about. Adopt it via\",\n \"`mu agent adopt <pane-id>` to register it as a managed agent,\",\n \"or kill it manually if it's not yours.\",\n ];\n case \"workspaces\":\n return [\n \"An 'orphan workspace dir' is a per-agent VCS workspace dir under\",\n \"the workstream with no vcs_workspaces row, so `mu workspace free`\",\n \"cannot remove it. mu never deletes it for you: it may hold the only\",\n \"copy of uncommitted work. Run `mu workspace orphans -w <ws>` to list\",\n \"them with a cleanup command, inspect each, then remove it by hand\",\n \"(`git worktree remove --force <path>` from the project root for a\",\n \"git checkout, else `rm -rf <path>`).\",\n ];\n case \"drift\":\n return [\n \"Drift means the ops log and the live tables disagree, and since\",\n \"undo/sync/history are ALL projections of that one log, a\",\n \"capture bug breaks all of them at once. This row is the shallow\",\n \"check (every live row must have at least one op naming its key);\",\n \"it cannot see an uncaptured UPDATE. Run `mu doctor --deep` for the\",\n \"full rebuild-and-diff, which names the exact table/key/field.\",\n \"Back up before acting: if capture missed a mutation the LIVE rows\",\n \"hold real work and rebuilding would discard it.\",\n ];\n case \"db-vs-sync\":\n return [\n \"MU_DB_PATH is inside MU_SYNC_DIR. A live WAL-mode SQLite DB is\",\n \"three files whose mutual consistency IS its durability; a file\",\n \"syncer copying them out of order, or resurrecting a peer's stale\",\n \"-wal, silently corrupts the DB. Move the DB out of the synced\",\n \"folder — mu syncs append-only per-machine segments precisely so\",\n \"the database file itself never has to travel.\",\n ];\n case \"db-filesystem\":\n return [\n \"The DB appears to be on a network mount (NFS/SMB/FUSE). SQLite's\",\n \"WAL mode needs working POSIX advisory locks and a shared-memory\",\n \"file, and network filesystems provide neither dependably: expect\",\n \"'database is locked' without contention, or corruption with it.\",\n \"Keep the DB on local disk and sync segments instead.\",\n ];\n case \"name-case\":\n return [\n \"Two workstream names differ only by letter case. They coexist on\",\n \"Linux but collide on macOS (APFS) and Windows (NTFS), and a\",\n \"workstream name IS a tmux session name and seeds workspace paths.\",\n \"A Mac in the fleet would see one session where Linux sees two.\",\n \"Rename one side before adding a Mac: export, re-init under a new\",\n \"name, tear down the old one.\",\n ];\n case \"schema\":\n return [\n \"Missing tables mean something dropped them after mu created\",\n \"them: every mu process runs CREATE TABLE IF NOT EXISTS for the\",\n \"whole schema at open, so re-running any mu command restores an\",\n \"empty table. If a table that held data is gone, back up the DB\",\n \"and rebuild from the ops log: `mu rebuild <new-file>`.\",\n ];\n case \"schema_version\":\n return [\n \"mu opens only a DB at exactly its own schema version: older\",\n \"DBs are refused with SchemaTooOldError and newer ones with\",\n \"SchemaTooNewError (exit 4), and there is no in-place migration.\",\n \"A mismatch seen here means the row changed after open (an\",\n \"external SQLite client). If `<` the expected version, migrate a\",\n \"copy with scripts/migrate.ts; if `>`, use the newer mu binary.\",\n ];\n case \"journal_mode\":\n return [\n \"WAL is the default journal mode for SQLite under mu. A\",\n \"different mode (e.g. `delete`) means an external tool\",\n \"rewrote the DB pragma. Re-open the DB with mu to restore.\",\n ];\n case \"foreign_keys\":\n return [\n \"Foreign keys must be ON for mu's CASCADE deletes to work.\",\n \"An OFF value usually means an external SQLite client opened\",\n \"the DB without `PRAGMA foreign_keys = ON`. Re-open with mu.\",\n ];\n default:\n return [\"See `mu doctor` for the canonical textual diagnostic.\"];\n }\n}\n","// mu — the ONE op → prose formatter.\n//\n// WHY THIS FILE EXISTS\n//\n// mu once rendered log lines by prefix-matching free prose: `classifyEventVerb`\n// walked `EVENT_VERB_PREFIXES` looking for a leading two-word verb, and\n// `CLAIM_EVENT_PREFIX` was bolted on because that matching kept breaking\n// (review_code_last_claim_actor_brittle). Rewording any payload silently\n// broke its renderer, and attribution had to be smuggled through a\n// tab-delimited prefix so it could be parsed back out.\n//\n// Since v2-capture + v2-retire-log-shim, every op carries a structured\n// `intent` ('task.close'), a natural `key` ('demo/t1'), and a JSON\n// payload holding ONLY the columns that changed. So rendering is a\n// lookup on intent, not a search through text. THIS FILE MUST NEVER\n// STRING-MATCH A PAYLOAD to decide what an op is — that is the exact\n// brittleness the ops log deletes. It reads `intent`, then pulls named fields\n// out of the parsed payload.\n//\n// Layering: pure and colour-free. `src/cli/format.ts` adds picocolors\n// for the terminal, and `src/cli/tui/` renders the same strings inside\n// ink. Neither owns any prose logic — one formatter, three surfaces\n// (ROADMAP: no second render layer).\n\nimport type { LocalIntent } from \"./logs.js\";\nimport { formatPair, resolvePair } from \"./tasks/status.js\";\n\n/** Every intent mu writes: the local ones (`emitEvent`, for changes no\n * trigger can see) plus the capture-trigger ones (set via\n * `withOpContext` around a portable-table mutation). */\nexport type CaptureIntent =\n | \"task.add\"\n | \"task.update\"\n | \"task.note\"\n | \"task.delete\"\n | \"task.close\"\n | \"task.open\"\n | \"task.park\"\n | \"task.unpark\"\n | \"task.accept\"\n | \"task.reject\"\n | \"task.defer\"\n | \"task.claim\"\n | \"task.release\"\n | \"task.reap\"\n | \"task.block\"\n | \"task.unblock\"\n | \"task.reparent\"\n | \"workstream.init\"\n | \"workstream.teardown\"\n // Any write made through `mu sql`, on whichever portable table it hit.\n | \"sql.write\"\n // Pre-1.2.0 name for workstream.teardown. Read-only: nothing emits it\n // any more, but ~5k ops in existing logs carry it and must keep\n // rendering. See LEGACY_INTENT_SYNONYMS in src/legacy-ops.ts.\n | \"workstream.destroy\";\n\nexport type KnownIntent = CaptureIntent | LocalIntent;\n\n/** A log row, reduced to what rendering needs. Structural so both\n * `LogRow` (the SDK shape) and raw op rows satisfy it. */\nexport interface RenderableOp {\n intent: string | null;\n /** `ops.entity`. */\n kind: string;\n /** `ops.key` — the natural key, verbatim. */\n workstreamName: string | null;\n payload: string;\n /** `ops.actor`. */\n source: string;\n op?: string;\n}\n\n/** Rendered op, split so callers can colour the verb independently.\n * `subject` is the entity the line is about; `detail` is the\n * human-readable consequence. */\nexport interface RenderedOp {\n /** Operator-facing verb, e.g. 'task close'. Colour this. */\n verb: string;\n /** The entity acted on, already stripped of workstream scope. */\n subject: string;\n /** What changed, in prose. May be empty. */\n detail: string;\n}\n\n// ─── payload access ────────────────────────────────────────────────────\n\n/** Parse an op payload into a field bag. Tolerant by design: a payload\n * that is not JSON (operator prose from `mu log \"<text>\"`) yields an empty\n * bag rather than throwing, and the caller falls back to showing the\n * text verbatim. */\nfunction fields(payload: string): Record<string, unknown> {\n if (!payload.startsWith(\"{\")) return {};\n try {\n const parsed: unknown = JSON.parse(payload);\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) return {};\n return parsed as Record<string, unknown>;\n } catch {\n return {};\n }\n}\n\nfunction str(bag: Record<string, unknown>, key: string): string | undefined {\n const v = bag[key];\n return typeof v === \"string\" ? v : undefined;\n}\n\nfunction num(bag: Record<string, unknown>, key: string): number | undefined {\n const v = bag[key];\n return typeof v === \"number\" ? v : undefined;\n}\n\n/** Columns that are pure bookkeeping — never interesting on their own. */\nconst NOISE_FIELDS = new Set([\"updated_at\", \"created_at\"]);\n\n/** Field names, in the order a human wants to read them. */\nfunction changedFields(bag: Record<string, unknown>): string[] {\n return Object.keys(bag).filter((k) => !NOISE_FIELDS.has(k));\n}\n\n// ─── key parsing ───────────────────────────────────────────────────────\n\n/**\n * Split a natural key into workstream + local part.\n *\n * 'demo' -> { workstream: 'demo' }\n * 'demo/t1' -> { workstream: 'demo', local: 't1' }\n * 'demo/t1#3' -> { workstream: 'demo', local: 't1', note: '3' }\n * 'demo/a->demo/b' -> { workstream: 'demo', local: 'a', to: 'b' }\n */\nexport function parseOpKey(key: string | null): {\n workstream?: string;\n local?: string;\n note?: string;\n to?: string;\n} {\n if (key === null || key === \"\") return {};\n // Edge keys are '<ws>/<from>-><ws>/<to>'.\n const arrow = key.indexOf(\"->\");\n if (arrow !== -1) {\n const from = parseOpKey(key.slice(0, arrow));\n const to = parseOpKey(key.slice(arrow + 2));\n const out: { workstream?: string; local?: string; to?: string } = {};\n if (from.workstream !== undefined) out.workstream = from.workstream;\n if (from.local !== undefined) out.local = from.local;\n if (to.local !== undefined) out.to = to.local;\n return out;\n }\n const slash = key.indexOf(\"/\");\n if (slash === -1) return { workstream: key };\n const workstream = key.slice(0, slash);\n const rest = key.slice(slash + 1);\n const hash = rest.indexOf(\"#\");\n if (hash === -1) return { workstream, local: rest };\n return { workstream, local: rest.slice(0, hash), note: rest.slice(hash + 1) };\n}\n\n// ─── the formatter ─────────────────────────────────────────────────────\n\n/** Human verb per intent. Space-separated so it reads as a command,\n * matching how operators talk about these ('task close', not\n * 'task.close'). */\nconst VERBS: Record<KnownIntent, string> = {\n \"task.add\": \"task add\",\n \"task.update\": \"task update\",\n \"task.note\": \"task note\",\n \"task.delete\": \"task delete\",\n \"task.close\": \"task close\",\n \"task.open\": \"task open\",\n \"task.park\": \"task park\",\n \"task.unpark\": \"task unpark\",\n \"task.accept\": \"task accept\",\n \"task.reject\": \"task reject\",\n \"task.defer\": \"task defer\",\n \"task.claim\": \"task claim\",\n \"task.release\": \"task release\",\n \"task.reap\": \"task reap\",\n \"task.block\": \"task block\",\n \"task.unblock\": \"task unblock\",\n \"task.reparent\": \"task reparent\",\n \"workstream.init\": \"workstream init\",\n \"workstream.teardown\": \"workstream teardown\",\n \"workstream.destroy\": \"workstream teardown\",\n \"sql.write\": \"sql write\",\n \"agent.spawn\": \"agent spawn\",\n \"agent.spawn_failed\": \"agent spawn failed\",\n \"agent.close\": \"agent close\",\n \"agent.adopt\": \"agent adopt\",\n \"agent.kick\": \"agent kick\",\n \"agent.send\": \"agent send\",\n \"agent.abort\": \"agent abort\",\n // Payload prose reads \"agent stalled ...\"; keep the verb matching it\n // so the emitted text is not printed with a second, different verb.\n \"agent.stall\": \"agent stalled\",\n \"workspace.create\": \"workspace create\",\n \"workspace.free\": \"workspace free\",\n \"workspace.refresh\": \"workspace refresh\",\n};\n\n/** Every intent this formatter knows, derived from the verb table so\n * the two can't drift. */\nexport const KNOWN_INTENTS: readonly KnownIntent[] = Object.keys(VERBS) as KnownIntent[];\n\n/** Every operator-facing verb the formatter can emit. Exported so audits\n * can check \"this emitter's verb is declared\" without re-deriving it\n * from the intent — the two are deliberately not always identical\n * (`agent.stall` renders as \"agent stalled\", matching its payload). */\nexport const KNOWN_VERBS: readonly string[] = Object.values(VERBS);\n\nfunction isKnownIntent(intent: string): intent is KnownIntent {\n return Object.hasOwn(VERBS, intent);\n}\n\n/**\n * Render one op as prose.\n *\n * Returns null when the row is not a rendered op at all — operator prose\n * from `mu log \"<text>\"` / a `--kind` ledger, which has no intent and\n * should be shown verbatim. Callers print `payload` in that case.\n */\nexport function renderOp(row: RenderableOp): RenderedOp | null {\n const intent = row.intent;\n if (intent === null) return null;\n\n // A bare status set (`setTaskStatus` with no more specific verb) uses\n // 'task.set-<status>' via intentIfUnset. Normalise it here rather than\n // enumerating six more table entries.\n const setPrefix = \"task.set-\";\n if (intent.startsWith(setPrefix)) {\n const status = intent.slice(setPrefix.length).toUpperCase();\n const { local } = parseOpKey(row.workstreamName);\n return { verb: \"task status\", subject: local ?? \"\", detail: `\\u2192 ${status}` };\n }\n\n if (!isKnownIntent(intent)) {\n // Forward-compatible: an intent written by a NEWER mu (ingested from\n // a peer's segment) — or by the one-shot scripts/migrate.ts\n // importer, whose 'migrate.v8' / 'migrate.archive' / 'migrate.status'\n // ops deliberately do NOT claim to be typed verbs — still renders\n // legibly instead of vanishing. Deliberately not a throw: sync must\n // never be blocked by a rendering gap.\n //\n // A PROSE payload is shown as the detail, because for an unknown\n // intent the prose is the only information the line carries and\n // dropping it renders a bare verb with no subject at all (which is\n // what every carried pre-1.0 log line looked like). A JSON payload is\n // still withheld — \"no raw JSON in mu log\" is a hard property —\n // and reduced to its changed field names.\n const bag = fields(row.payload);\n const detail = row.payload.startsWith(\"{\")\n ? changedFields(bag).join(\" \")\n : oneLine(row.payload, 100);\n return {\n verb: intent.replace(\".\", \" \"),\n subject: parseOpKey(row.workstreamName).local ?? \"\",\n detail,\n };\n }\n return renderKnown(row, intent);\n}\n\n/** Split from `renderOp` so the switch is this function's ONLY exit\n * path: that is what makes TS treat it as exhaustive and reject a\n * missing `KnownIntent` case at COMPILE time (TS2366), instead of\n * silently falling through to a runtime default. */\nfunction renderKnown(row: RenderableOp, intent: KnownIntent): RenderedOp {\n const bag = fields(row.payload);\n const key = parseOpKey(row.workstreamName);\n const subject = key.local ?? key.workstream ?? \"\";\n const deleted = row.op === \"del\";\n\n // Exhaustive switch over the closed union: adding an intent to VERBS\n // without handling it here is a COMPILE error, not a runtime fallback.\n switch (intent) {\n case \"task.add\": {\n const impact = num(bag, \"impact\");\n const effort = num(bag, \"effort_days\");\n const title = str(bag, \"title\");\n const bits: string[] = [];\n if (title !== undefined) bits.push(`\"${title}\"`);\n if (impact !== undefined) bits.push(`impact=${impact}`);\n if (effort !== undefined) bits.push(`effort=${effort}`);\n return { verb: VERBS[intent], subject, detail: bits.join(\" \") };\n }\n case \"task.update\": {\n const changed = changedFields(bag);\n const detail = changed\n .map((f) => {\n const v = bag[f];\n return typeof v === \"object\" ? f : `${f}=${String(v)}`;\n })\n .join(\" \");\n // A payload of only updated_at is a parent-row touch (a note or\n // edge bumped its task). Say so rather than printing nothing.\n return { verb: VERBS[intent], subject, detail: detail === \"\" ? \"(touched)\" : detail };\n }\n case \"task.note\": {\n const author = str(bag, \"author\");\n const content = str(bag, \"content\") ?? \"\";\n const n = key.note;\n const head = n === undefined ? \"\" : `#${n} `;\n const by = author === undefined || author === \"\" ? \"\" : ` by ${author}`;\n return { verb: VERBS[intent], subject, detail: `${head}${oneLine(content)}${by}` };\n }\n case \"task.delete\":\n // Always a tombstone (op='del'), so the payload is '{}' — there is\n // nothing to report beyond the fact of it.\n return { verb: VERBS[intent], subject, detail: \"\" };\n case \"task.close\":\n case \"task.open\":\n case \"task.reject\":\n case \"task.defer\": {\n const status = str(bag, \"status\");\n return {\n verb: VERBS[intent],\n subject,\n detail: status === undefined ? \"\" : `→ ${pairText(bag, status)}`,\n };\n }\n case \"task.park\":\n case \"task.unpark\":\n case \"task.accept\": {\n // All three stay OPEN, so the payload carries only the substate.\n const detail = str(bag, \"substate\") === undefined ? \"\" : `→ ${pairText(bag, \"OPEN\")}`;\n return { verb: VERBS[intent], subject, detail };\n }\n case \"task.claim\": {\n // The payload cannot name the actor on the `--self` path (owner_id\n // stays NULL by design), so attribution comes from ops.actor.\n const by = row.source === \"\" ? \"\" : `by ${row.source}`;\n const status = str(bag, \"status\");\n const tail = status === undefined ? \"\" : ` → ${status}`;\n return { verb: VERBS[intent], subject, detail: `${by}${tail}` };\n }\n case \"task.release\":\n case \"task.reap\": {\n const status = str(bag, \"status\");\n const bits: string[] = [];\n if (Object.hasOwn(bag, \"owner_id\") && bag.owner_id === null) bits.push(\"owner cleared\");\n if (status !== undefined) bits.push(`→ ${status}`);\n return { verb: VERBS[intent], subject, detail: bits.join(\" \") };\n }\n case \"task.block\":\n case \"task.unblock\":\n case \"task.reparent\": {\n // Edge ops carry the pair in the key; the task-row op that shares\n // the group is just a touch.\n if (key.to !== undefined) {\n const dir = intent === \"task.unblock\" ? \"no longer blocks\" : \"blocks\";\n return { verb: VERBS[intent], subject, detail: `${dir} ${key.to}` };\n }\n return { verb: VERBS[intent], subject, detail: deleted ? \"(edge removed)\" : \"(touched)\" };\n }\n case \"workstream.init\":\n return { verb: VERBS[intent], subject, detail: \"\" };\n case \"workstream.teardown\":\n case \"workstream.destroy\":\n return {\n verb: VERBS[intent],\n subject,\n detail: key.local === undefined ? \"\" : \"(cascaded)\",\n };\n case \"sql.write\": {\n // A raw write can hit any portable table, so name the entity and\n // the changed columns (values truncated: a note body is free text).\n if (deleted) return { verb: VERBS[intent], subject, detail: `${row.kind} deleted` };\n const edge = key.to === undefined ? \"\" : ` -> ${key.to}`;\n const changed = changedFields(bag)\n .map((f) => {\n const v = bag[f];\n return typeof v === \"object\" && v !== null ? f : `${f}=${oneLine(String(v), 40)}`;\n })\n .join(\" \");\n return {\n verb: VERBS[intent],\n subject,\n detail: `${row.kind}${edge} ${changed === \"\" ? \"(touched)\" : changed}`,\n };\n }\n // Local intents: no trigger can see these, so `emitEvent` wrote the\n // payload as prose. It is already human-readable — show it as the\n // detail rather than inventing a second phrasing. The leading verb\n // is stripped so it is not printed twice.\n case \"agent.spawn\":\n case \"agent.spawn_failed\":\n case \"agent.close\":\n case \"agent.adopt\":\n case \"agent.kick\":\n case \"agent.send\":\n case \"agent.abort\":\n case \"agent.stall\":\n case \"workspace.create\":\n case \"workspace.free\":\n case \"workspace.refresh\": {\n const verb = VERBS[intent];\n // These payloads are prose by construction (emitEvent writes them).\n // Guard anyway: a JSON payload here would otherwise be dumped raw\n // into the line, and \"no raw JSON in mu log\" is a hard property.\n if (row.payload.startsWith(\"{\")) {\n const named = str(bag, \"name\") ?? subject;\n return { verb, subject: named, detail: changedFields(bag).join(\" \") };\n }\n const prose = row.payload.startsWith(verb)\n ? row.payload.slice(verb.length).trim()\n : row.payload;\n const firstSpace = prose.indexOf(\" \");\n const name = firstSpace === -1 ? prose : prose.slice(0, firstSpace);\n const rest = firstSpace === -1 ? \"\" : prose.slice(firstSpace + 1).trim();\n return { verb, subject: name, detail: rest };\n }\n }\n}\n\n/** \"CLOSED/wontfix\", or bare \"CLOSED\" for a default substate. */\nfunction pairText(bag: Record<string, unknown>, status: string): string {\n const pair = resolvePair(status, str(bag, \"substate\"));\n return pair === null ? status : formatPair(pair);\n}\n\n/** Collapse a multi-line string to one line, truncated. Note contents\n * are free text and can be paragraphs; a log line is a line. */\nfunction oneLine(text: string, max = 60): string {\n const flat = text.replace(/\\s+/g, \" \").trim();\n return flat.length <= max ? flat : `${flat.slice(0, max - 1)}…`;\n}\n\n/**\n * Render an op as a single plain-text string. The convenience form for\n * callers that don't colour the verb separately (JSON `rendered` field,\n * TUI cards with their own column layout).\n */\nexport function renderOpLine(row: RenderableOp): string {\n const r = renderOp(row);\n if (r === null) return oneLine(row.payload, 120);\n return [r.verb, r.subject, r.detail].filter((s) => s !== \"\").join(\" \");\n}\n\n/**\n * The entity a row is about, for building a \"show me this\" command.\n * Reads `intent` + `key`, never prose.\n */\nexport function opSubject(row: RenderableOp): { kind: \"task\" | \"agent\"; id: string } | null {\n const intent = row.intent;\n if (intent === null) return null;\n const { local } = parseOpKey(row.workstreamName);\n if (intent.startsWith(\"task.\") && local !== undefined && local !== \"\") {\n return { kind: \"task\", id: local };\n }\n if (intent.startsWith(\"agent.\") || intent.startsWith(\"workspace.\")) {\n const r = renderOp(row);\n if (r !== null && r.subject !== \"\") return { kind: \"agent\", id: r.subject };\n }\n return null;\n}\n","// mu — parallel-track detection via union-find with diamond merge.\n//\n// Port of a parallel-tracks union-find algorithm cribbed from a\n// prior internal multi-agent runtime. The killer feature: when two goals share a prerequisite, their subgraphs\n// overlap and they collapse into ONE track, so two agents are never\n// assigned tasks that share a dependency.\n//\n// goal_a goal_b goal_a goal_b\n// \\ / \\ /\n// shared → shared (1 track)\n// | |\n// leaf leaf\n//\n// Algorithm:\n// 1. Get all open goals (tasks with no outgoing edges, not CLOSED).\n// 2. In one recursive query, compute each goal's prerequisite subgraph\n// (everything transitively reachable via reverse edges).\n// 3. Build union-find: merge goals while observing shared tasks.\n// 4. Each connected component is one Track.\n\nimport { compareStrings } from \"./compare.js\";\nimport type { Db } from \"./db.js\";\nimport { listGoals, listReady, type TaskRow } from \"./tasks.js\";\n\nexport interface Track {\n /** Goal tasks (no outgoing edges) belonging to this track. */\n roots: TaskRow[];\n /** Every task id reachable as a prerequisite of any root in this track. */\n taskIds: ReadonlySet<string>;\n /** Number of READY tasks (per the SQL view) within this track's subgraph. */\n readyCount: number;\n /** True when every non-CLOSED task in the track is OPEN/parked: the\n * track holds work, but none of it is schedulable. */\n parked: boolean;\n}\n\n/**\n * Identify independent task subtrees suitable for parallel assignment\n * within a workstream. Open goals only; CLOSED goals are excluded as\n * they no longer represent work to schedule.\n *\n * Scoping: only goals belonging to `workstream` are considered.\n * Cross-workstream edges are forbidden by addTask, so a goal's\n * prerequisite subgraph is naturally workstream-internal.\n */\nexport function getParallelTracks(db: Db, workstream: string): Track[] {\n // listGoals already filters via the SQL view (status <> CLOSED),\n // but defence-in-depth: a stale db snapshot or future view tweak\n // shouldn't let closed goals leak into track count.\n const goals = listGoals(db, workstream).filter((g) => g.status !== \"CLOSED\");\n if (goals.length === 0) return [];\n\n // 2. Compute every goal's prerequisite subgraph in one traversal.\n // Running one recursive query per goal made the TUI's fast tick scale\n // with the number of goals. The goal id carried through this CTE keeps\n // the same inclusive per-goal sets in one SQLite round-trip.\n const reach = db\n .prepare(\n `WITH RECURSIVE\n active_goals(id, local_id) AS (\n SELECT g.id, g.local_id\n FROM goals g\n JOIN workstreams ws ON ws.id = g.workstream_id\n WHERE ws.name = ?\n ),\n reach(goal_id, node_id) AS (\n SELECT id, id FROM active_goals\n UNION\n SELECT r.goal_id, e.from_task_id\n FROM reach r\n JOIN task_edges e ON e.to_task_id = r.node_id\n )\n SELECT goal.local_id AS goal_id, node.local_id AS task_id,\n node.status AS status, node.substate AS substate\n FROM reach r\n JOIN tasks goal ON goal.id = r.goal_id\n JOIN tasks node ON node.id = r.node_id`,\n )\n .all(workstream) as Array<{\n goal_id: string;\n task_id: string;\n status: string;\n substate: string;\n }>;\n\n const subgraphs = new Map(goals.map((goal) => [goal.name, new Set<string>()]));\n const uf = new UnionFind(goals.map((goal) => goal.name));\n const firstGoalByTask = new Map<string, string>();\n // Substate of every non-CLOSED task reached, for the per-track `parked` flag.\n const openSubstate = new Map<string, string>();\n for (const row of reach) {\n if (row.status !== \"CLOSED\") openSubstate.set(row.task_id, row.substate);\n subgraphs.get(row.goal_id)?.add(row.task_id);\n const firstGoal = firstGoalByTask.get(row.task_id);\n if (firstGoal === undefined) firstGoalByTask.set(row.task_id, row.goal_id);\n else uf.union(firstGoal, row.goal_id);\n }\n\n // 4. Group goals + subgraph task ids by union-find root.\n const componentTaskIds = new Map<string, Set<string>>();\n const componentRoots = new Map<string, TaskRow[]>();\n for (const goal of goals) {\n const root = uf.find(goal.name);\n let bucket = componentTaskIds.get(root);\n if (!bucket) {\n bucket = new Set<string>();\n componentTaskIds.set(root, bucket);\n componentRoots.set(root, []);\n }\n componentRoots.get(root)?.push(goal);\n const sub = subgraphs.get(goal.name);\n if (sub) {\n for (const id of sub) bucket.add(id);\n }\n }\n\n // 5. Compute ready counts per track.\n const readyIds = new Set(listReady(db, workstream).map((t) => t.name));\n const tracks: Track[] = [];\n for (const [root, taskIds] of componentTaskIds) {\n const trackRoots = componentRoots.get(root) ?? [];\n let readyCount = 0;\n let openCount = 0;\n let parkedCount = 0;\n for (const id of taskIds) {\n if (readyIds.has(id)) readyCount++;\n const sub = openSubstate.get(id);\n if (sub === undefined) continue;\n openCount++;\n if (sub === \"parked\") parkedCount++;\n }\n const parked = openCount > 0 && parkedCount === openCount;\n tracks.push({ roots: trackRoots, taskIds, readyCount, parked });\n }\n\n // Stable order: by primary root's localId so output is deterministic.\n tracks.sort((a, b) => {\n const an = a.roots[0]?.name ?? \"\";\n const bn = b.roots[0]?.name ?? \"\";\n return compareStrings(an, bn);\n });\n return tracks;\n}\n\nclass UnionFind {\n private readonly parent = new Map<string, string>();\n private readonly rank = new Map<string, number>();\n\n constructor(items: readonly string[]) {\n for (const item of items) {\n this.parent.set(item, item);\n this.rank.set(item, 0);\n }\n }\n\n find(x: string): string {\n let root = x;\n while (true) {\n const next = this.parent.get(root);\n if (next === undefined || next === root) break;\n root = next;\n }\n // Path compression.\n let curr = x;\n while (curr !== root) {\n const next = this.parent.get(curr);\n if (next === undefined) break;\n this.parent.set(curr, root);\n curr = next;\n }\n return root;\n }\n\n union(a: string, b: string): void {\n const rootA = this.find(a);\n const rootB = this.find(b);\n if (rootA === rootB) return;\n const rankA = this.rank.get(rootA) ?? 0;\n const rankB = this.rank.get(rootB) ?? 0;\n if (rankA < rankB) {\n this.parent.set(rootA, rootB);\n } else if (rankA > rankB) {\n this.parent.set(rootB, rootA);\n } else {\n this.parent.set(rootB, rootA);\n this.rank.set(rootA, rankA + 1);\n }\n }\n}\n","// SDK seam for `mu state` (static) and the interactive TUI.\n//\n// Both renderers (the legacy cli-table3-based static fallback in\n// src/cli/state.ts and the new ink-based TUI in src/cli/tui/) consume\n// the same WorkstreamSnapshot. Pure data + a few small derivation\n// helpers — no rendering. See design_sdk_seam in workstream `tui` for\n// the rationale (`mu task notes design_sdk_seam -w tui`).\n\nimport type { RuntimeState } from \"./agent-state.js\";\nimport { type LiveAgent, type LiveAgentsView, listLiveAgents } from \"./agents.js\";\nimport { compareStrings } from \"./compare.js\";\nimport type { Db } from \"./db.js\";\nimport { type DoctorSummary, loadDoctorSummary } from \"./doctor-summary.js\";\nimport { GLYPH } from \"./glyphs.js\";\nimport { type LogRow, listLogs } from \"./logs.js\";\nimport { activeMux } from \"./mux.js\";\nimport {\n listBlocked,\n listInProgress,\n listReady,\n listRecentClosed,\n listTasks,\n listTasksByOwner,\n type TaskRow,\n} from \"./tasks.js\";\nimport { getParallelTracks, type Track } from \"./tracks.js\";\nimport {\n type CommitSummary,\n detectBackend,\n type ProbeReport,\n type VcsBackend,\n type VcsBackendName,\n} from \"./vcs.js\";\nimport {\n decorateWithDirty,\n decorateWithStaleness,\n listWorkspaceOrphans,\n listWorkspaces,\n type WorkspaceOrphan,\n type WorkspaceRow,\n} from \"./workspace.js\";\n\n// ─── WorkstreamSnapshot ───────────────────────────────────────────\n\nexport interface RemoteWorker {\n taskName: string;\n host: string;\n path: string;\n}\n\nexport interface RemoteDispatch extends RemoteWorker {\n agentName: string;\n baseSha: string;\n}\n\nexport interface WorkstreamSnapshot {\n workstreamName: string;\n view: LiveAgentsView;\n tracks: Track[];\n ready: TaskRow[];\n inProgress: TaskRow[];\n blocked: TaskRow[];\n recentClosed: TaskRow[];\n /** OPEN/parked tasks in the workstream. The ready card names them\n * when nothing is ready, since parked work is otherwise invisible there. */\n parkedCount: number;\n /** OPEN/triage tasks: proposals (review findings) awaiting accept,\n * reject, or duplicate. Out of `ready`, so listed on their own. */\n triage: TaskRow[];\n /** Every task in the workstream, any status (a COUNT, not the rows). */\n taskCount: number;\n /** Populated only when callers explicitly pass `withAllTasks: true`.\n * The TUI dashboard fast tick leaves this empty and the all-tasks\n * popup reads its exhaustive list directly from SQLite while open. */\n allTasks: TaskRow[];\n workspaces: WorkspaceRow[];\n workspaceOrphans: WorkspaceOrphan[];\n recent: LogRow[];\n /** Last N commits from the project root (process.cwd()), populated\n * when `loadWorkstreamSnapshot` is called with withRecentCommits.\n * This is intentionally NOT a per-agent workspace log. */\n recentCommits: CommitSummary[];\n /** Backend that produced recentCommits. Null when recent commits were\n * not requested or no VCS backend was detected. */\n commitsBackend?: VcsBackendName | null;\n /** Populated when `loadWorkstreamSnapshot` is called with\n * `withDoctor: true`. Used by the TUI's slot-9 Doctor card to\n * render a glanceable health badge on the dashboard\n * (feat_card_9_doctor, workstream `tui-impl`). The static `mu\n * state` card and `mu doctor` itself don't consume it — they\n * read the textual doctor card directly. Null when not requested. */\n doctor: DoctorSummary | null;\n}\n\nexport interface LoadWorkstreamSnapshotOptions {\n /** Recent-events cap (default 200). */\n eventLimit?: number;\n /** When true, slow snapshot loading also populates `WorkspaceRow.dirty`\n * via decorateWithDirty (one `git status --porcelain` shellout per row,\n * capped at DECORATE_CONCURRENCY). The TUI caches this slow-tier value\n * and merges it into every fast SQL tick. */\n withDirty?: boolean;\n /** When true, slow snapshot loading also populates\n * `WorkstreamSnapshot.doctor` via `loadDoctorSummary`. The summary is\n * cheap SQL, but it reports tmux/workspace drift from slow-tier fields,\n * so the TUI refreshes it with the subprocess tier. */\n withDoctor?: boolean;\n /** Optional full task list for the TUI all-tasks popup. */\n withAllTasks?: true;\n /** Optional recent-project-commits slice for the TUI Commits card /\n * popup. Uses process.cwd() as the project root on purpose: the TUI\n * is launched from the project checkout, while worker workspaces live\n * elsewhere under the mu state dir. */\n withRecentCommits?: { limit: number };\n}\n\nexport interface WorkstreamSnapshotSlowFields {\n view: LiveAgentsView;\n /** Workspace rows decorated with slow-tier VCS observations\n * (`commitsBehindMain`, and `dirty` when requested). */\n workspaces: WorkspaceRow[];\n recentCommits: CommitSummary[];\n commitsBackend?: VcsBackendName | null;\n doctor: DoctorSummary | null;\n}\n\n/** Notes that may carry a REMOTE: / REMOTE_BASE: line. GLOB, not LIKE:\n * the parsers below are case-sensitive, so LIKE's case-folding only\n * fetched notes they then dropped, and GLOB's byte compare is ~2.5x\n * cheaper per note. Still one pass over the workstream's notes; no index\n * can serve a substring match, and a partial index would need a schema\n * version bump (f_remote_notes_like). */\nfunction remoteNoteRows(\n db: Db,\n workstream: string,\n taskName?: string,\n): Array<{ task_name: string; content: string }> {\n const filter = taskName === undefined ? \"\" : \" AND t.local_id = ?\";\n const params: string[] = taskName === undefined ? [workstream] : [workstream, taskName];\n return db\n .prepare(\n `SELECT t.local_id AS task_name, n.content AS content\n FROM task_notes n\n JOIN tasks t ON t.id = n.task_id\n JOIN workstreams ws ON ws.id = t.workstream_id\n WHERE ws.name = ?${filter}\n AND (n.content GLOB '*REMOTE: *' OR n.content GLOB '*REMOTE_BASE: *')\n ORDER BY n.id`,\n )\n .all(...params) as Array<{\n task_name: string;\n content: string;\n }>;\n}\n\nexport function listRemoteWorkers(db: Db, workstream: string): RemoteWorker[] {\n const remoteWorkers: RemoteWorker[] = [];\n for (const row of remoteNoteRows(db, workstream)) {\n for (const line of row.content.split(/\\r?\\n/)) {\n const match = /^REMOTE:\\s+([^:\\s]+):(\\S+)\\s*$/.exec(line);\n const host = match?.[1];\n const path = match?.[2];\n if (host !== undefined && path !== undefined) {\n remoteWorkers.push({ taskName: row.task_name, host, path });\n }\n }\n }\n return remoteWorkers;\n}\n\nexport function findRemoteDispatch(\n db: Db,\n workstream: string,\n taskName: string,\n agentName: string,\n): RemoteDispatch | undefined {\n let dispatch: RemoteDispatch | undefined;\n for (const row of remoteNoteRows(db, workstream, taskName)) {\n let location: RemoteWorker | undefined;\n let baseSha: string | undefined;\n for (const line of row.content.split(/\\r?\\n/)) {\n const remote = /^REMOTE:\\s+([^:\\s]+):(\\S+)\\s*$/.exec(line);\n if (remote?.[1] !== undefined && remote[2] !== undefined) {\n location = { taskName, host: remote[1], path: remote[2] };\n }\n const base = /^REMOTE_BASE:\\s+([^:\\s]+):(\\S+)\\s*$/.exec(line);\n if (base?.[1] === agentName && base[2] !== undefined) baseSha = base[2];\n }\n if (location !== undefined && baseSha !== undefined) {\n dispatch = { ...location, agentName, baseSha };\n }\n }\n return dispatch;\n}\n\n/**\n * Fast TUI/state snapshot tier: pure SQLite reads only. Subprocess-backed\n * fields are intentionally empty placeholders so callers can merge the last\n * slow-tier values without blocking a 1s render tick on tmux or VCS probes.\n */\nexport async function loadWorkstreamSnapshotFast(\n db: Db,\n workstream: string,\n opts: LoadWorkstreamSnapshotOptions = {},\n): Promise<WorkstreamSnapshot> {\n const eventLimit = opts.eventLimit ?? 200;\n return {\n workstreamName: workstream,\n view: emptyLiveAgentsView(),\n tracks: getParallelTracks(db, workstream),\n ready: listReady(db, workstream).sort(byRoiDesc),\n inProgress: listInProgress(db, workstream),\n blocked: listBlocked(db, workstream),\n recentClosed: listRecentClosed(db, workstream),\n parkedCount: listTasks(db, workstream, { status: \"OPEN\", substate: \"parked\" }).length,\n triage: listTasks(db, workstream, { status: \"OPEN\", substate: \"triage\" }),\n taskCount: (\n db\n .prepare(\n \"SELECT count(*) AS n FROM tasks t JOIN workstreams w ON w.id = t.workstream_id WHERE w.name = ?\",\n )\n .get(workstream) as { n: number }\n ).n,\n allTasks: opts.withAllTasks === true ? listTasks(db, workstream) : [],\n workspaces: listWorkspaces(db, workstream),\n workspaceOrphans: listWorkspaceOrphans(db, workstream),\n // v2-retire-log-shim: this used to filter `kind: \"event\"` — the\n // prose breadcrumbs. Those are gone, so the Recent card reads every\n // op for the workstream. Payloads are raw JSON for captured ops\n // until v2-log-verb renders them from `intent`; the card stays\n // populated in the meantime rather than going silently empty.\n recent: listLogs(db, { workstream, limit: eventLimit }),\n recentCommits: [],\n commitsBackend: null,\n doctor: null,\n };\n}\n\n/**\n * Slow snapshot tier: fields backed by tmux / VCS subprocess probes (plus\n * doctor, which reports over those slow-tier observations). Returns only the\n * fields the fast snapshot deliberately leaves empty or undecorated.\n *\n * The slow snapshot tier runs full reconciliation: missing panes are\n * reaped, while mid-spawn placeholders remain protected by the prune\n * loop's pending-pane guard.\n */\nexport async function loadWorkstreamSnapshotSlow(\n db: Db,\n workstream: string,\n opts: LoadWorkstreamSnapshotOptions = {},\n baseSnapshot?: WorkstreamSnapshot,\n): Promise<WorkstreamSnapshotSlowFields> {\n const view = await listLiveAgents(db, { workstream });\n // commitsBehindMain is a VCS subprocess probe, so it belongs to this\n // tier; the fast tier's listWorkspaces rows never carry it.\n let workspaces = await decorateWithStaleness(listWorkspaces(db, workstream));\n if (opts.withDirty === true) workspaces = await decorateWithDirty(workspaces);\n const commits = await loadRecentCommits(opts.withRecentCommits);\n const slow: WorkstreamSnapshotSlowFields = {\n view,\n workspaces,\n recentCommits: commits.items,\n commitsBackend: commits.backend,\n doctor: null,\n };\n if (opts.withDoctor === true) {\n const mux = await activeMux();\n slow.doctor = loadDoctorSummary(\n db,\n mergeSnapshotFastSlow(baseSnapshot ?? minimalSnapshot(workstream), slow),\n mux.paneStatus === undefined ? \"murmur\" : \"herdr\",\n );\n }\n return slow;\n}\n\n/** Merge the latest slow-tier subprocess observations into a fresh fast tier. */\nexport function mergeSnapshotFastSlow(\n fast: WorkstreamSnapshot,\n slow: WorkstreamSnapshotSlowFields | null,\n): WorkstreamSnapshot {\n if (slow === null) return fast;\n return {\n ...fast,\n view: slow.view,\n workspaces: mergeWorkspaceSlowFields(fast.workspaces, slow.workspaces),\n recentCommits: slow.recentCommits,\n commitsBackend: slow.commitsBackend ?? null,\n doctor: slow.doctor,\n };\n}\n\n/**\n * Back-compat wrapper for non-TUI callers: return the historical union shape\n * by composing the new fast SQL tier with one slow subprocess tier.\n */\nexport async function loadWorkstreamSnapshot(\n db: Db,\n workstream: string,\n opts: LoadWorkstreamSnapshotOptions = {},\n): Promise<WorkstreamSnapshot> {\n const fast = await loadWorkstreamSnapshotFast(db, workstream, opts);\n const slow = await loadWorkstreamSnapshotSlow(db, workstream, opts, fast);\n return mergeSnapshotFastSlow(fast, slow);\n}\n\nfunction emptyLiveAgentsView(): LiveAgentsView {\n return {\n agents: [],\n orphans: [],\n report: { prunedGhosts: 0, orphans: [], mode: \"full\" },\n };\n}\n\nfunction minimalSnapshot(workstream: string): WorkstreamSnapshot {\n return {\n workstreamName: workstream,\n view: emptyLiveAgentsView(),\n tracks: [],\n ready: [],\n inProgress: [],\n blocked: [],\n recentClosed: [],\n parkedCount: 0,\n triage: [],\n taskCount: 0,\n allTasks: [],\n workspaces: [],\n workspaceOrphans: [],\n recent: [],\n recentCommits: [],\n commitsBackend: null,\n doctor: null,\n };\n}\n\nfunction mergeWorkspaceSlowFields(\n fastRows: readonly WorkspaceRow[],\n slowRows: readonly WorkspaceRow[],\n): WorkspaceRow[] {\n const slowByAgent = new Map(slowRows.map((row) => [row.agentName, row]));\n return fastRows.map((fast) => {\n const slow = slowByAgent.get(fast.agentName);\n if (slow === undefined) return fast;\n return {\n ...fast,\n commitsBehindMain: slow.commitsBehindMain ?? fast.commitsBehindMain,\n dirty: slow.dirty,\n };\n });\n}\n\n/** Backends detected for `withRecentCommits`, per project root. Detection\n * spawns up to 4 processes (jj, sl x2, git) and the answer cannot change\n * while the TUI polls the same cwd every 10 s. `none` is not cached so a\n * later `git init` is still noticed; nor is a detection during which a\n * root probe failed indeterminately. Only this path reads the cache; the\n * one-shot `mu state` never asks for commits. */\nconst recentCommitsBackends = new Map<string, VcsBackend>();\n\n/** Test hook: forget cached backends. */\nexport function resetRecentCommitsBackendCacheForTests(): void {\n recentCommitsBackends.clear();\n}\n\nasync function loadRecentCommits(\n opt: LoadWorkstreamSnapshotOptions[\"withRecentCommits\"],\n): Promise<{ backend: VcsBackendName | null; items: CommitSummary[] }> {\n if (opt === undefined) return { backend: null, items: [] };\n const projectRoot = process.cwd();\n let backend = recentCommitsBackends.get(projectRoot);\n if (backend === undefined) {\n const report: ProbeReport = { failed: false };\n backend = await detectBackend(projectRoot, report);\n // A probe that failed (rather than cleanly answering \"not this VCS\")\n // may have hidden a higher-precedence backend; re-detect next tick.\n if (backend.name !== \"none\" && !report.failed) recentCommitsBackends.set(projectRoot, backend);\n }\n if (backend.name === \"none\") return { backend: null, items: [] };\n return { backend: backend.name, items: await backend.recentCommits(projectRoot, opt.limit) };\n}\n\n// ─── ROI helpers ───────────────────────────────────────────────────\n\n/**\n * ROI tiers used to colour task rows. Pure: returns the bucket name; the\n * consumer maps bucket → picocolors function (or ink text colour).\n * Magic numbers (≥100 high, ≥50 mid) lifted from the previous HUD impl.\n */\nexport type RoiBucket = \"high\" | \"mid\" | \"low\" | \"infinite\";\n\nexport function roiBucket(impact: number, effortDays: number): RoiBucket {\n const r = effortDays > 0 ? impact / effortDays : Number.POSITIVE_INFINITY;\n if (!Number.isFinite(r)) return \"infinite\";\n if (r >= 100) return \"high\";\n if (r >= 50) return \"mid\";\n return \"low\";\n}\n\n/** ROI sort comparator (descending). Used by loadWorkstreamSnapshot.ready. */\nfunction byRoiDesc(a: TaskRow, b: TaskRow): number {\n const ra = a.effortDays > 0 ? a.impact / a.effortDays : Number.POSITIVE_INFINITY;\n const rb = b.effortDays > 0 ? b.impact / b.effortDays : Number.POSITIVE_INFINITY;\n if (rb !== ra) return rb - ra;\n if (a.effortDays !== b.effortDays) return a.effortDays - b.effortDays;\n return compareStrings(a.name, b.name);\n}\n\n// ─── Agent helpers ─────────────────────────────────────────────────\n\n/** Histogram of agents by runtime state. Pure derivation (no colour render). */\nexport function agentStateHistogram(\n agents: readonly LiveAgent[],\n): ReadonlyMap<RuntimeState, number> {\n const out = new Map<RuntimeState, number>();\n for (const a of agents) {\n out.set(a.state, (out.get(a.state) ?? 0) + 1);\n }\n return out;\n}\n\n// ─── Task helpers ──────────────────────────────────────────────────\n\nexport interface OwnedTasksSummary {\n /** Display token: \"—\" (none), task id (one), or GLYPH.multi + count (many). */\n bit: string;\n /** Underlying count for callers that want their own format. */\n count: number;\n /** The single owned task's local id, when count===1. */\n onlyTaskId?: string;\n}\n\n/**\n * Per-agent task summary: condensed display token + raw count. Used by\n * both the static Agents table and the ink Agents card. Pure on the\n * input rows — caller (e.g. loadWorkstreamSnapshot consumer) does the\n * listTasksByOwner query upstream and feeds the rows in.\n */\nexport function summarizeOwnedTasks(owned: readonly TaskRow[]): OwnedTasksSummary {\n const count = owned.length;\n if (count === 0) return { bit: \"—\", count: 0 };\n if (count === 1) {\n const only = owned[0];\n if (!only) return { bit: \"—\", count: 0 };\n return { bit: only.name, count: 1, onlyTaskId: only.name };\n }\n return { bit: `${GLYPH.multi}${count}`, count };\n}\n\n// Re-export for convenience: callers wanting to combine listTasksByOwner\n// with summarizeOwnedTasks in one import.\nexport { listTasksByOwner };\n"],"mappings":"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","names":["str","pad","text","options","str","stylize","builder","colors","style","sequencer","map","Table","str","process","resolve","resolve","out","panes","delay","PANE_ID_RE","isValidPaneId","assertValidPaneId","realExecutor","currentExecutor","listSessions","sessionExists","newSession","appendEnvFlags","newSessionWithPane","killSession","listWindows","newWindow","selectLayout","listPanesInSession","listPanes","panes","splitWindow","killPane","paneExists","paneTTY","lockPaneTitle","setPaneTitle","getPaneTitle","currentAgentName","currentSessionName","defaultUndeliveredWarning","sendToPane","capturePane","enableMuPaneBordersForSession","enableMuPaneBordersForPane","attachHint","attachCommands","paneNotFoundNextSteps","healthCheck","dirname","existsSync","homedir","join","existsSync","dirname","resolve","execFile","existsSync","rmSync","statSync","dirname","resolve","promisify","picocolors","tableUtils","sep","Table","join","rowFromDb","workspacePath","join","existsSync","rmSync","resolve","existsSync","join","execFile","rmSync","dirname","workspacePath","execFile","dirname","rmSync","fields","existsSync","workspacePath","fields","join","existsSync","join","existsSync","workspacePath","join","existsSync","existsSync","workspacePath","existsSync","existsSync","workspacePath","BACKENDS","resolve","existsSync","rmSync","rowFromDb","listWorkspaces","rows","cached","join","listWorkspaces","join","rowFromDb","rowFromDb","live","existsSync","readdirSync","dirname","join","live","listWorkspaces","join","existsSync","readdirSync","dirname","row","changedFields","track","join","join","envVarNameForCli","promisify","execFile","existsSync","dirname","resolve","statSync","rmSync","workspacePath","dirname","existsSync","fields","join","homedir","existsSync","resolve","ageMs","snapshot","snap","realExecutor","currentExecutor","currentWaitSleep","resolve","resolve","currentWaitSleep","rowFromDb","rows","dirname","live","import_picocolors","pc","existsSync","mkdirSync","rmSync","statSync","dirname","existsSync","mkdirSync","dirname","rmSync","statSync","rmSync","join","join","live","rmSync","existsSync","resolve","existsSync","mkdirSync","readFileSync","rmSync","homedir","dirname","join","resolve","accessSync","constants","existsSync","readFileSync","realpathSync","delimiter","dirname","join","fileURLToPath","snapshot","delimiter","join","accessSync","constants","realpathSync","dirname","existsSync","readFileSync","fileURLToPath","listWorkspaces"]}