claude-flow-novice 1.5.21 → 1.5.22

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 (25) hide show
  1. package/.claude/agents/CLAUDE.md +186 -2386
  2. package/.claude/agents/agent-principles/agent-type-guidelines.md +328 -0
  3. package/.claude/agents/agent-principles/format-selection.md +204 -0
  4. package/.claude/agents/agent-principles/prompt-engineering.md +371 -0
  5. package/.claude/agents/agent-principles/quality-metrics.md +294 -0
  6. package/.claude/agents/frontend/README.md +574 -53
  7. package/.claude/agents/frontend/interaction-tester.md +850 -108
  8. package/.claude/agents/frontend/react-frontend-engineer.md +130 -0
  9. package/.claude/agents/frontend/state-architect.md +240 -152
  10. package/.claude/agents/frontend/ui-designer.md +292 -68
  11. package/.claude/agents/researcher.md +1 -1
  12. package/.claude/agents/swarm/test-coordinator.md +383 -0
  13. package/.claude/agents/task-coordinator.md +126 -0
  14. package/.claude/settings.json +7 -7
  15. package/.claude-flow-novice/dist/src/hooks/enhanced-hooks-cli.js +168 -167
  16. package/.claude-flow-novice/dist/src/providers/tiered-router.js +118 -0
  17. package/.claude-flow-novice/dist/src/providers/tiered-router.js.map +1 -0
  18. package/.claude-flow-novice/dist/src/providers/types.js.map +1 -1
  19. package/.claude-flow-novice/dist/src/providers/zai-provider.js +268 -0
  20. package/.claude-flow-novice/dist/src/providers/zai-provider.js.map +1 -0
  21. package/package.json +1 -1
  22. package/src/cli/simple-commands/init/templates/CLAUDE.md +25 -0
  23. package/src/hooks/enhanced-hooks-cli.js +23 -3
  24. package/src/hooks/enhanced-post-edit-pipeline.js +154 -75
  25. /package/.claude/agents/{CLAUDE_AGENT_DESIGN_PRINCIPLES.md → agent-principles/CLAUDE_AGENT_DESIGN_PRINCIPLES.md} +0 -0
