octomux 1.0.31 → 1.0.32

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.
package/README.md CHANGED
@@ -110,17 +110,17 @@ DISPATCH → BRANCH → CODE → INBOX → REVIEW → MERGE
110
110
 
111
111
  ## CLI
112
112
 
113
- | Command | Description |
114
- | ------------------------------------ | -------------------------------------------------------- |
115
- | `octomux start` | Dashboard at `:7777` |
116
- | `octomux init` | Defaults wizard (Jira, base branch, harness prefs) |
117
- | `octomux create-task` | New task (`--harness cursor` optional) |
118
- | `octomux list-tasks` / `get-task` | Inspect tasks |
119
- | `octomux close-task` / `delete-task` | Stop or fully remove |
120
- | `octomux resume-task` | Resume a closed task |
121
- | `octomux add-agent` | Another agent window (`--skeleton`, `--model` optional) |
122
- | `octomux send-message` | Message a running agent — course-correct without restart |
123
- | `octomux team run` / `schedule` / `list` | Run or schedule an agent crew from `.octomux/team.yaml` |
113
+ | Command | Description |
114
+ | ---------------------------------------- | -------------------------------------------------------- |
115
+ | `octomux start` | Dashboard at `:7777` |
116
+ | `octomux init` | Defaults wizard (Jira, base branch, harness prefs) |
117
+ | `octomux create-task` | New task (`--harness cursor` optional) |
118
+ | `octomux list-tasks` / `get-task` | Inspect tasks |
119
+ | `octomux close-task` / `delete-task` | Stop or fully remove |
120
+ | `octomux resume-task` | Resume a closed task |
121
+ | `octomux add-agent` | Another agent window (`--skeleton`, `--model` optional) |
122
+ | `octomux send-message` | Message a running agent — course-correct without restart |
123
+ | `octomux team run` / `schedule` / `list` | Run or schedule an agent crew from `.octomux/team.yaml` |
124
124
 
125
125
  ## Architecture
126
126
 
package/bin/octomux.js CHANGED
@@ -3,6 +3,7 @@
3
3
  import { execFileSync, exec as execCb } from 'child_process';
4
4
  import { readFileSync, existsSync, mkdirSync, readdirSync, cpSync, rmSync } from 'fs';
5
5
  import { fileURLToPath } from 'url';
6
+ import { createRequire } from 'module';
6
7
  import path from 'path';
7
8
  import os from 'os';
8
9
 
@@ -26,6 +27,24 @@ if (command === 'start') {
26
27
  await import('../cli/dist/index.js');
27
28
  }
28
29
 
30
+ // ─── tmux binary resolver ────────────────────────────────────────────────────
31
+ // Mirrors the resolution logic in server/tmux-bin.ts (kept in sync manually).
32
+ // Uses createRequire so the optional CJS package can be loaded from ESM context.
33
+
34
+ const _require = createRequire(import.meta.url);
35
+
36
+ function resolveTmuxBin() {
37
+ if (process.env.OCTOMUX_TMUX_BIN) return process.env.OCTOMUX_TMUX_BIN;
38
+ try {
39
+ const pkg = `@octomux/tmux-${process.platform}-${process.arch}`;
40
+ const { tmuxBin } = _require(pkg);
41
+ if (tmuxBin) return tmuxBin;
42
+ } catch {
43
+ /* not installed yet — fall back to PATH */
44
+ }
45
+ return 'tmux';
46
+ }
47
+
29
48
  // ─── start command ───────────────────────────────────────────────────────────
30
49
 
