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.
- package/dist/assets/{AgentLibrary-LBg3mVL8.js → AgentLibrary-FO2ei2wB.js} +1 -1
- package/dist/assets/{Button-C4BN5ISR.js → Button-CeIOXUPU.js} +1 -1
- package/dist/assets/{DataModel-CHhjk61s.js → DataModel-D0p__Hil.js} +1 -1
- package/dist/assets/{History-CL-T6Lv3.js → History-DVqQ5azN.js} +1 -1
- package/dist/assets/{Hooks-ByWVgXIf.js → Hooks-DkTnRHyT.js} +1 -1
- package/dist/assets/{Library-QvYVAEmY.js → Library-l7KS6pkE.js} +1 -1
- package/dist/assets/{ListDetail-FvNe6fo5.js → ListDetail-DDw8fuRT.js} +1 -1
- package/dist/assets/{McpServers-C7EmPm8B.js → McpServers-UUNIxk_3.js} +1 -1
- package/dist/assets/{Memory-nyLR4Yw4.js → Memory-CNYUoQ8C.js} +1 -1
- package/dist/assets/{Panel-thElCbLX.js → Panel-Bb54soc2.js} +1 -1
- package/dist/assets/{Permissions-FQ9GM6Ca.js → Permissions-D-dNdV3f.js} +1 -1
- package/dist/assets/{Plugins-D9KE7XTI.js → Plugins-DhcIXRhQ.js} +2 -2
- package/dist/assets/{ProvenanceBadge-lAViG8yV.js → ProvenanceBadge-DEAkDNjA.js} +1 -1
- package/dist/assets/{RemoteMachines-AWpARk7N.js → RemoteMachines-xCEgvTGU.js} +1 -1
- package/dist/assets/{SaveBar-c15EEGB_.js → SaveBar-BSEs7ecA.js} +1 -1
- package/dist/assets/{Scheduler-FvduP1FG.js → Scheduler-BIKJIU-C.js} +1 -1
- package/dist/assets/{ScopeSwitcher-BLep1rtB.js → ScopeSwitcher-DcaFyAV-.js} +1 -1
- package/dist/assets/{Settings-D1kTUIDB.js → Settings-vcdWy_Jx.js} +1 -1
- package/dist/assets/{SkillReferenceGraph-_40_f0t3.js → SkillReferenceGraph-CLrJWTPd.js} +1 -1
- package/dist/assets/{Skills-DaTkSOuU.js → Skills-CYM4rBEC.js} +1 -1
- package/dist/assets/{SystemPrompt-DxNf-soM.js → SystemPrompt-BWNIu-iY.js} +1 -1
- package/dist/assets/{TagLibrary-L6KpBV-x.js → TagLibrary-CYdwHK6m.js} +1 -1
- package/dist/assets/{TiptapBody-C_XjtJ82.js → TiptapBody-Kt90lHrD.js} +1 -1
- package/dist/assets/{Toggle-H0rERKNI.js → Toggle-D1OXWYOz.js} +1 -1
- package/dist/assets/{ViewTabs-ZUWphDat.js → ViewTabs-BeQR3CKh.js} +1 -1
- package/dist/assets/{historyTotals-BxFKOztb.js → historyTotals-B0qafrRo.js} +1 -1
- package/dist/assets/{index-B5wj0DEX.js → index-Bq9uH08R.js} +200 -200
- package/dist/assets/{settingsSchema-BRcYkXJN.js → settingsSchema-0ZksSAPB.js} +1 -1
- package/dist/assets/{skillFrontmatter-DFGp4DST.js → skillFrontmatter-C0nh8yfa.js} +1 -1
- package/dist/assets/{useAgentsDirWatch-VvrgalfC.js → useAgentsDirWatch-DPkoBybS.js} +1 -1
- package/dist/assets/{useRemotePeers-mvXKNEE3.js → useRemotePeers-BDJMUihy.js} +1 -1
- package/dist/index.html +1 -1
- package/package.json +1 -1
- package/src/main/build-info.json +4 -4
- package/src/main/chatRunner.cjs +43 -6
- package/src/main/ipcSchemas.cjs +15 -1
- package/src/main/lib/persona-macro/macroLibrary.cjs +75 -0
- package/src/main/lib/prd/prdCreate.cjs +25 -0
- package/src/main/lib/remoteTranscriptTail.cjs +69 -2
- package/src/main/webRemote.cjs +82 -91
- package/src/preload/api.d.ts +13 -0
- 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-
|
|
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-
|
|
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-
|
|
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-
|
|
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.
|
|
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",
|
package/src/main/build-info.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
3
|
-
"gitSha": "
|
|
4
|
-
"gitShortSha": "
|
|
2
|
+
"version": "0.121.0",
|
|
3
|
+
"gitSha": "9cde6952e65cad99fbe061866808a986c3dc0b41",
|
|
4
|
+
"gitShortSha": "9cde6952",
|
|
5
5
|
"gitBranch": "HEAD",
|
|
6
|
-
"builtAt": "2026-10-
|
|
6
|
+
"builtAt": "2026-10-23T06:21:05.281Z",
|
|
7
7
|
"dirty": false
|
|
8
8
|
}
|
package/src/main/chatRunner.cjs
CHANGED
|
@@ -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
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
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
|
};
|
package/src/main/ipcSchemas.cjs
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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 };
|