@devflow-tools/claude-code-plugin 0.8.10 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +44 -15
  2. package/dist/hooks/post-tool-use.js +2 -114
  3. package/dist/hooks/pre-tool-use.js +2 -2
  4. package/dist/hooks/stop.js +2 -118
  5. package/dist/skills/devflow:context/SKILL.md +0 -2
  6. package/dist/skills/devflow:docker/SKILL.md +0 -2
  7. package/dist/skills/devflow:electron/SKILL.md +0 -2
  8. package/dist/skills/devflow:graph/SKILL.md +0 -2
  9. package/dist/skills/devflow:graphql/SKILL.md +0 -2
  10. package/dist/skills/devflow:knowledge/SKILL.md +0 -2
  11. package/dist/skills/devflow:memory/SKILL.md +0 -2
  12. package/dist/skills/devflow:nest/SKILL.md +0 -2
  13. package/dist/skills/devflow:nextjs/SKILL.md +0 -2
  14. package/dist/skills/devflow:performance/SKILL.md +0 -2
  15. package/dist/skills/devflow:react/SKILL.md +0 -2
  16. package/dist/skills/devflow:tailwind/SKILL.md +0 -2
  17. package/dist/skills/devflow:taro/SKILL.md +0 -2
  18. package/dist/skills/devflow:vue/SKILL.md +0 -2
  19. package/dist/skills/devflow:workflow/SKILL.md +0 -2
  20. package/hooks/post-tool-use +2 -1
  21. package/hooks/pre-tool-use +2 -1
  22. package/hooks/stop +2 -1
  23. package/hooks.json +12 -0
  24. package/package.json +3 -3
  25. package/skills/devflow:animation/SKILL.md +0 -1
  26. package/skills/devflow:css/SKILL.md +0 -1
  27. package/skills/devflow:docker/SKILL.md +0 -20
  28. package/skills/devflow:electron/SKILL.md +0 -20
  29. package/skills/devflow:git/SKILL.md +0 -1
  30. package/skills/devflow:graphql/SKILL.md +0 -22
  31. package/skills/devflow:nest/SKILL.md +0 -22
  32. package/skills/devflow:nextjs/SKILL.md +0 -22
  33. package/skills/devflow:performance/SKILL.md +0 -20
  34. package/skills/devflow:react/SKILL.md +0 -30
  35. package/skills/devflow:tailwind/SKILL.md +0 -20
  36. package/skills/devflow:taro/SKILL.md +0 -20
  37. package/skills/devflow:ui-layout/SKILL.md +0 -1
  38. package/skills/devflow:vue/SKILL.md +0 -24
package/README.md CHANGED
@@ -1,24 +1,53 @@
1
1
  # @devflow-tools/claude-code-plugin
2
2
 
