claude-code-session-manager 0.120.0 → 0.121.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 (42) hide show
  1. package/dist/assets/{AgentLibrary-LBg3mVL8.js → AgentLibrary-FO2ei2wB.js} +1 -1
  2. package/dist/assets/{Button-C4BN5ISR.js → Button-CeIOXUPU.js} +1 -1
  3. package/dist/assets/{DataModel-CHhjk61s.js → DataModel-D0p__Hil.js} +1 -1
  4. package/dist/assets/{History-CL-T6Lv3.js → History-DVqQ5azN.js} +1 -1
  5. package/dist/assets/{Hooks-ByWVgXIf.js → Hooks-DkTnRHyT.js} +1 -1
  6. package/dist/assets/{Library-QvYVAEmY.js → Library-l7KS6pkE.js} +1 -1
  7. package/dist/assets/{ListDetail-FvNe6fo5.js → ListDetail-DDw8fuRT.js} +1 -1
  8. package/dist/assets/{McpServers-C7EmPm8B.js → McpServers-UUNIxk_3.js} +1 -1
  9. package/dist/assets/{Memory-nyLR4Yw4.js → Memory-CNYUoQ8C.js} +1 -1
  10. package/dist/assets/{Panel-thElCbLX.js → Panel-Bb54soc2.js} +1 -1
  11. package/dist/assets/{Permissions-FQ9GM6Ca.js → Permissions-D-dNdV3f.js} +1 -1
  12. package/dist/assets/{Plugins-D9KE7XTI.js → Plugins-DhcIXRhQ.js} +2 -2
  13. package/dist/assets/{ProvenanceBadge-lAViG8yV.js → ProvenanceBadge-DEAkDNjA.js} +1 -1
  14. package/dist/assets/{RemoteMachines-AWpARk7N.js → RemoteMachines-xCEgvTGU.js} +1 -1
  15. package/dist/assets/{SaveBar-c15EEGB_.js → SaveBar-BSEs7ecA.js} +1 -1
  16. package/dist/assets/{Scheduler-FvduP1FG.js → Scheduler-BIKJIU-C.js} +1 -1
  17. package/dist/assets/{ScopeSwitcher-BLep1rtB.js → ScopeSwitcher-DcaFyAV-.js} +1 -1
  18. package/dist/assets/{Settings-D1kTUIDB.js → Settings-vcdWy_Jx.js} +1 -1
  19. package/dist/assets/{SkillReferenceGraph-_40_f0t3.js → SkillReferenceGraph-CLrJWTPd.js} +1 -1
  20. package/dist/assets/{Skills-DaTkSOuU.js → Skills-CYM4rBEC.js} +1 -1
  21. package/dist/assets/{SystemPrompt-DxNf-soM.js → SystemPrompt-BWNIu-iY.js} +1 -1
  22. package/dist/assets/{TagLibrary-L6KpBV-x.js → TagLibrary-CYdwHK6m.js} +1 -1
  23. package/dist/assets/{TiptapBody-C_XjtJ82.js → TiptapBody-Kt90lHrD.js} +1 -1
  24. package/dist/assets/{Toggle-H0rERKNI.js → Toggle-D1OXWYOz.js} +1 -1
  25. package/dist/assets/{ViewTabs-ZUWphDat.js → ViewTabs-BeQR3CKh.js} +1 -1
  26. package/dist/assets/{historyTotals-BxFKOztb.js → historyTotals-B0qafrRo.js} +1 -1
  27. package/dist/assets/{index-B5wj0DEX.js → index-Bq9uH08R.js} +200 -200
  28. package/dist/assets/{settingsSchema-BRcYkXJN.js → settingsSchema-0ZksSAPB.js} +1 -1
  29. package/dist/assets/{skillFrontmatter-DFGp4DST.js → skillFrontmatter-C0nh8yfa.js} +1 -1
  30. package/dist/assets/{useAgentsDirWatch-VvrgalfC.js → useAgentsDirWatch-DPkoBybS.js} +1 -1
  31. package/dist/assets/{useRemotePeers-mvXKNEE3.js → useRemotePeers-BDJMUihy.js} +1 -1
  32. package/dist/index.html +1 -1
  33. package/package.json +1 -1
  34. package/src/main/build-info.json +4 -4
  35. package/src/main/chatRunner.cjs +43 -6
  36. package/src/main/ipcSchemas.cjs +15 -1
  37. package/src/main/lib/persona-macro/macroLibrary.cjs +75 -0
  38. package/src/main/lib/prd/prdCreate.cjs +25 -0
  39. package/src/main/lib/remoteTranscriptTail.cjs +69 -2
  40. package/src/main/webRemote.cjs +82 -91
  41. package/src/preload/api.d.ts +13 -0
  42. package/src/preload/index.cjs +2 -0