@@ -0,0 +1,268 @@
1
+ /**
2
+ * Z.ai Provider Implementation (Tier 3)
3
+ * Minimal implementation for testing Z.ai API integration
4
+ */ import { BaseProvider } from './base-provider.js';
5
+ import { LLMProviderError } from './types.js';
6
+ export class ZaiProvider extends BaseProvider {
7
+ name = 'zai';
8
+ capabilities = {
9
+ supportedModels: [
10
+ 'claude-3-5-sonnet-20241022'
11
+ ],
12
+ maxContextLength: {
13
+ 'claude-3-5-sonnet-20241022': 200000
14
+ },
15
+ maxOutputTokens: {
16
+ 'claude-3-5-sonnet-20241022': 8192
17
+ },
18
+ supportsStreaming: true,
19
+ supportsFunctionCalling: false,
20
+ supportsSystemMessages: true,
21
+ supportsVision: true,
22
+ supportsAudio: false,
23
+ supportsTools: false,
24
+ supportsFineTuning: false,
25
+ supportsEmbeddings: false,
26
+ supportsLogprobs: false,
27
+ supportsBatching: false,
28
+ pricing: {
29
+ 'claude-3-5-sonnet-20241022': {
30
+ promptCostPer1k: 0.003,
31
+ completionCostPer1k: 0.015,
32
+ currency: 'USD'
33
+ }
34
+ }
35
+ };
36
+ apiKey;
37
+ baseURL = 'https://api.z.ai/v1';
38
+ async doInitialize() {
39
+ // Validate API key
40
+ if (!this.config.apiKey) {
41
+ throw new Error('Z.ai API key is required. Set Z_AI_API_KEY in .env');
42
+ }
43
+ this.apiKey = this.config.apiKey;
44
+ this.logger.info('Z.ai provider initialized', {
45
+ model: this.config.model,
46
+ baseURL: this.baseURL
47
+ });
48
+ }
49
+ async doComplete(request) {
50
+ const model = request.model || this.config.model;
51
+ // Build request payload
52
+ const payload = {
53
+ model,
54
+ messages: request.messages.filter((msg)=>msg.role !== 'function').map((msg)=>({
55
+ role: msg.role,
56
+ content: msg.content
57
+ })),
58
+ temperature: request.temperature ?? this.config.temperature,
59
+ max_tokens: request.maxTokens ?? this.config.maxTokens,
60
+ stream: false
61
+ };
62
+ // Call Z.ai API
63
+ const response = await this.callZaiAPI('/chat/completions', payload);
64
+ // Calculate cost
65
+ const pricing = this.capabilities.pricing[model];
66
+ const promptCost = response.usage.prompt_tokens / 1000 * pricing.promptCostPer1k;
67
+ const completionCost = response.usage.completion_tokens / 1000 * pricing.completionCostPer1k;
68
+ // Convert to unified response format
69
+ return {
70
+ id: response.id,
71
+ model,
72
+ provider: 'zai',
73
+ content: response.choices[0].message.content,
74
+ usage: {
75
+ promptTokens: response.usage.prompt_tokens,
76
+ completionTokens: response.usage.completion_tokens,
77
+ totalTokens: response.usage.total_tokens
78
+ },
79
+ cost: {
80
+ promptCost,
81
+ completionCost,
82
+ totalCost: promptCost + completionCost,
83
+ currency: 'USD'
84
+ },
85
+ finishReason: response.choices[0].finish_reason === 'stop' ? 'stop' : 'length'
86
+ };
87
+ }
88
+ async *doStreamComplete(request) {
89
+ const model = request.model || this.config.model;
90
+ // Build request payload
91
+ const payload = {
92
+ model,
93
+ messages: request.messages.filter((msg)=>msg.role !== 'function').map((msg)=>({
94
+ role: msg.role,
95
+ content: msg.content
96
+ })),
97
+ temperature: request.temperature ?? this.config.temperature,
98
+ max_tokens: request.maxTokens ?? this.config.maxTokens,
99
+ stream: true
100
+ };
101
+ // Call Z.ai streaming API
102
+ const response = await fetch(`${this.baseURL}/chat/completions`, {
103
+ method: 'POST',
104
+ headers: {
105
+ 'Content-Type': 'application/json',
106
+ Authorization: `Bearer ${this.apiKey}`
107
+ },
108
+ body: JSON.stringify(payload)
109
+ });
110
+ if (!response.ok) {
111
+ throw new LLMProviderError(`Z.ai API error: ${response.status} ${response.statusText}`, 'API_ERROR', 'zai', undefined, response.status >= 500);
112
+ }
113
+ if (!response.body) {
114
+ throw new LLMProviderError('No response body from Z.ai API', 'NO_RESPONSE_BODY', 'zai');
115
+ }
116
+ // Process SSE stream
117
+ const reader = response.body.getReader();
118
+ const decoder = new TextDecoder();
119
+ let buffer = '';
120
+ let totalTokens = 0;
121
+ try {
122
+ while(true){
123
+ const { done, value } = await reader.read();
124
+ if (done) break;
125
+ buffer += decoder.decode(value, {
126
+ stream: true
127
+ });
128
+ const lines = buffer.split('\n');
129
+ buffer = lines.pop() || '';
130
+ for (const line of lines){
131
+ if (!line.trim() || line.startsWith(':')) continue;
132
+ if (line.startsWith('data: ')) {
133
+ const data = line.slice(6);
134
+ if (data === '[DONE]') continue;
135
+ try {
136
+ const event = JSON.parse(data);
137
+ if (event.choices?.[0]?.delta?.content) {
138
+ yield {
139
+ type: 'content',
140
+ delta: {
141
+ content: event.choices[0].delta.content
142
+ }
143
+ };
144
+ }
145
+ if (event.usage) {
146
+ totalTokens = event.usage.total_tokens;
147
+ }
148
+ } catch (parseError) {
149
+ this.logger.warn('Failed to parse SSE event', {
150
+ line,
151
+ error: parseError
152
+ });
153
+ }
154
+ }
155
+ }
156
+ }
157
+ // Emit final usage statistics
158
+ const pricing = this.capabilities.pricing[model];
159
+ const promptTokens = this.estimateTokens(JSON.stringify(request.messages));
160
+ const completionTokens = totalTokens - promptTokens;
161
+ const promptCost = promptTokens / 1000 * pricing.promptCostPer1k;
162
+ const completionCost = completionTokens / 1000 * pricing.completionCostPer1k;
163
+ yield {
164
+ type: 'done',
165
+ usage: {
166
+ promptTokens,
167
+ completionTokens,
168
+ totalTokens
169
+ },
170
+ cost: {
171
+ promptCost,
172
+ completionCost,
173
+ totalCost: promptCost + completionCost,
174
+ currency: 'USD'
175
+ }
176
+ };
177
+ } finally{
178
+ reader.releaseLock();
179
+ }
180
+ }
181
+ async listModels() {
182
+ return this.capabilities.supportedModels;
183
+ }
184
+ async getModelInfo(model) {
185
+ return {
186
+ model,
187
+ name: 'Claude 3.5 Sonnet',
188
+ description: 'Claude 3.5 Sonnet via Z.ai',
189
+ contextLength: this.capabilities.maxContextLength[model] || 200000,
190
+ maxOutputTokens: this.capabilities.maxOutputTokens[model] || 8192,
191
+ supportedFeatures: [
192
+ 'chat',
193
+ 'completion',
194
+ 'vision',
195
+ 'streaming'
196
+ ],
197
+ pricing: this.capabilities.pricing[model]
198
+ };
199
+ }
200
+ async doHealthCheck() {
201
+ try {
202
+ // Minimal health check request
203
+ const response = await this.callZaiAPI('/chat/completions', {
204
+ model: this.config.model,
205
+ messages: [
206
+ {
207
+ role: 'user',
208
+ content: 'Hi'
209
+ }
210
+ ],
211
+ max_tokens: 1,
212
+ stream: false
213
+ });
214
+ return {
215
+ healthy: true,
216
+ timestamp: new Date(),
217
+ details: {
218
+ model: response.model,
219
+ status: 'operational'
220
+ }
221
+ };
222
+ } catch (error) {
223
+ return {
224
+ healthy: false,
225
+ error: error instanceof Error ? error.message : 'Unknown error',
226
+ timestamp: new Date()
227
+ };
228
+ }
229
+ }
230
+ /**
231
+ * Call Z.ai API with error handling
232
+ */ async callZaiAPI(endpoint, payload) {
233
+ const url = `${this.baseURL}${endpoint}`;
234
+ try {
235
+ const response = await fetch(url, {
236
+ method: 'POST',
237
+ headers: {
238
+ 'Content-Type': 'application/json',
239
+ Authorization: `Bearer ${this.apiKey}`
240
+ },
241
+ body: JSON.stringify(payload)
242
+ });
243
+ if (!response.ok) {
244
+ const errorBody = await response.text();
245
+ let errorMessage = `Z.ai API error: ${response.status} ${response.statusText}`;
246
+ try {
247
+ const errorJson = JSON.parse(errorBody);
248
+ errorMessage = errorJson.error?.message || errorMessage;
249
+ } catch {
250
+ // Use default error message if body is not JSON
251
+ }
252
+ throw new LLMProviderError(errorMessage, response.status === 429 ? 'RATE_LIMIT' : 'API_ERROR', 'zai', undefined, response.status >= 500);
253
+ }
254
+ return await response.json();
255
+ } catch (error) {
256
+ if (error instanceof LLMProviderError) {
257
+ throw error;
258
+ }
259
+ throw new LLMProviderError(error instanceof Error ? error.message : String(error), 'NETWORK_ERROR', 'zai', undefined, true);
260
+ }
261
+ }
262
+ destroy() {
263
+ super.destroy();
264
+ this.logger.info('Z.ai provider destroyed');
265
+ }
266
+ }
267
+
268
+ //# sourceMappingURL=zai-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/providers/zai-provider.ts"],"names":["BaseProvider","LLMProviderError","ZaiProvider","name","capabilities","supportedModels","maxContextLength","maxOutputTokens","supportsStreaming","supportsFunctionCalling","supportsSystemMessages","supportsVision","supportsAudio","supportsTools","supportsFineTuning","supportsEmbeddings","supportsLogprobs","supportsBatching","pricing","promptCostPer1k","completionCostPer1k","currency","apiKey","baseURL","doInitialize","config","Error","logger","info","model","doComplete","request","payload","messages","filter","msg","role","map","content","temperature","max_tokens","maxTokens","stream","response","callZaiAPI","promptCost","usage","prompt_tokens","completionCost","completion_tokens","id","provider","choices","message","promptTokens","completionTokens","totalTokens","total_tokens","cost","totalCost","finishReason","finish_reason","doStreamComplete","fetch","method","headers","Authorization","body","JSON","stringify","ok","status","statusText","undefined","reader","getReader","decoder","TextDecoder","buffer","done","value","read","decode","lines","split","pop","line","trim","startsWith","data","slice","event","parse","delta","type","parseError","warn","error","estimateTokens","releaseLock","listModels","getModelInfo","description","contextLength","supportedFeatures","doHealthCheck","healthy","timestamp","Date","details","endpoint","url","errorBody","text","errorMessage","errorJson","json","String","destroy"],"mappings":"AAAA;;;CAGC,GAED,SAASA,YAAY,QAAQ,qBAAqB;AAClD,SASEC,gBAAgB,QACX,aAAa;AAgCpB,OAAO,MAAMC,oBAAoBF;IACtBG,OAAoB,MAAM;IAC1BC,eAAqC;QAC5CC,iBAAiB;YAAC;SAA6B;QAC/CC,kBAAkB;YAChB,8BAA8B;QAChC;QACAC,iBAAiB;YACf,8BAA8B;QAChC;QACAC,mBAAmB;QACnBC,yBAAyB;QACzBC,wBAAwB;QACxBC,gBAAgB;QAChBC,eAAe;QACfC,eAAe;QACfC,oBAAoB;QACpBC,oBAAoB;QACpBC,kBAAkB;QAClBC,kBAAkB;QAClBC,SAAS;YACP,8BAA8B;gBAC5BC,iBAAiB;gBACjBC,qBAAqB;gBACrBC,UAAU;YACZ;QACF;IACF,EAAE;IAEMC,OAAgB;IAChBC,UAAU,sBAAsB;IAExC,MAAgBC,eAA8B;QAC5C,mBAAmB;QACnB,IAAI,CAAC,IAAI,CAACC,MAAM,CAACH,MAAM,EAAE;YACvB,MAAM,IAAII,MAAM;QAClB;QAEA,IAAI,CAACJ,MAAM,GAAG,IAAI,CAACG,MAAM,CAACH,MAAM;QAChC,IAAI,CAACK,MAAM,CAACC,IAAI,CAAC,6BAA6B;YAC5CC,OAAO,IAAI,CAACJ,MAAM,CAACI,KAAK;YACxBN,SAAS,IAAI,CAACA,OAAO;QACvB;IACF;IAEA,MAAgBO,WAAWC,OAAmB,EAAwB;QACpE,MAAMF,QAAQE,QAAQF,KAAK,IAAI,IAAI,CAACJ,MAAM,CAACI,KAAK;QAEhD,wBAAwB;QACxB,MAAMG,UAAgC;YACpCH;YACAI,UAAUF,QAAQE,QAAQ,CACvBC,MAAM,CAAC,CAACC,MAAQA,IAAIC,IAAI,KAAK,YAC7BC,GAAG,CAAC,CAACF,MAAS,CAAA;oBACbC,MAAMD,IAAIC,IAAI;oBACdE,SAASH,IAAIG,OAAO;gBACtB,CAAA;YACFC,aAAaR,QAAQQ,WAAW,IAAI,IAAI,CAACd,MAAM,CAACc,WAAW;YAC3DC,YAAYT,QAAQU,SAAS,IAAI,IAAI,CAAChB,MAAM,CAACgB,SAAS;YACtDC,QAAQ;QACV;QAEA,gBAAgB;QAChB,MAAMC,WAAW,MAAM,IAAI,CAACC,UAAU,CAAwB,qBAAqBZ;QAEnF,iBAAiB;QACjB,MAAMd,UAAU,IAAI,CAACd,YAAY,CAACc,OAAO,AAAC,CAACW,MAAM;QACjD,MAAMgB,aAAa,AAACF,SAASG,KAAK,CAACC,aAAa,GAAG,OAAQ7B,QAAQC,eAAe;QAClF,MAAM6B,iBAAiB,AAACL,SAASG,KAAK,CAACG,iBAAiB,GAAG,OAAQ/B,QAAQE,mBAAmB;QAE9F,qCAAqC;QACrC,OAAO;YACL8B,IAAIP,SAASO,EAAE;YACfrB;YACAsB,UAAU;YACVb,SAASK,SAASS,OAAO,CAAC,EAAE,CAACC,OAAO,CAACf,OAAO;YAC5CQ,OAAO;gBACLQ,cAAcX,SAASG,KAAK,CAACC,aAAa;gBAC1CQ,kBAAkBZ,SAASG,KAAK,CAACG,iBAAiB;gBAClDO,aAAab,SAASG,KAAK,CAACW,YAAY;YAC1C;YACAC,MAAM;gBACJb;gBACAG;gBACAW,WAAWd,aAAaG;gBACxB3B,UAAU;YACZ;YACAuC,cAAcjB,SAASS,OAAO,CAAC,EAAE,CAACS,aAAa,KAAK,SAAS,SAAS;QACxE;IACF;IAEA,OAAiBC,iBAAiB/B,OAAmB,EAAiC;QACpF,MAAMF,QAAQE,QAAQF,KAAK,IAAI,IAAI,CAACJ,MAAM,CAACI,KAAK;QAEhD,wBAAwB;QACxB,MAAMG,UAAgC;YACpCH;YACAI,UAAUF,QAAQE,QAAQ,CACvBC,MAAM,CAAC,CAACC,MAAQA,IAAIC,IAAI,KAAK,YAC7BC,GAAG,CAAC,CAACF,MAAS,CAAA;oBACbC,MAAMD,IAAIC,IAAI;oBACdE,SAASH,IAAIG,OAAO;gBACtB,CAAA;YACFC,aAAaR,QAAQQ,WAAW,IAAI,IAAI,CAACd,MAAM,CAACc,WAAW;YAC3DC,YAAYT,QAAQU,SAAS,IAAI,IAAI,CAAChB,MAAM,CAACgB,SAAS;YACtDC,QAAQ;QACV;QAEA,0BAA0B;QAC1B,MAAMC,WAAW,MAAMoB,MAAM,GAAG,IAAI,CAACxC,OAAO,CAAC,iBAAiB,CAAC,EAAE;YAC/DyC,QAAQ;YACRC,SAAS;gBACP,gBAAgB;gBAChBC,eAAe,CAAC,OAAO,EAAE,IAAI,CAAC5C,MAAM,EAAE;YACxC;YACA6C,MAAMC,KAAKC,SAAS,CAACrC;QACvB;QAEA,IAAI,CAACW,SAAS2B,EAAE,EAAE;YAChB,MAAM,IAAIrE,iBACR,CAAC,gBAAgB,EAAE0C,SAAS4B,MAAM,CAAC,CAAC,EAAE5B,SAAS6B,UAAU,EAAE,EAC3D,aACA,OACAC,WACA9B,SAAS4B,MAAM,IAAI;QAEvB;QAEA,IAAI,CAAC5B,SAASwB,IAAI,EAAE;YAClB,MAAM,IAAIlE,iBAAiB,kCAAkC,oBAAoB;QACnF;QAEA,qBAAqB;QACrB,MAAMyE,SAAS/B,SAASwB,IAAI,CAACQ,SAAS;QACtC,MAAMC,UAAU,IAAIC;QACpB,IAAIC,SAAS;QACb,IAAItB,cAAc;QAElB,IAAI;YACF,MAAO,KAAM;gBACX,MAAM,EAAEuB,IAAI,EAAEC,KAAK,EAAE,GAAG,MAAMN,OAAOO,IAAI;gBACzC,IAAIF,MAAM;gBAEVD,UAAUF,QAAQM,MAAM,CAACF,OAAO;oBAAEtC,QAAQ;gBAAK;gBAC/C,MAAMyC,QAAQL,OAAOM,KAAK,CAAC;gBAC3BN,SAASK,MAAME,GAAG,MAAM;gBAExB,KAAK,MAAMC,QAAQH,MAAO;oBACxB,IAAI,CAACG,KAAKC,IAAI,MAAMD,KAAKE,UAAU,CAAC,MAAM;oBAE1C,IAAIF,KAAKE,UAAU,CAAC,WAAW;wBAC7B,MAAMC,OAAOH,KAAKI,KAAK,CAAC;wBACxB,IAAID,SAAS,UAAU;wBAEvB,IAAI;4BACF,MAAME,QAAQvB,KAAKwB,KAAK,CAACH;4BAEzB,IAAIE,MAAMvC,OAAO,EAAE,CAAC,EAAE,EAAEyC,OAAOvD,SAAS;gCACtC,MAAM;oCACJwD,MAAM;oCACND,OAAO;wCACLvD,SAASqD,MAAMvC,OAAO,CAAC,EAAE,CAACyC,KAAK,CAACvD,OAAO;oCACzC;gCACF;4BACF;4BAEA,IAAIqD,MAAM7C,KAAK,EAAE;gCACfU,cAAcmC,MAAM7C,KAAK,CAACW,YAAY;4BACxC;wBACF,EAAE,OAAOsC,YAAY;4BACnB,IAAI,CAACpE,MAAM,CAACqE,IAAI,CAAC,6BAA6B;gCAAEV;gCAAMW,OAAOF;4BAAW;wBAC1E;oBACF;gBACF;YACF;YAEA,8BAA8B;YAC9B,MAAM7E,UAAU,IAAI,CAACd,YAAY,CAACc,OAAO,AAAC,CAACW,MAAM;YACjD,MAAMyB,eAAe,IAAI,CAAC4C,cAAc,CAAC9B,KAAKC,SAAS,CAACtC,QAAQE,QAAQ;YACxE,MAAMsB,mBAAmBC,cAAcF;YAEvC,MAAMT,aAAa,AAACS,eAAe,OAAQpC,QAAQC,eAAe;YAClE,MAAM6B,iBAAiB,AAACO,mBAAmB,OAAQrC,QAAQE,mBAAmB;YAE9E,MAAM;gBACJ0E,MAAM;gBACNhD,OAAO;oBACLQ;oBACAC;oBACAC;gBACF;gBACAE,MAAM;oBACJb;oBACAG;oBACAW,WAAWd,aAAaG;oBACxB3B,UAAU;gBACZ;YACF;QACF,SAAU;YACRqD,OAAOyB,WAAW;QACpB;IACF;IAEA,MAAMC,aAAkC;QACtC,OAAO,IAAI,CAAChG,YAAY,CAACC,eAAe;IAC1C;IAEA,MAAMgG,aAAaxE,KAAe,EAAsB;QACtD,OAAO;YACLA;YACA1B,MAAM;YACNmG,aAAa;YACbC,eAAe,IAAI,CAACnG,YAAY,CAACE,gBAAgB,CAACuB,MAAM,IAAI;YAC5DtB,iBAAiB,IAAI,CAACH,YAAY,CAACG,eAAe,CAACsB,MAAM,IAAI;YAC7D2E,mBAAmB;gBAAC;gBAAQ;gBAAc;gBAAU;aAAY;YAChEtF,SAAS,IAAI,CAACd,YAAY,CAACc,OAAO,AAAC,CAACW,MAAM;QAC5C;IACF;IAEA,MAAgB4E,gBAA4C;QAC1D,IAAI;YACF,+BAA+B;YAC/B,MAAM9D,WAAW,MAAM,IAAI,CAACC,UAAU,CAAwB,qBAAqB;gBACjFf,OAAO,IAAI,CAACJ,MAAM,CAACI,KAAK;gBACxBI,UAAU;oBAAC;wBAAEG,MAAM;wBAAQE,SAAS;oBAAK;iBAAE;gBAC3CE,YAAY;gBACZE,QAAQ;YACV;YAEA,OAAO;gBACLgE,SAAS;gBACTC,WAAW,IAAIC;gBACfC,SAAS;oBACPhF,OAAOc,SAASd,KAAK;oBACrB0C,QAAQ;gBACV;YACF;QACF,EAAE,OAAO0B,OAAO;YACd,OAAO;gBACLS,SAAS;gBACTT,OAAOA,iBAAiBvE,QAAQuE,MAAM5C,OAAO,GAAG;gBAChDsD,WAAW,IAAIC;YACjB;QACF;IACF;IAEA;;GAEC,GACD,MAAchE,WAAckE,QAAgB,EAAE9E,OAAY,EAAc;QACtE,MAAM+E,MAAM,GAAG,IAAI,CAACxF,OAAO,GAAGuF,UAAU;QAExC,IAAI;YACF,MAAMnE,WAAW,MAAMoB,MAAMgD,KAAK;gBAChC/C,QAAQ;gBACRC,SAAS;oBACP,gBAAgB;oBAChBC,eAAe,CAAC,OAAO,EAAE,IAAI,CAAC5C,MAAM,EAAE;gBACxC;gBACA6C,MAAMC,KAAKC,SAAS,CAACrC;YACvB;YAEA,IAAI,CAACW,SAAS2B,EAAE,EAAE;gBAChB,MAAM0C,YAAY,MAAMrE,SAASsE,IAAI;gBACrC,IAAIC,eAAe,CAAC,gBAAgB,EAAEvE,SAAS4B,MAAM,CAAC,CAAC,EAAE5B,SAAS6B,UAAU,EAAE;gBAE9E,IAAI;oBACF,MAAM2C,YAAY/C,KAAKwB,KAAK,CAACoB;oBAC7BE,eAAeC,UAAUlB,KAAK,EAAE5C,WAAW6D;gBAC7C,EAAE,OAAM;gBACN,gDAAgD;gBAClD;gBAEA,MAAM,IAAIjH,iBACRiH,cACAvE,SAAS4B,MAAM,KAAK,MAAM,eAAe,aACzC,OACAE,WACA9B,SAAS4B,MAAM,IAAI;YAEvB;YAEA,OAAO,MAAM5B,SAASyE,IAAI;QAC5B,EAAE,OAAOnB,OAAO;YACd,IAAIA,iBAAiBhG,kBAAkB;gBACrC,MAAMgG;YACR;YAEA,MAAM,IAAIhG,iBACRgG,iBAAiBvE,QAAQuE,MAAM5C,OAAO,GAAGgE,OAAOpB,QAChD,iBACA,OACAxB,WACA;QAEJ;IACF;IAEA6C,UAAgB;QACd,KAAK,CAACA;QACN,IAAI,CAAC3F,MAAM,CAACC,IAAI,CAAC;IACnB;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-flow-novice",
3
- "version": "1.5.21",
3
+ "version": "1.5.22",
4
4
  "description": "Standalone Claude Flow for beginners - AI agent orchestration made easy with enhanced TDD testing pipeline. Enhanced init command creates complete agent system, MCP configuration with 30 essential tools, and automated hooks with single-file testing, real-time coverage analysis, and advanced validation. Fully standalone with zero external dependencies, complete project setup in one command.",