3
- DevFlow plugin for Claude Code — provides developer intelligence platform inside Claude Code.
4
-
5
- > **Note:** This package is not published to npm directly. It's bundled within `@devflow-tools/cli` and deployed to `~/.claude/plugins/cache/`.
6
-
7
- ## What You Get
8
-
9
- - **Context Engine** — Search code by natural language. Use `/devflow:context`
10
- - **Graph Engine** — View architecture layers and dependency graphs. Use `/devflow:graph`
11
- - **Memory Engine** — Access project conventions and past decisions. Use `/devflow:memory`
12
- - **Knowledge Engine** — Search official docs for React, Vue, NestJS, and more. Use `/devflow:knowledge`
13
- - **Workflow Engine** — Run standardized dev workflows. Use `/devflow:workflow`
14
- - **Domain Plugins** — Specialized expertise for 14 frameworks via `/devflow:react`, `/devflow:vue`, etc.
15
-
16
- ## Installation
3
+ DevFlow Claude Code 插件 — 在 Claude Code 中提供开发者智能平台的完整能力。
4
+
5
+ > **Note:** 此包不直接发布到 npm。由 `@devflow-tools/cli` 打包并部署到 `~/.claude/plugins/cache/`。
6
+
7
+ ## 能力
8
+
9
+ 安装后,在 Claude Code 中可以使用以下 slash commands 和 MCP tools:
10
+
11
+ ### Slash Commands
12
+
13
+ | 命令 | 功能 |
14
+ |------|------|
15
+ | `/devflow:context` | 代码上下文检索 — 自然语言查询最相关代码 |
16
+ | `/devflow:graph` | 依赖图谱 — 查看架构分层和文件依赖 |
17
+ | `/devflow:memory` | 项目记忆 — 约定、技术栈、历史决策 |
18
+ | `/devflow:knowledge` | 知识库搜索 — 官方文档查询 |
19
+ | `/devflow:workflow` | 工作流 — 标准化开发流程 |
20
+ | `/devflow:react` | React 专家能力 — Bug 诊断、组件重构、性能审计 |
21
+ | `/devflow:vue` | Vue 3 专家能力 |
22
+ | `/devflow:nest` | NestJS 专家能力 |
23
+ | `/devflow:nextjs` | Next.js 专家能力 |
24
+ | `/devflow:electron` | Electron 专家能力 |
25
+ | `/devflow:graphql` | GraphQL 专家能力 |
26
+ | `/devflow:docker` | Docker 专家能力 |
27
+ | `/devflow:css` | CSS 专家能力 |
28
+ | `/devflow:tailwind` | Tailwind 专家能力 |
29
+ | `/devflow:animation` | Animation 专家能力 |
30
+ | `/devflow:performance` | Web 性能专家能力 |
31
+ | `/devflow:taro` | Taro 跨端专家能力 |
32
+ | `/devflow:ui-layout` | UI Layout 专家能力 |
33
+ | `/devflow:git` | Git 专家能力 |
34
+
35
+ ### Hooks
36
+
37
+ 插件提供以下 Claude Code hooks:
38
+
39
+ | Hook | 触发时机 | 功能 |
40
+ |------|---------|------|
41
+ | `PreToolUse` | Tool 调用前 | 记录 telemetry 事件、保存 execution context |
42
+ | `PostToolUse` | Tool 调用后 | 回填 tool output、发送 memory event(exitCode、stderr) |
43
+ | `Stop` | Claude Code 停止 | 完成 skill execution 记录、聚合真实统计数据 |
44
+
45
+ ## 安装
17
46
 
18
47
  ```bash
19
- # The plugin is installed automatically via devflow init
20
48
  npm install -g @devflow-tools/cli
21
49
  devflow init
50
+ # 插件自动部署到 ~/.claude/plugins/
22
51
  ```
23
52
 
24
53
  ## License
