@hongmaple0820/scale-engine 0.40.1 → 0.43.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.
Files changed (228) hide show
  1. package/README.md +30 -2
  2. package/dist/api/cli.js +286 -7
  3. package/dist/api/cli.js.map +1 -1
  4. package/dist/api/doctor.js +1 -1
  5. package/dist/api/doctor.js.map +1 -1
  6. package/dist/api/quickstart.d.ts +11 -0
  7. package/dist/api/quickstart.js +98 -1
  8. package/dist/api/quickstart.js.map +1 -1
  9. package/dist/artifact/fsmDefinitions.js +15 -2
  10. package/dist/artifact/fsmDefinitions.js.map +1 -1
  11. package/dist/artifact/types.d.ts +1 -1
  12. package/dist/artifact/types.js.map +1 -1
  13. package/dist/bootstrap/DependencyBootstrap.d.ts +1 -0
  14. package/dist/bootstrap/DependencyBootstrap.js +137 -25
  15. package/dist/bootstrap/DependencyBootstrap.js.map +1 -1
  16. package/dist/cache/ScanCache.d.ts +41 -0
  17. package/dist/cache/ScanCache.js +120 -0
  18. package/dist/cache/ScanCache.js.map +1 -0
  19. package/dist/capabilities/BrowserQACapability.d.ts +14 -0
  20. package/dist/capabilities/BrowserQACapability.js +94 -0
  21. package/dist/capabilities/BrowserQACapability.js.map +1 -1
  22. package/dist/capabilities/InstalledSkillsIntegration.js +29 -9
  23. package/dist/capabilities/InstalledSkillsIntegration.js.map +1 -1
  24. package/dist/cli/autofixCommands.d.ts +22 -0
  25. package/dist/cli/autofixCommands.js +32 -0
  26. package/dist/cli/autofixCommands.js.map +1 -0
  27. package/dist/cli/cortexCommands.d.ts +71 -0
  28. package/dist/cli/cortexCommands.js +335 -0
  29. package/dist/cli/cortexCommands.js.map +1 -0
  30. package/dist/cli/costCommands.d.ts +13 -0
  31. package/dist/cli/costCommands.js +48 -0
  32. package/dist/cli/costCommands.js.map +1 -0
  33. package/dist/cli/orchCommands.d.ts +43 -0
  34. package/dist/cli/orchCommands.js +135 -0
  35. package/dist/cli/orchCommands.js.map +1 -0
  36. package/dist/cli/phaseCommands.js +1 -2
  37. package/dist/cli/phaseCommands.js.map +1 -1
  38. package/dist/cli/qaCommands.d.ts +22 -0
  39. package/dist/cli/qaCommands.js +84 -0
  40. package/dist/cli/qaCommands.js.map +1 -0
  41. package/dist/cli/quickstartCommands.d.ts +17 -0
  42. package/dist/cli/quickstartCommands.js +47 -0
  43. package/dist/cli/quickstartCommands.js.map +1 -0
  44. package/dist/cli/shieldCommands.d.ts +30 -0
  45. package/dist/cli/shieldCommands.js +212 -0
  46. package/dist/cli/shieldCommands.js.map +1 -0
  47. package/dist/cli/tuiCommands.d.ts +7 -0
  48. package/dist/cli/tuiCommands.js +33 -0
  49. package/dist/cli/tuiCommands.js.map +1 -0
  50. package/dist/config/profiles.js +26 -0
  51. package/dist/config/profiles.js.map +1 -1
  52. package/dist/context/ContextBudget.js +2 -2
  53. package/dist/core/GbrainRuntime.d.ts +25 -0
  54. package/dist/core/GbrainRuntime.js +270 -0
  55. package/dist/core/GbrainRuntime.js.map +1 -0
  56. package/dist/cortex/GovernanceMetrics.d.ts +66 -0
  57. package/dist/cortex/GovernanceMetrics.js +230 -0
  58. package/dist/cortex/GovernanceMetrics.js.map +1 -0
  59. package/dist/cortex/InstinctExtractor.d.ts +61 -0
  60. package/dist/cortex/InstinctExtractor.js +184 -0
  61. package/dist/cortex/InstinctExtractor.js.map +1 -0
  62. package/dist/cortex/InstinctStore.d.ts +54 -0
  63. package/dist/cortex/InstinctStore.js +266 -0
  64. package/dist/cortex/InstinctStore.js.map +1 -0
  65. package/dist/cortex/ReflexionEngine.d.ts +34 -0
  66. package/dist/cortex/ReflexionEngine.js +157 -0
  67. package/dist/cortex/ReflexionEngine.js.map +1 -0
  68. package/dist/cortex/SessionInjector.d.ts +44 -0
  69. package/dist/cortex/SessionInjector.js +127 -0
  70. package/dist/cortex/SessionInjector.js.map +1 -0
  71. package/dist/cortex/adapters/ClaudeAdapter.d.ts +17 -0
  72. package/dist/cortex/adapters/ClaudeAdapter.js +61 -0
  73. package/dist/cortex/adapters/ClaudeAdapter.js.map +1 -0
  74. package/dist/cortex/adapters/CodexAdapter.d.ts +10 -0
  75. package/dist/cortex/adapters/CodexAdapter.js +52 -0
  76. package/dist/cortex/adapters/CodexAdapter.js.map +1 -0
  77. package/dist/cortex/adapters/CursorAdapter.d.ts +10 -0
  78. package/dist/cortex/adapters/CursorAdapter.js +46 -0
  79. package/dist/cortex/adapters/CursorAdapter.js.map +1 -0
  80. package/dist/cortex/adapters/GeminiAdapter.d.ts +11 -0
  81. package/dist/cortex/adapters/GeminiAdapter.js +48 -0
  82. package/dist/cortex/adapters/GeminiAdapter.js.map +1 -0
  83. package/dist/env/EnvironmentDoctor.js +221 -5
  84. package/dist/env/EnvironmentDoctor.js.map +1 -1
  85. package/dist/eval/BenchmarkPublisher.d.ts +25 -0
  86. package/dist/eval/BenchmarkPublisher.js +27 -0
  87. package/dist/eval/BenchmarkPublisher.js.map +1 -0
  88. package/dist/guardrails/DependencyAuditor.js +10 -1
  89. package/dist/guardrails/DependencyAuditor.js.map +1 -1
  90. package/dist/memory/MemoryProviders.js +38 -91
  91. package/dist/memory/MemoryProviders.js.map +1 -1
  92. package/dist/orchestrator/OrchestratorDaemon.d.ts +44 -0
  93. package/dist/orchestrator/OrchestratorDaemon.js +150 -0
  94. package/dist/orchestrator/OrchestratorDaemon.js.map +1 -0
  95. package/dist/orchestrator/PolicyLoader.d.ts +80 -0
  96. package/dist/orchestrator/PolicyLoader.js +229 -0
  97. package/dist/orchestrator/PolicyLoader.js.map +1 -0
  98. package/dist/orchestrator/ReconciliationLoop.d.ts +71 -0
  99. package/dist/orchestrator/ReconciliationLoop.js +266 -0
  100. package/dist/orchestrator/ReconciliationLoop.js.map +1 -0
  101. package/dist/orchestrator/TrackerAdapter.d.ts +60 -0
  102. package/dist/orchestrator/TrackerAdapter.js +147 -0
  103. package/dist/orchestrator/TrackerAdapter.js.map +1 -0
  104. package/dist/orchestrator/WorkspaceManager.d.ts +66 -0
  105. package/dist/orchestrator/WorkspaceManager.js +257 -0
  106. package/dist/orchestrator/WorkspaceManager.js.map +1 -0
  107. package/dist/qa/BrowserDaemon.d.ts +23 -0
  108. package/dist/qa/BrowserDaemon.js +79 -0
  109. package/dist/qa/BrowserDaemon.js.map +1 -0
  110. package/dist/qa/E2ETestOrchestrator.d.ts +14 -0
  111. package/dist/qa/E2ETestOrchestrator.js +19 -0
  112. package/dist/qa/E2ETestOrchestrator.js.map +1 -0
  113. package/dist/review/CrossModelReviewer.d.ts +35 -0
  114. package/dist/review/CrossModelReviewer.js +75 -0
  115. package/dist/review/CrossModelReviewer.js.map +1 -0
  116. package/dist/review/ReviewAggregator.d.ts +13 -0
  117. package/dist/review/ReviewAggregator.js +28 -0
  118. package/dist/review/ReviewAggregator.js.map +1 -0
  119. package/dist/review/reviewCommands.d.ts +15 -0
  120. package/dist/review/reviewCommands.js +24 -0
  121. package/dist/review/reviewCommands.js.map +1 -0
  122. package/dist/routing/LocalModelProvider.d.ts +11 -0
  123. package/dist/routing/LocalModelProvider.js +21 -0
  124. package/dist/routing/LocalModelProvider.js.map +1 -0
  125. package/dist/routing/ModelRouter.d.ts +12 -0
  126. package/dist/routing/ModelRouter.js +31 -4
  127. package/dist/routing/ModelRouter.js.map +1 -1
  128. package/dist/runtime/AiOsRuntime.d.ts +1 -0
  129. package/dist/runtime/AiOsRuntime.js +15 -0
  130. package/dist/runtime/AiOsRuntime.js.map +1 -1
  131. package/dist/runtime/CostAnalyzer.d.ts +53 -0
  132. package/dist/runtime/CostAnalyzer.js +160 -0
  133. package/dist/runtime/CostAnalyzer.js.map +1 -0
  134. package/dist/runtime/CostOptimizer.d.ts +11 -0
  135. package/dist/runtime/CostOptimizer.js +21 -0
  136. package/dist/runtime/CostOptimizer.js.map +1 -0
  137. package/dist/runtime/ModelUsageLedger.d.ts +53 -2
  138. package/dist/runtime/ModelUsageLedger.js +243 -39
  139. package/dist/runtime/ModelUsageLedger.js.map +1 -1
  140. package/dist/setup/SetupVerification.d.ts +42 -0
  141. package/dist/setup/SetupVerification.js +180 -0
  142. package/dist/setup/SetupVerification.js.map +1 -0
  143. package/dist/shield/PolicyCompiler.d.ts +70 -0
  144. package/dist/shield/PolicyCompiler.js +540 -0
  145. package/dist/shield/PolicyCompiler.js.map +1 -0
  146. package/dist/shield/ProtectedPaths.d.ts +39 -0
  147. package/dist/shield/ProtectedPaths.js +179 -0
  148. package/dist/shield/ProtectedPaths.js.map +1 -0
  149. package/dist/shield/ShieldProtocol.d.ts +50 -0
  150. package/dist/shield/ShieldProtocol.js +103 -0
  151. package/dist/shield/ShieldProtocol.js.map +1 -0
  152. package/dist/skills/SkillMdStandard.d.ts +33 -0
  153. package/dist/skills/SkillMdStandard.js +88 -0
  154. package/dist/skills/SkillMdStandard.js.map +1 -0
  155. package/dist/skills/SkillRegistry.d.ts +9 -1
  156. package/dist/skills/SkillRegistry.js +20 -0
  157. package/dist/skills/SkillRegistry.js.map +1 -1
  158. package/dist/skills/interop/GStackInterop.d.ts +15 -0
  159. package/dist/skills/interop/GStackInterop.js +34 -0
  160. package/dist/skills/interop/GStackInterop.js.map +1 -0
  161. package/dist/skills/interop/OMCInterop.d.ts +15 -0
  162. package/dist/skills/interop/OMCInterop.js +34 -0
  163. package/dist/skills/interop/OMCInterop.js.map +1 -0
  164. package/dist/tools/ToolCapabilityRegistry.js +10 -0
  165. package/dist/tools/ToolCapabilityRegistry.js.map +1 -1
  166. package/dist/tui/TuiDashboard.d.ts +3 -0
  167. package/dist/tui/TuiDashboard.js +120 -0
  168. package/dist/tui/TuiDashboard.js.map +1 -0
  169. package/dist/workflow/GateCatalog.d.ts +2 -0
  170. package/dist/workflow/GateCatalog.js +59 -3
  171. package/dist/workflow/GateCatalog.js.map +1 -1
  172. package/dist/workflow/GovernanceTemplatePacks.d.ts +1 -1
  173. package/dist/workflow/GovernanceTemplatePacks.js +15 -0
  174. package/dist/workflow/GovernanceTemplatePacks.js.map +1 -1
  175. package/dist/workflow/TddLoop.d.ts +2 -0
  176. package/dist/workflow/TddLoop.js +2 -0
  177. package/dist/workflow/TddLoop.js.map +1 -1
  178. package/dist/workflow/UpgradeManager.d.ts +10 -1
  179. package/dist/workflow/UpgradeManager.js +55 -0
  180. package/dist/workflow/UpgradeManager.js.map +1 -1
  181. package/dist/workflow/VerificationProfile.d.ts +8 -0
  182. package/dist/workflow/VerificationProfile.js +62 -1
  183. package/dist/workflow/VerificationProfile.js.map +1 -1
  184. package/dist/workflow/VerificationSchema.d.ts +46 -0
  185. package/dist/workflow/VerificationSchema.js +97 -0
  186. package/dist/workflow/VerificationSchema.js.map +1 -0
  187. package/dist/workflow/autofix/AutoFixEngine.d.ts +37 -0
  188. package/dist/workflow/autofix/AutoFixEngine.js +169 -0
  189. package/dist/workflow/autofix/AutoFixEngine.js.map +1 -0
  190. package/dist/workflow/execution/RalphEngine.d.ts +18 -0
  191. package/dist/workflow/execution/RalphEngine.js +22 -0
  192. package/dist/workflow/execution/RalphEngine.js.map +1 -1
  193. package/dist/workflow/gates/EnhancedGates.d.ts +74 -0
  194. package/dist/workflow/gates/EnhancedGates.js +653 -0
  195. package/dist/workflow/gates/EnhancedGates.js.map +1 -0
  196. package/dist/workflow/gates/GateSystem.d.ts +3 -0
  197. package/dist/workflow/gates/GateSystem.js +94 -1
  198. package/dist/workflow/gates/GateSystem.js.map +1 -1
  199. package/dist/workflow/types.d.ts +1 -1
  200. package/docs/README.md +3 -0
  201. package/docs/guides/DEVELOPMENT_WORKFLOW.md +28 -9
  202. package/docs/guides/GETTING_STARTED.md +19 -0
  203. package/docs/guides/MIGRATION.md +119 -0
  204. package/docs/start/quickstart.md +1 -0
  205. package/docs/workflow/GATES_AND_SCORE.md +34 -1
  206. package/docs/workflow/README.md +58 -10
  207. package/package.json +7 -18
  208. package/scripts/workflow/lib/gbrain-runtime.mjs +185 -0
  209. package/scripts/workflow/lib/report-output.mjs +107 -0
  210. package/scripts/workflow/provider-rehearsal.mjs +129 -48
  211. package/scripts/workflow/setup-smoke.mjs +142 -8
  212. package/docs/ACTIVE_SECURITY_VISUAL_GATES.md +0 -87
  213. package/docs/AI_ENGINEERING_OS_POSITIONING.md +0 -607
  214. package/docs/BACKGROUND_HUNTER.md +0 -62
  215. package/docs/CODE_INTELLIGENCE.md +0 -180
  216. package/docs/CONTEXT_BUDGET.md +0 -155
  217. package/docs/DEPENDENCY_AUDIT.md +0 -118
  218. package/docs/EVOLUTION_SHADOW_MODE.md +0 -63
  219. package/docs/GITLAB_FLOW.md +0 -125
  220. package/docs/GOVERNANCE_DASHBOARD.md +0 -85
  221. package/docs/MEMORY_BRAIN.md +0 -104
  222. package/docs/MEMORY_FABRIC.md +0 -161
  223. package/docs/RESOURCE_GOVERNANCE.md +0 -92
  224. package/docs/RUNTIME_EVIDENCE.md +0 -101
  225. package/docs/WORKFLOW_EVAL.md +0 -151
  226. package/image/wechat-public.jpg +0 -0
  227. package/image/wxPay.jpg +0 -0
  228. package/image/zfb.jpg +0 -0
