principles-disciple 1.28.2 → 1.29.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/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/scripts/acceptance-test.mjs +314 -0
- package/scripts/seed-nocturnal-scenarios.mjs +16 -9
- package/scripts/validate-live-path.ts +141 -17
- package/src/commands/archive-impl.ts +3 -0
- package/src/commands/context.ts +4 -1
- package/src/commands/disable-impl.ts +2 -2
- package/src/commands/evolution-status.ts +2 -2
- package/src/commands/focus.ts +4 -2
- package/src/commands/nocturnal-train.ts +9 -1
- package/src/commands/pain.ts +3 -1
- package/src/commands/pd-reflect.ts +2 -0
- package/src/commands/rollback-impl.ts +5 -1
- 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 -1
- 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/empathy-keyword-matcher.ts +4 -1
- package/src/core/event-log.ts +6 -3
- package/src/core/evolution-engine.ts +4 -1
- package/src/core/evolution-logger.ts +1 -0
- package/src/core/external-training-contract.ts +2 -1
- package/src/core/focus-history.ts +15 -3
- package/src/core/init.ts +3 -1
- 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 -3
- package/src/core/nocturnal-candidate-scoring.ts +5 -0
- package/src/core/nocturnal-compliance.ts +22 -1
- package/src/core/nocturnal-dataset.ts +3 -1
- package/src/core/nocturnal-export.ts +5 -0
- package/src/core/nocturnal-reasoning-deriver.ts +6 -1
- package/src/core/nocturnal-snapshot-contract.ts +1 -0
- package/src/core/nocturnal-trinity.ts +24 -3
- package/src/core/pain-context-extractor.ts +3 -1
- package/src/core/pain.ts +3 -1
- package/src/core/path-resolver.ts +10 -4
- package/src/core/pd-task-reconciler.ts +3 -1
- package/src/core/pd-task-store.ts +1 -0
- package/src/core/principle-internalization/deprecated-readiness.ts +2 -1
- 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 -1
- package/src/core/promotion-gate.ts +7 -1
- package/src/core/replay-engine.ts +10 -4
- package/src/core/risk-calculator.ts +2 -1
- package/src/core/rule-host.ts +3 -2
- package/src/core/session-tracker.ts +5 -2
- package/src/core/shadow-observation-registry.ts +1 -0
- package/src/core/thinking-os-parser.ts +1 -0
- package/src/core/trajectory.ts +9 -5
- 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.ts +1 -0
- package/src/hooks/llm.ts +1 -0
- package/src/hooks/pain.ts +3 -1
- package/src/hooks/progressive-trust-gate.ts +3 -0
- package/src/hooks/prompt.ts +5 -2
- package/src/hooks/subagent.ts +1 -0
- package/src/hooks/thinking-checkpoint.ts +1 -0
- package/src/hooks/trajectory-collector.ts +2 -1
- package/src/http/principles-console-route.ts +5 -2
- package/src/index.ts +7 -0
- package/src/service/central-health-service.ts +1 -0
- package/src/service/central-overview-service.ts +2 -0
- package/src/service/evolution-query-service.ts +1 -0
- package/src/service/evolution-worker.ts +31 -1
- package/src/service/health-query-service.ts +6 -6
- package/src/service/monitoring-query-service.ts +4 -0
- package/src/service/nocturnal-runtime.ts +7 -5
- 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 -5
- package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +2 -1
- package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +2 -0
- package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +3 -2
- package/src/service/subagent-workflow/workflow-manager-base.ts +6 -1
- package/src/service/subagent-workflow/workflow-store.ts +2 -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 -1
- package/tests/core/nocturnal-e2e.test.ts +10 -0
- package/tests/tools/write-pain-flag.test.ts +29 -13
|
@@ -159,7 +159,7 @@ export interface TrinityStageValidationResult {
|
|
|
159
159
|
* Validate a Dreamer output contract.
|
|
160
160
|
* Ensures the output is well-formed before passing to Philosopher.
|
|
161
161
|
*/
|
|
162
|
-
|
|
162
|
+
|
|
163
163
|
export function validateDreamerOutput(output: unknown): TrinityStageValidationResult {
|
|
164
164
|
const failures: string[] = [];
|
|
165
165
|
|
|
@@ -238,7 +238,7 @@ export function validateDreamerOutput(output: unknown): TrinityStageValidationRe
|
|
|
238
238
|
* Validate a Philosopher output contract.
|
|
239
239
|
* Ensures the output is well-formed before passing to Scribe.
|
|
240
240
|
*/
|
|
241
|
-
|
|
241
|
+
|
|
242
242
|
export function validatePhilosopherOutput(output: unknown): TrinityStageValidationResult {
|
|
243
243
|
const failures: string[] = [];
|
|
244
244
|
|
|
@@ -262,7 +262,7 @@ export function validatePhilosopherOutput(output: unknown): TrinityStageValidati
|
|
|
262
262
|
failures.push('Philosopher output must have a judgments array');
|
|
263
263
|
} else {
|
|
264
264
|
// Validate each judgment
|
|
265
|
-
|
|
265
|
+
|
|
266
266
|
obj.judgments.forEach((judgment: unknown, idx: number) => {
|
|
267
267
|
if (judgment === null || judgment === undefined || typeof judgment !== 'object') {
|
|
268
268
|
failures.push(`Philosopher judgment at index ${idx} is not an object`);
|
|
@@ -694,6 +694,7 @@ export function parseAndValidateArtifact(
|
|
|
694
694
|
): ArbiterResult {
|
|
695
695
|
// Step 1: Parse JSON
|
|
696
696
|
|
|
697
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
697
698
|
let parsed: unknown;
|
|
698
699
|
try {
|
|
699
700
|
parsed = JSON.parse(jsonString);
|
|
@@ -293,6 +293,7 @@ export function validateCandidateDiversity(
|
|
|
293
293
|
|
|
294
294
|
for (let i = 0; i < candidates.length; i++) {
|
|
295
295
|
for (let j = i + 1; j < candidates.length; j++) {
|
|
296
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
296
297
|
const overlap = computeKeywordOverlap(
|
|
297
298
|
candidates[i].betterDecision ?? '',
|
|
298
299
|
candidates[j].betterDecision ?? '',
|
|
@@ -334,7 +335,9 @@ export function validateCandidateDiversity(
|
|
|
334
335
|
* Returns value between 0 and 1.
|
|
335
336
|
*/
|
|
336
337
|
function computeKeywordOverlap(textA: string, textB: string): number {
|
|
338
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
337
339
|
const wordsA = extractKeywords(textA);
|
|
340
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
338
341
|
const wordsB = extractKeywords(textB);
|
|
339
342
|
|
|
340
343
|
if (wordsA.length === 0 && wordsB.length === 0) return 0;
|
|
@@ -373,6 +376,7 @@ function extractKeywords(text: string): string[] {
|
|
|
373
376
|
* @returns All scored and ranked candidates
|
|
374
377
|
*/
|
|
375
378
|
|
|
379
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
376
380
|
export function rankCandidates(
|
|
377
381
|
candidates: DreamerCandidate[],
|
|
378
382
|
judgments: PhilosopherJudgment[],
|
|
@@ -460,6 +464,7 @@ export function rankCandidates(
|
|
|
460
464
|
* @returns Tournament result with winner
|
|
461
465
|
*/
|
|
462
466
|
|
|
467
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
463
468
|
export function runTournament(
|
|
464
469
|
candidates: DreamerCandidate[],
|
|
465
470
|
judgments: PhilosopherJudgment[],
|
|
@@ -242,22 +242,31 @@ export function detectOpportunity(principleId: string, session: SessionEvents):
|
|
|
242
242
|
|
|
243
243
|
switch (principleId) {
|
|
244
244
|
case 'T-01':
|
|
245
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
245
246
|
return detectT01Opportunity(session);
|
|
246
247
|
case 'T-02':
|
|
248
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
247
249
|
return detectT02Opportunity(session);
|
|
248
250
|
case 'T-03':
|
|
251
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
249
252
|
return detectT03Opportunity(session);
|
|
250
253
|
case 'T-04':
|
|
254
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
251
255
|
return detectT04Opportunity(session);
|
|
252
256
|
case 'T-05':
|
|
257
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
253
258
|
return detectT05Opportunity(session);
|
|
254
259
|
case 'T-06':
|
|
260
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
255
261
|
return detectT06Opportunity(session);
|
|
256
262
|
case 'T-07':
|
|
263
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
257
264
|
return detectT07Opportunity(session);
|
|
258
265
|
case 'T-08':
|
|
266
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
259
267
|
return detectT08Opportunity(session);
|
|
260
268
|
case 'T-09':
|
|
269
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
261
270
|
return detectT09Opportunity(session);
|
|
262
271
|
default:
|
|
263
272
|
return { applicable: false, reason: `Unknown principle: ${principleId}` };
|
|
@@ -513,7 +522,7 @@ function detectT09Opportunity(session: SessionEvents): OpportunityMatch {
|
|
|
513
522
|
* trigger pattern. Since P_* principles don't have T-xx specific detectors,
|
|
514
523
|
* we use the presence of negative signals as violation evidence.
|
|
515
524
|
*/
|
|
516
|
-
|
|
525
|
+
|
|
517
526
|
export function detectViolation(principleId: string, session: SessionEvents): ViolationMatch {
|
|
518
527
|
// #216: P_* principles (pain-derived) — generic violation detection
|
|
519
528
|
if (principleId.startsWith('P_')) {
|
|
@@ -541,22 +550,31 @@ export function detectViolation(principleId: string, session: SessionEvents): Vi
|
|
|
541
550
|
|
|
542
551
|
switch (principleId) {
|
|
543
552
|
case 'T-01':
|
|
553
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
544
554
|
return detectT01Violation(session);
|
|
545
555
|
case 'T-02':
|
|
556
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
546
557
|
return detectT02Violation(session);
|
|
547
558
|
case 'T-03':
|
|
559
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
548
560
|
return detectT03Violation(session);
|
|
549
561
|
case 'T-04':
|
|
562
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
550
563
|
return detectT04Violation(session);
|
|
551
564
|
case 'T-05':
|
|
565
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
552
566
|
return detectT05Violation(session);
|
|
553
567
|
case 'T-06':
|
|
568
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
554
569
|
return detectT06Violation(session);
|
|
555
570
|
case 'T-07':
|
|
571
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
556
572
|
return detectT07Violation(session);
|
|
557
573
|
case 'T-08':
|
|
574
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
558
575
|
return detectT08Violation(session);
|
|
559
576
|
case 'T-09':
|
|
577
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
560
578
|
return detectT09Violation(session);
|
|
561
579
|
default:
|
|
562
580
|
console.warn(`[PD:Compliance] Unknown principle ID: ${principleId} — treating as no violation. Check for typos (P-001 vs P_001).`);
|
|
@@ -915,9 +933,11 @@ export function computeCompliance(
|
|
|
915
933
|
: 0;
|
|
916
934
|
|
|
917
935
|
// Compute violationTrend using windows
|
|
936
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
918
937
|
const violationTrend = computeViolationTrend(applicableSessions, windowSize);
|
|
919
938
|
|
|
920
939
|
// Build explanation
|
|
940
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
921
941
|
const explanation = buildExplanation(
|
|
922
942
|
principleId,
|
|
923
943
|
applicableOpportunityCount,
|
|
@@ -989,6 +1009,7 @@ function computeViolationTrend(
|
|
|
989
1009
|
* Builds a human-readable explanation for the compliance result.
|
|
990
1010
|
*/
|
|
991
1011
|
|
|
1012
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
992
1013
|
function buildExplanation(
|
|
993
1014
|
principleId: string,
|
|
994
1015
|
applicableOpportunityCount: number,
|
|
@@ -284,6 +284,7 @@ function withRegistryLock<T>(workspaceDir: string, fn: (_records: NocturnalDatas
|
|
|
284
284
|
* @returns RegisterSampleResult
|
|
285
285
|
*/
|
|
286
286
|
|
|
287
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
287
288
|
export function registerSample(
|
|
288
289
|
workspaceDir: string,
|
|
289
290
|
artifact: NocturnalArtifact,
|
|
@@ -426,6 +427,7 @@ const VALID_TRANSITIONS: Record<NocturnalReviewStatus, NocturnalReviewStatus[]>
|
|
|
426
427
|
* @throws Error if transition is invalid
|
|
427
428
|
*/
|
|
428
429
|
|
|
430
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
429
431
|
export function updateReviewStatus(
|
|
430
432
|
workspaceDir: string,
|
|
431
433
|
sampleFingerprint: string,
|
|
@@ -645,7 +647,7 @@ export function getDatasetStats(
|
|
|
645
647
|
* @param targetModelFamily - Default target family for migrated samples
|
|
646
648
|
* @returns Number of newly registered samples
|
|
647
649
|
*/
|
|
648
|
-
|
|
650
|
+
|
|
649
651
|
export function migrateSampleArtifacts(
|
|
650
652
|
workspaceDir: string,
|
|
651
653
|
targetModelFamily: string | null = null
|
|
@@ -158,6 +158,7 @@ function computeDatasetFingerprint(sampleFingerprints: string[]): string {
|
|
|
158
158
|
* Caller guarantees record.targetModelFamily is non-null.
|
|
159
159
|
*/
|
|
160
160
|
|
|
161
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
161
162
|
function serializeORPOSample(
|
|
162
163
|
record: NocturnalDatasetRecord,
|
|
163
164
|
artifact: ReturnType<typeof readDatasetArtifact>,
|
|
@@ -166,6 +167,7 @@ function serializeORPOSample(
|
|
|
166
167
|
datasetFingerprint: string
|
|
167
168
|
): ORPOSample {
|
|
168
169
|
const now = new Date().toISOString();
|
|
170
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
169
171
|
const rejected = buildEvidenceBoundedRejected(artifact, evidenceSummary);
|
|
170
172
|
|
|
171
173
|
return {
|
|
@@ -178,6 +180,7 @@ function serializeORPOSample(
|
|
|
178
180
|
prompt: rejected,
|
|
179
181
|
chosen: artifact.betterDecision,
|
|
180
182
|
rejected,
|
|
183
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
181
184
|
rationale: buildEvidenceBoundedRationale(evidenceSummary),
|
|
182
185
|
datasetMetadata: {
|
|
183
186
|
sampleFingerprint: record.sampleFingerprint,
|
|
@@ -292,6 +295,7 @@ export function exportORPOSamples(
|
|
|
292
295
|
});
|
|
293
296
|
|
|
294
297
|
|
|
298
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
295
299
|
let eligibleRecords: typeof allApprovedRecords;
|
|
296
300
|
|
|
297
301
|
if (targetModelFamily !== undefined && targetModelFamily !== null) {
|
|
@@ -341,6 +345,7 @@ export function exportORPOSamples(
|
|
|
341
345
|
|
|
342
346
|
// Read artifact (throws on error — distinguishes read failure from missing artifact)
|
|
343
347
|
|
|
348
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
344
349
|
let artifact;
|
|
345
350
|
try {
|
|
346
351
|
artifact = readDatasetArtifact(workspaceDir, record.sampleFingerprint);
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* - deriveContextualFactors: Compute contextual factors from snapshot (Plan 02)
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
14
15
|
import type { NocturnalAssistantTurn, NocturnalToolCall, NocturnalUserTurn, NocturnalSessionSnapshot } from './nocturnal-trajectory-extractor.js';
|
|
15
16
|
import { detectThinkingModelMatches, listThinkingModels } from './thinking-models.js';
|
|
16
17
|
|
|
@@ -143,6 +144,7 @@ export function deriveReasoningChain(assistantTurns: NocturnalAssistantTurn[]):
|
|
|
143
144
|
// Without thinking tags we cannot extract a genuine reasoning trace, so
|
|
144
145
|
// we fall back to 'low' rather than misleading the downstream pipeline
|
|
145
146
|
// with activation derived from non-thinking patterns in the response text.
|
|
147
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
146
148
|
let confidenceSignal: "high" | "medium" | "low";
|
|
147
149
|
if (thinkingContent.length === 0) {
|
|
148
150
|
confidenceSignal = 'low';
|
|
@@ -211,6 +213,7 @@ export function deriveDecisionPoints(
|
|
|
211
213
|
|
|
212
214
|
// Binary search: find rightmost assistant turn with createdAt < tcTime
|
|
213
215
|
const findBeforeTurn = (tcTime: number): NocturnalAssistantTurn | undefined => {
|
|
216
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
214
217
|
let lo = 0, hi = sortedTurns.length - 1, result: NocturnalAssistantTurn | undefined;
|
|
215
218
|
while (lo <= hi) {
|
|
216
219
|
const mid = (lo + hi) >>> 1;
|
|
@@ -233,7 +236,9 @@ export function deriveDecisionPoints(
|
|
|
233
236
|
: '';
|
|
234
237
|
|
|
235
238
|
// On failure, find next assistant turn after tool call
|
|
239
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
236
240
|
let afterReflection: string | undefined;
|
|
241
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
237
242
|
let confidenceDelta: number | undefined;
|
|
238
243
|
|
|
239
244
|
if (tc.outcome === 'failure') {
|
|
@@ -280,7 +285,7 @@ export function deriveDecisionPoints(
|
|
|
280
285
|
*
|
|
281
286
|
* Empty/missing data returns all-false defaults. Never throws.
|
|
282
287
|
*/
|
|
283
|
-
|
|
288
|
+
|
|
284
289
|
export function deriveContextualFactors(
|
|
285
290
|
snapshot: NocturnalSessionSnapshot,
|
|
286
291
|
): DerivedContextualFactors {
|
|
@@ -584,6 +584,7 @@ export class OpenClawTrinityRuntimeAdapter implements TrinityRuntimeAdapter {
|
|
|
584
584
|
this.cleanupStaleTempDirs();
|
|
585
585
|
}
|
|
586
586
|
|
|
587
|
+
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
587
588
|
isRuntimeAvailable(): boolean {
|
|
588
589
|
return true;
|
|
589
590
|
}
|
|
@@ -642,7 +643,7 @@ export class OpenClawTrinityRuntimeAdapter implements TrinityRuntimeAdapter {
|
|
|
642
643
|
* runEmbeddedPiAgent does NOT read config.agents.defaults.model —
|
|
643
644
|
* it requires explicit params.provider and params.model.
|
|
644
645
|
*/
|
|
645
|
-
|
|
646
|
+
|
|
646
647
|
private resolveModel(): { provider: string; model: string } {
|
|
647
648
|
const config = this.loadFullConfig();
|
|
648
649
|
const agents = config?.agents as Record<string, unknown> | undefined;
|
|
@@ -681,6 +682,7 @@ export class OpenClawTrinityRuntimeAdapter implements TrinityRuntimeAdapter {
|
|
|
681
682
|
/**
|
|
682
683
|
* Extract text from runEmbeddedPiAgent result.
|
|
683
684
|
*/
|
|
685
|
+
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
684
686
|
private extractPayloadText(result: { payloads?: { isError?: boolean; text?: string }[] }): string {
|
|
685
687
|
return (result.payloads ?? [])
|
|
686
688
|
.filter(p => !p.isError)
|
|
@@ -690,11 +692,13 @@ export class OpenClawTrinityRuntimeAdapter implements TrinityRuntimeAdapter {
|
|
|
690
692
|
}
|
|
691
693
|
|
|
692
694
|
/** Clamp a value to [0, 1] range — used for LLM-produced scores that may be out of range */
|
|
695
|
+
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
693
696
|
private clamp01(val: unknown, fallback = 0): number {
|
|
694
697
|
if (typeof val !== 'number' || !Number.isFinite(val)) return fallback;
|
|
695
698
|
return Math.min(1, Math.max(0, val));
|
|
696
699
|
}
|
|
697
700
|
|
|
701
|
+
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
698
702
|
private classifyRuntimeError(error: unknown): TrinityRuntimeFailureCode {
|
|
699
703
|
const detail = error instanceof Error ? error.message : String(error);
|
|
700
704
|
return /timeout/i.test(detail) ? 'runtime_timeout' : 'runtime_run_failed';
|
|
@@ -742,6 +746,7 @@ export class OpenClawTrinityRuntimeAdapter implements TrinityRuntimeAdapter {
|
|
|
742
746
|
} catch (err) {
|
|
743
747
|
return this.buildRuntimeFailureDreamerOutput(this.classifyRuntimeError(err), err);
|
|
744
748
|
} finally {
|
|
749
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
745
750
|
try { fs.unlinkSync(sessionFile); } catch (err) { this.api.logger?.warn?.(`[Trinity] Failed to delete session file: ${sessionFile}`); }
|
|
746
751
|
}
|
|
747
752
|
}
|
|
@@ -786,11 +791,13 @@ export class OpenClawTrinityRuntimeAdapter implements TrinityRuntimeAdapter {
|
|
|
786
791
|
} catch (err) {
|
|
787
792
|
return this.buildRuntimeFailurePhilosopherOutput(this.classifyRuntimeError(err), err);
|
|
788
793
|
} finally {
|
|
794
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
789
795
|
try { fs.unlinkSync(sessionFile); } catch (err) { this.api.logger?.warn?.(`[Trinity] Failed to delete session file: ${sessionFile}`); }
|
|
790
796
|
}
|
|
791
797
|
}
|
|
792
798
|
|
|
793
799
|
|
|
800
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
794
801
|
async invokeScribe(
|
|
795
802
|
dreamerOutput: DreamerOutput,
|
|
796
803
|
philosopherOutput: PhilosopherOutput,
|
|
@@ -834,6 +841,7 @@ export class OpenClawTrinityRuntimeAdapter implements TrinityRuntimeAdapter {
|
|
|
834
841
|
this.recordFailure(this.classifyRuntimeError(err), err);
|
|
835
842
|
return null;
|
|
836
843
|
} finally {
|
|
844
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
837
845
|
try { fs.unlinkSync(sessionFile); } catch (err) { this.api.logger?.warn?.(`[Trinity] Failed to delete session file: ${sessionFile}`); }
|
|
838
846
|
}
|
|
839
847
|
}
|
|
@@ -857,6 +865,7 @@ export class OpenClawTrinityRuntimeAdapter implements TrinityRuntimeAdapter {
|
|
|
857
865
|
// ---------------------------------------------------------------------------
|
|
858
866
|
|
|
859
867
|
|
|
868
|
+
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
860
869
|
private buildDreamerPrompt(
|
|
861
870
|
snapshot: NocturnalSessionSnapshot,
|
|
862
871
|
principleId: string,
|
|
@@ -953,6 +962,7 @@ export class OpenClawTrinityRuntimeAdapter implements TrinityRuntimeAdapter {
|
|
|
953
962
|
}
|
|
954
963
|
|
|
955
964
|
|
|
965
|
+
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
956
966
|
private buildPhilosopherPrompt(
|
|
957
967
|
dreamerOutput: DreamerOutput,
|
|
958
968
|
principleId: string,
|
|
@@ -1035,8 +1045,10 @@ export class OpenClawTrinityRuntimeAdapter implements TrinityRuntimeAdapter {
|
|
|
1035
1045
|
|
|
1036
1046
|
return sections.join('\n');
|
|
1037
1047
|
}
|
|
1048
|
+
|
|
1038
1049
|
|
|
1039
1050
|
|
|
1051
|
+
// eslint-disable-next-line @typescript-eslint/max-params, @typescript-eslint/class-methods-use-this
|
|
1040
1052
|
private buildScribePrompt(
|
|
1041
1053
|
dreamerOutput: DreamerOutput,
|
|
1042
1054
|
philosopherOutput: PhilosopherOutput,
|
|
@@ -1245,10 +1257,12 @@ export class OpenClawTrinityRuntimeAdapter implements TrinityRuntimeAdapter {
|
|
|
1245
1257
|
falsePositiveEstimate?: number;
|
|
1246
1258
|
implementationComplexity: string;
|
|
1247
1259
|
breakingChangeRisk: boolean;
|
|
1260
|
+
|
|
1248
1261
|
} = {
|
|
1249
1262
|
implementationComplexity: (risks.implementationComplexity as string) ?? 'medium',
|
|
1250
1263
|
breakingChangeRisk: Boolean(risks.breakingChangeRisk),
|
|
1251
1264
|
};
|
|
1265
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
1252
1266
|
if (hasFp) risksObj.falsePositiveEstimate = this.clamp01(fp as number);
|
|
1253
1267
|
return { risks: risksObj };
|
|
1254
1268
|
})() : {}),
|
|
@@ -1292,6 +1306,7 @@ export class OpenClawTrinityRuntimeAdapter implements TrinityRuntimeAdapter {
|
|
|
1292
1306
|
}
|
|
1293
1307
|
|
|
1294
1308
|
|
|
1309
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
1295
1310
|
private parseScribeOutput(
|
|
1296
1311
|
text: string,
|
|
1297
1312
|
snapshot: NocturnalSessionSnapshot,
|
|
@@ -1360,6 +1375,7 @@ export class OpenClawTrinityRuntimeAdapter implements TrinityRuntimeAdapter {
|
|
|
1360
1375
|
* Extract JSON object from text that may contain markdown code blocks.
|
|
1361
1376
|
*/
|
|
1362
1377
|
|
|
1378
|
+
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
1363
1379
|
private extractJson(text: string): string | null {
|
|
1364
1380
|
// Try direct parse first
|
|
1365
1381
|
try {
|
|
@@ -1699,7 +1715,7 @@ export interface TrinityResult {
|
|
|
1699
1715
|
* In production, this would call the actual Dreamer subagent.
|
|
1700
1716
|
* The stub generates plausible candidates based on snapshot signals.
|
|
1701
1717
|
*/
|
|
1702
|
-
|
|
1718
|
+
|
|
1703
1719
|
export function invokeStubDreamer(
|
|
1704
1720
|
snapshot: NocturnalSessionSnapshot,
|
|
1705
1721
|
principleId: string,
|
|
@@ -1896,7 +1912,9 @@ export function invokeStubPhilosopher(
|
|
|
1896
1912
|
|
|
1897
1913
|
// Deterministic 6D scores based on strategic perspective (Phase 35 D-07 mapping)
|
|
1898
1914
|
const perspective = candidate.strategicPerspective;
|
|
1915
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
1899
1916
|
let sixDScores: Philosopher6DScores;
|
|
1917
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
1900
1918
|
let riskAssessment: PhilosopherRiskAssessment;
|
|
1901
1919
|
|
|
1902
1920
|
if (perspective === 'conservative_fix') {
|
|
@@ -1996,6 +2014,7 @@ export function invokeStubPhilosopher(
|
|
|
1996
2014
|
* The stub uses tournament selection (scoring + thresholds) to pick the winner.
|
|
1997
2015
|
*/
|
|
1998
2016
|
|
|
2017
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
1999
2018
|
export function invokeStubScribe(
|
|
2000
2019
|
dreamerOutput: DreamerOutput,
|
|
2001
2020
|
philosopherOutput: PhilosopherOutput,
|
|
@@ -2074,6 +2093,7 @@ export function runTrinity(options: RunTrinityOptions): TrinityResult {
|
|
|
2074
2093
|
// Stub path: use synchronous stub implementations
|
|
2075
2094
|
if (config.useStubs) {
|
|
2076
2095
|
|
|
2096
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
2077
2097
|
return runTrinityWithStubs(snapshot, principleId, config);
|
|
2078
2098
|
}
|
|
2079
2099
|
|
|
@@ -2113,6 +2133,7 @@ export async function runTrinityAsync(options: RunTrinityOptions): Promise<Trini
|
|
|
2113
2133
|
if (config.useStubs) {
|
|
2114
2134
|
// Stub path: use synchronous stubs
|
|
2115
2135
|
|
|
2136
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
2116
2137
|
return runTrinityWithStubs(snapshot, principleId, config);
|
|
2117
2138
|
}
|
|
2118
2139
|
|
|
@@ -2250,7 +2271,7 @@ export async function runTrinityAsync(options: RunTrinityOptions): Promise<Trini
|
|
|
2250
2271
|
|
|
2251
2272
|
/**
|
|
2252
2273
|
* Internal: Run Trinity chain with stub implementations (synchronous).
|
|
2253
|
-
// eslint-disable-next-line complexity -- complexity 14, refactor candidate
|
|
2274
|
+
// eslint-disable-next-line complexity, @typescript-eslint/class-methods-use-this -- complexity 14, refactor candidate
|
|
2254
2275
|
*/
|
|
2255
2276
|
function runTrinityWithStubs(
|
|
2256
2277
|
snapshot: NocturnalSessionSnapshot,
|
|
@@ -54,6 +54,7 @@ async function safeTail(filePath: string): Promise<string[]> {
|
|
|
54
54
|
try {
|
|
55
55
|
// Check existence and stats asynchronously
|
|
56
56
|
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
57
58
|
let stat: fs.Stats;
|
|
58
59
|
try {
|
|
59
60
|
stat = await fsPromises.stat(filePath);
|
|
@@ -203,7 +204,7 @@ function extractTurn(msg: ParsedMessage): string | null {
|
|
|
203
204
|
* SAFETY: Tail-only read, skip oversized lines, cap output.
|
|
204
205
|
* Returns empty string on any failure — caller should use pain reason as fallback.
|
|
205
206
|
*/
|
|
206
|
-
|
|
207
|
+
|
|
207
208
|
export async function extractRecentConversation(
|
|
208
209
|
sessionId: string,
|
|
209
210
|
agentId = 'main',
|
|
@@ -236,6 +237,7 @@ export async function extractRecentConversation(
|
|
|
236
237
|
/**
|
|
237
238
|
* Extracts failed tool call context with argument correlation.
|
|
238
239
|
*/
|
|
240
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
239
241
|
export async function extractFailedToolContext(
|
|
240
242
|
sessionId: string,
|
|
241
243
|
agentId: string,
|
package/src/core/pain.ts
CHANGED
|
@@ -98,6 +98,7 @@ export function validatePainFlag(data: Record<string, string>): string[] {
|
|
|
98
98
|
return missing;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
101
102
|
export function computePainScore(rc: number, isSpiral: boolean, missingTestCommand: boolean, softScore: number, projectDir?: string): number {
|
|
102
103
|
let score = Math.max(0, softScore || 0);
|
|
103
104
|
|
|
@@ -211,6 +212,7 @@ export function readPainFlagData(projectDir: string): Record<string, string> {
|
|
|
211
212
|
|
|
212
213
|
// Detect JSON format (wrong — should be KV)
|
|
213
214
|
if (content.startsWith('{')) {
|
|
215
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
214
216
|
let json: Record<string, unknown>;
|
|
215
217
|
try {
|
|
216
218
|
json = JSON.parse(content);
|
|
@@ -279,7 +281,7 @@ export function readPainFlagContract(projectDir: string): PainFlagContractResult
|
|
|
279
281
|
* Errors are silently ignored to avoid disrupting the pain pipeline.
|
|
280
282
|
*/
|
|
281
283
|
|
|
282
|
-
// eslint-disable-next-line
|
|
284
|
+
// eslint-disable-next-line @typescript-eslint/max-params -- complexity 12, refactor candidate
|
|
283
285
|
export function trackPrincipleValue(
|
|
284
286
|
workspaceDir: string,
|
|
285
287
|
painData: { reason?: string; source?: string; score?: string },
|
|
@@ -420,18 +420,24 @@ export function resolveWorkspaceDirFromApi(
|
|
|
420
420
|
if (!api) return undefined;
|
|
421
421
|
|
|
422
422
|
// 1. Official API: api.runtime.agent.resolveAgentWorkspaceDir
|
|
423
|
-
|
|
423
|
+
|
|
424
424
|
const officialAgent = (api.runtime as { agent?: { resolveAgentWorkspaceDir?: (cfg: unknown, id: string) => string } }).agent;
|
|
425
|
-
|
|
425
|
+
|
|
426
426
|
if (officialAgent?.resolveAgentWorkspaceDir) {
|
|
427
427
|
try {
|
|
428
428
|
return officialAgent.resolveAgentWorkspaceDir(api.config, agentId ?? 'main');
|
|
429
429
|
} catch {
|
|
430
|
-
// Fall through to
|
|
430
|
+
// Fall through to config check
|
|
431
431
|
}
|
|
432
432
|
}
|
|
433
433
|
|
|
434
|
-
// 2.
|
|
434
|
+
// 2. Direct config workspaceDir (for tests and programmatic usage)
|
|
435
|
+
const cfgWorkspaceDir = (api.config as { workspaceDir?: string })?.workspaceDir;
|
|
436
|
+
if (cfgWorkspaceDir && cfgWorkspaceDir.trim()) {
|
|
437
|
+
return cfgWorkspaceDir.trim();
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// 3. Fallback: PathResolver (PD_WORKSPACE_DIR env, config file, default)
|
|
435
441
|
try {
|
|
436
442
|
const pr = new PathResolver();
|
|
437
443
|
return pr.getWorkspaceDir();
|
|
@@ -103,7 +103,7 @@ async function writeCronStore(store: CronStoreFile): Promise<void> {
|
|
|
103
103
|
});
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
|
|
106
|
+
|
|
107
107
|
function diff(declared: PDTaskSpec[], actual: CronJob[]): DiffAction[] {
|
|
108
108
|
const actions: DiffAction[] = [];
|
|
109
109
|
const actualByName = new Map<string, CronJob>();
|
|
@@ -160,6 +160,7 @@ function buildCronJob(
|
|
|
160
160
|
payload: {
|
|
161
161
|
kind: 'agentTurn',
|
|
162
162
|
|
|
163
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
163
164
|
message: buildTaskPrompt(task, logger),
|
|
164
165
|
lightContext: task.execution.lightContext ?? true,
|
|
165
166
|
timeoutSeconds: task.execution.timeoutSeconds ?? 120,
|
|
@@ -294,6 +295,7 @@ export async function reconcilePDTasks(
|
|
|
294
295
|
|
|
295
296
|
const cronStore = await readCronStore(logger);
|
|
296
297
|
|
|
298
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
297
299
|
const healthUpdated = healthCheck(declared, cronStore, logger);
|
|
298
300
|
const actions = diff(healthUpdated, cronStore.jobs);
|
|
299
301
|
|
|
@@ -27,7 +27,7 @@ function clampScore(value: number): number {
|
|
|
27
27
|
return Math.max(0, Math.min(100, Number(value.toFixed(2))));
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
export function assessDeprecatedReadiness(
|
|
32
32
|
principle: PrincipleLifecycleEvidence,
|
|
33
33
|
precomputedRuleMetrics?: Record<string, RuleMetricResult>,
|
|
@@ -65,6 +65,7 @@ export function assessDeprecatedReadiness(
|
|
|
65
65
|
);
|
|
66
66
|
|
|
67
67
|
|
|
68
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
68
69
|
let status: DeprecatedReadinessStatus;
|
|
69
70
|
if (blockingReasons.length === 0 && stableCoverageRatio === 1) {
|
|
70
71
|
status = 'ready';
|
|
@@ -63,6 +63,7 @@ export function createDefaultPrincipleState(principleId: string): PrincipleTrain
|
|
|
63
63
|
|
|
64
64
|
export function loadStore(stateDir: string): PrincipleTrainingStore {
|
|
65
65
|
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
66
67
|
return ledgerTrainingStore(stateDir);
|
|
67
68
|
}
|
|
68
69
|
|
|
@@ -76,6 +77,7 @@ export function saveStore(stateDir: string, store: PrincipleTrainingStore): void
|
|
|
76
77
|
|
|
77
78
|
export async function loadStoreAsync(stateDir: string): Promise<PrincipleTrainingStore> {
|
|
78
79
|
|
|
80
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
79
81
|
return ledgerTrainingStore(stateDir);
|
|
80
82
|
}
|
|
81
83
|
|
|
@@ -78,6 +78,7 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
|
|
81
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
81
82
|
function clampFloat(value: unknown, min: number, max: number, fallback: number): number {
|
|
82
83
|
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
83
84
|
return fallback;
|
|
@@ -86,6 +87,7 @@ function clampFloat(value: unknown, min: number, max: number, fallback: number):
|
|
|
86
87
|
}
|
|
87
88
|
|
|
88
89
|
|
|
90
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
89
91
|
function clampInt(value: unknown, min: number, max: number, fallback: number): number {
|
|
90
92
|
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
91
93
|
return fallback;
|
|
@@ -318,6 +320,7 @@ function writeLedgerUnlocked(filePath: string, store: HybridLedgerStore): void {
|
|
|
318
320
|
|
|
319
321
|
function mutateLedger<T>(stateDir: string, mutate: (store: HybridLedgerStore) => T): T {
|
|
320
322
|
|
|
323
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
321
324
|
const filePath = getLedgerFilePath(stateDir);
|
|
322
325
|
return withLock(filePath, () => {
|
|
323
326
|
const store = readLedgerFromFile(filePath);
|
|
@@ -330,6 +333,7 @@ function mutateLedger<T>(stateDir: string, mutate: (store: HybridLedgerStore) =>
|
|
|
330
333
|
|
|
331
334
|
async function mutateLedgerAsync<T>(stateDir: string, mutate: (store: HybridLedgerStore) => Promise<T>): Promise<T> {
|
|
332
335
|
|
|
336
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
333
337
|
const filePath = getLedgerFilePath(stateDir);
|
|
334
338
|
return withLockAsync(filePath, async () => {
|
|
335
339
|
const store = readLedgerFromFile(filePath);
|
|
@@ -50,6 +50,7 @@ function trainingStateToTreePrinciple(
|
|
|
50
50
|
text: `Principle ${principleId}`, // Minimal text, will be enriched from PRINCIPLES.md if available
|
|
51
51
|
triggerPattern: '', // Unknown from legacy data
|
|
52
52
|
action: '', // Unknown from legacy data
|
|
53
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
53
54
|
status: mapInternalizationStatusToPrincipleStatus(state.internalizationStatus),
|
|
54
55
|
priority: 'P1', // Default priority
|
|
55
56
|
scope: 'general',
|
|
@@ -92,7 +93,7 @@ function mapInternalizationStatusToPrincipleStatus(
|
|
|
92
93
|
* This function is idempotent: it only migrates principles that don't exist
|
|
93
94
|
* in tree.principles yet.
|
|
94
95
|
*/
|
|
95
|
-
|
|
96
|
+
|
|
96
97
|
export function migratePrincipleTree(
|
|
97
98
|
stateDir: string,
|
|
98
99
|
workspaceDir?: string
|