@@ -1,114 +1,2 @@
1
- #!/usr/bin/env node
2
- /**
3
- * DevFlow PostToolUse Hook
4
- * 1. Records memory event with heuristic error detection
5
- * 2. Backfills tool_call_events output (from PreToolUse's last-event-id)
6
- */
7
-
8
- const http = require('http');
9
- const fs = require('fs');
10
- const path = require('path');
11
- const os = require('os');
12
-
13
- const SERVER_URL = process.env.DEVFLOW_SERVER_URL || 'http://127.0.0.1:13337';
14
- const API_KEY = process.env.DEVFLOW_API_KEY || 'dev-key-000000';
15
- const PROJECT_ROOT = process.env.CLAUDE_PROJECT_DIR || process.cwd();
16
- const SESSION_ID = `session:${PROJECT_ROOT.split('/').pop() || 'default'}`;
17
-
18
- function postJSON(urlPath, data) {
19
- return new Promise((resolve, reject) => {
20
- const body = JSON.stringify(data);
21
- const url = new URL(urlPath, SERVER_URL);
22
- const options = {
23
- hostname: url.hostname,
24
- port: url.port,
25
- path: url.pathname,
26
- method: 'POST',
27
- headers: {
28
- 'Content-Type': 'application/json',
29
- 'X-API-Key': API_KEY,
30
- 'Content-Length': Buffer.byteLength(body),
31
- },
32
- timeout: 5000,
33
- };
34
- const req = http.request(options, (res) => {
35
- let chunks = [];
36
- res.on('data', (c) => chunks.push(c));
37
- res.on('end', () => resolve(Buffer.concat(chunks).toString()));
38
- });
39
- req.on('error', () => reject(new Error('request failed')));
40
- req.write(body);
41
- req.end();
42
- });
43
- }
44
-
45
- async function main() {
46
- const inputJson = process.argv[2];
47
- if (!inputJson) {
48
- process.exit(0);
49
- }
50
-
51
- let data;
52
- try {
53
- data = JSON.parse(inputJson);
54
- } catch {
55
- process.exit(0);
56
- }
57
-
58
- const toolName = data.tool_name || '';
59
- const toolInput = data.tool_input || {};
60
- const toolResponse = data.tool_response || {};
61
-
62
- // Extract command from Bash tool input
63
- const command = typeof toolInput === 'object' && toolInput.command
64
- ? toolInput.command
65
- : '';
66
-
67
- // Heuristic error detection from tool_response
68
- const responseStr = typeof toolResponse === 'string'
69
- ? toolResponse
70
- : JSON.stringify(toolResponse);
71
- const hasErrorSignal = /error:|traceback|fatal|killed|command not found|ENOENT/i.test(responseStr);
72
- const exitCode = hasErrorSignal ? 1 : 0;
73
- const stderr = hasErrorSignal ? responseStr.slice(0, 500) : null;
74
-
75
- // 1. Record memory event
76
- const evt = {
77
- id: `evt_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`,
78
- sessionId: SESSION_ID,
79
- tool: toolName,
80
- command: command || toolName,
81
- exitCode,
82
- stderr,
83
- durationMs: 0,
84
- createdAt: Date.now(),
85
- };
86
-
87
- try {
88
- await postJSON(`/api/memory/events?rootPath=${encodeURIComponent(PROJECT_ROOT)}`, evt);
89
- } catch {}
90
-
91
- // 2. Backfill tool_call_events output
92
- try {
93
- const devflowDir = path.join(os.homedir(), '.devflow');
94
- const lastEventFile = path.join(devflowDir, 'last-event-id');
95
- const execFile = path.join(devflowDir, 'current-execution-id');
96
-
97
- if (fs.existsSync(lastEventFile) && fs.existsSync(execFile)) {
98
- const eventId = fs.readFileSync(lastEventFile, 'utf-8').trim();
99
- const execId = fs.readFileSync(execFile, 'utf-8').trim();
100
-
101
- const output = typeof toolResponse === 'string'
102
- ? { text: toolResponse.slice(0, 1000) }
103
- : toolResponse;
104
-
105
- await postJSON('/api/telemetry/tool-call/output', {
106
- eventId,
107
- executionId: execId,
108
- output,
109
- });
110
- }
111
- } catch {}
112
- }
113
-
114
- main().catch(() => process.exit(0));
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,unlinkSync,readdirSync}from'fs';import {request}from'http';import {join}from'path';import {homedir}from'os';var k=1e4,M=300*1e3;function g(r,t,e){return new Promise(n=>{try{let o=new URL(r),i=request({hostname:o.hostname,port:o.port||80,path:o.pathname+o.search,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":e,"Content-Length":Buffer.byteLength(t)},timeout:5e3},s=>{s.resume(),n(s.statusCode!=null&&s.statusCode>=200&&s.statusCode<300);});i.on("error",()=>n(!1)),i.on("timeout",()=>{i.destroy(),n(!1);}),i.write(t),i.end();}catch{n(false);}})}var l=class{constructor(t){this.retryScheduled=false;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},o=`${this.apiUrl}/api/telemetry/tool-call`;await g(o,JSON.stringify(n),this.apiKey)||this.cacheEvent({type:"tool_call",payload:n});}async sendExecutionStart(t,e,n){let o={executionId:t,skillName:e,startedAt:n},i=`${this.apiUrl}/api/telemetry/skill-execution/start`;await g(i,JSON.stringify(o),this.apiKey)||this.cacheEvent({type:"execution_start",payload:o});}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),o=readFileSync(n,"utf8"),i=JSON.parse(o),s=i.type==="execution_start"?"/api/telemetry/skill-execution/start":"/api/telemetry/tool-call",a=`${this.apiUrl}${s}`;await g(a,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(){this.retryScheduled||(this.retryScheduled=true,setTimeout(()=>{this.retryScheduled=false,this.flushCache().catch(()=>{});},M).unref());}truncateInput(t){let e=JSON.stringify(t);return e.length<=k?t:{_truncated:true,_original_size:e.length,_preview:e.substring(0,k)+"..."}}};var $=1800*1e3;function J(){return process.env.DEVFLOW_STATE_DIR??join(homedir(),".devflow")}var h=class{constructor(t){this.stateDir=J();}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>$?(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 o=`exec_${Date.now()}_${Math.random().toString(36).slice(2,11)}`;return writeFileSync(join(this.stateDir,"current-execution-id"),o),writeFileSync(join(this.stateDir,"current-skill.json"),JSON.stringify({name:t,required_mcp_tools:e?.required_mcp_tools??[],registeredAt:Date.now()})),o}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 p(){return {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow"}}}function j(r){return {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:r}}}async function A(r){try{if(!r||r.trim()==="")return p();let t=JSON.parse(r),e=new h;if(t.tool_name==="Skill"){let d=t.tool_input?.skill;if(d&&d.startsWith("devflow:")){let I=e.startExecution(d);new l().sendExecutionStart(I,d,Date.now()).catch(()=>{});}}let n=e.detect(),o=t.tool_name.startsWith("mcp__devflow__"),i=o?t.tool_name.replace("mcp__devflow__",""):void 0,s=n?.required_mcp_tools??[],a=s.length>0,y=a&&!o,m;y?m=j(`Skill "${n?.name||"unknown"}" requires MCP tools. Use one of: ${s.join(", ")}`):m=p();let D=e.getCurrentExecutionId()??`exec_orphan_${Date.now()}`,w=new l,E={eventId:`evt_${Date.now()}_${Math.random().toString(36).slice(2,11)}`,executionId:D,timestamp:Date.now(),toolName:t.tool_name,toolType:o?"mcp":t.tool_name==="Agent"?"subagent":"direct",isMcpTool:o,mcpToolName:i,mcpEnforced:o&&a,mcpFallback:!o&&a,input:t.tool_input,tokensUsed:0,duration:0,blocked:!1};return w.sendEvent(E).catch(()=>{}),m}catch{return p()}}if(process.argv[1]?.endsWith("pre-tool-use")||process.argv[1]?.endsWith("pre-tool-use.js")){let r="";process.stdin.setEncoding("utf8"),process.stdin.on("data",t=>{r+=t;}),process.stdin.on("end",async()=>{let t=await A(r);console.log(JSON.stringify(t));}),process.stdin.on("error",()=>{console.log(JSON.stringify(p())),process.exit(0);}),setTimeout(()=>{console.log(JSON.stringify(p())),process.exit(0);},4e3).unref();}
2
- export{A as handlePreToolUse};
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};
@@ -1,118 +1,2 @@
1
- #!/usr/bin/env node
2
- /**
3
- * DevFlow Stop Hook
4
- * 1. Completes pending skill execution with REAL aggregated data
5
- * 2. Triggers memory extraction for the session
6
- * 3. Outputs violation summary
7
- */
8
-
9
- const http = require('http');
10
- const fs = require('fs');
11
- const path = require('path');
12
- const os = require('os');
13
-
14
- const SERVER_URL = process.env.DEVFLOW_SERVER_URL || 'http://127.0.0.1:13337';
15
- const API_KEY = process.env.DEVFLOW_API_KEY || 'dev-key-000000';
16
- const PROJECT_ROOT = process.env.CLAUDE_PROJECT_DIR || process.cwd();
17
-
18
- function getJSON(urlPath) {
19
- return new Promise((resolve, reject) => {
20
- const url = new URL(urlPath, SERVER_URL);
21
- http.get(url.toString(), { headers: { 'X-API-Key': API_KEY }, timeout: 5000 }, (res) => {
22
- let chunks = [];
23
- res.on('data', (c) => chunks.push(c));
24
- res.on('end', () => {
25
- try { resolve(JSON.parse(Buffer.concat(chunks).toString())); }
26
- catch { resolve(null); }
27
- });
28
- }).on('error', () => resolve(null));
29
- });
30
- }
31
-
32
- function postJSON(urlPath, data) {
33
- return new Promise((resolve) => {
34
- const body = JSON.stringify(data);
35
- const url = new URL(urlPath, SERVER_URL);
36
- const req = http.request(url.toString(), {
37
- method: 'POST',
38
- headers: { 'Content-Type': 'application/json', 'X-API-Key': API_KEY, 'Content-Length': Buffer.byteLength(body) },
39
- timeout: 5000,
40
- }, (res) => { resolve(null); });
41
- req.on('error', () => resolve(null));
42
- req.write(body);
43
- req.end();
44
- });
45
- }
46
-
47
- async function main() {
48
- const devflowDir = path.join(os.homedir(), '.devflow');
49
- const execFile = path.join(devflowDir, 'current-execution-id');
50
- const skillFile = path.join(devflowDir, 'current-skill.json');
51
-
52
- // ── 1. Complete pending skill execution with REAL counts ──
53
- if (fs.existsSync(execFile)) {
54
- const execId = fs.readFileSync(execFile, 'utf-8').trim();
55
- if (execId) {
56
- try {
57
- // Query real event data from the API
58
- const result = await getJSON(`/api/telemetry/executions/${execId}/events`);
59
- const events = result?.data || [];
60
-
61
- const totalToolCalls = events.length;
62
- const mcpToolCalls = events.filter(e => e.isMcpTool).length;
63
- const directToolCalls = totalToolCalls - mcpToolCalls;
64
- const subagentCount = events.filter(e => e.toolType === 'subagent').length;
65
- const totalTokens = events.reduce((sum, e) => sum + (e.tokensUsed || 0), 0);
66
-
67
- const timestamps = events.map(e => e.timestamp).filter(Boolean);
68
- const totalDuration = timestamps.length >= 2
69
- ? Math.max(...timestamps) - Math.min(...timestamps)
70
- : 0;
71
-
72
- const mcpRate = totalToolCalls > 0
73
- ? Math.round((mcpToolCalls / totalToolCalls) * 10000) / 100
74
- : 0;
75
-
76
- const nowMs = Date.now();
77
-
78
- await postJSON('/api/telemetry/skill-execution/complete', {
79
- executionId: execId,
80
- finishedAt: nowMs,
81
- status: 'completed',
82
- summary: {
83
- totalToolCalls,
84
- mcpToolCalls,
85
- directToolCalls,
86
- subagentCount,
87
- totalTokens,
88
- totalDuration,
89
- mcpComplianceRate: mcpRate,
90
- },
91
- });
92
- } catch (e) {
93
- console.error('[devflow] Stop hook error:', e.message);
94
- }
95
- }
96
- try { fs.unlinkSync(execFile); } catch {}
97
- try { fs.unlinkSync(skillFile); } catch {}
98
- }
99
-
100
- // ── 2. Trigger memory extraction ──
101
- try {
102
- await postJSON(`/api/memory/process?rootPath=${encodeURIComponent(PROJECT_ROOT)}`, {});
103
- } catch {}
104
-
105
- // ── 3. Violation summary ──
106
- try {
107
- const sessionId = require('crypto').createHash('sha256').update(PROJECT_ROOT).digest('hex').slice(0, 16);
108
- const receiptFile = path.join(os.tmpdir(), '.devflow-receipts', `${sessionId}.json`);
109
- if (fs.existsSync(receiptFile)) {
110
- const receipt = JSON.parse(fs.readFileSync(receiptFile, 'utf-8'));
111
- const bypass = receipt.bypassCount || 0;
112
- console.error(`会话违规统计: ${bypass}/3`);
113
- try { fs.unlinkSync(receiptFile); } catch {}
114
- }
115
- } catch {}
116
- }
117
-
118
- main().catch(() => process.exit(0));
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};
@@ -11,7 +11,6 @@ required_mcp_tools:
11
11
  get_project_context / search_symbol
