claude-code-session-manager 0.100.0 → 0.101.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/DataModel-CXaH2GED.js +1 -0
- package/dist/assets/{History-Dr4Jr_5z.js → History-Cerii-HA.js} +2 -2
- package/dist/assets/{Hooks-NhrvH3JP.js → Hooks-aXMb5LDy.js} +3 -3
- package/dist/assets/{Library-Dv_EtIMr.js → Library-WrJFKEOJ.js} +1 -1
- package/dist/assets/{MarkdownEditor-DTKDWV_n.js → MarkdownEditor-D1BMCXS7.js} +1 -1
- package/dist/assets/{McpServers-M034G9B3.js → McpServers-Cf0davLd.js} +2 -2
- package/dist/assets/{Memory-DzF1B4gx.js → Memory-Dn6NHWPe.js} +3 -3
- package/dist/assets/Permissions-CTVuFPjg.js +3 -0
- package/dist/assets/{Plugins-Bd3ef35w.js → Plugins-C2TyF8Mn.js} +2 -2
- package/dist/assets/ProvenanceBadge-F_jwHSwE.js +1 -0
- package/dist/assets/{SaveBar-rimJem-Y.js → SaveBar-DA1KVJST.js} +1 -1
- package/dist/assets/{Scheduler-DjgFJl2w.js → Scheduler-Bm6Q_hlu.js} +8 -8
- package/dist/assets/{ScopeSwitcher-CnAzTBrl.js → ScopeSwitcher-BygZlJca.js} +1 -1
- package/dist/assets/Settings-BYCiv5KV.js +3 -0
- package/dist/assets/{SkillReferenceGraph-B9aZDecM.js → SkillReferenceGraph-CcLnl9np.js} +1 -1
- package/dist/assets/{Skills-DRXd18gu.js → Skills-ChffsdTD.js} +2 -2
- package/dist/assets/{SystemPrompt-ahy5-Fwe.js → SystemPrompt-dNkfHE_M.js} +1 -1
- package/dist/assets/{TagLibrary-C_tToDeL.js → TagLibrary-jVlEuB0m.js} +1 -1
- package/dist/assets/{TiptapBody-DvdefS6K.js → TiptapBody-6_cdwcP0.js} +1 -1
- package/dist/assets/{Toggle-6Jl5Njc6.js → Toggle-CVXqGpAP.js} +1 -1
- package/dist/assets/ViewTabs-DO1YVbpc.js +1 -0
- package/dist/assets/{index-Bta-hwud.css → index-D89EUizB.css} +1 -1
- package/dist/assets/{index-vx8O73l8.js → index-DbCQPWWY.js} +571 -571
- package/dist/assets/{settingsSchema-D6iRguNV.js → settingsSchema-Wrvn-Yz1.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/scripts/scheduler-mcp-server.cjs +28 -0
- package/src/main/build-info.json +4 -4
- package/src/main/chatRunner.cjs +4 -3
- package/src/main/index.cjs +17 -1
- package/src/main/ipcSchemas.cjs +8 -0
- package/src/main/lib/builtinMacros.cjs +39 -0
- package/src/main/lib/macroLibrary.cjs +102 -8
- package/src/main/lib/mcpToolCatalog.cjs +23 -0
- package/src/main/lib/opsOwnership.cjs +5 -4
- package/src/main/lib/projectHomeAdminRoutes.cjs +136 -21
- package/src/main/lib/shippedPersonaSeeds.cjs +47 -0
- package/src/main/lib/smfileHeaders.cjs +66 -0
- package/src/main/projectPages.cjs +43 -13
- package/src/main/seedAgentPersonas.cjs +1 -1
- package/src/preload/api.d.ts +12 -0
- package/src/seed/agents/architect.md +2 -1
- package/src/seed/agents/demo-video-builder.md +84 -0
- package/src/seed/agents/dev-lead.md +2 -1
- package/src/seed/agents/project-home-builder.md +66 -36
- package/dist/assets/DataModel-HdR0AxFq.js +0 -1
- package/dist/assets/Permissions-DrgbSGWl.js +0 -3
- package/dist/assets/ProvenanceBadge-DcBHT1Iy.js +0 -1
- package/dist/assets/Settings-Dc1F_sSg.js +0 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ay as b,aj as n,S as N,aP as O,aw as K}from"./index-vx8O73l8.js";function T({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 G(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 V(){return $||($=B(K)),$}export{T as E,V as s,G as u};
|
|
1
|
+
import{ax as b,ai as n,S as N,aO as O,av as K}from"./index-DbCQPWWY.js";function T({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 G(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 V(){return $||($=B(K)),$}export{T as E,V as s,G 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-DbCQPWWY.js"></script>
|
|
11
11
|
<link rel="modulepreload" crossorigin href="./assets/monaco-editor-BW5C4Iv1.js">
|
|
12
12
|
<link rel="stylesheet" crossorigin href="./assets/monaco-editor-BTnBOi8r.css">
|
|
13
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
13
|
+
<link rel="stylesheet" crossorigin href="./assets/index-D89EUizB.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.101.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",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* feedback_open_session({ ... }) -> POST /admin/feedback/open-session
|
|
13
13
|
*
|
|
14
14
|
* project_home_write({ cwd?, html }) -> POST /admin/project-home/write
|
|
15
|
+
* project_demo_video_write({ cwd?, html }) -> POST /admin/project-home/demo-video/write
|
|
15
16
|
*
|
|
16
17
|
* This is a separate process from the Electron app — it only ever reaches
|
|
17
18
|
* it over the token-authed loopback HTTP API in admin-api.json, never by
|
|
@@ -375,6 +376,25 @@ const TOOLS = [
|
|
|
375
376
|
required: ['html'],
|
|
376
377
|
},
|
|
377
378
|
},
|
|
379
|
+
{
|
|
380
|
+
name: 'project_demo_video_write',
|
|
381
|
+
description: descriptionFor('project_demo_video_write'),
|
|
382
|
+
inputSchema: {
|
|
383
|
+
type: 'object',
|
|
384
|
+
properties: {
|
|
385
|
+
cwd: { type: 'string', description: "Optional: absolute path to the target project. Defaults to the calling session's own project root (SM_PROJECT_ROOT or process.cwd()) when omitted." },
|
|
386
|
+
html: {
|
|
387
|
+
type: 'string',
|
|
388
|
+
description: 'The complete self-contained HTML/JS document for a 30-second-or-less demo video (<= 2MB). '
|
|
389
|
+
+ 'It is rejected for: being empty; <script src>, <link href=http*>, @import, or url(http*) (no remote references); '
|
|
390
|
+
+ 'fetch/XMLHttpRequest/WebSocket/EventSource/sendBeacon/dynamic import/importScripts/<iframe>/<object>/<embed>/window.open/'
|
|
391
|
+
+ 'any http(s)/// src or href (no network-capable APIs — the document is CSP-fenced after it is written); '
|
|
392
|
+
+ 'or missing a <meta name="sm-demo-duration" content="N"> tag with 5 <= N <= 30.',
|
|
393
|
+
},
|
|
394
|
+
},
|
|
395
|
+
required: ['html'],
|
|
396
|
+
},
|
|
397
|
+
},
|
|
378
398
|
{
|
|
379
399
|
name: 'session_manager_help',
|
|
380
400
|
description: descriptionFor('session_manager_help'),
|
|
@@ -599,6 +619,14 @@ async function handleCallTool(request) {
|
|
|
599
619
|
const result = await adminRequest('POST', '/admin/project-home/write', { cwd, html: args.html });
|
|
600
620
|
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
601
621
|
}
|
|
622
|
+
if (name === 'project_demo_video_write') {
|
|
623
|
+
if (!args || typeof args.html !== 'string' || args.html.length === 0) {
|
|
624
|
+
return errorResult('missing required argument: html');
|
|
625
|
+
}
|
|
626
|
+
const cwd = resolveCwdArg(args);
|
|
627
|
+
const result = await adminRequest('POST', '/admin/project-home/demo-video/write', { cwd, html: args.html });
|
|
628
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
629
|
+
}
|
|
602
630
|
if (name === 'session_manager_help') {
|
|
603
631
|
const toolName = args && typeof args.tool === 'string' ? args.tool : null;
|
|
604
632
|
const topic = args && typeof args.topic === 'string' ? args.topic : null;
|
package/src/main/build-info.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
3
|
-
"gitSha": "
|
|
4
|
-
"gitShortSha": "
|
|
2
|
+
"version": "0.101.0",
|
|
3
|
+
"gitSha": "c57a278f1ec1bf0c508ff6a1fcc260195febd6e3",
|
|
4
|
+
"gitShortSha": "c57a278f",
|
|
5
5
|
"gitBranch": "HEAD",
|
|
6
|
-
"builtAt": "2026-10-
|
|
6
|
+
"builtAt": "2026-10-03T17:17:40.599Z",
|
|
7
7
|
"dirty": false
|
|
8
8
|
}
|
package/src/main/chatRunner.cjs
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
* chat:run:queued { tabId, sessionId, position } — waiting behind a busy lane
|
|
31
31
|
* chat:run:started { tabId, sessionId }
|
|
32
32
|
* chat:run:output { tabId, delta }
|
|
33
|
-
* chat:run:tool-use { tabId, id, kind, label }
|
|
33
|
+
* chat:run:tool-use { tabId, id, kind, label, detail }
|
|
34
34
|
* chat:run:complete { tabId, sessionId, finalMessage }
|
|
35
35
|
* chat:run:needs-input { tabId, sessionId, questions, raw }
|
|
36
36
|
* chat:run:error { tabId, sessionId, message }
|
|
@@ -736,9 +736,10 @@ function executeRun({ tabId, sessionId, prompt, cwd, resume, silent, onSilentRes
|
|
|
736
736
|
if (!silent) broadcast('chat:run:output', { tabId, delta: block.text });
|
|
737
737
|
} else if (block.type === 'tool_use' && typeof block.name === 'string') {
|
|
738
738
|
const classified = classifyToolUse(block);
|
|
739
|
-
|
|
739
|
+
const detail = describeToolUseInput(block);
|
|
740
|
+
recentToolUses.push({ ...classified, detail });
|
|
740
741
|
if (recentToolUses.length > RECENT_TOOL_USE_LIMIT) recentToolUses.shift();
|
|
741
|
-
if (!silent) broadcast('chat:run:tool-use', { tabId, id: block.id, ...classified });
|
|
742
|
+
if (!silent) broadcast('chat:run:tool-use', { tabId, id: block.id, ...classified, detail });
|
|
742
743
|
}
|
|
743
744
|
}
|
|
744
745
|
} else if (event.type === 'user') {
|
package/src/main/index.cjs
CHANGED
|
@@ -33,6 +33,7 @@ const { createAdminHttp } = require('./lib/localAdminHttp.cjs');
|
|
|
33
33
|
const prdCreate = require('./lib/prdCreate.cjs');
|
|
34
34
|
const prdAdminRoutes = require('./lib/prdAdminRoutes.cjs');
|
|
35
35
|
const projectHomeAdminRoutes = require('./lib/projectHomeAdminRoutes.cjs');
|
|
36
|
+
const { smfileResponseHeaders, shouldBlockFrameNavigation } = require('./lib/smfileHeaders.cjs');
|
|
36
37
|
const { appendAuditEvent } = require('./lib/auditLog.cjs');
|
|
37
38
|
const chatRunner = require('./chatRunner.cjs');
|
|
38
39
|
const promptSessionEvents = require('./promptSessionEvents.cjs');
|
|
@@ -455,6 +456,21 @@ function createWindow() {
|
|
|
455
456
|
configMgr.releaseWatchesForSender(mainWindow.webContents.id);
|
|
456
457
|
});
|
|
457
458
|
|
|
459
|
+
// CSP (frame-src/connect-src) does not govern a subframe navigating itself —
|
|
460
|
+
// a demo-video document could still exfiltrate data via meta refresh or
|
|
461
|
+
// `location.href = 'https://…'`. Block any such navigation out of an
|
|
462
|
+
// smfile:// demo-video subframe.
|
|
463
|
+
mainWindow.webContents.on('will-frame-navigate', (details) => {
|
|
464
|
+
if (shouldBlockFrameNavigation({
|
|
465
|
+
isMainFrame: details.isMainFrame,
|
|
466
|
+
currentUrl: details.frame?.url,
|
|
467
|
+
targetUrl: details.url,
|
|
468
|
+
})) {
|
|
469
|
+
details.preventDefault();
|
|
470
|
+
console.warn('[main] blocked will-frame-navigate to', details.url);
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
|
|
458
474
|
mainWindow.webContents.on('context-menu', (_e, params) => {
|
|
459
475
|
const items = [];
|
|
460
476
|
if (params.editFlags.canCopy) items.push({ label: 'Copy', role: 'copy' });
|
|
@@ -1276,7 +1292,7 @@ app.whenReady().then(async () => {
|
|
|
1276
1292
|
const buf = await fs.promises.readFile(realPath);
|
|
1277
1293
|
const ext = path.extname(realPath).toLowerCase();
|
|
1278
1294
|
const type = SMFILE_MIME[ext] || 'application/octet-stream';
|
|
1279
|
-
return new Response(buf, { headers:
|
|
1295
|
+
return new Response(buf, { headers: smfileResponseHeaders(realPath, type) });
|
|
1280
1296
|
} catch (err) {
|
|
1281
1297
|
return new Response(`smfile error: ${err && err.message}`, { status: 404 });
|
|
1282
1298
|
}
|
package/src/main/ipcSchemas.cjs
CHANGED
|
@@ -730,6 +730,13 @@ const projectHomeAdminWriteBody = z.object({
|
|
|
730
730
|
html: z.string(),
|
|
731
731
|
}).strict();
|
|
732
732
|
|
|
733
|
+
// Mirrors projectHomeAdminWriteBody; content limits (network-check rejections,
|
|
734
|
+
// size cap, duration meta) live in projectHomeAdminRoutes.cjs's validateDemoVideoHtml.
|
|
735
|
+
const projectDemoVideoAdminWriteBody = z.object({
|
|
736
|
+
cwd: z.string().min(1).max(4096).optional(),
|
|
737
|
+
html: z.string(),
|
|
738
|
+
}).strict();
|
|
739
|
+
|
|
733
740
|
const projectBriefSetPin = z.object({
|
|
734
741
|
cwd: z.string().min(1).max(4096),
|
|
735
742
|
block: PROJECT_BRIEF_BLOCK,
|
|
@@ -1132,6 +1139,7 @@ module.exports = {
|
|
|
1132
1139
|
projectBriefCwd,
|
|
1133
1140
|
projectPagesCwd,
|
|
1134
1141
|
projectHomeAdminWriteBody,
|
|
1142
|
+
projectDemoVideoAdminWriteBody,
|
|
1135
1143
|
projectBriefSetPin,
|
|
1136
1144
|
projectBriefUpdate,
|
|
1137
1145
|
promptSessionTranscriptAppend,
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* builtinMacros.cjs — the machine-local Macro library's seeded built-ins.
|
|
5
|
+
*
|
|
6
|
+
* These drive Project Home's one-click actions through the same (agent, tag,
|
|
7
|
+
* prompt) hot-key framework as user-created macros. `macroLibrary.cjs`'s
|
|
8
|
+
* `ensureBuiltins` seeds any entry here that is missing from macros.json, and
|
|
9
|
+
* upgrades an unedited stored copy whose `builtinVersion` is behind this file.
|
|
10
|
+
*
|
|
11
|
+
* Plain Node, no Electron imports.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const BUILTIN_MACROS = Object.freeze([
|
|
15
|
+
Object.freeze({
|
|
16
|
+
id: 'builtin-project-home',
|
|
17
|
+
label: 'Project Home',
|
|
18
|
+
agentName: 'project-home-builder',
|
|
19
|
+
tag: 'project-home-builder',
|
|
20
|
+
surface: 'project-home',
|
|
21
|
+
projects: ['*'],
|
|
22
|
+
builtinVersion: 1,
|
|
23
|
+
prompt:
|
|
24
|
+
"Generate this project's Project Home page: one self-contained HTML overview (what it is, who it is for, key features, structure, how to run it, key commands), grounded only in what you read in the repository. Save it with a single project_home_write call.",
|
|
25
|
+
}),
|
|
26
|
+
Object.freeze({
|
|
27
|
+
id: 'builtin-demo-video',
|
|
28
|
+
label: 'Demo Video',
|
|
29
|
+
agentName: 'demo-video-builder',
|
|
30
|
+
tag: 'project-home-builder',
|
|
31
|
+
surface: 'project-home',
|
|
32
|
+
projects: ['*'],
|
|
33
|
+
builtinVersion: 1,
|
|
34
|
+
prompt:
|
|
35
|
+
'Generate a 30-second demo video for this project as one self-contained HTML/JavaScript animation that presents its main goals and key features, grounded only in what you read in the repository. Save it with a single project_demo_video_write call.',
|
|
36
|
+
}),
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
module.exports = { BUILTIN_MACROS };
|
|
@@ -43,6 +43,7 @@ const { EpicTagSchema } = require('./promptSessionSchema.cjs');
|
|
|
43
43
|
const { WORK_TYPES } = require('./workTypeLibrary.cjs');
|
|
44
44
|
const { PERSONA_NAME_RE } = require('./personaMerge.cjs');
|
|
45
45
|
const { schedulerHome } = require('./schedulerPaths.cjs');
|
|
46
|
+
const { BUILTIN_MACROS } = require('./builtinMacros.cjs');
|
|
46
47
|
|
|
47
48
|
const ALL_PROJECTS = '*';
|
|
48
49
|
const STORE_VERSION = 1;
|
|
@@ -57,6 +58,7 @@ const AbsolutePathSchema = z.string().max(1024).refine(
|
|
|
57
58
|
);
|
|
58
59
|
const MacroProjectEntrySchema = z.union([z.literal(ALL_PROJECTS), AbsolutePathSchema]);
|
|
59
60
|
const MacroProjectsSchema = z.array(MacroProjectEntrySchema).max(200);
|
|
61
|
+
const MacroSurfaceSchema = z.enum(['sessions', 'project-home']);
|
|
60
62
|
|
|
61
63
|
const MacroSchema = z.object({
|
|
62
64
|
id: MacroIdSchema,
|
|
@@ -65,6 +67,9 @@ const MacroSchema = z.object({
|
|
|
65
67
|
tag: EpicTagSchema,
|
|
66
68
|
prompt: MacroPromptSchema,
|
|
67
69
|
projects: MacroProjectsSchema,
|
|
70
|
+
surface: MacroSurfaceSchema.default('sessions'),
|
|
71
|
+
builtin: z.boolean().optional(),
|
|
72
|
+
builtinVersion: z.number().int().optional(),
|
|
68
73
|
createdAt: z.string().min(1).max(64),
|
|
69
74
|
updatedAt: z.string().min(1).max(64),
|
|
70
75
|
});
|
|
@@ -75,7 +80,11 @@ const MacroSaveSchema = z.object({
|
|
|
75
80
|
agentName: MacroAgentNameSchema,
|
|
76
81
|
tag: EpicTagSchema,
|
|
77
82
|
prompt: MacroPromptSchema,
|
|
78
|
-
|
|
83
|
+
// Omitted (not merely `[]`) means "leave projects unchanged" on update, so a
|
|
84
|
+
// label/prompt-only edit of a macro (builtin or otherwise) can't silently
|
|
85
|
+
// wipe its visibility back to no projects. `undefined` on create means [].
|
|
86
|
+
projects: MacroProjectsSchema.optional(),
|
|
87
|
+
surface: MacroSurfaceSchema.optional(),
|
|
79
88
|
});
|
|
80
89
|
|
|
81
90
|
const MacroDeleteSchema = z.object({ id: MacroIdSchema });
|
|
@@ -185,6 +194,73 @@ async function writeStore(filePath, macros) {
|
|
|
185
194
|
await writeJsonAtomic(filePath, { version: STORE_VERSION, macros });
|
|
186
195
|
}
|
|
187
196
|
|
|
197
|
+
function resolveBuiltins(opts) {
|
|
198
|
+
return opts && Object.prototype.hasOwnProperty.call(opts, 'builtins') ? opts.builtins : BUILTIN_MACROS;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Pure. Seeds any `builtins` entry missing from `macros` (as `builtin: true`),
|
|
203
|
+
* and upgrades a stored built-in that is behind the shipped `builtinVersion`
|
|
204
|
+
* AND was never user-edited (`updatedAt === createdAt`). A user-edited
|
|
205
|
+
* built-in is left untouched. Returns `{ macros, changed }`.
|
|
206
|
+
*/
|
|
207
|
+
function ensureBuiltins(macros, builtins) {
|
|
208
|
+
if (!builtins || builtins.length === 0) return { macros, changed: false };
|
|
209
|
+
let changed = false;
|
|
210
|
+
const next = macros.slice();
|
|
211
|
+
const now = new Date().toISOString();
|
|
212
|
+
for (const b of builtins) {
|
|
213
|
+
const idx = next.findIndex((m) => m.id === b.id);
|
|
214
|
+
if (idx === -1) {
|
|
215
|
+
next.push({
|
|
216
|
+
id: b.id,
|
|
217
|
+
label: b.label,
|
|
218
|
+
agentName: b.agentName,
|
|
219
|
+
tag: b.tag,
|
|
220
|
+
prompt: b.prompt,
|
|
221
|
+
projects: b.projects.slice(),
|
|
222
|
+
surface: b.surface,
|
|
223
|
+
builtin: true,
|
|
224
|
+
builtinVersion: b.builtinVersion,
|
|
225
|
+
createdAt: now,
|
|
226
|
+
updatedAt: now,
|
|
227
|
+
});
|
|
228
|
+
changed = true;
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
const stored = next[idx];
|
|
232
|
+
const storedVersion = stored.builtinVersion || 0;
|
|
233
|
+
const neverEdited = stored.updatedAt === stored.createdAt;
|
|
234
|
+
if (storedVersion < b.builtinVersion && neverEdited) {
|
|
235
|
+
next[idx] = {
|
|
236
|
+
...stored,
|
|
237
|
+
label: b.label,
|
|
238
|
+
agentName: b.agentName,
|
|
239
|
+
tag: b.tag,
|
|
240
|
+
prompt: b.prompt,
|
|
241
|
+
surface: b.surface,
|
|
242
|
+
builtinVersion: b.builtinVersion,
|
|
243
|
+
updatedAt: stored.createdAt,
|
|
244
|
+
};
|
|
245
|
+
changed = true;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return { macros: next, changed };
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** Apply builtin seeding/upgrades, writing only when something changed. */
|
|
252
|
+
async function applyBuiltins(filePath, macros, opts) {
|
|
253
|
+
const { macros: next, changed } = ensureBuiltins(macros, resolveBuiltins(opts));
|
|
254
|
+
if (!changed) return { macros, failed: false };
|
|
255
|
+
try {
|
|
256
|
+
await writeStore(filePath, next);
|
|
257
|
+
} catch (err) {
|
|
258
|
+
console.warn('[macroLibrary] could not persist built-in macro seeding:', err && err.message);
|
|
259
|
+
return { macros, failed: false };
|
|
260
|
+
}
|
|
261
|
+
return { macros: next, failed: false };
|
|
262
|
+
}
|
|
263
|
+
|
|
188
264
|
// --- migration --------------------------------------------------------------
|
|
189
265
|
|
|
190
266
|
function isValidProject(p) {
|
|
@@ -246,7 +322,7 @@ async function migrateFromPersonas(opts) {
|
|
|
246
322
|
*/
|
|
247
323
|
async function loadStore(filePath, opts) {
|
|
248
324
|
const cur = await readStore(filePath);
|
|
249
|
-
if (cur.state === 'ok') return
|
|
325
|
+
if (cur.state === 'ok') return applyBuiltins(filePath, cur.macros, opts);
|
|
250
326
|
if (cur.state === 'unreadable') return { macros: [], failed: true };
|
|
251
327
|
if (cur.state === 'corrupt') {
|
|
252
328
|
const quarantine = `${filePath}.corrupt-${Date.now()}`;
|
|
@@ -263,7 +339,7 @@ async function loadStore(filePath, opts) {
|
|
|
263
339
|
console.warn('[macroLibrary] could not write fresh macros.json:', err && err.message);
|
|
264
340
|
return { macros: [], failed: true };
|
|
265
341
|
}
|
|
266
|
-
return
|
|
342
|
+
return applyBuiltins(filePath, [], opts);
|
|
267
343
|
}
|
|
268
344
|
// missing: migrate once
|
|
269
345
|
const seeded = await migrateFromPersonas(opts);
|
|
@@ -274,7 +350,7 @@ async function loadStore(filePath, opts) {
|
|
|
274
350
|
console.warn('[macroLibrary] could not write migrated macros.json:', err && err.message);
|
|
275
351
|
return { macros: seeded, failed: true };
|
|
276
352
|
}
|
|
277
|
-
return
|
|
353
|
+
return applyBuiltins(filePath, seeded, opts);
|
|
278
354
|
}
|
|
279
355
|
|
|
280
356
|
// --- public API -------------------------------------------------------------
|
|
@@ -283,8 +359,11 @@ async function loadStore(filePath, opts) {
|
|
|
283
359
|
async function listMacros(opts = {}) {
|
|
284
360
|
const filePath = resolvePath(opts);
|
|
285
361
|
const first = await readStore(filePath);
|
|
286
|
-
if (first.state === 'ok')
|
|
287
|
-
|
|
362
|
+
if (first.state === 'ok') {
|
|
363
|
+
const { changed } = ensureBuiltins(first.macros, resolveBuiltins(opts));
|
|
364
|
+
if (!changed) return first.macros;
|
|
365
|
+
}
|
|
366
|
+
// Missing/corrupt/needs-seeding: repair inside the write chain so racing callers don't double-seed.
|
|
288
367
|
return serialize(async () => (await loadStore(filePath, opts)).macros);
|
|
289
368
|
}
|
|
290
369
|
|
|
@@ -305,14 +384,24 @@ async function saveMacro(input, opts = {}) {
|
|
|
305
384
|
return serialize(async () => {
|
|
306
385
|
const macros = await loadForWrite(filePath, opts);
|
|
307
386
|
const now = new Date().toISOString();
|
|
308
|
-
const projects = normalizeProjects(parsed.projects);
|
|
309
387
|
let saved;
|
|
310
388
|
if (parsed.id) {
|
|
311
389
|
const idx = macros.findIndex((m) => m.id === parsed.id);
|
|
312
390
|
if (idx === -1) throw new Error(`macro not found: ${parsed.id}`);
|
|
313
|
-
|
|
391
|
+
const projects = parsed.projects !== undefined ? normalizeProjects(parsed.projects) : macros[idx].projects;
|
|
392
|
+
saved = {
|
|
393
|
+
...macros[idx],
|
|
394
|
+
label: parsed.label,
|
|
395
|
+
agentName: parsed.agentName,
|
|
396
|
+
tag: parsed.tag,
|
|
397
|
+
prompt: parsed.prompt,
|
|
398
|
+
projects,
|
|
399
|
+
surface: parsed.surface ?? macros[idx].surface,
|
|
400
|
+
updatedAt: now,
|
|
401
|
+
};
|
|
314
402
|
macros[idx] = saved;
|
|
315
403
|
} else {
|
|
404
|
+
const projects = parsed.projects !== undefined ? normalizeProjects(parsed.projects) : [];
|
|
316
405
|
saved = {
|
|
317
406
|
id: newId(parsed.label, new Set(macros.map((m) => m.id))),
|
|
318
407
|
label: parsed.label,
|
|
@@ -320,6 +409,7 @@ async function saveMacro(input, opts = {}) {
|
|
|
320
409
|
tag: parsed.tag,
|
|
321
410
|
prompt: parsed.prompt,
|
|
322
411
|
projects,
|
|
412
|
+
surface: parsed.surface ?? 'sessions',
|
|
323
413
|
createdAt: now,
|
|
324
414
|
updatedAt: now,
|
|
325
415
|
};
|
|
@@ -336,6 +426,8 @@ async function deleteMacro(input, opts = {}) {
|
|
|
336
426
|
const filePath = resolvePath(opts);
|
|
337
427
|
return serialize(async () => {
|
|
338
428
|
const macros = await loadForWrite(filePath, opts);
|
|
429
|
+
const target = macros.find((m) => m.id === id);
|
|
430
|
+
if (target && target.builtin) throw new Error('built-in macros cannot be deleted');
|
|
339
431
|
const next = macros.filter((m) => m.id !== id);
|
|
340
432
|
if (next.length !== macros.length) await writeStore(filePath, next);
|
|
341
433
|
return { ok: true };
|
|
@@ -361,6 +453,7 @@ async function setMacroProject(input, opts = {}) {
|
|
|
361
453
|
if (enabled) return { ok: true, macro };
|
|
362
454
|
return { ok: false, error: 'macro is shown in every project' };
|
|
363
455
|
}
|
|
456
|
+
if (macro.builtin && !enabled) return { ok: false, error: 'built-in macro visibility cannot be narrowed' };
|
|
364
457
|
const has = macro.projects.includes(target);
|
|
365
458
|
if (enabled === has) return { ok: true, macro };
|
|
366
459
|
const projects = enabled ? [...macro.projects, target] : macro.projects.filter((p) => p !== target);
|
|
@@ -383,4 +476,5 @@ module.exports = {
|
|
|
383
476
|
deleteMacro,
|
|
384
477
|
setMacroProject,
|
|
385
478
|
defaultFilePath,
|
|
479
|
+
ensureBuiltins,
|
|
386
480
|
};
|
|
@@ -270,6 +270,29 @@ const MCP_TOOL_CATALOG = [
|
|
|
270
270
|
exampleArgs: { cwd: '/home/bilko/Projects/session-manager', html: '<!DOCTYPE html><html><body><h1>Example</h1></body></html>' },
|
|
271
271
|
notes: "cwd is optional — defaults to the calling session's own project root (SM_PROJECT_ROOT or process.cwd()) when omitted.",
|
|
272
272
|
},
|
|
273
|
+
{
|
|
274
|
+
name: 'project_demo_video_write',
|
|
275
|
+
group: 'project-home',
|
|
276
|
+
purpose: "Write this project's 30-second demo video — ONE self-contained HTML/JS document — to "
|
|
277
|
+
+ "session-manager-operations/project-pages/demo-video/index.html via the session-manager app's admin API. "
|
|
278
|
+
+ 'The only write path for the demo video.',
|
|
279
|
+
whenToUse: 'Use when asked to generate or refresh the demo video. Compose the whole document yourself '
|
|
280
|
+
+ '(inline <style>/<script>, data: URIs for assets, CSS/JS-driven animation) from what is really true about '
|
|
281
|
+
+ 'the project, declare its length with <meta name="sm-demo-duration" content="N"> (5-30 seconds), then '
|
|
282
|
+
+ 'pass the full document as `html`.',
|
|
283
|
+
whenNotToUse: 'Never fabricate content — every claim must trace to something concrete in the project. The '
|
|
284
|
+
+ 'document must be self-contained and non-network-capable: the call is rejected for empty input, more than '
|
|
285
|
+
+ '2MB, any <script src>, <link href="http…">, @import, or url(http…) (no remote references); any '
|
|
286
|
+
+ 'fetch/XMLHttpRequest/WebSocket/EventSource/sendBeacon/dynamic import/importScripts/<iframe>/<object>/'
|
|
287
|
+
+ '<embed>/window.open/http(s)-pointing src or href (no network-capable APIs); or a missing/out-of-range '
|
|
288
|
+
+ 'sm-demo-duration meta tag.',
|
|
289
|
+
exampleArgs: {
|
|
290
|
+
cwd: '/home/bilko/Projects/session-manager',
|
|
291
|
+
html: '<!DOCTYPE html><html><head><meta name="sm-demo-duration" content="30"></head><body><h1>Example</h1></body></html>',
|
|
292
|
+
},
|
|
293
|
+
notes: "cwd is optional — defaults to the calling session's own project root (SM_PROJECT_ROOT or process.cwd()) when omitted. "
|
|
294
|
+
+ 'The document is CSP-stamped after it is written, so the viewer sandbox is the real network fence — these checks are defence in depth.',
|
|
295
|
+
},
|
|
273
296
|
{
|
|
274
297
|
name: 'session_manager_help',
|
|
275
298
|
group: 'help',
|
|
@@ -48,10 +48,11 @@ const OWNERS = Object.freeze({
|
|
|
48
48
|
'scheduler': 'scheduler',
|
|
49
49
|
// Project Home owns the synthesized Brief (generate + hand-edit).
|
|
50
50
|
'project-brief': 'project-home',
|
|
51
|
-
// Project Home owns project-pages/home.html
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
51
|
+
// Project Home owns project-pages/home.html and project-pages/demo-video/
|
|
52
|
+
// index.html, written only via the project_home_write ->
|
|
53
|
+
// /admin/project-home/write and project_demo_video_write ->
|
|
54
|
+
// /admin/project-home/demo-video/write routes (config.cjs's
|
|
55
|
+
// writeTextAtomic). See session-manager-operations/project-pages/README.md.
|
|
55
56
|
'project-pages': 'project-home',
|
|
56
57
|
// Structured per-tab error log lines (JSONL), tagged for tracing/analysis.
|
|
57
58
|
'logs': 'logs',
|