claude-code-session-manager 0.102.0 → 0.104.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +4 -0
  2. package/dist/assets/{DataModel-CrthqiBI.js → DataModel-jHE3YZ1R.js} +1 -1
  3. package/dist/assets/{History-Ci8AMY-Z.js → History-BcmzvveB.js} +1 -1
  4. package/dist/assets/{Hooks-BUERs_jz.js → Hooks-7s-8_Swz.js} +1 -1
  5. package/dist/assets/{Library-DkEaEjWs.js → Library-87gLWVw2.js} +1 -1
  6. package/dist/assets/{MarkdownEditor-Gb_Vm2cQ.js → MarkdownEditor--uC2uo5Z.js} +1 -1
  7. package/dist/assets/{McpServers-ChtBd9J1.js → McpServers-JMiSnVw_.js} +1 -1
  8. package/dist/assets/{Memory-hO5wBnK4.js → Memory-BVA6XrVK.js} +1 -1
  9. package/dist/assets/{Permissions-DaqZyJrw.js → Permissions-DIoNtYJd.js} +1 -1
  10. package/dist/assets/{Plugins-Ck5p4acV.js → Plugins-DG7XAIlT.js} +2 -2
  11. package/dist/assets/{ProvenanceBadge-CnuIadnk.js → ProvenanceBadge-fipaqRJJ.js} +1 -1
  12. package/dist/assets/{SaveBar-rSB7cm1z.js → SaveBar-C7DFPoFJ.js} +1 -1
  13. package/dist/assets/Scheduler-CfKSiT_a.js +16 -0
  14. package/dist/assets/{ScopeSwitcher-qH4Rc4Kf.js → ScopeSwitcher-C5Uhek3u.js} +1 -1
  15. package/dist/assets/{Settings-CFP_-hF5.js → Settings-BAkeG1FK.js} +1 -1
  16. package/dist/assets/{SkillReferenceGraph-CTNaQVhr.js → SkillReferenceGraph-BjAnQnCI.js} +1 -1
  17. package/dist/assets/{Skills-Deim4Jh9.js → Skills-Bm0nqhpf.js} +1 -1
  18. package/dist/assets/{SystemPrompt-B-HhbNPo.js → SystemPrompt-DeCfwhFB.js} +1 -1
  19. package/dist/assets/{TagLibrary-La0wD_-k.js → TagLibrary-B2zo54TL.js} +1 -1
  20. package/dist/assets/{TiptapBody-6MYJQp2Z.js → TiptapBody-BnSRUmUc.js} +1 -1
  21. package/dist/assets/{Toggle-BzQFK045.js → Toggle-dYmhVb17.js} +1 -1
  22. package/dist/assets/{ViewTabs-CPKoy15S.js → ViewTabs-DsC7dKoh.js} +1 -1
  23. package/dist/assets/{index-DbZfl7rl.js → index-B-h-PcUp.js} +4 -4
  24. package/dist/assets/{settingsSchema-C_mZIOIl.js → settingsSchema-B0xACLrZ.js} +1 -1
  25. package/dist/index.html +1 -1
  26. package/package.json +16 -9
  27. package/scripts/scheduler-mcp-server.cjs +47 -0
  28. package/src/main/build-info.json +4 -4
  29. package/src/main/index.cjs +2 -0
  30. package/src/main/lib/macroAdminRoutes.cjs +111 -0
  31. package/src/main/lib/mcpToolCatalog.cjs +36 -1
  32. package/src/main/lib/projectHomeAdminRoutes.cjs +1 -0
  33. package/src/main/lib/shippedPersonaSeeds.cjs +33 -0
  34. package/src/main/otel.cjs +7 -7
  35. package/src/seed/agents/demo-video-builder.md +24 -13
  36. package/dist/assets/Scheduler-DpdAfUgp.js +0 -16
@@ -1 +1 @@
1
- import{ax as b,ai as n,S as N,aO as O,av as K}from"./index-DbZfl7rl.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-B-h-PcUp.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,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-DbZfl7rl.js"></script>
10
+ <script type="module" crossorigin src="./assets/index-B-h-PcUp.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
13
  <link rel="stylesheet" crossorigin href="./assets/index-D89EUizB.css">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-session-manager",
