@agile-vibe-coding/avc 0.1.1 → 0.3.1
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/cli/agent-loader.js +21 -0
- package/cli/agents/agent-selector.md +152 -0
- package/cli/agents/architecture-recommender.md +418 -0
- package/cli/agents/code-implementer.md +117 -0
- package/cli/agents/code-validator.md +80 -0
- package/cli/agents/context-reviewer-epic.md +101 -0
- package/cli/agents/context-reviewer-story.md +92 -0
- package/cli/agents/context-writer-epic.md +145 -0
- package/cli/agents/context-writer-story.md +111 -0
- package/cli/agents/database-deep-dive.md +470 -0
- package/cli/agents/database-recommender.md +634 -0
- package/cli/agents/doc-distributor.md +176 -0
- package/cli/agents/doc-writer-epic.md +42 -0
- package/cli/agents/doc-writer-story.md +43 -0
- package/cli/agents/documentation-updater.md +203 -0
- package/cli/agents/duplicate-detector.md +110 -0
- package/cli/agents/epic-story-decomposer.md +559 -0
- package/cli/agents/feature-context-generator.md +91 -0
- package/cli/agents/gap-checker-epic.md +52 -0
- package/cli/agents/impact-checker-story.md +51 -0
- package/cli/agents/migration-guide-generator.md +305 -0
- package/cli/agents/mission-scope-generator.md +143 -0
- package/cli/agents/mission-scope-validator.md +146 -0
- package/cli/agents/project-context-extractor.md +122 -0
- package/cli/agents/project-documentation-creator.json +226 -0
- package/cli/agents/project-documentation-creator.md +595 -0
- package/cli/agents/question-prefiller.md +269 -0
- package/cli/agents/refiner-epic.md +39 -0
- package/cli/agents/refiner-story.md +42 -0
- package/cli/agents/scaffolding-generator.md +99 -0
- package/cli/agents/seed-validator.md +71 -0
- package/cli/agents/story-doc-enricher.md +133 -0
- package/cli/agents/story-scope-reviewer.md +147 -0
- package/cli/agents/story-splitter.md +83 -0
- package/cli/agents/suggestion-business-analyst.md +88 -0
- package/cli/agents/suggestion-deployment-architect.md +263 -0
- package/cli/agents/suggestion-product-manager.md +129 -0
- package/cli/agents/suggestion-security-specialist.md +156 -0
- package/cli/agents/suggestion-technical-architect.md +269 -0
- package/cli/agents/suggestion-ux-researcher.md +93 -0
- package/cli/agents/task-subtask-decomposer.md +188 -0
- package/cli/agents/validator-documentation.json +183 -0
- package/cli/agents/validator-documentation.md +455 -0
- package/cli/agents/validator-selector.md +211 -0
- package/cli/ansi-colors.js +21 -0
- package/cli/api-reference-tool.js +368 -0
- package/cli/build-docs.js +29 -8
- package/cli/ceremony-history.js +369 -0
- package/cli/checks/catalog.json +76 -0
- package/cli/checks/code/quality.json +26 -0
- package/cli/checks/code/testing.json +14 -0
- package/cli/checks/code/traceability.json +26 -0
- package/cli/checks/cross-refs/epic.json +171 -0
- package/cli/checks/cross-refs/story.json +149 -0
- package/cli/checks/epic/api.json +114 -0
- package/cli/checks/epic/backend.json +126 -0
- package/cli/checks/epic/cloud.json +126 -0
- package/cli/checks/epic/data.json +102 -0
- package/cli/checks/epic/database.json +114 -0
- package/cli/checks/epic/developer.json +182 -0
- package/cli/checks/epic/devops.json +174 -0
- package/cli/checks/epic/frontend.json +162 -0
- package/cli/checks/epic/mobile.json +102 -0
- package/cli/checks/epic/qa.json +90 -0
- package/cli/checks/epic/security.json +184 -0
- package/cli/checks/epic/solution-architect.json +192 -0
- package/cli/checks/epic/test-architect.json +90 -0
- package/cli/checks/epic/ui.json +102 -0
- package/cli/checks/epic/ux.json +90 -0
- package/cli/checks/fixes/epic-fix-template.md +10 -0
- package/cli/checks/fixes/story-fix-template.md +10 -0
- package/cli/checks/story/api.json +186 -0
- package/cli/checks/story/backend.json +102 -0
- package/cli/checks/story/cloud.json +102 -0
- package/cli/checks/story/data.json +210 -0
- package/cli/checks/story/database.json +102 -0
- package/cli/checks/story/developer.json +168 -0
- package/cli/checks/story/devops.json +102 -0
- package/cli/checks/story/frontend.json +174 -0
- package/cli/checks/story/mobile.json +102 -0
- package/cli/checks/story/qa.json +210 -0
- package/cli/checks/story/security.json +198 -0
- package/cli/checks/story/solution-architect.json +230 -0
- package/cli/checks/story/test-architect.json +210 -0
- package/cli/checks/story/ui.json +102 -0
- package/cli/checks/story/ux.json +102 -0
- package/cli/coding-order.js +401 -0
- package/cli/command-logger.js +49 -12
- package/cli/components/static-output.js +63 -0
- package/cli/console-output-manager.js +94 -0
- package/cli/dependency-checker.js +72 -0
- package/cli/docs-sync.js +306 -0
- package/cli/epic-story-validator.js +659 -0
- package/cli/evaluation-prompts.js +1008 -0
- package/cli/execution-context.js +195 -0
- package/cli/generate-summary-table.js +340 -0
- package/cli/init-model-config.js +704 -0
- package/cli/init.js +1737 -278
- package/cli/kanban-server-manager.js +227 -0
- package/cli/llm-claude.js +150 -1
- package/cli/llm-gemini.js +109 -0
- package/cli/llm-local.js +493 -0
- package/cli/llm-mock.js +233 -0
- package/cli/llm-openai.js +454 -0
- package/cli/llm-provider.js +379 -3
- package/cli/llm-token-limits.js +211 -0
- package/cli/llm-verifier.js +662 -0
- package/cli/llm-xiaomi.js +143 -0
- package/cli/message-constants.js +49 -0
- package/cli/message-manager.js +334 -0
- package/cli/message-types.js +96 -0
- package/cli/messaging-api.js +291 -0
- package/cli/micro-check-fixer.js +335 -0
- package/cli/micro-check-runner.js +449 -0
- package/cli/micro-check-scorer.js +148 -0
- package/cli/micro-check-validator.js +538 -0
- package/cli/model-pricing.js +192 -0
- package/cli/model-query-engine.js +468 -0
- package/cli/model-recommendation-analyzer.js +495 -0
- package/cli/model-selector.js +270 -0
- package/cli/output-buffer.js +107 -0
- package/cli/process-manager.js +73 -2
- package/cli/prompt-logger.js +57 -0
- package/cli/repl-ink.js +4625 -1094
- package/cli/repl-old.js +3 -4
- package/cli/seed-processor.js +962 -0
- package/cli/sprint-planning-processor.js +4162 -0
- package/cli/template-processor.js +2149 -105
- package/cli/templates/project.md +25 -8
- package/cli/templates/vitepress-config.mts.template +5 -4
- package/cli/token-tracker.js +547 -0
- package/cli/tools/generate-story-validators.js +317 -0
- package/cli/tools/generate-validators.js +669 -0
- package/cli/update-checker.js +19 -17
- package/cli/update-notifier.js +4 -4
- package/cli/validation-router.js +667 -0
- package/cli/verification-tracker.js +563 -0
- package/cli/worktree-runner.js +654 -0
- package/kanban/README.md +386 -0
- package/kanban/client/README.md +205 -0
- package/kanban/client/components.json +20 -0
- package/kanban/client/dist/assets/index-D_KC5EQT.css +1 -0
- package/kanban/client/dist/assets/index-DjY5zqW7.js +351 -0
- package/kanban/client/dist/index.html +16 -0
- package/kanban/client/dist/vite.svg +1 -0
- package/kanban/client/index.html +15 -0
- package/kanban/client/package-lock.json +9442 -0
- package/kanban/client/package.json +44 -0
- package/kanban/client/postcss.config.js +6 -0
- package/kanban/client/public/vite.svg +1 -0
- package/kanban/client/src/App.jsx +651 -0
- package/kanban/client/src/components/ProjectFileEditorPopup.jsx +117 -0
- package/kanban/client/src/components/ceremony/AskArchPopup.jsx +420 -0
- package/kanban/client/src/components/ceremony/AskModelPopup.jsx +629 -0
- package/kanban/client/src/components/ceremony/CeremonyWorkflowModal.jsx +1133 -0
- package/kanban/client/src/components/ceremony/EpicStorySelectionModal.jsx +254 -0
- package/kanban/client/src/components/ceremony/ProviderSwitcherButton.jsx +290 -0
- package/kanban/client/src/components/ceremony/SponsorCallModal.jsx +686 -0
- package/kanban/client/src/components/ceremony/SprintPlanningModal.jsx +838 -0
- package/kanban/client/src/components/ceremony/steps/ArchitectureStep.jsx +150 -0
- package/kanban/client/src/components/ceremony/steps/CompleteStep.jsx +136 -0
- package/kanban/client/src/components/ceremony/steps/DatabaseStep.jsx +202 -0
- package/kanban/client/src/components/ceremony/steps/DeploymentStep.jsx +123 -0
- package/kanban/client/src/components/ceremony/steps/MissionStep.jsx +106 -0
- package/kanban/client/src/components/ceremony/steps/ReviewAnswersStep.jsx +329 -0
- package/kanban/client/src/components/ceremony/steps/RunningStep.jsx +249 -0
- package/kanban/client/src/components/kanban/CardDetailModal.jsx +646 -0
- package/kanban/client/src/components/kanban/EpicSection.jsx +146 -0
- package/kanban/client/src/components/kanban/FilterToolbar.jsx +222 -0
- package/kanban/client/src/components/kanban/GroupingSelector.jsx +63 -0
- package/kanban/client/src/components/kanban/KanbanBoard.jsx +211 -0
- package/kanban/client/src/components/kanban/KanbanCard.jsx +147 -0
- package/kanban/client/src/components/kanban/KanbanColumn.jsx +90 -0
- package/kanban/client/src/components/kanban/RefineWorkItemPopup.jsx +784 -0
- package/kanban/client/src/components/kanban/RunButton.jsx +162 -0
- package/kanban/client/src/components/kanban/SeedButton.jsx +176 -0
- package/kanban/client/src/components/layout/LoadingScreen.jsx +82 -0
- package/kanban/client/src/components/process/ProcessMonitorBar.jsx +80 -0
- package/kanban/client/src/components/settings/AgentEditorPopup.jsx +171 -0
- package/kanban/client/src/components/settings/AgentsTab.jsx +381 -0
- package/kanban/client/src/components/settings/ApiKeysTab.jsx +142 -0
- package/kanban/client/src/components/settings/CeremonyModelsTab.jsx +105 -0
- package/kanban/client/src/components/settings/CheckEditorPopup.jsx +507 -0
- package/kanban/client/src/components/settings/CostThresholdsTab.jsx +95 -0
- package/kanban/client/src/components/settings/ModelPricingTab.jsx +269 -0
- package/kanban/client/src/components/settings/OpenAIAuthSection.jsx +412 -0
- package/kanban/client/src/components/settings/ServersTab.jsx +121 -0
- package/kanban/client/src/components/settings/SettingsModal.jsx +84 -0
- package/kanban/client/src/components/stats/CostModal.jsx +384 -0
- package/kanban/client/src/components/ui/badge.jsx +27 -0
- package/kanban/client/src/components/ui/dialog.jsx +121 -0
- package/kanban/client/src/components/ui/tabs.jsx +85 -0
- package/kanban/client/src/hooks/__tests__/useGrouping.test.js +232 -0
- package/kanban/client/src/hooks/useGrouping.js +177 -0
- package/kanban/client/src/hooks/useWebSocket.js +120 -0
- package/kanban/client/src/lib/__tests__/api.test.js +196 -0
- package/kanban/client/src/lib/__tests__/status-grouping.test.js +94 -0
- package/kanban/client/src/lib/api.js +515 -0
- package/kanban/client/src/lib/status-grouping.js +154 -0
- package/kanban/client/src/lib/utils.js +11 -0
- package/kanban/client/src/main.jsx +10 -0
- package/kanban/client/src/store/__tests__/kanbanStore.test.js +164 -0
- package/kanban/client/src/store/ceremonyStore.js +172 -0
- package/kanban/client/src/store/filterStore.js +201 -0
- package/kanban/client/src/store/kanbanStore.js +123 -0
- package/kanban/client/src/store/processStore.js +65 -0
- package/kanban/client/src/store/sprintPlanningStore.js +33 -0
- package/kanban/client/src/styles/globals.css +59 -0
- package/kanban/client/tailwind.config.js +77 -0
- package/kanban/client/vite.config.js +28 -0
- package/kanban/client/vitest.config.js +28 -0
- package/kanban/dev-start.sh +47 -0
- package/kanban/package.json +12 -0
- package/kanban/server/index.js +537 -0
- package/kanban/server/routes/ceremony.js +454 -0
- package/kanban/server/routes/costs.js +163 -0
- package/kanban/server/routes/openai-oauth.js +366 -0
- package/kanban/server/routes/processes.js +50 -0
- package/kanban/server/routes/settings.js +736 -0
- package/kanban/server/routes/websocket.js +281 -0
- package/kanban/server/routes/work-items.js +487 -0
- package/kanban/server/services/CeremonyService.js +1441 -0
- package/kanban/server/services/FileSystemScanner.js +95 -0
- package/kanban/server/services/FileWatcher.js +144 -0
- package/kanban/server/services/HierarchyBuilder.js +196 -0
- package/kanban/server/services/ProcessRegistry.js +122 -0
- package/kanban/server/services/TaskRunnerService.js +261 -0
- package/kanban/server/services/WorkItemReader.js +123 -0
- package/kanban/server/services/WorkItemRefineService.js +510 -0
- package/kanban/server/start.js +49 -0
- package/kanban/server/utils/kanban-logger.js +132 -0
- package/kanban/server/utils/markdown.js +91 -0
- package/kanban/server/utils/status-grouping.js +107 -0
- package/kanban/server/workers/run-task-worker.js +121 -0
- package/kanban/server/workers/seed-worker.js +94 -0
- package/kanban/server/workers/sponsor-call-worker.js +92 -0
- package/kanban/server/workers/sprint-planning-worker.js +212 -0
- package/package.json +19 -7
- package/cli/agents/documentation.md +0 -302
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VerificationTracker - Tracks LLM verification workflow efficiency
|
|
3
|
+
*
|
|
4
|
+
* Provides comprehensive tracking of verification sessions:
|
|
5
|
+
* - Per-rule execution metrics (timing, results, content changes)
|
|
6
|
+
* - Per-agent session statistics (violations, API calls, duration)
|
|
7
|
+
* - Ceremony-level summaries (total overhead, most violated rules)
|
|
8
|
+
*
|
|
9
|
+
* Outputs:
|
|
10
|
+
* - Real-time console logs during execution
|
|
11
|
+
* - Structured JSON data for analysis
|
|
12
|
+
* - Human-readable summary report
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import fs from 'fs';
|
|
16
|
+
import path from 'path';
|
|
17
|
+
|
|
18
|
+
class VerificationTracker {
|
|
19
|
+
constructor(ceremonyName) {
|
|
20
|
+
this.ceremonyName = ceremonyName;
|
|
21
|
+
this.ceremonyStartTime = Date.now();
|
|
22
|
+
this.sessions = [];
|
|
23
|
+
this.currentSession = null;
|
|
24
|
+
this.currentRuleExecution = null;
|
|
25
|
+
this.verificationCache = new Map(); // Cache for current ceremony
|
|
26
|
+
this.ruleProfiles = this.loadRuleProfiles(); // Load historical pass rates
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Start tracking a verification session for an agent
|
|
31
|
+
*/
|
|
32
|
+
startSession(agentName, inputContent) {
|
|
33
|
+
this.currentSession = {
|
|
34
|
+
sessionId: `verify-${this.sessions.length + 1}`,
|
|
35
|
+
agentName,
|
|
36
|
+
startTime: new Date().toISOString(),
|
|
37
|
+
startTimeMs: Date.now(),
|
|
38
|
+
input: {
|
|
39
|
+
contentLength: inputContent.length,
|
|
40
|
+
contentPreview: inputContent.substring(0, 200),
|
|
41
|
+
contentHash: this.hashContent(inputContent)
|
|
42
|
+
},
|
|
43
|
+
ruleExecutions: [],
|
|
44
|
+
violations: []
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Start tracking a rule check
|
|
50
|
+
*/
|
|
51
|
+
startRuleCheck(rule) {
|
|
52
|
+
this.currentRuleExecution = {
|
|
53
|
+
ruleId: rule.id,
|
|
54
|
+
ruleName: rule.name,
|
|
55
|
+
severity: rule.severity,
|
|
56
|
+
checkStartTime: new Date().toISOString(),
|
|
57
|
+
checkStartTimeMs: Date.now()
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* End tracking a rule check
|
|
63
|
+
*/
|
|
64
|
+
endRuleCheck(result) {
|
|
65
|
+
this.currentRuleExecution.checkEndTime = new Date().toISOString();
|
|
66
|
+
this.currentRuleExecution.checkEndTimeMs = Date.now();
|
|
67
|
+
this.currentRuleExecution.checkDurationMs =
|
|
68
|
+
this.currentRuleExecution.checkEndTimeMs - this.currentRuleExecution.checkStartTimeMs;
|
|
69
|
+
this.currentRuleExecution.checkResult = result;
|
|
70
|
+
this.currentRuleExecution.wasViolated = result === 'YES';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Start tracking a rule fix
|
|
75
|
+
*/
|
|
76
|
+
startRuleFix(contentLength) {
|
|
77
|
+
this.currentRuleExecution.fixApplied = true;
|
|
78
|
+
this.currentRuleExecution.fixStartTime = new Date().toISOString();
|
|
79
|
+
this.currentRuleExecution.fixStartTimeMs = Date.now();
|
|
80
|
+
this.currentRuleExecution.contentLengthBefore = contentLength;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* End tracking a rule fix
|
|
85
|
+
*/
|
|
86
|
+
endRuleFix(contentLength) {
|
|
87
|
+
this.currentRuleExecution.fixEndTime = new Date().toISOString();
|
|
88
|
+
this.currentRuleExecution.fixEndTimeMs = Date.now();
|
|
89
|
+
this.currentRuleExecution.fixDurationMs =
|
|
90
|
+
this.currentRuleExecution.fixEndTimeMs - this.currentRuleExecution.fixStartTimeMs;
|
|
91
|
+
this.currentRuleExecution.contentLengthAfter = contentLength;
|
|
92
|
+
this.currentRuleExecution.contentChangedBy =
|
|
93
|
+
contentLength - this.currentRuleExecution.contentLengthBefore;
|
|
94
|
+
|
|
95
|
+
// Add to violations list
|
|
96
|
+
this.currentSession.violations.push({
|
|
97
|
+
ruleId: this.currentRuleExecution.ruleId,
|
|
98
|
+
severity: this.currentRuleExecution.severity,
|
|
99
|
+
fixed: true
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Complete the current rule execution
|
|
105
|
+
*/
|
|
106
|
+
completeRule() {
|
|
107
|
+
if (this.currentRuleExecution && this.currentSession) {
|
|
108
|
+
this.currentSession.ruleExecutions.push(this.currentRuleExecution);
|
|
109
|
+
this.currentRuleExecution = null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* End the current verification session
|
|
115
|
+
*/
|
|
116
|
+
endSession(outputContent, rulesApplied) {
|
|
117
|
+
this.currentSession.endTime = new Date().toISOString();
|
|
118
|
+
this.currentSession.endTimeMs = Date.now();
|
|
119
|
+
this.currentSession.durationMs =
|
|
120
|
+
this.currentSession.endTimeMs - this.currentSession.startTimeMs;
|
|
121
|
+
|
|
122
|
+
this.currentSession.output = {
|
|
123
|
+
contentLength: outputContent.length,
|
|
124
|
+
contentPreview: outputContent.substring(0, 200),
|
|
125
|
+
contentChangedBy: outputContent.length - this.currentSession.input.contentLength,
|
|
126
|
+
rulesAppliedCount: rulesApplied.length
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// Calculate statistics
|
|
130
|
+
const executions = this.currentSession.ruleExecutions;
|
|
131
|
+
this.currentSession.ruleStats = {
|
|
132
|
+
totalRulesChecked: executions.length,
|
|
133
|
+
rulesPassed: executions.filter(e => !e.wasViolated).length,
|
|
134
|
+
rulesViolated: executions.filter(e => e.wasViolated).length,
|
|
135
|
+
rulesFixed: executions.filter(e => e.fixApplied).length,
|
|
136
|
+
rulesSkipped: 0
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
this.currentSession.apiCalls = {
|
|
140
|
+
checkCalls: executions.length,
|
|
141
|
+
fixCalls: executions.filter(e => e.fixApplied).length,
|
|
142
|
+
totalCalls: executions.length + executions.filter(e => e.fixApplied).length
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
this.sessions.push(this.currentSession);
|
|
146
|
+
this.currentSession = null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Record a simple validation check (for multi-agent validation)
|
|
151
|
+
* Lighter-weight alternative to full startSession/endSession flow
|
|
152
|
+
*/
|
|
153
|
+
recordCheck(agentName, checkType, passed) {
|
|
154
|
+
const checkRecord = {
|
|
155
|
+
agentName,
|
|
156
|
+
checkType,
|
|
157
|
+
passed,
|
|
158
|
+
timestamp: new Date().toISOString()
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// Add to sessions as a lightweight record
|
|
162
|
+
this.sessions.push({
|
|
163
|
+
sessionId: `check-${this.sessions.length + 1}`,
|
|
164
|
+
agentName,
|
|
165
|
+
checkType,
|
|
166
|
+
passed,
|
|
167
|
+
startTime: checkRecord.timestamp,
|
|
168
|
+
endTime: checkRecord.timestamp,
|
|
169
|
+
durationMs: 0,
|
|
170
|
+
ruleStats: {
|
|
171
|
+
totalRulesChecked: 1,
|
|
172
|
+
rulesPassed: passed ? 1 : 0,
|
|
173
|
+
rulesViolated: passed ? 0 : 1,
|
|
174
|
+
rulesFixed: 0,
|
|
175
|
+
rulesSkipped: 0
|
|
176
|
+
},
|
|
177
|
+
apiCalls: {
|
|
178
|
+
checkCalls: 1,
|
|
179
|
+
fixCalls: 0,
|
|
180
|
+
totalCalls: 1
|
|
181
|
+
},
|
|
182
|
+
violations: []
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Get complete ceremony summary
|
|
188
|
+
*/
|
|
189
|
+
getCeremonySummary() {
|
|
190
|
+
const ceremonyEndTime = Date.now();
|
|
191
|
+
const ceremonyDurationMs = ceremonyEndTime - this.ceremonyStartTime;
|
|
192
|
+
|
|
193
|
+
const summary = {
|
|
194
|
+
ceremonyName: this.ceremonyName,
|
|
195
|
+
ceremonyStartTime: new Date(this.ceremonyStartTime).toISOString(),
|
|
196
|
+
ceremonyEndTime: new Date(ceremonyEndTime).toISOString(),
|
|
197
|
+
ceremonyDurationMs,
|
|
198
|
+
verificationSessions: this.sessions,
|
|
199
|
+
summary: this.calculateSummary(ceremonyDurationMs),
|
|
200
|
+
byAgent: this.calculateByAgent(),
|
|
201
|
+
mostViolatedRules: this.calculateMostViolatedRules()
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
return summary;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Calculate overall summary statistics
|
|
209
|
+
*/
|
|
210
|
+
calculateSummary(ceremonyDurationMs) {
|
|
211
|
+
const totalRulesChecked = this.sessions.reduce((sum, s) =>
|
|
212
|
+
sum + s.ruleStats.totalRulesChecked, 0);
|
|
213
|
+
const totalRulesViolated = this.sessions.reduce((sum, s) =>
|
|
214
|
+
sum + s.ruleStats.rulesViolated, 0);
|
|
215
|
+
const totalApiCalls = this.sessions.reduce((sum, s) =>
|
|
216
|
+
sum + s.apiCalls.totalCalls, 0);
|
|
217
|
+
const totalVerificationTimeMs = this.sessions.reduce((sum, s) =>
|
|
218
|
+
sum + s.durationMs, 0);
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
totalVerificationSessions: this.sessions.length,
|
|
222
|
+
totalRulesChecked,
|
|
223
|
+
totalRulesViolated,
|
|
224
|
+
totalRulesFixed: totalRulesViolated,
|
|
225
|
+
totalApiCalls,
|
|
226
|
+
totalVerificationTimeMs,
|
|
227
|
+
verificationTimePercentage:
|
|
228
|
+
ceremonyDurationMs > 0 ? (totalVerificationTimeMs / ceremonyDurationMs) * 100 : 0
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Calculate statistics by agent
|
|
234
|
+
*/
|
|
235
|
+
calculateByAgent() {
|
|
236
|
+
const byAgent = {};
|
|
237
|
+
this.sessions.forEach(session => {
|
|
238
|
+
byAgent[session.agentName] = {
|
|
239
|
+
rulesChecked: session.ruleStats.totalRulesChecked,
|
|
240
|
+
rulesViolated: session.ruleStats.rulesViolated,
|
|
241
|
+
apiCalls: session.apiCalls.totalCalls,
|
|
242
|
+
durationMs: session.durationMs
|
|
243
|
+
};
|
|
244
|
+
});
|
|
245
|
+
return byAgent;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Calculate most violated rules across all sessions
|
|
250
|
+
*/
|
|
251
|
+
calculateMostViolatedRules() {
|
|
252
|
+
const ruleViolations = {};
|
|
253
|
+
this.sessions.forEach(session => {
|
|
254
|
+
session.violations.forEach(v => {
|
|
255
|
+
if (!ruleViolations[v.ruleId]) {
|
|
256
|
+
ruleViolations[v.ruleId] = { count: 0, agents: [] };
|
|
257
|
+
}
|
|
258
|
+
ruleViolations[v.ruleId].count++;
|
|
259
|
+
ruleViolations[v.ruleId].agents.push(session.agentName);
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
return Object.entries(ruleViolations)
|
|
264
|
+
.map(([ruleId, data]) => ({ ruleId, ...data }))
|
|
265
|
+
.sort((a, b) => b.count - a.count);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Generate simple hash for content deduplication
|
|
270
|
+
*/
|
|
271
|
+
hashContent(content) {
|
|
272
|
+
let hash = 0;
|
|
273
|
+
for (let i = 0; i < content.length; i++) {
|
|
274
|
+
const char = content.charCodeAt(i);
|
|
275
|
+
hash = ((hash << 5) - hash) + char;
|
|
276
|
+
hash = hash & hash;
|
|
277
|
+
}
|
|
278
|
+
return hash.toString(16);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Load rule profiles from disk
|
|
283
|
+
* @returns {object} Rule profiles by agent:rule key
|
|
284
|
+
*/
|
|
285
|
+
loadRuleProfiles() {
|
|
286
|
+
try {
|
|
287
|
+
const profilePath = path.join(process.cwd(), '.avc', 'verification-profiles.json');
|
|
288
|
+
if (fs.existsSync(profilePath)) {
|
|
289
|
+
return JSON.parse(fs.readFileSync(profilePath, 'utf8'));
|
|
290
|
+
}
|
|
291
|
+
} catch (error) {
|
|
292
|
+
console.warn('Could not load rule profiles:', error.message);
|
|
293
|
+
}
|
|
294
|
+
return {};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Save rule profiles to disk
|
|
299
|
+
* @param {object} profiles - Rule profiles to save
|
|
300
|
+
*/
|
|
301
|
+
saveRuleProfiles(profiles) {
|
|
302
|
+
try {
|
|
303
|
+
const profilePath = path.join(process.cwd(), '.avc', 'verification-profiles.json');
|
|
304
|
+
fs.writeFileSync(profilePath, JSON.stringify(profiles, null, 2));
|
|
305
|
+
} catch (error) {
|
|
306
|
+
console.warn('Could not save rule profiles:', error.message);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Check if rule should be skipped based on historical pass rate
|
|
312
|
+
* @param {string} agentName - Agent name
|
|
313
|
+
* @param {string} ruleId - Rule ID
|
|
314
|
+
* @returns {boolean} - True if rule should be skipped
|
|
315
|
+
*/
|
|
316
|
+
shouldSkipRule(agentName, ruleId) {
|
|
317
|
+
const key = `${agentName}:${ruleId}`;
|
|
318
|
+
const profile = this.ruleProfiles[key];
|
|
319
|
+
|
|
320
|
+
if (!profile) {
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Skip if: passed >20 times, never violated, pass rate 100%
|
|
325
|
+
const shouldSkip = profile.passed > 20 && profile.violated === 0 && profile.passRate === 1.0;
|
|
326
|
+
|
|
327
|
+
if (shouldSkip) {
|
|
328
|
+
console.log(`[DEBUG] Skipping rule ${ruleId} for ${agentName} (100% pass rate over ${profile.passed} checks)`);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
return shouldSkip;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Update rule profile after check
|
|
336
|
+
* @param {string} agentName - Agent name
|
|
337
|
+
* @param {string} ruleId - Rule ID
|
|
338
|
+
* @param {boolean} violated - Whether rule was violated
|
|
339
|
+
*/
|
|
340
|
+
updateRuleProfile(agentName, ruleId, violated) {
|
|
341
|
+
const key = `${agentName}:${ruleId}`;
|
|
342
|
+
|
|
343
|
+
if (!this.ruleProfiles[key]) {
|
|
344
|
+
this.ruleProfiles[key] = { passed: 0, violated: 0, passRate: 0 };
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (violated) {
|
|
348
|
+
this.ruleProfiles[key].violated++;
|
|
349
|
+
} else {
|
|
350
|
+
this.ruleProfiles[key].passed++;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const total = this.ruleProfiles[key].passed + this.ruleProfiles[key].violated;
|
|
354
|
+
this.ruleProfiles[key].passRate = total > 0 ? this.ruleProfiles[key].passed / total : 0;
|
|
355
|
+
|
|
356
|
+
console.log(`[DEBUG] Updated profile for ${key}: ${this.ruleProfiles[key].passed} passed, ${this.ruleProfiles[key].violated} violated (${(this.ruleProfiles[key].passRate * 100).toFixed(1)}% pass rate)`);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Save tracking data to files
|
|
361
|
+
*/
|
|
362
|
+
saveToFile() {
|
|
363
|
+
const summary = this.getCeremonySummary();
|
|
364
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
365
|
+
|
|
366
|
+
// Include ceremony name in filename: {ceremony}-verification-{timestamp}.json
|
|
367
|
+
const jsonPath = path.join(process.cwd(), '.avc', 'logs',
|
|
368
|
+
`${this.ceremonyName}-verification-${timestamp}.json`);
|
|
369
|
+
const summaryPath = path.join(process.cwd(), '.avc', 'logs',
|
|
370
|
+
`${this.ceremonyName}-verification-summary-${timestamp}.txt`);
|
|
371
|
+
|
|
372
|
+
try {
|
|
373
|
+
// Save JSON
|
|
374
|
+
fs.writeFileSync(jsonPath, JSON.stringify(summary, null, 2));
|
|
375
|
+
|
|
376
|
+
// Save human-readable summary
|
|
377
|
+
const summaryText = this.formatSummaryText(summary);
|
|
378
|
+
fs.writeFileSync(summaryPath, summaryText);
|
|
379
|
+
|
|
380
|
+
// Save rule profiles
|
|
381
|
+
this.saveRuleProfiles(this.ruleProfiles);
|
|
382
|
+
|
|
383
|
+
// Clear cache after saving
|
|
384
|
+
if (this.verificationCache) {
|
|
385
|
+
console.log('[DEBUG] Verification cache cleared');
|
|
386
|
+
this.verificationCache.clear();
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return { jsonPath, summaryPath };
|
|
390
|
+
} catch (error) {
|
|
391
|
+
console.error('Error saving verification tracking:', error.message);
|
|
392
|
+
return { jsonPath: null, summaryPath: null };
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Format summary as human-readable text
|
|
398
|
+
*/
|
|
399
|
+
formatSummaryText(summary) {
|
|
400
|
+
const text = [];
|
|
401
|
+
text.push('='.repeat(80));
|
|
402
|
+
text.push(`VERIFICATION SUMMARY: ${summary.ceremonyName}`);
|
|
403
|
+
text.push(`Time: ${summary.ceremonyStartTime}`);
|
|
404
|
+
text.push('='.repeat(80));
|
|
405
|
+
text.push('');
|
|
406
|
+
|
|
407
|
+
text.push('OVERALL STATISTICS');
|
|
408
|
+
text.push('-'.repeat(80));
|
|
409
|
+
text.push(`Total verification sessions: ${summary.summary.totalVerificationSessions}`);
|
|
410
|
+
text.push(`Total rules checked: ${summary.summary.totalRulesChecked}`);
|
|
411
|
+
text.push(`Total rules violated: ${summary.summary.totalRulesViolated}`);
|
|
412
|
+
text.push(`Total API calls: ${summary.summary.totalApiCalls}`);
|
|
413
|
+
text.push(`Total verification time: ${(summary.summary.totalVerificationTimeMs / 1000).toFixed(2)}s`);
|
|
414
|
+
text.push(`Verification overhead: ${summary.summary.verificationTimePercentage.toFixed(1)}%`);
|
|
415
|
+
text.push('');
|
|
416
|
+
|
|
417
|
+
text.push('BY AGENT');
|
|
418
|
+
text.push('-'.repeat(80));
|
|
419
|
+
Object.entries(summary.byAgent).forEach(([agent, stats]) => {
|
|
420
|
+
text.push(`${agent}:`);
|
|
421
|
+
text.push(` Rules checked: ${stats.rulesChecked}`);
|
|
422
|
+
text.push(` Rules violated: ${stats.rulesViolated}`);
|
|
423
|
+
text.push(` API calls: ${stats.apiCalls}`);
|
|
424
|
+
text.push(` Duration: ${(stats.durationMs / 1000).toFixed(2)}s`);
|
|
425
|
+
text.push('');
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
if (summary.mostViolatedRules.length > 0) {
|
|
429
|
+
text.push('MOST VIOLATED RULES');
|
|
430
|
+
text.push('-'.repeat(80));
|
|
431
|
+
summary.mostViolatedRules.forEach(rule => {
|
|
432
|
+
text.push(`${rule.ruleId}: ${rule.count} violations`);
|
|
433
|
+
text.push(` Agents: ${rule.agents.join(', ')}`);
|
|
434
|
+
});
|
|
435
|
+
text.push('');
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
text.push('='.repeat(80));
|
|
439
|
+
return text.join('\n');
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Log session summary to console
|
|
444
|
+
*/
|
|
445
|
+
logSessionSummary() {
|
|
446
|
+
const session = this.sessions[this.sessions.length - 1];
|
|
447
|
+
if (!session) return;
|
|
448
|
+
|
|
449
|
+
console.log('');
|
|
450
|
+
console.log('='.repeat(60));
|
|
451
|
+
console.log(`VERIFICATION SESSION: ${session.agentName}`);
|
|
452
|
+
console.log('='.repeat(60));
|
|
453
|
+
console.log(`Rules checked: ${session.ruleStats.totalRulesChecked}`);
|
|
454
|
+
console.log(`Rules violated: ${session.ruleStats.rulesViolated} (${((session.ruleStats.rulesViolated / session.ruleStats.totalRulesChecked) * 100).toFixed(1)}%)`);
|
|
455
|
+
console.log(`Rules fixed: ${session.ruleStats.rulesFixed}`);
|
|
456
|
+
console.log(`API calls: ${session.apiCalls.totalCalls} (${session.apiCalls.checkCalls} checks + ${session.apiCalls.fixCalls} fixes)`);
|
|
457
|
+
console.log(`Duration: ${(session.durationMs / 1000).toFixed(2)}s`);
|
|
458
|
+
console.log(`Content changed: ${session.output.contentChangedBy} chars`);
|
|
459
|
+
|
|
460
|
+
if (session.violations.length > 0) {
|
|
461
|
+
console.log('');
|
|
462
|
+
console.log('Violations fixed:');
|
|
463
|
+
session.violations.forEach(v => {
|
|
464
|
+
console.log(` - ${v.ruleId} (${v.severity})`);
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
console.log('='.repeat(60));
|
|
468
|
+
console.log('');
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Log ceremony summary to console
|
|
473
|
+
*/
|
|
474
|
+
logCeremonySummary() {
|
|
475
|
+
const summary = this.getCeremonySummary();
|
|
476
|
+
|
|
477
|
+
console.log('');
|
|
478
|
+
console.log('Verification Summary');
|
|
479
|
+
console.log('');
|
|
480
|
+
console.log(`Total verification sessions: ${summary.summary.totalVerificationSessions}`);
|
|
481
|
+
console.log(`Total rules checked: ${summary.summary.totalRulesChecked}`);
|
|
482
|
+
console.log(`Total rules violated: ${summary.summary.totalRulesViolated} (${((summary.summary.totalRulesViolated / summary.summary.totalRulesChecked) * 100).toFixed(1)}%)`);
|
|
483
|
+
console.log(`Total API calls: ${summary.summary.totalApiCalls}`);
|
|
484
|
+
console.log(`Total verification time: ${(summary.summary.totalVerificationTimeMs / 1000).toFixed(2)}s (${summary.summary.verificationTimePercentage.toFixed(1)}% of ceremony)`);
|
|
485
|
+
console.log('');
|
|
486
|
+
|
|
487
|
+
if (Object.keys(summary.byAgent).length > 0) {
|
|
488
|
+
console.log('By Agent:');
|
|
489
|
+
Object.entries(summary.byAgent).forEach(([agent, stats]) => {
|
|
490
|
+
console.log(` ${agent}: ${stats.rulesViolated} violations, ${stats.apiCalls} calls, ${(stats.durationMs / 1000).toFixed(2)}s`);
|
|
491
|
+
});
|
|
492
|
+
console.log('');
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
if (summary.mostViolatedRules.length > 0) {
|
|
496
|
+
console.log('Most Violated Rules:');
|
|
497
|
+
summary.mostViolatedRules.forEach((rule, index) => {
|
|
498
|
+
console.log(` ${index + 1}. ${rule.ruleId}: ${rule.count} violations (${rule.agents.join(', ')})`);
|
|
499
|
+
});
|
|
500
|
+
console.log('');
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Clean up old verification log files (keep last N logs per ceremony)
|
|
506
|
+
*/
|
|
507
|
+
static cleanupOldLogs(ceremonyName, projectRoot = process.cwd(), keepCount = 10) {
|
|
508
|
+
const logsDir = path.join(projectRoot, '.avc', 'logs');
|
|
509
|
+
|
|
510
|
+
if (!fs.existsSync(logsDir)) return;
|
|
511
|
+
|
|
512
|
+
try {
|
|
513
|
+
const files = fs.readdirSync(logsDir);
|
|
514
|
+
|
|
515
|
+
// Find all verification files for this ceremony
|
|
516
|
+
const jsonFiles = [];
|
|
517
|
+
const summaryFiles = [];
|
|
518
|
+
|
|
519
|
+
files.forEach(file => {
|
|
520
|
+
if (file.startsWith(`${ceremonyName}-verification-`) && file.endsWith('.json')) {
|
|
521
|
+
jsonFiles.push({
|
|
522
|
+
name: file,
|
|
523
|
+
path: path.join(logsDir, file),
|
|
524
|
+
mtime: fs.statSync(path.join(logsDir, file)).mtime
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
if (file.startsWith(`${ceremonyName}-verification-summary-`) && file.endsWith('.txt')) {
|
|
528
|
+
summaryFiles.push({
|
|
529
|
+
name: file,
|
|
530
|
+
path: path.join(logsDir, file),
|
|
531
|
+
mtime: fs.statSync(path.join(logsDir, file)).mtime
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
// Sort by modification time (newest first)
|
|
537
|
+
jsonFiles.sort((a, b) => b.mtime - a.mtime);
|
|
538
|
+
summaryFiles.sort((a, b) => b.mtime - a.mtime);
|
|
539
|
+
|
|
540
|
+
// Delete old JSON files
|
|
541
|
+
jsonFiles.slice(keepCount).forEach(file => {
|
|
542
|
+
try {
|
|
543
|
+
fs.unlinkSync(file.path);
|
|
544
|
+
} catch (error) {
|
|
545
|
+
// Ignore deletion errors
|
|
546
|
+
}
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
// Delete old summary files
|
|
550
|
+
summaryFiles.slice(keepCount).forEach(file => {
|
|
551
|
+
try {
|
|
552
|
+
fs.unlinkSync(file.path);
|
|
553
|
+
} catch (error) {
|
|
554
|
+
// Ignore deletion errors
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
} catch (error) {
|
|
558
|
+
// Silently fail
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
export { VerificationTracker };
|