12
12
  </HARD-GATE>
13
13
 
14
-
15
14
  ## MANDATORY FIRST STEP - Skill Registration
16
15
 
17
16
  > **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
@@ -31,7 +30,6 @@ When the skill execution is complete, clean up:
31
30
  rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
32
31
  ```
33
32
 
34
-
35
33
  # /devflow:context
36
34
 
37
35
  ## 执行
@@ -10,7 +10,6 @@ required_mcp_tools:
10
10
  docker_dockerize_project
11
11
  </HARD-GATE>
12
12
 
13
-
14
13
  ## MANDATORY FIRST STEP - Skill Registration
15
14
 
16
15
  > **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
@@ -29,7 +28,6 @@ When the skill execution is complete, clean up:
29
28
  rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
30
29
  ```
31
30
 
32
-
33
31
  # 🐳 DOCKER
34
32
 
35
33
  你是一个 Docker 专家。使用多阶段构建优化镜像,遵循安全和性能最佳实践。遇到问题先查官方文档。
@@ -10,7 +10,6 @@ required_mcp_tools:
10
10
  electron_diagnose_bug
11
11
  </HARD-GATE>
12
12
 
13
-
14
13
  ## MANDATORY FIRST STEP - Skill Registration
15
14
 
16
15
  > **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
