@appiq/flutter-workflow 1.4.3 → 2.1.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/CHANGELOG.md +160 -0
- package/README.md +69 -9
- package/agents/claude/cubit-agent.md +164 -2
- package/agents/claude/data-agent.md +163 -2
- package/agents/claude/domain-agent.md +164 -2
- package/agents/claude/feature-manager.md +361 -22
- package/agents/claude/integration-validator.md +1 -0
- package/agents/claude/po-agent.md +1 -0
- package/agents/claude/security-agent.md +163 -2
- package/agents/claude/test-agent.md +165 -2
- package/agents/claude/ui-agent.md +159 -8
- package/config/agent-coordination.json +335 -0
- package/config/independent-mode-template.md +202 -0
- package/lib/independent-agent-tracker.js +565 -0
- package/lib/setup-independent-mode.js +562 -0
- package/lib/state-manager.js +526 -0
- package/package.json +4 -2
- package/templates/enhanced-task-breakdown-template.md +415 -0
- package/templates/enhanced-task-history-template.md +605 -0
- package/templates/feature-template.md +116 -30
- package/templates/additional_cubit_req.md +0 -357
- package/templates/additional_data_req.md +0 -480
- package/templates/additional_domain_req.md +0 -431
- package/templates/additional_ui_req.md +0 -205
- package/templates/feature-history-template.md +0 -280
- package/templates/platform-adaptive-widget-template.dart +0 -407
- package/templates/pretty-ui-examples.md +0 -597
- package/templates/task-breakdown-template.md +0 -265
- package/templates/task-history-template.md +0 -276
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AppIQ Flutter Workflow - Independent Agent Tracking System
|
|
3
|
+
* Enables individual agents to work autonomously with full tracking and history
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs').promises;
|
|
7
|
+
const path = require('path');
|
|
8
|
+
|
|
9
|
+
class IndependentAgentTracker {
|
|
10
|
+
constructor(basePath = 'docs/independent-sessions') {
|
|
11
|
+
this.basePath = basePath;
|
|
12
|
+
this.sessionsPath = basePath;
|
|
13
|
+
this.activeSessions = new Map();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Initialize independent session for an agent
|
|
18
|
+
*/
|
|
19
|
+
async startIndependentSession(agentName, taskDescription, relatedFeature = null) {
|
|
20
|
+
const sessionId = `${agentName}_${Date.now()}`;
|
|
21
|
+
const sessionData = {
|
|
22
|
+
sessionId,
|
|
23
|
+
agentName,
|
|
24
|
+
taskDescription,
|
|
25
|
+
relatedFeature,
|
|
26
|
+
startTime: new Date().toISOString(),
|
|
27
|
+
status: 'active',
|
|
28
|
+
mode: 'independent',
|
|
29
|
+
activities: [],
|
|
30
|
+
tracking: {
|
|
31
|
+
progress: 0,
|
|
32
|
+
currentActivity: 'initializing',
|
|
33
|
+
estimatedDuration: 'unknown',
|
|
34
|
+
actualDuration: null
|
|
35
|
+
},
|
|
36
|
+
quality: {
|
|
37
|
+
checks: [],
|
|
38
|
+
validations: [],
|
|
39
|
+
issues: []
|
|
40
|
+
},
|
|
41
|
+
collaboration: {
|
|
42
|
+
feedbackRequests: [],
|
|
43
|
+
agentCoordination: [],
|
|
44
|
+
escalations: []
|
|
45
|
+
},
|
|
46
|
+
deliverables: [],
|
|
47
|
+
nextSteps: []
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Ensure directory exists
|
|
51
|
+
await this.ensureDirectoryExists();
|
|
52
|
+
|
|
53
|
+
// Save session
|
|
54
|
+
await this.saveSession(sessionId, sessionData);
|
|
55
|
+
this.activeSessions.set(sessionId, sessionData);
|
|
56
|
+
|
|
57
|
+
// Log session start
|
|
58
|
+
await this.logActivity(sessionId, 'session_started', {
|
|
59
|
+
description: `Started independent session for ${agentName}`,
|
|
60
|
+
task: taskDescription,
|
|
61
|
+
relatedFeature
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
console.log(`🚀 Started independent session: ${sessionId}`);
|
|
65
|
+
return sessionData;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Find related feature for current task
|
|
70
|
+
*/
|
|
71
|
+
async findRelatedFeature(taskDescription) {
|
|
72
|
+
try {
|
|
73
|
+
const featuresPath = 'docs/features';
|
|
74
|
+
const files = await fs.readdir(featuresPath);
|
|
75
|
+
const featureFiles = files.filter(file => file.endsWith('.md') && !file.includes('_state') && !file.includes('_history'));
|
|
76
|
+
|
|
77
|
+
const relatedFeatures = [];
|
|
78
|
+
|
|
79
|
+
for (const file of featureFiles) {
|
|
80
|
+
const featurePath = path.join(featuresPath, file);
|
|
81
|
+
const content = await fs.readFile(featurePath, 'utf8');
|
|
82
|
+
|
|
83
|
+
// Simple keyword matching - could be enhanced with better NLP
|
|
84
|
+
const keywords = this.extractKeywords(taskDescription.toLowerCase());
|
|
85
|
+
const featureContent = content.toLowerCase();
|
|
86
|
+
|
|
87
|
+
let relevanceScore = 0;
|
|
88
|
+
for (const keyword of keywords) {
|
|
89
|
+
if (featureContent.includes(keyword)) {
|
|
90
|
+
relevanceScore++;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (relevanceScore > 0) {
|
|
95
|
+
relatedFeatures.push({
|
|
96
|
+
featureName: file.replace('.md', ''),
|
|
97
|
+
relevanceScore,
|
|
98
|
+
filePath: featurePath
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Sort by relevance
|
|
104
|
+
relatedFeatures.sort((a, b) => b.relevanceScore - a.relevanceScore);
|
|
105
|
+
|
|
106
|
+
return relatedFeatures.slice(0, 3); // Return top 3 matches
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.warn('Could not search for related features:', error.message);
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Update existing feature with independent agent work
|
|
115
|
+
*/
|
|
116
|
+
async updateFeatureFromSession(sessionId, featureName) {
|
|
117
|
+
const session = await this.getSession(sessionId);
|
|
118
|
+
if (!session) {
|
|
119
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Update feature state if it exists
|
|
123
|
+
try {
|
|
124
|
+
const { FeatureStateManager } = require('./state-manager.js');
|
|
125
|
+
const stateManager = new FeatureStateManager();
|
|
126
|
+
|
|
127
|
+
await stateManager.updateAgentProgress(featureName, session.agentName, {
|
|
128
|
+
status: 'active',
|
|
129
|
+
progress: session.tracking.progress,
|
|
130
|
+
lastActivity: new Date().toISOString(),
|
|
131
|
+
independentSession: sessionId,
|
|
132
|
+
tasks: session.activities.map(activity => ({
|
|
133
|
+
id: activity.id,
|
|
134
|
+
description: activity.description,
|
|
135
|
+
status: activity.status || 'completed',
|
|
136
|
+
timestamp: activity.timestamp
|
|
137
|
+
}))
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Log coordination with feature workflow
|
|
141
|
+
await this.logActivity(sessionId, 'feature_coordination', {
|
|
142
|
+
description: `Coordinated with feature workflow: ${featureName}`,
|
|
143
|
+
featureName,
|
|
144
|
+
agentUpdated: session.agentName
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
console.log(`🔄 Updated feature ${featureName} with session ${sessionId} progress`);
|
|
148
|
+
return true;
|
|
149
|
+
} catch (error) {
|
|
150
|
+
console.warn(`Could not update feature ${featureName}:`, error.message);
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Create standalone component outside feature workflow
|
|
157
|
+
*/
|
|
158
|
+
async createStandaloneComponent(sessionId, componentName, componentType = 'widget') {
|
|
159
|
+
const session = await this.getSession(sessionId);
|
|
160
|
+
if (!session) {
|
|
161
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const component = {
|
|
165
|
+
name: componentName,
|
|
166
|
+
type: componentType,
|
|
167
|
+
createdAt: new Date().toISOString(),
|
|
168
|
+
agentCreator: session.agentName,
|
|
169
|
+
sessionId: sessionId,
|
|
170
|
+
filePath: `lib/shared/widgets/${componentName.toLowerCase()}.dart`,
|
|
171
|
+
standalone: true,
|
|
172
|
+
relatedFeatures: [],
|
|
173
|
+
quality: {
|
|
174
|
+
responsive: false,
|
|
175
|
+
accessible: false,
|
|
176
|
+
performant: false,
|
|
177
|
+
tested: false
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// Add to session deliverables
|
|
182
|
+
session.deliverables.push(component);
|
|
183
|
+
await this.saveSession(sessionId, session);
|
|
184
|
+
|
|
185
|
+
// Log component creation
|
|
186
|
+
await this.logActivity(sessionId, 'component_created', {
|
|
187
|
+
description: `Created standalone component: ${componentName}`,
|
|
188
|
+
componentName,
|
|
189
|
+
componentType,
|
|
190
|
+
filePath: component.filePath
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
console.log(`🎨 Created standalone component: ${componentName}`);
|
|
194
|
+
return component;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Log activity in independent session
|
|
199
|
+
*/
|
|
200
|
+
async logActivity(sessionId, activityType, details = {}) {
|
|
201
|
+
const session = await this.getSession(sessionId);
|
|
202
|
+
if (!session) {
|
|
203
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const activity = {
|
|
207
|
+
id: `activity_${Date.now()}`,
|
|
208
|
+
type: activityType,
|
|
209
|
+
timestamp: new Date().toISOString(),
|
|
210
|
+
agent: session.agentName,
|
|
211
|
+
description: details.description || activityType,
|
|
212
|
+
...details
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
session.activities.push(activity);
|
|
216
|
+
session.tracking.currentActivity = activityType;
|
|
217
|
+
session.tracking.lastUpdate = activity.timestamp;
|
|
218
|
+
|
|
219
|
+
await this.saveSession(sessionId, session);
|
|
220
|
+
|
|
221
|
+
// Also log to central activity log
|
|
222
|
+
await this.logToCentralActivity(activity);
|
|
223
|
+
|
|
224
|
+
return activity;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Update session progress and status
|
|
229
|
+
*/
|
|
230
|
+
async updateProgress(sessionId, progress, status = null, currentActivity = null) {
|
|
231
|
+
const session = await this.getSession(sessionId);
|
|
232
|
+
if (!session) {
|
|
233
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
session.tracking.progress = Math.max(0, Math.min(100, progress));
|
|
237
|
+
if (status) session.status = status;
|
|
238
|
+
if (currentActivity) session.tracking.currentActivity = currentActivity;
|
|
239
|
+
|
|
240
|
+
await this.saveSession(sessionId, session);
|
|
241
|
+
|
|
242
|
+
await this.logActivity(sessionId, 'progress_update', {
|
|
243
|
+
description: `Progress updated to ${progress}%`,
|
|
244
|
+
progress,
|
|
245
|
+
status,
|
|
246
|
+
currentActivity
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
return session;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Validate quality of independent work
|
|
254
|
+
*/
|
|
255
|
+
async validateQuality(sessionId, checks = []) {
|
|
256
|
+
const session = await this.getSession(sessionId);
|
|
257
|
+
if (!session) {
|
|
258
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const validation = {
|
|
262
|
+
timestamp: new Date().toISOString(),
|
|
263
|
+
checks: checks.length > 0 ? checks : ['responsive', 'accessible', 'performant', 'consistent'],
|
|
264
|
+
results: {},
|
|
265
|
+
overall: 'pending'
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
// Perform quality checks (placeholder - would integrate with actual validation)
|
|
269
|
+
for (const check of validation.checks) {
|
|
270
|
+
validation.results[check] = await this.performQualityCheck(check, session);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Determine overall result
|
|
274
|
+
const passed = Object.values(validation.results).filter(result => result === true).length;
|
|
275
|
+
const total = validation.checks.length;
|
|
276
|
+
validation.overall = passed === total ? 'passed' : passed >= total * 0.8 ? 'warning' : 'failed';
|
|
277
|
+
|
|
278
|
+
session.quality.validations.push(validation);
|
|
279
|
+
await this.saveSession(sessionId, session);
|
|
280
|
+
|
|
281
|
+
await this.logActivity(sessionId, 'quality_validation', {
|
|
282
|
+
description: `Quality validation completed: ${validation.overall}`,
|
|
283
|
+
validation
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
return validation;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Request feedback from user
|
|
291
|
+
*/
|
|
292
|
+
async requestFeedback(sessionId, feedbackType, context = {}) {
|
|
293
|
+
const session = await this.getSession(sessionId);
|
|
294
|
+
if (!session) {
|
|
295
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const feedbackRequest = {
|
|
299
|
+
id: `feedback_${Date.now()}`,
|
|
300
|
+
type: feedbackType,
|
|
301
|
+
timestamp: new Date().toISOString(),
|
|
302
|
+
context,
|
|
303
|
+
status: 'pending',
|
|
304
|
+
response: null
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
session.collaboration.feedbackRequests.push(feedbackRequest);
|
|
308
|
+
await this.saveSession(sessionId, session);
|
|
309
|
+
|
|
310
|
+
await this.logActivity(sessionId, 'feedback_requested', {
|
|
311
|
+
description: `Requested ${feedbackType} feedback`,
|
|
312
|
+
feedbackType,
|
|
313
|
+
context
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
return feedbackRequest;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Coordinate with other agents
|
|
321
|
+
*/
|
|
322
|
+
async coordinateWithAgents(sessionId, agents, purpose, context = {}) {
|
|
323
|
+
const session = await this.getSession(sessionId);
|
|
324
|
+
if (!session) {
|
|
325
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const coordination = {
|
|
329
|
+
id: `coordination_${Date.now()}`,
|
|
330
|
+
timestamp: new Date().toISOString(),
|
|
331
|
+
initiatingAgent: session.agentName,
|
|
332
|
+
targetAgents: agents,
|
|
333
|
+
purpose,
|
|
334
|
+
context,
|
|
335
|
+
status: 'initiated',
|
|
336
|
+
responses: []
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
session.collaboration.agentCoordination.push(coordination);
|
|
340
|
+
await this.saveSession(sessionId, session);
|
|
341
|
+
|
|
342
|
+
await this.logActivity(sessionId, 'agent_coordination', {
|
|
343
|
+
description: `Coordinating with agents: ${agents.join(', ')}`,
|
|
344
|
+
purpose,
|
|
345
|
+
targetAgents: agents
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
return coordination;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Escalate to full workflow
|
|
353
|
+
*/
|
|
354
|
+
async escalateToWorkflow(sessionId, reason, complexity = 'medium') {
|
|
355
|
+
const session = await this.getSession(sessionId);
|
|
356
|
+
if (!session) {
|
|
357
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const escalation = {
|
|
361
|
+
id: `escalation_${Date.now()}`,
|
|
362
|
+
timestamp: new Date().toISOString(),
|
|
363
|
+
reason,
|
|
364
|
+
complexity,
|
|
365
|
+
sessionId,
|
|
366
|
+
agentName: session.agentName,
|
|
367
|
+
taskDescription: session.taskDescription,
|
|
368
|
+
currentProgress: session.tracking.progress,
|
|
369
|
+
workDone: session.activities,
|
|
370
|
+
status: 'pending'
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
session.collaboration.escalations.push(escalation);
|
|
374
|
+
session.status = 'escalated';
|
|
375
|
+
await this.saveSession(sessionId, session);
|
|
376
|
+
|
|
377
|
+
await this.logActivity(sessionId, 'workflow_escalation', {
|
|
378
|
+
description: `Escalated to full workflow: ${reason}`,
|
|
379
|
+
reason,
|
|
380
|
+
complexity
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
// Notify FeatureMaster about escalation
|
|
384
|
+
await this.notifyFeatureMaster(escalation);
|
|
385
|
+
|
|
386
|
+
return escalation;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Complete independent session
|
|
391
|
+
*/
|
|
392
|
+
async completeSession(sessionId, summary = '') {
|
|
393
|
+
const session = await this.getSession(sessionId);
|
|
394
|
+
if (!session) {
|
|
395
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
session.status = 'completed';
|
|
399
|
+
session.endTime = new Date().toISOString();
|
|
400
|
+
session.tracking.actualDuration = new Date(session.endTime) - new Date(session.startTime);
|
|
401
|
+
session.tracking.progress = 100;
|
|
402
|
+
session.summary = summary;
|
|
403
|
+
|
|
404
|
+
await this.saveSession(sessionId, session);
|
|
405
|
+
|
|
406
|
+
await this.logActivity(sessionId, 'session_completed', {
|
|
407
|
+
description: `Session completed successfully`,
|
|
408
|
+
summary,
|
|
409
|
+
duration: session.tracking.actualDuration
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
this.activeSessions.delete(sessionId);
|
|
413
|
+
console.log(`✅ Completed independent session: ${sessionId}`);
|
|
414
|
+
return session;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Get session health status
|
|
419
|
+
*/
|
|
420
|
+
async getSessionHealth(sessionId = null) {
|
|
421
|
+
if (sessionId) {
|
|
422
|
+
const session = await this.getSession(sessionId);
|
|
423
|
+
return this.analyzeSessionHealth(session);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Analyze all active sessions
|
|
427
|
+
const healthReport = {
|
|
428
|
+
timestamp: new Date().toISOString(),
|
|
429
|
+
totalSessions: this.activeSessions.size,
|
|
430
|
+
healthySessions: 0,
|
|
431
|
+
warningSessions: 0,
|
|
432
|
+
criticalSessions: 0,
|
|
433
|
+
sessions: {}
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
for (const [id, session] of this.activeSessions) {
|
|
437
|
+
const health = this.analyzeSessionHealth(session);
|
|
438
|
+
healthReport.sessions[id] = health;
|
|
439
|
+
|
|
440
|
+
if (health.status === 'healthy') healthReport.healthySessions++;
|
|
441
|
+
else if (health.status === 'warning') healthReport.warningSessions++;
|
|
442
|
+
else healthReport.criticalSessions++;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
return healthReport;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Helper methods
|
|
449
|
+
|
|
450
|
+
async ensureDirectoryExists() {
|
|
451
|
+
try {
|
|
452
|
+
await fs.mkdir(this.basePath, { recursive: true });
|
|
453
|
+
} catch (error) {
|
|
454
|
+
if (error.code !== 'EEXIST') throw error;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
async saveSession(sessionId, sessionData) {
|
|
459
|
+
const filePath = path.join(this.basePath, `${sessionId}.json`);
|
|
460
|
+
await fs.writeFile(filePath, JSON.stringify(sessionData, null, 2));
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
async getSession(sessionId) {
|
|
464
|
+
try {
|
|
465
|
+
if (this.activeSessions.has(sessionId)) {
|
|
466
|
+
return this.activeSessions.get(sessionId);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
const filePath = path.join(this.basePath, `${sessionId}.json`);
|
|
470
|
+
const data = await fs.readFile(filePath, 'utf8');
|
|
471
|
+
const session = JSON.parse(data);
|
|
472
|
+
|
|
473
|
+
if (session.status === 'active') {
|
|
474
|
+
this.activeSessions.set(sessionId, session);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
return session;
|
|
478
|
+
} catch (error) {
|
|
479
|
+
return null;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
extractKeywords(text) {
|
|
484
|
+
const commonWords = ['the', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'of', 'with', 'by', 'is', 'are', 'was', 'were', 'be', 'been', 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could', 'should', 'may', 'might', 'can', 'must', 'a', 'an'];
|
|
485
|
+
return text.split(/\s+/)
|
|
486
|
+
.filter(word => word.length > 2 && !commonWords.includes(word))
|
|
487
|
+
.slice(0, 10); // Top 10 keywords
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
async performQualityCheck(checkType, session) {
|
|
491
|
+
// Placeholder for actual quality checks
|
|
492
|
+
// In real implementation, this would integrate with testing frameworks
|
|
493
|
+
console.log(`🔍 Performing ${checkType} quality check for session ${session.sessionId}`);
|
|
494
|
+
return Math.random() > 0.2; // 80% pass rate for demo
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
async logToCentralActivity(activity) {
|
|
498
|
+
try {
|
|
499
|
+
const centralLogPath = 'docs/independent-sessions/activity-log.json';
|
|
500
|
+
|
|
501
|
+
let log = { activities: [] };
|
|
502
|
+
try {
|
|
503
|
+
const existingLog = await fs.readFile(centralLogPath, 'utf8');
|
|
504
|
+
log = JSON.parse(existingLog);
|
|
505
|
+
} catch {
|
|
506
|
+
// File doesn't exist, start fresh
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
log.activities.push(activity);
|
|
510
|
+
|
|
511
|
+
// Keep only last 1000 activities
|
|
512
|
+
if (log.activities.length > 1000) {
|
|
513
|
+
log.activities = log.activities.slice(-1000);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
await fs.writeFile(centralLogPath, JSON.stringify(log, null, 2));
|
|
517
|
+
} catch (error) {
|
|
518
|
+
console.warn('Could not log to central activity log:', error.message);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
async notifyFeatureMaster(escalation) {
|
|
523
|
+
// Placeholder for FeatureMaster notification
|
|
524
|
+
console.log(`📢 Notifying FeatureMaster about escalation: ${escalation.id}`);
|
|
525
|
+
// In real implementation, this would trigger FeatureMaster workflow
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
analyzeSessionHealth(session) {
|
|
529
|
+
if (!session) return { status: 'error', message: 'Session not found' };
|
|
530
|
+
|
|
531
|
+
const issues = [];
|
|
532
|
+
const now = new Date();
|
|
533
|
+
const sessionStart = new Date(session.startTime);
|
|
534
|
+
const hoursActive = (now - sessionStart) / (1000 * 60 * 60);
|
|
535
|
+
|
|
536
|
+
// Check session age
|
|
537
|
+
if (hoursActive > 24 && session.status === 'active') {
|
|
538
|
+
issues.push('Session active for over 24 hours');
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// Check progress
|
|
542
|
+
if (session.tracking.progress < 10 && hoursActive > 2) {
|
|
543
|
+
issues.push('Low progress after significant time');
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// Check activity
|
|
547
|
+
const lastActivity = session.activities[session.activities.length - 1];
|
|
548
|
+
if (lastActivity) {
|
|
549
|
+
const hoursSinceActivity = (now - new Date(lastActivity.timestamp)) / (1000 * 60 * 60);
|
|
550
|
+
if (hoursSinceActivity > 4 && session.status === 'active') {
|
|
551
|
+
issues.push('No activity for over 4 hours');
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
return {
|
|
556
|
+
status: issues.length === 0 ? 'healthy' : issues.length < 3 ? 'warning' : 'critical',
|
|
557
|
+
issues,
|
|
558
|
+
progress: session.tracking.progress,
|
|
559
|
+
duration: hoursActive,
|
|
560
|
+
lastActivity: lastActivity?.timestamp || session.startTime
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
module.exports = { IndependentAgentTracker };
|