@devflow-tools/claude-code-plugin 0.8.9

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 (49) hide show
  1. package/README.md +26 -0
  2. package/dist/command-registry.json +235 -0
  3. package/dist/hooks/post-tool-use.js +114 -0
  4. package/dist/hooks/pre-tool-use.js +2 -0
  5. package/dist/hooks/stop.js +118 -0
  6. package/dist/skills/devflow:context/SKILL.md +51 -0
  7. package/dist/skills/devflow:docker/SKILL.md +69 -0
  8. package/dist/skills/devflow:electron/SKILL.md +69 -0
  9. package/dist/skills/devflow:graph/SKILL.md +44 -0
  10. package/dist/skills/devflow:graphql/SKILL.md +70 -0
  11. package/dist/skills/devflow:knowledge/SKILL.md +44 -0
  12. package/dist/skills/devflow:memory/SKILL.md +43 -0
  13. package/dist/skills/devflow:nest/SKILL.md +70 -0
  14. package/dist/skills/devflow:nextjs/SKILL.md +67 -0
  15. package/dist/skills/devflow:performance/SKILL.md +69 -0
  16. package/dist/skills/devflow:react/SKILL.md +87 -0
  17. package/dist/skills/devflow:tailwind/SKILL.md +65 -0
  18. package/dist/skills/devflow:taro/SKILL.md +68 -0
  19. package/dist/skills/devflow:vue/SKILL.md +76 -0
  20. package/dist/skills/devflow:workflow/SKILL.md +44 -0
  21. package/hooks/constitution.md +20 -0
  22. package/hooks/post-tool-use +103 -0
  23. package/hooks/pre-tool-use +15 -0
  24. package/hooks/session-start +152 -0
  25. package/hooks/stop +10 -0
  26. package/hooks.json +40 -0
  27. package/package.json +31 -0
  28. package/skills/devflow/SKILL.md +20 -0
  29. package/skills/devflow:animation/SKILL.md +39 -0
  30. package/skills/devflow:context/SKILL.md +44 -0
  31. package/skills/devflow:css/SKILL.md +39 -0
  32. package/skills/devflow:docker/SKILL.md +62 -0
  33. package/skills/devflow:doctor/SKILL.md +17 -0
  34. package/skills/devflow:electron/SKILL.md +62 -0
  35. package/skills/devflow:git/SKILL.md +43 -0
  36. package/skills/devflow:graph/SKILL.md +37 -0
  37. package/skills/devflow:graphql/SKILL.md +63 -0
  38. package/skills/devflow:knowledge/SKILL.md +37 -0
  39. package/skills/devflow:memory/SKILL.md +36 -0
  40. package/skills/devflow:nest/SKILL.md +63 -0
  41. package/skills/devflow:nextjs/SKILL.md +60 -0
  42. package/skills/devflow:performance/SKILL.md +62 -0
  43. package/skills/devflow:react/SKILL.md +80 -0
  44. package/skills/devflow:start/SKILL.md +54 -0
  45. package/skills/devflow:tailwind/SKILL.md +58 -0
  46. package/skills/devflow:taro/SKILL.md +61 -0
  47. package/skills/devflow:ui-layout/SKILL.md +39 -0
  48. package/skills/devflow:vue/SKILL.md +69 -0
  49. package/skills/devflow:workflow/SKILL.md +37 -0
