@devflow-tools/devflow 0.8.11 → 0.10.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/hooks/post-tool-use.js +2 -2
- package/dist/mcp-server.js +6 -1
- package/dist/server.js +2 -2
- package/package.json +13 -13
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {request}from'http';import {existsSync,readFileSync,writeFileSync}from'fs';import {join}from'path';import {homedir}from'os';var
|
|
2
|
-
export{
|
|
1
|
+
import {request}from'http';import {existsSync,readFileSync,writeFileSync}from'fs';import {join}from'path';import {homedir}from'os';var x=process.env.DEVFLOW_SERVER_URL||"http://127.0.0.1:13337",A=process.env.DEVFLOW_API_KEY||"dev-key-000000",w=process.env.CLAUDE_PROJECT_DIR||process.cwd(),v=join(homedir(),".devflow","session-id"),f=join(homedir(),".devflow","event-map.json");function y(d,a){return new Promise(e=>{let n=JSON.stringify(a),t=new URL(d,x),o=request({hostname:t.hostname,port:t.port,path:t.pathname,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":A,"Content-Length":Buffer.byteLength(n)},timeout:5e3},()=>e());o.on("error",()=>e()),o.write(n),o.end();})}function L(){try{if(existsSync(v))return readFileSync(v,"utf-8").trim()}catch{}return null}function C(d,a){try{if(!existsSync(f))return null;let e=JSON.parse(readFileSync(f,"utf-8")),n=e.filter(c=>c.toolName===d);if(n.length===0)return null;let t=a??Date.now();n.sort((c,m)=>Math.abs(c.timestamp-t)-Math.abs(m.timestamp-t));let o=n[0],s=e.findIndex(c=>c.eventId===o.eventId);return s!==-1&&e.splice(s,1),writeFileSync(f,JSON.stringify(e)),{eventId:o.eventId,timestamp:o.timestamp}}catch{return null}}async function M(d){if(!d)return;let a;try{a=JSON.parse(d);}catch{return}let e=a.tool_name||"",n=a.tool_input||{},t=a.tool_response||{},o=L(),s=C(e,Date.now());if(s&&o){let r=typeof t=="string"?t:JSON.stringify(t),g=r.length>5e3?{_truncated:true,_originalSize:r.length,text:r.slice(0,5e3)}:t,i=Date.now()-s.timestamp;y("/api/telemetry/tool-call/output",{eventId:s.eventId,sessionId:o,output:g,duration:i,completedAt:Date.now()}).catch(()=>{});}let c=typeof n=="object"&&n.command?n.command:"",m=typeof t=="object"&&t!==null?t:null,p=m?.exitCode,O=m?.stderr;if(e==="Bash"&&p!==void 0&&p!==0){let r={id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:o??`session:${w.split("/").pop()||"default"}`,tool:e,command:c||e,exitCode:p,stderr:O??null,durationMs:0,createdAt:Date.now()};y(`/api/memory/events?rootPath=${encodeURIComponent(w)}`,r).catch(()=>{});}let R=["get_project_context","get_knowledge","get_memory","search_symbol","get_dependency_graph","react_diagnose_bug","react_new_component","react_audit_performance","vue_diagnose_bug","nest_diagnose_bug","nextjs_diagnose_bug","electron_diagnose_bug","graphql_diagnose_bug","run_workflow"],l=e.replace("mcp__devflow__","");if(e.startsWith("mcp__devflow__")&&R.includes(l)){let r=typeof t=="object"&&t!==null?t:null,g=["files","results","data","result","memories","nodes","chunks"],i=0,u=r?.data??r;if(Array.isArray(u))i=u.length;else if(typeof u=="object"&&u!==null){let _=u;for(let h of g)Array.isArray(_[h])&&(i+=_[h].length);i===0&&Object.keys(_).length>0&&(i=1);}let k=JSON.stringify(t),j=Buffer.byteLength(k,"utf8"),D={id:`metric:${Date.now()}:${Math.random().toString(36).slice(2,11)}`,toolCallEventId:s?.eventId??`unknown:${Date.now()}`,sessionId:o??"",toolName:l,query:typeof n=="object"&&n.query?n.query:void 0,status:r?.error?"error":i===0?"empty":"success",resultCount:i,resultSizeBytes:j,latencyMs:s?Date.now()-s.timestamp:0,engine:l.startsWith("get_project_context")||l==="search_symbol"||l==="get_dependency_graph"?"codegraph":l==="get_knowledge"?"knowledge":l==="get_memory"?"memory":void 0};y("/api/telemetry/tool-metrics",D).catch(()=>{});}}(process.argv[1]?.endsWith("post-tool-use")||process.argv[1]?.endsWith("post-tool-use.js"))&&M(process.argv[2]||"").catch(()=>process.exit(0));
|
|
2
|
+
export{M as handlePostToolUse};
|
package/dist/mcp-server.js
CHANGED
|
@@ -1,2 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {createHmac,createHash}from'crypto';import {Server}from'@modelcontextprotocol/sdk/server/index.js';import {StdioServerTransport}from'@modelcontextprotocol/sdk/server/stdio.js';import {ListToolsRequestSchema,CallToolRequestSchema}from'@modelcontextprotocol/sdk/types.js';import {DevFlowApiClient,loadPlugins}from'@devflow-tools/sdk';import {join}from'path';import {existsSync,mkdirSync,readFileSync,writeFileSync}from'fs';var fe=Object.defineProperty;var y=(t,e)=>()=>(t&&(e=t(t=0)),e);var W=(t,e)=>{for(var o in e)fe(t,o,{get:e[o],enumerable:true});};var J={};W(J,{createPluginHandlers:()=>we,createToolHandlers:()=>ge,getCoreTools:()=>M,getPluginTools:()=>A});function M(){return [{name:"get_project_context",description:"\u83B7\u53D6\u4E0E\u7F16\u7801\u4EFB\u52A1\u6700\u76F8\u5173\u7684\u6700\u5C0F\u4E0A\u4E0B\u6587",inputSchema:{type:"object",properties:{query:{type:"string",description:"\u81EA\u7136\u8BED\u8A00\u67E5\u8BE2"},mode:{type:"string",enum:["fast","deep"],default:"fast"},expandedTerms:{type:"string",description:"Agent \u9884\u7FFB\u8BD1\u7684\u82F1\u6587\u5173\u952E\u8BCD\uFF08\u7A7A\u683C\u5206\u9694\uFF09\uFF0C\u7528\u4E8E\u63D0\u5347\u4E2D\u6587\u67E5\u8BE2\u7684\u641C\u7D22\u6548\u679C"}},required:["query"]}},{name:"search_symbol",description:"\u6309\u7B26\u53F7\u540D\u641C\u7D22\u4EE3\u7801\u2014\u2014\u8BED\u4E49\u7EA7\u4EE3\u7801\u7ED3\u6784\u641C\u7D22",inputSchema:{type:"object",properties:{symbol:{type:"string",description:"\u7B26\u53F7\u540D\u79F0"}},required:["symbol"]}},{name:"get_dependency_graph",description:"\u83B7\u53D6\u6587\u4EF6/\u7EC4\u4EF6\u7684\u4F9D\u8D56\u5173\u7CFB",inputSchema:{type:"object",properties:{target:{type:"string",default:"all"},depth:{type:"number",default:2}}}},{name:"run_workflow",description:"\u6267\u884C\u6807\u51C6\u5316\u5F00\u53D1\u5DE5\u4F5C\u6D41",inputSchema:{type:"object",properties:{type:{type:"string",enum:["bugfix","feature","review"]},input:{type:"string"}},required:["type"]}},{name:"get_memory",description:"\u83B7\u53D6\u9879\u76EE\u8BB0\u5FC6\uFF1A\u6280\u672F\u6808\u3001\u7EA6\u5B9A\u3001\u504F\u597D\u3001\u5386\u53F2\u51B3\u7B56",inputSchema:{type:"object",properties:{}}},{name:"get_knowledge",description:"\u67E5\u8BE2\u6280\u672F\u6587\u6863\u77E5\u8BC6\u5E93",inputSchema:{type:"object",properties:{query:{type:"string"},scope:{type:"string",enum:["react","vue","nest","all"],default:"all"}},required:["query"]}},{name:"devflow_report_event",description:"Report fine-grained events within workflow steps (LLM calls, tool usage, file read/write etc.). Optional, for more granular observability.",inputSchema:{type:"object",properties:{runId:{type:"string"},stepId:{type:"string"},kind:{type:"string",enum:["llm_call","tool_use","memory_read","memory_write","file_read","file_write","bash_command","mcp_tool_call","error","user_input"]},duration:{type:"number"},model:{type:"string"},prompt:{type:"string"},response:{type:"string"},inputTokens:{type:"number"},outputTokens:{type:"number"},toolName:{type:"string"},toolInput:{type:"string"},toolOutput:{type:"string"},filePath:{type:"string"},command:{type:"string"},exitCode:{type:"number"},stdout:{type:"string"},stderr:{type:"string"},mcpToolName:{type:"string"},errorMessage:{type:"string"},errorStack:{type:"string"},memoryKey:{type:"string"},userMessage:{type:"string"}},required:["runId","stepId","kind"]}}]}function ge(t){return {get_project_context:async({query:e,mode:o,expandedTerms:r})=>{let n=await t.context.buildTaskContext(e,{mode:o??"fast"});return {taskType:n.taskType,requiredFiles:n.requiredFiles,optionalFiles:n.optionalFiles,keySymbols:n.keySymbols,graphSummary:n.graphSummary,riskHints:n.riskHints,nextActions:n.nextActions,reasoning:n.reasoning,confidence:n.confidence,tokenCount:n.tokenCount,_devflow_unique:{search_method:"bm25_semantic",task_oriented:true,risk_aware:true,memory_injected:true,knowledge_injected:true,token_estimated:true,required_vs_optional:true}}},search_symbol:async({symbol:e})=>({...await t.indexer.findSymbol(e),_devflow_unique:{index_backed:true,kind_annotated:true}}),get_dependency_graph:async({target:e,depth:o})=>{let r=e??"all",n=o??2;return {...r==="all"?t.graph.export():t.graph.getSubGraph(r,n),_devflow_unique:{layer_annotated:true,architecture_grouped:true,query_depth:n}}},run_workflow:async({type:e,input:o})=>({...await t.workflow.run(e,{input:o}),_devflow_unique:{dag_orchestrated:true,step_tracked:true,workflow_type:e}}),get_memory:async()=>({...await t.memory.getAll(),_devflow_unique:{memory_version:1,structured_storage:true,project_context_included:true}}),get_knowledge:async({query:e,scope:o})=>({...await t.knowledge.search(e,{sources:o==="all"?void 0:[o]}),_devflow_unique:{source_versioned:true,code_examples_included:true,search_scope:o}}),devflow_report_event:async e=>{let o=(d,m)=>!d||d.length<=m?{value:d??"",truncated:false}:{value:d.slice(0,m),truncated:true},r=o(e.prompt,500),n=o(e.response,500),s=o(e.stdout,1e3),a=o(e.stderr,500),i=r.truncated||n.truncated||s.truncated||a.truncated,u={id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,runId:e.runId,stepId:e.stepId,kind:e.kind,timestamp:Date.now(),duration:e.duration,data:{model:e.model,prompt:r.value,response:n.value,inputTokens:e.inputTokens,outputTokens:e.outputTokens,toolName:e.toolName,toolInput:e.toolInput,toolOutput:e.toolOutput,filePath:e.filePath,command:e.command,exitCode:e.exitCode,stdout:s.value,stderr:a.value,mcpToolName:e.mcpToolName,errorMessage:e.errorMessage,errorStack:e.errorStack,memoryKey:e.memoryKey,userMessage:e.userMessage},metadata:{source:"manual"},...i&&{metadata:{truncated:true,source:"manual"}}};return await t.telemetry.recordEvent(u),{acknowledged:true,eventId:u.id}}}}function A(t){let e=[];for(let o of t){let r=o.meta.name;for(let s of o.tools??[])e.push({name:s.name,description:s.description,inputSchema:s.inputSchema});let n=new Set(e.map(s=>s.name));for(let s of o.workflow?.templates??[]){let a=s.triggers?.find(u=>u.type==="mcp");if(!a?.tool)continue;let i=`${r}_${a.tool}`;n.has(i)||e.push({name:i,description:s.description,inputSchema:{type:"object",properties:s.steps.filter(u=>u.inputSchema).reduce((u,d)=>({...u,...d.inputSchema??{}}),{}),required:[]}});}}return e}function we(t,e){let o={};for(let r of e){let n=r.meta.name;for(let s of r.tools??[])s.handler&&(o[s.name]=s.handler);for(let s of r.workflow?.templates??[]){let a=s.triggers?.find(u=>u.type==="mcp");if(!a?.tool)continue;let i=`${n}_${a.tool}`;o[i]||(o[i]=async u=>{let d=await t.workflow.run(s.name,u),m="";try{let l={id:d.runId??`run:${Date.now()}`,source:"mcp",tool:i,workflow:s.name,input:u,status:"running",startedAt:Date.now(),finishedAt:null,steps:[],metadata:{}};m=t.workflow.renderPlan(l,s);}catch{}return {...d,plan:m,_devflow_unique:{dag_orchestrated:true,step_tracked:true,plugin_name:n,template_name:s.name}}});}}return o}var I=y(()=>{});var $,q=y(()=>{$=[{id:"C001",name:"\u5FC5\u987B\u643A\u5E26 Session Token",level:"constitutional",condition:{requireFields:["_devflow_token"]},action:"deny",message:"\u7F3A\u5C11 Session Token\u3002\u8BF7\u901A\u8FC7 /devflow: \u547D\u4EE4\u542F\u52A8\u4F1A\u8BDD\uFF0C\u6216\u8FD0\u884C devflow session token \u83B7\u53D6\u4EE4\u724C\u3002"},{id:"C002",name:"Token \u5DF2\u8FC7\u671F",level:"constitutional",condition:{},action:"deny",message:"Session Token \u5DF2\u8FC7\u671F\uFF08\u8D85\u8FC7 1 \u5C0F\u65F6\uFF09\u3002\u8BF7\u91CD\u65B0\u8FD0\u884C devflow session token \u83B7\u53D6\u65B0\u4EE4\u724C\u3002"},{id:"C003",name:"\u901F\u7387\u9650\u5236",level:"constitutional",condition:{maxCallsPerMinute:60},action:"warn",message:"\u8C03\u7528\u9891\u7387\u8FC7\u9AD8\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"}];});async function U(t){let e=await t.ruleGetAll();return [...$,...e]}function ye(t,e){let o=t.condition;if(o.tools&&!o.tools.includes("*")&&!o.tools.includes(e.toolName))return "allow";if(o.requireFields){for(let r of o.requireFields)if(!(r in e.args))return t.action}if(o.forbidPatterns){for(let r of o.forbidPatterns)for(let n of Object.values(e.args))if(typeof n=="string"&&new RegExp(r).test(n))return t.action}if(o.paramPatterns)for(let[r,n]of Object.entries(o.paramPatterns)){let s=String(e.args[r]??"");if(new RegExp(n).test(s))return t.action}if(o.maxCallsPerMinute){let r=`${e.toolName}:${e.sessionId??"anon"}`,n=Date.now(),s=K.get(r);if((!s||n>s.resetAt)&&(s={count:0,resetAt:n+6e4},K.set(r,s)),s.count++,s.count>o.maxCallsPerMinute)return t.action}return "allow"}function G(t,e){let o=[...t].sort((r,n)=>{let s={constitutional:0,project:1,session:2};return s[r.level]-s[n.level]});for(let r of o){let n=ye(r,e);if(n!=="allow")return {decision:n,rule:r}}return {decision:"allow"}}var K,V=y(()=>{q();K=new Map;});function x(t){let e=JSON.stringify(t,Object.keys(t).sort());return createHash("sha256").update(e).digest("hex")}async function H(t,e,o,r,n,s){let a=await t.auditGetSecret(),i=await t.auditGetAll(),u=i.length>0?i[i.length-1].signature:createHash("sha256").update("genesis").digest("hex"),d=Date.now(),m=i.length+1,l=`${m}|${d}|${e}|${o}|${r}|${n??""}|${s}|${u}`,f=createHmac("sha256",a).update(l).digest("hex");await t.auditAppend({seq:m,ts:d,tool:e,argsHash:o,decision:r,ruleId:n,sessionId:s,prevHash:u,signature:f});}async function B(t){let e=await t.auditGetSecret(),o=await t.auditGetAll(),r=createHash("sha256").update("genesis").digest("hex");for(let n of o){if(n.prevHash!==r)return {valid:false,brokenAt:n.seq};let s=`${n.seq}|${n.ts}|${n.tool}|${n.argsHash}|${n.decision}|${n.ruleId??""}|${n.sessionId}|${r}`,a=createHmac("sha256",e).update(s).digest("hex");if(n.signature!==a)return {valid:false,brokenAt:n.seq};r=n.signature;}return {valid:true,brokenAt:null}}async function z(t){let e=await t.auditGetSecret(),o=await t.auditGetAll(),r=createHash("sha256").update("genesis").digest("hex");for(let n of o){let s=`${n.seq}|${n.ts}|${n.tool}|${n.argsHash}|${n.decision}|${n.ruleId??""}|${n.sessionId}|${r}`,a=createHmac("sha256",e).update(s).digest("hex");await t.sqlExecute("UPDATE devflow_audit_chain SET prev_hash = ?, signature = ? WHERE seq = ?",[r,a,n.seq]),r=a;}}var N=y(()=>{});function S(t,e,o){let r=Date.now(),n=r+ve,s=createHash("sha256").update(JSON.stringify(e)).digest("hex"),a=`${t}|${r}|${n}|${s}`,i=createHmac("sha256",o).update(a).digest("hex");return {tool:t,ts:r,exp:n,queryHash:s,hmac:i}}function Q(t,e,o,r){if(Date.now()>t.exp)return false;let n=createHash("sha256").update(JSON.stringify(o)).digest("hex");if(t.queryHash!==n)return false;let s=`${e}|${t.ts}|${t.exp}|${n}`,a=createHmac("sha256",r).update(s).digest("hex");return t.hmac===a}function Z(t){return Date.now()>t.exp}var ve,F=y(()=>{ve=3e4;});var te={};W(te,{CONSTITUTIONAL_RULES:()=>$,enforce:()=>he,hashArgs:()=>x,isReceiptExpired:()=>Z,issueReceipt:()=>S,parseJwtPayload:()=>ee,rebuildAuditChain:()=>z,verifyAuditChain:()=>B,verifyReceipt:()=>Q});function ee(t){try{let e=t.split(".");if(e.length!==3)return null;let o=e[1],r=Buffer.from(o,"base64url").toString("utf-8");return JSON.parse(r)}catch{return null}}async function he(t,e,o){if(!e._devflow_token){let l=process.env.DEVFLOW_SESSION_TOKEN;if(l){let f=ee(l);f&&(e={...e,_devflow_token:f});}}let r=e._devflow_token?.sub??"anon",n={toolName:t,args:e,sessionId:r,tokenPayload:e._devflow_token};if(n.tokenPayload){let l=Math.floor(Date.now()/1e3);if(n.tokenPayload.exp&&l>n.tokenPayload.exp){let f=x(e);return await H(o,t,f,"deny","C002",r),{result:{allowed:false,message:"Session Token \u5DF2\u8FC7\u671F\uFF08\u8D85\u8FC7 1 \u5C0F\u65F6\uFF09\u3002\u8BF7\u91CD\u65B0\u8FD0\u884C devflow session token \u83B7\u53D6\u65B0\u4EE4\u724C\u3002"}}}}let s=await U(o),{decision:a,rule:i}=G(s,n),u=x(e);if(await H(o,t,u,a,i?.id??null,r),a==="deny"&&i)return {result:{allowed:false,rule:i,message:i.message}};if(a==="warn"&&i){let l=await o.auditGetSecret(),f=S(t,e,l);return {result:{allowed:true,warning:i.message,rule:i},receipt:f}}let d=await o.auditGetSecret(),m=S(t,e,d);return {result:{allowed:true},receipt:m}}var oe=y(()=>{V();N();F();N();F();q();});I();async function ie(t){Pe(t.projectRoot);let e=new Server({name:"devflow-mcp",version:"0.1.0"},{capabilities:{tools:{}}}),o=process.env.DEVFLOW_SERVER_URL??"http://127.0.0.1:13337",r=process.env.DEVFLOW_API_KEY??"dev-key-000000",n=new DevFlowApiClient({baseUrl:o,projectRoot:t.projectRoot,apiKey:r}),s=await n.ping(),a=await loadPlugins(),i=Array.from(a.values()),u=M(),d=A(i),m=[...u,...d];e.setRequestHandler(ListToolsRequestSchema,async()=>({tools:m}));let l=null,f=new Set(u.map(D=>D.name));e.setRequestHandler(CallToolRequestSchema,async D=>{let{name:c,arguments:ue}=D.params,w=ue??{},P=Date.now();try{let p;if(f.has(c)&&s){p=await Ae(n,c,w),se(t.projectRoot,c);let b=Date.now()-P,g=c.split("_")[0];try{await n.recordTelemetryEvent({toolName:c,args:w,durationMs:b,success:!0,pluginName:g,metadata:{projectRoot:t.projectRoot}});}catch(_){console.error("[devflow-mcp] Failed to record telemetry:",_);}try{await n.recordMemoryEvent({id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:`session:${t.projectRoot.split("/").pop()??"default"}`,tool:c,command:R(c)||c,exitCode:0,durationMs:b});}catch(_){console.error("[devflow-mcp] Failed to record memory event:",_);}}else {if(!l){let[{createEngines:T}]=await Promise.all([import('@devflow-tools/context-engine')]);l=await T(t.projectRoot);for(let C of i)for(let k of C.workflow?.templates??[])l.workflow.register(k);console.error(`[devflow-mcp] Warning: DevFlow server not reachable at ${o}`),console.error("[devflow-mcp] Running in local mode.");}let{enforce:b}=await Promise.resolve().then(()=>(oe(),te)),g=await b(c,w,l.data);if(!g.result.allowed)return {content:[{type:"text",text:JSON.stringify({_devflow:{v:1,tool:c,ts:Date.now(),marker:"devflow-mcp-v1"},error:g.result.message,rule:g.result.rule?.id})}],isError:!0};let{createToolHandlers:_,createPluginHandlers:de}=await Promise.resolve().then(()=>(I(),J)),pe=_(l),me=de(l,i),L={...pe,...me}[c];if(!L)throw new Error(`Unknown tool: ${c}`);p=await L(w),se(t.projectRoot,c);let j=Date.now()-P;try{await l.data.recordToolCall(c,w,j);let T=c.startsWith("devflow_")||c.includes("_"),C=c.split("_")[0],k=ce.has(C);await l.telemetry.recordToolCall({eventId:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,executionId:`exec:${t.projectRoot.split("/").pop()??"default"}:${Date.now()}`,timestamp:Date.now(),toolName:c,toolType:T||k?"mcp":"direct",isMcpTool:T||k,mcpToolName:k?c:void 0,mcpEnforced:!0,mcpFallback:!1,input:w,output:je(p),tokensUsed:0,duration:j,blocked:!1});}catch{}try{await l.memory.recordEvent({id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:`session:${t.projectRoot.split("/").pop()??"default"}`,tool:c,command:R(c)||c,exitCode:0,stderr:void 0,durationMs:j,createdAt:Date.now()}),l.memory.processSessionEvents().catch(()=>{});}catch{}g.receipt&&(p={...p,_receipt:g.receipt}),g.result.warning&&(p={...p,_warning:g.result.warning});}let h=Ce(c,p);return {content:[{type:"text",text:JSON.stringify(h,null,2)}]}}catch(p){let v=Date.now()-P;if(s){try{await n.recordTelemetryEvent({toolName:c,args:w,durationMs:v,success:!1,error:p.message,pluginName:c.split("_")[0],metadata:{projectRoot:t.projectRoot}});}catch(h){console.error("[devflow-mcp] Failed to record error telemetry:",h);}try{await n.recordMemoryEvent({id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:`session:${t.projectRoot.split("/").pop()??"default"}`,tool:c,command:R(c)||c,exitCode:1,stderr:p.message,durationMs:v});}catch(h){console.error("[devflow-mcp] Failed to record error memory event:",h);}}else if(l){try{await l.data.recordToolCall(c,w,v,p.message);}catch{}try{await l.memory.recordEvent({id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:`session:${t.projectRoot.split("/").pop()??"default"}`,tool:c,command:R(c)||c,exitCode:1,stderr:p.message,durationMs:v,createdAt:Date.now()});}catch{}}return {content:[{type:"text",text:`Error: ${p.message}`}],isError:true}}});let le=new StdioServerTransport;await e.connect(le);}function Pe(t){if(process.env.DEVFLOW_SESSION_TOKEN)return;let e=Buffer.from(JSON.stringify({alg:"HS256",typ:"JWT"})).toString("base64url"),o=Math.floor(Date.now()/1e3),r={sub:`devflow-mcp-${Date.now().toString(36)}`,project:t.split("/").pop()??"unknown",iat:o,exp:o+86400,scope:["context","knowledge","memory","workflow","graph"]},n=Buffer.from(JSON.stringify(r)).toString("base64url"),a=createHmac("sha256","devflow-local-mcp-secret-v1").update(`${e}.${n}`).digest("base64url");process.env.DEVFLOW_SESSION_TOKEN=`${e}.${n}.${a}`,console.error("[devflow-mcp] Auto-generated session token (no env token provided).");}var ce=new Set(["react","vue","nest","nextjs","graphql","docker","tailwind","taro","electron","performance"]);function R(t){let e={get_project_context:"context",search_symbol:"context",get_dependency_graph:"graph",get_knowledge:"knowledge",get_memory:"memory",run_workflow:"workflow"};if(e[t])return `devflow:${e[t]}`;let o=t.split("_")[0];return ce.has(o)?`devflow:${o}`:""}function se(t,e){try{let o=process.env.TMPDIR||"/tmp",r=join(o,".devflow-receipts"),n=createHash("sha256").update(t).digest("hex").slice(0,16),s=join(r,`${n}.json`);existsSync(r)||mkdirSync(r,{recursive:!0});let a={};if(existsSync(s))try{a=JSON.parse(readFileSync(s,"utf-8"));}catch{}a.lastMcpCall=Date.now(),a.bypassCount=0;let i=R(e);i&&(a.activeCommand=i),writeFileSync(s,JSON.stringify(a));}catch{}}function je(t){if(t&&typeof t=="object"&&!Array.isArray(t)){let{_devflow:e,_receipt:o,_warning:r,...n}=t;return Object.keys(n).length>0?n:t}return t}function Ce(t,e){let o={_devflow:{v:1,tool:t,ts:Date.now(),marker:"devflow-mcp-v1"}};return e&&typeof e=="object"&&!Array.isArray(e)?{...e,...o}:{result:e,...o}}async function Me(){let t=new Map,e=await loadPlugins(),o=Array.from(e.values());for(let r of o){let n=r.meta.name;for(let s of r.workflow?.templates??[]){let a=s.triggers?.find(i=>i.type==="mcp");if(a?.tool){let i=`${n}_${a.tool}`;t.set(i,s.name);}}}return t}async function Ae(t,e,o){switch(e){case "get_project_context":return t.buildContext(o.query,o.mode??"fast");case "search_symbol":return t.searchSymbol(o.symbol);case "get_dependency_graph":return t.getGraph(o.target??"all",o.depth??2);case "run_workflow":return t.runWorkflow(o.type,o.input);case "get_memory":return t.getMemory();case "get_knowledge":return t.searchKnowledge(o.query,o.scope??"all");case "devflow_report_event":return t.recordEvent(o);default:{let n=(await Me()).get(e)??e;return t.runWorkflow(n,o)}}}async function Ie(){let t=process.env.DEVFLOW_PROJECT_ROOT||process.cwd();await ie({mode:"stdio",projectRoot:t});}Ie().catch(t=>{console.error("MCP Server error:",t),process.exit(1);});
|
|
2
|
+
import {createHmac,createHash}from'crypto';import {Server}from'@modelcontextprotocol/sdk/server/index.js';import {StdioServerTransport}from'@modelcontextprotocol/sdk/server/stdio.js';import {ListToolsRequestSchema,ListResourcesRequestSchema,ReadResourceRequestSchema,ListPromptsRequestSchema,GetPromptRequestSchema,CallToolRequestSchema}from'@modelcontextprotocol/sdk/types.js';import {FallbackLLMClient,CliSubAgentClient,DevFlowApiClient,loadPlugins}from'@devflow-tools/sdk';import {join}from'path';import {existsSync,mkdirSync,readFileSync,writeFileSync,statSync}from'fs';var Se=Object.defineProperty;var Re=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,o)=>(typeof require<"u"?require:e)[o]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});var v=(t,e)=>()=>(t&&(e=t(t=0)),e);var K=(t,e)=>{for(var o in e)Se(t,o,{get:e[o],enumerable:true});};var B={};K(B,{TOOL_GROUPS:()=>Te,createPluginHandlers:()=>Pe,createToolHandlers:()=>Ee,getCoreTools:()=>O,getPluginTools:()=>I});function O(){return [{name:"get_project_context",description:"\u83B7\u53D6\u4E0E\u7F16\u7801\u4EFB\u52A1\u6700\u76F8\u5173\u7684\u6700\u5C0F\u4E0A\u4E0B\u6587",inputSchema:{type:"object",properties:{query:{type:"string",description:"\u81EA\u7136\u8BED\u8A00\u67E5\u8BE2"},mode:{type:"string",enum:["fast","deep"],default:"fast"},expandedTerms:{type:"string",description:"Agent \u9884\u7FFB\u8BD1\u7684\u82F1\u6587\u5173\u952E\u8BCD\uFF08\u7A7A\u683C\u5206\u9694\uFF09\uFF0C\u7528\u4E8E\u63D0\u5347\u4E2D\u6587\u67E5\u8BE2\u7684\u641C\u7D22\u6548\u679C"}},required:["query"]}},{name:"search_symbol",description:"\u6309\u7B26\u53F7\u540D\u641C\u7D22\u4EE3\u7801\u2014\u2014\u8BED\u4E49\u7EA7\u4EE3\u7801\u7ED3\u6784\u641C\u7D22",inputSchema:{type:"object",properties:{symbol:{type:"string",description:"\u7B26\u53F7\u540D\u79F0"}},required:["symbol"]}},{name:"get_dependency_graph",description:"\u83B7\u53D6\u6587\u4EF6/\u7EC4\u4EF6\u7684\u4F9D\u8D56\u5173\u7CFB",inputSchema:{type:"object",properties:{target:{type:"string",default:"all"},depth:{type:"number",default:2}}}},{name:"run_workflow",description:"\u6267\u884C\u6807\u51C6\u5316\u5F00\u53D1\u5DE5\u4F5C\u6D41",inputSchema:{type:"object",properties:{type:{type:"string",enum:["bugfix","feature","review"]},input:{type:"string"}},required:["type"]}},{name:"get_memory",description:"\u83B7\u53D6\u9879\u76EE\u8BB0\u5FC6\uFF1A\u6280\u672F\u6808\u3001\u7EA6\u5B9A\u3001\u504F\u597D\u3001\u5386\u53F2\u51B3\u7B56",inputSchema:{type:"object",properties:{}}},{name:"get_knowledge",description:"\u67E5\u8BE2\u6280\u672F\u6587\u6863\u77E5\u8BC6\u5E93",inputSchema:{type:"object",properties:{query:{type:"string"},scope:{type:"string",enum:["react","vue","nest","all"],default:"all"}},required:["query"]}},{name:"devflow_report_event",description:"Report fine-grained events within workflow steps (LLM calls, tool usage, file read/write etc.). Optional, for more granular observability.",inputSchema:{type:"object",properties:{runId:{type:"string"},stepId:{type:"string"},kind:{type:"string",enum:["llm_call","tool_use","memory_read","memory_write","file_read","file_write","bash_command","mcp_tool_call","error","user_input"]},duration:{type:"number"},model:{type:"string"},prompt:{type:"string"},response:{type:"string"},inputTokens:{type:"number"},outputTokens:{type:"number"},toolName:{type:"string"},toolInput:{type:"string"},toolOutput:{type:"string"},filePath:{type:"string"},command:{type:"string"},exitCode:{type:"number"},stdout:{type:"string"},stderr:{type:"string"},mcpToolName:{type:"string"},errorMessage:{type:"string"},errorStack:{type:"string"},memoryKey:{type:"string"},userMessage:{type:"string"}},required:["runId","stepId","kind"]}}]}function Ee(t){return {get_project_context:async({query:e,mode:o,expandedTerms:r})=>{let n=await t.context.buildTaskContext(e,{mode:o??"fast",sessionId:process.env.DEVFLOW_SESSION_ID??void 0});return {taskType:n.taskType,requiredFiles:n.requiredFiles,optionalFiles:n.optionalFiles,keySymbols:n.keySymbols,graphSummary:n.graphSummary,riskHints:n.riskHints,nextActions:n.nextActions,reasoning:n.reasoning,confidence:n.confidence,tokenCount:n.tokenCount,_devflow_unique:{search_method:"bm25_semantic",task_oriented:true,risk_aware:true,memory_injected:true,knowledge_injected:true,token_estimated:true,required_vs_optional:true}}},search_symbol:async({symbol:e})=>{let o=await t.indexer.findSymbol(e);return {result:Array.isArray(o)?o:[],_devflow_unique:{index_backed:true,kind_annotated:true,searched:e,match_count:Array.isArray(o)?o.length:0}}},get_dependency_graph:async({target:e,depth:o})=>{let r=e?.trim()??"all",n=o??2;if(r===""||r==="all")return {...t.graph.export(),_devflow_unique:{layer_annotated:true,architecture_grouped:true,query_depth:n}};let s=t.graph.getSubGraph(r,n);if(s.nodes.length===0){let a=t.graph.export();return {nodes:a.nodes.filter(i=>i.file.includes(r)),edges:a.edges.filter(i=>a.nodes.some(u=>u.id===i.from&&u.file.includes(r))||a.nodes.some(u=>u.id===i.to&&u.file.includes(r))),_fallback:"filename-filter",seeds:[r],depth:n}}return {...s,_devflow_unique:{layer_annotated:true,architecture_grouped:true,query_depth:n}}},run_workflow:async({type:e,input:o})=>({...await t.workflow.run(e,{input:o}),_devflow_unique:{dag_orchestrated:true,step_tracked:true,workflow_type:e}}),get_memory:async()=>({...await t.memory.getAll(),_devflow_unique:{memory_version:1,structured_storage:true,project_context_included:true}}),get_knowledge:async({query:e,scope:o})=>({...await t.knowledge.search(e,{sources:o==="all"?void 0:[o]}),_devflow_unique:{source_versioned:true,code_examples_included:true,search_scope:o}}),devflow_report_event:async e=>{let o=(p,f)=>!p||p.length<=f?{value:p??"",truncated:false}:{value:p.slice(0,f),truncated:true},r=o(e.prompt,500),n=o(e.response,500),s=o(e.stdout,1e3),a=o(e.stderr,500),i=r.truncated||n.truncated||s.truncated||a.truncated,u={id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,runId:e.runId,stepId:e.stepId,kind:e.kind,timestamp:Date.now(),duration:e.duration,data:{model:e.model,prompt:r.value,response:n.value,inputTokens:e.inputTokens,outputTokens:e.outputTokens,toolName:e.toolName,toolInput:e.toolInput,toolOutput:e.toolOutput,filePath:e.filePath,command:e.command,exitCode:e.exitCode,stdout:s.value,stderr:a.value,mcpToolName:e.mcpToolName,errorMessage:e.errorMessage,errorStack:e.errorStack,memoryKey:e.memoryKey,userMessage:e.userMessage},metadata:{source:"manual"},...i&&{metadata:{truncated:true,source:"manual"}}};return await t.telemetry.recordEvent(u),{acknowledged:true,eventId:u.id}}}}function I(t){let e=[];for(let o of t){let r=o.meta.name;for(let s of o.tools??[])e.push({name:s.name,description:s.description,inputSchema:s.inputSchema});let n=new Set(e.map(s=>s.name));for(let s of o.workflow?.templates??[]){let a=s.triggers?.find(u=>u.type==="mcp");if(!a?.tool)continue;let i=`${r}_${a.tool}`;n.has(i)||e.push({name:i,description:s.description,inputSchema:{type:"object",properties:s.steps.filter(u=>u.inputSchema).reduce((u,p)=>({...u,...p.inputSchema??{}}),{}),required:[]}});}}return e}function Pe(t,e){let o={};for(let r of e){let n=r.meta.name;for(let s of r.tools??[])s.handler&&(o[s.name]=s.handler);for(let s of r.workflow?.templates??[]){let a=s.triggers?.find(u=>u.type==="mcp");if(!a?.tool)continue;let i=`${n}_${a.tool}`;o[i]||(o[i]=async u=>{let p=await t.workflow.run(s.name,u),f="";try{let g={id:p.runId??`run:${Date.now()}`,source:"mcp",tool:i,workflow:s.name,input:u,status:"running",startedAt:Date.now(),finishedAt:null,steps:[],metadata:{}};f=t.workflow.renderPlan(g,s);}catch{}return {...p,plan:f,_devflow_unique:{dag_orchestrated:true,step_tracked:true,plugin_name:n,template_name:s.name}}});}}return o}var Te,N=v(()=>{Te={get_project_context:{group:"context",cacheable:true,idempotent:true},search_symbol:{group:"context",cacheable:true,idempotent:true},get_dependency_graph:{group:"context",cacheable:true,idempotent:true},get_memory:{group:"memory",cacheable:false,idempotent:true},devflow_report_event:{group:"memory",cacheable:false,idempotent:false},get_knowledge:{group:"knowledge",cacheable:true,idempotent:true},run_workflow:{group:"workflow",cacheable:false,idempotent:false},react_diagnose_bug:{group:"workflow",cacheable:false,idempotent:false},nest_diagnose_bug:{group:"workflow",cacheable:false,idempotent:false},nextjs_diagnose_bug:{group:"workflow",cacheable:false,idempotent:false},vue_diagnose_bug:{group:"workflow",cacheable:false,idempotent:false},graphql_diagnose_bug:{group:"workflow",cacheable:false,idempotent:false},electron_diagnose_bug:{group:"workflow",cacheable:false,idempotent:false},react_new_component:{group:"workflow",cacheable:false,idempotent:false},react_refactor_component:{group:"workflow",cacheable:false,idempotent:false},react_review_hooks:{group:"workflow",cacheable:false,idempotent:false},react_audit_performance:{group:"workflow",cacheable:false,idempotent:false},nest_new_module:{group:"workflow",cacheable:false,idempotent:false},graphql_new_graphql_type:{group:"workflow",cacheable:false,idempotent:false},nextjs_new_page:{group:"workflow",cacheable:false,idempotent:false},taro_new_page:{group:"workflow",cacheable:false,idempotent:false},vue_new_component:{group:"workflow",cacheable:false,idempotent:false},tailwind_new_component:{group:"workflow",cacheable:false,idempotent:false},docker_dockerize_project:{group:"lifecycle",cacheable:false,idempotent:false},performance_audit_performance:{group:"lifecycle",cacheable:false,idempotent:false}};});var $,F=v(()=>{$=[{id:"C001",name:"\u5FC5\u987B\u643A\u5E26 Session Token",level:"constitutional",condition:{requireFields:["_devflow_token"]},action:"deny",message:"\u7F3A\u5C11 Session Token\u3002\u8BF7\u901A\u8FC7 /devflow: \u547D\u4EE4\u542F\u52A8\u4F1A\u8BDD\uFF0C\u6216\u8FD0\u884C devflow session token \u83B7\u53D6\u4EE4\u724C\u3002"},{id:"C002",name:"Token \u5DF2\u8FC7\u671F",level:"constitutional",condition:{},action:"deny",message:"Session Token \u5DF2\u8FC7\u671F\uFF08\u8D85\u8FC7 1 \u5C0F\u65F6\uFF09\u3002\u8BF7\u91CD\u65B0\u8FD0\u884C devflow session token \u83B7\u53D6\u65B0\u4EE4\u724C\u3002"},{id:"C003",name:"\u901F\u7387\u9650\u5236",level:"constitutional",condition:{maxCallsPerMinute:60},action:"warn",message:"\u8C03\u7528\u9891\u7387\u8FC7\u9AD8\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"}];});async function ee(t){let e=await t.ruleGetAll();return [...$,...e]}function je(t,e){let o=t.condition;if(o.tools&&!o.tools.includes("*")&&!o.tools.includes(e.toolName))return "allow";if(o.requireFields){for(let r of o.requireFields)if(!(r in e.args))return t.action}if(o.forbidPatterns){for(let r of o.forbidPatterns)for(let n of Object.values(e.args))if(typeof n=="string"&&new RegExp(r).test(n))return t.action}if(o.paramPatterns)for(let[r,n]of Object.entries(o.paramPatterns)){let s=String(e.args[r]??"");if(new RegExp(n).test(s))return t.action}if(o.maxCallsPerMinute){let r=`${e.toolName}:${e.sessionId??"anon"}`,n=Date.now(),s=Z.get(r);if((!s||n>s.resetAt)&&(s={count:0,resetAt:n+6e4},Z.set(r,s)),s.count++,s.count>o.maxCallsPerMinute)return t.action}return "allow"}function te(t,e){let o=[...t].sort((r,n)=>{let s={constitutional:0,project:1,session:2};return s[r.level]-s[n.level]});for(let r of o){let n=je(r,e);if(n!=="allow")return {decision:n,rule:r}}return {decision:"allow"}}var Z,oe=v(()=>{F();Z=new Map;});function x(t){let e=JSON.stringify(t,Object.keys(t).sort());return createHash("sha256").update(e).digest("hex")}async function L(t,e,o,r,n,s){let a=await t.auditGetSecret(),i=await t.auditGetAll(),u=i.length>0?i[i.length-1].signature:createHash("sha256").update("genesis").digest("hex"),p=Date.now(),f=i.length+1,g=`${f}|${p}|${e}|${o}|${r}|${n??""}|${s}|${u}`,l=createHmac("sha256",a).update(g).digest("hex");await t.auditAppend({seq:f,ts:p,tool:e,argsHash:o,decision:r,ruleId:n,sessionId:s,prevHash:u,signature:l});}async function ne(t){let e=await t.auditGetSecret(),o=await t.auditGetAll(),r=createHash("sha256").update("genesis").digest("hex");for(let n of o){if(n.prevHash!==r)return {valid:false,brokenAt:n.seq};let s=`${n.seq}|${n.ts}|${n.tool}|${n.argsHash}|${n.decision}|${n.ruleId??""}|${n.sessionId}|${r}`,a=createHmac("sha256",e).update(s).digest("hex");if(n.signature!==a)return {valid:false,brokenAt:n.seq};r=n.signature;}return {valid:true,brokenAt:null}}async function re(t){let e=await t.auditGetSecret(),o=await t.auditGetAll(),r=createHash("sha256").update("genesis").digest("hex");for(let n of o){let s=`${n.seq}|${n.ts}|${n.tool}|${n.argsHash}|${n.decision}|${n.ruleId??""}|${n.sessionId}|${r}`,a=createHmac("sha256",e).update(s).digest("hex");await t.sqlExecute("UPDATE devflow_audit_chain SET prev_hash = ?, signature = ? WHERE seq = ?",[r,a,n.seq]),r=a;}}var J=v(()=>{});function b(t,e,o){let r=Date.now(),n=r+$e,s=createHash("sha256").update(JSON.stringify(e)).digest("hex"),a=`${t}|${r}|${n}|${s}`,i=createHmac("sha256",o).update(a).digest("hex");return {tool:t,ts:r,exp:n,queryHash:s,hmac:i}}function ie(t,e,o,r){if(Date.now()>t.exp)return false;let n=createHash("sha256").update(JSON.stringify(o)).digest("hex");if(t.queryHash!==n)return false;let s=`${e}|${t.ts}|${t.exp}|${n}`,a=createHmac("sha256",r).update(s).digest("hex");return t.hmac===a}function ce(t){return Date.now()>t.exp}var $e,W=v(()=>{$e=3e4;});var ue={};K(ue,{CONSTITUTIONAL_RULES:()=>$,enforce:()=>De,hashArgs:()=>x,isReceiptExpired:()=>ce,issueReceipt:()=>b,parseJwtPayload:()=>le,rebuildAuditChain:()=>re,verifyAuditChain:()=>ne,verifyReceipt:()=>ie});function le(t){try{let e=t.split(".");if(e.length!==3)return null;let o=e[1],r=Buffer.from(o,"base64url").toString("utf-8");return JSON.parse(r)}catch{return null}}async function De(t,e,o){if(!e._devflow_token){let g=process.env.DEVFLOW_SESSION_TOKEN;if(g){let l=le(g);l&&(e={...e,_devflow_token:l});}}let r=e._devflow_token?.sub??"anon",n={toolName:t,args:e,sessionId:r,tokenPayload:e._devflow_token};if(n.tokenPayload){let g=Math.floor(Date.now()/1e3);if(n.tokenPayload.exp&&g>n.tokenPayload.exp){let l=x(e);return await L(o,t,l,"deny","C002",r),{result:{allowed:false,message:"Session Token \u5DF2\u8FC7\u671F\uFF08\u8D85\u8FC7 1 \u5C0F\u65F6\uFF09\u3002\u8BF7\u91CD\u65B0\u8FD0\u884C devflow session token \u83B7\u53D6\u65B0\u4EE4\u724C\u3002"}}}}let s=await ee(o),{decision:a,rule:i}=te(s,n),u=x(e);if(await L(o,t,u,a,i?.id??null,r),a==="deny"&&i)return {result:{allowed:false,rule:i,message:i.message}};if(a==="warn"&&i){let g=await o.auditGetSecret(),l=b(t,e,g);return {result:{allowed:true,warning:i.message,rule:i},receipt:l}}let p=await o.auditGetSecret(),f=b(t,e,p);return {result:{allowed:true},receipt:f}}var pe=v(()=>{oe();J();W();J();W();F();});N();async function V(t){let e=await t.memory.listMemories({status:"approved"}),o=await t.knowledge.getSources();return {resources:[{uri:"devflow://memory/recent",name:"Recent Memories",description:`${e.length} approved project memories`,mimeType:"application/json"},{uri:"devflow://memory/pending",name:"Pending Memories",description:"Memory candidates awaiting approval",mimeType:"application/json"},{uri:"devflow://code/{file}:{line}",name:"Code Context",description:"Source code at specific file and line",mimeType:"text/plain"},{uri:"devflow://knowledge/{source}",name:"Knowledge Base",description:`Technical documentation (${o.length} sources)`,mimeType:"application/json"}]}}async function z(t,e){if(t==="devflow://memory/recent"){let o=await e.memory.listMemories({status:"approved"});return {contents:[{uri:t,mimeType:"application/json",text:JSON.stringify(o.slice(0,20),null,2)}]}}if(t==="devflow://memory/pending"){let o=await e.memory.getPendingMemories();return {contents:[{uri:t,mimeType:"application/json",text:JSON.stringify(o,null,2)}]}}if(t.startsWith("devflow://knowledge/")){let o=t.replace("devflow://knowledge/",""),r=await e.knowledge.search("",{sources:[o],limit:20});return {contents:[{uri:t,mimeType:"application/json",text:JSON.stringify(r,null,2)}]}}return {contents:[{uri:t,mimeType:"text/plain",text:JSON.stringify({message:"Resource not found"})}]}}var Y={"debug-react":{name:"Debug React Component",description:"Load React knowledge + project memories + related code for debugging",arguments:[{name:"query",description:"Bug description or component name",required:true}]},"code-review":{name:"Code Review",description:"Load project conventions + dependency graph for code review",arguments:[{name:"file",description:"File to review",required:true}]},"new-feature":{name:"New Feature",description:"Load project structure + knowledge base for feature planning",arguments:[{name:"feature",description:"Feature description",required:true}]},"fix-bug":{name:"Fix Bug",description:"Load failure lessons + dependency graph for bug fixing",arguments:[{name:"bug",description:"Bug description",required:true}]}};async function X(){return {prompts:Object.entries(Y).map(([t,e])=>({name:t,description:e.description,arguments:e.arguments}))}}async function Q(t,e){let o=Y[t];if(!o)throw new Error(`Prompt "${t}" not found`);return {messages:[{role:"user",content:{type:"text",text:`You are working on: ${o.description}
|
|
3
|
+
|
|
4
|
+
Context: ${JSON.stringify(e)}
|
|
5
|
+
|
|
6
|
+
Use available tools to complete this task.`}}]}}var j=class{constructor(e){this.server=e;this.name="mcp-sampling";}get isAvailable(){try{return this.server.getClientCapabilities()?.sampling!==void 0}catch{return false}}async chat(e){let o=await this.server.createMessage({messages:e.messages.map(s=>({role:s.role,content:{type:"text",text:s.content}})),maxTokens:e.maxTokens??4096,temperature:e.temperature,...e.systemPrompt?{systemPrompt:e.systemPrompt}:{}}),r=o.content,n="";return typeof r=="string"?n=r:"type"in r&&r.type==="text"?n=r.text:Array.isArray(r)&&(n=r.filter(s=>typeof s=="object"&&"type"in s&&s.type==="text").map(s=>s.text).join(`
|
|
7
|
+
`)),{content:n,model:o.model,usage:o.usage?{input:o.usage.inputTokens??0,output:o.usage.outputTokens??0}:void 0}}};async function fe(t){ze(t.projectRoot),Xe(t.projectRoot);let e=new Server({name:"devflow-mcp",version:"0.1.0"},{capabilities:{tools:{},resources:{},prompts:{}}}),o=new FallbackLLMClient(new j(e),new CliSubAgentClient),r=process.env.DEVFLOW_SERVER_URL??"http://127.0.0.1:13337",n=process.env.DEVFLOW_API_KEY??"dev-key-000000",s=new DevFlowApiClient({baseUrl:r,projectRoot:t.projectRoot,apiKey:n}),a=await s.ping(),i=await loadPlugins(),u=Array.from(i.values()),p=O(),f=I(u),g=[...p,...f];e.setRequestHandler(ListToolsRequestSchema,async()=>({tools:g})),e.setRequestHandler(ListResourcesRequestSchema,async()=>{if(a)return {resources:[]};if(!l){let[{createEngines:y}]=await Promise.all([import('@devflow-tools/context-engine')]);l=await y(t.projectRoot,o);}return V(l)}),e.setRequestHandler(ReadResourceRequestSchema,async y=>{if(a)throw new Error("Resources not available in remote mode");if(!l){let[{createEngines:c}]=await Promise.all([import('@devflow-tools/context-engine')]);l=await c(t.projectRoot,o);}return z(y.params.uri,l)}),e.setRequestHandler(ListPromptsRequestSchema,async()=>X()),e.setRequestHandler(GetPromptRequestSchema,async y=>Q(y.params.name,y.params.arguments??{}));let l=null,we=new Set(p.map(y=>y.name));e.setRequestHandler(CallToolRequestSchema,async y=>{let{name:c,arguments:he}=y.params,h=he??{},M=Date.now(),m=0;try{let d;if(we.has(c)&&a){d=await et(s,c,h),de(t.projectRoot,c),m=Date.now()-M;let q=c.split("_")[0];try{await s.recordTelemetryEvent({toolName:c,args:h,durationMs:m,success:!0,pluginName:q,metadata:{projectRoot:t.projectRoot}});}catch(w){console.error("[devflow-mcp] Failed to record telemetry:",w);}try{await s.recordMemoryEvent({id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:`session:${t.projectRoot.split("/").pop()??"default"}`,tool:c,command:S(c)||c,exitCode:0,durationMs:m});}catch(w){console.error("[devflow-mcp] Failed to record memory event:",w);}}else {if(!l){let[{createEngines:E}]=await Promise.all([import('@devflow-tools/context-engine')]),_=2;for(;_>0;)try{l=await E(t.projectRoot,o);break}catch(P){if(_--,_===0)throw P;console.error(`[devflow-mcp] createEngines failed, retrying... (${_} left):`,P.message),await new Promise(A=>setTimeout(A,1500));}let k=l;for(let P of u)for(let A of P.workflow?.templates??[])k.workflow.register(A);console.error(`[devflow-mcp] Warning: DevFlow server not reachable at ${r}`),console.error("[devflow-mcp] Running in local mode.");}if(!l)throw new Error("Failed to initialize local engines");let{enforce:q}=await Promise.resolve().then(()=>(pe(),ue)),w=await q(c,h,l.data);if(!w.result.allowed)return {content:[{type:"text",text:JSON.stringify({_devflow:{v:1,tool:c,ts:Date.now(),marker:"devflow-mcp-v1"},error:w.result.message,rule:w.result.rule?.id})}],isError:!0};let{createToolHandlers:ve,createPluginHandlers:ke}=await Promise.resolve().then(()=>(N(),B)),xe=ve(l),be=ke(l,u),U={...xe,...be}[c];if(!U)throw new Error(`Unknown tool: ${c}`);d=await U(h),de(t.projectRoot,c),m=Date.now()-M;try{await l.data.recordToolCall(c,h,m);let E=c.startsWith("devflow_")||c.includes("_"),_=c.split("_")[0],k=ge.has(_);await l.telemetry.recordToolCall({eventId:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,executionId:`exec:${t.projectRoot.split("/").pop()??"default"}:${Date.now()}`,timestamp:Date.now(),toolName:c,toolType:E||k?"mcp":"direct",isMcpTool:E||k,mcpToolName:k?c:void 0,mcpEnforced:!0,mcpFallback:!1,input:h,output:Ye(d),tokensUsed:0,duration:m,blocked:!1});}catch{}try{await l.memory.recordEvent({id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:`session:${t.projectRoot.split("/").pop()??"default"}`,tool:c,command:S(c)||c,exitCode:0,stderr:void 0,durationMs:m,createdAt:Date.now()}),l.memory.processSessionEvents().catch(()=>{});}catch{}w.receipt&&(d={...d,_receipt:w.receipt}),w.result.warning&&(d={...d,_warning:w.result.warning});}let _e=Qe(c,d,m);return {content:[{type:"text",text:JSON.stringify(_e,null,2)}]}}catch(d){if(m=Date.now()-M,a){try{await s.recordTelemetryEvent({toolName:c,args:h,durationMs:m,success:!1,error:d.message,pluginName:c.split("_")[0],metadata:{projectRoot:t.projectRoot}});}catch(T){console.error("[devflow-mcp] Failed to record error telemetry:",T);}try{await s.recordMemoryEvent({id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:`session:${t.projectRoot.split("/").pop()??"default"}`,tool:c,command:S(c)||c,exitCode:1,stderr:d.message,durationMs:m});}catch(T){console.error("[devflow-mcp] Failed to record error memory event:",T);}}else if(l){try{await l.data.recordToolCall(c,h,m,d.message);}catch{}try{await l.memory.recordEvent({id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:`session:${t.projectRoot.split("/").pop()??"default"}`,tool:c,command:S(c)||c,exitCode:1,stderr:d.message,durationMs:m,createdAt:Date.now()});}catch{}}return {content:[{type:"text",text:`Error: ${d.message}`}],isError:true}}});let ye=new StdioServerTransport;await e.connect(ye);}function ze(t){if(process.env.DEVFLOW_SESSION_TOKEN)return;let e=Buffer.from(JSON.stringify({alg:"HS256",typ:"JWT"})).toString("base64url"),o=Math.floor(Date.now()/1e3),r={sub:`devflow-mcp-${Date.now().toString(36)}`,project:t.split("/").pop()??"unknown",iat:o,exp:o+86400,scope:["context","knowledge","memory","workflow","graph"]},n=Buffer.from(JSON.stringify(r)).toString("base64url"),a=createHmac("sha256","devflow-local-mcp-secret-v1").update(`${e}.${n}`).digest("base64url");process.env.DEVFLOW_SESSION_TOKEN=`${e}.${n}.${a}`;let i=`session:${r.project}:${Date.now().toString(36)}`;process.env.DEVFLOW_SESSION_ID=i,console.error("[devflow-mcp] Auto-generated session token (no env token provided).");}var ge=new Set(["react","vue","nest","nextjs","graphql","docker","tailwind","taro","electron","performance"]);function S(t){let e={get_project_context:"context",search_symbol:"context",get_dependency_graph:"graph",get_knowledge:"knowledge",get_memory:"memory",run_workflow:"workflow"};if(e[t])return `devflow:${e[t]}`;let o=t.split("_")[0];return ge.has(o)?`devflow:${o}`:""}function de(t,e){try{let o=process.env.TMPDIR||"/tmp",r=join(o,".devflow-receipts"),n=createHash("sha256").update(t).digest("hex").slice(0,16),s=join(r,`${n}.json`);existsSync(r)||mkdirSync(r,{recursive:!0});let a={};if(existsSync(s))try{a=JSON.parse(readFileSync(s,"utf-8"));}catch{}a.lastMcpCall=Date.now(),a.bypassCount=0;let i=S(e);i&&(a.activeCommand=i),writeFileSync(s,JSON.stringify(a));}catch{}}function Ye(t){if(t&&typeof t=="object"&&!Array.isArray(t)){let{_devflow:e,_receipt:o,_warning:r,...n}=t;return Object.keys(n).length>0?n:t}return t}function Xe(t){try{let e=join(t,"apps/mcp-server/src"),o=join(t,"apps/mcp-server/dist");if(!existsSync(e)||!existsSync(o))return;let r=G(e),n=G(o);r>n&&console.error("[devflow-mcp] WARNING: dist/ is stale. Source files newer than build output. Run: npm run build --workspace=apps/mcp-server");}catch{}}function G(t){let e=0;try{let{readdirSync:o}=Re("fs"),r=o(t,{withFileTypes:!0});for(let n of r){let s=join(t,n.name);n.isDirectory()?e=Math.max(e,G(s)):e=Math.max(e,statSync(s).mtimeMs);}}catch{}return e}function Qe(t,e,o){let r={_devflow:{v:1,tool:t,ts:Date.now(),marker:"devflow-mcp-v1",...o!==void 0?{took_ms:o}:{}}};return e&&typeof e=="object"&&!Array.isArray(e)?{...e,...r}:{result:e,...r}}async function Ze(){let t=new Map,e=await loadPlugins(),o=Array.from(e.values());for(let r of o){let n=r.meta.name;for(let s of r.workflow?.templates??[]){let a=s.triggers?.find(i=>i.type==="mcp");if(a?.tool){let i=`${n}_${a.tool}`;t.set(i,s.name);}}}return t}async function et(t,e,o){switch(e){case "get_project_context":return t.buildContext(o.query,o.mode??"fast");case "search_symbol":return t.searchSymbol(o.symbol);case "get_dependency_graph":return t.getGraph(o.target??"all",o.depth??2);case "run_workflow":return t.runWorkflow(o.type,o.input);case "get_memory":return t.getMemory();case "get_knowledge":return t.searchKnowledge(o.query,o.scope??"all");case "devflow_report_event":return t.recordEvent(o);default:{let n=(await Ze()).get(e)??e;return t.runWorkflow(n,o)}}}async function tt(){let t=process.env.DEVFLOW_PROJECT_ROOT||process.cwd();await fe({mode:"stdio",projectRoot:t});}tt().catch(t=>{console.error("MCP Server error:",t),process.exit(1);});
|
package/dist/server.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import'reflect-metadata';import {Reflector,APP_GUARD,APP_INTERCEPTOR,NestFactory}from'@nestjs/core';import {FastifyAdapter}from'@nestjs/platform-fastify';import {Readable}from'stream';import {Injectable,Inject,Global,Module,Optional,Get,Query,Param,Post,Body,Delete,Controller,Headers,Put,forwardRef,Res,Catch,UnauthorizedException,NotFoundException,BadRequestException,SetMetadata,Logger,HttpException,HttpStatus}from'@nestjs/common';import {existsSync,readFileSync}from'fs';import {join}from'path';import {createEngines}from'@devflow-tools/context-engine';import {TelemetryEngine}from'@devflow-tools/telemetry';import {MemoryEngine,checkOllama,getOllamaInfoMessage}from'@devflow-tools/memory-engine';import {WorkflowEngine}from'@devflow-tools/workflow-engine';import {clearPluginCache,loadPlugins}from'@devflow-tools/sdk';import {Subject}from'rxjs';import {KnowledgeEngine}from'@devflow-tools/knowledge-engine';import {BenchmarkEngine}from'@devflow-tools/benchmark';import {DevFlowDatabase}from'@devflow-tools/database';import {homedir}from'os';import {map}from'rxjs/operators';var be=Object.defineProperty;var Pe=Object.getOwnPropertyDescriptor;var i=(c,t,e,s)=>{for(var n=s>1?void 0:s?Pe(t,e):t,o=c.length-1,a;o>=0;o--)(a=c[o])&&(n=(s?a(t,e,n):a(n))||n);return s&&n&&be(t,e,n),n},r=(c,t)=>(e,s)=>t(e,s,c);var Et="isPublic",Yt=()=>SetMetadata(Et,true);var xt={MISSING_API_KEY:"AUTH_MISSING_API_KEY",INVALID_API_KEY:"AUTH_INVALID_API_KEY"};var xe=(process.env.DEVFLOW_API_KEYS??"dev-key-000000").split(",").map(c=>c.trim()).filter(Boolean),Y=class{constructor(t){this.reflector=t;}canActivate(t){if(this.reflector.getAllAndOverride(Et,[t.getHandler(),t.getClass()]))return true;let n=t.switchToHttp().getRequest().headers["x-api-key"];if(!n)throw new UnauthorizedException({error:{code:xt.MISSING_API_KEY,message:"X-API-Key header is required",details:{}}});if(!xe.includes(n))throw new UnauthorizedException({error:{code:xt.INVALID_API_KEY,message:"Invalid API key",details:{}}});return true}};Y=i([Injectable(),r(0,Inject(Reflector))],Y);var z=class{};z=i([Global(),Module({providers:[Y,{provide:APP_GUARD,useClass:Y}]})],z);var d={WORKFLOW_NOT_FOUND:"WORKFLOW_NOT_FOUND",RUN_NOT_FOUND:"RUN_NOT_FOUND",PROJECT_NOT_FOUND:"PROJECT_NOT_FOUND",NODE_NOT_FOUND:"NODE_NOT_FOUND",PLUGIN_NOT_FOUND:"PLUGIN_NOT_FOUND",BAD_REQUEST:"BAD_REQUEST",VALIDATION_ERROR:"VALIDATION_ERROR",INTERNAL_ERROR:"INTERNAL_ERROR"};var p=class{constructor(t){this.database=t;this.projects=new Map;this.activeProjectRoot=process.env.DEVFLOW_PROJECT_ROOT??null;}onModuleInit(){if(!process.env.DEVFLOW_PROJECT_ROOT&&this.database){let t=this.database.getSetting("activeProjectRoot");t&&(this.activeProjectRoot=t);}}setActiveProject(t){this.activeProjectRoot=t,this.database&&this.database.setSetting("activeProjectRoot",t);}disconnectProject(){this.activeProjectRoot=null,this.database&&this.database.deleteSetting("activeProjectRoot");}getActiveProjectRoot(){return this.activeProjectRoot}async list(){return Array.from(this.projects.values())}async getById(t){let e=this.projects.get(t);if(!e)throw new NotFoundException({error:{code:d.PROJECT_NOT_FOUND,message:`Project "${t}" not found`,details:{}}});return e}async create(t){let e=`proj_${Date.now()}_${Math.random().toString(36).slice(2,7)}`,s={id:e,name:t.name,rootPath:t.rootPath,stack:t.stack,createdAt:Date.now()};return this.projects.set(e,s),this.activeProjectRoot||this.setActiveProject(t.rootPath),s}async delete(t){if(!this.projects.has(t))throw new NotFoundException({error:{code:d.PROJECT_NOT_FOUND,message:`Project "${t}" not found`,details:{}}});this.projects.delete(t);}async getOnboardingPack(t){let e=join(t,".devflow","onboarding-pack.json");if(!existsSync(e))throw new NotFoundException({error:{code:d.PROJECT_NOT_FOUND,message:"Onboarding pack not found. Run `devflow init` first.",details:{}}});return JSON.parse(readFileSync(e,"utf-8"))}async getOnboardingPackByRoot(t){let e=join(t,".devflow","onboarding-pack.json");try{return existsSync(e)?JSON.parse(readFileSync(e,"utf-8")):null}catch{return null}}};p=i([Injectable(),r(0,Optional()),r(0,Inject("DATABASE"))],p);var h=class{constructor(t){this.service=t;}async list(){return this.service.list()}async getOnboardingPackByRoot(t){if(!t)throw new BadRequestException({error:{code:d.BAD_REQUEST,message:"rootPath is required",details:{}}});return this.service.getOnboardingPackByRoot(t)}async getById(t){return this.service.getById(t)}async getOnboardingPack(t){let e=await this.service.getById(t);return this.service.getOnboardingPack(e.rootPath)}async create(t){return this.service.create(t)}async connect(t){return this.service.setActiveProject(t.rootPath),{rootPath:t.rootPath}}async switchProject(t){return this.service.setActiveProject(t.rootPath),{rootPath:t.rootPath}}async getActive(){return {rootPath:this.service.getActiveProjectRoot()}}async disconnect(){return this.service.disconnectProject(),{ok:true}}async delete(t){return this.service.delete(t)}};i([Get()],h.prototype,"list",1),i([Get("onboarding-pack"),r(0,Query("rootPath"))],h.prototype,"getOnboardingPackByRoot",1),i([Get(":id"),r(0,Param("id"))],h.prototype,"getById",1),i([Get(":id/onboarding-pack"),r(0,Param("id"))],h.prototype,"getOnboardingPack",1),i([Post(),r(0,Body())],h.prototype,"create",1),i([Post("connect"),r(0,Body())],h.prototype,"connect",1),i([Post("switch"),r(0,Body())],h.prototype,"switchProject",1),i([Get("active")],h.prototype,"getActive",1),i([Delete("active")],h.prototype,"disconnect",1),i([Delete(":id"),r(0,Param("id"))],h.prototype,"delete",1),h=i([Controller("projects"),r(0,Inject(p))],h);var v=class{};v=i([Module({controllers:[h],providers:[p],exports:[p]})],v);var P=class{constructor(t){this.engine=new TelemetryEngine;this.db=t??null;}async recordEvent(t){this.db&&this.db.insertEvent?.({runId:t.runId,kind:t.kind,timestamp:t.timestamp,duration:t.duration,toolName:t.data?.toolName,pluginName:t.data?.mcpToolName,metadata:t.data});}async createSession(t){this.db&&this.db.insertSession({id:t.id,projectRoot:t.projectRoot,label:t.label,startedAt:t.startedAt});}async getSession(t){if(!this.db)throw new NotFoundException({error:{code:d.RUN_NOT_FOUND,message:`Session "${t}" not found`,details:{}}});let e=this.db.getSession(t);if(!e)throw new NotFoundException({error:{code:d.RUN_NOT_FOUND,message:`Session "${t}" not found`,details:{}}});return e}async listSessions(t,e,s){return this.db?this.db.listSessions(t,e,s):[]}async getSessionEvents(t){return this.db?this.db.listToolCallEventsBySession?.(t)??[]:[]}async closeSession(t,e){this.db&&this.db.closeSession(t,e);}async createSkillExecution(t){this.db&&this.db.insertSkillExecution({executionId:t.executionId,sessionId:t.sessionId,skillName:t.skillName,startedAt:t.startedAt,status:"running"});}async listRuns(t,e,s){if(this.db)try{return this.db.listSessions(t,e).map(o=>({id:o.id,agent:"claude-code",mode:"hook",source:"hook",status:o.status,startedAt:o.startedAt,totalToolCalls:o.totalToolCalls,mcpToolCalls:o.mcpToolCalls,mcpComplianceRate:o.mcpToolCalls>0?Math.round(o.mcpToolCalls/o.totalToolCalls*100)/100:0}))}catch{}return []}async getRun(t){if(this.db)try{let s=this.db.getSession(t);if(s)return {meta:{runId:s.id,agent:"claude-code",mode:"hook",source:"hook"},status:s.status,startedAt:s.startedAt,finishedAt:s.finishedAt,totalToolCalls:s.totalToolCalls,mcpToolCalls:s.mcpToolCalls,steps:[]};let n=this.db.getSkillExecution(t);if(n)return {meta:{runId:n.executionId,agent:"claude-code",mode:"hook",source:"hook"},status:n.status,startedAt:n.startedAt,finishedAt:n.finishedAt,skillName:n.skillName,totalToolCalls:n.totalToolCalls,mcpToolCalls:n.mcpToolCalls,mcpComplianceRate:n.mcpComplianceRate,steps:[]}}catch{}let e=this.engine.runs.get(t);if(e)return e;throw new NotFoundException({error:{code:d.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}})}async getTimeline(t,e){if(!this.db)return [];try{return this.db.listSessions(500,0).filter(n=>!(t&&n.startedAt<Number(t)||e&&n.startedAt>Number(e))).map(n=>({runId:n.id,stepId:n.id,type:"session",duration:n.durationMs,timestamp:n.startedAt}))}catch{return []}}async getRunEvents(t){if(this.db)try{let s=this.db.listToolCallEventsBySession(t);if(s&&s.length>0)return s;let n=this.db.listToolCallEvents(t);if(n&&n.length>0)return n}catch{}return await this.engine.listEvents(t)??[]}async getRunStats(t){if(this.db)try{let e=this.db.listToolCallEventsBySession(t)??this.db.listToolCallEvents(t)??[];if(e.length>0)return {totalEvents:e.length,llmCalls:0,totalTokens:0,toolUses:e.length,fileReads:0,fileWrites:0,bashCommands:0,errors:e.filter(s=>s.error).length,totalDuration:0,mcpToolCalls:e.filter(s=>s.isMcpTool).length,directToolCalls:e.filter(s=>!s.isMcpTool).length,mcpComplianceRate:e.length>0?e.filter(s=>s.isMcpTool).length/e.length:0}}catch{}return this.engine.getRunStats(t)}async endRun(t,e){await this.engine.endRun(t,e);}async getStats(t=7){if(!this.db)return this.emptyStats();let e=Date.now(),s=e-t*24*60*60*1e3;try{let o=this.db.listSessions(1e3,0).filter(u=>u.startedAt>=s),a={},l=0;for(let u of o){let y=new Date(u.startedAt).toISOString().slice(0,10);a[y]||(a[y]={runs:0}),a[y].runs++,l+=u.totalToolCalls??0;}return {period:{from:new Date(s).toISOString().slice(0,10),to:new Date(e).toISOString().slice(0,10)},summary:{totalRuns:o.length,completedRuns:o.filter(u=>u.status==="completed").length,failedRuns:o.filter(u=>u.status==="failed").length,totalTokens:0,totalLlmCalls:0,totalToolUses:l,avgRunDuration:o.length>0?Math.round(o.reduce((u,y)=>u+(y.durationMs??0),0)/o.length):0},byDay:Object.entries(a).map(([u,y])=>({date:u,tokens:0,...y})).sort((u,y)=>u.date.localeCompare(y.date)),byWorkflow:[],byPlugin:[]}}catch{return this.emptyStats()}}emptyStats(){return {period:{from:"",to:""},summary:{totalRuns:0,completedRuns:0,failedRuns:0,totalTokens:0,totalLlmCalls:0,totalToolUses:0,avgRunDuration:0},byDay:[],byWorkflow:[],byPlugin:[]}}async getRoiSummary(t=7){if(!this.db)return this.emptyRoiSummary();let e=Date.now(),s=e-t*24*60*60*1e3;try{let o=this.db.listSessions(1e3,0).filter(g=>g.startedAt>=s),a=o.length,l=o.filter(g=>g.status==="completed").length,u=o.filter(g=>g.status==="failed").length,y=a>0?Math.round(o.reduce((g,R)=>g+(R.durationMs??0),0)/a):0,mt={};for(let g of o){let R=new Date(g.startedAt).toISOString().slice(0,10);mt[R]||(mt[R]={runs:0,failures:0}),mt[R].runs++,g.status!=="completed"&&mt[R].failures++;}let Qt=this.db.listToolCallEventsBySessions(o.map(g=>g.id)),yt={tool_error:0,mcp_unavailable:0,unknown:0},St={};for(let g of o){let R=Qt[g.id]??[];for(let K of R){if(K.error){let k=K.error.toLowerCase();k.includes("mcp")||k.includes("unavailable")||k.includes("not found")?yt.mcp_unavailable++:k.includes("tool")||k.includes("command")||k.includes("error")?yt.tool_error++:yt.unknown++;}if(K.mcpToolName){let k=K.mcpToolName.split("_")[0];k&&(St[k]=(St[k]??0)+1);}}}return {period:{from:new Date(s).toISOString().slice(0,10),to:new Date(e).toISOString().slice(0,10)},overview:{totalRuns:a,completedRuns:l,failedRuns:u,avgDuration:y,firstPassSuccessRate:a>0?Math.round(l/a*1e4)/100:0},efficiency:{avgTimePerTask:y},failures:{total:u,breakdown:yt},workflows:[],plugins:Object.entries(St).map(([g,R])=>{let K=o.filter(kt=>(Qt[kt.id]??[]).some(Re=>Re.mcpToolName?.startsWith(g+"_"))),k=K.filter(kt=>kt.status==="completed").length,ye=K.length>0?Math.round(k/K.length*1e4)/100:0;return {name:g,runs:R,successRate:ye}}),byDay:Object.entries(mt).map(([g,R])=>({date:g,...R,tokens:0})).sort((g,R)=>g.date.localeCompare(R.date))}}catch{return this.emptyRoiSummary()}}emptyRoiSummary(){return {period:{from:"",to:""},overview:{totalRuns:0,completedRuns:0,failedRuns:0,avgDuration:0,avgTokens:0,firstPassSuccessRate:0,feedbackHitRate:0},efficiency:{totalTokensSaved:0,avgTimePerTask:0,avgRetryCount:0},failures:{total:0,breakdown:{tool_error:0,mcp_unavailable:0,unknown:0}},workflows:[],plugins:[],byDay:[]}}async recordExecutionStart(t){this.db&&this.db.insertSkillExecution({executionId:t.executionId,sessionId:t.sessionId,skillName:t.skillName,startedAt:t.startedAt,status:"running"});}async recordToolCall(t){this.db&&this.db.insertToolCallEvent({eventId:t.eventId,executionId:t.executionId,sessionId:t.sessionId,timestamp:t.timestamp,toolName:t.toolName,toolType:t.toolType,isMcpTool:t.isMcpTool,mcpToolName:t.mcpToolName,mcpEnforced:t.mcpEnforced,mcpFallback:t.mcpFallback,kind:t.kind??"tool_use",input:t.input,duration:t.duration,parentToolCallId:t.parentToolCallId,subagentId:t.subagentId,error:t.error,blocked:t.blocked,blockReason:t.blockReason});}async updateToolCallOutput(t,e,s,n){this.db&&this.db.updateToolCallEvent(t,{output:JSON.stringify(e),duration:n});}async recordExecutionComplete(t){this.db&&this.db.updateSkillExecution(t.executionId,{status:t.status,finishedAt:t.finishedAt,totalDuration:t.summary.totalDuration,mcpComplianceRate:t.summary.mcpComplianceRate,totalToolCalls:t.summary.totalToolCalls,mcpToolCalls:t.summary.mcpToolCalls,directToolCalls:t.summary.directToolCalls,subagentCount:t.summary.subagentCount});}async getExecutions(t,e){return this.db?this.db.listSkillExecutions(t,e):[]}async getExecutionEvents(t){return this.db?this.db.listToolCallEvents(t):[]}async getMcpCompliance(){return this.db?this.db.getMcpCompliance():{overall:0,bySkill:{},missedTools:[]}}async classifyFailure(t){let e=await this.getRun(t).catch(()=>null);if(!e||e.status!=="failed")return {};let s=e.steps?.find(o=>o.status==="failed");if(!s)return {};let n=s.error?.toLowerCase()??"";return n.includes("context")||n.includes("insufficient")?{failureCategory:"context_insufficient",failureReason:"Context provided was insufficient for the task",suggestedActions:[{action:"Supplement task context",priority:"high"},{action:"View graph roots",priority:"medium"},{action:"Add related memory",priority:"medium"}]}:n.includes("knowledge")||n.includes("docs")?{failureCategory:"knowledge_missing",failureReason:"Required knowledge was not available",suggestedActions:[{action:"Sync knowledge source",priority:"high"},{action:"Add docs source",priority:"medium"}]}:n.includes("workflow")||n.includes("step")?{failureCategory:"workflow_design_issue",failureReason:"Workflow design issue detected",suggestedActions:[{action:"Adjust specific step",priority:"high"},{action:"Split workflow",priority:"medium"}]}:n.includes("tool")||n.includes("connection")?{failureCategory:"tool_error",failureReason:"Tool execution error",suggestedActions:[{action:"Check tool connectivity",priority:"high"},{action:"Retry or fallback",priority:"medium"}]}:{failureCategory:"agent_override",failureReason:"Agent override detected",suggestedActions:[{action:"Enable/strengthen enforcer",priority:"high"}]}}async cleanup(t){if(!this.db)return 0;try{this.db.cleanupStaleRecords?.();}catch{}let e=this.engine.runs,s=Date.now()-t*24*60*60*1e3,n=0;for(let[o,a]of e)a.startedAt&&a.startedAt<s&&(e.delete(o),n++);return n}async cleanupStaleRecords(){if(this.db)try{this.db.cleanupStaleRecords?.();}catch{}}async getFeedbackStats(t,e){return {total:0,hits:0,partials:0,misses:0,hitRate:0,partialRate:0,missRate:0}}async getOpsRoiSummary(){return {period:"all-time",totalRuns:0,successfulRuns:0,successRate:0,avgTokenUsage:0,avgDuration:0,feedbackHitRate:0,trend:"stable"}}async getExperimentalRoiSummary(){return {totalScenarios:0,avgTimeSavedRate:null,avgTokenReductionRate:null,avgFirstPassLift:null,avgReworkReductionRate:null,conclusion:"No experimental data available yet"}}async getPluginEffectiveness(t,e){if(!this.db)return {name:t,totalRuns:0,successRate:0,lastUsedAt:null};let s=this.db.listSessions(1e3,0),n=0;for(let o of s){let a=this.db.listToolCallEventsBySession(o.id);for(let l of a)l.mcpToolName?.startsWith(t+"_")&&n++;}return {name:t,totalRuns:n,successRate:0,lastUsedAt:null}}async getPluginUsageStats(t){let e=await this.getPluginEffectiveness(t);return {activeProjects:0,totalRuns:e.totalRuns,successfulRuns:0,lastUsedAt:e.lastUsedAt??void 0}}};P=i([Injectable(),r(0,Optional()),r(0,Inject("DATABASE"))],P);var j=class{constructor(t,e){this.telemetryService=t;this.database=e;this.projectStats=new Map;this.benchmarkResults=[];}async recordTelemetryEvent(t){let e=`evt_${Date.now()}_${Math.random().toString(36).slice(2,7)}`,s=t.toolName?"tool_use":"step_end",n={id:e,runId:t.metadata?.runId??`event_${Date.now()}_${Math.random().toString(36).slice(2,7)}`,stepId:e,kind:s,timestamp:Date.now(),duration:t.durationMs,data:{toolName:t.toolName,toolInput:t.args,errorMessage:t.error},metadata:{source:"claude-code"}};return await this.telemetryService.recordEvent(n),{eventId:e}}async getProjectStats(t){return this.database?this.database.getProjectStats(t):this.projectStats.get(t)??null}async updateProjectStats(t,e){if(this.database){let a={...await this.getProjectStats(t)??{projectRoot:t,totalRuns:0,successfulRuns:0,totalTokens:0,lastActiveAt:Date.now(),topTools:[]},...e,lastActiveAt:Date.now()};return await this.database.upsertProjectStats(a),a}let n={...this.projectStats.get(t)??{projectRoot:t,totalRuns:0,successfulRuns:0,totalTokens:0,lastActiveAt:Date.now(),topTools:[]},...e,lastActiveAt:Date.now()};return this.projectStats.set(t,n),n}recordBenchmarkResult(t){this.benchmarkResults.push(t);}getBenchmarkResults(t){return t?this.benchmarkResults.filter(e=>this.projectStats.get(e.scenarioId)?.projectRoot===t):this.benchmarkResults}async getPluginEffectiveness(t){return []}};j=i([Injectable(),r(0,Inject(P)),r(1,Optional()),r(1,Inject("DATABASE"))],j);var F=class{constructor(t){this.dataService=t;this.feedbackEntries=[];}async indexProject(t){let{context:e,codegraph:s}=await createEngines(t);await e.index(t);let n=s.getStats();return {totalFiles:n.fileCount,totalSymbols:n.nodeCount,lastIndexTime:n.lastUpdated,indexing:s.isIndexing()}}async getStatus(t){try{let{codegraph:e}=await createEngines(t),s=e.getStats();return {totalFiles:s.fileCount,totalSymbols:s.nodeCount,lastIndexTime:s.lastUpdated,indexing:e.isIndexing()}}catch{return {totalFiles:0,totalSymbols:0,lastIndexTime:0,indexing:false}}}async buildContext(t,e,s,n){let{context:o}=await createEngines(t);return o.build({query:e,mode:s,maxTokens:n??8e3,includeGraph:s==="deep"})}async buildTaskContext(t,e,s,n){let{context:o}=await createEngines(t);return o.buildTaskContext(e,{mode:s,maxTokens:n??8e3})}async findSymbol(t,e){let{indexer:s}=await createEngines(t);return s.findSymbol(e)}async recordFeedback(t,e,s,n){let o={query:e,feedback:s,timestamp:Date.now(),projectRoot:t};return this.feedbackEntries.push(o),this.dataService&&await this.dataService.recordTelemetryEvent({toolName:"context_feedback",args:{query:e,feedback:s,taskType:n?.taskType,contextMode:n?.contextMode,projectRoot:t},durationMs:0,success:true,metadata:{projectRoot:t,query:e,taskType:n?.taskType}}),o}async getFeedbackSummaries(){let t=this.feedbackEntries.length,e=this.feedbackEntries.filter(o=>o.feedback==="hit").length,s=this.feedbackEntries.filter(o=>o.feedback==="partial").length,n=this.feedbackEntries.filter(o=>o.feedback==="miss").length;return {total:t,hits:e,partials:s,misses:n,hitRate:t>0?e/t:0}}};F=i([Injectable(),r(0,Optional()),r(0,Inject(j))],F);var w=class{constructor(t,e){this.service=t;this.projects=e;}resolveRootPath(t,e){let s=t??e??this.projects.getActiveProjectRoot();if(!s)throw new BadRequestException("rootPath is required \u2014 no active project connected");return s}async status(t,e){let s=t??e??this.projects.getActiveProjectRoot();return s?this.service.getStatus(s):null}async index(t,e){return this.service.indexProject(this.resolveRootPath(t.rootPath,e))}async build(t,e){return this.service.buildContext(this.resolveRootPath(t.rootPath,e),t.query,t.mode??"fast",t.maxTokens)}async buildTask(t,e){return this.service.buildTaskContext(this.resolveRootPath(t.rootPath,e),t.query,t.mode??"fast",t.maxTokens)}async feedback(t,e){return this.service.recordFeedback(this.resolveRootPath(t.rootPath,e),t.query,t.feedback,{taskType:t.taskType,contextMode:t.contextMode,runId:t.runId,tokenCount:t.tokenCount})}async feedbackSummary(){return this.service.getFeedbackSummaries()}async findSymbol(t,e,s){return this.service.findSymbol(this.resolveRootPath(e,s),t)}};i([Get("status"),r(0,Query("rootPath")),r(1,Headers("x-devflow-project"))],w.prototype,"status",1),i([Post("index"),r(0,Body()),r(1,Headers("x-devflow-project"))],w.prototype,"index",1),i([Post("build"),r(0,Body()),r(1,Headers("x-devflow-project"))],w.prototype,"build",1),i([Post("build-task"),r(0,Body()),r(1,Headers("x-devflow-project"))],w.prototype,"buildTask",1),i([Post("feedback"),r(0,Body()),r(1,Headers("x-devflow-project"))],w.prototype,"feedback",1),i([Get("feedback-summary")],w.prototype,"feedbackSummary",1),i([Get("symbol/:name"),r(0,Param("name")),r(1,Query("rootPath")),r(2,Headers("x-devflow-project"))],w.prototype,"findSymbol",1),w=i([Controller("context"),r(0,Inject(F)),r(1,Inject(p))],w);var N=class{constructor(t){this.dataService=t;}async recordTelemetryEvent(t){return {success:true,...await this.dataService.recordTelemetryEvent(t)}}async getProjectStats(t){return this.dataService.getProjectStats(t)}async updateProjectStats(t){return this.dataService.updateProjectStats(t.projectRoot,t.stats)}recordBenchmarkResult(t){return this.dataService.recordBenchmarkResult(t),{success:true}}getBenchmarkResults(t){return this.dataService.getBenchmarkResults(t)}};i([Post("telemetry/event"),r(0,Body())],N.prototype,"recordTelemetryEvent",1),i([Get("project/stats"),r(0,Query("rootPath"))],N.prototype,"getProjectStats",1),i([Post("project/stats"),r(0,Body())],N.prototype,"updateProjectStats",1),i([Post("benchmark/result"),r(0,Body())],N.prototype,"recordBenchmarkResult",1),i([Get("benchmark/results"),r(0,Query("projectRoot"))],N.prototype,"getBenchmarkResults",1),N=i([Controller("data"),r(0,Inject(j))],N);var O=class{constructor(){this.engines=new Map;this.ENGINE_TTL=3600*1e3;}getEngine(t){let e=Date.now();for(let[o,a]of this.engines)if(e-a.lastAccess>this.ENGINE_TTL){try{a.engine.close?.();}catch{}this.engines.delete(o);}let s=t.replace(/\/+$/,""),n=this.engines.get(s);return n?n.lastAccess=e:(n={engine:new MemoryEngine(s),lastAccess:e},this.engines.set(s,n)),n.engine}async getAll(t){let e=this.getEngine(t),[s,n]=await Promise.all([e.listMemories(),checkOllama()]);return {memories:s.map(o=>({id:o.id,category:o.category,content:o.content,originalText:o.originalText,source:o.source,status:o.status,confidence:o.confidence,scope:o.scope,createdAt:o.createdAt,approvedAt:o.approvedAt})),ollama:{installed:n.installed,running:n.running,modelAvailable:n.modelAvailable,modelName:n.modelName,infoMessage:getOllamaInfoMessage(n)}}}async add(t,e){return this.getEngine(t).addMemory({category:e.category,content:e.content,source:"manual",confidence:1,scope:e.scope??""})}async update(t,e,s){await this.getEngine(t).updateMemory(e,s);}async delete(t,e){await this.getEngine(t).deleteMemory(e);}async getCandidates(t){return this.getEngine(t).getPendingMemories()}async approveCandidate(t,e){await this.getEngine(t).approveMemory(e);}async rejectCandidate(t,e){await this.getEngine(t).rejectMemory(e);}async search(t,e,s){return (await this.getEngine(t).search(e,s)).map(o=>o.entry)}async extract(t,e){return this.getEngine(t).extractMemories(e)}async getOllamaStatus(){let t=await checkOllama();return {...t,infoMessage:getOllamaInfoMessage(t)}}async updateLegacy(t,e,s,n){e!=="user"&&await this.getEngine(t).addMemory({category:"project_knowledge",content:`${s}: ${JSON.stringify(n)}`,source:"manual",confidence:1,scope:s});}async recordEvent(t,e){let s=this.getEngine(t);return await s.recordEvent({id:e.id,sessionId:e.sessionId,tool:e.tool,command:e.command,exitCode:e.exitCode,stderr:e.stderr,durationMs:e.durationMs,createdAt:Date.now()}),{acknowledged:true,extracted:(await s.extractFromEventsRealtime([{tool:e.tool,command:e.command,exitCode:e.exitCode,stderr:e.stderr}])).length}}async processSessionEvents(t){return this.getEngine(t).processSessionEvents()}};O=i([Injectable()],O);var m=class{constructor(t,e,s){this.service=t;this.memoryService=e;this.projectsService=s;}async listRuns(t,e,s){return this.service.listRuns(Number(t)||20,Number(e)||0,s)}async getRun(t){let e=await this.service.getRun(t),s=await this.service.classifyFailure(t);return {...e,...s}}async getTimeline(t,e){return this.service.getTimeline(t,e)}async getRunEvents(t){return this.service.getRunEvents(t)}async getRunStats(t){return this.service.getRunStats(t)}async completeRun(t){await this.service.endRun(t,{status:"success"});let e=await this.service.getRunEvents(t),s=this.projectsService.getActiveProjectRoot(),n=await this.memoryService.extract(s??"",e);return {extracted:Array.isArray(n)?n.length:0}}async getStats(t){return this.service.getStats(Number(t)||7)}async getRoiSummary(t){return this.service.getRoiSummary(Number(t)||7)}async cleanup(t){return {removedRuns:await this.service.cleanup(t.olderThanDays??30)}}async cleanupStale(){return await this.service.cleanupStaleRecords(),{ok:true}}async createSession(t){return await this.service.createSession(t),{id:t.id}}async listSessions(t,e,s){return this.service.listSessions(Number(t)||20,Number(e)||0,s)}async getSession(t){return this.service.getSession(t)}async getSessionEvents(t){return this.service.getSessionEvents(t)}async closeSession(t,e){return await this.service.closeSession(t,e.finishedAt),{}}async startSessionSkillExecution(t,e){return await this.service.createSkillExecution({...e,sessionId:t}),{executionId:e.executionId}}async startSkillExecution(t){return await this.service.recordExecutionStart(t),{executionId:t.executionId}}async recordToolCall(t){return await this.service.recordToolCall(t),{eventId:t.eventId}}async updateToolCallOutput(t){return await this.service.updateToolCallOutput(t.eventId,t.output,t.completedAt,t.duration),{}}async completeSkillExecution(t){return await this.service.recordExecutionComplete(t),{}}async getExecutions(t,e){return this.service.getExecutions(Number(t)||20,e)}async getExecutionEvents(t){return this.service.getExecutionEvents(t)}async getMcpCompliance(){return await this.service.getMcpCompliance()}};i([Get("runs"),r(0,Query("limit")),r(1,Query("offset")),r(2,Query("source"))],m.prototype,"listRuns",1),i([Get("runs/:id"),r(0,Param("id"))],m.prototype,"getRun",1),i([Get("timeline"),r(0,Query("from")),r(1,Query("to"))],m.prototype,"getTimeline",1),i([Get("runs/:runId/events"),r(0,Param("runId"))],m.prototype,"getRunEvents",1),i([Get("runs/:runId/stats"),r(0,Param("runId"))],m.prototype,"getRunStats",1),i([Post("runs/:id/complete"),r(0,Param("id"))],m.prototype,"completeRun",1),i([Get("stats"),r(0,Query("days"))],m.prototype,"getStats",1),i([Get("roi-summary"),r(0,Query("days"))],m.prototype,"getRoiSummary",1),i([Post("cleanup"),r(0,Body())],m.prototype,"cleanup",1),i([Post("cleanup-stale")],m.prototype,"cleanupStale",1),i([Post("sessions"),r(0,Body())],m.prototype,"createSession",1),i([Get("sessions"),r(0,Query("limit")),r(1,Query("offset")),r(2,Query("projectRoot"))],m.prototype,"listSessions",1),i([Get("sessions/:id"),r(0,Param("id"))],m.prototype,"getSession",1),i([Get("sessions/:id/events"),r(0,Param("id"))],m.prototype,"getSessionEvents",1),i([Post("sessions/:id/close"),r(0,Param("id")),r(1,Body())],m.prototype,"closeSession",1),i([Post("sessions/:id/skill-executions"),r(0,Param("id")),r(1,Body())],m.prototype,"startSessionSkillExecution",1),i([Post("skill-execution/start"),r(0,Body())],m.prototype,"startSkillExecution",1),i([Post("tool-call"),r(0,Body())],m.prototype,"recordToolCall",1),i([Post("tool-call/output"),r(0,Body())],m.prototype,"updateToolCallOutput",1),i([Post("skill-execution/complete"),r(0,Body())],m.prototype,"completeSkillExecution",1),i([Get("executions"),r(0,Query("limit")),r(1,Query("skillName"))],m.prototype,"getExecutions",1),i([Get("executions/:id/events"),r(0,Param("id"))],m.prototype,"getExecutionEvents",1),i([Get("mcp-compliance")],m.prototype,"getMcpCompliance",1),m=i([Controller("telemetry"),r(0,Inject(P)),r(1,Inject(O)),r(2,Inject(p))],m);var f=class{constructor(t,e){this.service=t;this.projects=e;}resolveRootPath(t,e){let s=t??e??this.projects.getActiveProjectRoot();if(!s)throw new BadRequestException({error:{code:d.BAD_REQUEST,message:"rootPath is required \u2014 no active project connected",details:{}}});return s}async getAll(t,e){return this.service.getAll(this.resolveRootPath(t,e))}async add(t,e,s){return this.service.add(this.resolveRootPath(t,s),e)}async update(t,e,s,n){return await this.service.update(this.resolveRootPath(t,n),e,s),{ok:true}}async delete(t,e,s){return await this.service.delete(this.resolveRootPath(t,s),e),{ok:true}}async getCandidates(t,e){return this.service.getCandidates(this.resolveRootPath(t,e))}async approve(t,e,s){return await this.service.approveCandidate(this.resolveRootPath(t,s),e),{approved:true}}async reject(t,e,s){return await this.service.rejectCandidate(this.resolveRootPath(t,s),e),{rejected:true}}async search(t,e,s){return this.service.search(this.resolveRootPath(t,s),e.query,{limit:e.limit,categories:e.categories})}async extract(t,e,s){return this.service.extract(this.resolveRootPath(t,s),e.events)}async ollamaStatus(){return this.service.getOllamaStatus()}async updateLegacy(t,e,s,n,o){return await this.service.updateLegacy(this.resolveRootPath(t,o),e,s,n.value),{ok:true}}async recordEvent(t,e,s){return this.service.recordEvent(this.resolveRootPath(t,s),e)}async processEvents(t,e,s){return this.service.processSessionEvents(this.resolveRootPath(t,e))}};i([Get(),r(0,Query("rootPath")),r(1,Headers("x-devflow-project"))],f.prototype,"getAll",1),i([Post(),r(0,Query("rootPath")),r(1,Body()),r(2,Headers("x-devflow-project"))],f.prototype,"add",1),i([Put(":id"),r(0,Query("rootPath")),r(1,Param("id")),r(2,Body()),r(3,Headers("x-devflow-project"))],f.prototype,"update",1),i([Delete(":id"),r(0,Query("rootPath")),r(1,Param("id")),r(2,Headers("x-devflow-project"))],f.prototype,"delete",1),i([Get("candidates"),r(0,Query("rootPath")),r(1,Headers("x-devflow-project"))],f.prototype,"getCandidates",1),i([Post("candidates/:id/approve"),r(0,Query("rootPath")),r(1,Param("id")),r(2,Headers("x-devflow-project"))],f.prototype,"approve",1),i([Post("candidates/:id/reject"),r(0,Query("rootPath")),r(1,Param("id")),r(2,Headers("x-devflow-project"))],f.prototype,"reject",1),i([Post("search"),r(0,Query("rootPath")),r(1,Body()),r(2,Headers("x-devflow-project"))],f.prototype,"search",1),i([Post("extract"),r(0,Query("rootPath")),r(1,Body()),r(2,Headers("x-devflow-project"))],f.prototype,"extract",1),i([Get("ollama/status")],f.prototype,"ollamaStatus",1),i([Put(":layer/:key"),r(0,Query("rootPath")),r(1,Param("layer")),r(2,Param("key")),r(3,Body()),r(4,Headers("x-devflow-project"))],f.prototype,"updateLegacy",1),i([Post("events"),r(0,Query("rootPath")),r(1,Body()),r(2,Headers("x-devflow-project"))],f.prototype,"recordEvent",1),i([Post("process"),r(0,Query("rootPath")),r(1,Headers("x-devflow-project")),r(2,Body())],f.prototype,"processEvents",1),f=i([Controller("memory"),r(0,Inject(O)),r(1,Inject(p))],f);var et=class{};et=i([Module({imports:[forwardRef(()=>T),v],controllers:[f],providers:[O],exports:[O]})],et);var H=class{};H=i([Module({imports:[et,v],controllers:[m],providers:[P],exports:[P]})],H);var st=class{};st=i([Module({imports:[H],controllers:[N],providers:[j],exports:[j]})],st);var T=class{};T=i([Module({imports:[v,st],controllers:[w],providers:[F],exports:[F]})],T);var M=class{async getFullGraph(t){let{graph:e}=await createEngines(t);return e.export()}async getLayeredGraph(t){let{graph:e}=await createEngines(t);return e.getLayeredGraph()}async getNode(t,e){let{codegraph:s}=await createEngines(t),n=s.getNode(e);if(!n)throw new NotFoundException({error:{code:d.NODE_NOT_FOUND,message:`Node "${e}" not found`,details:{}}});return n}async expandNode(t,e,s,n){let{graph:o}=await createEngines(t),a=o.expand([e],{depth:s,direction:n});return {node:a.nodes.find(l=>l.id===e),subGraph:a}}};M=i([Injectable()],M);var U=class{constructor(t,e){this.service=t;this.projects=e;}resolveRootPath(t,e){let s=t??e??this.projects.getActiveProjectRoot();if(!s)throw new BadRequestException({error:{code:d.BAD_REQUEST,message:"rootPath is required \u2014 no active project connected",details:{}}});return s}async getFullGraph(t,e,s){return e==="layered"?this.service.getLayeredGraph(this.resolveRootPath(t,s)):this.service.getFullGraph(this.resolveRootPath(t,s))}async getNode(t,e,s){return this.service.getNode(this.resolveRootPath(t,s),e)}async expandNode(t,e,s,n,o){return this.service.expandNode(this.resolveRootPath(t,o),e,Number(s)||2,n||"both")}};i([Get(),r(0,Query("rootPath")),r(1,Query("view")),r(2,Headers("x-devflow-project"))],U.prototype,"getFullGraph",1),i([Get(":nodeId"),r(0,Query("rootPath")),r(1,Param("nodeId")),r(2,Headers("x-devflow-project"))],U.prototype,"getNode",1),i([Get(":nodeId/expand"),r(0,Query("rootPath")),r(1,Param("nodeId")),r(2,Query("depth")),r(3,Query("direction")),r(4,Headers("x-devflow-project"))],U.prototype,"expandNode",1),U=i([Controller("graph"),r(0,Inject(M)),r(1,Inject(p))],U);var nt=class{};nt=i([Module({imports:[T,v],controllers:[U],providers:[M],exports:[M]})],nt);var B=class{constructor(t){this.db=t;this.engine=new WorkflowEngine;this.events=new Map;this.engineRunIds=new Map;}async onModuleInit(){try{clearPluginCache();let t=await loadPlugins(),e=Array.from(t.values());for(let n of e)for(let o of n.workflow?.templates??[])this.engine.register(o);let s=await this.engine.list();console.log(`[WorkflowService] Loaded ${e.length} plugins with ${s.length} workflows`);}catch(t){console.error("[WorkflowService] Failed to load plugins:",t);}}async list(){return this.engine.list()}async run(t,e){if(!(await this.engine.list()).find(a=>a.name===t))throw new NotFoundException({error:{code:d.WORKFLOW_NOT_FOUND,message:`Workflow "${t}" not found`,details:{}}});let n=`run_${Date.now()}_${Math.random().toString(36).slice(2,7)}`,o=new Subject;if(this.events.set(n,o),this.db)try{this.db.insertSkillExecution({executionId:n,skillName:`workflow:${t}`,startedAt:Date.now(),status:"running"});}catch{}return this.engine.run(t,e).then(a=>{if(this.engineRunIds.set(n,a.runId),a.status!=="running"&&this.db)try{this.db.updateSkillExecution(n,{status:a.status==="success"?"completed":"failed",finishedAt:Date.now()});}catch{}this.engineRunIds.set(n,a.runId);let l=this.engine.getRun(a.runId);if(l){for(let u of l.steps)o.next({runId:n,stepId:u.stepId,status:u.status==="success"?"completed":u.status==="failed"?"failed":"started",output:u.output,error:u.error,timestamp:Date.now()});a.status!=="running"&&o.complete();}a.status==="running"&&this.engine.onEvent(a.runId,u=>{o.next({runId:n,stepId:u.stepId,status:u.type==="step-done"?"completed":u.type==="step-error"?"failed":"started",output:"output"in u?u.output:void 0,error:"error"in u?u.error:void 0,timestamp:Date.now()});});}).catch(a=>{if(this.db)try{this.db.updateSkillExecution(n,{status:"failed",finishedAt:Date.now()});}catch{}o.next({runId:n,stepId:"engine",status:"failed",error:a.message,timestamp:Date.now()}),o.complete();}),{runId:n}}async listRuns(t,e){return (await this.engine.listRuns()).map(o=>({runId:Array.from(this.engineRunIds.entries()).find(([,l])=>l===o.runId)?.[0]??o.runId,workflowName:o.type,status:o.status,steps:o.steps.map(l=>({stepId:l.stepId,status:l.status,output:l.output,error:l.error,startedAt:0})),startedAt:o.startedAt,finishedAt:o.finishedAt})).slice(e,e+t)}async getRun(t){let e=this.engineRunIds.get(t)??t,s=this.engine.getRun(e);if(!s)throw new NotFoundException({error:{code:d.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}});return {runId:t,workflowName:s.type,status:s.status,steps:s.steps.map(n=>({stepId:n.stepId,status:n.status,output:n.output,error:n.error})),startedAt:s.startedAt,finishedAt:s.finishedAt}}streamRun(t){let e=this.events.get(t);if(!e)throw new NotFoundException({error:{code:d.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}});return e}async approveRun(t){let e=this.engineRunIds.get(t)??t,s=this.engine.getRun(e);if(!s)throw new NotFoundException({error:{code:d.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}});let n=s.steps.find(o=>o.status==="awaiting_approval");n&&await this.engine.approve(e,n.stepId);}async rejectRun(t,e){let s=this.engineRunIds.get(t)??t,n=this.engine.getRun(s);if(!n)throw new NotFoundException({error:{code:d.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}});let o=n.steps.find(a=>a.status==="awaiting_approval");o&&await this.engine.reject(s,o.stepId,e??"Rejected");}async getNextStep(t){if(!t){(await this.engine.list())[0];return null}let e=this.engineRunIds.get(t)??t,s=this.engine.getRun(e);return s?(Array.isArray(s.steps)?s.steps:[]).find(o=>o.status==="pending")??null:null}};B=i([Injectable(),r(0,Optional()),r(0,Inject("DATABASE"))],B);var b=class{constructor(t){this.service=t;}async list(){return this.service.list()}async run(t,e){return this.service.run(t,e.input??{})}async listRuns(t,e){return this.service.listRuns(Number(t)||20,Number(e)||0)}async getRun(t){return this.service.getRun(t)}async stream(t,e){e.raw.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"});let n=this.service.streamRun(t).subscribe({next:o=>{e.raw.write(`event: step-${o.status}
|
|
1
|
+
import'reflect-metadata';import {Reflector,APP_GUARD,APP_INTERCEPTOR,NestFactory}from'@nestjs/core';import {FastifyAdapter}from'@nestjs/platform-fastify';import {Readable}from'stream';import {Injectable,Inject,Global,Module,Optional,Get,Query,Param,Post,Body,Delete,Controller,Headers,Put,forwardRef,Res,Catch,UnauthorizedException,NotFoundException,BadRequestException,SetMetadata,Logger,HttpException,HttpStatus}from'@nestjs/common';import {existsSync,readFileSync}from'fs';import {join}from'path';import {createEngines}from'@devflow-tools/context-engine';import {TelemetryEngine}from'@devflow-tools/telemetry';import {MemoryEngine,checkOllama,getOllamaInfoMessage}from'@devflow-tools/memory-engine';import {WorkflowEngine}from'@devflow-tools/workflow-engine';import {clearPluginCache,loadPlugins}from'@devflow-tools/sdk';import {Subject}from'rxjs';import {KnowledgeEngine}from'@devflow-tools/knowledge-engine';import {BenchmarkEngine}from'@devflow-tools/benchmark';import {DevFlowDatabase}from'@devflow-tools/database';import {homedir}from'os';import {map}from'rxjs/operators';var we=Object.defineProperty;var ke=Object.getOwnPropertyDescriptor;var i=(c,t,e,s)=>{for(var n=s>1?void 0:s?ke(t,e):t,o=c.length-1,a;o>=0;o--)(a=c[o])&&(n=(s?a(t,e,n):a(n))||n);return s&&n&&we(t,e,n),n},r=(c,t)=>(e,s)=>t(e,s,c);var xt="isPublic",Yt=()=>SetMetadata(xt,true);var Tt={MISSING_API_KEY:"AUTH_MISSING_API_KEY",INVALID_API_KEY:"AUTH_INVALID_API_KEY"};var xe=(process.env.DEVFLOW_API_KEYS??"dev-key-000000").split(",").map(c=>c.trim()).filter(Boolean),X=class{constructor(t){this.reflector=t;}canActivate(t){if(this.reflector.getAllAndOverride(xt,[t.getHandler(),t.getClass()]))return true;let n=t.switchToHttp().getRequest().headers["x-api-key"];if(!n)throw new UnauthorizedException({error:{code:Tt.MISSING_API_KEY,message:"X-API-Key header is required",details:{}}});if(!xe.includes(n))throw new UnauthorizedException({error:{code:Tt.INVALID_API_KEY,message:"Invalid API key",details:{}}});return true}};X=i([Injectable(),r(0,Inject(Reflector))],X);var st=class{};st=i([Global(),Module({providers:[X,{provide:APP_GUARD,useClass:X}]})],st);var g={WORKFLOW_NOT_FOUND:"WORKFLOW_NOT_FOUND",RUN_NOT_FOUND:"RUN_NOT_FOUND",PROJECT_NOT_FOUND:"PROJECT_NOT_FOUND",NODE_NOT_FOUND:"NODE_NOT_FOUND",PLUGIN_NOT_FOUND:"PLUGIN_NOT_FOUND",BAD_REQUEST:"BAD_REQUEST",VALIDATION_ERROR:"VALIDATION_ERROR",INTERNAL_ERROR:"INTERNAL_ERROR"};var f=class{constructor(t){this.database=t;this.projects=new Map;this.activeProjectRoot=process.env.DEVFLOW_PROJECT_ROOT??null;}onModuleInit(){if(!process.env.DEVFLOW_PROJECT_ROOT&&this.database){let t=this.database.getSetting("activeProjectRoot");t&&(this.activeProjectRoot=t);}}setActiveProject(t){this.activeProjectRoot=t,this.database&&this.database.setSetting("activeProjectRoot",t);}disconnectProject(){this.activeProjectRoot=null,this.database&&this.database.deleteSetting("activeProjectRoot");}getActiveProjectRoot(){return this.activeProjectRoot}async list(){return Array.from(this.projects.values())}async getById(t){let e=this.projects.get(t);if(!e)throw new NotFoundException({error:{code:g.PROJECT_NOT_FOUND,message:`Project "${t}" not found`,details:{}}});return e}async create(t){let e=`proj_${Date.now()}_${Math.random().toString(36).slice(2,7)}`,s={id:e,name:t.name,rootPath:t.rootPath,stack:t.stack,createdAt:Date.now()};return this.projects.set(e,s),this.activeProjectRoot||this.setActiveProject(t.rootPath),s}async delete(t){if(!this.projects.has(t))throw new NotFoundException({error:{code:g.PROJECT_NOT_FOUND,message:`Project "${t}" not found`,details:{}}});this.projects.delete(t);}async getOnboardingPack(t){let e=join(t,".devflow","onboarding-pack.json");if(!existsSync(e))throw new NotFoundException({error:{code:g.PROJECT_NOT_FOUND,message:"Onboarding pack not found. Run `devflow init` first.",details:{}}});return JSON.parse(readFileSync(e,"utf-8"))}async getOnboardingPackByRoot(t){let e=join(t,".devflow","onboarding-pack.json");try{return existsSync(e)?JSON.parse(readFileSync(e,"utf-8")):null}catch{return null}}};f=i([Injectable(),r(0,Optional()),r(0,Inject("DATABASE"))],f);var b=class{constructor(t){this.service=t;}async list(){return this.service.list()}async getOnboardingPackByRoot(t){if(!t)throw new BadRequestException({error:{code:g.BAD_REQUEST,message:"rootPath is required",details:{}}});return this.service.getOnboardingPackByRoot(t)}async getById(t){return this.service.getById(t)}async getOnboardingPack(t){let e=await this.service.getById(t);return this.service.getOnboardingPack(e.rootPath)}async create(t){return this.service.create(t)}async connect(t){return this.service.setActiveProject(t.rootPath),{rootPath:t.rootPath}}async switchProject(t){return this.service.setActiveProject(t.rootPath),{rootPath:t.rootPath}}async getActive(){return {rootPath:this.service.getActiveProjectRoot()}}async disconnect(){return this.service.disconnectProject(),{ok:true}}async delete(t){return this.service.delete(t)}};i([Get()],b.prototype,"list",1),i([Get("onboarding-pack"),r(0,Query("rootPath"))],b.prototype,"getOnboardingPackByRoot",1),i([Get(":id"),r(0,Param("id"))],b.prototype,"getById",1),i([Get(":id/onboarding-pack"),r(0,Param("id"))],b.prototype,"getOnboardingPack",1),i([Post(),r(0,Body())],b.prototype,"create",1),i([Post("connect"),r(0,Body())],b.prototype,"connect",1),i([Post("switch"),r(0,Body())],b.prototype,"switchProject",1),i([Get("active")],b.prototype,"getActive",1),i([Delete("active")],b.prototype,"disconnect",1),i([Delete(":id"),r(0,Param("id"))],b.prototype,"delete",1),b=i([Controller("projects"),r(0,Inject(f))],b);var w=class{};w=i([Module({controllers:[b],providers:[f],exports:[f]})],w);var kt=class{constructor(t){this.db=t;}checkAll(){return [...this.checkMemorySemanticDupes(),...this.checkMemoryPendingBacklog(),...this.checkKnowledgeEmptyResults(),...this.checkCodeGraphLowConfidence(),...this.checkOutputCaptureRate()]}checkMemorySemanticDupes(){try{return (this.db.get("SELECT COUNT(*) as c FROM tool_metrics WHERE engine = 'memory'")?.c??0)===0?[{name:"memory-semantic-dupes",severity:"ok",detail:"No memory tool calls \u2014 semantic dedup check skipped"}]:[{name:"memory-semantic-dupes",severity:"ok",detail:"Semantic dedup active \u2014 checked at write time by memory-engine"}]}catch{return [{name:"memory-semantic-dupes",severity:"ok",detail:"Check skipped \u2014 embedding data not available"}]}}checkMemoryPendingBacklog(){try{let t=this.db.get("SELECT COUNT(*) as c FROM tool_metrics WHERE engine = 'memory'")?.c??0;return t===0?[{name:"memory-pending-backlog",severity:"ok",detail:"No memory calls recorded yet"}]:[{name:"memory-pending-backlog",severity:"ok",detail:`${t} memory tool calls recorded`,value:t}]}catch{return [{name:"memory-pending-backlog",severity:"ok",detail:"Check skipped"}]}}checkKnowledgeEmptyResults(){try{let t=this.db.get("SELECT COUNT(*) as c FROM tool_metrics WHERE tool_name = 'get_knowledge'")?.c??0;if(t===0)return [{name:"knowledge-empty-results",severity:"ok",detail:"No get_knowledge calls yet"}];let e=this.db.get("SELECT COUNT(*) as c FROM tool_metrics WHERE tool_name = 'get_knowledge' AND result_count = 0")?.c??0,s=t>0?Math.round(e/t*100):0;return [{name:"knowledge-empty-results",severity:s>50?"warning":"ok",detail:`${s}% empty result rate for get_knowledge (${e}/${t})`,value:s,threshold:50}]}catch{return [{name:"knowledge-empty-results",severity:"ok",detail:"Check skipped"}]}}checkCodeGraphLowConfidence(){try{let t=this.db.get("SELECT COUNT(*) as c FROM accuracy_queries WHERE engine = 'codegraph'")?.c??0;if(t===0)return [{name:"codegraph-low-confidence",severity:"ok",detail:"No codegraph queries yet"}];let e=this.db.all("SELECT top_k_results FROM accuracy_queries WHERE engine = 'codegraph' ORDER BY created_at DESC LIMIT 100"),s=0;for(let o of e)try{let a=JSON.parse(o.top_k_results);if(a.length===0){s++;continue}a.reduce((p,Q)=>p+(Q.score??.5),0)/a.length<.3&&s++;}catch{}let n=t>0?Math.round(s/Math.min(t,100)*100):0;return [{name:"codegraph-low-confidence",severity:n>30?"warning":"ok",detail:`${n}% of recent codegraph queries have low confidence (avg score < 0.3)`,value:n,threshold:30}]}catch{return [{name:"codegraph-low-confidence",severity:"ok",detail:"Check skipped"}]}}checkOutputCaptureRate(){try{let t=this.db.get("SELECT COUNT(*) as c FROM tool_call_events WHERE is_mcp_tool = 1")?.c??0;if(t===0)return [{name:"output-capture-rate",severity:"ok",detail:"No MCP tool calls yet"}];let e=this.db.get("SELECT COUNT(*) as c FROM tool_call_events WHERE is_mcp_tool = 1 AND output IS NOT NULL")?.c??0,s=t>0?Math.round(e/t*100):0;return [{name:"output-capture-rate",severity:s<80?"error":s<95?"warning":"ok",detail:`${s}% of MCP tool calls have output captured (${e}/${t})`,value:s,threshold:95}]}catch{return [{name:"output-capture-rate",severity:"ok",detail:"Check skipped"}]}}};var S=class{constructor(t){this.engine=new TelemetryEngine;this.db=t??null;}async recordEvent(t){this.db&&this.db.insertEvent?.({runId:t.runId,kind:t.kind,timestamp:t.timestamp,duration:t.duration,toolName:t.data?.toolName,pluginName:t.data?.mcpToolName,metadata:t.data});}async createSession(t){this.db&&this.db.insertSession({id:t.id,projectRoot:t.projectRoot,label:t.label,startedAt:t.startedAt});}async getSession(t){if(!this.db)throw new NotFoundException({error:{code:g.RUN_NOT_FOUND,message:`Session "${t}" not found`,details:{}}});let e=this.db.getSession(t);if(!e)throw new NotFoundException({error:{code:g.RUN_NOT_FOUND,message:`Session "${t}" not found`,details:{}}});return e}async listSessions(t,e,s){return this.db?this.db.listSessions(t,e,s):[]}async getSessionEvents(t){return this.db?this.db.listToolCallEventsBySession?.(t)??[]:[]}async closeSession(t,e){this.db&&this.db.closeSession(t,e);}async createSkillExecution(t){this.db&&this.db.insertSkillExecution({executionId:t.executionId,sessionId:t.sessionId,skillName:t.skillName,startedAt:t.startedAt,status:"running"});}async listRuns(t,e,s){if(this.db)try{return this.db.listSessions(t,e).map(o=>({id:o.id,agent:"claude-code",mode:"hook",source:"hook",status:o.status,startedAt:o.startedAt,totalToolCalls:o.totalToolCalls,mcpToolCalls:o.mcpToolCalls,mcpComplianceRate:o.mcpToolCalls>0?Math.round(o.mcpToolCalls/o.totalToolCalls*100)/100:0}))}catch{}return []}async getRun(t){if(this.db)try{let s=this.db.getSession(t);if(s)return {meta:{runId:s.id,agent:"claude-code",mode:"hook",source:"hook"},status:s.status,startedAt:s.startedAt,finishedAt:s.finishedAt,totalToolCalls:s.totalToolCalls,mcpToolCalls:s.mcpToolCalls,steps:[]};let n=this.db.getSkillExecution(t);if(n)return {meta:{runId:n.executionId,agent:"claude-code",mode:"hook",source:"hook"},status:n.status,startedAt:n.startedAt,finishedAt:n.finishedAt,skillName:n.skillName,totalToolCalls:n.totalToolCalls,mcpToolCalls:n.mcpToolCalls,mcpComplianceRate:n.mcpComplianceRate,steps:[]}}catch{}let e=this.engine.runs.get(t);if(e)return e;throw new NotFoundException({error:{code:g.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}})}async getTimeline(t,e){if(!this.db)return [];try{return this.db.listSessions(500,0).filter(n=>!(t&&n.startedAt<Number(t)||e&&n.startedAt>Number(e))).map(n=>({runId:n.id,stepId:n.id,type:"session",duration:n.durationMs,timestamp:n.startedAt}))}catch{return []}}async getRunEvents(t){if(this.db)try{let s=this.db.listToolCallEventsBySession(t);if(s&&s.length>0)return s;let n=this.db.listToolCallEvents(t);if(n&&n.length>0)return n}catch{}return await this.engine.listEvents(t)??[]}async getRunStats(t){if(this.db)try{let e=this.db.listToolCallEventsBySession(t)??this.db.listToolCallEvents(t)??[];if(e.length>0)return {totalEvents:e.length,llmCalls:0,totalTokens:0,toolUses:e.length,fileReads:0,fileWrites:0,bashCommands:0,errors:e.filter(s=>s.error).length,totalDuration:0,mcpToolCalls:e.filter(s=>s.isMcpTool).length,directToolCalls:e.filter(s=>!s.isMcpTool).length,mcpComplianceRate:e.length>0?e.filter(s=>s.isMcpTool).length/e.length:0}}catch{}return this.engine.getRunStats(t)}async endRun(t,e){await this.engine.endRun(t,e);}async getStats(t=7){if(!this.db)return this.emptyStats();let e=Date.now(),s=e-t*24*60*60*1e3;try{let o=this.db.listSessions(1e3,0).filter(u=>u.startedAt>=s),a={},m=0;for(let u of o){let d=new Date(u.startedAt).toISOString().slice(0,10);a[d]||(a[d]={runs:0}),a[d].runs++,m+=u.totalToolCalls??0;}let p=o.map(u=>u.id),Q=this.db.listToolCallEventsBySessions?.(p)??{},W=0,ht=0,H={},z={};for(let[,u]of Object.entries(Q))for(let d of u){W+=d.tokensUsed??0,d.kind==="llm_call"&&ht++;let I=d.toolName?.split("_")?.[1];I&&(H[I]=(H[I]??0)+1);let R=d.mcpToolName?.split("_")?.[0];R&&(z[R]=(z[R]??0)+1);}return {period:{from:new Date(s).toISOString().slice(0,10),to:new Date(e).toISOString().slice(0,10)},summary:{totalRuns:o.length,completedRuns:o.filter(u=>u.status==="completed").length,failedRuns:o.filter(u=>u.status==="failed").length,totalTokens:W,totalLlmCalls:ht,totalToolUses:m,avgRunDuration:o.length>0?Math.round(o.reduce((u,d)=>u+(d.durationMs??0),0)/o.length):0},byDay:Object.entries(a).map(([u,d])=>({date:u,tokens:0,...d})).sort((u,d)=>u.date.localeCompare(d.date)),byWorkflow:Object.entries(H).map(([u,d])=>({workflow:u,count:d})).sort((u,d)=>d.count-u.count),byPlugin:Object.entries(z).map(([u,d])=>({plugin:u,count:d})).sort((u,d)=>d.count-u.count)}}catch{return this.emptyStats()}}emptyStats(){return {period:{from:"",to:""},summary:{totalRuns:0,completedRuns:0,failedRuns:0,totalTokens:0,totalLlmCalls:0,totalToolUses:0,avgRunDuration:0},byDay:[],byWorkflow:[],byPlugin:[]}}async getRoiSummary(t=7){if(!this.db)return this.emptyRoiSummary();let e=Date.now(),s=e-t*24*60*60*1e3;try{let o=this.db.listSessions(1e3,0).filter(u=>u.startedAt>=s),a=o.length,m=o.filter(u=>u.status==="completed").length,p=o.filter(u=>u.status==="failed").length,Q=a>0?Math.round(o.reduce((u,d)=>u+(d.durationMs??0),0)/a):0,W={};for(let u of o){let d=new Date(u.startedAt).toISOString().slice(0,10);W[d]||(W[d]={runs:0,failures:0}),W[d].runs++,u.status==="failed"&&W[d].failures++;}let ht=this.db.listToolCallEventsBySessions(o.map(u=>u.id)),H={tool_error:0,mcp_unavailable:0,unknown:0},z={};for(let u of o){let d=ht[u.id]??[];for(let I of d){if(I.error){let R=I.error.toLowerCase();R.includes("mcp")||R.includes("unavailable")||R.includes("not found")?H.mcp_unavailable++:R.includes("tool")||R.includes("command")||R.includes("error")?H.tool_error++:H.unknown++;}if(I.mcpToolName){let R=I.mcpToolName.split("_")[0];R&&(z[R]=(z[R]??0)+1);}}}return {period:{from:new Date(s).toISOString().slice(0,10),to:new Date(e).toISOString().slice(0,10)},overview:{totalRuns:a,completedRuns:m,failedRuns:p,avgDuration:Q,firstPassSuccessRate:a>0?Math.round(m/a*1e4)/100:0},efficiency:{avgTimePerTask:Q},failures:{total:p,breakdown:H},workflows:[],plugins:Object.entries(z).map(([u,d])=>{let I=o.filter(It=>(ht[It.id]??[]).some(be=>be.mcpToolName?.startsWith(u+"_"))),R=I.filter(It=>It.status==="completed").length,Re=I.length>0?Math.round(R/I.length*1e4)/100:0;return {name:u,runs:d,successRate:Re}}),byDay:Object.entries(W).map(([u,d])=>({date:u,...d,tokens:0})).sort((u,d)=>u.date.localeCompare(d.date))}}catch{return this.emptyRoiSummary()}}emptyRoiSummary(){return {period:{from:"",to:""},overview:{totalRuns:0,completedRuns:0,failedRuns:0,avgDuration:0,firstPassSuccessRate:0},efficiency:{avgTimePerTask:0},failures:{total:0,breakdown:{tool_error:0,mcp_unavailable:0,unknown:0}},workflows:[],plugins:[],byDay:[]}}async recordExecutionStart(t){this.db&&this.db.insertSkillExecution({executionId:t.executionId,sessionId:t.sessionId,skillName:t.skillName,startedAt:t.startedAt,status:"running"});}async recordToolCall(t){if(this.db)try{this.db.insertToolCallEvent({eventId:t.eventId,executionId:t.executionId,sessionId:t.sessionId,timestamp:t.timestamp,toolName:t.toolName,toolType:t.toolType,isMcpTool:t.isMcpTool,mcpToolName:t.mcpToolName,mcpEnforced:t.mcpEnforced,mcpFallback:t.mcpFallback,kind:t.kind??"tool_use",input:t.input,duration:t.duration,parentToolCallId:t.parentToolCallId,subagentId:t.subagentId,error:t.error,blocked:t.blocked,blockReason:t.blockReason});}catch{}}async updateToolCallOutput(t,e,s,n){if(this.db)try{this.db.updateToolCallEvent(t,{output:JSON.stringify(e),duration:n});}catch{}}async recordExecutionComplete(t){this.db&&this.db.updateSkillExecution(t.executionId,{status:t.status,finishedAt:t.finishedAt,totalDuration:t.summary.totalDuration,mcpComplianceRate:t.summary.mcpComplianceRate,totalToolCalls:t.summary.totalToolCalls,mcpToolCalls:t.summary.mcpToolCalls,directToolCalls:t.summary.directToolCalls,subagentCount:t.summary.subagentCount});}async getExecutions(t,e){return this.db?this.db.listSkillExecutions(t,e):[]}async getExecutionEvents(t){return this.db?this.db.listToolCallEvents(t):[]}async getMcpCompliance(){return this.db?this.db.getMcpCompliance():{overall:0,bySkill:{},missedTools:[]}}async classifyFailure(t){let e=await this.getRun(t).catch(()=>null);if(!e||e.status!=="failed")return {};let s=e.steps?.find(o=>o.status==="failed");if(!s)return {};let n=s.error?.toLowerCase()??"";return n.includes("context")||n.includes("insufficient")?{failureCategory:"context_insufficient",failureReason:"Context provided was insufficient for the task",suggestedActions:[{action:"Supplement task context",priority:"high"},{action:"View graph roots",priority:"medium"},{action:"Add related memory",priority:"medium"}]}:n.includes("knowledge")||n.includes("docs")?{failureCategory:"knowledge_missing",failureReason:"Required knowledge was not available",suggestedActions:[{action:"Sync knowledge source",priority:"high"},{action:"Add docs source",priority:"medium"}]}:n.includes("workflow")||n.includes("step")?{failureCategory:"workflow_design_issue",failureReason:"Workflow design issue detected",suggestedActions:[{action:"Adjust specific step",priority:"high"},{action:"Split workflow",priority:"medium"}]}:n.includes("tool")||n.includes("connection")?{failureCategory:"tool_error",failureReason:"Tool execution error",suggestedActions:[{action:"Check tool connectivity",priority:"high"},{action:"Retry or fallback",priority:"medium"}]}:{failureCategory:"agent_override",failureReason:"Agent override detected",suggestedActions:[{action:"Enable/strengthen enforcer",priority:"high"}]}}async cleanup(t){if(!this.db)return 0;try{this.db.cleanupStaleRecords?.();}catch{}let e=this.engine.runs,s=Date.now()-t*24*60*60*1e3,n=0;for(let[o,a]of e)a.startedAt&&a.startedAt<s&&(e.delete(o),n++);return n}async cleanupStaleRecords(){if(this.db)try{this.db.cleanupStaleRecords?.();}catch{}}async recordToolMetric(t){this.db&&this.db.insertToolMetric({...t,createdAt:Date.now()});}async getToolMetrics(t,e,s=100,n=0){return this.db?this.db.getToolMetrics(t,e,s,n):[]}async getToolMetricsSummary(t=7){return this.db?this.db.getToolMetricsSummary(t):[]}async recordAccuracyQuery(t){this.db&&this.db.insertAccuracyQuery({...t,createdAt:Date.now()});}async getAccuracyQueries(t){return this.db?this.db.getAccuracyQueries(t):[]}async updateAccuracyFeedback(t,e){this.db&&this.db.updateAccuracyFeedback(t,e);}async getAccuracyStats(t,e){return this.db?this.db.getAccuracyStats(t,e):{totalQueries:0,annotatedQueries:0,hitRate:null}}async runAutoCheck(){return this.db?new kt(this.db).checkAll():[]}async getFeedbackStats(t,e){return {total:0,hits:0,partials:0,misses:0,hitRate:0,partialRate:0,missRate:0}}async getOpsRoiSummary(){return {period:"all-time",totalRuns:0,successfulRuns:0,successRate:0,avgDuration:0,trend:"stable"}}async getExperimentalRoiSummary(){return {totalScenarios:0,avgTimeSavedRate:null,avgTokenReductionRate:null,avgFirstPassLift:null,avgReworkReductionRate:null,conclusion:"No experimental data available yet"}}async getPluginEffectiveness(t,e){if(!this.db)return {name:t,totalRuns:0,successRate:0,lastUsedAt:null};let s=this.db.listSessions(1e3,0),n=0;for(let o of s){let a=this.db.listToolCallEventsBySession(o.id);for(let m of a)m.mcpToolName?.startsWith(t+"_")&&n++;}return {name:t,totalRuns:n,successRate:0,lastUsedAt:null}}async getPluginUsageStats(t){let e=await this.getPluginEffectiveness(t);return {activeProjects:0,totalRuns:e.totalRuns,successfulRuns:0,lastUsedAt:e.lastUsedAt??void 0}}};S=i([Injectable(),r(0,Optional()),r(0,Inject("DATABASE"))],S);var O=class{constructor(t,e){this.telemetryService=t;this.database=e;this.projectStats=new Map;this.benchmarkResults=[];}async recordTelemetryEvent(t){let e=`evt_${Date.now()}_${Math.random().toString(36).slice(2,7)}`,s=t.toolName?"tool_use":"step_end",n={id:e,runId:t.metadata?.runId??`event_${Date.now()}_${Math.random().toString(36).slice(2,7)}`,stepId:e,kind:s,timestamp:Date.now(),duration:t.durationMs,data:{toolName:t.toolName,toolInput:t.args,errorMessage:t.error},metadata:{source:"claude-code"}};return await this.telemetryService.recordEvent(n),{eventId:e}}async getProjectStats(t){return this.database?this.database.getProjectStats(t):this.projectStats.get(t)??null}async updateProjectStats(t,e){if(this.database){let a={...await this.getProjectStats(t)??{projectRoot:t,totalRuns:0,successfulRuns:0,totalTokens:0,lastActiveAt:Date.now(),topTools:[]},...e,lastActiveAt:Date.now()};return await this.database.upsertProjectStats(a),a}let n={...this.projectStats.get(t)??{projectRoot:t,totalRuns:0,successfulRuns:0,totalTokens:0,lastActiveAt:Date.now(),topTools:[]},...e,lastActiveAt:Date.now()};return this.projectStats.set(t,n),n}recordBenchmarkResult(t){this.benchmarkResults.push(t);}getBenchmarkResults(t){return t?this.benchmarkResults.filter(e=>this.projectStats.get(e.scenarioId)?.projectRoot===t):this.benchmarkResults}async getPluginEffectiveness(t){return []}};O=i([Injectable(),r(0,Inject(S)),r(1,Optional()),r(1,Inject("DATABASE"))],O);var F=class{constructor(t){this.dataService=t;this.feedbackEntries=[];}async indexProject(t){let{indexer:e,codegraph:s}=await createEngines(t);await e.reconcile();let n=s.getStats();return {totalFiles:n.fileCount,totalSymbols:n.nodeCount,lastIndexTime:n.lastUpdated,indexing:s.isIndexing()}}async getStatus(t){try{let{codegraph:e}=await createEngines(t),s=e.getStats();return {totalFiles:s.fileCount,totalSymbols:s.nodeCount,lastIndexTime:s.lastUpdated,indexing:e.isIndexing()}}catch{return {totalFiles:0,totalSymbols:0,lastIndexTime:0,indexing:false}}}async buildContext(t,e,s,n){let{context:o}=await createEngines(t);return o.build({query:e,mode:s,maxTokens:n??8e3,includeGraph:s==="deep"})}async buildTaskContext(t,e,s,n){let{context:o}=await createEngines(t);return o.buildTaskContext(e,{mode:s,maxTokens:n??8e3})}async findSymbol(t,e){let{indexer:s}=await createEngines(t);return s.findSymbol(e)}async recordFeedback(t,e,s,n){let o={query:e,feedback:s,timestamp:Date.now(),projectRoot:t};return this.feedbackEntries.push(o),this.dataService&&await this.dataService.recordTelemetryEvent({toolName:"context_feedback",args:{query:e,feedback:s,taskType:n?.taskType,contextMode:n?.contextMode,projectRoot:t},durationMs:0,success:true,metadata:{projectRoot:t,query:e,taskType:n?.taskType}}),o}async getFeedbackSummaries(){let t=this.feedbackEntries.length,e=this.feedbackEntries.filter(o=>o.feedback==="hit").length,s=this.feedbackEntries.filter(o=>o.feedback==="partial").length,n=this.feedbackEntries.filter(o=>o.feedback==="miss").length;return {total:t,hits:e,partials:s,misses:n,hitRate:t>0?e/t:0}}};F=i([Injectable(),r(0,Optional()),r(0,Inject(O))],F);var E=class{constructor(t,e){this.service=t;this.projects=e;}resolveRootPath(t,e){let s=t??e??this.projects.getActiveProjectRoot();if(!s)throw new BadRequestException("rootPath is required \u2014 no active project connected");return s}async status(t,e){let s=t??e??this.projects.getActiveProjectRoot();return s?this.service.getStatus(s):null}async index(t,e){return this.service.indexProject(this.resolveRootPath(t.rootPath,e))}async build(t,e){return this.service.buildContext(this.resolveRootPath(t.rootPath,e),t.query,t.mode??"fast",t.maxTokens)}async buildTask(t,e){return this.service.buildTaskContext(this.resolveRootPath(t.rootPath,e),t.query,t.mode??"fast",t.maxTokens)}async feedback(t,e){return this.service.recordFeedback(this.resolveRootPath(t.rootPath,e),t.query,t.feedback,{taskType:t.taskType,contextMode:t.contextMode,runId:t.runId,tokenCount:t.tokenCount})}async feedbackSummary(){return this.service.getFeedbackSummaries()}async findSymbol(t,e,s){return this.service.findSymbol(this.resolveRootPath(e,s),t)}};i([Get("status"),r(0,Query("rootPath")),r(1,Headers("x-devflow-project"))],E.prototype,"status",1),i([Post("index"),r(0,Body()),r(1,Headers("x-devflow-project"))],E.prototype,"index",1),i([Post("build"),r(0,Body()),r(1,Headers("x-devflow-project"))],E.prototype,"build",1),i([Post("build-task"),r(0,Body()),r(1,Headers("x-devflow-project"))],E.prototype,"buildTask",1),i([Post("feedback"),r(0,Body()),r(1,Headers("x-devflow-project"))],E.prototype,"feedback",1),i([Get("feedback-summary")],E.prototype,"feedbackSummary",1),i([Get("symbol/:name"),r(0,Param("name")),r(1,Query("rootPath")),r(2,Headers("x-devflow-project"))],E.prototype,"findSymbol",1),E=i([Controller("context"),r(0,Inject(F)),r(1,Inject(f))],E);var _=class{constructor(t){this.dataService=t;}async recordTelemetryEvent(t){return {success:true,...await this.dataService.recordTelemetryEvent(t)}}async getProjectStats(t){return this.dataService.getProjectStats(t)}async updateProjectStats(t){return this.dataService.updateProjectStats(t.projectRoot,t.stats)}recordBenchmarkResult(t){return this.dataService.recordBenchmarkResult(t),{success:true}}getBenchmarkResults(t){return this.dataService.getBenchmarkResults(t)}};i([Post("telemetry/event"),r(0,Body())],_.prototype,"recordTelemetryEvent",1),i([Get("project/stats"),r(0,Query("rootPath"))],_.prototype,"getProjectStats",1),i([Post("project/stats"),r(0,Body())],_.prototype,"updateProjectStats",1),i([Post("benchmark/result"),r(0,Body())],_.prototype,"recordBenchmarkResult",1),i([Get("benchmark/results"),r(0,Query("projectRoot"))],_.prototype,"getBenchmarkResults",1),_=i([Controller("data"),r(0,Inject(O))],_);var D=class{constructor(){this.engines=new Map;this.ENGINE_TTL=3600*1e3;}getEngine(t){let e=Date.now();for(let[o,a]of this.engines)if(e-a.lastAccess>this.ENGINE_TTL){try{a.engine.close?.();}catch{}this.engines.delete(o);}let s=t.replace(/\/+$/,""),n=this.engines.get(s);return n?n.lastAccess=e:(n={engine:new MemoryEngine(s),lastAccess:e},this.engines.set(s,n)),n.engine}async getAll(t){let e=this.getEngine(t),[s,n]=await Promise.all([e.listMemories(),checkOllama()]);return {memories:s.map(o=>({id:o.id,category:o.category,content:o.content,originalText:o.originalText,source:o.source,status:o.status,confidence:o.confidence,scope:o.scope,createdAt:o.createdAt,approvedAt:o.approvedAt})),ollama:{installed:n.installed,running:n.running,modelAvailable:n.modelAvailable,modelName:n.modelName,infoMessage:getOllamaInfoMessage(n)}}}async add(t,e){return this.getEngine(t).addMemory({category:e.category,content:e.content,source:"manual",confidence:1,scope:e.scope??""})}async update(t,e,s){await this.getEngine(t).updateMemory(e,s);}async delete(t,e){await this.getEngine(t).deleteMemory(e);}async getCandidates(t){return this.getEngine(t).getPendingMemories()}async approveCandidate(t,e){await this.getEngine(t).approveMemory(e);}async rejectCandidate(t,e){await this.getEngine(t).rejectMemory(e);}async search(t,e,s){return (await this.getEngine(t).search(e,s)).map(o=>o.entry)}async extract(t,e){return this.getEngine(t).extractMemories(e)}async getOllamaStatus(){let t=await checkOllama();return {...t,infoMessage:getOllamaInfoMessage(t)}}async updateLegacy(t,e,s,n){e!=="user"&&await this.getEngine(t).addMemory({category:"semantic",content:`${s}: ${JSON.stringify(n)}`,source:"manual",confidence:1,scope:s});}async recordEvent(t,e){let s=this.getEngine(t);return await s.recordEvent({id:e.id,sessionId:e.sessionId,tool:e.tool,command:e.command,exitCode:e.exitCode,stderr:e.stderr,durationMs:e.durationMs,createdAt:Date.now()}),{acknowledged:true,extracted:(await s.extractFromEventsRealtime([{tool:e.tool,command:e.command,exitCode:e.exitCode,stderr:e.stderr}])).length}}async processSessionEvents(t){return this.getEngine(t).processSessionEvents()}};D=i([Injectable()],D);var l=class{constructor(t,e,s){this.service=t;this.memoryService=e;this.projectsService=s;}async listRuns(t,e,s){return this.service.listRuns(Number(t)||20,Number(e)||0,s)}async getRun(t){let e=await this.service.getRun(t),s=await this.service.classifyFailure(t);return {...e,...s}}async getTimeline(t,e){return this.service.getTimeline(t,e)}async getRunEvents(t){return this.service.getRunEvents(t)}async recordRunEvent(t,e){let s={...e,runId:t,id:e.id||`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,stepId:e.stepId||e.metadata?.stepId||"unknown"};return await this.service.recordEvent(s),{ok:true,eventId:s.id}}async getRunStats(t){return this.service.getRunStats(t)}async completeRun(t){await this.service.endRun(t,{status:"success"});let e=await this.service.getRunEvents(t),s=this.projectsService.getActiveProjectRoot(),n=await this.memoryService.extract(s??"",e);return {extracted:Array.isArray(n)?n.length:0}}async getStats(t){return this.service.getStats(Number(t)||7)}async getRoiSummary(t){return this.service.getRoiSummary(Number(t)||7)}async cleanup(t){return {removedRuns:await this.service.cleanup(t.olderThanDays??30)}}async cleanupStale(){return await this.service.cleanupStaleRecords(),{ok:true}}async createSession(t){return await this.service.createSession(t),{id:t.id}}async listSessions(t,e,s){return this.service.listSessions(Number(t)||20,Number(e)||0,s)}async getSession(t){return this.service.getSession(t)}async getSessionEvents(t){return this.service.getSessionEvents(t)}async closeSession(t,e){return await this.service.closeSession(t,e.finishedAt),{}}async startSessionSkillExecution(t,e){return await this.service.createSkillExecution({...e,sessionId:t}),{executionId:e.executionId}}async startSkillExecution(t){return await this.service.recordExecutionStart(t),{executionId:t.executionId}}async recordToolCall(t){return await this.service.recordToolCall(t),{eventId:t.eventId}}async updateToolCallOutput(t){return await this.service.updateToolCallOutput(t.eventId,t.output,t.completedAt,t.duration),{}}async completeSkillExecution(t){return await this.service.recordExecutionComplete(t),{}}async getExecutions(t,e){return this.service.getExecutions(Number(t)||20,e)}async getExecutionEvents(t){return this.service.getExecutionEvents(t)}async getMcpCompliance(){return await this.service.getMcpCompliance()}async recordToolMetric(t){return await this.service.recordToolMetric(t),{ok:true}}async getToolMetrics(t,e,s,n){return this.service.getToolMetrics(t,e,Number(s)||100,Number(n)||0)}async getToolMetricsSummary(t){return this.service.getToolMetricsSummary(Number(t)||7)}async recordAccuracyQuery(t){return await this.service.recordAccuracyQuery({...t,topKResults:JSON.stringify(t.topKResults),selectedIds:t.selectedIds?JSON.stringify(t.selectedIds):void 0}),{id:t.id}}async getAccuracyQueries(t,e,s,n){return this.service.getAccuracyQueries({engine:t,status:e,limit:Number(s)||50,offset:Number(n)||0})}async updateAccuracyFeedback(t){return await this.service.updateAccuracyFeedback(t.queryId,{relevance:t.relevance,note:t.note}),{ok:true}}async getAccuracyStats(t,e){return this.service.getAccuracyStats(t,e?Number(e):void 0)}async runAutoCheck(){return this.service.runAutoCheck()}};i([Get("runs"),r(0,Query("limit")),r(1,Query("offset")),r(2,Query("source"))],l.prototype,"listRuns",1),i([Get("runs/:id"),r(0,Param("id"))],l.prototype,"getRun",1),i([Get("timeline"),r(0,Query("from")),r(1,Query("to"))],l.prototype,"getTimeline",1),i([Get("runs/:runId/events"),r(0,Param("runId"))],l.prototype,"getRunEvents",1),i([Post("runs/:runId/events"),r(0,Param("runId")),r(1,Body())],l.prototype,"recordRunEvent",1),i([Get("runs/:runId/stats"),r(0,Param("runId"))],l.prototype,"getRunStats",1),i([Post("runs/:id/complete"),r(0,Param("id"))],l.prototype,"completeRun",1),i([Get("stats"),r(0,Query("days"))],l.prototype,"getStats",1),i([Get("roi-summary"),r(0,Query("days"))],l.prototype,"getRoiSummary",1),i([Post("cleanup"),r(0,Body())],l.prototype,"cleanup",1),i([Post("cleanup-stale")],l.prototype,"cleanupStale",1),i([Post("sessions"),r(0,Body())],l.prototype,"createSession",1),i([Get("sessions"),r(0,Query("limit")),r(1,Query("offset")),r(2,Query("projectRoot"))],l.prototype,"listSessions",1),i([Get("sessions/:id"),r(0,Param("id"))],l.prototype,"getSession",1),i([Get("sessions/:id/events"),r(0,Param("id"))],l.prototype,"getSessionEvents",1),i([Post("sessions/:id/close"),r(0,Param("id")),r(1,Body())],l.prototype,"closeSession",1),i([Post("sessions/:id/skill-executions"),r(0,Param("id")),r(1,Body())],l.prototype,"startSessionSkillExecution",1),i([Post("skill-execution/start"),r(0,Body())],l.prototype,"startSkillExecution",1),i([Post("tool-call"),r(0,Body())],l.prototype,"recordToolCall",1),i([Post("tool-call/output"),r(0,Body())],l.prototype,"updateToolCallOutput",1),i([Post("skill-execution/complete"),r(0,Body())],l.prototype,"completeSkillExecution",1),i([Get("executions"),r(0,Query("limit")),r(1,Query("skillName"))],l.prototype,"getExecutions",1),i([Get("executions/:id/events"),r(0,Param("id"))],l.prototype,"getExecutionEvents",1),i([Get("mcp-compliance")],l.prototype,"getMcpCompliance",1),i([Post("tool-metrics"),r(0,Body())],l.prototype,"recordToolMetric",1),i([Get("tool-metrics"),r(0,Query("sessionId")),r(1,Query("toolName")),r(2,Query("limit")),r(3,Query("offset"))],l.prototype,"getToolMetrics",1),i([Get("tool-metrics/summary"),r(0,Query("days"))],l.prototype,"getToolMetricsSummary",1),i([Post("accuracy/query"),r(0,Body())],l.prototype,"recordAccuracyQuery",1),i([Get("accuracy/queries"),r(0,Query("engine")),r(1,Query("status")),r(2,Query("limit")),r(3,Query("offset"))],l.prototype,"getAccuracyQueries",1),i([Post("accuracy/feedback"),r(0,Body())],l.prototype,"updateAccuracyFeedback",1),i([Get("accuracy/stats"),r(0,Query("engine")),r(1,Query("since"))],l.prototype,"getAccuracyStats",1),i([Get("auto-check")],l.prototype,"runAutoCheck",1),l=i([Controller("telemetry"),r(0,Inject(S)),r(1,Inject(D)),r(2,Inject(f))],l);var y=class{constructor(t,e){this.service=t;this.projects=e;}resolveRootPath(t,e){let s=t??e??this.projects.getActiveProjectRoot();if(!s)throw new BadRequestException({error:{code:g.BAD_REQUEST,message:"rootPath is required \u2014 no active project connected",details:{}}});return s}async getAll(t,e){return this.service.getAll(this.resolveRootPath(t,e))}async add(t,e,s){return this.service.add(this.resolveRootPath(t,s),e)}async update(t,e,s,n){return await this.service.update(this.resolveRootPath(t,n),e,s),{ok:true}}async delete(t,e,s){return await this.service.delete(this.resolveRootPath(t,s),e),{ok:true}}async getCandidates(t,e){return this.service.getCandidates(this.resolveRootPath(t,e))}async approve(t,e,s){return await this.service.approveCandidate(this.resolveRootPath(t,s),e),{approved:true}}async reject(t,e,s){return await this.service.rejectCandidate(this.resolveRootPath(t,s),e),{rejected:true}}async search(t,e,s){return this.service.search(this.resolveRootPath(t,s),e.query,{limit:e.limit,categories:e.categories})}async extract(t,e,s){return this.service.extract(this.resolveRootPath(t,s),e.events)}async ollamaStatus(){return this.service.getOllamaStatus()}async updateLegacy(t,e,s,n,o){return await this.service.updateLegacy(this.resolveRootPath(t,o),e,s,n.value),{ok:true}}async recordEvent(t,e,s){return this.service.recordEvent(this.resolveRootPath(t,s),e)}async processEvents(t,e,s){return this.service.processSessionEvents(this.resolveRootPath(t,e))}};i([Get(),r(0,Query("rootPath")),r(1,Headers("x-devflow-project"))],y.prototype,"getAll",1),i([Post(),r(0,Query("rootPath")),r(1,Body()),r(2,Headers("x-devflow-project"))],y.prototype,"add",1),i([Put(":id"),r(0,Query("rootPath")),r(1,Param("id")),r(2,Body()),r(3,Headers("x-devflow-project"))],y.prototype,"update",1),i([Delete(":id"),r(0,Query("rootPath")),r(1,Param("id")),r(2,Headers("x-devflow-project"))],y.prototype,"delete",1),i([Get("candidates"),r(0,Query("rootPath")),r(1,Headers("x-devflow-project"))],y.prototype,"getCandidates",1),i([Post("candidates/:id/approve"),r(0,Query("rootPath")),r(1,Param("id")),r(2,Headers("x-devflow-project"))],y.prototype,"approve",1),i([Post("candidates/:id/reject"),r(0,Query("rootPath")),r(1,Param("id")),r(2,Headers("x-devflow-project"))],y.prototype,"reject",1),i([Post("search"),r(0,Query("rootPath")),r(1,Body()),r(2,Headers("x-devflow-project"))],y.prototype,"search",1),i([Post("extract"),r(0,Query("rootPath")),r(1,Body()),r(2,Headers("x-devflow-project"))],y.prototype,"extract",1),i([Get("ollama/status")],y.prototype,"ollamaStatus",1),i([Put(":layer/:key"),r(0,Query("rootPath")),r(1,Param("layer")),r(2,Param("key")),r(3,Body()),r(4,Headers("x-devflow-project"))],y.prototype,"updateLegacy",1),i([Post("events"),r(0,Query("rootPath")),r(1,Body()),r(2,Headers("x-devflow-project"))],y.prototype,"recordEvent",1),i([Post("process"),r(0,Query("rootPath")),r(1,Headers("x-devflow-project")),r(2,Body())],y.prototype,"processEvents",1),y=i([Controller("memory"),r(0,Inject(D)),r(1,Inject(f))],y);var it=class{};it=i([Module({imports:[forwardRef(()=>N),w],controllers:[y],providers:[D],exports:[D]})],it);var J=class{};J=i([Module({imports:[it,w],controllers:[l],providers:[S],exports:[S]})],J);var ot=class{};ot=i([Module({imports:[J],controllers:[_],providers:[O],exports:[O]})],ot);var N=class{};N=i([Module({imports:[w,ot],controllers:[E],providers:[F],exports:[F]})],N);var U=class{async getFullGraph(t){let{graph:e}=await createEngines(t);return e.export()}async getSubGraph(t,e,s){let{graph:n}=await createEngines(t);return n.getSubGraph(e,s)}async getLayeredGraph(t){let{graph:e}=await createEngines(t);return e.getLayeredGraph()}async getNode(t,e){let{codegraph:s}=await createEngines(t),n=s.getNode(e);if(!n)throw new NotFoundException({error:{code:g.NODE_NOT_FOUND,message:`Node "${e}" not found`,details:{}}});return n}async expandNode(t,e,s,n){let{graph:o}=await createEngines(t),a=o.expand([e],{depth:s,direction:n});return {node:a.nodes.find(m=>m.id===e),subGraph:a}}};U=i([Injectable()],U);var B=class{constructor(t,e){this.service=t;this.projects=e;}resolveRootPath(t,e){let s=t??e??this.projects.getActiveProjectRoot();if(!s)throw new BadRequestException({error:{code:g.BAD_REQUEST,message:"rootPath is required \u2014 no active project connected",details:{}}});return s}async getFullGraph(t,e,s,n,o){let a=this.resolveRootPath(t,o);return s?this.service.getSubGraph(a,s,Number(n)||2):e==="layered"?this.service.getLayeredGraph(a):this.service.getFullGraph(a)}async getNode(t,e,s){return this.service.getNode(this.resolveRootPath(t,s),e)}async expandNode(t,e,s,n,o){return this.service.expandNode(this.resolveRootPath(t,o),e,Number(s)||2,n||"both")}};i([Get(),r(0,Query("rootPath")),r(1,Query("view")),r(2,Query("target")),r(3,Query("depth")),r(4,Headers("x-devflow-project"))],B.prototype,"getFullGraph",1),i([Get(":nodeId"),r(0,Query("rootPath")),r(1,Param("nodeId")),r(2,Headers("x-devflow-project"))],B.prototype,"getNode",1),i([Get(":nodeId/expand"),r(0,Query("rootPath")),r(1,Param("nodeId")),r(2,Query("depth")),r(3,Query("direction")),r(4,Headers("x-devflow-project"))],B.prototype,"expandNode",1),B=i([Controller("graph"),r(0,Inject(U)),r(1,Inject(f))],B);var at=class{};at=i([Module({imports:[N,w],controllers:[B],providers:[U],exports:[U]})],at);var L=class{constructor(t){this.db=t;this.engine=new WorkflowEngine;this.events=new Map;this.engineRunIds=new Map;}async onModuleInit(){try{clearPluginCache();let t=await loadPlugins(),e=Array.from(t.values());for(let n of e)for(let o of n.workflow?.templates??[])this.engine.register(o);let s=await this.engine.list();console.log(`[WorkflowService] Loaded ${e.length} plugins with ${s.length} workflows`);}catch(t){console.error("[WorkflowService] Failed to load plugins:",t);}}async list(){return this.engine.list()}async run(t,e){if(!(await this.engine.list()).find(a=>a.name===t))throw new NotFoundException({error:{code:g.WORKFLOW_NOT_FOUND,message:`Workflow "${t}" not found`,details:{}}});let n=`run_${Date.now()}_${Math.random().toString(36).slice(2,7)}`,o=new Subject;if(this.events.set(n,o),this.db)try{this.db.insertSkillExecution({executionId:n,skillName:`workflow:${t}`,startedAt:Date.now(),status:"running"});}catch{}return this.engine.run(t,e).then(a=>{if(this.engineRunIds.set(n,a.runId),a.status!=="running"&&this.db)try{this.db.updateSkillExecution(n,{status:a.status==="success"?"completed":"failed",finishedAt:Date.now()});}catch{}this.engineRunIds.set(n,a.runId);let m=this.engine.getRun(a.runId);if(m){for(let p of m.steps)o.next({runId:n,stepId:p.stepId,status:p.status==="success"?"completed":p.status==="failed"?"failed":"started",output:p.output,error:p.error,timestamp:Date.now()});a.status!=="running"&&o.complete();}a.status==="running"&&this.engine.onEvent(a.runId,p=>{o.next({runId:n,stepId:p.stepId,status:p.type==="step-done"?"completed":p.type==="step-error"?"failed":"started",output:"output"in p?p.output:void 0,error:"error"in p?p.error:void 0,timestamp:Date.now()});});}).catch(a=>{if(this.db)try{this.db.updateSkillExecution(n,{status:"failed",finishedAt:Date.now()});}catch{}o.next({runId:n,stepId:"engine",status:"failed",error:a.message,timestamp:Date.now()}),o.complete();}),{runId:n}}async listRuns(t,e){return (await this.engine.listRuns()).map(o=>({runId:Array.from(this.engineRunIds.entries()).find(([,m])=>m===o.runId)?.[0]??o.runId,workflowName:o.type,status:o.status,steps:o.steps.map(m=>({stepId:m.stepId,status:m.status,output:m.output,error:m.error,startedAt:0})),startedAt:o.startedAt,finishedAt:o.finishedAt})).slice(e,e+t)}async getRun(t){let e=this.engineRunIds.get(t)??t,s=this.engine.getRun(e);if(!s)throw new NotFoundException({error:{code:g.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}});return {runId:t,workflowName:s.type,status:s.status,steps:s.steps.map(n=>({stepId:n.stepId,status:n.status,output:n.output,error:n.error})),startedAt:s.startedAt,finishedAt:s.finishedAt}}streamRun(t){let e=this.events.get(t);if(!e)throw new NotFoundException({error:{code:g.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}});return e}async approveRun(t){let e=this.engineRunIds.get(t)??t,s=this.engine.getRun(e);if(!s)throw new NotFoundException({error:{code:g.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}});let n=s.steps.find(o=>o.status==="awaiting_approval");n&&await this.engine.approve(e,n.stepId);}async rejectRun(t,e){let s=this.engineRunIds.get(t)??t,n=this.engine.getRun(s);if(!n)throw new NotFoundException({error:{code:g.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}});let o=n.steps.find(a=>a.status==="awaiting_approval");o&&await this.engine.reject(s,o.stepId,e??"Rejected");}async getNextStep(t){if(!t){(await this.engine.list())[0];return null}let e=this.engineRunIds.get(t)??t,s=this.engine.getRun(e);return s?(Array.isArray(s.steps)?s.steps:[]).find(o=>o.status==="pending")??null:null}};L=i([Injectable(),r(0,Optional()),r(0,Inject("DATABASE"))],L);var P=class{constructor(t){this.service=t;}async list(){return this.service.list()}async run(t,e){return this.service.run(t,e.input??{})}async listRuns(t,e){return this.service.listRuns(Number(t)||20,Number(e)||0)}async getRun(t){return this.service.getRun(t)}async stream(t,e){e.raw.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"});let n=this.service.streamRun(t).subscribe({next:o=>{e.raw.write(`event: step-${o.status}
|
|
2
2
|
data: ${JSON.stringify(o)}
|
|
3
3
|
|
|
4
4
|
`);},error:o=>{e.raw.write(`event: error
|
|
@@ -7,4 +7,4 @@ data: ${JSON.stringify({error:o.message})}
|
|
|
7
7
|
`),e.raw.end();},complete:()=>{e.raw.write(`event: done
|
|
8
8
|
data: {}
|
|
9
9
|
|
|
10
|
-
`),e.raw.end();}});e.raw.on("close",()=>n.unsubscribe());}async approve(t){return await this.service.approveRun(t),{approved:true}}async reject(t,e){return await this.service.rejectRun(t,e.reason),{rejected:true}}async nextStep(t){return this.service.getNextStep(t)}};i([Get()],b.prototype,"list",1),i([Post(":type/run"),r(0,Param("type")),r(1,Body())],b.prototype,"run",1),i([Get("runs"),r(0,Query("limit")),r(1,Query("offset"))],b.prototype,"listRuns",1),i([Get("runs/:id"),r(0,Param("id"))],b.prototype,"getRun",1),i([Get("runs/:id/stream"),r(0,Param("id")),r(1,Res())],b.prototype,"stream",1),i([Post("runs/:id/approve"),r(0,Param("id"))],b.prototype,"approve",1),i([Post("runs/:id/reject"),r(0,Param("id")),r(1,Body())],b.prototype,"reject",1),i([Get("next-step"),r(0,Query("runId"))],b.prototype,"nextStep",1),b=i([Controller("workflows"),r(0,Inject(B))],b);var it=class{};it=i([Module({controllers:[b],providers:[B],exports:[B]})],it);var L=class{constructor(t){this.projectsService=t;}getEngine(t){return new KnowledgeEngine({projectRoot:t})}async onModuleInit(){this._initKnowledge();}async _initKnowledge(){let t=this.projectsService.getActiveProjectRoot()??process.env.DEVFLOW_PROJECT_ROOT??process.cwd();try{let e=this.getEngine(t),s=await loadPlugins(),n=Array.from(s.values());for(let l of n)for(let u of l.knowledge?.sources??[])await e.registerSource({...u,version:u.version||l.meta.version});let o=await e.getSources(),a=Date.now()-10080*60*1e3;for(let l of o)(!l.lastSyncTime||l.lastSyncTime<a)&&await e.syncDocs(l.source.name);}catch{}}async search(t,e,s){return this.getEngine(t).search(e,{sources:s&&s!=="all"?[s]:void 0})}async sync(t,e){return this.getEngine(t).syncDocs(e??"")}async getSources(t){return this.getEngine(t).getSources()}};L=i([Injectable(),r(0,Inject(p))],L);var $=class{constructor(t,e){this.service=t;this.projects=e;}resolveRootPath(t,e){let s=t??e??this.projects.getActiveProjectRoot();if(!s)throw new BadRequestException("rootPath is required \u2014 no active project connected");return s}async search(t,e,s,n){return this.service.search(this.resolveRootPath(t,n),e??"",s)}async sync(t,e){return this.service.sync(this.resolveRootPath(t.rootPath,e),t.pluginName)}async getSources(t,e){return this.service.getSources(this.resolveRootPath(t,e))}};i([Get("search"),r(0,Query("rootPath")),r(1,Query("q")),r(2,Query("scope")),r(3,Headers("x-devflow-project"))],$.prototype,"search",1),i([Post("sync"),r(0,Body()),r(1,Headers("x-devflow-project"))],$.prototype,"sync",1),i([Get("sources"),r(0,Query("rootPath")),r(1,Headers("x-devflow-project"))],$.prototype,"getSources",1),$=i([Controller("knowledge"),r(0,Inject(L)),r(1,Inject(p))],$);var ot=class{};ot=i([Module({imports:[T,v],controllers:[$],providers:[L],exports:[L]})],ot);var q=class{constructor(){this.results=[];this.scenarioIds=[];this.engine=new BenchmarkEngine,this.registerDefaultScenarios();}registerDefaultScenarios(){let t=[{id:"understand-codebase",category:"understand",desc:"\u7406\u89E3\u4EE3\u7801\u5E93\u67B6\u6784",expectedFiles:2},{id:"modify-component",category:"modify",desc:"\u4FEE\u6539 React \u7EC4\u4EF6",expectedFiles:1,expectedComponents:1},{id:"review-code",category:"review",desc:"\u4EE3\u7801\u5BA1\u67E5",expectedIssues:2}];for(let e of t)this.engine.registerScenario(e),this.scenarioIds.push(e.id);}async runScenarioSet(t){let e=async a=>({prepTimeMs:1e3+Math.random()*500,tokenCount:500+Math.floor(Math.random()*200),firstPassSuccess:Math.random()>.5,reworkCount:Math.floor(Math.random()*3),durationMs:5e3+Math.random()*3e3}),s=async a=>({prepTimeMs:500+Math.random()*300,tokenCount:300+Math.floor(Math.random()*100),firstPassSuccess:Math.random()>.2,reworkCount:Math.floor(Math.random()*2),durationMs:3e3+Math.random()*2e3}),n=t??this.scenarioIds,o=await this.engine.runScenarioBatch(n,e,s);return this.results=o,o}async getScenarioResults(){return this.results.length===0&&await this.runScenarioSet(),this.results}async getComparisonSummary(){let t=await this.getScenarioResults(),e=t.length;return {totalScenarios:e,avgTimeSavedRate:t.reduce((s,n)=>s+n.comparison.timeSavedRate,0)/e,avgTokenReductionRate:t.reduce((s,n)=>s+n.comparison.tokenReductionRate,0)/e,avgFirstPassLift:t.reduce((s,n)=>s+n.comparison.firstPassLift,0)/e,avgReworkReductionRate:t.reduce((s,n)=>s+n.comparison.reworkReductionRate,0)/e}}async getExperimentalRoiSummary(){let t=await this.getComparisonSummary();return {totalScenarios:t.totalScenarios,avgTimeSavedRate:t.avgTimeSavedRate,avgTokenReductionRate:t.avgTokenReductionRate,avgFirstPassLift:t.avgFirstPassLift,avgReworkReductionRate:t.avgReworkReductionRate,conclusion:"DevFlow shows significant improvement in all metrics"}}};q=i([Injectable()],q);var D=class{constructor(t){this.service=t;}async run(t){return this.service.runScenarioSet(t.scenarioIds)}async getResults(){return this.service.getScenarioResults()}async getComparisonSummary(){return this.service.getComparisonSummary()}async getExperimentalRoiSummary(){return this.service.getExperimentalRoiSummary()}};i([Post("run"),r(0,Body())],D.prototype,"run",1),i([Get("results")],D.prototype,"getResults",1),i([Get("summary")],D.prototype,"getComparisonSummary",1),i([Get("roi-summary")],D.prototype,"getExperimentalRoiSummary",1),D=i([Controller("benchmark"),r(0,Inject(q))],D);var at=class{};at=i([Module({controllers:[D],providers:[q],exports:[q]})],at);var G=class{constructor(t){this.telemetryService=t;this.plugins=new Map;this.installRecords=[];}async list(t,e){let s=Array.from(this.plugins.values());if(t){let n=t.toLowerCase();s=s.filter(o=>o.name.toLowerCase().includes(n)||o.description.toLowerCase().includes(n));}return e&&(s=s.filter(n=>n.tags.includes(e))),s}async getByName(t){let e=this.plugins.get(t);if(!e)throw new NotFoundException({error:{code:d.PLUGIN_NOT_FOUND,message:`Plugin "${t}" not found`,details:{}}});return e}async publish(t){let e=t.npmPackage.replace(/^@devflow-tools\/plugin-/,""),s={name:e,npmPackage:t.npmPackage,version:t.version,description:t.description,tags:t.tags??[],createdAt:Date.now()};return this.plugins.set(e,s),s}async install(t,e){let s=t.startsWith("@devflow-tools/plugin-")?t:`@devflow-tools/plugin-${t}`,n=t.replace(/^@devflow-tools\/plugin-/,"");return this.plugins.set(n,{name:n,npmPackage:s,version:"0.1.0",description:"Installed plugin",tags:[],createdAt:Date.now()}),e&&await this.recordPluginInstall(n,e),{ok:true,name:n}}async uninstall(t,e){let s=t.replace(/^@devflow-tools\/plugin-/,"");return this.plugins.delete(s),e&&await this.recordPluginUninstall(s,e),{ok:true,name:s}}async recordPluginInstall(t,e){let s=this.installRecords.find(n=>n.pluginName===t&&n.projectRoot===e);s?s.uninstalledAt=void 0:this.installRecords.push({pluginName:t,projectRoot:e,installedAt:Date.now()});}async recordPluginUninstall(t,e){let s=this.installRecords.find(n=>n.pluginName===t&&n.projectRoot===e);s&&(s.uninstalledAt=Date.now());}async listInstalledProjects(t){return this.installRecords.filter(e=>e.pluginName===t&&!e.uninstalledAt).map(e=>e.projectRoot)}async buildPluginEffectiveness(t){let s=(await this.listInstalledProjects(t)).length,n=await this.telemetryService.getPluginUsageStats(t),o=s>0?n.activeProjects/s:0,a=n.totalRuns>0?n.successfulRuns/n.totalRuns:0,l="optimize";return o>.7&&a>.8?l="install":(o<.3||a<.5)&&(l="remove"),{name:t,installCount:s,usageCount:n.totalRuns,activeRate:o,successRate:a,lastUsedAt:n.lastUsedAt,recommendation:l}}async getPluginEffectiveness(t){let e=t?this.installRecords.filter(o=>o.projectRoot===t&&!o.uninstalledAt):this.installRecords.filter(o=>!o.uninstalledAt),s=[...new Set(e.map(o=>o.pluginName))],n=[];for(let o of s){let a=await this.buildPluginEffectiveness(o);n.push(a);}return n}};G=i([Injectable(),r(0,Inject(P))],G);var A=class{constructor(t){this.service=t;}async list(t,e){return this.service.list(t,e)}async getPluginEffectiveness(t){return this.service.getPluginEffectiveness(t)}async getByName(t){return this.service.getByName(t)}async publish(t){return this.service.publish(t)}async install(t,e){return this.service.install(t.name,t.rootPath??e)}async uninstall(t,e,s){return this.service.uninstall(t,e.rootPath??s)}};i([Get("plugins"),r(0,Query("search")),r(1,Query("tag"))],A.prototype,"list",1),i([Get("plugins/effectiveness"),r(0,Query("rootPath"))],A.prototype,"getPluginEffectiveness",1),i([Get("plugins/:name"),r(0,Param("name"))],A.prototype,"getByName",1),i([Post("plugins"),r(0,Body())],A.prototype,"publish",1),i([Post("plugins/install"),r(0,Body()),r(1,Headers("x-devflow-project"))],A.prototype,"install",1),i([Post("plugins/:name/uninstall"),r(0,Param("name")),r(1,Body()),r(2,Headers("x-devflow-project"))],A.prototype,"uninstall",1),A=i([Controller("registry"),r(0,Inject(G))],A);var ct=class{};ct=i([Module({imports:[H],controllers:[A],providers:[G],exports:[G]})],ct);var he={provide:"DATABASE",useFactory:()=>{let c=process.env.DEVFLOW_STATE_DIR??join(homedir(),".devflow","global");return new DevFlowDatabase(c)}},ut=class{};ut=i([Global(),Module({providers:[he],exports:[he]})],ut);var lt=class{intercept(t,e){return e.handle().pipe(map(s=>s&&typeof s=="object"&&"error"in s?s:{ok:true,data:s??null}))}};lt=i([Injectable()],lt);var X=class{constructor(){this.startTime=Date.now();}health(){return {version:"0.2.3",uptime:Date.now()-this.startTime}}};i([Yt(),Get("health")],X.prototype,"health",1),X=i([Controller()],X);var dt=class{};dt=i([Module({imports:[ut,z,v,T,nt,ot,it,at,ct],controllers:[X],providers:[{provide:APP_INTERCEPTOR,useClass:lt}]})],dt);function ve(c){return c===400?d.BAD_REQUEST:c===404?d.PROJECT_NOT_FOUND:c===422?d.VALIDATION_ERROR:d.INTERNAL_ERROR}var Q=class{constructor(){this.logger=new Logger(Q.name);}catch(t,e){let n=e.switchToHttp().getResponse();if(t instanceof HttpException){let o=t.getStatus(),a=t.getResponse();if(typeof a=="object"&&a!==null&&"error"in a){let u=a.error;if(typeof u=="object"&&u!==null&&"code"in u){n.status(o).send(a);return}let y=typeof a.message=="string"?a.message:"Request failed";n.status(o).send({error:{code:ve(o),message:y,details:{}}});return}let l=typeof a=="string"?a:a.message??"Request failed";n.status(o).send({error:{code:ve(o),message:l,details:{}}});return}this.logger.error("Unhandled exception",t instanceof Error?t.stack:String(t)),n.status(HttpStatus.INTERNAL_SERVER_ERROR).send({error:{code:d.INTERNAL_ERROR,message:"Internal server error",details:{}}});}};Q=i([Catch()],Q);async function dr(){let c=new FastifyAdapter,t=await NestFactory.create(dt,c);return t.setGlobalPrefix("api"),t.useGlobalFilters(new Q),t.enableCors({origin:true,credentials:true}),c.getInstance().addHook("preParsing",async(s,n,o)=>{if(s.headers["content-length"]==="0"){let a=Buffer.from("{}");return s.headers["content-length"]=String(a.length),Readable.from([a])}return o}),await t.listen({port:parseInt(process.env.PORT||"13337",10),host:"127.0.0.1"}),t}(process.argv[1]?.endsWith("main.js")||process.argv[1]?.endsWith("main.ts")||process.argv[1]?.endsWith("server.js"))&&dr();export{dr as bootstrap};
|
|
10
|
+
`),e.raw.end();}});e.raw.on("close",()=>n.unsubscribe());}async approve(t){return await this.service.approveRun(t),{approved:true}}async reject(t,e){return await this.service.rejectRun(t,e.reason),{rejected:true}}async nextStep(t){return this.service.getNextStep(t)}};i([Get()],P.prototype,"list",1),i([Post(":type/run"),r(0,Param("type")),r(1,Body())],P.prototype,"run",1),i([Get("runs"),r(0,Query("limit")),r(1,Query("offset"))],P.prototype,"listRuns",1),i([Get("runs/:id"),r(0,Param("id"))],P.prototype,"getRun",1),i([Get("runs/:id/stream"),r(0,Param("id")),r(1,Res())],P.prototype,"stream",1),i([Post("runs/:id/approve"),r(0,Param("id"))],P.prototype,"approve",1),i([Post("runs/:id/reject"),r(0,Param("id")),r(1,Body())],P.prototype,"reject",1),i([Get("next-step"),r(0,Query("runId"))],P.prototype,"nextStep",1),P=i([Controller("workflows"),r(0,Inject(L))],P);var ct=class{};ct=i([Module({controllers:[P],providers:[L],exports:[L]})],ct);var q=class{constructor(t){this.projectsService=t;}getEngine(t){return new KnowledgeEngine({projectRoot:t})}async onModuleInit(){this._initKnowledge();}async _initKnowledge(){let t=this.projectsService.getActiveProjectRoot()??process.env.DEVFLOW_PROJECT_ROOT??process.cwd();try{let e=this.getEngine(t),s=await loadPlugins(),n=Array.from(s.values());for(let m of n)for(let p of m.knowledge?.sources??[])await e.registerSource({...p,version:p.version||m.meta.version});let o=await e.getSources(),a=Date.now()-10080*60*1e3;for(let m of o)(!m.lastSyncTime||m.lastSyncTime<a)&&await e.syncDocs(m.source.name);}catch{}}async search(t,e,s){return this.getEngine(t).search(e,{sources:s&&s!=="all"?[s]:void 0})}async sync(t,e){return this.getEngine(t).syncDocs(e??"")}async getSources(t){return this.getEngine(t).getSources()}};q=i([Injectable(),r(0,Inject(f))],q);var $=class{constructor(t,e){this.service=t;this.projects=e;}resolveRootPath(t,e){let s=t??e??this.projects.getActiveProjectRoot();if(!s)throw new BadRequestException("rootPath is required \u2014 no active project connected");return s}async search(t,e,s,n){return this.service.search(this.resolveRootPath(t,n),e??"",s)}async sync(t,e){return this.service.sync(this.resolveRootPath(t.rootPath,e),t.pluginName)}async getSources(t,e){return this.service.getSources(this.resolveRootPath(t,e))}};i([Get("search"),r(0,Query("rootPath")),r(1,Query("q")),r(2,Query("scope")),r(3,Headers("x-devflow-project"))],$.prototype,"search",1),i([Post("sync"),r(0,Body()),r(1,Headers("x-devflow-project"))],$.prototype,"sync",1),i([Get("sources"),r(0,Query("rootPath")),r(1,Headers("x-devflow-project"))],$.prototype,"getSources",1),$=i([Controller("knowledge"),r(0,Inject(q)),r(1,Inject(f))],$);var ut=class{};ut=i([Module({imports:[N,w],controllers:[$],providers:[q],exports:[q]})],ut);var G=class{constructor(){this.results=[];this.scenarioIds=[];this.engine=new BenchmarkEngine,this.registerDefaultScenarios();}registerDefaultScenarios(){let t=[{id:"understand-codebase",category:"understand",desc:"\u7406\u89E3\u4EE3\u7801\u5E93\u67B6\u6784",expectedFiles:2},{id:"modify-component",category:"modify",desc:"\u4FEE\u6539 React \u7EC4\u4EF6",expectedFiles:1,expectedComponents:1},{id:"review-code",category:"review",desc:"\u4EE3\u7801\u5BA1\u67E5",expectedIssues:2}];for(let e of t)this.engine.registerScenario(e),this.scenarioIds.push(e.id);}async runScenarioSet(t){let e=async a=>({prepTimeMs:1e3+Math.random()*500,tokenCount:500+Math.floor(Math.random()*200),firstPassSuccess:Math.random()>.5,reworkCount:Math.floor(Math.random()*3),durationMs:5e3+Math.random()*3e3}),s=async a=>({prepTimeMs:500+Math.random()*300,tokenCount:300+Math.floor(Math.random()*100),firstPassSuccess:Math.random()>.2,reworkCount:Math.floor(Math.random()*2),durationMs:3e3+Math.random()*2e3}),n=t??this.scenarioIds,o=await this.engine.runScenarioBatch(n,e,s);return this.results=o,o}async getScenarioResults(){return this.results.length===0&&await this.runScenarioSet(),this.results}async getComparisonSummary(){let t=await this.getScenarioResults(),e=t.length;return {totalScenarios:e,avgTimeSavedRate:t.reduce((s,n)=>s+n.comparison.timeSavedRate,0)/e,avgTokenReductionRate:t.reduce((s,n)=>s+n.comparison.tokenReductionRate,0)/e,avgFirstPassLift:t.reduce((s,n)=>s+n.comparison.firstPassLift,0)/e,avgReworkReductionRate:t.reduce((s,n)=>s+n.comparison.reworkReductionRate,0)/e}}async getExperimentalRoiSummary(){let t=await this.getComparisonSummary();return {totalScenarios:t.totalScenarios,avgTimeSavedRate:t.avgTimeSavedRate,avgTokenReductionRate:t.avgTokenReductionRate,avgFirstPassLift:t.avgFirstPassLift,avgReworkReductionRate:t.avgReworkReductionRate,conclusion:"DevFlow shows significant improvement in all metrics"}}};G=i([Injectable()],G);var M=class{constructor(t){this.service=t;}async run(t){return this.service.runScenarioSet(t.scenarioIds)}async getResults(){return this.service.getScenarioResults()}async getComparisonSummary(){return this.service.getComparisonSummary()}async getExperimentalRoiSummary(){return this.service.getExperimentalRoiSummary()}};i([Post("run"),r(0,Body())],M.prototype,"run",1),i([Get("results")],M.prototype,"getResults",1),i([Get("summary")],M.prototype,"getComparisonSummary",1),i([Get("roi-summary")],M.prototype,"getExperimentalRoiSummary",1),M=i([Controller("benchmark"),r(0,Inject(G))],M);var lt=class{};lt=i([Module({controllers:[M],providers:[G],exports:[G]})],lt);var K=class{constructor(t){this.telemetryService=t;this.plugins=new Map;this.installRecords=[];}async list(t,e){let s=Array.from(this.plugins.values());if(t){let n=t.toLowerCase();s=s.filter(o=>o.name.toLowerCase().includes(n)||o.description.toLowerCase().includes(n));}return e&&(s=s.filter(n=>n.tags.includes(e))),s}async getByName(t){let e=this.plugins.get(t);if(!e)throw new NotFoundException({error:{code:g.PLUGIN_NOT_FOUND,message:`Plugin "${t}" not found`,details:{}}});return e}async publish(t){let e=t.npmPackage.replace(/^@devflow-tools\/plugin-/,""),s={name:e,npmPackage:t.npmPackage,version:t.version,description:t.description,tags:t.tags??[],createdAt:Date.now()};return this.plugins.set(e,s),s}async install(t,e){let s=t.startsWith("@devflow-tools/plugin-")?t:`@devflow-tools/plugin-${t}`,n=t.replace(/^@devflow-tools\/plugin-/,"");return this.plugins.set(n,{name:n,npmPackage:s,version:"0.1.0",description:"Installed plugin",tags:[],createdAt:Date.now()}),e&&await this.recordPluginInstall(n,e),{ok:true,name:n}}async uninstall(t,e){let s=t.replace(/^@devflow-tools\/plugin-/,"");return this.plugins.delete(s),e&&await this.recordPluginUninstall(s,e),{ok:true,name:s}}async recordPluginInstall(t,e){let s=this.installRecords.find(n=>n.pluginName===t&&n.projectRoot===e);s?s.uninstalledAt=void 0:this.installRecords.push({pluginName:t,projectRoot:e,installedAt:Date.now()});}async recordPluginUninstall(t,e){let s=this.installRecords.find(n=>n.pluginName===t&&n.projectRoot===e);s&&(s.uninstalledAt=Date.now());}async listInstalledProjects(t){return this.installRecords.filter(e=>e.pluginName===t&&!e.uninstalledAt).map(e=>e.projectRoot)}async buildPluginEffectiveness(t){let s=(await this.listInstalledProjects(t)).length,n=await this.telemetryService.getPluginUsageStats(t),o=s>0?n.activeProjects/s:0,a=n.totalRuns>0?n.successfulRuns/n.totalRuns:0,m="optimize";return o>.7&&a>.8?m="install":(o<.3||a<.5)&&(m="remove"),{name:t,installCount:s,usageCount:n.totalRuns,activeRate:o,successRate:a,lastUsedAt:n.lastUsedAt,recommendation:m}}async getPluginEffectiveness(t){let e=t?this.installRecords.filter(o=>o.projectRoot===t&&!o.uninstalledAt):this.installRecords.filter(o=>!o.uninstalledAt),s=[...new Set(e.map(o=>o.pluginName))],n=[];for(let o of s){let a=await this.buildPluginEffectiveness(o);n.push(a);}return n}};K=i([Injectable(),r(0,Inject(S))],K);var j=class{constructor(t){this.service=t;}async list(t,e){return this.service.list(t,e)}async getPluginEffectiveness(t){return this.service.getPluginEffectiveness(t)}async getByName(t){return this.service.getByName(t)}async publish(t){return this.service.publish(t)}async install(t,e){return this.service.install(t.name,t.rootPath??e)}async uninstall(t,e,s){return this.service.uninstall(t,e.rootPath??s)}};i([Get("plugins"),r(0,Query("search")),r(1,Query("tag"))],j.prototype,"list",1),i([Get("plugins/effectiveness"),r(0,Query("rootPath"))],j.prototype,"getPluginEffectiveness",1),i([Get("plugins/:name"),r(0,Param("name"))],j.prototype,"getByName",1),i([Post("plugins"),r(0,Body())],j.prototype,"publish",1),i([Post("plugins/install"),r(0,Body()),r(1,Headers("x-devflow-project"))],j.prototype,"install",1),i([Post("plugins/:name/uninstall"),r(0,Param("name")),r(1,Body()),r(2,Headers("x-devflow-project"))],j.prototype,"uninstall",1),j=i([Controller("registry"),r(0,Inject(K))],j);var dt=class{};dt=i([Module({imports:[J],controllers:[j],providers:[K],exports:[K]})],dt);var ye={provide:"DATABASE",useFactory:()=>{let c=process.env.DEVFLOW_STATE_DIR??join(homedir(),".devflow","global");return new DevFlowDatabase(c)}},mt=class{};mt=i([Global(),Module({providers:[ye],exports:[ye]})],mt);var gt=class{intercept(t,e){return e.handle().pipe(map(s=>s&&typeof s=="object"&&"error"in s?s:{ok:true,data:s??null}))}};gt=i([Injectable()],gt);var et=class{constructor(){this.startTime=Date.now();}health(){return {version:"0.2.3",uptime:Date.now()-this.startTime}}};i([Yt(),Get("health")],et.prototype,"health",1),et=i([Controller()],et);var pt=class{};pt=i([Module({imports:[mt,st,w,N,at,ut,ct,lt,dt],controllers:[et],providers:[{provide:APP_INTERCEPTOR,useClass:gt}]})],pt);function ve(c){return c===400?g.BAD_REQUEST:c===404?g.PROJECT_NOT_FOUND:c===422?g.VALIDATION_ERROR:g.INTERNAL_ERROR}var V=class{constructor(){this.logger=new Logger(V.name);}catch(t,e){let n=e.switchToHttp().getResponse();if(t instanceof HttpException){let o=t.getStatus(),a=t.getResponse();if(typeof a=="object"&&a!==null&&"error"in a){let p=a.error;if(typeof p=="object"&&p!==null&&"code"in p){n.status(o).send(a);return}let Q=typeof a.message=="string"?a.message:"Request failed";n.status(o).send({error:{code:ve(o),message:Q,details:{}}});return}let m=typeof a=="string"?a:a.message??"Request failed";n.status(o).send({error:{code:ve(o),message:m,details:{}}});return}this.logger.error("Unhandled exception",t instanceof Error?t.stack:String(t)),n.status(HttpStatus.INTERNAL_SERVER_ERROR).send({error:{code:g.INTERNAL_ERROR,message:"Internal server error",details:{}}});}};V=i([Catch()],V);async function mr(){let c=new FastifyAdapter,t=await NestFactory.create(pt,c);return t.setGlobalPrefix("api"),t.useGlobalFilters(new V),t.enableCors({origin:true,credentials:true}),c.getInstance().addHook("preParsing",async(s,n,o)=>{if(s.headers["content-length"]==="0"){let a=Buffer.from("{}");return s.headers["content-length"]=String(a.length),Readable.from([a])}return o}),await t.listen({port:parseInt(process.env.PORT||"13337",10),host:"127.0.0.1"}),t}(process.argv[1]?.endsWith("main.js")||process.argv[1]?.endsWith("main.ts")||process.argv[1]?.endsWith("server.js"))&&mr();export{mr as bootstrap};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devflow-tools/devflow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "DevFlow - Developer Intelligence Platform (Distribution Package)",
|
|
6
6
|
"bin": {
|
|
@@ -15,17 +15,17 @@
|
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@colbymchenry/codegraph": "^1.1.1",
|
|
18
|
-
"@devflow-tools/adapters": "^0.
|
|
19
|
-
"@devflow-tools/benchmark": "^0.
|
|
20
|
-
"@devflow-tools/context-engine": "^0.
|
|
21
|
-
"@devflow-tools/database": "^0.
|
|
22
|
-
"@devflow-tools/knowledge-engine": "^0.
|
|
23
|
-
"@devflow-tools/mcp-server": "^0.
|
|
24
|
-
"@devflow-tools/memory-engine": "^0.
|
|
25
|
-
"@devflow-tools/sdk": "^0.
|
|
26
|
-
"@devflow-tools/server": "^0.
|
|
27
|
-
"@devflow-tools/telemetry": "^0.
|
|
28
|
-
"@devflow-tools/workflow-engine": "^0.
|
|
18
|
+
"@devflow-tools/adapters": "^0.10.0",
|
|
19
|
+
"@devflow-tools/benchmark": "^0.10.0",
|
|
20
|
+
"@devflow-tools/context-engine": "^0.10.0",
|
|
21
|
+
"@devflow-tools/database": "^0.10.0",
|
|
22
|
+
"@devflow-tools/knowledge-engine": "^0.10.0",
|
|
23
|
+
"@devflow-tools/mcp-server": "^0.10.0",
|
|
24
|
+
"@devflow-tools/memory-engine": "^0.10.0",
|
|
25
|
+
"@devflow-tools/sdk": "^0.10.0",
|
|
26
|
+
"@devflow-tools/server": "^0.10.0",
|
|
27
|
+
"@devflow-tools/telemetry": "^0.10.0",
|
|
28
|
+
"@devflow-tools/workflow-engine": "^0.10.0",
|
|
29
29
|
"@inquirer/prompts": "^7.10.1",
|
|
30
30
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
31
31
|
"@nestjs/common": "^10.4.0",
|
|
@@ -52,5 +52,5 @@
|
|
|
52
52
|
"plugin-registry.json",
|
|
53
53
|
"scripts/postinstall.js"
|
|
54
54
|
],
|
|
55
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "20444d2631e3d77c3b3a4c3afd9398b21d888a4f"
|
|
56
56
|
}
|