claude-code-session-manager 0.113.0 → 0.115.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.
- package/dist/assets/{AgentLibrary-wvrcLGGS.js → AgentLibrary-CjsZLl5e.js} +1 -1
- package/dist/assets/{Button-B6h0F0XT.js → Button-mj0vvcdc.js} +1 -1
- package/dist/assets/{DataModel-C5pW9E3u.js → DataModel-CG6ycpfG.js} +1 -1
- package/dist/assets/{History-BV4e8YOM.js → History-DDqLQiAN.js} +1 -1
- package/dist/assets/{Hooks-CrFSv4x1.js → Hooks-dRje24Nk.js} +1 -1
- package/dist/assets/{Library-D-GIt3EY.js → Library-Dl71nylN.js} +1 -1
- package/dist/assets/{ListDetail-Bco_wfs6.js → ListDetail-DcAD_cuA.js} +1 -1
- package/dist/assets/{MarkdownEditor-C-yHSXNV.js → MarkdownEditor-D7JTNOOp.js} +1 -1
- package/dist/assets/{McpServers-CfDekadG.js → McpServers-BbvbhemH.js} +1 -1
- package/dist/assets/Memory-dyz8ZU1e.js +8 -0
- package/dist/assets/{Panel-DGMEuYYG.js → Panel-BkfK-W74.js} +1 -1
- package/dist/assets/{Permissions-Cx2zjtYZ.js → Permissions-BnjsXblr.js} +1 -1
- package/dist/assets/{Plugins-Bc_W3IyR.js → Plugins-DSyTJtTp.js} +2 -2
- package/dist/assets/{ProvenanceBadge-DiKAUR1u.js → ProvenanceBadge-CQXSiPHq.js} +1 -1
- package/dist/assets/{RemoteMachines-8_77-WPD.js → RemoteMachines-li6EBPAt.js} +1 -1
- package/dist/assets/{SaveBar-Blpzdq1R.js → SaveBar-0aiuy1L2.js} +1 -1
- package/dist/assets/{Scheduler-Bd70AM4X.js → Scheduler-Ul4jiK7q.js} +1 -1
- package/dist/assets/{ScopeSwitcher-wxN0h4YW.js → ScopeSwitcher-DR262W_R.js} +1 -1
- package/dist/assets/{Settings-CQ7DA3zW.js → Settings-BwUcGuar.js} +1 -1
- package/dist/assets/{SkillReferenceGraph-DH1NLOiS.js → SkillReferenceGraph-fv2FJUNK.js} +1 -1
- package/dist/assets/{Skills-CmyRyu4_.js → Skills-BA2I-iRE.js} +1 -1
- package/dist/assets/{SystemPrompt-KAc3UMCd.js → SystemPrompt-BgvyrAKx.js} +1 -1
- package/dist/assets/{TagLibrary-C8EvHnpg.js → TagLibrary-B5rKEDVT.js} +1 -1
- package/dist/assets/{TiptapBody-d423mH6D.js → TiptapBody-CBxxEulT.js} +1 -1
- package/dist/assets/{Toggle-D1wsGE9S.js → Toggle-W944m375.js} +1 -1
- package/dist/assets/{ViewTabs-CjHw3kGY.js → ViewTabs-BLQrBE2n.js} +1 -1
- package/dist/assets/{historyTotals-DFHzqLt7.js → historyTotals-BUeyjlNY.js} +1 -1
- package/dist/assets/{index-Dutcsly-.css → index-HpEbvDiE.css} +1 -1
- package/dist/assets/{index-Ci1u018F.js → index-t37UuEZu.js} +101 -101
- package/dist/assets/{settingsSchema-Ctf3pZVI.js → settingsSchema-HwiOXtC7.js} +1 -1
- package/dist/assets/{useAgentsDirWatch-B1NBmOAe.js → useAgentsDirWatch-D0rI9G_h.js} +1 -1
- package/dist/assets/{useRemotePeers-BHjSJs9D.js → useRemotePeers-BipAySOB.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/main/build-info.json +4 -4
- package/src/main/chatRunner.cjs +8 -2
- package/src/main/index.cjs +0 -2
- package/src/main/ipcSchemas.cjs +50 -35
- package/src/main/lib/memoryDirResolve.cjs +139 -0
- package/src/main/lib/memoryIndex.cjs +98 -0
- package/src/main/lib/remoteDrilldown.cjs +91 -0
- package/src/main/lib/remoteTranscriptTail.cjs +90 -0
- package/src/main/memoryAggregate.cjs +15 -8
- package/src/main/memoryTool.cjs +151 -22
- package/src/main/webRemote.cjs +90 -57
- package/src/preload/api.d.ts +44 -52
- package/src/preload/index.cjs +19 -21
- package/dist/assets/Memory-CGGLexkR.js +0 -8
- package/src/main/agentMemory.cjs +0 -246
|
@@ -1 +1 @@
|
|
|
1
|
-
import{aF as b,ap as n,S as N,aZ as O}from"./index-Ci1u018F.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(I,{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&&_(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 I({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 _(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,aZ as O}from"./index-t37UuEZu.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(I,{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&&_(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 I({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 _(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 +1 @@
|
|
|
1
|
-
import{V as e,b3 as a,a_ as n}from"./index-
|
|
1
|
+
import{V as e,b3 as a,a_ as n}from"./index-t37UuEZu.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,be as g,aF as d}from"./index-
|
|
1
|
+
import{ap as t,A as f,be as g,aF as d}from"./index-t37UuEZu.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,10 +7,10 @@
|
|
|
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-
|
|
10
|
+
<script type="module" crossorigin src="./assets/index-t37UuEZu.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
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
13
|
+
<link rel="stylesheet" crossorigin href="./assets/index-HpEbvDiE.css">
|
|
14
14
|
</head>
|
|
15
15
|
<body class="bg-bg text-fg font-sans antialiased">
|
|
16
16
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-session-manager",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.115.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",
|
package/src/main/build-info.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
3
|
-
"gitSha": "
|
|
4
|
-
"gitShortSha": "
|
|
2
|
+
"version": "0.115.0",
|
|
3
|
+
"gitSha": "76b8ec0587142349394786fefc05b0cfa0ef9a66",
|
|
4
|
+
"gitShortSha": "76b8ec05",
|
|
5
5
|
"gitBranch": "HEAD",
|
|
6
|
-
"builtAt": "2026-10-
|
|
6
|
+
"builtAt": "2026-10-13T18:38:06.307Z",
|
|
7
7
|
"dirty": false
|
|
8
8
|
}
|
package/src/main/chatRunner.cjs
CHANGED
|
@@ -966,8 +966,14 @@ function cancel(tabId) {
|
|
|
966
966
|
// directly, reusing send()'s existing queued-vs-immediate branching rather
|
|
967
967
|
// than duplicating it here.
|
|
968
968
|
|
|
969
|
-
function enqueueExternalPrompt(tabId, prompt) {
|
|
970
|
-
|
|
969
|
+
function enqueueExternalPrompt(tabId, prompt, extra = {}) {
|
|
970
|
+
const { sessionId, cwd } = extra ?? {};
|
|
971
|
+
broadcast('chat:external-send', {
|
|
972
|
+
tabId,
|
|
973
|
+
prompt,
|
|
974
|
+
...(sessionId !== undefined ? { sessionId } : {}),
|
|
975
|
+
...(cwd !== undefined ? { cwd } : {}),
|
|
976
|
+
});
|
|
971
977
|
}
|
|
972
978
|
|
|
973
979
|
// Asks the renderer to start a new Session (same launchSession a macro press
|
package/src/main/index.cjs
CHANGED
|
@@ -115,7 +115,6 @@ const { registerProjectBriefIpc } = require('./projectBrief.cjs');
|
|
|
115
115
|
const { registerProjectPagesIpc, attachWindow: attachProjectPagesWindow, closeAllOutputWatchers: closeAllProjectPagesWatchers } = require('./projectPages.cjs');
|
|
116
116
|
const promptSessionTranscript = require('./promptSessionTranscript.cjs');
|
|
117
117
|
const { computeEpicDelegationStats } = require('./lib/epic/epicDelegationStats.cjs');
|
|
118
|
-
const agentMemory = require('./agentMemory.cjs');
|
|
119
118
|
const git = require('./git.cjs');
|
|
120
119
|
const heapSnapshot = require('./heapSnapshot.cjs');
|
|
121
120
|
const filesIpc = require('./files.cjs');
|
|
@@ -1034,7 +1033,6 @@ ipcMain.handle('auditLog:append', validated(schemas.auditLogAppend, async ({ kin
|
|
|
1034
1033
|
appendAuditEvent(kind, { cwd, epicId, source });
|
|
1035
1034
|
return { ok: true };
|
|
1036
1035
|
}));
|
|
1037
|
-
agentMemory.registerAgentMemoryHandlers();
|
|
1038
1036
|
git.register(ipcMain);
|
|
1039
1037
|
filesIpc.registerFilesHandlers();
|
|
1040
1038
|
registerDocEditHandlers();
|
package/src/main/ipcSchemas.cjs
CHANGED
|
@@ -634,30 +634,48 @@ const { MEMORY_SLUG_RE } = require('./lib/memorySlug.cjs');
|
|
|
634
634
|
// 1 MiB hard cap — matches MAX_FILE_BYTES in memoryTool.cjs.
|
|
635
635
|
const MEMORY_MAX_BYTES = 1024 * 1024;
|
|
636
636
|
|
|
637
|
+
// Optional native-dir addressing: `cwd` selects Claude Code's own workspace dir
|
|
638
|
+
// (git root + autoMemoryDirectory); `agent` selects native subagent memory.
|
|
639
|
+
const MEMORY_CWD = z.string().max(4096).optional();
|
|
640
|
+
const MEMORY_AGENT = z.object({
|
|
641
|
+
name: z.string().regex(/^[A-Za-z0-9._-]{1,128}$/),
|
|
642
|
+
scope: z.enum(['user', 'project', 'local']),
|
|
643
|
+
}).strict().optional();
|
|
644
|
+
|
|
637
645
|
const memoryList = z.object({
|
|
638
646
|
workspace: z.string().regex(MEMORY_WORKSPACE_RE).optional(),
|
|
647
|
+
cwd: MEMORY_CWD,
|
|
648
|
+
agent: MEMORY_AGENT,
|
|
639
649
|
}).strict();
|
|
640
650
|
|
|
641
651
|
const memoryRead = z.object({
|
|
642
652
|
workspace: z.string().regex(MEMORY_WORKSPACE_RE).optional(),
|
|
643
653
|
name: z.string().regex(MEMORY_SLUG_RE),
|
|
654
|
+
cwd: MEMORY_CWD,
|
|
655
|
+
agent: MEMORY_AGENT,
|
|
644
656
|
}).strict();
|
|
645
657
|
|
|
646
658
|
const memoryWrite = z.object({
|
|
647
659
|
workspace: z.string().regex(MEMORY_WORKSPACE_RE).optional(),
|
|
648
660
|
name: z.string().regex(MEMORY_SLUG_RE),
|
|
649
661
|
content: z.string().max(MEMORY_MAX_BYTES),
|
|
662
|
+
cwd: MEMORY_CWD,
|
|
663
|
+
agent: MEMORY_AGENT,
|
|
650
664
|
}).strict();
|
|
651
665
|
|
|
652
666
|
const memoryDelete = z.object({
|
|
653
667
|
workspace: z.string().regex(MEMORY_WORKSPACE_RE).optional(),
|
|
654
668
|
name: z.string().regex(MEMORY_SLUG_RE),
|
|
669
|
+
cwd: MEMORY_CWD,
|
|
670
|
+
agent: MEMORY_AGENT,
|
|
655
671
|
}).strict();
|
|
656
672
|
|
|
657
673
|
const memoryCreate = z.object({
|
|
658
674
|
workspace: z.string().regex(MEMORY_WORKSPACE_RE).optional(),
|
|
659
675
|
name: z.string().regex(MEMORY_SLUG_RE),
|
|
660
676
|
description: z.string().max(2048).optional(),
|
|
677
|
+
cwd: MEMORY_CWD,
|
|
678
|
+
agent: MEMORY_AGENT,
|
|
661
679
|
}).strict();
|
|
662
680
|
|
|
663
681
|
// memory:stale — deterministic staleness scorer (PRD 601). `cwd`, when given,
|
|
@@ -666,6 +684,11 @@ const memoryCreate = z.object({
|
|
|
666
684
|
const memoryStale = z.object({
|
|
667
685
|
workspace: z.string().regex(MEMORY_WORKSPACE_RE).optional(),
|
|
668
686
|
cwd: z.string().max(4096).optional(),
|
|
687
|
+
agent: MEMORY_AGENT,
|
|
688
|
+
}).strict();
|
|
689
|
+
|
|
690
|
+
const memoryAgents = z.object({
|
|
691
|
+
cwd: MEMORY_CWD,
|
|
669
692
|
}).strict();
|
|
670
693
|
|
|
671
694
|
// memory:aggregate — Memory Clusters (PRD 356). `workspace` here is already
|
|
@@ -826,36 +849,6 @@ const auditLogAppend = z.object({
|
|
|
826
849
|
source: z.string().min(1).max(256),
|
|
827
850
|
}).strict();
|
|
828
851
|
|
|
829
|
-
// ──────────────────────────────────────────── Per-subagent memory
|
|
830
|
-
// Distinct from the workspace-scoped Memory tool: agentMemory is keyed by
|
|
831
|
-
// subagent name (the .md filename in ~/.claude/agents/, e.g. "code-reviewer"),
|
|
832
|
-
// not by cwd. Storage lives at ~/.claude/session-manager/agent-memory/<agentId>.json.
|
|
833
|
-
// Regex caps must stay in lockstep with agentMemory.cjs AGENT_ID_RE / ENTRY_ID_RE.
|
|
834
|
-
const AGENT_MEMORY_ID_RE = /^[A-Za-z0-9._-]{1,128}$/;
|
|
835
|
-
const AGENT_MEMORY_CATEGORY = z.enum(['command', 'preference', 'pattern', 'failure', 'workflow']);
|
|
836
|
-
const AGENT_MEMORY_MAX_BODY = 1024 * 1024; // 1 MiB — must match MAX_BODY_BYTES in agentMemory.cjs
|
|
837
|
-
|
|
838
|
-
const agentMemoryList = z.object({
|
|
839
|
-
agentId: z.string().regex(AGENT_MEMORY_ID_RE),
|
|
840
|
-
}).strict();
|
|
841
|
-
|
|
842
|
-
const agentMemoryGet = z.object({
|
|
843
|
-
agentId: z.string().regex(AGENT_MEMORY_ID_RE),
|
|
844
|
-
entryId: z.string().regex(AGENT_MEMORY_ID_RE),
|
|
845
|
-
}).strict();
|
|
846
|
-
|
|
847
|
-
const agentMemorySet = z.object({
|
|
848
|
-
agentId: z.string().regex(AGENT_MEMORY_ID_RE),
|
|
849
|
-
entryId: z.string().regex(AGENT_MEMORY_ID_RE),
|
|
850
|
-
body: z.string().max(AGENT_MEMORY_MAX_BODY),
|
|
851
|
-
category: AGENT_MEMORY_CATEGORY.optional(),
|
|
852
|
-
}).strict();
|
|
853
|
-
|
|
854
|
-
const agentMemoryDelete = z.object({
|
|
855
|
-
agentId: z.string().regex(AGENT_MEMORY_ID_RE),
|
|
856
|
-
entryId: z.string().regex(AGENT_MEMORY_ID_RE),
|
|
857
|
-
}).strict();
|
|
858
|
-
|
|
859
852
|
// ──────────────────────────────────────────── Exchanges (PRD 324 read path)
|
|
860
853
|
const SESSION_ID_RE = /^[A-Za-z0-9_-]{1,128}$/;
|
|
861
854
|
|
|
@@ -947,6 +940,21 @@ const chatExternalSend = z.object({
|
|
|
947
940
|
),
|
|
948
941
|
});
|
|
949
942
|
|
|
943
|
+
// Phone drill-down reads. cwd is re-checked against the open tabs in
|
|
944
|
+
// webRemote.cjs; sessionKey becomes a transcript filename lookup so it is
|
|
945
|
+
// restricted to a session-id charset (no '/', so no traversal).
|
|
946
|
+
const remoteProjectSessions = z.object({ cwd: z.string().min(1).max(4096) });
|
|
947
|
+
const remoteSessionTranscript = z.object({
|
|
948
|
+
cwd: z.string().min(1).max(4096),
|
|
949
|
+
sessionKey: z.string().min(1).max(128).regex(/^[A-Za-z0-9][A-Za-z0-9_.-]*$/),
|
|
950
|
+
limit: z.number().int().min(1).max(100).optional(),
|
|
951
|
+
});
|
|
952
|
+
// One Epic's PRD list (slug/title/status projection only, never bodies).
|
|
953
|
+
const remoteSessionPrds = z.object({
|
|
954
|
+
cwd: z.string().min(1).max(4096),
|
|
955
|
+
epicId: z.string().min(1).max(128).regex(/^[A-Za-z0-9][A-Za-z0-9_.-]*$/),
|
|
956
|
+
});
|
|
957
|
+
|
|
950
958
|
// Phone-initiated new Session. cwd/agentName are re-checked against the open
|
|
951
959
|
// tabs / persona list in webRemote.cjs before anything touches the filesystem.
|
|
952
960
|
const remoteSessionCreate = z.object({
|
|
@@ -1170,13 +1178,20 @@ const READ_COMMANDS = new Set([
|
|
|
1170
1178
|
// Sensitive reads — return user data; require SAS confirmation same as MUTATE.
|
|
1171
1179
|
const SAS_GATED_READS = new Set([
|
|
1172
1180
|
'cmd:sessions:load',
|
|
1173
|
-
// Same data
|
|
1181
|
+
// Same data the phone reads on demand (projects + their active Epics).
|
|
1174
1182
|
'cmd:sessions:list',
|
|
1175
1183
|
'cmd:history:aggregate',
|
|
1176
1184
|
// subscribe initiates a live stream of session state/summary — sensitive.
|
|
1177
1185
|
'cmd:session:subscribe',
|
|
1178
1186
|
// Picker data (projects, personas, tags, macros) for the phone's New Session.
|
|
1179
1187
|
'cmd:session:options',
|
|
1188
|
+
// Drill-down: project list, one project's Epics, one session's recent
|
|
1189
|
+
// transcript text — all user data, so SAS-gated.
|
|
1190
|
+
'cmd:projects:list',
|
|
1191
|
+
'cmd:project:sessions',
|
|
1192
|
+
'cmd:session:transcript',
|
|
1193
|
+
// PRD slugs/titles/statuses for one Epic — project work content, so SAS-gated.
|
|
1194
|
+
'cmd:session:prds',
|
|
1180
1195
|
// NOTE: cmd:exchanges:list is intentionally NOT allowlisted — webRemote.cjs has
|
|
1181
1196
|
// no dispatch handler for it, so an allowlist entry would only fail closed with
|
|
1182
1197
|
// an opaque reject. Re-add here together with the handler when remote exchanges
|
|
@@ -1282,6 +1297,7 @@ module.exports = {
|
|
|
1282
1297
|
memoryCreate,
|
|
1283
1298
|
memoryAggregate,
|
|
1284
1299
|
memoryStale,
|
|
1300
|
+
memoryAgents,
|
|
1285
1301
|
projectBriefCwd,
|
|
1286
1302
|
projectPagesCwd,
|
|
1287
1303
|
projectHomeAdminWriteBody,
|
|
@@ -1298,10 +1314,6 @@ module.exports = {
|
|
|
1298
1314
|
promptSessionsGetWorktreeDisabled,
|
|
1299
1315
|
promptSessionsSetWorktreeDisabled,
|
|
1300
1316
|
auditLogAppend,
|
|
1301
|
-
agentMemoryList,
|
|
1302
|
-
agentMemoryGet,
|
|
1303
|
-
agentMemorySet,
|
|
1304
|
-
agentMemoryDelete,
|
|
1305
1317
|
watchersAdd,
|
|
1306
1318
|
watchersList,
|
|
1307
1319
|
watchersRemove,
|
|
@@ -1315,6 +1327,9 @@ module.exports = {
|
|
|
1315
1327
|
chatClassifyTicket,
|
|
1316
1328
|
chatExternalSend,
|
|
1317
1329
|
remoteSessionCreate,
|
|
1330
|
+
remoteProjectSessions,
|
|
1331
|
+
remoteSessionTranscript,
|
|
1332
|
+
remoteSessionPrds,
|
|
1318
1333
|
exchangesList,
|
|
1319
1334
|
agentsSavePersona,
|
|
1320
1335
|
macrosSave,
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* memoryDirResolve.cjs — where Claude Code itself keeps memory.
|
|
3
|
+
*
|
|
4
|
+
* Pure resolver (all IO injected) so the Memory tab reads and writes exactly the native locations:
|
|
5
|
+
* - workspace memory: ~/.claude/projects/<encoded git-repo root>/memory/ (all worktrees of a
|
|
6
|
+
* repo share it), unless the `autoMemoryDirectory` setting overrides it.
|
|
7
|
+
* - subagent memory: enabled by a `memory:` frontmatter field on the agent.
|
|
8
|
+
*
|
|
9
|
+
* Top-level in lib/ because it spans settings, git and agent files (no single domain folder fits).
|
|
10
|
+
*/
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
const path = require('node:path');
|
|
14
|
+
const { encodeCwd } = require('./util/encodeCwd.cjs');
|
|
15
|
+
|
|
16
|
+
const SCOPES = ['user', 'project', 'local'];
|
|
17
|
+
const NAME_RE = /^[A-Za-z0-9._-]{1,128}$/;
|
|
18
|
+
|
|
19
|
+
/** Highest-precedence value (local > project > user) of `key` passing `pred`. */
|
|
20
|
+
function pick(settings, key, pred) {
|
|
21
|
+
for (const layer of ['local', 'project', 'user']) {
|
|
22
|
+
const s = settings && settings[layer];
|
|
23
|
+
if (s && typeof s === 'object' && pred(s[key])) return s[key];
|
|
24
|
+
}
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function expandDir(value, home, cwd) {
|
|
29
|
+
if (value === '~') return home;
|
|
30
|
+
if (value.startsWith('~/')) return path.join(home, value.slice(2));
|
|
31
|
+
return path.resolve(cwd, value);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function resolveWorkspaceMemoryDir({ home, cwd, settings, repoRoot }) {
|
|
35
|
+
const override = pick(settings, 'autoMemoryDirectory', (v) => typeof v === 'string' && v.trim() !== '');
|
|
36
|
+
if (override !== undefined) {
|
|
37
|
+
return { dir: expandDir(override.trim(), home, cwd), source: 'autoMemoryDirectory' };
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
dir: path.join(home, '.claude', 'projects', encodeCwd(repoRoot || cwd), 'memory'),
|
|
41
|
+
source: 'default',
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function autoMemoryEnabled(settings) {
|
|
46
|
+
return pick(settings, 'autoMemoryEnabled', (v) => typeof v === 'boolean') !== false;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function resolveAgentMemoryDir({ home, root, name, scope }) {
|
|
50
|
+
if (typeof name !== 'string' || !NAME_RE.test(name) || name === '.' || name === '..') {
|
|
51
|
+
throw new Error(`invalid agent name: ${JSON.stringify(name)}`);
|
|
52
|
+
}
|
|
53
|
+
if (!SCOPES.includes(scope)) throw new Error(`unknown memory scope: ${JSON.stringify(scope)}`);
|
|
54
|
+
if (scope === 'user') return path.join(home, '.claude', 'agent-memory', name);
|
|
55
|
+
if (typeof root !== 'string' || !root) throw new Error(`scope '${scope}' requires a project root`);
|
|
56
|
+
return path.join(root, '.claude', scope === 'project' ? 'agent-memory' : 'agent-memory-local', name);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Parse the leading `---` block into a flat key -> string map. */
|
|
60
|
+
function parseFrontmatter(text) {
|
|
61
|
+
const out = {};
|
|
62
|
+
if (typeof text !== 'string') return out;
|
|
63
|
+
const lines = text.replace(/^/, '').split(/\r?\n/);
|
|
64
|
+
if (lines[0].trim() !== '---') return out;
|
|
65
|
+
for (let i = 1; i < lines.length; i++) {
|
|
66
|
+
if (lines[i].trim() === '---') return out;
|
|
67
|
+
const m = /^([A-Za-z0-9_-]+)\s*:\s*(.*)$/.exec(lines[i]);
|
|
68
|
+
if (m) out[m[1]] = m[2].trim().replace(/^(["'])(.*)\1$/, '$2');
|
|
69
|
+
}
|
|
70
|
+
return {}; // unterminated block: not frontmatter
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function scanAgents(dir, origin, readDir, readText) {
|
|
74
|
+
let names;
|
|
75
|
+
try {
|
|
76
|
+
names = readDir(dir);
|
|
77
|
+
} catch {
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
const out = [];
|
|
81
|
+
for (const file of names || []) {
|
|
82
|
+
if (typeof file !== 'string' || !file.endsWith('.md')) continue;
|
|
83
|
+
const agentFile = path.join(dir, file);
|
|
84
|
+
let text;
|
|
85
|
+
try {
|
|
86
|
+
text = readText(agentFile);
|
|
87
|
+
} catch {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (text == null) continue;
|
|
91
|
+
const fm = parseFrontmatter(text);
|
|
92
|
+
out.push({
|
|
93
|
+
name: fm.name || file.slice(0, -3),
|
|
94
|
+
origin,
|
|
95
|
+
memoryScope: SCOPES.includes(fm.memory) ? fm.memory : null,
|
|
96
|
+
agentFile,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function listMemoryAgents({ home, root, readDir, readText }) {
|
|
103
|
+
const byName = new Map();
|
|
104
|
+
for (const a of scanAgents(path.join(home, '.claude', 'agents'), 'user', readDir, readText)) byName.set(a.name, a);
|
|
105
|
+
if (root) {
|
|
106
|
+
for (const a of scanAgents(path.join(root, '.claude', 'agents'), 'project', readDir, readText)) byName.set(a.name, a);
|
|
107
|
+
}
|
|
108
|
+
return [...byName.values()].sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const rootCache = new Map();
|
|
112
|
+
|
|
113
|
+
function gitRepoRoot(cwd, execFileSync) {
|
|
114
|
+
if (rootCache.has(cwd)) return rootCache.get(cwd);
|
|
115
|
+
let root = null;
|
|
116
|
+
try {
|
|
117
|
+
const out = String(
|
|
118
|
+
execFileSync('git', ['rev-parse', '--path-format=absolute', '--git-common-dir'], {
|
|
119
|
+
cwd,
|
|
120
|
+
timeout: 5000,
|
|
121
|
+
encoding: 'utf8',
|
|
122
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
123
|
+
}),
|
|
124
|
+
).trim();
|
|
125
|
+
if (out.endsWith('/.git')) root = out.slice(0, -'/.git'.length) || null;
|
|
126
|
+
} catch {
|
|
127
|
+
root = null;
|
|
128
|
+
}
|
|
129
|
+
rootCache.set(cwd, root);
|
|
130
|
+
return root;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
module.exports = {
|
|
134
|
+
resolveWorkspaceMemoryDir,
|
|
135
|
+
autoMemoryEnabled,
|
|
136
|
+
resolveAgentMemoryDir,
|
|
137
|
+
listMemoryAgents,
|
|
138
|
+
gitRepoRoot,
|
|
139
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pure helpers for Claude Code's auto-memory index file (MEMORY.md): one line
|
|
5
|
+
* per memory, `- [Title](file.md) — hook`. Claude Code loads only the first
|
|
6
|
+
* 200 lines / 25KB of it per session, so an unlisted memory is invisible.
|
|
7
|
+
* No fs/electron access; callers pass text in and write text out.
|
|
8
|
+
*
|
|
9
|
+
* Top-level (not in a lib/ subfolder) to sit beside its sibling memoryStale.cjs.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const MAX_LINES = 200;
|
|
13
|
+
const MAX_BYTES = 25600;
|
|
14
|
+
const NEAR_LINES = 180;
|
|
15
|
+
const NEAR_BYTES = 23040;
|
|
16
|
+
|
|
17
|
+
// `- [Title](name.md)` with optional ` — hook` / ` - hook`. Bare file names only
|
|
18
|
+
// (no path separators), so links into subfolders or URLs never match.
|
|
19
|
+
const LINE_RE = /^\s*[-*]\s+\[([^\]]*)\]\(([^)\s/\\]+\.md)\)(?:\s+(?:—|-)\s+(.*?))?\s*$/;
|
|
20
|
+
|
|
21
|
+
/** Split into lines; a trailing newline does not add a line. */
|
|
22
|
+
function splitLines(text) {
|
|
23
|
+
if (typeof text !== 'string' || text === '') return [];
|
|
24
|
+
const lines = text.split('\n');
|
|
25
|
+
if (lines[lines.length - 1] === '') lines.pop();
|
|
26
|
+
return lines;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function matchLine(raw) {
|
|
30
|
+
return LINE_RE.exec(raw.replace(/\r$/, ''));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Parse index link lines. Complexity: O(lines).
|
|
35
|
+
* @param {string|null} text
|
|
36
|
+
* @returns {{line: string, lineNo: number, title: string, file: string, hook: string}[]}
|
|
37
|
+
*/
|
|
38
|
+
function parseIndex(text) {
|
|
39
|
+
const out = [];
|
|
40
|
+
splitLines(text).forEach((raw, i) => {
|
|
41
|
+
const m = matchLine(raw);
|
|
42
|
+
if (!m) return;
|
|
43
|
+
out.push({ line: raw.replace(/\r$/, ''), lineNo: i + 1, title: m[1], file: m[2], hook: m[3] || '' });
|
|
44
|
+
});
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Append an index line unless `file` is already linked. Complexity: O(lines).
|
|
50
|
+
* @param {string|null} text
|
|
51
|
+
* @param {{file: string, title: string, hook?: string}} entry
|
|
52
|
+
* @returns {string}
|
|
53
|
+
*/
|
|
54
|
+
function addIndexLine(text, { file, title, hook }) {
|
|
55
|
+
const base = typeof text === 'string' ? text : '';
|
|
56
|
+
if (parseIndex(base).some((e) => e.file === file)) return base;
|
|
57
|
+
const line = `- [${title}](${file})${hook ? ` — ${hook}` : ''}`;
|
|
58
|
+
const trimmed = base.replace(/(\r?\n)+$/, '');
|
|
59
|
+
return `${trimmed === '' ? '' : `${trimmed}\n`}${line}\n`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Remove every line linking to `file`; other lines are untouched.
|
|
64
|
+
* Complexity: O(lines).
|
|
65
|
+
* @param {string|null} text
|
|
66
|
+
* @param {string} file
|
|
67
|
+
* @returns {string}
|
|
68
|
+
*/
|
|
69
|
+
function removeIndexLines(text, file) {
|
|
70
|
+
if (typeof text !== 'string' || text === '') return '';
|
|
71
|
+
const parts = text.split('\n');
|
|
72
|
+
const hadTrailing = parts[parts.length - 1] === '';
|
|
73
|
+
if (hadTrailing) parts.pop();
|
|
74
|
+
const kept = parts.filter((raw) => {
|
|
75
|
+
const m = matchLine(raw);
|
|
76
|
+
return !(m && m[2] === file);
|
|
77
|
+
});
|
|
78
|
+
return kept.length === 0 ? '' : kept.join('\n') + (hadTrailing ? '\n' : '');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Index budget + consistency report. Complexity: O((lines + files) log n).
|
|
83
|
+
* @param {{indexText: string|null, files: string[]}} args
|
|
84
|
+
*/
|
|
85
|
+
function indexHealth({ indexText, files }) {
|
|
86
|
+
const text = typeof indexText === 'string' ? indexText : '';
|
|
87
|
+
const lines = splitLines(text).length;
|
|
88
|
+
const bytes = Buffer.byteLength(text, 'utf8');
|
|
89
|
+
const overBudget = lines > MAX_LINES || bytes > MAX_BYTES;
|
|
90
|
+
const nearBudget = !overBudget && (lines >= NEAR_LINES || bytes >= NEAR_BYTES);
|
|
91
|
+
const present = new Set((files || []).filter((f) => f !== 'MEMORY.md'));
|
|
92
|
+
const linked = new Set(parseIndex(text).map((e) => e.file));
|
|
93
|
+
const orphans = [...present].filter((f) => !linked.has(f)).sort();
|
|
94
|
+
const dangling = [...linked].filter((f) => f !== 'MEMORY.md' && !present.has(f)).sort();
|
|
95
|
+
return { lines, bytes, maxLines: MAX_LINES, maxBytes: MAX_BYTES, overBudget, nearBudget, orphans, dangling };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = { parseIndex, addIndexLine, removeIndexLines, indexHealth };
|