@devflow-tools/claude-code-plugin 0.13.3 → 0.14.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.
@@ -1,7 +1,8 @@
1
- import {createConnection}from'net';import {join}from'path';import {homedir}from'os';var f=join(homedir(),".devflow","hook-daemon.sock"),n=process.argv[2],d=process.argv[3];function t(){process.exit(1);}var o=createConnection(f,()=>{if(n==="stop")o.write(JSON.stringify({type:"stop"})+`
2
- `);else if(n==="post-tool-use")o.write(JSON.stringify({type:"post-tool-use",input:d||""})+`
3
- `);else if(n==="pre-tool-use"){let e="";process.stdin.setEncoding("utf8"),process.stdin.on("data",s=>{e+=s;}),process.stdin.on("end",()=>{o.write(JSON.stringify({type:"pre-tool-use",input:e})+`
4
- `);}),process.stdin.on("error",()=>t());}else t();}),r="";o.on("data",e=>{if(r+=e.toString(),r.includes(`
5
- `)){let s=r.split(`
6
- `).filter(Boolean);for(let i of s)process.stdout.write(i+`
7
- `);o.end();}});o.on("error",()=>t());o.on("close",()=>process.exit(0));setTimeout(()=>t(),4e3).unref();
1
+ import {createConnection}from'net';import {join}from'path';import {homedir}from'os';var l=join(homedir(),".devflow","hook-daemon.sock"),s=process.argv[2],d=process.argv[3];function t(){process.exit(1);}var e=createConnection(l,()=>{if(s==="stop")e.write(JSON.stringify({type:"stop"})+`
2
+ `);else if(s==="session-end")e.write(JSON.stringify({type:"session-end"})+`
3
+ `);else if(s==="post-tool-use")e.write(JSON.stringify({type:"post-tool-use",input:d||""})+`
4
+ `);else if(s==="pre-tool-use"){let o="";process.stdin.setEncoding("utf8"),process.stdin.on("data",n=>{o+=n;}),process.stdin.on("end",()=>{e.write(JSON.stringify({type:"pre-tool-use",input:o})+`
5
+ `);}),process.stdin.on("error",()=>t());}else t();}),i="";e.on("data",o=>{if(i+=o.toString(),i.includes(`
6
+ `)){let n=i.split(`
7
+ `).filter(Boolean);for(let r of n)process.stdout.write(r+`
8
+ `);e.end();}});e.on("error",()=>t());e.on("close",()=>process.exit(0));setTimeout(()=>t(),4e3).unref();
@@ -1,8 +1,8 @@
1
- import {createServer}from'net';import {join,dirname}from'path';import {homedir}from'os';import {existsSync,unlinkSync,readdirSync,readFileSync,mkdirSync,writeFileSync}from'fs';import {createHash}from'crypto';import {request}from'http';import {fileURLToPath}from'url';import {spawn}from'child_process';var $=1e4,lt=3e4,ut=300*1e3;function S(a,e,t){return new Promise(s=>{try{let o=new URL(a),n=request({hostname:o.hostname,port:o.port||80,path:o.pathname+o.search,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":t,"Content-Length":Buffer.byteLength(e)},timeout:5e3},r=>{let i=[];r.on("data",c=>i.push(c)),r.on("end",()=>{let c=Buffer.concat(i).toString();s(r.statusCode!=null&&r.statusCode>=200&&r.statusCode<300?c:null);});});n.on("error",()=>s(null)),n.on("timeout",()=>{n.destroy(),s(null);}),n.write(e),n.end();}catch{s(null);}})}var w=class{constructor(e){this.retryScheduled=false;this.retryAttempts=0;this.apiUrl=e?.apiUrl??process.env.DEVFLOW_API_URL??"http://127.0.0.1:13337",this.apiKey=e?.apiKey??process.env.DEVFLOW_API_KEY??"dev-key-000000",this.cacheDir=e?.cacheDir??join(homedir(),".devflow","telemetry-cache");}async sendEvent(e){let t=this.truncateInput(e.input),s={...e,input:t},o=`${this.apiUrl}/api/telemetry/tool-call`,n=await S(o,JSON.stringify(s),this.apiKey);if(n)try{let r=JSON.parse(n),i=r.data?.eventId??r.eventId??null;if(i)return i}catch{}return this.cacheEvent({type:"tool_call",payload:s}),null}async sendExecutionStart(e,t,s,o){let n={executionId:e,sessionId:t,skillName:s,startedAt:o},r=`${this.apiUrl}/api/telemetry/skill-execution/start`;await S(r,JSON.stringify(n),this.apiKey)||this.cacheEvent({type:"execution_start",payload:n});}async sendSessionStart(e,t,s){let o={id:e,projectRoot:t,startedAt:s,label:t.split("/").pop()??"unknown"},n=`${this.apiUrl}/api/telemetry/sessions`;return await S(n,JSON.stringify(o),this.apiKey)!==null}async flushCache(){if(!existsSync(this.cacheDir))return;let e=readdirSync(this.cacheDir).filter(t=>t.endsWith(".json"));for(let t of e)try{let s=join(this.cacheDir,t),o=readFileSync(s,"utf8"),n=JSON.parse(o),r=n.type==="execution_start"?"/api/telemetry/skill-execution/start":"/api/telemetry/tool-call",i=`${this.apiUrl}${r}`;await S(i,JSON.stringify(n.payload),this.apiKey)&&unlinkSync(s);}catch{}}cacheEvent(e){try{existsSync(this.cacheDir)||mkdirSync(this.cacheDir,{recursive:!0});let t=join(this.cacheDir,`${Date.now()}_${Math.random().toString(36).slice(2,11)}.json`);writeFileSync(t,JSON.stringify(e,null,2)),this.scheduleRetry();}catch{}}scheduleRetry(){if(this.retryScheduled)return;this.retryScheduled=true;let e=Math.min(lt*Math.pow(2,this.retryAttempts),ut);setTimeout(()=>{this.retryScheduled=false,this.flushCache().then(()=>{this.retryAttempts=0;}).catch(()=>{this.retryAttempts++;});},e).unref();}truncateInput(e){let t=JSON.stringify(e);return t.length<=$?e:{_truncated:true,_original_size:t.length,_preview:t.substring(0,$)+"..."}}};var ft=1800*1e3;function J(){return process.env.DEVFLOW_STATE_DIR??join(homedir(),".devflow")}function gt(){if(process.env.CLAUDE_PLUGIN_ROOT)return process.env.CLAUDE_PLUGIN_ROOT;try{let a=fileURLToPath(import.meta.url);return join(dirname(a),"..","..")}catch{return process.cwd()}}function yt(){let a=gt(),e=[join(a,"dist","command-registry.json"),join(a,"command-registry.json")],t=[];try{for(let s of e){if(existsSync(s)){let o=JSON.parse(readFileSync(s,"utf8")).commands;if(o)return o}t.push(`${s}: ${existsSync(s)?"found":"missing"}`);}}catch(s){t.push(`error: ${s.message}`);}try{writeFileSync(join(J(),"hook-debug.log"),JSON.stringify({ts:Date.now(),pluginRoot:a,CLAUDE_PLUGIN_ROOT:process.env.CLAUDE_PLUGIN_ROOT??"(unset)",cwd:process.cwd(),paths:t},null,2));}catch{}return null}function x(a){let e=yt();return e?e[a]?.mcpTools??[]:[]}var _=class{constructor(e){this.stateDir=J();}detect(){let e=join(this.stateDir,"current-skill.json");if(!existsSync(e))return null;try{let t=readFileSync(e,"utf8"),s=JSON.parse(t);return !s.registeredAt||Date.now()-s.registeredAt>ft?(this.endExecution(),null):s}catch{return null}}startExecution(e,t){existsSync(this.stateDir)||mkdirSync(this.stateDir,{recursive:true});let s=this.getCurrentExecutionId();if(s)return s;let o=`exec_${Date.now()}_${Math.random().toString(36).slice(2,11)}`;return writeFileSync(join(this.stateDir,"current-execution-id"),o),writeFileSync(join(this.stateDir,"current-skill.json"),JSON.stringify({name:e,required_mcp_tools:t?.required_mcp_tools??[],registeredAt:Date.now()})),o}getCurrentExecutionId(){let e=join(this.stateDir,"current-execution-id");if(!existsSync(e))return null;try{return readFileSync(e,"utf8").trim()}catch{return null}}endExecution(){let e=join(this.stateDir,"current-skill.json"),t=join(this.stateDir,"current-execution-id");try{existsSync(e)&&unlinkSync(e);}catch{}try{existsSync(t)&&unlinkSync(t);}catch{}}};var O=join(homedir(),".devflow"),j=join(O,"server-refs.json"),Rt="http://127.0.0.1:13337/api/health",Et=600*1e3,It=500;function Pt(){existsSync(O)||mkdirSync(O,{recursive:true});}function T(){try{if(existsSync(j))return JSON.parse(readFileSync(j,"utf-8"))}catch{}return {sessions:[],lastActivity:0}}function B(a){Pt(),writeFileSync(j,JSON.stringify(a));}var R=class{constructor(e){this.process=null;this.idleTimer=null;this.onShutdown=null;this.projectRoot=e;}setOnShutdown(e){this.onShutdown=e;}addRef(e){let t=T();t.sessions.includes(e)||t.sessions.push(e),t.lastActivity=Date.now(),B(t),this.resetIdleTimer();}removeRef(e){let t=T();t.sessions=t.sessions.filter(s=>s!==e),t.lastActivity=Date.now(),B(t),t.sessions.length===0&&this.resetIdleTimer();}get activeSessions(){return T().sessions.length}async ensureRunning(){return await this.healthCheck()?true:(await this.startServer(),this.waitForReady())}get isRunning(){return this.process!==null&&!this.process.killed}async stop(){this.idleTimer&&clearTimeout(this.idleTimer),this.process&&(this.process.kill("SIGTERM"),await new Promise(e=>{let t=setTimeout(()=>{this.process&&!this.process.killed&&this.process.kill("SIGKILL"),e();},5e3);this.process?this.process.on("exit",()=>{clearTimeout(t),e();}):(clearTimeout(t),e());}),this.process=null);}async startServer(){let e=join(this.projectRoot,"apps","server","dist","main.js"),t=join(this.projectRoot,"node_modules","@devflow-tools","server","dist","main.js"),s=existsSync(e)?e:t;this.process=spawn("node",[s],{cwd:this.projectRoot,env:{...process.env,NODE_ENV:process.env.NODE_ENV||"development"},stdio:["ignore","pipe","pipe"]}),this.process.stdout?.on("data",o=>{}),this.process.stderr?.on("data",o=>{}),this.process.on("exit",o=>{this.process=null,this.onShutdown&&this.onShutdown();}),this.process.on("error",()=>{this.process=null;});}async waitForReady(){let e=Date.now()+3e4;for(;Date.now()<e;){if(await this.healthCheck())return true;await new Promise(t=>setTimeout(t,It));}return false}healthCheck(){return new Promise(e=>{let t=new URL(Rt),s=request({hostname:t.hostname,port:t.port,path:t.pathname,method:"GET",timeout:2e3},o=>{e(o.statusCode===200);});s.on("error",()=>e(false)),s.on("timeout",()=>{s.destroy(),e(false);}),s.end();})}resetIdleTimer(){this.idleTimer&&clearTimeout(this.idleTimer),!(T().sessions.length>0)&&(this.idleTimer=setTimeout(()=>{this.stop();},Et).unref());}};var m=join(homedir(),".devflow","telemetry-buffer.jsonl"),W=500;function Dt(){let a=join(homedir(),".devflow");existsSync(a)||mkdirSync(a,{recursive:true});}var I=class{append(e){try{Dt();let t=[];existsSync(m)&&(t=readFileSync(m,"utf-8").split(`
1
+ import {createServer}from'net';import {join,dirname}from'path';import {homedir}from'os';import {existsSync,unlinkSync,readdirSync,readFileSync,mkdirSync,writeFileSync}from'fs';import {createHash}from'crypto';import {request}from'http';import {fileURLToPath}from'url';import {spawn}from'child_process';var F=1e4,lt=3e4,ut=300*1e3;function S(a,e,t){return new Promise(s=>{try{let n=new URL(a),o=request({hostname:n.hostname,port:n.port||80,path:n.pathname+n.search,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":t,"Content-Length":Buffer.byteLength(e)},timeout:5e3},r=>{let i=[];r.on("data",c=>i.push(c)),r.on("end",()=>{let c=Buffer.concat(i).toString();s(r.statusCode!=null&&r.statusCode>=200&&r.statusCode<300?c:null);});});o.on("error",()=>s(null)),o.on("timeout",()=>{o.destroy(),s(null);}),o.write(e),o.end();}catch{s(null);}})}var _=class{constructor(e){this.retryScheduled=false;this.retryAttempts=0;this.apiUrl=e?.apiUrl??process.env.DEVFLOW_API_URL??"http://127.0.0.1:13337",this.apiKey=e?.apiKey??process.env.DEVFLOW_API_KEY??"dev-key-000000",this.cacheDir=e?.cacheDir??join(homedir(),".devflow","telemetry-cache");}async sendEvent(e){let t=this.truncateInput(e.input),s={...e,input:t},n=`${this.apiUrl}/api/telemetry/tool-call`,o=await S(n,JSON.stringify(s),this.apiKey);if(o)try{let r=JSON.parse(o),i=r.data?.eventId??r.eventId??null;if(i)return i}catch{}return this.cacheEvent({type:"tool_call",payload:s}),null}async sendExecutionStart(e,t,s,n){let o={executionId:e,sessionId:t,skillName:s,startedAt:n},r=`${this.apiUrl}/api/telemetry/skill-execution/start`;await S(r,JSON.stringify(o),this.apiKey)||this.cacheEvent({type:"execution_start",payload:o});}async sendSessionStart(e,t,s){let n={id:e,projectRoot:t,startedAt:s,label:t.split("/").pop()??"unknown"},o=`${this.apiUrl}/api/telemetry/sessions`;return await S(o,JSON.stringify(n),this.apiKey)!==null}async flushCache(){if(!existsSync(this.cacheDir))return;let e=readdirSync(this.cacheDir).filter(t=>t.endsWith(".json"));for(let t of e)try{let s=join(this.cacheDir,t),n=readFileSync(s,"utf8"),o=JSON.parse(n),r=o.type==="execution_start"?"/api/telemetry/skill-execution/start":"/api/telemetry/tool-call",i=`${this.apiUrl}${r}`;await S(i,JSON.stringify(o.payload),this.apiKey)&&unlinkSync(s);}catch{}}cacheEvent(e){try{existsSync(this.cacheDir)||mkdirSync(this.cacheDir,{recursive:!0});let t=join(this.cacheDir,`${Date.now()}_${Math.random().toString(36).slice(2,11)}.json`);writeFileSync(t,JSON.stringify(e,null,2)),this.scheduleRetry();}catch{}}scheduleRetry(){if(this.retryScheduled)return;this.retryScheduled=true;let e=Math.min(lt*Math.pow(2,this.retryAttempts),ut);setTimeout(()=>{this.retryScheduled=false,this.flushCache().then(()=>{this.retryAttempts=0;}).catch(()=>{this.retryAttempts++;});},e).unref();}truncateInput(e){let t=JSON.stringify(e);return t.length<=F?e:{_truncated:true,_original_size:t.length,_preview:t.substring(0,F)+"..."}}};var ft=1800*1e3;function J(){return process.env.DEVFLOW_STATE_DIR??join(homedir(),".devflow")}function gt(){if(process.env.CLAUDE_PLUGIN_ROOT)return process.env.CLAUDE_PLUGIN_ROOT;try{let a=fileURLToPath(import.meta.url);return join(dirname(a),"..","..")}catch{return process.cwd()}}function yt(){let a=gt(),e=[join(a,"dist","command-registry.json"),join(a,"command-registry.json")],t=[];try{for(let s of e){if(existsSync(s)){let n=JSON.parse(readFileSync(s,"utf8")).commands;if(n)return n}t.push(`${s}: ${existsSync(s)?"found":"missing"}`);}}catch(s){t.push(`error: ${s.message}`);}try{writeFileSync(join(J(),"hook-debug.log"),JSON.stringify({ts:Date.now(),pluginRoot:a,CLAUDE_PLUGIN_ROOT:process.env.CLAUDE_PLUGIN_ROOT??"(unset)",cwd:process.cwd(),paths:t},null,2));}catch{}return null}function x(a){let e=yt();return e?e[a]?.mcpTools??[]:[]}var w=class{constructor(e){this.stateDir=J();}detect(){let e=join(this.stateDir,"current-skill.json");if(!existsSync(e))return null;try{let t=readFileSync(e,"utf8"),s=JSON.parse(t);return !s.registeredAt||Date.now()-s.registeredAt>ft?(this.endExecution(),null):s}catch{return null}}startExecution(e,t){existsSync(this.stateDir)||mkdirSync(this.stateDir,{recursive:true});let s=this.getCurrentExecutionId();if(s)return s;let n=`exec_${Date.now()}_${Math.random().toString(36).slice(2,11)}`;return writeFileSync(join(this.stateDir,"current-execution-id"),n),writeFileSync(join(this.stateDir,"current-skill.json"),JSON.stringify({name:e,required_mcp_tools:t?.required_mcp_tools??[],registeredAt:Date.now()})),n}getCurrentExecutionId(){let e=join(this.stateDir,"current-execution-id");if(!existsSync(e))return null;try{return readFileSync(e,"utf8").trim()}catch{return null}}endExecution(){let e=join(this.stateDir,"current-skill.json"),t=join(this.stateDir,"current-execution-id");try{existsSync(e)&&unlinkSync(e);}catch{}try{existsSync(t)&&unlinkSync(t);}catch{}}};var O=join(homedir(),".devflow"),j=join(O,"server-refs.json"),Rt="http://127.0.0.1:13337/api/health",Et=600*1e3,It=500;function Dt(){existsSync(O)||mkdirSync(O,{recursive:true});}function T(){try{if(existsSync(j))return JSON.parse(readFileSync(j,"utf-8"))}catch{}return {sessions:[],lastActivity:0}}function B(a){Dt(),writeFileSync(j,JSON.stringify(a));}var R=class{constructor(e){this.process=null;this.idleTimer=null;this.onShutdown=null;this.projectRoot=e;}setOnShutdown(e){this.onShutdown=e;}addRef(e){let t=T();t.sessions.includes(e)||t.sessions.push(e),t.lastActivity=Date.now(),B(t),this.resetIdleTimer();}removeRef(e){let t=T();t.sessions=t.sessions.filter(s=>s!==e),t.lastActivity=Date.now(),B(t),t.sessions.length===0&&this.resetIdleTimer();}get activeSessions(){return T().sessions.length}async ensureRunning(){return await this.healthCheck()?true:(await this.startServer(),this.waitForReady())}get isRunning(){return this.process!==null&&!this.process.killed}async stop(){this.idleTimer&&clearTimeout(this.idleTimer),this.process&&(this.process.kill("SIGTERM"),await new Promise(e=>{let t=setTimeout(()=>{this.process&&!this.process.killed&&this.process.kill("SIGKILL"),e();},5e3);this.process?this.process.on("exit",()=>{clearTimeout(t),e();}):(clearTimeout(t),e());}),this.process=null);}async startServer(){let e=join(this.projectRoot,"apps","server","dist","main.js"),t=join(this.projectRoot,"node_modules","@devflow-tools","server","dist","main.js"),s=existsSync(e)?e:t;this.process=spawn("node",[s],{cwd:this.projectRoot,env:{...process.env,NODE_ENV:process.env.NODE_ENV||"development"},stdio:["ignore","pipe","pipe"]}),this.process.stdout?.on("data",n=>{}),this.process.stderr?.on("data",n=>{}),this.process.on("exit",n=>{this.process=null,this.onShutdown&&this.onShutdown();}),this.process.on("error",()=>{this.process=null;});}async waitForReady(){let e=Date.now()+3e4;for(;Date.now()<e;){if(await this.healthCheck())return true;await new Promise(t=>setTimeout(t,It));}return false}healthCheck(){return new Promise(e=>{let t=new URL(Rt),s=request({hostname:t.hostname,port:t.port,path:t.pathname,method:"GET",timeout:2e3},n=>{e(n.statusCode===200);});s.on("error",()=>e(false)),s.on("timeout",()=>{s.destroy(),e(false);}),s.end();})}resetIdleTimer(){this.idleTimer&&clearTimeout(this.idleTimer),!(T().sessions.length>0)&&(this.idleTimer=setTimeout(()=>{this.stop();},Et).unref());}};var m=join(homedir(),".devflow","telemetry-buffer.jsonl"),W=500;function Pt(){let a=join(homedir(),".devflow");existsSync(a)||mkdirSync(a,{recursive:true});}var I=class{append(e){try{Pt();let t=[];existsSync(m)&&(t=readFileSync(m,"utf-8").split(`
2
2
  `).filter(s=>s.trim())),t.push(JSON.stringify(e)),t.length>W&&(t=t.slice(t.length-W)),writeFileSync(m,t.join(`
3
3
  `)+`
4
4
  `);}catch{}}readAll(){try{return existsSync(m)?readFileSync(m,"utf-8").split(`
5
- `).filter(e=>e.trim()):[]}catch{return []}}clear(){try{existsSync(m)&&writeFileSync(m,"");}catch{}}get size(){return this.readAll().length}};var v=join(homedir(),".devflow","hook-daemon.sock");join(homedir(),".devflow");var jt=600*1e3,Y={Agent:"get_project_context",Bash:"get_project_context",Glob:"get_project_context",Grep:"get_project_context",WebSearch:"get_knowledge",WebFetch:"get_knowledge"};function At(a){switch(a){case "WebSearch":case "WebFetch":return 1;case "Agent":return 3;case "Grep":case "Glob":return 3;case "Bash":return 5;default:return 2}}function Ut(a){switch(a){case "Read":case "Glob":return "file_read";case "Write":case "Edit":case "NotebookEdit":return "file_write";case "Bash":return "bash_command";case "Agent":return "subagent";case "Skill":return "skill_invoke";default:return "tool_use"}}function tt(a){let e=createHash("sha256").update(a).digest("hex").slice(0,16);return join(process.env.TMPDIR||"/tmp",".devflow-receipts",`${e}.json`)}function Z(a){try{let e=tt(a);return existsSync(e)?JSON.parse(readFileSync(e,"utf-8")):{}}catch{return {}}}function P(a,e){try{let t=tt(a),s=join(process.env.TMPDIR||"/tmp",".devflow-receipts");existsSync(s)||mkdirSync(s,{recursive:!0}),writeFileSync(t,JSON.stringify(e));}catch{}}var U=class{constructor(e){this.sessionId=null;this.eventMap=[];this.idleTimer=null;this.projectRoot=e,this.projectName=e.split("/").pop()||"unknown",this.telemetry=new w,this.skillManager=new _,this.serverManager=new R(e),this.telemetryBuffer=new I;}async start(){try{existsSync(v)&&unlinkSync(v);}catch{}let e=createServer(t=>{this.resetIdleTimer();let s="";t.on("data",async o=>{s+=o.toString();let n=s.split(`
6
- `);s=n.pop()||"";for(let r of n)if(r.trim())try{let i=JSON.parse(r),c=await this.handleRequest(i);c!==null&&t.write(JSON.stringify(c)+`
5
+ `).filter(e=>e.trim()):[]}catch{return []}}clear(){try{existsSync(m)&&writeFileSync(m,"");}catch{}}get size(){return this.readAll().length}};var v=join(homedir(),".devflow","hook-daemon.sock");join(homedir(),".devflow");var jt=600*1e3,Y={Agent:"get_project_context",Bash:"get_project_context",Glob:"get_project_context",Grep:"get_project_context",WebSearch:"get_knowledge",WebFetch:"get_knowledge"};function At(a){switch(a){case "WebSearch":case "WebFetch":return 1;case "Agent":return 3;case "Grep":case "Glob":return 3;case "Bash":return 5;default:return 2}}function Ut(a){switch(a){case "Read":case "Glob":return "file_read";case "Write":case "Edit":case "NotebookEdit":return "file_write";case "Bash":return "bash_command";case "Agent":return "subagent";case "Skill":return "skill_invoke";default:return "tool_use"}}function tt(a){let e=createHash("sha256").update(a).digest("hex").slice(0,16);return join(process.env.TMPDIR||"/tmp",".devflow-receipts",`${e}.json`)}function Z(a){try{let e=tt(a);return existsSync(e)?JSON.parse(readFileSync(e,"utf-8")):{}}catch{return {}}}function D(a,e){try{let t=tt(a),s=join(process.env.TMPDIR||"/tmp",".devflow-receipts");existsSync(s)||mkdirSync(s,{recursive:!0}),writeFileSync(t,JSON.stringify(e));}catch{}}var U=class{constructor(e){this.sessionId=null;this.eventMap=[];this.idleTimer=null;this.projectRoot=e,this.projectName=e.split("/").pop()||"unknown",this.telemetry=new _,this.skillManager=new w,this.serverManager=new R(e),this.telemetryBuffer=new I;}async start(){try{existsSync(v)&&unlinkSync(v);}catch{}let e=createServer(t=>{this.resetIdleTimer();let s="";t.on("data",async n=>{s+=n.toString();let o=s.split(`
6
+ `);s=o.pop()||"";for(let r of o)if(r.trim())try{let i=JSON.parse(r),c=await this.handleRequest(i);c!==null&&t.write(JSON.stringify(c)+`
7
7
  `);}catch(i){t.write(JSON.stringify({error:i.message})+`
8
- `);}}),t.on("error",()=>{});});e.on("error",t=>{console.error("[devflow-daemon] Server error:",t.message);}),e.listen(v,()=>{console.error("[devflow-daemon] Listening on",v);}),this.flushBuffer(),this.resetIdleTimer();}resetIdleTimer(){this.idleTimer&&clearTimeout(this.idleTimer),this.idleTimer=setTimeout(()=>{console.error("[devflow-daemon] Idle timeout, exiting"),this.shutdown();},jt).unref();}async handleRequest(e){switch(e.type){case "pre-tool-use":return this.handlePreToolUse(e.input);case "post-tool-use":return this.handlePostToolUse(e.input);case "stop":return await this.handleStop(),{status:"ok"};default:return {error:"unknown request type"}}}async handlePreToolUse(e){try{if(!e||e.trim()==="")return {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow"}};let t=JSON.parse(e);if(this.sessionId||(this.sessionId=`session:${this.projectName}:${Date.now().toString(36)}`,this.telemetry.sendSessionStart(this.sessionId,this.projectRoot,Date.now()).catch(()=>{})),t.tool_name==="Skill"){let l=t.tool_input?.skill;if(l&&l.startsWith("devflow:")){let D=x(l),y=this.skillManager.startExecution(l,{required_mcp_tools:D});this.telemetry.sendExecutionStart(y,this.sessionId,l,Date.now()).catch(()=>{});}}let s=this.skillManager.detect(),o=t.tool_name.startsWith("mcp__"),n=o?t.tool_name.replace(/^mcp__[^_]+__/,""):void 0,r=s?.required_mcp_tools??[],i=r.length>0,c=i&&!o&&t.tool_name!=="Skill",p;if(c)p={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow",additionalContext:`\u5EFA\u8BAE\u5148\u8C03\u7528 ${r[0]||"get_project_context"} \u83B7\u53D6\u9879\u76EE\u4E0A\u4E0B\u6587\uFF0C\u7ED3\u679C\u4F1A\u66F4\u7CBE\u786E\u3002`}};else if(!o&&t.tool_name!=="Skill"){let D=Z(this.projectRoot).bypassCount??0,y=Y[t.tool_name],et=y?At(t.tool_name):1/0;y&&D>=et?p={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow",additionalContext:`\u5DF2\u591A\u6B21\u4F7F\u7528 ${t.tool_name}\uFF0C\u5EFA\u8BAE\u5207\u6362\u5230 ${y} \u83B7\u53D6\u66F4\u7CBE\u786E\u7684\u4E0A\u4E0B\u6587\u3002`}}:p={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow"}};}else p={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow"}};let g=this.skillManager.getCurrentExecutionId()??this.sessionId,f={eventId:`evt_${Date.now()}_${Math.random().toString(36).slice(2,11)}`,executionId:g,sessionId:this.sessionId,timestamp:Date.now(),toolName:t.tool_name,toolType:o?"mcp":t.tool_name==="Agent"?"subagent":"direct",isMcpTool:o,mcpToolName:n,mcpEnforced:o&&i,mcpFallback:!o&&i,kind:Ut(t.tool_name),input:t.tool_input,duration:0,blocked:p&&p.hookSpecificOutput?.permissionDecision==="deny"};return this.telemetry.sendEvent(f).then(l=>{l&&this.eventMap.push({toolName:t.tool_name,eventId:l,timestamp:f.timestamp});}).catch(()=>{}),p}catch{return {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow"}}}}popEventFromMap(e){let t=this.eventMap.filter(o=>o.toolName===e);if(t.length===0)return null;t.sort((o,n)=>Math.abs(o.timestamp-Date.now())-Math.abs(n.timestamp-Date.now()));let s=t[0];return this.eventMap=this.eventMap.filter(o=>o.eventId!==s.eventId),s}enforcePostToolUse(e){if(!Y[e])return null;let t=Z(this.projectRoot),s=t.lastMcpCall??0;if(Math.floor(Date.now()/1e3)-s<30)return null;let n=t.bypassCount??0;if(n===0)return P(this.projectRoot,{...t,bypassCount:1}),null;let r=n+1;P(this.projectRoot,{...t,bypassCount:r});let i;switch(e){case "Agent":i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u4F60\u521A\u624D\u4F7F\u7528\u4E86 Agent \u5B50\u4EE3\u7406\u6267\u884C\u641C\u7D22\u3002\u4E0B\u6B21\u8BF7\u7528 get_project_context MCP \u5DE5\u5177\u66FF\u4EE3\u3002`;break;case "Bash":i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u4F60\u521A\u624D\u7528\u4E86 Bash \u547D\u4EE4\u641C\u7D22\u4EE3\u7801\u3002\u4E0B\u6B21\u8BF7\u7528 get_project_context MCP \u5DE5\u5177\u66FF\u4EE3\u3002`;break;case "Glob":i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u4F60\u521A\u624D\u7528\u4E86 Glob \u5339\u914D\u6587\u4EF6\u3002\u4E0B\u6B21\u8BF7\u7528 get_project_context MCP \u5DE5\u5177\u66FF\u4EE3\u3002`;break;case "Grep":i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u4F60\u521A\u624D\u7528\u4E86 Grep \u641C\u7D22\u4EE3\u7801\u3002\u4E0B\u6B21\u8BF7\u7528 get_project_context MCP \u5DE5\u5177\u66FF\u4EE3\u3002`;break;case "WebSearch":case "WebFetch":i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u4F60\u521A\u624D\u7528\u4E86\u7F51\u7EDC\u641C\u7D22\u3002\u4E0B\u6B21\u8BF7\u7528 get_knowledge MCP \u5DE5\u5177\u66FF\u4EE3\u3002`;break;default:i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u8BF7\u4F7F\u7528 DevFlow MCP \u5DE5\u5177\u66FF\u4EE3\u76F4\u63A5\u8C03\u7528\u3002`;}return r>=3?i=`${i} \u5DF2\u8FBE\u5230\u6700\u5927\u8FDD\u89C4\u6B21\u6570\uFF0C\u540E\u7EED\u7ED5\u8FC7\u5C06\u88AB\u786C\u963B\u6B62\u3002`:r>=2?i=`${i} \u4E0B\u6B21\u8FDD\u89C4\u5C06\u88AB\u963B\u6B62\u3002`:i=`${i} \u8BF7\u7ACB\u5373\u7EA0\u6B63\u3002`,i}async handlePostToolUse(e){if(!e)return null;let t;try{t=JSON.parse(e);}catch{return null}let s=t.tool_name||"",o=t.tool_input||{},n=t.tool_response;if(s==="Skill"){let h=o?.skill;if(h&&h.startsWith("devflow:")){let f=x(h);this.skillManager.startExecution(h,{required_mcp_tools:f}),P(this.projectRoot,{lastMcpCall:Math.floor(Date.now()/1e3),bypassCount:0});}}s.startsWith("mcp__")&&P(this.projectRoot,{lastMcpCall:Math.floor(Date.now()/1e3),bypassCount:0});let r=this.popEventFromMap(s);if(r&&this.sessionId){let h=typeof n=="string"?n:JSON.stringify(n),f=h.length>5e3?{_truncated:true,_originalSize:h.length,text:h.slice(0,5e3)}:n,l=Date.now()-r.timestamp;this.sendHttp("/api/telemetry/tool-call/output",{eventId:r.eventId,sessionId:this.sessionId,output:f,duration:l,completedAt:Date.now()});}let i=typeof n=="object"&&n!==null?n:null,c=i?.exitCode,p=i?.stderr;s==="Bash"&&c!==void 0&&c!==0&&this.sendHttp(`/api/memory/events?rootPath=${encodeURIComponent(this.projectRoot)}`,{id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:this.sessionId??`session:${this.projectName}`,tool:s,command:o.command||s,exitCode:c,stderr:p??null,durationMs:0,createdAt:Date.now()});let g=this.enforcePostToolUse(s);return g?(console.error("[devflow-daemon] Enforcement:",g),{hookSpecificOutput:{hookEventName:"PostToolUse",additionalContext:JSON.stringify(g)}}):null}sendHttp(e,t){let s=JSON.stringify(t),o=new URL(e,"http://127.0.0.1:13337"),n=request({hostname:o.hostname,port:o.port,path:o.pathname+o.search,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":"dev-key-000000","Content-Length":Buffer.byteLength(s)},timeout:5e3},r=>{r.statusCode===200&&this.flushBuffer();});n.on("error",()=>{this.telemetryBuffer.append({path:e,data:t,timestamp:Date.now()});}),n.write(s),n.end();}flushBuffer(){let e=this.telemetryBuffer.readAll();if(e.length!==0){for(let t of e)try{let s=JSON.parse(t),o=JSON.stringify(s.data),n=new URL(s.path,"http://127.0.0.1:13337"),r=request({hostname:n.hostname,port:n.port,path:n.pathname+n.search,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":"dev-key-000000","Content-Length":Buffer.byteLength(o)},timeout:5e3},()=>{});r.on("error",()=>{}),r.write(o),r.end();}catch{}this.telemetryBuffer.clear();}}async handleStop(){this.sessionId&&(this.sendHttp(`/api/telemetry/sessions/${this.sessionId}/close`,{finishedAt:Date.now()}),this.serverManager.removeRef(this.sessionId)),this.sendHttp(`/api/memory/process?rootPath=${encodeURIComponent(this.projectRoot)}`,{}),await this.telemetry.flushCache().catch(()=>{}),this.shutdown();}shutdown(){this.idleTimer&&clearTimeout(this.idleTimer);try{unlinkSync(v);}catch{}this.serverManager.stop(),process.exit(0);}},Lt=process.argv[2]||process.env.CLAUDE_PROJECT_DIR||process.cwd(),Ft=new U(Lt);Ft.start().catch(a=>{console.error("[devflow-daemon] Failed to start:",a),process.exit(1);});
8
+ `);}}),t.on("error",()=>{});});e.on("error",t=>{console.error("[devflow-daemon] Server error:",t.message);}),e.listen(v,()=>{console.error("[devflow-daemon] Listening on",v);}),this.flushBuffer(),this.resetIdleTimer();}resetIdleTimer(){this.idleTimer&&clearTimeout(this.idleTimer),this.idleTimer=setTimeout(()=>{console.error("[devflow-daemon] Idle timeout, exiting"),this.shutdown();},jt).unref();}async handleRequest(e){switch(e.type){case "pre-tool-use":return this.handlePreToolUse(e.input);case "post-tool-use":return this.handlePostToolUse(e.input);case "stop":return {status:"ok",result:this.handleStop()};case "session-end":return this.handleSessionEnd(),{status:"ok"};default:return {error:"unknown request type"}}}async handlePreToolUse(e){try{if(!e||e.trim()==="")return {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow"}};let t=JSON.parse(e);if(this.sessionId||(this.sessionId=`session:${this.projectName}:${Date.now().toString(36)}`,this.telemetry.sendSessionStart(this.sessionId,this.projectRoot,Date.now()).catch(()=>{})),t.tool_name==="Skill"){let l=t.tool_input?.skill;if(l&&l.startsWith("devflow:")){let P=x(l),y=this.skillManager.startExecution(l,{required_mcp_tools:P});this.telemetry.sendExecutionStart(y,this.sessionId,l,Date.now()).catch(()=>{});}}let s=this.skillManager.detect(),n=t.tool_name.startsWith("mcp__"),o=n?t.tool_name.replace(/^mcp__[^_]+__/,""):void 0,r=s?.required_mcp_tools??[],i=r.length>0,c=i&&!n&&t.tool_name!=="Skill",p;if(c)p={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow",additionalContext:`\u5EFA\u8BAE\u5148\u8C03\u7528 ${r[0]||"get_project_context"} \u83B7\u53D6\u9879\u76EE\u4E0A\u4E0B\u6587\uFF0C\u7ED3\u679C\u4F1A\u66F4\u7CBE\u786E\u3002`}};else if(!n&&t.tool_name!=="Skill"){let P=Z(this.projectRoot).bypassCount??0,y=Y[t.tool_name],et=y?At(t.tool_name):1/0;y&&P>=et?p={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow",additionalContext:`\u5DF2\u591A\u6B21\u4F7F\u7528 ${t.tool_name}\uFF0C\u5EFA\u8BAE\u5207\u6362\u5230 ${y} \u83B7\u53D6\u66F4\u7CBE\u786E\u7684\u4E0A\u4E0B\u6587\u3002`}}:p={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow"}};}else p={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow"}};let g=this.skillManager.getCurrentExecutionId()??this.sessionId,f={eventId:`evt_${Date.now()}_${Math.random().toString(36).slice(2,11)}`,executionId:g,sessionId:this.sessionId,timestamp:Date.now(),toolName:t.tool_name,toolType:n?"mcp":t.tool_name==="Agent"?"subagent":"direct",isMcpTool:n,mcpToolName:o,mcpEnforced:n&&i,mcpFallback:!n&&i,kind:Ut(t.tool_name),input:t.tool_input,duration:0,blocked:p&&p.hookSpecificOutput?.permissionDecision==="deny"};return this.telemetry.sendEvent(f).then(l=>{l&&this.eventMap.push({toolName:t.tool_name,eventId:l,timestamp:f.timestamp});}).catch(()=>{}),p}catch{return {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow"}}}}popEventFromMap(e){let t=this.eventMap.filter(n=>n.toolName===e);if(t.length===0)return null;t.sort((n,o)=>Math.abs(n.timestamp-Date.now())-Math.abs(o.timestamp-Date.now()));let s=t[0];return this.eventMap=this.eventMap.filter(n=>n.eventId!==s.eventId),s}enforcePostToolUse(e){if(!Y[e])return null;let t=Z(this.projectRoot),s=t.lastMcpCall??0;if(Math.floor(Date.now()/1e3)-s<30)return null;let o=t.bypassCount??0;if(o===0)return D(this.projectRoot,{...t,bypassCount:1}),null;let r=o+1;D(this.projectRoot,{...t,bypassCount:r});let i;switch(e){case "Agent":i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u4F60\u521A\u624D\u4F7F\u7528\u4E86 Agent \u5B50\u4EE3\u7406\u6267\u884C\u641C\u7D22\u3002\u4E0B\u6B21\u8BF7\u7528 get_project_context MCP \u5DE5\u5177\u66FF\u4EE3\u3002`;break;case "Bash":i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u4F60\u521A\u624D\u7528\u4E86 Bash \u547D\u4EE4\u641C\u7D22\u4EE3\u7801\u3002\u4E0B\u6B21\u8BF7\u7528 get_project_context MCP \u5DE5\u5177\u66FF\u4EE3\u3002`;break;case "Glob":i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u4F60\u521A\u624D\u7528\u4E86 Glob \u5339\u914D\u6587\u4EF6\u3002\u4E0B\u6B21\u8BF7\u7528 get_project_context MCP \u5DE5\u5177\u66FF\u4EE3\u3002`;break;case "Grep":i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u4F60\u521A\u624D\u7528\u4E86 Grep \u641C\u7D22\u4EE3\u7801\u3002\u4E0B\u6B21\u8BF7\u7528 get_project_context MCP \u5DE5\u5177\u66FF\u4EE3\u3002`;break;case "WebSearch":case "WebFetch":i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u4F60\u521A\u624D\u7528\u4E86\u7F51\u7EDC\u641C\u7D22\u3002\u4E0B\u6B21\u8BF7\u7528 get_knowledge MCP \u5DE5\u5177\u66FF\u4EE3\u3002`;break;default:i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u8BF7\u4F7F\u7528 DevFlow MCP \u5DE5\u5177\u66FF\u4EE3\u76F4\u63A5\u8C03\u7528\u3002`;}return r>=3?i=`${i} \u5DF2\u8FBE\u5230\u6700\u5927\u8FDD\u89C4\u6B21\u6570\uFF0C\u540E\u7EED\u7ED5\u8FC7\u5C06\u88AB\u786C\u963B\u6B62\u3002`:r>=2?i=`${i} \u4E0B\u6B21\u8FDD\u89C4\u5C06\u88AB\u963B\u6B62\u3002`:i=`${i} \u8BF7\u7ACB\u5373\u7EA0\u6B63\u3002`,i}async handlePostToolUse(e){if(!e)return null;let t;try{t=JSON.parse(e);}catch{return null}let s=t.tool_name||"",n=t.tool_input||{},o=t.tool_response;if(s==="Skill"){let h=n?.skill;if(h&&h.startsWith("devflow:")){let f=x(h);this.skillManager.startExecution(h,{required_mcp_tools:f}),D(this.projectRoot,{lastMcpCall:Math.floor(Date.now()/1e3),bypassCount:0});}}s.startsWith("mcp__")&&D(this.projectRoot,{lastMcpCall:Math.floor(Date.now()/1e3),bypassCount:0});let r=this.popEventFromMap(s);if(r&&this.sessionId){let h=typeof o=="string"?o:JSON.stringify(o),f=h.length>5e3?{_truncated:true,_originalSize:h.length,text:h.slice(0,5e3)}:o,l=Date.now()-r.timestamp;this.sendHttp("/api/telemetry/tool-call/output",{eventId:r.eventId,sessionId:this.sessionId,output:f,duration:l,completedAt:Date.now()});}let i=typeof o=="object"&&o!==null?o:null,c=i?.exitCode,p=i?.stderr;s==="Bash"&&c!==void 0&&c!==0&&this.sendHttp(`/api/memory/events?rootPath=${encodeURIComponent(this.projectRoot)}`,{id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:this.sessionId??`session:${this.projectName}`,tool:s,command:n.command||s,exitCode:c,stderr:p??null,durationMs:0,createdAt:Date.now()});let g=this.enforcePostToolUse(s);return g?(console.error("[devflow-daemon] Enforcement:",g),{hookSpecificOutput:{hookEventName:"PostToolUse",additionalContext:JSON.stringify(g)}}):null}sendHttp(e,t){let s=JSON.stringify(t),n=new URL(e,"http://127.0.0.1:13337"),o=request({hostname:n.hostname,port:n.port,path:n.pathname+n.search,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":"dev-key-000000","Content-Length":Buffer.byteLength(s)},timeout:5e3},r=>{r.statusCode===200&&this.flushBuffer();});o.on("error",()=>{this.telemetryBuffer.append({path:e,data:t,timestamp:Date.now()});}),o.write(s),o.end();}flushBuffer(){let e=this.telemetryBuffer.readAll();if(e.length!==0){for(let t of e)try{let s=JSON.parse(t),n=JSON.stringify(s.data),o=new URL(s.path,"http://127.0.0.1:13337"),r=request({hostname:o.hostname,port:o.port,path:o.pathname+o.search,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":"dev-key-000000","Content-Length":Buffer.byteLength(n)},timeout:5e3},()=>{});r.on("error",()=>{}),r.write(n),r.end();}catch{}this.telemetryBuffer.clear();}}handleStop(){this.sessionId&&this.sendHttp(`/api/telemetry/sessions/${this.sessionId}/tick`,{timestamp:Date.now()});}handleSessionEnd(){this.sessionId&&(this.sendHttp(`/api/telemetry/sessions/${this.sessionId}/close`,{finishedAt:Date.now()}),this.serverManager.removeRef(this.sessionId)),this.sendHttp(`/api/memory/process?rootPath=${encodeURIComponent(this.projectRoot)}`,{trigger:"session_end",sessionId:this.sessionId}),this.telemetry.flushCache().catch(()=>{}),this.shutdown();}shutdown(){this.idleTimer&&clearTimeout(this.idleTimer);try{unlinkSync(v);}catch{}this.serverManager.stop(),process.exit(0);}},Lt=process.argv[2]||process.env.CLAUDE_PROJECT_DIR||process.cwd(),$t=new U(Lt);$t.start().catch(a=>{console.error("[devflow-daemon] Failed to start:",a),process.exit(1);});
@@ -0,0 +1,2 @@
1
+ import {request}from'http';var c=process.env.DEVFLOW_SERVER_URL||"http://127.0.0.1:13337",p=process.env.DEVFLOW_API_KEY||"dev-key-000000",i=process.env.CLAUDE_PROJECT_DIR||process.cwd();function d(t,o){return new Promise(s=>{let e=JSON.stringify(o),n=new URL(t,c),r=request({hostname:n.hostname,port:n.port,path:n.pathname,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":p,"Content-Length":Buffer.byteLength(e)},timeout:5e3},()=>s());r.on("error",()=>s()),r.write(e),r.end();})}async function u(t){let o;try{o=JSON.parse(t);}catch{return}let s=o.tool_name||"",e=o.tool_input||{},n=o.error||"",r={id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:o.session_id??`session:${i.split("/").pop()||"default"}`,tool:s,command:typeof e=="object"&&e.command?e.command:s,exitCode:-1,stderr:n,durationMs:0,createdAt:Date.now(),failureSource:"PostToolUseFailure"};d(`/api/memory/events?rootPath=${encodeURIComponent(i)}`,r).catch(()=>{});}if(process.argv[1]?.endsWith("post-tool-use-failure")||process.argv[1]?.endsWith("post-tool-use-failure.js")){let t="";process.stdin.setEncoding("utf8"),process.stdin.on("data",o=>{t+=o;}),process.stdin.on("end",async()=>{await u(t.trim()||process.argv[2]||""),process.exit(0);}),process.stdin.on("error",()=>process.exit(0)),setTimeout(()=>process.exit(0),5e3).unref();}
2
+ export{u as handlePostToolUseFailure};
@@ -0,0 +1,2 @@
1
+ import {request}from'http';var p=process.env.DEVFLOW_SERVER_URL||"http://127.0.0.1:13337",i=process.env.DEVFLOW_API_KEY||"dev-key-000000",a=process.env.CLAUDE_PROJECT_DIR||process.cwd();function m(s,r){return new Promise(o=>{let n=JSON.stringify(r),e=new URL(s,p),t=request({hostname:e.hostname,port:e.port,path:e.pathname,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":i,"Content-Length":Buffer.byteLength(n)},timeout:5e3},()=>o());t.on("error",()=>o()),t.write(n),t.end();})}async function h(){m(`/api/memory/extract-rules?rootPath=${encodeURIComponent(a)}`,{mode:"precompact",timestamp:Date.now()}).catch(()=>{});}(process.argv[1]?.endsWith("pre-compact")||process.argv[1]?.endsWith("pre-compact.js"))&&(h().then(()=>process.exit(0)).catch(()=>process.exit(0)),setTimeout(()=>process.exit(0),14e3).unref());
2
+ export{h as handlePreCompact};
@@ -0,0 +1,2 @@
1
+ import {get,request}from'http';import {existsSync,readFileSync,unlinkSync}from'fs';import {join}from'path';import {homedir}from'os';var I=process.env.DEVFLOW_SERVER_URL||"http://127.0.0.1:13337",x=process.env.DEVFLOW_API_KEY||"dev-key-000000",A=process.env.CLAUDE_PROJECT_DIR||process.cwd();function F(e){return new Promise(o=>{let i=new URL(e,I);get(i.toString(),{headers:{"X-API-Key":x},timeout:5e3},t=>{let n=[];t.on("data",c=>n.push(c)),t.on("end",()=>{try{o(JSON.parse(Buffer.concat(n).toString()));}catch{o(null);}});}).on("error",()=>o(null));})}function g(e,o){return new Promise(i=>{let l=JSON.stringify(o),t=new URL(e,I),n=request({hostname:t.hostname,port:t.port,path:t.pathname,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":x,"Content-Length":Buffer.byteLength(l)},timeout:5e3},()=>i());n.on("error",()=>i()),n.write(l),n.end();})}var u=join(homedir(),".devflow"),y=join(u,"session-id"),E=join(u,"current-execution-id"),U=join(u,"current-skill.json"),k=join(u,"event-map.json");function j(){try{if(existsSync(y))return readFileSync(y,"utf-8").trim()}catch{}return null}function B(){for(let e of [y,E,U,k])try{existsSync(e)&&unlinkSync(e);}catch{}}async function J(e){let o;try{o=JSON.parse(e);}catch{return}let i=o.session_id||j();if(!i)return;let t=(await F(`/api/telemetry/sessions/${encodeURIComponent(i)}/events`))?.data||[],n=t.length,c=t.filter(s=>s.isMcpTool).length,S=n-c,_=t.filter(s=>s.toolType==="subagent").length,d=t.map(s=>s.timestamp).filter(Boolean),R=d.length>=2?Math.max(...d)-Math.min(...d):0,v=n>0?Math.round(c/n*1e4)/100:0;if(existsSync(E)){let s="";try{s=readFileSync(E,"utf-8").trim();}catch{}if(s){let p=t.filter(r=>r.executionId===s),m=p.length,h=p.filter(r=>r.isMcpTool).length,w=m-h,L=p.filter(r=>r.toolType==="subagent").length,f=p.map(r=>r.timestamp).filter(Boolean),P=f.length>=2?Math.max(...f)-Math.min(...f):0;try{await g("/api/telemetry/skill-execution/complete",{executionId:s,finishedAt:Date.now(),status:"completed",summary:{totalToolCalls:m,mcpToolCalls:h,directToolCalls:w,subagentCount:L,totalDuration:P,mcpComplianceRate:m>0?Math.round(h/m*1e4)/100:0}});}catch{}}}await g(`/api/telemetry/sessions/${encodeURIComponent(i)}/close`,{finishedAt:Date.now(),stats:{totalToolCalls:n,mcpToolCalls:c,directToolCalls:S,subagentCount:_,totalDuration:R,mcpComplianceRate:v}}),g(`/api/memory/process?rootPath=${encodeURIComponent(A)}`,{trigger:"session_end",sessionId:i}).catch(()=>{}),B();}if(process.argv[1]?.endsWith("session-end")||process.argv[1]?.endsWith("session-end.js")){let e="";process.stdin.setEncoding("utf8"),process.stdin.on("data",o=>{e+=o;}),process.stdin.on("end",async()=>{await J(e.trim()||process.argv[2]||""),process.exit(0);}),process.stdin.on("error",()=>process.exit(0)),setTimeout(()=>process.exit(0),1e4).unref();}
2
+ export{J as handleSessionEnd};
@@ -1,2 +1,2 @@
1
- import {get,request}from'http';import {existsSync,readFileSync,unlinkSync}from'fs';import {join}from'path';import {homedir}from'os';var I=process.env.DEVFLOW_SERVER_URL||"http://127.0.0.1:13337",x=process.env.DEVFLOW_API_KEY||"dev-key-000000",D=process.env.CLAUDE_PROJECT_DIR||process.cwd();function b(t){return new Promise(r=>{let e=new URL(t,I);get(e.toString(),{headers:{"X-API-Key":x},timeout:5e3},n=>{let c=[];n.on("data",g=>c.push(g)),n.on("end",()=>{try{r(JSON.parse(Buffer.concat(c).toString()));}catch{r(null);}});}).on("error",()=>r(null));})}function d(t,r){return new Promise(e=>{let s=JSON.stringify(r),n=new URL(t,I),c=request({hostname:n.hostname,port:n.port,path:n.pathname,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":x,"Content-Length":Buffer.byteLength(s)},timeout:5e3},()=>e());c.on("error",()=>e()),c.write(s),c.end();})}var p=join(homedir(),".devflow"),E=join(p,"session-id"),T=join(p,"current-execution-id"),M=join(p,"current-skill.json"),O=join(p,"event-map.json");function A(){for(let t of [E,T,M,O])try{existsSync(t)&&unlinkSync(t);}catch{}}async function F(){let t=(()=>{try{if(existsSync(E))return readFileSync(E,"utf-8").trim()}catch{}return null})();if(t){let e=(await b(`/api/telemetry/sessions/${t}/events`))?.data||[];e.length;e.filter(o=>o.isMcpTool).length;e.filter(o=>o.toolType==="subagent").length;let u=e.map(o=>o.timestamp).filter(Boolean);u.length>=2?Math.max(...u)-Math.min(...u):0;if(existsSync(T)){let o="";try{o=readFileSync(T,"utf-8").trim();}catch{}if(o){let l=e.filter(a=>a.executionId===o),m=l.length,h=l.filter(a=>a.isMcpTool).length,S=m-h,R=l.filter(a=>a.toolType==="subagent").length,f=l.map(a=>a.timestamp).filter(Boolean),_=f.length>=2?Math.max(...f)-Math.min(...f):0;try{await d("/api/telemetry/skill-execution/complete",{executionId:o,finishedAt:Date.now(),status:"completed",summary:{totalToolCalls:m,mcpToolCalls:h,directToolCalls:S,subagentCount:R,totalDuration:_,mcpComplianceRate:m>0?Math.round(h/m*1e4)/100:0}});}catch{}}}await d(`/api/telemetry/sessions/${t}/close`,{finishedAt:Date.now()});}d(`/api/memory/process?rootPath=${encodeURIComponent(D)}`,{}).catch(()=>{}),A();}(process.argv[1]?.endsWith("stop")||process.argv[1]?.endsWith("stop.js"))&&F().catch(()=>process.exit(0));
2
- export{F as handleStop};
1
+ import {request}from'http';import {existsSync,readFileSync}from'fs';import {join}from'path';import {homedir}from'os';var m=process.env.DEVFLOW_SERVER_URL||"http://127.0.0.1:13337",l=process.env.DEVFLOW_API_KEY||"dev-key-000000";function h(t,e){return new Promise(n=>{let r=JSON.stringify(e),o=new URL(t,m),s=request({hostname:o.hostname,port:o.port,path:o.pathname,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":l,"Content-Length":Buffer.byteLength(r)},timeout:5e3},()=>n());s.on("error",()=>n()),s.write(r),s.end();})}var f=join(homedir(),".devflow"),i=join(f,"session-id");function S(){try{if(existsSync(i))return readFileSync(i,"utf-8").trim()}catch{}return null}async function _(t){let e;try{e=JSON.parse(t);}catch{return null}if(e.stop_hook_active)return null;let n=S();return n&&h(`/api/telemetry/sessions/${encodeURIComponent(n)}/tick`,{timestamp:Date.now()}).catch(()=>{}),null}if(process.argv[1]?.endsWith("stop")||process.argv[1]?.endsWith("stop.js")){let t="";process.stdin.setEncoding("utf8"),process.stdin.on("data",e=>{t+=e;}),process.stdin.on("end",async()=>{await _(t.trim()||process.argv[2]||""),process.exit(0);}),process.stdin.on("error",()=>process.exit(0)),setTimeout(()=>process.exit(0),4e3).unref();}
2
+ export{_ as handleStop};
@@ -0,0 +1,2 @@
1
+ import {request}from'http';var c=process.env.DEVFLOW_SERVER_URL||"http://127.0.0.1:13337",p=process.env.DEVFLOW_API_KEY||"dev-key-000000",m=process.env.CLAUDE_PROJECT_DIR||process.cwd(),a=[{regex:/\b(remember|记住|save this|保存|记一下)\b/i,score:1},{regex:/^\/memory\b/,score:1},{regex:/\b(prefer|default|以后默认|always use|偏好|preference)\b/i,score:.8},{regex:/\b(no\b|不对|don't|wrong|不是这样|错了|不对的)\b/i,score:.75},{regex:/\b(原因|because|问题在于|root cause|根本原因|why)\b/i,score:.5},{regex:/\b(we\b|我们|项目里|our team|团队|our project)\b/i,score:.3},{regex:/\b(line \d+|above|below|↑|这段|那段代码|the code above)\b/i,score:.2}];function u(t){let e=.1;for(let o of a)o.regex.test(t)&&(e=Math.max(e,o.score));return e}function b(t,e){return new Promise(o=>{let r=JSON.stringify(e),s=new URL(t,c),n=request({hostname:s.hostname,port:s.port,path:s.pathname,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":p,"Content-Length":Buffer.byteLength(r)},timeout:5e3},()=>o());n.on("error",()=>o()),n.write(r),n.end();})}async function g(t){let e;try{e=JSON.parse(t);}catch{return {hookSpecificOutput:{hookEventName:"UserPromptSubmit",permissionDecision:"allow"}}}let o=e.prompt||"";if(!o.trim())return {hookSpecificOutput:{hookEventName:"UserPromptSubmit",permissionDecision:"allow"}};let r=u(o);return b(`/api/memory/signal?rootPath=${encodeURIComponent(m)}`,{type:"user_message",content:o.slice(0,2e3),score:r,sessionId:e.session_id,timestamp:Date.now()}).catch(()=>{}),{hookSpecificOutput:{hookEventName:"UserPromptSubmit",permissionDecision:"allow"}}}if(process.argv[1]?.endsWith("user-prompt-submit")||process.argv[1]?.endsWith("user-prompt-submit.js")){let t="";process.stdin.setEncoding("utf8"),process.stdin.on("data",e=>{t+=e;}),process.stdin.on("end",async()=>{let e=await g(t.trim()||process.argv[2]||"");console.log(JSON.stringify(e)),process.exit(0);}),process.stdin.on("error",()=>{console.log(JSON.stringify({hookSpecificOutput:{hookEventName:"UserPromptSubmit",permissionDecision:"allow"}})),process.exit(0);}),setTimeout(()=>{console.log(JSON.stringify({hookSpecificOutput:{hookEventName:"UserPromptSubmit",permissionDecision:"allow"}})),process.exit(0);},3e4).unref();}
2
+ export{g as handleUserPromptSubmit};
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$SCRIPT_DIR/..}"
6
+ CLIENT_JS="$PLUGIN_ROOT/dist/hooks/hook-client.js"
7
+ FALLBACK_JS="$PLUGIN_ROOT/dist/hooks/post-tool-use-failure.js"
8
+
9
+ INPUT="$(cat)"
10
+
11
+ if [ -f "$CLIENT_JS" ]; then
12
+ node "$CLIENT_JS" post-tool-use-failure "$INPUT" 2>/dev/null || {
13
+ echo "$INPUT" | node "$FALLBACK_JS" 2>/dev/null || true
14
+ }
15
+ elif [ -f "$FALLBACK_JS" ]; then
16
+ echo "$INPUT" | node "$FALLBACK_JS" 2>/dev/null || true
17
+ fi
18
+
19
+ exit 0
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$SCRIPT_DIR/..}"
6
+ CLIENT_JS="$PLUGIN_ROOT/dist/hooks/hook-client.js"
7
+ FALLBACK_JS="$PLUGIN_ROOT/dist/hooks/pre-compact.js"
8
+
9
+ INPUT="$(cat)"
10
+
11
+ if [ -f "$CLIENT_JS" ]; then
12
+ node "$CLIENT_JS" pre-compact "$INPUT" 2>/dev/null || {
13
+ echo "$INPUT" | node "$FALLBACK_JS" 2>/dev/null || true
14
+ }
15
+ elif [ -f "$FALLBACK_JS" ]; then
16
+ echo "$INPUT" | node "$FALLBACK_JS" 2>/dev/null || true
17
+ fi
18
+
19
+ exit 0
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$SCRIPT_DIR/..}"
6
+ CLIENT_JS="$PLUGIN_ROOT/dist/hooks/hook-client.js"
7
+ FALLBACK_JS="$PLUGIN_ROOT/dist/hooks/session-end.js"
8
+
9
+ INPUT="$(cat)"
10
+
11
+ if [ -f "$CLIENT_JS" ]; then
12
+ node "$CLIENT_JS" session-end "$INPUT" 2>/dev/null || {
13
+ echo "$INPUT" | node "$FALLBACK_JS" 2>/dev/null || true
14
+ }
15
+ elif [ -f "$FALLBACK_JS" ]; then
16
+ echo "$INPUT" | node "$FALLBACK_JS" 2>/dev/null || true
17
+ fi
18
+
19
+ exit 0
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$SCRIPT_DIR/..}"
6
+ CLIENT_JS="$PLUGIN_ROOT/dist/hooks/hook-client.js"
7
+ FALLBACK_JS="$PLUGIN_ROOT/dist/hooks/user-prompt-submit.js"
8
+
9
+ INPUT="$(cat)"
10
+
11
+ if [ -f "$CLIENT_JS" ]; then
12
+ node "$CLIENT_JS" user-prompt-submit "$INPUT" 2>/dev/null || {
13
+ echo "$INPUT" | node "$FALLBACK_JS" 2>/dev/null || true
14
+ }
15
+ elif [ -f "$FALLBACK_JS" ]; then
16
+ echo "$INPUT" | node "$FALLBACK_JS" 2>/dev/null || true
17
+ fi
18
+
19
+ exit 0
package/hooks.json CHANGED
@@ -6,8 +6,7 @@
6
6
  "hooks": [
7
7
  {
8
8
  "type": "command",
9
- "command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/session-start\"",
10
- "async": false
9
+ "command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/session-start\""
11
10
  }
12
11
  ]
13
12
  }
@@ -18,8 +17,7 @@
18
17
  "hooks": [
19
18
  {
20
19
  "type": "command",
21
- "command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/pre-tool-use\"",
22
- "async": false
20
+ "command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/pre-tool-use\""
23
21
  }
24
22
  ]
25
23
  }
@@ -30,8 +28,30 @@
30
28
  "hooks": [
31
29
  {
32
30
  "type": "command",
33
- "command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/post-tool-use\"",
34
- "async": false
31
+ "command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/post-tool-use\""
32
+ }
33
+ ]
34
+ }
35
+ ],
36
+ "PostToolUseFailure": [
37
+ {
38
+ "matcher": "*",
39
+ "hooks": [
40
+ {
41
+ "type": "command",
42
+ "command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/post-tool-use-failure\""
43
+ }
44
+ ]
45
+ }
46
+ ],
47
+ "UserPromptSubmit": [
48
+ {
49
+ "matcher": "",
50
+ "hooks": [
51
+ {
52
+ "type": "command",
53
+ "command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/user-prompt-submit\"",
54
+ "timeout": 30
35
55
  }
36
56
  ]
37
57
  }
@@ -42,8 +62,30 @@
42
62
  "hooks": [
43
63
  {
44
64
  "type": "command",
45
- "command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/stop\"",
46
- "async": false
65
+ "command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/stop\""
66
+ }
67
+ ]
68
+ }
69
+ ],
70
+ "PreCompact": [
71
+ {
72
+ "matcher": "",
73
+ "hooks": [
74
+ {
75
+ "type": "command",
76
+ "command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/pre-compact\"",
77
+ "timeout": 15
78
+ }
79
+ ]
80
+ }
81
+ ],
82
+ "SessionEnd": [
83
+ {
84
+ "matcher": "",
85
+ "hooks": [
86
+ {
87
+ "type": "command",
88
+ "command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/session-end\""
47
89
  }
48
90
  ]
49
91
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devflow-tools/claude-code-plugin",
3
- "version": "0.13.3",
3
+ "version": "0.14.0",
4
4
  "description": "DevFlow — Developer Intelligence Platform for Claude Code",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -8,7 +8,7 @@
8
8
  "deploy": "npx tsx scripts/inject-gates.ts --deploy"
9
9
  },
10
10
  "devDependencies": {
11
- "@devflow-tools/mcp-server": "^0.13.3"
11
+ "@devflow-tools/mcp-server": "^0.14.0"
12
12
  },
13
13
  "keywords": [
14
14
  "pi-package",
@@ -28,5 +28,5 @@
28
28
  "hooks.json",
29
29
  "skills"
30
30
  ],
31
- "gitHead": "1ec6f7748cc94dcd35f8aa9947af854c23ea6be1"
31
+ "gitHead": "af6ac81c0242d77fe11ae205a9733d92926c0ac9"
32
32
  }