package/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # @devflow-tools/claude-code-plugin
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
17
+
18
+ ```bash
19
+ # The plugin is installed automatically via devflow init
20
+ npm install -g @devflow-tools/cli
21
+ devflow init
22
+ ```
23
+
24
+ ## License
25
+
26
+ MIT
@@ -0,0 +1,235 @@
1
+ {
2
+ "version": 1,
3
+ "commands": {
4
+ "devflow:context": {
5
+ "mcpTools": [
6
+ "get_project_context",
7
+ "search_symbol"
8
+ ],
9
+ "blockedNative": [
10
+ "grep",
11
+ "find",
12
+ "rg",
13
+ "ag",
14
+ "Grep",
15
+ "Glob",
16
+ "Explore",
17
+ "WebSearch",
18
+ "WebFetch"
19
+ ]
20
+ },
21
+ "devflow:graph": {
22
+ "mcpTools": [
23
+ "get_dependency_graph"
24
+ ],
25
+ "blockedNative": [
26
+ "grep",
27
+ "find",
28
+ "rg",
29
+ "ag",
30
+ "Grep",
31
+ "Glob",
32
+ "Explore"
33
+ ]
34
+ },
35
+ "devflow:knowledge": {
36
+ "mcpTools": [
37
+ "get_knowledge"
38
+ ],
39
+ "blockedNative": [
40
+ "WebSearch",
41
+ "WebFetch"
42
+ ]
43
+ },
44
+ "devflow:memory": {
45
+ "mcpTools": [
46
+ "get_memory"
47
+ ],
48
+ "blockedNative": [
49
+ "grep",
50
+ "find",
51
+ "rg",
52
+ "ag",
53
+ "Grep",
54
+ "Glob",
55
+ "Explore"
56
+ ]
57
+ },
58
+ "devflow:workflow": {
59
+ "mcpTools": [
60
+ "run_workflow"
61
+ ],
62
+ "blockedNative": []
63
+ },
64
+ "devflow:react": {
65
+ "mcpTools": [
66
+ "react_diagnose_bug",
67
+ "react_new_feature",
68
+ "react_audit_performance",
69
+ "react_review_hooks",
70
+ "react_refactor_component",
71
+ "react_new_component"
72
+ ],
73
+ "blockedNative": [
74
+ "grep",
75
+ "find",
76
+ "rg",
77
+ "ag",
78
+ "Grep",
79
+ "Glob",
80
+ "Explore",
81
+ "WebSearch",
82
+ "WebFetch"
83
+ ]
84
+ },
85
+ "devflow:vue": {
86
+ "mcpTools": [
87
+ "vue_diagnose_bug",
88
+ "vue_new_component",
89
+ "vue_debug_reactivity"
90
+ ],
91
+ "blockedNative": [
92
+ "grep",
93
+ "find",
94
+ "rg",
95
+ "ag",
96
+ "Grep",
97
+ "Glob",
98
+ "Explore",
99
+ "WebSearch",
100
+ "WebFetch"
101
+ ]
102
+ },
103
+ "devflow:tailwind": {
104
+ "mcpTools": [
105
+ "tailwind_new_component"
106
+ ],
107
+ "blockedNative": [
108
+ "grep",
109
+ "find",
110
+ "rg",
111
+ "ag",
112
+ "Grep",
113
+ "Glob",
114
+ "Explore",
115
+ "WebSearch",
116
+ "WebFetch"
117
+ ]
118
+ },
119
+ "devflow:taro": {
120
+ "mcpTools": [
121
+ "taro_new_page"
122
+ ],
123
+ "blockedNative": [
124
+ "grep",
125
+ "find",
126
+ "rg",
127
+ "ag",
128
+ "Grep",
129
+ "Glob",
130
+ "Explore",
131
+ "WebSearch",
132
+ "WebFetch"
133
+ ]
134
+ },
135
+ "devflow:nest": {
136
+ "mcpTools": [
137
+ "nest_new_module",
138
+ "nest_diagnose_bug"
139
+ ],
140
+ "blockedNative": [
141
+ "grep",
142
+ "find",
143
+ "rg",
144
+ "ag",
145
+ "Grep",
146
+ "Glob",
147
+ "Explore",
148
+ "WebSearch",
149
+ "WebFetch"
150
+ ]
151
+ },
152
+ "devflow:graphql": {
153
+ "mcpTools": [
154
+ "graphql_new_graphql_type",
155
+ "graphql_diagnose_bug"
156
+ ],
157
+ "blockedNative": [
158
+ "grep",
159
+ "find",
160
+ "rg",
161
+ "ag",
162
+ "Grep",
163
+ "Glob",
164
+ "Explore",
165
+ "WebSearch",
166
+ "WebFetch"
167
+ ]
168
+ },
169
+ "devflow:docker": {
170
+ "mcpTools": [
171
+ "docker_dockerize_project"
172
+ ],
173
+ "blockedNative": [
174
+ "grep",
175
+ "find",
176
+ "rg",
177
+ "ag",
178
+ "Grep",
179
+ "Glob",
180
+ "Explore",
181
+ "WebSearch",
182
+ "WebFetch"
183
+ ]
184
+ },
185
+ "devflow:performance": {
186
+ "mcpTools": [
187
+ "performance_audit_performance"
188
+ ],
189
+ "blockedNative": [
190
+ "grep",
191
+ "find",
192
+ "rg",
193
+ "ag",
194
+ "Grep",
195
+ "Glob",
196
+ "Explore",
197
+ "WebSearch",
198
+ "WebFetch"
199
+ ]
200
+ },
201
+ "devflow:nextjs": {
202
+ "mcpTools": [
203
+ "nextjs_new_page",
204
+ "nextjs_diagnose_bug"
205
+ ],
206
+ "blockedNative": [
207
+ "grep",
208
+ "find",
209
+ "rg",
210
+ "ag",
211
+ "Grep",
212
+ "Glob",
213
+ "Explore",
214
+ "WebSearch",
215
+ "WebFetch"
216
+ ]
217
+ },
218
+ "devflow:electron": {
219
+ "mcpTools": [
220
+ "electron_diagnose_bug"
221
+ ],
222
+ "blockedNative": [
223
+ "grep",
224
+ "find",
225
+ "rg",
226
+ "ag",
227
+ "Grep",
228
+ "Glob",
229
+ "Explore",
230
+ "WebSearch",
231
+ "WebFetch"
232
+ ]
233
+ }
234
+ }
235
+ }
@@ -0,0 +1,114 @@
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));
@@ -0,0 +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).then(()=>{try{let f=require('fs'),p=require('path'),o=require('os'),d=p.join(o.homedir(),'.devflow');f.existsSync(d)||f.mkdirSync(d,{recursive:!0});f.writeFileSync(p.join(d,'last-event-id'),E.eventId)}catch{}}).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};
@@ -0,0 +1,118 @@
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));
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: devflow:context
3
+ description: 检索项目上下文 — 自然语言查询相关代码、符号、依赖关系
4
+ required_mcp_tools:
5
+ - get_project_context
6
+ - search_symbol
7
+ ---
8
+
9
+ <HARD-GATE>
10
+ 收到 devflow:context 时,必须先调用以下 MCP 工具之一:
11
+ get_project_context / search_symbol
12
+ </HARD-GATE>
13
+
14
+
15
+ ## MANDATORY FIRST STEP - Skill Registration
16
+
17
+ > **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
18
+
19
+ ```bash
20
+ mkdir -p ~/.devflow && echo '{"name":"devflow:context","required_mcp_tools":["get_project_context","search_symbol"],"description":"devflow:context skill","registeredAt":'"$(date +%s)000"'}' > ~/.devflow/current-skill.json
21
+ ```
22
+
23
+ After registration, you **MUST** use ONLY these MCP tools for all work in this skill:
24
+ - `mcp__devflow__get_project_context`
25
+ - `mcp__devflow__search_symbol`
26
+
27
+ **Never use direct tools** (Read, Write, Edit, Bash, Grep, etc.) for tasks that can be handled by the MCP tools above.
28
+
29
+ When the skill execution is complete, clean up:
30
+ ```bash
31
+ rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
32
+ ```
33
+
34
+
35
+ # /devflow:context
36
+
37
+ ## 执行
38
+
39
+ 1. 如果用户的查询包含中文,先将其中的中文关键词翻译为英文代码术语(空格分隔)
40
+ 2. 调用 `get_project_context` MCP 工具:
41
+
42
+ ```
43
+ query = 用户的原始查询内容(包含中文)
44
+ expandedTerms = 你翻译的英文关键词(如 "code review audit module")
45
+ mode = "fast" (首次调用;如需更深入结果,再改用 "deep")
46
+ ```
47
+
48
+ 示例:
49
+ - 用户查询 "代码审核模块的流程" → expandedTerms = "code review audit module workflow pipeline process"
50
+ - 用户查询 "用户登录认证逻辑" → expandedTerms = "user login authentication auth logic service handler"
51
+ - 用户查询 "数据库缓存策略" → expandedTerms = "database db cache memo redis storage strategy"
@@ -0,0 +1,69 @@
1
+ ---
2
+ name: devflow:docker
3
+ description: Docker 专家 — 镜像优化、Compose 编排、安全扫描、多阶段构建
4
+ required_mcp_tools:
5
+ - docker_dockerize_project
6
+ ---
7
+
8
+ <HARD-GATE>
9
+ 收到 devflow:docker 时,必须先调用以下 MCP 工具之一:
10
+ docker_dockerize_project
11
+ </HARD-GATE>
12
+
13
+
14
+ ## MANDATORY FIRST STEP - Skill Registration
15
+
16
+ > **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
17
+
18
+ ```bash
19
+ 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
20
+ ```
21
+
22
+ After registration, you **MUST** use ONLY these MCP tools for all work in this skill:
23
+ - `mcp__devflow__docker_dockerize_project`
24
+
25
+ **Never use direct tools** (Read, Write, Edit, Bash, Grep, etc.) for tasks that can be handled by the MCP tools above.
26
+
27
+ When the skill execution is complete, clean up:
28
+ ```bash
29
+ rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
30
+ ```
31
+
32
+
33
+ # 🐳 DOCKER
34
+
35
+ 你是一个 Docker 专家。使用多阶段构建优化镜像,遵循安全和性能最佳实践。遇到问题先查官方文档。
36
+
37
+ ## 适用场景
38
+
39
+ **项目 Docker 化:分析项目 → 多阶段 Dockerfile → Compose → 构建验证**
40
+
41
+ **镜像优化:体积分析 → 层优化 → 多阶段重构**
42
+
43
+ **安全扫描:漏洞检测 → 配置审查 → 修复建议**
44
+
45
+ **多服务 Compose 编排:依赖分析 → 网络设计 → 环境管理**
46
+
47
+ ## 核心规则
48
+
49
+ - 使用多阶段构建减小镜像体积
50
+ - 基础镜像固定版本标签(不使用 latest)
51
+ - 利用层缓存优化构建顺序
52
+ - 使用非 root 用户运行应用
53
+ - 使用 .dockerignore 排除无用文件
54
+ - 添加 HEALTHCHECK 监控容器健康状态
55
+ - 不在镜像层中写入敏感信息
56
+ - 修复安全问题时先查 Docker 官方文档确认方案
57
+
58
+ ## 当前版本
59
+
60
+ - docker-docs: 26.0.0 — https://docs.docker.com/reference/
61
+
62
+ ## 工作流
63
+
64
+ | 场景 | 触发方式 |
65
+ |------|----------|
66
+ | 项目 Docker 化:分析项目 → 多阶段 Dockerfile → Compose → 构建验证 | 调用 MCP 工具 `docker_dockerize_project` |
67
+ | 镜像优化:体积分析 → 层优化 → 多阶段重构 | 调用 MCP 工具 `docker_optimize:image` |
68
+ | 安全扫描:漏洞检测 → 配置审查 → 修复建议 | 调用 MCP 工具 `docker_scan:security` |
69
+ | 多服务 Compose 编排:依赖分析 → 网络设计 → 环境管理 | 调用 MCP 工具 `docker_setup:compose` |
@@ -0,0 +1,69 @@
1
+ ---
2
+ name: devflow:electron
3
+ description: Electron 专家 — IPC 通信、窗口管理、原生模块、自动更新、安全配置
4
+ required_mcp_tools:
5
+ - electron_diagnose_bug
6
+ ---
7
+
8
+ <HARD-GATE>
9
+ 收到 devflow:electron 时,必须先调用以下 MCP 工具之一:
10
+ electron_diagnose_bug
11
+ </HARD-GATE>
12
+
13
+
14
+ ## MANDATORY FIRST STEP - Skill Registration
15
+
16
+ > **IMPORTANT: Before ANY other action, execute the registration command below. This is NON-NEGOTIABLE.**
17
+
18
+ ```bash
19
+ 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
20
+ ```
21
+
22
+ After registration, you **MUST** use ONLY these MCP tools for all work in this skill:
23
+ - `mcp__devflow__electron_diagnose_bug`
24
+
25
+ **Never use direct tools** (Read, Write, Edit, Bash, Grep, etc.) for tasks that can be handled by the MCP tools above.
26
+
27
+ When the skill execution is complete, clean up:
28
+ ```bash
29
+ rm -f ~/.devflow/current-skill.json ~/.devflow/current-execution-id
30
+ ```
31
+
32
+
33
+ # ⚛️ ELECTRON
34
+
35
+ 你是一个 Electron 专家。使用 contextBridge + IPC 安全通信模式。严格遵循 Electron 安全最佳实践。
36
+
37
+ ## 适用场景
38
+
39
+ **新建 IPC 通道:定义 API → Preload 暴露 → 主进程处理**
40
+
41
+ **安全审计:配置检查 → IPC 暴露面 → CSP → 第三方依赖**
42
+
43
+ **自动更新配置:electron-updater → 发布渠道 → 更新 UI**
44
+
45
+ **Electron Bug 诊断:进程分类 → IPC 追踪 → 原生调试**
46
+
47
+ ## 核心规则
48
+
49
+ - 使用 contextBridge + ipcRenderer/ipcMain 通信
50
+ - 必须启用 contextIsolation,禁用 nodeIntegration
51
+ - 主进程负责系统操作,渲染进程只做 UI
52
+ - Preload 脚本只暴露最小必要的安全 API
53
+ - 使用 electron-updater 实现自动更新
54
+ - 启用 sandbox 和 CSP 安全策略
55
+ - 避免使用 remote 模块(已废弃)
56
+ - 构建使用 electron-builder 并配置代码签名
57
+
58
+ ## 当前版本
59
+
60
+ - electron-docs: 30.0.0 — https://www.electronjs.org/docs/latest/
61
+
62
+ ## 工作流
63
+
64
+ | 场景 | 触发方式 |
65
+ |------|----------|
66
+ | 新建 IPC 通道:定义 API → Preload 暴露 → 主进程处理 | 调用 MCP 工具 `electron_new:ipc` |
67
+ | 安全审计:配置检查 → IPC 暴露面 → CSP → 第三方依赖 | 调用 MCP 工具 `electron_audit:security` |
68
+ | 自动更新配置:electron-updater → 发布渠道 → 更新 UI | 调用 MCP 工具 `electron_setup:auto-update` |
69
+ | Electron Bug 诊断:进程分类 → IPC 追踪 → 原生调试 | 调用 MCP 工具 `electron_diagnose_bug` |