@@ -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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReconciliationLoop.js","sourceRoot":"","sources":["../../src/orchestrator/ReconciliationLoop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ export type IssueState = 'open' | 'in_progress' | 'resolved' | 'closed' | 'cancelled';
2
+ export interface TrackerIssue {
3
+ id: string;
4
+ title: string;
5
+ description: string;
6
+ state: IssueState;
7
+ labels: string[];
8
+ assignee?: string;
9
+ priority: number;
10
+ createdAt: string;
11
+ updatedAt: string;
12
+ blockedBy: string[];
13
+ metadata?: Record<string, unknown>;
14
+ }
15
+ export interface TrackerConfig {
16
+ type: 'github' | 'linear' | 'jira' | 'mock';
17
+ repo?: string;
18
+ owner?: string;
19
+ token?: string;
20
+ baseUrl?: string;
21
+ projectKey?: string;
22
+ activeStates: IssueState[];
23
+ terminalStates: IssueState[];
24
+ priorityLabels: Record<string, number>;
25
+ }
26
+ export interface ITrackerAdapter {
27
+ readonly config: TrackerConfig;
28
+ /** Fetch all active candidates from the tracker */
29
+ fetchCandidates(): Promise<TrackerIssue[]>;
30
+ /** Update issue state (claim, release, resolve) */
31
+ updateState(issueId: string, state: IssueState, metadata?: Record<string, unknown>): Promise<void>;
32
+ /** Add a comment to an issue */
33
+ addComment(issueId: string, body: string): Promise<void>;
34
+ /** Check if an issue exists */
35
+ exists(issueId: string): Promise<boolean>;
36
+ /** Get a single issue by ID */
37
+ getIssue(issueId: string): Promise<TrackerIssue | null>;
38
+ }
39
+ export declare class GitHubTrackerAdapter implements ITrackerAdapter {
40
+ readonly config: TrackerConfig;
41
+ constructor(config: TrackerConfig);
42
+ fetchCandidates(): Promise<TrackerIssue[]>;
43
+ updateState(issueId: string, state: IssueState, _metadata?: Record<string, unknown>): Promise<void>;
44
+ addComment(issueId: string, body: string): Promise<void>;
45
+ exists(issueId: string): Promise<boolean>;
46
+ getIssue(issueId: string): Promise<TrackerIssue | null>;
47
+ private mapState;
48
+ private computePriority;
49
+ private extractBlockedBy;
50
+ }
51
+ export declare class MockTrackerAdapter implements ITrackerAdapter {
52
+ readonly config: TrackerConfig;
53
+ private issues;
54
+ constructor(issues?: TrackerIssue[]);
55
+ fetchCandidates(): Promise<TrackerIssue[]>;
56
+ updateState(issueId: string, state: IssueState): Promise<void>;
57
+ addComment(_issueId: string, _body: string): Promise<void>;
58
+ exists(issueId: string): Promise<boolean>;
59
+ getIssue(issueId: string): Promise<TrackerIssue | null>;
60
+ }