@@ -1 +1 @@
1
- import{aF as b,ap as n,S as N,a_ as O}from"./index-B5wj0DEX.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-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,4 +1,4 @@
1
- import{ap as k,F as E}from"./index-B5wj0DEX.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-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(`
2
2
  `)?"":`
3
3
  `;return`---
4
4
  ${u}: true
@@ -1 +1 @@
1
- import{W as e,b4 as a,a$ as n}from"./index-B5wj0DEX.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-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 +1 @@
1
- import{ap as t,A as f,bf as g,aF as d}from"./index-B5wj0DEX.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-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};
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-B5wj0DEX.js"></script>
10
+ <script type="module" crossorigin src="./assets/index-Bq9uH08R.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.120.0",
3
+ "version": "0.121.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",
@@ -1,8 +1,8 @@
1
1
  {
2
- "version": "0.120.0",
3
- "gitSha": "f81d47d11d2bd35b1be6a9da74ca84c3c56d0357",
4
- "gitShortSha": "f81d47d1",
2
+ "version": "0.121.0",
3
+ "gitSha": "9cde6952e65cad99fbe061866808a986c3dc0b41",
4
+ "gitShortSha": "9cde6952",
5
5
  "gitBranch": "HEAD",
6
- "builtAt": "2026-10-22T04:34:31.316Z",
6
+ "builtAt": "2026-10-23T06:21:05.281Z",
7
7
  "dirty": false
8
8
  }
@@ -969,16 +969,48 @@ function cancel(tabId) {
969
969
  // directly, reusing send()'s existing queued-vs-immediate branching rather
970
970
  // than duplicating it here.
971
971
 
972
+ const EXTERNAL_SEND_ACK_TIMEOUT_MS = 8000;
973
+ const pendingExternalSends = new Map(); // requestId -> { resolve, timer }
974
+
975
+ function hasLiveWindow() {
976
+ try {
977
+ return !!(mainWindow && !mainWindow.isDestroyed() && mainWindow.webContents && !mainWindow.webContents.isDestroyed());
978
+ } catch { return false; }
979
+ }
980
+
981
+ /**
982
+ * Resolves { disposition, reason? } once the renderer reports what it did, or
983
+ * { disposition: 'unconfirmed', reason: 'timeout' | 'no-window' }. Never rejects.
984
+ */
972
985
  function enqueueExternalPrompt(tabId, prompt, extra = {}) {
973
986
  const { sessionId, cwd } = extra ?? {};
974
- broadcast('chat:external-send', {
975
- tabId,
976
- prompt,
977
- ...(sessionId !== undefined ? { sessionId } : {}),
978
- ...(cwd !== undefined ? { cwd } : {}),
987
+ if (!hasLiveWindow()) return Promise.resolve({ disposition: 'unconfirmed', reason: 'no-window' });
988
+ const requestId = require('node:crypto').randomUUID();
989
+ return new Promise((resolve) => {
990
+ const timer = setTimeout(() => {
991
+ pendingExternalSends.delete(requestId);
992
+ resolve({ disposition: 'unconfirmed', reason: 'timeout' });
993
+ }, EXTERNAL_SEND_ACK_TIMEOUT_MS);
994
+ timer.unref?.();
995
+ pendingExternalSends.set(requestId, { resolve, timer });
996
+ broadcast('chat:external-send', {
997
+ requestId,
998
+ tabId,
999
+ prompt,
1000
+ ...(sessionId !== undefined ? { sessionId } : {}),
1001
+ ...(cwd !== undefined ? { cwd } : {}),
1002
+ });
979
1003
  });
980
1004
  }
981
1005
 
1006
+ function settleExternalSend({ requestId, disposition, reason }) {
1007
+ const entry = pendingExternalSends.get(requestId);
1008
+ if (!entry) return;
1009
+ clearTimeout(entry.timer);
1010
+ pendingExternalSends.delete(requestId);
1011
+ entry.resolve({ disposition, ...(reason !== undefined ? { reason } : {}) });
1012
+ }
1013
+
982
1014
  // Asks the renderer to start a new Session (same launchSession a macro press
983
1015
  // uses) on behalf of the paired phone. Payload is pre-validated by the caller.
984
1016
  function requestExternalNewSession(payload) {
@@ -1010,7 +1042,7 @@ function registerAdminRoute(adminHttp) {
1010
1042
  sendJson(res, 400, { ok: false, error: e?.message ?? 'invalid body' });
1011
1043
  return;
1012
1044
  }
1013
- enqueueExternalPrompt(body.tabId, body.prompt);
1045
+ void enqueueExternalPrompt(body.tabId, body.prompt);
1014
1046
  sendJson(res, 200, { ok: true });
1015
1047
  });
1016
1048
  }
@@ -1052,6 +1084,10 @@ function registerChatHandlers() {
1052
1084
  return classifyPromptTicket(text);
1053
1085
  }));
