principles-disciple 1.28.1 → 1.28.3
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/openclaw.plugin.json +4 -4
- package/package.json +1 -1
- package/src/commands/archive-impl.ts +3 -0
- package/src/commands/context.ts +4 -0
- package/src/commands/disable-impl.ts +2 -0
- package/src/commands/evolution-status.ts +2 -0
- package/src/commands/focus.ts +4 -0
- package/src/commands/nocturnal-train.ts +9 -1
- package/src/commands/pain.ts +3 -0
- package/src/commands/pd-reflect.ts +2 -0
- package/src/commands/principle-rollback.ts +1 -0
- package/src/commands/rollback-impl.ts +5 -0
- package/src/commands/rollback.ts +2 -1
- package/src/commands/samples.ts +1 -0
- package/src/commands/workflow-debug.ts +1 -0
- package/src/core/adaptive-thresholds.ts +2 -0
- package/src/core/code-implementation-storage.ts +2 -0
- package/src/core/config.ts +1 -0
- package/src/core/diagnostician-task-store.ts +2 -0
- package/src/core/dictionary.ts +1 -0
- package/src/core/empathy-keyword-matcher.ts +4 -0
- package/src/core/event-log.ts +6 -1
- package/src/core/evolution-engine.ts +4 -0
- package/src/core/evolution-logger.ts +1 -0
- package/src/core/external-training-contract.ts +2 -0
- package/src/core/focus-history.ts +15 -0
- package/src/core/init.ts +3 -0
- package/src/core/merge-gate-audit.ts +3 -0
- package/src/core/model-deployment-registry.ts +1 -0
- package/src/core/model-training-registry.ts +1 -0
- package/src/core/nocturnal-arbiter.ts +4 -0
- package/src/core/nocturnal-candidate-scoring.ts +5 -0
- package/src/core/nocturnal-compliance.ts +22 -0
- package/src/core/nocturnal-dataset.ts +3 -0
- package/src/core/nocturnal-executability.ts +1 -0
- package/src/core/nocturnal-export.ts +5 -0
- package/src/core/nocturnal-reasoning-deriver.ts +6 -0
- package/src/core/nocturnal-rule-implementation-validator.ts +1 -0
- package/src/core/nocturnal-snapshot-contract.ts +1 -0
- package/src/core/nocturnal-trinity.ts +24 -0
- package/src/core/pain-context-extractor.ts +3 -0
- package/src/core/pain.ts +3 -0
- package/src/core/pd-task-reconciler.ts +3 -0
- package/src/core/pd-task-service.ts +1 -0
- package/src/core/pd-task-store.ts +1 -0
- package/src/core/principle-internalization/deprecated-readiness.ts +2 -0
- package/src/core/principle-internalization/principle-lifecycle-service.ts +1 -0
- package/src/core/principle-training-state.ts +2 -0
- package/src/core/principle-tree-ledger.ts +4 -0
- package/src/core/principle-tree-migration.ts +2 -0
- package/src/core/promotion-gate.ts +7 -1
- package/src/core/replay-engine.ts +10 -0
- package/src/core/risk-calculator.ts +2 -0
- package/src/core/rule-host.ts +3 -0
- package/src/core/session-tracker.ts +5 -0
- package/src/core/shadow-observation-registry.ts +1 -0
- package/src/core/thinking-models.ts +1 -0
- package/src/core/thinking-os-parser.ts +1 -0
- package/src/core/trajectory.ts +9 -1
- package/src/hooks/bash-risk.ts +2 -0
- package/src/hooks/edit-verification.ts +3 -0
- package/src/hooks/gate-block-helper.ts +3 -0
- package/src/hooks/gate.ts +8 -0
- package/src/hooks/gfi-gate.ts +2 -0
- package/src/hooks/lifecycle-routing.ts +1 -0
- package/src/hooks/lifecycle.ts +1 -0
- package/src/hooks/llm.ts +1 -0
- package/src/hooks/pain.ts +3 -0
- package/src/hooks/progressive-trust-gate.ts +3 -0
- package/src/hooks/prompt.ts +5 -1
- package/src/hooks/subagent.ts +1 -0
- package/src/hooks/thinking-checkpoint.ts +1 -0
- package/src/hooks/trajectory-collector.ts +2 -0
- package/src/http/principles-console-route.ts +5 -0
- package/src/index.ts +7 -0
- package/src/service/central-database.ts +2 -0
- package/src/service/central-health-service.ts +1 -0
- package/src/service/central-overview-service.ts +2 -0
- package/src/service/central-sync-service.ts +1 -0
- package/src/service/control-ui-query-service.ts +2 -0
- package/src/service/event-log-auditor.ts +2 -0
- package/src/service/evolution-query-service.ts +1 -0
- package/src/service/evolution-worker.ts +31 -0
- package/src/service/health-query-service.ts +6 -1
- package/src/service/monitoring-query-service.ts +4 -0
- package/src/service/nocturnal-runtime.ts +7 -1
- package/src/service/nocturnal-service.ts +21 -0
- package/src/service/nocturnal-target-selector.ts +2 -0
- package/src/service/runtime-summary-service.ts +6 -0
- package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +2 -0
- package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +2 -0
- package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +3 -0
- package/src/service/subagent-workflow/subagent-error-utils.ts +1 -0
- package/src/service/subagent-workflow/workflow-manager-base.ts +6 -0
- package/src/service/subagent-workflow/workflow-store.ts +2 -0
- package/src/tools/critique-prompt.ts +1 -0
- package/src/tools/deep-reflect.ts +9 -0
- package/src/tools/model-index.ts +1 -0
- package/src/tools/write-pain-flag.ts +1 -0
- package/src/utils/file-lock.ts +1 -0
- package/src/utils/io.ts +2 -0
|
@@ -200,6 +200,7 @@ export class CentralDatabase {
|
|
|
200
200
|
/**
|
|
201
201
|
* Sync data from a single workspace into the central database
|
|
202
202
|
*/
|
|
203
|
+
// eslint-disable-next-line complexity -- complexity 12, refactor candidate
|
|
203
204
|
syncWorkspace(workspaceName: string): number {
|
|
204
205
|
const workspace = this.workspaces.find(w => w.name === workspaceName);
|
|
205
206
|
if (!workspace) {
|
|
@@ -713,6 +714,7 @@ export class CentralDatabase {
|
|
|
713
714
|
syncEnabled: c.sync_enabled === 1,
|
|
714
715
|
}));
|
|
715
716
|
}
|
|
717
|
+
// eslint-disable-next-line complexity -- complexity 12, refactor candidate
|
|
716
718
|
|
|
717
719
|
updateWorkspaceConfig(
|
|
718
720
|
workspaceName: string,
|
|
@@ -18,6 +18,7 @@ export interface CentralHealthResponse {
|
|
|
18
18
|
*/
|
|
19
19
|
export class CentralHealthService {
|
|
20
20
|
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
21
22
|
getAllWorkspaceHealth(): CentralHealthResponse {
|
|
22
23
|
const centralDb = getCentralDatabase();
|
|
23
24
|
const workspaces: WorkspaceHealthEntry[] = [];
|
|
@@ -24,6 +24,7 @@ export class CentralOverviewService {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
27
28
|
dispose(): void {
|
|
28
29
|
// Do NOT dispose centralDb — it's a singleton shared across all requests.
|
|
29
30
|
// Individual services that open per-request connections (e.g. HealthQueryService)
|
|
@@ -61,6 +62,7 @@ export class CentralOverviewService {
|
|
|
61
62
|
|
|
62
63
|
// D-06: sampleQueue.counters from aggregated_correction_samples GROUP BY review_status
|
|
63
64
|
|
|
65
|
+
// eslint-disable-next-line no-useless-assignment
|
|
64
66
|
let sampleCounters: Record<string, number> = {};
|
|
65
67
|
try {
|
|
66
68
|
sampleCounters = this.centralDb.getSampleCountersByStatus();
|
|
@@ -18,6 +18,7 @@ let centralDb: CentralDatabase | null = null;
|
|
|
18
18
|
*/
|
|
19
19
|
const DEFAULT_SYNC_INTERVAL_MS = 5 * 60 * 1000;
|
|
20
20
|
|
|
21
|
+
// eslint-disable-next-line complexity -- complexity 12, refactor candidate
|
|
21
22
|
async function runSyncCycle(): Promise<void> {
|
|
22
23
|
if (!centralDb) {
|
|
23
24
|
logger?.warn?.('[PD:CentralSync] CentralDatabase not initialized, skipping sync');
|
|
@@ -255,6 +255,7 @@ export class ControlUiQueryService {
|
|
|
255
255
|
this.uiDb.dispose();
|
|
256
256
|
}
|
|
257
257
|
|
|
258
|
+
// eslint-disable-next-line complexity -- complexity 14, refactor candidate
|
|
258
259
|
getOverview(days = 30): OverviewResponse {
|
|
259
260
|
const stats = this.trajectory.getDataStats();
|
|
260
261
|
const regressionRows = this.uiDb.all<{
|
|
@@ -399,6 +400,7 @@ export class ControlUiQueryService {
|
|
|
399
400
|
};
|
|
400
401
|
}
|
|
401
402
|
|
|
403
|
+
// eslint-disable-next-line complexity -- complexity 13, refactor candidate
|
|
402
404
|
listSamples(filters: SampleListFilters = {}): SamplesResponse {
|
|
403
405
|
const page = Math.max(1, Number(filters.page ?? 1));
|
|
404
406
|
const pageSize = clampPageSize(filters.pageSize);
|
|
@@ -137,6 +137,7 @@ function countAllHooks(filePath: string): Record<string, number> {
|
|
|
137
137
|
* @param openclawDir - Base OpenClaw directory (e.g., ~/.openclaw)
|
|
138
138
|
* @param expectedToolHooks - Hook names that should appear in the primary workspace
|
|
139
139
|
*/
|
|
140
|
+
// eslint-disable-next-line complexity -- complexity 11, slightly over threshold
|
|
140
141
|
export async function auditEventLogs(
|
|
141
142
|
openclawDir: string,
|
|
142
143
|
expectedToolHooks: string[] = ['before_tool_call', 'after_tool_call'],
|
|
@@ -209,6 +210,7 @@ export async function auditEventLogs(
|
|
|
209
210
|
/**
|
|
210
211
|
* Format audit report for display.
|
|
211
212
|
*/
|
|
213
|
+
// eslint-disable-next-line complexity -- complexity 13, refactor candidate
|
|
212
214
|
export function formatAuditReport(report: AuditReport): string {
|
|
213
215
|
const lines: string[] = [];
|
|
214
216
|
|
|
@@ -155,6 +155,7 @@ export class EvolutionQueryService {
|
|
|
155
155
|
* 注意:不关闭 trajectory,因为它是单例由 TrajectoryRegistry 管理
|
|
156
156
|
*/
|
|
157
157
|
|
|
158
|
+
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
158
159
|
dispose(): void {
|
|
159
160
|
// EvolutionQueryService 不拥有 trajectory,所以不关闭它
|
|
160
161
|
// trajectory 是由 TrajectoryRegistry 管理的单例
|
|
@@ -427,6 +427,7 @@ export const LOCK_RETRY_DELAY_MS = 50;
|
|
|
427
427
|
export const LOCK_STALE_MS = 30_000;
|
|
428
428
|
|
|
429
429
|
|
|
430
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
430
431
|
export function createEvolutionTaskId(
|
|
431
432
|
source: string,
|
|
432
433
|
score: number,
|
|
@@ -460,6 +461,7 @@ export async function acquireQueueLock(resourcePath: string, logger: PluginLogge
|
|
|
460
461
|
}
|
|
461
462
|
|
|
462
463
|
|
|
464
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
463
465
|
async function requireQueueLock(resourcePath: string, logger: PluginLogger | { warn?: (message: string) => void; info?: (message: string) => void } | undefined, scope: string, lockSuffix: string = EVOLUTION_QUEUE_LOCK_SUFFIX): Promise<() => void> {
|
|
464
466
|
try {
|
|
465
467
|
return await acquireQueueLock(resourcePath, logger, lockSuffix);
|
|
@@ -475,6 +477,7 @@ export function extractEvolutionTaskId(task: string): string | null {
|
|
|
475
477
|
}
|
|
476
478
|
|
|
477
479
|
|
|
480
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
478
481
|
function findRecentDuplicateTask(
|
|
479
482
|
queue: EvolutionQueueItem[],
|
|
480
483
|
source: string,
|
|
@@ -483,12 +486,14 @@ function findRecentDuplicateTask(
|
|
|
483
486
|
reason?: string
|
|
484
487
|
): EvolutionQueueItem | undefined {
|
|
485
488
|
|
|
489
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
486
490
|
const key = normalizePainDedupKey(source, preview, reason);
|
|
487
491
|
return queue.find((task) => {
|
|
488
492
|
if (task.status === 'completed') return false;
|
|
489
493
|
const taskTime = new Date(task.enqueued_at || task.timestamp).getTime();
|
|
490
494
|
if (!Number.isFinite(taskTime) || (now - taskTime) > PAIN_QUEUE_DEDUP_WINDOW_MS) return false;
|
|
491
495
|
|
|
496
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
492
497
|
return normalizePainDedupKey(task.source, task.trigger_text_preview || '', task.reason) === key;
|
|
493
498
|
});
|
|
494
499
|
}
|
|
@@ -542,6 +547,7 @@ function normalizePainDedupKey(source: string, preview: string, reason?: string)
|
|
|
542
547
|
}
|
|
543
548
|
|
|
544
549
|
|
|
550
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
545
551
|
export function hasRecentDuplicateTask(queue: EvolutionQueueItem[], source: string, preview: string, now: number, reason?: string): boolean {
|
|
546
552
|
return !!findRecentDuplicateTask(queue, source, preview, now, reason);
|
|
547
553
|
}
|
|
@@ -657,6 +663,7 @@ function shouldSkipForDedup(
|
|
|
657
663
|
const recentSimilarReflection = hasRecentSimilarReflection(queue, painSourceKey, now);
|
|
658
664
|
|
|
659
665
|
if (recentSimilarReflection) {
|
|
666
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
660
667
|
const completedTime = new Date(recentSimilarReflection.completed_at!).getTime();
|
|
661
668
|
logger?.debug?.(`[PD:EvolutionWorker] Skipping sleep_reflection — similar reflection completed ${Math.round((now - completedTime) / 60000)}min ago (same pain pattern: ${painSourceKey})`);
|
|
662
669
|
return true;
|
|
@@ -668,6 +675,7 @@ function shouldSkipForDedup(
|
|
|
668
675
|
* Load and migrate the evolution queue. Returns empty array if file doesn't exist.
|
|
669
676
|
*/
|
|
670
677
|
function loadEvolutionQueue(queuePath: string): EvolutionQueueItem[] {
|
|
678
|
+
// eslint-disable-next-line no-useless-assignment
|
|
671
679
|
let rawQueue: RawQueueItem[] = [];
|
|
672
680
|
try {
|
|
673
681
|
rawQueue = JSON.parse(fs.readFileSync(queuePath, 'utf8'));
|
|
@@ -681,6 +689,7 @@ function loadEvolutionQueue(queuePath: string): EvolutionQueueItem[] {
|
|
|
681
689
|
/**
|
|
682
690
|
* Build and persist a new sleep_reflection task.
|
|
683
691
|
*/
|
|
692
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
684
693
|
function enqueueNewSleepReflectionTask(
|
|
685
694
|
queue: EvolutionQueueItem[],
|
|
686
695
|
recentPainContext: ReturnType<typeof readRecentPainContext>,
|
|
@@ -752,6 +761,7 @@ interface ParsedPainValues {
|
|
|
752
761
|
}
|
|
753
762
|
|
|
754
763
|
|
|
764
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
755
765
|
async function doEnqueuePainTask(
|
|
756
766
|
wctx: WorkspaceContext, logger: PluginLogger, painFlagPath: string,
|
|
757
767
|
result: WorkerStatusReport['pain_flag'], v: ParsedPainValues,
|
|
@@ -998,6 +1008,7 @@ async function checkPainFlag(wctx: WorkspaceContext, logger: PluginLogger): Prom
|
|
|
998
1008
|
}
|
|
999
1009
|
|
|
1000
1010
|
|
|
1011
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
1001
1012
|
async function processEvolutionQueue(wctx: WorkspaceContext, logger: PluginLogger, eventLog: EventLog, api?: OpenClawPluginApi) {
|
|
1002
1013
|
const queuePath = wctx.resolve('EVOLUTION_QUEUE');
|
|
1003
1014
|
if (!fs.existsSync(queuePath)) {
|
|
@@ -1595,10 +1606,13 @@ async function processEvolutionQueue(wctx: WorkspaceContext, logger: PluginLogge
|
|
|
1595
1606
|
logger?.info?.(`[PD:EvolutionWorker] Processing sleep_reflection task ${sleepTask.id}`);
|
|
1596
1607
|
}
|
|
1597
1608
|
|
|
1609
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
1598
1610
|
let workflowId: string | undefined;
|
|
1599
1611
|
|
|
1612
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
1600
1613
|
let nocturnalManager: NocturnalWorkflowManager;
|
|
1601
1614
|
|
|
1615
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
1602
1616
|
let snapshotData: NocturnalSessionSnapshot | undefined;
|
|
1603
1617
|
|
|
1604
1618
|
if (isPollingTask) {
|
|
@@ -1636,11 +1650,13 @@ async function processEvolutionQueue(wctx: WorkspaceContext, logger: PluginLogge
|
|
|
1636
1650
|
s => s.failureCount > 0 || s.painEventCount > 0 || s.gateBlockCount > 0
|
|
1637
1651
|
);
|
|
1638
1652
|
if (sessionsWithViolations.length > 0) {
|
|
1653
|
+
// eslint-disable-next-line @typescript-eslint/prefer-destructuring
|
|
1639
1654
|
const targetSession = sessionsWithViolations[0];
|
|
1640
1655
|
logger?.info?.(`[PD:EvolutionWorker] Task ${sleepTask.id} using session with violations: ${targetSession.sessionId} (failed=${targetSession.failureCount}, pain=${targetSession.painEventCount}, gates=${targetSession.gateBlockCount})`);
|
|
1641
1656
|
fullSnapshot = extractor.getNocturnalSessionSnapshot(targetSession.sessionId);
|
|
1642
1657
|
} else if (recentSessions.length > 0) {
|
|
1643
1658
|
// No sessions with violations, use most recent as last resort
|
|
1659
|
+
// eslint-disable-next-line @typescript-eslint/prefer-destructuring
|
|
1644
1660
|
const latestSession = recentSessions[0];
|
|
1645
1661
|
logger?.warn?.(`[PD:EvolutionWorker] Task ${sleepTask.id} no sessions with violations found, using most recent: ${latestSession.sessionId} (failed=${latestSession.failureCount}, pain=${latestSession.painEventCount}, gates=${latestSession.gateBlockCount})`);
|
|
1646
1662
|
fullSnapshot = extractor.getNocturnalSessionSnapshot(latestSession.sessionId);
|
|
@@ -1707,6 +1723,7 @@ async function processEvolutionQueue(wctx: WorkspaceContext, logger: PluginLogge
|
|
|
1707
1723
|
},
|
|
1708
1724
|
});
|
|
1709
1725
|
sleepTask.resultRef = workflowHandle.workflowId;
|
|
1726
|
+
// eslint-disable-next-line @typescript-eslint/prefer-destructuring
|
|
1710
1727
|
workflowId = workflowHandle.workflowId;
|
|
1711
1728
|
}
|
|
1712
1729
|
|
|
@@ -1739,13 +1756,20 @@ async function processEvolutionQueue(wctx: WorkspaceContext, logger: PluginLogge
|
|
|
1739
1756
|
const errorReason = lastEvent?.reason ?? 'unknown';
|
|
1740
1757
|
// #219: Include payload details for better diagnostics
|
|
1741
1758
|
let detailedError = `Workflow terminal_error: ${errorReason}`;
|
|
1759
|
+
|
|
1742
1760
|
let payload: unknown = {};
|
|
1761
|
+
|
|
1743
1762
|
try {
|
|
1744
1763
|
payload = lastEvent?.payload ?? {};
|
|
1764
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1745
1765
|
if ((payload as any).skipReason) {
|
|
1766
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1746
1767
|
detailedError += ` (skipReason: ${(payload as any).skipReason})`;
|
|
1768
|
+
|
|
1747
1769
|
}
|
|
1770
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1748
1771
|
if ((payload as any).failures && Array.isArray((payload as any).failures) && (payload as any).failures.length > 0) {
|
|
1772
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1749
1773
|
detailedError += ` | failures: ${((payload as any).failures as string[]).slice(0, 3).join(', ')}`;
|
|
1750
1774
|
}
|
|
1751
1775
|
} catch { /* ignore parse errors */ }
|
|
@@ -1755,9 +1779,12 @@ async function processEvolutionQueue(wctx: WorkspaceContext, logger: PluginLogge
|
|
|
1755
1779
|
if (isExpectedSubagentError(errorReason)) {
|
|
1756
1780
|
// #237: Expected unavailability → stub fallback, not hard failure
|
|
1757
1781
|
sleepTask.status = 'completed';
|
|
1782
|
+
|
|
1758
1783
|
sleepTask.completed_at = new Date().toISOString();
|
|
1759
1784
|
sleepTask.resolution = 'stub_fallback';
|
|
1785
|
+
|
|
1760
1786
|
logger?.warn?.(`[PD:EvolutionWorker] sleep_reflection task ${sleepTask.id} background runtime unavailable, using stub fallback: ${errorReason}`);
|
|
1787
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1761
1788
|
} else if ((payload as any).skipReason === 'no_violating_sessions') {
|
|
1762
1789
|
// #244: No meaningful violations found (thin filter) → skip without failure
|
|
1763
1790
|
sleepTask.status = 'completed';
|
|
@@ -1873,6 +1900,7 @@ async function processEvolutionQueue(wctx: WorkspaceContext, logger: PluginLogge
|
|
|
1873
1900
|
}
|
|
1874
1901
|
}
|
|
1875
1902
|
|
|
1903
|
+
|
|
1876
1904
|
async function processDetectionQueue(wctx: WorkspaceContext, api: OpenClawPluginApi, eventLog: EventLog) {
|
|
1877
1905
|
const {logger} = api;
|
|
1878
1906
|
try {
|
|
@@ -1928,6 +1956,7 @@ async function processDetectionQueue(wctx: WorkspaceContext, api: OpenClawPlugin
|
|
|
1928
1956
|
// Evolution queue is now the single active pain→principle path
|
|
1929
1957
|
|
|
1930
1958
|
|
|
1959
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
1931
1960
|
export async function registerEvolutionTaskSession(
|
|
1932
1961
|
workspaceResolve: (key: string) => string,
|
|
1933
1962
|
taskId: string,
|
|
@@ -1941,6 +1970,7 @@ export async function registerEvolutionTaskSession(
|
|
|
1941
1970
|
|
|
1942
1971
|
try {
|
|
1943
1972
|
|
|
1973
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
1944
1974
|
let rawQueue: RawQueueItem[];
|
|
1945
1975
|
try {
|
|
1946
1976
|
rawQueue = JSON.parse(fs.readFileSync(queuePath, 'utf8'));
|
|
@@ -2008,6 +2038,7 @@ function writeWorkerStatus(stateDir: string, report: WorkerStatusReport): void {
|
|
|
2008
2038
|
}
|
|
2009
2039
|
|
|
2010
2040
|
|
|
2041
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
2011
2042
|
async function processEvolutionQueueWithResult(
|
|
2012
2043
|
wctx: WorkspaceContext,
|
|
2013
2044
|
logger: PluginLogger,
|
|
@@ -337,6 +337,7 @@ export class HealthQueryService {
|
|
|
337
337
|
}));
|
|
338
338
|
}
|
|
339
339
|
|
|
340
|
+
|
|
340
341
|
getGateStats(): {
|
|
341
342
|
today: {
|
|
342
343
|
gfiBlocks: number;
|
|
@@ -658,6 +659,7 @@ export class HealthQueryService {
|
|
|
658
659
|
return null;
|
|
659
660
|
}
|
|
660
661
|
|
|
662
|
+
|
|
661
663
|
private readNocturnalTraining(): {
|
|
662
664
|
queue: { pending: number; inProgress: number; completed: number };
|
|
663
665
|
trinityRecords: { artifactId: string; status: string; createdAt: string }[];
|
|
@@ -785,7 +787,8 @@ export class HealthQueryService {
|
|
|
785
787
|
}
|
|
786
788
|
|
|
787
789
|
|
|
788
|
-
|
|
790
|
+
|
|
791
|
+
// eslint-disable-next-line @typescript-eslint/class-methods-use-this -- complexity 15, refactor candidate
|
|
789
792
|
private getEventDedupKey(entry: EventLogEntry): string {
|
|
790
793
|
const eventId = typeof entry.data?.eventId === 'string' ? entry.data.eventId : null;
|
|
791
794
|
if (eventId) {
|
|
@@ -856,6 +859,7 @@ export class HealthQueryService {
|
|
|
856
859
|
}
|
|
857
860
|
|
|
858
861
|
|
|
862
|
+
|
|
859
863
|
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
860
864
|
private resolveGateType(row: GateBlockRow): string {
|
|
861
865
|
if (typeof row.gate_type === 'string' && row.gate_type.trim().length > 0) {
|
|
@@ -990,6 +994,7 @@ export class HealthQueryService {
|
|
|
990
994
|
* Read the most recent session JSON file from disk.
|
|
991
995
|
* Used to sync GFI from session-tracker's persistence into SQLite.
|
|
992
996
|
*/
|
|
997
|
+
|
|
993
998
|
private readLatestSessionFromFile(): SessionState | null {
|
|
994
999
|
const sessionsDir = path.join(this.stateDir, 'sessions');
|
|
995
1000
|
if (!fs.existsSync(sessionsDir)) {
|
|
@@ -36,6 +36,7 @@ export class MonitoringQueryService {
|
|
|
36
36
|
const now = Date.now();
|
|
37
37
|
const workflowsWithStuckDetection = workflows.map(wf => {
|
|
38
38
|
// Parse metadata for timeout configuration
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
39
40
|
const metadata = parseWorkflowMetadata(wf.metadata_json);
|
|
40
41
|
const timeoutMs = metadata.timeoutMs ?? 15 * 60 * 1000; // Default 15 minutes
|
|
41
42
|
|
|
@@ -84,8 +85,10 @@ export class MonitoringQueryService {
|
|
|
84
85
|
|
|
85
86
|
// Determine status
|
|
86
87
|
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
87
89
|
let status: 'pending' | 'running' | 'completed' | 'failed';
|
|
88
90
|
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
89
92
|
let reason: string | undefined;
|
|
90
93
|
|
|
91
94
|
if (!startEvent) {
|
|
@@ -107,6 +110,7 @@ export class MonitoringQueryService {
|
|
|
107
110
|
|
|
108
111
|
// Calculate duration if stage started and completed/failed
|
|
109
112
|
|
|
113
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
110
114
|
let duration: number | undefined;
|
|
111
115
|
if (startEvent && (completeEvent || failedEvent)) {
|
|
112
116
|
const endEvent = completeEvent || failedEvent;
|
|
@@ -40,6 +40,7 @@ import { withLockAsync } from '../utils/file-lock.js';
|
|
|
40
40
|
* Excluded (NOT system sessions):
|
|
41
41
|
* - User sessions like agent:main:feishu:user:xxx — third component is channel type
|
|
42
42
|
*/
|
|
43
|
+
|
|
43
44
|
function isSystemSession(state: SessionState): boolean {
|
|
44
45
|
const { sessionId, sessionKey, trigger } = state;
|
|
45
46
|
|
|
@@ -269,6 +270,7 @@ async function writeState(stateDir: string, state: NocturnalRuntimeState): Promi
|
|
|
269
270
|
* @param trajectoryLastActivityAt - Optional trajectory timestamp as secondary guardrail
|
|
270
271
|
* @returns IdleCheckResult with full diagnostic information
|
|
271
272
|
*/
|
|
273
|
+
|
|
272
274
|
export function checkWorkspaceIdle(
|
|
273
275
|
workspaceDir: string,
|
|
274
276
|
options: {
|
|
@@ -319,6 +321,7 @@ export function checkWorkspaceIdle(
|
|
|
319
321
|
}
|
|
320
322
|
|
|
321
323
|
|
|
324
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
322
325
|
let reason: string;
|
|
323
326
|
if (mostRecentActivityAt === 0) {
|
|
324
327
|
reason = 'No active sessions found — workspace is idle';
|
|
@@ -355,6 +358,7 @@ export function checkWorkspaceIdle(
|
|
|
355
358
|
* @param options - Cooldown configuration options
|
|
356
359
|
* @returns CooldownCheckResult
|
|
357
360
|
*/
|
|
361
|
+
|
|
358
362
|
export function checkCooldown(
|
|
359
363
|
stateDir: string,
|
|
360
364
|
principleId?: string,
|
|
@@ -366,7 +370,7 @@ export function checkCooldown(
|
|
|
366
370
|
} = {}
|
|
367
371
|
): CooldownCheckResult {
|
|
368
372
|
const {
|
|
369
|
-
|
|
373
|
+
|
|
370
374
|
globalCooldownMs: _globalCooldownMs = DEFAULT_GLOBAL_COOLDOWN_MS,
|
|
371
375
|
principleCooldownMs: _principleCooldownMs = DEFAULT_PRINCIPLE_COOLDOWN_MS,
|
|
372
376
|
maxRunsPerWindow = DEFAULT_MAX_RUNS_PER_WINDOW,
|
|
@@ -386,6 +390,7 @@ export function checkCooldown(
|
|
|
386
390
|
if (cooldownEnd > now) {
|
|
387
391
|
globalCooldownActive = true;
|
|
388
392
|
globalCooldownRemainingMs = cooldownEnd - now;
|
|
393
|
+
// eslint-disable-next-line @typescript-eslint/prefer-destructuring
|
|
389
394
|
globalCooldownUntil = state.globalCooldownUntil;
|
|
390
395
|
}
|
|
391
396
|
}
|
|
@@ -555,6 +560,7 @@ export interface PreflightCheckResult {
|
|
|
555
560
|
* @param idleCheckOverride - Optional override for idle check result (for testing)
|
|
556
561
|
*/
|
|
557
562
|
|
|
563
|
+
// eslint-disable-next-line @typescript-eslint/max-params -- complexity 12, refactor candidate
|
|
558
564
|
export function checkPreflight(
|
|
559
565
|
workspaceDir: string,
|
|
560
566
|
stateDir: string,
|
|
@@ -289,12 +289,16 @@ function invokeStubReflector(
|
|
|
289
289
|
const hasPain = snapshot.stats.totalPainEvents > 0;
|
|
290
290
|
const hasFailures = (snapshot.stats.failureCount ?? 0) > 0;
|
|
291
291
|
|
|
292
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
292
293
|
let badDecision: string;
|
|
294
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
293
295
|
let betterDecision: string;
|
|
296
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
294
297
|
let rationale: string;
|
|
295
298
|
|
|
296
299
|
if (hasGateBlocks && snapshot.gateBlocks.length > 0) {
|
|
297
300
|
// Use actual gate block content
|
|
301
|
+
// eslint-disable-next-line @typescript-eslint/prefer-destructuring
|
|
298
302
|
const block = snapshot.gateBlocks[0];
|
|
299
303
|
const tool = block.toolName ?? 'a tool';
|
|
300
304
|
const file = block.filePath ? ` on ${block.filePath}` : '';
|
|
@@ -303,6 +307,7 @@ function invokeStubReflector(
|
|
|
303
307
|
rationale = `Gate blocks exist for a reason — bypassing them without understanding the underlying constraint risks unintended consequences. The block on ${tool}${file} indicates the operation exceeded allowed thresholds for the current evolution tier.`;
|
|
304
308
|
} else if (hasPain && snapshot.painEvents.length > 0) {
|
|
305
309
|
// Use actual pain event content
|
|
310
|
+
// eslint-disable-next-line @typescript-eslint/prefer-destructuring
|
|
306
311
|
const pain = snapshot.painEvents[0];
|
|
307
312
|
const painSource = pain.source ?? 'unknown';
|
|
308
313
|
const painReason = pain.reason ? `: ${pain.reason}` : '';
|
|
@@ -398,6 +403,7 @@ function buildGateBlockRefs(snapshot: NocturnalSessionSnapshot): string[] {
|
|
|
398
403
|
}
|
|
399
404
|
|
|
400
405
|
|
|
406
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
401
407
|
function buildDefaultArtificerOutput(
|
|
402
408
|
ruleId: string,
|
|
403
409
|
artifact: NocturnalArtifact,
|
|
@@ -447,6 +453,7 @@ function buildDefaultArtificerOutput(
|
|
|
447
453
|
}
|
|
448
454
|
|
|
449
455
|
|
|
456
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
450
457
|
function persistCodeCandidate(
|
|
451
458
|
workspaceDir: string,
|
|
452
459
|
stateDir: string,
|
|
@@ -543,6 +550,7 @@ function persistCodeCandidate(
|
|
|
543
550
|
}
|
|
544
551
|
|
|
545
552
|
|
|
553
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
546
554
|
function maybePersistArtificerCandidate(
|
|
547
555
|
workspaceDir: string,
|
|
548
556
|
stateDir: string,
|
|
@@ -784,9 +792,11 @@ export function executeNocturnalReflection(
|
|
|
784
792
|
// Step 5: Artifact generation (Trinity or single-reflector)
|
|
785
793
|
// -------------------------------------------------------------------------
|
|
786
794
|
|
|
795
|
+
// eslint-disable-next-line no-useless-assignment
|
|
787
796
|
let trinityArtifact: TrinityDraftArtifact | null = null;
|
|
788
797
|
let trinityResult: TrinityResult | null = null;
|
|
789
798
|
|
|
799
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
790
800
|
let rawJson: string;
|
|
791
801
|
|
|
792
802
|
if (options.skipReflector) {
|
|
@@ -1011,6 +1021,7 @@ export function executeNocturnalReflection(
|
|
|
1011
1021
|
};
|
|
1012
1022
|
|
|
1013
1023
|
|
|
1024
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
1014
1025
|
let persistedPath: string;
|
|
1015
1026
|
try {
|
|
1016
1027
|
persistedPath = persistArtifact(workspaceDir, artifactWithBoundedAction);
|
|
@@ -1138,6 +1149,7 @@ export async function executeNocturnalReflectionAsync(
|
|
|
1138
1149
|
// If runtime adapter is provided, use async Trinity path
|
|
1139
1150
|
if (options.runtimeAdapter) {
|
|
1140
1151
|
|
|
1152
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
1141
1153
|
return executeNocturnalReflectionWithAdapter(workspaceDir, stateDir, options);
|
|
1142
1154
|
}
|
|
1143
1155
|
|
|
@@ -1188,10 +1200,13 @@ async function executeNocturnalReflectionWithAdapter(
|
|
|
1188
1200
|
|
|
1189
1201
|
// Step 2: Target selection (or use override to skip)
|
|
1190
1202
|
|
|
1203
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
1191
1204
|
let selectedPrincipleId: string | undefined;
|
|
1192
1205
|
|
|
1206
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
1193
1207
|
let selectedSessionId: string | undefined;
|
|
1194
1208
|
|
|
1209
|
+
// eslint-disable-next-line no-useless-assignment
|
|
1195
1210
|
let snapshot: NocturnalSessionSnapshot | null = null;
|
|
1196
1211
|
|
|
1197
1212
|
if (options.principleIdOverride && options.snapshotOverride) {
|
|
@@ -1214,6 +1229,7 @@ async function executeNocturnalReflectionWithAdapter(
|
|
|
1214
1229
|
// Skip Selector: use provided principleId and snapshot directly
|
|
1215
1230
|
selectedPrincipleId = options.principleIdOverride;
|
|
1216
1231
|
selectedSessionId = snapshotValidation.snapshot.sessionId;
|
|
1232
|
+
// eslint-disable-next-line @typescript-eslint/prefer-destructuring
|
|
1217
1233
|
snapshot = snapshotValidation.snapshot;
|
|
1218
1234
|
// Calculate violation density from snapshot stats for meaningful diagnostics
|
|
1219
1235
|
const snapStats = snapshotValidation.snapshot.stats;
|
|
@@ -1270,8 +1286,10 @@ async function executeNocturnalReflectionWithAdapter(
|
|
|
1270
1286
|
}
|
|
1271
1287
|
|
|
1272
1288
|
|
|
1289
|
+
// eslint-disable-next-line @typescript-eslint/prefer-destructuring
|
|
1273
1290
|
selectedPrincipleId = selection.selectedPrincipleId;
|
|
1274
1291
|
|
|
1292
|
+
// eslint-disable-next-line @typescript-eslint/prefer-destructuring
|
|
1275
1293
|
selectedSessionId = selection.selectedSessionId;
|
|
1276
1294
|
|
|
1277
1295
|
if (!selectedPrincipleId || !selectedSessionId) {
|
|
@@ -1305,9 +1323,11 @@ async function executeNocturnalReflectionWithAdapter(
|
|
|
1305
1323
|
|
|
1306
1324
|
// Step 4: Trinity execution via adapter (async)
|
|
1307
1325
|
|
|
1326
|
+
// eslint-disable-next-line no-useless-assignment
|
|
1308
1327
|
let trinityArtifact: TrinityDraftArtifact | null = null;
|
|
1309
1328
|
let trinityResult: TrinityResult | null = null;
|
|
1310
1329
|
|
|
1330
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
1311
1331
|
let rawJson: string;
|
|
1312
1332
|
|
|
1313
1333
|
if (options.skipReflector) {
|
|
@@ -1414,6 +1434,7 @@ async function executeNocturnalReflectionWithAdapter(
|
|
|
1414
1434
|
// Step 7: Persist artifact
|
|
1415
1435
|
const artifactWithBoundedAction = { ...arbiterResult.artifact, boundedAction: execResult.boundedAction };
|
|
1416
1436
|
|
|
1437
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
1417
1438
|
let persistedPath: string;
|
|
1418
1439
|
try {
|
|
1419
1440
|
persistedPath = persistArtifact(workspaceDir, artifactWithBoundedAction);
|
|
@@ -287,6 +287,7 @@ export class NocturnalTargetSelector {
|
|
|
287
287
|
};
|
|
288
288
|
|
|
289
289
|
|
|
290
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
290
291
|
constructor(
|
|
291
292
|
workspaceDir: string,
|
|
292
293
|
stateDir: string,
|
|
@@ -528,6 +529,7 @@ export class NocturnalTargetSelector {
|
|
|
528
529
|
* This is a convenience wrapper for the common case.
|
|
529
530
|
*/
|
|
530
531
|
|
|
532
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
531
533
|
export function selectNocturnalTarget(
|
|
532
534
|
workspaceDir: string,
|
|
533
535
|
stateDir: string,
|
|
@@ -362,6 +362,7 @@ export class RuntimeSummaryService {
|
|
|
362
362
|
return { session: sessions[0], reason: 'latest_active' };
|
|
363
363
|
}
|
|
364
364
|
|
|
365
|
+
|
|
365
366
|
private static mergeSessionSnapshots(
|
|
366
367
|
persistedSessions: PersistedSessionState[],
|
|
367
368
|
workspaceDir: string
|
|
@@ -419,6 +420,7 @@ export class RuntimeSummaryService {
|
|
|
419
420
|
* Queue is the only authoritative execution truth source.
|
|
420
421
|
*/
|
|
421
422
|
|
|
423
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
422
424
|
private static buildDirectiveSummary(
|
|
423
425
|
queue: QueueItem[] | null,
|
|
424
426
|
directive: DirectiveFile | null,
|
|
@@ -510,7 +512,9 @@ export class RuntimeSummaryService {
|
|
|
510
512
|
})
|
|
511
513
|
.slice(-MAX_SOURCE_EVENTS)
|
|
512
514
|
.reverse();
|
|
515
|
+
|
|
513
516
|
|
|
517
|
+
|
|
514
518
|
return filtered.map((entry) => {
|
|
515
519
|
if (entry.type === 'pain_signal') {
|
|
516
520
|
return {
|
|
@@ -581,6 +585,7 @@ export class RuntimeSummaryService {
|
|
|
581
585
|
return [...merged.values()].sort((a, b) => (a.ts || '').localeCompare(b.ts || ''));
|
|
582
586
|
}
|
|
583
587
|
|
|
588
|
+
|
|
584
589
|
private static getEventDedupKey(entry: EventLogEntry): string {
|
|
585
590
|
const eventId = typeof entry.data?.eventId === 'string' ? entry.data.eventId : null;
|
|
586
591
|
if (eventId) {
|
|
@@ -637,6 +642,7 @@ export class RuntimeSummaryService {
|
|
|
637
642
|
return candidate ? new Date(candidate).getTime() : NaN;
|
|
638
643
|
}
|
|
639
644
|
|
|
645
|
+
|
|
640
646
|
private static buildDirectiveTaskPreview(item: QueueItem): string {
|
|
641
647
|
const task = typeof item.task === 'string' ? item.task.trim() : '';
|
|
642
648
|
if (task && task.toLowerCase() !== 'undefined') {
|
|
@@ -70,6 +70,7 @@ export class DeepReflectWorkflowManager extends WorkflowManagerBase {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
|
|
73
|
+
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
73
74
|
protected override generateWorkflowId(): string {
|
|
74
75
|
return `wf_dr_${Date.now()}_${Math.random().toString(36).substring(2, 10)}`;
|
|
75
76
|
}
|
|
@@ -150,6 +151,7 @@ export const deepReflectWorkflowSpec: SubagentWorkflowSpec<DeepReflectResult> =
|
|
|
150
151
|
};
|
|
151
152
|
},
|
|
152
153
|
|
|
154
|
+
|
|
153
155
|
async persistResult(ctx: WorkflowPersistContext<DeepReflectResult>): Promise<void> {
|
|
154
156
|
const { result, metadata, workspaceDir } = ctx;
|
|
155
157
|
|
|
@@ -71,6 +71,7 @@ export class EmpathyObserverWorkflowManager extends WorkflowManagerBase {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
|
|
74
|
+
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
74
75
|
protected override createWorkflowMetadata<TResult>(
|
|
75
76
|
spec: SubagentWorkflowSpec<TResult>,
|
|
76
77
|
options: {
|
|
@@ -104,6 +105,7 @@ export class EmpathyObserverWorkflowManager extends WorkflowManagerBase {
|
|
|
104
105
|
}
|
|
105
106
|
|
|
106
107
|
|
|
108
|
+
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
107
109
|
protected override generateWorkflowId(): string {
|
|
108
110
|
return `wf_${Date.now()}_${Math.random().toString(36).substring(2, 10)}`;
|
|
109
111
|
}
|
|
@@ -243,6 +243,7 @@ export class NocturnalWorkflowManager implements WorkflowManager {
|
|
|
243
243
|
// #213: Wrap fire-and-forget Promise with .catch() to prevent
|
|
244
244
|
// unhandled promise rejections if anything throws outside the try-catch
|
|
245
245
|
// (e.g., during parameter construction or environment errors).
|
|
246
|
+
|
|
246
247
|
Promise.resolve().then(async () => {
|
|
247
248
|
try {
|
|
248
249
|
const result = await executeNocturnalReflectionAsync(
|
|
@@ -371,6 +372,7 @@ export class NocturnalWorkflowManager implements WorkflowManager {
|
|
|
371
372
|
}
|
|
372
373
|
|
|
373
374
|
|
|
375
|
+
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
374
376
|
async notifyLifecycleEvent(
|
|
375
377
|
|
|
376
378
|
_workflowId: string,
|
|
@@ -651,6 +653,7 @@ export class NocturnalWorkflowManager implements WorkflowManager {
|
|
|
651
653
|
* Derives stage events from TrinityResult.telemetry and TrinityResult.failures.
|
|
652
654
|
* Always records _start event for each stage that ran, plus _complete or _failed based on outcome.
|
|
653
655
|
*/
|
|
656
|
+
|
|
654
657
|
private recordStageEvents(workflowId: string, result: TrinityResult): void {
|
|
655
658
|
const { telemetry, failures } = result;
|
|
656
659
|
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Callers should suppress warnings for these errors — they are not real failures.
|
|
7
7
|
*/
|
|
8
|
+
// eslint-disable-next-line complexity -- complexity 13, refactor candidate
|
|
8
9
|
export function isExpectedSubagentError(err: unknown): boolean {
|
|
9
10
|
const msg = String(err);
|
|
10
11
|
return (
|