31
50
  async function runStart(startArgs) {
@@ -61,8 +80,16 @@ async function runStart(startArgs) {
61
80
  // Preflight: warn about missing tools (install from dashboard Setup — no blocking exit)
62
81
  const { warnBinary, checkNeovimVersion } = await import('../dist-server/startup.js');
63
82
 
83
+ const resolvedTmux = resolveTmuxBin();
64
84
  const preflight = [
65
- { cmd: 'tmux', checkArgs: ['-V'], brewPkg: 'tmux' },
85
+ {
86
+ cmd: resolvedTmux,
87
+ checkArgs: ['-V'],
88
+ name: 'tmux',
89
+ // No brewPkg — tmux is bundled via @octomux/tmux-<platform>-<arch>.
90
+ // If the bundled package isn't available and PATH tmux is also missing,
91
+ // the bundled binary isn't available for this platform/arch and PATH tmux is also missing.
92
+ },
66
93
  { cmd: 'git', checkArgs: ['--version'], brewPkg: 'git' },
67
94
  {
68
95
  cmd: 'claude',
@@ -1 +1 @@
1
- import{a,b,c,d,e,f,g,h}from"./chunk-OCUH4C35.js";export{f as createAgent,h as deleteAgent,c as getAgent,a as isBuiltInAgent,b as listAgents,e as resetAgent,d as saveAgent,g as syncAgents};
1
+ import{a,b,c,d,e,f,g,h}from"./chunk-F5R6D6FU.js";export{f as createAgent,h as deleteAgent,c as getAgent,a as isBuiltInAgent,b as listAgents,e as resetAgent,d as saveAgent,g as syncAgents};
@@ -1 +1 @@
1
- import{a as s}from"./chunk-G45FZHCE.js";import{d as a}from"./chunk-CVVNVVF6.js";var g=["Bash(git push --force:*)","Bash(git reset --hard:*)","Bash(rm -rf:*)"],e=["Bash(cat:*)","Bash(cd:*)","Bash(echo:*)","Bash(env:*)","Bash(find:*)","Bash(grep:*)","Bash(head:*)","Bash(jq:*)","Bash(ls:*)","Bash(lsof:*)","Bash(pwd:*)","Bash(rg:*)","Bash(sed:*)","Bash(sort:*)","Bash(sqlite3:*)","Bash(stat:*)","Bash(tail:*)","Bash(tree:*)","Bash(wc:*)","Bash(which:*)","Bash(xargs:*)","Bash(bun:*)","Bash(bunx:*)","Bash(go:*)","Bash(node:*)","Bash(npx:*)","Bash(npm:*)","Bash(python3:*)","Bash(tsc:*)","Bash(vitest:*)","Bash(playwright:*)","Bash(git add:*)","Bash(git branch:*)","Bash(git checkout:*)","Bash(git diff:*)","Bash(git log:*)","Bash(git pull:*)","Bash(git push:*)","Bash(git stash:*)","Bash(git status:*)","Bash(git show:*)","Bash(git rev-parse:*)","Bash(git worktree:*)","Bash(git ls-remote:*)","Bash(git remote:*)","Bash(git fetch:*)","Bash(git merge:*)","Bash(git rebase:*)","Bash(git cherry-pick:*)","Bash(git tag:*)","Bash(gh issue:*)","Bash(gh api:*)","Bash(gh repo view:*)","Bash(gh pr view:*)","Bash(gh pr list:*)","Bash(cp:*)","Bash(mkdir:*)","Bash(chmod:*)","Bash(touch:*)","Bash(mv:*)","Bash(curl:*)","Bash(for:*)","ExitPlanMode","AskUserQuestion","mcp__plugin_atlassian_atlassian__getJiraIssue","mcp__plugin_atlassian_atlassian__searchJiraIssuesUsingJql","mcp__plugin_atlassian_atlassian__getVisibleJiraProjects","mcp__plugin_atlassian_atlassian__getConfluencePage","mcp__plugin_atlassian_atlassian__searchConfluenceUsingCql","mcp__plugin_atlassian_atlassian__searchAtlassian","mcp__plugin_playwright_playwright__browser_click","mcp__plugin_playwright_playwright__browser_close","mcp__plugin_playwright_playwright__browser_console_messages","mcp__plugin_playwright_playwright__browser_evaluate","mcp__plugin_playwright_playwright__browser_fill_form","mcp__plugin_playwright_playwright__browser_navigate","mcp__plugin_playwright_playwright__browser_run_code","mcp__plugin_playwright_playwright__browser_snapshot","mcp__plugin_playwright_playwright__browser_take_screenshot","mcp__plugin_playwright_playwright__browser_type"];async function l(h,_="claude-code",i=""){await a(_).installHooks(h,s(),i)}export{g as a,e as b,l as c};
1
+ import{a as s}from"./chunk-G45FZHCE.js";import{g as a}from"./chunk-72XPVTY6.js";var g=["Bash(git push --force:*)","Bash(git reset --hard:*)","Bash(rm -rf:*)"],e=["Bash(cat:*)","Bash(cd:*)","Bash(echo:*)","Bash(env:*)","Bash(find:*)","Bash(grep:*)","Bash(head:*)","Bash(jq:*)","Bash(ls:*)","Bash(lsof:*)","Bash(pwd:*)","Bash(rg:*)","Bash(sed:*)","Bash(sort:*)","Bash(sqlite3:*)","Bash(stat:*)","Bash(tail:*)","Bash(tree:*)","Bash(wc:*)","Bash(which:*)","Bash(xargs:*)","Bash(bun:*)","Bash(bunx:*)","Bash(go:*)","Bash(node:*)","Bash(npx:*)","Bash(npm:*)","Bash(python3:*)","Bash(tsc:*)","Bash(vitest:*)","Bash(playwright:*)","Bash(git add:*)","Bash(git branch:*)","Bash(git checkout:*)","Bash(git diff:*)","Bash(git log:*)","Bash(git pull:*)","Bash(git push:*)","Bash(git stash:*)","Bash(git status:*)","Bash(git show:*)","Bash(git rev-parse:*)","Bash(git worktree:*)","Bash(git ls-remote:*)","Bash(git remote:*)","Bash(git fetch:*)","Bash(git merge:*)","Bash(git rebase:*)","Bash(git cherry-pick:*)","Bash(git tag:*)","Bash(gh issue:*)","Bash(gh api:*)","Bash(gh repo view:*)","Bash(gh pr view:*)","Bash(gh pr list:*)","Bash(cp:*)","Bash(mkdir:*)","Bash(chmod:*)","Bash(touch:*)","Bash(mv:*)","Bash(curl:*)","Bash(for:*)","ExitPlanMode","AskUserQuestion","mcp__plugin_atlassian_atlassian__getJiraIssue","mcp__plugin_atlassian_atlassian__searchJiraIssuesUsingJql","mcp__plugin_atlassian_atlassian__getVisibleJiraProjects","mcp__plugin_atlassian_atlassian__getConfluencePage","mcp__plugin_atlassian_atlassian__searchConfluenceUsingCql","mcp__plugin_atlassian_atlassian__searchAtlassian","mcp__plugin_playwright_playwright__browser_click","mcp__plugin_playwright_playwright__browser_close","mcp__plugin_playwright_playwright__browser_console_messages","mcp__plugin_playwright_playwright__browser_evaluate","mcp__plugin_playwright_playwright__browser_fill_form","mcp__plugin_playwright_playwright__browser_navigate","mcp__plugin_playwright_playwright__browser_run_code","mcp__plugin_playwright_playwright__browser_snapshot","mcp__plugin_playwright_playwright__browser_take_screenshot","mcp__plugin_playwright_playwright__browser_type"];async function l(h,_="claude-code",i=""){await a(_).installHooks(h,s(),i)}export{g as a,e as b,l as c};
@@ -1,2 +1,2 @@
1
- import $ from"crypto";import g from"fs";import d from"path";var p=/^[A-Za-z0-9_-]{1,64}$/,O=/[`;|&><\n\r]|\$\(/;function c(s){if(!p.test(s))throw new Error(`Invalid agent name: ${JSON.stringify(s)}. Must match ${p}`);return s}function u(s,n){if(typeof s!="string")throw new Error(`Invalid ${n}: must be a string`);let e=s.trim();if(O.test(e))throw new Error(`Invalid ${n}: contains forbidden shell metacharacter (one of \` ; | & > < $( or newline)`);let t=(e.match(/'/g)??[]).length,o=(e.match(/"/g)??[]).length;if(t%2!==0||o%2!==0)throw new Error(`Invalid ${n}: unbalanced quotes`);return e}function m(s,n){return n?`${s.replace(/\s*--model\s+\S+/g,"")} --model ${n}`:s}function P(s,n){let e=t=>`${s}/api/hooks/${t}?token=${encodeURIComponent(n)}`;return{UserPromptSubmit:[{hooks:[{type:"http",url:e("user-prompt-submit"),timeout:5}]}],PermissionRequest:[{hooks:[{type:"http",url:e("permission-request"),timeout:5}]}],PostToolUse:[{hooks:[{type:"http",url:e("post-tool-use"),timeout:5}]}],Stop:[{hooks:[{type:"http",url:e("stop"),timeout:5}]}]}}var C={id:"claude-code",displayName:"Claude Code",sessionIdMode:"orchestrator-assigned",newSessionId(){return $.randomUUID()},buildLaunchCommand({sessionId:s,agent:n,flags:e="",model:t}){let o=n?` --agent ${c(n)}`:"",i=m(e,t);return`claude${o} --session-id ${s}${i}`},buildResumeCommand({sessionId:s,flags:n="",model:e}){let t=m(n,e);return`claude --resume ${s}${t}`},buildContinueCommand({sessionId:s,flags:n="",model:e}){let t=m(n,e);return`claude --continue --session-id ${s}${t}`},async installHooks(s,n,e){let{ALLOWED_TOOLS:t,DENIED_TOOLS:o}=await import("./hook-settings-L5RLGF4W.js"),i=d.join(s,".claude"),l=d.join(i,"settings.local.json");g.mkdirSync(i,{recursive:!0});let r={};try{let v=g.readFileSync(l,"utf-8");r=JSON.parse(v),(typeof r!="object"||r===null||Array.isArray(r))&&(r={})}catch{r={}}let y={...typeof r.hooks=="object"&&r.hooks!==null&&!Array.isArray(r.hooks)?r.hooks:{},...P(n,e)},a=typeof r.permissions=="object"&&r.permissions!==null&&!Array.isArray(r.permissions)?r.permissions:{},f=Array.isArray(a.allow)?a.allow:[],h=[...new Set([...t,...f])],w=Array.isArray(a.deny)?a.deny:[],k=[...new Set([...o,...w])],S={...a,allow:h,deny:k},A={...r,permissions:S,hooks:y};g.writeFileSync(l,JSON.stringify(A,null,2)+`
2
- `)},async syncAgents(s){let{listAgents:n,getAgent:e}=await import("./agents-JPRPV2IY.js"),t=d.join(s,".claude","agents");await g.promises.mkdir(t,{recursive:!0});let o=await n();for(let i of o){let l=await e(i.name);await g.promises.writeFile(d.join(t,`${i.name}.md`),l.content,"utf-8")}},resolveFlags(s){let n=process.env.OCTOMUX_CLAUDE_FLAGS?.trim();if(n)return` ${u(n,"OCTOMUX_CLAUDE_FLAGS")}`;let e=s.harnesses?.["claude-code"]??{},t=[];return e.dangerouslySkipPermissions&&t.push("--dangerously-skip-permissions"),e.flags&&t.push(u(e.flags,"harnesses.claude-code.flags")),t.length>0?` ${t.join(" ")}`:""},validateSettings(s){if(typeof s!="object"||s===null||Array.isArray(s))throw new Error("Invalid claude-code settings: expected object");let n=s,e={};if(n.flags!==void 0&&(e.flags=u(n.flags,"harnesses.claude-code.flags")),n.dangerouslySkipPermissions!==void 0){if(typeof n.dangerouslySkipPermissions!="boolean")throw new Error("Invalid claude-code.dangerouslySkipPermissions: expected boolean");e.dangerouslySkipPermissions=n.dangerouslySkipPermissions}return e},validateAgentName(s){return c(s)}};export{c as a,u as b,C as c};
1
+ import $ from"crypto";import g from"fs";import d from"path";var p=/^[A-Za-z0-9_-]{1,64}$/,O=/[`;|&><\n\r]|\$\(/;function c(s){if(!p.test(s))throw new Error(`Invalid agent name: ${JSON.stringify(s)}. Must match ${p}`);return s}function u(s,n){if(typeof s!="string")throw new Error(`Invalid ${n}: must be a string`);let e=s.trim();if(O.test(e))throw new Error(`Invalid ${n}: contains forbidden shell metacharacter (one of \` ; | & > < $( or newline)`);let t=(e.match(/'/g)??[]).length,o=(e.match(/"/g)??[]).length;if(t%2!==0||o%2!==0)throw new Error(`Invalid ${n}: unbalanced quotes`);return e}function m(s,n){return n?`${s.replace(/\s*--model\s+\S+/g,"")} --model ${n}`:s}function P(s,n){let e=t=>`${s}/api/hooks/${t}?token=${encodeURIComponent(n)}`;return{UserPromptSubmit:[{hooks:[{type:"http",url:e("user-prompt-submit"),timeout:5}]}],PermissionRequest:[{hooks:[{type:"http",url:e("permission-request"),timeout:5}]}],PostToolUse:[{hooks:[{type:"http",url:e("post-tool-use"),timeout:5}]}],Stop:[{hooks:[{type:"http",url:e("stop"),timeout:5}]}]}}var C={id:"claude-code",displayName:"Claude Code",sessionIdMode:"orchestrator-assigned",newSessionId(){return $.randomUUID()},buildLaunchCommand({sessionId:s,agent:n,flags:e="",model:t}){let o=n?` --agent ${c(n)}`:"",i=m(e,t);return`claude${o} --session-id ${s}${i}`},buildResumeCommand({sessionId:s,flags:n="",model:e}){let t=m(n,e);return`claude --resume ${s}${t}`},buildContinueCommand({sessionId:s,flags:n="",model:e}){let t=m(n,e);return`claude --continue --session-id ${s}${t}`},async installHooks(s,n,e){let{ALLOWED_TOOLS:t,DENIED_TOOLS:o}=await import("./hook-settings-BSWHE3FL.js"),i=d.join(s,".claude"),l=d.join(i,"settings.local.json");g.mkdirSync(i,{recursive:!0});let r={};try{let v=g.readFileSync(l,"utf-8");r=JSON.parse(v),(typeof r!="object"||r===null||Array.isArray(r))&&(r={})}catch{r={}}let y={...typeof r.hooks=="object"&&r.hooks!==null&&!Array.isArray(r.hooks)?r.hooks:{},...P(n,e)},a=typeof r.permissions=="object"&&r.permissions!==null&&!Array.isArray(r.permissions)?r.permissions:{},f=Array.isArray(a.allow)?a.allow:[],h=[...new Set([...t,...f])],w=Array.isArray(a.deny)?a.deny:[],k=[...new Set([...o,...w])],S={...a,allow:h,deny:k},A={...r,permissions:S,hooks:y};g.writeFileSync(l,JSON.stringify(A,null,2)+`
2
+ `)},async syncAgents(s){let{listAgents:n,getAgent:e}=await import("./agents-XWAPBJ6K.js"),t=d.join(s,".claude","agents");await g.promises.mkdir(t,{recursive:!0});let o=await n();for(let i of o){let l=await e(i.name);await g.promises.writeFile(d.join(t,`${i.name}.md`),l.content,"utf-8")}},resolveFlags(s){let n=process.env.OCTOMUX_CLAUDE_FLAGS?.trim();if(n)return` ${u(n,"OCTOMUX_CLAUDE_FLAGS")}`;let e=s.harnesses?.["claude-code"]??{},t=[];return e.dangerouslySkipPermissions&&t.push("--dangerously-skip-permissions"),e.flags&&t.push(u(e.flags,"harnesses.claude-code.flags")),t.length>0?` ${t.join(" ")}`:""},validateSettings(s){if(typeof s!="object"||s===null||Array.isArray(s))throw new Error("Invalid claude-code settings: expected object");let n=s,e={};if(n.flags!==void 0&&(e.flags=u(n.flags,"harnesses.claude-code.flags")),n.dangerouslySkipPermissions!==void 0){if(typeof n.dangerouslySkipPermissions!="boolean")throw new Error("Invalid claude-code.dangerouslySkipPermissions: expected boolean");e.dangerouslySkipPermissions=n.dangerouslySkipPermissions}return e},validateAgentName(s){return c(s)}};export{c as a,u as b,C as c};
@@ -0,0 +1,16 @@
1
+ import{a as g}from"./chunk-GAXJZSQT.js";import{a as D,b as w,c as p}from"./chunk-5XTSTJXV.js";import{a as x}from"./chunk-E5HYNQ6D.js";import q from"crypto";import i from"fs";import m from"path";import{fileURLToPath as z}from"url";import{execFile as I}from"child_process";import{promisify as N}from"util";import{createRequire as _}from"module";import l from"path";import U from"os";import v from"fs";import{fileURLToPath as B}from"url";var S=x("tmux-bin"),M=N(I),J=l.dirname(B(import.meta.url)),W=process.env.NODE_ENV==="production",V=l.join(U.homedir(),".octomux"),X=l.join(J,"..","data"),E=W?V:X,d=null;function T(){if(d)return d;if(process.env.OCTOMUX_TMUX_BIN){let n=process.env.OCTOMUX_TMUX_BIN,t=g({cmd:n,checkArgs:["-V"]}).ok;return d={path:n,source:"env",verified:t},S.debug({path:n,source:"env",verified:t},"tmux resolved via env override"),d}let r=process.resourcesPath;if(process.versions.electron&&r)try{let n=process.platform,t=process.arch,o=`@octomux/tmux-${n}-${t}`,s=l.join(r,"app.asar.unpacked","node_modules",o),c=l.join(s,"index.js");if(v.existsSync(c)){let a=_(c)(c);if(a.tmuxBin&&v.existsSync(a.tmuxBin)){let f=g({cmd:a.tmuxBin,checkArgs:["-V"]}).ok;return d={path:a.tmuxBin,source:"bundled",verified:f,terminfoDir:a.terminfoDir},S.debug({path:a.tmuxBin,source:"bundled",verified:f,terminfoDir:a.terminfoDir,electron:!0},"tmux resolved via packaged Electron asar.unpacked"),d}}}catch{}try{let n=process.platform,t=process.arch,o=`@octomux/tmux-${n}-${t}`,c=_(import.meta.url)(o);if(c.tmuxBin){let u=g({cmd:c.tmuxBin,checkArgs:["-V"]}).ok;return d={path:c.tmuxBin,source:"bundled",verified:u,terminfoDir:c.terminfoDir},S.debug({path:c.tmuxBin,source:"bundled",verified:u,terminfoDir:c.terminfoDir},"tmux resolved via bundled package"),d}}catch{}let e=g({cmd:"tmux",checkArgs:["-V"]}).ok;return d={path:"tmux",source:"path",verified:e},S.debug({source:"path",verified:e},"tmux resolved via PATH fallback"),d}function A(){return T().path}function O(){return["-S",l.join(E,"run","tmux.sock")]}function P(r=process.env){let{terminfoDir:e}=T();return e?{...r,TERMINFO_DIRS:`${e}:${r.TERMINFO_DIRS??""}`}:{...r}}async function R(r,e){let n=A(),t=[...O(),...r],o=P();return M(n,t,{...e,env:o})}function pr(r){return{file:A(),args:[...O(),...r],env:P()}}var b=!1;function gr(){if(b)return;let r=l.join(E,"run");v.mkdirSync(r,{recursive:!0}),b=!0}function j(r){return`'${r.replace(/'/g,"'\\''")}'`}var h=x("harness:cursor"),Z="composer-2.5",Q=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;function H(r){let e=r.trim();if(!Q.test(e))throw new Error(`Invalid harnesses.cursor.model: ${JSON.stringify(r)}. Use an id from cursor-agent --list-models`);return e}var L="octomux-agent-",G=/trust this (?:workspace|folder)|do you trust/i,K=200,$=5e3;function C(r){return` --workspace ${j(r)}`}function Y(r){let e=r.match(/^---\s*\n([\s\S]*?)\n---\s*\n?([\s\S]*)$/);if(!e)return{fm:{},body:r.trim()};let n={};for(let t of e[1].split(`
2
+ `)){let o=t.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);if(!o)continue;let s=o[2].trim();(s.startsWith('"')&&s.endsWith('"')||s.startsWith("'")&&s.endsWith("'"))&&(s=s.slice(1,-1)),n[o[1]]=s}return{fm:n,body:e[2].trim()}}function rr(r,e){let{fm:n,body:t}=Y(e),o=n.description||n.name?[n.description,n.name===r?void 0:n.name].filter(Boolean).join(" \xB7 "):"",s=o.trim()?o:`Octomux agent (${r})`;return`---
3
+ description: ${JSON.stringify(s)}
4
+ alwaysApply: false
5
+ ---
6
+
7
+ <!--
8
+ Synced from octomux agent definitions for Cursor CLI sessions in this workspace.
9
+ Personas mirror Claude Code --agent presets; edit definitions under Settings \u2192 Agents.
10
+ Harness \u2192 Cursor lets you append CLI flags (--resume, --model, etc.).
11
+ -->
12
+
13
+ ${t}
14
+ `}function er(r){if(i.existsSync(r))for(let e of i.readdirSync(r,{withFileTypes:!0}))e.isFile()&&e.name.startsWith(L)&&(e.name.endsWith(".mdc")||e.name.endsWith(".md"))&&i.unlinkSync(m.join(r,e.name))}function nr(r){let e={command:r,type:"command",timeout:5};return JSON.stringify({version:1,hooks:{sessionStart:[e],beforeSubmitPrompt:[e],beforeShellExecution:[e],postToolUse:[e],afterFileEdit:[e]}},null,2)+`
15
+ `}function tr(){let r=m.dirname(z(import.meta.url)),e=r;for(let n=0;n<6;n++){let t=m.join(e,"bin","octomux-hook-bridge.js");if(i.existsSync(t))return t;let o=m.dirname(e);if(o===e)break;e=o}throw new Error(`Cannot locate bin/octomux-hook-bridge.js from ${r} (walked up 6 levels)`)}var k={id:"cursor",displayName:"Cursor",sessionIdMode:"harness-issued",newSessionId(){return q.randomUUID()},buildLaunchCommand({flags:r="",workspacePath:e}){return`cursor-agent${e?C(e):""}${r}`},buildResumeCommand({sessionId:r,flags:e="",workspacePath:n}){return`cursor-agent${n?C(n):""} --resume ${r}${e}`},buildContinueCommand(r){return null},async installHooks(r,e,n){let t=m.join(r,".octomux-hooks");i.mkdirSync(t,{recursive:!0,mode:448}),i.chmodSync(t,448);let o=tr(),s=m.join(t,"bridge.js");try{i.existsSync(s)&&i.chmodSync(s,384)}catch{}i.copyFileSync(o,s),i.chmodSync(s,320);let c=JSON.stringify({baseUrl:e,token:n},null,2)+`
16
+ `,u=m.join(t,"config.json");try{(!i.existsSync(u)||i.readFileSync(u,"utf-8")!==c)&&i.writeFileSync(u,c,{mode:384})}catch{i.writeFileSync(u,c,{mode:384})}i.chmodSync(u,384);let a=nr(s),f=m.join(r,".cursor");i.mkdirSync(f,{recursive:!0});let y=m.join(f,"hooks.json");try{(!i.existsSync(y)||i.readFileSync(y,"utf-8")!==a)&&i.writeFileSync(y,a)}catch{i.writeFileSync(y,a)}},async syncAgents(r){let{listAgents:e,getAgent:n}=await import("./agents-XWAPBJ6K.js"),t=m.join(r,".cursor","rules");i.mkdirSync(t,{recursive:!0}),er(t);let o=await e();for(let s of o)try{let c=await n(s.name),u=`${L}${s.name}.mdc`,a=m.join(t,u),f=rr(s.name,c.content);try{if(i.existsSync(a)&&i.readFileSync(a,"utf-8")===f)continue}catch{}i.writeFileSync(a,f,"utf-8")}catch(c){h.warn({worktree_path:r,agent:s.name,err:c.message},"cursor syncAgents: failed to mirror agent definition")}},async postLaunch(r){if(process.env.NODE_ENV==="test")return;let e=Date.now();for(;Date.now()-e<$;){let n;try{({stdout:n}=await R(["capture-pane","-t",r,"-p"]))}catch(t){h.warn({target:r,err:t.message},"cursor postLaunch: tmux capture-pane failed; abandoning trust auto-accept");return}if(G.test(n)){try{await R(["send-keys","-t",r,"a"]),h.info({target:r,elapsed_ms:Date.now()-e},"cursor postLaunch: accepted Workspace Trust prompt")}catch(t){h.warn({target:r,err:t.message},"cursor postLaunch: tmux send-keys failed while accepting trust prompt")}return}await new Promise(t=>setTimeout(t,K))}h.info({target:r,timeout_ms:$},"cursor postLaunch: no Workspace Trust prompt detected within timeout (workspace probably already trusted)")},resolveFlags(r){let e=r.harnesses?.["claude-code"],t=(typeof e?.dangerouslySkipPermissions=="boolean"?e.dangerouslySkipPermissions:!1)||!!r.dangerouslySkipPermissions,o=r.harnesses?.cursor??{},s=[];(o.force||t)&&s.push("--force"),o.flags&&s.push(w(o.flags,"harnesses.cursor.flags"));let c=s.join(" ");if(!/\B--model\b/.test(c)){let u=typeof o.model=="string"&&o.model.trim()?H(o.model):Z;s.push(`--model ${u}`)}return s.length>0?` ${s.join(" ")}`:""},validateSettings(r){if(typeof r!="object"||r===null||Array.isArray(r))throw new Error("Invalid cursor settings: expected object");let e=r,n={},t=new Set(["flags","force","model"]);for(let o of Object.keys(e))if(!t.has(o))throw new Error(`Invalid cursor settings: unknown key "${o}"`);if(e.flags!==void 0&&(n.flags=w(e.flags,"harnesses.cursor.flags")),e.force!==void 0){if(typeof e.force!="boolean")throw new Error("Invalid cursor.force: expected boolean");n.force=e.force}if(e.model!==void 0){if(typeof e.model!="string")throw new Error("Invalid cursor.model: expected string");let o=e.model.trim();o&&(n.model=H(o))}return n},validateAgentName(r){return D(r)}};var F=new Map([[p.id,p],[k.id,k]]),or=p.id;function Ar(r){let e=r??or,n=F.get(e);if(!n)throw new Error(`Unknown harness: ${e}`);return n}function Or(){return Array.from(F.values())}export{R as a,pr as b,gr as c,j as d,k as e,or as f,Ar as g,Or as h};
@@ -1 +1 @@
1
- import s from"fs";import o from"path";import l from"os";import{fileURLToPath as w}from"url";var h=o.dirname(w(import.meta.url));function d(){return o.resolve(h,"..","agents")}function m(){return process.env.OCTOMUX_AGENTS_DIR||o.join(l.homedir(),".octomux","agents")}function p(t){let i=t.match(/^---\n([\s\S]*?)\n---/);if(!i)return{name:"",description:""};let n=i[1],r=n.match(/^name:\s*(.+)$/m),e=n.match(/^description:\s*(.+)$/m);return{name:r?r[1].trim():"",description:e?e[1].trim():""}}function C(t){return s.existsSync(o.join(d(),`${t}.md`))}async function c(t){try{return await s.promises.access(t),!0}catch{return!1}}async function j(){let t=d(),i=m(),n=new Map;if(await c(t)){let r=await s.promises.readdir(t);for(let e of r){if(!e.endsWith(".md"))continue;let a=e.replace(".md",""),u=await s.promises.readFile(o.join(t,e),"utf-8"),f=p(u);n.set(a,{name:a,description:f.description,isCustom:!1})}}if(await c(i)){let r=await s.promises.readdir(i);for(let e of r){if(!e.endsWith(".md"))continue;let a=e.replace(".md",""),u=await s.promises.readFile(o.join(i,e),"utf-8"),f=p(u),g=n.get(a);n.set(a,{name:a,description:f.description||g?.description||"",isCustom:!0})}}return Array.from(n.values()).sort((r,e)=>r.name.localeCompare(e.name))}async function v(t){let i=o.join(d(),`${t}.md`),n=o.join(m(),`${t}.md`),r=await c(i),e=await c(n);if(!r&&!e)throw new Error(`Agent not found: ${t}`);let a=r?await s.promises.readFile(i,"utf-8"):"",u=e?await s.promises.readFile(n,"utf-8"):null;return{name:t,content:u??a,defaultContent:a,isCustom:e}}async function A(t,i){let n=m();await s.promises.mkdir(n,{recursive:!0}),await s.promises.writeFile(o.join(n,`${t}.md`),i,"utf-8")}async function b(t){let i=o.join(m(),`${t}.md`);try{await s.promises.unlink(i)}catch(n){if(n.code==="ENOENT")return;throw n}}async function E(t,i){let n=o.join(m(),`${t}.md`);if(await c(n))throw new Error(`Agent already exists: ${t}`);await A(t,i)}async function D(t){let{claudeCodeHarness:i}=await import("./claude-code-54GJGR3J.js");await i.syncAgents(t??process.cwd())}async function I(t){let i=o.join(d(),`${t}.md`);if(await c(i))throw new Error(`Cannot delete built-in agent: ${t}. Use reset to restore defaults.`);let n=o.join(m(),`${t}.md`);if(!await c(n))throw new Error(`Agent not found: ${t}`);await s.promises.unlink(n)}export{C as a,j as b,v as c,A as d,b as e,E as f,D as g,I as h};
1
+ import s from"fs";import o from"path";import l from"os";import{fileURLToPath as w}from"url";var h=o.dirname(w(import.meta.url));function d(){return o.resolve(h,"..","agents")}function m(){return process.env.OCTOMUX_AGENTS_DIR||o.join(l.homedir(),".octomux","agents")}function p(t){let i=t.match(/^---\n([\s\S]*?)\n---/);if(!i)return{name:"",description:""};let n=i[1],r=n.match(/^name:\s*(.+)$/m),e=n.match(/^description:\s*(.+)$/m);return{name:r?r[1].trim():"",description:e?e[1].trim():""}}function C(t){return s.existsSync(o.join(d(),`${t}.md`))}async function c(t){try{return await s.promises.access(t),!0}catch{return!1}}async function j(){let t=d(),i=m(),n=new Map;if(await c(t)){let r=await s.promises.readdir(t);for(let e of r){if(!e.endsWith(".md"))continue;let a=e.replace(".md",""),u=await s.promises.readFile(o.join(t,e),"utf-8"),f=p(u);n.set(a,{name:a,description:f.description,isCustom:!1})}}if(await c(i)){let r=await s.promises.readdir(i);for(let e of r){if(!e.endsWith(".md"))continue;let a=e.replace(".md",""),u=await s.promises.readFile(o.join(i,e),"utf-8"),f=p(u),g=n.get(a);n.set(a,{name:a,description:f.description||g?.description||"",isCustom:!0})}}return Array.from(n.values()).sort((r,e)=>r.name.localeCompare(e.name))}async function v(t){let i=o.join(d(),`${t}.md`),n=o.join(m(),`${t}.md`),r=await c(i),e=await c(n);if(!r&&!e)throw new Error(`Agent not found: ${t}`);let a=r?await s.promises.readFile(i,"utf-8"):"",u=e?await s.promises.readFile(n,"utf-8"):null;return{name:t,content:u??a,defaultContent:a,isCustom:e}}async function A(t,i){let n=m();await s.promises.mkdir(n,{recursive:!0}),await s.promises.writeFile(o.join(n,`${t}.md`),i,"utf-8")}async function b(t){let i=o.join(m(),`${t}.md`);try{await s.promises.unlink(i)}catch(n){if(n.code==="ENOENT")return;throw n}}async function E(t,i){let n=o.join(m(),`${t}.md`);if(await c(n))throw new Error(`Agent already exists: ${t}`);await A(t,i)}async function D(t){let{claudeCodeHarness:i}=await import("./claude-code-FPRNRVIA.js");await i.syncAgents(t??process.cwd())}async function I(t){let i=o.join(d(),`${t}.md`);if(await c(i))throw new Error(`Cannot delete built-in agent: ${t}. Use reset to restore defaults.`);let n=o.join(m(),`${t}.md`);if(!await c(n))throw new Error(`Agent not found: ${t}`);await s.promises.unlink(n)}export{C as a,j as b,v as c,A as d,b as e,E as f,D as g,I as h};
@@ -0,0 +1,2 @@
1
+ import{execFileSync as n}from"child_process";function o({cmd:r,checkArgs:e}){try{return{ok:!0,version:n(r,e,{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).split(`
2
+ `)[0]?.trim()||void 0}}catch{return{ok:!1}}}function s(){try{return n("brew",["--version"],{stdio:"ignore"}),!0}catch{return!1}}function a(r,e){if(process.platform!=="darwin"||!s())return!1;let t=e?.cmd??(r==="neovim"?"nvim":r),i=e?.checkArgs??(t==="tmux"?["-V"]:["--version"]);try{return n("brew",["install",r],{stdio:"inherit"}),o({cmd:t,checkArgs:i}).ok}catch{return!1}}export{o as a,s as b,a as c};
@@ -0,0 +1 @@
1
+ import{a as l,c as m}from"./chunk-GAXJZSQT.js";import{a as c}from"./chunk-E5HYNQ6D.js";import{execFileSync as f}from"child_process";import{existsSync as p,readdirSync as d}from"fs";import a from"path";var o=c("startup");function x({cmd:n,checkArgs:r,name:i,brewPkg:e,installUrl:s}){let t=i||n;if(l({cmd:n,checkArgs:r}).ok||e&&process.platform==="darwin"&&m(e,{cmd:n,checkArgs:r})&&l({cmd:n,checkArgs:r}).ok)return;let u=s||`https://formulae.brew.sh/formula/${e||n}`;o.error({label:t,install_url:u},`${t} not found \u2014 install it manually`),process.exit(1)}function S({cmd:n,checkArgs:r,name:i,installUrl:e,brewPkg:s}){let t=i||n;if(l({cmd:n,checkArgs:r}).ok)return;let u=e||(s?`https://formulae.brew.sh/formula/${s}`:void 0);o.warn({label:t,install_url:u},`${t} not found \u2014 install from the Setup page or run: octomux start after fixing`)}function _(){let n;try{let i=f("nvim",["--version"],{encoding:"utf8"}).match(/(\d+)\.(\d+)\.(\d+)/);i&&(n={major:parseInt(i[1],10),minor:parseInt(i[2],10),raw:i[0]})}catch{}n||(o.error("Could not determine neovim version"),process.exit(1)),n.major===0&&n.minor<10&&o.warn({found:n.raw,required:">=0.10.0"},"Neovim version too old \u2014 upgrade with: brew upgrade neovim (or use VS Code/Cursor editor in Setup)")}function D(n){let r=a.join(n,".local","share","nvim","lazy");if(!p(r)||d(r).length===0){o.info("Syncing LazyVim plugins (first run \u2014 this may take a minute)");try{f("nvim",["--headless","+Lazy! sync","+qa"],{stdio:"inherit",env:{...process.env,XDG_CONFIG_HOME:a.join(n,".config"),XDG_DATA_HOME:a.join(n,".local","share"),XDG_STATE_HOME:a.join(n,".local","state"),XDG_CACHE_HOME:a.join(n,".local","cache")}})}catch(e){o.warn({err:e},"LazyVim plugin sync failed \u2014 editor may not work correctly")}}}export{x as a,S as b,_ as c,D as d};
@@ -0,0 +1,49 @@
1
+ import{a as A}from"./chunk-BYZCD2AS.js";import{a as v}from"./chunk-G45FZHCE.js";import{a as u,d as I,g as R}from"./chunk-72XPVTY6.js";import{b as C}from"./chunk-YUNRZQSW.js";import{a as f}from"./chunk-RHMOEXMR.js";import{a as W}from"./chunk-E5HYNQ6D.js";import{execFile as he}from"child_process";import{promisify as fe}from"util";import q from"crypto";import b from"path";import ge from"os";import w from"fs";import{nanoid as U}from"nanoid";import{execFile as se}from"child_process";import{promisify as ie}from"util";var Y=ie(se);async function j(e){let t=f(),n=t.prepare("SELECT * FROM repo_configs WHERE repo_path = ?").get(e);if(n)return n;let i=null;try{let{stdout:s}=await Y("git",["-C",e,"symbolic-ref","refs/remotes/origin/HEAD"]);i=s.trim().replace("refs/remotes/origin/","")}catch{let s=["main","master","staging"],r=(await Promise.all(s.map(a=>Y("git",["-C",e,"rev-parse","--verify",a]).then(()=>!0).catch(()=>!1)))).findIndex(a=>a);r>=0&&(i=s[r])}return t.prepare("INSERT INTO repo_configs (repo_path, base_branch) VALUES (?, ?) RETURNING *").get(e,i)}function Ae(e,t){let n=f(),i=n.prepare("SELECT * FROM repo_configs WHERE repo_path = ?").get(e);if(!i)throw new Error(`No config found for repo: ${e}`);let s=[],o=[];for(let[r,a]of Object.entries(t))a!==void 0&&(s.push(`${r} = ?`),o.push(a));return s.length>0?(s.push("updated_at = datetime('now')"),o.push(e),n.prepare(`UPDATE repo_configs SET ${s.join(", ")} WHERE repo_path = ? RETURNING *`).get(...o)):i}function Pe(){return f().prepare("SELECT * FROM repo_configs ORDER BY repo_path").all()}function oe(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t.filter(n=>typeof n=="object"&&n!==null&&typeof n.integration=="string"&&typeof n.pattern=="string"):[]}catch{return[]}}function J(e,t,n){let i=oe(t.ref_inference_json);if(i.length===0)return[];let s=new Set,o=[];for(let r of i){if(s.has(r.integration))continue;let a;try{a=new RegExp(r.pattern)}catch{continue}let d=e.match(a);if(!d)continue;let l=d[1]??d[0],E=r.url_template?r.url_template.replace("{ref}",l):void 0;s.add(r.integration),o.push({task_id:n,integration:r.integration,ref:l,url:E??null,metadata:null,created_at:new Date().toISOString()})}return o}import ae from"crypto";import V from"path";import de from"os";import F from"fs";import{nanoid as ce}from"nanoid";var y=W("chats");function le(){return V.join(de.homedir(),".octomux","chats")}function N(e){return V.join(le(),e)}function z(e){return`octomux-chat-${e}`}async function ze(e={}){let t=f(),n=ce(12),i=e.label??"Chat",s=e.cwd??N(n),o=e.agent??null;F.mkdirSync(s,{recursive:!0});let r=z(n),a=R(e.harnessId??null),d=n,l=ae.randomBytes(32).toString("hex"),E=a.resolveFlags(await C()),m,h;if(a.sessionIdMode==="orchestrator-assigned"){let _=a.newSessionId();m=_,h=_}else m=null,h=a.newSessionId();t.prepare(`INSERT INTO agents
2
+ (id, task_id, window_index, label, status, harness_id, harness_session_id,
3
+ hook_token, hook_activity, tmux_session, agent, created_at)
4
+ VALUES (?, NULL, 0, ?, 'running', ?, ?, ?, 'active', ?, ?, datetime('now'))`).run(n,i,a.id,m,l,r,o);try{await a.syncAgents(s),await a.installHooks(s,v(),l),await u(["new-session","-d","-s",r,"-c",s]),await u(["set-option","-t",r,"aggressive-resize","on"]);let x=a.buildLaunchCommand({sessionId:h,agent:o,flags:E,workspacePath:s}),p=null,g=e.prompt?.trim();if(g&&(p=V.join(s,`.claude-prompt-${d}`),F.writeFileSync(p,g,{mode:384,flag:"wx"}),x+=` "$(cat ${I(p)})"`),await u(["send-keys","-t",r,x,"Enter"]),p){let S=p;setTimeout(()=>{try{F.unlinkSync(S)}catch{}},3e4)}y.info({chat_id:n,tmux_session:r,cwd:s,agent:o,harness:a.id,harness_session_id:m,operation:"createChat"},"createChat: complete")}catch(_){throw y.error({chat_id:n,operation:"createChat",err:_},"createChat: failed"),t.prepare("UPDATE agents SET status = 'stopped' WHERE id = ?").run(n),_}return t.prepare("SELECT * FROM agents WHERE id = ?").get(n)}function Ge(){return f().prepare(`SELECT * FROM agents
5
+ WHERE task_id IS NULL
6
+ ORDER BY created_at ASC`).all()}function Ye(e){return f().prepare("SELECT * FROM agents WHERE id = ? AND task_id IS NULL").get(e)??null}function ue(e){let t=e?.stderr??"";return/can't find (?:session|window|pane):/i.test(t)}async function K(e,t,n){try{await u(["kill-session","-t",t]),y.info({chat_id:e,operation:n,tmux_session:t},`${n}: tmux session killed`)}catch(i){ue(i)?y.debug({chat_id:e,operation:n,tmux_session:t},`${n}: tmux session already gone`):y.warn({chat_id:e,operation:n,tmux_session:t,err:i},`${n}: tmux kill-session failed`)}}async function Je(e){let t=f();y.info({chat_id:e.id,operation:"closeChat"},"closeChat: start"),t.prepare(`UPDATE agents SET status = 'stopped', hook_activity = 'idle',
7
+ hook_activity_updated_at = datetime('now')
8
+ WHERE id = ?`).run(e.id),e.tmux_session&&await K(e.id,e.tmux_session,"closeChat"),y.info({chat_id:e.id,operation:"closeChat"},"closeChat: complete")}async function Ke(e){let t=f();y.info({chat_id:e.id,operation:"deleteChat"},"deleteChat: start"),e.tmux_session&&await K(e.id,e.tmux_session,"deleteChat");let n=N(e.id);try{F.rmSync(n,{recursive:!0,force:!0}),y.info({chat_id:e.id,operation:"deleteChat",chat_dir:n},"deleteChat: scratch dir removed")}catch(i){y.warn({chat_id:e.id,operation:"deleteChat",chat_dir:n,err:i},"deleteChat: scratch dir remove failed (may already be gone)")}t.prepare("DELETE FROM agents WHERE id = ?").run(e.id),y.info({chat_id:e.id,operation:"deleteChat"},"deleteChat: complete")}import{execFile as pe}from"child_process";import{promisify as me}from"util";var H=me(pe);async function _e(e,t){let{stdout:n}=await H("git",["-C",e,...t],{maxBuffer:16777216,env:A()});return n}async function Q(e,t,n){let{stdout:i}=await H("git",["-C",e,"merge-base",t,n],{env:A()});return i.trim()}async function et(e,t){let{from:n,to:i="HEAD",limit:s}=t,o=n?`${n}..${i}`:i,r=["log","--pretty=format:%H%x09%h%x09%s%x09%an%x09%ae%x09%aI","-n",String(s+1),o],a="";try{a=await _e(e,r)}catch(m){let h=m.message;if(h.includes("unknown revision")||h.includes("does not have any commits yet")||h.includes("bad revision"))return{commits:[],truncated:!1};throw m}let d=a.split(`
9
+ `).filter(Boolean),l=d.length>s;return l&&(d.length=s),{commits:d.map(m=>{let[h,_,x,p,g,S]=m.split(" ");return{sha:h??"",short_sha:_??"",subject:x??"",author:p??"",author_email:g??"",authored_at:S??""}}),truncated:l}}async function tt(e){let{stdout:t}=await H("git",["-C",e,"branch","-a","--format=%(refname:short)"],{env:A()}),n=t.trim().split(`
10
+ `).filter(Boolean).map(r=>r.replace(/^origin\//,"")),i=[...new Set(n)].filter(r=>r!=="HEAD").sort(),s=null;try{let{stdout:r}=await H("git",["-C",e,"symbolic-ref","--short","HEAD"],{env:A()});s=r.trim()||null}catch{s=null}let o=null;try{let{stdout:r}=await H("git",["-C",e,"symbolic-ref","--short","refs/remotes/origin/HEAD"],{env:A()});o=r.trim().replace(/^origin\//,"")||null}catch{o=null}return{branches:i,current:s,default:o}}var c=W("task-runner"),k=fe(he);function X(){return b.join(ge.homedir(),".octomux","scratch")}function Z(e){return b.join(X(),e)}function L(e){let t=e?.stderr??"";return/can't find (?:session|window|pane):/i.test(t)}async function G(e){let{stdout:t}=await u(["display-message","-t",e,"-p","#{window_index}"]);return parseInt(t.trim(),10)}async function $(e){let{stdout:t}=await u(["list-windows","-t",e,"-F","#{window_index}"]),n=t.trim().split(`
11
+ `).map(Number);return Math.max(...n)}var we=6e4,ee=["remember@claude-plugins-official"];function Ee(e){let t=b.join(e,".claude");w.mkdirSync(t,{recursive:!0});let n=b.join(t,"settings.local.json");if(w.existsSync(n))return;let i={};for(let s of ee)i[s]=!1;w.writeFileSync(n,JSON.stringify({plugins:i},null,2))}function M(e){let t=e.baseCmd;if(e.prompt&&e.worktreePath&&e.agentId){let s=b.join(e.worktreePath,`.claude-prompt-${e.agentId}`);w.writeFileSync(s,e.prompt,{mode:384,flag:"wx"}),t+=` "$(cat ${I(s)})"`,setTimeout(()=>{try{w.unlinkSync(s)}catch{}},we)}let n=process.env.SHELL||"/bin/sh",i=`${t}; exec ${n} -i`;return`${n} -ic ${I(i)}`}async function ke(e,t){try{await k("sh",["-c",t.format_command],{cwd:e})}catch{}try{await k("sh",["-c",t.lint_command],{cwd:e})}catch{}let{stdout:n}=await k("git",["diff","--name-only"],{cwd:e});n.trim()&&(await k("git",["add","-A"],{cwd:e}),await k("git",["commit","-m","chore: fix pre-existing formatting"],{cwd:e}))}async function B(e){let t;try{({stdout:t}=await u(["list-sessions","-F","#{session_name}"]))}catch{return}let n=`${e}-v-`,i=t.trim().split(`
12
+ `).filter(s=>s.startsWith(n));for(let s of i)await u(["kill-session","-t",s]).catch(()=>{})}async function xt(){let e;try{({stdout:e}=await u(["list-sessions","-F","#{session_name}"]))}catch{return}let t=new Set(e.trim().split(`
13
+ `).filter(Boolean)),n=/^(octomux-agent-.+)-v-/;for(let i of t){let s=i.match(n);if(s){let o=s[1];t.has(o)||await u(["kill-session","-t",i]).catch(()=>{})}}}function xe(e,t){let n=e.normalize("NFKD").replace(/[̀-ͯ]/g,"").toLowerCase().replace(/[^a-z0-9-]+/g,"-").replace(/-{2,}/g,"-").replace(/^-|-$/g,"").slice(0,50),i=t.slice(0,6);return`${n}-${i}`}async function Tt(){let e=f(),t=e.prepare("SELECT id, tmux_session FROM tasks WHERE runtime_state = 'setting_up'").all();for(let n of t){let i=!1;if(n.tmux_session)try{await u(["has-session","-t",n.tmux_session]),i=!0}catch{i=!1}i||(e.prepare("UPDATE tasks SET runtime_state = 'error', error = ?, updated_at = datetime('now') WHERE id = ?").run("orphan setting_up on boot",n.id),c.warn({task_id:n.id,operation:"reconcileOrphanSettingUp"},"transitioned orphan setting_up task to error"))}}async function bt(){let e=X();if(!w.existsSync(e))return;let t=f(),n=new Set(t.prepare(`SELECT t.id AS id FROM tasks t
14
+ LEFT JOIN worktrees w ON t.worktree_id = w.id
15
+ WHERE w.mode = 'scratch' AND t.runtime_state IN ('idle','setting_up','running')
16
+ AND t.deleted_at IS NULL`).all().map(s=>s.id)),i=w.readdirSync(e,{withFileTypes:!0});for(let s of i){if(!s.isDirectory()||n.has(s.name))continue;let o=b.join(e,s.name);try{w.rmSync(o,{recursive:!0,force:!0}),c.info({scratch_dir:o,operation:"scratch_gc_removed"},"scratch_gc_removed")}catch(r){c.warn({scratch_dir:o,operation:"scratch_gc_removed",err:r},"scratch_gc_remove_failed")}}}async function te(e){if(!w.existsSync(e))throw new Error(`Repository path does not exist: ${e}`);await k("git",["-C",e,"rev-parse","--is-inside-work-tree"])}async function O(e,t="HEAD"){let{stdout:n}=await k("git",["-C",e,"rev-parse",`${t}^{commit}`]);return n.trim()}async function ne(e){let{stdout:t}=await k("git",["-C",e,"status","--porcelain=v1"]);return t.split(`
17
+ `).map(n=>n.trim()).filter(Boolean)}async function Te(e){await te(e.repo_path);let t=xe(e.title,e.id),n=e.branch||`agents/${t}`,i=e.branch||t,s=b.join(e.repo_path,".worktrees",i),o=b.join(e.repo_path,".worktrees");w.mkdirSync(o,{recursive:!0});let r=["-C",e.repo_path,"worktree","add",s,"-b",n];if(e.base_branch&&r.push(e.base_branch),await k("git",r),e.source==="auto_review"&&e.pr_head_sha){if(e.pr_number)try{await k("git",["-C",e.repo_path,"fetch","origin",`pull/${e.pr_number}/head`])}catch(m){c.warn({task_id:e.id,operation:"createTask",err:m},"createTask: failed to fetch PR head; review may show no files")}try{await k("git",["-C",s,"reset","--hard",e.pr_head_sha])}catch(m){c.warn({task_id:e.id,operation:"createTask",err:m},"createTask: failed to reset worktree to pr_head_sha; leaving at base-branch tip")}}let a=e.base_branch||"HEAD",d;if(e.source==="auto_review"&&e.pr_head_sha&&e.base_branch)try{d=await Q(e.repo_path,e.base_branch,e.pr_head_sha)}catch(m){c.warn({task_id:e.id,operation:"createTask",err:m},"createTask: git merge-base failed, falling back to rev-parse"),d=await O(e.repo_path,a)}else d=await O(e.repo_path,a);let l=b.join(e.repo_path,".claude","settings.local.json"),E=b.join(s,".claude","settings.local.json");return w.existsSync(l)&&(w.mkdirSync(b.dirname(E),{recursive:!0}),w.copyFileSync(l,E)),Ee(s),c.info({task_id:e.id,operation:"createTask",settings_path:E,disabled_plugins:ee.length},"createTask: wrote agent-local settings"),{worktreePath:s,branch:n,baseBranch:e.base_branch,baseSha:d,installHooksAt:s,runPreflight:!0}}async function be(e){let t=e.worktree;if(!t)throw new Error("existing mode requires a worktree path");if(!w.existsSync(t))throw new Error(`existing worktree does not exist: ${t}`);await k("git",["-C",t,"rev-parse","--is-inside-work-tree"]);let n=await O(t),i=null;try{let{stdout:o}=await k("git",["-C",t,"rev-parse","--abbrev-ref","HEAD"]),r=o.trim();i=r==="HEAD"?null:r}catch{i=null}let s=null;try{let{stdout:o}=await k("git",["-C",t,"rev-parse","--abbrev-ref","--symbolic-full-name","@{upstream}"]),r=o.trim();r&&(s=r.replace(/^origin\//,""))}catch{s=i}return{worktreePath:t,branch:i,baseBranch:s,baseSha:n,installHooksAt:t,runPreflight:!1}}async function ye(e){await te(e.repo_path);let{stdout:t}=await k("git",["-C",e.repo_path,"rev-parse","--abbrev-ref","HEAD"]),n=t.trim(),i=e.base_branch?.trim()||null;if(i){let{preflightNoneMode:r}=await import("./preflight-KHWEEL74.js"),a=await r(e.repo_path,i,e.id);if(!a.ok){let d=a.conflicts.length?`another chat is active on a different branch at ${e.repo_path}: ${a.conflicts.map(l=>`${l.task_id} (${l.branch??"unknown"})`).join(", ")}`:`working tree at ${e.repo_path} has ${a.dirty.count} uncommitted changes`;throw new Error(`none mode preflight failed: ${d}`)}i!==n&&await k("git",["-C",e.repo_path,"checkout",i])}else{let r=await ne(e.repo_path);if(r.length>0){let a=r.slice(0,5).join(", "),d=r.length>5?` (+${r.length-5} more)`:"";throw new Error(`none mode refuses dirty checkout at ${e.repo_path}: ${a}${d}`)}}let s=i??n,o=await O(e.repo_path);return{worktreePath:e.repo_path,branch:s,baseBranch:i,baseSha:o,installHooksAt:e.repo_path,runPreflight:!1}}async function Se(e){let t=Z(e.id);return w.mkdirSync(t,{recursive:!0}),{worktreePath:t,branch:null,baseBranch:null,baseSha:null,installHooksAt:t,runPreflight:!1}}async function yt(e){let t=f(),n=e.id,i=`octomux-agent-${n}`,s=e.run_mode;c.info({task_id:n,operation:"createTask",run_mode:s,repo_path:e.repo_path},"createTask: start");let o="validate";try{o="mode_setup";let r;switch(s){case"new":r=await Te(e);break;case"existing":r=await be(e);break;case"none":r=await ye(e);break;case"scratch":r=await Se(e);break;default:throw new Error(`unknown run_mode: ${String(s)}`)}t.prepare("UPDATE tasks SET runtime_state = 'setting_up', updated_at = datetime('now') WHERE id = ?").run(n);let a=s==="scratch"?null:e.repo_path;if(e.worktree_id)t.prepare(`UPDATE worktrees
18
+ SET path = ?, repo_path = ?, branch = ?, base_branch = ?, base_sha = ?,
19
+ mode = ?, status = 'in_use', last_used_at = datetime('now')
20
+ WHERE id = ?`).run(r.worktreePath,a,r.branch,r.baseBranch,r.baseSha,s,e.worktree_id);else{let T=U(12);t.prepare(`INSERT INTO worktrees
21
+ (id, path, repo_path, branch, base_branch, base_sha, mode, status, last_used_at)
22
+ VALUES (?, ?, ?, ?, ?, ?, ?, 'in_use', datetime('now'))`).run(T,r.worktreePath,a,r.branch,r.baseBranch,r.baseSha,s),t.prepare("UPDATE tasks SET worktree_id = ? WHERE id = ?").run(T,n)}if(c.info({task_id:n,operation:"createTask",run_mode:s,branch:r.branch,worktree:r.worktreePath,base_sha:r.baseSha},"createTask: setup complete"),r.branch&&e.repo_path)try{let T=await j(e.repo_path),P=J(r.branch,T,n);if(P.length>0){let re=t.prepare(`INSERT OR IGNORE INTO task_external_refs (task_id, integration, ref, url, created_at)
23
+ VALUES (?, ?, ?, ?, datetime('now'))`);for(let D of P)re.run(n,D.integration,D.ref,D.url),c.info({task_id:n,integration:D.integration,ref:D.ref},"ref-inference: inferred ref from branch name")}}catch(T){c.warn({task_id:n,err:T},"ref-inference: error during inference")}if(r.runPreflight){o="preflight";let T=await j(e.repo_path);await ke(r.worktreePath,T)}o="launch_agent";let d=R(e.harness_id),l=U(12),E=e.agent??null,m=q.randomBytes(32).toString("hex"),h=d.resolveFlags(await C()),_,x;if(d.sessionIdMode==="orchestrator-assigned"){let T=d.newSessionId();_=T,x=T}else _=null,x=d.newSessionId();await d.syncAgents(r.worktreePath),await d.installHooks(r.worktreePath,v(),m);let p=d.buildLaunchCommand({sessionId:x,agent:E,flags:h,model:e.model??null,workspacePath:r.worktreePath}),g=M({baseCmd:p,prompt:e.initial_prompt,worktreePath:r.worktreePath,agentId:l});o="tmux_session",await u(["new-session","-d","-s",i,"-c",r.worktreePath,g]),await u(["set-option","-t",i,"aggressive-resize","on"]),t.prepare("UPDATE tasks SET tmux_session = ?, updated_at = datetime('now') WHERE id = ?").run(i,n),c.info({task_id:n,operation:"createTask",tmux_session:i},"createTask: tmux session created");let S=await G(i);t.prepare(`INSERT INTO agents
24
+ (id, task_id, window_index, label, harness_id, harness_session_id, hook_token, agent)
25
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(l,n,S,"Agent 1",d.id,_,m,E),d.postLaunch?.(`${i}:${S}`),c.info({task_id:n,agent_id:l,operation:"createTask",window_index:S,harness:d.id,harness_session_id:_},"createTask: first agent launched"),t.prepare(`UPDATE tasks SET runtime_state = 'running', error = NULL,
26
+ workflow_status = CASE
27
+ WHEN workflow_status IN ('backlog', 'planned') THEN 'in_progress'
28
+ ELSE workflow_status
29
+ END,
30
+ updated_at = datetime('now') WHERE id = ?`).run(n),c.info({task_id:n,operation:"createTask"},"createTask: complete")}catch(r){c.error({task_id:n,operation:"createTask",stage:o,run_mode:s,err:r},"createTask: failed during setup stage"),t.prepare("UPDATE tasks SET runtime_state = 'error', error = ?, updated_at = datetime('now') WHERE id = ?").run(r.message,n)}}async function St(e,t={}){let n=f(),i=t.agent??null;c.info({task_id:e.id,operation:"addAgent",agent:i},"addAgent: start");let s=n.prepare("SELECT * FROM agents WHERE task_id = ? AND status != 'stopped' ORDER BY window_index").all(e.id),o=t.label??`Agent ${s.length+1}`,r=R(e.harness_id),a=U(12),l=n.prepare("SELECT hook_token FROM agents WHERE task_id = ? AND hook_token != '' LIMIT 1").get(e.id)?.hook_token??q.randomBytes(32).toString("hex"),E=r.resolveFlags(await C()),m=t.prompt;if(t.skeleton){let T=b.join(e.worktree,".octomux","agents",`${t.skeleton}.md`);if(!w.existsSync(T))throw new Error(`skeleton not found: ${t.skeleton} (expected at ${T})`);let P=w.readFileSync(T,"utf-8");m=t.prompt?`${P}
31
+
32
+ # Task
33
+
34
+ ${t.prompt}`:P}let h,_;if(r.sessionIdMode==="orchestrator-assigned"){let T=r.newSessionId();h=T,_=T}else h=null,_=r.newSessionId();await r.syncAgents(e.worktree),await r.installHooks(e.worktree,v(),l);let x=r.buildLaunchCommand({sessionId:_,agent:i,flags:E,model:t.model??e.model??null,workspacePath:e.worktree}),p=M({baseCmd:x,prompt:m,worktreePath:e.worktree,agentId:a});await u(["new-window","-t",e.tmux_session,"-c",e.worktree,p]);let g=await $(e.tmux_session),S=`${e.tmux_session}:${g}`;return n.prepare(`INSERT INTO agents
35
+ (id, task_id, window_index, label, harness_id, harness_session_id, hook_token, agent, notify_agent_id)
36
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(a,e.id,g,o,r.id,h,l,i,t.notify_agent_id??null),r.postLaunch?.(S),c.info({task_id:e.id,agent_id:a,operation:"addAgent",window_index:g,harness:r.id,harness_session_id:h},"addAgent: claude launched"),{id:a,task_id:e.id,window_index:g,label:o,status:"running",harness_id:r.id,harness_session_id:h,hook_token:l,hook_activity:"active",hook_activity_updated_at:null,tmux_session:null,agent:i,notify_agent_id:t.notify_agent_id??null,created_at:new Date().toISOString()}}async function Rt(e){let t=f();if(c.info({task_id:e.id,operation:"closeTask",run_mode:e.run_mode},"closeTask: start"),t.prepare(`UPDATE permission_prompts SET status = 'resolved', resolved_at = datetime('now')
37
+ WHERE task_id = ? AND status = 'pending'`).run(e.id),t.prepare("DELETE FROM user_terminals WHERE task_id = ?").run(e.id),t.prepare("UPDATE tasks SET runtime_state = 'idle', updated_at = datetime('now') WHERE id = ?").run(e.id),t.prepare("UPDATE agents SET status = 'stopped', hook_activity = 'idle', hook_activity_updated_at = datetime('now') WHERE task_id = ?").run(e.id),t.prepare(`UPDATE worktrees SET status = 'available', last_used_at = datetime('now')
38
+ WHERE id = (SELECT worktree_id FROM tasks WHERE id = ?)`).run(e.id),c.info({task_id:e.id,operation:"closeTask"},"closeTask: DB marked task closed + agents stopped"),e.tmux_session){await B(e.tmux_session);try{await u(["kill-session","-t",e.tmux_session]),c.info({task_id:e.id,operation:"closeTask",tmux_session:e.tmux_session},"closeTask: tmux session killed")}catch(n){L(n)?c.debug({task_id:e.id,operation:"closeTask",tmux_session:e.tmux_session},"closeTask: tmux session already gone"):c.warn({task_id:e.id,operation:"closeTask",tmux_session:e.tmux_session,err:n},"closeTask: tmux kill-session failed")}}c.info({task_id:e.id,operation:"closeTask"},"closeTask: complete")}async function Ct(e){let t=f();if(c.info({task_id:e.id,operation:"softDeleteTask"},"softDeleteTask: start"),e.tmux_session){await B(e.tmux_session);try{await u(["kill-session","-t",e.tmux_session])}catch(n){L(n)||c.warn({task_id:e.id,tmux_session:e.tmux_session,err:n},"softDeleteTask: tmux kill-session failed")}}t.prepare(`UPDATE tasks SET deleted_at = datetime('now'),
39
+ runtime_state = 'idle',
40
+ updated_at = datetime('now')
41
+ WHERE id = ?`).run(e.id),t.prepare(`UPDATE agents
42
+ SET status = 'stopped',
43
+ hook_activity = 'idle',
44
+ hook_activity_updated_at = datetime('now')
45
+ WHERE task_id = ? AND status = 'running'`).run(e.id),c.info({task_id:e.id,operation:"softDeleteTask"},"softDeleteTask: complete")}async function vt(e){let t=f();if(c.info({task_id:e.id,operation:"deleteTask",run_mode:e.run_mode},"deleteTask: start"),e.tmux_session){await B(e.tmux_session);try{await u(["kill-session","-t",e.tmux_session]),c.info({task_id:e.id,operation:"deleteTask",tmux_session:e.tmux_session},"deleteTask: tmux session killed")}catch(i){L(i)?c.debug({task_id:e.id,operation:"deleteTask",tmux_session:e.tmux_session},"deleteTask: tmux session already gone"):c.warn({task_id:e.id,operation:"deleteTask",tmux_session:e.tmux_session,err:i},"deleteTask: tmux kill-session failed")}}switch(e.run_mode){case"new":{if(e.worktree)try{await k("git",["-C",e.repo_path,"worktree","remove",e.worktree,"--force"]),c.info({task_id:e.id,operation:"deleteTask",worktree:e.worktree},"deleteTask: worktree removed")}catch(i){c.warn({task_id:e.id,operation:"deleteTask",worktree:e.worktree,err:i},"deleteTask: worktree remove failed (may already be gone)")}if(e.branch)try{await k("git",["-C",e.repo_path,"branch","-D",e.branch]),c.info({task_id:e.id,operation:"deleteTask",branch:e.branch},"deleteTask: branch deleted")}catch(i){c.warn({task_id:e.id,operation:"deleteTask",branch:e.branch,err:i},"deleteTask: branch delete failed (may already be gone)")}break}case"existing":case"none":c.info({task_id:e.id,operation:"deleteTask",run_mode:e.run_mode},"deleteTask: skipped filesystem cleanup (user-owned path)");break;case"scratch":{let i=e.worktree||Z(e.id);try{w.rmSync(i,{recursive:!0,force:!0}),c.info({task_id:e.id,operation:"deleteTask",scratch_dir:i},"deleteTask: scratch dir removed")}catch(s){c.warn({task_id:e.id,operation:"deleteTask",scratch_dir:i,err:s},"deleteTask: scratch dir remove failed (may already be gone)")}break}}let n=e.worktree_id;n&&(t.prepare("UPDATE tasks SET worktree_id = NULL WHERE id = ?").run(e.id),e.run_mode==="new"||e.run_mode==="scratch"?t.prepare("DELETE FROM worktrees WHERE id = ?").run(n):t.prepare("UPDATE worktrees SET status = 'available', last_used_at = datetime('now') WHERE id = ?").run(n)),c.info({task_id:e.id,operation:"deleteTask"},"deleteTask: complete")}async function At(e,t){let n=f();c.info({task_id:e.id,agent_id:t.id,operation:"stopAgent",window_index:t.window_index},"stopAgent: start"),n.prepare(`UPDATE permission_prompts SET status = 'resolved', resolved_at = datetime('now')
46
+ WHERE agent_id = ? AND status = 'pending'`).run(t.id),await u(["kill-window","-t",`${e.tmux_session}:${t.window_index}`]).catch(i=>{L(i)?c.debug({task_id:e.id,agent_id:t.id,operation:"stopAgent"},"stopAgent: tmux window already gone"):c.warn({task_id:e.id,agent_id:t.id,operation:"stopAgent",err:i},"stopAgent: kill-window failed")}),n.prepare("UPDATE agents SET status = 'stopped', hook_activity = 'idle', hook_activity_updated_at = datetime('now') WHERE id = ?").run(t.id),c.info({task_id:e.id,agent_id:t.id,operation:"stopAgent"},"stopAgent: complete")}async function Pt(e){let n=(await C()).editor;if(n==="vscode"||n==="cursor")return await k(n==="vscode"?"code":"cursor",[e.worktree]),{editor:n,windowIndex:null};if(e.user_window_index!==null&&e.user_window_index!==void 0)return{editor:n,windowIndex:e.user_window_index};let i=f();await u(["new-window","-t",e.tmux_session,"-c",e.worktree]);let s=await $(e.tmux_session);return await u(["send-keys","-t",`${e.tmux_session}:${s}`,"nvim .","Enter"]),i.prepare("UPDATE tasks SET user_window_index = ?, updated_at = datetime('now') WHERE id = ?").run(s,e.id),{editor:"nvim",windowIndex:s}}async function Dt(e){let t=f();await u(["new-window","-t",e.tmux_session,"-c",e.worktree]);let n=await $(e.tmux_session),{count:i}=t.prepare("SELECT COUNT(*) as count FROM user_terminals WHERE task_id = ?").get(e.id),s=`Terminal ${i+1}`,o=U(12);return t.prepare("INSERT INTO user_terminals (id, task_id, window_index, label) VALUES (?, ?, ?, ?)").run(o,e.id,n,s),{id:o,task_id:e.id,window_index:n,label:s,status:"idle",created_at:new Date().toISOString()}}async function It(e,t){let n=f();await u(["kill-window","-t",`${e.tmux_session}:${t.window_index}`]).catch(()=>{}),n.prepare("DELETE FROM user_terminals WHERE id = ?").run(t.id)}async function Ht(e){let t=f(),n=e.tmux_session,i=e.run_mode;c.info({task_id:e.id,operation:"resumeTask",run_mode:i,tmux_session:n,worktree:e.worktree},"resumeTask: start");try{if(i==="existing"){if(!e.worktree||!w.existsSync(e.worktree))throw new Error(`existing worktree no longer exists: ${e.worktree??"<null>"}`)}else if(i==="scratch"){if(!e.worktree||!w.existsSync(e.worktree))throw new Error(`scratch dir no longer exists: ${e.worktree??"<null>"}`)}else if(i==="none"){if(!w.existsSync(e.repo_path))throw new Error(`repo_path no longer exists: ${e.repo_path}`);let a=await ne(e.repo_path);if(a.length>0){let d=a.slice(0,5).join(", "),l=a.length>5?` (+${a.length-5} more)`:"";throw new Error(`none mode refuses dirty checkout at ${e.repo_path}: ${d}${l}`)}}t.prepare("UPDATE tasks SET runtime_state = 'setting_up', error = NULL, user_window_index = NULL, updated_at = datetime('now') WHERE id = ?").run(e.id),t.prepare("DELETE FROM user_terminals WHERE task_id = ?").run(e.id),await B(n),await u(["kill-session","-t",n]).catch(()=>{}),t.prepare("UPDATE agents SET status = 'stopped', hook_activity = 'idle', hook_activity_updated_at = datetime('now') WHERE task_id = ? AND status != 'stopped'").run(e.id);let s=e.worktree,o=t.prepare("SELECT * FROM agents WHERE task_id = ? AND status = 'stopped' ORDER BY window_index").all(e.id);if(o.length>0){let a=R(o[0].harness_id);await a.syncAgents(s),await a.installHooks(s,v(),o[0].hook_token)}else await u(["new-session","-d","-s",n,"-c",s]),await u(["set-option","-t",n,"aggressive-resize","on"]);let r=!1;for(let a=0;a<o.length;a++){let d=o[a],l=R(d.harness_id),E=l.resolveFlags(await C()),m=e.model??null,h;if(d.harness_session_id)h=l.buildResumeCommand({sessionId:d.harness_session_id,flags:E,model:m,workspacePath:s});else{let p=l.newSessionId(),g=l.buildContinueCommand({sessionId:p,flags:E,model:m,workspacePath:s});g!==null?h=g:(h=l.buildLaunchCommand({sessionId:p,agent:d.agent,flags:E,model:m,workspacePath:s}),c.warn({agent_id:d.id,harness:l.id},"continue unsupported, launching fresh")),l.sessionIdMode==="orchestrator-assigned"&&t.prepare("UPDATE agents SET harness_session_id = ? WHERE id = ?").run(p,d.id)}let _=M({baseCmd:h}),x;r?(await u(["new-window","-t",n,"-c",s,_]),x=await $(n)):(await u(["new-session","-d","-s",n,"-c",s,_]),await u(["set-option","-t",n,"aggressive-resize","on"]),r=!0,x=await G(n)),l.postLaunch?.(`${n}:${x}`),t.prepare("UPDATE agents SET window_index = ?, status = 'running' WHERE id = ?").run(x,d.id),c.info({task_id:e.id,agent_id:d.id,operation:"resumeTask",window_index:x,harness:l.id,harness_session_id:d.harness_session_id},"resumeTask: agent recovered")}t.prepare("UPDATE tasks SET runtime_state = 'running', updated_at = datetime('now') WHERE id = ?").run(e.id),c.info({task_id:e.id,operation:"resumeTask",recovered_agents:o.length},"resumeTask: complete")}catch(s){c.error({task_id:e.id,operation:"resumeTask",err:s},"resumeTask: failed"),t.prepare("UPDATE tasks SET runtime_state = 'error', error = ?, updated_at = datetime('now') WHERE id = ?").run(s.message,e.id)}}async function Lt(e,t){let n=f(),i=e.task_id;c.info({agent_id:e.id,from_task_id:i,to_task_id:t,operation:"task_hop"},"task_hop: start");let s=null;if(e.task_id){let p=n.prepare("SELECT tmux_session FROM tasks WHERE id = ?").get(e.task_id);p?.tmux_session&&(s={session:p.tmux_session,window:e.window_index})}else e.tmux_session&&(s={session:e.tmux_session,window:e.window_index});let o,r,a;if(t===null)a=!0,o=z(e.id),r=N(e.id),w.mkdirSync(r,{recursive:!0});else{a=!1;let p=n.prepare("SELECT * FROM tasks WHERE id = ?").get(t);if(!p)throw new Error(`Task not found: ${t}`);if(!p.worktree_id)throw new Error(`Task ${t} has no worktree`);let g=n.prepare("SELECT * FROM worktrees WHERE id = ?").get(p.worktree_id);if(!g)throw new Error(`Worktree not found for task ${t}`);if(!g.path||!w.existsSync(g.path))throw new Error(`Worktree path does not exist: ${g.path}`);if(!p.tmux_session)throw new Error(`Task ${t} has no tmux session (not running)`);o=p.tmux_session,r=g.path}if(s)try{!e.task_id&&e.tmux_session?await u(["kill-session","-t",e.tmux_session]):await u(["kill-window","-t",`${s.session}:${s.window}`])}catch(p){L(p)||c.warn({agent_id:e.id,operation:"task_hop",err:p},"task_hop: kill old tmux target failed")}let d=R(e.harness_id),l=d.resolveFlags(await C()),E=null;t&&(E=n.prepare("SELECT model FROM tasks WHERE id = ?").get(t)?.model??null),await d.syncAgents(r),await d.installHooks(r,v(),e.hook_token);let m;if(e.harness_session_id)m=d.buildResumeCommand({sessionId:e.harness_session_id,flags:l,model:E,workspacePath:r});else{let p=d.newSessionId(),g=d.buildContinueCommand({sessionId:p,flags:l,model:E,workspacePath:r});g!==null?m=g:(m=d.buildLaunchCommand({sessionId:p,agent:e.agent,flags:l,model:E,workspacePath:r}),c.warn({agent_id:e.id,harness:d.id},"continue unsupported, launching fresh")),d.sessionIdMode==="orchestrator-assigned"&&n.prepare("UPDATE agents SET harness_session_id = ? WHERE id = ?").run(p,e.id)}let h=M({baseCmd:m}),_;a?(await u(["new-session","-d","-s",o,"-c",r,h]),await u(["set-option","-t",o,"aggressive-resize","on"]),_=await G(o)):(await u(["new-window","-t",o,"-c",r,h]),_=await $(o));let x=`${o}:${_}`;return d.postLaunch?.(x),n.prepare(`UPDATE agents
47
+ SET task_id = ?, window_index = ?, tmux_session = ?, status = 'running',
48
+ hook_activity = 'active', hook_activity_updated_at = datetime('now')
49
+ WHERE id = ?`).run(t,_,a?o:null,e.id),c.info({agent_id:e.id,from_task_id:i,to_task_id:t,new_window_index:_,new_tmux_session:o,operation:"task_hop"},"task_hop: complete"),n.prepare("SELECT * FROM agents WHERE id = ?").get(e.id)}export{j as a,Ae as b,Pe as c,ze as d,Ge as e,Ye as f,Je as g,Ke as h,et as i,tt as j,xt as k,Tt as l,bt as m,yt as n,St as o,Rt as p,Ct as q,vt as r,At as s,Pt as t,Dt as u,It as v,Ht as w,Lt as x};
@@ -1 +1 @@
1
- import{a as c}from"./chunk-E5HYNQ6D.js";import l from"fs";import k from"path";import T from"os";var g=c("settings"),u={editor:"nvim",defaultHarnessId:"claude-code",harnesses:{}},m=["nvim","vscode","cursor"];function S(){return k.join(T.homedir(),".octomux","settings.json")}var y=!1;async function p(){let e;try{let n=await l.promises.readFile(S(),"utf-8");e=JSON.parse(n)}catch(n){if(n.code==="ENOENT")return{...u};throw n}let r=e.harnesses??{},s={...r["claude-code"]??{}},a=!1;e.claudeFlags!==void 0&&s.flags===void 0&&(s.flags=e.claudeFlags,a=!0),e.dangerouslySkipPermissions!==void 0&&s.dangerouslySkipPermissions===void 0&&(s.dangerouslySkipPermissions=e.dangerouslySkipPermissions,a=!0);let t={...r,"claude-code":s},{listHarnesses:d}=await import("./harnesses-ABKYBCYK.js");for(let n of d())if(t[n.id])try{t[n.id]=n.validateSettings(t[n.id])}catch(o){g.warn({harness:n.id,err:o.message},"invalid harness settings; ignoring blob"),delete t[n.id]}return a&&!y&&(g.warn("settings.json contains deprecated top-level keys (claudeFlags, dangerouslySkipPermissions); they will be removed on next save"),y=!0),{editor:e.editor??u.editor,defaultHarnessId:e.defaultHarnessId??u.defaultHarnessId,harnesses:t,defaultTracker:e.defaultTracker==="jira"||e.defaultTracker==="linear"?e.defaultTracker:void 0,defaultJiraBaseUrl:typeof e.defaultJiraBaseUrl=="string"?e.defaultJiraBaseUrl:void 0,defaultJiraProjectKey:typeof e.defaultJiraProjectKey=="string"?e.defaultJiraProjectKey:void 0,defaultLinearTeamKey:typeof e.defaultLinearTeamKey=="string"?e.defaultLinearTeamKey:void 0,defaultBaseBranch:typeof e.defaultBaseBranch=="string"?e.defaultBaseBranch:void 0,onboardingCompletedAt:typeof e.onboardingCompletedAt=="string"?e.onboardingCompletedAt:void 0,deleteGraceHours:typeof e.deleteGraceHours=="number"?e.deleteGraceHours:void 0}}async function B(e){if(e.editor&&!m.includes(e.editor))throw new Error(`Invalid editor: ${e.editor}. Must be one of: ${m.join(", ")}`);if(e.deleteGraceHours!==void 0&&(!Number.isFinite(e.deleteGraceHours)||e.deleteGraceHours<0))throw new Error(`Invalid deleteGraceHours: ${e.deleteGraceHours}. Must be a number >= 0.`);if(e.defaultTracker!==void 0&&e.defaultTracker!=="jira"&&e.defaultTracker!=="linear")throw new Error(`Invalid defaultTracker: ${e.defaultTracker}. Must be 'jira' or 'linear'.`);let r=await p(),s={...r.harnesses},{listHarnesses:a,getHarness:t}=await import("./harnesses-ABKYBCYK.js");if(e.harnesses){let o=new Set(a().map(i=>i.id));for(let[i,f]of Object.entries(e.harnesses))o.has(i)?s[i]=t(i).validateSettings(f):s[i]=f}if(e.claudeFlags!==void 0||e.dangerouslySkipPermissions!==void 0){let i={...s["claude-code"]??{}};e.claudeFlags!==void 0&&(i.flags=e.claudeFlags),e.dangerouslySkipPermissions!==void 0&&(i.dangerouslySkipPermissions=e.dangerouslySkipPermissions),s["claude-code"]=t("claude-code").validateSettings(i)}let d={editor:e.editor??r.editor,defaultHarnessId:e.defaultHarnessId??r.defaultHarnessId,harnesses:s,defaultTracker:e.defaultTracker!==void 0?e.defaultTracker:r.defaultTracker,defaultJiraBaseUrl:e.defaultJiraBaseUrl!==void 0?e.defaultJiraBaseUrl:r.defaultJiraBaseUrl,defaultJiraProjectKey:e.defaultJiraProjectKey!==void 0?e.defaultJiraProjectKey:r.defaultJiraProjectKey,defaultLinearTeamKey:e.defaultLinearTeamKey!==void 0?e.defaultLinearTeamKey:r.defaultLinearTeamKey,defaultBaseBranch:e.defaultBaseBranch!==void 0?e.defaultBaseBranch:r.defaultBaseBranch,onboardingCompletedAt:e.onboardingCompletedAt!==void 0?e.onboardingCompletedAt:r.onboardingCompletedAt,deleteGraceHours:e.deleteGraceHours!==void 0?e.deleteGraceHours:r.deleteGraceHours},n=S();return await l.promises.mkdir(k.dirname(n),{recursive:!0}),await l.promises.writeFile(n,JSON.stringify(d,null,2),"utf-8"),d}function v(e){let r=process.env.OCTOMUX_CLAUDE_FLAGS?.trim();if(r)return` ${r}`;let s=e.harnesses?.["claude-code"]??{},a=[];s.dangerouslySkipPermissions&&a.push("--dangerously-skip-permissions");let t=(s.flags??"").trim();return t&&a.push(t),a.length>0?` ${a.join(" ")}`:""}export{u as a,p as b,B as c,v as d};
1
+ import{a as c}from"./chunk-E5HYNQ6D.js";import l from"fs";import k from"path";import T from"os";var g=c("settings"),u={editor:"nvim",defaultHarnessId:"claude-code",harnesses:{}},m=["nvim","vscode","cursor"];function S(){return k.join(T.homedir(),".octomux","settings.json")}var y=!1;async function p(){let e;try{let n=await l.promises.readFile(S(),"utf-8");e=JSON.parse(n)}catch(n){if(n.code==="ENOENT")return{...u};throw n}let r=e.harnesses??{},s={...r["claude-code"]??{}},a=!1;e.claudeFlags!==void 0&&s.flags===void 0&&(s.flags=e.claudeFlags,a=!0),e.dangerouslySkipPermissions!==void 0&&s.dangerouslySkipPermissions===void 0&&(s.dangerouslySkipPermissions=e.dangerouslySkipPermissions,a=!0);let t={...r,"claude-code":s},{listHarnesses:d}=await import("./harnesses-ZAGCSSES.js");for(let n of d())if(t[n.id])try{t[n.id]=n.validateSettings(t[n.id])}catch(o){g.warn({harness:n.id,err:o.message},"invalid harness settings; ignoring blob"),delete t[n.id]}return a&&!y&&(g.warn("settings.json contains deprecated top-level keys (claudeFlags, dangerouslySkipPermissions); they will be removed on next save"),y=!0),{editor:e.editor??u.editor,defaultHarnessId:e.defaultHarnessId??u.defaultHarnessId,harnesses:t,defaultTracker:e.defaultTracker==="jira"||e.defaultTracker==="linear"?e.defaultTracker:void 0,defaultJiraBaseUrl:typeof e.defaultJiraBaseUrl=="string"?e.defaultJiraBaseUrl:void 0,defaultJiraProjectKey:typeof e.defaultJiraProjectKey=="string"?e.defaultJiraProjectKey:void 0,defaultLinearTeamKey:typeof e.defaultLinearTeamKey=="string"?e.defaultLinearTeamKey:void 0,defaultBaseBranch:typeof e.defaultBaseBranch=="string"?e.defaultBaseBranch:void 0,onboardingCompletedAt:typeof e.onboardingCompletedAt=="string"?e.onboardingCompletedAt:void 0,deleteGraceHours:typeof e.deleteGraceHours=="number"?e.deleteGraceHours:void 0}}async function B(e){if(e.editor&&!m.includes(e.editor))throw new Error(`Invalid editor: ${e.editor}. Must be one of: ${m.join(", ")}`);if(e.deleteGraceHours!==void 0&&(!Number.isFinite(e.deleteGraceHours)||e.deleteGraceHours<0))throw new Error(`Invalid deleteGraceHours: ${e.deleteGraceHours}. Must be a number >= 0.`);if(e.defaultTracker!==void 0&&e.defaultTracker!=="jira"&&e.defaultTracker!=="linear")throw new Error(`Invalid defaultTracker: ${e.defaultTracker}. Must be 'jira' or 'linear'.`);let r=await p(),s={...r.harnesses},{listHarnesses:a,getHarness:t}=await import("./harnesses-ZAGCSSES.js");if(e.harnesses){let o=new Set(a().map(i=>i.id));for(let[i,f]of Object.entries(e.harnesses))o.has(i)?s[i]=t(i).validateSettings(f):s[i]=f}if(e.claudeFlags!==void 0||e.dangerouslySkipPermissions!==void 0){let i={...s["claude-code"]??{}};e.claudeFlags!==void 0&&(i.flags=e.claudeFlags),e.dangerouslySkipPermissions!==void 0&&(i.dangerouslySkipPermissions=e.dangerouslySkipPermissions),s["claude-code"]=t("claude-code").validateSettings(i)}let d={editor:e.editor??r.editor,defaultHarnessId:e.defaultHarnessId??r.defaultHarnessId,harnesses:s,defaultTracker:e.defaultTracker!==void 0?e.defaultTracker:r.defaultTracker,defaultJiraBaseUrl:e.defaultJiraBaseUrl!==void 0?e.defaultJiraBaseUrl:r.defaultJiraBaseUrl,defaultJiraProjectKey:e.defaultJiraProjectKey!==void 0?e.defaultJiraProjectKey:r.defaultJiraProjectKey,defaultLinearTeamKey:e.defaultLinearTeamKey!==void 0?e.defaultLinearTeamKey:r.defaultLinearTeamKey,defaultBaseBranch:e.defaultBaseBranch!==void 0?e.defaultBaseBranch:r.defaultBaseBranch,onboardingCompletedAt:e.onboardingCompletedAt!==void 0?e.onboardingCompletedAt:r.onboardingCompletedAt,deleteGraceHours:e.deleteGraceHours!==void 0?e.deleteGraceHours:r.deleteGraceHours},n=S();return await l.promises.mkdir(k.dirname(n),{recursive:!0}),await l.promises.writeFile(n,JSON.stringify(d,null,2),"utf-8"),d}function v(e){let r=process.env.OCTOMUX_CLAUDE_FLAGS?.trim();if(r)return` ${r}`;let s=e.harnesses?.["claude-code"]??{},a=[];s.dangerouslySkipPermissions&&a.push("--dangerously-skip-permissions");let t=(s.flags??"").trim();return t&&a.push(t),a.length>0?` ${a.join(" ")}`:""}export{u as a,p as b,B as c,v as d};
@@ -0,0 +1 @@
1
+ import{c as a}from"./chunk-5XTSTJXV.js";export{a as claudeCodeHarness};
@@ -0,0 +1 @@
1
+ import{e as d,f as e,g as f,h as g}from"./chunk-72XPVTY6.js";import"./chunk-GAXJZSQT.js";import{a,b,c}from"./chunk-5XTSTJXV.js";import"./chunk-E5HYNQ6D.js";export{e as DEFAULT_HARNESS_ID,c as claudeCodeHarness,d as cursorHarness,f as getHarness,g as listHarnesses,a as validateAgentName,b as validateFlagString};
@@ -0,0 +1 @@
1
+ import{a,b,c}from"./chunk-34KJHQCF.js";import"./chunk-G45FZHCE.js";import"./chunk-72XPVTY6.js";import"./chunk-GAXJZSQT.js";import"./chunk-5XTSTJXV.js";import"./chunk-E5HYNQ6D.js";export{b as ALLOWED_TOOLS,a as DENIED_TOOLS,c as installHookSettings};