@hongmaple0820/scale-engine 0.40.2 → 0.44.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/README.md +30 -2
- package/dist/api/cli.js +43 -2
- package/dist/api/cli.js.map +1 -1
- package/dist/api/quickstart.d.ts +11 -0
- package/dist/api/quickstart.js +98 -1
- package/dist/api/quickstart.js.map +1 -1
- package/dist/artifact/fsmDefinitions.js +15 -2
- package/dist/artifact/fsmDefinitions.js.map +1 -1
- package/dist/artifact/types.d.ts +1 -1
- package/dist/artifact/types.js.map +1 -1
- package/dist/cache/ScanCache.d.ts +41 -0
- package/dist/cache/ScanCache.js +120 -0
- package/dist/cache/ScanCache.js.map +1 -0
- package/dist/capabilities/BrowserQACapability.d.ts +14 -0
- package/dist/capabilities/BrowserQACapability.js +94 -0
- package/dist/capabilities/BrowserQACapability.js.map +1 -1
- package/dist/cli/autofixCommands.d.ts +22 -0
- package/dist/cli/autofixCommands.js +32 -0
- package/dist/cli/autofixCommands.js.map +1 -0
- package/dist/cli/cortexCommands.d.ts +71 -0
- package/dist/cli/cortexCommands.js +335 -0
- package/dist/cli/cortexCommands.js.map +1 -0
- package/dist/cli/costCommands.d.ts +13 -0
- package/dist/cli/costCommands.js +48 -0
- package/dist/cli/costCommands.js.map +1 -0
- package/dist/cli/orchCommands.d.ts +43 -0
- package/dist/cli/orchCommands.js +135 -0
- package/dist/cli/orchCommands.js.map +1 -0
- package/dist/cli/phaseCommands.js +1 -2
- package/dist/cli/phaseCommands.js.map +1 -1
- package/dist/cli/qaCommands.d.ts +22 -0
- package/dist/cli/qaCommands.js +84 -0
- package/dist/cli/qaCommands.js.map +1 -0
- package/dist/cli/quickstartCommands.d.ts +17 -0
- package/dist/cli/quickstartCommands.js +47 -0
- package/dist/cli/quickstartCommands.js.map +1 -0
- package/dist/cli/shieldCommands.d.ts +30 -0
- package/dist/cli/shieldCommands.js +212 -0
- package/dist/cli/shieldCommands.js.map +1 -0
- package/dist/cli/tuiCommands.d.ts +7 -0
- package/dist/cli/tuiCommands.js +33 -0
- package/dist/cli/tuiCommands.js.map +1 -0
- package/dist/codegraph/CodeIntelligence.d.ts +27 -0
- package/dist/codegraph/CodeIntelligence.js +316 -3
- package/dist/codegraph/CodeIntelligence.js.map +1 -1
- package/dist/config/profiles.js +26 -0
- package/dist/config/profiles.js.map +1 -1
- package/dist/cortex/GovernanceMetrics.d.ts +66 -0
- package/dist/cortex/GovernanceMetrics.js +230 -0
- package/dist/cortex/GovernanceMetrics.js.map +1 -0
- package/dist/cortex/InstinctExtractor.d.ts +61 -0
- package/dist/cortex/InstinctExtractor.js +184 -0
- package/dist/cortex/InstinctExtractor.js.map +1 -0
- package/dist/cortex/InstinctStore.d.ts +54 -0
- package/dist/cortex/InstinctStore.js +266 -0
- package/dist/cortex/InstinctStore.js.map +1 -0
- package/dist/cortex/ReflexionEngine.d.ts +34 -0
- package/dist/cortex/ReflexionEngine.js +157 -0
- package/dist/cortex/ReflexionEngine.js.map +1 -0
- package/dist/cortex/SessionInjector.d.ts +44 -0
- package/dist/cortex/SessionInjector.js +127 -0
- package/dist/cortex/SessionInjector.js.map +1 -0
- package/dist/cortex/adapters/ClaudeAdapter.d.ts +17 -0
- package/dist/cortex/adapters/ClaudeAdapter.js +61 -0
- package/dist/cortex/adapters/ClaudeAdapter.js.map +1 -0
- package/dist/cortex/adapters/CodexAdapter.d.ts +10 -0
- package/dist/cortex/adapters/CodexAdapter.js +52 -0
- package/dist/cortex/adapters/CodexAdapter.js.map +1 -0
- package/dist/cortex/adapters/CursorAdapter.d.ts +10 -0
- package/dist/cortex/adapters/CursorAdapter.js +46 -0
- package/dist/cortex/adapters/CursorAdapter.js.map +1 -0
- package/dist/cortex/adapters/GeminiAdapter.d.ts +11 -0
- package/dist/cortex/adapters/GeminiAdapter.js +48 -0
- package/dist/cortex/adapters/GeminiAdapter.js.map +1 -0
- package/dist/dashboard/DashboardServer.d.ts +33 -13
- package/dist/dashboard/DashboardServer.js +314 -182
- package/dist/dashboard/DashboardServer.js.map +1 -1
- package/dist/dashboard/index.d.ts +2 -2
- package/dist/dashboard/index.js +1 -1
- package/dist/dashboard/index.js.map +1 -1
- package/dist/dashboard/server.d.ts +8 -22
- package/dist/dashboard/server.js +2 -83
- package/dist/dashboard/server.js.map +1 -1
- package/dist/eval/BenchmarkPublisher.d.ts +25 -0
- package/dist/eval/BenchmarkPublisher.js +27 -0
- package/dist/eval/BenchmarkPublisher.js.map +1 -0
- package/dist/guardrails/DependencyAuditor.js +10 -1
- package/dist/guardrails/DependencyAuditor.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/orchestrator/OrchestratorDaemon.d.ts +44 -0
- package/dist/orchestrator/OrchestratorDaemon.js +150 -0
- package/dist/orchestrator/OrchestratorDaemon.js.map +1 -0
- package/dist/orchestrator/PolicyLoader.d.ts +80 -0
- package/dist/orchestrator/PolicyLoader.js +229 -0
- package/dist/orchestrator/PolicyLoader.js.map +1 -0
- package/dist/orchestrator/ReconciliationLoop.d.ts +71 -0
- package/dist/orchestrator/ReconciliationLoop.js +266 -0
- package/dist/orchestrator/ReconciliationLoop.js.map +1 -0
- package/dist/orchestrator/TrackerAdapter.d.ts +60 -0
- package/dist/orchestrator/TrackerAdapter.js +147 -0
- package/dist/orchestrator/TrackerAdapter.js.map +1 -0
- package/dist/orchestrator/WorkspaceManager.d.ts +66 -0
- package/dist/orchestrator/WorkspaceManager.js +257 -0
- package/dist/orchestrator/WorkspaceManager.js.map +1 -0
- package/dist/qa/BrowserDaemon.d.ts +23 -0
- package/dist/qa/BrowserDaemon.js +79 -0
- package/dist/qa/BrowserDaemon.js.map +1 -0
- package/dist/qa/E2ETestOrchestrator.d.ts +14 -0
- package/dist/qa/E2ETestOrchestrator.js +19 -0
- package/dist/qa/E2ETestOrchestrator.js.map +1 -0
- package/dist/review/CrossModelReviewer.d.ts +35 -0
- package/dist/review/CrossModelReviewer.js +75 -0
- package/dist/review/CrossModelReviewer.js.map +1 -0
- package/dist/review/ReviewAggregator.d.ts +13 -0
- package/dist/review/ReviewAggregator.js +28 -0
- package/dist/review/ReviewAggregator.js.map +1 -0
- package/dist/review/reviewCommands.d.ts +15 -0
- package/dist/review/reviewCommands.js +24 -0
- package/dist/review/reviewCommands.js.map +1 -0
- package/dist/routing/LocalModelProvider.d.ts +11 -0
- package/dist/routing/LocalModelProvider.js +21 -0
- package/dist/routing/LocalModelProvider.js.map +1 -0
- package/dist/routing/ModelRouter.d.ts +12 -0
- package/dist/routing/ModelRouter.js +31 -4
- package/dist/routing/ModelRouter.js.map +1 -1
- package/dist/runtime/AiOsRuntime.d.ts +1 -0
- package/dist/runtime/AiOsRuntime.js +15 -0
- package/dist/runtime/AiOsRuntime.js.map +1 -1
- package/dist/runtime/CostAnalyzer.d.ts +53 -0
- package/dist/runtime/CostAnalyzer.js +160 -0
- package/dist/runtime/CostAnalyzer.js.map +1 -0
- package/dist/runtime/CostOptimizer.d.ts +11 -0
- package/dist/runtime/CostOptimizer.js +21 -0
- package/dist/runtime/CostOptimizer.js.map +1 -0
- package/dist/shield/PolicyCompiler.d.ts +70 -0
- package/dist/shield/PolicyCompiler.js +540 -0
- package/dist/shield/PolicyCompiler.js.map +1 -0
- package/dist/shield/ProtectedPaths.d.ts +39 -0
- package/dist/shield/ProtectedPaths.js +179 -0
- package/dist/shield/ProtectedPaths.js.map +1 -0
- package/dist/shield/ShieldProtocol.d.ts +50 -0
- package/dist/shield/ShieldProtocol.js +103 -0
- package/dist/shield/ShieldProtocol.js.map +1 -0
- package/dist/skills/SkillMdStandard.d.ts +33 -0
- package/dist/skills/SkillMdStandard.js +88 -0
- package/dist/skills/SkillMdStandard.js.map +1 -0
- package/dist/skills/SkillRegistry.d.ts +9 -1
- package/dist/skills/SkillRegistry.js +20 -0
- package/dist/skills/SkillRegistry.js.map +1 -1
- package/dist/skills/interop/GStackInterop.d.ts +15 -0
- package/dist/skills/interop/GStackInterop.js +34 -0
- package/dist/skills/interop/GStackInterop.js.map +1 -0
- package/dist/skills/interop/OMCInterop.d.ts +15 -0
- package/dist/skills/interop/OMCInterop.js +34 -0
- package/dist/skills/interop/OMCInterop.js.map +1 -0
- package/dist/topology/DomainMapper.d.ts +23 -0
- package/dist/topology/DomainMapper.js +179 -0
- package/dist/topology/DomainMapper.js.map +1 -0
- package/dist/topology/LayerClassifier.d.ts +8 -0
- package/dist/topology/LayerClassifier.js +109 -0
- package/dist/topology/LayerClassifier.js.map +1 -0
- package/dist/topology/TourGenerator.d.ts +18 -0
- package/dist/topology/TourGenerator.js +120 -0
- package/dist/topology/TourGenerator.js.map +1 -0
- package/dist/topology/index.d.ts +3 -0
- package/dist/topology/index.js +4 -0
- package/dist/topology/index.js.map +1 -0
- package/dist/tui/TuiDashboard.d.ts +3 -0
- package/dist/tui/TuiDashboard.js +120 -0
- package/dist/tui/TuiDashboard.js.map +1 -0
- package/dist/workflow/GateCatalog.d.ts +2 -0
- package/dist/workflow/GateCatalog.js +59 -3
- package/dist/workflow/GateCatalog.js.map +1 -1
- package/dist/workflow/GovernanceTemplatePacks.d.ts +1 -1
- package/dist/workflow/GovernanceTemplatePacks.js +15 -0
- package/dist/workflow/GovernanceTemplatePacks.js.map +1 -1
- package/dist/workflow/TddLoop.d.ts +2 -0
- package/dist/workflow/TddLoop.js +2 -0
- package/dist/workflow/TddLoop.js.map +1 -1
- package/dist/workflow/UpgradeManager.d.ts +10 -1
- package/dist/workflow/UpgradeManager.js +55 -0
- package/dist/workflow/UpgradeManager.js.map +1 -1
- package/dist/workflow/VerificationProfile.d.ts +8 -0
- package/dist/workflow/VerificationProfile.js +61 -0
- package/dist/workflow/VerificationProfile.js.map +1 -1
- package/dist/workflow/VerificationSchema.d.ts +46 -0
- package/dist/workflow/VerificationSchema.js +97 -0
- package/dist/workflow/VerificationSchema.js.map +1 -0
- package/dist/workflow/autofix/AutoFixEngine.d.ts +37 -0
- package/dist/workflow/autofix/AutoFixEngine.js +169 -0
- package/dist/workflow/autofix/AutoFixEngine.js.map +1 -0
- package/dist/workflow/execution/RalphEngine.d.ts +18 -0
- package/dist/workflow/execution/RalphEngine.js +22 -0
- package/dist/workflow/execution/RalphEngine.js.map +1 -1
- package/dist/workflow/gates/EnhancedGates.d.ts +74 -0
- package/dist/workflow/gates/EnhancedGates.js +653 -0
- package/dist/workflow/gates/EnhancedGates.js.map +1 -0
- package/dist/workflow/gates/GateSystem.d.ts +3 -0
- package/dist/workflow/gates/GateSystem.js +94 -1
- package/dist/workflow/gates/GateSystem.js.map +1 -1
- package/dist/workflow/types.d.ts +1 -1
- package/docs/README.md +3 -0
- package/docs/guides/DEVELOPMENT_WORKFLOW.md +28 -9
- package/docs/guides/GETTING_STARTED.md +19 -0
- package/docs/guides/MIGRATION.md +119 -0
- package/docs/workflow/GATES_AND_SCORE.md +34 -1
- package/docs/workflow/README.md +58 -10
- package/package.json +7 -17
- package/docs/ACTIVE_SECURITY_VISUAL_GATES.md +0 -87
- package/docs/AI_ENGINEERING_OS_POSITIONING.md +0 -607
- package/docs/BACKGROUND_HUNTER.md +0 -62
- package/docs/CODE_INTELLIGENCE.md +0 -180
- package/docs/CONTEXT_BUDGET.md +0 -165
- package/docs/DEPENDENCY_AUDIT.md +0 -118
- package/docs/EVOLUTION_SHADOW_MODE.md +0 -63
- package/docs/GITLAB_FLOW.md +0 -125
- package/docs/GOVERNANCE_DASHBOARD.md +0 -92
- package/docs/MEMORY_BRAIN.md +0 -104
- package/docs/MEMORY_FABRIC.md +0 -161
- package/docs/RESOURCE_GOVERNANCE.md +0 -92
- package/docs/RUNTIME_EVIDENCE.md +0 -101
- package/docs/WORKFLOW_EVAL.md +0 -151
- package/image/wechat-public.jpg +0 -0
- package/image/wxPay.jpg +0 -0
- package/image/zfb.jpg +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OrchestratorDaemon.js","sourceRoot":"","sources":["../../src/orchestrator/OrchestratorDaemon.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
export interface OrchestratorPolicy {
|
|
2
|
+
tracker: TrackerSection;
|
|
3
|
+
polling: PollingSection;
|
|
4
|
+
workspace: WorkspaceSection;
|
|
5
|
+
hooks: HooksSection;
|
|
6
|
+
agent: AgentSection;
|
|
7
|
+
codex: CodexSection;
|
|
8
|
+
version: number;
|
|
9
|
+
rawBody: string;
|
|
10
|
+
filePath: string;
|
|
11
|
+
lastModified: number;
|
|
12
|
+
hash: string;
|
|
13
|
+
}
|
|
14
|
+
export interface TrackerSection {
|
|
15
|
+
type: 'github' | 'linear' | 'jira';
|
|
16
|
+
owner?: string;
|
|
17
|
+
repo?: string;
|
|
18
|
+
projectKey?: string;
|
|
19
|
+
baseUrl?: string;
|
|
20
|
+
activeStates: string[];
|
|
21
|
+
terminalStates: string[];
|
|
22
|
+
}
|
|
23
|
+
export interface PollingSection {
|
|
24
|
+
intervalMs: number;
|
|
25
|
+
maxParallelWorkspaces: number;
|
|
26
|
+
maxRetryBackoffMs: number;
|
|
27
|
+
maxAttempts: number;
|
|
28
|
+
priorityLabels: Record<string, number>;
|
|
29
|
+
}
|
|
30
|
+
export interface WorkspaceSection {
|
|
31
|
+
root: string;
|
|
32
|
+
allowedChars: string;
|
|
33
|
+
maxWorkspaceAgeHours: number;
|
|
34
|
+
}
|
|
35
|
+
export interface HooksSection {
|
|
36
|
+
afterCreate?: string;
|
|
37
|
+
beforeRun?: string;
|
|
38
|
+
afterRun?: string;
|
|
39
|
+
beforeRemove?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface AgentSection {
|
|
42
|
+
model: string;
|
|
43
|
+
maxTurns: number;
|
|
44
|
+
timeoutMinutes: number;
|
|
45
|
+
instructions?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface CodexSection {
|
|
48
|
+
enabled: boolean;
|
|
49
|
+
promptTemplate?: string;
|
|
50
|
+
}
|
|
51
|
+
export declare const DEFAULT_POLICY: OrchestratorPolicy;
|
|
52
|
+
export declare class PolicyLoader {
|
|
53
|
+
private currentPolicy;
|
|
54
|
+
private lastGoodPolicy;
|
|
55
|
+
private watcherActive;
|
|
56
|
+
/**
|
|
57
|
+
* Load SCALE_POLICY.md from project root.
|
|
58
|
+
* Falls back to good policy if the loaded one is invalid.
|
|
59
|
+
*/
|
|
60
|
+
load(projectDir: string): OrchestratorPolicy;
|
|
61
|
+
/**
|
|
62
|
+
* Enable dynamic reload via file watcher.
|
|
63
|
+
* On file change: reload, retain last-good on parse failure.
|
|
64
|
+
*/
|
|
65
|
+
watch(projectDir: string): void;
|
|
66
|
+
/**
|
|
67
|
+
* Get the current loaded policy (already validated/reloaded).
|
|
68
|
+
*/
|
|
69
|
+
get(): OrchestratorPolicy;
|
|
70
|
+
/**
|
|
71
|
+
* Parse YAML frontmatter from Markdown.
|
|
72
|
+
* Format: ---\n<YAML>\n---\n<MARKDOWN BODY>
|
|
73
|
+
*/
|
|
74
|
+
parsePolicyMarkdown(raw: string, filePath: string, lastModified: number): OrchestratorPolicy;
|
|
75
|
+
/**
|
|
76
|
+
* Minimal YAML parser for the SCALE_POLICY.md frontmatter subset.
|
|
77
|
+
* Handles nested objects and arrays needed by the 6-key schema.
|
|
78
|
+
*/
|
|
79
|
+
private minimalYamlParse;
|
|
80
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
// SCALE Orchestrator — Policy Loader
|
|
2
|
+
// 对齐 Symphony: YAML frontmatter + Markdown body in SCALE_POLICY.md
|
|
3
|
+
// 动态重载: 文件变更自动重载,无效配置保留上一次良好配置
|
|
4
|
+
import { existsSync, readFileSync, statSync, watchFile } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { logger } from '../core/logger.js';
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Default policy
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
export const DEFAULT_POLICY = {
|
|
11
|
+
tracker: {
|
|
12
|
+
type: 'github',
|
|
13
|
+
activeStates: ['open', 'in_progress'],
|
|
14
|
+
terminalStates: ['resolved', 'closed', 'cancelled'],
|
|
15
|
+
},
|
|
16
|
+
polling: {
|
|
17
|
+
intervalMs: 30000,
|
|
18
|
+
maxParallelWorkspaces: 3,
|
|
19
|
+
maxRetryBackoffMs: 300000,
|
|
20
|
+
maxAttempts: 3,
|
|
21
|
+
priorityLabels: { 'priority:critical': 0, 'priority:high': 1, 'priority:medium': 2, 'priority:low': 3 },
|
|
22
|
+
},
|
|
23
|
+
workspace: {
|
|
24
|
+
root: '.scale/worktrees',
|
|
25
|
+
allowedChars: '[A-Za-z0-9._-]',
|
|
26
|
+
maxWorkspaceAgeHours: 24,
|
|
27
|
+
},
|
|
28
|
+
hooks: {},
|
|
29
|
+
agent: {
|
|
30
|
+
model: 'claude-sonnet-4-6',
|
|
31
|
+
maxTurns: 50,
|
|
32
|
+
timeoutMinutes: 30,
|
|
33
|
+
},
|
|
34
|
+
codex: {
|
|
35
|
+
enabled: true,
|
|
36
|
+
},
|
|
37
|
+
version: 1,
|
|
38
|
+
rawBody: '',
|
|
39
|
+
filePath: '',
|
|
40
|
+
lastModified: 0,
|
|
41
|
+
hash: '',
|
|
42
|
+
};
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
// PolicyLoader
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
export class PolicyLoader {
|
|
47
|
+
constructor() {
|
|
48
|
+
this.currentPolicy = { ...DEFAULT_POLICY };
|
|
49
|
+
this.lastGoodPolicy = { ...DEFAULT_POLICY };
|
|
50
|
+
this.watcherActive = false;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Load SCALE_POLICY.md from project root.
|
|
54
|
+
* Falls back to good policy if the loaded one is invalid.
|
|
55
|
+
*/
|
|
56
|
+
load(projectDir) {
|
|
57
|
+
const policyPath = join(projectDir, 'SCALE_POLICY.md');
|
|
58
|
+
if (!existsSync(policyPath)) {
|
|
59
|
+
logger.warn('No SCALE_POLICY.md found, using defaults');
|
|
60
|
+
this.currentPolicy = { ...DEFAULT_POLICY, filePath: policyPath, lastModified: Date.now(), hash: 'default' };
|
|
61
|
+
return this.currentPolicy;
|
|
62
|
+
}
|
|
63
|
+
const raw = readFileSync(policyPath, 'utf-8');
|
|
64
|
+
const stat = statSync(policyPath);
|
|
65
|
+
try {
|
|
66
|
+
const parsed = this.parsePolicyMarkdown(raw, policyPath, stat.mtimeMs);
|
|
67
|
+
this.lastGoodPolicy = parsed;
|
|
68
|
+
this.currentPolicy = parsed;
|
|
69
|
+
logger.info({ path: policyPath, version: parsed.version }, 'SCALE_POLICY.md loaded');
|
|
70
|
+
return parsed;
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
logger.error({ err, path: policyPath }, 'Failed to parse SCALE_POLICY.md — using last-good config');
|
|
74
|
+
this.currentPolicy = { ...this.lastGoodPolicy, filePath: policyPath, lastModified: stat.mtimeMs };
|
|
75
|
+
return this.currentPolicy;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Enable dynamic reload via file watcher.
|
|
80
|
+
* On file change: reload, retain last-good on parse failure.
|
|
81
|
+
*/
|
|
82
|
+
watch(projectDir) {
|
|
83
|
+
if (this.watcherActive)
|
|
84
|
+
return;
|
|
85
|
+
const policyPath = join(projectDir, 'SCALE_POLICY.md');
|
|
86
|
+
watchFile(policyPath, { interval: 5000 }, () => {
|
|
87
|
+
logger.info('SCALE_POLICY.md changed — reloading');
|
|
88
|
+
this.load(projectDir);
|
|
89
|
+
});
|
|
90
|
+
this.watcherActive = true;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Get the current loaded policy (already validated/reloaded).
|
|
94
|
+
*/
|
|
95
|
+
get() {
|
|
96
|
+
return this.currentPolicy;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Parse YAML frontmatter from Markdown.
|
|
100
|
+
* Format: ---\n<YAML>\n---\n<MARKDOWN BODY>
|
|
101
|
+
*/
|
|
102
|
+
parsePolicyMarkdown(raw, filePath, lastModified) {
|
|
103
|
+
const frontmatterMatch = raw.match(/^---\n([\s\S]*?)\n---/);
|
|
104
|
+
if (!frontmatterMatch) {
|
|
105
|
+
throw new Error('SCALE_POLICY.md missing YAML frontmatter (---...---)');
|
|
106
|
+
}
|
|
107
|
+
const yamlStr = frontmatterMatch[1];
|
|
108
|
+
const bodyStart = (frontmatterMatch.index ?? 0) + frontmatterMatch[0].length;
|
|
109
|
+
const rawBody = raw.slice(bodyStart).trim();
|
|
110
|
+
const frontmatter = this.minimalYamlParse(yamlStr);
|
|
111
|
+
// Merge with defaults so partial configs work
|
|
112
|
+
const merged = {
|
|
113
|
+
tracker: { ...DEFAULT_POLICY.tracker, ...(frontmatter.tracker ?? {}) },
|
|
114
|
+
polling: { ...DEFAULT_POLICY.polling, ...(frontmatter.polling ?? {}) },
|
|
115
|
+
workspace: { ...DEFAULT_POLICY.workspace, ...(frontmatter.workspace ?? {}) },
|
|
116
|
+
hooks: { ...DEFAULT_POLICY.hooks, ...(frontmatter.hooks ?? {}) },
|
|
117
|
+
agent: { ...DEFAULT_POLICY.agent, ...(frontmatter.agent ?? {}) },
|
|
118
|
+
codex: { ...DEFAULT_POLICY.codex, ...(frontmatter.codex ?? {}) },
|
|
119
|
+
version: frontmatter.version ?? 1,
|
|
120
|
+
rawBody,
|
|
121
|
+
filePath,
|
|
122
|
+
lastModified,
|
|
123
|
+
hash: '',
|
|
124
|
+
};
|
|
125
|
+
const crypto = __non_webpack_require__('node:crypto') ?? require('crypto');
|
|
126
|
+
merged.hash = crypto.createHash('sha256').update(raw).digest('hex').slice(0, 12);
|
|
127
|
+
return merged;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Minimal YAML parser for the SCALE_POLICY.md frontmatter subset.
|
|
131
|
+
* Handles nested objects and arrays needed by the 6-key schema.
|
|
132
|
+
*/
|
|
133
|
+
minimalYamlParse(yamlStr) {
|
|
134
|
+
const result = {};
|
|
135
|
+
// Split into lines and parse top-level key: value pairs
|
|
136
|
+
const lines = yamlStr.split('\n');
|
|
137
|
+
let currentSection = null;
|
|
138
|
+
let currentObj = {};
|
|
139
|
+
let inArray = null;
|
|
140
|
+
let arrayValues = [];
|
|
141
|
+
for (const line of lines) {
|
|
142
|
+
const trimmed = line.trim();
|
|
143
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
144
|
+
continue;
|
|
145
|
+
// Section headers
|
|
146
|
+
if (trimmed.match(/^[a-zA-Z_]+:/) && !trimmed.includes(': ') && !trimmed.endsWith(':')) {
|
|
147
|
+
// Simple key: value at top level
|
|
148
|
+
const [key, ...rest] = trimmed.split(':');
|
|
149
|
+
const val = rest.join(':').trim();
|
|
150
|
+
if (val && currentSection === null) {
|
|
151
|
+
result[key.trim()] = isNaN(Number(val)) ? val : Number(val);
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// Start of a section object
|
|
156
|
+
if (trimmed.endsWith(':') && !trimmed.match(/^\s*-/)) {
|
|
157
|
+
const sectionName = trimmed.slice(0, -1).trim();
|
|
158
|
+
currentSection = sectionName;
|
|
159
|
+
currentObj = {};
|
|
160
|
+
result[sectionName] = currentObj;
|
|
161
|
+
inArray = null;
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
// Key: value within a section
|
|
165
|
+
if (currentSection && trimmed.includes(':') && !trimmed.startsWith('-')) {
|
|
166
|
+
const [key, ...rest] = trimmed.split(':');
|
|
167
|
+
const val = rest.join(':').trim();
|
|
168
|
+
if (val) {
|
|
169
|
+
// Numeric values
|
|
170
|
+
if (/^\d+$/.test(val))
|
|
171
|
+
currentObj[key.trim()] = parseInt(val, 10);
|
|
172
|
+
// Boolean values
|
|
173
|
+
else if (val === 'true')
|
|
174
|
+
currentObj[key.trim()] = true;
|
|
175
|
+
else if (val === 'false')
|
|
176
|
+
currentObj[key.trim()] = false;
|
|
177
|
+
// Strings
|
|
178
|
+
else
|
|
179
|
+
currentObj[key.trim()] = val;
|
|
180
|
+
}
|
|
181
|
+
inArray = null;
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
// Array item — start
|
|
185
|
+
if (currentSection && trimmed === '-') {
|
|
186
|
+
inArray = null;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
// Array items — list
|
|
190
|
+
if (currentSection && trimmed.startsWith('- ') && !trimmed.includes(':')) {
|
|
191
|
+
const val = trimmed.slice(2).trim();
|
|
192
|
+
if (inArray) {
|
|
193
|
+
arrayValues.push(val);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
// Check if an array key was just defined
|
|
197
|
+
const lastKey = Object.keys(currentObj).pop();
|
|
198
|
+
if (lastKey && Array.isArray(currentObj[lastKey])) {
|
|
199
|
+
;
|
|
200
|
+
currentObj[lastKey].push(val);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
// Key: (empty) — start of an array
|
|
206
|
+
if (currentSection && trimmed.includes(':') && trimmed.slice(-1) === ':') {
|
|
207
|
+
const key = trimmed.slice(0, -1).trim();
|
|
208
|
+
const valAfterColon = trimmed.split(':').slice(1).join(':').trim();
|
|
209
|
+
if (!valAfterColon) {
|
|
210
|
+
inArray = key;
|
|
211
|
+
arrayValues = [];
|
|
212
|
+
currentObj[key] = arrayValues;
|
|
213
|
+
}
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return result;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// Avoid bundler issues with dynamic require
|
|
221
|
+
function __non_webpack_require__(mod) {
|
|
222
|
+
try {
|
|
223
|
+
return require(mod);
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=PolicyLoader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PolicyLoader.js","sourceRoot":"","sources":["../../src/orchestrator/PolicyLoader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import type { ITrackerAdapter } from './TrackerAdapter.js';
|
|
3
|
+
import type { OrchestratorPolicy } from './PolicyLoader.js';
|
|
4
|
+
import { WorkspaceManager } from './WorkspaceManager.js';
|
|
5
|
+
export type OrchestrationState = 'Unclaimed' | 'Claimed' | 'Running' | 'RetryQueued' | 'Released';
|
|
6
|
+
export interface DispatchRecord {
|
|
7
|
+
issueId: string;
|
|
8
|
+
state: OrchestrationState;
|
|
9
|
+
workspaceId: string;
|
|
10
|
+
branch: string;
|
|
11
|
+
claimedAt: string;
|
|
12
|
+
lastActivityAt: string;
|
|
13
|
+
attempts: number;
|
|
14
|
+
maxAttempts: number;
|
|
15
|
+
turnsCompleted: number;
|
|
16
|
+
pid?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface ReconciliationEvents {
|
|
19
|
+
claimed: (issueId: string) => void;
|
|
20
|
+
dispatched: (record: DispatchRecord) => void;
|
|
21
|
+
completed: (issueId: string, success: boolean) => void;
|
|
22
|
+
retryQueued: (issueId: string, attempt: number) => void;
|
|
23
|
+
released: (issueId: string) => void;
|
|
24
|
+
error: (issueId: string, error: Error) => void;
|
|
25
|
+
}
|
|
26
|
+
export declare interface ReconciliationLoop {
|
|
27
|
+
on<E extends keyof ReconciliationEvents>(event: E, listener: ReconciliationEvents[E]): this;
|
|
28
|
+
emit<E extends keyof ReconciliationEvents>(event: E, ...args: Parameters<ReconciliationEvents[E]>): boolean;
|
|
29
|
+
}
|
|
30
|
+
export declare class ReconciliationLoop extends EventEmitter {
|
|
31
|
+
private dispatchRecords;
|
|
32
|
+
private workspaceManager;
|
|
33
|
+
private tracker;
|
|
34
|
+
private policy;
|
|
35
|
+
private running;
|
|
36
|
+
private timer;
|
|
37
|
+
constructor(tracker: ITrackerAdapter, workspaceManager: WorkspaceManager, policy: OrchestratorPolicy);
|
|
38
|
+
/**
|
|
39
|
+
* Main reconciliation tick.
|
|
40
|
+
* Called on each polling interval.
|
|
41
|
+
*/
|
|
42
|
+
tick(): Promise<{
|
|
43
|
+
dispatched: number;
|
|
44
|
+
completed: number;
|
|
45
|
+
errors: number;
|
|
46
|
+
}>;
|
|
47
|
+
/**
|
|
48
|
+
* Start the polling loop.
|
|
49
|
+
*/
|
|
50
|
+
start(): void;
|
|
51
|
+
/**
|
|
52
|
+
* Stop the polling loop.
|
|
53
|
+
*/
|
|
54
|
+
stop(): void;
|
|
55
|
+
/**
|
|
56
|
+
* Get dispatch records for status display.
|
|
57
|
+
*/
|
|
58
|
+
getDispatchRecords(): DispatchRecord[];
|
|
59
|
+
/**
|
|
60
|
+
* Compute retry delay using exponential backoff.
|
|
61
|
+
* delay = min(10000 * 2^(attempt-1), max_retry_backoff_ms)
|
|
62
|
+
*/
|
|
63
|
+
computeRetryDelay(attempt: number): number;
|
|
64
|
+
private startupRecovery;
|
|
65
|
+
private preflightValidation;
|
|
66
|
+
private fetchCandidates;
|
|
67
|
+
private dispatch;
|
|
68
|
+
private reconcileRunning;
|
|
69
|
+
private completeIssue;
|
|
70
|
+
private emitCompletions;
|
|
71
|
+
}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
// SCALE Orchestrator — Reconciliation Loop
|
|
2
|
+
// 对齐 Symphony: poll → filter → isolate → dispatch → reconcile → notify → loop
|
|
3
|
+
// State machine: Unclaimed → Claimed → Running → RetryQueued → Released
|
|
4
|
+
// Startup recovery: no persistent orchestrator state — cleanup + repoll
|
|
5
|
+
import { EventEmitter } from 'node:events';
|
|
6
|
+
import { logger } from '../core/logger.js';
|
|
7
|
+
export class ReconciliationLoop extends EventEmitter {
|
|
8
|
+
constructor(tracker, workspaceManager, policy) {
|
|
9
|
+
super();
|
|
10
|
+
this.dispatchRecords = new Map();
|
|
11
|
+
this.running = false;
|
|
12
|
+
this.timer = null;
|
|
13
|
+
this.tracker = tracker;
|
|
14
|
+
this.workspaceManager = workspaceManager;
|
|
15
|
+
this.policy = policy;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Main reconciliation tick.
|
|
19
|
+
* Called on each polling interval.
|
|
20
|
+
*/
|
|
21
|
+
async tick() {
|
|
22
|
+
let dispatched = 0;
|
|
23
|
+
let completed = 0;
|
|
24
|
+
let errors = 0;
|
|
25
|
+
try {
|
|
26
|
+
// 1. Reconcile running: check status of active dispatches
|
|
27
|
+
await this.reconcileRunning();
|
|
28
|
+
// 2. Preflight validation: verify workspace safety
|
|
29
|
+
this.preflightValidation();
|
|
30
|
+
// 3. Fetch candidates from tracker
|
|
31
|
+
const candidates = await this.fetchCandidates();
|
|
32
|
+
// 4. Sort by priority
|
|
33
|
+
candidates.sort((a, b) => a.priority - b.priority);
|
|
34
|
+
// 5. Dispatch eligible candidates
|
|
35
|
+
for (const candidate of candidates) {
|
|
36
|
+
if (!this.workspaceManager.canCreate)
|
|
37
|
+
break;
|
|
38
|
+
try {
|
|
39
|
+
const dispatched_ = await this.dispatch(candidate);
|
|
40
|
+
if (dispatched_)
|
|
41
|
+
dispatched++;
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
logger.error({ err, issueId: candidate.id }, 'Dispatch failed');
|
|
45
|
+
this.emit('error', candidate.id, err);
|
|
46
|
+
errors++;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// 6. Notify: emit completion events
|
|
50
|
+
completed = this.emitCompletions();
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
logger.error({ err }, 'Reconciliation tick failed');
|
|
54
|
+
errors++;
|
|
55
|
+
}
|
|
56
|
+
return { dispatched, completed, errors };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Start the polling loop.
|
|
60
|
+
*/
|
|
61
|
+
start() {
|
|
62
|
+
if (this.running)
|
|
63
|
+
return;
|
|
64
|
+
this.running = true;
|
|
65
|
+
// Startup recovery: clean terminal workspaces + repoll
|
|
66
|
+
this.startupRecovery();
|
|
67
|
+
const interval = this.policy.polling.intervalMs;
|
|
68
|
+
logger.info({ interval }, 'Reconciliation loop started');
|
|
69
|
+
const run = async () => {
|
|
70
|
+
if (!this.running)
|
|
71
|
+
return;
|
|
72
|
+
const result = await this.tick();
|
|
73
|
+
logger.info({ ...result, active: this.workspaceManager.activeCount }, 'Reconciliation tick');
|
|
74
|
+
if (this.running)
|
|
75
|
+
this.timer = setTimeout(run, interval);
|
|
76
|
+
};
|
|
77
|
+
// First tick immediately
|
|
78
|
+
void run();
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Stop the polling loop.
|
|
82
|
+
*/
|
|
83
|
+
stop() {
|
|
84
|
+
this.running = false;
|
|
85
|
+
if (this.timer) {
|
|
86
|
+
clearTimeout(this.timer);
|
|
87
|
+
this.timer = null;
|
|
88
|
+
}
|
|
89
|
+
logger.info('Reconciliation loop stopped');
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get dispatch records for status display.
|
|
93
|
+
*/
|
|
94
|
+
getDispatchRecords() {
|
|
95
|
+
return Array.from(this.dispatchRecords.values());
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Compute retry delay using exponential backoff.
|
|
99
|
+
* delay = min(10000 * 2^(attempt-1), max_retry_backoff_ms)
|
|
100
|
+
*/
|
|
101
|
+
computeRetryDelay(attempt) {
|
|
102
|
+
const base = 10000;
|
|
103
|
+
const exponential = base * Math.pow(2, attempt - 1);
|
|
104
|
+
return Math.min(exponential, this.policy.polling.maxRetryBackoffMs);
|
|
105
|
+
}
|
|
106
|
+
// -----------------------------------------------------------------------
|
|
107
|
+
// Internal
|
|
108
|
+
// -----------------------------------------------------------------------
|
|
109
|
+
async startupRecovery() {
|
|
110
|
+
logger.info('Running startup recovery');
|
|
111
|
+
this.workspaceManager.cleanupTerminal();
|
|
112
|
+
// Re-fetch and re-dispatch any active work
|
|
113
|
+
const candidates = await this.fetchCandidates();
|
|
114
|
+
for (const c of candidates) {
|
|
115
|
+
if (!this.dispatchRecords.has(c.id) && this.workspaceManager.canCreate) {
|
|
116
|
+
await this.dispatch(c);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
preflightValidation() {
|
|
121
|
+
const workspaces = this.workspaceManager.listActive();
|
|
122
|
+
for (const ws of workspaces) {
|
|
123
|
+
const safety = this.workspaceManager.verifySafety(ws.path);
|
|
124
|
+
if (!safety.safe) {
|
|
125
|
+
logger.error({ workspace: ws.id, violations: safety.violations }, 'Workspace safety violation');
|
|
126
|
+
this.workspaceManager.updateStatus(ws.issueId, 'terminal');
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
async fetchCandidates() {
|
|
131
|
+
const allIssues = await this.tracker.fetchCandidates();
|
|
132
|
+
const activeStates = this.policy.tracker.activeStates;
|
|
133
|
+
const terminalStates = this.policy.tracker.terminalStates;
|
|
134
|
+
return allIssues.filter(issue => {
|
|
135
|
+
// Must be in active state
|
|
136
|
+
const state = issue.state;
|
|
137
|
+
if (!activeStates.includes(state))
|
|
138
|
+
return false;
|
|
139
|
+
if (terminalStates.includes(state))
|
|
140
|
+
return false;
|
|
141
|
+
// Not already dispatched (unless retryable)
|
|
142
|
+
const record = this.dispatchRecords.get(issue.id);
|
|
143
|
+
if (record) {
|
|
144
|
+
if (record.state === 'Released')
|
|
145
|
+
return false;
|
|
146
|
+
if (record.state === 'Running')
|
|
147
|
+
return false;
|
|
148
|
+
if (record.state === 'RetryQueued')
|
|
149
|
+
return record.attempts < record.maxAttempts;
|
|
150
|
+
if (record.state === 'Claimed')
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
// All blocked_by must be in terminal states
|
|
154
|
+
if (issue.blockedBy.length > 0) {
|
|
155
|
+
const allBlockersResolved = issue.blockedBy.every(blockerId => {
|
|
156
|
+
const rec = this.dispatchRecords.get(blockerId);
|
|
157
|
+
return rec?.state === 'Released';
|
|
158
|
+
});
|
|
159
|
+
if (!allBlockersResolved)
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
return true;
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
async dispatch(issue) {
|
|
166
|
+
const record = this.dispatchRecords.get(issue.id);
|
|
167
|
+
const attempt = record ? record.attempts + 1 : 1;
|
|
168
|
+
const maxAttempts = this.policy.polling.maxAttempts;
|
|
169
|
+
if (attempt > maxAttempts) {
|
|
170
|
+
logger.warn({ issueId: issue.id, attempts: attempt }, 'Max attempts exceeded');
|
|
171
|
+
await this.tracker.updateState(issue.id, 'cancelled');
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
// Claim the issue
|
|
175
|
+
await this.tracker.updateState(issue.id, 'in_progress');
|
|
176
|
+
this.emit('claimed', issue.id);
|
|
177
|
+
// Create isolated workspace
|
|
178
|
+
const result = this.workspaceManager.create(issue.id);
|
|
179
|
+
if (!result.success) {
|
|
180
|
+
logger.error({ issueId: issue.id, error: result.error }, 'Workspace creation failed');
|
|
181
|
+
await this.tracker.updateState(issue.id, 'open');
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
// Run beforeRun hook
|
|
185
|
+
this.workspaceManager.beforeRun(issue.id);
|
|
186
|
+
const dispatchRecord = {
|
|
187
|
+
issueId: issue.id,
|
|
188
|
+
state: 'Claimed',
|
|
189
|
+
workspaceId: result.path,
|
|
190
|
+
branch: result.branch,
|
|
191
|
+
claimedAt: new Date().toISOString(),
|
|
192
|
+
lastActivityAt: new Date().toISOString(),
|
|
193
|
+
attempts: attempt,
|
|
194
|
+
maxAttempts,
|
|
195
|
+
turnsCompleted: 0,
|
|
196
|
+
};
|
|
197
|
+
this.dispatchRecords.set(issue.id, dispatchRecord);
|
|
198
|
+
this.emit('dispatched', dispatchRecord);
|
|
199
|
+
// Transition to Running
|
|
200
|
+
dispatchRecord.state = 'Running';
|
|
201
|
+
this.dispatchRecords.set(issue.id, dispatchRecord);
|
|
202
|
+
logger.info({ issueId: issue.id, path: result.path, branch: result.branch, attempt }, 'Issue dispatched');
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
async reconcileRunning() {
|
|
206
|
+
for (const [id, record] of this.dispatchRecords) {
|
|
207
|
+
if (record.state !== 'Running')
|
|
208
|
+
continue;
|
|
209
|
+
// Check if agent process is still alive
|
|
210
|
+
if (record.pid) {
|
|
211
|
+
try {
|
|
212
|
+
process.kill(record.pid, 0);
|
|
213
|
+
}
|
|
214
|
+
catch { /* process gone */ }
|
|
215
|
+
}
|
|
216
|
+
// Check if turns exhausted
|
|
217
|
+
if (record.turnsCompleted >= this.policy.agent.maxTurns) {
|
|
218
|
+
await this.completeIssue(id, true);
|
|
219
|
+
}
|
|
220
|
+
// Check timeout
|
|
221
|
+
const elapsed = Date.now() - new Date(record.claimedAt).getTime();
|
|
222
|
+
if (elapsed > this.policy.agent.timeoutMinutes * 60 * 1000) {
|
|
223
|
+
logger.warn({ issueId: id, elapsed }, 'Agent timeout — queueing retry');
|
|
224
|
+
record.state = 'RetryQueued';
|
|
225
|
+
this.dispatchRecords.set(id, record);
|
|
226
|
+
this.emit('retryQueued', id, record.attempts);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
async completeIssue(issueId, success) {
|
|
231
|
+
const record = this.dispatchRecords.get(issueId);
|
|
232
|
+
if (!record)
|
|
233
|
+
return;
|
|
234
|
+
if (success) {
|
|
235
|
+
await this.tracker.updateState(issueId, 'resolved');
|
|
236
|
+
record.state = 'Released';
|
|
237
|
+
this.emit('completed', issueId, true);
|
|
238
|
+
this.emit('released', issueId);
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
if (record.attempts < record.maxAttempts) {
|
|
242
|
+
record.state = 'RetryQueued';
|
|
243
|
+
this.emit('retryQueued', issueId, record.attempts + 1);
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
await this.tracker.updateState(issueId, 'cancelled');
|
|
247
|
+
record.state = 'Released';
|
|
248
|
+
this.emit('completed', issueId, false);
|
|
249
|
+
this.emit('released', issueId);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
this.dispatchRecords.set(issueId, record);
|
|
253
|
+
this.workspaceManager.updateStatus(issueId, 'terminal');
|
|
254
|
+
this.workspaceManager.afterRun(issueId);
|
|
255
|
+
}
|
|
256
|
+
emitCompletions() {
|
|
257
|
+
let count = 0;
|
|
258
|
+
for (const [id, record] of this.dispatchRecords) {
|
|
259
|
+
if (record.state === 'Released' && this.workspaceManager.activeCount > 0) {
|
|
260
|
+
count++;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return count;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=ReconciliationLoop.js.map
|