5
5
  "mcpName": "io.github.ruvnet/claude-flow",
6
6
  "main": ".claude-flow-novice/dist/index.js",
@@ -32,6 +32,31 @@
32
32
  - Refactoring or optimization work
33
33
  - ANY feature development (even "simple" ones)
34
34
 
35
+ ## 🚨 CRITICAL: Safe Test Execution
36
+
37
+ **NEVER run tests inside agents** - causes memory leaks from orphaned processes.
38
+
39
+ ### Correct Pattern:
40
+ ```bash
41
+ # 1. Run tests ONCE, save results
42
+ npm test -- --run --reporter=json > test-results.json 2>&1
43
+
44
+ # 2. Agents READ results file (no execution)
45
+ cat test-results.json
46
+
47
+ # 3. Kill orphaned processes after swarm
48
+ pkill -f vitest; pkill -f "npm test"
49
+ ```
50
+
51
+ ### Forbidden:
52
+ - ❌ `Task("agent", "run npm test", "type")` - spawns orphaned process
53
+ - ❌ Multiple agents running tests concurrently - 3x memory usage
54
+ - ❌ Long-running test commands without timeout cleanup
55
+
56
+ ### Memory Impact:
57
+ - Each test run: 65MB+ heap
58
+ - Concurrent runs: 65MB × agent_count
59
+ - Orphaned processes persist after swarm completion
35
60
  ### Agent Requirements by Task Complexity