@@ -29,7 +28,6 @@ When the skill execution is complete, clean up:
29
28
  rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
30
29
  ```
31
30
 
32
-
33
31
  # ⚛️ ELECTRON
34
32
 
35
33
  你是一个 Electron 专家。使用 contextBridge + IPC 安全通信模式。严格遵循 Electron 安全最佳实践。
@@ -10,7 +10,6 @@ required_mcp_tools:
10
10
  get_dependency_graph
11
11
  </HARD-GATE>
12
12
 
13
-
14
13
  ## MANDATORY FIRST STEP - Skill Registration
15
14
 
16
15
  > **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
@@ -29,7 +28,6 @@ When the skill execution is complete, clean up:
29
28
  rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
30
29
  ```
31
30
 
32
-
33
31
  # /devflow:graph
34
32
 
35
33
  ## 执行
@@ -11,7 +11,6 @@ required_mcp_tools:
11
11
  graphql_new_graphql_type / graphql_diagnose_bug
12
12
  </HARD-GATE>
13
13
 
14
-
15
14
  ## MANDATORY FIRST STEP - Skill Registration
16
15
 
17
16
  > **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
@@ -31,7 +30,6 @@ When the skill execution is complete, clean up:
31
30
  rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
32
31
  ```
33
32
 
34
-
35
33
  # ◈ GRAPHQL
36
34
 
37
35
  你是一个 GraphQL 专家。使用 Schema-First 设计,Apollo Server 实现。遇到问题先查文档,不凭空猜测。
@@ -10,7 +10,6 @@ required_mcp_tools:
10
10
  get_knowledge
11
11
  </HARD-GATE>
12
12
 
13
-
14
13
  ## MANDATORY FIRST STEP - Skill Registration
15
14
 
16
15
  > **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
@@ -29,7 +28,6 @@ When the skill execution is complete, clean up:
29
28
  rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
30
29
  ```
