claude-code-session-manager 0.121.0 → 0.122.0

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.
Files changed (76) hide show
  1. package/dist/assets/{AgentLibrary-FO2ei2wB.js → AgentLibrary-BmJ8hIPw.js} +1 -1
  2. package/dist/assets/{Button-CeIOXUPU.js → Button-BS4kmz4p.js} +1 -1
  3. package/dist/assets/{DataModel-D0p__Hil.js → DataModel-DZHBZrfL.js} +1 -1
  4. package/dist/assets/History-pg00b2Gd.js +2 -0
  5. package/dist/assets/{Hooks-DkTnRHyT.js → Hooks-BTEs0UZY.js} +1 -1
  6. package/dist/assets/{Library-l7KS6pkE.js → Library-DuaJ-VSn.js} +1 -1
  7. package/dist/assets/{ListDetail-DDw8fuRT.js → ListDetail-Cud72s-O.js} +1 -1
  8. package/dist/assets/{McpServers-UUNIxk_3.js → McpServers-Dy-wnG_X.js} +1 -1
  9. package/dist/assets/{Memory-CNYUoQ8C.js → Memory-Bs1T1Jo7.js} +1 -1
  10. package/dist/assets/{Panel-Bb54soc2.js → Panel-8UhLXEOW.js} +1 -1
  11. package/dist/assets/{Permissions-D-dNdV3f.js → Permissions-BfwzvmBS.js} +1 -1
  12. package/dist/assets/Plugins-McjyvvKh.js +2 -0
  13. package/dist/assets/{ProvenanceBadge-DEAkDNjA.js → ProvenanceBadge-D0Ov_6WJ.js} +1 -1
  14. package/dist/assets/{RemoteMachines-xCEgvTGU.js → RemoteMachines-gOlFTvWq.js} +1 -1
  15. package/dist/assets/{SaveBar-BSEs7ecA.js → SaveBar-Cd6hJR6K.js} +1 -1
  16. package/dist/assets/Scheduler-BZXKqYJP.js +16 -0
  17. package/dist/assets/{ScopeSwitcher-DcaFyAV-.js → ScopeSwitcher-C24ysV1K.js} +1 -1
  18. package/dist/assets/{Settings-vcdWy_Jx.js → Settings-DWnN2qxn.js} +1 -1
  19. package/dist/assets/{SkillReferenceGraph-CLrJWTPd.js → SkillReferenceGraph-BsWuiTbw.js} +1 -1
  20. package/dist/assets/{Skills-CYM4rBEC.js → Skills-6pHn6glu.js} +1 -1
  21. package/dist/assets/{SystemPrompt-BWNIu-iY.js → SystemPrompt-DT0LBH-K.js} +1 -1
  22. package/dist/assets/{TagLibrary-CYdwHK6m.js → TagLibrary-DbJ0zbYL.js} +1 -1
  23. package/dist/assets/{TiptapBody-Kt90lHrD.js → TiptapBody-C4kIvIMH.js} +1 -1
  24. package/dist/assets/{Toggle-D1OXWYOz.js → Toggle-pP19zlyk.js} +1 -1
  25. package/dist/assets/{ViewTabs-BeQR3CKh.js → ViewTabs-CpzN8e5I.js} +1 -1
  26. package/dist/assets/{historyTotals-B0qafrRo.js → historyTotals-Caq78bb5.js} +1 -1
  27. package/dist/assets/{index-Bq9uH08R.js → index-Bjtguv6I.js} +396 -396
  28. package/dist/assets/{settingsSchema-0ZksSAPB.js → settingsSchema-CC2ySu3d.js} +1 -1
  29. package/dist/assets/{skillFrontmatter-C0nh8yfa.js → skillFrontmatter-hDhNo8jE.js} +1 -1
  30. package/dist/assets/{useAgentsDirWatch-DPkoBybS.js → useAgentsDirWatch-BuOtY25U.js} +1 -1
  31. package/dist/assets/{useRemotePeers-BDJMUihy.js → useRemotePeers-CNQmRBpt.js} +1 -1
  32. package/dist/index.html +1 -1
  33. package/package.json +1 -1
  34. package/plugins/session-manager-dev/skills/develop/SKILL.md +7 -7
  35. package/plugins/session-manager-dev/skills/develop/standards.md +4 -10
  36. package/scripts/scheduler-mcp-server.cjs +2 -2
  37. package/src/main/build-info.json +4 -4
  38. package/src/main/chatRunner.cjs +13 -37
  39. package/src/main/docEdit.cjs +1 -0
  40. package/src/main/index.cjs +12 -13
  41. package/src/main/ipcSchemas.cjs +2 -2
  42. package/src/main/lib/classifyPromptTicket.cjs +1 -0
  43. package/src/main/lib/claude/effectiveModelInfo.cjs +9 -21
  44. package/src/main/lib/claude/personaToolScope.cjs +7 -1
  45. package/src/main/lib/claude/runClaudeP.cjs +1 -0
  46. package/src/main/lib/epic/delegationReadiness.cjs +75 -8
  47. package/src/main/lib/mcpToolCatalog.cjs +0 -1
  48. package/src/main/lib/persona-macro/shippedPersonaSeeds.cjs +11 -0
  49. package/src/main/lib/prd/prdCreate.cjs +3 -1
  50. package/src/main/lib/prd/prdSizing.cjs +1 -8
  51. package/src/main/lib/runSeeders.cjs +21 -0
  52. package/src/main/lib/scheduler/loopEfficiency.cjs +109 -0
  53. package/src/main/lib/scheduler/queueHistory.cjs +44 -1
  54. package/src/main/lib/scheduler/queueStore.cjs +4 -72
  55. package/src/main/lib/scheduler/rcaReport.cjs +1 -1
  56. package/src/main/lib/scheduler/refireCap.cjs +40 -0
  57. package/src/main/lib/scheduler/reviewNotice.cjs +1 -1
  58. package/src/main/lib/scheduler/schedulerConfig.cjs +1 -2
  59. package/src/main/lib/scheduler/schedulerPaths.cjs +0 -2
  60. package/src/main/lib/scheduler/sessionSlots.cjs +1 -1
  61. package/src/main/lib/telemetry/auditLog.cjs +65 -14
  62. package/src/main/loopEfficiencyHandlers.cjs +160 -0
  63. package/src/main/queueOps.cjs +4 -9
  64. package/src/main/runVerify.cjs +22 -454
  65. package/src/main/scheduler/reviewLadder.cjs +12 -2
  66. package/src/main/scheduler.cjs +103 -177
  67. package/src/main/seedDevPlugin.cjs +49 -22
  68. package/src/main/seedStatus.cjs +3 -2
  69. package/src/main/supervisor.cjs +1 -0
  70. package/src/main/templates/PRD_AUTHORING.md +16 -31
  71. package/src/preload/api.d.ts +26 -6
  72. package/src/preload/index.cjs +1 -0
  73. package/src/seed/agents/dev-lead.md +2 -9
  74. package/dist/assets/History-DVqQ5azN.js +0 -2
  75. package/dist/assets/Plugins-DhcIXRhQ.js +0 -2
  76. package/dist/assets/Scheduler-BIKJIU-C.js +0 -16
