0xray 3.1.1 → 3.2.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/.opencode/codex.codex +1 -1
- package/.opencode/commands/auto-format.md +3 -3
- package/.opencode/commands/auto-summary-capture.md +2 -2
- package/.opencode/commands/enforcer-daily-scan.md +3 -3
- package/.opencode/commands/framework-compliance-audit.md +4 -4
- package/.opencode/commands/interactive-validator.md +2 -2
- package/.opencode/commands/job-summary-logger.md +2 -2
- package/.opencode/commands/mode-switch.md +1 -1
- package/.opencode/commands/model-health-check.md +2 -2
- package/.opencode/commands/performance-analysis.md +2 -2
- package/.opencode/commands/pre-commit-introspection.md +3 -3
- package/.opencode/commands/security-scan.md +3 -3
- package/.opencode/commands/sisyphus-validation.md +3 -3
- package/.opencode/commands/summary-logger.md +2 -2
- package/AGENTS.md +3 -13
- package/README.md +3 -3
- package/dist/AGENTS.md +3 -13
- package/dist/CHANGELOG.md +29 -0
- package/dist/README.md +3 -3
- package/dist/analytics/consent-manager.js +0 -1
- package/dist/analytics/emerging-pattern-detector.js +0 -1
- package/dist/analytics/pattern-learning-engine.js +0 -1
- package/dist/analytics/pattern-performance-tracker.js +0 -1
- package/dist/analytics/predictive-analytics.js +0 -1
- package/dist/analytics/prompt-pattern-analyzer.js +0 -1
- package/dist/analytics/routing-performance-analyzer.js +0 -1
- package/dist/analytics/routing-refiner.js +0 -1
- package/dist/analytics/simple-pattern-analyzer.js +0 -1
- package/dist/cli/commands/archive-logs.js +0 -1
- package/dist/cli/commands/opencode-install.js +13 -0
- package/dist/cli/commands/plugin-commands.js +0 -1
- package/dist/cli/commands/status.js +11 -13
- package/dist/cli/index.js +2 -7
- package/dist/core/activity-logger.js +0 -1
- package/dist/core/adaptive-kernel.js +0 -1
- package/dist/core/boot-orchestrator.js +2 -12
- package/dist/core/bridge.mjs +0 -1
- package/dist/core/codex-formatter.js +0 -1
- package/dist/core/codex-injector.js +0 -1
- package/dist/core/config-loader.js +36 -28
- package/dist/core/context-loader.js +0 -1
- package/dist/core/context-validator.js +0 -1
- package/dist/core/features-config.js +37 -1
- package/dist/core/kernel-patterns.js +0 -1
- package/dist/core/model-router.js +23 -64
- package/dist/core/system-prompt-generator.js +0 -1
- package/dist/delegation/agent-delegator.js +0 -1
- package/dist/delegation/agent-expertise.js +0 -1
- package/dist/delegation/analytics/index.js +0 -1
- package/dist/delegation/analytics/learning-engine.js +0 -1
- package/dist/delegation/analytics/outcome-tracker.js +0 -1
- package/dist/delegation/analytics/routing-analytics.js +0 -1
- package/dist/delegation/ast-code-parser.js +0 -1
- package/dist/delegation/complexity-analyzer.js +0 -1
- package/dist/delegation/dependency-graph-builder.js +0 -1
- package/dist/delegation/index.js +0 -1
- package/dist/delegation/metrics-aggregator.js +0 -1
- package/dist/delegation/session-coordinator.js +0 -1
- package/dist/delegation/strategy-selector.js +0 -1
- package/dist/delegation/voting-coordinator.js +0 -1
- package/dist/delegation/voting-types.js +0 -1
- package/dist/delegation/weighted-voting-aggregator.js +0 -1
- package/dist/enforcement/core/index.js +0 -1
- package/dist/enforcement/core/rule-executor.js +0 -1
- package/dist/enforcement/core/rule-hierarchy.js +0 -1
- package/dist/enforcement/core/rule-registry.js +0 -1
- package/dist/enforcement/core/violation-fixer.js +0 -1
- package/dist/enforcement/index.js +0 -1
- package/dist/enforcement/loaders/agent-triage-loader.js +0 -1
- package/dist/enforcement/loaders/agents-md-validation-loader.js +0 -1
- package/dist/enforcement/loaders/base-loader.js +0 -1
- package/dist/enforcement/loaders/codex-loader.js +0 -1
- package/dist/enforcement/loaders/index.js +0 -1
- package/dist/enforcement/loaders/loader-orchestrator.js +0 -1
- package/dist/enforcement/loaders/processor-loader.js +0 -1
- package/dist/enforcement/types.js +0 -1
- package/dist/enforcement/validators/architecture-validators.js +0 -1
- package/dist/enforcement/validators/base-validator.js +0 -1
- package/dist/enforcement/validators/code-quality-validators.js +0 -1
- package/dist/enforcement/validators/index.js +0 -1
- package/dist/enforcement/validators/security-validators.js +0 -1
- package/dist/enforcement/validators/testing-validators.js +0 -1
- package/dist/enforcement/validators/validator-registry.js +0 -1
- package/dist/governance/codex-policy.service.js +0 -1
- package/dist/inference/inference-agent-invoker.js +67 -0
- package/dist/inference/inference-applier.js +178 -0
- package/dist/inference/inference-cycle.js +51 -827
- package/dist/inference/inference-proposal-generator.js +149 -0
- package/dist/infrastructure/iac-validator.js +465 -0
- package/dist/infrastructure/schemas/cloud-schemas.js +488 -0
- package/dist/integrations/base/ExampleIntegration.js +0 -1
- package/dist/integrations/base/Integration.js +0 -1
- package/dist/integrations/base/index.js +0 -1
- package/dist/integrations/base/registry.js +0 -1
- package/dist/integrations/base/types.js +0 -1
- package/dist/integrations/enforcement-gate.js +3 -3
- package/dist/integrations/governance/governance-client.js +0 -1
- package/dist/integrations/governance/index.js +11 -19
- package/dist/integrations/governance/types.js +0 -1
- package/dist/integrations/hermes-agent/__init__.py +4 -0
- package/dist/integrations/hermes-agent/bridge.mjs +37 -0
- package/dist/integrations/openclaw/api-server.js +0 -1
- package/dist/integrations/openclaw/client.js +0 -1
- package/dist/integrations/openclaw/config.js +0 -1
- package/dist/integrations/openclaw/hooks/xray-hooks.js +0 -1
- package/dist/integrations/openclaw/index.js +0 -1
- package/dist/integrations/openclaw/types.js +0 -1
- package/dist/integrations/plugins/index.js +0 -1
- package/dist/integrations/plugins/plugin-integration.js +0 -1
- package/dist/integrations/plugins/plugin-registry.js +0 -1
- package/dist/mcps/agent-resolver.js +0 -1
- package/dist/mcps/architect-tools.server.js +119 -185
- package/dist/mcps/auto-format.server.js +56 -74
- package/dist/mcps/boot-orchestrator.server.js +67 -85
- package/dist/mcps/config/config-loader.js +6 -0
- package/dist/mcps/config/plugin-server-registry.js +0 -1
- package/dist/mcps/enforcer-tools.server.js +207 -273
- package/dist/mcps/estimation.server.js +63 -107
- package/dist/mcps/framework-compliance-audit.server.js +52 -81
- package/dist/mcps/framework-help.server.js +71 -89
- package/dist/mcps/governance.server.js +97 -149
- package/dist/mcps/knowledge-skills/api-design.server.js +33 -65
- package/dist/mcps/knowledge-skills/architecture-patterns.server.js +33 -65
- package/dist/mcps/knowledge-skills/bug-triage-specialist.server.js +123 -163
- package/dist/mcps/knowledge-skills/code-analyzer.server.js +210 -237
- package/dist/mcps/knowledge-skills/code-review.server.js +108 -142
- package/dist/mcps/knowledge-skills/content-creator.server.js +203 -225
- package/dist/mcps/knowledge-skills/database-design.server.js +116 -150
- package/dist/mcps/knowledge-skills/devops-deployment.server.js +123 -157
- package/dist/mcps/knowledge-skills/git-workflow.server.js +34 -67
- package/dist/mcps/knowledge-skills/growth-strategist.server.js +301 -323
- package/dist/mcps/knowledge-skills/log-monitor.server.js +139 -159
- package/dist/mcps/knowledge-skills/mobile-development.server.js +170 -200
- package/dist/mcps/knowledge-skills/multimodal-looker.server.js +122 -158
- package/dist/mcps/knowledge-skills/performance-optimization.server.js +88 -138
- package/dist/mcps/knowledge-skills/project-analysis.server.js +131 -218
- package/dist/mcps/knowledge-skills/refactoring-strategies.server.js +115 -150
- package/dist/mcps/knowledge-skills/security-audit.server.js +16 -143
- package/dist/mcps/knowledge-skills/seo-consultant.server.js +20 -213
- package/dist/mcps/knowledge-skills/session-management.server.js +13 -90
- package/dist/mcps/knowledge-skills/skill-invocation.server.js +43 -421
- package/dist/mcps/knowledge-skills/strategist.server.js +10 -55
- package/dist/mcps/knowledge-skills/tech-writer.server.js +16 -191
- package/dist/mcps/knowledge-skills/testing-best-practices.server.js +18 -191
- package/dist/mcps/knowledge-skills/testing-strategy.server.js +18 -156
- package/dist/mcps/knowledge-skills/ui-ux-design.server.js +22 -296
- package/dist/mcps/lint.server.js +50 -91
- package/dist/mcps/model-health-check.server.js +32 -60
- package/dist/mcps/orchestrator/aside-context.js +207 -0
- package/dist/mcps/orchestrator/handlers/complexity-handler.js +5 -1
- package/dist/mcps/orchestrator/handlers/status-handler.js +8 -1
- package/dist/mcps/orchestrator/handlers/task-handler.js +5 -0
- package/dist/mcps/orchestrator/index.js +5 -0
- package/dist/mcps/orchestrator/server.js +63 -8
- package/dist/mcps/performance-analysis.server.js +56 -87
- package/dist/mcps/processor-pipeline.server.js +68 -99
- package/dist/mcps/researcher.server.js +80 -153
- package/dist/mcps/security-scan.server.js +56 -70
- package/dist/mcps/shared/knowledge-skill-base.js +11 -4
- package/dist/mcps/state-manager.server.js +124 -152
- package/dist/monitoring/nudge-watchdog.js +0 -1
- package/dist/nucleus/default-plugins.js +13 -19
- package/dist/nucleus/index.js +0 -1
- package/dist/orchestrator/agent-spawn-governor.js +0 -1
- package/dist/orchestrator/intelligent-commit-batcher.js +2 -10
- package/dist/orchestrator/multi-agent-orchestration-coordinator.js +0 -1
- package/dist/orchestrator/orchestrator.js +8 -18
- package/dist/orchestrator/self-direction-activation.js +0 -1
- package/dist/orchestrator/universal-registry-bridge.js +0 -1
- package/dist/performance/performance-budget-enforcer.js +0 -1
- package/dist/performance/performance-regression-tester.js +0 -1
- package/dist/plugin/plugin-codex-context.js +87 -0
- package/dist/plugin/plugin-helpers.js +155 -0
- package/dist/plugin/plugin-logger.js +46 -0
- package/dist/plugin/plugin-modules.js +144 -0
- package/dist/plugin/plugin-quality-gate.js +88 -0
- package/dist/plugin/plugin-types.js +1 -0
- package/dist/plugin/xray-codex-injection.js +338 -0
- package/dist/postprocessor/PostProcessor.js +3 -9
- package/dist/postprocessor/analysis/CodeChangeAnalyzer.js +50 -0
- package/dist/postprocessor/config/ProcessorConfigLoader.js +16 -0
- package/dist/postprocessor/integration.js +194 -0
- package/dist/postprocessor/metamorphosis/SelfProposalEngine.js +472 -0
- package/dist/postprocessor/metamorphosis/index.js +1 -0
- package/dist/postprocessor/redeploy/RetryHandler.js +118 -0
- package/dist/postprocessor/services/RegressionAnalysisService.js +0 -1
- package/dist/postprocessor/triggers/APITrigger.js +0 -1
- package/dist/postprocessor/triggers/WebhookTrigger.js +0 -1
- package/dist/processors/implementations/agents-md-validation-processor.js +0 -1
- package/dist/processors/implementations/async-pattern-processor.js +0 -1
- package/dist/processors/implementations/console-log-guard-processor.js +0 -1
- package/dist/processors/implementations/coverage-analysis-processor.js +0 -1
- package/dist/processors/implementations/inference-improvement-processor.js +2 -9
- package/dist/processors/implementations/log-protection-processor.js +0 -1
- package/dist/processors/implementations/nudge-processor.js +0 -1
- package/dist/processors/implementations/performance-budget-processor.js +0 -1
- package/dist/processors/implementations/postprocessor-chain-validator.js +0 -1
- package/dist/processors/implementations/publish-preflight-processor.js +4 -12
- package/dist/processors/implementations/session-summary-processor.js +8 -16
- package/dist/processors/implementations/spawn-governance-processor.js +0 -1
- package/dist/processors/implementations/storytelling-trigger-processor.js +3 -28
- package/dist/processors/implementations/test-auto-creation-processor.js +0 -1
- package/dist/processors/implementations/typescript-compilation-processor.js +0 -1
- package/dist/processors/implementations/version-compliance-processor.js +0 -1
- package/dist/processors/processor-interfaces.js +0 -1
- package/dist/processors/processor-types.js +0 -1
- package/dist/scripts/integration.js +0 -1
- package/dist/security/comprehensive-security-audit.js +0 -1
- package/dist/security/security-agent-coordinator.js +0 -1
- package/dist/security/security-auditor.js +0 -1
- package/dist/security/security-hardener.js +0 -1
- package/dist/security/security-hardening-system.js +0 -1
- package/dist/security/security-headers.js +0 -1
- package/dist/security/security-orchestration-layer.js +0 -1
- package/dist/services/inference-tuner.js +0 -1
- package/dist/session/session-cleanup-manager.js +0 -1
- package/dist/session/session-monitor.js +0 -1
- package/dist/session/session-state-manager.js +0 -1
- package/dist/skills/xray-orchestrator/index.js +0 -1
- package/dist/utils/codex-parser.js +0 -1
- package/dist/utils/language-detector.js +0 -1
- package/dist/utils/shutdown-handler.js +0 -1
- package/dist/validation/agent-config-validator.js +280 -0
- package/dist/validation/orchestration-flow-validator.js +606 -0
- package/package.json +1 -1
- package/scripts/node/release.mjs +2 -2
- package/scripts/node/setup.cjs +28 -0
- package/scripts/node/universal-version-manager.js +1 -1
- package/src/mcps/agent-resolver.ts +0 -1
- package/src/mcps/architect-tools.server.ts +129 -211
- package/src/mcps/auto-format.server.ts +74 -103
- package/src/mcps/boot-orchestrator.server.ts +71 -96
- package/src/mcps/config/__tests__/config-loader.test.ts +6 -6
- package/src/mcps/config/config-loader.ts +7 -0
- package/src/mcps/config/plugin-server-registry.ts +0 -1
- package/src/mcps/enforcer-tools.server.ts +217 -294
- package/src/mcps/estimation.server.ts +62 -122
- package/src/mcps/framework-compliance-audit.server.ts +53 -95
- package/src/mcps/framework-help.server.ts +74 -96
- package/src/mcps/governance.server.ts +97 -162
- package/src/mcps/knowledge-skills/api-design.server.ts +33 -72
- package/src/mcps/knowledge-skills/architecture-patterns.server.ts +33 -72
- package/src/mcps/knowledge-skills/bug-triage-specialist.server.ts +148 -193
- package/src/mcps/knowledge-skills/code-analyzer.server.ts +222 -254
- package/src/mcps/knowledge-skills/code-review.server.ts +115 -157
- package/src/mcps/knowledge-skills/content-creator.server.ts +219 -246
- package/src/mcps/knowledge-skills/database-design.server.ts +119 -160
- package/src/mcps/knowledge-skills/devops-deployment.server.ts +126 -167
- package/src/mcps/knowledge-skills/git-workflow.server.ts +32 -77
- package/src/mcps/knowledge-skills/growth-strategist.server.ts +322 -360
- package/src/mcps/knowledge-skills/log-monitor.server.ts +68 -95
- package/src/mcps/knowledge-skills/mobile-development.server.ts +16 -56
- package/src/mcps/knowledge-skills/multimodal-looker.server.ts +13 -59
- package/src/mcps/knowledge-skills/performance-optimization.server.ts +13 -74
- package/src/mcps/knowledge-skills/project-analysis.server.ts +13 -120
- package/src/mcps/knowledge-skills/refactoring-strategies.server.ts +13 -60
- package/src/mcps/knowledge-skills/security-audit.server.ts +19 -157
- package/src/mcps/knowledge-skills/seo-consultant.server.ts +23 -227
- package/src/mcps/knowledge-skills/session-management.server.ts +17 -106
- package/src/mcps/knowledge-skills/skill-invocation.server.ts +45 -446
- package/src/mcps/knowledge-skills/strategist.server.ts +13 -63
- package/src/mcps/knowledge-skills/tech-writer.server.ts +19 -204
- package/src/mcps/knowledge-skills/testing-best-practices.server.ts +21 -204
- package/src/mcps/knowledge-skills/testing-strategy.server.ts +21 -165
- package/src/mcps/knowledge-skills/ui-ux-design.server.ts +25 -342
- package/src/mcps/lint.server.ts +52 -105
- package/src/mcps/model-health-check.server.ts +34 -70
- package/src/mcps/orchestrator/aside-context.ts +245 -0
- package/src/mcps/orchestrator/handlers/complexity-handler.ts +9 -3
- package/src/mcps/orchestrator/handlers/status-handler.ts +11 -1
- package/src/mcps/orchestrator/handlers/task-handler.ts +8 -1
- package/src/mcps/orchestrator/index.ts +29 -0
- package/src/mcps/orchestrator/server.ts +79 -24
- package/src/mcps/orchestrator/types.ts +37 -0
- package/src/mcps/performance-analysis.server.ts +59 -102
- package/src/mcps/processor-pipeline.server.ts +70 -108
- package/src/mcps/researcher.server.ts +87 -175
- package/src/mcps/security-scan.server.ts +57 -76
- package/src/mcps/shared/knowledge-skill-base.ts +12 -4
- package/src/mcps/state-manager.server.ts +129 -169
- package/src/opencode/codex.codex +1 -1
- package/src/opencode/commands/auto-format.md +3 -3
- package/src/opencode/commands/auto-summary-capture.md +2 -2
- package/src/opencode/commands/enforcer-daily-scan.md +3 -3
- package/src/opencode/commands/framework-compliance-audit.md +4 -4
- package/src/opencode/commands/interactive-validator.md +2 -2
- package/src/opencode/commands/job-summary-logger.md +2 -2
- package/src/opencode/commands/mode-switch.md +1 -1
- package/src/opencode/commands/model-health-check.md +2 -2
- package/src/opencode/commands/performance-analysis.md +2 -2
- package/src/opencode/commands/pre-commit-introspection.md +3 -3
- package/src/opencode/commands/security-scan.md +3 -3
- package/src/opencode/commands/sisyphus-validation.md +3 -3
- package/src/opencode/commands/summary-logger.md +2 -2
- package/src/skills/xray-orchestrator/index.ts +0 -1
- package/dist/nucleus/orchestrator.js +0 -479
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SelfProposalEngine — Phase 2.2
|
|
3
|
+
*
|
|
4
|
+
* Concrete MetamorphosisEngine that reads activity.log, parses structured
|
|
5
|
+
* log entries, detects semantic patterns, generates governance proposals
|
|
6
|
+
* (type: 'metamorphosis'), and submits them through the full 3-agent +
|
|
7
|
+
* Dynamo governance pipeline.
|
|
8
|
+
*
|
|
9
|
+
* Safety constraints:
|
|
10
|
+
* - Max proposals per hour (default 1, configurable)
|
|
11
|
+
* - Circuit breaker: after N consecutive failures, halt for cooldown (default 3/24h)
|
|
12
|
+
* - Only proposes changes to whitelisted targets
|
|
13
|
+
* - All proposals go through full governance with metamorphosisThreshold (default 0.7)
|
|
14
|
+
* - Detection thresholds are configurable (not hard-coded)
|
|
15
|
+
*
|
|
16
|
+
* Coupling note: currently triggered by PostProcessor.onPhase(). A future
|
|
17
|
+
* refactor should extract log-reading into a dedicated LogReader that can
|
|
18
|
+
* run on its own schedule or fs.watch, decoupling from PostProcessor lifecycle.
|
|
19
|
+
*/
|
|
20
|
+
import { promises as fs, existsSync } from 'fs';
|
|
21
|
+
import { join } from 'path';
|
|
22
|
+
import { frameworkLogger } from '../../core/framework-logger.js';
|
|
23
|
+
import { handleGovernRequest } from '../../nucleus/govern-http.js';
|
|
24
|
+
const DEFAULT_CONFIG = {
|
|
25
|
+
maxProposalsPerHour: 1,
|
|
26
|
+
circuitBreakerThreshold: 3,
|
|
27
|
+
circuitBreakerCooldownHours: 24,
|
|
28
|
+
activityLogPath: 'logs/framework/activity.log',
|
|
29
|
+
whitelistedTargets: ['config/', 'features.json', 'src/processors/'],
|
|
30
|
+
maxLogLines: 100,
|
|
31
|
+
errorThreshold: 5,
|
|
32
|
+
warningThreshold: 10,
|
|
33
|
+
governanceRejectionThreshold: 3,
|
|
34
|
+
proposalConfidence: 0.7,
|
|
35
|
+
metamorphosisThreshold: 0.7,
|
|
36
|
+
projectRoot: process.cwd(),
|
|
37
|
+
};
|
|
38
|
+
const LOG_LINE_PATTERN = /^(\d{4}-\d{2}-\d{2}T[^ ]+)\s+(?:\[([^\]]*)\]\s+)?(?:\[([^\]]*)\]\s+)?\[([^\]]*)\]\s+(\S+)\s+-\s+(\w+)(?:\s+\|(.+))?$/;
|
|
39
|
+
function parseLogEntry(line) {
|
|
40
|
+
const match = line.match(LOG_LINE_PATTERN);
|
|
41
|
+
if (!match) {
|
|
42
|
+
// Fallback: try JSON parse for entangled log entries
|
|
43
|
+
try {
|
|
44
|
+
const json = JSON.parse(line);
|
|
45
|
+
if (json && typeof json === 'object' && json.action) {
|
|
46
|
+
return {
|
|
47
|
+
timestamp: json.timestamp ? new Date(json.timestamp).toISOString() : new Date().toISOString(),
|
|
48
|
+
component: json.component || 'unknown',
|
|
49
|
+
action: json.action,
|
|
50
|
+
status: (json.status || json.level || 'info').toLowerCase(),
|
|
51
|
+
details: json.details || json,
|
|
52
|
+
raw: line,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch { }
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
const [, timestamp, , , component, action, status, detailsStr] = match;
|
|
60
|
+
let details;
|
|
61
|
+
if (detailsStr) {
|
|
62
|
+
try {
|
|
63
|
+
details = JSON.parse(detailsStr.trim());
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
details = { rawDetails: detailsStr.trim() };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const entry = {
|
|
70
|
+
timestamp: timestamp ?? new Date().toISOString(),
|
|
71
|
+
component: component || 'unknown',
|
|
72
|
+
action: action ?? 'unknown',
|
|
73
|
+
status: (status ?? 'info').toLowerCase(),
|
|
74
|
+
raw: line,
|
|
75
|
+
};
|
|
76
|
+
if (details !== undefined) {
|
|
77
|
+
entry.details = details;
|
|
78
|
+
}
|
|
79
|
+
return entry;
|
|
80
|
+
}
|
|
81
|
+
export class SelfProposalEngine {
|
|
82
|
+
name = 'self-proposal';
|
|
83
|
+
config;
|
|
84
|
+
proposalHistory = [];
|
|
85
|
+
consecutiveFailures = 0;
|
|
86
|
+
circuitBreakerUntil = 0;
|
|
87
|
+
constructor(config) {
|
|
88
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
89
|
+
}
|
|
90
|
+
async onPhase(phase, context) {
|
|
91
|
+
if (phase !== 'monitoring-complete' && phase !== 'post-process-complete') {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
await frameworkLogger.log('self-proposal', 'phase-hook', 'info', {
|
|
95
|
+
phase,
|
|
96
|
+
message: 'Self-proposal engine triggered by phase',
|
|
97
|
+
});
|
|
98
|
+
if (this.isCircuitBreakerActive()) {
|
|
99
|
+
await frameworkLogger.log('self-proposal', 'circuit-breaker-active', 'warning', {
|
|
100
|
+
message: `Circuit breaker active until ${new Date(this.circuitBreakerUntil).toISOString()}`,
|
|
101
|
+
consecutiveFailures: this.consecutiveFailures,
|
|
102
|
+
});
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (this.isRateLimited()) {
|
|
106
|
+
await frameworkLogger.log('self-proposal', 'rate-limited', 'info', {
|
|
107
|
+
message: 'Max proposals per hour reached',
|
|
108
|
+
});
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
await this.evaluateAndPropose();
|
|
112
|
+
}
|
|
113
|
+
async onProposal(proposal) {
|
|
114
|
+
await frameworkLogger.log('self-proposal', 'external-proposal', 'info', {
|
|
115
|
+
proposalId: proposal.id,
|
|
116
|
+
type: proposal.type,
|
|
117
|
+
target: proposal.target,
|
|
118
|
+
impact: proposal.impact,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
isCircuitBreakerActive() {
|
|
122
|
+
if (this.consecutiveFailures >= this.config.circuitBreakerThreshold) {
|
|
123
|
+
if (Date.now() < this.circuitBreakerUntil) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
this.consecutiveFailures = 0;
|
|
127
|
+
this.circuitBreakerUntil = 0;
|
|
128
|
+
}
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
isRateLimited() {
|
|
132
|
+
const oneHourAgo = Date.now() - 60 * 60 * 1000;
|
|
133
|
+
const recentProposals = this.proposalHistory.filter(a => a.timestamp > oneHourAgo);
|
|
134
|
+
return recentProposals.length >= this.config.maxProposalsPerHour;
|
|
135
|
+
}
|
|
136
|
+
getMetrics() {
|
|
137
|
+
const oneHourAgo = Date.now() - 60 * 60 * 1000;
|
|
138
|
+
const recentProposals = this.proposalHistory.filter(a => a.timestamp > oneHourAgo);
|
|
139
|
+
return {
|
|
140
|
+
totalProposals: this.proposalHistory.length,
|
|
141
|
+
recentProposals: recentProposals.length,
|
|
142
|
+
consecutiveFailures: this.consecutiveFailures,
|
|
143
|
+
circuitBreakerActive: this.isCircuitBreakerActive(),
|
|
144
|
+
circuitBreakerUntil: this.circuitBreakerUntil,
|
|
145
|
+
successRate: this.proposalHistory.length > 0
|
|
146
|
+
? this.proposalHistory.filter(a => a.result === 'approved').length / this.proposalHistory.length
|
|
147
|
+
: 0,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
async evaluateAndPropose() {
|
|
151
|
+
let logEntries = [];
|
|
152
|
+
try {
|
|
153
|
+
const logContent = await fs.readFile(this.config.activityLogPath, 'utf-8');
|
|
154
|
+
const lines = logContent.trim().split('\n');
|
|
155
|
+
logEntries = lines.slice(-this.config.maxLogLines).filter(line => line.trim().length > 0);
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
await frameworkLogger.log('self-proposal', 'log-read-error', 'warning', {
|
|
159
|
+
path: this.config.activityLogPath,
|
|
160
|
+
message: 'Activity log not found or unreadable — skipping self-proposal',
|
|
161
|
+
});
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const patterns = this.detectPatterns(logEntries);
|
|
165
|
+
if (patterns.length === 0) {
|
|
166
|
+
await frameworkLogger.log('self-proposal', 'no-patterns', 'info', {
|
|
167
|
+
message: 'No actionable patterns detected in activity log',
|
|
168
|
+
});
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
for (const pattern of patterns) {
|
|
172
|
+
await this.submitProposal(pattern);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Detect actionable patterns from parsed activity log entries.
|
|
177
|
+
* Uses structured parsing instead of raw string matching to handle
|
|
178
|
+
* the actual xray log format:
|
|
179
|
+
* ISO_TIMESTAMP [jobId] [traceId.spanId] [component] action - STATUS | {details}
|
|
180
|
+
*/
|
|
181
|
+
detectPatterns(entries) {
|
|
182
|
+
const parsed = entries.map(parseLogEntry).filter((e) => e !== null);
|
|
183
|
+
const proposals = [];
|
|
184
|
+
const errorEntries = parsed.filter(e => e.status === 'error');
|
|
185
|
+
const warningEntries = parsed.filter(e => e.status === 'warning');
|
|
186
|
+
const rejectedEntries = parsed.filter(e => e.component === 'governance' && (e.status === 'rejected' || e.details?.decision === 'reject'));
|
|
187
|
+
if (errorEntries.length >= this.config.errorThreshold) {
|
|
188
|
+
const components = [...new Set(errorEntries.map(e => e.component))];
|
|
189
|
+
proposals.push({
|
|
190
|
+
id: `meta-errors-${Date.now()}`,
|
|
191
|
+
type: 'modify',
|
|
192
|
+
target: 'config/error-handling',
|
|
193
|
+
description: `Elevated error rate: ${errorEntries.length} errors in last ${this.config.maxLogLines} entries. Components: ${components.join(', ')}. Propose adjusting error handling thresholds.`,
|
|
194
|
+
rationale: `High error count (${errorEntries.length}) across ${components.length} component(s) indicates a systemic issue. Affected components: ${components.join(', ')}. Governance review recommended for self-optimization.`,
|
|
195
|
+
impact: 'medium',
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
if (warningEntries.length >= this.config.warningThreshold) {
|
|
199
|
+
const components = [...new Set(warningEntries.map(e => e.component))];
|
|
200
|
+
proposals.push({
|
|
201
|
+
id: `meta-warnings-${Date.now()}`,
|
|
202
|
+
type: 'modify',
|
|
203
|
+
target: 'config/monitoring',
|
|
204
|
+
description: `Elevated warning rate: ${warningEntries.length} warnings in last ${this.config.maxLogLines} entries. Components: ${components.join(', ')}. Propose adjusting monitoring sensitivity.`,
|
|
205
|
+
rationale: `Frequent warnings (${warningEntries.length}) across ${components.length} component(s) may indicate configuration drift. Affected: ${components.join(', ')}.`,
|
|
206
|
+
impact: 'low',
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
if (rejectedEntries.length >= this.config.governanceRejectionThreshold) {
|
|
210
|
+
proposals.push({
|
|
211
|
+
id: `meta-governance-rejections-${Date.now()}`,
|
|
212
|
+
type: 'modify',
|
|
213
|
+
target: 'config/governance',
|
|
214
|
+
description: `Repeated governance rejections: ${rejectedEntries.length} in last ${this.config.maxLogLines} entries. Propose reviewing governance thresholds or submission patterns.`,
|
|
215
|
+
rationale: `${rejectedEntries.length} governance rejections suggest a pattern mismatch between proposals and governance criteria. Review recommended.`,
|
|
216
|
+
impact: 'medium',
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
return proposals.filter(p => this.config.whitelistedTargets.some(t => p.target.startsWith(t)));
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Apply an approved self-evolution proposal by recording the change
|
|
223
|
+
* in a state file within the first matching whitelisted target directory.
|
|
224
|
+
* Returns true if the change was written and verified, false otherwise.
|
|
225
|
+
*/
|
|
226
|
+
async applySelfProposal(pattern, score, decision) {
|
|
227
|
+
const matchedTarget = this.config.whitelistedTargets.find(t => pattern.target.startsWith(t));
|
|
228
|
+
if (!matchedTarget) {
|
|
229
|
+
await frameworkLogger.log('self-proposal', 'apply-no-matching-target', 'warning', {
|
|
230
|
+
proposalId: pattern.id,
|
|
231
|
+
target: pattern.target,
|
|
232
|
+
message: 'No whitelisted target matches this proposal — skipping apply',
|
|
233
|
+
});
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
const root = this.config.projectRoot;
|
|
237
|
+
const stateDir = join(root, matchedTarget);
|
|
238
|
+
const statePath = join(stateDir, 'self-evolution-state.json');
|
|
239
|
+
let applied = [];
|
|
240
|
+
try {
|
|
241
|
+
const content = await fs.readFile(statePath, 'utf-8');
|
|
242
|
+
const parsed = JSON.parse(content);
|
|
243
|
+
if (Array.isArray(parsed.applied))
|
|
244
|
+
applied = parsed.applied;
|
|
245
|
+
}
|
|
246
|
+
catch { }
|
|
247
|
+
applied.push({
|
|
248
|
+
proposalId: pattern.id,
|
|
249
|
+
target: pattern.target,
|
|
250
|
+
type: pattern.type,
|
|
251
|
+
description: pattern.description,
|
|
252
|
+
rationale: pattern.rationale,
|
|
253
|
+
impact: pattern.impact,
|
|
254
|
+
metamorphosisScore: score,
|
|
255
|
+
decision: decision,
|
|
256
|
+
appliedAt: new Date().toISOString(),
|
|
257
|
+
});
|
|
258
|
+
try {
|
|
259
|
+
await fs.mkdir(stateDir, { recursive: true });
|
|
260
|
+
// Backup existing state file before overwriting
|
|
261
|
+
const backupDir = join(root, '.xray', 'metamorphosis', 'backups');
|
|
262
|
+
let backupPath = null;
|
|
263
|
+
if (existsSync(statePath)) {
|
|
264
|
+
await fs.mkdir(backupDir, { recursive: true });
|
|
265
|
+
backupPath = join(backupDir, `self-evolution-state-${Date.now()}.json`);
|
|
266
|
+
await fs.copyFile(statePath, backupPath);
|
|
267
|
+
await frameworkLogger.log('self-proposal', 'backup-created', 'info', {
|
|
268
|
+
proposalId: pattern.id,
|
|
269
|
+
backupPath,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
try {
|
|
273
|
+
await fs.writeFile(statePath, JSON.stringify({ applied }, null, 2), 'utf-8');
|
|
274
|
+
}
|
|
275
|
+
catch (writeError) {
|
|
276
|
+
// Restore from backup on write failure
|
|
277
|
+
if (backupPath && existsSync(backupPath)) {
|
|
278
|
+
await fs.copyFile(backupPath, statePath);
|
|
279
|
+
await frameworkLogger.log('self-proposal', 'restored-from-backup', 'warning', {
|
|
280
|
+
proposalId: pattern.id,
|
|
281
|
+
backupPath,
|
|
282
|
+
error: writeError instanceof Error ? writeError.message : String(writeError),
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
await frameworkLogger.log('self-proposal', 'apply-write-error', 'error', {
|
|
286
|
+
proposalId: pattern.id,
|
|
287
|
+
path: statePath,
|
|
288
|
+
error: writeError instanceof Error ? writeError.message : String(writeError),
|
|
289
|
+
});
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
catch (writeError) {
|
|
294
|
+
await frameworkLogger.log('self-proposal', 'apply-mkdir-error', 'error', {
|
|
295
|
+
proposalId: pattern.id,
|
|
296
|
+
error: writeError instanceof Error ? writeError.message : String(writeError),
|
|
297
|
+
});
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
try {
|
|
301
|
+
const verify = await fs.readFile(statePath, 'utf-8');
|
|
302
|
+
const parsed = JSON.parse(verify);
|
|
303
|
+
const found = Array.isArray(parsed.applied) && parsed.applied.some((a) => a.proposalId === pattern.id);
|
|
304
|
+
if (!found) {
|
|
305
|
+
await frameworkLogger.log('self-proposal', 'apply-verify-failed', 'error', {
|
|
306
|
+
proposalId: pattern.id,
|
|
307
|
+
message: 'Applied change not found in state file after write — verification failed',
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
return found;
|
|
311
|
+
}
|
|
312
|
+
catch (verifyError) {
|
|
313
|
+
await frameworkLogger.log('self-proposal', 'apply-verify-error', 'error', {
|
|
314
|
+
proposalId: pattern.id,
|
|
315
|
+
error: verifyError instanceof Error ? verifyError.message : String(verifyError),
|
|
316
|
+
});
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
async submitProposal(pattern) {
|
|
321
|
+
const governanceRequest = {
|
|
322
|
+
proposals: [{
|
|
323
|
+
id: pattern.id,
|
|
324
|
+
type: 'metamorphosis',
|
|
325
|
+
title: `Self-proposal: ${pattern.description.slice(0, 80)}`,
|
|
326
|
+
description: pattern.description,
|
|
327
|
+
evidence: [pattern.rationale],
|
|
328
|
+
source: 'metamorphosis',
|
|
329
|
+
confidence: this.config.proposalConfidence,
|
|
330
|
+
tags: ['0xray'],
|
|
331
|
+
}],
|
|
332
|
+
context: {
|
|
333
|
+
project: 'xray-self',
|
|
334
|
+
phase: 'self-evolution',
|
|
335
|
+
source: 'self-proposal-engine',
|
|
336
|
+
tags: ['0xray'],
|
|
337
|
+
},
|
|
338
|
+
options: {
|
|
339
|
+
requireExternalDynamo: true,
|
|
340
|
+
metamorphosisThreshold: this.config.metamorphosisThreshold,
|
|
341
|
+
},
|
|
342
|
+
};
|
|
343
|
+
await frameworkLogger.log('self-proposal', 'submitting', 'info', {
|
|
344
|
+
proposalId: pattern.id,
|
|
345
|
+
target: pattern.target,
|
|
346
|
+
impact: pattern.impact,
|
|
347
|
+
});
|
|
348
|
+
try {
|
|
349
|
+
const response = await handleGovernRequest(governanceRequest);
|
|
350
|
+
const result = response.results[0];
|
|
351
|
+
if (!result) {
|
|
352
|
+
await frameworkLogger.log('self-proposal', 'no-result', 'warning', {
|
|
353
|
+
proposalId: pattern.id,
|
|
354
|
+
message: 'Governance returned no results',
|
|
355
|
+
});
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
const decision = result.finalDecision;
|
|
359
|
+
const attempt = {
|
|
360
|
+
timestamp: Date.now(),
|
|
361
|
+
result: decision === 'approve' ? 'approved' : decision === 'reject' ? 'rejected' : 'needs_revision',
|
|
362
|
+
};
|
|
363
|
+
if (result.metamorphosisScore !== undefined) {
|
|
364
|
+
attempt.metamorphosisScore = result.metamorphosisScore;
|
|
365
|
+
}
|
|
366
|
+
this.proposalHistory.push(attempt);
|
|
367
|
+
if (decision === 'approve' && (result.metamorphosisScore ?? 0) >= this.config.metamorphosisThreshold) {
|
|
368
|
+
this.consecutiveFailures = 0;
|
|
369
|
+
await frameworkLogger.log('self-proposal', 'approved', 'success', {
|
|
370
|
+
proposalId: pattern.id,
|
|
371
|
+
metamorphosisScore: result.metamorphosisScore,
|
|
372
|
+
finalDecision: decision,
|
|
373
|
+
averageConfidence: result.averageConfidence,
|
|
374
|
+
voteSummary: result.votes ? result.votes.map((v) => ({ server: v.server, decision: v.decision })) : undefined,
|
|
375
|
+
message: 'Self-evolution proposal approved by governance — applying change',
|
|
376
|
+
tags: ['0xray'],
|
|
377
|
+
});
|
|
378
|
+
const applied = await this.applySelfProposal(pattern, result.metamorphosisScore, decision);
|
|
379
|
+
if (applied) {
|
|
380
|
+
await frameworkLogger.log('self-proposal', 'applied', 'success', {
|
|
381
|
+
proposalId: pattern.id,
|
|
382
|
+
target: pattern.target,
|
|
383
|
+
metamorphosisScore: result.metamorphosisScore,
|
|
384
|
+
decision,
|
|
385
|
+
message: 'Self-evolution change applied and verified',
|
|
386
|
+
tags: ['0xray'],
|
|
387
|
+
});
|
|
388
|
+
await this.audit0xrayProposalTraceability(pattern.id, decision, result.metamorphosisScore);
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
this.consecutiveFailures++;
|
|
392
|
+
if (this.consecutiveFailures >= this.config.circuitBreakerThreshold) {
|
|
393
|
+
this.circuitBreakerUntil = Date.now() + this.config.circuitBreakerCooldownHours * 60 * 60 * 1000;
|
|
394
|
+
}
|
|
395
|
+
await frameworkLogger.log('self-proposal', 'apply-failed', 'error', {
|
|
396
|
+
proposalId: pattern.id,
|
|
397
|
+
target: pattern.target,
|
|
398
|
+
consecutiveFailures: this.consecutiveFailures,
|
|
399
|
+
message: 'Self-evolution change apply failed — circuit breaker may activate',
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
this.consecutiveFailures++;
|
|
405
|
+
if (this.consecutiveFailures >= this.config.circuitBreakerThreshold) {
|
|
406
|
+
this.circuitBreakerUntil = Date.now() + this.config.circuitBreakerCooldownHours * 60 * 60 * 1000;
|
|
407
|
+
}
|
|
408
|
+
await frameworkLogger.log('self-proposal', 'not-approved', 'warning', {
|
|
409
|
+
proposalId: pattern.id,
|
|
410
|
+
decision: decision,
|
|
411
|
+
metamorphosisScore: result.metamorphosisScore,
|
|
412
|
+
consecutiveFailures: this.consecutiveFailures,
|
|
413
|
+
circuitBreakerUntil: this.circuitBreakerUntil || 'not active',
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
catch (error) {
|
|
418
|
+
this.consecutiveFailures++;
|
|
419
|
+
await frameworkLogger.log('self-proposal', 'submission-error', 'error', {
|
|
420
|
+
proposalId: pattern.id,
|
|
421
|
+
error: error instanceof Error ? error.message : String(error),
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Post-apply audit for Term 72 (Self-Evolution Traceability).
|
|
427
|
+
* For 0xray-tagged proposals (framework self-evolution), asserts that
|
|
428
|
+
* frameworkLogger entries exist with full provenance:
|
|
429
|
+
* - source proposal ID
|
|
430
|
+
* - governance vote results / finalDecision / averageConfidence
|
|
431
|
+
* - metamorphosisScore
|
|
432
|
+
* Logs the audit outcome via frameworkLogger.
|
|
433
|
+
*/
|
|
434
|
+
async audit0xrayProposalTraceability(proposalId, decision, score) {
|
|
435
|
+
if (!proposalId) {
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
try {
|
|
439
|
+
const logContent = await fs.readFile(this.config.activityLogPath, 'utf-8');
|
|
440
|
+
const lines = logContent.trim().split('\n').filter(l => l.trim().length > 0);
|
|
441
|
+
const recentLines = lines.slice(-this.config.maxLogLines);
|
|
442
|
+
// Look for entries tied to this proposalId that carry the required provenance.
|
|
443
|
+
// We expect 'approved' (with vote info) and 'applied' (with score/decision) for 0xray self-proposals.
|
|
444
|
+
const relevant = recentLines.filter(line => line.includes(proposalId) &&
|
|
445
|
+
(line.includes('approved') || line.includes('applied') || line.includes('submitting')));
|
|
446
|
+
const hasProposalId = relevant.length > 0;
|
|
447
|
+
const hasGovernanceVote = relevant.some(l => l.includes('finalDecision') || l.includes('averageConfidence') || l.includes('voteSummary'));
|
|
448
|
+
const hasMetamorphosisScore = relevant.some(l => l.includes('metamorphosisScore'));
|
|
449
|
+
const has0xrayTag = relevant.some(l => l.includes('0xray') || l.includes('"tags"') && l.includes('0xray'));
|
|
450
|
+
const auditPassed = hasProposalId && hasGovernanceVote && hasMetamorphosisScore && has0xrayTag;
|
|
451
|
+
await frameworkLogger.log('self-proposal', 'post-apply-audit', auditPassed ? 'success' : 'warning', {
|
|
452
|
+
proposalId,
|
|
453
|
+
decision,
|
|
454
|
+
metamorphosisScore: score,
|
|
455
|
+
hasProposalId,
|
|
456
|
+
hasGovernanceVote,
|
|
457
|
+
hasMetamorphosisScore,
|
|
458
|
+
has0xrayTag,
|
|
459
|
+
relevantEntryCount: relevant.length,
|
|
460
|
+
message: auditPassed
|
|
461
|
+
? 'Term 72 traceability audit passed: frameworkLogger entries with full provenance (proposalId, governance votes, metamorphosisScore, 0xray tag) verified for self-evolution proposal.'
|
|
462
|
+
: 'Term 72 traceability audit warning: missing or incomplete frameworkLogger provenance for 0xray-tagged self-evolution proposal.',
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
catch (auditError) {
|
|
466
|
+
await frameworkLogger.log('self-proposal', 'post-apply-audit-error', 'error', {
|
|
467
|
+
proposalId,
|
|
468
|
+
error: auditError instanceof Error ? auditError.message : String(auditError),
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SelfProposalEngine } from './SelfProposalEngine.js';
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retry Handler for Redeploy Operations
|
|
3
|
+
*/
|
|
4
|
+
import { frameworkLogger } from "../../core/framework-logger.js";
|
|
5
|
+
export class RetryHandler {
|
|
6
|
+
config;
|
|
7
|
+
constructor(config = {
|
|
8
|
+
maxRetries: 3,
|
|
9
|
+
baseDelay: 30000,
|
|
10
|
+
backoffStrategy: "exponential",
|
|
11
|
+
}) {
|
|
12
|
+
this.config = config;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Execute an operation with retry logic
|
|
16
|
+
*/
|
|
17
|
+
async executeWithRetry(operation, shouldRetry) {
|
|
18
|
+
let lastError = {};
|
|
19
|
+
for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
|
|
20
|
+
try {
|
|
21
|
+
return await operation();
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
const retryable = error;
|
|
25
|
+
lastError = retryable;
|
|
26
|
+
// Don't retry on the last attempt
|
|
27
|
+
if (attempt === this.config.maxRetries) {
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
// Check if we should retry this error
|
|
31
|
+
if (shouldRetry && !shouldRetry(retryable, attempt)) {
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
// Calculate delay and wait
|
|
35
|
+
const delay = this.calculateDelay(attempt);
|
|
36
|
+
await frameworkLogger.log("-retry-handler", "-operation-failed-attempt-attempt-1-retrying-in-de", "error", {
|
|
37
|
+
message: `⏳ Operation failed (attempt ${attempt + 1}), retrying in ${delay}ms...`,
|
|
38
|
+
});
|
|
39
|
+
await this.wait(delay);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
throw lastError;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Calculate delay based on backoff strategy
|
|
46
|
+
*/
|
|
47
|
+
calculateDelay(attempt) {
|
|
48
|
+
const { baseDelay, backoffStrategy } = this.config;
|
|
49
|
+
switch (backoffStrategy) {
|
|
50
|
+
case "exponential":
|
|
51
|
+
return baseDelay * Math.pow(2, attempt);
|
|
52
|
+
case "linear":
|
|
53
|
+
return baseDelay * (attempt + 1);
|
|
54
|
+
default:
|
|
55
|
+
return baseDelay;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Wait for the specified duration
|
|
60
|
+
*/
|
|
61
|
+
async wait(duration) {
|
|
62
|
+
return new Promise((resolve) => setTimeout(resolve, duration));
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Default retry conditions for deployment operations
|
|
66
|
+
*/
|
|
67
|
+
static shouldRetryDeployment(error, attempt) {
|
|
68
|
+
// Don't retry certain types of errors
|
|
69
|
+
const nonRetryableErrors = [
|
|
70
|
+
"authentication_failed",
|
|
71
|
+
"authorization_failed",
|
|
72
|
+
"invalid_configuration",
|
|
73
|
+
"quota_exceeded",
|
|
74
|
+
];
|
|
75
|
+
if (nonRetryableErrors.some((type) => error.type?.includes(type))) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
// Don't retry after too many attempts for transient errors
|
|
79
|
+
if (attempt >= 2 && error.type === "transient") {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
// Retry network and timeout errors
|
|
83
|
+
if (error.code === "ECONNRESET" ||
|
|
84
|
+
error.code === "ETIMEDOUT" ||
|
|
85
|
+
error.code === "ENOTFOUND") {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
// Retry 5xx HTTP errors
|
|
89
|
+
if (error.statusCode >= 500 && error.statusCode < 600) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
// Default: retry for most errors
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Specialized retry handler for deployment operations
|
|
97
|
+
*/
|
|
98
|
+
async executeDeploymentWithRetry(deploymentOperation) {
|
|
99
|
+
return this.executeWithRetry(deploymentOperation, RetryHandler.shouldRetryDeployment);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Specialized retry handler for API calls
|
|
103
|
+
*/
|
|
104
|
+
async executeApiCallWithRetry(apiCall) {
|
|
105
|
+
return this.executeWithRetry(apiCall, (error, attempt) => {
|
|
106
|
+
// Retry on network errors and 5xx status codes
|
|
107
|
+
return (error.code === "ECONNRESET" ||
|
|
108
|
+
error.code === "ETIMEDOUT" ||
|
|
109
|
+
(error.statusCode >= 500 && error.statusCode < 600));
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get retry statistics
|
|
114
|
+
*/
|
|
115
|
+
getStats() {
|
|
116
|
+
return { ...this.config };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
* Detects anti-patterns in async code: callback patterns, long promise chains,
|
|
6
6
|
* missing await inside async functions, and mixed callback/promise styles.
|
|
7
7
|
*
|
|
8
|
-
* @version 1.0.0
|
|
9
8
|
* @since 2026-03-28
|
|
10
9
|
*/
|
|
11
10
|
import { frameworkLogger } from "../../core/framework-logger.js";
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
* Analyzes test coverage for modified files and reports coverage gaps.
|
|
5
5
|
*
|
|
6
6
|
* @module processors/implementations
|
|
7
|
-
* @version 1.0.0
|
|
8
7
|
*/
|
|
9
8
|
import { PostProcessor } from "../processor-interfaces.js";
|
|
10
9
|
import { frameworkLogger } from "../../core/framework-logger.js";
|
|
@@ -12,6 +12,7 @@ import * as path from "path";
|
|
|
12
12
|
import { PostProcessor } from "../processor-interfaces.js";
|
|
13
13
|
import { frameworkLogger } from "../../core/framework-logger.js";
|
|
14
14
|
import { getConfigDir } from "../../core/config-paths.js";
|
|
15
|
+
import { featuresConfigLoader } from "../../core/features-config.js";
|
|
15
16
|
export class InferenceImprovementProcessor extends PostProcessor {
|
|
16
17
|
name = "inferenceImprovement";
|
|
17
18
|
priority = 5;
|
|
@@ -37,15 +38,7 @@ export class InferenceImprovementProcessor extends PostProcessor {
|
|
|
37
38
|
}
|
|
38
39
|
loadInferenceConfig() {
|
|
39
40
|
try {
|
|
40
|
-
|
|
41
|
-
path.join(process.cwd(), ".xray", "features.json"),
|
|
42
|
-
];
|
|
43
|
-
for (const configPath of configPaths) {
|
|
44
|
-
if (fs.existsSync(configPath)) {
|
|
45
|
-
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
46
|
-
return config.inference || config;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
41
|
+
return featuresConfigLoader.loadConfig().inference ?? null;
|
|
49
42
|
}
|
|
50
43
|
catch (e) {
|
|
51
44
|
// ignore - use defaults
|