31
30
 
32
-
33
31
  # /devflow:knowledge
34
32
 
35
33
  ## 执行
@@ -10,7 +10,6 @@ required_mcp_tools:
10
10
  get_memory
11
11
  </HARD-GATE>
12
12
 
13
-
14
13
  ## MANDATORY FIRST STEP - Skill Registration
15
14
 
16
15
  > **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
@@ -29,7 +28,6 @@ When the skill execution is complete, clean up:
29
28
  rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
30
29
  ```
31
30
 
32
-
33
31
  # /devflow:memory
34
32
 
35
33
  ## 执行
@@ -11,7 +11,6 @@ required_mcp_tools:
11
11
  nest_new_module / nest_diagnose_bug
12
12
  </HARD-GATE>
13
13
 
14
-
15
14
  ## MANDATORY FIRST STEP - Skill Registration
16
15
 
17
16
  > **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
@@ -31,7 +30,6 @@ When the skill execution is complete, clean up:
31
30
  rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
32
31
  ```
33
32
 
34
-
35
33
  # 🐱 NEST
36
34
 
37
35
  你是一个 NestJS 专家。使用装饰器模式、依赖注入和模块化架构。遵循 SOLID 原则。
@@ -11,7 +11,6 @@ required_mcp_tools:
11
11
  nextjs_new_page / nextjs_diagnose_bug
12
12
  </HARD-GATE>
13
13
 
14
-
15
14
  ## MANDATORY FIRST STEP - Skill Registration
16
15
 
17
16
  > **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
@@ -31,7 +30,6 @@ When the skill execution is complete, clean up:
31
30
  rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
