@devflow-tools/devflow 0.6.1

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.
@@ -0,0 +1,2 @@
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 ue=Object.defineProperty;var y=(t,e)=>()=>(t&&(e=t(t=0)),e);var O=(t,e)=>{for(var o in e)ue(t,o,{get:e[o],enumerable:true});};var I={};O(I,{createPluginHandlers:()=>pe,createToolHandlers:()=>de,getCoreTools:()=>T,getPluginTools:()=>P});function T(){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 de(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=(u,p)=>!u||u.length<=p?{value:u??"",truncated:false}:{value:u.slice(0,p),truncated:true},r=o(e.prompt,500),n=o(e.response,500),s=o(e.stdout,1e3),i=o(e.stderr,500),a=r.truncated||n.truncated||s.truncated||i.truncated,l={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:i.value,mcpToolName:e.mcpToolName,errorMessage:e.errorMessage,errorStack:e.errorStack,memoryKey:e.memoryKey,userMessage:e.userMessage},metadata:{source:"manual"},...a&&{metadata:{truncated:true,source:"manual"}}};return await t.telemetry.recordEvent(l),{acknowledged:true,eventId:l.id}}}}function P(t){let e=[];for(let o of t){let r=o.meta.name;for(let n of o.workflow?.templates??[]){let s=n.triggers?.find(i=>i.type==="mcp");s?.tool&&e.push({name:`${r}_${s.tool}`,description:n.description,inputSchema:{type:"object",properties:n.steps.filter(i=>i.inputSchema).reduce((i,a)=>({...i,...a.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.workflow?.templates??[]){let i=s.triggers?.find(l=>l.type==="mcp");if(!i?.tool)continue;let a=`${n}_${i.tool}`;o[a]=async l=>{let u=await t.workflow.run(s.name,l),p="";try{let c={id:u.runId??`run:${Date.now()}`,source:"mcp",tool:a,workflow:s.name,input:l,status:"running",startedAt:Date.now(),finishedAt:null,steps:[],metadata:{}};p=t.workflow.renderPlan(c,s);}catch{}return {...u,plan:p,_devflow_unique:{dag_orchestrated:true,step_tracked:true,plugin_name:n,template_name:s.name}}};}}return o}var E=y(()=>{});var x,$=y(()=>{x=[{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 H(t){let e=await t.ruleGetAll();return [...x,...e]}function me(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=M.get(r);if((!s||n>s.resetAt)&&(s={count:0,resetAt:n+6e4},M.set(r,s)),s.count++,s.count>o.maxCallsPerMinute)return t.action}return "allow"}function N(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=me(r,e);if(n!=="allow")return {decision:n,rule:r}}return {decision:"allow"}}var M,F=y(()=>{$();M=new Map;});function _(t){let e=JSON.stringify(t,Object.keys(t).sort());return createHash("sha256").update(e).digest("hex")}async function D(t,e,o,r,n,s){let i=await t.auditGetSecret(),a=await t.auditGetAll(),l=a.length>0?a[a.length-1].signature:createHash("sha256").update("genesis").digest("hex"),u=Date.now(),p=a.length+1,c=`${p}|${u}|${e}|${o}|${r}|${n??""}|${s}|${l}`,f=createHmac("sha256",i).update(c).digest("hex");await t.auditAppend({seq:p,ts:u,tool:e,argsHash:o,decision:r,ruleId:n,sessionId:s,prevHash:l,signature:f});}async function L(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}`,i=createHmac("sha256",e).update(s).digest("hex");if(n.signature!==i)return {valid:false,brokenAt:n.seq};r=n.signature;}return {valid:true,brokenAt:null}}async function J(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}`,i=createHmac("sha256",e).update(s).digest("hex");await t.sqlExecute("UPDATE devflow_audit_chain SET prev_hash = ?, signature = ? WHERE seq = ?",[r,i,n.seq]),r=i;}}var C=y(()=>{});function h(t,e,o){let r=Date.now(),n=r+fe,s=createHash("sha256").update(JSON.stringify(e)).digest("hex"),i=`${t}|${r}|${n}|${s}`,a=createHmac("sha256",o).update(i).digest("hex");return {tool:t,ts:r,exp:n,queryHash:s,hmac:a}}function G(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}`,i=createHmac("sha256",r).update(s).digest("hex");return t.hmac===i}function U(t){return Date.now()>t.exp}var fe,q=y(()=>{fe=3e4;});var B={};O(B,{CONSTITUTIONAL_RULES:()=>x,enforce:()=>ge,hashArgs:()=>_,isReceiptExpired:()=>U,issueReceipt:()=>h,parseJwtPayload:()=>V,rebuildAuditChain:()=>J,verifyAuditChain:()=>L,verifyReceipt:()=>G});function V(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 ge(t,e,o){if(!e._devflow_token){let c=process.env.DEVFLOW_SESSION_TOKEN;if(c){let f=V(c);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 c=Math.floor(Date.now()/1e3);if(n.tokenPayload.exp&&c>n.tokenPayload.exp){let f=_(e);return await D(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 H(o),{decision:i,rule:a}=N(s,n),l=_(e);if(await D(o,t,l,i,a?.id??null,r),i==="deny"&&a)return {result:{allowed:false,rule:a,message:a.message}};if(i==="warn"&&a){let c=await o.auditGetSecret(),f=h(t,e,c);return {result:{allowed:true,warning:a.message,rule:a},receipt:f}}let u=await o.auditGetSecret(),p=h(t,e,u);return {result:{allowed:true},receipt:p}}var z=y(()=>{F();C();q();C();q();$();});E();async function ee(t){Te(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(),i=await loadPlugins(),a=Array.from(i.values()),l=T(),u=P(a),p=[...l,...u];e.setRequestHandler(ListToolsRequestSchema,async()=>({tools:p}));let c=null;e.setRequestHandler(CallToolRequestSchema,async te=>{let{name:d,arguments:ne}=te.params,w=ne??{},b=Date.now();try{let m;if(s){m=await De(n,d,w),Q(t.projectRoot,d);let v=Date.now()-b,g=d.split("_")[0];try{await n.recordTelemetryEvent({toolName:d,args:w,durationMs:v,success:!0,pluginName:g,metadata:{projectRoot:t.projectRoot}});}catch(R){console.error("[devflow-mcp] Failed to record telemetry:",R);}}else {if(!c){let[{createEngines:ae}]=await Promise.all([import('@devflow-tools/context-engine')]);c=await ae(t.projectRoot);for(let ce of a)for(let le of ce.workflow?.templates??[])c.workflow.register(le);console.error(`[devflow-mcp] Warning: DevFlow server not reachable at ${o}`),console.error("[devflow-mcp] Running in local mode.");}let{enforce:v}=await Promise.resolve().then(()=>(z(),B)),g=await v(d,w,c.data);if(!g.result.allowed)return {content:[{type:"text",text:JSON.stringify({_devflow:{v:1,tool:d,ts:Date.now(),marker:"devflow-mcp-v1"},error:g.result.message,rule:g.result.rule?.id})}],isError:!0};let{createToolHandlers:R,createPluginHandlers:oe}=await Promise.resolve().then(()=>(E(),I)),re=R(c),se=oe(c,a),A={...re,...se}[d];if(!A)throw new Error(`Unknown tool: ${d}`);m=await A(w),Q(t.projectRoot,d);let ie=Date.now()-b;try{await c.data.recordToolCall(d,w,ie);}catch{}g.receipt&&(m={...m,_receipt:g.receipt}),g.result.warning&&(m={...m,_warning:g.result.warning});}let k=$e(d,m);return {content:[{type:"text",text:JSON.stringify(k,null,2)}]}}catch(m){let k=Date.now()-b;if(s)try{await n.recordTelemetryEvent({toolName:d,args:w,durationMs:k,success:!1,error:m.message,pluginName:d.split("_")[0],metadata:{projectRoot:t.projectRoot}});}catch(v){console.error("[devflow-mcp] Failed to record error telemetry:",v);}else if(c)try{await c.data.recordToolCall(d,w,k,m.message);}catch{}return {content:[{type:"text",text:`Error: ${m.message}`}],isError:true}}});let f=new StdioServerTransport;await e.connect(f);}function Te(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"),i=createHmac("sha256","devflow-local-mcp-secret-v1").update(`${e}.${n}`).digest("base64url");process.env.DEVFLOW_SESSION_TOKEN=`${e}.${n}.${i}`,console.error("[devflow-mcp] Auto-generated session token (no env token provided).");}var Pe=new Set(["react","vue","nest","nextjs","graphql","docker","tailwind","taro","electron","performance"]);function Ee(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 Pe.has(o)?`devflow:${o}`:""}function Q(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 i={};if(existsSync(s))try{i=JSON.parse(readFileSync(s,"utf-8"));}catch{}i.lastMcpCall=Date.now(),i.bypassCount=0;let a=Ee(e);a&&(i.activeCommand=a),writeFileSync(s,JSON.stringify(i));}catch{}}function $e(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 je(){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 i=s.triggers?.find(a=>a.type==="mcp");if(i?.tool){let a=`${n}_${i.tool}`;t.set(a,s.name);}}}return t}async function De(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 je()).get(e)??e;return t.runWorkflow(n,o)}}}async function Ce(){let t=process.env.DEVFLOW_PROJECT_ROOT||process.cwd();await ee({mode:"stdio",projectRoot:t});}Ce().catch(t=>{console.error("MCP Server error:",t),process.exit(1);});
package/dist/server.js ADDED
@@ -0,0 +1,10 @@
1
+ import'reflect-metadata';import {Reflector,APP_GUARD,APP_INTERCEPTOR,NestFactory}from'@nestjs/core';import {FastifyAdapter}from'@nestjs/platform-fastify';import {Injectable,Inject,Global,Module,Get,Query,Param,Post,Body,Delete,Controller,Optional,Headers,Res,Put,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 {WorkflowEngine}from'@devflow-tools/workflow-engine';import {loadPlugins}from'@devflow-tools/sdk';import {Subject}from'rxjs';import {KnowledgeEngine}from'@devflow-tools/knowledge-engine';import {BenchmarkEngine}from'@devflow-tools/benchmark';import {map}from'rxjs/operators';import {DevFlowDatabase}from'@devflow-tools/database';var fe=Object.defineProperty;var he=Object.getOwnPropertyDescriptor;var o=(c,t,e,r)=>{for(var s=r>1?void 0:r?he(t,e):t,n=c.length-1,a;n>=0;n--)(a=c[n])&&(s=(r?a(t,e,s):a(s))||s);return r&&s&&fe(t,e,s),s},i=(c,t)=>(e,r)=>t(e,r,c);var xt="isPublic",Kt=()=>SetMetadata(xt,true);var jt={MISSING_API_KEY:"AUTH_MISSING_API_KEY",INVALID_API_KEY:"AUTH_INVALID_API_KEY"};var we=(process.env.DEVFLOW_API_KEYS??"dev-key-000000").split(",").map(c=>c.trim()).filter(Boolean),W=class{constructor(t){this.reflector=t;}canActivate(t){if(this.reflector.getAllAndOverride(xt,[t.getHandler(),t.getClass()]))return true;let s=t.switchToHttp().getRequest().headers["x-api-key"];if(!s)throw new UnauthorizedException({error:{code:jt.MISSING_API_KEY,message:"X-API-Key header is required",details:{}}});if(!we.includes(s))throw new UnauthorizedException({error:{code:jt.INVALID_API_KEY,message:"Invalid API key",details:{}}});return true}};W=o([Injectable(),i(0,Inject(Reflector))],W);var X=class{};X=o([Global(),Module({providers:[W,{provide:APP_GUARD,useClass:W}]})],X);var f={WORKFLOW_NOT_FOUND:"WORKFLOW_NOT_FOUND",RUN_NOT_FOUND:"RUN_NOT_FOUND",MEMORY_KEY_NOT_FOUND:"MEMORY_KEY_NOT_FOUND",PROJECT_NOT_FOUND:"PROJECT_NOT_FOUND",NODE_NOT_FOUND:"NODE_NOT_FOUND",PLUGIN_NOT_FOUND:"PLUGIN_NOT_FOUND",INTERNAL_ERROR:"INTERNAL_ERROR"};var v=class{constructor(){this.projects=new Map;this.activeProjectRoot=process.env.DEVFLOW_PROJECT_ROOT??null;}setActiveProject(t){this.activeProjectRoot=t;}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:f.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)}`,r={id:e,name:t.name,rootPath:t.rootPath,stack:t.stack,createdAt:Date.now()};return this.projects.set(e,r),this.activeProjectRoot||(this.activeProjectRoot=t.rootPath),r}async delete(t){if(!this.projects.has(t))throw new NotFoundException({error:{code:f.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:f.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}}};v=o([Injectable()],v);var R=class{constructor(t){this.service=t;}async list(){return this.service.list()}async getOnboardingPackByRoot(t){if(!t)throw new BadRequestException("rootPath is required");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 getActive(){return {rootPath:this.service.getActiveProjectRoot()}}async delete(t){return this.service.delete(t)}};o([Get()],R.prototype,"list",1),o([Get("onboarding-pack"),i(0,Query("rootPath"))],R.prototype,"getOnboardingPackByRoot",1),o([Get(":id"),i(0,Param("id"))],R.prototype,"getById",1),o([Get(":id/onboarding-pack"),i(0,Param("id"))],R.prototype,"getOnboardingPack",1),o([Post(),i(0,Body())],R.prototype,"create",1),o([Post("connect"),i(0,Body())],R.prototype,"connect",1),o([Get("active")],R.prototype,"getActive",1),o([Delete(":id"),i(0,Param("id"))],R.prototype,"delete",1),R=o([Controller("projects"),i(0,Inject(v))],R);var P=class{};P=o([Module({controllers:[R],providers:[v],exports:[v]})],P);var S=class{constructor(){this.engine=new TelemetryEngine;}async recordEvent(t){await this.engine.recordEvent(t);}async listRuns(t,e,r){let s=Array.from(this.engine.runs.values()),n=s;return r&&(n=s.filter(a=>a.meta?.source===r)),n.slice(e,e+t).map(a=>({id:a.meta?.runId??"",agent:a.meta?.agent??"",mode:a.meta?.mode??"",source:a.meta?.source??"unknown",status:a.status,startedAt:a.startedAt,tokenUsed:a.tokenUsed}))}async getRun(t){let e=this.engine.runs.get(t);if(!e)throw new NotFoundException({error:{code:f.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}});return e}async getTimeline(t,e){return Array.from(this.engine.runs.values()).filter(s=>!(t&&s.startedAt<Number(t)||e&&s.startedAt>Number(e))).flatMap(s=>s.steps?.map(n=>({runId:s.meta?.runId,stepId:n.stepId,type:n.type,duration:n.duration,timestamp:n.timestamp}))??[])}async getRunEvents(t){return this.engine.listEvents(t)}async getRunStats(t){return this.engine.getRunStats(t)}async getFeedbackStats(t,e){let r=this.collectAllEvents(),s=e!=null?Date.now()-e*24*60*60*1e3:void 0,n=r.filter(m=>!(m.data?.toolName!=="context_feedback"||t&&m.data?.toolInput?.projectRoot!==t||s!=null&&(m.timestamp??0)<s)),a=n.length,u=n.filter(m=>m.data?.toolInput?.feedback==="hit").length,l=n.filter(m=>m.data?.toolInput?.feedback==="partial").length,g=n.filter(m=>m.data?.toolInput?.feedback==="miss").length;return {total:a,hits:u,partials:l,misses:g,hitRate:a>0?u/a:0,partialRate:a>0?l/a:0,missRate:a>0?g/a:0}}collectAllEvents(){let t=this.engine.events;if(!t)return [];let e=[];for(let r of t.values())Array.isArray(r)&&e.push(...r);return e}async getStats(t=7){let e=Array.from(this.engine.runs.values()),r=Date.now(),s=r-t*24*60*60*1e3,n=e.filter(p=>p.startedAt>=s),a={};for(let p of n){let y=new Date(p.startedAt).toISOString().slice(0,10);a[y]||(a[y]={runs:0,tokens:0}),a[y].runs++,a[y].tokens+=p.tokenUsed??0;}let u=0,l=0,g=0;for(let p of n){let y=this.engine.events.get(p.meta?.runId)??[];u+=p.tokenUsed??0,l+=y.filter(G=>G.kind==="llm_call").length,g+=y.filter(G=>G.kind==="tool_use").length;}let m=new Date(s).toISOString().slice(0,10),x=new Date(r).toISOString().slice(0,10);return {period:{from:m,to:x},summary:{totalRuns:n.length,completedRuns:n.filter(p=>p.status==="completed").length,failedRuns:n.filter(p=>p.status==="failed").length,totalTokens:u,totalLlmCalls:l,totalToolUses:g,avgRunDuration:n.length>0?Math.round(n.reduce((p,y)=>p+((y.finishedAt??r)-y.startedAt),0)/n.length):0},byDay:Object.entries(a).map(([p,y])=>({date:p,...y})).sort((p,y)=>p.date.localeCompare(y.date)),byWorkflow:this.buildWorkflowBreakdown(n,r),byPlugin:this.buildPluginBreakdown(n)}}buildWorkflowBreakdown(t,e){let r={};for(let s of t){let n=s.workflowName??s.meta?.workflowName??"unknown";r[n]||(r[n]={runs:0,completed:0,failed:0,avgDuration:0}),r[n].runs++,s.status==="completed"?r[n].completed++:r[n].failed++,r[n].avgDuration+=(s.finishedAt??e)-s.startedAt;}for(let s of Object.keys(r))r[s].avgDuration=r[s].runs>0?Math.round(r[s].avgDuration/r[s].runs):0;return Object.entries(r).map(([s,n])=>({name:s,runs:n.runs,successRate:n.runs>0?n.completed/n.runs:0,avgDuration:n.avgDuration}))}buildPluginBreakdown(t){let e={};for(let r of t){let s=r.pluginName??r.meta?.pluginName??"none";e[s]||(e[s]={runs:0,completed:0,failed:0}),e[s].runs++,r.status==="completed"?e[s].completed++:e[s].failed++;}return Object.entries(e).map(([r,s])=>({name:r,runs:s.runs,successRate:s.runs>0?s.completed/s.runs:0}))}async getOpsRoiSummary(){let t=Array.from(this.engine.runs.values()),e=Date.now(),r=t.length,s=t.filter(k=>k.status==="completed").length,n=r>0?s/r:0,a=t.reduce((k,Y)=>k+(Y.tokenUsed??0),0),u=r>0?a/r:0,l=t.reduce((k,Y)=>{let St=Y.startedAt??0,It=Y.finishedAt??e;return k+(It-St)},0),g=r>0?l/r:0,m=t.filter(k=>k.relevanceFeedback==="hit"||k.meta?.relevanceFeedback==="hit").length,x=t.filter(k=>k.relevanceFeedback!==void 0||k.meta?.relevanceFeedback!==void 0).length,p=await this.getFeedbackStats(),y=m+p.hits,G=x+p.total,vt=G>0?y/G:0;return {period:"all-time",totalRuns:r,successfulRuns:s,successRate:n,avgTokenUsage:u,avgDuration:g,feedbackHitRate:vt,trend:"stable"}}async getExperimentalRoiSummary(){return {totalScenarios:0,avgTimeSavedRate:0,avgTokenReductionRate:0,avgFirstPassLift:0,avgReworkReductionRate:0,conclusion:"No experimental data available yet"}}async getRoiSummary(t=7){let e=Array.from(this.engine.runs.values()),r=Date.now(),s=r-t*24*60*60*1e3,n=e.filter(d=>d.startedAt>=s),a=n.length,u=n.filter(d=>d.status==="completed").length,l=n.filter(d=>d.status!=="completed").length,g=a>0?Math.round(n.reduce((d,h)=>d+((h.finishedAt??r)-h.startedAt),0)/a):0,m=a>0?Math.round(n.reduce((d,h)=>d+(h.tokenUsed??0),0)/a):0,x=n.filter(d=>d.firstPassSuccess===true||d.meta?.firstPassSuccess===true).length,p=a>0?x/a:0,y=n.filter(d=>d.relevanceFeedback==="hit"||d.meta?.relevanceFeedback==="hit").length,G=n.filter(d=>d.relevanceFeedback!==void 0||d.meta?.relevanceFeedback!==void 0).length,vt=await this.getFeedbackStats(void 0,t),k=y+vt.hits,Y=G+vt.total,St=Y>0?k/Y:0,It=n.reduce((d,h)=>d+(h.retryCount??h.meta?.retryCount??0),0),ge=a>0?It/a:0,pe=g,ut={context_insufficient:0,knowledge_missing:0,workflow_design_issue:0,tool_error:0,agent_override:0,unknown:0};for(let d of n)if(d.status!=="completed"){let h=d.meta?.runId;if(h)try{let Ht=await this.engine.classifyFailure(h);ut[Ht]=(ut[Ht]??0)+1;}catch{ut.unknown++;}else ut.unknown++;}let z={};for(let d of n){let h=new Date(d.startedAt).toISOString().slice(0,10);z[h]||(z[h]={runs:0,tokens:0,failures:0}),z[h].runs++,z[h].tokens+=d.tokenUsed??0,d.status!=="completed"&&z[h].failures++;}return {period:{from:new Date(s).toISOString().slice(0,10),to:new Date(r).toISOString().slice(0,10)},overview:{totalRuns:a,completedRuns:u,failedRuns:l,avgDuration:g,avgTokens:m,firstPassSuccessRate:p,feedbackHitRate:St},efficiency:{totalTokensSaved:0,avgTimePerTask:pe,avgRetryCount:ge},failures:{total:l,breakdown:ut},workflows:this.buildWorkflowBreakdown(n,r),plugins:this.buildPluginBreakdown(n),byDay:Object.entries(z).map(([d,h])=>({date:d,...h})).sort((d,h)=>d.date.localeCompare(h.date))}}async getPluginEffectiveness(t,e){await this.getPluginUsageStats(t);let n=Array.from(this.engine.runs.values()).filter(g=>!((g.pluginName??g.meta?.pluginName)!==t||e&&g.meta?.projectRoot!==e)),a=n.length,u=n.filter(g=>g.status==="completed").length,l=a>0?n.reduce((g,m)=>g+((m.finishedAt??Date.now())-m.startedAt),0)/a:0;return {name:t,installCount:1,activeRate:a>0?1:0,successRate:a>0?u/a:0,avgTokenImpact:-l*.1,lastUsedAt:n.length>0?new Date(Math.max(...n.map(g=>g.startedAt))).toISOString():void 0,recommendation:this.getRecommendation(a>0?u/a:0,a)}}async getPluginUsageStats(t){let r=Array.from(this.engine.runs.values()).filter(m=>(m.pluginName??m.meta?.pluginName)===t),s=r.length,n=r.filter(m=>m.status==="completed").length,a=new Set;for(let m of r){let x=m.meta?.projectRoot;x&&a.add(x);}let u=s>0?r.reduce((m,x)=>m+((x.finishedAt??Date.now())-x.startedAt),0)/s:0,l=r.map(m=>m.startedAt).filter(m=>typeof m=="number"),g=l.length>0?new Date(Math.max(...l)).toISOString():void 0;return {activeProjects:a.size,totalRuns:s,successfulRuns:n,avgTokenImpact:-u*.1,lastUsedAt:g}}getRecommendation(t,e){return e===0?"remove":t>.8?"install":t>.5?"optimize":"remove"}async classifyFailure(t){let e=await this.getRun(t).catch(()=>null);if(!e||e.status!=="failed")return {};let r=e.steps?.find(n=>n.status==="failed");if(!r)return {};let s=r.error?.toLowerCase()??"";return s.includes("context")||s.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"}]}:s.includes("knowledge")||s.includes("docs")?{failureCategory:"knowledge_missing",failureReason:"Required knowledge was not available",suggestedActions:[{action:"Sync knowledge source",priority:"high"},{action:"Add docs source",priority:"medium"}]}:s.includes("workflow")||s.includes("step")?{failureCategory:"workflow_design_issue",failureReason:"Workflow design issue detected",suggestedActions:[{action:"Adjust specific step",priority:"high"},{action:"Split workflow",priority:"medium"}]}:s.includes("tool")||s.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){let e=this.engine.runs,r=Date.now()-t*24*60*60*1e3,s=0;for(let[n,a]of e)a.startedAt&&a.startedAt<r&&(e.delete(n),s++);return s}};S=o([Injectable()],S);var N=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)}`,r=t.toolName?"tool_use":"step_end",s={id:e,runId:t.metadata?.runId??`event_${Date.now()}_${Math.random().toString(36).slice(2,7)}`,stepId:e,kind:r,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(s),{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 s={...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,s),s}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 []}};N=o([Injectable(),i(0,Inject(S)),i(1,Optional()),i(1,Inject("DATABASE"))],N);var D=class{constructor(t){this.dataService=t;this.feedbackEntries=[];}async indexProject(t){let{context:e,codegraph:r}=await createEngines(t);await e.index(t);let s=r.getStats();return {totalFiles:s.fileCount,totalSymbols:s.nodeCount,lastIndexTime:s.lastUpdated,indexing:r.isIndexing()}}async getStatus(t){try{let{codegraph:e}=await createEngines(t),r=e.getStats();return {totalFiles:r.fileCount,totalSymbols:r.nodeCount,lastIndexTime:r.lastUpdated,indexing:e.isIndexing()}}catch{return {totalFiles:0,totalSymbols:0,lastIndexTime:0,indexing:false}}}async buildContext(t,e,r,s){let{context:n}=await createEngines(t);return n.build({query:e,mode:r,maxTokens:s??8e3,includeGraph:r==="deep"})}async buildTaskContext(t,e,r,s){let{context:n}=await createEngines(t);return n.buildTaskContext(e,{mode:r,maxTokens:s??8e3})}async findSymbol(t,e){let{indexer:r}=await createEngines(t);return r.findSymbol(e)}async recordFeedback(t,e,r,s){let n={query:e,feedback:r,timestamp:Date.now(),projectRoot:t};return this.feedbackEntries.push(n),this.dataService&&await this.dataService.recordTelemetryEvent({toolName:"context_feedback",args:{query:e,feedback:r,taskType:s?.taskType,contextMode:s?.contextMode,projectRoot:t},durationMs:0,success:true,metadata:{projectRoot:t,query:e,taskType:s?.taskType}}),n}async getFeedbackSummaries(){let t=this.feedbackEntries.length,e=this.feedbackEntries.filter(n=>n.feedback==="hit").length,r=this.feedbackEntries.filter(n=>n.feedback==="partial").length,s=this.feedbackEntries.filter(n=>n.feedback==="miss").length;return {total:t,hits:e,partials:r,misses:s,hitRate:t>0?e/t:0}}};D=o([Injectable(),i(0,Optional()),i(0,Inject(N))],D);var I=class{constructor(t,e){this.service=t;this.projects=e;}resolveRootPath(t,e){let r=t??e??this.projects.getActiveProjectRoot();if(!r)throw new BadRequestException("rootPath is required \u2014 no active project connected");return r}async status(t,e){return this.service.getStatus(this.resolveRootPath(t,e))}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,r){return this.service.findSymbol(this.resolveRootPath(e,r),t)}};o([Get("status"),i(0,Query("rootPath")),i(1,Headers("x-devflow-project"))],I.prototype,"status",1),o([Post("index"),i(0,Body()),i(1,Headers("x-devflow-project"))],I.prototype,"index",1),o([Post("build"),i(0,Body()),i(1,Headers("x-devflow-project"))],I.prototype,"build",1),o([Post("build-task"),i(0,Body()),i(1,Headers("x-devflow-project"))],I.prototype,"buildTask",1),o([Post("feedback"),i(0,Body()),i(1,Headers("x-devflow-project"))],I.prototype,"feedback",1),o([Get("feedback-summary")],I.prototype,"feedbackSummary",1),o([Get("symbol/:name"),i(0,Param("name")),i(1,Query("rootPath")),i(2,Headers("x-devflow-project"))],I.prototype,"findSymbol",1),I=o([Controller("context"),i(0,Inject(D)),i(1,Inject(v))],I);var A=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)}};o([Post("telemetry/event"),i(0,Body())],A.prototype,"recordTelemetryEvent",1),o([Get("project/stats"),i(0,Query("rootPath"))],A.prototype,"getProjectStats",1),o([Post("project/stats"),i(0,Body())],A.prototype,"updateProjectStats",1),o([Post("benchmark/result"),i(0,Body())],A.prototype,"recordBenchmarkResult",1),o([Get("benchmark/results"),i(0,Query("projectRoot"))],A.prototype,"getBenchmarkResults",1),A=o([Controller("data"),i(0,Inject(N))],A);var w=class{constructor(t){this.service=t;}async listRuns(t,e,r){return this.service.listRuns(Number(t)||20,Number(e)||0,r)}async getRun(t){let e=await this.service.getRun(t),r=await this.service.classifyFailure(t);return {...e,...r}}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 getStats(t){return this.service.getStats(Number(t)||7)}async getRoiSummary(t){return this.service.getRoiSummary(Number(t)||7)}async cleanup(t){return {ok:true,data:{removedRuns:await this.service.cleanup(t.olderThanDays??30)}}}};o([Get("runs"),i(0,Query("limit")),i(1,Query("offset")),i(2,Query("source"))],w.prototype,"listRuns",1),o([Get("runs/:id"),i(0,Param("id"))],w.prototype,"getRun",1),o([Get("timeline"),i(0,Query("from")),i(1,Query("to"))],w.prototype,"getTimeline",1),o([Get("runs/:runId/events"),i(0,Param("runId"))],w.prototype,"getRunEvents",1),o([Get("runs/:runId/stats"),i(0,Param("runId"))],w.prototype,"getRunStats",1),o([Get("stats"),i(0,Query("days"))],w.prototype,"getStats",1),o([Get("roi-summary"),i(0,Query("days"))],w.prototype,"getRoiSummary",1),o([Post("cleanup"),i(0,Body())],w.prototype,"cleanup",1),w=o([Controller("telemetry"),i(0,Inject(S))],w);var O=class{};O=o([Module({controllers:[w],providers:[S],exports:[S]})],O);var H=class{};H=o([Module({imports:[O],controllers:[A],providers:[N],exports:[N]})],H);var j=class{};j=o([Module({imports:[P,H],controllers:[I],providers:[D],exports:[D]})],j);var F=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:r}=await createEngines(t),s=r.getNode(e);if(!s)throw new NotFoundException({error:{code:f.NODE_NOT_FOUND,message:`Node "${e}" not found`,details:{}}});return s}async expandNode(t,e,r,s){let{graph:n}=await createEngines(t),a=n.expand([e],{depth:r,direction:s});return {node:a.nodes.find(u=>u.id===e),subGraph:a}}};F=o([Injectable()],F);var M=class{constructor(t,e){this.service=t;this.projects=e;}resolveRootPath(t,e){let r=t??e??this.projects.getActiveProjectRoot();if(!r)throw new BadRequestException("rootPath is required \u2014 no active project connected");return r}async getFullGraph(t,e,r){return e==="layered"?this.service.getLayeredGraph(this.resolveRootPath(t,r)):this.service.getFullGraph(this.resolveRootPath(t,r))}async getNode(t,e,r){return this.service.getNode(this.resolveRootPath(t,r),e)}async expandNode(t,e,r,s,n){return this.service.expandNode(this.resolveRootPath(t,n),e,Number(r)||2,s||"both")}};o([Get(),i(0,Query("rootPath")),i(1,Query("view")),i(2,Headers("x-devflow-project"))],M.prototype,"getFullGraph",1),o([Get(":nodeId"),i(0,Query("rootPath")),i(1,Param("nodeId")),i(2,Headers("x-devflow-project"))],M.prototype,"getNode",1),o([Get(":nodeId/expand"),i(0,Query("rootPath")),i(1,Param("nodeId")),i(2,Query("depth")),i(3,Query("direction")),i(4,Headers("x-devflow-project"))],M.prototype,"expandNode",1),M=o([Controller("graph"),i(0,Inject(F)),i(1,Inject(v))],M);var et=class{};et=o([Module({imports:[j,P],controllers:[M],providers:[F],exports:[F]})],et);var U=class{constructor(){this.engine=new WorkflowEngine;this.events=new Map;this.engineRunIds=new Map;}async onModuleInit(){try{let t=await loadPlugins(),e=Array.from(t.values());for(let s of e)for(let n of s.workflow?.templates??[])this.engine.register(n);let r=await this.engine.list();console.log(`[WorkflowService] Loaded ${e.length} plugins with ${r.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:f.WORKFLOW_NOT_FOUND,message:`Workflow "${t}" not found`,details:{}}});let s=`run_${Date.now()}_${Math.random().toString(36).slice(2,7)}`,n=new Subject;return this.events.set(s,n),this.engine.run(t,e).then(a=>{this.engineRunIds.set(s,a.runId);let u=this.engine.getRun(a.runId);if(u){for(let l of u.steps)n.next({runId:s,stepId:l.stepId,status:l.status==="success"?"completed":l.status==="failed"?"failed":"started",output:l.output,error:l.error,timestamp:Date.now()});a.status!=="running"&&n.complete();}a.status==="running"&&this.engine.onEvent(a.runId,l=>{n.next({runId:s,stepId:l.stepId,status:l.type==="step-done"?"completed":l.type==="step-error"?"failed":"started",output:"output"in l?l.output:void 0,error:"error"in l?l.error:void 0,timestamp:Date.now()});});}).catch(a=>{n.next({runId:s,stepId:"engine",status:"failed",error:a.message,timestamp:Date.now()}),n.complete();}),{runId:s}}async listRuns(t,e){return (await this.engine.listRuns()).map(n=>({runId:Array.from(this.engineRunIds.entries()).find(([,u])=>u===n.runId)?.[0]??n.runId,workflowName:n.type,status:n.status,steps:n.steps.map(u=>({stepId:u.stepId,status:u.status,output:u.output,error:u.error,startedAt:0})),startedAt:n.startedAt,finishedAt:n.finishedAt})).slice(e,e+t)}async getRun(t){let e=this.engineRunIds.get(t)??t,r=this.engine.getRun(e);if(!r)throw new NotFoundException({error:{code:f.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}});return {runId:t,workflowName:r.type,status:r.status,steps:r.steps.map(s=>({stepId:s.stepId,status:s.status,output:s.output,error:s.error})),startedAt:r.startedAt,finishedAt:r.finishedAt}}streamRun(t){let e=this.events.get(t);if(!e)throw new NotFoundException({error:{code:f.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}});return e}async approveRun(t){let e=this.engineRunIds.get(t)??t,r=this.engine.getRun(e);if(!r)throw new NotFoundException({error:{code:f.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}});let s=r.steps.find(n=>n.status==="awaiting_approval");s&&await this.engine.approve(e,s.stepId);}async rejectRun(t,e){let r=this.engineRunIds.get(t)??t,s=this.engine.getRun(r);if(!s)throw new NotFoundException({error:{code:f.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}});let n=s.steps.find(a=>a.status==="awaiting_approval");n&&await this.engine.reject(r,n.stepId,e??"Rejected");}async getNextStep(t){if(!t){(await this.engine.list())[0];return null}let e=this.engineRunIds.get(t)??t,r=this.engine.getRun(e);return r?(Array.isArray(r.steps)?r.steps:[]).find(n=>n.status==="pending")??null:null}};U=o([Injectable()],U);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 s=this.service.streamRun(t).subscribe({next:n=>{e.raw.write(`event: step-${n.status}
2
+ data: ${JSON.stringify(n)}
3
+
4
+ `);},error:n=>{e.raw.write(`event: error
5
+ data: ${JSON.stringify({error:n.message})}
6
+
7
+ `),e.raw.end();},complete:()=>{e.raw.write(`event: done
8
+ data: {}
9
+
10
+ `),e.raw.end();}});e.raw.on("close",()=>s.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)}};o([Get()],b.prototype,"list",1),o([Post(":type/run"),i(0,Param("type")),i(1,Body())],b.prototype,"run",1),o([Get("runs"),i(0,Query("limit")),i(1,Query("offset"))],b.prototype,"listRuns",1),o([Get("runs/:id"),i(0,Param("id"))],b.prototype,"getRun",1),o([Get("runs/:id/stream"),i(0,Param("id")),i(1,Res())],b.prototype,"stream",1),o([Post("runs/:id/approve"),i(0,Param("id"))],b.prototype,"approve",1),o([Post("runs/:id/reject"),i(0,Param("id")),i(1,Body())],b.prototype,"reject",1),o([Get("next-step"),i(0,Query("runId"))],b.prototype,"nextStep",1),b=o([Controller("workflows"),i(0,Inject(U))],b);var rt=class{};rt=o([Module({controllers:[b],providers:[U],exports:[U]})],rt);var B=class{async getAll(t){let{memory:e}=await createEngines(t),r=await e.getProjectContext(),s=await e.getUserPreferences();return {project:{stack:r.stack,conventions:r.conventions,metadata:r.metadata},user:{preferences:s.preferences,stack:s.stack}}}async update(t,e,r,s){let{memory:n}=await createEngines(t);if(e==="user")await n.updateUserPreference(r,s);else if(e==="project"){let a=await n.getProjectContext();a.metadata[r]=s,await n.setProjectContext(a);}else throw new NotFoundException({error:{code:f.MEMORY_KEY_NOT_FOUND,message:`Layer "${e}" not found`,details:{}}})}async getCandidates(t){let{memory:e}=await createEngines(t);return e.getCandidates()}async approveCandidate(t,e){let{memory:r}=await createEngines(t);await r.approveCandidate(e);}async rejectCandidate(t,e){let{memory:r}=await createEngines(t);await r.rejectCandidate(e);}};B=o([Injectable()],B);var T=class{constructor(t,e){this.service=t;this.projects=e;}resolveRootPath(t,e){let r=t??e??this.projects.getActiveProjectRoot();if(!r)throw new BadRequestException("rootPath is required \u2014 no active project connected");return r}async getAll(t,e){return this.service.getAll(this.resolveRootPath(t,e))}async update(t,e,r,s,n){return await this.service.update(this.resolveRootPath(t,n),e,r,s.value),{ok:true}}async getCandidates(t,e){return this.service.getCandidates(this.resolveRootPath(t,e))}async approve(t,e,r){return await this.service.approveCandidate(this.resolveRootPath(t,r),e),{approved:true}}async reject(t,e,r){return await this.service.rejectCandidate(this.resolveRootPath(t,r),e),{rejected:true}}};o([Get(),i(0,Query("rootPath")),i(1,Headers("x-devflow-project"))],T.prototype,"getAll",1),o([Put(":layer/:key"),i(0,Query("rootPath")),i(1,Param("layer")),i(2,Param("key")),i(3,Body()),i(4,Headers("x-devflow-project"))],T.prototype,"update",1),o([Get("candidates"),i(0,Query("rootPath")),i(1,Headers("x-devflow-project"))],T.prototype,"getCandidates",1),o([Post("candidates/:id/approve"),i(0,Query("rootPath")),i(1,Param("id")),i(2,Headers("x-devflow-project"))],T.prototype,"approve",1),o([Post("candidates/:id/reject"),i(0,Query("rootPath")),i(1,Param("id")),i(2,Headers("x-devflow-project"))],T.prototype,"reject",1),T=o([Controller("memory"),i(0,Inject(B)),i(1,Inject(v))],T);var st=class{};st=o([Module({imports:[j,P],controllers:[T],providers:[B],exports:[B]})],st);var L=class{getEngine(t){return new KnowledgeEngine({projectRoot:t})}async onModuleInit(){let t=process.env.DEVFLOW_PROJECT_ROOT??process.cwd();try{let e=this.getEngine(t),r=await e.getSources(),s=Date.now()-10080*60*1e3;for(let n of r)(!n.lastSyncTime||n.lastSyncTime<s)&&await e.syncDocs(n.source.name);}catch{}}async search(t,e,r){return this.getEngine(t).search(e,{sources:r&&r!=="all"?[r]:void 0})}async sync(t,e){return this.getEngine(t).syncDocs(e??"")}async getSources(t){return this.getEngine(t).getSources()}};L=o([Injectable()],L);var C=class{constructor(t,e){this.service=t;this.projects=e;}resolveRootPath(t,e){let r=t??e??this.projects.getActiveProjectRoot();if(!r)throw new BadRequestException("rootPath is required \u2014 no active project connected");return r}async search(t,e,r,s){return this.service.search(this.resolveRootPath(t,s),e??"",r)}async sync(t,e){return this.service.sync(this.resolveRootPath(t.rootPath,e),t.pluginName)}async getSources(t,e){return {ok:true,data:await this.service.getSources(this.resolveRootPath(t,e))}}};o([Get("search"),i(0,Query("rootPath")),i(1,Query("q")),i(2,Query("scope")),i(3,Headers("x-devflow-project"))],C.prototype,"search",1),o([Post("sync"),i(0,Body()),i(1,Headers("x-devflow-project"))],C.prototype,"sync",1),o([Get("sources"),i(0,Query("rootPath")),i(1,Headers("x-devflow-project"))],C.prototype,"getSources",1),C=o([Controller("knowledge"),i(0,Inject(L)),i(1,Inject(v))],C);var nt=class{};nt=o([Module({imports:[j,P],controllers:[C],providers:[L],exports:[L]})],nt);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}),r=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}),s=t??this.scenarioIds,n=await this.engine.runScenarioBatch(s,e,r);return this.results=n,n}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((r,s)=>r+s.comparison.timeSavedRate,0)/e,avgTokenReductionRate:t.reduce((r,s)=>r+s.comparison.tokenReductionRate,0)/e,avgFirstPassLift:t.reduce((r,s)=>r+s.comparison.firstPassLift,0)/e,avgReworkReductionRate:t.reduce((r,s)=>r+s.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=o([Injectable()],q);var _=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()}};o([Post("run"),i(0,Body())],_.prototype,"run",1),o([Get("results")],_.prototype,"getResults",1),o([Get("summary")],_.prototype,"getComparisonSummary",1),o([Get("roi-summary")],_.prototype,"getExperimentalRoiSummary",1),_=o([Controller("benchmark"),i(0,Inject(q))],_);var ot=class{};ot=o([Module({controllers:[_],providers:[q],exports:[q]})],ot);var $=class{constructor(t){this.telemetryService=t;this.plugins=new Map;this.installRecords=[];}async list(t,e){let r=Array.from(this.plugins.values());if(t){let s=t.toLowerCase();r=r.filter(n=>n.name.toLowerCase().includes(s)||n.description.toLowerCase().includes(s));}return e&&(r=r.filter(s=>s.tags.includes(e))),r}async getByName(t){let e=this.plugins.get(t);if(!e)throw new NotFoundException({error:{code:f.PLUGIN_NOT_FOUND,message:`Plugin "${t}" not found`,details:{}}});return e}async publish(t){let e=t.npmPackage.replace(/^@devflow-tools\/plugin-/,""),r={name:e,npmPackage:t.npmPackage,version:t.version,description:t.description,tags:t.tags??[],createdAt:Date.now()};return this.plugins.set(e,r),r}async install(t,e){let r=t.startsWith("@devflow-tools/plugin-")?t:`@devflow-tools/plugin-${t}`,s=t.replace(/^@devflow-tools\/plugin-/,"");return this.plugins.set(s,{name:s,npmPackage:r,version:"0.1.0",description:"Installed plugin",tags:[],createdAt:Date.now()}),e&&await this.recordPluginInstall(s,e),{ok:true,name:s}}async uninstall(t,e){let r=t.replace(/^@devflow-tools\/plugin-/,"");return this.plugins.delete(r),e&&await this.recordPluginUninstall(r,e),{ok:true,name:r}}async recordPluginInstall(t,e){let r=this.installRecords.find(s=>s.pluginName===t&&s.projectRoot===e);r?r.uninstalledAt=void 0:this.installRecords.push({pluginName:t,projectRoot:e,installedAt:Date.now()});}async recordPluginUninstall(t,e){let r=this.installRecords.find(s=>s.pluginName===t&&s.projectRoot===e);r&&(r.uninstalledAt=Date.now());}async listInstalledProjects(t){return this.installRecords.filter(e=>e.pluginName===t&&!e.uninstalledAt).map(e=>e.projectRoot)}async buildPluginEffectiveness(t){let r=(await this.listInstalledProjects(t)).length,s=await this.telemetryService.getPluginUsageStats(t),n=r>0?s.activeProjects/r:0,a=s.totalRuns>0?s.successfulRuns/s.totalRuns:0,u="optimize";return n>.7&&a>.8?u="install":(n<.3||a<.5)&&(u="remove"),{name:t,installCount:r,usageCount:s.totalRuns,activeRate:n,successRate:a,avgTokenImpact:s.avgTokenImpact,lastUsedAt:s.lastUsedAt,recommendation:u}}async getPluginEffectiveness(t){let e=t?this.installRecords.filter(n=>n.projectRoot===t&&!n.uninstalledAt):this.installRecords.filter(n=>!n.uninstalledAt),r=[...new Set(e.map(n=>n.pluginName))],s=[];for(let n of r){let a=await this.buildPluginEffectiveness(n);s.push(a);}return s}};$=o([Injectable(),i(0,Inject(S))],$);var E=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,r){return this.service.uninstall(t,e.rootPath??r)}};o([Get("plugins"),i(0,Query("search")),i(1,Query("tag"))],E.prototype,"list",1),o([Get("plugins/effectiveness"),i(0,Query("rootPath"))],E.prototype,"getPluginEffectiveness",1),o([Get("plugins/:name"),i(0,Param("name"))],E.prototype,"getByName",1),o([Post("plugins"),i(0,Body())],E.prototype,"publish",1),o([Post("plugins/install"),i(0,Body()),i(1,Headers("x-devflow-project"))],E.prototype,"install",1),o([Post("plugins/:name/uninstall"),i(0,Param("name")),i(1,Body()),i(2,Headers("x-devflow-project"))],E.prototype,"uninstall",1),E=o([Controller("registry"),i(0,Inject($))],E);var it=class{};it=o([Module({imports:[O],controllers:[E],providers:[$],exports:[$]})],it);var at=class{intercept(t,e){return e.handle().pipe(map(r=>r&&typeof r=="object"&&"error"in r?r:{ok:true,data:r??null}))}};at=o([Injectable()],at);var Q=class{constructor(){this.startTime=Date.now();}health(){return {version:"0.2.3",uptime:Date.now()-this.startTime}}};o([Kt(),Get("health")],Q.prototype,"health",1),Q=o([Controller()],Q);var ct=class{};ct=o([Module({imports:[X,P,j,et,rt,st,nt,O,ot,it,H],controllers:[Q],providers:[{provide:APP_INTERCEPTOR,useClass:at},{provide:"DATABASE",useFactory:()=>{let c=process.cwd();return new DevFlowDatabase(c)}}]})],ct);var K=class{constructor(){this.logger=new Logger(K.name);}catch(t,e){let s=e.switchToHttp().getResponse();if(t instanceof HttpException){let n=t.getStatus(),a=t.getResponse();if(typeof a=="object"&&a!==null&&"error"in a){s.status(n).send(a);return}let u=typeof a=="string"?a:a.message??"Request failed";s.status(n).send({error:{code:f.INTERNAL_ERROR,message:u,details:{}}});return}this.logger.error("Unhandled exception",t instanceof Error?t.stack:String(t)),s.status(HttpStatus.INTERNAL_SERVER_ERROR).send({error:{code:f.INTERNAL_ERROR,message:"Internal server error",details:{}}});}};K=o([Catch()],K);async function zr(){let c=await NestFactory.create(ct,new FastifyAdapter);return c.setGlobalPrefix("api"),c.useGlobalFilters(new K),c.enableCors({origin:true,credentials:true}),await c.listen({port:13337,host:"0.0.0.0"}),c}(process.argv[1]?.endsWith("main.js")||process.argv[1]?.endsWith("main.ts"))&&zr();export{zr as bootstrap};
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@devflow-tools/devflow",
3
+ "version": "0.6.1",
4
+ "type": "module",
5
+ "description": "DevFlow - Developer Intelligence Platform (Distribution Package)",
6
+ "bin": {
7
+ "devflow": "./bin/devflow"
8
+ },
9
+ "scripts": {
10
+ "build": "tsup",
11
+ "build:watch": "tsup --watch",
12
+ "clean": "rm -rf dist"
13
+ },
14
+ "dependencies": {
15
+ "@devflow-tools/sdk": "*",
16
+ "@devflow-tools/context-engine": "*",
17
+ "@devflow-tools/workflow-engine": "*",
18
+ "@devflow-tools/knowledge-engine": "*",
19
+ "@devflow-tools/memory-engine": "*",
20
+ "@devflow-tools/telemetry": "*",
21
+ "@devflow-tools/benchmark": "*",
22
+ "@devflow-tools/database": "*",
23
+ "@devflow-tools/adapters": "*",
24
+ "@devflow-tools/mcp-server": "*",
25
+ "@nestjs/common": "^10.4.0",
26
+ "@nestjs/core": "^10.4.0",
27
+ "@nestjs/platform-fastify": "^10.4.0",
28
+ "fastify": "^4.28.0",
29
+ "reflect-metadata": "^0.2.0",
30
+ "rxjs": "^7.8.0",
31
+ "class-transformer": "^0.5.1",
32
+ "class-validator": "^0.14.0",
33
+ "@modelcontextprotocol/sdk": "^1.0.0",
34
+ "commander": "^12.0.0",
35
+ "chalk": "^5.3.0"
36
+ },
37
+ "devDependencies": {
38
+ "tsup": "^8.0.0",
39
+ "typescript": "^5.5.0"
40
+ },
41
+ "engines": {
42
+ "node": ">=22.0.0"
43
+ },
44
+ "files": [
45
+ "dist",
46
+ "bin",
47
+ "plugin-registry.json"
48
+ ]
49
+ }
@@ -0,0 +1,174 @@
1
+ {
2
+ "version": "1.0.0",
3
+ "lastUpdated": "2026-07-06T07:44:33.230Z",
4
+ "plugins": [
5
+ {
6
+ "name": "@devflow-tools/plugin-animation",
7
+ "version": "0.5.0",
8
+ "description": "",
9
+ "tags": [],
10
+ "compatibleStacks": [
11
+ "animation"
12
+ ],
13
+ "size": "776K",
14
+ "author": "DevFlow Team",
15
+ "homepage": ""
16
+ },
17
+ {
18
+ "name": "@devflow-tools/plugin-css",
19
+ "version": "0.5.0",
20
+ "description": "",
21
+ "tags": [],
22
+ "compatibleStacks": [
23
+ "css"
24
+ ],
25
+ "size": "744K",
26
+ "author": "DevFlow Team",
27
+ "homepage": ""
28
+ },
29
+ {
30
+ "name": "@devflow-tools/plugin-docker",
31
+ "version": "0.5.0",
32
+ "description": "",
33
+ "tags": [],
34
+ "compatibleStacks": [
35
+ "docker"
36
+ ],
37
+ "size": "820K",
38
+ "author": "DevFlow Team",
39
+ "homepage": ""
40
+ },
41
+ {
42
+ "name": "@devflow-tools/plugin-electron",
43
+ "version": "0.5.0",
44
+ "description": "",
45
+ "tags": [],
46
+ "compatibleStacks": [
47
+ "electron"
48
+ ],
49
+ "size": "836K",
50
+ "author": "DevFlow Team",
51
+ "homepage": ""
52
+ },
53
+ {
54
+ "name": "@devflow-tools/plugin-git",
55
+ "version": "0.5.0",
56
+ "description": "",
57
+ "tags": [],
58
+ "compatibleStacks": [
59
+ "git"
60
+ ],
61
+ "size": "776K",
62
+ "author": "DevFlow Team",
63
+ "homepage": ""
64
+ },
65
+ {
66
+ "name": "@devflow-tools/plugin-graphql",
67
+ "version": "0.5.0",
68
+ "description": "",
69
+ "tags": [],
70
+ "compatibleStacks": [
71
+ "graphql"
72
+ ],
73
+ "size": "768K",
74
+ "author": "DevFlow Team",
75
+ "homepage": ""
76
+ },
77
+ {
78
+ "name": "@devflow-tools/plugin-nest",
79
+ "version": "0.5.0",
80
+ "description": "",
81
+ "tags": [],
82
+ "compatibleStacks": [
83
+ "nest"
84
+ ],
85
+ "size": "844K",
86
+ "author": "DevFlow Team",
87
+ "homepage": ""
88
+ },
89
+ {
90
+ "name": "@devflow-tools/plugin-nextjs",
91
+ "version": "0.5.0",
92
+ "description": "",
93
+ "tags": [],
94
+ "compatibleStacks": [
95
+ "nextjs"
96
+ ],
97
+ "size": "748K",
98
+ "author": "DevFlow Team",
99
+ "homepage": ""
100
+ },
101
+ {
102
+ "name": "@devflow-tools/plugin-performance",
103
+ "version": "0.5.0",
104
+ "description": "",
105
+ "tags": [],
106
+ "compatibleStacks": [
107
+ "performance"
108
+ ],
109
+ "size": "864K",
110
+ "author": "DevFlow Team",
111
+ "homepage": ""
112
+ },
113
+ {
114
+ "name": "@devflow-tools/plugin-react",
115
+ "version": "0.5.0",
116
+ "description": "",
117
+ "tags": [],
118
+ "compatibleStacks": [
119
+ "react"
120
+ ],
121
+ "size": "852K",
122
+ "author": "DevFlow Team",
123
+ "homepage": ""
124
+ },
125
+ {
126
+ "name": "@devflow-tools/plugin-tailwind",
127
+ "version": "0.5.0",
128
+ "description": "",
129
+ "tags": [],
130
+ "compatibleStacks": [
131
+ "tailwind"
132
+ ],
133
+ "size": "780K",
134
+ "author": "DevFlow Team",
135
+ "homepage": ""
136
+ },
137
+ {
138
+ "name": "@devflow-tools/plugin-taro",
139
+ "version": "0.5.0",
140
+ "description": "",
141
+ "tags": [],
142
+ "compatibleStacks": [
143
+ "taro"
144
+ ],
145
+ "size": "804K",
146
+ "author": "DevFlow Team",
147
+ "homepage": ""
148
+ },
149
+ {
150
+ "name": "@devflow-tools/plugin-ui-layout",
151
+ "version": "0.5.0",
152
+ "description": "",
153
+ "tags": [],
154
+ "compatibleStacks": [
155
+ "ui-layout"
156
+ ],
157
+ "size": "744K",
158
+ "author": "DevFlow Team",
159
+ "homepage": ""
160
+ },
161
+ {
162
+ "name": "@devflow-tools/plugin-vue",
163
+ "version": "0.5.0",
164
+ "description": "",
165
+ "tags": [],
166
+ "compatibleStacks": [
167
+ "vue"
168
+ ],
169
+ "size": "788K",
170
+ "author": "DevFlow Team",
171
+ "homepage": ""
172
+ }
173
+ ]
174
+ }