36
61
 
37
62
  | Task Size | Steps | Agent Count | Example Team Composition |
@@ -61,8 +61,9 @@ Enhanced Features:
61
61
  }
62
62
 
63
63
  // Build unified pipeline command with TDD mode enabled by default
64
- // Use process.cwd() to find config/hooks in the actual project, not dist
65
- const pipelinePath = join(process.cwd(), 'config/hooks/post-edit-pipeline.js');
64
+ // Use __dirname to find config/hooks in the installed package location
65
+ // Path: .claude-flow-novice/dist/src/hooks -> ../../../../config/hooks
66
+ const pipelinePath = join(__dirname, '../../../../config/hooks/post-edit-pipeline.js');
66
67
  const pipelineArgs = [file, '--tdd-mode'];
67
68
 
68
69
  // Pass through all relevant flags
@@ -81,18 +82,28 @@ Enhanced Features:
81
82
  // Structured output is default in unified pipeline
82
83
  }
83
84
 
84
- // Execute unified pipeline
85
+ // Execute unified pipeline with timeout protection
85
86
  const proc = spawn('node', [pipelinePath, ...pipelineArgs], {
86
87
  stdio: 'inherit',
87
88
  cwd: process.cwd()
88
89
  });
89
90
 
91
+ // Set timeout to kill hanging processes (5 minutes max)
92
+ const timeout = setTimeout(() => {
93
+ console.error('❌ Pipeline timeout - killing process');
94
+ proc.kill('SIGKILL');
95
+ process.exit(1);
96
+ }, 300000); // 5 minutes
97
+
90
98
  proc.on('close', (code) => {
99
+ clearTimeout(timeout);
91
100
  process.exit(code || 0);
92
101
  });