32
31
  ```
33
32
 
34
-
35
33
  # ▲ NEXTJS
36
34
 
37
35
  你是一个 Next.js 14 专家。使用 App Router、React Server Components。默认服务端渲染,按需客户端交互。
@@ -10,7 +10,6 @@ required_mcp_tools:
10
10
  performance_audit_performance
11
11
  </HARD-GATE>
12
12
 
13
-
14
13
  ## MANDATORY FIRST STEP - Skill Registration
15
14
 
16
15
  > **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
@@ -29,7 +28,6 @@ When the skill execution is complete, clean up:
29
28
  rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
30
29
  ```
31
30
 
32
-
33
31
  # ⚡ PERFORMANCE
34
32
 
35
33
  你是一个 Web 性能专家。精通 Core Web Vitals、Bundle 优化和运行时性能。所有优化建议必须有数据依据。
@@ -15,7 +15,6 @@ required_mcp_tools:
15
15
  react_diagnose_bug / react_new_feature / react_audit_performance / react_review_hooks / react_refactor_component / react_new_component
16
16
  </HARD-GATE>
17
17
 
18
-
19
18
  ## MANDATORY FIRST STEP - Skill Registration
20
19
 
21
20
  > **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
@@ -39,7 +38,6 @@ When the skill execution is complete, clean up:
39
38
  rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
40
39
  ```
41
40
 
42
-
43
41
  # ⚛️ REACT
44
42
 
45
43
  你是一个 React 18 专家。使用函数组件、Hooks 和 TypeScript。遇到问题先查文档再给方案,不凭空猜测 API 行为。
@@ -10,7 +10,6 @@ required_mcp_tools:
10
10
  tailwind_new_component
11
11
  </HARD-GATE>
12
12
 
13
-
14
13
  ## MANDATORY FIRST STEP - Skill Registration
15
14
 
16
15
  > **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
@@ -29,7 +28,6 @@ When the skill execution is complete, clean up:
29
28
  rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
30
29
  ```
31
30
 
32
-
33
31
  # 🌊 TAILWIND
34
32
 
35
33
  你是一个 Tailwind CSS 专家。使用 utility-first 方法构建界面。遇到问题先查 Tailwind 官方文档。
@@ -10,7 +10,6 @@ required_mcp_tools:
10
10
  taro_new_page
11
11
  </HARD-GATE>
12
12
 
13
-
14
13
  ## MANDATORY FIRST STEP - Skill Registration
15
14
 
16
15
  > **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
@@ -29,7 +28,6 @@ When the skill execution is complete, clean up:
29
28
  rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
30
29
  ```
31
30
 
32
-
33
31
  # 🛠️ TARO
34
32
 
35
33
  你是一个 Taro 跨端开发专家。使用 Taro 内置组件和 API,确保多端兼容。遇到小程序问题先查文档,不凭经验猜测。
@@ -12,7 +12,6 @@ required_mcp_tools:
12
12
  vue_diagnose_bug / vue_new_component / vue_debug_reactivity
13
13
  </HARD-GATE>
14
14
 
15
-
16
15
  ## MANDATORY FIRST STEP - Skill Registration
17
16
 
18
17
  > **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
@@ -33,7 +32,6 @@ When the skill execution is complete, clean up:
33
32
  rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
34
33
  ```
35
34
 
36
-
37
35
  # 💚 VUE
38
36
 
39
37
  你是一个 Vue 3 专家。使用 Composition API、<script setup> 和 TypeScript。遇到问题先查文档再给方案,不凭空猜测。
@@ -10,7 +10,6 @@ required_mcp_tools:
10
10
  run_workflow
11
11
  </HARD-GATE>
12
12
 
13
-
14
13
  ## MANDATORY FIRST STEP - Skill Registration
15
14
 
16
15
  > **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
@@ -29,7 +28,6 @@ When the skill execution is complete, clean up:
29
28
  rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
