@devflow-tools/devflow 0.7.6 → 0.8.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/mcp-server.js +1 -1
- package/package.json +12 -12
package/dist/mcp-server.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
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 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);});
|
|
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 n in e)ue(t,n,{get:e[n],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:n,expandedTerms:r})=>{let o=await t.context.buildTaskContext(e,{mode:n??"fast"});return {taskType:o.taskType,requiredFiles:o.requiredFiles,optionalFiles:o.optionalFiles,keySymbols:o.keySymbols,graphSummary:o.graphSummary,riskHints:o.riskHints,nextActions:o.nextActions,reasoning:o.reasoning,confidence:o.confidence,tokenCount:o.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:n})=>{let r=e??"all",o=n??2;return {...r==="all"?t.graph.export():t.graph.getSubGraph(r,o),_devflow_unique:{layer_annotated:true,architecture_grouped:true,query_depth:o}}},run_workflow:async({type:e,input:n})=>({...await t.workflow.run(e,{input:n}),_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:n})=>({...await t.knowledge.search(e,{sources:n==="all"?void 0:[n]}),_devflow_unique:{source_versioned:true,code_examples_included:true,search_scope:n}}),devflow_report_event:async e=>{let n=(u,p)=>!u||u.length<=p?{value:u??"",truncated:false}:{value:u.slice(0,p),truncated:true},r=n(e.prompt,500),o=n(e.response,500),s=n(e.stdout,1e3),i=n(e.stderr,500),a=r.truncated||o.truncated||s.truncated||i.truncated,c={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:o.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(c),{acknowledged:true,eventId:c.id}}}}function P(t){let e=[];for(let n of t){let r=n.meta.name;for(let s of n.tools??[])e.push({name:s.name,description:s.description,inputSchema:s.inputSchema});let o=new Set(e.map(s=>s.name));for(let s of n.workflow?.templates??[]){let i=s.triggers?.find(c=>c.type==="mcp");if(!i?.tool)continue;let a=`${r}_${i.tool}`;o.has(a)||e.push({name:a,description:s.description,inputSchema:{type:"object",properties:s.steps.filter(c=>c.inputSchema).reduce((c,u)=>({...c,...u.inputSchema??{}}),{}),required:[]}});}}return e}function pe(t,e){let n={};for(let r of e){let o=r.meta.name;for(let s of r.tools??[])s.handler&&(n[s.name]=s.handler);for(let s of r.workflow?.templates??[]){let i=s.triggers?.find(c=>c.type==="mcp");if(!i?.tool)continue;let a=`${o}_${i.tool}`;n[a]||(n[a]=async c=>{let u=await t.workflow.run(s.name,c),p="";try{let l={id:u.runId??`run:${Date.now()}`,source:"mcp",tool:a,workflow:s.name,input:c,status:"running",startedAt:Date.now(),finishedAt:null,steps:[],metadata:{}};p=t.workflow.renderPlan(l,s);}catch{}return {...u,plan:p,_devflow_unique:{dag_orchestrated:true,step_tracked:true,plugin_name:o,template_name:s.name}}});}}return n}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 n=t.condition;if(n.tools&&!n.tools.includes("*")&&!n.tools.includes(e.toolName))return "allow";if(n.requireFields){for(let r of n.requireFields)if(!(r in e.args))return t.action}if(n.forbidPatterns){for(let r of n.forbidPatterns)for(let o of Object.values(e.args))if(typeof o=="string"&&new RegExp(r).test(o))return t.action}if(n.paramPatterns)for(let[r,o]of Object.entries(n.paramPatterns)){let s=String(e.args[r]??"");if(new RegExp(o).test(s))return t.action}if(n.maxCallsPerMinute){let r=`${e.toolName}:${e.sessionId??"anon"}`,o=Date.now(),s=M.get(r);if((!s||o>s.resetAt)&&(s={count:0,resetAt:o+6e4},M.set(r,s)),s.count++,s.count>n.maxCallsPerMinute)return t.action}return "allow"}function N(t,e){let n=[...t].sort((r,o)=>{let s={constitutional:0,project:1,session:2};return s[r.level]-s[o.level]});for(let r of n){let o=me(r,e);if(o!=="allow")return {decision:o,rule:r}}return {decision:"allow"}}var M,F=y(()=>{$();M=new Map;});function v(t){let e=JSON.stringify(t,Object.keys(t).sort());return createHash("sha256").update(e).digest("hex")}async function j(t,e,n,r,o,s){let i=await t.auditGetSecret(),a=await t.auditGetAll(),c=a.length>0?a[a.length-1].signature:createHash("sha256").update("genesis").digest("hex"),u=Date.now(),p=a.length+1,l=`${p}|${u}|${e}|${n}|${r}|${o??""}|${s}|${c}`,f=createHmac("sha256",i).update(l).digest("hex");await t.auditAppend({seq:p,ts:u,tool:e,argsHash:n,decision:r,ruleId:o,sessionId:s,prevHash:c,signature:f});}async function L(t){let e=await t.auditGetSecret(),n=await t.auditGetAll(),r=createHash("sha256").update("genesis").digest("hex");for(let o of n){if(o.prevHash!==r)return {valid:false,brokenAt:o.seq};let s=`${o.seq}|${o.ts}|${o.tool}|${o.argsHash}|${o.decision}|${o.ruleId??""}|${o.sessionId}|${r}`,i=createHmac("sha256",e).update(s).digest("hex");if(o.signature!==i)return {valid:false,brokenAt:o.seq};r=o.signature;}return {valid:true,brokenAt:null}}async function J(t){let e=await t.auditGetSecret(),n=await t.auditGetAll(),r=createHash("sha256").update("genesis").digest("hex");for(let o of n){let s=`${o.seq}|${o.ts}|${o.tool}|${o.argsHash}|${o.decision}|${o.ruleId??""}|${o.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,o.seq]),r=i;}}var C=y(()=>{});function _(t,e,n){let r=Date.now(),o=r+fe,s=createHash("sha256").update(JSON.stringify(e)).digest("hex"),i=`${t}|${r}|${o}|${s}`,a=createHmac("sha256",n).update(i).digest("hex");return {tool:t,ts:r,exp:o,queryHash:s,hmac:a}}function G(t,e,n,r){if(Date.now()>t.exp)return false;let o=createHash("sha256").update(JSON.stringify(n)).digest("hex");if(t.queryHash!==o)return false;let s=`${e}|${t.ts}|${t.exp}|${o}`,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:()=>v,isReceiptExpired:()=>U,issueReceipt:()=>_,parseJwtPayload:()=>V,rebuildAuditChain:()=>J,verifyAuditChain:()=>L,verifyReceipt:()=>G});function V(t){try{let e=t.split(".");if(e.length!==3)return null;let n=e[1],r=Buffer.from(n,"base64url").toString("utf-8");return JSON.parse(r)}catch{return null}}async function ge(t,e,n){if(!e._devflow_token){let l=process.env.DEVFLOW_SESSION_TOKEN;if(l){let f=V(l);f&&(e={...e,_devflow_token:f});}}let r=e._devflow_token?.sub??"anon",o={toolName:t,args:e,sessionId:r,tokenPayload:e._devflow_token};if(o.tokenPayload){let l=Math.floor(Date.now()/1e3);if(o.tokenPayload.exp&&l>o.tokenPayload.exp){let f=v(e);return await j(n,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(n),{decision:i,rule:a}=N(s,o),c=v(e);if(await j(n,t,c,i,a?.id??null,r),i==="deny"&&a)return {result:{allowed:false,rule:a,message:a.message}};if(i==="warn"&&a){let l=await n.auditGetSecret(),f=_(t,e,l);return {result:{allowed:true,warning:a.message,rule:a},receipt:f}}let u=await n.auditGetSecret(),p=_(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:{}}}),n=process.env.DEVFLOW_SERVER_URL??"http://127.0.0.1:13337",r=process.env.DEVFLOW_API_KEY??"dev-key-000000",o=new DevFlowApiClient({baseUrl:n,projectRoot:t.projectRoot,apiKey:r}),s=await o.ping(),i=await loadPlugins(),a=Array.from(i.values()),c=T(),u=P(a),p=[...c,...u];e.setRequestHandler(ListToolsRequestSchema,async()=>({tools:p}));let l=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 je(o,d,w),Q(t.projectRoot,d);let h=Date.now()-b,g=d.split("_")[0];try{await o.recordTelemetryEvent({toolName:d,args:w,durationMs:h,success:!0,pluginName:g,metadata:{projectRoot:t.projectRoot}});}catch(R){console.error("[devflow-mcp] Failed to record telemetry:",R);}}else {if(!l){let[{createEngines:ae}]=await Promise.all([import('@devflow-tools/context-engine')]);l=await ae(t.projectRoot);for(let ce of a)for(let le of ce.workflow?.templates??[])l.workflow.register(le);console.error(`[devflow-mcp] Warning: DevFlow server not reachable at ${n}`),console.error("[devflow-mcp] Running in local mode.");}let{enforce:h}=await Promise.resolve().then(()=>(z(),B)),g=await h(d,w,l.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(l),se=oe(l,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 l.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 o.recordTelemetryEvent({toolName:d,args:w,durationMs:k,success:!1,error:m.message,pluginName:d.split("_")[0],metadata:{projectRoot:t.projectRoot}});}catch(h){console.error("[devflow-mcp] Failed to record error telemetry:",h);}else if(l)try{await l.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"),n=Math.floor(Date.now()/1e3),r={sub:`devflow-mcp-${Date.now().toString(36)}`,project:t.split("/").pop()??"unknown",iat:n,exp:n+86400,scope:["context","knowledge","memory","workflow","graph"]},o=Buffer.from(JSON.stringify(r)).toString("base64url"),i=createHmac("sha256","devflow-local-mcp-secret-v1").update(`${e}.${o}`).digest("base64url");process.env.DEVFLOW_SESSION_TOKEN=`${e}.${o}.${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 n=t.split("_")[0];return Pe.has(n)?`devflow:${n}`:""}function Q(t,e){try{let n=process.env.TMPDIR||"/tmp",r=join(n,".devflow-receipts"),o=createHash("sha256").update(t).digest("hex").slice(0,16),s=join(r,`${o}.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 n={_devflow:{v:1,tool:t,ts:Date.now(),marker:"devflow-mcp-v1"}};return e&&typeof e=="object"&&!Array.isArray(e)?{...e,...n}:{result:e,...n}}async function De(){let t=new Map,e=await loadPlugins(),n=Array.from(e.values());for(let r of n){let o=r.meta.name;for(let s of r.workflow?.templates??[]){let i=s.triggers?.find(a=>a.type==="mcp");if(i?.tool){let a=`${o}_${i.tool}`;t.set(a,s.name);}}}return t}async function je(t,e,n){switch(e){case "get_project_context":return t.buildContext(n.query,n.mode??"fast");case "search_symbol":return t.searchSymbol(n.symbol);case "get_dependency_graph":return t.getGraph(n.target??"all",n.depth??2);case "run_workflow":return t.runWorkflow(n.type,n.input);case "get_memory":return t.getMemory();case "get_knowledge":return t.searchKnowledge(n.query,n.scope??"all");case "devflow_report_event":return t.recordEvent(n);default:{let o=(await De()).get(e)??e;return t.runWorkflow(o,n)}}}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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devflow-tools/devflow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "DevFlow - Developer Intelligence Platform (Distribution Package)",
|
|
6
6
|
"bin": {
|
|
@@ -15,16 +15,16 @@
|
|
|
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/telemetry": "^0.
|
|
27
|
-
"@devflow-tools/workflow-engine": "^0.
|
|
18
|
+
"@devflow-tools/adapters": "^0.8.0",
|
|
19
|
+
"@devflow-tools/benchmark": "^0.8.0",
|
|
20
|
+
"@devflow-tools/context-engine": "^0.8.0",
|
|
21
|
+
"@devflow-tools/database": "^0.8.0",
|
|
22
|
+
"@devflow-tools/knowledge-engine": "^0.8.0",
|
|
23
|
+
"@devflow-tools/mcp-server": "^0.8.0",
|
|
24
|
+
"@devflow-tools/memory-engine": "^0.8.0",
|
|
25
|
+
"@devflow-tools/sdk": "^0.8.0",
|
|
26
|
+
"@devflow-tools/telemetry": "^0.8.0",
|
|
27
|
+
"@devflow-tools/workflow-engine": "^0.8.0",
|
|
28
28
|
"@inquirer/prompts": "^7.10.1",
|
|
29
29
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
30
30
|
"@nestjs/common": "^10.4.0",
|
|
@@ -51,5 +51,5 @@
|
|
|
51
51
|
"plugin-registry.json",
|
|
52
52
|
"scripts/postinstall.js"
|
|
53
53
|
],
|
|
54
|
-
"gitHead": "
|
|
54
|
+
"gitHead": "5c9a804d3c2e6e6822b516fde67d5b789dbdb5b3"
|
|
55
55
|
}
|