0xray 3.1.1 → 3.3.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 +55 -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 +40 -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/config/agent-capabilities.js +30 -11
- package/dist/mcps/orchestrator/config/memory-routing-bridge.js +70 -0
- package/dist/mcps/orchestrator/execution/execution-planner.js +25 -7
- 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 +59 -1
- 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/memory-routing/index.js +4 -0
- package/dist/memory-routing/null-provider.js +51 -0
- package/dist/memory-routing/provider-loader.js +91 -0
- package/dist/memory-routing/provider-registry.js +40 -0
- package/dist/memory-routing/types.js +7 -0
- package/dist/memory-routing/validate-config.js +32 -0
- 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/nucleus/thin-dispatch.js +29 -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/config/agent-capabilities.ts +49 -14
- package/src/mcps/orchestrator/config/memory-routing-bridge.ts +80 -0
- package/src/mcps/orchestrator/execution/execution-planner.ts +36 -9
- 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 +78 -2
- package/src/mcps/orchestrator/index.ts +29 -0
- package/src/mcps/orchestrator/server.ts +79 -24
- package/src/mcps/orchestrator/types.ts +50 -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
|
@@ -2,31 +2,18 @@ import * as fs from "fs";
|
|
|
2
2
|
import * as path from "path";
|
|
3
3
|
import { shouldTriggerCycle, accumulateCorpus } from "./inference-accumulator.js";
|
|
4
4
|
import { DeployVerifier } from "./deploy-verifier.js";
|
|
5
|
-
import { VotingCoordinator } from "../delegation/voting-coordinator.js";
|
|
6
|
-
import { XrayStateManager } from "../state/state-manager.js";
|
|
7
5
|
import { frameworkLogger } from "../core/framework-logger.js";
|
|
8
|
-
import { getGovernanceIntegration } from "../integrations/governance/index.js";
|
|
9
6
|
import { featuresConfigLoader } from "../core/features-config.js";
|
|
10
7
|
import { mcpClientManager } from "../mcps/mcp-client.js";
|
|
11
8
|
import { getConfigDir } from "../core/config-paths.js";
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
9
|
+
import { generateProposals } from "./inference-proposal-generator.js";
|
|
10
|
+
import { applyProposals as applyProposalsEx } from "./inference-applier.js";
|
|
14
11
|
const CYCLE_STATE_FILE = "inference-cycle-state.json";
|
|
15
12
|
const CYCLE_HISTORY_FILE = "inference-cycle-history.json";
|
|
16
|
-
const GOVERNANCE_AGENTS = {
|
|
17
|
-
// Real individual knowledge-skill MCP servers (have analyze_proposal handlers)
|
|
18
|
-
fix: ["code-review", "security-audit", "researcher"],
|
|
19
|
-
refactor: ["code-review", "security-audit", "researcher"],
|
|
20
|
-
guard: ["code-review", "security-audit", "researcher"],
|
|
21
|
-
automate: ["code-review", "security-audit", "researcher"],
|
|
22
|
-
codify: ["code-review", "security-audit", "researcher"],
|
|
23
|
-
};
|
|
24
13
|
export class InferenceCycle {
|
|
25
|
-
// Singleton registry + state management to prevent recursive agent spawning
|
|
26
14
|
static instances = new Map();
|
|
27
15
|
static reEntryLock = false;
|
|
28
16
|
static governedProposalIds = new Set();
|
|
29
|
-
static votingCoordinator = null;
|
|
30
17
|
static getInstance(projectRoot, options) {
|
|
31
18
|
const root = path.resolve(projectRoot || process.cwd());
|
|
32
19
|
if (!InferenceCycle.instances.has(root)) {
|
|
@@ -38,7 +25,6 @@ export class InferenceCycle {
|
|
|
38
25
|
InferenceCycle.instances.clear();
|
|
39
26
|
InferenceCycle.reEntryLock = false;
|
|
40
27
|
InferenceCycle.governedProposalIds.clear();
|
|
41
|
-
InferenceCycle.votingCoordinator = null;
|
|
42
28
|
}
|
|
43
29
|
inferenceDir;
|
|
44
30
|
stateDir;
|
|
@@ -55,7 +41,6 @@ export class InferenceCycle {
|
|
|
55
41
|
this.options = options ?? {};
|
|
56
42
|
}
|
|
57
43
|
async governExternalProposals(proposals) {
|
|
58
|
-
// GATE: prevent re-entry — same as maybeRunCycle
|
|
59
44
|
if (InferenceCycle.reEntryLock) {
|
|
60
45
|
const blockedId = `blocked-${Date.now()}`;
|
|
61
46
|
frameworkLogger.log("inference-cycle", "external-re-entry-blocked", "warning", {});
|
|
@@ -93,12 +78,10 @@ export class InferenceCycle {
|
|
|
93
78
|
p.status = "approved";
|
|
94
79
|
for (const p of proposals.filter((p) => p.status !== "approved"))
|
|
95
80
|
p.status = "rejected";
|
|
96
|
-
// Track governed proposals for dedup across cycles
|
|
97
81
|
for (const p of proposals)
|
|
98
82
|
InferenceCycle.governedProposalIds.add(p.id);
|
|
99
83
|
this.setPhase("complete");
|
|
100
84
|
this.saveCycleState(cycleId);
|
|
101
|
-
this.saveGovernanceState(this.getCoordinator());
|
|
102
85
|
const result = this.buildResult(cycleId, true, "external proposals", startTime, undefined, proposals, votes);
|
|
103
86
|
this.appendHistory(result);
|
|
104
87
|
frameworkLogger.log("inference-cycle", "external-governance-complete", "info", {
|
|
@@ -113,7 +96,6 @@ export class InferenceCycle {
|
|
|
113
96
|
}
|
|
114
97
|
}
|
|
115
98
|
async maybeRunCycle() {
|
|
116
|
-
// GATE: prevent recursive re-entry while a cycle is in progress
|
|
117
99
|
if (InferenceCycle.reEntryLock) {
|
|
118
100
|
const blockedId = `blocked-${Date.now()}`;
|
|
119
101
|
frameworkLogger.log("inference-cycle", "re-entry-blocked", "warning", {});
|
|
@@ -136,14 +118,30 @@ export class InferenceCycle {
|
|
|
136
118
|
});
|
|
137
119
|
const corpus = accumulateCorpus(this.inferenceDir);
|
|
138
120
|
this.setPhase("proposing");
|
|
139
|
-
const proposals = this.
|
|
140
|
-
this.adjustFromHistory(proposals);
|
|
121
|
+
const proposals = generateProposals(corpus, this.loadHistory());
|
|
141
122
|
if (proposals.length === 0) {
|
|
142
123
|
this.setPhase("complete");
|
|
143
124
|
return this.buildResult(cycleId, true, threshold.reason, startTime, corpus, proposals);
|
|
144
125
|
}
|
|
145
126
|
this.setPhase("governing");
|
|
146
|
-
|
|
127
|
+
let votes = [];
|
|
128
|
+
try {
|
|
129
|
+
votes = await this.governProposals(proposals);
|
|
130
|
+
}
|
|
131
|
+
catch (e) {
|
|
132
|
+
frameworkLogger.log("inference-cycle", "govern-proposals-error", "error", {
|
|
133
|
+
error: e.message,
|
|
134
|
+
stack: e.stack?.substring(0, 500),
|
|
135
|
+
});
|
|
136
|
+
for (const proposal of proposals) {
|
|
137
|
+
votes.push({
|
|
138
|
+
proposalId: proposal.id,
|
|
139
|
+
decision: "reject",
|
|
140
|
+
confidence: 0,
|
|
141
|
+
details: [`rejected: governance error: ${e.message}`],
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
147
145
|
// Track governed proposals for dedup across cycles
|
|
148
146
|
for (const p of proposals)
|
|
149
147
|
InferenceCycle.governedProposalIds.add(p.id);
|
|
@@ -157,7 +155,7 @@ export class InferenceCycle {
|
|
|
157
155
|
if (approved.length > 0) {
|
|
158
156
|
if (!this.options.skipApply) {
|
|
159
157
|
this.setPhase("applying");
|
|
160
|
-
await this.
|
|
158
|
+
await applyProposalsEx(approved, this.projectRoot, this.agentInvoker, this.options);
|
|
161
159
|
}
|
|
162
160
|
let deployResult;
|
|
163
161
|
if (!this.options.skipDeployVerify) {
|
|
@@ -188,7 +186,6 @@ export class InferenceCycle {
|
|
|
188
186
|
}
|
|
189
187
|
this.setPhase("complete");
|
|
190
188
|
this.saveCycleState(cycleId);
|
|
191
|
-
this.saveGovernanceState(this.getCoordinator());
|
|
192
189
|
this.appendHistory(this.buildResult(cycleId, true, threshold.reason, startTime, corpus, proposals, votes, deployResult));
|
|
193
190
|
return this.buildResult(cycleId, true, threshold.reason, startTime, corpus, proposals, votes, deployResult);
|
|
194
191
|
}
|
|
@@ -201,311 +198,38 @@ export class InferenceCycle {
|
|
|
201
198
|
InferenceCycle.reEntryLock = false;
|
|
202
199
|
}
|
|
203
200
|
}
|
|
204
|
-
generateProposals(corpus) {
|
|
205
|
-
const proposals = [];
|
|
206
|
-
for (const problem of corpus.recurringProblems) {
|
|
207
|
-
proposals.push({
|
|
208
|
-
id: `prop-${Date.now()}-${proposals.length}`,
|
|
209
|
-
type: this.classifyProposalType(problem.pattern),
|
|
210
|
-
title: this.generateTitle(problem),
|
|
211
|
-
description: `Recurring across ${problem.occurrences} sessions: ${problem.pattern}`,
|
|
212
|
-
evidence: problem.sessions.map((s) => `Seen in session ${s}`),
|
|
213
|
-
confidence: Math.min(0.95, 0.5 + problem.occurrences * 0.15),
|
|
214
|
-
source: "recurring_problem",
|
|
215
|
-
status: "pending",
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
const seenPatterns = new Set(corpus.recurringProblems.map((p) => p.pattern));
|
|
219
|
-
const allProblems = corpus.sessions.flatMap((s) => s.problems.map((p) => ({ problem: p, session: s.sessionId })));
|
|
220
|
-
for (const { problem, session } of allProblems) {
|
|
221
|
-
const normalized = problem.replace(/\([a-f0-9]{7}\)/g, "").trim();
|
|
222
|
-
if (seenPatterns.has(normalized))
|
|
223
|
-
continue;
|
|
224
|
-
if (proposals.length >= 5)
|
|
225
|
-
break;
|
|
226
|
-
proposals.push({
|
|
227
|
-
id: `prop-${Date.now()}-${proposals.length}`,
|
|
228
|
-
type: this.classifyProposalType(problem),
|
|
229
|
-
title: `Investigate: ${problem.substring(0, 80)}`,
|
|
230
|
-
description: `Observed in session ${session}: ${problem}`,
|
|
231
|
-
evidence: [problem],
|
|
232
|
-
confidence: 0.4,
|
|
233
|
-
source: "recurring_problem",
|
|
234
|
-
status: "pending",
|
|
235
|
-
});
|
|
236
|
-
seenPatterns.add(normalized);
|
|
237
|
-
}
|
|
238
|
-
for (const pattern of corpus.recurringPatterns) {
|
|
239
|
-
if (pattern.occurrences < 2)
|
|
240
|
-
continue;
|
|
241
|
-
const type = this.patternToProposalType(pattern);
|
|
242
|
-
proposals.push({
|
|
243
|
-
id: `prop-${Date.now()}-${proposals.length}`,
|
|
244
|
-
type,
|
|
245
|
-
title: `Codify ${pattern.name} pattern`,
|
|
246
|
-
description: `${pattern.name} detected across ${pattern.occurrences} sessions (avg confidence: ${Math.round(pattern.avgConfidence * 100)}%). ${pattern.description}`,
|
|
247
|
-
evidence: pattern.evidence,
|
|
248
|
-
confidence: pattern.avgConfidence,
|
|
249
|
-
source: "recurring_pattern",
|
|
250
|
-
status: "pending",
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
const wrongTurns = corpus.allWrongTurns.slice(0, 2);
|
|
254
|
-
for (const wt of wrongTurns) {
|
|
255
|
-
const summary = wt.length > 50 ? `${wt.substring(0, 47)}...` : wt;
|
|
256
|
-
proposals.push({
|
|
257
|
-
id: `prop-${Date.now()}-${proposals.length}`,
|
|
258
|
-
type: "guard",
|
|
259
|
-
title: `Guard against: ${summary}`,
|
|
260
|
-
description: `Recurring wrong turn detected: ${wt}. Add a guard or validation to prevent this pattern.`,
|
|
261
|
-
evidence: [wt],
|
|
262
|
-
confidence: 0.7,
|
|
263
|
-
source: "wrong_turn",
|
|
264
|
-
status: "pending",
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
return proposals.sort((a, b) => b.confidence - a.confidence).slice(0, 3);
|
|
268
|
-
}
|
|
269
|
-
adjustFromHistory(proposals) {
|
|
270
|
-
this.adjustConfidenceFromHistory(proposals);
|
|
271
|
-
proposals.sort((a, b) => b.confidence - a.confidence);
|
|
272
|
-
}
|
|
273
|
-
getCoordinator() {
|
|
274
|
-
if (!InferenceCycle.votingCoordinator) {
|
|
275
|
-
const stateManager = this.getGovernanceStateManager();
|
|
276
|
-
InferenceCycle.votingCoordinator = new VotingCoordinator(stateManager);
|
|
277
|
-
}
|
|
278
|
-
return InferenceCycle.votingCoordinator;
|
|
279
|
-
}
|
|
280
|
-
async applyProposals(proposals) {
|
|
281
|
-
const applier = new ProposalApplier(this.projectRoot, async (p) => this.applyProposalWork(p), async (p, prUrl) => {
|
|
282
|
-
if (this.options.skipResearcherReview)
|
|
283
|
-
return "go";
|
|
284
|
-
return this.researcherReview(p, prUrl);
|
|
285
|
-
});
|
|
286
|
-
const results = await applier.applyProposals(proposals);
|
|
287
|
-
for (const r of results) {
|
|
288
|
-
const p = proposals.find(pr => pr.id === r.proposalId);
|
|
289
|
-
if (p)
|
|
290
|
-
p.status = r.success ? "applied" : "failed";
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
async applyProposalWork(p) {
|
|
294
|
-
let filesChanged = false;
|
|
295
|
-
if (p.type === "fix" || p.type === "refactor") {
|
|
296
|
-
filesChanged = await this.applyCodeChange(p);
|
|
297
|
-
}
|
|
298
|
-
else if (p.type === "guard") {
|
|
299
|
-
filesChanged = await this.applyGuard(p);
|
|
300
|
-
}
|
|
301
|
-
else if (p.type === "automate") {
|
|
302
|
-
filesChanged = await this.applyAutomation(p);
|
|
303
|
-
}
|
|
304
|
-
return filesChanged;
|
|
305
|
-
}
|
|
306
|
-
async applyCodeChange(p) {
|
|
307
|
-
const targetFiles = this.extractTargetFiles(p.evidence);
|
|
308
|
-
const prompt = [
|
|
309
|
-
`Apply approved inference proposal`,
|
|
310
|
-
``,
|
|
311
|
-
`Type: ${p.type}`,
|
|
312
|
-
`Title: ${p.title}`,
|
|
313
|
-
`Description: ${p.description}`,
|
|
314
|
-
targetFiles.length > 0 ? `Target files: ${targetFiles.join(", ")}` : "No specific target files identified",
|
|
315
|
-
`Evidence: ${p.evidence.slice(0, 5).join("; ")}`,
|
|
316
|
-
`Confidence: ${(p.confidence * 100).toFixed(0)}%`,
|
|
317
|
-
``,
|
|
318
|
-
`1. Read the relevant source files`,
|
|
319
|
-
`2. Apply the ${p.type} described above`,
|
|
320
|
-
`3. Make minimal, surgical changes`,
|
|
321
|
-
`4. If the change is unsafe or unclear, skip and explain`,
|
|
322
|
-
].join("\n");
|
|
323
|
-
frameworkLogger.log("inference-cycle", "apply-invoking-agent", "info", {
|
|
324
|
-
proposalId: p.id,
|
|
325
|
-
proposalType: p.type,
|
|
326
|
-
targetFiles,
|
|
327
|
-
});
|
|
328
|
-
try {
|
|
329
|
-
let agentName = p.type === "refactor" ? "refactorer" : "code-reviewer";
|
|
330
|
-
// In pure MCP mode, use real skill server names so the orchestrator dispatches to actual MCP tools
|
|
331
|
-
if (process.env.XRAY_FORCE_MCP_GOVERNANCE === 'true') {
|
|
332
|
-
agentName = p.type === "refactor" ? "refactoring-strategies" : "code-review";
|
|
333
|
-
}
|
|
334
|
-
await this.invokeAgentInternal(agentName, prompt);
|
|
335
|
-
return true;
|
|
336
|
-
}
|
|
337
|
-
catch (err) {
|
|
338
|
-
frameworkLogger.log("inference-cycle", "apply-agent-failed", "warning", {
|
|
339
|
-
proposalId: p.id,
|
|
340
|
-
error: String(err),
|
|
341
|
-
});
|
|
342
|
-
return false;
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
async applyGuard(p) {
|
|
346
|
-
const prompt = [
|
|
347
|
-
`Add guard/validation for the following issue:`,
|
|
348
|
-
``,
|
|
349
|
-
`Title: ${p.title}`,
|
|
350
|
-
`Description: ${p.description}`,
|
|
351
|
-
`Evidence: ${p.evidence.join("; ")}`,
|
|
352
|
-
`Confidence: ${(p.confidence * 100).toFixed(0)}%`,
|
|
353
|
-
``,
|
|
354
|
-
`1. Read the relevant source files`,
|
|
355
|
-
`2. Add the missing guard, validation, or edge case handling`,
|
|
356
|
-
`3. If this is a codex rule, add the term to .xray/codex.json`,
|
|
357
|
-
`4. Make minimal, surgical changes`,
|
|
358
|
-
].join("\n");
|
|
359
|
-
try {
|
|
360
|
-
const agentName = process.env.XRAY_FORCE_MCP_GOVERNANCE === 'true'
|
|
361
|
-
? "code-review"
|
|
362
|
-
: "code-reviewer";
|
|
363
|
-
await this.invokeAgentInternal(agentName, prompt);
|
|
364
|
-
return true;
|
|
365
|
-
}
|
|
366
|
-
catch (err) {
|
|
367
|
-
frameworkLogger.log("inference-cycle", "apply-guard-failed", "warning", {
|
|
368
|
-
proposalId: p.id,
|
|
369
|
-
error: String(err),
|
|
370
|
-
});
|
|
371
|
-
const guardPath = path.join(this.projectRoot, "docs", "guards", `${p.title.replace(/[^a-z0-9]/gi, "-")}.md`);
|
|
372
|
-
fs.mkdirSync(path.dirname(guardPath), { recursive: true });
|
|
373
|
-
fs.writeFileSync(guardPath, `# Guard: ${p.title}\n\n${p.description}\n\n## Evidence\n${p.evidence.join("\n")}`);
|
|
374
|
-
return true;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
async applyAutomation(p) {
|
|
378
|
-
const prompt = [
|
|
379
|
-
`Design automation for the following manual process:`,
|
|
380
|
-
``,
|
|
381
|
-
`Title: ${p.title}`,
|
|
382
|
-
`Description: ${p.description}`,
|
|
383
|
-
`Evidence: ${p.evidence.join("; ")}`,
|
|
384
|
-
`Confidence: ${(p.confidence * 100).toFixed(0)}%`,
|
|
385
|
-
``,
|
|
386
|
-
`1. Read the relevant source files`,
|
|
387
|
-
`2. Design the automation (script, processor, or config change)`,
|
|
388
|
-
`3. Implement it if straightforward, otherwise describe the design`,
|
|
389
|
-
].join("\n");
|
|
390
|
-
try {
|
|
391
|
-
const agentName = process.env.XRAY_FORCE_MCP_GOVERNANCE === 'true'
|
|
392
|
-
? "architecture-patterns"
|
|
393
|
-
: "architect";
|
|
394
|
-
await this.invokeAgentInternal(agentName, prompt);
|
|
395
|
-
return true;
|
|
396
|
-
}
|
|
397
|
-
catch (err) {
|
|
398
|
-
frameworkLogger.log("inference-cycle", "apply-automation-failed", "warning", {
|
|
399
|
-
proposalId: p.id,
|
|
400
|
-
error: String(err),
|
|
401
|
-
});
|
|
402
|
-
const automationPath = path.join(this.projectRoot, "docs", "automation-proposals.md");
|
|
403
|
-
const entry = `\n## ${p.title}\n\n${p.description}\n\n**Evidence:** ${p.evidence.join(", ")}\n`;
|
|
404
|
-
fs.mkdirSync(path.dirname(automationPath), { recursive: true });
|
|
405
|
-
fs.appendFileSync(automationPath, entry);
|
|
406
|
-
return true;
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
extractTargetFiles(evidence) {
|
|
410
|
-
const filePattern = /[a-zA-Z0-9/_-]+\.(ts|js|mjs|json|yml|yaml)/g;
|
|
411
|
-
const files = new Set();
|
|
412
|
-
for (const item of evidence) {
|
|
413
|
-
const matches = item.matchAll(filePattern);
|
|
414
|
-
for (const match of matches) {
|
|
415
|
-
const f = match[0];
|
|
416
|
-
if (f.startsWith("src/") || f.startsWith("dist/") || f.startsWith(".opencode/")) {
|
|
417
|
-
files.add(f);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
return [...files];
|
|
422
|
-
}
|
|
423
|
-
async researcherReview(p, prUrl) {
|
|
424
|
-
const prompt = `You are a researcher agent reviewing a PR for proposal: "${p.title}".
|
|
425
|
-
|
|
426
|
-
PR URL: ${prUrl}
|
|
427
|
-
|
|
428
|
-
Proposal Type: ${p.type}
|
|
429
|
-
Description: ${p.description}
|
|
430
|
-
Evidence: ${p.evidence.slice(0, 5).join("; ")}
|
|
431
|
-
|
|
432
|
-
Your job: Review the actual codebase to verify this proposal makes sense. Search the code to confirm:
|
|
433
|
-
1. Does the problem described actually exist in the codebase?
|
|
434
|
-
2. Is the proposed solution appropriate?
|
|
435
|
-
3. Are there any missed edge cases?
|
|
436
|
-
|
|
437
|
-
Respond with EXACTLY one of:
|
|
438
|
-
- GO (proposal is valid, approve)
|
|
439
|
-
- NO-GO (proposal is invalid, reject)
|
|
440
|
-
- MODIFY: <specific changes needed>`;
|
|
441
|
-
try {
|
|
442
|
-
const result = await this.invokeAgentInternal("researcher", prompt);
|
|
443
|
-
const output = result.toLowerCase();
|
|
444
|
-
if (output.includes("no-go"))
|
|
445
|
-
return "no-go";
|
|
446
|
-
if (output.includes("modify"))
|
|
447
|
-
return "modify";
|
|
448
|
-
return "go";
|
|
449
|
-
}
|
|
450
|
-
catch (err) {
|
|
451
|
-
frameworkLogger.log("inference-cycle", "researcher-review-failed", "warning", { error: String(err) });
|
|
452
|
-
return "go";
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
201
|
async governProposals(proposals) {
|
|
456
|
-
//
|
|
457
|
-
//
|
|
202
|
+
// Governance MCP is the sole governance path (governance.server.ts + GovernanceService).
|
|
203
|
+
// It calls individual skill MCPs (code-review, security-audit, researcher) internally
|
|
204
|
+
// and integrates with external Dynamo Solar SSOT.
|
|
458
205
|
const useGovernanceMcp = process.env.XRAY_FORCE_MCP_GOVERNANCE === 'true' ||
|
|
459
206
|
this.isGovernanceMcpPreferred();
|
|
460
|
-
if (useGovernanceMcp) {
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
catch (err) {
|
|
487
|
-
frameworkLogger.log("inference-cycle", "governance-mcp-failed", "error", {
|
|
488
|
-
error: err instanceof Error ? err.message : String(err),
|
|
489
|
-
});
|
|
490
|
-
// In forced pure MCP mode we must not silently fall back
|
|
491
|
-
if (process.env.XRAY_FORCE_MCP_GOVERNANCE === 'true') {
|
|
492
|
-
throw err;
|
|
493
|
-
}
|
|
494
|
-
// In normal mode, fall back to legacy path with deprecation warning.
|
|
495
|
-
// The legacy path will be removed once all consumers have migrated to the Governance MCP + Dynamo Solar SSOT model.
|
|
496
|
-
frameworkLogger.log("inference-cycle", "governance-legacy-fallback", "warning", {
|
|
497
|
-
message: "Falling back to legacy governance path. This path is deprecated and will be removed in a future version.",
|
|
498
|
-
});
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
// Legacy internal path (deprecated)
|
|
502
|
-
const internalVotes = await this.governProposalsInternal(proposals);
|
|
503
|
-
const governanceIntegration = getGovernanceIntegration();
|
|
504
|
-
if (governanceIntegration?.isAvailable()) {
|
|
505
|
-
const externalVotes = await this.governProposalsExternal(proposals);
|
|
506
|
-
return this.mergeGovernanceVotes(internalVotes, externalVotes, proposals);
|
|
507
|
-
}
|
|
508
|
-
return internalVotes;
|
|
207
|
+
if (!useGovernanceMcp) {
|
|
208
|
+
throw new Error("Governance MCP is required but not available");
|
|
209
|
+
}
|
|
210
|
+
const result = await Promise.race([
|
|
211
|
+
mcpClientManager.callServerTool("governance", "govern_proposals", {
|
|
212
|
+
proposals: proposals.map(p => ({
|
|
213
|
+
id: p.id,
|
|
214
|
+
type: p.type,
|
|
215
|
+
title: p.title,
|
|
216
|
+
description: p.description,
|
|
217
|
+
evidence: p.evidence || [],
|
|
218
|
+
source: p.source || "inference",
|
|
219
|
+
confidence: p.confidence || 0.8,
|
|
220
|
+
})),
|
|
221
|
+
context: { source: "inference-cycle" },
|
|
222
|
+
options: { require_external: true },
|
|
223
|
+
}),
|
|
224
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("Governance MCP timed out after 8s")), 8000)),
|
|
225
|
+
]);
|
|
226
|
+
const text = result?.content?.[0]?.text || "";
|
|
227
|
+
const parsed = this.parseGovernanceMcpResponse(text, proposals);
|
|
228
|
+
frameworkLogger.log("inference-cycle", "governance-mcp-primary-path", "info", {
|
|
229
|
+
proposalCount: proposals.length,
|
|
230
|
+
overall: parsed.overallDecision,
|
|
231
|
+
});
|
|
232
|
+
return parsed.votes;
|
|
509
233
|
}
|
|
510
234
|
isGovernanceMcpPreferred() {
|
|
511
235
|
try {
|
|
@@ -547,415 +271,6 @@ Respond with EXACTLY one of:
|
|
|
547
271
|
return { votes, overallDecision: "needs_revision" };
|
|
548
272
|
}
|
|
549
273
|
}
|
|
550
|
-
/**
|
|
551
|
-
* Oscillator 1: Internal VotingCoordinator-based governance
|
|
552
|
-
*/
|
|
553
|
-
async governProposalsInternal(proposals) {
|
|
554
|
-
// Defensive: if pure MCP mode is forced, use individual skill servers only
|
|
555
|
-
if (process.env.XRAY_FORCE_MCP_GOVERNANCE === 'true') {
|
|
556
|
-
return this.governProposalsWithIndividualSkills(proposals);
|
|
557
|
-
}
|
|
558
|
-
const coordinator = this.getCoordinator();
|
|
559
|
-
const sessionId = `inference-governance-${Date.now()}`;
|
|
560
|
-
const results = [];
|
|
561
|
-
const todoPrompt = [
|
|
562
|
-
`Vote on ${proposals.length} inference proposals. Output EXACTLY one PROPOSAL block per proposal.`,
|
|
563
|
-
``,
|
|
564
|
-
`FORMAT (exact, no extra text, no markdown):`,
|
|
565
|
-
`PROPOSAL: <number>`,
|
|
566
|
-
` AGENT: architect`,
|
|
567
|
-
` DECISION: approve|reject|abstain`,
|
|
568
|
-
` CONFIDENCE: 0.XX`,
|
|
569
|
-
` REASONING: <brief reason>`,
|
|
570
|
-
``,
|
|
571
|
-
`Example:`,
|
|
572
|
-
`PROPOSAL: 1`,
|
|
573
|
-
` AGENT: architect`,
|
|
574
|
-
` DECISION: approve`,
|
|
575
|
-
` CONFIDENCE: 0.85`,
|
|
576
|
-
` REASONING: Cleanup reduces maintenance burden`,
|
|
577
|
-
``,
|
|
578
|
-
`PROPOSALS:`,
|
|
579
|
-
];
|
|
580
|
-
for (let i = 0; i < proposals.length; i++) {
|
|
581
|
-
const p = proposals[i];
|
|
582
|
-
todoPrompt.push(`${i + 1}. [${p.type}] "${p.title}"`);
|
|
583
|
-
}
|
|
584
|
-
try {
|
|
585
|
-
const jsonOutput = await this.invokeAgentInternal("architect", todoPrompt.join("\n"));
|
|
586
|
-
const allVotes = this.parseSubagentVotes(jsonOutput, proposals);
|
|
587
|
-
for (const proposal of proposals) {
|
|
588
|
-
const agents = GOVERNANCE_AGENTS[proposal.type] ?? ["code-reviewer"];
|
|
589
|
-
const participants = ["architect", ...agents];
|
|
590
|
-
const voteId = await coordinator.initiateVoting(sessionId, proposal.title, proposal.description, participants, {
|
|
591
|
-
complexity: Math.min(50, 10 + proposal.evidence.length * 5 + (proposal.confidence > 0.8 ? 10 : 0)),
|
|
592
|
-
riskLevel: proposal.type === "fix" ? "low" : proposal.type === "guard" ? "high" : "medium",
|
|
593
|
-
hasSecurityConcerns: proposal.type === "guard" || proposal.type === "fix",
|
|
594
|
-
hasArchitecturalImpact: proposal.type === "codify" || proposal.type === "automate",
|
|
595
|
-
participantCount: participants.length,
|
|
596
|
-
});
|
|
597
|
-
const proposalVotes = allVotes.filter((v) => v.proposalId === proposal.id);
|
|
598
|
-
for (const v of proposalVotes) {
|
|
599
|
-
coordinator.submitVote(voteId, v.agentName, v.decision, v.confidence, v.reasoning);
|
|
600
|
-
}
|
|
601
|
-
const resolved = coordinator.resolveVoting(voteId);
|
|
602
|
-
if (resolved) {
|
|
603
|
-
results.push({
|
|
604
|
-
proposalId: proposal.id,
|
|
605
|
-
decision: resolved.decision === "approve" ? "approve" : "reject",
|
|
606
|
-
confidence: resolved.confidence,
|
|
607
|
-
details: resolved.details?.map((d) => `${d.agentName}: vote=${d.vote}, weight=${d.weight.toFixed(2)}`) || [],
|
|
608
|
-
});
|
|
609
|
-
if (resolved.details) {
|
|
610
|
-
for (const detail of resolved.details) {
|
|
611
|
-
this.getCoordinator().getAggregator().updateAgentPerformance(detail.agentName, resolved.decision, detail.vote, detail.vote === resolved.decision, proposal.confidence);
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
else {
|
|
616
|
-
results.push(this.rejectNoQuorum(proposal, "agents did not vote (no quorum)"));
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
catch (error) {
|
|
621
|
-
frameworkLogger.log("inference-cycle", "architect-governance-failed", "error", { error: String(error) });
|
|
622
|
-
for (const proposal of proposals) {
|
|
623
|
-
results.push(this.rejectNoQuorum(proposal, `agent invocation failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
const metrics = coordinator.getMetrics();
|
|
627
|
-
frameworkLogger.log("inference-cycle", "governance-metrics", "info", {
|
|
628
|
-
totalVotes: metrics.totalVotes,
|
|
629
|
-
avgConfidence: metrics.averageConfidence.toFixed(2),
|
|
630
|
-
strategyUsage: metrics.strategyUsage,
|
|
631
|
-
});
|
|
632
|
-
return results;
|
|
633
|
-
}
|
|
634
|
-
/**
|
|
635
|
-
* Pure individual knowledge-skill MCP path for governance.
|
|
636
|
-
* Used when XRAY_FORCE_MCP_GOVERNANCE=true.
|
|
637
|
-
* Each proposal is evaluated directly by the relevant skill servers using analyze_proposal.
|
|
638
|
-
*/
|
|
639
|
-
async governProposalsWithIndividualSkills(proposals) {
|
|
640
|
-
const results = [];
|
|
641
|
-
const GOVERNANCE_AGENTS = {
|
|
642
|
-
fix: ["code-review", "security-audit", "researcher"],
|
|
643
|
-
refactor: ["code-review", "security-audit", "researcher"],
|
|
644
|
-
guard: ["code-review", "security-audit", "researcher"],
|
|
645
|
-
automate: ["code-review", "security-audit", "researcher"],
|
|
646
|
-
codify: ["code-review", "security-audit", "researcher"],
|
|
647
|
-
};
|
|
648
|
-
for (const proposal of proposals) {
|
|
649
|
-
const agents = GOVERNANCE_AGENTS[proposal.type] ?? ["code-review", "security-audit"];
|
|
650
|
-
const skillVotes = [];
|
|
651
|
-
for (const agent of agents) {
|
|
652
|
-
try {
|
|
653
|
-
const skillResult = await mcpClientManager.callServerTool(agent, "analyze_proposal", {
|
|
654
|
-
proposalTitle: proposal.title,
|
|
655
|
-
proposalDescription: proposal.description,
|
|
656
|
-
evidence: proposal.evidence,
|
|
657
|
-
proposalType: proposal.type,
|
|
658
|
-
});
|
|
659
|
-
let structured = "";
|
|
660
|
-
const contents = skillResult?.content || [];
|
|
661
|
-
for (const c of contents) {
|
|
662
|
-
if (c?.text && c.text.includes("DECISION:")) {
|
|
663
|
-
structured = c.text.trim();
|
|
664
|
-
break;
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
if (!structured) {
|
|
668
|
-
const full = JSON.stringify(skillResult);
|
|
669
|
-
const m = full.match(/DECISION:\s*(approve|reject|abstain)[\s\S]{0,300}?REASONING:[^\n"]*/i);
|
|
670
|
-
if (m)
|
|
671
|
-
structured = m[0].trim();
|
|
672
|
-
}
|
|
673
|
-
skillVotes.push({
|
|
674
|
-
agent,
|
|
675
|
-
toolUsed: "analyze_proposal",
|
|
676
|
-
rawResponse: structured || JSON.stringify(skillResult),
|
|
677
|
-
structuredVote: structured || null,
|
|
678
|
-
});
|
|
679
|
-
}
|
|
680
|
-
catch (err) {
|
|
681
|
-
skillVotes.push({
|
|
682
|
-
agent,
|
|
683
|
-
toolUsed: "analyze_proposal",
|
|
684
|
-
rawResponse: `error: ${err}`,
|
|
685
|
-
structuredVote: null,
|
|
686
|
-
});
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
const approves = skillVotes.filter((v) => v.structuredVote && v.structuredVote.includes("DECISION: approve")).length;
|
|
690
|
-
const rejects = skillVotes.filter((v) => v.structuredVote && v.structuredVote.includes("DECISION: reject")).length;
|
|
691
|
-
const decision = approves > rejects ? "approve" : (rejects > approves ? "reject" : "abstain");
|
|
692
|
-
let avgConf = 0.75;
|
|
693
|
-
const confMatches = skillVotes.map((v) => {
|
|
694
|
-
if (!v.structuredVote)
|
|
695
|
-
return 0.75;
|
|
696
|
-
const m = v.structuredVote.match(/CONFIDENCE:\s*([0-9.]+)/);
|
|
697
|
-
return m ? parseFloat(m[1]) : 0.75;
|
|
698
|
-
});
|
|
699
|
-
if (confMatches.length > 0)
|
|
700
|
-
avgConf = confMatches.reduce((a, b) => a + b, 0) / confMatches.length;
|
|
701
|
-
results.push({
|
|
702
|
-
proposalId: proposal.id,
|
|
703
|
-
decision: decision,
|
|
704
|
-
confidence: Math.round(avgConf * 100) / 100,
|
|
705
|
-
details: skillVotes.map((v) => `${v.agent}: ${v.structuredVote?.split('\n')[0] || 'no structured vote'}`),
|
|
706
|
-
});
|
|
707
|
-
}
|
|
708
|
-
return results;
|
|
709
|
-
}
|
|
710
|
-
/**
|
|
711
|
-
* Merge internal and external governance votes.
|
|
712
|
-
* A proposal passes both oscillators — must be approved by internal AND external.
|
|
713
|
-
*/
|
|
714
|
-
mergeGovernanceVotes(internalVotes, externalVotes, proposals) {
|
|
715
|
-
const merged = [];
|
|
716
|
-
for (const proposal of proposals) {
|
|
717
|
-
const internal = internalVotes.find((v) => v.proposalId === proposal.id);
|
|
718
|
-
const external = externalVotes.find((v) => v.proposalId === proposal.id);
|
|
719
|
-
if (!internal) {
|
|
720
|
-
merged.push(this.rejectNoQuorum(proposal, "internal governance vote missing"));
|
|
721
|
-
continue;
|
|
722
|
-
}
|
|
723
|
-
const internalApproved = internal.decision === "approve";
|
|
724
|
-
const externalApproved = external?.decision === "approve";
|
|
725
|
-
const bothApproved = internalApproved && (!external || externalApproved);
|
|
726
|
-
merged.push({
|
|
727
|
-
proposalId: proposal.id,
|
|
728
|
-
decision: bothApproved ? "approve" : "reject",
|
|
729
|
-
confidence: internal.confidence * (external ? external.confidence : 1.0),
|
|
730
|
-
details: [
|
|
731
|
-
...internal.details,
|
|
732
|
-
...(external ? [`External governance: ${external.decision} (conf: ${external.confidence.toFixed(2)})`, ...external.details] : []),
|
|
733
|
-
],
|
|
734
|
-
});
|
|
735
|
-
}
|
|
736
|
-
return merged;
|
|
737
|
-
}
|
|
738
|
-
// Removed: buildOrchestratorGovernancePrompt (replaced by inline TODO prompt in governProposals)
|
|
739
|
-
/**
|
|
740
|
-
* Govern proposals using external chrono-warp-drive Dynamo endpoint
|
|
741
|
-
*/
|
|
742
|
-
async governProposalsExternal(proposals) {
|
|
743
|
-
const governanceIntegration = getGovernanceIntegration();
|
|
744
|
-
if (!governanceIntegration) {
|
|
745
|
-
throw new Error("Governance integration not available");
|
|
746
|
-
}
|
|
747
|
-
// Build agent reviews from proposal evidence
|
|
748
|
-
const agentReviews = proposals.flatMap((p) => p.evidence.slice(0, 2).map((e) => `[${p.type}] ${e}`));
|
|
749
|
-
try {
|
|
750
|
-
const batchResult = await governanceIntegration.checkProposals(proposals, agentReviews, []);
|
|
751
|
-
const votes = batchResult.results.map((result) => ({
|
|
752
|
-
proposalId: result.governanceResponse.proposalId,
|
|
753
|
-
decision: result.vote.toLowerCase() === "yes" ? "approve" : "reject",
|
|
754
|
-
confidence: result.governanceResponse.confidence,
|
|
755
|
-
details: [
|
|
756
|
-
`Governance: ${result.governanceResponse.recommendation}`,
|
|
757
|
-
`Isotope: ${result.governanceResponse.governanceIsotopeId}`,
|
|
758
|
-
...result.governanceResponse.reasons.slice(0, 2),
|
|
759
|
-
],
|
|
760
|
-
}));
|
|
761
|
-
frameworkLogger.log("inference-cycle", "external-governance-complete", "info", {
|
|
762
|
-
proposalCount: proposals.length,
|
|
763
|
-
passedCount: batchResult.results.filter((r) => r.passed).length,
|
|
764
|
-
});
|
|
765
|
-
return votes;
|
|
766
|
-
}
|
|
767
|
-
catch (error) {
|
|
768
|
-
frameworkLogger.log("inference-cycle", "external-governance-failed", "error", {
|
|
769
|
-
error: error instanceof Error ? error.message : String(error),
|
|
770
|
-
});
|
|
771
|
-
return proposals.map((p) => this.rejectNoQuorum(p, "external governance endpoint failed"));
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
async invokeAgentInternal(agentName, prompt) {
|
|
775
|
-
frameworkLogger.log("inference-cycle", "invoke-agent-internal", "info", {
|
|
776
|
-
agentName,
|
|
777
|
-
promptLength: prompt.length,
|
|
778
|
-
});
|
|
779
|
-
try {
|
|
780
|
-
const { mcpClientManager } = await import("../mcps/mcp-client.js");
|
|
781
|
-
const MCP_TIMEOUT_MS = 8000;
|
|
782
|
-
const result = await Promise.race([
|
|
783
|
-
mcpClientManager.callServerTool("orchestrator", "orchestrate-task", {
|
|
784
|
-
description: prompt,
|
|
785
|
-
tasks: [{
|
|
786
|
-
id: `task-${Date.now()}`,
|
|
787
|
-
description: prompt,
|
|
788
|
-
type: agentName,
|
|
789
|
-
priority: "high",
|
|
790
|
-
}],
|
|
791
|
-
executionMode: "sequential",
|
|
792
|
-
}),
|
|
793
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error(`Orchestrator MCP timed out after ${MCP_TIMEOUT_MS}ms`)), MCP_TIMEOUT_MS)),
|
|
794
|
-
]);
|
|
795
|
-
const content = result.content;
|
|
796
|
-
let responseText = "";
|
|
797
|
-
if (content && Array.isArray(content)) {
|
|
798
|
-
responseText = content.map((c) => c.text ?? "").join("");
|
|
799
|
-
}
|
|
800
|
-
else {
|
|
801
|
-
responseText = JSON.stringify(result);
|
|
802
|
-
}
|
|
803
|
-
// In pure MCP governance mode, trust the orchestrator response (it now does real work)
|
|
804
|
-
const isPureMcp = process.env.XRAY_FORCE_MCP_GOVERNANCE === 'true';
|
|
805
|
-
const hasRealContent = /PROPOSAL:\s*\d+/i.test(responseText) ||
|
|
806
|
-
/DECISION:\s*(approve|reject|abstain)/i.test(responseText) ||
|
|
807
|
-
/Agent Outputs \(real MCP responses\):/i.test(responseText);
|
|
808
|
-
if (hasRealContent || isPureMcp) {
|
|
809
|
-
if (isPureMcp && !hasRealContent) {
|
|
810
|
-
frameworkLogger.log("inference-cycle", "pure-mcp-orchestrator-response", "info", {
|
|
811
|
-
agentName,
|
|
812
|
-
responsePreview: responseText.substring(0, 300),
|
|
813
|
-
});
|
|
814
|
-
}
|
|
815
|
-
return responseText;
|
|
816
|
-
}
|
|
817
|
-
frameworkLogger.log("inference-cycle", "mcp-no-useful-content", "info", {
|
|
818
|
-
agentName,
|
|
819
|
-
responsePreview: responseText.substring(0, 200),
|
|
820
|
-
});
|
|
821
|
-
}
|
|
822
|
-
catch (mcpError) {
|
|
823
|
-
frameworkLogger.log("inference-cycle", "mcp-invocation-failed", "info", {
|
|
824
|
-
agentName,
|
|
825
|
-
error: String(mcpError),
|
|
826
|
-
});
|
|
827
|
-
}
|
|
828
|
-
if (this.agentInvoker) {
|
|
829
|
-
frameworkLogger.log("inference-cycle", "invoke-via-callback", "info", { agentName });
|
|
830
|
-
return this.agentInvoker(agentName, prompt);
|
|
831
|
-
}
|
|
832
|
-
// Only fall back to OpenCode if not in forced pure MCP mode
|
|
833
|
-
if (process.env.XRAY_FORCE_MCP_GOVERNANCE === 'true') {
|
|
834
|
-
throw new Error(`[PURE MCP] Orchestrator returned no usable response for agent "${agentName}" and OpenCode fallback is disabled`);
|
|
835
|
-
}
|
|
836
|
-
return this.invokeViaOpencode(agentName, prompt);
|
|
837
|
-
}
|
|
838
|
-
async invokeViaOpencode(agentName, prompt) {
|
|
839
|
-
return invokeOpencodeFromEngine(agentName, prompt, this.projectRoot);
|
|
840
|
-
}
|
|
841
|
-
parseSubagentVotes(jsonOutput, proposals) {
|
|
842
|
-
const votes = [];
|
|
843
|
-
const lines = jsonOutput.split("\n").filter((l) => l.trim());
|
|
844
|
-
for (const line of lines) {
|
|
845
|
-
try {
|
|
846
|
-
const obj = JSON.parse(line);
|
|
847
|
-
if (obj.type === "tool_use" && obj.part?.type === "tool" && obj.part.tool === "task") {
|
|
848
|
-
const agentName = obj.part.state?.input?.subagent_type || "";
|
|
849
|
-
const output = obj.part.state?.output || "";
|
|
850
|
-
// Each task output may contain multiple PROPOSAL blocks
|
|
851
|
-
const blocks = output.split(/PROPOSAL:\s*/).filter((b) => b.trim().length > 0);
|
|
852
|
-
for (const block of blocks) {
|
|
853
|
-
const numMatch = block.match(/^(\d+)/);
|
|
854
|
-
if (!numMatch)
|
|
855
|
-
continue;
|
|
856
|
-
const proposalIdx = parseInt(numMatch[1], 10) - 1;
|
|
857
|
-
if (proposalIdx < 0 || proposalIdx >= proposals.length)
|
|
858
|
-
continue;
|
|
859
|
-
const decisionMatch = block.match(/DECISION:\s*(\w+)/i);
|
|
860
|
-
const confMatch = block.match(/CONFIDENCE:\s*(0?\.\d+|1\.0|1|0)/i);
|
|
861
|
-
const reasonMatch = block.match(/REASONING:\s*(.+)/i);
|
|
862
|
-
if (decisionMatch) {
|
|
863
|
-
const proposal = proposals[proposalIdx];
|
|
864
|
-
if (proposal) {
|
|
865
|
-
votes.push({
|
|
866
|
-
proposalId: proposal.id,
|
|
867
|
-
agentName,
|
|
868
|
-
decision: decisionMatch[1].toLowerCase(),
|
|
869
|
-
confidence: confMatch ? Math.min(1, Math.max(0, parseFloat(confMatch[1]))) : 0.5,
|
|
870
|
-
reasoning: reasonMatch ? reasonMatch[1].trim() : "",
|
|
871
|
-
});
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
catch {
|
|
878
|
-
// Not JSON, skip
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
// Fallback: if no votes found from JSON format, try parsing plain-text
|
|
882
|
-
// PROPOSAL/DECISION blocks directly (e.g. from opencode CLI fallback path)
|
|
883
|
-
if (votes.length === 0 && /PROPOSAL:\s*\d+/i.test(jsonOutput)) {
|
|
884
|
-
const blocks = jsonOutput.split(/PROPOSAL:\s*/).filter((b) => b.trim().length > 0);
|
|
885
|
-
for (const block of blocks) {
|
|
886
|
-
const numMatch = block.match(/^(\d+)/);
|
|
887
|
-
if (!numMatch)
|
|
888
|
-
continue;
|
|
889
|
-
const numStr = numMatch[1];
|
|
890
|
-
if (!numStr)
|
|
891
|
-
continue;
|
|
892
|
-
const proposalIdx = parseInt(numStr, 10) - 1;
|
|
893
|
-
if (proposalIdx < 0 || proposalIdx >= proposals.length)
|
|
894
|
-
continue;
|
|
895
|
-
const agentMatch = block.match(/AGENT:\s*(\w[\w-]*)/i);
|
|
896
|
-
const decisionMatch = block.match(/DECISION:\s*(\w+)/i);
|
|
897
|
-
const confMatch = block.match(/CONFIDENCE:\s*(0?\.\d+|1\.0|1|0)/i);
|
|
898
|
-
const reasonMatch = block.match(/REASONING:\s*(.+)/i);
|
|
899
|
-
if (decisionMatch) {
|
|
900
|
-
const proposal = proposals[proposalIdx];
|
|
901
|
-
if (proposal) {
|
|
902
|
-
let decision = decisionMatch[1].toLowerCase();
|
|
903
|
-
if (decision === "yes")
|
|
904
|
-
decision = "approve";
|
|
905
|
-
if (decision === "no")
|
|
906
|
-
decision = "reject";
|
|
907
|
-
votes.push({
|
|
908
|
-
proposalId: proposal.id,
|
|
909
|
-
agentName: agentMatch?.[1] ?? "architect",
|
|
910
|
-
decision,
|
|
911
|
-
confidence: confMatch ? Math.min(1, Math.max(0, parseFloat(confMatch[1]))) : 0.5,
|
|
912
|
-
reasoning: reasonMatch ? reasonMatch[1].trim() : "",
|
|
913
|
-
});
|
|
914
|
-
}
|
|
915
|
-
}
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
return votes;
|
|
919
|
-
}
|
|
920
|
-
getGovernanceStateManager() {
|
|
921
|
-
if (!fs.existsSync(this.stateDir)) {
|
|
922
|
-
fs.mkdirSync(this.stateDir, { recursive: true });
|
|
923
|
-
}
|
|
924
|
-
const stateFile = path.join(this.stateDir, "governance-state.json");
|
|
925
|
-
const stateManager = new XrayStateManager();
|
|
926
|
-
if (fs.existsSync(stateFile)) {
|
|
927
|
-
try {
|
|
928
|
-
const data = JSON.parse(fs.readFileSync(stateFile, "utf-8"));
|
|
929
|
-
for (const [key, value] of Object.entries(data)) {
|
|
930
|
-
stateManager.set(key, value);
|
|
931
|
-
}
|
|
932
|
-
}
|
|
933
|
-
catch {
|
|
934
|
-
frameworkLogger.log("inference-cycle", "governance-state-load-failed", "warning", {});
|
|
935
|
-
}
|
|
936
|
-
}
|
|
937
|
-
return stateManager;
|
|
938
|
-
}
|
|
939
|
-
saveGovernanceState(coordinator) {
|
|
940
|
-
const stateFile = path.join(this.stateDir, "governance-state.json");
|
|
941
|
-
try {
|
|
942
|
-
// Export the coordinator's internal state (voting history, metrics, etc.)
|
|
943
|
-
const history = coordinator.getVotingHistory();
|
|
944
|
-
const metrics = coordinator.getMetrics();
|
|
945
|
-
const exportData = {
|
|
946
|
-
votingHistory: history,
|
|
947
|
-
metrics,
|
|
948
|
-
exportedAt: new Date().toISOString(),
|
|
949
|
-
};
|
|
950
|
-
if (!fs.existsSync(this.stateDir)) {
|
|
951
|
-
fs.mkdirSync(this.stateDir, { recursive: true });
|
|
952
|
-
}
|
|
953
|
-
fs.writeFileSync(stateFile, JSON.stringify(exportData, null, 2));
|
|
954
|
-
}
|
|
955
|
-
catch (error) {
|
|
956
|
-
frameworkLogger.log("inference-cycle", "governance-state-save-failed", "warning", { error: String(error) });
|
|
957
|
-
}
|
|
958
|
-
}
|
|
959
274
|
extractTextFromNdjson(output) {
|
|
960
275
|
const texts = [];
|
|
961
276
|
for (const line of output.split("\n")) {
|
|
@@ -975,13 +290,10 @@ Respond with EXACTLY one of:
|
|
|
975
290
|
return texts.join("\n").trim();
|
|
976
291
|
}
|
|
977
292
|
resolveOpencodeRoot() {
|
|
978
|
-
// Use the provider-agnostic config path resolver (prefers .xray/)
|
|
979
293
|
const configDir = getConfigDir(this.projectRoot);
|
|
980
|
-
// If we resolved to a .xray or custom dir, use its parent as the "root"
|
|
981
294
|
if (configDir.includes(".xray") || configDir.includes("xray")) {
|
|
982
295
|
return path.dirname(configDir);
|
|
983
296
|
}
|
|
984
|
-
// Legacy fallback
|
|
985
297
|
let dir = this.projectRoot;
|
|
986
298
|
for (let i = 0; i < 10; i++) {
|
|
987
299
|
if (fs.existsSync(path.join(dir, ".opencode")))
|
|
@@ -996,61 +308,6 @@ Respond with EXACTLY one of:
|
|
|
996
308
|
return cwd;
|
|
997
309
|
return this.projectRoot;
|
|
998
310
|
}
|
|
999
|
-
rejectNoQuorum(proposal, reason) {
|
|
1000
|
-
return {
|
|
1001
|
-
proposalId: proposal.id,
|
|
1002
|
-
decision: "reject",
|
|
1003
|
-
confidence: 0,
|
|
1004
|
-
details: [`rejected: ${reason}`],
|
|
1005
|
-
};
|
|
1006
|
-
}
|
|
1007
|
-
classifyProposalType(problemPattern) {
|
|
1008
|
-
const lower = problemPattern.toLowerCase();
|
|
1009
|
-
if (lower.includes("bug") || lower.includes("fix") || lower.includes("stability"))
|
|
1010
|
-
return "fix";
|
|
1011
|
-
if (lower.includes("dead code") || lower.includes("remove") || lower.includes("health"))
|
|
1012
|
-
return "refactor";
|
|
1013
|
-
if (lower.includes("manual") || lower.includes("automate"))
|
|
1014
|
-
return "automate";
|
|
1015
|
-
if (lower.includes("guard") || lower.includes("path") || lower.includes("timing") || lower.includes("edge case"))
|
|
1016
|
-
return "guard";
|
|
1017
|
-
return "codify";
|
|
1018
|
-
}
|
|
1019
|
-
patternToProposalType(pattern) {
|
|
1020
|
-
const name = pattern.name.toLowerCase();
|
|
1021
|
-
if (name.includes("dead code"))
|
|
1022
|
-
return "refactor";
|
|
1023
|
-
if (name.includes("extract"))
|
|
1024
|
-
return "refactor";
|
|
1025
|
-
if (name.includes("registry") || name.includes("facade"))
|
|
1026
|
-
return "codify";
|
|
1027
|
-
if (name.includes("test"))
|
|
1028
|
-
return "guard";
|
|
1029
|
-
if (name.includes("stability"))
|
|
1030
|
-
return "fix";
|
|
1031
|
-
return "codify";
|
|
1032
|
-
}
|
|
1033
|
-
generateTitle(problem) {
|
|
1034
|
-
const pattern = problem.pattern;
|
|
1035
|
-
const ACTION_MAP = [
|
|
1036
|
-
[/^Bug fix$/i, "Fix recurring bug pattern"],
|
|
1037
|
-
[/^Code health cleanup$/i, "Clean up code health issues"],
|
|
1038
|
-
[/^Accumulated dead code$/i, "Remove accumulated dead code"],
|
|
1039
|
-
[/^Incomplete implementation$/i, "Complete partial implementation"],
|
|
1040
|
-
[/^Technical debt/i, "Address technical debt"],
|
|
1041
|
-
[/^Missing guard/i, "Add missing guard"],
|
|
1042
|
-
[/^Manual step/i, "Automate manual step"],
|
|
1043
|
-
];
|
|
1044
|
-
for (const [re, title] of ACTION_MAP) {
|
|
1045
|
-
if (re.test(pattern)) {
|
|
1046
|
-
return `${title} (${problem.occurrences}x across ${problem.sessions.length} sessions)`;
|
|
1047
|
-
}
|
|
1048
|
-
}
|
|
1049
|
-
if (pattern.length > 80) {
|
|
1050
|
-
return `Address: ${pattern.substring(0, 77)}... (${problem.occurrences}x)`;
|
|
1051
|
-
}
|
|
1052
|
-
return `Address: ${pattern} (${problem.occurrences}x)`;
|
|
1053
|
-
}
|
|
1054
311
|
setPhase(phase) {
|
|
1055
312
|
this.phase = phase;
|
|
1056
313
|
frameworkLogger.log("inference-cycle", "phase-change", "info", { phase });
|
|
@@ -1098,39 +355,6 @@ Respond with EXACTLY one of:
|
|
|
1098
355
|
return [];
|
|
1099
356
|
}
|
|
1100
357
|
}
|
|
1101
|
-
adjustConfidenceFromHistory(proposals) {
|
|
1102
|
-
const history = this.loadHistory();
|
|
1103
|
-
if (history.length === 0)
|
|
1104
|
-
return;
|
|
1105
|
-
const recentVotes = history.slice(-10).flatMap((h) => h.votes);
|
|
1106
|
-
const approvedIds = new Set(recentVotes.filter((v) => v.decision === "approve").map((v) => v.proposalId));
|
|
1107
|
-
const approvedTypes = new Map();
|
|
1108
|
-
const rejectedTypes = new Map();
|
|
1109
|
-
for (const h of history.slice(-10)) {
|
|
1110
|
-
for (const p of h.proposals) {
|
|
1111
|
-
if (p.status === "approved" || p.status === "applied") {
|
|
1112
|
-
approvedTypes.set(p.type, (approvedTypes.get(p.type) ?? 0) + 1);
|
|
1113
|
-
}
|
|
1114
|
-
else if (p.status === "rejected" || p.status === "failed") {
|
|
1115
|
-
rejectedTypes.set(p.type, (rejectedTypes.get(p.type) ?? 0) + 1);
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
|
-
}
|
|
1119
|
-
for (const proposal of proposals) {
|
|
1120
|
-
const approved = approvedTypes.get(proposal.type) ?? 0;
|
|
1121
|
-
const rejected = rejectedTypes.get(proposal.type) ?? 0;
|
|
1122
|
-
const total = approved + rejected;
|
|
1123
|
-
if (total >= 3) {
|
|
1124
|
-
const successRate = approved / total;
|
|
1125
|
-
if (successRate < 0.3) {
|
|
1126
|
-
proposal.confidence *= 0.8;
|
|
1127
|
-
}
|
|
1128
|
-
else if (successRate > 0.7) {
|
|
1129
|
-
proposal.confidence = Math.min(0.95, proposal.confidence * 1.05);
|
|
1130
|
-
}
|
|
1131
|
-
}
|
|
1132
|
-
}
|
|
1133
|
-
}
|
|
1134
358
|
buildBlockedResult(cycleId, reason) {
|
|
1135
359
|
return {
|
|
1136
360
|
cycleId,
|