30
29
  ```
31
30
 
32
-
33
31
  # /devflow:workflow
34
32
 
35
33
  ## 执行
@@ -5,7 +5,8 @@ INPUT_JSON=$(cat)
5
5
  PROJECT_ROOT="${CLAUDE_PROJECT_DIR:-$(pwd)}"
6
6
 
7
7
  # ── Event Recording via Node.js (best-effort, never blocks hook) ──
8
- HOOK_JS="${CLAUDE_PLUGIN_ROOT:-}/dist/hooks/post-tool-use.js"
8
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
+ HOOK_JS="${CLAUDE_PLUGIN_ROOT:-$SCRIPT_DIR/..}/dist/hooks/post-tool-use.js"
9
10
  if [ -f "$HOOK_JS" ]; then
10
11
  node "$HOOK_JS" "$INPUT_JSON" 2>/dev/null || true
11
12
  fi
@@ -4,7 +4,8 @@ set -euo pipefail
4
4
  # DevFlow PreToolUse Hook — Node.js handler
5
5
  # Falls back to allow if Node.js handler is not available
6
6
 
7
- HOOK_HANDLER="${CLAUDE_PLUGIN_ROOT:-}/dist/hooks/pre-tool-use.js"
7
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
+ HOOK_HANDLER="${CLAUDE_PLUGIN_ROOT:-$SCRIPT_DIR/..}/dist/hooks/pre-tool-use.js"
8
9
 
9
10
  if [ -f "$HOOK_HANDLER" ]; then
10
11
  # Pass stdin through to Node.js handler; fallback to allow on any failure
package/hooks/stop CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
- HOOK_JS="${CLAUDE_PLUGIN_ROOT:-}/dist/hooks/stop.js"
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ HOOK_JS="${CLAUDE_PLUGIN_ROOT:-$SCRIPT_DIR/..}/dist/hooks/stop.js"
5
6
 
6
7
  if [ -f "$HOOK_JS" ]; then
7
8
  node "$HOOK_JS" 2>/dev/null || true
package/hooks.json CHANGED
@@ -35,6 +35,18 @@
35
35
  }
36
36
  ]
37
37
  }
38
+ ],
39
+ "Stop": [
40
+ {
41
+ "matcher": "",
42
+ "hooks": [
43
+ {
44
+ "type": "command",
45
+ "command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/stop\"",
46
+ "async": false
47
+ }
48
+ ]
49
+ }
38
50
  ]
39
51
  }
40
52
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devflow-tools/claude-code-plugin",
3
- "version": "0.8.10",
3
+ "version": "0.9.0",
4
4
  "description": "DevFlow — Developer Intelligence Platform for Claude Code",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -8,7 +8,7 @@
8
8
  "deploy": "npx tsx scripts/inject-gates.ts --deploy"
9
9
  },
10
10
  "devDependencies": {
11
- "@devflow-tools/mcp-server": "^0.8.10"
11
+ "@devflow-tools/mcp-server": "^0.9.0"
12
12
  },
13
13
  "keywords": [
14
14
  "pi-package",
@@ -28,5 +28,5 @@
28
28
  "hooks.json",
29
29
  "skills"
30
30
  ],
31
- "gitHead": "ac4f93d6a52fa40b4126b514e899eee581f8f46e"
31
+ "gitHead": "7872bccedbacd09cc92b983f30b3702db6878125"
32
32
  }
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  name: devflow:animation
3
3
  description: Animation 动画专家 — CSS 动画、Framer Motion、GSAP、Lottie、性能优化
4
- required_mcp_tools: []
5
4
  ---
6
5
 
7
6
  # ✨ ANIMATION
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  name: devflow:css
3
3
  description: CSS 专家 — 布局调试、响应式审查、BEM 规范、性能优化
4
- required_mcp_tools: []
5
4
  ---
6
5
 
7
6
  # 🎨 CSS
@@ -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,7 +1,6 @@
1
1
  ---
2
2
  name: devflow:git
3
3
  description: Git 专家 — 提交规范、分支审查、Changelog 生成、冲突解决
4
- required_mcp_tools: []
5
4
  ---
6
5
 
7
6
  # 🔀 GIT
@@ -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,7 +1,6 @@
1
1
  ---
2
2
  name: devflow:ui-layout
3
3
  description: UI Layout 专家 — 布局模式、组件组合、响应式架构、设计系统
4
- required_mcp_tools: []
5
4
  ---
6
5
 
7
6
  # 📐 UI-LAYOUT
@@ -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