@devflow-tools/devflow 0.8.10 → 0.8.11
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/README.md +34 -21
- package/dist/hooks/post-tool-use.js +2 -0
- package/dist/hooks/pre-tool-use.js +2 -2
- package/dist/hooks/stop.js +2 -0
- package/dist/mcp-server.js +1 -1
- package/dist/plugin/hooks.json +12 -0
- package/dist/plugin/skills/devflow:animation/SKILL.md +0 -1
- package/dist/plugin/skills/devflow:css/SKILL.md +0 -1
- package/dist/plugin/skills/devflow:docker/SKILL.md +0 -20
- package/dist/plugin/skills/devflow:electron/SKILL.md +0 -20
- package/dist/plugin/skills/devflow:git/SKILL.md +0 -1
- package/dist/plugin/skills/devflow:graphql/SKILL.md +0 -22
- package/dist/plugin/skills/devflow:nest/SKILL.md +0 -22
- package/dist/plugin/skills/devflow:nextjs/SKILL.md +0 -22
- package/dist/plugin/skills/devflow:performance/SKILL.md +0 -20
- package/dist/plugin/skills/devflow:react/SKILL.md +0 -30
- package/dist/plugin/skills/devflow:tailwind/SKILL.md +0 -20
- package/dist/plugin/skills/devflow:taro/SKILL.md +0 -20
- package/dist/plugin/skills/devflow:ui-layout/SKILL.md +0 -1
- package/dist/plugin/skills/devflow:vue/SKILL.md +0 -24
- package/dist/server.js +2 -2
- package/package.json +14 -14
- package/plugin-registry.json +40 -24
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @devflow-tools/devflow
|
|
2
2
|
|
|
3
|
-
DevFlow 主发行包
|
|
3
|
+
DevFlow 主发行包 — 开发者智能平台,一键安装所有核心能力。
|
|
4
4
|
|
|
5
5
|
## 安装
|
|
6
6
|
|
|
@@ -11,40 +11,53 @@ npm install -g @devflow-tools/devflow
|
|
|
11
11
|
## 使用
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
#
|
|
14
|
+
# 初始化项目(自动生成 Onboarding Pack)
|
|
15
|
+
cd your-project
|
|
15
16
|
devflow init
|
|
16
17
|
|
|
17
18
|
# 启动服务
|
|
18
19
|
devflow start
|
|
19
20
|
|
|
20
|
-
#
|
|
21
|
-
devflow
|
|
21
|
+
# 连接 AI Agent
|
|
22
|
+
devflow connect claude
|
|
22
23
|
|
|
23
|
-
#
|
|
24
|
-
devflow
|
|
25
|
-
```
|
|
24
|
+
# 查看索引状态
|
|
25
|
+
devflow index
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
# 依赖图谱
|
|
28
|
+
devflow graph src/App.tsx --depth 3
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
# 上下文检索
|
|
31
|
+
devflow context "fix the login bug"
|
|
30
32
|
|
|
31
|
-
|
|
33
|
+
# 工作流管理
|
|
34
|
+
devflow workflow list
|
|
35
|
+
devflow workflow run bugfix
|
|
32
36
|
|
|
33
|
-
|
|
37
|
+
# 查看记忆
|
|
38
|
+
devflow memory show
|
|
34
39
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
# 搜索知识库
|
|
41
|
+
devflow knowledge useState
|
|
42
|
+
```
|
|
38
43
|
|
|
39
|
-
|
|
40
|
-
devflow plugin search react
|
|
44
|
+
## 包含的包
|
|
41
45
|
|
|
42
|
-
|
|
43
|
-
devflow plugin install @devflow-tools/plugin-react
|
|
46
|
+
此发行包聚合了以下 DevFlow 核心模块:
|
|
44
47
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
- `@devflow-tools/server` — REST API 服务端 (NestJS + Fastify)
|
|
49
|
+
- `@devflow-tools/cli` — CLI 命令行工具
|
|
50
|
+
- `@devflow-tools/mcp-server` — MCP 协议服务端
|
|
51
|
+
- `@devflow-tools/context-engine` — 上下文构建引擎
|
|
52
|
+
- `@devflow-tools/memory-engine` — 项目记忆引擎
|
|
53
|
+
- `@devflow-tools/knowledge-engine` — 知识库引擎
|
|
54
|
+
- `@devflow-tools/workflow-engine` — 工作流引擎
|
|
55
|
+
- `@devflow-tools/telemetry` — 遥测与追踪
|
|
56
|
+
- `@devflow-tools/database` — SQLite 持久化存储
|
|
57
|
+
|
|
58
|
+
## 系统要求
|
|
59
|
+
|
|
60
|
+
- Node.js >= 18
|
|
48
61
|
|
|
49
62
|
## 许可证
|
|
50
63
|
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import {request}from'http';import {existsSync,readFileSync,writeFileSync}from'fs';import {join}from'path';import {homedir}from'os';var R=process.env.DEVFLOW_SERVER_URL||"http://127.0.0.1:13337",O=process.env.DEVFLOW_API_KEY||"dev-key-000000",p=process.env.CLAUDE_PROJECT_DIR||process.cwd(),u=join(homedir(),".devflow","session-id"),d=join(homedir(),".devflow","event-map.json");function m(r,n){return new Promise(e=>{let o=JSON.stringify(n),t=new URL(r,R),s=request({hostname:t.hostname,port:t.port,path:t.pathname,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":O,"Content-Length":Buffer.byteLength(o)},timeout:5e3},()=>e());s.on("error",()=>e()),s.write(o),s.end();})}function P(){try{if(existsSync(u))return readFileSync(u,"utf-8").trim()}catch{}return null}function L(r){try{if(!existsSync(d))return null;let n=JSON.parse(readFileSync(d,"utf-8")),e=n.findIndex(t=>t.toolName===r);if(e===-1)return null;let o=n[e];return n.splice(e,1),writeFileSync(d,JSON.stringify(n)),{eventId:o.eventId,timestamp:o.timestamp}}catch{return null}}async function N(r){if(!r)return;let n;try{n=JSON.parse(r);}catch{return}let e=n.tool_name||"",o=n.tool_input||{},t=n.tool_response||{},s=P(),c=L(e);if(c&&s){let i=typeof t=="string"?t:JSON.stringify(t),I=i.length>5e3?{_truncated:true,_originalSize:i.length,text:i.slice(0,5e3)}:t,S=Date.now()-c.timestamp;m("/api/telemetry/tool-call/output",{eventId:c.eventId,sessionId:s,output:I,duration:S,completedAt:Date.now()}).catch(()=>{});}let v=typeof o=="object"&&o.command?o.command:"",l=typeof t=="object"&&t!==null?t:null,a=l?.exitCode,_=l?.stderr;if(e==="Bash"&&a!==void 0&&a!==0){let i={id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:s??`session:${p.split("/").pop()||"default"}`,tool:e,command:v||e,exitCode:a,stderr:_??null,durationMs:0,createdAt:Date.now()};m(`/api/memory/events?rootPath=${encodeURIComponent(p)}`,i).catch(()=>{});}}(process.argv[1]?.endsWith("post-tool-use")||process.argv[1]?.endsWith("post-tool-use.js"))&&N(process.argv[2]||"").catch(()=>process.exit(0));
|
|
2
|
+
export{N as handlePostToolUse};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {existsSync,readFileSync,mkdirSync,writeFileSync
|
|
2
|
-
export{
|
|
1
|
+
import {existsSync,readdirSync,readFileSync,unlinkSync,mkdirSync,writeFileSync}from'fs';import {join}from'path';import {homedir}from'os';import {request}from'http';var I=1e4,q=3e4,W=300*1e3;function m(o,t,e){return new Promise(n=>{try{let r=new URL(o),i=request({hostname:r.hostname,port:r.port||80,path:r.pathname+r.search,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":e,"Content-Length":Buffer.byteLength(t)},timeout:5e3},s=>{let c=[];s.on("data",a=>c.push(a)),s.on("end",()=>{let a=Buffer.concat(c).toString();n(s.statusCode!=null&&s.statusCode>=200&&s.statusCode<300?a:null);});});i.on("error",()=>n(null)),i.on("timeout",()=>{i.destroy(),n(null);}),i.write(t),i.end();}catch{n(null);}})}var f=class{constructor(t){this.retryScheduled=false;this.retryAttempts=0;this.apiUrl=t?.apiUrl??process.env.DEVFLOW_API_URL??"http://127.0.0.1:13337",this.apiKey=t?.apiKey??process.env.DEVFLOW_API_KEY??"dev-key-000000",this.cacheDir=t?.cacheDir??join(homedir(),".devflow","telemetry-cache");}async sendEvent(t){let e=this.truncateInput(t.input),n={...t,input:e},r=`${this.apiUrl}/api/telemetry/tool-call`,i=await m(r,JSON.stringify(n),this.apiKey);if(i)try{let s=JSON.parse(i),c=s.data?.eventId??s.eventId??null;if(c)return c}catch{}return this.cacheEvent({type:"tool_call",payload:n}),null}async sendExecutionStart(t,e,n,r){let i={executionId:t,sessionId:e,skillName:n,startedAt:r},s=`${this.apiUrl}/api/telemetry/skill-execution/start`;await m(s,JSON.stringify(i),this.apiKey)||this.cacheEvent({type:"execution_start",payload:i});}async sendSessionStart(t,e,n){let r={id:t,projectRoot:e,startedAt:n,label:e.split("/").pop()??"unknown"},i=`${this.apiUrl}/api/telemetry/sessions`;return await m(i,JSON.stringify(r),this.apiKey)!==null}async flushCache(){if(!existsSync(this.cacheDir))return;let t=readdirSync(this.cacheDir).filter(e=>e.endsWith(".json"));for(let e of t)try{let n=join(this.cacheDir,e),r=readFileSync(n,"utf8"),i=JSON.parse(r),s=i.type==="execution_start"?"/api/telemetry/skill-execution/start":"/api/telemetry/tool-call",c=`${this.apiUrl}${s}`;await m(c,JSON.stringify(i.payload),this.apiKey)&&unlinkSync(n);}catch{}}cacheEvent(t){try{existsSync(this.cacheDir)||mkdirSync(this.cacheDir,{recursive:!0});let e=join(this.cacheDir,`${Date.now()}_${Math.random().toString(36).slice(2,11)}.json`);writeFileSync(e,JSON.stringify(t,null,2)),this.scheduleRetry();}catch{}}scheduleRetry(){if(this.retryScheduled)return;this.retryScheduled=true;let t=Math.min(q*Math.pow(2,this.retryAttempts),W);setTimeout(()=>{this.retryScheduled=false,this.flushCache().then(()=>{this.retryAttempts=0;}).catch(()=>{this.retryAttempts++;});},t).unref();}truncateInput(t){let e=JSON.stringify(t);return e.length<=I?t:{_truncated:true,_original_size:e.length,_preview:e.substring(0,I)+"..."}}};var V=1800*1e3;function X(){return process.env.DEVFLOW_STATE_DIR??join(homedir(),".devflow")}var g=class{constructor(t){this.stateDir=X();}detect(){let t=join(this.stateDir,"current-skill.json");if(!existsSync(t))return null;try{let e=readFileSync(t,"utf8"),n=JSON.parse(e);return !n.registeredAt||Date.now()-n.registeredAt>V?(this.endExecution(),null):n}catch{return null}}startExecution(t,e){existsSync(this.stateDir)||mkdirSync(this.stateDir,{recursive:true});let n=this.getCurrentExecutionId();if(n)return n;let r=`exec_${Date.now()}_${Math.random().toString(36).slice(2,11)}`;return writeFileSync(join(this.stateDir,"current-execution-id"),r),writeFileSync(join(this.stateDir,"current-skill.json"),JSON.stringify({name:t,required_mcp_tools:e?.required_mcp_tools??[],registeredAt:Date.now()})),r}getCurrentExecutionId(){let t=join(this.stateDir,"current-execution-id");if(!existsSync(t))return null;try{return readFileSync(t,"utf8").trim()}catch{return null}}endExecution(){let t=join(this.stateDir,"current-skill.json"),e=join(this.stateDir,"current-execution-id");try{existsSync(t)&&unlinkSync(t);}catch{}try{existsSync(e)&&unlinkSync(e);}catch{}}};function d(){return {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow"}}}function G(o){return {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:o}}}var h=join(homedir(),".devflow");function A(){existsSync(h)||mkdirSync(h,{recursive:true});}function Z(){try{let o=join(h,"session-id");if(existsSync(o))return readFileSync(o,"utf-8").trim()}catch{}return null}function Q(o){A(),writeFileSync(join(h,"session-id"),o);}function tt(o,t,e){A();let n=join(h,"event-map.json"),r=[];try{existsSync(n)&&(r=JSON.parse(readFileSync(n,"utf-8")));}catch{}r.push({toolName:o,eventId:t,timestamp:e}),writeFileSync(n,JSON.stringify(r));}function et(o){switch(o){case "Read":case "Glob":return "file_read";case "Write":case "Edit":case "NotebookEdit":return "file_write";case "Bash":return "bash_command";case "Agent":return "subagent";case "Skill":return "skill_invoke";default:return "tool_use"}}async function nt(o){try{if(!o||o.trim()==="")return d();let t=JSON.parse(o),e=process.env.CLAUDE_PROJECT_DIR||process.cwd(),n=e.split("/").pop()||"unknown",r=new f,i=Z();i||(i=`session:${n}:${Date.now().toString(36)}`,Q(i),r.sendSessionStart(i,e,Date.now()).catch(()=>{}));let s=new g;if(t.tool_name==="Skill"){let l=t.tool_input?.skill;if(l&&l.startsWith("devflow:")){let C=s.startExecution(l);r.sendExecutionStart(C,i,l,Date.now()).catch(()=>{});}}let c=s.detect(),a=t.tool_name.startsWith("mcp__devflow__"),M=a?t.tool_name.replace("mcp__devflow__",""):void 0,w=c?.required_mcp_tools??[],_=w.length>0,D=_&&!a,S;D?S=G(`Skill "${c?.name||"unknown"}" requires MCP tools. Use one of: ${w.join(", ")}`):S=d();let R=s.getCurrentExecutionId()??i,E={eventId:`evt_${Date.now()}_${Math.random().toString(36).slice(2,11)}`,executionId:R,sessionId:i,timestamp:Date.now(),toolName:t.tool_name,toolType:a?"mcp":t.tool_name==="Agent"?"subagent":"direct",isMcpTool:a,mcpToolName:M,mcpEnforced:a&&_,mcpFallback:!a&&_,kind:et(t.tool_name),input:t.tool_input,duration:0,blocked:D};return r.sendEvent(E).then(l=>{l&&tt(t.tool_name,l,E.timestamp);}).catch(()=>{}),S}catch{return d()}}if(process.argv[1]?.endsWith("pre-tool-use")||process.argv[1]?.endsWith("pre-tool-use.js")){let o="";process.stdin.setEncoding("utf8"),process.stdin.on("data",t=>{o+=t;}),process.stdin.on("end",async()=>{let t=await nt(o);console.log(JSON.stringify(t));}),process.stdin.on("error",()=>{console.log(JSON.stringify(d())),process.exit(0);}),setTimeout(()=>{console.log(JSON.stringify(d())),process.exit(0);},4e3).unref();}
|
|
2
|
+
export{nt as handlePreToolUse};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import {get,request}from'http';import {existsSync,readFileSync,unlinkSync}from'fs';import {join}from'path';import {homedir}from'os';var I=process.env.DEVFLOW_SERVER_URL||"http://127.0.0.1:13337",x=process.env.DEVFLOW_API_KEY||"dev-key-000000",D=process.env.CLAUDE_PROJECT_DIR||process.cwd();function b(t){return new Promise(r=>{let e=new URL(t,I);get(e.toString(),{headers:{"X-API-Key":x},timeout:5e3},n=>{let c=[];n.on("data",g=>c.push(g)),n.on("end",()=>{try{r(JSON.parse(Buffer.concat(c).toString()));}catch{r(null);}});}).on("error",()=>r(null));})}function d(t,r){return new Promise(e=>{let s=JSON.stringify(r),n=new URL(t,I),c=request({hostname:n.hostname,port:n.port,path:n.pathname,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":x,"Content-Length":Buffer.byteLength(s)},timeout:5e3},()=>e());c.on("error",()=>e()),c.write(s),c.end();})}var p=join(homedir(),".devflow"),E=join(p,"session-id"),T=join(p,"current-execution-id"),M=join(p,"current-skill.json"),O=join(p,"event-map.json");function A(){for(let t of [E,T,M,O])try{existsSync(t)&&unlinkSync(t);}catch{}}async function F(){let t=(()=>{try{if(existsSync(E))return readFileSync(E,"utf-8").trim()}catch{}return null})();if(t){let e=(await b(`/api/telemetry/sessions/${t}/events`))?.data||[];e.length;e.filter(o=>o.isMcpTool).length;e.filter(o=>o.toolType==="subagent").length;let u=e.map(o=>o.timestamp).filter(Boolean);u.length>=2?Math.max(...u)-Math.min(...u):0;if(existsSync(T)){let o="";try{o=readFileSync(T,"utf-8").trim();}catch{}if(o){let l=e.filter(a=>a.executionId===o),m=l.length,h=l.filter(a=>a.isMcpTool).length,S=m-h,R=l.filter(a=>a.toolType==="subagent").length,f=l.map(a=>a.timestamp).filter(Boolean),_=f.length>=2?Math.max(...f)-Math.min(...f):0;try{await d("/api/telemetry/skill-execution/complete",{executionId:o,finishedAt:Date.now(),status:"completed",summary:{totalToolCalls:m,mcpToolCalls:h,directToolCalls:S,subagentCount:R,totalDuration:_,mcpComplianceRate:m>0?Math.round(h/m*1e4)/100:0}});}catch{}}}await d(`/api/telemetry/sessions/${t}/close`,{finishedAt:Date.now()});}d(`/api/memory/process?rootPath=${encodeURIComponent(D)}`,{}).catch(()=>{}),A();}(process.argv[1]?.endsWith("stop")||process.argv[1]?.endsWith("stop.js"))&&F().catch(()=>process.exit(0));
|
|
2
|
+
export{F as handleStop};
|
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 pe=Object.defineProperty;var h=(t,e)=>()=>(t&&(e=t(t=0)),e);var F=(t,e)=>{for(var o in e)pe(t,o,{get:e[o],enumerable:true});};var L={};F(L,{createPluginHandlers:()=>fe,createToolHandlers:()=>me,getCoreTools:()=>j,getPluginTools:()=>C});function j(){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 me(t){return {get_project_context:async({query:e,mode:o,expandedTerms:r})=>{let n=await t.context.buildTaskContext(e,{mode:o??"fast"});return {taskType:n.taskType,requiredFiles:n.requiredFiles,optionalFiles:n.optionalFiles,keySymbols:n.keySymbols,graphSummary:n.graphSummary,riskHints:n.riskHints,nextActions:n.nextActions,reasoning:n.reasoning,confidence:n.confidence,tokenCount:n.tokenCount,_devflow_unique:{search_method:"bm25_semantic",task_oriented:true,risk_aware:true,memory_injected:true,knowledge_injected:true,token_estimated:true,required_vs_optional:true}}},search_symbol:async({symbol:e})=>({...await t.indexer.findSymbol(e),_devflow_unique:{index_backed:true,kind_annotated:true}}),get_dependency_graph:async({target:e,depth:o})=>{let r=e??"all",n=o??2;return {...r==="all"?t.graph.export():t.graph.getSubGraph(r,n),_devflow_unique:{layer_annotated:true,architecture_grouped:true,query_depth:n}}},run_workflow:async({type:e,input:o})=>({...await t.workflow.run(e,{input:o}),_devflow_unique:{dag_orchestrated:true,step_tracked:true,workflow_type:e}}),get_memory:async()=>({...await t.memory.getAll(),_devflow_unique:{memory_version:1,structured_storage:true,project_context_included:true}}),get_knowledge:async({query:e,scope:o})=>({...await t.knowledge.search(e,{sources:o==="all"?void 0:[o]}),_devflow_unique:{source_versioned:true,code_examples_included:true,search_scope:o}}),devflow_report_event:async e=>{let o=(d,m)=>!d||d.length<=m?{value:d??"",truncated:false}:{value:d.slice(0,m),truncated:true},r=o(e.prompt,500),n=o(e.response,500),s=o(e.stdout,1e3),a=o(e.stderr,500),i=r.truncated||n.truncated||s.truncated||a.truncated,u={id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,runId:e.runId,stepId:e.stepId,kind:e.kind,timestamp:Date.now(),duration:e.duration,data:{model:e.model,prompt:r.value,response:n.value,inputTokens:e.inputTokens,outputTokens:e.outputTokens,toolName:e.toolName,toolInput:e.toolInput,toolOutput:e.toolOutput,filePath:e.filePath,command:e.command,exitCode:e.exitCode,stdout:s.value,stderr:a.value,mcpToolName:e.mcpToolName,errorMessage:e.errorMessage,errorStack:e.errorStack,memoryKey:e.memoryKey,userMessage:e.userMessage},metadata:{source:"manual"},...i&&{metadata:{truncated:true,source:"manual"}}};return await t.telemetry.recordEvent(u),{acknowledged:true,eventId:u.id}}}}function C(t){let e=[];for(let o of t){let r=o.meta.name;for(let s of o.tools??[])e.push({name:s.name,description:s.description,inputSchema:s.inputSchema});let n=new Set(e.map(s=>s.name));for(let s of o.workflow?.templates??[]){let a=s.triggers?.find(u=>u.type==="mcp");if(!a?.tool)continue;let i=`${r}_${a.tool}`;n.has(i)||e.push({name:i,description:s.description,inputSchema:{type:"object",properties:s.steps.filter(u=>u.inputSchema).reduce((u,d)=>({...u,...d.inputSchema??{}}),{}),required:[]}});}}return e}function fe(t,e){let o={};for(let r of e){let n=r.meta.name;for(let s of r.tools??[])s.handler&&(o[s.name]=s.handler);for(let s of r.workflow?.templates??[]){let a=s.triggers?.find(u=>u.type==="mcp");if(!a?.tool)continue;let i=`${n}_${a.tool}`;o[i]||(o[i]=async u=>{let d=await t.workflow.run(s.name,u),m="";try{let l={id:d.runId??`run:${Date.now()}`,source:"mcp",tool:i,workflow:s.name,input:u,status:"running",startedAt:Date.now(),finishedAt:null,steps:[],metadata:{}};m=t.workflow.renderPlan(l,s);}catch{}return {...d,plan:m,_devflow_unique:{dag_orchestrated:true,step_tracked:true,plugin_name:n,template_name:s.name}}});}}return o}var M=h(()=>{});var T,A=h(()=>{T=[{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 J(t){let e=await t.ruleGetAll();return [...T,...e]}function ge(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=W.get(r);if((!s||n>s.resetAt)&&(s={count:0,resetAt:n+6e4},W.set(r,s)),s.count++,s.count>o.maxCallsPerMinute)return t.action}return "allow"}function K(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=ge(r,e);if(n!=="allow")return {decision:n,rule:r}}return {decision:"allow"}}var W,U=h(()=>{A();W=new Map;});function x(t){let e=JSON.stringify(t,Object.keys(t).sort());return createHash("sha256").update(e).digest("hex")}async function q(t,e,o,r,n,s){let a=await t.auditGetSecret(),i=await t.auditGetAll(),u=i.length>0?i[i.length-1].signature:createHash("sha256").update("genesis").digest("hex"),d=Date.now(),m=i.length+1,l=`${m}|${d}|${e}|${o}|${r}|${n??""}|${s}|${u}`,f=createHmac("sha256",a).update(l).digest("hex");await t.auditAppend({seq:m,ts:d,tool:e,argsHash:o,decision:r,ruleId:n,sessionId:s,prevHash:u,signature:f});}async function G(t){let e=await t.auditGetSecret(),o=await t.auditGetAll(),r=createHash("sha256").update("genesis").digest("hex");for(let n of o){if(n.prevHash!==r)return {valid:false,brokenAt:n.seq};let s=`${n.seq}|${n.ts}|${n.tool}|${n.argsHash}|${n.decision}|${n.ruleId??""}|${n.sessionId}|${r}`,a=createHmac("sha256",e).update(s).digest("hex");if(n.signature!==a)return {valid:false,brokenAt:n.seq};r=n.signature;}return {valid:true,brokenAt:null}}async function V(t){let e=await t.auditGetSecret(),o=await t.auditGetAll(),r=createHash("sha256").update("genesis").digest("hex");for(let n of o){let s=`${n.seq}|${n.ts}|${n.tool}|${n.argsHash}|${n.decision}|${n.ruleId??""}|${n.sessionId}|${r}`,a=createHmac("sha256",e).update(s).digest("hex");await t.sqlExecute("UPDATE devflow_audit_chain SET prev_hash = ?, signature = ? WHERE seq = ?",[r,a,n.seq]),r=a;}}var O=h(()=>{});function S(t,e,o){let r=Date.now(),n=r+we,s=createHash("sha256").update(JSON.stringify(e)).digest("hex"),a=`${t}|${r}|${n}|${s}`,i=createHmac("sha256",o).update(a).digest("hex");return {tool:t,ts:r,exp:n,queryHash:s,hmac:i}}function X(t,e,o,r){if(Date.now()>t.exp)return false;let n=createHash("sha256").update(JSON.stringify(o)).digest("hex");if(t.queryHash!==n)return false;let s=`${e}|${t.ts}|${t.exp}|${n}`,a=createHmac("sha256",r).update(s).digest("hex");return t.hmac===a}function Y(t){return Date.now()>t.exp}var we,H=h(()=>{we=3e4;});var Z={};F(Z,{CONSTITUTIONAL_RULES:()=>T,enforce:()=>ye,hashArgs:()=>x,isReceiptExpired:()=>Y,issueReceipt:()=>S,parseJwtPayload:()=>Q,rebuildAuditChain:()=>V,verifyAuditChain:()=>G,verifyReceipt:()=>X});function Q(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 ye(t,e,o){if(!e._devflow_token){let l=process.env.DEVFLOW_SESSION_TOKEN;if(l){let f=Q(l);f&&(e={...e,_devflow_token:f});}}let r=e._devflow_token?.sub??"anon",n={toolName:t,args:e,sessionId:r,tokenPayload:e._devflow_token};if(n.tokenPayload){let l=Math.floor(Date.now()/1e3);if(n.tokenPayload.exp&&l>n.tokenPayload.exp){let f=x(e);return await q(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 J(o),{decision:a,rule:i}=K(s,n),u=x(e);if(await q(o,t,u,a,i?.id??null,r),a==="deny"&&i)return {result:{allowed:false,rule:i,message:i.message}};if(a==="warn"&&i){let l=await o.auditGetSecret(),f=S(t,e,l);return {result:{allowed:true,warning:i.message,rule:i},receipt:f}}let d=await o.auditGetSecret(),m=S(t,e,d);return {result:{allowed:true},receipt:m}}var ee=h(()=>{U();O();H();O();H();A();});M();async function se(t){Ee(t.projectRoot);let e=new Server({name:"devflow-mcp",version:"0.1.0"},{capabilities:{tools:{}}}),o=process.env.DEVFLOW_SERVER_URL??"http://127.0.0.1:13337",r=process.env.DEVFLOW_API_KEY??"dev-key-000000",n=new DevFlowApiClient({baseUrl:o,projectRoot:t.projectRoot,apiKey:r}),s=await n.ping(),a=await loadPlugins(),i=Array.from(a.values()),u=j(),d=C(i),m=[...u,...d];e.setRequestHandler(ListToolsRequestSchema,async()=>({tools:m}));let l=null;e.setRequestHandler(CallToolRequestSchema,async ie=>{let{name:c,arguments:ce}=ie.params,w=ce??{},E=Date.now();try{let p;if(s){p=await Ce(n,c,w),ne(t.projectRoot,c);let y=Date.now()-E,g=c.split("_")[0];try{await n.recordTelemetryEvent({toolName:c,args:w,durationMs:y,success:!0,pluginName:g,metadata:{projectRoot:t.projectRoot}});}catch(_){console.error("[devflow-mcp] Failed to record telemetry:",_);}try{await n.recordMemoryEvent({id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:`session:${t.projectRoot.split("/").pop()??"default"}`,tool:c,command:R(c)||c,exitCode:0,durationMs:y});}catch(_){console.error("[devflow-mcp] Failed to record memory event:",_);}}else {if(!l){let[{createEngines:b}]=await Promise.all([import('@devflow-tools/context-engine')]);l=await b(t.projectRoot);for(let P of i)for(let k of P.workflow?.templates??[])l.workflow.register(k);console.error(`[devflow-mcp] Warning: DevFlow server not reachable at ${o}`),console.error("[devflow-mcp] Running in local mode.");}let{enforce:y}=await Promise.resolve().then(()=>(ee(),Z)),g=await y(c,w,l.data);if(!g.result.allowed)return {content:[{type:"text",text:JSON.stringify({_devflow:{v:1,tool:c,ts:Date.now(),marker:"devflow-mcp-v1"},error:g.result.message,rule:g.result.rule?.id})}],isError:!0};let{createToolHandlers:_,createPluginHandlers:le}=await Promise.resolve().then(()=>(M(),L)),ue=_(l),de=le(l,i),N={...ue,...de}[c];if(!N)throw new Error(`Unknown tool: ${c}`);p=await N(w),ne(t.projectRoot,c);let D=Date.now()-E;try{await l.data.recordToolCall(c,w,D);let b=c.startsWith("devflow_")||c.includes("_"),P=c.split("_")[0],k=ae.has(P);await l.telemetry.recordToolCall({eventId:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,executionId:`exec:${t.projectRoot.split("/").pop()??"default"}:${Date.now()}`,timestamp:Date.now(),toolName:c,toolType:b||k?"mcp":"direct",isMcpTool:b||k,mcpToolName:k?c:void 0,mcpEnforced:!0,mcpFallback:!1,input:w,output:De(p),tokensUsed:0,duration:D,blocked:!1});}catch{}try{await l.memory.recordEvent({id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:`session:${t.projectRoot.split("/").pop()??"default"}`,tool:c,command:R(c)||c,exitCode:0,stderr:void 0,durationMs:D,createdAt:Date.now()}),l.memory.processSessionEvents().catch(()=>{});}catch{}g.receipt&&(p={...p,_receipt:g.receipt}),g.result.warning&&(p={...p,_warning:g.result.warning});}let v=Pe(c,p);return {content:[{type:"text",text:JSON.stringify(v,null,2)}]}}catch(p){let v=Date.now()-E;if(s){try{await n.recordTelemetryEvent({toolName:c,args:w,durationMs:v,success:!1,error:p.message,pluginName:c.split("_")[0],metadata:{projectRoot:t.projectRoot}});}catch(y){console.error("[devflow-mcp] Failed to record error telemetry:",y);}try{await n.recordMemoryEvent({id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:`session:${t.projectRoot.split("/").pop()??"default"}`,tool:c,command:R(c)||c,exitCode:1,stderr:p.message,durationMs:v});}catch(y){console.error("[devflow-mcp] Failed to record error memory event:",y);}}else if(l){try{await l.data.recordToolCall(c,w,v,p.message);}catch{}try{await l.memory.recordEvent({id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:`session:${t.projectRoot.split("/").pop()??"default"}`,tool:c,command:R(c)||c,exitCode:1,stderr:p.message,durationMs:v,createdAt:Date.now()});}catch{}}return {content:[{type:"text",text:`Error: ${p.message}`}],isError:true}}});let f=new StdioServerTransport;await e.connect(f);}function Ee(t){if(process.env.DEVFLOW_SESSION_TOKEN)return;let e=Buffer.from(JSON.stringify({alg:"HS256",typ:"JWT"})).toString("base64url"),o=Math.floor(Date.now()/1e3),r={sub:`devflow-mcp-${Date.now().toString(36)}`,project:t.split("/").pop()??"unknown",iat:o,exp:o+86400,scope:["context","knowledge","memory","workflow","graph"]},n=Buffer.from(JSON.stringify(r)).toString("base64url"),a=createHmac("sha256","devflow-local-mcp-secret-v1").update(`${e}.${n}`).digest("base64url");process.env.DEVFLOW_SESSION_TOKEN=`${e}.${n}.${a}`,console.error("[devflow-mcp] Auto-generated session token (no env token provided).");}var ae=new Set(["react","vue","nest","nextjs","graphql","docker","tailwind","taro","electron","performance"]);function R(t){let e={get_project_context:"context",search_symbol:"context",get_dependency_graph:"graph",get_knowledge:"knowledge",get_memory:"memory",run_workflow:"workflow"};if(e[t])return `devflow:${e[t]}`;let o=t.split("_")[0];return ae.has(o)?`devflow:${o}`:""}function ne(t,e){try{let o=process.env.TMPDIR||"/tmp",r=join(o,".devflow-receipts"),n=createHash("sha256").update(t).digest("hex").slice(0,16),s=join(r,`${n}.json`);existsSync(r)||mkdirSync(r,{recursive:!0});let a={};if(existsSync(s))try{a=JSON.parse(readFileSync(s,"utf-8"));}catch{}a.lastMcpCall=Date.now(),a.bypassCount=0;let i=R(e);i&&(a.activeCommand=i),writeFileSync(s,JSON.stringify(a));}catch{}}function De(t){if(t&&typeof t=="object"&&!Array.isArray(t)){let{_devflow:e,_receipt:o,_warning:r,...n}=t;return Object.keys(n).length>0?n:t}return t}function Pe(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 a=s.triggers?.find(i=>i.type==="mcp");if(a?.tool){let i=`${n}_${a.tool}`;t.set(i,s.name);}}}return t}async function Ce(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 Me(){let t=process.env.DEVFLOW_PROJECT_ROOT||process.cwd();await se({mode:"stdio",projectRoot:t});}Me().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 fe=Object.defineProperty;var y=(t,e)=>()=>(t&&(e=t(t=0)),e);var W=(t,e)=>{for(var o in e)fe(t,o,{get:e[o],enumerable:true});};var J={};W(J,{createPluginHandlers:()=>we,createToolHandlers:()=>ge,getCoreTools:()=>M,getPluginTools:()=>A});function M(){return [{name:"get_project_context",description:"\u83B7\u53D6\u4E0E\u7F16\u7801\u4EFB\u52A1\u6700\u76F8\u5173\u7684\u6700\u5C0F\u4E0A\u4E0B\u6587",inputSchema:{type:"object",properties:{query:{type:"string",description:"\u81EA\u7136\u8BED\u8A00\u67E5\u8BE2"},mode:{type:"string",enum:["fast","deep"],default:"fast"},expandedTerms:{type:"string",description:"Agent \u9884\u7FFB\u8BD1\u7684\u82F1\u6587\u5173\u952E\u8BCD\uFF08\u7A7A\u683C\u5206\u9694\uFF09\uFF0C\u7528\u4E8E\u63D0\u5347\u4E2D\u6587\u67E5\u8BE2\u7684\u641C\u7D22\u6548\u679C"}},required:["query"]}},{name:"search_symbol",description:"\u6309\u7B26\u53F7\u540D\u641C\u7D22\u4EE3\u7801\u2014\u2014\u8BED\u4E49\u7EA7\u4EE3\u7801\u7ED3\u6784\u641C\u7D22",inputSchema:{type:"object",properties:{symbol:{type:"string",description:"\u7B26\u53F7\u540D\u79F0"}},required:["symbol"]}},{name:"get_dependency_graph",description:"\u83B7\u53D6\u6587\u4EF6/\u7EC4\u4EF6\u7684\u4F9D\u8D56\u5173\u7CFB",inputSchema:{type:"object",properties:{target:{type:"string",default:"all"},depth:{type:"number",default:2}}}},{name:"run_workflow",description:"\u6267\u884C\u6807\u51C6\u5316\u5F00\u53D1\u5DE5\u4F5C\u6D41",inputSchema:{type:"object",properties:{type:{type:"string",enum:["bugfix","feature","review"]},input:{type:"string"}},required:["type"]}},{name:"get_memory",description:"\u83B7\u53D6\u9879\u76EE\u8BB0\u5FC6\uFF1A\u6280\u672F\u6808\u3001\u7EA6\u5B9A\u3001\u504F\u597D\u3001\u5386\u53F2\u51B3\u7B56",inputSchema:{type:"object",properties:{}}},{name:"get_knowledge",description:"\u67E5\u8BE2\u6280\u672F\u6587\u6863\u77E5\u8BC6\u5E93",inputSchema:{type:"object",properties:{query:{type:"string"},scope:{type:"string",enum:["react","vue","nest","all"],default:"all"}},required:["query"]}},{name:"devflow_report_event",description:"Report fine-grained events within workflow steps (LLM calls, tool usage, file read/write etc.). Optional, for more granular observability.",inputSchema:{type:"object",properties:{runId:{type:"string"},stepId:{type:"string"},kind:{type:"string",enum:["llm_call","tool_use","memory_read","memory_write","file_read","file_write","bash_command","mcp_tool_call","error","user_input"]},duration:{type:"number"},model:{type:"string"},prompt:{type:"string"},response:{type:"string"},inputTokens:{type:"number"},outputTokens:{type:"number"},toolName:{type:"string"},toolInput:{type:"string"},toolOutput:{type:"string"},filePath:{type:"string"},command:{type:"string"},exitCode:{type:"number"},stdout:{type:"string"},stderr:{type:"string"},mcpToolName:{type:"string"},errorMessage:{type:"string"},errorStack:{type:"string"},memoryKey:{type:"string"},userMessage:{type:"string"}},required:["runId","stepId","kind"]}}]}function ge(t){return {get_project_context:async({query:e,mode:o,expandedTerms:r})=>{let n=await t.context.buildTaskContext(e,{mode:o??"fast"});return {taskType:n.taskType,requiredFiles:n.requiredFiles,optionalFiles:n.optionalFiles,keySymbols:n.keySymbols,graphSummary:n.graphSummary,riskHints:n.riskHints,nextActions:n.nextActions,reasoning:n.reasoning,confidence:n.confidence,tokenCount:n.tokenCount,_devflow_unique:{search_method:"bm25_semantic",task_oriented:true,risk_aware:true,memory_injected:true,knowledge_injected:true,token_estimated:true,required_vs_optional:true}}},search_symbol:async({symbol:e})=>({...await t.indexer.findSymbol(e),_devflow_unique:{index_backed:true,kind_annotated:true}}),get_dependency_graph:async({target:e,depth:o})=>{let r=e??"all",n=o??2;return {...r==="all"?t.graph.export():t.graph.getSubGraph(r,n),_devflow_unique:{layer_annotated:true,architecture_grouped:true,query_depth:n}}},run_workflow:async({type:e,input:o})=>({...await t.workflow.run(e,{input:o}),_devflow_unique:{dag_orchestrated:true,step_tracked:true,workflow_type:e}}),get_memory:async()=>({...await t.memory.getAll(),_devflow_unique:{memory_version:1,structured_storage:true,project_context_included:true}}),get_knowledge:async({query:e,scope:o})=>({...await t.knowledge.search(e,{sources:o==="all"?void 0:[o]}),_devflow_unique:{source_versioned:true,code_examples_included:true,search_scope:o}}),devflow_report_event:async e=>{let o=(d,m)=>!d||d.length<=m?{value:d??"",truncated:false}:{value:d.slice(0,m),truncated:true},r=o(e.prompt,500),n=o(e.response,500),s=o(e.stdout,1e3),a=o(e.stderr,500),i=r.truncated||n.truncated||s.truncated||a.truncated,u={id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,runId:e.runId,stepId:e.stepId,kind:e.kind,timestamp:Date.now(),duration:e.duration,data:{model:e.model,prompt:r.value,response:n.value,inputTokens:e.inputTokens,outputTokens:e.outputTokens,toolName:e.toolName,toolInput:e.toolInput,toolOutput:e.toolOutput,filePath:e.filePath,command:e.command,exitCode:e.exitCode,stdout:s.value,stderr:a.value,mcpToolName:e.mcpToolName,errorMessage:e.errorMessage,errorStack:e.errorStack,memoryKey:e.memoryKey,userMessage:e.userMessage},metadata:{source:"manual"},...i&&{metadata:{truncated:true,source:"manual"}}};return await t.telemetry.recordEvent(u),{acknowledged:true,eventId:u.id}}}}function A(t){let e=[];for(let o of t){let r=o.meta.name;for(let s of o.tools??[])e.push({name:s.name,description:s.description,inputSchema:s.inputSchema});let n=new Set(e.map(s=>s.name));for(let s of o.workflow?.templates??[]){let a=s.triggers?.find(u=>u.type==="mcp");if(!a?.tool)continue;let i=`${r}_${a.tool}`;n.has(i)||e.push({name:i,description:s.description,inputSchema:{type:"object",properties:s.steps.filter(u=>u.inputSchema).reduce((u,d)=>({...u,...d.inputSchema??{}}),{}),required:[]}});}}return e}function we(t,e){let o={};for(let r of e){let n=r.meta.name;for(let s of r.tools??[])s.handler&&(o[s.name]=s.handler);for(let s of r.workflow?.templates??[]){let a=s.triggers?.find(u=>u.type==="mcp");if(!a?.tool)continue;let i=`${n}_${a.tool}`;o[i]||(o[i]=async u=>{let d=await t.workflow.run(s.name,u),m="";try{let l={id:d.runId??`run:${Date.now()}`,source:"mcp",tool:i,workflow:s.name,input:u,status:"running",startedAt:Date.now(),finishedAt:null,steps:[],metadata:{}};m=t.workflow.renderPlan(l,s);}catch{}return {...d,plan:m,_devflow_unique:{dag_orchestrated:true,step_tracked:true,plugin_name:n,template_name:s.name}}});}}return o}var I=y(()=>{});var $,q=y(()=>{$=[{id:"C001",name:"\u5FC5\u987B\u643A\u5E26 Session Token",level:"constitutional",condition:{requireFields:["_devflow_token"]},action:"deny",message:"\u7F3A\u5C11 Session Token\u3002\u8BF7\u901A\u8FC7 /devflow: \u547D\u4EE4\u542F\u52A8\u4F1A\u8BDD\uFF0C\u6216\u8FD0\u884C devflow session token \u83B7\u53D6\u4EE4\u724C\u3002"},{id:"C002",name:"Token \u5DF2\u8FC7\u671F",level:"constitutional",condition:{},action:"deny",message:"Session Token \u5DF2\u8FC7\u671F\uFF08\u8D85\u8FC7 1 \u5C0F\u65F6\uFF09\u3002\u8BF7\u91CD\u65B0\u8FD0\u884C devflow session token \u83B7\u53D6\u65B0\u4EE4\u724C\u3002"},{id:"C003",name:"\u901F\u7387\u9650\u5236",level:"constitutional",condition:{maxCallsPerMinute:60},action:"warn",message:"\u8C03\u7528\u9891\u7387\u8FC7\u9AD8\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"}];});async function U(t){let e=await t.ruleGetAll();return [...$,...e]}function ye(t,e){let o=t.condition;if(o.tools&&!o.tools.includes("*")&&!o.tools.includes(e.toolName))return "allow";if(o.requireFields){for(let r of o.requireFields)if(!(r in e.args))return t.action}if(o.forbidPatterns){for(let r of o.forbidPatterns)for(let n of Object.values(e.args))if(typeof n=="string"&&new RegExp(r).test(n))return t.action}if(o.paramPatterns)for(let[r,n]of Object.entries(o.paramPatterns)){let s=String(e.args[r]??"");if(new RegExp(n).test(s))return t.action}if(o.maxCallsPerMinute){let r=`${e.toolName}:${e.sessionId??"anon"}`,n=Date.now(),s=K.get(r);if((!s||n>s.resetAt)&&(s={count:0,resetAt:n+6e4},K.set(r,s)),s.count++,s.count>o.maxCallsPerMinute)return t.action}return "allow"}function G(t,e){let o=[...t].sort((r,n)=>{let s={constitutional:0,project:1,session:2};return s[r.level]-s[n.level]});for(let r of o){let n=ye(r,e);if(n!=="allow")return {decision:n,rule:r}}return {decision:"allow"}}var K,V=y(()=>{q();K=new Map;});function x(t){let e=JSON.stringify(t,Object.keys(t).sort());return createHash("sha256").update(e).digest("hex")}async function H(t,e,o,r,n,s){let a=await t.auditGetSecret(),i=await t.auditGetAll(),u=i.length>0?i[i.length-1].signature:createHash("sha256").update("genesis").digest("hex"),d=Date.now(),m=i.length+1,l=`${m}|${d}|${e}|${o}|${r}|${n??""}|${s}|${u}`,f=createHmac("sha256",a).update(l).digest("hex");await t.auditAppend({seq:m,ts:d,tool:e,argsHash:o,decision:r,ruleId:n,sessionId:s,prevHash:u,signature:f});}async function B(t){let e=await t.auditGetSecret(),o=await t.auditGetAll(),r=createHash("sha256").update("genesis").digest("hex");for(let n of o){if(n.prevHash!==r)return {valid:false,brokenAt:n.seq};let s=`${n.seq}|${n.ts}|${n.tool}|${n.argsHash}|${n.decision}|${n.ruleId??""}|${n.sessionId}|${r}`,a=createHmac("sha256",e).update(s).digest("hex");if(n.signature!==a)return {valid:false,brokenAt:n.seq};r=n.signature;}return {valid:true,brokenAt:null}}async function z(t){let e=await t.auditGetSecret(),o=await t.auditGetAll(),r=createHash("sha256").update("genesis").digest("hex");for(let n of o){let s=`${n.seq}|${n.ts}|${n.tool}|${n.argsHash}|${n.decision}|${n.ruleId??""}|${n.sessionId}|${r}`,a=createHmac("sha256",e).update(s).digest("hex");await t.sqlExecute("UPDATE devflow_audit_chain SET prev_hash = ?, signature = ? WHERE seq = ?",[r,a,n.seq]),r=a;}}var N=y(()=>{});function S(t,e,o){let r=Date.now(),n=r+ve,s=createHash("sha256").update(JSON.stringify(e)).digest("hex"),a=`${t}|${r}|${n}|${s}`,i=createHmac("sha256",o).update(a).digest("hex");return {tool:t,ts:r,exp:n,queryHash:s,hmac:i}}function Q(t,e,o,r){if(Date.now()>t.exp)return false;let n=createHash("sha256").update(JSON.stringify(o)).digest("hex");if(t.queryHash!==n)return false;let s=`${e}|${t.ts}|${t.exp}|${n}`,a=createHmac("sha256",r).update(s).digest("hex");return t.hmac===a}function Z(t){return Date.now()>t.exp}var ve,F=y(()=>{ve=3e4;});var te={};W(te,{CONSTITUTIONAL_RULES:()=>$,enforce:()=>he,hashArgs:()=>x,isReceiptExpired:()=>Z,issueReceipt:()=>S,parseJwtPayload:()=>ee,rebuildAuditChain:()=>z,verifyAuditChain:()=>B,verifyReceipt:()=>Q});function ee(t){try{let e=t.split(".");if(e.length!==3)return null;let o=e[1],r=Buffer.from(o,"base64url").toString("utf-8");return JSON.parse(r)}catch{return null}}async function he(t,e,o){if(!e._devflow_token){let l=process.env.DEVFLOW_SESSION_TOKEN;if(l){let f=ee(l);f&&(e={...e,_devflow_token:f});}}let r=e._devflow_token?.sub??"anon",n={toolName:t,args:e,sessionId:r,tokenPayload:e._devflow_token};if(n.tokenPayload){let l=Math.floor(Date.now()/1e3);if(n.tokenPayload.exp&&l>n.tokenPayload.exp){let f=x(e);return await H(o,t,f,"deny","C002",r),{result:{allowed:false,message:"Session Token \u5DF2\u8FC7\u671F\uFF08\u8D85\u8FC7 1 \u5C0F\u65F6\uFF09\u3002\u8BF7\u91CD\u65B0\u8FD0\u884C devflow session token \u83B7\u53D6\u65B0\u4EE4\u724C\u3002"}}}}let s=await U(o),{decision:a,rule:i}=G(s,n),u=x(e);if(await H(o,t,u,a,i?.id??null,r),a==="deny"&&i)return {result:{allowed:false,rule:i,message:i.message}};if(a==="warn"&&i){let l=await o.auditGetSecret(),f=S(t,e,l);return {result:{allowed:true,warning:i.message,rule:i},receipt:f}}let d=await o.auditGetSecret(),m=S(t,e,d);return {result:{allowed:true},receipt:m}}var oe=y(()=>{V();N();F();N();F();q();});I();async function ie(t){Pe(t.projectRoot);let e=new Server({name:"devflow-mcp",version:"0.1.0"},{capabilities:{tools:{}}}),o=process.env.DEVFLOW_SERVER_URL??"http://127.0.0.1:13337",r=process.env.DEVFLOW_API_KEY??"dev-key-000000",n=new DevFlowApiClient({baseUrl:o,projectRoot:t.projectRoot,apiKey:r}),s=await n.ping(),a=await loadPlugins(),i=Array.from(a.values()),u=M(),d=A(i),m=[...u,...d];e.setRequestHandler(ListToolsRequestSchema,async()=>({tools:m}));let l=null,f=new Set(u.map(D=>D.name));e.setRequestHandler(CallToolRequestSchema,async D=>{let{name:c,arguments:ue}=D.params,w=ue??{},P=Date.now();try{let p;if(f.has(c)&&s){p=await Ae(n,c,w),se(t.projectRoot,c);let b=Date.now()-P,g=c.split("_")[0];try{await n.recordTelemetryEvent({toolName:c,args:w,durationMs:b,success:!0,pluginName:g,metadata:{projectRoot:t.projectRoot}});}catch(_){console.error("[devflow-mcp] Failed to record telemetry:",_);}try{await n.recordMemoryEvent({id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:`session:${t.projectRoot.split("/").pop()??"default"}`,tool:c,command:R(c)||c,exitCode:0,durationMs:b});}catch(_){console.error("[devflow-mcp] Failed to record memory event:",_);}}else {if(!l){let[{createEngines:T}]=await Promise.all([import('@devflow-tools/context-engine')]);l=await T(t.projectRoot);for(let C of i)for(let k of C.workflow?.templates??[])l.workflow.register(k);console.error(`[devflow-mcp] Warning: DevFlow server not reachable at ${o}`),console.error("[devflow-mcp] Running in local mode.");}let{enforce:b}=await Promise.resolve().then(()=>(oe(),te)),g=await b(c,w,l.data);if(!g.result.allowed)return {content:[{type:"text",text:JSON.stringify({_devflow:{v:1,tool:c,ts:Date.now(),marker:"devflow-mcp-v1"},error:g.result.message,rule:g.result.rule?.id})}],isError:!0};let{createToolHandlers:_,createPluginHandlers:de}=await Promise.resolve().then(()=>(I(),J)),pe=_(l),me=de(l,i),L={...pe,...me}[c];if(!L)throw new Error(`Unknown tool: ${c}`);p=await L(w),se(t.projectRoot,c);let j=Date.now()-P;try{await l.data.recordToolCall(c,w,j);let T=c.startsWith("devflow_")||c.includes("_"),C=c.split("_")[0],k=ce.has(C);await l.telemetry.recordToolCall({eventId:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,executionId:`exec:${t.projectRoot.split("/").pop()??"default"}:${Date.now()}`,timestamp:Date.now(),toolName:c,toolType:T||k?"mcp":"direct",isMcpTool:T||k,mcpToolName:k?c:void 0,mcpEnforced:!0,mcpFallback:!1,input:w,output:je(p),tokensUsed:0,duration:j,blocked:!1});}catch{}try{await l.memory.recordEvent({id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:`session:${t.projectRoot.split("/").pop()??"default"}`,tool:c,command:R(c)||c,exitCode:0,stderr:void 0,durationMs:j,createdAt:Date.now()}),l.memory.processSessionEvents().catch(()=>{});}catch{}g.receipt&&(p={...p,_receipt:g.receipt}),g.result.warning&&(p={...p,_warning:g.result.warning});}let h=Ce(c,p);return {content:[{type:"text",text:JSON.stringify(h,null,2)}]}}catch(p){let v=Date.now()-P;if(s){try{await n.recordTelemetryEvent({toolName:c,args:w,durationMs:v,success:!1,error:p.message,pluginName:c.split("_")[0],metadata:{projectRoot:t.projectRoot}});}catch(h){console.error("[devflow-mcp] Failed to record error telemetry:",h);}try{await n.recordMemoryEvent({id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:`session:${t.projectRoot.split("/").pop()??"default"}`,tool:c,command:R(c)||c,exitCode:1,stderr:p.message,durationMs:v});}catch(h){console.error("[devflow-mcp] Failed to record error memory event:",h);}}else if(l){try{await l.data.recordToolCall(c,w,v,p.message);}catch{}try{await l.memory.recordEvent({id:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:`session:${t.projectRoot.split("/").pop()??"default"}`,tool:c,command:R(c)||c,exitCode:1,stderr:p.message,durationMs:v,createdAt:Date.now()});}catch{}}return {content:[{type:"text",text:`Error: ${p.message}`}],isError:true}}});let le=new StdioServerTransport;await e.connect(le);}function Pe(t){if(process.env.DEVFLOW_SESSION_TOKEN)return;let e=Buffer.from(JSON.stringify({alg:"HS256",typ:"JWT"})).toString("base64url"),o=Math.floor(Date.now()/1e3),r={sub:`devflow-mcp-${Date.now().toString(36)}`,project:t.split("/").pop()??"unknown",iat:o,exp:o+86400,scope:["context","knowledge","memory","workflow","graph"]},n=Buffer.from(JSON.stringify(r)).toString("base64url"),a=createHmac("sha256","devflow-local-mcp-secret-v1").update(`${e}.${n}`).digest("base64url");process.env.DEVFLOW_SESSION_TOKEN=`${e}.${n}.${a}`,console.error("[devflow-mcp] Auto-generated session token (no env token provided).");}var ce=new Set(["react","vue","nest","nextjs","graphql","docker","tailwind","taro","electron","performance"]);function R(t){let e={get_project_context:"context",search_symbol:"context",get_dependency_graph:"graph",get_knowledge:"knowledge",get_memory:"memory",run_workflow:"workflow"};if(e[t])return `devflow:${e[t]}`;let o=t.split("_")[0];return ce.has(o)?`devflow:${o}`:""}function se(t,e){try{let o=process.env.TMPDIR||"/tmp",r=join(o,".devflow-receipts"),n=createHash("sha256").update(t).digest("hex").slice(0,16),s=join(r,`${n}.json`);existsSync(r)||mkdirSync(r,{recursive:!0});let a={};if(existsSync(s))try{a=JSON.parse(readFileSync(s,"utf-8"));}catch{}a.lastMcpCall=Date.now(),a.bypassCount=0;let i=R(e);i&&(a.activeCommand=i),writeFileSync(s,JSON.stringify(a));}catch{}}function je(t){if(t&&typeof t=="object"&&!Array.isArray(t)){let{_devflow:e,_receipt:o,_warning:r,...n}=t;return Object.keys(n).length>0?n:t}return t}function Ce(t,e){let o={_devflow:{v:1,tool:t,ts:Date.now(),marker:"devflow-mcp-v1"}};return e&&typeof e=="object"&&!Array.isArray(e)?{...e,...o}:{result:e,...o}}async function Me(){let t=new Map,e=await loadPlugins(),o=Array.from(e.values());for(let r of o){let n=r.meta.name;for(let s of r.workflow?.templates??[]){let a=s.triggers?.find(i=>i.type==="mcp");if(a?.tool){let i=`${n}_${a.tool}`;t.set(i,s.name);}}}return t}async function Ae(t,e,o){switch(e){case "get_project_context":return t.buildContext(o.query,o.mode??"fast");case "search_symbol":return t.searchSymbol(o.symbol);case "get_dependency_graph":return t.getGraph(o.target??"all",o.depth??2);case "run_workflow":return t.runWorkflow(o.type,o.input);case "get_memory":return t.getMemory();case "get_knowledge":return t.searchKnowledge(o.query,o.scope??"all");case "devflow_report_event":return t.recordEvent(o);default:{let n=(await Me()).get(e)??e;return t.runWorkflow(n,o)}}}async function Ie(){let t=process.env.DEVFLOW_PROJECT_ROOT||process.cwd();await ie({mode:"stdio",projectRoot:t});}Ie().catch(t=>{console.error("MCP Server error:",t),process.exit(1);});
|
package/dist/plugin/hooks.json
CHANGED
|
@@ -1,27 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: devflow:docker
|
|
3
3
|
description: Docker 专家 — 镜像优化、Compose 编排、安全扫描、多阶段构建
|
|
4
|
-
required_mcp_tools:
|
|
5
|
-
- docker_dockerize_project
|
|
6
4
|
---
|
|
7
|
-
## MANDATORY FIRST STEP - Skill Registration
|
|
8
|
-
|
|
9
|
-
> **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
mkdir -p ~/.devflow && echo '{"name":"devflow:docker","required_mcp_tools":["docker_dockerize_project"],"description":"devflow:docker skill","registeredAt":'"$(date +%s)000"'}' > ~/.devflow/current-skill.json
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
After registration, you **MUST** use ONLY these MCP tools for all work in this skill:
|
|
16
|
-
- `mcp__devflow__docker_dockerize_project`
|
|
17
|
-
|
|
18
|
-
**Never use direct tools** (Read, Write, Edit, Bash, Grep, etc.) for tasks that can be handled by the MCP tools above.
|
|
19
|
-
|
|
20
|
-
When the skill execution is complete, clean up:
|
|
21
|
-
```bash
|
|
22
|
-
rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
|
|
23
|
-
```
|
|
24
|
-
|
|
25
5
|
|
|
26
6
|
# 🐳 DOCKER
|
|
27
7
|
|
|
@@ -1,27 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: devflow:electron
|
|
3
3
|
description: Electron 专家 — IPC 通信、窗口管理、原生模块、自动更新、安全配置
|
|
4
|
-
required_mcp_tools:
|
|
5
|
-
- electron_diagnose_bug
|
|
6
4
|
---
|
|
7
|
-
## MANDATORY FIRST STEP - Skill Registration
|
|
8
|
-
|
|
9
|
-
> **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
mkdir -p ~/.devflow && echo '{"name":"devflow:electron","required_mcp_tools":["electron_diagnose_bug"],"description":"devflow:electron skill","registeredAt":'"$(date +%s)000"'}' > ~/.devflow/current-skill.json
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
After registration, you **MUST** use ONLY these MCP tools for all work in this skill:
|
|
16
|
-
- `mcp__devflow__electron_diagnose_bug`
|
|
17
|
-
|
|
18
|
-
**Never use direct tools** (Read, Write, Edit, Bash, Grep, etc.) for tasks that can be handled by the MCP tools above.
|
|
19
|
-
|
|
20
|
-
When the skill execution is complete, clean up:
|
|
21
|
-
```bash
|
|
22
|
-
rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
|
|
23
|
-
```
|
|
24
|
-
|
|
25
5
|
|
|
26
6
|
# ⚛️ ELECTRON
|
|
27
7
|
|
|
@@ -1,29 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: devflow:graphql
|
|
3
3
|
description: GraphQL 专家 — Schema 设计、N+1 检测、Resolver 优化、安全审计
|
|
4
|
-
required_mcp_tools:
|
|
5
|
-
- graphql_new_graphql_type
|
|
6
|
-
- graphql_diagnose_bug
|
|
7
4
|
---
|
|
8
|
-
## MANDATORY FIRST STEP - Skill Registration
|
|
9
|
-
|
|
10
|
-
> **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
mkdir -p ~/.devflow && echo '{"name":"devflow:graphql","required_mcp_tools":["graphql_new_graphql_type","graphql_diagnose_bug"],"description":"devflow:graphql skill","registeredAt":'"$(date +%s)000"'}' > ~/.devflow/current-skill.json
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
After registration, you **MUST** use ONLY these MCP tools for all work in this skill:
|
|
17
|
-
- `mcp__devflow__graphql_new_graphql_type`
|
|
18
|
-
- `mcp__devflow__graphql_diagnose_bug`
|
|
19
|
-
|
|
20
|
-
**Never use direct tools** (Read, Write, Edit, Bash, Grep, etc.) for tasks that can be handled by the MCP tools above.
|
|
21
|
-
|
|
22
|
-
When the skill execution is complete, clean up:
|
|
23
|
-
```bash
|
|
24
|
-
rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
|
|
25
|
-
```
|
|
26
|
-
|
|
27
5
|
|
|
28
6
|
# ◈ GRAPHQL
|
|
29
7
|
|
|
@@ -1,29 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: devflow:nest
|
|
3
3
|
description: NestJS 专家 — 模块架构、守卫调试、微服务配置、Swagger 生成
|
|
4
|
-
required_mcp_tools:
|
|
5
|
-
- nest_new_module
|
|
6
|
-
- nest_diagnose_bug
|
|
7
4
|
---
|
|
8
|
-
## MANDATORY FIRST STEP - Skill Registration
|
|
9
|
-
|
|
10
|
-
> **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
mkdir -p ~/.devflow && echo '{"name":"devflow:nest","required_mcp_tools":["nest_new_module","nest_diagnose_bug"],"description":"devflow:nest skill","registeredAt":'"$(date +%s)000"'}' > ~/.devflow/current-skill.json
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
After registration, you **MUST** use ONLY these MCP tools for all work in this skill:
|
|
17
|
-
- `mcp__devflow__nest_new_module`
|
|
18
|
-
- `mcp__devflow__nest_diagnose_bug`
|
|
19
|
-
|
|
20
|
-
**Never use direct tools** (Read, Write, Edit, Bash, Grep, etc.) for tasks that can be handled by the MCP tools above.
|
|
21
|
-
|
|
22
|
-
When the skill execution is complete, clean up:
|
|
23
|
-
```bash
|
|
24
|
-
rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
|
|
25
|
-
```
|
|
26
|
-
|
|
27
5
|
|
|
28
6
|
# 🐱 NEST
|
|
29
7
|
|
|
@@ -1,29 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: devflow:nextjs
|
|
3
3
|
description: Next.js 专家 — App Router、SSR/SSG/ISR、Server Components、Middleware、部署
|
|
4
|
-
required_mcp_tools:
|
|
5
|
-
- nextjs_new_page
|
|
6
|
-
- nextjs_diagnose_bug
|
|
7
4
|
---
|
|
8
|
-
## MANDATORY FIRST STEP - Skill Registration
|
|
9
|
-
|
|
10
|
-
> **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
mkdir -p ~/.devflow && echo '{"name":"devflow:nextjs","required_mcp_tools":["nextjs_new_page","nextjs_diagnose_bug"],"description":"devflow:nextjs skill","registeredAt":'"$(date +%s)000"'}' > ~/.devflow/current-skill.json
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
After registration, you **MUST** use ONLY these MCP tools for all work in this skill:
|
|
17
|
-
- `mcp__devflow__nextjs_new_page`
|
|
18
|
-
- `mcp__devflow__nextjs_diagnose_bug`
|
|
19
|
-
|
|
20
|
-
**Never use direct tools** (Read, Write, Edit, Bash, Grep, etc.) for tasks that can be handled by the MCP tools above.
|
|
21
|
-
|
|
22
|
-
When the skill execution is complete, clean up:
|
|
23
|
-
```bash
|
|
24
|
-
rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
|
|
25
|
-
```
|
|
26
|
-
|
|
27
5
|
|
|
28
6
|
# ▲ NEXTJS
|
|
29
7
|
|
|
@@ -1,27 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: devflow:performance
|
|
3
3
|
description: Web 性能专家 — Core Web Vitals、Bundle 优化、加载策略、渲染性能
|
|
4
|
-
required_mcp_tools:
|
|
5
|
-
- performance_audit_performance
|
|
6
4
|
---
|
|
7
|
-
## MANDATORY FIRST STEP - Skill Registration
|
|
8
|
-
|
|
9
|
-
> **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
mkdir -p ~/.devflow && echo '{"name":"devflow:performance","required_mcp_tools":["performance_audit_performance"],"description":"devflow:performance skill","registeredAt":'"$(date +%s)000"'}' > ~/.devflow/current-skill.json
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
After registration, you **MUST** use ONLY these MCP tools for all work in this skill:
|
|
16
|
-
- `mcp__devflow__performance_audit_performance`
|
|
17
|
-
|
|
18
|
-
**Never use direct tools** (Read, Write, Edit, Bash, Grep, etc.) for tasks that can be handled by the MCP tools above.
|
|
19
|
-
|
|
20
|
-
When the skill execution is complete, clean up:
|
|
21
|
-
```bash
|
|
22
|
-
rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
|
|
23
|
-
```
|
|
24
|
-
|
|
25
5
|
|
|
26
6
|
# ⚡ PERFORMANCE
|
|
27
7
|
|
|
@@ -1,37 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: devflow:react
|
|
3
3
|
description: React 18 专家能力 — Bug 诊断、组件重构、性能优化、Hooks 审查
|
|
4
|
-
required_mcp_tools:
|
|
5
|
-
- react_diagnose_bug
|
|
6
|
-
- react_new_feature
|
|
7
|
-
- react_audit_performance
|
|
8
|
-
- react_review_hooks
|
|
9
|
-
- react_refactor_component
|
|
10
|
-
- react_new_component
|
|
11
4
|
---
|
|
12
|
-
## MANDATORY FIRST STEP - Skill Registration
|
|
13
|
-
|
|
14
|
-
> **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
mkdir -p ~/.devflow && echo '{"name":"devflow:react","required_mcp_tools":["react_diagnose_bug","react_new_feature","react_audit_performance","react_review_hooks","react_refactor_component","react_new_component"],"description":"devflow:react skill","registeredAt":'"$(date +%s)000"'}' > ~/.devflow/current-skill.json
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
After registration, you **MUST** use ONLY these MCP tools for all work in this skill:
|
|
21
|
-
- `mcp__devflow__react_diagnose_bug`
|
|
22
|
-
- `mcp__devflow__react_new_feature`
|
|
23
|
-
- `mcp__devflow__react_audit_performance`
|
|
24
|
-
- `mcp__devflow__react_review_hooks`
|
|
25
|
-
- `mcp__devflow__react_refactor_component`
|
|
26
|
-
- `mcp__devflow__react_new_component`
|
|
27
|
-
|
|
28
|
-
**Never use direct tools** (Read, Write, Edit, Bash, Grep, etc.) for tasks that can be handled by the MCP tools above.
|
|
29
|
-
|
|
30
|
-
When the skill execution is complete, clean up:
|
|
31
|
-
```bash
|
|
32
|
-
rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
|
|
33
|
-
```
|
|
34
|
-
|
|
35
5
|
|
|
36
6
|
# ⚛️ REACT
|
|
37
7
|
|
|
@@ -1,27 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: devflow:tailwind
|
|
3
3
|
description: Tailwind 专家 — 响应式设计、主题定制、Purge 检查、Utility 审查
|
|
4
|
-
required_mcp_tools:
|
|
5
|
-
- tailwind_new_component
|
|
6
4
|
---
|
|
7
|
-
## MANDATORY FIRST STEP - Skill Registration
|
|
8
|
-
|
|
9
|
-
> **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
mkdir -p ~/.devflow && echo '{"name":"devflow:tailwind","required_mcp_tools":["tailwind_new_component"],"description":"devflow:tailwind skill","registeredAt":'"$(date +%s)000"'}' > ~/.devflow/current-skill.json
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
After registration, you **MUST** use ONLY these MCP tools for all work in this skill:
|
|
16
|
-
- `mcp__devflow__tailwind_new_component`
|
|
17
|
-
|
|
18
|
-
**Never use direct tools** (Read, Write, Edit, Bash, Grep, etc.) for tasks that can be handled by the MCP tools above.
|
|
19
|
-
|
|
20
|
-
When the skill execution is complete, clean up:
|
|
21
|
-
```bash
|
|
22
|
-
rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
|
|
23
|
-
```
|
|
24
|
-
|
|
25
5
|
|
|
26
6
|
# 🌊 TAILWIND
|
|
27
7
|
|
|
@@ -1,27 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: devflow:taro
|
|
3
3
|
description: Taro 跨端专家 — 多端适配、小程序调试、性能优化、兼容方案
|
|
4
|
-
required_mcp_tools:
|
|
5
|
-
- taro_new_page
|
|
6
4
|
---
|
|
7
|
-
## MANDATORY FIRST STEP - Skill Registration
|
|
8
|
-
|
|
9
|
-
> **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
mkdir -p ~/.devflow && echo '{"name":"devflow:taro","required_mcp_tools":["taro_new_page"],"description":"devflow:taro skill","registeredAt":'"$(date +%s)000"'}' > ~/.devflow/current-skill.json
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
After registration, you **MUST** use ONLY these MCP tools for all work in this skill:
|
|
16
|
-
- `mcp__devflow__taro_new_page`
|
|
17
|
-
|
|
18
|
-
**Never use direct tools** (Read, Write, Edit, Bash, Grep, etc.) for tasks that can be handled by the MCP tools above.
|
|
19
|
-
|
|
20
|
-
When the skill execution is complete, clean up:
|
|
21
|
-
```bash
|
|
22
|
-
rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
|
|
23
|
-
```
|
|
24
|
-
|
|
25
5
|
|
|
26
6
|
# 🛠️ TARO
|
|
27
7
|
|
|
@@ -1,31 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: devflow:vue
|
|
3
3
|
description: Vue 3 专家 — Bug 诊断、Composition API、响应式调试、组件重构
|
|
4
|
-
required_mcp_tools:
|
|
5
|
-
- vue_diagnose_bug
|
|
6
|
-
- vue_new_component
|
|
7
|
-
- vue_debug_reactivity
|
|
8
4
|
---
|
|
9
|
-
## MANDATORY FIRST STEP - Skill Registration
|
|
10
|
-
|
|
11
|
-
> **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
mkdir -p ~/.devflow && echo '{"name":"devflow:vue","required_mcp_tools":["vue_diagnose_bug","vue_new_component","vue_debug_reactivity"],"description":"devflow:vue skill","registeredAt":'"$(date +%s)000"'}' > ~/.devflow/current-skill.json
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
After registration, you **MUST** use ONLY these MCP tools for all work in this skill:
|
|
18
|
-
- `mcp__devflow__vue_diagnose_bug`
|
|
19
|
-
- `mcp__devflow__vue_new_component`
|
|
20
|
-
- `mcp__devflow__vue_debug_reactivity`
|
|
21
|
-
|
|
22
|
-
**Never use direct tools** (Read, Write, Edit, Bash, Grep, etc.) for tasks that can be handled by the MCP tools above.
|
|
23
|
-
|
|
24
|
-
When the skill execution is complete, clean up:
|
|
25
|
-
```bash
|
|
26
|
-
rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
|
|
27
|
-
```
|
|
28
|
-
|
|
29
5
|
|
|
30
6
|
# 💚 VUE
|
|
31
7
|
|
package/dist/server.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import'reflect-metadata';import {Reflector,APP_GUARD,APP_INTERCEPTOR,NestFactory}from'@nestjs/core';import {FastifyAdapter}from'@nestjs/platform-fastify';import {Readable}from'stream';import {Injectable,Inject,Global,Module,Optional,Get,Query,Param,Post,Body,Delete,Controller,Headers,Put,forwardRef,Res,Catch,UnauthorizedException,NotFoundException,BadRequestException,SetMetadata,Logger,HttpException,HttpStatus}from'@nestjs/common';import {existsSync,readFileSync}from'fs';import {join}from'path';import {createEngines}from'@devflow-tools/context-engine';import {TelemetryEngine}from'@devflow-tools/telemetry';import {MemoryEngine,checkOllama,getOllamaInfoMessage}from'@devflow-tools/memory-engine';import {WorkflowEngine}from'@devflow-tools/workflow-engine';import {loadPlugins}from'@devflow-tools/sdk';import {Subject}from'rxjs';import {KnowledgeEngine}from'@devflow-tools/knowledge-engine';import {BenchmarkEngine}from'@devflow-tools/benchmark';import {DevFlowDatabase}from'@devflow-tools/database';import {map}from'rxjs/operators';var xe=Object.defineProperty;var Ee=Object.getOwnPropertyDescriptor;var i=(u,t,e,s)=>{for(var r=s>1?void 0:s?Ee(t,e):t,o=u.length-1,a;o>=0;o--)(a=u[o])&&(r=(s?a(t,e,r):a(r))||r);return s&&r&&xe(t,e,r),r},n=(u,t)=>(e,s)=>t(e,s,u);var Nt="isPublic",Zt=()=>SetMetadata(Nt,true);var Ot={MISSING_API_KEY:"AUTH_MISSING_API_KEY",INVALID_API_KEY:"AUTH_INVALID_API_KEY"};var Ne=(process.env.DEVFLOW_API_KEYS??"dev-key-000000").split(",").map(u=>u.trim()).filter(Boolean),z=class{constructor(t){this.reflector=t;}canActivate(t){if(this.reflector.getAllAndOverride(Nt,[t.getHandler(),t.getClass()]))return true;let r=t.switchToHttp().getRequest().headers["x-api-key"];if(!r)throw new UnauthorizedException({error:{code:Ot.MISSING_API_KEY,message:"X-API-Key header is required",details:{}}});if(!Ne.includes(r))throw new UnauthorizedException({error:{code:Ot.INVALID_API_KEY,message:"Invalid API key",details:{}}});return true}};z=i([Injectable(),n(0,Inject(Reflector))],z);var rt=class{};rt=i([Global(),Module({providers:[z,{provide:APP_GUARD,useClass:z}]})],rt);var m={WORKFLOW_NOT_FOUND:"WORKFLOW_NOT_FOUND",RUN_NOT_FOUND:"RUN_NOT_FOUND",PROJECT_NOT_FOUND:"PROJECT_NOT_FOUND",NODE_NOT_FOUND:"NODE_NOT_FOUND",PLUGIN_NOT_FOUND:"PLUGIN_NOT_FOUND",BAD_REQUEST:"BAD_REQUEST",VALIDATION_ERROR:"VALIDATION_ERROR",INTERNAL_ERROR:"INTERNAL_ERROR"};var h=class{constructor(t){this.database=t;this.projects=new Map;this.activeProjectRoot=process.env.DEVFLOW_PROJECT_ROOT??null;}onModuleInit(){if(!process.env.DEVFLOW_PROJECT_ROOT&&this.database){let t=this.database.getSetting("activeProjectRoot");t&&(this.activeProjectRoot=t);}}setActiveProject(t){this.activeProjectRoot=t,this.database&&this.database.setSetting("activeProjectRoot",t);}disconnectProject(){this.activeProjectRoot=null,this.database&&this.database.deleteSetting("activeProjectRoot");}getActiveProjectRoot(){return this.activeProjectRoot}async list(){return Array.from(this.projects.values())}async getById(t){let e=this.projects.get(t);if(!e)throw new NotFoundException({error:{code:m.PROJECT_NOT_FOUND,message:`Project "${t}" not found`,details:{}}});return e}async create(t){let e=`proj_${Date.now()}_${Math.random().toString(36).slice(2,7)}`,s={id:e,name:t.name,rootPath:t.rootPath,stack:t.stack,createdAt:Date.now()};return this.projects.set(e,s),this.activeProjectRoot||this.setActiveProject(t.rootPath),s}async delete(t){if(!this.projects.has(t))throw new NotFoundException({error:{code:m.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:m.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}}};h=i([Injectable(),n(0,Optional()),n(0,Inject("DATABASE"))],h);var w=class{constructor(t){this.service=t;}async list(){return this.service.list()}async getOnboardingPackByRoot(t){if(!t)throw new BadRequestException({error:{code:m.BAD_REQUEST,message:"rootPath is required",details:{}}});return this.service.getOnboardingPackByRoot(t)}async getById(t){return this.service.getById(t)}async getOnboardingPack(t){let e=await this.service.getById(t);return this.service.getOnboardingPack(e.rootPath)}async create(t){return this.service.create(t)}async connect(t){return this.service.setActiveProject(t.rootPath),{rootPath:t.rootPath}}async switchProject(t){return this.service.setActiveProject(t.rootPath),{rootPath:t.rootPath}}async getActive(){return {rootPath:this.service.getActiveProjectRoot()}}async disconnect(){return this.service.disconnectProject(),{ok:true}}async delete(t){return this.service.delete(t)}};i([Get()],w.prototype,"list",1),i([Get("onboarding-pack"),n(0,Query("rootPath"))],w.prototype,"getOnboardingPackByRoot",1),i([Get(":id"),n(0,Param("id"))],w.prototype,"getById",1),i([Get(":id/onboarding-pack"),n(0,Param("id"))],w.prototype,"getOnboardingPack",1),i([Post(),n(0,Body())],w.prototype,"create",1),i([Post("connect"),n(0,Body())],w.prototype,"connect",1),i([Post("switch"),n(0,Body())],w.prototype,"switchProject",1),i([Get("active")],w.prototype,"getActive",1),i([Delete("active")],w.prototype,"disconnect",1),i([Delete(":id"),n(0,Param("id"))],w.prototype,"delete",1),w=i([Controller("projects"),n(0,Inject(h))],w);var P=class{};P=i([Module({controllers:[w],providers:[h],exports:[h]})],P);var E=class{constructor(t){this.engine=new TelemetryEngine;this.db=t??null;}async recordEvent(t){await this.engine.recordEvent(t);}async listRuns(t,e,s){let r=Array.from(this.engine.runs.values()),o=r;s&&(o=r.filter(c=>c.meta?.source===s));let a=o.slice(e,e+t).map(c=>({id:c.meta?.runId??"",agent:c.meta?.agent??"",mode:c.meta?.mode??"",source:c.meta?.source??"unknown",status:c.status,startedAt:c.startedAt,tokenUsed:c.tokenUsed}));if(this.db)try{let l=this.db.listSkillExecutions(t,0).map(k=>({id:k.executionId,agent:"claude-code",mode:"hook",source:"hook",status:k.status,startedAt:k.startedAt,tokenUsed:k.totalTokens,skillName:k.skillName,totalToolCalls:k.totalToolCalls,mcpToolCalls:k.mcpToolCalls,mcpComplianceRate:k.mcpComplianceRate})),g=new Set;return [...l,...a].filter(k=>g.has(k.id)?!1:(g.add(k.id),!0)).slice(e,e+t)}catch{}return a}async getRun(t){let e=this.engine.runs.get(t);if(e)return e;if(this.db)try{let s=this.db.getSkillExecution(t);if(s)return {meta:{runId:s.executionId,agent:"claude-code",mode:"hook",source:"hook"},status:s.status,startedAt:s.startedAt,finishedAt:s.finishedAt,tokenUsed:s.totalTokens,steps:[],skillName:s.skillName,totalToolCalls:s.totalToolCalls,mcpToolCalls:s.mcpToolCalls,directToolCalls:s.directToolCalls,mcpComplianceRate:s.mcpComplianceRate}}catch{}throw new NotFoundException({error:{code:m.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}})}async getTimeline(t,e){return Array.from(this.engine.runs.values()).filter(r=>!(t&&r.startedAt<Number(t)||e&&r.startedAt>Number(e))).flatMap(r=>r.steps?.map(o=>({runId:r.meta?.runId,stepId:o.stepId,type:o.type,duration:o.duration,timestamp:o.timestamp}))??[])}async getRunEvents(t){let e=await this.engine.listEvents(t);if(e&&e.length>0)return e;if(this.db)try{let s=this.db.listToolCallEvents(t);if(s&&s.length>0)return s.map(r=>({eventId:r.eventId,runId:t,stepId:r.eventId,type:r.isMcpTool?"mcp_tool":r.toolType==="subagent"?"subagent":"tool_use",timestamp:r.timestamp,duration:r.duration,toolName:r.toolName,toolType:r.toolType,isMcpTool:r.isMcpTool,mcpToolName:r.mcpToolName,mcpEnforced:r.mcpEnforced,mcpFallback:r.mcpFallback,tokensUsed:r.tokensUsed,blocked:r.blocked,blockReason:r.blockReason,error:r.error,output:r.output,input:r.input}))}catch{}return e??[]}async getRunStats(t){let e=await this.engine.getRunStats(t);if(e&&e.totalEvents>0)return e;if(this.db)try{let s=this.db.getSkillExecution(t),r=this.db.listToolCallEvents(t);if(s){let o=r?.reduce((a,c)=>a+(c.tokensUsed??0),0)??0;return {totalEvents:r?.length??0,llmCalls:0,totalTokens:s.totalTokens||o,toolUses:s.totalToolCalls,fileReads:0,fileWrites:0,bashCommands:0,errors:r?.filter(a=>a.error).length??0,totalDuration:s.totalDuration,mcpToolCalls:s.mcpToolCalls,directToolCalls:s.directToolCalls,mcpComplianceRate:s.mcpComplianceRate}}}catch{}return e}async endRun(t,e){await this.engine.endRun(t,e);}async getFeedbackStats(t,e){let s=this.collectAllEvents(),r=e!=null?Date.now()-e*24*60*60*1e3:void 0,o=s.filter(y=>!(y.data?.toolName!=="context_feedback"||t&&y.data?.toolInput?.projectRoot!==t||r!=null&&(y.timestamp??0)<r)),a=o.length,c=o.filter(y=>y.data?.toolInput?.feedback==="hit").length,l=o.filter(y=>y.data?.toolInput?.feedback==="partial").length,g=o.filter(y=>y.data?.toolInput?.feedback==="miss").length;return {total:a,hits:c,partials:l,misses:g,hitRate:a>0?c/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 s of t.values())Array.isArray(s)&&e.push(...s);return e}async getStats(t=7){let e=Array.from(this.engine.runs.values()),s=Date.now(),r=s-t*24*60*60*1e3,o=e.filter(p=>p.startedAt>=r),a={};for(let p of o){let b=new Date(p.startedAt).toISOString().slice(0,10);a[b]||(a[b]={runs:0,tokens:0}),a[b].runs++,a[b].tokens+=p.tokenUsed??0;}let c=0,l=0,g=0;for(let p of o){let b=this.engine.events.get(p.meta?.runId)??[];c+=p.tokenUsed??0,l+=b.filter(Q=>Q.kind==="llm_call").length,g+=b.filter(Q=>Q.kind==="tool_use").length;}let y=new Date(r).toISOString().slice(0,10),k=new Date(s).toISOString().slice(0,10);return {period:{from:y,to:k},summary:{totalRuns:o.length,completedRuns:o.filter(p=>p.status==="completed").length,failedRuns:o.filter(p=>p.status==="failed").length,totalTokens:c,totalLlmCalls:l,totalToolUses:g,avgRunDuration:o.length>0?Math.round(o.reduce((p,b)=>p+((b.finishedAt??s)-b.startedAt),0)/o.length):0},byDay:Object.entries(a).map(([p,b])=>({date:p,...b})).sort((p,b)=>p.date.localeCompare(b.date)),byWorkflow:this.buildWorkflowBreakdown(o,s),byPlugin:this.buildPluginBreakdown(o)}}buildWorkflowBreakdown(t,e){let s={};for(let r of t){let o=r.workflowName??r.meta?.workflowName??"unknown";s[o]||(s[o]={runs:0,completed:0,failed:0,avgDuration:0}),s[o].runs++,r.status==="completed"?s[o].completed++:s[o].failed++,s[o].avgDuration+=(r.finishedAt??e)-r.startedAt;}for(let r of Object.keys(s))s[r].avgDuration=s[r].runs>0?Math.round(s[r].avgDuration/s[r].runs):0;return Object.entries(s).map(([r,o])=>({name:r,runs:o.runs,successRate:o.runs>0?o.completed/o.runs:0,avgDuration:o.avgDuration}))}buildPluginBreakdown(t){let e={};for(let s of t){let r=s.pluginName??s.meta?.pluginName??"none";e[r]||(e[r]={runs:0,completed:0,failed:0}),e[r].runs++,s.status==="completed"?e[r].completed++:e[r].failed++;}return Object.entries(e).map(([s,r])=>({name:s,runs:r.runs,successRate:r.runs>0?r.completed/r.runs:0}))}async getOpsRoiSummary(){let t=Array.from(this.engine.runs.values()),e=Date.now(),s=t.length,r=t.filter(x=>x.status==="completed").length,o=s>0?r/s:0,a=t.reduce((x,X)=>x+(X.tokenUsed??0),0),c=s>0?a/s:0,l=t.reduce((x,X)=>{let At=X.startedAt??0,jt=X.finishedAt??e;return x+(jt-At)},0),g=s>0?l/s:0,y=t.filter(x=>x.relevanceFeedback==="hit"||x.meta?.relevanceFeedback==="hit").length,k=t.filter(x=>x.relevanceFeedback!==void 0||x.meta?.relevanceFeedback!==void 0).length,p=await this.getFeedbackStats(),b=y+p.hits,Q=k+p.total,St=Q>0?b/Q:0;return {period:"all-time",totalRuns:s,successfulRuns:r,successRate:o,avgTokenUsage:c,avgDuration:g,feedbackHitRate:St,trend:"stable"}}async getExperimentalRoiSummary(){return {totalScenarios:0,avgTimeSavedRate:null,avgTokenReductionRate:null,avgFirstPassLift:null,avgReworkReductionRate:null,conclusion:"No experimental data available yet"}}async getRoiSummary(t=7){let e=Array.from(this.engine.runs.values()),s=Date.now(),r=s-t*24*60*60*1e3,o=e.filter(d=>d.startedAt>=r),a=o.length,c=o.filter(d=>d.status==="completed").length,l=o.filter(d=>d.status!=="completed").length,g=a>0?Math.round(o.reduce((d,v)=>d+((v.finishedAt??s)-v.startedAt),0)/a):0,y=a>0?Math.round(o.reduce((d,v)=>d+(v.tokenUsed??0),0)/a):0,k=o.filter(d=>d.firstPassSuccess===true||d.meta?.firstPassSuccess===true).length,p=a>0?k/a:0,b=o.filter(d=>d.relevanceFeedback==="hit"||d.meta?.relevanceFeedback==="hit").length,Q=o.filter(d=>d.relevanceFeedback!==void 0||d.meta?.relevanceFeedback!==void 0).length,St=await this.getFeedbackStats(void 0,t),x=b+St.hits,X=Q+St.total,At=X>0?x/X:0,jt=o.reduce((d,v)=>d+(v.retryCount??v.meta?.retryCount??0),0),Pe=a>0?jt/a:0,Se=g,ht={context_insufficient:0,knowledge_missing:0,workflow_design_issue:0,tool_error:0,agent_override:0,unknown:0};for(let d of o)if(d.status!=="completed"){let v=d.meta?.runId;if(v)try{let zt=await this.engine.classifyFailure(v);ht[zt]=(ht[zt]??0)+1;}catch{ht.unknown++;}else ht.unknown++;}let st={};for(let d of o){let v=new Date(d.startedAt).toISOString().slice(0,10);st[v]||(st[v]={runs:0,tokens:0,failures:0}),st[v].runs++,st[v].tokens+=d.tokenUsed??0,d.status!=="completed"&&st[v].failures++;}return {period:{from:new Date(r).toISOString().slice(0,10),to:new Date(s).toISOString().slice(0,10)},overview:{totalRuns:a,completedRuns:c,failedRuns:l,avgDuration:g,avgTokens:y,firstPassSuccessRate:p,feedbackHitRate:At},efficiency:{totalTokensSaved:0,avgTimePerTask:Se,avgRetryCount:Pe},failures:{total:l,breakdown:ht},workflows:this.buildWorkflowBreakdown(o,s),plugins:this.buildPluginBreakdown(o),byDay:Object.entries(st).map(([d,v])=>({date:d,...v})).sort((d,v)=>d.date.localeCompare(v.date))}}async getPluginEffectiveness(t,e){let r=Array.from(this.engine.runs.values()).filter(l=>!((l.pluginName??l.meta?.pluginName)!==t||e&&l.meta?.projectRoot!==e)),o=r.length,a=r.filter(l=>l.status==="completed").length,c=r.map(l=>l.startedAt).filter(l=>typeof l=="number");return {name:t,totalRuns:o,successRate:o>0?a/o:0,lastUsedAt:c.length>0?new Date(Math.max(...c)).toISOString():null}}async getPluginUsageStats(t){let s=Array.from(this.engine.runs.values()).filter(g=>(g.pluginName??g.meta?.pluginName)===t),r=s.length,o=s.filter(g=>g.status==="completed").length,a=new Set;for(let g of s){let y=g.meta?.projectRoot;y&&a.add(y);}let c=s.map(g=>g.startedAt).filter(g=>typeof g=="number"),l=c.length>0?new Date(Math.max(...c)).toISOString():void 0;return {activeProjects:a.size,totalRuns:r,successfulRuns:o,lastUsedAt:l}}async classifyFailure(t){let e=await this.getRun(t).catch(()=>null);if(!e||e.status!=="failed")return {};let s=e.steps?.find(o=>o.status==="failed");if(!s)return {};let r=s.error?.toLowerCase()??"";return r.includes("context")||r.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"}]}:r.includes("knowledge")||r.includes("docs")?{failureCategory:"knowledge_missing",failureReason:"Required knowledge was not available",suggestedActions:[{action:"Sync knowledge source",priority:"high"},{action:"Add docs source",priority:"medium"}]}:r.includes("workflow")||r.includes("step")?{failureCategory:"workflow_design_issue",failureReason:"Workflow design issue detected",suggestedActions:[{action:"Adjust specific step",priority:"high"},{action:"Split workflow",priority:"medium"}]}:r.includes("tool")||r.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,s=Date.now()-t*24*60*60*1e3,r=0;for(let[o,a]of e)a.startedAt&&a.startedAt<s&&(e.delete(o),r++);return r}async recordExecutionStart(t){this.db&&this.db.insertSkillExecution({executionId:t.executionId,skillName:t.skillName,startedAt:t.startedAt,status:"running"});}async recordToolCall(t){if(!this.db)return;this.db.getSkillExecution(t.executionId)||this.db.insertSkillExecution({executionId:t.executionId,skillName:t.mcpToolName??t.toolName,startedAt:t.timestamp,status:"running"}),this.db.insertToolCallEvent({eventId:t.eventId,executionId:t.executionId,timestamp:t.timestamp,toolName:t.toolName,toolType:t.toolType,isMcpTool:t.isMcpTool,mcpToolName:t.mcpToolName,mcpEnforced:t.mcpEnforced,mcpFallback:t.mcpFallback,input:t.input,tokensUsed:t.tokensUsed,duration:t.duration,parentToolCallId:t.parentToolCallId,subagentId:t.subagentId,error:t.error,blocked:t.blocked,blockReason:t.blockReason});}async updateToolCallOutput(t,e){this.db&&this.db.updateToolCallEvent(t,{output:JSON.stringify(e)});}async recordExecutionComplete(t){if(!this.db)return;let e=this.db.listToolCallEvents(t.executionId),s=e.length,r=e.filter(c=>c.isMcpTool).length,o=e.filter(c=>!c.isMcpTool).length,a=e.filter(c=>c.toolType==="subagent").length;this.db.updateSkillExecution(t.executionId,{status:t.status,finishedAt:t.finishedAt,totalDuration:t.summary.totalDuration,totalTokens:t.summary.totalTokens,mcpComplianceRate:s>0?Math.round(r/s*1e4)/100:0,totalToolCalls:s,mcpToolCalls:r,directToolCalls:o,subagentCount:a});}async getExecutions(t,e){return this.db?this.db.listSkillExecutions(t,e):[]}async getExecutionEvents(t){return this.db?this.db.listToolCallEvents(t):[]}async getMcpCompliance(){return this.db?this.db.getMcpCompliance():{overall:0,bySkill:{},missedTools:[]}}};E=i([Injectable(),n(0,Optional()),n(0,Inject("DATABASE"))],E);var O=class{constructor(t,e){this.telemetryService=t;this.database=e;this.projectStats=new Map;this.benchmarkResults=[];}async recordTelemetryEvent(t){let e=`evt_${Date.now()}_${Math.random().toString(36).slice(2,7)}`,s=t.toolName?"tool_use":"step_end",r={id:e,runId:t.metadata?.runId??`event_${Date.now()}_${Math.random().toString(36).slice(2,7)}`,stepId:e,kind:s,timestamp:Date.now(),duration:t.durationMs,data:{toolName:t.toolName,toolInput:t.args,errorMessage:t.error},metadata:{source:"claude-code"}};return await this.telemetryService.recordEvent(r),{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 r={...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,r),r}recordBenchmarkResult(t){this.benchmarkResults.push(t);}getBenchmarkResults(t){return t?this.benchmarkResults.filter(e=>this.projectStats.get(e.scenarioId)?.projectRoot===t):this.benchmarkResults}async getPluginEffectiveness(t){return []}};O=i([Injectable(),n(0,Inject(E)),n(1,Optional()),n(1,Inject("DATABASE"))],O);var U=class{constructor(t){this.dataService=t;this.feedbackEntries=[];}async indexProject(t){let{context:e,codegraph:s}=await createEngines(t);await e.index(t);let r=s.getStats();return {totalFiles:r.fileCount,totalSymbols:r.nodeCount,lastIndexTime:r.lastUpdated,indexing:s.isIndexing()}}async getStatus(t){try{let{codegraph:e}=await createEngines(t),s=e.getStats();return {totalFiles:s.fileCount,totalSymbols:s.nodeCount,lastIndexTime:s.lastUpdated,indexing:e.isIndexing()}}catch{return {totalFiles:0,totalSymbols:0,lastIndexTime:0,indexing:false}}}async buildContext(t,e,s,r){let{context:o}=await createEngines(t);return o.build({query:e,mode:s,maxTokens:r??8e3,includeGraph:s==="deep"})}async buildTaskContext(t,e,s,r){let{context:o}=await createEngines(t);return o.buildTaskContext(e,{mode:s,maxTokens:r??8e3})}async findSymbol(t,e){let{indexer:s}=await createEngines(t);return s.findSymbol(e)}async recordFeedback(t,e,s,r){let o={query:e,feedback:s,timestamp:Date.now(),projectRoot:t};return this.feedbackEntries.push(o),this.dataService&&await this.dataService.recordTelemetryEvent({toolName:"context_feedback",args:{query:e,feedback:s,taskType:r?.taskType,contextMode:r?.contextMode,projectRoot:t},durationMs:0,success:true,metadata:{projectRoot:t,query:e,taskType:r?.taskType}}),o}async getFeedbackSummaries(){let t=this.feedbackEntries.length,e=this.feedbackEntries.filter(o=>o.feedback==="hit").length,s=this.feedbackEntries.filter(o=>o.feedback==="partial").length,r=this.feedbackEntries.filter(o=>o.feedback==="miss").length;return {total:t,hits:e,partials:s,misses:r,hitRate:t>0?e/t:0}}};U=i([Injectable(),n(0,Optional()),n(0,Inject(O))],U);var I=class{constructor(t,e){this.service=t;this.projects=e;}resolveRootPath(t,e){let s=t??e??this.projects.getActiveProjectRoot();if(!s)throw new BadRequestException("rootPath is required \u2014 no active project connected");return s}async status(t,e){let s=t??e??this.projects.getActiveProjectRoot();return s?this.service.getStatus(s):null}async index(t,e){return this.service.indexProject(this.resolveRootPath(t.rootPath,e))}async build(t,e){return this.service.buildContext(this.resolveRootPath(t.rootPath,e),t.query,t.mode??"fast",t.maxTokens)}async buildTask(t,e){return this.service.buildTaskContext(this.resolveRootPath(t.rootPath,e),t.query,t.mode??"fast",t.maxTokens)}async feedback(t,e){return this.service.recordFeedback(this.resolveRootPath(t.rootPath,e),t.query,t.feedback,{taskType:t.taskType,contextMode:t.contextMode,runId:t.runId,tokenCount:t.tokenCount})}async feedbackSummary(){return this.service.getFeedbackSummaries()}async findSymbol(t,e,s){return this.service.findSymbol(this.resolveRootPath(e,s),t)}};i([Get("status"),n(0,Query("rootPath")),n(1,Headers("x-devflow-project"))],I.prototype,"status",1),i([Post("index"),n(0,Body()),n(1,Headers("x-devflow-project"))],I.prototype,"index",1),i([Post("build"),n(0,Body()),n(1,Headers("x-devflow-project"))],I.prototype,"build",1),i([Post("build-task"),n(0,Body()),n(1,Headers("x-devflow-project"))],I.prototype,"buildTask",1),i([Post("feedback"),n(0,Body()),n(1,Headers("x-devflow-project"))],I.prototype,"feedback",1),i([Get("feedback-summary")],I.prototype,"feedbackSummary",1),i([Get("symbol/:name"),n(0,Param("name")),n(1,Query("rootPath")),n(2,Headers("x-devflow-project"))],I.prototype,"findSymbol",1),I=i([Controller("context"),n(0,Inject(U)),n(1,Inject(h))],I);var _=class{constructor(t){this.dataService=t;}async recordTelemetryEvent(t){return {success:true,...await this.dataService.recordTelemetryEvent(t)}}async getProjectStats(t){return this.dataService.getProjectStats(t)}async updateProjectStats(t){return this.dataService.updateProjectStats(t.projectRoot,t.stats)}recordBenchmarkResult(t){return this.dataService.recordBenchmarkResult(t),{success:true}}getBenchmarkResults(t){return this.dataService.getBenchmarkResults(t)}};i([Post("telemetry/event"),n(0,Body())],_.prototype,"recordTelemetryEvent",1),i([Get("project/stats"),n(0,Query("rootPath"))],_.prototype,"getProjectStats",1),i([Post("project/stats"),n(0,Body())],_.prototype,"updateProjectStats",1),i([Post("benchmark/result"),n(0,Body())],_.prototype,"recordBenchmarkResult",1),i([Get("benchmark/results"),n(0,Query("projectRoot"))],_.prototype,"getBenchmarkResults",1),_=i([Controller("data"),n(0,Inject(O))],_);var D=class{constructor(){this.engines=new Map;}getEngine(t){return this.engines.has(t)||this.engines.set(t,new MemoryEngine(t)),this.engines.get(t)}async getAll(t){let e=this.getEngine(t),[s,r]=await Promise.all([e.listMemories(),checkOllama()]);return {memories:s.map(o=>({id:o.id,category:o.category,content:o.content,originalText:o.originalText,source:o.source,status:o.status,confidence:o.confidence,scope:o.scope,createdAt:o.createdAt,approvedAt:o.approvedAt})),ollama:{installed:r.installed,running:r.running,modelAvailable:r.modelAvailable,modelName:r.modelName,infoMessage:getOllamaInfoMessage(r)}}}async add(t,e){return this.getEngine(t).addMemory({category:e.category,content:e.content,source:"manual",confidence:1,scope:e.scope??""})}async update(t,e,s){await this.getEngine(t).updateMemory(e,s);}async delete(t,e){await this.getEngine(t).deleteMemory(e);}async getCandidates(t){return this.getEngine(t).getPendingMemories()}async approveCandidate(t,e){await this.getEngine(t).approveMemory(e);}async rejectCandidate(t,e){await this.getEngine(t).rejectMemory(e);}async search(t,e,s){return (await this.getEngine(t).search(e,s)).map(o=>o.entry)}async extract(t,e){return this.getEngine(t).extractMemories(e)}async getOllamaStatus(){let t=await checkOllama();return {...t,infoMessage:getOllamaInfoMessage(t)}}async updateLegacy(t,e,s,r){e!=="user"&&await this.getEngine(t).addMemory({category:"project_knowledge",content:`${s}: ${JSON.stringify(r)}`,source:"manual",confidence:1,scope:s});}async recordEvent(t,e){let s=this.getEngine(t);return await s.recordEvent({id:e.id,sessionId:e.sessionId,tool:e.tool,command:e.command,exitCode:e.exitCode,stderr:e.stderr,durationMs:e.durationMs,createdAt:Date.now()}),{acknowledged:true,extracted:(await s.extractFromEventsRealtime([{tool:e.tool,command:e.command,exitCode:e.exitCode,stderr:e.stderr}])).length}}async processSessionEvents(t){return this.getEngine(t).processSessionEvents()}};D=i([Injectable()],D);var f=class{constructor(t,e,s){this.service=t;this.memoryService=e;this.projectsService=s;}async listRuns(t,e,s){return this.service.listRuns(Number(t)||20,Number(e)||0,s)}async getRun(t){let e=await this.service.getRun(t),s=await this.service.classifyFailure(t);return {...e,...s}}async getTimeline(t,e){return this.service.getTimeline(t,e)}async getRunEvents(t){return this.service.getRunEvents(t)}async getRunStats(t){return this.service.getRunStats(t)}async completeRun(t){await this.service.endRun(t,{status:"success",tokenUsed:0});let e=await this.service.getRunEvents(t),s=this.projectsService.getActiveProjectRoot(),r=await this.memoryService.extract(s??"",e);return {ok:true,extracted:Array.isArray(r)?r.length:0}}async getStats(t){return this.service.getStats(Number(t)||7)}async getRoiSummary(t){return this.service.getRoiSummary(Number(t)||7)}async cleanup(t){return {ok:true,data:{removedRuns:await this.service.cleanup(t.olderThanDays??30)}}}async startSkillExecution(t){return await this.service.recordExecutionStart(t),{executionId:t.executionId}}async recordToolCall(t){return await this.service.recordToolCall(t),{eventId:t.eventId}}async updateToolCallOutput(t){return await this.service.updateToolCallOutput(t.eventId,t.output),{ok:true}}async completeSkillExecution(t){return await this.service.recordExecutionComplete(t),{}}async getExecutions(t,e){return {data:await this.service.getExecutions(Number(t)||20,e)}}async getExecutionEvents(t){return {data:await this.service.getExecutionEvents(t)}}async getMcpCompliance(){return await this.service.getMcpCompliance()}};i([Get("runs"),n(0,Query("limit")),n(1,Query("offset")),n(2,Query("source"))],f.prototype,"listRuns",1),i([Get("runs/:id"),n(0,Param("id"))],f.prototype,"getRun",1),i([Get("timeline"),n(0,Query("from")),n(1,Query("to"))],f.prototype,"getTimeline",1),i([Get("runs/:runId/events"),n(0,Param("runId"))],f.prototype,"getRunEvents",1),i([Get("runs/:runId/stats"),n(0,Param("runId"))],f.prototype,"getRunStats",1),i([Post("runs/:id/complete"),n(0,Param("id"))],f.prototype,"completeRun",1),i([Get("stats"),n(0,Query("days"))],f.prototype,"getStats",1),i([Get("roi-summary"),n(0,Query("days"))],f.prototype,"getRoiSummary",1),i([Post("cleanup"),n(0,Body())],f.prototype,"cleanup",1),i([Post("skill-execution/start"),n(0,Body())],f.prototype,"startSkillExecution",1),i([Post("tool-call"),n(0,Body())],f.prototype,"recordToolCall",1),i([Post("tool-call/output"),n(0,Body())],f.prototype,"updateToolCallOutput",1),i([Post("skill-execution/complete"),n(0,Body())],f.prototype,"completeSkillExecution",1),i([Get("executions"),n(0,Query("limit")),n(1,Query("skillName"))],f.prototype,"getExecutions",1),i([Get("executions/:id/events"),n(0,Param("id"))],f.prototype,"getExecutionEvents",1),i([Get("mcp-compliance")],f.prototype,"getMcpCompliance",1),f=i([Controller("telemetry"),n(0,Inject(E)),n(1,Inject(D)),n(2,Inject(h))],f);var R=class{constructor(t,e){this.service=t;this.projects=e;}resolveRootPath(t,e){let s=t??e??this.projects.getActiveProjectRoot();if(!s)throw new BadRequestException({error:{code:m.BAD_REQUEST,message:"rootPath is required \u2014 no active project connected",details:{}}});return s}async getAll(t,e){return this.service.getAll(this.resolveRootPath(t,e))}async add(t,e,s){return this.service.add(this.resolveRootPath(t,s),e)}async update(t,e,s,r){return await this.service.update(this.resolveRootPath(t,r),e,s),{ok:true}}async delete(t,e,s){return await this.service.delete(this.resolveRootPath(t,s),e),{ok:true}}async getCandidates(t,e){return this.service.getCandidates(this.resolveRootPath(t,e))}async approve(t,e,s){return await this.service.approveCandidate(this.resolveRootPath(t,s),e),{approved:true}}async reject(t,e,s){return await this.service.rejectCandidate(this.resolveRootPath(t,s),e),{rejected:true}}async search(t,e,s){return this.service.search(this.resolveRootPath(t,s),e.query,{limit:e.limit,categories:e.categories})}async extract(t,e,s){return this.service.extract(this.resolveRootPath(t,s),e.events)}async ollamaStatus(){return this.service.getOllamaStatus()}async updateLegacy(t,e,s,r,o){return await this.service.updateLegacy(this.resolveRootPath(t,o),e,s,r.value),{ok:true}}async recordEvent(t,e,s){return this.service.recordEvent(this.resolveRootPath(t,s),e)}async processEvents(t,e,s){return this.service.processSessionEvents(this.resolveRootPath(t,e))}};i([Get(),n(0,Query("rootPath")),n(1,Headers("x-devflow-project"))],R.prototype,"getAll",1),i([Post(),n(0,Query("rootPath")),n(1,Body()),n(2,Headers("x-devflow-project"))],R.prototype,"add",1),i([Put(":id"),n(0,Query("rootPath")),n(1,Param("id")),n(2,Body()),n(3,Headers("x-devflow-project"))],R.prototype,"update",1),i([Delete(":id"),n(0,Query("rootPath")),n(1,Param("id")),n(2,Headers("x-devflow-project"))],R.prototype,"delete",1),i([Get("candidates"),n(0,Query("rootPath")),n(1,Headers("x-devflow-project"))],R.prototype,"getCandidates",1),i([Post("candidates/:id/approve"),n(0,Query("rootPath")),n(1,Param("id")),n(2,Headers("x-devflow-project"))],R.prototype,"approve",1),i([Post("candidates/:id/reject"),n(0,Query("rootPath")),n(1,Param("id")),n(2,Headers("x-devflow-project"))],R.prototype,"reject",1),i([Post("search"),n(0,Query("rootPath")),n(1,Body()),n(2,Headers("x-devflow-project"))],R.prototype,"search",1),i([Post("extract"),n(0,Query("rootPath")),n(1,Body()),n(2,Headers("x-devflow-project"))],R.prototype,"extract",1),i([Get("ollama/status")],R.prototype,"ollamaStatus",1),i([Put(":layer/:key"),n(0,Query("rootPath")),n(1,Param("layer")),n(2,Param("key")),n(3,Body()),n(4,Headers("x-devflow-project"))],R.prototype,"updateLegacy",1),i([Post("events"),n(0,Query("rootPath")),n(1,Body()),n(2,Headers("x-devflow-project"))],R.prototype,"recordEvent",1),i([Post("process"),n(0,Query("rootPath")),n(1,Headers("x-devflow-project")),n(2,Body())],R.prototype,"processEvents",1),R=i([Controller("memory"),n(0,Inject(D)),n(1,Inject(h))],R);var Y=class{};Y=i([Module({imports:[forwardRef(()=>j),P],controllers:[R],providers:[D],exports:[D]})],Y);var M=class{};M=i([Module({imports:[Y,P],controllers:[f],providers:[E],exports:[E]})],M);var J=class{};J=i([Module({imports:[M],controllers:[_],providers:[O],exports:[O]})],J);var j=class{};j=i([Module({imports:[P,J],controllers:[I],providers:[U],exports:[U]})],j);var L=class{async getFullGraph(t){let{graph:e}=await createEngines(t);return e.export()}async getLayeredGraph(t){let{graph:e}=await createEngines(t);return e.getLayeredGraph()}async getNode(t,e){let{codegraph:s}=await createEngines(t),r=s.getNode(e);if(!r)throw new NotFoundException({error:{code:m.NODE_NOT_FOUND,message:`Node "${e}" not found`,details:{}}});return r}async expandNode(t,e,s,r){let{graph:o}=await createEngines(t),a=o.expand([e],{depth:s,direction:r});return {node:a.nodes.find(c=>c.id===e),subGraph:a}}};L=i([Injectable()],L);var q=class{constructor(t,e){this.service=t;this.projects=e;}resolveRootPath(t,e){let s=t??e??this.projects.getActiveProjectRoot();if(!s)throw new BadRequestException({error:{code:m.BAD_REQUEST,message:"rootPath is required \u2014 no active project connected",details:{}}});return s}async getFullGraph(t,e,s){return e==="layered"?this.service.getLayeredGraph(this.resolveRootPath(t,s)):this.service.getFullGraph(this.resolveRootPath(t,s))}async getNode(t,e,s){return this.service.getNode(this.resolveRootPath(t,s),e)}async expandNode(t,e,s,r,o){return this.service.expandNode(this.resolveRootPath(t,o),e,Number(s)||2,r||"both")}};i([Get(),n(0,Query("rootPath")),n(1,Query("view")),n(2,Headers("x-devflow-project"))],q.prototype,"getFullGraph",1),i([Get(":nodeId"),n(0,Query("rootPath")),n(1,Param("nodeId")),n(2,Headers("x-devflow-project"))],q.prototype,"getNode",1),i([Get(":nodeId/expand"),n(0,Query("rootPath")),n(1,Param("nodeId")),n(2,Query("depth")),n(3,Query("direction")),n(4,Headers("x-devflow-project"))],q.prototype,"expandNode",1),q=i([Controller("graph"),n(0,Inject(L)),n(1,Inject(h))],q);var ct=class{};ct=i([Module({imports:[j,P],controllers:[q],providers:[L],exports:[L]})],ct);var $=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 r of e)for(let o of r.workflow?.templates??[])this.engine.register(o);let s=await this.engine.list();console.log(`[WorkflowService] Loaded ${e.length} plugins with ${s.length} workflows`);}catch(t){console.error("[WorkflowService] Failed to load plugins:",t);}}async list(){return this.engine.list()}async run(t,e){if(!(await this.engine.list()).find(a=>a.name===t))throw new NotFoundException({error:{code:m.WORKFLOW_NOT_FOUND,message:`Workflow "${t}" not found`,details:{}}});let r=`run_${Date.now()}_${Math.random().toString(36).slice(2,7)}`,o=new Subject;return this.events.set(r,o),this.engine.run(t,e).then(a=>{this.engineRunIds.set(r,a.runId);let c=this.engine.getRun(a.runId);if(c){for(let l of c.steps)o.next({runId:r,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"&&o.complete();}a.status==="running"&&this.engine.onEvent(a.runId,l=>{o.next({runId:r,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=>{o.next({runId:r,stepId:"engine",status:"failed",error:a.message,timestamp:Date.now()}),o.complete();}),{runId:r}}async listRuns(t,e){return (await this.engine.listRuns()).map(o=>({runId:Array.from(this.engineRunIds.entries()).find(([,c])=>c===o.runId)?.[0]??o.runId,workflowName:o.type,status:o.status,steps:o.steps.map(c=>({stepId:c.stepId,status:c.status,output:c.output,error:c.error,startedAt:0})),startedAt:o.startedAt,finishedAt:o.finishedAt})).slice(e,e+t)}async getRun(t){let e=this.engineRunIds.get(t)??t,s=this.engine.getRun(e);if(!s)throw new NotFoundException({error:{code:m.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}});return {runId:t,workflowName:s.type,status:s.status,steps:s.steps.map(r=>({stepId:r.stepId,status:r.status,output:r.output,error:r.error})),startedAt:s.startedAt,finishedAt:s.finishedAt}}streamRun(t){let e=this.events.get(t);if(!e)throw new NotFoundException({error:{code:m.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}});return e}async approveRun(t){let e=this.engineRunIds.get(t)??t,s=this.engine.getRun(e);if(!s)throw new NotFoundException({error:{code:m.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}});let r=s.steps.find(o=>o.status==="awaiting_approval");r&&await this.engine.approve(e,r.stepId);}async rejectRun(t,e){let s=this.engineRunIds.get(t)??t,r=this.engine.getRun(s);if(!r)throw new NotFoundException({error:{code:m.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}});let o=r.steps.find(a=>a.status==="awaiting_approval");o&&await this.engine.reject(s,o.stepId,e??"Rejected");}async getNextStep(t){if(!t){(await this.engine.list())[0];return null}let e=this.engineRunIds.get(t)??t,s=this.engine.getRun(e);return s?(Array.isArray(s.steps)?s.steps:[]).find(o=>o.status==="pending")??null:null}};$=i([Injectable()],$);var S=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 r=this.service.streamRun(t).subscribe({next:o=>{e.raw.write(`event: step-${o.status}
|
|
1
|
+
import'reflect-metadata';import {Reflector,APP_GUARD,APP_INTERCEPTOR,NestFactory}from'@nestjs/core';import {FastifyAdapter}from'@nestjs/platform-fastify';import {Readable}from'stream';import {Injectable,Inject,Global,Module,Optional,Get,Query,Param,Post,Body,Delete,Controller,Headers,Put,forwardRef,Res,Catch,UnauthorizedException,NotFoundException,BadRequestException,SetMetadata,Logger,HttpException,HttpStatus}from'@nestjs/common';import {existsSync,readFileSync}from'fs';import {join}from'path';import {createEngines}from'@devflow-tools/context-engine';import {TelemetryEngine}from'@devflow-tools/telemetry';import {MemoryEngine,checkOllama,getOllamaInfoMessage}from'@devflow-tools/memory-engine';import {WorkflowEngine}from'@devflow-tools/workflow-engine';import {clearPluginCache,loadPlugins}from'@devflow-tools/sdk';import {Subject}from'rxjs';import {KnowledgeEngine}from'@devflow-tools/knowledge-engine';import {BenchmarkEngine}from'@devflow-tools/benchmark';import {DevFlowDatabase}from'@devflow-tools/database';import {homedir}from'os';import {map}from'rxjs/operators';var be=Object.defineProperty;var Pe=Object.getOwnPropertyDescriptor;var i=(c,t,e,s)=>{for(var n=s>1?void 0:s?Pe(t,e):t,o=c.length-1,a;o>=0;o--)(a=c[o])&&(n=(s?a(t,e,n):a(n))||n);return s&&n&&be(t,e,n),n},r=(c,t)=>(e,s)=>t(e,s,c);var Et="isPublic",Yt=()=>SetMetadata(Et,true);var xt={MISSING_API_KEY:"AUTH_MISSING_API_KEY",INVALID_API_KEY:"AUTH_INVALID_API_KEY"};var xe=(process.env.DEVFLOW_API_KEYS??"dev-key-000000").split(",").map(c=>c.trim()).filter(Boolean),Y=class{constructor(t){this.reflector=t;}canActivate(t){if(this.reflector.getAllAndOverride(Et,[t.getHandler(),t.getClass()]))return true;let n=t.switchToHttp().getRequest().headers["x-api-key"];if(!n)throw new UnauthorizedException({error:{code:xt.MISSING_API_KEY,message:"X-API-Key header is required",details:{}}});if(!xe.includes(n))throw new UnauthorizedException({error:{code:xt.INVALID_API_KEY,message:"Invalid API key",details:{}}});return true}};Y=i([Injectable(),r(0,Inject(Reflector))],Y);var z=class{};z=i([Global(),Module({providers:[Y,{provide:APP_GUARD,useClass:Y}]})],z);var d={WORKFLOW_NOT_FOUND:"WORKFLOW_NOT_FOUND",RUN_NOT_FOUND:"RUN_NOT_FOUND",PROJECT_NOT_FOUND:"PROJECT_NOT_FOUND",NODE_NOT_FOUND:"NODE_NOT_FOUND",PLUGIN_NOT_FOUND:"PLUGIN_NOT_FOUND",BAD_REQUEST:"BAD_REQUEST",VALIDATION_ERROR:"VALIDATION_ERROR",INTERNAL_ERROR:"INTERNAL_ERROR"};var p=class{constructor(t){this.database=t;this.projects=new Map;this.activeProjectRoot=process.env.DEVFLOW_PROJECT_ROOT??null;}onModuleInit(){if(!process.env.DEVFLOW_PROJECT_ROOT&&this.database){let t=this.database.getSetting("activeProjectRoot");t&&(this.activeProjectRoot=t);}}setActiveProject(t){this.activeProjectRoot=t,this.database&&this.database.setSetting("activeProjectRoot",t);}disconnectProject(){this.activeProjectRoot=null,this.database&&this.database.deleteSetting("activeProjectRoot");}getActiveProjectRoot(){return this.activeProjectRoot}async list(){return Array.from(this.projects.values())}async getById(t){let e=this.projects.get(t);if(!e)throw new NotFoundException({error:{code:d.PROJECT_NOT_FOUND,message:`Project "${t}" not found`,details:{}}});return e}async create(t){let e=`proj_${Date.now()}_${Math.random().toString(36).slice(2,7)}`,s={id:e,name:t.name,rootPath:t.rootPath,stack:t.stack,createdAt:Date.now()};return this.projects.set(e,s),this.activeProjectRoot||this.setActiveProject(t.rootPath),s}async delete(t){if(!this.projects.has(t))throw new NotFoundException({error:{code:d.PROJECT_NOT_FOUND,message:`Project "${t}" not found`,details:{}}});this.projects.delete(t);}async getOnboardingPack(t){let e=join(t,".devflow","onboarding-pack.json");if(!existsSync(e))throw new NotFoundException({error:{code:d.PROJECT_NOT_FOUND,message:"Onboarding pack not found. Run `devflow init` first.",details:{}}});return JSON.parse(readFileSync(e,"utf-8"))}async getOnboardingPackByRoot(t){let e=join(t,".devflow","onboarding-pack.json");try{return existsSync(e)?JSON.parse(readFileSync(e,"utf-8")):null}catch{return null}}};p=i([Injectable(),r(0,Optional()),r(0,Inject("DATABASE"))],p);var h=class{constructor(t){this.service=t;}async list(){return this.service.list()}async getOnboardingPackByRoot(t){if(!t)throw new BadRequestException({error:{code:d.BAD_REQUEST,message:"rootPath is required",details:{}}});return this.service.getOnboardingPackByRoot(t)}async getById(t){return this.service.getById(t)}async getOnboardingPack(t){let e=await this.service.getById(t);return this.service.getOnboardingPack(e.rootPath)}async create(t){return this.service.create(t)}async connect(t){return this.service.setActiveProject(t.rootPath),{rootPath:t.rootPath}}async switchProject(t){return this.service.setActiveProject(t.rootPath),{rootPath:t.rootPath}}async getActive(){return {rootPath:this.service.getActiveProjectRoot()}}async disconnect(){return this.service.disconnectProject(),{ok:true}}async delete(t){return this.service.delete(t)}};i([Get()],h.prototype,"list",1),i([Get("onboarding-pack"),r(0,Query("rootPath"))],h.prototype,"getOnboardingPackByRoot",1),i([Get(":id"),r(0,Param("id"))],h.prototype,"getById",1),i([Get(":id/onboarding-pack"),r(0,Param("id"))],h.prototype,"getOnboardingPack",1),i([Post(),r(0,Body())],h.prototype,"create",1),i([Post("connect"),r(0,Body())],h.prototype,"connect",1),i([Post("switch"),r(0,Body())],h.prototype,"switchProject",1),i([Get("active")],h.prototype,"getActive",1),i([Delete("active")],h.prototype,"disconnect",1),i([Delete(":id"),r(0,Param("id"))],h.prototype,"delete",1),h=i([Controller("projects"),r(0,Inject(p))],h);var v=class{};v=i([Module({controllers:[h],providers:[p],exports:[p]})],v);var P=class{constructor(t){this.engine=new TelemetryEngine;this.db=t??null;}async recordEvent(t){this.db&&this.db.insertEvent?.({runId:t.runId,kind:t.kind,timestamp:t.timestamp,duration:t.duration,toolName:t.data?.toolName,pluginName:t.data?.mcpToolName,metadata:t.data});}async createSession(t){this.db&&this.db.insertSession({id:t.id,projectRoot:t.projectRoot,label:t.label,startedAt:t.startedAt});}async getSession(t){if(!this.db)throw new NotFoundException({error:{code:d.RUN_NOT_FOUND,message:`Session "${t}" not found`,details:{}}});let e=this.db.getSession(t);if(!e)throw new NotFoundException({error:{code:d.RUN_NOT_FOUND,message:`Session "${t}" not found`,details:{}}});return e}async listSessions(t,e,s){return this.db?this.db.listSessions(t,e,s):[]}async getSessionEvents(t){return this.db?this.db.listToolCallEventsBySession?.(t)??[]:[]}async closeSession(t,e){this.db&&this.db.closeSession(t,e);}async createSkillExecution(t){this.db&&this.db.insertSkillExecution({executionId:t.executionId,sessionId:t.sessionId,skillName:t.skillName,startedAt:t.startedAt,status:"running"});}async listRuns(t,e,s){if(this.db)try{return this.db.listSessions(t,e).map(o=>({id:o.id,agent:"claude-code",mode:"hook",source:"hook",status:o.status,startedAt:o.startedAt,totalToolCalls:o.totalToolCalls,mcpToolCalls:o.mcpToolCalls,mcpComplianceRate:o.mcpToolCalls>0?Math.round(o.mcpToolCalls/o.totalToolCalls*100)/100:0}))}catch{}return []}async getRun(t){if(this.db)try{let s=this.db.getSession(t);if(s)return {meta:{runId:s.id,agent:"claude-code",mode:"hook",source:"hook"},status:s.status,startedAt:s.startedAt,finishedAt:s.finishedAt,totalToolCalls:s.totalToolCalls,mcpToolCalls:s.mcpToolCalls,steps:[]};let n=this.db.getSkillExecution(t);if(n)return {meta:{runId:n.executionId,agent:"claude-code",mode:"hook",source:"hook"},status:n.status,startedAt:n.startedAt,finishedAt:n.finishedAt,skillName:n.skillName,totalToolCalls:n.totalToolCalls,mcpToolCalls:n.mcpToolCalls,mcpComplianceRate:n.mcpComplianceRate,steps:[]}}catch{}let e=this.engine.runs.get(t);if(e)return e;throw new NotFoundException({error:{code:d.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}})}async getTimeline(t,e){if(!this.db)return [];try{return this.db.listSessions(500,0).filter(n=>!(t&&n.startedAt<Number(t)||e&&n.startedAt>Number(e))).map(n=>({runId:n.id,stepId:n.id,type:"session",duration:n.durationMs,timestamp:n.startedAt}))}catch{return []}}async getRunEvents(t){if(this.db)try{let s=this.db.listToolCallEventsBySession(t);if(s&&s.length>0)return s;let n=this.db.listToolCallEvents(t);if(n&&n.length>0)return n}catch{}return await this.engine.listEvents(t)??[]}async getRunStats(t){if(this.db)try{let e=this.db.listToolCallEventsBySession(t)??this.db.listToolCallEvents(t)??[];if(e.length>0)return {totalEvents:e.length,llmCalls:0,totalTokens:0,toolUses:e.length,fileReads:0,fileWrites:0,bashCommands:0,errors:e.filter(s=>s.error).length,totalDuration:0,mcpToolCalls:e.filter(s=>s.isMcpTool).length,directToolCalls:e.filter(s=>!s.isMcpTool).length,mcpComplianceRate:e.length>0?e.filter(s=>s.isMcpTool).length/e.length:0}}catch{}return this.engine.getRunStats(t)}async endRun(t,e){await this.engine.endRun(t,e);}async getStats(t=7){if(!this.db)return this.emptyStats();let e=Date.now(),s=e-t*24*60*60*1e3;try{let o=this.db.listSessions(1e3,0).filter(u=>u.startedAt>=s),a={},l=0;for(let u of o){let y=new Date(u.startedAt).toISOString().slice(0,10);a[y]||(a[y]={runs:0}),a[y].runs++,l+=u.totalToolCalls??0;}return {period:{from:new Date(s).toISOString().slice(0,10),to:new Date(e).toISOString().slice(0,10)},summary:{totalRuns:o.length,completedRuns:o.filter(u=>u.status==="completed").length,failedRuns:o.filter(u=>u.status==="failed").length,totalTokens:0,totalLlmCalls:0,totalToolUses:l,avgRunDuration:o.length>0?Math.round(o.reduce((u,y)=>u+(y.durationMs??0),0)/o.length):0},byDay:Object.entries(a).map(([u,y])=>({date:u,tokens:0,...y})).sort((u,y)=>u.date.localeCompare(y.date)),byWorkflow:[],byPlugin:[]}}catch{return this.emptyStats()}}emptyStats(){return {period:{from:"",to:""},summary:{totalRuns:0,completedRuns:0,failedRuns:0,totalTokens:0,totalLlmCalls:0,totalToolUses:0,avgRunDuration:0},byDay:[],byWorkflow:[],byPlugin:[]}}async getRoiSummary(t=7){if(!this.db)return this.emptyRoiSummary();let e=Date.now(),s=e-t*24*60*60*1e3;try{let o=this.db.listSessions(1e3,0).filter(g=>g.startedAt>=s),a=o.length,l=o.filter(g=>g.status==="completed").length,u=o.filter(g=>g.status==="failed").length,y=a>0?Math.round(o.reduce((g,R)=>g+(R.durationMs??0),0)/a):0,mt={};for(let g of o){let R=new Date(g.startedAt).toISOString().slice(0,10);mt[R]||(mt[R]={runs:0,failures:0}),mt[R].runs++,g.status!=="completed"&&mt[R].failures++;}let Qt=this.db.listToolCallEventsBySessions(o.map(g=>g.id)),yt={tool_error:0,mcp_unavailable:0,unknown:0},St={};for(let g of o){let R=Qt[g.id]??[];for(let K of R){if(K.error){let k=K.error.toLowerCase();k.includes("mcp")||k.includes("unavailable")||k.includes("not found")?yt.mcp_unavailable++:k.includes("tool")||k.includes("command")||k.includes("error")?yt.tool_error++:yt.unknown++;}if(K.mcpToolName){let k=K.mcpToolName.split("_")[0];k&&(St[k]=(St[k]??0)+1);}}}return {period:{from:new Date(s).toISOString().slice(0,10),to:new Date(e).toISOString().slice(0,10)},overview:{totalRuns:a,completedRuns:l,failedRuns:u,avgDuration:y,firstPassSuccessRate:a>0?Math.round(l/a*1e4)/100:0},efficiency:{avgTimePerTask:y},failures:{total:u,breakdown:yt},workflows:[],plugins:Object.entries(St).map(([g,R])=>{let K=o.filter(kt=>(Qt[kt.id]??[]).some(Re=>Re.mcpToolName?.startsWith(g+"_"))),k=K.filter(kt=>kt.status==="completed").length,ye=K.length>0?Math.round(k/K.length*1e4)/100:0;return {name:g,runs:R,successRate:ye}}),byDay:Object.entries(mt).map(([g,R])=>({date:g,...R,tokens:0})).sort((g,R)=>g.date.localeCompare(R.date))}}catch{return this.emptyRoiSummary()}}emptyRoiSummary(){return {period:{from:"",to:""},overview:{totalRuns:0,completedRuns:0,failedRuns:0,avgDuration:0,avgTokens:0,firstPassSuccessRate:0,feedbackHitRate:0},efficiency:{totalTokensSaved:0,avgTimePerTask:0,avgRetryCount:0},failures:{total:0,breakdown:{tool_error:0,mcp_unavailable:0,unknown:0}},workflows:[],plugins:[],byDay:[]}}async recordExecutionStart(t){this.db&&this.db.insertSkillExecution({executionId:t.executionId,sessionId:t.sessionId,skillName:t.skillName,startedAt:t.startedAt,status:"running"});}async recordToolCall(t){this.db&&this.db.insertToolCallEvent({eventId:t.eventId,executionId:t.executionId,sessionId:t.sessionId,timestamp:t.timestamp,toolName:t.toolName,toolType:t.toolType,isMcpTool:t.isMcpTool,mcpToolName:t.mcpToolName,mcpEnforced:t.mcpEnforced,mcpFallback:t.mcpFallback,kind:t.kind??"tool_use",input:t.input,duration:t.duration,parentToolCallId:t.parentToolCallId,subagentId:t.subagentId,error:t.error,blocked:t.blocked,blockReason:t.blockReason});}async updateToolCallOutput(t,e,s,n){this.db&&this.db.updateToolCallEvent(t,{output:JSON.stringify(e),duration:n});}async recordExecutionComplete(t){this.db&&this.db.updateSkillExecution(t.executionId,{status:t.status,finishedAt:t.finishedAt,totalDuration:t.summary.totalDuration,mcpComplianceRate:t.summary.mcpComplianceRate,totalToolCalls:t.summary.totalToolCalls,mcpToolCalls:t.summary.mcpToolCalls,directToolCalls:t.summary.directToolCalls,subagentCount:t.summary.subagentCount});}async getExecutions(t,e){return this.db?this.db.listSkillExecutions(t,e):[]}async getExecutionEvents(t){return this.db?this.db.listToolCallEvents(t):[]}async getMcpCompliance(){return this.db?this.db.getMcpCompliance():{overall:0,bySkill:{},missedTools:[]}}async classifyFailure(t){let e=await this.getRun(t).catch(()=>null);if(!e||e.status!=="failed")return {};let s=e.steps?.find(o=>o.status==="failed");if(!s)return {};let n=s.error?.toLowerCase()??"";return n.includes("context")||n.includes("insufficient")?{failureCategory:"context_insufficient",failureReason:"Context provided was insufficient for the task",suggestedActions:[{action:"Supplement task context",priority:"high"},{action:"View graph roots",priority:"medium"},{action:"Add related memory",priority:"medium"}]}:n.includes("knowledge")||n.includes("docs")?{failureCategory:"knowledge_missing",failureReason:"Required knowledge was not available",suggestedActions:[{action:"Sync knowledge source",priority:"high"},{action:"Add docs source",priority:"medium"}]}:n.includes("workflow")||n.includes("step")?{failureCategory:"workflow_design_issue",failureReason:"Workflow design issue detected",suggestedActions:[{action:"Adjust specific step",priority:"high"},{action:"Split workflow",priority:"medium"}]}:n.includes("tool")||n.includes("connection")?{failureCategory:"tool_error",failureReason:"Tool execution error",suggestedActions:[{action:"Check tool connectivity",priority:"high"},{action:"Retry or fallback",priority:"medium"}]}:{failureCategory:"agent_override",failureReason:"Agent override detected",suggestedActions:[{action:"Enable/strengthen enforcer",priority:"high"}]}}async cleanup(t){if(!this.db)return 0;try{this.db.cleanupStaleRecords?.();}catch{}let e=this.engine.runs,s=Date.now()-t*24*60*60*1e3,n=0;for(let[o,a]of e)a.startedAt&&a.startedAt<s&&(e.delete(o),n++);return n}async cleanupStaleRecords(){if(this.db)try{this.db.cleanupStaleRecords?.();}catch{}}async getFeedbackStats(t,e){return {total:0,hits:0,partials:0,misses:0,hitRate:0,partialRate:0,missRate:0}}async getOpsRoiSummary(){return {period:"all-time",totalRuns:0,successfulRuns:0,successRate:0,avgTokenUsage:0,avgDuration:0,feedbackHitRate:0,trend:"stable"}}async getExperimentalRoiSummary(){return {totalScenarios:0,avgTimeSavedRate:null,avgTokenReductionRate:null,avgFirstPassLift:null,avgReworkReductionRate:null,conclusion:"No experimental data available yet"}}async getPluginEffectiveness(t,e){if(!this.db)return {name:t,totalRuns:0,successRate:0,lastUsedAt:null};let s=this.db.listSessions(1e3,0),n=0;for(let o of s){let a=this.db.listToolCallEventsBySession(o.id);for(let l of a)l.mcpToolName?.startsWith(t+"_")&&n++;}return {name:t,totalRuns:n,successRate:0,lastUsedAt:null}}async getPluginUsageStats(t){let e=await this.getPluginEffectiveness(t);return {activeProjects:0,totalRuns:e.totalRuns,successfulRuns:0,lastUsedAt:e.lastUsedAt??void 0}}};P=i([Injectable(),r(0,Optional()),r(0,Inject("DATABASE"))],P);var j=class{constructor(t,e){this.telemetryService=t;this.database=e;this.projectStats=new Map;this.benchmarkResults=[];}async recordTelemetryEvent(t){let e=`evt_${Date.now()}_${Math.random().toString(36).slice(2,7)}`,s=t.toolName?"tool_use":"step_end",n={id:e,runId:t.metadata?.runId??`event_${Date.now()}_${Math.random().toString(36).slice(2,7)}`,stepId:e,kind:s,timestamp:Date.now(),duration:t.durationMs,data:{toolName:t.toolName,toolInput:t.args,errorMessage:t.error},metadata:{source:"claude-code"}};return await this.telemetryService.recordEvent(n),{eventId:e}}async getProjectStats(t){return this.database?this.database.getProjectStats(t):this.projectStats.get(t)??null}async updateProjectStats(t,e){if(this.database){let a={...await this.getProjectStats(t)??{projectRoot:t,totalRuns:0,successfulRuns:0,totalTokens:0,lastActiveAt:Date.now(),topTools:[]},...e,lastActiveAt:Date.now()};return await this.database.upsertProjectStats(a),a}let n={...this.projectStats.get(t)??{projectRoot:t,totalRuns:0,successfulRuns:0,totalTokens:0,lastActiveAt:Date.now(),topTools:[]},...e,lastActiveAt:Date.now()};return this.projectStats.set(t,n),n}recordBenchmarkResult(t){this.benchmarkResults.push(t);}getBenchmarkResults(t){return t?this.benchmarkResults.filter(e=>this.projectStats.get(e.scenarioId)?.projectRoot===t):this.benchmarkResults}async getPluginEffectiveness(t){return []}};j=i([Injectable(),r(0,Inject(P)),r(1,Optional()),r(1,Inject("DATABASE"))],j);var F=class{constructor(t){this.dataService=t;this.feedbackEntries=[];}async indexProject(t){let{context:e,codegraph:s}=await createEngines(t);await e.index(t);let n=s.getStats();return {totalFiles:n.fileCount,totalSymbols:n.nodeCount,lastIndexTime:n.lastUpdated,indexing:s.isIndexing()}}async getStatus(t){try{let{codegraph:e}=await createEngines(t),s=e.getStats();return {totalFiles:s.fileCount,totalSymbols:s.nodeCount,lastIndexTime:s.lastUpdated,indexing:e.isIndexing()}}catch{return {totalFiles:0,totalSymbols:0,lastIndexTime:0,indexing:false}}}async buildContext(t,e,s,n){let{context:o}=await createEngines(t);return o.build({query:e,mode:s,maxTokens:n??8e3,includeGraph:s==="deep"})}async buildTaskContext(t,e,s,n){let{context:o}=await createEngines(t);return o.buildTaskContext(e,{mode:s,maxTokens:n??8e3})}async findSymbol(t,e){let{indexer:s}=await createEngines(t);return s.findSymbol(e)}async recordFeedback(t,e,s,n){let o={query:e,feedback:s,timestamp:Date.now(),projectRoot:t};return this.feedbackEntries.push(o),this.dataService&&await this.dataService.recordTelemetryEvent({toolName:"context_feedback",args:{query:e,feedback:s,taskType:n?.taskType,contextMode:n?.contextMode,projectRoot:t},durationMs:0,success:true,metadata:{projectRoot:t,query:e,taskType:n?.taskType}}),o}async getFeedbackSummaries(){let t=this.feedbackEntries.length,e=this.feedbackEntries.filter(o=>o.feedback==="hit").length,s=this.feedbackEntries.filter(o=>o.feedback==="partial").length,n=this.feedbackEntries.filter(o=>o.feedback==="miss").length;return {total:t,hits:e,partials:s,misses:n,hitRate:t>0?e/t:0}}};F=i([Injectable(),r(0,Optional()),r(0,Inject(j))],F);var w=class{constructor(t,e){this.service=t;this.projects=e;}resolveRootPath(t,e){let s=t??e??this.projects.getActiveProjectRoot();if(!s)throw new BadRequestException("rootPath is required \u2014 no active project connected");return s}async status(t,e){let s=t??e??this.projects.getActiveProjectRoot();return s?this.service.getStatus(s):null}async index(t,e){return this.service.indexProject(this.resolveRootPath(t.rootPath,e))}async build(t,e){return this.service.buildContext(this.resolveRootPath(t.rootPath,e),t.query,t.mode??"fast",t.maxTokens)}async buildTask(t,e){return this.service.buildTaskContext(this.resolveRootPath(t.rootPath,e),t.query,t.mode??"fast",t.maxTokens)}async feedback(t,e){return this.service.recordFeedback(this.resolveRootPath(t.rootPath,e),t.query,t.feedback,{taskType:t.taskType,contextMode:t.contextMode,runId:t.runId,tokenCount:t.tokenCount})}async feedbackSummary(){return this.service.getFeedbackSummaries()}async findSymbol(t,e,s){return this.service.findSymbol(this.resolveRootPath(e,s),t)}};i([Get("status"),r(0,Query("rootPath")),r(1,Headers("x-devflow-project"))],w.prototype,"status",1),i([Post("index"),r(0,Body()),r(1,Headers("x-devflow-project"))],w.prototype,"index",1),i([Post("build"),r(0,Body()),r(1,Headers("x-devflow-project"))],w.prototype,"build",1),i([Post("build-task"),r(0,Body()),r(1,Headers("x-devflow-project"))],w.prototype,"buildTask",1),i([Post("feedback"),r(0,Body()),r(1,Headers("x-devflow-project"))],w.prototype,"feedback",1),i([Get("feedback-summary")],w.prototype,"feedbackSummary",1),i([Get("symbol/:name"),r(0,Param("name")),r(1,Query("rootPath")),r(2,Headers("x-devflow-project"))],w.prototype,"findSymbol",1),w=i([Controller("context"),r(0,Inject(F)),r(1,Inject(p))],w);var N=class{constructor(t){this.dataService=t;}async recordTelemetryEvent(t){return {success:true,...await this.dataService.recordTelemetryEvent(t)}}async getProjectStats(t){return this.dataService.getProjectStats(t)}async updateProjectStats(t){return this.dataService.updateProjectStats(t.projectRoot,t.stats)}recordBenchmarkResult(t){return this.dataService.recordBenchmarkResult(t),{success:true}}getBenchmarkResults(t){return this.dataService.getBenchmarkResults(t)}};i([Post("telemetry/event"),r(0,Body())],N.prototype,"recordTelemetryEvent",1),i([Get("project/stats"),r(0,Query("rootPath"))],N.prototype,"getProjectStats",1),i([Post("project/stats"),r(0,Body())],N.prototype,"updateProjectStats",1),i([Post("benchmark/result"),r(0,Body())],N.prototype,"recordBenchmarkResult",1),i([Get("benchmark/results"),r(0,Query("projectRoot"))],N.prototype,"getBenchmarkResults",1),N=i([Controller("data"),r(0,Inject(j))],N);var O=class{constructor(){this.engines=new Map;this.ENGINE_TTL=3600*1e3;}getEngine(t){let e=Date.now();for(let[o,a]of this.engines)if(e-a.lastAccess>this.ENGINE_TTL){try{a.engine.close?.();}catch{}this.engines.delete(o);}let s=t.replace(/\/+$/,""),n=this.engines.get(s);return n?n.lastAccess=e:(n={engine:new MemoryEngine(s),lastAccess:e},this.engines.set(s,n)),n.engine}async getAll(t){let e=this.getEngine(t),[s,n]=await Promise.all([e.listMemories(),checkOllama()]);return {memories:s.map(o=>({id:o.id,category:o.category,content:o.content,originalText:o.originalText,source:o.source,status:o.status,confidence:o.confidence,scope:o.scope,createdAt:o.createdAt,approvedAt:o.approvedAt})),ollama:{installed:n.installed,running:n.running,modelAvailable:n.modelAvailable,modelName:n.modelName,infoMessage:getOllamaInfoMessage(n)}}}async add(t,e){return this.getEngine(t).addMemory({category:e.category,content:e.content,source:"manual",confidence:1,scope:e.scope??""})}async update(t,e,s){await this.getEngine(t).updateMemory(e,s);}async delete(t,e){await this.getEngine(t).deleteMemory(e);}async getCandidates(t){return this.getEngine(t).getPendingMemories()}async approveCandidate(t,e){await this.getEngine(t).approveMemory(e);}async rejectCandidate(t,e){await this.getEngine(t).rejectMemory(e);}async search(t,e,s){return (await this.getEngine(t).search(e,s)).map(o=>o.entry)}async extract(t,e){return this.getEngine(t).extractMemories(e)}async getOllamaStatus(){let t=await checkOllama();return {...t,infoMessage:getOllamaInfoMessage(t)}}async updateLegacy(t,e,s,n){e!=="user"&&await this.getEngine(t).addMemory({category:"project_knowledge",content:`${s}: ${JSON.stringify(n)}`,source:"manual",confidence:1,scope:s});}async recordEvent(t,e){let s=this.getEngine(t);return await s.recordEvent({id:e.id,sessionId:e.sessionId,tool:e.tool,command:e.command,exitCode:e.exitCode,stderr:e.stderr,durationMs:e.durationMs,createdAt:Date.now()}),{acknowledged:true,extracted:(await s.extractFromEventsRealtime([{tool:e.tool,command:e.command,exitCode:e.exitCode,stderr:e.stderr}])).length}}async processSessionEvents(t){return this.getEngine(t).processSessionEvents()}};O=i([Injectable()],O);var m=class{constructor(t,e,s){this.service=t;this.memoryService=e;this.projectsService=s;}async listRuns(t,e,s){return this.service.listRuns(Number(t)||20,Number(e)||0,s)}async getRun(t){let e=await this.service.getRun(t),s=await this.service.classifyFailure(t);return {...e,...s}}async getTimeline(t,e){return this.service.getTimeline(t,e)}async getRunEvents(t){return this.service.getRunEvents(t)}async getRunStats(t){return this.service.getRunStats(t)}async completeRun(t){await this.service.endRun(t,{status:"success"});let e=await this.service.getRunEvents(t),s=this.projectsService.getActiveProjectRoot(),n=await this.memoryService.extract(s??"",e);return {extracted:Array.isArray(n)?n.length:0}}async getStats(t){return this.service.getStats(Number(t)||7)}async getRoiSummary(t){return this.service.getRoiSummary(Number(t)||7)}async cleanup(t){return {removedRuns:await this.service.cleanup(t.olderThanDays??30)}}async cleanupStale(){return await this.service.cleanupStaleRecords(),{ok:true}}async createSession(t){return await this.service.createSession(t),{id:t.id}}async listSessions(t,e,s){return this.service.listSessions(Number(t)||20,Number(e)||0,s)}async getSession(t){return this.service.getSession(t)}async getSessionEvents(t){return this.service.getSessionEvents(t)}async closeSession(t,e){return await this.service.closeSession(t,e.finishedAt),{}}async startSessionSkillExecution(t,e){return await this.service.createSkillExecution({...e,sessionId:t}),{executionId:e.executionId}}async startSkillExecution(t){return await this.service.recordExecutionStart(t),{executionId:t.executionId}}async recordToolCall(t){return await this.service.recordToolCall(t),{eventId:t.eventId}}async updateToolCallOutput(t){return await this.service.updateToolCallOutput(t.eventId,t.output,t.completedAt,t.duration),{}}async completeSkillExecution(t){return await this.service.recordExecutionComplete(t),{}}async getExecutions(t,e){return this.service.getExecutions(Number(t)||20,e)}async getExecutionEvents(t){return this.service.getExecutionEvents(t)}async getMcpCompliance(){return await this.service.getMcpCompliance()}};i([Get("runs"),r(0,Query("limit")),r(1,Query("offset")),r(2,Query("source"))],m.prototype,"listRuns",1),i([Get("runs/:id"),r(0,Param("id"))],m.prototype,"getRun",1),i([Get("timeline"),r(0,Query("from")),r(1,Query("to"))],m.prototype,"getTimeline",1),i([Get("runs/:runId/events"),r(0,Param("runId"))],m.prototype,"getRunEvents",1),i([Get("runs/:runId/stats"),r(0,Param("runId"))],m.prototype,"getRunStats",1),i([Post("runs/:id/complete"),r(0,Param("id"))],m.prototype,"completeRun",1),i([Get("stats"),r(0,Query("days"))],m.prototype,"getStats",1),i([Get("roi-summary"),r(0,Query("days"))],m.prototype,"getRoiSummary",1),i([Post("cleanup"),r(0,Body())],m.prototype,"cleanup",1),i([Post("cleanup-stale")],m.prototype,"cleanupStale",1),i([Post("sessions"),r(0,Body())],m.prototype,"createSession",1),i([Get("sessions"),r(0,Query("limit")),r(1,Query("offset")),r(2,Query("projectRoot"))],m.prototype,"listSessions",1),i([Get("sessions/:id"),r(0,Param("id"))],m.prototype,"getSession",1),i([Get("sessions/:id/events"),r(0,Param("id"))],m.prototype,"getSessionEvents",1),i([Post("sessions/:id/close"),r(0,Param("id")),r(1,Body())],m.prototype,"closeSession",1),i([Post("sessions/:id/skill-executions"),r(0,Param("id")),r(1,Body())],m.prototype,"startSessionSkillExecution",1),i([Post("skill-execution/start"),r(0,Body())],m.prototype,"startSkillExecution",1),i([Post("tool-call"),r(0,Body())],m.prototype,"recordToolCall",1),i([Post("tool-call/output"),r(0,Body())],m.prototype,"updateToolCallOutput",1),i([Post("skill-execution/complete"),r(0,Body())],m.prototype,"completeSkillExecution",1),i([Get("executions"),r(0,Query("limit")),r(1,Query("skillName"))],m.prototype,"getExecutions",1),i([Get("executions/:id/events"),r(0,Param("id"))],m.prototype,"getExecutionEvents",1),i([Get("mcp-compliance")],m.prototype,"getMcpCompliance",1),m=i([Controller("telemetry"),r(0,Inject(P)),r(1,Inject(O)),r(2,Inject(p))],m);var f=class{constructor(t,e){this.service=t;this.projects=e;}resolveRootPath(t,e){let s=t??e??this.projects.getActiveProjectRoot();if(!s)throw new BadRequestException({error:{code:d.BAD_REQUEST,message:"rootPath is required \u2014 no active project connected",details:{}}});return s}async getAll(t,e){return this.service.getAll(this.resolveRootPath(t,e))}async add(t,e,s){return this.service.add(this.resolveRootPath(t,s),e)}async update(t,e,s,n){return await this.service.update(this.resolveRootPath(t,n),e,s),{ok:true}}async delete(t,e,s){return await this.service.delete(this.resolveRootPath(t,s),e),{ok:true}}async getCandidates(t,e){return this.service.getCandidates(this.resolveRootPath(t,e))}async approve(t,e,s){return await this.service.approveCandidate(this.resolveRootPath(t,s),e),{approved:true}}async reject(t,e,s){return await this.service.rejectCandidate(this.resolveRootPath(t,s),e),{rejected:true}}async search(t,e,s){return this.service.search(this.resolveRootPath(t,s),e.query,{limit:e.limit,categories:e.categories})}async extract(t,e,s){return this.service.extract(this.resolveRootPath(t,s),e.events)}async ollamaStatus(){return this.service.getOllamaStatus()}async updateLegacy(t,e,s,n,o){return await this.service.updateLegacy(this.resolveRootPath(t,o),e,s,n.value),{ok:true}}async recordEvent(t,e,s){return this.service.recordEvent(this.resolveRootPath(t,s),e)}async processEvents(t,e,s){return this.service.processSessionEvents(this.resolveRootPath(t,e))}};i([Get(),r(0,Query("rootPath")),r(1,Headers("x-devflow-project"))],f.prototype,"getAll",1),i([Post(),r(0,Query("rootPath")),r(1,Body()),r(2,Headers("x-devflow-project"))],f.prototype,"add",1),i([Put(":id"),r(0,Query("rootPath")),r(1,Param("id")),r(2,Body()),r(3,Headers("x-devflow-project"))],f.prototype,"update",1),i([Delete(":id"),r(0,Query("rootPath")),r(1,Param("id")),r(2,Headers("x-devflow-project"))],f.prototype,"delete",1),i([Get("candidates"),r(0,Query("rootPath")),r(1,Headers("x-devflow-project"))],f.prototype,"getCandidates",1),i([Post("candidates/:id/approve"),r(0,Query("rootPath")),r(1,Param("id")),r(2,Headers("x-devflow-project"))],f.prototype,"approve",1),i([Post("candidates/:id/reject"),r(0,Query("rootPath")),r(1,Param("id")),r(2,Headers("x-devflow-project"))],f.prototype,"reject",1),i([Post("search"),r(0,Query("rootPath")),r(1,Body()),r(2,Headers("x-devflow-project"))],f.prototype,"search",1),i([Post("extract"),r(0,Query("rootPath")),r(1,Body()),r(2,Headers("x-devflow-project"))],f.prototype,"extract",1),i([Get("ollama/status")],f.prototype,"ollamaStatus",1),i([Put(":layer/:key"),r(0,Query("rootPath")),r(1,Param("layer")),r(2,Param("key")),r(3,Body()),r(4,Headers("x-devflow-project"))],f.prototype,"updateLegacy",1),i([Post("events"),r(0,Query("rootPath")),r(1,Body()),r(2,Headers("x-devflow-project"))],f.prototype,"recordEvent",1),i([Post("process"),r(0,Query("rootPath")),r(1,Headers("x-devflow-project")),r(2,Body())],f.prototype,"processEvents",1),f=i([Controller("memory"),r(0,Inject(O)),r(1,Inject(p))],f);var et=class{};et=i([Module({imports:[forwardRef(()=>T),v],controllers:[f],providers:[O],exports:[O]})],et);var H=class{};H=i([Module({imports:[et,v],controllers:[m],providers:[P],exports:[P]})],H);var st=class{};st=i([Module({imports:[H],controllers:[N],providers:[j],exports:[j]})],st);var T=class{};T=i([Module({imports:[v,st],controllers:[w],providers:[F],exports:[F]})],T);var M=class{async getFullGraph(t){let{graph:e}=await createEngines(t);return e.export()}async getLayeredGraph(t){let{graph:e}=await createEngines(t);return e.getLayeredGraph()}async getNode(t,e){let{codegraph:s}=await createEngines(t),n=s.getNode(e);if(!n)throw new NotFoundException({error:{code:d.NODE_NOT_FOUND,message:`Node "${e}" not found`,details:{}}});return n}async expandNode(t,e,s,n){let{graph:o}=await createEngines(t),a=o.expand([e],{depth:s,direction:n});return {node:a.nodes.find(l=>l.id===e),subGraph:a}}};M=i([Injectable()],M);var U=class{constructor(t,e){this.service=t;this.projects=e;}resolveRootPath(t,e){let s=t??e??this.projects.getActiveProjectRoot();if(!s)throw new BadRequestException({error:{code:d.BAD_REQUEST,message:"rootPath is required \u2014 no active project connected",details:{}}});return s}async getFullGraph(t,e,s){return e==="layered"?this.service.getLayeredGraph(this.resolveRootPath(t,s)):this.service.getFullGraph(this.resolveRootPath(t,s))}async getNode(t,e,s){return this.service.getNode(this.resolveRootPath(t,s),e)}async expandNode(t,e,s,n,o){return this.service.expandNode(this.resolveRootPath(t,o),e,Number(s)||2,n||"both")}};i([Get(),r(0,Query("rootPath")),r(1,Query("view")),r(2,Headers("x-devflow-project"))],U.prototype,"getFullGraph",1),i([Get(":nodeId"),r(0,Query("rootPath")),r(1,Param("nodeId")),r(2,Headers("x-devflow-project"))],U.prototype,"getNode",1),i([Get(":nodeId/expand"),r(0,Query("rootPath")),r(1,Param("nodeId")),r(2,Query("depth")),r(3,Query("direction")),r(4,Headers("x-devflow-project"))],U.prototype,"expandNode",1),U=i([Controller("graph"),r(0,Inject(M)),r(1,Inject(p))],U);var nt=class{};nt=i([Module({imports:[T,v],controllers:[U],providers:[M],exports:[M]})],nt);var B=class{constructor(t){this.db=t;this.engine=new WorkflowEngine;this.events=new Map;this.engineRunIds=new Map;}async onModuleInit(){try{clearPluginCache();let t=await loadPlugins(),e=Array.from(t.values());for(let n of e)for(let o of n.workflow?.templates??[])this.engine.register(o);let s=await this.engine.list();console.log(`[WorkflowService] Loaded ${e.length} plugins with ${s.length} workflows`);}catch(t){console.error("[WorkflowService] Failed to load plugins:",t);}}async list(){return this.engine.list()}async run(t,e){if(!(await this.engine.list()).find(a=>a.name===t))throw new NotFoundException({error:{code:d.WORKFLOW_NOT_FOUND,message:`Workflow "${t}" not found`,details:{}}});let n=`run_${Date.now()}_${Math.random().toString(36).slice(2,7)}`,o=new Subject;if(this.events.set(n,o),this.db)try{this.db.insertSkillExecution({executionId:n,skillName:`workflow:${t}`,startedAt:Date.now(),status:"running"});}catch{}return this.engine.run(t,e).then(a=>{if(this.engineRunIds.set(n,a.runId),a.status!=="running"&&this.db)try{this.db.updateSkillExecution(n,{status:a.status==="success"?"completed":"failed",finishedAt:Date.now()});}catch{}this.engineRunIds.set(n,a.runId);let l=this.engine.getRun(a.runId);if(l){for(let u of l.steps)o.next({runId:n,stepId:u.stepId,status:u.status==="success"?"completed":u.status==="failed"?"failed":"started",output:u.output,error:u.error,timestamp:Date.now()});a.status!=="running"&&o.complete();}a.status==="running"&&this.engine.onEvent(a.runId,u=>{o.next({runId:n,stepId:u.stepId,status:u.type==="step-done"?"completed":u.type==="step-error"?"failed":"started",output:"output"in u?u.output:void 0,error:"error"in u?u.error:void 0,timestamp:Date.now()});});}).catch(a=>{if(this.db)try{this.db.updateSkillExecution(n,{status:"failed",finishedAt:Date.now()});}catch{}o.next({runId:n,stepId:"engine",status:"failed",error:a.message,timestamp:Date.now()}),o.complete();}),{runId:n}}async listRuns(t,e){return (await this.engine.listRuns()).map(o=>({runId:Array.from(this.engineRunIds.entries()).find(([,l])=>l===o.runId)?.[0]??o.runId,workflowName:o.type,status:o.status,steps:o.steps.map(l=>({stepId:l.stepId,status:l.status,output:l.output,error:l.error,startedAt:0})),startedAt:o.startedAt,finishedAt:o.finishedAt})).slice(e,e+t)}async getRun(t){let e=this.engineRunIds.get(t)??t,s=this.engine.getRun(e);if(!s)throw new NotFoundException({error:{code:d.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}});return {runId:t,workflowName:s.type,status:s.status,steps:s.steps.map(n=>({stepId:n.stepId,status:n.status,output:n.output,error:n.error})),startedAt:s.startedAt,finishedAt:s.finishedAt}}streamRun(t){let e=this.events.get(t);if(!e)throw new NotFoundException({error:{code:d.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}});return e}async approveRun(t){let e=this.engineRunIds.get(t)??t,s=this.engine.getRun(e);if(!s)throw new NotFoundException({error:{code:d.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}});let n=s.steps.find(o=>o.status==="awaiting_approval");n&&await this.engine.approve(e,n.stepId);}async rejectRun(t,e){let s=this.engineRunIds.get(t)??t,n=this.engine.getRun(s);if(!n)throw new NotFoundException({error:{code:d.RUN_NOT_FOUND,message:`Run "${t}" not found`,details:{}}});let o=n.steps.find(a=>a.status==="awaiting_approval");o&&await this.engine.reject(s,o.stepId,e??"Rejected");}async getNextStep(t){if(!t){(await this.engine.list())[0];return null}let e=this.engineRunIds.get(t)??t,s=this.engine.getRun(e);return s?(Array.isArray(s.steps)?s.steps:[]).find(o=>o.status==="pending")??null:null}};B=i([Injectable(),r(0,Optional()),r(0,Inject("DATABASE"))],B);var b=class{constructor(t){this.service=t;}async list(){return this.service.list()}async run(t,e){return this.service.run(t,e.input??{})}async listRuns(t,e){return this.service.listRuns(Number(t)||20,Number(e)||0)}async getRun(t){return this.service.getRun(t)}async stream(t,e){e.raw.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"});let n=this.service.streamRun(t).subscribe({next:o=>{e.raw.write(`event: step-${o.status}
|
|
2
2
|
data: ${JSON.stringify(o)}
|
|
3
3
|
|
|
4
4
|
`);},error:o=>{e.raw.write(`event: error
|
|
@@ -7,4 +7,4 @@ data: ${JSON.stringify({error:o.message})}
|
|
|
7
7
|
`),e.raw.end();},complete:()=>{e.raw.write(`event: done
|
|
8
8
|
data: {}
|
|
9
9
|
|
|
10
|
-
`),e.raw.end();}});e.raw.on("close",()=>r.unsubscribe());}async approve(t){return await this.service.approveRun(t),{approved:true}}async reject(t,e){return await this.service.rejectRun(t,e.reason),{rejected:true}}async nextStep(t){return this.service.getNextStep(t)}};i([Get()],S.prototype,"list",1),i([Post(":type/run"),n(0,Param("type")),n(1,Body())],S.prototype,"run",1),i([Get("runs"),n(0,Query("limit")),n(1,Query("offset"))],S.prototype,"listRuns",1),i([Get("runs/:id"),n(0,Param("id"))],S.prototype,"getRun",1),i([Get("runs/:id/stream"),n(0,Param("id")),n(1,Res())],S.prototype,"stream",1),i([Post("runs/:id/approve"),n(0,Param("id"))],S.prototype,"approve",1),i([Post("runs/:id/reject"),n(0,Param("id")),n(1,Body())],S.prototype,"reject",1),i([Get("next-step"),n(0,Query("runId"))],S.prototype,"nextStep",1),S=i([Controller("workflows"),n(0,Inject($))],S);var ut=class{};ut=i([Module({controllers:[S],providers:[$],exports:[$]})],ut);var G=class{constructor(t){this.projectsService=t;}getEngine(t){return new KnowledgeEngine({projectRoot:t})}async onModuleInit(){let t=this.projectsService.getActiveProjectRoot()??process.env.DEVFLOW_PROJECT_ROOT??process.cwd();try{let e=this.getEngine(t),s=await loadPlugins(),r=Array.from(s.values());for(let c of r)for(let l of c.knowledge?.sources??[])await e.registerSource({...l,version:l.version||c.meta.version});let o=await e.getSources(),a=Date.now()-10080*60*1e3;for(let c of o)(!c.lastSyncTime||c.lastSyncTime<a)&&await e.syncDocs(c.source.name);}catch{}}async search(t,e,s){return this.getEngine(t).search(e,{sources:s&&s!=="all"?[s]:void 0})}async sync(t,e){return this.getEngine(t).syncDocs(e??"")}async getSources(t){return this.getEngine(t).getSources()}};G=i([Injectable(),n(0,Inject(h))],G);var H=class{constructor(t,e){this.service=t;this.projects=e;}resolveRootPath(t,e){let s=t??e??this.projects.getActiveProjectRoot();if(!s)throw new BadRequestException("rootPath is required \u2014 no active project connected");return s}async search(t,e,s,r){return this.service.search(this.resolveRootPath(t,r),e??"",s)}async sync(t,e){return this.service.sync(this.resolveRootPath(t.rootPath,e),t.pluginName)}async getSources(t,e){return this.service.getSources(this.resolveRootPath(t,e))}};i([Get("search"),n(0,Query("rootPath")),n(1,Query("q")),n(2,Query("scope")),n(3,Headers("x-devflow-project"))],H.prototype,"search",1),i([Post("sync"),n(0,Body()),n(1,Headers("x-devflow-project"))],H.prototype,"sync",1),i([Get("sources"),n(0,Query("rootPath")),n(1,Headers("x-devflow-project"))],H.prototype,"getSources",1),H=i([Controller("knowledge"),n(0,Inject(G)),n(1,Inject(h))],H);var lt=class{};lt=i([Module({imports:[j,P],controllers:[H],providers:[G],exports:[G]})],lt);var K=class{constructor(){this.results=[];this.scenarioIds=[];this.engine=new BenchmarkEngine,this.registerDefaultScenarios();}registerDefaultScenarios(){let t=[{id:"understand-codebase",category:"understand",desc:"\u7406\u89E3\u4EE3\u7801\u5E93\u67B6\u6784",expectedFiles:2},{id:"modify-component",category:"modify",desc:"\u4FEE\u6539 React \u7EC4\u4EF6",expectedFiles:1,expectedComponents:1},{id:"review-code",category:"review",desc:"\u4EE3\u7801\u5BA1\u67E5",expectedIssues:2}];for(let e of t)this.engine.registerScenario(e),this.scenarioIds.push(e.id);}async runScenarioSet(t){let e=async a=>({prepTimeMs:1e3+Math.random()*500,tokenCount:500+Math.floor(Math.random()*200),firstPassSuccess:Math.random()>.5,reworkCount:Math.floor(Math.random()*3),durationMs:5e3+Math.random()*3e3}),s=async a=>({prepTimeMs:500+Math.random()*300,tokenCount:300+Math.floor(Math.random()*100),firstPassSuccess:Math.random()>.2,reworkCount:Math.floor(Math.random()*2),durationMs:3e3+Math.random()*2e3}),r=t??this.scenarioIds,o=await this.engine.runScenarioBatch(r,e,s);return this.results=o,o}async getScenarioResults(){return this.results.length===0&&await this.runScenarioSet(),this.results}async getComparisonSummary(){let t=await this.getScenarioResults(),e=t.length;return {totalScenarios:e,avgTimeSavedRate:t.reduce((s,r)=>s+r.comparison.timeSavedRate,0)/e,avgTokenReductionRate:t.reduce((s,r)=>s+r.comparison.tokenReductionRate,0)/e,avgFirstPassLift:t.reduce((s,r)=>s+r.comparison.firstPassLift,0)/e,avgReworkReductionRate:t.reduce((s,r)=>s+r.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"}}};K=i([Injectable()],K);var C=class{constructor(t){this.service=t;}async run(t){return this.service.runScenarioSet(t.scenarioIds)}async getResults(){return this.service.getScenarioResults()}async getComparisonSummary(){return this.service.getComparisonSummary()}async getExperimentalRoiSummary(){return this.service.getExperimentalRoiSummary()}};i([Post("run"),n(0,Body())],C.prototype,"run",1),i([Get("results")],C.prototype,"getResults",1),i([Get("summary")],C.prototype,"getComparisonSummary",1),i([Get("roi-summary")],C.prototype,"getExperimentalRoiSummary",1),C=i([Controller("benchmark"),n(0,Inject(K))],C);var dt=class{};dt=i([Module({controllers:[C],providers:[K],exports:[K]})],dt);var W=class{constructor(t){this.telemetryService=t;this.plugins=new Map;this.installRecords=[];}async list(t,e){let s=Array.from(this.plugins.values());if(t){let r=t.toLowerCase();s=s.filter(o=>o.name.toLowerCase().includes(r)||o.description.toLowerCase().includes(r));}return e&&(s=s.filter(r=>r.tags.includes(e))),s}async getByName(t){let e=this.plugins.get(t);if(!e)throw new NotFoundException({error:{code:m.PLUGIN_NOT_FOUND,message:`Plugin "${t}" not found`,details:{}}});return e}async publish(t){let e=t.npmPackage.replace(/^@devflow-tools\/plugin-/,""),s={name:e,npmPackage:t.npmPackage,version:t.version,description:t.description,tags:t.tags??[],createdAt:Date.now()};return this.plugins.set(e,s),s}async install(t,e){let s=t.startsWith("@devflow-tools/plugin-")?t:`@devflow-tools/plugin-${t}`,r=t.replace(/^@devflow-tools\/plugin-/,"");return this.plugins.set(r,{name:r,npmPackage:s,version:"0.1.0",description:"Installed plugin",tags:[],createdAt:Date.now()}),e&&await this.recordPluginInstall(r,e),{ok:true,name:r}}async uninstall(t,e){let s=t.replace(/^@devflow-tools\/plugin-/,"");return this.plugins.delete(s),e&&await this.recordPluginUninstall(s,e),{ok:true,name:s}}async recordPluginInstall(t,e){let s=this.installRecords.find(r=>r.pluginName===t&&r.projectRoot===e);s?s.uninstalledAt=void 0:this.installRecords.push({pluginName:t,projectRoot:e,installedAt:Date.now()});}async recordPluginUninstall(t,e){let s=this.installRecords.find(r=>r.pluginName===t&&r.projectRoot===e);s&&(s.uninstalledAt=Date.now());}async listInstalledProjects(t){return this.installRecords.filter(e=>e.pluginName===t&&!e.uninstalledAt).map(e=>e.projectRoot)}async buildPluginEffectiveness(t){let s=(await this.listInstalledProjects(t)).length,r=await this.telemetryService.getPluginUsageStats(t),o=s>0?r.activeProjects/s:0,a=r.totalRuns>0?r.successfulRuns/r.totalRuns:0,c="optimize";return o>.7&&a>.8?c="install":(o<.3||a<.5)&&(c="remove"),{name:t,installCount:s,usageCount:r.totalRuns,activeRate:o,successRate:a,lastUsedAt:r.lastUsedAt,recommendation:c}}async getPluginEffectiveness(t){let e=t?this.installRecords.filter(o=>o.projectRoot===t&&!o.uninstalledAt):this.installRecords.filter(o=>!o.uninstalledAt),s=[...new Set(e.map(o=>o.pluginName))],r=[];for(let o of s){let a=await this.buildPluginEffectiveness(o);r.push(a);}return r}};W=i([Injectable(),n(0,Inject(E))],W);var N=class{constructor(t){this.service=t;}async list(t,e){return this.service.list(t,e)}async getPluginEffectiveness(t){return this.service.getPluginEffectiveness(t)}async getByName(t){return this.service.getByName(t)}async publish(t){return this.service.publish(t)}async install(t,e){return this.service.install(t.name,t.rootPath??e)}async uninstall(t,e,s){return this.service.uninstall(t,e.rootPath??s)}};i([Get("plugins"),n(0,Query("search")),n(1,Query("tag"))],N.prototype,"list",1),i([Get("plugins/effectiveness"),n(0,Query("rootPath"))],N.prototype,"getPluginEffectiveness",1),i([Get("plugins/:name"),n(0,Param("name"))],N.prototype,"getByName",1),i([Post("plugins"),n(0,Body())],N.prototype,"publish",1),i([Post("plugins/install"),n(0,Body()),n(1,Headers("x-devflow-project"))],N.prototype,"install",1),i([Post("plugins/:name/uninstall"),n(0,Param("name")),n(1,Body()),n(2,Headers("x-devflow-project"))],N.prototype,"uninstall",1),N=i([Controller("registry"),n(0,Inject(W))],N);var mt=class{};mt=i([Module({imports:[M],controllers:[N],providers:[W],exports:[W]})],mt);var ke={provide:"DATABASE",useFactory:()=>{let u=process.cwd();return new DevFlowDatabase(u)}},gt=class{};gt=i([Global(),Module({providers:[ke],exports:[ke]})],gt);var pt=class{intercept(t,e){return e.handle().pipe(map(s=>s&&typeof s=="object"&&"error"in s?s:{ok:true,data:s??null}))}};pt=i([Injectable()],pt);var et=class{constructor(){this.startTime=Date.now();}health(){return {version:"0.2.3",uptime:Date.now()-this.startTime}}};i([Zt(),Get("health")],et.prototype,"health",1),et=i([Controller()],et);var ft=class{};ft=i([Module({imports:[gt,rt,P,j,ct,ut,Y,lt,M,dt,mt,J],controllers:[et],providers:[{provide:APP_INTERCEPTOR,useClass:pt}]})],ft);function we(u){return u===400?m.BAD_REQUEST:u===404?m.PROJECT_NOT_FOUND:u===422?m.VALIDATION_ERROR:m.INTERNAL_ERROR}var V=class{constructor(){this.logger=new Logger(V.name);}catch(t,e){let r=e.switchToHttp().getResponse();if(t instanceof HttpException){let o=t.getStatus(),a=t.getResponse();if(typeof a=="object"&&a!==null&&"error"in a){let l=a.error;if(typeof l=="object"&&l!==null&&"code"in l){r.status(o).send(a);return}let g=typeof a.message=="string"?a.message:"Request failed";r.status(o).send({error:{code:we(o),message:g,details:{}}});return}let c=typeof a=="string"?a:a.message??"Request failed";r.status(o).send({error:{code:we(o),message:c,details:{}}});return}this.logger.error("Unhandled exception",t instanceof Error?t.stack:String(t)),r.status(HttpStatus.INTERNAL_SERVER_ERROR).send({error:{code:m.INTERNAL_ERROR,message:"Internal server error",details:{}}});}};V=i([Catch()],V);async function mr(){let u=new FastifyAdapter,t=await NestFactory.create(ft,u);return t.setGlobalPrefix("api"),t.useGlobalFilters(new V),t.enableCors({origin:true,credentials:true}),u.getInstance().addHook("preParsing",async(s,r,o)=>{if(s.headers["content-length"]==="0"){let a=Buffer.from("{}");return s.headers["content-length"]=String(a.length),Readable.from([a])}return o}),await t.listen({port:parseInt(process.env.PORT||"13337",10),host:"0.0.0.0"}),t}(process.argv[1]?.endsWith("main.js")||process.argv[1]?.endsWith("main.ts")||process.argv[1]?.endsWith("server.js"))&&mr();export{mr as bootstrap};
|
|
10
|
+
`),e.raw.end();}});e.raw.on("close",()=>n.unsubscribe());}async approve(t){return await this.service.approveRun(t),{approved:true}}async reject(t,e){return await this.service.rejectRun(t,e.reason),{rejected:true}}async nextStep(t){return this.service.getNextStep(t)}};i([Get()],b.prototype,"list",1),i([Post(":type/run"),r(0,Param("type")),r(1,Body())],b.prototype,"run",1),i([Get("runs"),r(0,Query("limit")),r(1,Query("offset"))],b.prototype,"listRuns",1),i([Get("runs/:id"),r(0,Param("id"))],b.prototype,"getRun",1),i([Get("runs/:id/stream"),r(0,Param("id")),r(1,Res())],b.prototype,"stream",1),i([Post("runs/:id/approve"),r(0,Param("id"))],b.prototype,"approve",1),i([Post("runs/:id/reject"),r(0,Param("id")),r(1,Body())],b.prototype,"reject",1),i([Get("next-step"),r(0,Query("runId"))],b.prototype,"nextStep",1),b=i([Controller("workflows"),r(0,Inject(B))],b);var it=class{};it=i([Module({controllers:[b],providers:[B],exports:[B]})],it);var L=class{constructor(t){this.projectsService=t;}getEngine(t){return new KnowledgeEngine({projectRoot:t})}async onModuleInit(){this._initKnowledge();}async _initKnowledge(){let t=this.projectsService.getActiveProjectRoot()??process.env.DEVFLOW_PROJECT_ROOT??process.cwd();try{let e=this.getEngine(t),s=await loadPlugins(),n=Array.from(s.values());for(let l of n)for(let u of l.knowledge?.sources??[])await e.registerSource({...u,version:u.version||l.meta.version});let o=await e.getSources(),a=Date.now()-10080*60*1e3;for(let l of o)(!l.lastSyncTime||l.lastSyncTime<a)&&await e.syncDocs(l.source.name);}catch{}}async search(t,e,s){return this.getEngine(t).search(e,{sources:s&&s!=="all"?[s]:void 0})}async sync(t,e){return this.getEngine(t).syncDocs(e??"")}async getSources(t){return this.getEngine(t).getSources()}};L=i([Injectable(),r(0,Inject(p))],L);var $=class{constructor(t,e){this.service=t;this.projects=e;}resolveRootPath(t,e){let s=t??e??this.projects.getActiveProjectRoot();if(!s)throw new BadRequestException("rootPath is required \u2014 no active project connected");return s}async search(t,e,s,n){return this.service.search(this.resolveRootPath(t,n),e??"",s)}async sync(t,e){return this.service.sync(this.resolveRootPath(t.rootPath,e),t.pluginName)}async getSources(t,e){return this.service.getSources(this.resolveRootPath(t,e))}};i([Get("search"),r(0,Query("rootPath")),r(1,Query("q")),r(2,Query("scope")),r(3,Headers("x-devflow-project"))],$.prototype,"search",1),i([Post("sync"),r(0,Body()),r(1,Headers("x-devflow-project"))],$.prototype,"sync",1),i([Get("sources"),r(0,Query("rootPath")),r(1,Headers("x-devflow-project"))],$.prototype,"getSources",1),$=i([Controller("knowledge"),r(0,Inject(L)),r(1,Inject(p))],$);var ot=class{};ot=i([Module({imports:[T,v],controllers:[$],providers:[L],exports:[L]})],ot);var q=class{constructor(){this.results=[];this.scenarioIds=[];this.engine=new BenchmarkEngine,this.registerDefaultScenarios();}registerDefaultScenarios(){let t=[{id:"understand-codebase",category:"understand",desc:"\u7406\u89E3\u4EE3\u7801\u5E93\u67B6\u6784",expectedFiles:2},{id:"modify-component",category:"modify",desc:"\u4FEE\u6539 React \u7EC4\u4EF6",expectedFiles:1,expectedComponents:1},{id:"review-code",category:"review",desc:"\u4EE3\u7801\u5BA1\u67E5",expectedIssues:2}];for(let e of t)this.engine.registerScenario(e),this.scenarioIds.push(e.id);}async runScenarioSet(t){let e=async a=>({prepTimeMs:1e3+Math.random()*500,tokenCount:500+Math.floor(Math.random()*200),firstPassSuccess:Math.random()>.5,reworkCount:Math.floor(Math.random()*3),durationMs:5e3+Math.random()*3e3}),s=async a=>({prepTimeMs:500+Math.random()*300,tokenCount:300+Math.floor(Math.random()*100),firstPassSuccess:Math.random()>.2,reworkCount:Math.floor(Math.random()*2),durationMs:3e3+Math.random()*2e3}),n=t??this.scenarioIds,o=await this.engine.runScenarioBatch(n,e,s);return this.results=o,o}async getScenarioResults(){return this.results.length===0&&await this.runScenarioSet(),this.results}async getComparisonSummary(){let t=await this.getScenarioResults(),e=t.length;return {totalScenarios:e,avgTimeSavedRate:t.reduce((s,n)=>s+n.comparison.timeSavedRate,0)/e,avgTokenReductionRate:t.reduce((s,n)=>s+n.comparison.tokenReductionRate,0)/e,avgFirstPassLift:t.reduce((s,n)=>s+n.comparison.firstPassLift,0)/e,avgReworkReductionRate:t.reduce((s,n)=>s+n.comparison.reworkReductionRate,0)/e}}async getExperimentalRoiSummary(){let t=await this.getComparisonSummary();return {totalScenarios:t.totalScenarios,avgTimeSavedRate:t.avgTimeSavedRate,avgTokenReductionRate:t.avgTokenReductionRate,avgFirstPassLift:t.avgFirstPassLift,avgReworkReductionRate:t.avgReworkReductionRate,conclusion:"DevFlow shows significant improvement in all metrics"}}};q=i([Injectable()],q);var D=class{constructor(t){this.service=t;}async run(t){return this.service.runScenarioSet(t.scenarioIds)}async getResults(){return this.service.getScenarioResults()}async getComparisonSummary(){return this.service.getComparisonSummary()}async getExperimentalRoiSummary(){return this.service.getExperimentalRoiSummary()}};i([Post("run"),r(0,Body())],D.prototype,"run",1),i([Get("results")],D.prototype,"getResults",1),i([Get("summary")],D.prototype,"getComparisonSummary",1),i([Get("roi-summary")],D.prototype,"getExperimentalRoiSummary",1),D=i([Controller("benchmark"),r(0,Inject(q))],D);var at=class{};at=i([Module({controllers:[D],providers:[q],exports:[q]})],at);var G=class{constructor(t){this.telemetryService=t;this.plugins=new Map;this.installRecords=[];}async list(t,e){let s=Array.from(this.plugins.values());if(t){let n=t.toLowerCase();s=s.filter(o=>o.name.toLowerCase().includes(n)||o.description.toLowerCase().includes(n));}return e&&(s=s.filter(n=>n.tags.includes(e))),s}async getByName(t){let e=this.plugins.get(t);if(!e)throw new NotFoundException({error:{code:d.PLUGIN_NOT_FOUND,message:`Plugin "${t}" not found`,details:{}}});return e}async publish(t){let e=t.npmPackage.replace(/^@devflow-tools\/plugin-/,""),s={name:e,npmPackage:t.npmPackage,version:t.version,description:t.description,tags:t.tags??[],createdAt:Date.now()};return this.plugins.set(e,s),s}async install(t,e){let s=t.startsWith("@devflow-tools/plugin-")?t:`@devflow-tools/plugin-${t}`,n=t.replace(/^@devflow-tools\/plugin-/,"");return this.plugins.set(n,{name:n,npmPackage:s,version:"0.1.0",description:"Installed plugin",tags:[],createdAt:Date.now()}),e&&await this.recordPluginInstall(n,e),{ok:true,name:n}}async uninstall(t,e){let s=t.replace(/^@devflow-tools\/plugin-/,"");return this.plugins.delete(s),e&&await this.recordPluginUninstall(s,e),{ok:true,name:s}}async recordPluginInstall(t,e){let s=this.installRecords.find(n=>n.pluginName===t&&n.projectRoot===e);s?s.uninstalledAt=void 0:this.installRecords.push({pluginName:t,projectRoot:e,installedAt:Date.now()});}async recordPluginUninstall(t,e){let s=this.installRecords.find(n=>n.pluginName===t&&n.projectRoot===e);s&&(s.uninstalledAt=Date.now());}async listInstalledProjects(t){return this.installRecords.filter(e=>e.pluginName===t&&!e.uninstalledAt).map(e=>e.projectRoot)}async buildPluginEffectiveness(t){let s=(await this.listInstalledProjects(t)).length,n=await this.telemetryService.getPluginUsageStats(t),o=s>0?n.activeProjects/s:0,a=n.totalRuns>0?n.successfulRuns/n.totalRuns:0,l="optimize";return o>.7&&a>.8?l="install":(o<.3||a<.5)&&(l="remove"),{name:t,installCount:s,usageCount:n.totalRuns,activeRate:o,successRate:a,lastUsedAt:n.lastUsedAt,recommendation:l}}async getPluginEffectiveness(t){let e=t?this.installRecords.filter(o=>o.projectRoot===t&&!o.uninstalledAt):this.installRecords.filter(o=>!o.uninstalledAt),s=[...new Set(e.map(o=>o.pluginName))],n=[];for(let o of s){let a=await this.buildPluginEffectiveness(o);n.push(a);}return n}};G=i([Injectable(),r(0,Inject(P))],G);var A=class{constructor(t){this.service=t;}async list(t,e){return this.service.list(t,e)}async getPluginEffectiveness(t){return this.service.getPluginEffectiveness(t)}async getByName(t){return this.service.getByName(t)}async publish(t){return this.service.publish(t)}async install(t,e){return this.service.install(t.name,t.rootPath??e)}async uninstall(t,e,s){return this.service.uninstall(t,e.rootPath??s)}};i([Get("plugins"),r(0,Query("search")),r(1,Query("tag"))],A.prototype,"list",1),i([Get("plugins/effectiveness"),r(0,Query("rootPath"))],A.prototype,"getPluginEffectiveness",1),i([Get("plugins/:name"),r(0,Param("name"))],A.prototype,"getByName",1),i([Post("plugins"),r(0,Body())],A.prototype,"publish",1),i([Post("plugins/install"),r(0,Body()),r(1,Headers("x-devflow-project"))],A.prototype,"install",1),i([Post("plugins/:name/uninstall"),r(0,Param("name")),r(1,Body()),r(2,Headers("x-devflow-project"))],A.prototype,"uninstall",1),A=i([Controller("registry"),r(0,Inject(G))],A);var ct=class{};ct=i([Module({imports:[H],controllers:[A],providers:[G],exports:[G]})],ct);var he={provide:"DATABASE",useFactory:()=>{let c=process.env.DEVFLOW_STATE_DIR??join(homedir(),".devflow","global");return new DevFlowDatabase(c)}},ut=class{};ut=i([Global(),Module({providers:[he],exports:[he]})],ut);var lt=class{intercept(t,e){return e.handle().pipe(map(s=>s&&typeof s=="object"&&"error"in s?s:{ok:true,data:s??null}))}};lt=i([Injectable()],lt);var X=class{constructor(){this.startTime=Date.now();}health(){return {version:"0.2.3",uptime:Date.now()-this.startTime}}};i([Yt(),Get("health")],X.prototype,"health",1),X=i([Controller()],X);var dt=class{};dt=i([Module({imports:[ut,z,v,T,nt,ot,it,at,ct],controllers:[X],providers:[{provide:APP_INTERCEPTOR,useClass:lt}]})],dt);function ve(c){return c===400?d.BAD_REQUEST:c===404?d.PROJECT_NOT_FOUND:c===422?d.VALIDATION_ERROR:d.INTERNAL_ERROR}var Q=class{constructor(){this.logger=new Logger(Q.name);}catch(t,e){let n=e.switchToHttp().getResponse();if(t instanceof HttpException){let o=t.getStatus(),a=t.getResponse();if(typeof a=="object"&&a!==null&&"error"in a){let u=a.error;if(typeof u=="object"&&u!==null&&"code"in u){n.status(o).send(a);return}let y=typeof a.message=="string"?a.message:"Request failed";n.status(o).send({error:{code:ve(o),message:y,details:{}}});return}let l=typeof a=="string"?a:a.message??"Request failed";n.status(o).send({error:{code:ve(o),message:l,details:{}}});return}this.logger.error("Unhandled exception",t instanceof Error?t.stack:String(t)),n.status(HttpStatus.INTERNAL_SERVER_ERROR).send({error:{code:d.INTERNAL_ERROR,message:"Internal server error",details:{}}});}};Q=i([Catch()],Q);async function dr(){let c=new FastifyAdapter,t=await NestFactory.create(dt,c);return t.setGlobalPrefix("api"),t.useGlobalFilters(new Q),t.enableCors({origin:true,credentials:true}),c.getInstance().addHook("preParsing",async(s,n,o)=>{if(s.headers["content-length"]==="0"){let a=Buffer.from("{}");return s.headers["content-length"]=String(a.length),Readable.from([a])}return o}),await t.listen({port:parseInt(process.env.PORT||"13337",10),host:"127.0.0.1"}),t}(process.argv[1]?.endsWith("main.js")||process.argv[1]?.endsWith("main.ts")||process.argv[1]?.endsWith("server.js"))&&dr();export{dr as bootstrap};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devflow-tools/devflow",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "DevFlow - Developer Intelligence Platform (Distribution Package)",
|
|
6
6
|
"bin": {
|
|
@@ -10,22 +10,22 @@
|
|
|
10
10
|
"build": "tsup",
|
|
11
11
|
"build:watch": "tsup --watch",
|
|
12
12
|
"clean": "rm -rf dist",
|
|
13
|
-
"postbuild": "cp ../../apps/server/public/fallback.html dist/fallback.html && npx tsx scripts/bundle-plugin.ts && mkdir -p ../../plugins/claude-code/dist/hooks && cp dist/hooks
|
|
13
|
+
"postbuild": "cp ../../apps/server/public/fallback.html dist/fallback.html && npx tsx scripts/bundle-plugin.ts && mkdir -p ../../plugins/claude-code/dist/hooks && cp dist/hooks/*.js ../../plugins/claude-code/dist/hooks/",
|
|
14
14
|
"postinstall": "node scripts/postinstall.js"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@colbymchenry/codegraph": "^1.1.1",
|
|
18
|
-
"@devflow-tools/adapters": "^0.8.
|
|
19
|
-
"@devflow-tools/benchmark": "^0.8.
|
|
20
|
-
"@devflow-tools/context-engine": "^0.8.
|
|
21
|
-
"@devflow-tools/database": "^0.8.
|
|
22
|
-
"@devflow-tools/knowledge-engine": "^0.8.
|
|
23
|
-
"@devflow-tools/mcp-server": "^0.8.
|
|
24
|
-
"@devflow-tools/memory-engine": "^0.8.
|
|
25
|
-
"@devflow-tools/sdk": "^0.8.
|
|
26
|
-
"@devflow-tools/server": "^0.8.
|
|
27
|
-
"@devflow-tools/telemetry": "^0.8.
|
|
28
|
-
"@devflow-tools/workflow-engine": "^0.8.
|
|
18
|
+
"@devflow-tools/adapters": "^0.8.11",
|
|
19
|
+
"@devflow-tools/benchmark": "^0.8.11",
|
|
20
|
+
"@devflow-tools/context-engine": "^0.8.11",
|
|
21
|
+
"@devflow-tools/database": "^0.8.11",
|
|
22
|
+
"@devflow-tools/knowledge-engine": "^0.8.11",
|
|
23
|
+
"@devflow-tools/mcp-server": "^0.8.11",
|
|
24
|
+
"@devflow-tools/memory-engine": "^0.8.11",
|
|
25
|
+
"@devflow-tools/sdk": "^0.8.11",
|
|
26
|
+
"@devflow-tools/server": "^0.8.11",
|
|
27
|
+
"@devflow-tools/telemetry": "^0.8.11",
|
|
28
|
+
"@devflow-tools/workflow-engine": "^0.8.11",
|
|
29
29
|
"@inquirer/prompts": "^7.10.1",
|
|
30
30
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
31
31
|
"@nestjs/common": "^10.4.0",
|
|
@@ -52,5 +52,5 @@
|
|
|
52
52
|
"plugin-registry.json",
|
|
53
53
|
"scripts/postinstall.js"
|
|
54
54
|
],
|
|
55
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "a0a0b61377aa88ebbd380f50a5d532f63175ef45"
|
|
56
56
|
}
|
package/plugin-registry.json
CHANGED
|
@@ -1,34 +1,50 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "1.0.0",
|
|
3
|
-
"lastUpdated": "2026-07-
|
|
3
|
+
"lastUpdated": "2026-07-10T02:47:16.762Z",
|
|
4
4
|
"plugins": [
|
|
5
5
|
{
|
|
6
6
|
"name": "@devflow-tools/plugin-animation",
|
|
7
|
-
"version": "0.8.
|
|
7
|
+
"version": "0.8.10",
|
|
8
8
|
"description": "",
|
|
9
9
|
"tags": [],
|
|
10
10
|
"compatibleStacks": [
|
|
11
11
|
"animation"
|
|
12
12
|
],
|
|
13
|
-
"size": "
|
|
13
|
+
"size": "820K",
|
|
14
|
+
"author": "DevFlow Team",
|
|
15
|
+
"homepage": ""
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "@devflow-tools/claude-code-plugin",
|
|
19
|
+
"version": "0.8.10",
|
|
20
|
+
"description": "DevFlow — Developer Intelligence Platform for Claude Code",
|
|
21
|
+
"tags": [
|
|
22
|
+
"pi-package",
|
|
23
|
+
"skills",
|
|
24
|
+
"development",
|
|
25
|
+
"context",
|
|
26
|
+
"knowledge-base"
|
|
27
|
+
],
|
|
28
|
+
"compatibleStacks": [],
|
|
29
|
+
"size": "276K",
|
|
14
30
|
"author": "DevFlow Team",
|
|
15
31
|
"homepage": ""
|
|
16
32
|
},
|
|
17
33
|
{
|
|
18
34
|
"name": "@devflow-tools/plugin-css",
|
|
19
|
-
"version": "0.8.
|
|
35
|
+
"version": "0.8.10",
|
|
20
36
|
"description": "",
|
|
21
37
|
"tags": [],
|
|
22
38
|
"compatibleStacks": [
|
|
23
39
|
"css"
|
|
24
40
|
],
|
|
25
|
-
"size": "
|
|
41
|
+
"size": "792K",
|
|
26
42
|
"author": "DevFlow Team",
|
|
27
43
|
"homepage": ""
|
|
28
44
|
},
|
|
29
45
|
{
|
|
30
46
|
"name": "@devflow-tools/plugin-docker",
|
|
31
|
-
"version": "0.8.
|
|
47
|
+
"version": "0.8.10",
|
|
32
48
|
"description": "",
|
|
33
49
|
"tags": [],
|
|
34
50
|
"compatibleStacks": [
|
|
@@ -40,31 +56,31 @@
|
|
|
40
56
|
},
|
|
41
57
|
{
|
|
42
58
|
"name": "@devflow-tools/plugin-electron",
|
|
43
|
-
"version": "0.8.
|
|
59
|
+
"version": "0.8.10",
|
|
44
60
|
"description": "",
|
|
45
61
|
"tags": [],
|
|
46
62
|
"compatibleStacks": [
|
|
47
63
|
"electron"
|
|
48
64
|
],
|
|
49
|
-
"size": "
|
|
65
|
+
"size": "888K",
|
|
50
66
|
"author": "DevFlow Team",
|
|
51
67
|
"homepage": ""
|
|
52
68
|
},
|
|
53
69
|
{
|
|
54
70
|
"name": "@devflow-tools/plugin-git",
|
|
55
|
-
"version": "0.8.
|
|
71
|
+
"version": "0.8.10",
|
|
56
72
|
"description": "",
|
|
57
73
|
"tags": [],
|
|
58
74
|
"compatibleStacks": [
|
|
59
75
|
"git"
|
|
60
76
|
],
|
|
61
|
-
"size": "
|
|
77
|
+
"size": "820K",
|
|
62
78
|
"author": "DevFlow Team",
|
|
63
79
|
"homepage": ""
|
|
64
80
|
},
|
|
65
81
|
{
|
|
66
82
|
"name": "@devflow-tools/plugin-graphql",
|
|
67
|
-
"version": "0.8.
|
|
83
|
+
"version": "0.8.10",
|
|
68
84
|
"description": "",
|
|
69
85
|
"tags": [],
|
|
70
86
|
"compatibleStacks": [
|
|
@@ -76,31 +92,31 @@
|
|
|
76
92
|
},
|
|
77
93
|
{
|
|
78
94
|
"name": "@devflow-tools/plugin-nest",
|
|
79
|
-
"version": "0.8.
|
|
95
|
+
"version": "0.8.10",
|
|
80
96
|
"description": "",
|
|
81
97
|
"tags": [],
|
|
82
98
|
"compatibleStacks": [
|
|
83
99
|
"nest"
|
|
84
100
|
],
|
|
85
|
-
"size": "
|
|
101
|
+
"size": "920K",
|
|
86
102
|
"author": "DevFlow Team",
|
|
87
103
|
"homepage": ""
|
|
88
104
|
},
|
|
89
105
|
{
|
|
90
106
|
"name": "@devflow-tools/plugin-nextjs",
|
|
91
|
-
"version": "0.8.
|
|
107
|
+
"version": "0.8.10",
|
|
92
108
|
"description": "",
|
|
93
109
|
"tags": [],
|
|
94
110
|
"compatibleStacks": [
|
|
95
111
|
"nextjs"
|
|
96
112
|
],
|
|
97
|
-
"size": "
|
|
113
|
+
"size": "820K",
|
|
98
114
|
"author": "DevFlow Team",
|
|
99
115
|
"homepage": ""
|
|
100
116
|
},
|
|
101
117
|
{
|
|
102
118
|
"name": "@devflow-tools/plugin-performance",
|
|
103
|
-
"version": "0.8.
|
|
119
|
+
"version": "0.8.10",
|
|
104
120
|
"description": "",
|
|
105
121
|
"tags": [],
|
|
106
122
|
"compatibleStacks": [
|
|
@@ -112,7 +128,7 @@
|
|
|
112
128
|
},
|
|
113
129
|
{
|
|
114
130
|
"name": "@devflow-tools/plugin-react",
|
|
115
|
-
"version": "0.8.
|
|
131
|
+
"version": "0.8.10",
|
|
116
132
|
"description": "",
|
|
117
133
|
"tags": [],
|
|
118
134
|
"compatibleStacks": [
|
|
@@ -124,43 +140,43 @@
|
|
|
124
140
|
},
|
|
125
141
|
{
|
|
126
142
|
"name": "@devflow-tools/plugin-tailwind",
|
|
127
|
-
"version": "0.8.
|
|
143
|
+
"version": "0.8.10",
|
|
128
144
|
"description": "",
|
|
129
145
|
"tags": [],
|
|
130
146
|
"compatibleStacks": [
|
|
131
147
|
"tailwind"
|
|
132
148
|
],
|
|
133
|
-
"size": "
|
|
149
|
+
"size": "848K",
|
|
134
150
|
"author": "DevFlow Team",
|
|
135
151
|
"homepage": ""
|
|
136
152
|
},
|
|
137
153
|
{
|
|
138
154
|
"name": "@devflow-tools/plugin-taro",
|
|
139
|
-
"version": "0.8.
|
|
155
|
+
"version": "0.8.10",
|
|
140
156
|
"description": "",
|
|
141
157
|
"tags": [],
|
|
142
158
|
"compatibleStacks": [
|
|
143
159
|
"taro"
|
|
144
160
|
],
|
|
145
|
-
"size": "
|
|
161
|
+
"size": "856K",
|
|
146
162
|
"author": "DevFlow Team",
|
|
147
163
|
"homepage": ""
|
|
148
164
|
},
|
|
149
165
|
{
|
|
150
166
|
"name": "@devflow-tools/plugin-ui-layout",
|
|
151
|
-
"version": "0.8.
|
|
167
|
+
"version": "0.8.10",
|
|
152
168
|
"description": "",
|
|
153
169
|
"tags": [],
|
|
154
170
|
"compatibleStacks": [
|
|
155
171
|
"ui-layout"
|
|
156
172
|
],
|
|
157
|
-
"size": "
|
|
173
|
+
"size": "788K",
|
|
158
174
|
"author": "DevFlow Team",
|
|
159
175
|
"homepage": ""
|
|
160
176
|
},
|
|
161
177
|
{
|
|
162
178
|
"name": "@devflow-tools/plugin-vue",
|
|
163
|
-
"version": "0.8.
|
|
179
|
+
"version": "0.8.10",
|
|
164
180
|
"description": "",
|
|
165
181
|
"tags": [],
|
|
166
182
|
"compatibleStacks": [
|