3
- "version": "0.102.0",
3
+ "version": "0.104.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",
@@ -100,23 +100,30 @@
100
100
  "node": ">=22.12.0"
101
101
  },
102
102
  "overrides": {
103
- "dompurify": "^3.4.8"
103
+ "dompurify": "^3.4.8",
104
+ "@hono/node-server": "^1.19.15",
105
+ "fast-uri": "^3.1.8",
106
+ "hono": "^4.13.7",
107
+ "ip-address": "^10.7.1",
108
+ "qs": "^6.16.0",
109
+ "tar": "^7.5.21",
110
+ "undici": "^7.29.1"
104
111
  },
105
112
  "os": [
106
113
  "darwin",
107
114
  "linux"
108
115
  ],
109
116
  "dependencies": {
110
- "@electron/rebuild": "4.0.4",
117
+ "@electron/rebuild": "4.2.0",
111
118
  "@modelcontextprotocol/sdk": "^1.29.0",
112
119
  "@opentelemetry/api": "^1.9.0",
113
- "@opentelemetry/exporter-trace-otlp-http": "^0.57.0",
114
- "@opentelemetry/resources": "^1.30.0",
115
- "@opentelemetry/sdk-trace-base": "^1.30.0",
116
- "@opentelemetry/sdk-trace-node": "^1.30.0",
117
- "@opentelemetry/semantic-conventions": "^1.28.0",
120
+ "@opentelemetry/exporter-trace-otlp-http": "^0.222.0",
121
+ "@opentelemetry/resources": "^2.11.0",
122
+ "@opentelemetry/sdk-trace-base": "^2.11.0",
123
+ "@opentelemetry/sdk-trace-node": "^2.11.0",
124
+ "@opentelemetry/semantic-conventions": "^1.43.0",
118
125
  "chokidar": "^4.0.1",
119
- "electron": "42.1.0",
126
+ "electron": "42.11.10",
120
127
  "marked": "^14.0.0",
121
128
  "node-pty": "^1.2.0-beta.12",
122
129
  "zod": "^3.23.8"
@@ -14,6 +14,9 @@
14
14
  * project_home_write({ cwd?, html }) -> POST /admin/project-home/write
15
15
  * project_demo_video_write({ cwd?, html }) -> POST /admin/project-home/demo-video/write
16
16
  *
17
+ * macro_list({ cwd? }) -> GET /admin/macros?cwd=<encoded>
18
+ * macro_save({ cwd?, id?, label, agentName, tag, prompt }) -> POST /admin/macros/save
19
+ *
17
20
  * This is a separate process from the Electron app — it only ever reaches
18
21
  * it over the token-authed loopback HTTP API in admin-api.json, never by
19
22
  * requiring scheduler.cjs/localAdminHttp.cjs directly. The admin server IS the
@@ -395,6 +398,32 @@ const TOOLS = [
395
398
  required: ['html'],
396
399
  },
397
400
  },
