bosun 0.41.7 → 0.41.9
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 +23 -1
- package/agent/agent-event-bus.mjs +31 -2
- package/agent/agent-pool.mjs +251 -11
- package/agent/agent-prompts.mjs +5 -1
- package/agent/agent-supervisor.mjs +22 -0
- package/agent/primary-agent.mjs +115 -5
- package/cli.mjs +3 -2
- package/config/config.mjs +4 -1
- package/desktop/main.mjs +350 -25
- package/desktop/preload.cjs +8 -0
- package/desktop/preload.mjs +19 -0
- package/entrypoint.mjs +332 -0
- package/infra/health-status.mjs +72 -0
- package/infra/library-manager.mjs +58 -1
- package/infra/maintenance.mjs +1 -2
- package/infra/monitor.mjs +25 -7
- package/infra/session-tracker.mjs +30 -3
- package/package.json +10 -4
- package/server/bosun-mcp-server.mjs +1004 -0
- package/server/setup-web-server.mjs +287 -258
- package/server/ui-server.mjs +218 -23
- package/shell/claude-shell.mjs +14 -1
- package/shell/codex-model-profiles.mjs +166 -29
- package/shell/codex-shell.mjs +56 -18
- package/shell/opencode-providers.mjs +20 -8
- package/task/task-executor.mjs +28 -0
- package/task/task-store.mjs +13 -4
- package/tools/list-todos.mjs +7 -1
- package/ui/app.js +3 -2
- package/ui/components/agent-selector.js +127 -0
- package/ui/components/session-list.js +2 -0
- package/ui/demo-defaults.js +6 -6
- package/ui/modules/router.js +2 -0
- package/ui/modules/state.js +13 -5
- package/ui/tabs/chat.js +3 -0
- package/ui/tabs/library.js +284 -52
- package/ui/tabs/tasks.js +5 -13
- package/workflow/workflow-engine.mjs +16 -4
- package/workflow/workflow-nodes/definitions.mjs +37 -0
- package/workflow/workflow-nodes.mjs +489 -153
- package/workflow/workflow-templates.mjs +0 -5
- package/workflow-templates/github.mjs +106 -16
- package/workspace/worktree-manager.mjs +1 -1
|
@@ -1622,6 +1622,8 @@ export const GITHUB_KANBAN_SYNC_TEMPLATE = {
|
|
|
1622
1622
|
node("fetch-pr-state", "action.run_command", "Fetch Bosun PR State", {
|
|
1623
1623
|
command: [
|
|
1624
1624
|
"node -e \"",
|
|
1625
|
+
"const fs=require('fs');",
|
|
1626
|
+
"const path=require('path');",
|
|
1625
1627
|
"const {execFileSync}=require('child_process');",
|
|
1626
1628
|
"const hours=Number('{{lookbackHours}}')||24;",
|
|
1627
1629
|
"const repoScope=String('{{repoScope}}'||'auto').trim();",
|
|
@@ -1630,18 +1632,79 @@ export const GITHUB_KANBAN_SYNC_TEMPLATE = {
|
|
|
1630
1632
|
" try{const o=execFileSync('gh',args,{encoding:'utf8',stdio:['pipe','pipe','pipe']}).trim();return o?JSON.parse(o):[];}",
|
|
1631
1633
|
" catch{return [];}",
|
|
1632
1634
|
"}",
|
|
1633
|
-
"
|
|
1634
|
-
"const
|
|
1635
|
+
"function configPath(){",
|
|
1636
|
+
" const home=String(process.env.BOSUN_HOME||process.env.VK_PROJECT_DIR||'').trim();",
|
|
1637
|
+
" return home?path.join(home,'bosun.config.json'):path.join(process.cwd(),'bosun.config.json');",
|
|
1638
|
+
"}",
|
|
1639
|
+
"function collectReposFromConfig(){",
|
|
1640
|
+
" const repos=[];",
|
|
1641
|
+
" try{",
|
|
1642
|
+
" const cfg=JSON.parse(fs.readFileSync(configPath(),'utf8'));",
|
|
1643
|
+
" const workspaces=Array.isArray(cfg?.workspaces)?cfg.workspaces:[];",
|
|
1644
|
+
" if(workspaces.length>0){",
|
|
1645
|
+
" const active=String(cfg?.activeWorkspace||'').trim().toLowerCase();",
|
|
1646
|
+
" const activeWs=active?workspaces.find(w=>String(w?.id||'').trim().toLowerCase()===active):null;",
|
|
1647
|
+
" const wsList=activeWs?[activeWs]:workspaces;",
|
|
1648
|
+
" for(const ws of wsList){",
|
|
1649
|
+
" for(const repo of (Array.isArray(ws?.repos)?ws.repos:[])){",
|
|
1650
|
+
" const slug=typeof repo==='string'?String(repo).trim():String(repo?.slug||'').trim();",
|
|
1651
|
+
" if(slug) repos.push(slug);",
|
|
1652
|
+
" }",
|
|
1653
|
+
" }",
|
|
1654
|
+
" }",
|
|
1655
|
+
" if(repos.length===0){",
|
|
1656
|
+
" for(const repo of (Array.isArray(cfg?.repos)?cfg.repos:[])){",
|
|
1657
|
+
" const slug=typeof repo==='string'?String(repo).trim():String(repo?.slug||'').trim();",
|
|
1658
|
+
" if(slug) repos.push(slug);",
|
|
1659
|
+
" }",
|
|
1660
|
+
" }",
|
|
1661
|
+
" }catch{}",
|
|
1662
|
+
" return repos;",
|
|
1663
|
+
"}",
|
|
1664
|
+
"function resolveRepoTargets(){",
|
|
1665
|
+
" if(repoScope&&repoScope!=='auto'&&repoScope!=='all'&&repoScope!=='current'){",
|
|
1666
|
+
" return [...new Set(repoScope.split(',').map(v=>v.trim()).filter(Boolean))];",
|
|
1667
|
+
" }",
|
|
1668
|
+
" if(repoScope==='current') return [''];",
|
|
1669
|
+
" const fromConfig=collectReposFromConfig();",
|
|
1670
|
+
" if(fromConfig.length>0) return [...new Set(fromConfig)];",
|
|
1671
|
+
" const envRepo=String(process.env.GITHUB_REPOSITORY||'').trim();",
|
|
1672
|
+
" if(envRepo) return [envRepo];",
|
|
1673
|
+
" return [''];",
|
|
1674
|
+
"}",
|
|
1675
|
+
"function parseRepoFromUrl(url){",
|
|
1676
|
+
" const raw=String(url||'');",
|
|
1677
|
+
" const marker='github.com/';",
|
|
1678
|
+
" const idx=raw.toLowerCase().indexOf(marker);",
|
|
1679
|
+
" if(idx<0) return '';",
|
|
1680
|
+
" const tail=raw.slice(idx+marker.length).split('/');",
|
|
1681
|
+
" if(tail.length<2) return '';",
|
|
1682
|
+
" const owner=String(tail[0]||'').trim();",
|
|
1683
|
+
" const repo=String(tail[1]||'').trim();",
|
|
1684
|
+
" return owner&&repo?(owner+'/'+repo):'';",
|
|
1685
|
+
"}",
|
|
1635
1686
|
"function extractTaskId(pr){",
|
|
1636
1687
|
" const src=String((pr.body||'')+'\\n'+(pr.title||''));",
|
|
1637
1688
|
" const m=src.match(/(?:Bosun-Task|VE-Task|Task-ID|task[_-]?id)[:\\s]+([a-zA-Z0-9_-]{4,64})/i);",
|
|
1638
1689
|
" return m?m[1].trim():null;",
|
|
1639
1690
|
"}",
|
|
1691
|
+
"const repoTargets=resolveRepoTargets();",
|
|
1692
|
+
"const merged=[];",
|
|
1693
|
+
"const open=[];",
|
|
1694
|
+
"for(const target of repoTargets){",
|
|
1695
|
+
" const repo=String(target||'').trim();",
|
|
1696
|
+
" const mergedArgs=['pr','list','--state','merged','--label','bosun-attached','--json','number,title,body,headRefName,mergedAt,url','--limit','50'];",
|
|
1697
|
+
" const openArgs=['pr','list','--state','open','--label','bosun-attached','--json','number,title,body,headRefName,isDraft,url','--limit','50'];",
|
|
1698
|
+
" if(repo){ mergedArgs.push('--repo',repo); openArgs.push('--repo',repo); }",
|
|
1699
|
+
" for(const pr of ghJson(mergedArgs)){ merged.push({...pr,__repo:repo||parseRepoFromUrl(pr?.url)||String(process.env.GITHUB_REPOSITORY||'').trim()}); }",
|
|
1700
|
+
" for(const pr of ghJson(openArgs)){ open.push({...pr,__repo:repo||parseRepoFromUrl(pr?.url)||String(process.env.GITHUB_REPOSITORY||'').trim()}); }",
|
|
1701
|
+
"}",
|
|
1640
1702
|
"const recentMerged=merged.filter(p=>!p.mergedAt||new Date(p.mergedAt)>=new Date(since));",
|
|
1641
1703
|
"console.log(JSON.stringify({",
|
|
1642
1704
|
" repoScope,",
|
|
1643
|
-
"
|
|
1644
|
-
"
|
|
1705
|
+
" reposScanned: repoTargets.length,",
|
|
1706
|
+
" merged:recentMerged.map(p=>({n:p.number,repo:p.__repo||'',title:p.title,branch:p.headRefName,taskId:extractTaskId(p)})),",
|
|
1707
|
+
" open:open.filter(p=>!p.isDraft).map(p=>({n:p.number,repo:p.__repo||'',title:p.title,branch:p.headRefName,taskId:extractTaskId(p)})),",
|
|
1645
1708
|
"}));",
|
|
1646
1709
|
"\"",
|
|
1647
1710
|
].join(" "),
|
|
@@ -1667,27 +1730,54 @@ export const GITHUB_KANBAN_SYNC_TEMPLATE = {
|
|
|
1667
1730
|
"const merged=Array.isArray(data.merged)?data.merged:[];",
|
|
1668
1731
|
"const open=Array.isArray(data.open)?data.open:[];",
|
|
1669
1732
|
"const updates=[]; const unresolved=[];",
|
|
1733
|
+
"const maxBuffer=25*1024*1024;",
|
|
1734
|
+
"const cliPath=fs.existsSync('cli.mjs')?'cli.mjs':'';",
|
|
1670
1735
|
"const taskCli=['task-cli.mjs','task/task-cli.mjs'].find(p=>fs.existsSync(p))||'';",
|
|
1671
|
-
"
|
|
1672
|
-
"
|
|
1736
|
+
"const taskRunner=cliPath?'cli':(taskCli?'task-cli':'');",
|
|
1737
|
+
"if(!taskRunner){",
|
|
1738
|
+
" console.log(JSON.stringify({updated:0,unresolved:[{reason:'task_command_missing'}],needsAgent:true}));",
|
|
1673
1739
|
" process.exit(0);",
|
|
1674
1740
|
"}",
|
|
1675
|
-
"function runTask(args){
|
|
1676
|
-
"function parseJsonObject(raw){const txt=String(raw||'').trim();if(!txt)return null;try{return JSON.parse(txt);}catch{}const lines=txt.split(/\\r?\\n/).map(s=>s.trim()).filter(Boolean);for(let i=
|
|
1741
|
+
"function runTask(args){const cmdArgs=taskRunner==='cli'?['cli.mjs','task',...args,'--config-dir','.bosun','--repo-root','.']:[taskCli,...args];return execFileSync('node',cmdArgs,{encoding:'utf8',stdio:['pipe','pipe','pipe'],maxBuffer}).trim();}",
|
|
1742
|
+
"function parseJsonObject(raw){const txt=String(raw||'').trim();if(!txt)return null;try{return JSON.parse(txt);}catch{}const lines=txt.split(/\\r?\\n/);for(let start=0;start<lines.length;start++){const token=lines[start].trim();if(!(token==='['||token==='{'||token.startsWith('[{')||token.startsWith('{\"')||token.startsWith('[\"')))continue;const candidate=lines.slice(start).join('\\n').trim();try{return JSON.parse(candidate);}catch{}}const compact=lines.map(s=>s.trim()).filter(Boolean);for(let i=compact.length-1;i>=0;i--){const line=compact[i];if(!(line.startsWith('{')||line.startsWith('[')))continue;try{return JSON.parse(line);}catch{}}const start=txt.indexOf('{');const end=txt.lastIndexOf('}');if(start>=0&&end>start){try{return JSON.parse(txt.slice(start,end+1));}catch{}}return null;}",
|
|
1743
|
+
"let taskListCache=null;",
|
|
1744
|
+
"function normalizeRepo(value){return String(value||'').trim().toLowerCase();}",
|
|
1745
|
+
"function listTasks(){",
|
|
1746
|
+
" if(Array.isArray(taskListCache)) return taskListCache;",
|
|
1747
|
+
" try{const raw=runTask(['list','--json']);const tasks=parseJsonObject(raw);taskListCache=Array.isArray(tasks)?tasks:[];return taskListCache;}catch{taskListCache=[];return taskListCache;}",
|
|
1748
|
+
"}",
|
|
1749
|
+
"function resolveTaskId(item){",
|
|
1750
|
+
" const explicit=String(item?.taskId||'').trim();",
|
|
1751
|
+
" if(explicit) return explicit;",
|
|
1752
|
+
" const branch=String(item?.branch||'').trim();",
|
|
1753
|
+
" if(!branch) return '';",
|
|
1754
|
+
" const repo=normalizeRepo(item?.repo);",
|
|
1755
|
+
" const matches=listTasks().filter((task)=>{",
|
|
1756
|
+
" const taskBranch=String(task?.branchName||'').trim();",
|
|
1757
|
+
" if(taskBranch!==branch) return false;",
|
|
1758
|
+
" const taskRepo=normalizeRepo(task?.repository||'');",
|
|
1759
|
+
" if(!repo || !taskRepo) return true;",
|
|
1760
|
+
" return taskRepo===repo;",
|
|
1761
|
+
" });",
|
|
1762
|
+
" if(matches.length===1) return String(matches[0]?.id||'').trim();",
|
|
1763
|
+
" const exactRepo=matches.find((task)=>normalizeRepo(task?.repository||'')===repo);",
|
|
1764
|
+
" return exactRepo?String(exactRepo?.id||'').trim():'';",
|
|
1765
|
+
"}",
|
|
1677
1766
|
"function getTaskSnapshot(id){",
|
|
1678
1767
|
" try{const raw=runTask(['get',id,'--json']);const task=parseJsonObject(raw);return {status:task?.status||null,reviewStatus:task?.reviewStatus||null};}catch{return {status:null,reviewStatus:null};}",
|
|
1679
1768
|
"}",
|
|
1680
1769
|
"for(const item of merged){",
|
|
1681
|
-
" const id=
|
|
1682
|
-
" if(!id)
|
|
1770
|
+
" const id=resolveTaskId(item);",
|
|
1771
|
+
" if(!id){unresolved.push({taskId:null,repo:String(item?.repo||''),branch:String(item?.branch||''),status:'done',reason:'task_lookup_failed'});continue;}",
|
|
1683
1772
|
" try{runTask(['update',id,'--status','done']);updates.push({taskId:id,status:'done'});}catch(e){unresolved.push({taskId:id,status:'done',error:String(e?.message||e)});}",
|
|
1684
1773
|
"}",
|
|
1685
1774
|
"for(const item of open){",
|
|
1686
|
-
" const id=
|
|
1687
|
-
" if(!id)
|
|
1688
|
-
" try{const snap=getTaskSnapshot(id);const current=snap?.status;const review=String(snap?.reviewStatus||'').toLowerCase();if(current==='inreview'||current==='done'){updates.push({taskId:id,status:current,skipped:true});continue;}
|
|
1775
|
+
" const id=resolveTaskId(item);",
|
|
1776
|
+
" if(!id){unresolved.push({taskId:null,repo:String(item?.repo||''),branch:String(item?.branch||''),status:'inreview',reason:'task_lookup_failed'});continue;}",
|
|
1777
|
+
" try{const snap=getTaskSnapshot(id);const current=String(snap?.status||'').trim().toLowerCase();const review=String(snap?.reviewStatus||'').toLowerCase();if(current==='inreview'||current==='done'){updates.push({taskId:id,status:current,skipped:true});continue;}runTask(['update',id,'--status','inreview']);updates.push({taskId:id,status:'inreview',fromStatus:current||null,reviewStatus:review||null});}catch(e){unresolved.push({taskId:id,status:'inreview',error:String(e?.message||e)});}",
|
|
1689
1778
|
"}",
|
|
1690
|
-
"
|
|
1779
|
+
"const actionableUnresolved=unresolved.filter((item)=>String(item?.taskId||'').trim());",
|
|
1780
|
+
"console.log(JSON.stringify({updated:updates.length,updates,unresolved,needsAgent:actionableUnresolved.length>0}));",
|
|
1691
1781
|
"\"",
|
|
1692
1782
|
].join(" "),
|
|
1693
1783
|
continueOnError: true,
|
|
@@ -1703,7 +1793,8 @@ export const GITHUB_KANBAN_SYNC_TEMPLATE = {
|
|
|
1703
1793
|
"(()=>{try{" +
|
|
1704
1794
|
"const raw=$ctx.getNodeOutput('sync-programmatic')?.output||'{}';" +
|
|
1705
1795
|
"const d=JSON.parse(raw);" +
|
|
1706
|
-
"
|
|
1796
|
+
"const actionable=Array.isArray(d?.unresolved)?d.unresolved.some((item)=>String(item?.taskId||'').trim()):false;" +
|
|
1797
|
+
"return d?.needsAgent===true || actionable;" +
|
|
1707
1798
|
"}catch{return true;}})()",
|
|
1708
1799
|
}, { x: 400, y: 615 }),
|
|
1709
1800
|
|
|
@@ -2002,4 +2093,3 @@ export const SDK_CONFLICT_RESOLVER_TEMPLATE = {
|
|
|
2002
2093
|
},
|
|
2003
2094
|
},
|
|
2004
2095
|
};
|
|
2005
|
-
|
|
@@ -599,7 +599,7 @@ class WorktreeManager {
|
|
|
599
599
|
const detection = detectProjectStack(worktreePath);
|
|
600
600
|
if (!detection?.primary) return;
|
|
601
601
|
|
|
602
|
-
const plan = buildBootstrapPlan(worktreePath, policy, detection);
|
|
602
|
+
const plan = buildBootstrapPlan(worktreePath, policy, detection, this.repoRoot);
|
|
603
603
|
ensureWorktreeSharedPaths(this.repoRoot, worktreePath, plan.sharedPaths);
|
|
604
604
|
|
|
605
605
|
const signature = buildBootstrapSignature(plan);
|