@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.
- package/README.md +44 -15
- package/dist/hooks/post-tool-use.js +2 -114
- package/dist/hooks/pre-tool-use.js +2 -2
- package/dist/hooks/stop.js +2 -118
- package/dist/skills/devflow:context/SKILL.md +0 -2
- package/dist/skills/devflow:docker/SKILL.md +0 -2
- package/dist/skills/devflow:electron/SKILL.md +0 -2
- package/dist/skills/devflow:graph/SKILL.md +0 -2
- package/dist/skills/devflow:graphql/SKILL.md +0 -2
- package/dist/skills/devflow:knowledge/SKILL.md +0 -2
- package/dist/skills/devflow:memory/SKILL.md +0 -2
- package/dist/skills/devflow:nest/SKILL.md +0 -2
- package/dist/skills/devflow:nextjs/SKILL.md +0 -2
- package/dist/skills/devflow:performance/SKILL.md +0 -2
- package/dist/skills/devflow:react/SKILL.md +0 -2
- package/dist/skills/devflow:tailwind/SKILL.md +0 -2
- package/dist/skills/devflow:taro/SKILL.md +0 -2
- package/dist/skills/devflow:vue/SKILL.md +0 -2
- package/dist/skills/devflow:workflow/SKILL.md +0 -2
- package/hooks/post-tool-use +2 -1
- package/hooks/pre-tool-use +2 -1
- package/hooks/stop +2 -1
- package/hooks.json +12 -0
- package/package.json +3 -3
- package/skills/devflow:animation/SKILL.md +0 -1
- package/skills/devflow:css/SKILL.md +0 -1
- package/skills/devflow:docker/SKILL.md +0 -20
- package/skills/devflow:electron/SKILL.md +0 -20
- package/skills/devflow:git/SKILL.md +0 -1
- package/skills/devflow:graphql/SKILL.md +0 -22
- package/skills/devflow:nest/SKILL.md +0 -22
- package/skills/devflow:nextjs/SKILL.md +0 -22
- package/skills/devflow:performance/SKILL.md +0 -20
- package/skills/devflow:react/SKILL.md +0 -30
- package/skills/devflow:tailwind/SKILL.md +0 -20
- package/skills/devflow:taro/SKILL.md +0 -20
- package/skills/devflow:ui-layout/SKILL.md +0 -1
- 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
|
|
4
|
-
|
|
5
|
-
> **Note:**
|
|
6
|
-
|
|
7
|
-
##
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
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
|
|
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};
|
package/dist/hooks/stop.js
CHANGED
|
@@ -1,118 +1,2 @@
|
|
|
1
|
-
|
|
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
|
## 执行
|
package/hooks/post-tool-use
CHANGED
|
@@ -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
|
-
|
|
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
|
package/hooks/pre-tool-use
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devflow-tools/claude-code-plugin",
|
|
3
|
-
"version": "0.
|
|
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.
|
|
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": "
|
|
31
|
+
"gitHead": "7872bccedbacd09cc92b983f30b3702db6878125"
|
|
32
32
|
}
|
|
@@ -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
|
|