claude-code-session-manager 0.64.0 → 0.66.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/AgentLibrary-Bzg89D5Y.js +3 -0
- package/dist/assets/{History-Dp3-_bjQ.js → History-CNH9vA0A.js} +2 -2
- package/dist/assets/{Hooks-DMQFgGDd.js → Hooks-CyTksPza.js} +3 -3
- package/dist/assets/{HostBilko-zNU1NtBh.js → HostBilko-DXQVDNHn.js} +1 -1
- package/dist/assets/{Library-BrODBbeL.js → Library-9E2UOIsm.js} +1 -1
- package/dist/assets/{ListDetail-C5vbA1gC.js → ListDetail-CQWU_Yn5.js} +1 -1
- package/dist/assets/{MarkdownEditor-CpzAEiiG.js → MarkdownEditor-DQgfpSef.js} +1 -1
- package/dist/assets/{McpServers-DWuw-flj.js → McpServers-r3qwDIj2.js} +2 -2
- package/dist/assets/{Memory-B4TC9SsJ.js → Memory-BaxOpj-3.js} +6 -6
- package/dist/assets/{Panel-Bap7G-pI.js → Panel-BhFD8Lqo.js} +1 -1
- package/dist/assets/{Permissions-BIpNWItH.js → Permissions-Cj-mODQQ.js} +3 -3
- package/dist/assets/{Plugins-DrwklmW4.js → Plugins-DEL3Fqng.js} +2 -2
- package/dist/assets/{ProvenanceBadge-CCp_EhjV.js → ProvenanceBadge-CIAg6-JQ.js} +1 -1
- package/dist/assets/Scheduler-YOuZKkES.js +14 -0
- package/dist/assets/{ScopeSwitcher-BlQvpyLE.js → ScopeSwitcher-DZ_3gEus.js} +1 -1
- package/dist/assets/{Settings-BzvmZvGa.js → Settings-B0x4oflz.js} +3 -3
- package/dist/assets/{SkillReferenceGraph-CGtwmCjm.js → SkillReferenceGraph-CoIwsol8.js} +1 -1
- package/dist/assets/{Skills-Cauvbtk7.js → Skills-CN8R6AWn.js} +2 -2
- package/dist/assets/{SystemPrompt-BqzM76PV.js → SystemPrompt-DceChpAi.js} +1 -1
- package/dist/assets/{TagLibrary-DVKPjeRu.js → TagLibrary-BKmz2W7B.js} +1 -1
- package/dist/assets/{TiptapBody-CUWdBAYf.js → TiptapBody-W7n5SwPM.js} +1 -1
- package/dist/assets/{Toggle-Bos67yDJ.js → Toggle-QuxlVHGI.js} +1 -1
- package/dist/assets/{index-LlWpj2VJ.css → index-14dBLqE_.css} +1 -1
- package/dist/assets/{index-BfPVknuV.js → index-TejhHSzN.js} +526 -525
- package/dist/assets/{settingsSchema-DKuyaEK5.js → settingsSchema-DNqx6BKJ.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +5 -1
- package/plugins/session-manager-dev/skills/builder/4-manual/SKILL.md +120 -0
- package/plugins/session-manager-dev/skills/builder/SKILL.md +13 -3
- package/plugins/session-manager-dev/skills/develop/SKILL.md +41 -13
- package/plugins/session-manager-dev/skills/ops-sweep/SKILL.md +10 -0
- package/src/main/__tests__/agentLibrary.test.cjs +40 -0
- package/src/main/__tests__/flatPrdTickSweep.test.cjs +110 -0
- package/src/main/__tests__/prdAdminRouteParity.test.cjs +68 -0
- package/src/main/__tests__/prdAdminRoutes.test.cjs +311 -0
- package/src/main/__tests__/prdCreate.test.cjs +7 -2
- package/src/main/__tests__/prdMigration.test.cjs +17 -0
- package/src/main/__tests__/prdMigrationLegacyAdopt.test.cjs +91 -0
- package/src/main/__tests__/reconcileFlatPrdSweep.test.cjs +109 -0
- package/src/main/__tests__/scheduleJobSchema.test.cjs +127 -0
- package/src/main/__tests__/scheduleJobStatusDrift.test.cjs +65 -0
- package/src/main/__tests__/scheduleJobTransitions.test.cjs +152 -0
- package/src/main/__tests__/scheduleJobTransitionsGrep.test.cjs +59 -0
- package/src/main/__tests__/scheduler-reconcile-invalid-repair.test.cjs +203 -0
- package/src/main/__tests__/scheduler-reconcile-quarantine.test.cjs +196 -0
- package/src/main/agentLibrary.cjs +40 -2
- package/src/main/index.cjs +2 -0
- package/src/main/ipcSchemas.cjs +60 -0
- package/src/main/lib/localAdminHttp.cjs +10 -3
- package/src/main/lib/prdAdminRoutes.cjs +175 -0
- package/src/main/lib/prdCreate.cjs +37 -2
- package/src/main/lib/prdFrontmatter.cjs +179 -1
- package/src/main/lib/prdMigration.cjs +82 -5
- package/src/main/lib/queueStore.cjs +41 -7
- package/src/main/lib/scheduleJobSchema.cjs +114 -0
- package/src/main/lib/scheduleJobTransitions.cjs +164 -0
- package/src/main/scheduler/prdParser.cjs +7 -0
- package/src/main/scheduler.cjs +649 -137
- package/src/preload/api.d.ts +54 -2
- package/src/preload/index.cjs +12 -0
- package/dist/assets/AgentLibrary-9KJ4fedH.js +0 -1
- package/dist/assets/Scheduler-DfoTegGG.js +0 -14
- /package/plugins/session-manager-dev/skills/builder/{4-report → 5-report}/SKILL.md +0 -0
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{X as x,I as o,S as j,a7 as P}from"./index-BfPVknuV.js";function re({node:e,targetScope:t,onOverride:r,schema:n,rootLabel:m}){const[c,f]=x.useState(""),[d,l]=x.useState(!0),g=[],i=e.kind==="object"&&Object.keys(e.children).length===0,h=((n==null?void 0:n.rootKeys())??[]).length>0;return o.jsxs("div",{className:"h-full flex flex-col",children:[o.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:[o.jsxs("span",{className:"text-fg-faint",children:["merged · overrides → ",o.jsx("span",{className:"text-fg-dim",children:j[t].label})]}),h&&o.jsxs("label",{className:"flex items-center gap-1 text-fg-faint cursor-pointer",children:[o.jsx("input",{type:"checkbox",checked:d,onChange:s=>l(s.target.checked),className:"accent-accent"}),"show unset keys"]}),o.jsx("div",{className:"flex-1"}),o.jsx("input",{value:c,onChange:s=>f(s.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"})]}),o.jsx("div",{className:"flex-1 overflow-auto px-3 py-2 font-mono text-xs",children:i&&!d?o.jsx("div",{className:"text-fg-faint italic px-2 py-4",children:"no settings resolved — all scope files empty or missing"}):o.jsx(O,{node:e,path:g,label:m??"(root)",targetScope:t,onOverride:r,filter:c,depth:0,schema:n,showGhosts:d,defaultOpen:!0})})]})}function O(e){return e.node.kind==="object"?o.jsx(D,{...e,node:e.node}):e.node.kind==="array"?o.jsx(R,{...e,node:e.node}):o.jsx($,{...e,node:e.node})}function L(e,t){return t.trim()?e.toLowerCase().includes(t.toLowerCase()):!0}function w(e,t,r){return!!(!r.trim()||e.some(n=>L(n,r))||t!=null&&t.description&&L(t.description,r))}function D({node:e,path:t,label:r,targetScope:n,onOverride:m,filter:c,depth:f,schema:d,showGhosts:l,defaultOpen:g}){const[i,b]=x.useState(g??f<2),h=(d==null?void 0:d.at(t))??null,s=new Set(Object.keys(e.children)),a=l?(h==null?void 0:h.knownChildren)??[]:[],u=Array.from(new Set([...s,...a])).sort(),p=x.useMemo(()=>c.trim()?u.filter(y=>{const v=(d==null?void 0:d.at([...t,y]))??null;return w([...t,y],v,c)?!0:s.has(y)?N(e.children[y],[...t,y],c,d):!1}):u,[u.join(","),c,e,t.join("."),d]);if(c.trim()&&p.length===0&&!w(t,h,c))return null;if(t.length===0)return o.jsx("div",{children:p.map(y=>k(y))});return o.jsxs("div",{children:[o.jsxs("div",{className:"flex items-center gap-1 py-0.5 hover:bg-bg-elev/50 rounded cursor-pointer",style:{paddingLeft:f*14},onClick:()=>b(!i),children:[o.jsx("span",{className:"text-fg-faint w-3 shrink-0",children:i?"▾":"▸"}),o.jsx("span",{className:"text-fg",children:r}),o.jsxs("span",{className:"text-fg-faint",children:[" {",s.size,a.length>s.size?`/${new Set([...s,...a]).size}`:"","}"]}),(h==null?void 0:h.description)&&o.jsxs("span",{className:"text-fg-faint truncate max-w-md",title:h.description,children:["— ",h.description]})]}),i&&p.map(y=>k(y))]});function k(y){if(s.has(y))return o.jsx(O,{node:e.children[y],path:[...t,y],label:y,targetScope:n,onOverride:m,filter:c,depth:f+1,schema:d,showGhosts:l},y);const v=(d==null?void 0:d.at([...t,y]))??null;return v?o.jsx(_,{path:[...t,y],label:y,info:v,targetScope:n,onSet:m,depth:f+1,filter:c},y):null}}function N(e,t,r,n){const m=(n==null?void 0:n.at(t))??null;if(w(t,m,r))return!0;if(e.kind!=="object")return!1;for(const c of Object.keys(e.children))if(N(e.children[c],[...t,c],r,n))return!0;return!1}function R({node:e,path:t,label:r,filter:n,depth:m,schema:c}){const[f,d]=x.useState(!0),l=(c==null?void 0:c.at(t))??null;return w(t,l,n)?o.jsxs("div",{children:[o.jsxs("div",{className:"flex items-center gap-1 py-0.5 hover:bg-bg-elev/50 rounded cursor-pointer",style:{paddingLeft:m*14},onClick:()=>d(!f),children:[o.jsx("span",{className:"text-fg-faint w-3 shrink-0",children:f?"▾":"▸"}),o.jsx("span",{className:"text-fg",children:r}),o.jsxs("span",{className:"text-fg-faint",children:[" [",e.items.length,"]"]}),o.jsx(S,{tone:"warn",children:"accumulated"}),(l==null?void 0:l.description)&&o.jsxs("span",{className:"text-fg-faint truncate max-w-md",title:l.description,children:["— ",l.description]})]}),f&&e.items.map((g,i)=>o.jsxs("div",{className:"flex items-start gap-2 py-0.5",style:{paddingLeft:(m+1)*14},children:[o.jsx("span",{className:"text-fg-faint w-3 shrink-0"}),o.jsxs("span",{className:"text-fg-faint",children:[i,":"]}),o.jsx("span",{className:"text-fg-dim truncate max-w-xl",children:E(g.value)}),o.jsx(M,{scope:g.fromScope})]},i))]}):null}function $({node:e,path:t,label:r,targetScope:n,onOverride:m,filter:c,depth:f,schema:d}){const[l,g]=x.useState(!1),i=(d==null?void 0:d.at(t))??null;if(!w(t,i,c))return null;const b=e.winner!==n,h=e.shadowed.length>0;return o.jsxs("div",{children:[o.jsxs("div",{className:"group flex items-center gap-2 py-0.5 hover:bg-bg-elev/50 rounded",style:{paddingLeft:f*14},children:[o.jsx("span",{className:`w-3 shrink-0 ${h?"text-fg-faint cursor-pointer":""}`,onClick:()=>h&&g(!l),children:h?l?"▾":"▸":""}),o.jsxs("span",{className:"text-fg",children:[r,":"]}),o.jsx("span",{className:"text-fg-dim truncate max-w-md",children:E(e.value)}),o.jsx(M,{scope:e.winner}),(i==null?void 0:i.deprecated)&&o.jsx(S,{tone:"warn",children:"deprecated"}),(i==null?void 0:i.default)!==void 0&&I(e.value,i.default)&&o.jsx(S,{tone:"dim",children:"= default"}),e.typeMismatch&&o.jsx("span",{className:"text-yellow-500/80",title:"shadowed scopes have a different value type",children:"⚠"}),(i==null?void 0:i.description)&&o.jsxs("span",{className:"text-fg-faint truncate max-w-md",title:i.description,children:["— ",i.description]}),o.jsx("div",{className:"flex-1"}),(i==null?void 0:i.enum)&&o.jsx(T,{values:i.enum}),o.jsx("button",{disabled:!b,onClick:()=>m(t,e.value),className:`opacity-0 group-hover:opacity-100 px-1.5 py-0 text-[10px] border rounded transition-opacity ${b?"border-accent/50 text-accent hover:bg-accent hover:text-bg":"border-line text-fg-faint cursor-not-allowed"}`,title:b?`copy into ${j[n].label} draft`:`already winning in ${j[n].label}`,children:"override"})]}),l&&e.shadowed.map((s,a)=>o.jsxs("div",{className:"flex items-center gap-2 py-0.5 text-fg-faint line-through",style:{paddingLeft:(f+1)*14+12},children:[o.jsx("span",{children:"shadowed:"}),o.jsx("span",{className:"truncate max-w-xl",children:E(s.value)}),o.jsx(M,{scope:s.scope,dim:!0})]},a))]})}function _({path:e,label:t,info:r,targetScope:n,onSet:m,depth:c,filter:f}){if(!w(e,r,f))return null;const d=r.default!==void 0?r.default:H(r.type),l=Array.isArray(r.type)?r.type.join("|"):r.type??"?";return o.jsxs("div",{className:"group flex items-center gap-2 py-0.5 hover:bg-bg-elev/50 rounded opacity-60",style:{paddingLeft:c*14},children:[o.jsx("span",{className:"w-3 shrink-0"}),o.jsx("span",{className:"text-fg-dim",children:t}),o.jsx(S,{tone:"dim",children:l}),r.required&&o.jsx(S,{tone:"warn",children:"required"}),r.default!==void 0&&o.jsxs("span",{className:"text-fg-faint",children:["default: ",E(r.default)]}),r.description&&o.jsxs("span",{className:"text-fg-faint truncate max-w-md",title:r.description,children:["— ",r.description]}),o.jsx("div",{className:"flex-1"}),r.enum&&o.jsx(T,{values:r.enum}),o.jsx("button",{onClick:()=>m(e,d),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 ${j[n].label} draft`,children:"set"})]})}function I(e,t){return e===t?!0:typeof e!=typeof t?!1:e&&t&&typeof e=="object"?JSON.stringify(e)===JSON.stringify(t):!1}function H(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 E(e){if(typeof e=="string")return JSON.stringify(e);if(e===null)return"null";if(typeof e=="object"){const t=JSON.stringify(e);return t.length>100?t.slice(0,100)+"…":t}return String(e)}function M({scope:e,dim:t}){const r=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 o.jsx("span",{className:`text-[10px] px-1 py-0 rounded border uppercase tracking-wide shrink-0 ${r} ${t?"opacity-60":""}`,children:j[e].label})}function S({children:e,tone:t="default"}){const r={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"}[t];return o.jsx("span",{className:`text-[10px] px-1 py-0 rounded border uppercase tracking-wide shrink-0 ${r}`,children:e})}function T({values:e}){const t=e.map(r=>String(r)).join(" | ");return o.jsxs("span",{className:"text-[10px] text-fg-faint truncate max-w-xs",title:`allowed: ${t}`,children:["∈ ",t.length>30?t.slice(0,30)+"…":t]})}function ie(e,t,r){const n=P(l=>l.files),m=P(l=>l.loadJson),c=P(l=>l.watchFile),f=P(l=>l.unwatchFile),d=x.useMemo(()=>{const l={};for(const g of e.scopes){const i=e.resolve(g,t??"",r);i&&(l[g]=i)}return l},[e,t,r]);return x.useEffect(()=>{const l=Object.values(d).filter(Boolean);return l.forEach(g=>{n[g]||m(g),c(g)}),()=>{l.forEach(g=>f(g))}},[JSON.stringify(d)]),d}const q=[];function C(e){return Array.isArray(e)?"array":e!==null&&typeof e=="object"?"object":"scalar"}function ne(e){const t=e.filter(r=>r.data!==void 0);return t.length===0?{kind:"object",children:{}}:U(t,[])}function U(e,t){const r=q.includes(t.join(".")),n=e.every(i=>C(i.data)==="object"),m=e.every(i=>C(i.data)==="array");if(n){const i=new Set;for(const h of e)for(const s of Object.keys(h.data))i.add(s);const b={};for(const h of i){const s=e.filter(a=>h in a.data).map(a=>({scope:a.scope,data:a.data[h]}));b[h]=U(s,[...t,h])}return{kind:"object",children:b}}if(m&&!r){const i=[];for(const b of[...e].reverse())for(const h of b.data)i.push({value:h,fromScope:b.scope,index:i.length});return{kind:"array",items:i}}const c=[...e].reverse(),f=c[0],d=c.slice(1).map(i=>({scope:i.scope,value:i.data})),l=C(f.data),g=d.some(i=>C(i.value)!==l);return{kind:"leaf",value:f.data,winner:f.scope,shadowed:d,...g?{typeMismatch:!0}:{}}}function B(e,t){if(t.length===0)return e;if(e.kind!=="object")return null;const[r,...n]=t,m=e.children[r];return m?B(m,n):null}function G(e,t,r){if(t.length===0)return r;const[n,...m]=t,c=e&&typeof e=="object"&&!Array.isArray(e)?{...e}:{};return c[n]=G(c[n],m,r),c}const F=["user","project","local"];function ae(e,t){const r=[];for(const n of F){const m=t[n];if(!m)continue;const c=e[m];if(!c||!c.exists)continue;const f=c.draftRaw??"";if(f.trim())try{r.push({scope:n,data:JSON.parse(f)})}catch{}}return r}const W="http://json-schema.org/draft-07/schema#",K="https://json.schemastore.org/claude-code-settings.json",J={permissionRule:{type:"string",description:`Tool permission rule.
|
|
1
|
+
import{Y as x,K as o,S as j,a8 as P}from"./index-TejhHSzN.js";function re({node:e,targetScope:t,onOverride:r,schema:n,rootLabel:m}){const[c,f]=x.useState(""),[d,l]=x.useState(!0),g=[],i=e.kind==="object"&&Object.keys(e.children).length===0,h=((n==null?void 0:n.rootKeys())??[]).length>0;return o.jsxs("div",{className:"h-full flex flex-col",children:[o.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:[o.jsxs("span",{className:"text-fg-faint",children:["merged · overrides → ",o.jsx("span",{className:"text-fg-dim",children:j[t].label})]}),h&&o.jsxs("label",{className:"flex items-center gap-1 text-fg-faint cursor-pointer",children:[o.jsx("input",{type:"checkbox",checked:d,onChange:s=>l(s.target.checked),className:"accent-accent"}),"show unset keys"]}),o.jsx("div",{className:"flex-1"}),o.jsx("input",{value:c,onChange:s=>f(s.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"})]}),o.jsx("div",{className:"flex-1 overflow-auto px-3 py-2 font-mono text-xs",children:i&&!d?o.jsx("div",{className:"text-fg-faint italic px-2 py-4",children:"no settings resolved — all scope files empty or missing"}):o.jsx(O,{node:e,path:g,label:m??"(root)",targetScope:t,onOverride:r,filter:c,depth:0,schema:n,showGhosts:d,defaultOpen:!0})})]})}function O(e){return e.node.kind==="object"?o.jsx(D,{...e,node:e.node}):e.node.kind==="array"?o.jsx(R,{...e,node:e.node}):o.jsx($,{...e,node:e.node})}function L(e,t){return t.trim()?e.toLowerCase().includes(t.toLowerCase()):!0}function w(e,t,r){return!!(!r.trim()||e.some(n=>L(n,r))||t!=null&&t.description&&L(t.description,r))}function D({node:e,path:t,label:r,targetScope:n,onOverride:m,filter:c,depth:f,schema:d,showGhosts:l,defaultOpen:g}){const[i,b]=x.useState(g??f<2),h=(d==null?void 0:d.at(t))??null,s=new Set(Object.keys(e.children)),a=l?(h==null?void 0:h.knownChildren)??[]:[],u=Array.from(new Set([...s,...a])).sort(),p=x.useMemo(()=>c.trim()?u.filter(y=>{const v=(d==null?void 0:d.at([...t,y]))??null;return w([...t,y],v,c)?!0:s.has(y)?N(e.children[y],[...t,y],c,d):!1}):u,[u.join(","),c,e,t.join("."),d]);if(c.trim()&&p.length===0&&!w(t,h,c))return null;if(t.length===0)return o.jsx("div",{children:p.map(y=>k(y))});return o.jsxs("div",{children:[o.jsxs("div",{className:"flex items-center gap-1 py-0.5 hover:bg-bg-elev/50 rounded cursor-pointer",style:{paddingLeft:f*14},onClick:()=>b(!i),children:[o.jsx("span",{className:"text-fg-faint w-3 shrink-0",children:i?"▾":"▸"}),o.jsx("span",{className:"text-fg",children:r}),o.jsxs("span",{className:"text-fg-faint",children:[" {",s.size,a.length>s.size?`/${new Set([...s,...a]).size}`:"","}"]}),(h==null?void 0:h.description)&&o.jsxs("span",{className:"text-fg-faint truncate max-w-md",title:h.description,children:["— ",h.description]})]}),i&&p.map(y=>k(y))]});function k(y){if(s.has(y))return o.jsx(O,{node:e.children[y],path:[...t,y],label:y,targetScope:n,onOverride:m,filter:c,depth:f+1,schema:d,showGhosts:l},y);const v=(d==null?void 0:d.at([...t,y]))??null;return v?o.jsx(_,{path:[...t,y],label:y,info:v,targetScope:n,onSet:m,depth:f+1,filter:c},y):null}}function N(e,t,r,n){const m=(n==null?void 0:n.at(t))??null;if(w(t,m,r))return!0;if(e.kind!=="object")return!1;for(const c of Object.keys(e.children))if(N(e.children[c],[...t,c],r,n))return!0;return!1}function R({node:e,path:t,label:r,filter:n,depth:m,schema:c}){const[f,d]=x.useState(!0),l=(c==null?void 0:c.at(t))??null;return w(t,l,n)?o.jsxs("div",{children:[o.jsxs("div",{className:"flex items-center gap-1 py-0.5 hover:bg-bg-elev/50 rounded cursor-pointer",style:{paddingLeft:m*14},onClick:()=>d(!f),children:[o.jsx("span",{className:"text-fg-faint w-3 shrink-0",children:f?"▾":"▸"}),o.jsx("span",{className:"text-fg",children:r}),o.jsxs("span",{className:"text-fg-faint",children:[" [",e.items.length,"]"]}),o.jsx(S,{tone:"warn",children:"accumulated"}),(l==null?void 0:l.description)&&o.jsxs("span",{className:"text-fg-faint truncate max-w-md",title:l.description,children:["— ",l.description]})]}),f&&e.items.map((g,i)=>o.jsxs("div",{className:"flex items-start gap-2 py-0.5",style:{paddingLeft:(m+1)*14},children:[o.jsx("span",{className:"text-fg-faint w-3 shrink-0"}),o.jsxs("span",{className:"text-fg-faint",children:[i,":"]}),o.jsx("span",{className:"text-fg-dim truncate max-w-xl",children:E(g.value)}),o.jsx(M,{scope:g.fromScope})]},i))]}):null}function $({node:e,path:t,label:r,targetScope:n,onOverride:m,filter:c,depth:f,schema:d}){const[l,g]=x.useState(!1),i=(d==null?void 0:d.at(t))??null;if(!w(t,i,c))return null;const b=e.winner!==n,h=e.shadowed.length>0;return o.jsxs("div",{children:[o.jsxs("div",{className:"group flex items-center gap-2 py-0.5 hover:bg-bg-elev/50 rounded",style:{paddingLeft:f*14},children:[o.jsx("span",{className:`w-3 shrink-0 ${h?"text-fg-faint cursor-pointer":""}`,onClick:()=>h&&g(!l),children:h?l?"▾":"▸":""}),o.jsxs("span",{className:"text-fg",children:[r,":"]}),o.jsx("span",{className:"text-fg-dim truncate max-w-md",children:E(e.value)}),o.jsx(M,{scope:e.winner}),(i==null?void 0:i.deprecated)&&o.jsx(S,{tone:"warn",children:"deprecated"}),(i==null?void 0:i.default)!==void 0&&I(e.value,i.default)&&o.jsx(S,{tone:"dim",children:"= default"}),e.typeMismatch&&o.jsx("span",{className:"text-yellow-500/80",title:"shadowed scopes have a different value type",children:"⚠"}),(i==null?void 0:i.description)&&o.jsxs("span",{className:"text-fg-faint truncate max-w-md",title:i.description,children:["— ",i.description]}),o.jsx("div",{className:"flex-1"}),(i==null?void 0:i.enum)&&o.jsx(T,{values:i.enum}),o.jsx("button",{disabled:!b,onClick:()=>m(t,e.value),className:`opacity-0 group-hover:opacity-100 px-1.5 py-0 text-[10px] border rounded transition-opacity ${b?"border-accent/50 text-accent hover:bg-accent hover:text-bg":"border-line text-fg-faint cursor-not-allowed"}`,title:b?`copy into ${j[n].label} draft`:`already winning in ${j[n].label}`,children:"override"})]}),l&&e.shadowed.map((s,a)=>o.jsxs("div",{className:"flex items-center gap-2 py-0.5 text-fg-faint line-through",style:{paddingLeft:(f+1)*14+12},children:[o.jsx("span",{children:"shadowed:"}),o.jsx("span",{className:"truncate max-w-xl",children:E(s.value)}),o.jsx(M,{scope:s.scope,dim:!0})]},a))]})}function _({path:e,label:t,info:r,targetScope:n,onSet:m,depth:c,filter:f}){if(!w(e,r,f))return null;const d=r.default!==void 0?r.default:H(r.type),l=Array.isArray(r.type)?r.type.join("|"):r.type??"?";return o.jsxs("div",{className:"group flex items-center gap-2 py-0.5 hover:bg-bg-elev/50 rounded opacity-60",style:{paddingLeft:c*14},children:[o.jsx("span",{className:"w-3 shrink-0"}),o.jsx("span",{className:"text-fg-dim",children:t}),o.jsx(S,{tone:"dim",children:l}),r.required&&o.jsx(S,{tone:"warn",children:"required"}),r.default!==void 0&&o.jsxs("span",{className:"text-fg-faint",children:["default: ",E(r.default)]}),r.description&&o.jsxs("span",{className:"text-fg-faint truncate max-w-md",title:r.description,children:["— ",r.description]}),o.jsx("div",{className:"flex-1"}),r.enum&&o.jsx(T,{values:r.enum}),o.jsx("button",{onClick:()=>m(e,d),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 ${j[n].label} draft`,children:"set"})]})}function I(e,t){return e===t?!0:typeof e!=typeof t?!1:e&&t&&typeof e=="object"?JSON.stringify(e)===JSON.stringify(t):!1}function H(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 E(e){if(typeof e=="string")return JSON.stringify(e);if(e===null)return"null";if(typeof e=="object"){const t=JSON.stringify(e);return t.length>100?t.slice(0,100)+"…":t}return String(e)}function M({scope:e,dim:t}){const r=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 o.jsx("span",{className:`text-[10px] px-1 py-0 rounded border uppercase tracking-wide shrink-0 ${r} ${t?"opacity-60":""}`,children:j[e].label})}function S({children:e,tone:t="default"}){const r={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"}[t];return o.jsx("span",{className:`text-[10px] px-1 py-0 rounded border uppercase tracking-wide shrink-0 ${r}`,children:e})}function T({values:e}){const t=e.map(r=>String(r)).join(" | ");return o.jsxs("span",{className:"text-[10px] text-fg-faint truncate max-w-xs",title:`allowed: ${t}`,children:["∈ ",t.length>30?t.slice(0,30)+"…":t]})}function ie(e,t,r){const n=P(l=>l.files),m=P(l=>l.loadJson),c=P(l=>l.watchFile),f=P(l=>l.unwatchFile),d=x.useMemo(()=>{const l={};for(const g of e.scopes){const i=e.resolve(g,t??"",r);i&&(l[g]=i)}return l},[e,t,r]);return x.useEffect(()=>{const l=Object.values(d).filter(Boolean);return l.forEach(g=>{n[g]||m(g),c(g)}),()=>{l.forEach(g=>f(g))}},[JSON.stringify(d)]),d}const q=[];function C(e){return Array.isArray(e)?"array":e!==null&&typeof e=="object"?"object":"scalar"}function ne(e){const t=e.filter(r=>r.data!==void 0);return t.length===0?{kind:"object",children:{}}:U(t,[])}function U(e,t){const r=q.includes(t.join(".")),n=e.every(i=>C(i.data)==="object"),m=e.every(i=>C(i.data)==="array");if(n){const i=new Set;for(const h of e)for(const s of Object.keys(h.data))i.add(s);const b={};for(const h of i){const s=e.filter(a=>h in a.data).map(a=>({scope:a.scope,data:a.data[h]}));b[h]=U(s,[...t,h])}return{kind:"object",children:b}}if(m&&!r){const i=[];for(const b of[...e].reverse())for(const h of b.data)i.push({value:h,fromScope:b.scope,index:i.length});return{kind:"array",items:i}}const c=[...e].reverse(),f=c[0],d=c.slice(1).map(i=>({scope:i.scope,value:i.data})),l=C(f.data),g=d.some(i=>C(i.value)!==l);return{kind:"leaf",value:f.data,winner:f.scope,shadowed:d,...g?{typeMismatch:!0}:{}}}function B(e,t){if(t.length===0)return e;if(e.kind!=="object")return null;const[r,...n]=t,m=e.children[r];return m?B(m,n):null}function G(e,t,r){if(t.length===0)return r;const[n,...m]=t,c=e&&typeof e=="object"&&!Array.isArray(e)?{...e}:{};return c[n]=G(c[n],m,r),c}const F=["user","project","local"];function ae(e,t){const r=[];for(const n of F){const m=t[n];if(!m)continue;const c=e[m];if(!c||!c.exists)continue;const f=c.draftRaw??"";if(f.trim())try{r.push({scope:n,data:JSON.parse(f)})}catch{}}return r}const W="http://json-schema.org/draft-07/schema#",K="https://json.schemastore.org/claude-code-settings.json",J={permissionRule:{type:"string",description:`Tool permission rule.
|
|
2
2
|
See https://code.claude.com/docs/en/settings#permission-rule-syntax
|
|
3
3
|
See https://code.claude.com/docs/en/settings#tools-available-to-claude for full list of tools available to Claude.`,pattern:"^((Agent|Bash|Edit|ExitPlanMode|Glob|Grep|KillShell|LSP|NotebookEdit|Read|Skill|TaskCreate|TaskGet|TaskList|TaskOutput|TaskStop|TaskUpdate|TodoWrite|ToolSearch|WebFetch|WebSearch|Write)(\\((?=.*[^)*?])[^)]+\\))?|mcp__.*)$",examples:["Bash","Bash(npm run build)","Bash(git commit *)","Bash(npm run *)","Bash(ls*)","Bash(git * main)","Edit","Edit(/src/**/*.ts)","Read(./.env)","Read(./secrets/**)","Read(//Users/alice/secrets/**)","Read(~/Documents/*.pdf)","Agent(Explore)","WebFetch","WebFetch(domain:example.com)","mcp__puppeteer","mcp__github__search_repositories"]},hookCommand:{anyOf:[{type:"object",description:"Bash command hook",additionalProperties:!1,required:["type","command"],properties:{type:{type:"string",description:"Hook type",const:"command"},command:{type:"string",description:"Shell command to execute",minLength:1},timeout:{type:"number",description:"Optional timeout in seconds",exclusiveMinimum:0},async:{type:"boolean",description:"Run this hook asynchronously without blocking Claude Code"},statusMessage:{type:"string",description:"Custom spinner message displayed while the hook runs"}}},{type:"object",description:"LLM prompt hook. See https://code.claude.com/docs/en/hooks#prompt-based-hooks",additionalProperties:!1,required:["type","prompt"],properties:{type:{type:"string",description:"Hook type",const:"prompt"},prompt:{type:"string",description:"Prompt to evaluate with LLM. Use $ARGUMENTS placeholder for hook input JSON.",minLength:1},model:{type:"string",description:"Model to use for evaluation. Defaults to a fast model"},timeout:{type:"number",description:"Optional timeout in seconds (default: 30)",exclusiveMinimum:0},statusMessage:{type:"string",description:"Custom spinner message displayed while the hook runs"}}},{type:"object",description:"Agent hook with multi-turn tool access for verification. See https://code.claude.com/docs/en/hooks#agent-based-hooks",additionalProperties:!1,required:["type","prompt"],properties:{type:{type:"string",description:"Hook type",const:"agent"},prompt:{type:"string",description:"Prompt describing what to verify. Use $ARGUMENTS placeholder for hook input JSON.",minLength:1},model:{type:"string",description:"Model to use for evaluation. Defaults to a fast model"},timeout:{type:"number",description:"Optional timeout in seconds (default: 60)",exclusiveMinimum:0},statusMessage:{type:"string",description:"Custom spinner message displayed while the hook runs"}}},{type:"object",description:"HTTP webhook hook. POST JSON to a URL and receive JSON response. See https://code.claude.com/docs/en/hooks#http-hooks",additionalProperties:!1,required:["type","url"],properties:{type:{type:"string",description:"Hook type",const:"http"},url:{type:"string",description:"URL to POST hook input JSON to. Endpoint must accept POST requests and return JSON.",minLength:1},headers:{type:"object",additionalProperties:{type:"string"},description:"Custom HTTP headers (e.g., Authorization: Bearer token). Values support $VAR_NAME or ${VAR_NAME} interpolation."},allowedEnvVars:{type:"array",items:{type:"string",minLength:1},description:"List of environment variable names permitted for interpolation in headers. If not set, no env var interpolation is allowed."},timeout:{type:"number",description:"Optional timeout in seconds (default: 30)",exclusiveMinimum:0},statusMessage:{type:"string",description:"Custom spinner message displayed while the hook runs"}}}]},hookMatcher:{type:"object",description:"Hook matcher configuration with multiple hooks",additionalProperties:!1,required:["hooks"],properties:{matcher:{type:"string",description:"Optional pattern to match event contexts, case-sensitive. Behavior depends on event type. See https://code.claude.com/docs/en/hooks#matcher-patterns for event-specific details and examples"},hooks:{type:"array",description:"Array of hooks to execute",items:{$ref:"#/$defs/hookCommand"}}}}},V="Configuration settings for Claude Code. Learn more: https://code.claude.com/docs/en/settings",z=!0,Y=!0,Z="object",X=JSON.parse(`{"$schema":{"type":"string","description":"JSON Schema reference for Claude Code settings"},"apiKeyHelper":{"type":"string","description":"Path to a script that outputs authentication values","examples":["/bin/generate_temp_api_key.sh"],"minLength":1},"autoMemoryEnabled":{"type":"boolean","description":"Enable automatic memory saves that capture useful context to .claude/memory/. Also configurable via CLAUDE_CODE_DISABLE_AUTO_MEMORY environment variable (set to 1 to disable, 0 to enable). See https://code.claude.com/docs/en/memory#auto-memory","default":true},"autoUpdatesChannel":{"type":"string","enum":["stable","latest"],"description":"Release channel to follow for updates. Use \\"stable\\" for a version that is typically about one week old and skips versions with major regressions, or \\"latest\\" (default) for the most recent release. Set DISABLE_AUTOUPDATER=1 to disable updates entirely.","default":"latest"},"awsCredentialExport":{"type":"string","description":"Path to a script that exports AWS credentials","examples":["/bin/generate_aws_grant.sh"],"minLength":1},"awsAuthRefresh":{"type":"string","description":"Path to a script that refreshes AWS authentication","examples":["aws sso login --profile myprofile"],"minLength":1},"claudeMdExcludes":{"type":"array","items":{"type":"string","minLength":1},"description":"Glob patterns for CLAUDE.md files to exclude from loading. Useful in monorepos to skip irrelevant instructions from other teams. Patterns match against absolute file paths. Arrays merge across settings layers. Managed policy CLAUDE.md files cannot be excluded. See https://code.claude.com/docs/en/memory#exclude-specific-claudemd-files","examples":[["**/monorepo/CLAUDE.md","/home/user/monorepo/other-team/.claude/rules/**"]]},"cleanupPeriodDays":{"type":"integer","minimum":0,"description":"Number of days to retain chat transcripts (0 to disable cleanup)","examples":[20,30,60],"default":30},"env":{"type":"object","additionalProperties":false,"description":"Environment variables to set for Claude Code sessions. Many environment variables provide settings dimensions not available as dedicated settings.json properties (e.g., thinking tokens, prompt caching, bash timeouts, shell configuration). See https://code.claude.com/docs/en/settings#environment-variables for the full list.\\nUNDOCUMENTED: CLAUDE_CODE_PLUGIN_GIT_TIMEOUT_MS (plugin marketplace git timeout in ms, default 120000, see https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md#2151).\\nUNDOCUMENTED: ENABLE_CLAUDEAI_MCP_SERVERS (set to false to opt out of claude.ai MCP servers, see https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md#2163).","examples":[{"ANTHROPIC_MODEL":"claude-opus-4-1","ANTHROPIC_SMALL_FAST_MODEL":"claude-3-5-haiku-latest"}],"default":{},"patternProperties":{"^[A-Z_][A-Z0-9_]*$":{"type":"string","description":"Environment variable value"}}},"attribution":{"type":"object","description":"Customize attribution for git commits and pull requests. See https://code.claude.com/docs/en/settings#attribution-settings","additionalProperties":false,"properties":{"commit":{"type":"string","description":"Attribution for git commits, including any trailers. Empty string hides commit attribution"},"pr":{"type":"string","description":"Attribution for pull request descriptions. Empty string hides pull request attribution"}}},"includeGitInstructions":{"type":"boolean","description":"Include built-in git commit and PR workflow instructions in Claude's system prompt. Also configurable via CLAUDE_CODE_DISABLE_GIT_INSTRUCTIONS environment variable (set to 1 to disable). See https://code.claude.com/docs/en/settings#available-settings","default":true},"includeCoAuthoredBy":{"type":"boolean","description":"DEPRECATED. Use 'attribution' instead. Whether to include the co-authored-by Claude byline in git commits and pull requests (default: true)","default":true},"plansDirectory":{"type":"string","description":"Customize where plan files are stored. Path is relative to project root (default: ~/.claude/plans)","default":"~/.claude/plans","examples":["./plans"]},"respectGitignore":{"type":"boolean","description":"Control whether the @ file picker respects .gitignore patterns. When true (default), files matching .gitignore patterns are excluded from suggestions","default":true},"permissions":{"type":"object","properties":{"allow":{"type":"array","items":{"$ref":"#/$defs/permissionRule"},"description":"List of permission rules for allowed operations","uniqueItems":true},"deny":{"type":"array","items":{"$ref":"#/$defs/permissionRule"},"description":"List of permission rules for denied operations","uniqueItems":true},"ask":{"type":"array","items":{"$ref":"#/$defs/permissionRule"},"description":"List of permission rules that should always prompt for confirmation","uniqueItems":true},"defaultMode":{"type":"string","enum":["acceptEdits","bypassPermissions","default","delegate","dontAsk","plan"],"description":"Default permission mode.\\n\\"default\\": prompts on first use.\\n\\"acceptEdits\\": auto-accepts file edits.\\n\\"plan\\": read-only, no modifications.\\nUNDOCUMENTED. \\"delegate\\": coordination-only for agent team leads (agent teams are experimental; enable via CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS).\\n\\"dontAsk\\": auto-denies unless pre-approved via permissions.\\n\\"bypassPermissions\\": skips all prompts (use only in isolated environments).\\nSee https://code.claude.com/docs/en/permissions"},"disableBypassPermissionsMode":{"type":"string","enum":["disable"],"description":"Disable the ability to bypass permission prompts"},"additionalDirectories":{"type":"array","items":{"type":"string","minLength":1},"description":"Additional directories to include in the permission scope","examples":[["//Users/alice/Documents","~/projects"]],"uniqueItems":true}},"additionalProperties":false,"description":"Tool usage permissions configuration.\\nSee https://code.claude.com/docs/en/permissions and https://code.claude.com/docs/en/settings#permission-settings\\nSee https://code.claude.com/docs/en/settings#tools-available-to-claude for full list of tools available to Claude.","examples":[{"allow":["Bash(git add:*)"],"ask":["Bash(gh pr create:*)","Bash(git commit:*)"],"deny":["Read(*.env)","Bash(rm:*)","Bash(curl:*)"],"defaultMode":"default"}]},"language":{"type":"string","description":"Preferred language for Claude's responses","examples":["japanese","spanish","french"]},"model":{"type":"string","enum":["opus","sonnet","haiku","default"],"description":"Override the default model used by Claude Code. Accepts a short alias (opus|sonnet|haiku) or a full model ID. For finer control, use environment variables: ANTHROPIC_MODEL (runtime override), ANTHROPIC_DEFAULT_OPUS_MODEL, ANTHROPIC_DEFAULT_SONNET_MODEL, ANTHROPIC_DEFAULT_HAIKU_MODEL (per-class pinning), CLAUDE_CODE_SUBAGENT_MODEL (subagent model). See https://code.claude.com/docs/en/model-config"},"availableModels":{"type":"array","items":{"type":"string"},"description":"Restrict which models users can select. When defined at multiple settings levels (user, project, etc.), arrays are merged and deduplicated. See https://code.claude.com/docs/en/model-config#restrict-model-selection","examples":[["sonnet","haiku"]]},"modelOverrides":{"type":"object","additionalProperties":{"type":"string"},"description":"Map Anthropic model IDs to provider-specific model IDs such as Bedrock inference profile ARNs, Vertex AI version names, or Foundry deployment names. Each model picker entry uses its mapped value when calling the provider API. Unknown keys are ignored. See https://code.claude.com/docs/en/model-config#override-model-ids-per-version","examples":[{"claude-opus-4-6":"arn:aws:bedrock:us-east-2:123456789012:application-inference-profile/opus-prod"}]},"effortLevel":{"type":"string","enum":["low","medium","high"],"description":"Control Opus 4.6 adaptive reasoning effort. Lower effort is faster and cheaper for straightforward tasks, higher effort provides deeper reasoning. Defaults vary by model and plan (Opus 4.6 defaults to medium for Max and Team subscribers). Use /effort auto to reset to model default. Also configurable via CLAUDE_CODE_EFFORT_LEVEL environment variable. See https://code.claude.com/docs/en/model-config#adjust-effort-level"},"fastMode":{"type":"boolean","description":"Enable fast mode for Opus 4.6 (research preview). Fast mode uses the same model with 2.5x faster output at higher per-token cost. Requires extra usage enabled. Alternatively, toggle with /fast command. See https://code.claude.com/docs/en/fast-mode","default":false},"fastModePerSessionOptIn":{"type":"boolean","description":"Require per-session opt-in for fast mode. When true, fast mode does not persist across sessions and users must enable it with /fast each session. Useful for controlling costs. See https://code.claude.com/docs/en/fast-mode","default":false},"feedbackSurveyRate":{"type":"number","minimum":0,"maximum":1,"description":"Probability (0–1) that the session quality survey appears when eligible. A value of 0.05 means 5% of eligible sessions. See https://code.claude.com/docs/en/settings","examples":[0.05]},"editorMode":{"type":"string","enum":["normal","vim"],"default":"normal","description":"Editor input mode for the Claude Code terminal prompt. 'vim' enables modal editing (Esc for normal mode, i for insert). See https://code.claude.com/docs/en/settings"},"skillOverrides":{"type":"object","additionalProperties":{"type":"string","enum":["on","name-only","user-invocable-only","off"]},"description":"Per-skill availability override map. Keys are skill names; values are one of 'on' (default), 'name-only' (skill name listed but not auto-loaded), 'user-invocable-only' (load only when user explicitly invokes), or 'off' (hidden). Requires Claude Code v2.1.129+. See https://code.claude.com/docs/en/settings","examples":[{"playwright-debug":"user-invocable-only","init":"off"}]},"disableAgentView":{"type":"boolean","default":false,"description":"Disable the Agent View feature (read-only inspection of sub-agent activity). Useful when administering managed deployments. Requires Claude Code v2.1.139+. See https://code.claude.com/docs/en/settings"},"disableRemoteControl":{"type":"boolean","default":false,"description":"Block the \`claude remote-control\` channel that allows external clients to drive this Claude Code instance. Recommended default for shared/CI environments. Requires Claude Code v2.1.128+. See https://code.claude.com/docs/en/settings"},"enableAllProjectMcpServers":{"type":"boolean","description":"Whether to automatically approve all MCP servers in the project. See https://code.claude.com/docs/en/mcp","examples":[true]},"enabledMcpjsonServers":{"type":"array","items":{"type":"string","minLength":1},"description":"List of approved MCP servers from .mcp.json. See https://code.claude.com/docs/en/mcp","examples":[["memory","github"]]},"disabledMcpjsonServers":{"type":"array","items":{"type":"string","minLength":1},"description":"List of rejected MCP servers from .mcp.json. See https://code.claude.com/docs/en/mcp","examples":[["filesystem"]]},"allowedMcpServers":{"type":"array","items":{"anyOf":[{"type":"object","properties":{"serverName":{"type":"string","pattern":"^[a-zA-Z0-9_-]+$","description":"Name of the MCP server that users are allowed to configure"}},"required":["serverName"],"additionalProperties":false},{"type":"object","properties":{"serverCommand":{"type":"array","items":{"type":"string"},"description":"Exact command and arguments used to start stdio servers"}},"required":["serverCommand"],"additionalProperties":false},{"type":"object","properties":{"serverUrl":{"type":"string","description":"URL pattern for remote servers, supports wildcards (e.g., https://*.example.com/*)"}},"required":["serverUrl"],"additionalProperties":false}]},"description":"Enterprise allowlist of MCP servers that can be used. Applies to all scopes including enterprise servers from managed-mcp.json. If undefined, all servers are allowed. If empty array, no servers are allowed. Denylist takes precedence - if a server is on both lists, it is denied. See https://code.claude.com/docs/en/mcp#restriction-options"},"deniedMcpServers":{"type":"array","items":{"anyOf":[{"type":"object","properties":{"serverName":{"type":"string","pattern":"^[a-zA-Z0-9_-]+$","description":"Name of the MCP server that is explicitly blocked"}},"required":["serverName"],"additionalProperties":false},{"type":"object","properties":{"serverCommand":{"type":"array","items":{"type":"string"},"description":"Exact command and arguments used to start stdio servers"}},"required":["serverCommand"],"additionalProperties":false},{"type":"object","properties":{"serverUrl":{"type":"string","description":"URL pattern for remote servers, supports wildcards (e.g., https://*.example.com/*)"}},"required":["serverUrl"],"additionalProperties":false}]},"description":"Enterprise denylist of MCP servers that are explicitly blocked. If a server is on the denylist, it will be blocked across all scopes including enterprise. Denylist takes precedence over allowlist - if a server is on both lists, it is denied. See https://code.claude.com/docs/en/mcp#restriction-options"},"httpHookAllowedEnvVars":{"type":"array","items":{"type":"string","minLength":1},"description":"Allowlist of environment variable names HTTP hooks may interpolate into headers. When set, each hook's effective allowedEnvVars is the intersection with this list. Undefined = no restriction. Arrays merge across settings sources. See https://code.claude.com/docs/en/settings#hook-configuration","examples":[["MY_TOKEN","HOOK_SECRET"]]},"hooks":{"type":"object","additionalProperties":false,"description":"Custom commands to run before/after tool executions. See https://code.claude.com/docs/en/hooks","examples":[{"PostToolUse":[{"matcher":"Edit|Write","hooks":[{"type":"command","command":"prettier --write","timeout":5}]}]}],"properties":{"PreToolUse":{"type":"array","description":"Hooks that run before tool calls","items":{"$ref":"#/$defs/hookMatcher"}},"PostToolUse":{"type":"array","description":"Hooks that run after tool completion","items":{"$ref":"#/$defs/hookMatcher"}},"PostToolUseFailure":{"type":"array","description":"Hooks that run after a tool fails","items":{"$ref":"#/$defs/hookMatcher"}},"PermissionRequest":{"type":"array","description":"Hooks that run when a permission dialog appears","items":{"$ref":"#/$defs/hookMatcher"}},"Notification":{"type":"array","description":"Hooks that trigger on notifications","items":{"$ref":"#/$defs/hookMatcher"}},"UserPromptSubmit":{"type":"array","description":"Hooks that run when a user submits a prompt","items":{"$ref":"#/$defs/hookMatcher"}},"Stop":{"type":"array","description":"Hooks that run when agents finish responding. Does not run on user interrupt","items":{"$ref":"#/$defs/hookMatcher"}},"SubagentStart":{"type":"array","description":"Hooks that run when a subagent is spawned","items":{"$ref":"#/$defs/hookMatcher"}},"SubagentStop":{"type":"array","description":"Hooks that run when subagents finish responding","items":{"$ref":"#/$defs/hookMatcher"}},"PreCompact":{"type":"array","description":"Hooks that run before the context is compacted","items":{"$ref":"#/$defs/hookMatcher"}},"PostCompact":{"type":"array","description":"Hooks that run after the context is compacted. See https://code.claude.com/docs/en/hooks","items":{"$ref":"#/$defs/hookMatcher"}},"Elicitation":{"type":"array","description":"Hooks that run when an MCP server requests user input during a tool call. See https://code.claude.com/docs/en/hooks","items":{"$ref":"#/$defs/hookMatcher"}},"ElicitationResult":{"type":"array","description":"Hooks that run after a user responds to an MCP elicitation, before the response is sent back to the server. See https://code.claude.com/docs/en/hooks","items":{"$ref":"#/$defs/hookMatcher"}},"TeammateIdle":{"type":"array","description":"Hooks that run when an agent team teammate is about to go idle. Exit code 2 sends feedback and keeps the teammate working. Does not support matchers. Agent teams are experimental. See https://code.claude.com/docs/en/hooks#teammateidle","items":{"$ref":"#/$defs/hookMatcher"}},"TaskCompleted":{"type":"array","description":"Hooks that run when a task is being marked as completed. Exit code 2 prevents completion and sends feedback. Does not support matchers. See https://code.claude.com/docs/en/hooks#taskcompleted","items":{"$ref":"#/$defs/hookMatcher"}},"Setup":{"type":"array","description":"UNDOCUMENTED. Hooks that run during repository initialization (--init, --init-only) or maintenance (--maintenance)","items":{"$ref":"#/$defs/hookMatcher"}},"InstructionsLoaded":{"type":"array","description":"Hooks that run when a CLAUDE.md or .claude/rules/*.md file is loaded into context. Fires at session start and when files are lazily loaded (e.g., nested traversal, path glob match). No decision control; used for audit logging and observability. Does not support matchers. See https://code.claude.com/docs/en/hooks#instructionsloaded","items":{"$ref":"#/$defs/hookMatcher"}},"ConfigChange":{"type":"array","description":"Hooks that run when settings, managed settings, or skill files change during a session. Supports matchers: user_settings, project_settings, local_settings, policy_settings, skills. Command handlers only. Exit code 2 blocks the change (except policy_settings which is audit-only). See https://code.claude.com/docs/en/hooks#configchange","items":{"$ref":"#/$defs/hookMatcher"}},"WorktreeCreate":{"type":"array","description":"Hooks that run when a worktree is created via --worktree or isolation: \\"worktree\\" in subagents. Command handlers only, no matchers. Hook must print absolute path to created worktree on stdout; non-zero exit fails creation. See https://code.claude.com/docs/en/hooks#worktreecreate","items":{"$ref":"#/$defs/hookMatcher"}},"WorktreeRemove":{"type":"array","description":"Hooks that run when a worktree is being removed at session exit or when a subagent finishes. Command handlers only, no matchers. Used for cleanup tasks; cannot block removal. See https://code.claude.com/docs/en/hooks#worktreeremove","items":{"$ref":"#/$defs/hookMatcher"}},"SessionStart":{"type":"array","description":"Hooks that run when a new session starts","items":{"$ref":"#/$defs/hookMatcher"}},"SessionEnd":{"type":"array","description":"Hooks that run when a session ends","items":{"$ref":"#/$defs/hookMatcher"}}}},"disableAllHooks":{"type":"boolean","description":"Disable all hooks and statusLine execution. When true in managed settings, user and project-level disableAllHooks cannot override it. See https://code.claude.com/docs/en/hooks#disable-or-remove-hooks"},"allowedHttpHookUrls":{"type":"array","items":{"type":"string","minLength":1},"description":"Allowlist of URL patterns that HTTP hooks may target. Supports * as a wildcard. When set, hooks with non-matching URLs are blocked. Undefined = no restriction, empty array = block all HTTP hooks. Arrays merge across settings sources. See https://code.claude.com/docs/en/settings#hook-configuration","examples":[["https://hooks.example.com/*","http://localhost:*"]]},"allowManagedHooksOnly":{"type":"boolean","description":"(Managed settings only) Prevent loading of user, project, and plugin hooks. Only allows managed hooks and SDK hooks. See https://code.claude.com/docs/en/settings#hook-configuration"},"allowManagedPermissionRulesOnly":{"type":"boolean","description":"(Managed settings only) Prevent user and project settings from defining allow, ask, or deny permission rules. Only rules in managed settings apply. See https://code.claude.com/docs/en/settings#permission-settings"},"statusLine":{"type":"object","properties":{"type":{"type":"string","description":"The type of status line handler; must be set to \\"command\\" to run a custom shell script that receives JSON session data via stdin.","const":"command"},"command":{"type":"string","description":"A shell command or path to a script that displays session information (context usage, costs, git status, etc.) by reading JSON data from stdin and writing output to stdout. See https://code.claude.com/docs/en/statusline"},"padding":{"type":"number","description":"Optional number of extra horizontal spacing characters added to the status line content; defaults to 0."}},"required":["type","command"],"additionalProperties":false,"description":"Custom status line display configuration. See https://code.claude.com/docs/en/statusline","examples":[{"type":"command","command":"~/.claude/statusline.sh"}]},"fileSuggestion":{"type":"object","properties":{"type":{"type":"string","description":"The type of file suggestion handler; must be set to \\"command\\" to execute a custom shell script that generates file suggestions for the @ file picker.","const":"command"},"command":{"type":"string","description":"Shell command to execute for file suggestions"}},"required":["type","command"],"additionalProperties":false,"description":"Configure a custom script for @ file autocomplete. See https://code.claude.com/docs/en/settings#file-suggestion-settings","examples":[{"type":"command","command":"~/.claude/file-suggestion.sh"}]},"enabledPlugins":{"type":"object","additionalProperties":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"boolean"},{"not":{}}]},"description":"Enabled plugins using plugin-id@marketplace-id format. Example: { \\"formatter@anthropic-tools\\": true }. See https://code.claude.com/docs/en/plugins"},"extraKnownMarketplaces":{"type":"object","additionalProperties":{"type":"object","properties":{"source":{"anyOf":[{"type":"object","properties":{"source":{"type":"string","description":"Identifies the marketplace source type","const":"url"},"url":{"type":"string","format":"uri","description":"Direct URL to marketplace.json file"}},"required":["source","url"],"additionalProperties":false},{"type":"object","properties":{"source":{"type":"string","description":"Identifies the marketplace source type","const":"hostPattern"},"hostPattern":{"type":"string","description":"Git host pattern to trust for repositories in source specifications"}},"required":["source","hostPattern"],"additionalProperties":false},{"type":"object","properties":{"source":{"type":"string","description":"Identifies the marketplace source type","const":"github"},"repo":{"type":"string","description":"GitHub repository in owner/repo format"},"ref":{"type":"string","description":"Git branch or tag to use (e.g., \\"main\\", \\"v1.0.0\\"). Defaults to repository default branch."},"path":{"type":"string","description":"Path to marketplace.json within repo (defaults to .claude-plugin/marketplace.json)"}},"required":["source","repo"],"additionalProperties":false},{"type":"object","properties":{"source":{"type":"string","description":"Identifies the marketplace source type","const":"git"},"url":{"type":"string","pattern":"\\\\.git$","description":"Full git repository URL"},"ref":{"type":"string","description":"Git branch or tag to use (e.g., \\"main\\", \\"v1.0.0\\"). Defaults to repository default branch."},"path":{"type":"string","description":"Path to marketplace.json within repo (defaults to .claude-plugin/marketplace.json)"}},"required":["source","url"],"additionalProperties":false},{"type":"object","properties":{"source":{"type":"string","description":"Identifies the marketplace source type","const":"npm"},"package":{"type":"string","description":"NPM package containing marketplace.json"}},"required":["source","package"],"additionalProperties":false},{"type":"object","properties":{"source":{"type":"string","description":"Identifies the marketplace source type","const":"file"},"path":{"type":"string","description":"Local file path to marketplace.json"}},"required":["source","path"],"additionalProperties":false},{"type":"object","properties":{"source":{"type":"string","description":"Identifies the marketplace source type","const":"directory"},"path":{"type":"string","description":"Local directory containing .claude-plugin/marketplace.json"}},"required":["source","path"],"additionalProperties":false}],"description":"Where to fetch the marketplace from"},"installLocation":{"type":"string","description":"Local cache path where marketplace manifest is stored (auto-generated if not provided)"}},"required":["source"],"additionalProperties":false},"description":"Additional marketplaces to make available for this repository. Typically used in repository .claude/settings.json to ensure team members have required plugin sources. See https://code.claude.com/docs/en/plugin-marketplaces"},"strictKnownMarketplaces":{"type":"array","description":"(Managed settings only) Allowlist of plugin marketplaces users can add. Undefined = no restrictions, empty array = lockdown. Uses exact matching for source specifications. See https://code.claude.com/docs/en/settings#strictknownmarketplaces","items":{"anyOf":[{"type":"object","properties":{"source":{"type":"string","description":"Identifies the marketplace source type","const":"hostPattern"},"hostPattern":{"type":"string","description":"Git host pattern to trust for repositories in source specifications"}},"required":["source","hostPattern"],"additionalProperties":false},{"type":"object","properties":{"source":{"type":"string","description":"Identifies the marketplace source type","const":"github"},"repo":{"type":"string","description":"GitHub repository in owner/repo format"},"ref":{"type":"string","description":"Git branch, tag, or SHA"},"path":{"type":"string","description":"Subdirectory path"}},"required":["source","repo"],"additionalProperties":false},{"type":"object","properties":{"source":{"type":"string","description":"Identifies the marketplace source type","const":"git"},"url":{"type":"string","description":"Full git repository URL"},"ref":{"type":"string","description":"Git branch, tag, or SHA"},"path":{"type":"string","description":"Subdirectory path"}},"required":["source","url"],"additionalProperties":false},{"type":"object","properties":{"source":{"type":"string","description":"Identifies the marketplace source type","const":"url"},"url":{"type":"string","format":"uri","description":"Direct URL to marketplace.json"},"headers":{"type":"object","additionalProperties":{"type":"string"},"description":"HTTP headers for authenticated access"}},"required":["source","url"],"additionalProperties":false},{"type":"object","properties":{"source":{"type":"string","description":"Identifies the marketplace source type","const":"npm"},"package":{"type":"string","description":"NPM package name (supports scoped packages)"}},"required":["source","package"],"additionalProperties":false},{"type":"object","properties":{"source":{"type":"string","description":"Identifies the marketplace source type","const":"file"},"path":{"type":"string","description":"Absolute path to marketplace.json file"}},"required":["source","path"],"additionalProperties":false},{"type":"object","properties":{"source":{"type":"string","description":"Identifies the marketplace source type","const":"directory"},"path":{"type":"string","description":"Absolute path to directory containing .claude-plugin/marketplace.json"}},"required":["source","path"],"additionalProperties":false},{"type":"object","properties":{"source":{"type":"string","description":"Identifies the marketplace source type","const":"pathPattern"},"pathPattern":{"type":"string","description":"Regex pattern to match file or directory paths for marketplace sources"}},"required":["source","pathPattern"],"additionalProperties":false}]},"examples":[[{"source":"github","repo":"acme-corp/approved-plugins"},{"source":"npm","package":"@acme-corp/compliance-plugins"}]]},"skippedMarketplaces":{"type":"array","items":{"type":"string","minLength":1},"description":"List of marketplace names the user has chosen not to install when prompted"},"skippedPlugins":{"type":"array","items":{"type":"string","minLength":1},"description":"List of plugin IDs (plugin@marketplace format) the user has chosen not to install when prompted"},"forceLoginMethod":{"type":"string","enum":["claudeai","console"],"description":"Force a specific login method: \\"claudeai\\" for Claude Pro/Max, \\"console\\" for Console billing","examples":["claudeai"]},"forceLoginOrgUUID":{"type":"string","description":"Organization UUID to use for OAuth login","examples":["xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"],"minLength":1},"otelHeadersHelper":{"type":"string","description":"Path to a script that outputs OpenTelemetry headers","minLength":1},"outputStyle":{"type":"string","description":"Controls the output style for assistant responses. Built-in styles: default, Explanatory, Learning. Custom styles can be added in ~/.claude/output-styles/ or .claude/output-styles/. See https://code.claude.com/docs/en/output-styles","examples":["default","Explanatory","Learning"],"minLength":1},"skipWebFetchPreflight":{"type":"boolean","description":"Skip the WebFetch blocklist check for enterprise environments with restrictive security policies"},"sandbox":{"type":"object","description":"Sandbox execution configuration. See https://code.claude.com/docs/en/sandboxing","properties":{"network":{"type":"object","description":"Configures network isolation settings for the sandboxed bash environment, including domain restrictions, Unix socket access, and custom proxy configuration.","properties":{"allowUnixSockets":{"type":"array","items":{"type":"string"},"description":"Allow Unix domain sockets for local IPC (SSH agent, Docker, etc.). Provide an array of specific paths. Defaults to blocking if not specified"},"allowLocalBinding":{"type":"boolean","description":"Allow binding to local network addresses (e.g., localhost ports). Defaults to false if not specified"},"httpProxyPort":{"type":"integer","minimum":1,"maximum":65535,"description":"HTTP proxy port to use for network filtering. If not specified, a proxy server will be started automatically"},"socksProxyPort":{"type":"integer","minimum":1,"maximum":65535,"description":"SOCKS proxy port to use for network filtering. If not specified, a proxy server will be started automatically"},"allowAllUnixSockets":{"type":"boolean","description":"Allow all Unix domain socket connections. If true, this overrides allowUnixSockets"},"allowedDomains":{"type":"array","items":{"type":"string","minLength":1},"description":"Allowlist of network domains for sandboxed commands. Supports wildcard patterns like *.example.com"},"allowManagedDomainsOnly":{"type":"boolean","description":"(Managed settings only) Only allowedDomains and WebFetch(domain:...) allow rules from managed settings are respected. User, project, local, and flag settings domains are ignored. Denied domains are still respected from all sources. Non-allowed domains are automatically blocked without user prompts."}},"additionalProperties":false},"ignoreViolations":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"},"description":"List of filesystem paths to ignore sandbox violations for when this command pattern matches"},"description":"Map of command patterns to filesystem paths to ignore violations for. Use \\"*\\" to match all commands"},"excludedCommands":{"type":"array","items":{"type":"string"},"description":"Commands that should never run in the sandbox (e.g., [\\"git\\", \\"docker\\"])"},"autoAllowBashIfSandboxed":{"type":"boolean","description":"Automatically allow bash commands without prompting when they run in the sandbox. Only applies to commands that will run sandboxed.","default":true},"enableWeakerNetworkIsolation":{"type":"boolean","description":"macOS only. Allow access to the system TLS trust service (com.apple.trustd.agent) in the sandbox. Required for Go-based tools like gh, gcloud, and terraform to verify TLS certificates when using httpProxyPort with a MITM proxy and custom CA. Reduces security by opening a potential data exfiltration path. Default: false. See https://code.claude.com/docs/en/settings#sandbox-settings","default":false},"enableWeakerNestedSandbox":{"type":"boolean","description":"Enable weaker sandbox mode for unprivileged docker environments where --proc mounting fails. This significantly reduces the strength of the sandbox and should only be used when this risk is acceptable.Default: false (secure)."},"allowUnsandboxedCommands":{"type":"boolean","description":"Allow commands to run outside the sandbox via the dangerouslyDisableSandbox parameter. When false, the dangerouslyDisableSandbox parameter is completely ignored and all commands must run sandboxed. Default: true."},"enabled":{"type":"boolean","description":"Enable sandboxed bash"},"filesystem":{"type":"object","description":"Filesystem access control for sandboxed commands. See https://code.claude.com/docs/en/sandboxing#filesystem-isolation","properties":{"allowWrite":{"type":"array","items":{"type":"string","minLength":1},"description":"Paths where subprocesses are allowed to write. Supports prefixes: // (absolute), ~/ (home directory), / (relative to settings file), ./ or no prefix (relative path)"},"denyWrite":{"type":"array","items":{"type":"string","minLength":1},"description":"Paths where subprocesses are explicitly denied write access. Takes precedence over allowWrite"},"denyRead":{"type":"array","items":{"type":"string","minLength":1},"description":"Paths where subprocesses are explicitly denied read access"},"allowRead":{"type":"array","items":{"type":"string","minLength":1},"description":"Paths to re-allow reading within denyRead regions. Takes precedence over denyRead for matching paths"},"allowManagedReadPathsOnly":{"type":"boolean","description":"When true (managed settings only), only allowRead paths from managed settings are used"}},"additionalProperties":false}},"additionalProperties":false},"spinnerVerbs":{"type":"object","description":"Customize the verbs shown in spinner progress messages","properties":{"mode":{"type":"string","enum":["append","replace"],"description":"How to combine custom verbs with default spinner verbs: 'append' adds custom verbs to the default list, 'replace' uses only custom verbs"},"verbs":{"type":"array","items":{"type":"string","minLength":1},"minItems":1,"description":"Custom verbs used in spinner progress text"}},"required":["verbs"],"additionalProperties":false},"spinnerTipsEnabled":{"type":"boolean","description":"Show tips in the spinner while Claude is working. Set to false to disable tips (default: true)","default":true},"spinnerTipsOverride":{"type":"object","description":"Customize the tips displayed in the spinner while Claude is working. See https://code.claude.com/docs/en/settings#available-settings","properties":{"excludeDefault":{"type":"boolean","description":"If true, only show custom tips. If false or absent, custom tips merge with built-in tips","default":false},"tips":{"type":"array","items":{"type":"string","minLength":1},"description":"Custom tip strings to display in the spinner","minItems":1}},"required":["tips"],"additionalProperties":false},"terminalProgressBarEnabled":{"type":"boolean","description":"Enable the terminal progress bar that shows progress in supported terminals like Windows Terminal and iTerm2 (default: true)","default":true},"showTurnDuration":{"type":"boolean","description":"Show turn duration messages after responses (e.g., \\"Cooked for 1m 6s\\"). Set to false to hide these messages (default: true)","default":true},"prefersReducedMotion":{"type":"boolean","description":"Reduce or disable UI animations (spinners, shimmer, flash effects) for accessibility","default":false},"alwaysThinkingEnabled":{"type":"boolean","description":"Enable extended thinking by default for all sessions. Typically configured via the /config command rather than editing directly. See https://code.claude.com/docs/en/common-workflows#use-extended-thinking-thinking-mode"},"companyAnnouncements":{"type":"array","items":{"type":"string","minLength":1},"description":"Company announcements to display at startup (one will be randomly selected if multiple are provided)"},"teammateMode":{"type":"string","enum":["auto","in-process","tmux"],"description":"How agent team teammates display: \\"auto\\" picks split panes in tmux or iTerm2, in-process otherwise. Agent teams are experimental and disabled by default. Enable them by adding CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS to your settings.json or environment. See https://code.claude.com/docs/en/agent-teams","default":"auto"},"worktree":{"type":"object","additionalProperties":false,"description":"Configuration for --worktree sessions. See https://code.claude.com/docs/en/settings","properties":{"sparsePaths":{"type":"array","items":{"type":"string","minLength":1},"description":"Directories to check out in each worktree via git sparse-checkout (cone mode). Only the listed paths are written to disk, which is faster in large monorepos.","examples":[["packages/my-app","shared/utils"]]}}},"pluginTrustMessage":{"type":"string","description":"(Managed settings only) Custom message appended to the plugin trust warning shown before installation. Use to provide organization-specific context about approved plugins. See https://code.claude.com/docs/en/settings#plugin-settings","minLength":1},"pluginConfigs":{"type":"object","additionalProperties":{"type":"object","properties":{"mcpServers":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"type":"string"}}]}},"description":"User configuration values for MCP servers keyed by server name"}},"additionalProperties":false},"description":"Per-plugin configuration including MCP server user configs, keyed by plugin ID (plugin@marketplace format). See https://code.claude.com/docs/en/plugins"},"allowManagedMcpServersOnly":{"type":"boolean","description":"(Managed settings only) Only allowedMcpServers from managed settings are respected. deniedMcpServers still merges from all sources. Users can still add their own MCP servers, but only the admin-defined allowlist applies."},"blockedMarketplaces":{"type":"array","description":"(Managed settings only) Blocklist of marketplace sources. These exact sources are blocked from being added as marketplaces. The check happens before downloading, so blocked sources never touch the filesystem.","items":{"anyOf":[{"type":"object","additionalProperties":false,"properties":{"source":{"type":"string","const":"url","description":"Block marketplace fetched from direct URL"},"url":{"type":"string","format":"uri","description":"Direct URL to marketplace.json file"},"headers":{"type":"object","additionalProperties":{"type":"string"},"description":"Custom HTTP headers (e.g., for authentication)"}},"required":["source","url"]},{"type":"object","additionalProperties":false,"properties":{"source":{"type":"string","const":"github","description":"Block marketplace from GitHub repository"},"repo":{"type":"string","description":"GitHub repository in owner/repo format"},"ref":{"type":"string","description":"Git branch or tag to use"},"path":{"type":"string","description":"Path to marketplace.json within repo"}},"required":["source","repo"]},{"type":"object","additionalProperties":false,"properties":{"source":{"type":"string","const":"git","description":"Block marketplace from git repository URL"},"url":{"type":"string","pattern":".*\\\\.git$","description":"Full git repository URL"},"ref":{"type":"string","description":"Git branch or tag to use"},"path":{"type":"string","description":"Path to marketplace.json within repo"}},"required":["source","url"]},{"type":"object","additionalProperties":false,"properties":{"source":{"type":"string","const":"npm","description":"Block marketplace from NPM package"},"package":{"type":"string","description":"NPM package containing marketplace.json"}},"required":["source","package"]},{"type":"object","additionalProperties":false,"properties":{"source":{"type":"string","const":"file","description":"Block marketplace from local file"},"path":{"type":"string","description":"Local file path to marketplace.json"}},"required":["source","path"]},{"type":"object","additionalProperties":false,"properties":{"source":{"type":"string","const":"directory","description":"Block marketplace from local directory"},"path":{"type":"string","description":"Local directory containing .claude-plugin/marketplace.json"}},"required":["source","path"]},{"type":"object","additionalProperties":false,"properties":{"source":{"type":"string","const":"hostPattern","description":"Block marketplace by host pattern matching"},"hostPattern":{"type":"string","description":"Regex pattern to match the host/domain extracted from any marketplace source type"}},"required":["source","hostPattern"]},{"type":"object","additionalProperties":false,"properties":{"source":{"type":"string","const":"pathPattern","description":"Block marketplace by file/directory path pattern matching"},"pathPattern":{"type":"string","description":"Regex pattern to match file or directory paths for marketplace sources"}},"required":["source","pathPattern"]}]}}}`),Q="Claude Code Settings",ee={$schema:W,$id:K,$defs:J,description:V,allowTrailingCommas:z,additionalProperties:Y,type:Z,properties:X,title:Q};function te(e){const t=e??{},r={...t.$defs??{},...t.definitions??{}},n=s=>{if(!s)return{};if(!s.$ref)return f(s);const a=/^#\/(\$defs|definitions)\/(.+)$/.exec(s.$ref);if(!a)return f(s);const u=r[a[2]];return u?n({...u,...d(s)}):f(s)},m=new Set(["__proto__","constructor","prototype"]),c=s=>{if(!s)return{};const a={};for(const[u,p]of Object.entries(s))m.has(u)||(a[u]=p);return a},f=s=>{if(!s.allOf||s.allOf.length===0)return s;const a={...s};delete a.allOf;for(const u of s.allOf){const p=n(u);Object.assign(a,{properties:{...c(a.properties),...c(p.properties)},required:se([...a.required??[],...p.required??[]])}),!a.description&&p.description&&(a.description=p.description),a.default===void 0&&p.default!==void 0&&(a.default=p.default),!a.type&&p.type&&(a.type=p.type)}return a},d=s=>{const{$ref:a,...u}=s;return u},l=(s,a)=>{let u=n(s);for(const p of a){if(!u)return null;if(/^\d+$/.test(p)){const v=Array.isArray(u.items)?u.items[Number(p)]:u.items;u=v?n(v):null;continue}const k=u.properties;if(k&&!m.has(p)&&p in k){u=n(k[p]);continue}const y=u.additionalProperties;if(y&&typeof y=="object"){u=n(y);continue}return null}return u},g=(s,a,u)=>{if(!s)return null;const p={};if(s.description&&(p.description=s.description),s.type&&(p.type=s.type),s.default!==void 0&&(p.default=s.default),s.enum&&(p.enum=s.enum),s.const!==void 0&&(p.const=s.const),s.deprecated&&(p.deprecated=!0),s.examples&&(p.examples=s.examples),s.properties&&(p.knownChildren=Object.keys(s.properties)),u&&(a!=null&&a.includes(u))&&(p.required=!0),s.items&&!Array.isArray(s.items)){const k=n(s.items),y=g(k,void 0,null);y&&(p.itemsInfo=y)}return(s.additionalProperties===!0||typeof s.additionalProperties=="object")&&(p.open=!0),p},i=s=>a=>{if(a.length===0)return g(n(s),void 0,null);const u=l(s,a.slice(0,-1));if(!u)return null;const p=a[a.length-1],k=l(u,[p]);return g(k,u.required,p)},b=s=>{const a=n(s);return Object.keys(a.properties??{})},h=s=>({at:i(s),rootKeys:()=>b(s),rootedAt:a=>{const u=l(s,a);return h(u??{})}});return h(t)}function se(e){return Array.from(new Set(e))}let A=null;function ce(){return A||(A=te(ee)),A}export{re as E,ce as a,B as g,ne as m,ae as p,G as s,ie 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-TejhHSzN.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-14dBLqE_.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.66.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",
|
|
@@ -40,6 +40,9 @@
|
|
|
40
40
|
"test:e2e:gen-fixture": "espeak-ng -w /tmp/sm-raw.wav -s 140 'testing one two three four five' && ffmpeg -y -i /tmp/sm-raw.wav -ar 48000 -ac 2 -sample_fmt s16 e2e/fixtures/speech.wav",
|
|
41
41
|
"refresh:vad-assets": "cp node_modules/@ricky0123/vad-web/dist/silero_vad_v5.onnx node_modules/@ricky0123/vad-web/dist/vad.worklet.bundle.min.js src/renderer/public/vad/ && cp node_modules/onnxruntime-web/dist/ort-wasm-simd-threaded.wasm node_modules/onnxruntime-web/dist/ort-wasm-simd-threaded.mjs node_modules/onnxruntime-web/dist/ort-wasm-simd-threaded.jsep.wasm node_modules/onnxruntime-web/dist/ort-wasm-simd-threaded.jsep.mjs src/renderer/public/vad/",
|
|
42
42
|
"health": "node src/main/health.cjs",
|
|
43
|
+
"manual:check": "node scripts/build-manual.mjs --check",
|
|
44
|
+
"manual:build": "node scripts/build-manual.mjs",
|
|
45
|
+
"manual:figures": "xvfb-run -a node scripts/capture-manual-figures.mjs",
|
|
43
46
|
"lint:selectors": "node scripts/check-unstable-selectors.cjs",
|
|
44
47
|
"lint:hooks": "node scripts/check-conditional-hooks.cjs",
|
|
45
48
|
"lint": "npm run lint:selectors && npm run lint:hooks"
|
|
@@ -111,6 +114,7 @@
|
|
|
111
114
|
"node-pty": "^1.2.0-beta.12",
|
|
112
115
|
"onnxruntime-web": "^1.24.3",
|
|
113
116
|
"react-force-graph-2d": "^1.29.1",
|
|
117
|
+
"sharp": "^0.35.3",
|
|
114
118
|
"tiptap-markdown": "^0.9.0",
|
|
115
119
|
"ws": "^8.18.0",
|
|
116
120
|
"zod": "^3.23.8",
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: builder:manual
|
|
3
|
+
description: Keep The Session Manager Field Manual — the paid $19.99 digital product sold at bilko.run/manual — in step with what actually shipped. Runs after builder:publish (or standalone), diffs the just-released commits against the manual's chapter map, revises the affected chapters, bumps the manual's own version, builds the release bundle into the Bilko repo, and reports what changed. Invoked as the last step of /builder, or directly via "/builder:manual", "update the manual", "does the manual need a revision".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# builder:manual (step 5)
|
|
7
|
+
|
|
8
|
+
The manual is a **product we sell**, not documentation we generate. It has its own version
|
|
9
|
+
line, its own release cadence, and a buyer who paid $19.99 and is owed accuracy. This step
|
|
10
|
+
exists so a shipped feature never silently invalidates a paid chapter.
|
|
11
|
+
|
|
12
|
+
- **Source of truth:** `session-manager-operations/manual/` (see its `README.md` for the
|
|
13
|
+
on-disk shape and the release checklist).
|
|
14
|
+
- **Build:** `npm run manual:build` → `~/Projects/Bilko/data/manual/releases/<version>/`.
|
|
15
|
+
- **Sold via:** the already-live `session_manager` Stripe SKU. There is no second price to
|
|
16
|
+
create; entitlement already exists for every past buyer.
|
|
17
|
+
|
|
18
|
+
## Inputs
|
|
19
|
+
|
|
20
|
+
The commit list from `builder:diff` (step 0) and the version `builder:publish` (step 3) just
|
|
21
|
+
shipped. When run standalone, derive both the same way step 0 does.
|
|
22
|
+
|
|
23
|
+
## Procedure
|
|
24
|
+
|
|
25
|
+
### 1. Decide whether a revision is owed
|
|
26
|
+
|
|
27
|
+
Read `session-manager-operations/manual/manual.json`. Compare its `documentsAppVersion`
|
|
28
|
+
against the version just published.
|
|
29
|
+
|
|
30
|
+
Then map the release's commits onto the chapter list. A chapter is **affected** when a commit
|
|
31
|
+
in the diff touched a surface that chapter describes — check the chapter body for the file
|
|
32
|
+
paths, tab names, flags, and CLI invocations it names, and grep the diff for those.
|
|
33
|
+
|
|
34
|
+
Three outcomes, and only one of them is work:
|
|
35
|
+
|
|
36
|
+
| Finding | Action |
|
|
37
|
+
| --- | --- |
|
|
38
|
+
| No commit touches any documented surface | Bump `documentsAppVersion` only, note "no content change", stop. Do **not** cut a manual release for a version bump alone. |
|
|
39
|
+
| A commit changes behaviour a chapter describes | Revise that chapter. Continue to step 2. |
|
|
40
|
+
| A commit ships a surface no chapter covers | Report it as a **gap** — propose the new chapter, but do not author a whole chapter unprompted; that's a scope decision for the human or an Epic. |
|
|
41
|
+
|
|
42
|
+
### 2. Revise the affected chapters
|
|
43
|
+
|
|
44
|
+
Edit the chapter HTML in `session-manager-operations/manual/chapters/`.
|
|
45
|
+
|
|
46
|
+
Hard rules — these are the ones that protect a paying customer:
|
|
47
|
+
|
|
48
|
+
- **Every claim must be checkable against real code right now.** Read the file, run the
|
|
49
|
+
command, confirm the constant. A wrong instruction in a paid product is a refund.
|
|
50
|
+
- **Never invent a screenshot.** A figure slot that has no captured image stays a
|
|
51
|
+
`manual-figure__frame` placeholder stating what still needs capturing. Placeholder text is
|
|
52
|
+
honest; a fabricated UI is not.
|
|
53
|
+
- **Don't restate the codebase.** The manual is an operator's guide — what a surface is for,
|
|
54
|
+
the one thing people get wrong, the workflow that pays off. If a paragraph would be equally
|
|
55
|
+
at home in `CLAUDE.md`, cut it.
|
|
56
|
+
- **Preserve the free chapter.** At least one chapter must stay `free: true` — it is the
|
|
57
|
+
marketing sample, and `scripts/build-manual.mjs` refuses to build without one.
|
|
58
|
+
|
|
59
|
+
### 3. Bump the manual's own version
|
|
60
|
+
|
|
61
|
+
In `manual.json`:
|
|
62
|
+
|
|
63
|
+
- `documentsAppVersion` → the app version just published, always.
|
|
64
|
+
- `version` → **patch** for corrections and figure fills, **minor** for a revised or added
|
|
65
|
+
chapter, **major** for a restructure that changes the chapter map. This is independent of
|
|
66
|
+
the app's version — a buyer tracks the manual's line, not the app's.
|
|
67
|
+
- `releasedAt` → today, in the user's local timezone (America/Los_Angeles).
|
|
68
|
+
|
|
69
|
+
### 4. Build and verify
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npm run manual:check # sources valid, nothing written
|
|
73
|
+
npm run manual:build # emits into ../Bilko/data/manual/releases/<version>/
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The build is the gate. It refuses on a missing chapter file, a malformed or duplicated slug,
|
|
77
|
+
an asset declared without a source, or no free chapter. A refusal is a stop, not a warning.
|
|
78
|
+
|
|
79
|
+
Then confirm the bundle is real — the manifest must not over-promise:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
ls ~/Projects/Bilko/data/manual/releases/<version>/
|
|
83
|
+
cd ~/Projects/Bilko && npx vitest run tests/manual.test.ts
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
That test walks the shipped manifest and asserts every chapter and asset it advertises
|
|
87
|
+
actually exists on disk.
|
|
88
|
+
|
|
89
|
+
### 5. Commit both repos
|
|
90
|
+
|
|
91
|
+
The bundle is served from the Bilko repo on Render, so an uncommitted bundle is an
|
|
92
|
+
unpublished manual. Two commits, one logical release:
|
|
93
|
+
|
|
94
|
+
- `session-manager`: the chapter sources + `manual.json`.
|
|
95
|
+
- `~/Projects/Bilko`: `data/manual/releases/<version>/`.
|
|
96
|
+
|
|
97
|
+
Per the project's standing rule, commit locally as soon as the build and test pass — don't
|
|
98
|
+
wait to be asked. Pushing the Bilko side is what actually ships it to buyers, so treat that
|
|
99
|
+
push with the same release trigger the npm publish gets.
|
|
100
|
+
|
|
101
|
+
## Output
|
|
102
|
+
|
|
103
|
+
Report, in this order:
|
|
104
|
+
|
|
105
|
+
1. Manual version before → after, and `documentsAppVersion` before → after.
|
|
106
|
+
2. Chapters revised, one line each, saying what changed and why.
|
|
107
|
+
3. Coverage gaps found (shipped surfaces with no chapter) — as proposals, not as work done.
|
|
108
|
+
4. Figures still pending capture, by chapter.
|
|
109
|
+
5. Whether the Bilko-side bundle is committed and pushed. If it isn't pushed, say plainly
|
|
110
|
+
that buyers are still seeing the previous edition.
|
|
111
|
+
|
|
112
|
+
## What this step is not
|
|
113
|
+
|
|
114
|
+
- Not a screenshot pipeline. Capturing and annotating real app screenshots is its own PRD;
|
|
115
|
+
until it lands, figures are placed by hand and unplaced slots render as honest placeholders.
|
|
116
|
+
- Not a marketing-copy editor. The sales page (`SessionManagerPage.tsx` in the Bilko repo) is
|
|
117
|
+
separate from the product it sells.
|
|
118
|
+
- Not a pricing or entitlement change. The $19.99 `session_manager` SKU and the
|
|
119
|
+
`MANUAL_PRODUCT_KEY` mapping in `shared/manual-catalog.ts` are deliberately fixed — changing
|
|
120
|
+
either strands existing buyers and needs an explicit decision, not a release step.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: builder
|
|
3
|
-
description: Watch the current project's git history against its published npm package and drive the next publish — diff HEAD against the last release, classify + bump the version from conventional-commit prefixes, gate on typecheck/tests, publish from an isolated git worktree (never the live working directory), then report. Orchestrates
|
|
3
|
+
description: Watch the current project's git history against its published npm package and drive the next publish — diff HEAD against the last release, classify + bump the version from conventional-commit prefixes, gate on typecheck/tests, publish from an isolated git worktree (never the live working directory), keep the paid Field Manual in step with what shipped, then report. Orchestrates 6 nested sub-skills (builder:diff, :classify-and-bump, :gate, :publish, :manual, :report). Use when the user says "/builder", "publish", "release", "cut a release", "bump the version", "ship to npm", "update the manual", or asks whether there's anything unpublished.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# builder (orchestrator)
|
|
@@ -40,7 +40,12 @@ identifier (`builder:diff`) without the numeric prefix.
|
|
|
40
40
|
│ version bumped, tagged, pushed, published, dist-tag verified
|
|
41
41
|
▼
|
|
42
42
|
┌───────────────────────┐
|
|
43
|
-
│ 4. builder:
|
|
43
|
+
│ 4. builder:manual │ does the PAID Field Manual still describe reality?
|
|
44
|
+
└───────────────────────┘ revise chapters → bump manual version → build bundle
|
|
45
|
+
│ manual release (or an explicit "no content change")
|
|
46
|
+
▼
|
|
47
|
+
┌───────────────────────┐
|
|
48
|
+
│ 5. builder:report │ version, commits covered, dist-tag, manual + push confirmation
|
|
44
49
|
└───────────────────────┘
|
|
45
50
|
```
|
|
46
51
|
|
|
@@ -50,7 +55,8 @@ identifier (`builder:diff`) without the numeric prefix.
|
|
|
50
55
|
| 1. `builder:classify-and-bump` | commit list | bump kind (`patch`/`minor`/`major`) | commits don't follow conventional-commit style → say so, ask the user rather than guessing |
|
|
51
56
|
| 2. `builder:gate` | working tree at HEAD | typecheck + unit test result | either fails → stop, report the failure, do not publish |
|
|
52
57
|
| 3. `builder:publish` | bump kind, gate-passed HEAD | published npm package, pushed tag + main | any step fails → stop, report which step and the worktree's state (don't leave it behind uncleaned unless it's evidence of the failure) |
|
|
53
|
-
| 4. `builder:
|
|
58
|
+
| 4. `builder:manual` | commit list + published version | revised chapters + a built manual release bundle, or an explicit "no content change" | build refuses (missing chapter/asset, bad slug, no free chapter) → stop and report; the npm publish already landed and is unaffected |
|
|
59
|
+
| 5. `builder:report` | publish + manual result | one summary: version bumped, commits covered, npm dist-tag verified, git push confirmed, manual edition shipped or explicitly unchanged | n/a |
|
|
54
60
|
|
|
55
61
|
## Hard rules — read before running any step
|
|
56
62
|
|
|
@@ -65,6 +71,10 @@ identifier (`builder:diff`) without the numeric prefix.
|
|
|
65
71
|
after the gate is green is exactly the friction this skill exists to remove.
|
|
66
72
|
- **The gate is a hard stop.** A failing `typecheck` or `test:unit` run means step 3 never
|
|
67
73
|
executes — no publish, no version bump, no tag. Report the failure and stop.
|
|
74
|
+
- **The manual is a product, not a changelog.** `builder:manual` may only claim what it has
|
|
75
|
+
verified against real code, and may never invent a screenshot. A wrong instruction in a
|
|
76
|
+
$19.99 paid guide is a refund — treat its accuracy bar as higher than the app's own docs.
|
|
77
|
+
A manual bundle that isn't pushed to the Bilko repo is not shipped; say so plainly.
|
|
68
78
|
- **Never guess a version bump from unconventional commit messages.** If the commit list
|
|
69
79
|
doesn't cleanly map to `fix:`/`feat:`/`BREAKING CHANGE:` prefixes, `builder:classify-and-bump`
|
|
70
80
|
asks the user which bump to apply rather than inferring one.
|
|
@@ -57,11 +57,15 @@ scheduler isn't decomposition need, it's model economics: keep the interactive m
|
|
|
57
57
|
(an expensive planner-tier model) focused on discussion and decisions, and let a cheaper executor
|
|
58
58
|
model do the implementing as a headless `claude -p` job.
|
|
59
59
|
|
|
60
|
-
**Only execution is delegated — authoring never is.**
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
the
|
|
60
|
+
**Only execution is delegated — authoring never is.** Do the thinking — decomposition, scope,
|
|
61
|
+
title, goal, and acceptance criteria — yourself, in the main loop; that's what "authoring" means
|
|
62
|
+
here, and it's non-negotiable regardless of which mechanism ends up putting bytes on disk. Do
|
|
63
|
+
not spawn a subagent to draft a PRD or otherwise hand off the writing/thinking — that defeats the
|
|
64
|
+
point of keeping planning on the expensive model. Once you've composed the PRD yourself, submit
|
|
65
|
+
it through `scheduler_create_prd` (the MCP tool — see step 4's "PRD structure and location"
|
|
66
|
+
below): that tool call is the sanctioned path from your own composed content to a file on disk,
|
|
67
|
+
not a second author. The scheduled `claude -p` job remains the only step that runs on the
|
|
68
|
+
cheaper executor.
|
|
65
69
|
|
|
66
70
|
## Standards (single source of truth)
|
|
67
71
|
|
|
@@ -206,8 +210,11 @@ can't load skills.
|
|
|
206
210
|
separate PRDs into one oversized one; if the sub-task groups would each take real time on
|
|
207
211
|
their own, that's a signal to split into a chain link instead of one bloated PRD.
|
|
208
212
|
|
|
209
|
-
|
|
210
|
-
|
|
213
|
+
**`scheduler_create_prd` is the ONLY sanctioned way to author a PRD — not a preference, a
|
|
214
|
+
rule.** Every PRD reaches disk through the MCP tool
|
|
215
|
+
(`mcp__session-manager-scheduler__scheduler_create_prd`). Hand-writing the file directly is a
|
|
216
|
+
degraded, LAST-RESORT fallback (below) reserved for the single case where the tool itself is
|
|
217
|
+
unreachable — never a co-equal alternative to reach for out of habit or convenience. Its input
|
|
211
218
|
(`title`, `cwd`, `estimateMinutes`, `goal`, `acceptanceCriteria[]`, `implementationNotes`,
|
|
212
219
|
`outOfScope[]`) maps directly onto the sections below — pass them straight through. **Always
|
|
213
220
|
pass `sourcePromptId` explicitly, set to the `<epic-id>` resolved in the Epic-gated step
|
|
@@ -222,7 +229,17 @@ can't load skills.
|
|
|
222
229
|
|
|
223
230
|
**Fallback — only when the tool errors with "app not running" / admin API unreachable**
|
|
224
231
|
(the session-manager Electron app must be running for this MCP tool to work; if it isn't,
|
|
225
|
-
don't block on it)
|
|
232
|
+
don't block on it). This is a deliberate bypass of the service boundary, not a shortcut:
|
|
233
|
+
using it means the frontmatter validation, atomic `NN` allocation, standards-pointer
|
|
234
|
+
insertion, and Epic-existence check that `scheduler_create_prd` normally performs did not
|
|
235
|
+
run. **You MUST call this out, visibly, in your report** — state plainly that the app wasn't
|
|
236
|
+
running, that you hand-authored the PRD file directly instead of using the tool, name the
|
|
237
|
+
exact file, and flag it for human verification (this bypass is also what
|
|
238
|
+
`scripts/audit-ops-hygiene.cjs` and the `ops-sweep` skill look for and report as a hygiene
|
|
239
|
+
finding, independent of your own report). Do not use this path when the tool is reachable but
|
|
240
|
+
merely returned a validation error (bad frontmatter, unresolvable Epic, etc.) — fix the input
|
|
241
|
+
and retry the tool; a validation error is not "the app is not running."
|
|
242
|
+
When you do use it: compute the highest in-use number deterministically yourself — never
|
|
226
243
|
eyeball or narrow-grep the `ls` (a narrowed pattern like `'^10[0-9]'` silently misses `110+`
|
|
227
244
|
and collides). PRDs are stored per-project, so `NN` allocation for a given PRD only needs
|
|
228
245
|
*that project's own* prds directory scanned — not every project's:
|
|
@@ -268,9 +285,16 @@ can't load skills.
|
|
|
268
285
|
**Anywhere else doesn't get scheduled or gets retired.** `data/prds/`, `docs/prds/`, and the
|
|
269
286
|
old global `prds/` dir under `~/.claude/session-manager/scheduled-plans/` are invisible to
|
|
270
287
|
the scheduler; the legacy flat `session-manager-operations/scheduler/prds/` dir is RETIRED —
|
|
271
|
-
anything written there is auto-consolidated into `prds-archived/`
|
|
272
|
-
|
|
273
|
-
|
|
288
|
+
anything written there is auto-consolidated into `prds-archived/` and never executed. This
|
|
289
|
+
consolidation runs at the top of every `reconcile()` call (`consolidateAllFlatPrds`, called
|
|
290
|
+
from inside `reconcile()` itself in `src/main/scheduler.cjs`, before `reconcile` scans that
|
|
291
|
+
dir for PRD sources) — not only at app boot, and not just from the tick-queue poll:
|
|
292
|
+
`reconcile()` also runs from job completion, the `schedule:state`/`schedule:rescan` IPC
|
|
293
|
+
handlers, and `rescheduleTimer()`, so the sweep is guaranteed regardless of which of those
|
|
294
|
+
triggers the next pass. A file landing in the flat dir while the app is already running is
|
|
295
|
+
swept out before it could ever be turned into a job, closing the window a boot-only pass left
|
|
296
|
+
open. PRD *source* files are per-project and per-Epic, resolved at runtime via
|
|
297
|
+
`src/main/lib/prdLocations.cjs`.
|
|
274
298
|
|
|
275
299
|
**Filename rules.** `NN` is the PRD's unique per-project number (always next free =
|
|
276
300
|
max+1 per the `ls` command above; ordering via `dependsOn` frontmatter, never via shared
|
|
@@ -423,11 +447,15 @@ single definition of "tracked to done" for both entry paths.
|
|
|
423
447
|
|
|
424
448
|
## Notes
|
|
425
449
|
|
|
426
|
-
-
|
|
450
|
+
- Submit each PRD through `scheduler_create_prd`, then confirm — don't draft them inline in chat
|
|
451
|
+
for review first, and don't hand-write the file yourself unless the tool is unreachable (app
|
|
452
|
+
not running); see the fallback note above, including its mandatory bypass warning.
|
|
427
453
|
- Don't combine unrelated features into one PRD. One focused, completable unit each.
|
|
428
454
|
- Don't add a `parallelGroup` frontmatter key — the filename `NN-` prefix drives grouping.
|
|
429
455
|
- Don't write a PRD to `data/prds/`, `docs/prds/`, the project's own folder, or anywhere outside
|
|
430
|
-
the canonical path
|
|
456
|
+
the canonical path — and don't reach for a hand-written file at the canonical path either, when
|
|
457
|
+
`scheduler_create_prd` is reachable. The user has explicitly flagged this as a recurring
|
|
458
|
+
problem.
|
|
431
459
|
- Don't leave `cwd` unset hoping for the default. Be explicit.
|
|
432
460
|
- Don't skip a step-3 lens silently and don't force every request into a chain — most asks are
|
|
433
461
|
still an independent set of small PRDs; reach for the 3-5-PRD evolving chain only when the
|
|
@@ -36,6 +36,16 @@ etc.), this skill makes **no assumption about the target project's namespace
|
|
|
36
36
|
names, its OWNERS table shape, or whether it has a CLAUDE.md at all**. It
|
|
37
37
|
re-derives the source-of-truth hierarchy from what that specific project has:
|
|
38
38
|
|
|
39
|
+
**Hand-authored-PRD detection stays out of this generic script on purpose.**
|
|
40
|
+
`audit-ops-hygiene.cjs`'s Pattern E (cross-referencing a live PRD `.md` file
|
|
41
|
+
against the machine-wide `prd_create` audit log to flag a PRD that bypassed
|
|
42
|
+
`scheduler_create_prd`) requires session-manager's own scheduler/PRD/audit-log
|
|
43
|
+
concepts, which a swept project may not even have — adding it here would break
|
|
44
|
+
the "no assumption about vocabulary" guarantee above. When sweeping
|
|
45
|
+
session-manager's own repo, run `node scripts/audit-ops-hygiene.cjs` alongside
|
|
46
|
+
this skill and fold its Pattern C/D/E findings into the same report; when
|
|
47
|
+
sweeping a different project, Pattern E simply doesn't apply.
|
|
48
|
+
|
|
39
49
|
1. That project's own `CLAUDE.md` (if present) — the declared architecture.
|
|
40
50
|
2. Each namespace's own `README.md` under its `session-manager-operations/<namespace>/`.
|
|
41
51
|
3. On-disk content — folder names, and archived/processed subfolders.
|
|
@@ -213,3 +213,43 @@ test('removeOverride deletes a project overlay resolved by project name, and rej
|
|
|
213
213
|
removeOverride({ name: 'builder', projectName: 'not-open', loadSessions, validatePath: identityValidatePath }),
|
|
214
214
|
).rejects.toThrow(/project not open/);
|
|
215
215
|
});
|
|
216
|
+
|
|
217
|
+
test('projects/action/actionLabel round-trip through savePersona -> listPersonas, with newlines preserved', async () => {
|
|
218
|
+
const globalDir = await mkTmp('sm-agent-library-action-');
|
|
219
|
+
const action = '/builder\n\nCheck git vs the published package and publish anything new.';
|
|
220
|
+
await savePersona({
|
|
221
|
+
name: 'builder',
|
|
222
|
+
description: 'Drives the next publish.',
|
|
223
|
+
tools: ['Bash'],
|
|
224
|
+
model: 'inherit',
|
|
225
|
+
color: '',
|
|
226
|
+
tags: ['build'],
|
|
227
|
+
projects: ['/home/bilko/Projects/alpha', '/home/bilko/Projects/beta'],
|
|
228
|
+
action,
|
|
229
|
+
actionLabel: 'Run Build',
|
|
230
|
+
body: 'Body.',
|
|
231
|
+
globalDir,
|
|
232
|
+
validatePath: identityValidatePath,
|
|
233
|
+
writeTextAtomic: fakeWriteTextAtomic,
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// The frontmatter parser is line-based, so the multi-line action must be
|
|
237
|
+
// stored escaped — a raw newline would silently truncate it on read.
|
|
238
|
+
const raw = await fsp.readFile(path.join(globalDir, 'builder.md'), 'utf8');
|
|
239
|
+
expect(raw).toContain('action: /builder\\n\\nCheck git');
|
|
240
|
+
expect(raw).toContain('projects: /home/bilko/Projects/alpha, /home/bilko/Projects/beta');
|
|
241
|
+
|
|
242
|
+
const [p] = await listPersonas({ globalDir, loadSessions: async () => ({ tabs: [] }), validatePath: identityValidatePath });
|
|
243
|
+
expect(p.projects).toEqual(['/home/bilko/Projects/alpha', '/home/bilko/Projects/beta']);
|
|
244
|
+
expect(p.action).toBe(action);
|
|
245
|
+
expect(p.actionLabel).toBe('Run Build');
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
test('a persona with no Action fields reports them as empty/null rather than undefined', async () => {
|
|
249
|
+
const globalDir = await mkTmp('sm-agent-library-noaction-');
|
|
250
|
+
await fsp.writeFile(path.join(globalDir, 'plain.md'), '---\nname: plain\n---\nBody.\n');
|
|
251
|
+
const [p] = await listPersonas({ globalDir, loadSessions: async () => ({ tabs: [] }), validatePath: identityValidatePath });
|
|
252
|
+
expect(p.projects).toEqual([]);
|
|
253
|
+
expect(p.action).toBeNull();
|
|
254
|
+
expect(p.actionLabel).toBeNull();
|
|
255
|
+
});
|