93
102
 
94
103
  proc.on('error', (error) => {
104
+ clearTimeout(timeout);
95
105
  console.error(`❌ Failed to execute unified pipeline: ${error.message}`);
106
+ proc.kill('SIGKILL');
96
107
  process.exit(1);
97
108
  });
98
109
 
@@ -121,10 +132,17 @@ export async function enhancedPostEdit(file, memoryKey = null, options = {}) {
121
132
  let stdout = '';
122
133
  let stderr = '';
123
134
 
135
+ // Set timeout to kill hanging processes (5 minutes max)
136
+ const timeout = setTimeout(() => {
137
+ proc.kill('SIGKILL');
138
+ reject(new Error('Pipeline execution timeout after 5 minutes'));
139
+ }, 300000); // 5 minutes
140
+
124
141
  proc.stdout.on('data', (data) => stdout += data.toString());
125
142
  proc.stderr.on('data', (data) => stderr += data.toString());
126
143
 
127
144
  proc.on('close', (code) => {
145
+ clearTimeout(timeout);
128
146
  resolve({
129
147
  success: code === 0,
130
148
  file,
@@ -137,6 +155,8 @@ export async function enhancedPostEdit(file, memoryKey = null, options = {}) {
137
155
  });
138
156
 
139
157
  proc.on('error', (error) => {
158
+ clearTimeout(timeout);
159
+ proc.kill('SIGKILL');
140
160
  reject(error);
141
161
  });
142
162
  });