@@ -1 +1 @@
1
- import{aF as b,ap as n,S as N,a_ as O}from"./index-Bq9uH08R.js";import{r as K}from"./claude-settings-schema-COigsajx.js";function G({node:e,targetScope:r,onOverride:s,schema:a,rootLabel:m}){const[f,x]=b.useState(""),[u,o]=b.useState(!0),g=[],d=e.kind==="object"&&Object.keys(e.children).length===0,y=((a==null?void 0:a.rootKeys())??[]).length>0;return n.jsxs("div",{className:"h-full flex flex-col",children:[n.jsxs("div",{className:"shrink-0 border-b border-line bg-bg-elev px-3 py-1.5 flex items-center gap-2 text-xs",children:[n.jsxs("span",{className:"text-fg-faint",children:["merged · overrides → ",n.jsx("span",{className:"text-fg-dim",children:N[r].label})]}),y&&n.jsxs("label",{className:"flex items-center gap-1 text-fg-faint cursor-pointer",children:[n.jsx("input",{type:"checkbox",checked:u,onChange:t=>o(t.target.checked),className:"accent-accent"}),"show unset keys"]}),n.jsx("div",{className:"flex-1"}),n.jsx("input",{value:f,onChange:t=>x(t.target.value),placeholder:"filter keys or descriptions…",className:"bg-bg border border-line rounded px-2 py-0.5 text-xs text-fg w-56"})]}),n.jsx("div",{className:"flex-1 overflow-auto px-3 py-2 font-mono text-xs",children:d&&!u?n.jsx("div",{className:"text-fg-faint italic px-2 py-4",children:"no settings resolved — all scope files empty or missing"}):n.jsx(E,{node:e,path:g,label:m??"(root)",targetScope:r,onOverride:s,filter:f,depth:0,schema:a,showGhosts:u,defaultOpen:!0})})]})}function E(e){return e.node.kind==="object"?n.jsx(P,{...e,node:e.node}):e.node.kind==="array"?n.jsx(J,{...e,node:e.node}):n.jsx(R,{...e,node:e.node})}function A(e,r){return r.trim()?e.toLowerCase().includes(r.toLowerCase()):!0}function w(e,r,s){return!!(!s.trim()||e.some(a=>A(a,s))||r!=null&&r.description&&A(r.description,s))}function P({node:e,path:r,label:s,targetScope:a,onOverride:m,filter:f,depth:x,schema:u,showGhosts:o,defaultOpen:g}){const[d,h]=b.useState(g??x<2),y=(u==null?void 0:u.at(r))??null,t=new Set(Object.keys(e.children)),i=o?(y==null?void 0:y.knownChildren)??[]:[],c=Array.from(new Set([...t,...i])).sort(),l=b.useMemo(()=>f.trim()?c.filter(p=>{const v=(u==null?void 0:u.at([...r,p]))??null;return w([...r,p],v,f)?!0:t.has(p)?L(e.children[p],[...r,p],f,u):!1}):c,[c.join(","),f,e,r.join("."),u]);if(f.trim()&&l.length===0&&!w(r,y,f))return null;if(r.length===0)return n.jsx("div",{children:l.map(p=>j(p))});return n.jsxs("div",{children:[n.jsxs("div",{className:"flex items-center gap-1 py-0.5 hover:bg-bg-elev/50 rounded cursor-pointer",style:{paddingLeft:x*14},onClick:()=>h(!d),children:[n.jsx("span",{className:"text-fg-faint w-3 shrink-0",children:d?"▾":"▸"}),n.jsx("span",{className:"text-fg",children:s}),n.jsxs("span",{className:"text-fg-faint",children:[" {",t.size,i.length>t.size?`/${new Set([...t,...i]).size}`:"","}"]}),(y==null?void 0:y.description)&&n.jsxs("span",{className:"text-fg-faint truncate max-w-md",title:y.description,children:["— ",y.description]})]}),d&&l.map(p=>j(p))]});function j(p){if(t.has(p))return n.jsx(E,{node:e.children[p],path:[...r,p],label:p,targetScope:a,onOverride:m,filter:f,depth:x+1,schema:u,showGhosts:o},p);const v=(u==null?void 0:u.at([...r,p]))??null;return v?n.jsx(_,{path:[...r,p],label:p,info:v,targetScope:a,onSet:m,depth:x+1,filter:f},p):null}}function L(e,r,s,a){const m=(a==null?void 0:a.at(r))??null;if(w(r,m,s))return!0;if(e.kind!=="object")return!1;for(const f of Object.keys(e.children))if(L(e.children[f],[...r,f],s,a))return!0;return!1}function J({node:e,path:r,label:s,filter:a,depth:m,schema:f}){const[x,u]=b.useState(!0),o=(f==null?void 0:f.at(r))??null;return w(r,o,a)?n.jsxs("div",{children:[n.jsxs("div",{className:"flex items-center gap-1 py-0.5 hover:bg-bg-elev/50 rounded cursor-pointer",style:{paddingLeft:m*14},onClick:()=>u(!x),children:[n.jsx("span",{className:"text-fg-faint w-3 shrink-0",children:x?"▾":"▸"}),n.jsx("span",{className:"text-fg",children:s}),n.jsxs("span",{className:"text-fg-faint",children:[" [",e.items.length,"]"]}),n.jsx(S,{tone:"warn",children:"accumulated"}),(o==null?void 0:o.description)&&n.jsxs("span",{className:"text-fg-faint truncate max-w-md",title:o.description,children:["— ",o.description]})]}),x&&e.items.map((g,d)=>n.jsxs("div",{className:"flex items-start gap-2 py-0.5",style:{paddingLeft:(m+1)*14},children:[n.jsx("span",{className:"text-fg-faint w-3 shrink-0"}),n.jsxs("span",{className:"text-fg-faint",children:[d,":"]}),n.jsx("span",{className:"text-fg-dim truncate max-w-xl",children:k(g.value)}),n.jsx(C,{scope:g.fromScope})]},d))]}):null}function R({node:e,path:r,label:s,targetScope:a,onOverride:m,filter:f,depth:x,schema:u}){const[o,g]=b.useState(!1),d=(u==null?void 0:u.at(r))??null;if(!w(r,d,f))return null;const h=e.winner!==a,y=e.shadowed.length>0;return n.jsxs("div",{children:[n.jsxs("div",{className:"group flex items-center gap-2 py-0.5 hover:bg-bg-elev/50 rounded",style:{paddingLeft:x*14},children:[n.jsx("span",{className:`w-3 shrink-0 ${y?"text-fg-faint cursor-pointer":""}`,onClick:()=>y&&g(!o),children:y?o?"▾":"▸":""}),n.jsxs("span",{className:"text-fg",children:[s,":"]}),n.jsx("span",{className:"text-fg-dim truncate max-w-md",children:k(e.value)}),n.jsx(C,{scope:e.winner}),(d==null?void 0:d.deprecated)&&n.jsx(S,{tone:"warn",children:"deprecated"}),(d==null?void 0:d.default)!==void 0&&I(e.value,d.default)&&n.jsx(S,{tone:"dim",children:"= default"}),e.typeMismatch&&n.jsx("span",{className:"text-yellow-500/80",title:"shadowed scopes have a different value type",children:"⚠"}),(d==null?void 0:d.description)&&n.jsxs("span",{className:"text-fg-faint truncate max-w-md",title:d.description,children:["— ",d.description]}),n.jsx("div",{className:"flex-1"}),(d==null?void 0:d.enum)&&n.jsx(F,{values:d.enum}),n.jsx("button",{disabled:!h,onClick:()=>m(r,e.value),className:`opacity-0 group-hover:opacity-100 px-1.5 py-0 text-[10px] border rounded transition-opacity ${h?"border-accent/50 text-accent hover:bg-accent hover:text-bg":"border-line text-fg-faint cursor-not-allowed"}`,title:h?`copy into ${N[a].label} draft`:`already winning in ${N[a].label}`,children:"override"})]}),o&&e.shadowed.map((t,i)=>n.jsxs("div",{className:"flex items-center gap-2 py-0.5 text-fg-faint line-through",style:{paddingLeft:(x+1)*14+12},children:[n.jsx("span",{children:"shadowed:"}),n.jsx("span",{className:"truncate max-w-xl",children:k(t.value)}),n.jsx(C,{scope:t.scope,dim:!0})]},i))]})}function _({path:e,label:r,info:s,targetScope:a,onSet:m,depth:f,filter:x}){if(!w(e,s,x))return null;const u=s.default!==void 0?s.default:M(s.type),o=Array.isArray(s.type)?s.type.join("|"):s.type??"?";return n.jsxs("div",{className:"group flex items-center gap-2 py-0.5 hover:bg-bg-elev/50 rounded opacity-60",style:{paddingLeft:f*14},children:[n.jsx("span",{className:"w-3 shrink-0"}),n.jsx("span",{className:"text-fg-dim",children:r}),n.jsx(S,{tone:"dim",children:o}),s.required&&n.jsx(S,{tone:"warn",children:"required"}),s.default!==void 0&&n.jsxs("span",{className:"text-fg-faint",children:["default: ",k(s.default)]}),s.description&&n.jsxs("span",{className:"text-fg-faint truncate max-w-md",title:s.description,children:["— ",s.description]}),n.jsx("div",{className:"flex-1"}),s.enum&&n.jsx(F,{values:s.enum}),n.jsx("button",{onClick:()=>m(e,u),className:"opacity-0 group-hover:opacity-100 px-1.5 py-0 text-[10px] border border-accent/50 rounded text-accent hover:bg-accent hover:text-bg transition-opacity",title:`write to ${N[a].label} draft`,children:"set"})]})}function I(e,r){return e===r?!0:typeof e!=typeof r?!1:e&&r&&typeof e=="object"?JSON.stringify(e)===JSON.stringify(r):!1}function M(e){switch(Array.isArray(e)?e[0]:e){case"boolean":return!1;case"integer":case"number":return 0;case"string":return"";case"array":return[];case"object":return{};case"null":return null;default:return null}}function k(e){if(typeof e=="string")return JSON.stringify(e);if(e===null)return"null";if(typeof e=="object"){const r=JSON.stringify(e);return r.length>100?r.slice(0,100)+"…":r}return String(e)}function C({scope:e,dim:r}){const s=e==="user"?"bg-bg-hi text-fg-dim border-line":e==="project"?"bg-blue-950/30 text-blue-400/80 border-blue-900/40":"bg-purple-950/30 text-purple-400/80 border-purple-900/40";return n.jsx("span",{className:`text-[10px] px-1 py-0 rounded border uppercase tracking-wide shrink-0 ${s} ${r?"opacity-60":""}`,children:N[e].label})}function S({children:e,tone:r="default"}){const s={default:"bg-bg-hi text-fg-dim border-line",warn:"bg-yellow-950/30 text-yellow-500/80 border-yellow-900/40",dim:"bg-bg-elev text-fg-faint border-line"}[r];return n.jsx("span",{className:`text-[10px] px-1 py-0 rounded border uppercase tracking-wide shrink-0 ${s}`,children:e})}function F({values:e}){const r=e.map(s=>String(s)).join(" | ");return n.jsxs("span",{className:"text-[10px] text-fg-faint truncate max-w-xs",title:`allowed: ${r}`,children:["∈ ",r.length>30?r.slice(0,30)+"…":r]})}function V(e,r,s){const a=O(o=>o.files),m=O(o=>o.loadJson),f=O(o=>o.watchFile),x=O(o=>o.unwatchFile),u=b.useMemo(()=>{const o={};for(const g of e.scopes){const d=e.resolve(g,r??"",s);d&&(o[g]=d)}return o},[e,r,s]);return b.useEffect(()=>{const o=Object.values(u).filter(Boolean);return o.forEach(g=>{a[g]||m(g),f(g)}),()=>{o.forEach(g=>x(g))}},[JSON.stringify(u)]),u}function B(e){const r=e??{},s={...r.$defs??{},...r.definitions??{}},a=t=>{if(!t)return{};if(!t.$ref)return x(t);const i=/^#\/(\$defs|definitions)\/(.+)$/.exec(t.$ref);if(!i)return x(t);const c=s[i[2]];return c?a({...c,...u(t)}):x(t)},m=new Set(["__proto__","constructor","prototype"]),f=t=>{if(!t)return{};const i={};for(const[c,l]of Object.entries(t))m.has(c)||(i[c]=l);return i},x=t=>{if(!t.allOf||t.allOf.length===0)return t;const i={...t};delete i.allOf;for(const c of t.allOf){const l=a(c);Object.assign(i,{properties:{...f(i.properties),...f(l.properties)},required:q([...i.required??[],...l.required??[]])}),!i.description&&l.description&&(i.description=l.description),i.default===void 0&&l.default!==void 0&&(i.default=l.default),!i.type&&l.type&&(i.type=l.type)}return i},u=t=>{const{$ref:i,...c}=t;return c},o=(t,i)=>{let c=a(t);for(const l of i){if(!c)return null;if(/^\d+$/.test(l)){const v=Array.isArray(c.items)?c.items[Number(l)]:c.items;c=v?a(v):null;continue}const j=c.properties;if(j&&!m.has(l)&&l in j){c=a(j[l]);continue}const p=c.additionalProperties;if(p&&typeof p=="object"){c=a(p);continue}return null}return c},g=(t,i,c)=>{if(!t)return null;const l={};if(t.description&&(l.description=t.description),t.type&&(l.type=t.type),t.default!==void 0&&(l.default=t.default),t.enum&&(l.enum=t.enum),t.const!==void 0&&(l.const=t.const),t.deprecated&&(l.deprecated=!0),t.examples&&(l.examples=t.examples),t.properties&&(l.knownChildren=Object.keys(t.properties)),c&&(i!=null&&i.includes(c))&&(l.required=!0),t.items&&!Array.isArray(t.items)){const j=a(t.items),p=g(j,void 0,null);p&&(l.itemsInfo=p)}return(t.additionalProperties===!0||typeof t.additionalProperties=="object")&&(l.open=!0),l},d=t=>i=>{if(i.length===0)return g(a(t),void 0,null);const c=o(t,i.slice(0,-1));if(!c)return null;const l=i[i.length-1],j=o(c,[l]);return g(j,c.required,l)},h=t=>{const i=a(t);return Object.keys(i.properties??{})},y=t=>({at:d(t),rootKeys:()=>h(t),rootedAt:i=>{const c=o(t,i);return y(c??{})}});return y(r)}function q(e){return Array.from(new Set(e))}let $=null;function D(){return $||($=B(K)),$}export{G as E,D as s,V as u};
1
+ import{aF as b,ap as n,S as N,a_ as O}from"./index-Bjtguv6I.js";import{r as K}from"./claude-settings-schema-COigsajx.js";function G({node:e,targetScope:r,onOverride:s,schema:a,rootLabel:m}){const[f,x]=b.useState(""),[u,o]=b.useState(!0),g=[],d=e.kind==="object"&&Object.keys(e.children).length===0,y=((a==null?void 0:a.rootKeys())??[]).length>0;return n.jsxs("div",{className:"h-full flex flex-col",children:[n.jsxs("div",{className:"shrink-0 border-b border-line bg-bg-elev px-3 py-1.5 flex items-center gap-2 text-xs",children:[n.jsxs("span",{className:"text-fg-faint",children:["merged · overrides → ",n.jsx("span",{className:"text-fg-dim",children:N[r].label})]}),y&&n.jsxs("label",{className:"flex items-center gap-1 text-fg-faint cursor-pointer",children:[n.jsx("input",{type:"checkbox",checked:u,onChange:t=>o(t.target.checked),className:"accent-accent"}),"show unset keys"]}),n.jsx("div",{className:"flex-1"}),n.jsx("input",{value:f,onChange:t=>x(t.target.value),placeholder:"filter keys or descriptions…",className:"bg-bg border border-line rounded px-2 py-0.5 text-xs text-fg w-56"})]}),n.jsx("div",{className:"flex-1 overflow-auto px-3 py-2 font-mono text-xs",children:d&&!u?n.jsx("div",{className:"text-fg-faint italic px-2 py-4",children:"no settings resolved — all scope files empty or missing"}):n.jsx(E,{node:e,path:g,label:m??"(root)",targetScope:r,onOverride:s,filter:f,depth:0,schema:a,showGhosts:u,defaultOpen:!0})})]})}function E(e){return e.node.kind==="object"?n.jsx(P,{...e,node:e.node}):e.node.kind==="array"?n.jsx(J,{...e,node:e.node}):n.jsx(R,{...e,node:e.node})}function A(e,r){return r.trim()?e.toLowerCase().includes(r.toLowerCase()):!0}function w(e,r,s){return!!(!s.trim()||e.some(a=>A(a,s))||r!=null&&r.description&&A(r.description,s))}function P({node:e,path:r,label:s,targetScope:a,onOverride:m,filter:f,depth:x,schema:u,showGhosts:o,defaultOpen:g}){const[d,h]=b.useState(g??x<2),y=(u==null?void 0:u.at(r))??null,t=new Set(Object.keys(e.children)),i=o?(y==null?void 0:y.knownChildren)??[]:[],c=Array.from(new Set([...t,...i])).sort(),l=b.useMemo(()=>f.trim()?c.filter(p=>{const v=(u==null?void 0:u.at([...r,p]))??null;return w([...r,p],v,f)?!0:t.has(p)?L(e.children[p],[...r,p],f,u):!1}):c,[c.join(","),f,e,r.join("."),u]);if(f.trim()&&l.length===0&&!w(r,y,f))return null;if(r.length===0)return n.jsx("div",{children:l.map(p=>j(p))});return n.jsxs("div",{children:[n.jsxs("div",{className:"flex items-center gap-1 py-0.5 hover:bg-bg-elev/50 rounded cursor-pointer",style:{paddingLeft:x*14},onClick:()=>h(!d),children:[n.jsx("span",{className:"text-fg-faint w-3 shrink-0",children:d?"▾":"▸"}),n.jsx("span",{className:"text-fg",children:s}),n.jsxs("span",{className:"text-fg-faint",children:[" {",t.size,i.length>t.size?`/${new Set([...t,...i]).size}`:"","}"]}),(y==null?void 0:y.description)&&n.jsxs("span",{className:"text-fg-faint truncate max-w-md",title:y.description,children:["— ",y.description]})]}),d&&l.map(p=>j(p))]});function j(p){if(t.has(p))return n.jsx(E,{node:e.children[p],path:[...r,p],label:p,targetScope:a,onOverride:m,filter:f,depth:x+1,schema:u,showGhosts:o},p);const v=(u==null?void 0:u.at([...r,p]))??null;return v?n.jsx(_,{path:[...r,p],label:p,info:v,targetScope:a,onSet:m,depth:x+1,filter:f},p):null}}function L(e,r,s,a){const m=(a==null?void 0:a.at(r))??null;if(w(r,m,s))return!0;if(e.kind!=="object")return!1;for(const f of Object.keys(e.children))if(L(e.children[f],[...r,f],s,a))return!0;return!1}function J({node:e,path:r,label:s,filter:a,depth:m,schema:f}){const[x,u]=b.useState(!0),o=(f==null?void 0:f.at(r))??null;return w(r,o,a)?n.jsxs("div",{children:[n.jsxs("div",{className:"flex items-center gap-1 py-0.5 hover:bg-bg-elev/50 rounded cursor-pointer",style:{paddingLeft:m*14},onClick:()=>u(!x),children:[n.jsx("span",{className:"text-fg-faint w-3 shrink-0",children:x?"▾":"▸"}),n.jsx("span",{className:"text-fg",children:s}),n.jsxs("span",{className:"text-fg-faint",children:[" [",e.items.length,"]"]}),n.jsx(S,{tone:"warn",children:"accumulated"}),(o==null?void 0:o.description)&&n.jsxs("span",{className:"text-fg-faint truncate max-w-md",title:o.description,children:["— ",o.description]})]}),x&&e.items.map((g,d)=>n.jsxs("div",{className:"flex items-start gap-2 py-0.5",style:{paddingLeft:(m+1)*14},children:[n.jsx("span",{className:"text-fg-faint w-3 shrink-0"}),n.jsxs("span",{className:"text-fg-faint",children:[d,":"]}),n.jsx("span",{className:"text-fg-dim truncate max-w-xl",children:k(g.value)}),n.jsx(C,{scope:g.fromScope})]},d))]}):null}function R({node:e,path:r,label:s,targetScope:a,onOverride:m,filter:f,depth:x,schema:u}){const[o,g]=b.useState(!1),d=(u==null?void 0:u.at(r))??null;if(!w(r,d,f))return null;const h=e.winner!==a,y=e.shadowed.length>0;return n.jsxs("div",{children:[n.jsxs("div",{className:"group flex items-center gap-2 py-0.5 hover:bg-bg-elev/50 rounded",style:{paddingLeft:x*14},children:[n.jsx("span",{className:`w-3 shrink-0 ${y?"text-fg-faint cursor-pointer":""}`,onClick:()=>y&&g(!o),children:y?o?"▾":"▸":""}),n.jsxs("span",{className:"text-fg",children:[s,":"]}),n.jsx("span",{className:"text-fg-dim truncate max-w-md",children:k(e.value)}),n.jsx(C,{scope:e.winner}),(d==null?void 0:d.deprecated)&&n.jsx(S,{tone:"warn",children:"deprecated"}),(d==null?void 0:d.default)!==void 0&&I(e.value,d.default)&&n.jsx(S,{tone:"dim",children:"= default"}),e.typeMismatch&&n.jsx("span",{className:"text-yellow-500/80",title:"shadowed scopes have a different value type",children:"⚠"}),(d==null?void 0:d.description)&&n.jsxs("span",{className:"text-fg-faint truncate max-w-md",title:d.description,children:["— ",d.description]}),n.jsx("div",{className:"flex-1"}),(d==null?void 0:d.enum)&&n.jsx(F,{values:d.enum}),n.jsx("button",{disabled:!h,onClick:()=>m(r,e.value),className:`opacity-0 group-hover:opacity-100 px-1.5 py-0 text-[10px] border rounded transition-opacity ${h?"border-accent/50 text-accent hover:bg-accent hover:text-bg":"border-line text-fg-faint cursor-not-allowed"}`,title:h?`copy into ${N[a].label} draft`:`already winning in ${N[a].label}`,children:"override"})]}),o&&e.shadowed.map((t,i)=>n.jsxs("div",{className:"flex items-center gap-2 py-0.5 text-fg-faint line-through",style:{paddingLeft:(x+1)*14+12},children:[n.jsx("span",{children:"shadowed:"}),n.jsx("span",{className:"truncate max-w-xl",children:k(t.value)}),n.jsx(C,{scope:t.scope,dim:!0})]},i))]})}function _({path:e,label:r,info:s,targetScope:a,onSet:m,depth:f,filter:x}){if(!w(e,s,x))return null;const u=s.default!==void 0?s.default:M(s.type),o=Array.isArray(s.type)?s.type.join("|"):s.type??"?";return n.jsxs("div",{className:"group flex items-center gap-2 py-0.5 hover:bg-bg-elev/50 rounded opacity-60",style:{paddingLeft:f*14},children:[n.jsx("span",{className:"w-3 shrink-0"}),n.jsx("span",{className:"text-fg-dim",children:r}),n.jsx(S,{tone:"dim",children:o}),s.required&&n.jsx(S,{tone:"warn",children:"required"}),s.default!==void 0&&n.jsxs("span",{className:"text-fg-faint",children:["default: ",k(s.default)]}),s.description&&n.jsxs("span",{className:"text-fg-faint truncate max-w-md",title:s.description,children:["— ",s.description]}),n.jsx("div",{className:"flex-1"}),s.enum&&n.jsx(F,{values:s.enum}),n.jsx("button",{onClick:()=>m(e,u),className:"opacity-0 group-hover:opacity-100 px-1.5 py-0 text-[10px] border border-accent/50 rounded text-accent hover:bg-accent hover:text-bg transition-opacity",title:`write to ${N[a].label} draft`,children:"set"})]})}function I(e,r){return e===r?!0:typeof e!=typeof r?!1:e&&r&&typeof e=="object"?JSON.stringify(e)===JSON.stringify(r):!1}function M(e){switch(Array.isArray(e)?e[0]:e){case"boolean":return!1;case"integer":case"number":return 0;case"string":return"";case"array":return[];case"object":return{};case"null":return null;default:return null}}function k(e){if(typeof e=="string")return JSON.stringify(e);if(e===null)return"null";if(typeof e=="object"){const r=JSON.stringify(e);return r.length>100?r.slice(0,100)+"…":r}return String(e)}function C({scope:e,dim:r}){const s=e==="user"?"bg-bg-hi text-fg-dim border-line":e==="project"?"bg-blue-950/30 text-blue-400/80 border-blue-900/40":"bg-purple-950/30 text-purple-400/80 border-purple-900/40";return n.jsx("span",{className:`text-[10px] px-1 py-0 rounded border uppercase tracking-wide shrink-0 ${s} ${r?"opacity-60":""}`,children:N[e].label})}function S({children:e,tone:r="default"}){const s={default:"bg-bg-hi text-fg-dim border-line",warn:"bg-yellow-950/30 text-yellow-500/80 border-yellow-900/40",dim:"bg-bg-elev text-fg-faint border-line"}[r];return n.jsx("span",{className:`text-[10px] px-1 py-0 rounded border uppercase tracking-wide shrink-0 ${s}`,children:e})}function F({values:e}){const r=e.map(s=>String(s)).join(" | ");return n.jsxs("span",{className:"text-[10px] text-fg-faint truncate max-w-xs",title:`allowed: ${r}`,children:["∈ ",r.length>30?r.slice(0,30)+"…":r]})}function V(e,r,s){const a=O(o=>o.files),m=O(o=>o.loadJson),f=O(o=>o.watchFile),x=O(o=>o.unwatchFile),u=b.useMemo(()=>{const o={};for(const g of e.scopes){const d=e.resolve(g,r??"",s);d&&(o[g]=d)}return o},[e,r,s]);return b.useEffect(()=>{const o=Object.values(u).filter(Boolean);return o.forEach(g=>{a[g]||m(g),f(g)}),()=>{o.forEach(g=>x(g))}},[JSON.stringify(u)]),u}function B(e){const r=e??{},s={...r.$defs??{},...r.definitions??{}},a=t=>{if(!t)return{};if(!t.$ref)return x(t);const i=/^#\/(\$defs|definitions)\/(.+)$/.exec(t.$ref);if(!i)return x(t);const c=s[i[2]];return c?a({...c,...u(t)}):x(t)},m=new Set(["__proto__","constructor","prototype"]),f=t=>{if(!t)return{};const i={};for(const[c,l]of Object.entries(t))m.has(c)||(i[c]=l);return i},x=t=>{if(!t.allOf||t.allOf.length===0)return t;const i={...t};delete i.allOf;for(const c of t.allOf){const l=a(c);Object.assign(i,{properties:{...f(i.properties),...f(l.properties)},required:q([...i.required??[],...l.required??[]])}),!i.description&&l.description&&(i.description=l.description),i.default===void 0&&l.default!==void 0&&(i.default=l.default),!i.type&&l.type&&(i.type=l.type)}return i},u=t=>{const{$ref:i,...c}=t;return c},o=(t,i)=>{let c=a(t);for(const l of i){if(!c)return null;if(/^\d+$/.test(l)){const v=Array.isArray(c.items)?c.items[Number(l)]:c.items;c=v?a(v):null;continue}const j=c.properties;if(j&&!m.has(l)&&l in j){c=a(j[l]);continue}const p=c.additionalProperties;if(p&&typeof p=="object"){c=a(p);continue}return null}return c},g=(t,i,c)=>{if(!t)return null;const l={};if(t.description&&(l.description=t.description),t.type&&(l.type=t.type),t.default!==void 0&&(l.default=t.default),t.enum&&(l.enum=t.enum),t.const!==void 0&&(l.const=t.const),t.deprecated&&(l.deprecated=!0),t.examples&&(l.examples=t.examples),t.properties&&(l.knownChildren=Object.keys(t.properties)),c&&(i!=null&&i.includes(c))&&(l.required=!0),t.items&&!Array.isArray(t.items)){const j=a(t.items),p=g(j,void 0,null);p&&(l.itemsInfo=p)}return(t.additionalProperties===!0||typeof t.additionalProperties=="object")&&(l.open=!0),l},d=t=>i=>{if(i.length===0)return g(a(t),void 0,null);const c=o(t,i.slice(0,-1));if(!c)return null;const l=i[i.length-1],j=o(c,[l]);return g(j,c.required,l)},h=t=>{const i=a(t);return Object.keys(i.properties??{})},y=t=>({at:d(t),rootKeys:()=>h(t),rootedAt:i=>{const c=o(t,i);return y(c??{})}});return y(r)}function q(e){return Array.from(new Set(e))}let $=null;function D(){return $||($=B(K)),$}export{G as E,D as s,V as u};
@@ -1,4 +1,4 @@
1
- import{ap as k,F as E}from"./index-Bq9uH08R.js";function M({value:t,onChange:n,path:e,readOnly:i}){return k.jsx(E,{path:`file://${e}`,defaultLanguage:"markdown",value:t,onChange:s=>n(s??""),theme:"vs-dark",options:{minimap:{enabled:!1},fontSize:13,fontFamily:"JetBrains Mono, ui-monospace, Menlo, monospace",lineNumbers:"on",renderLineHighlight:"line",scrollBeyondLastLine:!1,tabSize:2,wordWrap:"on",readOnly:i,automaticLayout:!0}})}const f=/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/,u="disable-model-invocation",g=/^\s*disable-model-invocation\s*:/;function j(t){const n=t.match(f);if(!n)return!1;for(const e of n[1].split(/\r?\n/)){if(!g.test(e))continue;const i=e.slice(e.indexOf(":")+1).trim().toLowerCase();return i==="true"||i==="yes"}return!1}function S(t){const n=t.trim();return n.length>=2&&(n[0]==='"'&&n[n.length-1]==='"'||n[0]==="'"&&n[n.length-1]==="'")?n.slice(1,-1):n}function h(t){return t.length-t.trimStart().length}function v(t){const n=t.match(f);if(!n)return{name:null,description:null,body:t};const e=n[1].split(/\r?\n/),i=n[2]??"";let s=null,r=null;for(let o=0;o<e.length;o++){const m=e[o],d=m.match(/^(\s*)(name|description)\s*:(.*)$/);if(!d)continue;const[,,y,$]=d,l=$.trim(),b=h(m);let c;if(l===""||l===">-"||l===">"||l==="|-"||l==="|"){const p=[];let a=o+1;for(;a<e.length&&e[a].trim()!==""&&h(e[a])>b;)p.push(e[a].trim()),a++;c=p.join(" ")}else c=S(l);y==="name"?s=c:r=c}return{name:s,description:r,body:i}}function w(t,n){const e=t.match(f);if(!e){if(!n)return t;const o=t.startsWith(`
1
+ import{ap as k,F as E}from"./index-Bjtguv6I.js";function M({value:t,onChange:n,path:e,readOnly:i}){return k.jsx(E,{path:`file://${e}`,defaultLanguage:"markdown",value:t,onChange:s=>n(s??""),theme:"vs-dark",options:{minimap:{enabled:!1},fontSize:13,fontFamily:"JetBrains Mono, ui-monospace, Menlo, monospace",lineNumbers:"on",renderLineHighlight:"line",scrollBeyondLastLine:!1,tabSize:2,wordWrap:"on",readOnly:i,automaticLayout:!0}})}const f=/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/,u="disable-model-invocation",g=/^\s*disable-model-invocation\s*:/;function j(t){const n=t.match(f);if(!n)return!1;for(const e of n[1].split(/\r?\n/)){if(!g.test(e))continue;const i=e.slice(e.indexOf(":")+1).trim().toLowerCase();return i==="true"||i==="yes"}return!1}function S(t){const n=t.trim();return n.length>=2&&(n[0]==='"'&&n[n.length-1]==='"'||n[0]==="'"&&n[n.length-1]==="'")?n.slice(1,-1):n}function h(t){return t.length-t.trimStart().length}function v(t){const n=t.match(f);if(!n)return{name:null,description:null,body:t};const e=n[1].split(/\r?\n/),i=n[2]??"";let s=null,r=null;for(let o=0;o<e.length;o++){const m=e[o],d=m.match(/^(\s*)(name|description)\s*:(.*)$/);if(!d)continue;const[,,y,$]=d,l=$.trim(),b=h(m);let c;if(l===""||l===">-"||l===">"||l==="|-"||l==="|"){const p=[];let a=o+1;for(;a<e.length&&e[a].trim()!==""&&h(e[a])>b;)p.push(e[a].trim()),a++;c=p.join(" ")}else c=S(l);y==="name"?s=c:r=c}return{name:s,description:r,body:i}}function w(t,n){const e=t.match(f);if(!e){if(!n)return t;const o=t.startsWith(`
2
2
  `)?"":`
3
3
  `;return`---
4
4
  ${u}: true
@@ -1 +1 @@
1
- import{W as e,b4 as a,a$ as n}from"./index-Bq9uH08R.js";const c=new Set(e.map(t=>t.tag));function l(t){return t.filter(o=>c.has(o))}function s(t,o={}){return{name:t.name,originalName:t.name,description:t.description??"",tools:t.tools,model:t.model??"inherit",effort:t.effort??void 0,color:t.color??"",tags:l(t.tags),projects:t.projects,action:t.action??void 0,actionLabel:t.actionLabel??void 0,title:t.title??void 0,body:t.body,...o}}function d(t,o){const i=a();n([i?`${i}/.claude/agents`:null,t?`${t}/.claude/agents`:null],o)}export{s as a,l as t,d as u};
1
+ import{W as e,b4 as a,a$ as n}from"./index-Bjtguv6I.js";const c=new Set(e.map(t=>t.tag));function l(t){return t.filter(o=>c.has(o))}function s(t,o={}){return{name:t.name,originalName:t.name,description:t.description??"",tools:t.tools,model:t.model??"inherit",effort:t.effort??void 0,color:t.color??"",tags:l(t.tags),projects:t.projects,action:t.action??void 0,actionLabel:t.actionLabel??void 0,title:t.title??void 0,body:t.body,...o}}function d(t,o){const i=a();n([i?`${i}/.claude/agents`:null,t?`${t}/.claude/agents`:null],o)}export{s as a,l as t,d as u};
@@ -1 +1 @@
1
- import{ap as t,A as f,bf as g,aF as d}from"./index-Bq9uH08R.js";function j({children:s,right:e}){return t.jsxs("div",{className:"flex items-baseline justify-between mb-2.5",children:[t.jsx("span",{className:"text-[11.5px] font-bold uppercase tracking-[0.8px] text-fg-faint",children:s}),e]})}function y({kind:s="soft",icon:e,children:c,onClick:i,disabled:o,testId:n}){return t.jsxs("button",{type:"button","data-testid":n,onClick:i,disabled:o,className:`shrink-0 inline-flex items-center gap-2 rounded-lg px-3.5 py-2 text-[13px] font-semibold transition-colors disabled:opacity-50 ${s==="soft"?"bg-bg-hi border border-line text-fg hover:bg-bg":"text-fg-dim hover:text-fg"}`,children:[e&&t.jsx(f,{name:e,size:15}),c]})}function N({icon:s,title:e,subtitle:c,badge:i,action:o,testId:n}){return t.jsxs("div",{"data-testid":n,className:"flex items-center gap-3.5 bg-bg-hi border border-line rounded-xl px-[18px] py-3.5",children:[t.jsx("span",{className:"w-[34px] h-[34px] rounded-lg bg-bg border border-line grid place-items-center text-fg-dim shrink-0",children:t.jsx(f,{name:s,size:17})}),t.jsxs("div",{className:"flex-1 min-w-0",children:[t.jsxs("div",{className:"flex items-center gap-2.5 mb-0.5",children:[t.jsx("span",{className:"text-sm font-semibold text-fg truncate",children:e}),i]}),t.jsx("div",{className:"font-mono text-[11.5px] text-fg-faint truncate",children:c})]}),o]})}function v({onClick:s,disabled:e,testId:c,children:i="Revoke"}){return t.jsx("button",{"data-testid":c,onClick:s,disabled:e,className:"shrink-0 rounded-lg border border-line bg-bg text-accent px-3.5 py-1.5 text-[12.5px] font-semibold hover:bg-bg-hi disabled:opacity-50 transition-colors",children:i})}function k({code:s,onConfirm:e,testId:c,codeTestId:i,confirmTestId:o,peer:n="browser"}){return t.jsxs("div",{"data-testid":c,className:"flex items-start gap-3.5 px-5 py-4 rounded-2xl border border-accent/40 bg-accent/[0.06]",children:[t.jsx("span",{className:"w-[38px] h-[38px] rounded-[11px] shrink-0 grid place-items-center bg-bg-hi text-accent",children:t.jsx(f,{name:"shield",size:20})}),t.jsxs("div",{className:"flex-1 min-w-0 text-sm text-fg",children:[t.jsx("strong",{className:"font-semibold",children:"Verify E2E session."})," Compare this code with the ",n," — they must match.",t.jsx("div",{"data-testid":i,className:"my-2 text-3xl font-mono tracking-[0.3em] text-center text-accent select-all",children:s}),t.jsx("p",{className:"text-[12.5px] text-fg-faint mb-3",children:"If the codes match, confirm below. Mutating commands are blocked until confirmed."}),t.jsx("button",{"data-testid":o,onClick:e,className:"rounded-lg bg-accent text-white px-4 py-2 text-[13px] font-semibold hover:opacity-90 transition-opacity",children:"Codes match — confirm"})]})]})}function C({children:s,testId:e}){return t.jsx("div",{"data-testid":e,className:"bg-bg-hi border border-line rounded-xl p-5 text-center text-[13.5px] text-fg-faint italic font-serif",children:s})}const m=s=>(s==null?void 0:s.message)||String(s);function S(s){const e=g(r=>r.show),[c,i]=d.useState([]),o=d.useRef(s);o.current=s;const n=d.useCallback(async()=>{try{i(await window.api.remoteClient.list())}catch(r){e("error",m(r))}},[e]);d.useEffect(()=>{n();const r=window.api.remoteClient.onStatus(a=>{var x;(x=o.current)==null||x.call(o,a),i(l=>l.map(b=>b.peerId===a.peerId?{...b,status:a.status,reason:a.reason,sas:a.sas}:b))});return()=>{r()}},[n]);const p=d.useCallback(async r=>{try{const a=await window.api.remoteClient.connect(r);i(x=>x.map(l=>l.peerId===r?{...l,status:a.status,reason:a.reason,sas:a.sas}:l))}catch(a){e("error",m(a))}},[e]),u=d.useCallback(async r=>{try{const a=await window.api.remoteClient.confirmSas(r);a.ok||e("error",a.reason??"SAS confirmation failed"),await n()}catch(a){e("error",m(a))}},[e,n]),h=d.useCallback(async r=>{try{await window.api.remoteClient.remove(r),await n()}catch(a){e("error",m(a))}},[e,n]);return{peers:c,refresh:n,connect:p,confirmSas:u,revoke:h}}export{C as E,y as P,N as R,k as S,v as a,j as b,S as u};
1
+ import{ap as t,A as f,bf as g,aF as d}from"./index-Bjtguv6I.js";function j({children:s,right:e}){return t.jsxs("div",{className:"flex items-baseline justify-between mb-2.5",children:[t.jsx("span",{className:"text-[11.5px] font-bold uppercase tracking-[0.8px] text-fg-faint",children:s}),e]})}function y({kind:s="soft",icon:e,children:c,onClick:i,disabled:o,testId:n}){return t.jsxs("button",{type:"button","data-testid":n,onClick:i,disabled:o,className:`shrink-0 inline-flex items-center gap-2 rounded-lg px-3.5 py-2 text-[13px] font-semibold transition-colors disabled:opacity-50 ${s==="soft"?"bg-bg-hi border border-line text-fg hover:bg-bg":"text-fg-dim hover:text-fg"}`,children:[e&&t.jsx(f,{name:e,size:15}),c]})}function N({icon:s,title:e,subtitle:c,badge:i,action:o,testId:n}){return t.jsxs("div",{"data-testid":n,className:"flex items-center gap-3.5 bg-bg-hi border border-line rounded-xl px-[18px] py-3.5",children:[t.jsx("span",{className:"w-[34px] h-[34px] rounded-lg bg-bg border border-line grid place-items-center text-fg-dim shrink-0",children:t.jsx(f,{name:s,size:17})}),t.jsxs("div",{className:"flex-1 min-w-0",children:[t.jsxs("div",{className:"flex items-center gap-2.5 mb-0.5",children:[t.jsx("span",{className:"text-sm font-semibold text-fg truncate",children:e}),i]}),t.jsx("div",{className:"font-mono text-[11.5px] text-fg-faint truncate",children:c})]}),o]})}function v({onClick:s,disabled:e,testId:c,children:i="Revoke"}){return t.jsx("button",{"data-testid":c,onClick:s,disabled:e,className:"shrink-0 rounded-lg border border-line bg-bg text-accent px-3.5 py-1.5 text-[12.5px] font-semibold hover:bg-bg-hi disabled:opacity-50 transition-colors",children:i})}function k({code:s,onConfirm:e,testId:c,codeTestId:i,confirmTestId:o,peer:n="browser"}){return t.jsxs("div",{"data-testid":c,className:"flex items-start gap-3.5 px-5 py-4 rounded-2xl border border-accent/40 bg-accent/[0.06]",children:[t.jsx("span",{className:"w-[38px] h-[38px] rounded-[11px] shrink-0 grid place-items-center bg-bg-hi text-accent",children:t.jsx(f,{name:"shield",size:20})}),t.jsxs("div",{className:"flex-1 min-w-0 text-sm text-fg",children:[t.jsx("strong",{className:"font-semibold",children:"Verify E2E session."})," Compare this code with the ",n," — they must match.",t.jsx("div",{"data-testid":i,className:"my-2 text-3xl font-mono tracking-[0.3em] text-center text-accent select-all",children:s}),t.jsx("p",{className:"text-[12.5px] text-fg-faint mb-3",children:"If the codes match, confirm below. Mutating commands are blocked until confirmed."}),t.jsx("button",{"data-testid":o,onClick:e,className:"rounded-lg bg-accent text-white px-4 py-2 text-[13px] font-semibold hover:opacity-90 transition-opacity",children:"Codes match — confirm"})]})]})}function C({children:s,testId:e}){return t.jsx("div",{"data-testid":e,className:"bg-bg-hi border border-line rounded-xl p-5 text-center text-[13.5px] text-fg-faint italic font-serif",children:s})}const m=s=>(s==null?void 0:s.message)||String(s);function S(s){const e=g(r=>r.show),[c,i]=d.useState([]),o=d.useRef(s);o.current=s;const n=d.useCallback(async()=>{try{i(await window.api.remoteClient.list())}catch(r){e("error",m(r))}},[e]);d.useEffect(()=>{n();const r=window.api.remoteClient.onStatus(a=>{var x;(x=o.current)==null||x.call(o,a),i(l=>l.map(b=>b.peerId===a.peerId?{...b,status:a.status,reason:a.reason,sas:a.sas}:b))});return()=>{r()}},[n]);const p=d.useCallback(async r=>{try{const a=await window.api.remoteClient.connect(r);i(x=>x.map(l=>l.peerId===r?{...l,status:a.status,reason:a.reason,sas:a.sas}:l))}catch(a){e("error",m(a))}},[e]),u=d.useCallback(async r=>{try{const a=await window.api.remoteClient.confirmSas(r);a.ok||e("error",a.reason??"SAS confirmation failed"),await n()}catch(a){e("error",m(a))}},[e,n]),h=d.useCallback(async r=>{try{await window.api.remoteClient.remove(r),await n()}catch(a){e("error",m(a))}},[e,n]);return{peers:c,refresh:n,connect:p,confirmSas:u,revoke:h}}export{C as E,y as P,N as R,k as S,v as a,j as b,S as u};
package/dist/index.html CHANGED
@@ -7,7 +7,7 @@
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,500;0,6..72,600;0,6..72,700;1,6..72,400&family=Geist:wght@300;400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet">
10
- <script type="module" crossorigin src="./assets/index-Bq9uH08R.js"></script>
10
+ <script type="module" crossorigin src="./assets/index-Bjtguv6I.js"></script>
11
11
  <link rel="modulepreload" crossorigin href="./assets/monaco-editor-BsIlgG7c.js">
12
12
  <link rel="stylesheet" crossorigin href="./assets/monaco-editor-Cu5D__1H.css">
13
13
  <link rel="stylesheet" crossorigin href="./assets/index-Dd7UQabV.css">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-session-manager",
3
- "version": "0.121.0",
3
+ "version": "0.122.0",
4
4
  "description": "Local cockpit for the Claude Code CLI — multi-tab terminal, full config surface, scheduler, voice dictation, and live observability.",
5
5
  "type": "module",
6
6
  "main": "src/main/index.cjs",
@@ -104,9 +104,9 @@ failure modes have different fixes:
104
104
  its test), `migration` (mechanical change), `doc`, `validate`.
105
105
  7. **Keep each PRD small**: at most 3 edited files, 1 new file, 6 criteria. The validate PRD is
106
106
  exempt: it has one criterion per PRD, plus the record. A new helper and its first caller are
107
- two PRDs. Most PRDs take 5–10 executor minutes; past estimates were 3–5×
108
- too high. Never estimate over 15; split. Why: the kill budget floors at 45 minutes, so a low
109
- estimate never starves a run.
107
+ two PRDs. Most PRDs take 5–10 executor minutes; split anything expected
108
+ to take over 15. Do not write an estimate. Why: the kill budget floors at 45 minutes, so a
109
+ run without one is never starved.
110
110
  8. **Make each PRD self-contained.** The executor sees only the PRD and the project. Notes are
111
111
  a recipe: `Read first:` (at most 4 files, with line ranges), `Steps:` (numbered, each naming
112
112
  file and function), `Do not touch:` (files a sibling owns). Quote signatures. Say when a PRD
@@ -114,7 +114,7 @@ failure modes have different fixes:
114
114
  9. **Write plain, checkable criteria.** Each names a file, a symbol and the result; one names
115
115
  the test file and tests. Commands go in `gate`. No open-ended "grep X and update" lines.
116
116
  10. **Show the plan once**: the plan goal line, the stage view (for example `Stage 1: A ∥ B →
117
- Stage 2: C → validate`), and a table (#, PRD, files, gate, dependsOn, estimate) — not PRD
117
+ Stage 2: C → validate`), and a table (#, PRD, files, gate, dependsOn) — not PRD
118
118
  drafts. Queue at once when the Epic is `feature` or `bug` and scope is clear; otherwise ask
119
119
  one approval question, once.
120
120
  11. Before the first `scheduler_create_prd` call, run `git -C "$SM_PROJECT_ROOT" rev-parse HEAD`
@@ -135,7 +135,7 @@ failure modes have different fixes:
135
135
  | --- | --- |
136
136
  | `title`, `goal`, `acceptanceCriteria`, `implementationNotes`, `outOfScope` | Steps 6–9. Goal: 2–4 sentences. |
137
137
  | `gate`, `files` | **REQUIRED.** Rules below. The tool refuses a call without them. |
138
- | `estimateMinutes` | Honest: 5–10, never over 15. |
138
+ | `estimateMinutes` | Omit. Pass one only for a run that legitimately needs more than the 45-minute kill-budget floor. |
139
139
  | `sourcePromptId` | Always `<epic-id>`. Never rely on the server's fallback. |
140
140
  | `cwd` | The Epic's project root, as an absolute path or `~/…`. The API always uses the Epic's project, whatever you pass. To work in another project, open an Epic there. |
141
141
  | `dependsOn` | Slugs that must finish first. The only ordering tool. |
@@ -206,7 +206,7 @@ paths → verdict line.
206
206
 
207
207
  End every plan with exactly one validate PRD:
208
208
 
209
- 1. `agentType: "validator"`, `tag: "build"`, `estimateMinutes: 10`, slug
209
+ 1. `agentType: "validator"`, `tag: "build"`, slug
210
210
  `validate-<short-plan-name>`. Its title is the plan goal shown on the Scheduler card, so
211
211
  write it as `Validate: <plain-language goal>`.
212
212
  2. `dependsOn`: every other slug in the plan. Past the cap of 100, only the sinks (PRDs nothing
@@ -238,7 +238,7 @@ here. Never write the record yourself.
238
238
 
239
239
  The scheduler heals most parks itself:
240
240
 
241
- 1. Transcript-noise parks (verdicts transcript_errors, no_verdict_sentinel,
241
+ 1. Verdict-line parks (verdicts no_verdict_sentinel,
242
242
  abandoned_background_task) complete when the gate re-run is green, the landed commit is on
243
243
  HEAD and the tracked tree is clean.
244
244
  2. Stray-checkout parks (the main checkout was on another branch) are re-landed onto the base
@@ -71,21 +71,15 @@ a higher-priority source exists:
71
71
 
72
72
  ## Execution discipline (headless runs)
73
73
 
74
- Data from 400+ scheduler runs: long hangs, not bad code, cause most failures, and "exited clean but left a red test" is the top verifier downgrade. The PRD body carries a one-line pointer to this file, never a copy. The dev-lead persona and the scheduler's finish protocol carry the per-run rules; this file gives the reasons behind them. Run order: orient → red → build → finish protocol (review → verify the `# Gate` commands → commit exact paths → verdict line).
74
+ Long hangs, not bad code, cause most failed runs. The PRD body carries a one-line pointer to this file, never a copy. The dev-lead persona and the scheduler's finish protocol carry the per-run rules; this file gives the reasons behind them. Run order: orient → red → build → finish protocol (review → verify the `# Gate` commands → commit exact paths → verdict line).
75
75
 
76
76
  - **Bound every command.** Wrap every test, build, dev-server, deploy, or poll command in a hard timeout, e.g. `timeout 300 <typecheck|unit>` or `curl --max-time 15`. Why: a bare `playwright test`, `vite`, `pnpm dev`, full e2e suite, or endpoint-polling publish hangs until the 4-hour watchdog kills it with SIGTERM.
77
- - **Verify before done.** Run the acceptance test once before declaring success. Why: ending the run on a failing test trips the verifier's `transcript_errors` downgrade — fix it or `exit 1` with the failure instead.
77
+ - **Verify before done.** Run the acceptance test once before declaring success. Why: a run that ends on a failing test is not done — fix it or `exit 1` with the failure instead.
78
78
  - **Fail loud, fail fast.** On any step failure, print one diagnostic line and `exit 1`. Do not swallow it with `|| true` or retry silently. Exception: a `rateLimited` exit-1 is the scheduler's own benign auto-pause — it resumes next window on its own, so do not engineer around it.
79
79
  - **Stay in the AC.** Do not add work past the acceptance checklist — "while we're here" extras are how runs overrun. Keep the body clean UTF-8, with no NUL or control bytes.
80
80
  - **You ARE the executor — never re-queue or self-schedule.** Do the acceptance criteria yourself. Why: `/develop` or any queue-authoring skill just writes a *new* PRD and returns — the run exits 0 having done nothing, with no commit and no verdict line (`needs_review` with `no_verdict_sentinel`). The same applies to calling `ScheduleWakeup`, or backgrounding a review agent (`/code-review`, `/security-review`) and ending your turn with something like "I'll wait for the review agents to complete": a headless run has no next turn, so nothing ever resumes it — no verdict line prints, and the job parks in `needs_review` even though the work already landed. Run a required second review pass synchronously, inline, before the finish protocol — call the reviewer and read its result in the same turn. If the work is too big for one run, do not queue more work; see the timeout rule below. (Incidents: PRD 460 invoked `/develop` and exited 0 with no work. PRD 479 landed its commit, then backgrounded `/code-review --fix` + `/security-review` and called `ScheduleWakeup` to "wait" — same failure, different entry point.)
81
81
  - **Never `git stash`, `git reset`, `git checkout -- <path>`, or `git clean` against working-tree state you did not create.** There is no polite version of this. You are normally isolated in your own `git worktree` on branch `sm-job/<slug>` (`src/main/lib/git/gitWorktree.cjs`), and the scheduler salvages any uncommitted diff of yours on teardown — so you never need to touch shared state to protect your own work. Confirm isolation with `git rev-parse --git-common-dir` (a worktree's common-dir differs from its own `.git`) or by checking your cwd; `git diff`/`git status` are always safe. If you land in a SHARED tree with pre-existing dirty tracked files anyway, work around them — scope `git add`/commits to only the paths you touched — or end with `SCHEDULER_VERDICT: FAIL <reason>` (`SCHEDULER_VERDICT: BLOCKED_BY_FOREIGN_WIP` only when your gate failed on those files, as the finish protocol says); never discard, stash, or revert someone else's uncommitted changes to get a clean checkout. A shared tree may be feeding a running service that reads its config straight from the working tree, so reverting it is a production change, not a local inconvenience. The scheduler runs a shared-tree stash guard as a backstop (`scheduler.cjs`'s `checkSharedTreeGuard`/`evaluateSharedTreeGuard`), but that guard exists to catch a mistake, not to license one. (Incidents: PRD 477 stashed a sibling job's WIP to get its own checkout and never restored it. 2026-09-01: a headless executor in the trader repo ran a blanket `git stash` against an operator's uncommitted live trading-config edit and exited without restoring it — the third incident of this class.)
82
- - **`gh pr edit --body` can fail on repos with legacy GitHub Projects (classic) boards.** It queries the deprecated `repository.pullRequest.projectCards` field and errors with a `GraphQL: Projects (classic) is being deprecated` message even though the edit itself would otherwise succeed — a known `gh` CLI quirk, not a defect in your work. Prefer `gh api -X PATCH repos/<owner>/<repo>/pulls/<n> -f body="$(cat body.md)"` instead; it skips that field. If `gh pr edit` fails this way anyway, retry immediately with the `gh api` form and print one line noting the fallback — don't leave the bare GraphQL error as the step's last output, or the verifier reads it as unrecovered.
83
- - **`gh pr checks`/`gh run watch` exit non-zero while CI is merely *pending*, not failed — don't let that read as a bare error.** `gh pr checks <n>` returns a non-zero exit (e.g. 8) with output like `check pending 0 <url>` before checks finish — normal, documented `gh` CLI behavior, not a failure. Poll with the exact same command and description every time; the verifier's self-recovery detector pairs a failure with a later success only when the wording matches, so switching wording mid-poll (e.g. dropping a `sleep N &&` prefix) can leave the earlier pending-state error looking unrecovered. (Incident: `745-pr188-ci-lint-docs-integrity` — a fully green, committed, pushed run was flagged `needs_review` over exactly this.)
84
- - **Negative-assertion checks must exit 0 when clean.** A check for the *absence* of something (a `grep` that should find nothing, a `diff` expecting no change) must exit 0 on the clean case. Why: a bare `grep` exits 1 on no-match, so the success path surfaces as `is_error=true` and the verifier downgrades a perfect run. Invert it: `if <detector>; then echo "HALT: <what was found>"; exit 1; fi; echo clean` — never let the clean path carry a non-zero exit.
85
- - **Recover or annotate every error — don't strand a Traceback in the transcript.** The verifier's `transcript_errors` heuristic downgrades an otherwise-perfect run when a `Traceback`/`Error` has no visible recovery within ~10 lines — the single most common false-positive on green work. The top cause is a throwaway probe that errors (a quoting/f-string slip in an inline `python -c`, a wrong kwarg, a bad path): when a probe errors, immediately re-run the corrected version, or print `# expected/handled: <why>` right after it so the recovery sits next to the error. Prefer a small temp `.py` file over a fragile multi-quote one-liner. (The timeout rule below is the other cause.)
86
- - **An *expected* bounded timeout (exit 124) must be annotated, not left bare.** Capping a genuinely long task (a full-universe ingest, a long scan) at its expected limit is correct, but a bare `Exit code 124` reads as a failure to the verifier. Wrap it so the cap reads as success-with-note: `timeout 120 <cmd> || { rc=$?; [ $rc -eq 124 ] && echo "hit time cap — OK" || { echo "HALT: rc=$rc"; exit 1; }; }` — distinguish the expected 124 from a real non-zero. If the work needs longer than a safe cap, the PRD is too big: end with `SCHEDULER_VERDICT: FAIL <reason>` so the planner splits it. Never run it in the background.
87
- - **Never `sleep N && <cmd>` to poll remote CI/job status.** The harness hard-blocks a `sleep` chained to another command, and that block itself lands in the transcript as a bare error — usually in the last 20% of the run, right where the verifier weighs errors most. Use the tool's own blocking watcher under a hard cap instead: `timeout 600 gh run watch <run-id> --repo <owner>/<repo> --exit-status`. `gh pr checks` is itself negative-assertion-shaped (exits 8 pending, 1 failed/none-reported — see above), so wrap it the same way. (Incident: PRD 745 landed a truthful PASS and a fully green CI run, but an unannotated `sleep 20 && gh pr checks` and a harness-blocked `sleep 90 && gh pr checks` sat at the end of the transcript and the run was flagged anyway.)
88
- - **Don't leak expected-error text into tool output.** The verifier pattern-matches the transcript for `Traceback`/`FAIL`/`Error:`. When a step is *expected* to error (a TDD red-phase test, an existence probe), capture it and print a clean token instead of letting the raw exception land verbatim — e.g. `if <probe> 2>/dev/null; then echo PROBE_OK; else echo PROBE_ABSENT; fi`, or filter a noisy run down to `RED (expected)` / `GREEN`. When retrying a transient failure, re-run the exact same command with the same description — the self-recovery detector only pairs a failure with a later success when the wording matches.
89
- - **End green: run the AC gate LAST, and let nothing error after it.** The verifier weighs the final ~20% of the run most heavily — a tool error there trips a downgrade even when everything actually passed. Order the run so any intentionally-failing step (a TDD red test, an expected-nonzero probe) runs early, never after the gate. If you must demonstrate a failure late anyway, capture it (`… 2>&1 | tail` inside a conditional, or assert on the captured text) instead of letting it hit the transcript bare.
82
+ - **`gh pr edit --body` can fail on repos with legacy GitHub Projects (classic) boards.** It queries the deprecated `repository.pullRequest.projectCards` field and errors with a `GraphQL: Projects (classic) is being deprecated` message even though the edit itself would otherwise succeed — a known `gh` CLI quirk, not a defect in your work. Prefer `gh api -X PATCH repos/<owner>/<repo>/pulls/<n> -f body="$(cat body.md)"` instead; it skips that field. If `gh pr edit` fails this way anyway retry immediately with the `gh api` form and note the fallback in your report.
83
+ - **Never `sleep N && <cmd>` to poll remote CI/job status.** The harness hard-blocks a `sleep` chained to another command. Use the tool's own blocking watcher under a hard cap instead: `timeout 600 gh run watch <run-id> --repo <owner>/<repo> --exit-status`. `gh pr checks` exits 8 while checks are pending and 1 on failure — that is not a defect in your work.
90
84
  - **The verdict line is your authoritative "I passed" signal — emit it truthfully.** The scheduler's finish protocol ends by printing `SCHEDULER_VERDICT: PASS` once the AC gate is green and the commit has landed (or `SCHEDULER_VERDICT: FAIL <reason>` + `exit 1` otherwise). `PASS` plus a landed commit is authoritative: it overrides incidental transcript markers, so a deliberately reproduced red test or a grep result containing "Error" will not false-trip `needs_review`, as long as the run genuinely ends green and committed. Exiting 0 with uncommitted changes, or with no verdict line at all, is the #1 cause of needless `needs_review`. Never print `PASS` when the gate is red — that turns a safety net into a silent-failure machine.
91
85
  - **If your own AC gate failed on a SIBLING job's in-flight file, say so with the right verdict — don't print a lying FAIL.** If the prompt disclosed a `--- FOREIGN WORKING-TREE STATE ---` section and your gate failure is confined to paths that section named as not your work, print `SCHEDULER_VERDICT: BLOCKED_BY_FOREIGN_WIP` (and `exit 1`) plus a `FOREIGN_WIP_PATHS: <path1>, <path2>, ...` line naming exactly the failing paths. The scheduler validates every listed path against the manifest it disclosed to you — list a path it never named, or claim this verdict for your own regression, and it is rejected back to `FAIL`. This is not an escape hatch: it exists so a correctly-diagnosed "not my regression" gets auto-requeued once the sibling clears its WIP, instead of spawning a fix-plan investigation into someone else's unfinished work.
@@ -186,7 +186,7 @@ const TOOLS = [
186
186
  properties: {
187
187
  title: { type: 'string', description: 'One-line human-readable title' },
188
188
  cwd: { type: 'string', description: 'Absolute path to the target project (where claude -p will run). Optional inside an Epic session — the server resolves the real project from the calling session (originClaudeSessionId/sourcePromptId) when omitted.' },
189
- estimateMinutes: { type: 'number', description: 'Integer wall-clock estimate in minutes. Most PRDs take 5-10; never over 15 (split instead)' },
189
+ estimateMinutes: { type: 'number', description: 'Optional; normally omit. A run without one gets the 45-minute kill-budget floor. Pass one only for work that legitimately needs longer (budget = 3x the estimate, capped at 180 minutes).' },
190
190
  goal: { type: 'string', description: '2-4 sentences: what the executor will build and why' },
191
191
  acceptanceCriteria: {
192
192
  type: 'array', items: { type: 'string' },
@@ -226,7 +226,7 @@ const TOOLS = [
226
226
  description: 'Optional: set true only when this PRD\'s acceptance criteria are wall-clock/timing measurements (frame time, performance fences) that CPU contention from concurrent jobs would invalidate. The scheduler dispatches it only once zero other jobs are running machine-wide, and holds every other job off the whole slot pool for its run — a whole-machine exclusive lease, not a per-project one. If the machine never goes quiet within the configured wait window (default 30 minutes), it dispatches anyway and is marked degraded. Opt-in only; omit for ordinary PRDs.',
227
227
  },
228
228
  },
229
- required: ['title', 'estimateMinutes', 'goal', 'acceptanceCriteria', 'implementationNotes', 'gate', 'files'],
229
+ required: ['title', 'goal', 'acceptanceCriteria', 'implementationNotes', 'gate', 'files'],
230
230
  },
231
231
  },
232
232
  {
@@ -1,8 +1,8 @@
1
1
  {
2
- "version": "0.121.0",
3
- "gitSha": "9cde6952e65cad99fbe061866808a986c3dc0b41",
4
- "gitShortSha": "9cde6952",
2
+ "version": "0.122.0",
3
+ "gitSha": "667f0ce89dfac1ce0af310e3103720a9235d1d45",
4
+ "gitShortSha": "667f0ce8",
5
5
  "gitBranch": "HEAD",
6
- "builtAt": "2026-10-23T06:21:05.281Z",
6
+ "builtAt": "2026-10-23T15:49:36.718Z",
7
7
  "dirty": false
8
8
  }
@@ -5,19 +5,12 @@
5
5
  * the terminal chat UI (PRD 319). Each call spawns a fresh process that exits
6
6
  * when done; no idle process lives between commands.
7
7
  *
8
- * v0.34: silent (automated) runs are serialized through a FIFO queue capped at
9
- * CONCURRENCY_CAP (SM_CHAT_CONCURRENCY overrides, clamped to [1,3]); modeled
10
- * on the scheduler's serialized queue so a burst of probes can't fan out into
11
- * the parallel-`claude -p` OOM that SIGKILLed a job on 2026-06-26.
12
- * PRD 493 had manual, user-initiated runs bypass that lane entirely (always
13
- * immediate, uncapped). A later PRD (per-tab prompt queue) folded manual runs
14
- * back into the SAME FIFO lane — a per-tab queue in the renderer (chat.ts)
15
- * now only ever calls run() once per tab at a time, so the cap governs
16
- * cross-tab fan-out, not per-tab ordering.
8
+ * Runs (silent and manual) go through one FIFO queue gated only by the shared
9
+ * sessionSlots pool; there is no chat-private concurrency cap.
17
10
  *
18
11
  * Public surface:
19
12
  * run({ tabId, sessionId, prompt, cwd, resume, silent }): void — fire-and-forget enqueue.
20
- * Both silent (PRD 470) and manual runs go through the same CONCURRENCY_CAP FIFO lane.
13
+ * Both silent (PRD 470) and manual runs go through the same FIFO queue.
21
14
  * Silent runs additionally suppress the six turn-affecting broadcasts + recordExchange.
22
15
  * cancel(tabId): Promise<void> — resolves once the cancelled run fully settles
23
16
  * parseStopSignal(finalText): { questions: string[] } | null — exported for reuse
@@ -295,22 +288,10 @@ const CHAT_MODE_TRUTH_INSTRUCTION =
295
288
  `either a real result or an explicit statement that the user needs to ` +
296
289
  `reply for the work to continue.\n\n`;
297
290
 
298
- // ─── Serial run queue (v0.34) ───────────────────────────────────────────────
299
- // CONCURRENCY_CAP=2 (default) governs ALL runs — silent probes and manual
300
- // sends alike share one FIFO lane; two can run at once across all tabs before
301
- // a 3rd queues. SM_CHAT_CONCURRENCY still overrides, clamped to [1, 3].
302
-
303
- const DEFAULT_CAP = 2;
304
- // Clamp to [1, 3]; default 2 = "two loops at a time". Read lazily (not
305
- // captured at module-load time) so tests can stub the env per-case without
306
- // vi.resetModules(); production behavior is unaffected since the env var
307
- // never changes mid-process.
308
- function getConcurrencyCap() {
309
- return Math.min(
310
- 3,
311
- Math.max(1, parseInt(process.env.SM_CHAT_CONCURRENCY || String(DEFAULT_CAP), 10) || DEFAULT_CAP),
312
- );
313
- }
291
+ // ─── Run queue ──────────────────────────────────────────────────────────────
292
+ // FIFO lane for ALL runs (silent probes and manual sends). There is NO private
293
+ // cap: a queued run starts exactly when lib/scheduler/sessionSlots.cjs grants a
294
+ // slot — the sole machine-wide cap.
314
295
 
315
296
  // tabId → { cancelFn, donePromise } for every ACTIVE run; FIFO list of WAITING
316
297
  // runs; live count. `donePromise` resolves once the run's own executeRun()
@@ -330,7 +311,6 @@ const dispatching = new Set();
330
311
  // "Session ID … is already in use", so pump() refuses to start a second run
331
312
  // for a held sessionId (it waits in `waiting` like any other blocked run).
332
313
  const liveSessions = new Set();
333
- let activeCount = 0;
334
314
 
335
315
  // Indirection so tests can stub the spawn without launching claude.
336
316
  let executor = executeRun;
@@ -347,7 +327,6 @@ function __resetQueueForTests() {
347
327
  dispatching.clear();
348
328
  liveSessions.clear();
349
329
  waiting.length = 0;
350
- activeCount = 0;
351
330
  sessionSlots.__resetForTests();
352
331
  }
353
332
 
@@ -370,7 +349,7 @@ function broadcast(channel, payload) {
370
349
  /**
371
350
  * Enqueue a chat run for a tab. Fire-and-forget — results arrive via IPC.
372
351
  * Both silent (automated probe) and manual (user-initiated) runs share the
373
- * CONCURRENCY_CAP=2 (default) FIFO lane — extra submits queue and are
352
+ * FIFO lane — submits beyond the free slots queue and are
374
353
  * announced via chat:run:queued (silent runs stay invisible to the renderer;
375
354
  * see pump() below). De-dupes a tab already in the pipeline (the renderer's
376
355
  * per-tab prompt queue in chat.ts only ever calls this once per tab at a
@@ -407,10 +386,10 @@ function run(opts) {
407
386
  return { accepted: true, queued: tabBusy };
408
387
  }
409
388
 
410
- // Fill open lanes FIFO up to CONCURRENCY_CAP, then announce queue positions for
389
+ // Start queued runs FIFO while sessionSlots grants a slot, then announce queue positions for
411
390
  // the remainder. O(n) over the waiting list (bounded by open tabs).
412
391
  function pump() {
413
- while (activeCount < getConcurrencyCap() && waiting.length > 0) {
392
+ while (waiting.length > 0) {
414
393
  // Per-tab exclusivity: skip past any waiting run whose tab already has one
415
394
  // live, rather than head-blocking the whole lane on it. `dispatching`
416
395
  // covers the gap between picking a job here and executeRun() registering
@@ -422,14 +401,12 @@ function pump() {
422
401
  // Everything queued is blocked behind its own tab's live run; the settle()
423
402
  // of that run re-pumps.
424
403
  if (idx === -1) break;
425
- // The chat lane cap is a POLICY bound; actual capacity comes from the
426
- // Session-Manager-wide slot pool shared with the scheduler
427
- // (lib/scheduler/sessionSlots.cjs). No slot → everyone keeps waiting; the next
428
- // settle() in either subsystem re-pumps.
404
+ // Capacity comes only from the Session-Manager-wide slot pool shared with
405
+ // the scheduler (lib/scheduler/sessionSlots.cjs). Refusal → stop; the rest
406
+ // stay queued in order and the next release in either subsystem re-pumps.
429
407
  const slotToken = sessionSlots.acquire(`chat:${waiting[idx].tabId}`);
430
408
  if (!slotToken) break;
431
409
  const [job] = waiting.splice(idx, 1);
432
- activeCount += 1;
433
410
  dispatching.add(job.tabId);
434
411
  liveSessions.add(job.sessionId);
435
412
  Promise.resolve()
@@ -444,7 +421,6 @@ function pump() {
444
421
  dispatching.delete(job.tabId);
445
422
  liveSessions.delete(job.sessionId);
446
423
  sessionSlots.release(slotToken);
447
- activeCount -= 1;
448
424
  pump();
449
425
  });
450
426
  }
@@ -97,6 +97,7 @@ async function runClaude(prompt, { model = 'sonnet', timeoutMs = 90_000, systemP
97
97
  '--model', model,
98
98
  '--dangerously-skip-permissions',
99
99
  ...headlessPermissionArgs(),
100
+ '--strict-mcp-config',
100
101
  '--output-format', 'text',
101
102
  ];
102
103
  if (systemPrompt) args.push('--append-system-prompt', systemPrompt);
@@ -100,12 +100,14 @@ const pluginInstall = require('./pluginInstall.cjs');
100
100
  const { seedDevPlugin } = require('./seedDevPlugin.cjs');
101
101
  const { seedAgentPersonas } = require('./seedAgentPersonas.cjs');
102
102
  const { seedSchedulerMcp } = require('./seedSchedulerMcp.cjs');
103
+ const { runSeedersSerially } = require('./lib/runSeeders.cjs');
103
104
  const { getSeedStatus } = require('./seedStatus.cjs');
104
105
  const otel = require('./otel.cjs');
105
106
  const otelSettings = require('./otelSettings.cjs');
106
107
  const { registerHistoryAggregatorHandlers, finalizeClosedDays, refreshIntradayToday } = require('./historyAggregator.cjs');
107
108
  const runLogRetention = require('./lib/scheduler/runLogRetention.cjs');
108
109
  const { registerHistoryDashboardHandlers } = require('./historyDashboard.cjs');
110
+ const { registerLoopEfficiencyHandlers } = require('./loopEfficiencyHandlers.cjs');
109
111
  const { tryAcquireLock, releaseLock, DEFAULT_LOCK_PATH } = require('./lib/scheduler/watchdogHelpers.cjs');
110
112
  const { createIntradayRefresh } = require('./lib/intradayRefresh.cjs');
111
113
  const schedulerConfig = require('./lib/scheduler/schedulerConfig.cjs');
@@ -1003,6 +1005,7 @@ watchers.registerWatcherHandlers();
1003
1005
  queueOps.registerQueueOpsHandlers({ retireCompletedSlugs: scheduler.retireCompletedSlugs });
1004
1006
  registerHistoryAggregatorHandlers();
1005
1007
  registerHistoryDashboardHandlers();
1008
+ registerLoopEfficiencyHandlers();
1006
1009
  pluginInstall.registerPluginInstallHandlers();
1007
1010
  memoryTool.registerMemoryHandlers();
1008
1011
  activeIndexMerge.registerActiveIndexMergeHandlers();
@@ -1442,9 +1445,6 @@ app.whenReady().then(async () => {
1442
1445
  // First-boot default: install the bundled session-manager-dev plugin (its 3
1443
1446
  // dev skills) from the app's own marketplace. One-shot + idempotent; never
1444
1447
  // throws. SM_SEED_DEV_PLUGIN_DISABLE=1 to opt out.
1445
- seedDevPlugin({ logger: console, writeLog: logs.writeLine }).catch((e) => {
1446
- logs.writeLine({ scope: 'seed-dev-plugin', level: 'error', message: 'seed failed', meta: { error: e?.message } });
1447
- });
1448
1448
  webRemote.init().catch((e) => {
1449
1449
  logs.writeLine({ scope: 'webRemote', level: 'error', message: 'init failed', meta: { error: e?.message } });
1450
1450
  });
@@ -1452,16 +1452,15 @@ app.whenReady().then(async () => {
1452
1452
  // into ~/.claude/agents/ so the Agent Library isn't empty on a fresh
1453
1453
  // install. One-shot + idempotent; never overwrites an existing persona;
1454
1454
  // never throws. SM_SEED_AGENT_PERSONAS_DISABLE=1 to opt out.
1455
- seedAgentPersonas({ logger: console, writeLog: logs.writeLine }).catch((e) => {
1456
- logs.writeLine({ scope: 'seed-agent-personas', level: 'error', message: 'seed failed', meta: { error: e?.message } });
1457
- });
1458
- // First-boot default: register the session-manager-scheduler MCP server at
1459
- // USER scope so scheduler_create_prd is available in every project, not
1460
- // just this repo's own .mcp.json. One-shot + idempotent; never overwrites
1461
- // an existing registration; never throws. SM_SEED_SCHEDULER_MCP_DISABLE=1
1462
- // to opt out.
1463
- seedSchedulerMcp({ logger: console, writeLog: logs.writeLine }).catch((e) => {
1464
- logs.writeLine({ scope: 'seed-scheduler-mcp', level: 'error', message: 'seed failed', meta: { error: e?.message } });
1455
+ // Seeders run through ONE serial chain (runSeeders.cjs): plugin install and
1456
+ // `mcp add --scope user` both write Claude's config files, and concurrent
1457
+ // writes can drop an entry. Fire-and-forget relative to window creation.
1458
+ runSeedersSerially([
1459
+ { name: 'dev-plugin', run: () => seedDevPlugin({ logger: console, writeLog: logs.writeLine }) },
1460
+ { name: 'agent-personas', run: () => seedAgentPersonas({ logger: console, writeLog: logs.writeLine }) },
1461
+ { name: 'scheduler-mcp', run: () => seedSchedulerMcp({ logger: console, writeLog: logs.writeLine }) },
1462
+ ]).catch((e) => {
1463
+ logs.writeLine({ scope: 'seed', level: 'error', message: 'seed chain failed', meta: { error: e?.message } });
1465
1464
  });
1466
1465
  // Rewrite the stable guard-hook shims (~/.claude/session-manager/hooks/) to
1467
1466
  // point at THIS running app's root, on every boot. An already-installed
@@ -365,7 +365,7 @@ const schedulerCreatePrd = z.object({
365
365
  // sourcePromptId/originProjectRoot. A call with none of those still fails with
366
366
  // a clear "cwd is required" error.
367
367
  cwd: z.string().min(1).max(4096).regex(NO_NEWLINE_RE, 'must not contain newlines').optional(),
368
- estimateMinutes: z.number().int().min(1).max(100000),
368
+ estimateMinutes: z.number().int().min(1).max(100000).optional(),
369
369
  goal: z.string().min(1).max(20000),
370
370
  acceptanceCriteria: z.array(z.string().min(1).max(2000)).min(1).max(100),
371
371
  implementationNotes: z.string().min(1).max(20000),
@@ -596,7 +596,7 @@ const setConfigSchema = z.object({
596
596
  (s) => s === home || s.startsWith(home + path.sep),
597
597
  'defaultCwd must be inside home directory'
598
598
  ).optional(),
599
- firePolicy: z.enum(['when-available', 'on-reset', 'manual']).optional(),
599
+ firePolicy: z.enum(['when-available', 'manual']).optional(),
600
600
  utilizationThreshold: z.number().min(0).max(200).optional(),
601
601
  supervisor: z.object({
602
602
  enabled: z.boolean().optional(),
@@ -64,6 +64,7 @@ function classifyPromptTicket(text) {
64
64
  const args = [
65
65
  '-p', `${CLASSIFY_PROMPT_PREFIX}${text}`,
66
66
  '--model', CLASSIFY_MODEL,
67
+ '--strict-mcp-config',
67
68
  '--output-format', 'text',
68
69
  ];
69
70
 
@@ -137,28 +137,16 @@ function readHotJobsForCwd(cwd, deps) {
137
137
  /** Best-effort read of `<cwd>/session-manager-operations/scheduler/state/history.jsonl`'s archived rows. */
138
138
  function readHistoryEntriesForCwd(cwd, deps) {
139
139
  const { projectHistoryPath } = deps.queueStore || require('../scheduler/queueStore.cjs');
140
- let text;
141
- try {
142
- text = fs.readFileSync(projectHistoryPath(cwd), 'utf8');
143
- } catch {
144
- return [];
145
- }
140
+ const { readHistoryFileTailSync } = deps.queueHistory || require('../scheduler/queueHistory.cjs');
141
+ // Bounded tail (<=500 rows / <=1 MB): only the most recent matching row matters.
142
+ const rows = readHistoryFileTailSync(projectHistoryPath(cwd), { maxRows: 500, maxBytes: 1024 * 1024 });
143
+ // Tail reader is newest-first; callers sort by timestamp anyway.
146
144
  const entries = [];
147
- for (const line of text.split('\n')) {
148
- if (!line.trim()) continue;
149
- try {
150
- const j = JSON.parse(line);
151
- // needs_review_entry/needs_review_resolution lines (needsReviewLedger.cjs)
152
- // share history.jsonl with terminal job rows but carry no `agentType` —
153
- // findLatestSchedulerModel's own `j.agentType === agentType` filter
154
- // already excludes them, but skip explicitly here too so this reader
155
- // stays correct even if a future ledger line shape happens to pick up
156
- // an agentType-shaped field.
157
- if (j?.kind && j.kind !== 'terminal') continue;
158
- entries.push(j);
159
- } catch {
160
- // corrupt/partial line — skip
161
- }
145
+ for (const j of rows) {
146
+ // needs_review_entry/needs_review_resolution lines (needsReviewLedger.cjs)
147
+ // share history.jsonl with terminal job rows; skip non-terminal kinds.
148
+ if (j?.kind && j.kind !== 'terminal') continue;
149
+ entries.push(j);
162
150
  }
163
151
  return entries;
164
152
  }
@@ -54,10 +54,16 @@ function personaToolScopeArgs(scope) {
54
54
  prompt: 'Tool scope is enforced by the scheduler.',
55
55
  tools: scope.tools,
56
56
  };
57
- return [
57
+ const args = [
58
58
  '--agents', JSON.stringify({ [HEADLESS_SCOPE_AGENT_NAME]: def }),
59
59
  '--agent', HEADLESS_SCOPE_AGENT_NAME,
60
60
  ];
61
+ // A scope naming no MCP tool never uses a server: with --strict-mcp-config and
62
+ // no --mcp-config (variadic; would swallow later args) the CLI boots none.
63
+ if (!scope.tools.some((t) => String(t).startsWith('mcp__'))) {
64
+ args.push('--strict-mcp-config');
65
+ }
66
+ return args;
61
67
  }
62
68
 
63
69
  module.exports = {
@@ -32,6 +32,7 @@ async function runClaudeP(prompt, { model = 'sonnet', timeoutMs = 180_000, syste
32
32
  '--model', model,
33
33
  '--dangerously-skip-permissions',
34
34
  ...headlessPermissionArgs(),
35
+ '--strict-mcp-config',
35
36
  '--output-format', 'text',
36
37
  ];
37
38
  if (systemPrompt) args.push('--append-system-prompt', systemPrompt);