1054
1086
 
1087
+ ipcMain.handle('chat:external-send-result', validated(schemas.chatExternalSendResult, async (payload) => {
1088
+ settleExternalSend(payload);
1089
+ }));
1090
+
1055
1091
  ipcMain.handle('chat:cancel', async (_e, payload) => {
1056
1092
  let tabId;
1057
1093
  try { tabId = schemas.chatCancel.parse(payload).tabId; } catch { return; }
@@ -1082,6 +1118,7 @@ module.exports = {
1082
1118
  WARN_CEILING_MS,
1083
1119
  __setExecutor,
1084
1120
  enqueueExternalPrompt,
1121
+ EXTERNAL_SEND_ACK_TIMEOUT_MS,
1085
1122
  requestExternalNewSession,
1086
1123
  registerAdminRoute,
1087
1124
  };
@@ -13,7 +13,7 @@ const { PromptSessionSchema, EpicTagSchema, EpicSourceSchema, EpicIntakeSectionS
13
13
  const { PrdWorkTypeSchema } = require('./lib/prd/workTypeLibrary.cjs');
14
14
  const { PERSONA_NAME_RE } = require('./agentLibrary.cjs');
15
15
  const { AgentPersonaSaveSchema } = require('./lib/persona-macro/agentPersonaSchema.cjs');
16
- const { MacroSaveSchema, MacroDeleteSchema, MacroSetProjectSchema } = require('./lib/persona-macro/macroLibrary.cjs');
16
+ const { MacroSaveSchema, MacroDeleteSchema, MacroSetProjectSchema, MacroInputSchema } = require('./lib/persona-macro/macroLibrary.cjs');
17
17
 
18
18
  // ──────────────────────────────────────────── PTY
19
19
  const ptySpawn = z.object({
@@ -960,6 +960,14 @@ const chatExternalSend = z.object({
960
960
  ),
961
961
  });
962
962
 
963
+ // Renderer's report of what it did with a `chat:external-send` (mirrors
964
+ // ChatExternalSendResult in preload/api.d.ts).
965
+ const chatExternalSendResult = z.object({
966
+ requestId: z.string().min(1).max(64),
967
+ disposition: z.enum(['sent', 'queued', 'refused']),
968
+ reason: z.enum(['terminal-attached', 'completed', 'unknown-target', 'empty-prompt']).optional(),
969
+ });
970
+
963
971
  // Phone drill-down reads. cwd is re-checked against the open tabs in
964
972
  // webRemote.cjs; sessionKey becomes a transcript filename lookup so it is
965
973
  // restricted to a session-id charset (no '/', so no traversal).
@@ -968,6 +976,7 @@ const remoteSessionTranscript = z.object({
968
976
  cwd: z.string().min(1).max(4096),
969
977
  sessionKey: z.string().min(1).max(128).regex(/^[A-Za-z0-9][A-Za-z0-9_.-]*$/),
970
978
  limit: z.number().int().min(1).max(100).optional(),
979
+ before: z.number().int().min(0).max(10000).optional(),
971
980
  });
972
981
  // One Epic's PRD list (slug/title/status projection only, never bodies).
973
982
  const remoteSessionPrds = z.object({
@@ -986,6 +995,10 @@ const remoteSessionCreate = z.object({
986
995
  (s) => Buffer.byteLength(s, 'utf8') <= CHAT_PROMPT_MAX_BYTES,
987
996
  `prompt must be ≤ ${CHAT_PROMPT_MAX_BYTES} bytes`,
988
997
  ),
998
+ macroId: MacroDeleteSchema.shape.id.optional(),
999
+ inputs: z.record(MacroInputSchema.shape.name, z.string().max(2000))
1000
+ .refine((o) => Object.keys(o).length <= 20, 'too many inputs')
1001
+ .optional(),
989
1002
  });
990
1003
 
991
1004
  // ──────────────────────────────────────────── Web Remote
@@ -1352,6 +1365,7 @@ module.exports = {
1352
1365
  chatCancel,
1353
1366
  chatClassifyTicket,
1354
1367
  chatExternalSend,
1368
+ chatExternalSendResult,
1355
1369
  remoteSessionCreate,
1356
1370
  remoteProjectSessions,
1357
1371
  remoteSessionTranscript,
@@ -93,6 +93,61 @@ function refineInputs(value, ctx) {
93
93
  }
94
94
  }
95
95
 
96
+ /** Distinct `{{name}}` placeholder names in first-seen order. */
97
+ function macroPlaceholders(prompt) {
98
+ const names = [];
99
+ for (const m of String(prompt).matchAll(new RegExp(MACRO_PLACEHOLDER_RE.source, 'g'))) {
100
+ if (!names.includes(m[1])) names.push(m[1]);
101
+ }
102
+ return names;
103
+ }
104
+
105
+ /** `{ [name]: default ?? '' }` for every declared input. */
106
+ function defaultMacroValues(inputs) {
107
+ const out = {};
108
+ for (const i of inputs || []) out[i.name] = i.default ?? '';
109
+ return out;
110
+ }
111
+
112
+ function sanitizeMacroValue(v) {
113
+ // eslint-disable-next-line no-control-regex
114
+ return v.replace(/[\r\n\t]+/g, ' ').replace(/[\u0000-\u001f\u007f]/g, '').trim();
115
+ }
116
+
117
+ const MACRO_PROMPT_RENDERED_MAX_LEN = 8000;
118
+
119
+ /**
120
+ * Mirrors `src/renderer/lib/macroPrompt.ts` renderMacroPrompt, but strict for macros
121
+ * without inputs: a placeholder with no declared input is always an error.
122
+ * @returns {{ ok: true, prompt: string } | { ok: false, error: string }}
123
+ */
124
+ function renderMacroPrompt(prompt, inputs, values) {
125
+ const vals = values && typeof values === 'object' ? values : {};
126
+ const clean = Object.create(null);
127
+ for (const input of inputs || []) {
128
+ const own = Object.prototype.hasOwnProperty.call(vals, input.name) && typeof vals[input.name] === 'string';
129
+ const v = sanitizeMacroValue(own ? vals[input.name] : (input.default ?? ''));
130
+ if (v === '') {
131
+ if (input.required) return { ok: false, error: `"${input.label}" is required` };
132
+ } else if (v.length > MACRO_INPUT_MAX_LEN) {
133
+ return { ok: false, error: `"${input.label}" is longer than ${MACRO_INPUT_MAX_LEN} characters` };
134
+ } else if (input.options && input.options.length > 0 && !input.options.includes(v)) {
135
+ return { ok: false, error: `"${input.label}" must be one of: ${input.options.join(', ')}` };
136
+ }
137
+ clean[input.name] = v;
138
+ }
139
+
140
+ for (const name of macroPlaceholders(prompt)) {
141
+ if (!(name in clean)) return { ok: false, error: `prompt uses undeclared input {{${name}}}` };
142
+ }
143
+
144
+ const rendered = String(prompt).replace(new RegExp(MACRO_PLACEHOLDER_RE.source, 'g'), (_m, n) => clean[n]);
145
+ if (rendered.length > MACRO_PROMPT_RENDERED_MAX_LEN) {
146
+ return { ok: false, error: `rendered prompt is longer than ${MACRO_PROMPT_RENDERED_MAX_LEN} characters` };
147
+ }
148
+ return { ok: true, prompt: rendered };
149
+ }
150
+
96
151
  const MacroSchema = z.object({
97
152
  id: MacroIdSchema,
98
153
  label: MacroLabelSchema,
@@ -151,6 +206,12 @@ function normalizeCwd(cwd) {
151
206
  return collapsed.replace(/\/+$/, '');
152
207
  }
153
208
 
209
+ /** True iff the macro is shown for `cwd`: its projects include '*' or the normalized cwd. */
210
+ function macroVisibleIn(macro, cwd) {
211
+ const projects = (macro && macro.projects) || [];
212
+ return projects.includes(ALL_PROJECTS) || projects.includes(normalizeCwd(cwd));
213
+ }
214
+
154
215
  function normalizeProjects(projects) {
155
216
  const out = [];
156
217
  for (const p of projects || []) {
@@ -414,6 +475,14 @@ async function loadForWrite(filePath, opts) {
414
475
  * Create (no id) or update (id) a macro. Returns the saved Macro.
415
476
  * Throws on invalid input or unknown id.
416
477
  */
478
+ /** Merged-macro check: every `{{name}}` in the prompt must be a declared input. */
479
+ function assertPlaceholdersDeclared(macro) {
480
+ const declared = new Set((macro.inputs || []).map((i) => i.name));
481
+ for (const name of macroPlaceholders(macro.prompt)) {
482
+ if (!declared.has(name)) throw new Error(`prompt placeholder {{${name}}} is not declared in inputs`);
483
+ }
484
+ }
485
+
417
486
  async function saveMacro(input, opts = {}) {
418
487
  const parsed = MacroSaveSchema.parse(input);
419
488
  const filePath = resolvePath(opts);
@@ -442,6 +511,7 @@ async function saveMacro(input, opts = {}) {
442
511
  } else {
443
512
  saved.inputs = parsed.inputs;
444
513
  }
514
+ assertPlaceholdersDeclared(saved);
445
515
  macros[idx] = saved;
446
516
  } else {
447
517
  const projects = parsed.projects !== undefined ? normalizeProjects(parsed.projects) : [];
@@ -457,6 +527,7 @@ async function saveMacro(input, opts = {}) {
457
527
  updatedAt: now,
458
528
  };
459
529
  if (parsed.inputs && parsed.inputs.length > 0) saved.inputs = parsed.inputs;
530
+ assertPlaceholdersDeclared(saved);
460
531
  macros.push(saved);
461
532
  }
462
533
  await writeStore(filePath, macros);
@@ -518,6 +589,10 @@ module.exports = {
518
589
  MacroSaveSchema,
519
590
  MacroDeleteSchema,
520
591
  MacroSetProjectSchema,
592
+ macroPlaceholders,
593
+ defaultMacroValues,
594
+ renderMacroPrompt,
595
+ macroVisibleIn,
521
596
  listMacros,
522
597
  saveMacro,
523
598
  deleteMacro,
@@ -29,6 +29,7 @@ const { resolveProjectContext } = require('../projectRootResolve.cjs');
29
29
  const { fixChainDepthOf, baseSlugOf } = require('../scheduler/fixChainDepth.cjs');
30
30
  const { DEFAULT_PRD_AGENT_TYPE, assertAgentTypeWritable } = require('./prdAgentType.cjs');
31
31
  const { resolveDepSlug, findNearMatches } = require('./depSlugResolve.cjs');
32
+ const { resolveEpicPrdWriteDir } = require('./prdLocations.cjs');
32
33
  const { isFixPlanSlug } = require('../scheduler/fixPlanSlug.cjs');
33
34
  const { isIncomplete, resolveChainTerminals, isValidPlanId, mintPlanId, resolveInheritedPlanId } = require('./prdDisposition.cjs');
34
35
  const { sizingWarnings } = require('./prdSizing.cjs');
@@ -443,6 +444,30 @@ async function createPrd(input, remote) {
443
444
  }
444
445
  extraWarnings.push(...await worktreeReachAdvisory(input, cwd));
445
446
 
447
+ // Duplicate-slug guard (2110/2111 phone-drop-summary-state: duplicate re-issue after archive).
448
+ // Finished rows leave queue.json, so an author can re-issue a landed PRD under a fresh NN.
449
+ // Refused before NN allocation so it burns no number. Fix plans are exempt.
450
+ if (input.sourcePromptId && !isFixPlanSlug(`0-${slug}`)) {
451
+ let epicDirs = [];
452
+ try {
453
+ const prdsDir = resolveEpicPrdWriteDir(cwd, input.sourcePromptId);
454
+ epicDirs = [prdsDir, path.join(path.dirname(prdsDir), 'prds-archived')];
455
+ } catch { /* unsafe epic id — no dirs to scan */ }
456
+ for (const dir of epicDirs) {
457
+ let names = [];
458
+ try { names = await fsp.readdir(dir); } catch { /* missing dir counts as empty */ }
459
+ const dup = names.find((n) => n.endsWith('.md') && n.slice(0, -3).replace(/^\d+-/, '') === slug);
460
+ if (dup) {
461
+ return {
462
+ ok: false,
463
+ status: 409,
464
+ error: `A PRD with slug "${slug}" already exists in this Epic as "${dup}". Its work may already have landed. ` +
465
+ 'Use scheduler_update_prd / scheduler_reset_job on it, or pick a distinct slug.',
466
+ };
467
+ }
468
+ }
469
+ }
470
+
446
471
  const nn = await remote.allocateParallelGroup(input.cwd);
447
472
  const filenameSlug = `${nn}-${slug}`;
448
473
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  // Bounded-tail reader for Claude Code JSONL transcripts: the last N human-readable
4
4
  // chat messages (user prompts + assistant text) without reading the whole file.
5
+ // Also builds the phone's conversation page (exchanges + live tail) in pure code.
5
6
  // Top-level (no domain fits: epic/ transcripts are path-only; util/ is domain-free).
6
7
  // Transcripts reach hundreds of MB, so cost is O(maxBytes), never O(file).
7
8
 
@@ -11,6 +12,10 @@ const DEFAULT_LIMIT = 30;
11
12
  const MAX_LIMIT = 100;
12
13
  const DEFAULT_MAX_BYTES = 524288;
13
14
  const MAX_TEXT_CHARS = 4000;
15
+ const MAX_PROMPT_CHARS = 2000;
16
+ const MAX_RESULT_CHARS = 16000;
17
+ const MAX_LIVE_MESSAGES = 20;
18
+ const MAX_PAGE_TEXT_BYTES = 100000; // relay closes any message over 256 KB
14
19
 
15
20
  /** Join the plain-text parts of a message `content` (string or block array). */
16
21
  function textOf(content) {
@@ -22,8 +27,12 @@ function textOf(content) {
22
27
  .join('\n');
23
28
  }
24
29
 
30
+ function cap(text, max) {
31
+ return text.length > max ? text.slice(0, max - 1) + '…' : text;
32
+ }
33
+
25
34
  function truncate(text) {
26
- return text.length > MAX_TEXT_CHARS ? text.slice(0, MAX_TEXT_CHARS - 1) + '…' : text;
35
+ return cap(text, MAX_TEXT_CHARS);
27
36
  }
28
37
 
29
38
  /** Parse one JSONL line into a chat message, or null when it is not one. */
@@ -87,4 +96,62 @@ async function readRecentChatMessages(filePath, { limit = DEFAULT_LIMIT, maxByte
87
96
  }
88
97
  }
89
98
 
90
- module.exports = { readRecentChatMessages };
99
+ /**
100
+ * Pure: build one phone-ready conversation page from exchanges (NEWEST-FIRST,
101
+ * callers fetch `limit + 1` so `hasMore` is derivable) plus the live transcript tail.
102
+ * @param {{ exchanges?: any[], tail?: any[], limit?: number, before?: number }} [opts]
103
+ * @returns {{ messages: Array<{ role: string, text: string, ts: string|null, uuid: string|null, live?: true }>, hasMore: boolean, nextBefore: number|null }}
104
+ * messages oldest-first: history, then live.
105
+ */
106
+ function buildRemoteConversation({ exchanges = [], tail = [], limit = 10, before = 0 } = {}) {
107
+ const n = Math.floor(Number(limit));
108
+ const lim = Number.isFinite(n) && n >= 1 ? n : 10;
109
+ const b = Math.max(0, Math.floor(Number(before)) || 0);
110
+ const valid = (Array.isArray(exchanges) ? exchanges : []).filter((e) => e && typeof e === 'object' && typeof e.ts === 'string');
111
+ const candidates = valid.slice(0, lim);
112
+ let hasMore = valid.length > lim;
113
+ let budget = MAX_PAGE_TEXT_BYTES;
114
+ const size = (text) => Buffer.byteLength(text, 'utf8');
115
+
116
+ // Live tail (first page only): newest-first until the budget is hit.
117
+ const live = [];
118
+ if (b === 0 && Array.isArray(tail)) {
119
+ const newest = valid.reduce((m, e) => Math.max(m, Date.parse(e.ts) || 0), 0);
120
+ const fresh = tail.filter((m) => {
121
+ if (!m || typeof m !== 'object' || typeof m.text !== 'string') return false;
122
+ if (!valid.length) return true;
123
+ const t = typeof m.ts === 'string' ? Date.parse(m.ts) : NaN;
124
+ return Number.isFinite(t) && t > newest;
125
+ });
126
+ for (const m of fresh.slice(-MAX_LIVE_MESSAGES).reverse()) {
127
+ const bytes = size(m.text);
128
+ if (bytes > budget) break;
129
+ budget -= bytes;
130
+ live.push({ role: m.role, text: m.text, ts: m.ts ?? null, uuid: m.uuid ?? null, live: true });
131
+ }
132
+ live.reverse();
133
+ }
134
+
135
+ // History: whole exchanges newest-first, oldest dropped when over budget.
136
+ const history = [];
137
+ let returned = 0;
138
+ for (const e of candidates) {
139
+ const pair = [];
140
+ const prompt = typeof e.prompt === 'string' ? e.prompt.trim() : '';
141
+ const result = typeof e.result === 'string' ? e.result.trim() : '';
142
+ if (prompt) pair.push({ role: 'user', text: cap(prompt, MAX_PROMPT_CHARS), ts: e.ts, uuid: `ex:${e.ts}:u` });
143
+ if (result) pair.push({ role: 'assistant', text: cap(result, MAX_RESULT_CHARS), ts: e.ts, uuid: `ex:${e.ts}:a` });
144
+ const bytes = pair.reduce((s, m) => s + size(m.text), 0);
145
+ if (bytes > budget) {
146
+ hasMore = true;
147
+ break;
148
+ }
149
+ budget -= bytes;
150
+ history.unshift(...pair);
151
+ returned++;
152
+ }
153
+
154
+ return { messages: [...history, ...live], hasMore, nextBefore: hasMore ? b + returned : null };
155
+ }
156
+
157
+ module.exports = { readRecentChatMessages, buildRemoteConversation };