401
+ {
402
+ name: 'macro_list',
403
+ description: descriptionFor('macro_list'),
404
+ inputSchema: {
405
+ type: 'object',
406
+ properties: {
407
+ 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." },
408
+ },
409
+ },
410
+ },
411
+ {
412
+ name: 'macro_save',
413
+ description: descriptionFor('macro_save'),
414
+ inputSchema: {
415
+ type: 'object',
416
+ properties: {
417
+ 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." },
418
+ id: { type: 'string', description: 'Optional: id of an existing macro (already visible to this project) to update. Omit to create a new macro scoped to this project.' },
419
+ label: { type: 'string', description: 'Short label shown on the HOT KEYS button.' },
420
+ agentName: { type: 'string', description: 'Persona to run the macro as (e.g. "builder").' },
421
+ tag: { type: 'string', description: 'Mission tag for the macro.' },
422
+ prompt: { type: 'string', description: 'The opening prompt the macro sends.' },
423
+ },
424
+ required: ['label', 'agentName', 'tag', 'prompt'],
425
+ },
426
+ },
398
427
  {
399
428
  name: 'session_manager_help',
400
429
  description: descriptionFor('session_manager_help'),
@@ -627,6 +656,24 @@ async function handleCallTool(request) {
627
656
  const result = await adminRequest('POST', '/admin/project-home/demo-video/write', { cwd, html: args.html });
628
657
  return { content: [{ type: 'text', text: JSON.stringify(result) }] };
629
658
  }
659
+ if (name === 'macro_list') {
660
+ const cwd = resolveCwdArg(args);
661
+ const result = await adminRequest('GET', `/admin/macros?cwd=${encodeURIComponent(cwd)}`);
662
+ return { content: [{ type: 'text', text: JSON.stringify(result) }] };
663
+ }
664
+ if (name === 'macro_save') {
665
+ const missing = ['label', 'agentName', 'tag', 'prompt'].filter(
666
+ (field) => !args || typeof args[field] !== 'string',
667
+ );
668
+ if (missing.length > 0) {
669
+ return errorResult(`missing or invalid required argument(s): ${missing.join(', ')}`);
670
+ }
671
+ const cwd = resolveCwdArg(args);
672
+ const payload = { cwd, label: args.label, agentName: args.agentName, tag: args.tag, prompt: args.prompt };
673
+ if (typeof args.id === 'string' && args.id) payload.id = args.id;
674
+ const result = await adminRequest('POST', '/admin/macros/save', payload);
675
+ return { content: [{ type: 'text', text: JSON.stringify(result) }] };
676
+ }
630
677
  if (name === 'session_manager_help') {
631
678
  const toolName = args && typeof args.tool === 'string' ? args.tool : null;
632
679
  const topic = args && typeof args.topic === 'string' ? args.topic : null;
@@ -1,8 +1,8 @@
1
1
  {
2
- "version": "0.102.0",
3
- "gitSha": "3d8f172cc5c5bf040b150eb37c67257ed473643f",
4
- "gitShortSha": "3d8f172c",
2
+ "version": "0.104.0",
3
+ "gitSha": "36272fc5173ad2015632696376d4cdee65c550d8",
4
+ "gitShortSha": "36272fc5",
5
5
  "gitBranch": "HEAD",
6
- "builtAt": "2026-10-03T19:43:51.978Z",
6
+ "builtAt": "2026-10-03T21:56:15.195Z",
7
7
  "dirty": false
8
8
  }
@@ -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 macroAdminRoutes = require('./lib/macroAdminRoutes.cjs');
36
37
  const { smfileResponseHeaders, shouldBlockFrameNavigation } = require('./lib/smfileHeaders.cjs');
37
38
  const { appendAuditEvent } = require('./lib/auditLog.cjs');
38
39
  const chatRunner = require('./chatRunner.cjs');
@@ -60,6 +61,7 @@ scheduler.registerAdminRoutes(adminHttp);
60
61
  prdCreate.registerAdminRoute(adminHttp, scheduler.remote);
61
62
  prdAdminRoutes.registerAdminRoute(adminHttp, scheduler.remote);
62
63
  projectHomeAdminRoutes.registerAdminRoute(adminHttp);
64
+ macroAdminRoutes.registerAdminRoute(adminHttp, { onChanged: () => broadcastMacrosChanged() });
63
65
  chatRunner.registerAdminRoute(adminHttp);
64
66
  // Project-to-project feedback conduit — the app is the only process holding
65
67
  // several projects' operations roots open, so it performs the cross-folder
@@ -0,0 +1,111 @@
1
+ /**
2
+ * macroAdminRoutes.cjs — loopback admin HTTP routes so an agent session (via
3
+ * the scheduler MCP, next PRD) can list and create/update a HOT KEYS macro
4
+ * for its own project, through the existing macroLibrary.cjs store:
5
+ * GET /admin/macros?cwd=… -> { ok, macros }
6
+ * POST /admin/macros/save {cwd, id?, label, agentName, tag, prompt}
7
+ *
8
+ * cwd resolution matches projectHomeAdminRoutes.cjs's resolveCwd exactly
9
+ * (reused, not copied). A create always stores `projects: [resolvedCwd]`,
10
+ * `surface: 'sessions'`; an update is refused (400) if the resolved cwd is
11
+ * not already in the macro's `projects` (no cross-project hijack), if `id`
12
+ * starts with `builtin-`, or if `id` is not found. Field validation reuses
13
+ * macroLibrary's `MacroSaveSchema`.
14
+ *
15
+ * A successful save calls `onChanged()` exactly once so the Sessions HOT
16
+ * KEYS strip updates live, matching the IPC handlers in index.cjs.
17
+ */
18
+ 'use strict';
19
+
20
+ const { readBody, sendJson } = require('./localAdminHttp.cjs');
21
+ const { resolveCwd } = require('./projectHomeAdminRoutes.cjs');
22
+ const macroLibrary = require('./macroLibrary.cjs');
23
+
24
+ function listHandler(onChanged, libOpts) {
25
+ return async (_req, res, query) => {
26
+ const resolved = resolveCwd(query.get('cwd'));
27
+ if (!resolved.ok) {
28
+ sendJson(res, resolved.status, { ok: false, error: resolved.error });
29
+ return;
30
+ }
31
+ const macros = await macroLibrary.listMacros(libOpts);
32
+ const visible = macros.filter(
33
+ (m) => m.projects.includes(resolved.cwd) || m.projects.includes(macroLibrary.ALL_PROJECTS),
34
+ );
35
+ sendJson(res, 200, { ok: true, macros: visible });
36
+ };
37
+ }
38
+
39
+ function saveHandler(onChanged, libOpts) {
40
+ return async (req, res) => {
41
+ let raw;
42
+ try {
43
+ raw = await readBody(req);
44
+ } catch (e) {
45
+ sendJson(res, 400, { ok: false, error: `request body rejected: ${e?.message ?? 'unreadable'}` });
46
+ return;
47
+ }
48
+ let body;
49
+ try {
50
+ body = raw ? JSON.parse(raw) : {};
51
+ } catch {
52
+ sendJson(res, 400, { ok: false, error: 'invalid JSON body' });
53
+ return;
54
+ }
55
+ const resolved = resolveCwd(body.cwd);
56
+ if (!resolved.ok) {
57
+ sendJson(res, resolved.status, { ok: false, error: resolved.error });
58
+ return;
59
+ }
60
+ if (typeof body.id === 'string' && body.id.startsWith('builtin-')) {
61
+ sendJson(res, 400, { ok: false, error: 'built-in macros cannot be edited through this route' });
62
+ return;
63
+ }
64
+ let input;
65
+ try {
66
+ input = macroLibrary.MacroSaveSchema.parse({
67
+ id: body.id,
68
+ label: body.label,
69
+ agentName: body.agentName,
70
+ tag: body.tag,
71
+ prompt: body.prompt,
72
+ });
73
+ } catch (e) {
74
+ sendJson(res, 400, { ok: false, error: e?.issues?.[0]?.message ?? e?.message ?? 'invalid payload' });
75
+ return;
76
+ }
77
+ if (input.id) {
78
+ const macros = await macroLibrary.listMacros(libOpts);
79
+ const existing = macros.find((m) => m.id === input.id);
80
+ if (!existing) {
81
+ sendJson(res, 400, { ok: false, error: `macro not found: ${input.id}` });
82
+ return;
83
+ }
84
+ if (!existing.projects.includes(resolved.cwd)) {
85
+ sendJson(res, 400, { ok: false, error: `macro ${input.id} is not visible to ${resolved.cwd}` });
86
+ return;
87
+ }
88
+ } else {
89
+ input = { ...input, projects: [resolved.cwd], surface: 'sessions' };
90
+ }
91
+ let macro;
92
+ try {
93
+ macro = await macroLibrary.saveMacro(input, libOpts);
94
+ } catch (e) {
95
+ sendJson(res, 400, { ok: false, error: e?.message ?? 'save failed' });
96
+ return;
97
+ }
98
+ if (onChanged) onChanged();
99
+ sendJson(res, 200, { ok: true, macro });
100
+ };
101
+ }
102
+
103
+ function registerAdminRoute(adminHttp, { onChanged } = {}, opts = {}) {
104
+ const libOpts = opts.filePath ? { filePath: opts.filePath } : undefined;
105
+ adminHttp.registerRoute('GET', '/admin/macros', listHandler(onChanged, libOpts));
106
+ adminHttp.registerRoute('POST', '/admin/macros/save', saveHandler(onChanged, libOpts));
107
+ }
108
+
109
+ module.exports = {
110
+ registerAdminRoute,
111
+ };
@@ -23,7 +23,7 @@ const { z } = require('zod');
23
23
 
24
24
  const CatalogEntrySchema = z.object({
25
25
  name: z.string().min(1),
26
- group: z.enum(['scheduler', 'chat', 'feedback', 'help', 'project-home']),
26
+ group: z.enum(['scheduler', 'chat', 'feedback', 'help', 'project-home', 'macros']),
27
27
  purpose: z.string().min(1),
28
28
  whenToUse: z.string().min(1),
29
29
  whenNotToUse: z.string().min(1),
@@ -293,6 +293,41 @@ const MCP_TOOL_CATALOG = [
293
293
  notes: "cwd is optional — defaults to the calling session's own project root (SM_PROJECT_ROOT or process.cwd()) when omitted. "
294
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
295
  },
296
+ {
297
+ name: 'macro_list',
298
+ group: 'macros',
299
+ purpose: "List this project's HOT KEYS macros — the saved (agent, tag, prompt) one-click buttons shown "
300
+ + "in the Sessions tab's HOT KEYS strip, via the session-manager app's admin API.",
301
+ whenToUse: 'Use to see what macros already exist for this project (including machine-wide `*` macros and '
302
+ + 'built-ins) before deciding whether to add or update one.',
303
+ whenNotToUse: 'WHEN NOT TO USE IT: macros are scoped to the caller\'s own project — this only ever returns '
304
+ + "macros visible to the resolved cwd, never another project's.",
305
+ exampleArgs: { cwd: '/home/bilko/Projects/session-manager' },
306
+ notes: "cwd is optional — defaults to the calling session's own project root (SM_PROJECT_ROOT or process.cwd()) when omitted.",
307
+ },
308
+ {
309
+ name: 'macro_save',
310
+ group: 'macros',
311
+ purpose: "Create or update one of this project's HOT KEYS macros — a saved (agentName, tag, prompt) "
312
+ + 'one-click button — via the session-manager app\'s admin API, through the same macroLibrary.cjs store '
313
+ + 'the Sessions HOT KEYS strip reads from.',
314
+ whenToUse: 'Pass `id` to update an existing macro already visible to this project; omit `id` to create a new '
315
+ + 'one scoped to this project. Use for things like a "Publish git + npm" macro a human will press '
316
+ + 'repeatedly, when they have asked for that macro to exist.',
317
+ whenNotToUse: 'WHEN NOT TO USE IT: macros are scoped to the caller\'s own project — this call is refused if '
318
+ + '`id` resolves to a macro not visible to this project. Built-in macros (`id` starting with `builtin-`) '
319
+ + "cannot be edited through this route. A macro is a HUMAN's one-click button, not a task runner — never "
320
+ + 'create or update one unless the human has actually asked for that macro to exist.',
321
+ exampleArgs: {
322
+ cwd: '/home/bilko/Projects/session-manager',
323
+ label: 'Publish git + npm',
324
+ agentName: 'builder',
325
+ tag: 'feature',
326
+ prompt: 'Run the full publish flow: commit, bump version, gate, npm publish, push.',
327
+ },
328
+ notes: "cwd is optional — defaults to the calling session's own project root (SM_PROJECT_ROOT or "
329
+ + 'process.cwd()) when omitted. label, agentName, tag and prompt are all required strings.',
330
+ },
296
331
  {
297
332
  name: 'session_manager_help',
298
333
  group: 'help',
@@ -243,4 +243,5 @@ module.exports = {
243
243
  DEMO_VIDEO_CSP,
244
244
  MAX_HTML_BYTES,
245
245
  MAX_DEMO_VIDEO_BYTES,
246
+ resolveCwd,
246
247
  };
@@ -231,6 +231,39 @@ const SHIPPED_PERSONA_SEEDS = deepFreeze({
231
231
  effort: "medium",
232
232
  },
233
233
  },
234
+ {
235
+ commit: "b1fce824",
236
+ bodySha256: "c89991e8aba90f63c1fa5094268aec0e19bd38e5f8af3df375b80112d7a4a781",
237
+ fm: {
238
+ description: "30-second self-contained HTML/JS demo video for Project Home, saved via project_demo_video_write.",
239
+ tools: "Read, Grep, Glob, Bash, Write, Edit",
240
+ title: "Project Home — Demo Video",
241
+ model: "sonnet",
242
+ effort: "medium",
243
+ },
244
+ },
245
+ {
246
+ commit: "4a7d4a80",
247
+ bodySha256: "6d61ec0653d7866c035d59c6ee09421a8ed8ce657f842040b064d84a83d447e0",
248
+ fm: {
249
+ description: "30-second self-contained HTML/JS demo video for Project Home, saved via project_demo_video_write.",
250
+ tools: "Read, Grep, Glob, Bash, Write, Edit",
251
+ title: "Project Home — Demo Video",
252
+ model: "sonnet",
253
+ effort: "medium",
254
+ },
255
+ },
256
+ {
257
+ commit: "6d484642",
258
+ bodySha256: "f663bd4f82ce140dd23d8a9760c1ad7237c99b741fc0f96dd66c41932df192ca",
259
+ fm: {
260
+ description: "30-second self-contained HTML/JS demo video for Project Home, saved via project_demo_video_write.",
261
+ tools: "Read, Grep, Glob, Bash, Write, Edit",
262
+ title: "Project Home — Demo Video",
263
+ model: "sonnet",
264
+ effort: "medium",
265
+ },
266
+ },
234
267
  ],
235
268
  });
236
269
 
package/src/main/otel.cjs CHANGED
@@ -35,9 +35,9 @@ function loadDeps() {
35
35
  const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node');
36
36
  const { BatchSpanProcessor } = require('@opentelemetry/sdk-trace-base');
37
37
  const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http');
38
- const { Resource } = require('@opentelemetry/resources');
39
- const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions');
40
- return { api, NodeTracerProvider, BatchSpanProcessor, OTLPTraceExporter, Resource, SemanticResourceAttributes };
38
+ const { resourceFromAttributes } = require('@opentelemetry/resources');
39
+ const { ATTR_SERVICE_NAME } = require('@opentelemetry/semantic-conventions');
40
+ return { api, NodeTracerProvider, BatchSpanProcessor, OTLPTraceExporter, resourceFromAttributes, ATTR_SERVICE_NAME };
41
41
  } catch (err) {
42
42
  return { error: err };
43
43
  }
@@ -83,7 +83,7 @@ async function init({ endpoint, headers, serviceName, includeContent: ic } = {})
83
83
  return { ok: false, error: lastError };
84
84
  }
85
85
 
86
- const { NodeTracerProvider, BatchSpanProcessor, OTLPTraceExporter, Resource, SemanticResourceAttributes } = deps;
86
+ const { NodeTracerProvider, BatchSpanProcessor, OTLPTraceExporter, resourceFromAttributes, ATTR_SERVICE_NAME } = deps;
87
87
 
88
88
  try {
89
89
  const exporter = new OTLPTraceExporter({
@@ -91,11 +91,11 @@ async function init({ endpoint, headers, serviceName, includeContent: ic } = {})
91
91
  headers: typeof headers === 'object' && headers ? headers : {},
92
92
  });
93
93
  const tp = new NodeTracerProvider({
94
- resource: new Resource({
95
- [SemanticResourceAttributes.SERVICE_NAME]: String(serviceName || 'session-manager'),
94
+ resource: resourceFromAttributes({
95
+ [ATTR_SERVICE_NAME]: String(serviceName || 'session-manager'),
96
96
  }),
97
+ spanProcessors: [new BatchSpanProcessor(exporter)],
97
98
  });
98
- tp.addSpanProcessor(new BatchSpanProcessor(exporter));
99
99
  // Note: we deliberately do NOT call tp.register() — that installs a global
100
100
  // tracer provider, which would intercept any other OTEL user in the
101
101
  // process. We only want to emit our own spans, so we use the provider
@@ -66,19 +66,30 @@ Narrate the storyboard captions with a short, pleasant on-device voice track —
66
66
  block the video on it. Generate it at build time, not at playback time; the shipped document
67
67
  never calls out to a network TTS service.
68
68
 
69
- - Use **Piper** (`pip install piper-tts`, MIT-licensed, small ONNX voices, no GPU needed) for the
70
- voice. If `python3 -m pip` isn't on PATH, bootstrap it first: `curl -sS
71
- https://bootstrap.pypa.io/get-pip.py | python3 - --user --break-system-packages`, then
72
- `python3 -m pip install --user --break-system-packages piper-tts`. Pull one voice once, e.g.
73
- `en_US-amy-medium` from `https://huggingface.co/rhasspy/piper-voices` (`.onnx` + `.onnx.json`).
74
- Kokoro-82M (Apache-2.0) sounds a step better but needs PyTorch and a much larger model
75
- download — prefer it only when you have the time/bandwidth budget for it.
76
- - Synthesize one short line per scene (`python3 -m piper -m <voice>.onnx -c <voice>.onnx.json -f
77
- sceneN.wav`), sized to fit that scene's on-screen hold time. Lay the scene clips onto one
78
- mono 22050 Hz track at each scene's start offset, encode the result with `ffmpeg -ar 16000 -c:a
79
- libmp3lame -b:a 20k` (mono, ~16 kbps is plenty for speech and keeps the whole track under
80
- ~80 KB), then base64 it into a single `<audio src="data:audio/mpeg;base64,...">` tag. Keep the
81
- whole document — markup plus audio — under the 2 MB cap.
69
+ - Use **Kokoro-82M via the `kokoro-onnx` package** (`pip install kokoro-onnx`, Apache-2.0,
70
+ ONNX runtime only — no PyTorch needed despite earlier guidance here claiming otherwise;
71
+ confirmed by running it for real). If `python3 -m pip` isn't on PATH, bootstrap it first:
72
+ `curl -sS https://bootstrap.pypa.io/get-pip.py | python3 - --user --break-system-packages`,
73
+ then `python3 -m pip install --user --break-system-packages kokoro-onnx soundfile`. Pull the
74
+ model once: `kokoro-v1.0.onnx` (~325 MB) + `voices-v1.0.bin` (~28 MB) from
75
+ `https://github.com/thewh1teagle/kokoro-onnx/releases/download/model-files-v1.0/`. Use the
76
+ **`af_heart`** or **`af_bella`** voice (both are Kokoro's top-rated English voices and read
77
+ as clearly more natural than Piper, including Piper's `-high` tier — but which one of the
78
+ two sounds better is a taste call, not a settled fact; if the human reacts to a generated
79
+ video with "still not it," try the other one before reaching for a different library).
80
+ `Kokoro(model, voices).create(line, voice='af_heart', speed=1.0, lang='en-us')` returns
81
+ `(samples, sample_rate)` (24000 Hz); write each scene's line with `soundfile.write`. If
82
+ `kokoro-onnx`/its model download genuinely isn't available (offline, no bandwidth for a
83
+ ~350 MB pull), fall back to **Piper** (`pip install piper-tts`) with a `-high` voice tier
84
+ (e.g. `en_US-lessac-high`, not `-medium` — `-medium` reads as noticeably robotic) from
85
+ `https://huggingface.co/rhasspy/piper-voices`.
86
+ - Synthesize one short line per scene, sized to fit that scene's on-screen hold time. Lay the
87
+ scene clips onto one mono track (at the model's native sample rate) at each scene's start
88
+ offset, encode the result with `ffmpeg -c:a libmp3lame -b:a 64k` **at that native sample
89
+ rate — do not downsample or drop below ~48 kbps; both make speech sound crushed/robotic for
90
+ only a small size win** (a 30 s mono track at 64 kbps is still only ~235 KB). Base64 it into
91
+ a single `<audio src="data:audio/mpeg;base64,...">` tag. Keep the whole document — markup
92
+ plus audio — under the 2 MB cap (plenty of headroom at this bitrate).
82
93
  - Wire `play()`/`pause()`/`seek(t)` to the `<audio>` element too (`audio.currentTime = t` on
83
94
  seek) so the narration never drifts from the visual clock, and start muted-fallback: call
84
95
  `.play()` on load, and on rejection (autoplay-blocked browsers) show a small "tap for sound"