@popmelt.com/core 0.5.4 → 0.5.6

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/server.mjs CHANGED
@@ -1,4 +1,4 @@
1
- var Dt=Object.defineProperty,At=Object.defineProperties;var Jt=Object.getOwnPropertyDescriptors;var Re=Object.getOwnPropertySymbols;var Ze=Object.prototype.hasOwnProperty,et=Object.prototype.propertyIsEnumerable;var Ke=(r,t)=>(t=Symbol[r])?t:Symbol.for("Symbol."+r);var Xe=(r,t,n)=>t in r?Dt(r,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):r[t]=n,Z=(r,t)=>{for(var n in t||(t={}))Ze.call(t,n)&&Xe(r,n,t[n]);if(Re)for(var n of Re(t))et.call(t,n)&&Xe(r,n,t[n]);return r},ae=(r,t)=>At(r,Jt(t));var tt=(r,t)=>{var n={};for(var e in r)Ze.call(r,e)&&t.indexOf(e)<0&&(n[e]=r[e]);if(r!=null&&Re)for(var e of Re(r))t.indexOf(e)<0&&et.call(r,e)&&(n[e]=r[e]);return n};var ce=(r,t,n)=>(t=r[Ke("asyncIterator")])?t.call(r):(r=r[Ke("iterator")](),t={},n=(e,s)=>(s=r[e])&&(t[e]=a=>new Promise((i,c,p)=>(a=s.call(r,a),p=a.done,Promise.resolve(a.value).then(u=>i({value:u,done:p}),c)))),n("next"),n("return"),t);import{execFileSync as an}from"child_process";import{randomUUID as he}from"crypto";import{mkdir as cn,readdir as ln,stat as dn,unlink as un,writeFile as ye}from"fs/promises";import{createServer as pn}from"http";import{tmpdir as hn}from"os";import{join as le}from"path";import{spawn as Nt}from"child_process";import{createInterface as _t}from"readline";function $e(r,t){let{prompt:n,projectRoot:e,maxTurns:s=10,maxBudgetUsd:a=1,allowedTools:i=["Read","Edit","Write","Glob","Grep","Bash"],claudePath:c="claude",resumeSessionId:p,model:u,onEvent:x}=t,L=[];p?L.push("--resume",p,"-p",n):L.push("-p",n),L.push("--output-format","stream-json","--verbose","--max-turns",String(s),"--max-budget-usd",String(a)),u&&L.push("--model",u);for(let I of i)L.push("--allowedTools",I);let w=Nt(c,L,{cwd:e,stdio:["ignore","pipe","pipe"],env:ae(Z({},process.env),{ANTHROPIC_API_KEY:void 0})}),M=new Promise(I=>{var J;let F,b=[],z=[],Q=!1,ee="",G=_t({input:w.stdout}),B=new Set;G.on("line",j=>{var R,q,H,K,Ie,ke,Pe,be,Te;if(j.trim())try{let Y=JSON.parse(j);Y.session_id&&!F&&(F=Y.session_id);let Ae=(q=Y.type)!=null?q:(R=Y.event)!=null&&R.type?`event.${Y.event.type}`:"unknown";if(B.add(Ae),Y.type==="result"&&Y.result&&b.length===0){let A=typeof Y.result=="string"?Y.result:"";A&&(b.push(A),x==null||x({type:"delta",jobId:r,text:A},r))}if(Y.type==="assistant"&&Array.isArray((H=Y.message)==null?void 0:H.content))for(let A of Y.message.content){if(A.type==="text"&&A.text&&(b.push(A.text),x==null||x({type:"delta",jobId:r,text:A.text},r)),A.type==="tool_use"&&A.name){let we=((K=A.input)==null?void 0:K.file_path)||((Ie=A.input)==null?void 0:Ie.path)||void 0;x==null||x(Z({type:"tool_use",jobId:r,tool:A.name},we?{file:we}:{}),r),A.name==="Edit"&&((ke=A.input)!=null&&ke.file_path)?z.push({tool:"Edit",file_path:A.input.file_path,old_string:A.input.old_string,new_string:A.input.new_string,replace_all:A.input.replace_all}):A.name==="Write"&&((Pe=A.input)!=null&&Pe.file_path)&&z.push({tool:"Write",file_path:A.input.file_path,content:A.input.content})}A.type==="thinking"&&A.thinking&&(x==null||x({type:"thinking",jobId:r,text:A.thinking},r))}Y.type==="user"&&((Te=(be=Y.tool_use_result)==null?void 0:be.file)!=null&&Te.filePath)&&(x==null||x({type:"tool_use",jobId:r,tool:"Read",file:Y.tool_use_result.file.filePath},r))}catch(Y){}});let te=[];(J=w.stderr)==null||J.on("data",j=>{te.push(j.toString())}),w.on("close",j=>{G.close(),j!==0&&j!==null&&(Q=!0,ee=te.join("")||`Claude process exited with code ${j}`),I({sessionId:F,text:b.join(""),success:!Q,error:Q?ee:void 0,fileEdits:z.length>0?z:void 0})}),w.on("error",j=>{Q=!0,ee=j.message,I({sessionId:F,text:b.join(""),success:!1,error:ee,fileEdits:z.length>0?z:void 0})})});return{process:w,result:M}}import{spawn as Bt}from"child_process";import{createInterface as Ut}from"readline";function nt(r,t){let{prompt:n,projectRoot:e,screenshotPath:s,resumeSessionId:a,model:i,onEvent:c}=t,p=[];a?(p.push("exec","resume",a),i&&p.push("-m",i),p.push("--json","--full-auto",n),s&&p.push("--image",s)):(p.push("exec","--json","--full-auto"),i&&p.push("-m",i),p.push(n),s&&p.push("--image",s));let u=Bt("codex",p,{cwd:e,stdio:["ignore","pipe","pipe"],env:Z({},process.env)}),x=new Promise(L=>{var ee;let w,M=[],I=!1,F="",b=Ut({input:u.stdout}),z=new Set;b.on("line",G=>{var B,te,J,j;if(G.trim())try{let R=JSON.parse(G),q=(B=R.type)!=null?B:"unknown";if(z.add(q),q==="thread.started"&&R.thread_id&&!w&&(w=R.thread_id),q==="item/agentMessage/delta"&&((te=R.delta)!=null&&te.text)&&(M.push(R.delta.text),c==null||c({type:"delta",jobId:r,text:R.delta.text},r)),q==="item/reasoning/delta"&&((J=R.delta)!=null&&J.text)&&(c==null||c({type:"thinking",jobId:r,text:R.delta.text},r)),q==="item/started"&&R.item){let H=R.item.type;if(H==="command_execution")c==null||c({type:"tool_use",jobId:r,tool:"Bash"},r);else if(H==="file_change"){let K=R.item.filename||R.item.path;c==null||c(Z({type:"tool_use",jobId:r,tool:"Edit"},K?{file:K}:{}),r)}else if(H==="file_read"){let K=R.item.filename||R.item.path;c==null||c(Z({type:"tool_use",jobId:r,tool:"Read"},K?{file:K}:{}),r)}else if(H==="web_search")c==null||c({type:"tool_use",jobId:r,tool:"WebSearch"},r);else if(H==="mcp_tool_call"){let K=R.item.tool_name||R.item.name||"MCP";c==null||c({type:"tool_use",jobId:r,tool:K},r)}}if(q==="item/completed"&&R.item){if(R.item.type==="agent_message"){let H=R.item.text;typeof H=="string"&&H&&M.push(H)}else if(R.item.type==="reasoning"){let H=R.item.text;typeof H=="string"&&H&&(c==null||c({type:"thinking",jobId:r,text:H},r))}}q==="turn.failed"&&(I=!0,F=((j=R.error)==null?void 0:j.message)||R.message||"Turn failed")}catch(R){}});let Q=[];(ee=u.stderr)==null||ee.on("data",G=>{Q.push(G.toString())}),u.on("close",G=>{b.close(),G!==0&&G!==null&&(I=!0,F=Q.join("")||`Codex process exited with code ${G}`),L({sessionId:w,text:M.join(""),success:!I,error:I?F:void 0})}),u.on("error",G=>{I=!0,F=G.message,L({sessionId:w,text:M.join(""),success:!1,error:F})})});return{process:u,result:x}}import{execFile as Ft}from"child_process";import{copyFile as st,mkdir as ot,readdir as zt,readFile as jt,writeFile as Ht}from"fs/promises";import{join as pe}from"path";var Me=class{constructor(t){this.projectRoot=t;let n=pe(t,".popmelt");this.decisionsDir=pe(n,"decisions"),this.screenshotsDir=pe(n,"screenshots")}async persist(t,n,e){try{await ot(this.decisionsDir,{recursive:!0}),await ot(this.screenshotsDir,{recursive:!0});try{await st(n,pe(this.screenshotsDir,`s-${t.id}.png`))}catch(s){}for(let s=0;s<e.length;s++)try{let a=t.pastedImagePaths[s];a&&await st(e[s],pe(this.screenshotsDir,a.replace("screenshots/","")))}catch(a){}await Ht(pe(this.decisionsDir,`d-${t.id}.json`),JSON.stringify(t,null,2))}catch(s){console.error("[DecisionStore] Failed to persist decision record:",s)}}async listDecisionIds(){try{return(await zt(this.decisionsDir)).filter(n=>n.startsWith("d-")&&n.endsWith(".json")).map(n=>n.slice(2,-5))}catch(t){return[]}}async loadDecision(t){try{let n=await jt(pe(this.decisionsDir,`d-${t}.json`),"utf-8");return JSON.parse(n)}catch(n){return null}}async loadDecisions(t){return(await Promise.all(t.map(e=>this.loadDecision(e)))).filter(e=>e!==null)}captureGitDiff(t){return new Promise(n=>{Ft("git",["diff","HEAD"],{cwd:t,timeout:5e3,maxBuffer:1024*1024},(e,s)=>{if(e){n(null);return}n(s||null)})})}};import{readFile as rt,writeFile as fe}from"fs/promises";import{join as Ne}from"path";var oe="[Materializer]",Lt={version:1,materializedIds:[],lastRunAt:null,lastRunDecisionIds:[],lastRunError:null},Oe=class{constructor(t,n,e={}){this.projectRoot=t;this.decisionStore=n;this.options=e;this.cachedIndex=null;this.running=!1;let s=Ne(t,".popmelt");this.indexPath=Ne(s,"materialized.json"),this.modelPath=Ne(s,"model.json")}get isRunning(){return this.running}async loadModel(){try{let t=await rt(this.modelPath,"utf-8");return JSON.parse(t)}catch(t){return null}}async addComponent(t){let n=await this.loadModel();n||(n={tokens:{},components:{},rules:[]}),(!n.components||typeof n.components!="object")&&(n.components={});let e=n.components;return e[t]?{added:!1,alreadyExists:!0}:(e[t]={description:""},await fe(this.modelPath,JSON.stringify(n,null,2)),console.log(`${oe} Added component "${t}" to model`),{added:!0,alreadyExists:!1})}async updateToken(t,n){let e=await this.loadModel();e||(e={tokens:{},components:{},rules:[]});let s=t.split("."),a=e;for(let p=0;p<s.length-1;p++){let u=s[p];(!a[u]||typeof a[u]!="object")&&(a[u]={}),a=a[u]}let i=s[s.length-1],c;try{c=JSON.parse(n)}catch(p){c=null}if(c&&typeof c=="object"&&c!==null&&"value"in c)a[i]=c;else{let p=a[i];p&&typeof p=="object"&&p!==null&&"value"in p?p.value=n:a[i]=n}return await fe(this.modelPath,JSON.stringify(e,null,2)),console.log(`${oe} Updated token "${t}" \u2192 "${n.slice(0,80)}"`),{updated:!0}}async removeToken(t){let n=await this.loadModel();if(!n)return{removed:!1};let e=t.split("."),s=n;for(let i=0;i<e.length-1;i++){let c=e[i];if(!s[c]||typeof s[c]!="object")return{removed:!1};s=s[c]}let a=e[e.length-1];return a in s?(delete s[a],await fe(this.modelPath,JSON.stringify(n,null,2)),console.log(`${oe} Removed token "${t}" from model`),{removed:!0}):{removed:!1}}async removeComponent(t){let n=await this.loadModel();if(!n)return{removed:!1};let e=n.components;return!e||!e[t]?{removed:!1}:(delete e[t],await fe(this.modelPath,JSON.stringify(n,null,2)),console.log(`${oe} Removed component "${t}" from model`),{removed:!0})}async getUnmaterializedPatternDecisions(){let t=await this.loadIndex(),n=new Set(t.materializedIds),s=(await this.decisionStore.listDecisionIds()).filter(i=>!n.has(i));return s.length===0?[]:(await this.decisionStore.loadDecisions(s)).filter(i=>i.resolutions.some(c=>{var u;let p=(u=c.finalScope)!=null?u:c.inferredScope;return(p==null?void 0:p.breadth)==="pattern"}))}async run(){var t,n,e,s,a,i,c;if(this.running)return{processedIds:[],success:!0,error:"Already running"};this.running=!0;try{let p=await this.getUnmaterializedPatternDecisions();if(p.length===0)return{processedIds:[],success:!0};let u=p.map(b=>b.id);console.log(`${oe} Processing ${u.length} pattern-scoped decision(s): ${u.join(", ")}`),(n=(t=this.options).onEvent)==null||n.call(t,{type:"materialize_started",decisionIds:u});let x=await this.loadModel(),L=Gt(p,x),w=!0,M;try{let{result:b}=$e(`mat-${Date.now()}`,{prompt:L,projectRoot:this.projectRoot,maxTurns:(e=this.options.maxTurns)!=null?e:5,maxBudgetUsd:(s=this.options.maxBudgetUsd)!=null?s:.5,allowedTools:["Read"],claudePath:(a=this.options.claudePath)!=null?a:"claude"}),z=await b;if(!z.success)w=!1,M=z.error,console.error(`${oe} Claude spawn error:`,M);else{let Q=Wt(z.text);Q?(await fe(this.modelPath,JSON.stringify(Q,null,2)),console.log(`${oe} Successfully materialized ${u.length} decision(s) \u2192 ${this.modelPath}`)):(w=!1,M="No <model> block found in response",console.error(`${oe} ${M}`))}}catch(b){w=!1,M=b instanceof Error?b.message:String(b),console.error(`${oe} Error:`,M)}let I=await this.loadIndex(),F=new Set(I.materializedIds);for(let b of u)F.add(b);return I.materializedIds=[...F],I.lastRunAt=Date.now(),I.lastRunDecisionIds=u,I.lastRunError=M!=null?M:null,await this.persistIndex(I),(c=(i=this.options).onEvent)==null||c.call(i,{type:"materialize_done",decisionIds:u,success:w,error:M}),{processedIds:u,success:w,error:M}}finally{this.running=!1}}async loadIndex(){if(this.cachedIndex)return this.cachedIndex;try{let t=await rt(this.indexPath,"utf-8"),n=JSON.parse(t);return this.cachedIndex=n,n}catch(t){return this.cachedIndex=ae(Z({},Lt),{materializedIds:[],lastRunDecisionIds:[]}),this.cachedIndex}}async persistIndex(t){this.cachedIndex=t;try{await fe(this.indexPath,JSON.stringify(t,null,2))}catch(n){console.error(`${oe} Failed to write index:`,n)}}};function Wt(r){let t=r.match(/<model>\s*([\s\S]*?)\s*<\/model>/);if(!(t!=null&&t[1]))return null;try{let n=JSON.parse(t[1]);return typeof n!="object"||n===null||Array.isArray(n)?null:n}catch(n){return null}}function Gt(r,t){let n=r.map(s=>{let i=s.resolutions.filter(u=>{var L;let x=(L=u.finalScope)!=null?L:u.inferredScope;return(x==null?void 0:x.breadth)==="pattern"}).map(u=>{var M,I,F,b;let x=(M=u.finalScope)!=null?M:u.inferredScope,L=(I=x==null?void 0:x.target)!=null?I:"unknown",w=(b=(F=u.filesModified)==null?void 0:F.join(", "))!=null?b:"none";return`- **${u.summary}** [scope: pattern/${L}]
1
+ var Dt=Object.defineProperty,At=Object.defineProperties;var Jt=Object.getOwnPropertyDescriptors;var Re=Object.getOwnPropertySymbols;var Ze=Object.prototype.hasOwnProperty,et=Object.prototype.propertyIsEnumerable;var Ke=(r,t)=>(t=Symbol[r])?t:Symbol.for("Symbol."+r);var Xe=(r,t,n)=>t in r?Dt(r,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):r[t]=n,Z=(r,t)=>{for(var n in t||(t={}))Ze.call(t,n)&&Xe(r,n,t[n]);if(Re)for(var n of Re(t))et.call(t,n)&&Xe(r,n,t[n]);return r},ae=(r,t)=>At(r,Jt(t));var tt=(r,t)=>{var n={};for(var e in r)Ze.call(r,e)&&t.indexOf(e)<0&&(n[e]=r[e]);if(r!=null&&Re)for(var e of Re(r))t.indexOf(e)<0&&et.call(r,e)&&(n[e]=r[e]);return n};var ce=(r,t,n)=>(t=r[Ke("asyncIterator")])?t.call(r):(r=r[Ke("iterator")](),t={},n=(e,s)=>(s=r[e])&&(t[e]=a=>new Promise((i,c,p)=>(a=s.call(r,a),p=a.done,Promise.resolve(a.value).then(u=>i({value:u,done:p}),c)))),n("next"),n("return"),t);import{execFileSync as an}from"child_process";import{randomUUID as he}from"crypto";import{mkdir as cn,readdir as ln,stat as dn,unlink as un,writeFile as ye}from"fs/promises";import{createServer as pn}from"http";import{tmpdir as hn}from"os";import{join as le}from"path";import{spawn as Nt}from"child_process";import{createInterface as _t}from"readline";function $e(r,t){let{prompt:n,projectRoot:e,maxTurns:s=40,maxBudgetUsd:a=1,allowedTools:i=["Read","Edit","Write","Glob","Grep","Bash"],claudePath:c="claude",resumeSessionId:p,model:u,onEvent:x}=t,L=[];p?L.push("--resume",p,"-p",n):L.push("-p",n),L.push("--output-format","stream-json","--verbose","--max-turns",String(s),"--max-budget-usd",String(a)),u&&L.push("--model",u);for(let I of i)L.push("--allowedTools",I);let w=Nt(c,L,{cwd:e,stdio:["ignore","pipe","pipe"],env:ae(Z({},process.env),{ANTHROPIC_API_KEY:void 0})}),M=new Promise(I=>{var J;let F,b=[],z=[],Q=!1,ee="",G=_t({input:w.stdout}),B=new Set;G.on("line",j=>{var R,q,H,K,Ie,ke,Pe,be,Te;if(j.trim())try{let Y=JSON.parse(j);Y.session_id&&!F&&(F=Y.session_id);let Ae=(q=Y.type)!=null?q:(R=Y.event)!=null&&R.type?`event.${Y.event.type}`:"unknown";if(B.add(Ae),Y.type==="result"&&Y.result&&b.length===0){let A=typeof Y.result=="string"?Y.result:"";A&&(b.push(A),x==null||x({type:"delta",jobId:r,text:A},r))}if(Y.type==="assistant"&&Array.isArray((H=Y.message)==null?void 0:H.content))for(let A of Y.message.content){if(A.type==="text"&&A.text&&(b.push(A.text),x==null||x({type:"delta",jobId:r,text:A.text},r)),A.type==="tool_use"&&A.name){let we=((K=A.input)==null?void 0:K.file_path)||((Ie=A.input)==null?void 0:Ie.path)||void 0;x==null||x(Z({type:"tool_use",jobId:r,tool:A.name},we?{file:we}:{}),r),A.name==="Edit"&&((ke=A.input)!=null&&ke.file_path)?z.push({tool:"Edit",file_path:A.input.file_path,old_string:A.input.old_string,new_string:A.input.new_string,replace_all:A.input.replace_all}):A.name==="Write"&&((Pe=A.input)!=null&&Pe.file_path)&&z.push({tool:"Write",file_path:A.input.file_path,content:A.input.content})}A.type==="thinking"&&A.thinking&&(x==null||x({type:"thinking",jobId:r,text:A.thinking},r))}Y.type==="user"&&((Te=(be=Y.tool_use_result)==null?void 0:be.file)!=null&&Te.filePath)&&(x==null||x({type:"tool_use",jobId:r,tool:"Read",file:Y.tool_use_result.file.filePath},r))}catch(Y){}});let te=[];(J=w.stderr)==null||J.on("data",j=>{te.push(j.toString())}),w.on("close",j=>{G.close(),j!==0&&j!==null&&(Q=!0,ee=te.join("")||`Claude process exited with code ${j}`),I({sessionId:F,text:b.join(""),success:!Q,error:Q?ee:void 0,fileEdits:z.length>0?z:void 0})}),w.on("error",j=>{Q=!0,ee=j.message,I({sessionId:F,text:b.join(""),success:!1,error:ee,fileEdits:z.length>0?z:void 0})})});return{process:w,result:M}}import{spawn as Bt}from"child_process";import{createInterface as Ut}from"readline";function nt(r,t){let{prompt:n,projectRoot:e,screenshotPath:s,resumeSessionId:a,model:i,onEvent:c}=t,p=[];a?(p.push("exec","resume",a),i&&p.push("-m",i),p.push("--json","--full-auto",n),s&&p.push("--image",s)):(p.push("exec","--json","--full-auto"),i&&p.push("-m",i),p.push(n),s&&p.push("--image",s));let u=Bt("codex",p,{cwd:e,stdio:["ignore","pipe","pipe"],env:Z({},process.env)}),x=new Promise(L=>{var ee;let w,M=[],I=!1,F="",b=Ut({input:u.stdout}),z=new Set;b.on("line",G=>{var B,te,J,j;if(G.trim())try{let R=JSON.parse(G),q=(B=R.type)!=null?B:"unknown";if(z.add(q),q==="thread.started"&&R.thread_id&&!w&&(w=R.thread_id),q==="item/agentMessage/delta"&&((te=R.delta)!=null&&te.text)&&(M.push(R.delta.text),c==null||c({type:"delta",jobId:r,text:R.delta.text},r)),q==="item/reasoning/delta"&&((J=R.delta)!=null&&J.text)&&(c==null||c({type:"thinking",jobId:r,text:R.delta.text},r)),q==="item/started"&&R.item){let H=R.item.type;if(H==="command_execution")c==null||c({type:"tool_use",jobId:r,tool:"Bash"},r);else if(H==="file_change"){let K=R.item.filename||R.item.path;c==null||c(Z({type:"tool_use",jobId:r,tool:"Edit"},K?{file:K}:{}),r)}else if(H==="file_read"){let K=R.item.filename||R.item.path;c==null||c(Z({type:"tool_use",jobId:r,tool:"Read"},K?{file:K}:{}),r)}else if(H==="web_search")c==null||c({type:"tool_use",jobId:r,tool:"WebSearch"},r);else if(H==="mcp_tool_call"){let K=R.item.tool_name||R.item.name||"MCP";c==null||c({type:"tool_use",jobId:r,tool:K},r)}}if(q==="item/completed"&&R.item){if(R.item.type==="agent_message"){let H=R.item.text;typeof H=="string"&&H&&M.push(H)}else if(R.item.type==="reasoning"){let H=R.item.text;typeof H=="string"&&H&&(c==null||c({type:"thinking",jobId:r,text:H},r))}}q==="turn.failed"&&(I=!0,F=((j=R.error)==null?void 0:j.message)||R.message||"Turn failed")}catch(R){}});let Q=[];(ee=u.stderr)==null||ee.on("data",G=>{Q.push(G.toString())}),u.on("close",G=>{b.close(),G!==0&&G!==null&&(I=!0,F=Q.join("")||`Codex process exited with code ${G}`),L({sessionId:w,text:M.join(""),success:!I,error:I?F:void 0})}),u.on("error",G=>{I=!0,F=G.message,L({sessionId:w,text:M.join(""),success:!1,error:F})})});return{process:u,result:x}}import{execFile as Ft}from"child_process";import{copyFile as st,mkdir as ot,readdir as zt,readFile as jt,writeFile as Ht}from"fs/promises";import{join as pe}from"path";var Me=class{constructor(t){this.projectRoot=t;let n=pe(t,".popmelt");this.decisionsDir=pe(n,"decisions"),this.screenshotsDir=pe(n,"screenshots")}async persist(t,n,e){try{await ot(this.decisionsDir,{recursive:!0}),await ot(this.screenshotsDir,{recursive:!0});try{await st(n,pe(this.screenshotsDir,`s-${t.id}.png`))}catch(s){}for(let s=0;s<e.length;s++)try{let a=t.pastedImagePaths[s];a&&await st(e[s],pe(this.screenshotsDir,a.replace("screenshots/","")))}catch(a){}await Ht(pe(this.decisionsDir,`d-${t.id}.json`),JSON.stringify(t,null,2))}catch(s){console.error("[DecisionStore] Failed to persist decision record:",s)}}async listDecisionIds(){try{return(await zt(this.decisionsDir)).filter(n=>n.startsWith("d-")&&n.endsWith(".json")).map(n=>n.slice(2,-5))}catch(t){return[]}}async loadDecision(t){try{let n=await jt(pe(this.decisionsDir,`d-${t}.json`),"utf-8");return JSON.parse(n)}catch(n){return null}}async loadDecisions(t){return(await Promise.all(t.map(e=>this.loadDecision(e)))).filter(e=>e!==null)}captureGitDiff(t){return new Promise(n=>{Ft("git",["diff","HEAD"],{cwd:t,timeout:5e3,maxBuffer:1024*1024},(e,s)=>{if(e){n(null);return}n(s||null)})})}};import{readFile as rt,writeFile as fe}from"fs/promises";import{join as Ne}from"path";var oe="[Materializer]",Lt={version:1,materializedIds:[],lastRunAt:null,lastRunDecisionIds:[],lastRunError:null},Oe=class{constructor(t,n,e={}){this.projectRoot=t;this.decisionStore=n;this.options=e;this.cachedIndex=null;this.running=!1;let s=Ne(t,".popmelt");this.indexPath=Ne(s,"materialized.json"),this.modelPath=Ne(s,"model.json")}get isRunning(){return this.running}async loadModel(){try{let t=await rt(this.modelPath,"utf-8");return JSON.parse(t)}catch(t){return null}}async addComponent(t){let n=await this.loadModel();n||(n={tokens:{},components:{},rules:[]}),(!n.components||typeof n.components!="object")&&(n.components={});let e=n.components;return e[t]?{added:!1,alreadyExists:!0}:(e[t]={description:""},await fe(this.modelPath,JSON.stringify(n,null,2)),console.log(`${oe} Added component "${t}" to model`),{added:!0,alreadyExists:!1})}async updateToken(t,n){let e=await this.loadModel();e||(e={tokens:{},components:{},rules:[]});let s=t.split("."),a=e;for(let p=0;p<s.length-1;p++){let u=s[p];(!a[u]||typeof a[u]!="object")&&(a[u]={}),a=a[u]}let i=s[s.length-1],c;try{c=JSON.parse(n)}catch(p){c=null}if(c&&typeof c=="object"&&c!==null&&"value"in c)a[i]=c;else{let p=a[i];p&&typeof p=="object"&&p!==null&&"value"in p?p.value=n:a[i]=n}return await fe(this.modelPath,JSON.stringify(e,null,2)),console.log(`${oe} Updated token "${t}" \u2192 "${n.slice(0,80)}"`),{updated:!0}}async removeToken(t){let n=await this.loadModel();if(!n)return{removed:!1};let e=t.split("."),s=n;for(let i=0;i<e.length-1;i++){let c=e[i];if(!s[c]||typeof s[c]!="object")return{removed:!1};s=s[c]}let a=e[e.length-1];return a in s?(delete s[a],await fe(this.modelPath,JSON.stringify(n,null,2)),console.log(`${oe} Removed token "${t}" from model`),{removed:!0}):{removed:!1}}async removeComponent(t){let n=await this.loadModel();if(!n)return{removed:!1};let e=n.components;return!e||!e[t]?{removed:!1}:(delete e[t],await fe(this.modelPath,JSON.stringify(n,null,2)),console.log(`${oe} Removed component "${t}" from model`),{removed:!0})}async getUnmaterializedPatternDecisions(){let t=await this.loadIndex(),n=new Set(t.materializedIds),s=(await this.decisionStore.listDecisionIds()).filter(i=>!n.has(i));return s.length===0?[]:(await this.decisionStore.loadDecisions(s)).filter(i=>i.resolutions.some(c=>{var u;let p=(u=c.finalScope)!=null?u:c.inferredScope;return(p==null?void 0:p.breadth)==="pattern"}))}async run(){var t,n,e,s,a,i,c;if(this.running)return{processedIds:[],success:!0,error:"Already running"};this.running=!0;try{let p=await this.getUnmaterializedPatternDecisions();if(p.length===0)return{processedIds:[],success:!0};let u=p.map(b=>b.id);console.log(`${oe} Processing ${u.length} pattern-scoped decision(s): ${u.join(", ")}`),(n=(t=this.options).onEvent)==null||n.call(t,{type:"materialize_started",decisionIds:u});let x=await this.loadModel(),L=Gt(p,x),w=!0,M;try{let{result:b}=$e(`mat-${Date.now()}`,{prompt:L,projectRoot:this.projectRoot,maxTurns:(e=this.options.maxTurns)!=null?e:5,maxBudgetUsd:(s=this.options.maxBudgetUsd)!=null?s:.5,allowedTools:["Read"],claudePath:(a=this.options.claudePath)!=null?a:"claude"}),z=await b;if(!z.success)w=!1,M=z.error,console.error(`${oe} Claude spawn error:`,M);else{let Q=Wt(z.text);Q?(await fe(this.modelPath,JSON.stringify(Q,null,2)),console.log(`${oe} Successfully materialized ${u.length} decision(s) \u2192 ${this.modelPath}`)):(w=!1,M="No <model> block found in response",console.error(`${oe} ${M}`))}}catch(b){w=!1,M=b instanceof Error?b.message:String(b),console.error(`${oe} Error:`,M)}let I=await this.loadIndex(),F=new Set(I.materializedIds);for(let b of u)F.add(b);return I.materializedIds=[...F],I.lastRunAt=Date.now(),I.lastRunDecisionIds=u,I.lastRunError=M!=null?M:null,await this.persistIndex(I),(c=(i=this.options).onEvent)==null||c.call(i,{type:"materialize_done",decisionIds:u,success:w,error:M}),{processedIds:u,success:w,error:M}}finally{this.running=!1}}async loadIndex(){if(this.cachedIndex)return this.cachedIndex;try{let t=await rt(this.indexPath,"utf-8"),n=JSON.parse(t);return this.cachedIndex=n,n}catch(t){return this.cachedIndex=ae(Z({},Lt),{materializedIds:[],lastRunDecisionIds:[]}),this.cachedIndex}}async persistIndex(t){this.cachedIndex=t;try{await fe(this.indexPath,JSON.stringify(t,null,2))}catch(n){console.error(`${oe} Failed to write index:`,n)}}};function Wt(r){let t=r.match(/<model>\s*([\s\S]*?)\s*<\/model>/);if(!(t!=null&&t[1]))return null;try{let n=JSON.parse(t[1]);return typeof n!="object"||n===null||Array.isArray(n)?null:n}catch(n){return null}}function Gt(r,t){let n=r.map(s=>{let i=s.resolutions.filter(u=>{var L;let x=(L=u.finalScope)!=null?L:u.inferredScope;return(x==null?void 0:x.breadth)==="pattern"}).map(u=>{var M,I,F,b;let x=(M=u.finalScope)!=null?M:u.inferredScope,L=(I=x==null?void 0:x.target)!=null?I:"unknown",w=(b=(F=u.filesModified)==null?void 0:F.join(", "))!=null?b:"none";return`- **${u.summary}** [scope: pattern/${L}]
2
2
  Files modified: ${w}`}).join(`
3
3
  `),c=s.annotations.map(u=>u.instruction).filter(Boolean).join(`
4
4
  `),p=s.gitDiff?`
@@ -86,7 +86,7 @@ url = "${r}"
86
86
  `)}function Rt(r){let t=r.match(/<review>\s*([\s\S]*?)\s*<\/review>/);if(!(t!=null&&t[1]))return null;try{let n=JSON.parse(t[1]);return typeof n!="object"||n===null||n.verdict!=="pass"&&n.verdict!=="fail"||typeof n.summary!="string"?null:{verdict:n.verdict,summary:n.summary,issues:Array.isArray(n.issues)?n.issues.filter(e=>typeof e=="string"):void 0}}catch(n){return null}}var Ee=class{constructor(t=5){this.queue=[];this.activeJobs=new Map;this.activeProcesses=new Map;this.listeners=new Set;this.processor=null;this.maxConcurrency=t}setProcessor(t){this.processor=t}get active(){let t=this.activeJobs.values().next();return t.done?null:t.value}get allActive(){return Array.from(this.activeJobs.values())}get activeCount(){return this.activeJobs.size}get depth(){return this.queue.length}get isRunning(){return this.activeJobs.size>0}setActiveProcess(t,n){n?this.activeProcesses.set(t,n):this.activeProcesses.delete(t)}enqueue(t){return this.queue.push(t),this.processNext(),this.queue.length+this.activeJobs.size}addListener(t){return this.listeners.add(t),()=>this.listeners.delete(t)}broadcast(t,n){for(let e of this.listeners)e(t,n)}cancelJob(t){let n=this.activeProcesses.get(t),e=this.activeJobs.get(t);return!n||!e?!1:(n.kill("SIGTERM"),this.activeProcesses.delete(t),this.activeJobs.delete(t),e.status="error",e.error="Cancelled by user",this.broadcast({type:"error",jobId:e.id,message:"Cancelled by user"},e.id),this.processNext(),!0)}cancelActive(){if(this.activeJobs.size===0)return!1;let t=Array.from(this.activeJobs.keys());for(let n of t)this.cancelJob(n);return!0}destroy(){for(let t of this.activeProcesses.values())t.kill("SIGTERM");this.activeProcesses.clear(),this.activeJobs.clear(),this.queue=[],this.listeners.clear()}processNext(){for(;this.activeJobs.size<this.maxConcurrency&&this.queue.length>0&&this.processor;){let t=this.queue.shift();this.activeJobs.set(t.id,t),t.status="running",this.broadcast({type:"job_started",jobId:t.id,position:0},t.id),this.processor(t).catch(n=>{t.status="error",t.error=n instanceof Error?n.message:String(n),this.broadcast({type:"error",jobId:t.id,message:t.error},t.id)}).finally(()=>{this.activeJobs.delete(t.id),this.activeProcesses.delete(t.id),this.processNext(),this.activeJobs.size===0&&this.queue.length===0&&this.broadcast({type:"queue_drained"},t.id)})}}};import{mkdir as en,readFile as tn,writeFile as nn}from"fs/promises";import{dirname as sn,join as on}from"path";var rn={version:1,threads:{}},De=class{constructor(t){this.cache=null;this.writeChain=Promise.resolve();this.filePath=on(t,".popmelt","threads.json")}async load(){if(this.cache)return this.cache;try{let t=await tn(this.filePath,"utf-8"),n=JSON.parse(t);if(n&&n.version===1&&n.threads)return this.cache=n,this.cache}catch(t){}return this.cache=ae(Z({},rn),{threads:{}}),this.cache}async getThread(t){var e;return(e=(await this.load()).threads[t])!=null?e:null}async findContinuationThread(t){if(t.length===0)return null;let n=await this.load(),e=new Set(t);for(let s of Object.values(n.threads))if(s.elementIdentifiers.some(i=>e.has(i)))return s;return null}async createThread(t,n){let e=await this.load(),s={id:t,createdAt:Date.now(),updatedAt:Date.now(),elementIdentifiers:n,messages:[]};return e.threads[t]=s,await this.persist(),s}async appendMessage(t,n){let s=(await this.load()).threads[t];s&&(s.messages.push(n),s.updatedAt=Date.now(),await this.persist())}async addElementIdentifiers(t,n){let s=(await this.load()).threads[t];if(!s)return;let a=new Set(s.elementIdentifiers);for(let i of n)a.has(i)||s.elementIdentifiers.push(i);s.updatedAt=Date.now(),await this.persist()}async getThreadHistory(t,n=6){let e=await this.getThread(t);return!e||e.messages.length===0?[]:e.messages.length<=n?e.messages:[e.messages[0],...e.messages.slice(-(n-1))]}async persist(){this.writeChain=this.writeChain.then(async()=>{if(this.cache)try{await en(sn(this.filePath),{recursive:!0}),await nn(this.filePath,JSON.stringify(this.cache,null,2))}catch(t){console.error("[ThreadStore] Failed to persist:",t)}}),await this.writeChain}};var fn=1111,mn=["Read","Edit","Write","Glob","Grep","Bash","WebFetch","WebSearch","Bash(curl:*)"],gn=1800*1e3,yn=3600*1e3;function wn(r){if(!r)return!1;try{let t=new URL(r);return t.hostname==="localhost"||t.hostname==="127.0.0.1"}catch(t){return!1}}function vn(r,t){let n=r.headers.origin;wn(n)&&(t.setHeader("Access-Control-Allow-Origin",n),t.setHeader("Access-Control-Allow-Methods","GET, POST, PATCH, DELETE, OPTIONS"),t.setHeader("Access-Control-Allow-Headers","Content-Type"))}function g(r,t,n){r.writeHead(t,{"Content-Type":"application/json"}),r.end(JSON.stringify(n))}function Sn(r,t){if(!r)return t;let n=r.match(/^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i);if(!n)return t;let[,e,s,a]=n;return`\x1B[38;2;${parseInt(e,16)};${parseInt(s,16)};${parseInt(a,16)}m${t}\x1B[0m`}function $t(r,t){try{r.res.write(`event: ${t.type}
87
87
  data: ${JSON.stringify(t)}
88
88
 
89
- `)}catch(n){}}async function Ot(r={}){var we,He,Le,We,Ge,qe,Ye,Qe;let t=(we=r.port)!=null?we:fn,n=(He=r.projectRoot)!=null?He:process.cwd(),e=(Le=r.tempDir)!=null?Le:le(hn(),"popmelt-bridge"),s=(We=r.maxTurns)!=null?We:10,a=(Ge=r.maxBudgetUsd)!=null?Ge:1,i=(qe=r.allowedTools)!=null?qe:mn,c=(Ye=r.claudePath)!=null?Ye:"claude",p=(Qe=r.provider)!=null?Qe:"claude",u={};for(let o of["claude","codex"])try{let l=an("which",[o],{encoding:"utf-8"}).trim();u[o]={available:!0,path:l}}catch(l){u[o]={available:!1,path:null}}let[x,L]=await Promise.all([Fe(n),ze(n)]);u.claude&&(u.claude.mcp=x),u.codex&&(u.codex.mcp=L),await cn(e,{recursive:!0}),Mt(e).catch(()=>{});let w=new Ee(1),M=new Set,I=new De(n),F=new Me(n),b=new Oe(n,F,{claudePath:c,onEvent:o=>{for(let l of M)$t(l,o)}}),z=new Map;w.addListener((o,l)=>{for(let h of M)$t(h,o)}),w.setProcessor(async o=>{var V,se,E,ne,ie,ve,de;let l=o._replyPrompt,h=o._replyImagePaths,d=(V=o.provider)!=null?V:p,f;if(o.threadId){let $=await I.getThread(o.threadId);if($){for(let m=$.messages.length-1;m>=0;m--)if($.messages[m].sessionId){f=$.messages[m].sessionId;break}}}let P;if(f&&l){let $=(se=await I.getThread(o.threadId))==null?void 0:se.messages.filter(O=>O.role==="human").pop();if(P=($==null?void 0:$.replyToQuestion)||($==null?void 0:$.feedbackSummary)||"",h&&h.length>0){P+=`
89
+ `)}catch(n){}}async function Ot(r={}){var we,He,Le,We,Ge,qe,Ye,Qe;let t=(we=r.port)!=null?we:fn,n=(He=r.projectRoot)!=null?He:process.cwd(),e=(Le=r.tempDir)!=null?Le:le(hn(),"popmelt-bridge"),s=(We=r.maxTurns)!=null?We:40,a=(Ge=r.maxBudgetUsd)!=null?Ge:1,i=(qe=r.allowedTools)!=null?qe:mn,c=(Ye=r.claudePath)!=null?Ye:"claude",p=(Qe=r.provider)!=null?Qe:"claude",u={};for(let o of["claude","codex"])try{let l=an("which",[o],{encoding:"utf-8"}).trim();u[o]={available:!0,path:l}}catch(l){u[o]={available:!1,path:null}}let[x,L]=await Promise.all([Fe(n),ze(n)]);u.claude&&(u.claude.mcp=x),u.codex&&(u.codex.mcp=L),await cn(e,{recursive:!0}),Mt(e).catch(()=>{});let w=new Ee(1),M=new Set,I=new De(n),F=new Me(n),b=new Oe(n,F,{claudePath:c,onEvent:o=>{for(let l of M)$t(l,o)}}),z=new Map;w.addListener((o,l)=>{for(let h of M)$t(h,o)}),w.setProcessor(async o=>{var V,se,E,ne,ie,ve,de;let l=o._replyPrompt,h=o._replyImagePaths,d=(V=o.provider)!=null?V:p,f;if(o.threadId){let $=await I.getThread(o.threadId);if($){for(let m=$.messages.length-1;m>=0;m--)if($.messages[m].sessionId){f=$.messages[m].sessionId;break}}}let P;if(f&&l){let $=(se=await I.getThread(o.threadId))==null?void 0:se.messages.filter(O=>O.role==="human").pop();if(P=($==null?void 0:$.replyToQuestion)||($==null?void 0:$.feedbackSummary)||"",h&&h.length>0){P+=`
90
90
 
91
91
  The developer attached reference images with their reply:`;for(let O of h)P+=`
92
92
  Attached image: use the Read tool to view the image at: ${O}`}P+=`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@popmelt.com/core",
3
- "version": "0.5.4",
3
+ "version": "0.5.6",
4
4
  "description": "The design collaboration layer for AI coding agents",
5
5
  "license": "PolyForm-Shield-1.0.0",
6
6
  "author": "Popmelt <hello@popmelt.com> (https://popmelt.com)",