principles-disciple 1.41.0 → 1.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.
- package/.planning/codebase/ARCHITECTURE.md +157 -0
- package/.planning/codebase/CONCERNS.md +145 -0
- package/.planning/codebase/CONVENTIONS.md +148 -0
- package/.planning/codebase/INTEGRATIONS.md +81 -0
- package/.planning/codebase/STACK.md +87 -0
- package/.planning/codebase/STRUCTURE.md +193 -0
- package/.planning/codebase/TESTING.md +243 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/src/commands/archive-impl.ts +5 -3
- package/src/commands/context.ts +1 -0
- package/src/commands/disable-impl.ts +1 -1
- package/src/commands/evolution-status.ts +2 -2
- package/src/commands/pain.ts +12 -5
- package/src/commands/principle-rollback.ts +1 -1
- package/src/commands/promote-impl.ts +13 -7
- package/src/commands/rollback.ts +10 -4
- package/src/commands/samples.ts +1 -1
- package/src/commands/thinking-os.ts +1 -0
- package/src/commands/workflow-debug.ts +1 -1
- package/src/core/config.ts +1 -0
- package/src/core/dictionary.ts +1 -0
- package/src/core/event-log.ts +8 -6
- package/src/core/evolution-types.ts +33 -1
- package/src/core/external-training-contract.ts +1 -1
- package/src/core/merge-gate-audit.ts +3 -3
- package/src/core/nocturnal-arbiter.ts +1 -1
- package/src/core/nocturnal-compliance.ts +21 -21
- package/src/core/nocturnal-executability.ts +1 -1
- package/src/core/nocturnal-reasoning-deriver.ts +4 -4
- package/src/core/nocturnal-rule-implementation-validator.ts +1 -1
- package/src/core/nocturnal-snapshot-contract.ts +1 -1
- package/src/core/pain-context-extractor.ts +2 -2
- package/src/core/path-resolver.ts +1 -0
- package/src/core/pd-task-reconciler.ts +1 -0
- package/src/core/pd-task-service.ts +1 -1
- package/src/core/pd-task-store.ts +1 -0
- package/src/core/principle-internalization/deprecated-readiness.ts +1 -1
- package/src/core/principle-internalization/principle-lifecycle-service.ts +1 -1
- package/src/core/principle-training-state.ts +2 -2
- package/src/core/principle-tree-migration.ts +1 -1
- package/src/core/replay-engine.ts +1 -0
- package/src/core/risk-calculator.ts +2 -1
- package/src/core/rule-host.ts +1 -1
- package/src/core/session-tracker.ts +1 -0
- package/src/core/shadow-observation-registry.ts +1 -1
- package/src/core/thinking-models.ts +1 -1
- package/src/core/thinking-os-parser.ts +1 -1
- package/src/core/trajectory.ts +2 -0
- package/src/hooks/bash-risk.ts +2 -2
- package/src/hooks/edit-verification.ts +3 -3
- package/src/hooks/gate.ts +8 -8
- package/src/hooks/gfi-gate.ts +2 -2
- package/src/hooks/lifecycle-routing.ts +1 -1
- package/src/hooks/message-sanitize.ts +18 -5
- package/src/hooks/pain.ts +2 -2
- package/src/hooks/progressive-trust-gate.ts +3 -3
- package/src/hooks/prompt.ts +17 -4
- package/src/hooks/subagent.ts +2 -3
- package/src/hooks/thinking-checkpoint.ts +1 -1
- package/src/http/principles-console-route.ts +21 -4
- package/src/service/central-database.ts +3 -2
- package/src/service/central-health-service.ts +2 -1
- package/src/service/central-overview-service.ts +3 -2
- package/src/service/control-ui-query-service.ts +2 -2
- package/src/service/event-log-auditor.ts +2 -2
- package/src/service/evolution-query-service.ts +1 -1
- package/src/service/evolution-worker.ts +96 -370
- package/src/service/health-query-service.ts +11 -10
- package/src/service/monitoring-query-service.ts +4 -4
- package/src/service/nocturnal-target-selector.ts +2 -2
- package/src/service/queue-io.ts +375 -0
- package/src/service/queue-migration.ts +122 -0
- package/src/service/runtime-summary-service.ts +1 -1
- package/src/service/sleep-cycle.ts +157 -0
- package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +1 -0
- package/src/service/subagent-workflow/runtime-direct-driver.ts +1 -1
- package/src/service/subagent-workflow/subagent-error-utils.ts +1 -1
- package/src/service/subagent-workflow/workflow-store.ts +3 -2
- package/src/service/workflow-watchdog.ts +168 -0
- package/src/tools/critique-prompt.ts +1 -1
- package/src/tools/deep-reflect.ts +22 -11
- package/src/tools/model-index.ts +1 -1
- package/src/types/event-payload.ts +80 -0
- package/src/types/queue.ts +70 -0
- package/src/utils/file-lock.ts +2 -2
- package/src/utils/io.ts +11 -3
- package/tests/core/evolution-migration.test.ts +325 -1
- package/tests/core/queue-purge.test.ts +337 -0
- package/tests/fixtures/legacy-queue-v1.json +74 -0
- package/tests/queue/async-lock.test.ts +200 -0
- package/tests/service/evolution-worker.queue.test.ts +296 -0
- package/tests/service/queue-io.test.ts +229 -0
- package/tests/service/queue-migration.test.ts +147 -0
- package/tests/service/workflow-watchdog.test.ts +372 -0
package/src/core/config.ts
CHANGED
package/src/core/dictionary.ts
CHANGED
package/src/core/event-log.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
|
|
1
2
|
import * as fs from 'fs';
|
|
2
3
|
import * as path from 'path';
|
|
3
4
|
import type {
|
|
@@ -94,7 +95,7 @@ export class EventLog {
|
|
|
94
95
|
/**
|
|
95
96
|
* Clean up event files older than EVENT_LOG_RETENTION_DAYS.
|
|
96
97
|
*/
|
|
97
|
-
private cleanupOldEventFiles(
|
|
98
|
+
private cleanupOldEventFiles(_today: string): void {
|
|
98
99
|
if (EVENT_LOG_RETENTION_DAYS <= 0) return;
|
|
99
100
|
|
|
100
101
|
try {
|
|
@@ -110,8 +111,8 @@ export class EventLog {
|
|
|
110
111
|
fs.unlinkSync(filePath);
|
|
111
112
|
}
|
|
112
113
|
}
|
|
113
|
-
} catch {
|
|
114
|
-
|
|
114
|
+
} catch (err) {
|
|
115
|
+
this.logger?.debug?.(`[PD] Event file cleanup failed (non-blocking): ${String(err)}`);
|
|
115
116
|
}
|
|
116
117
|
}
|
|
117
118
|
|
|
@@ -220,6 +221,7 @@ export class EventLog {
|
|
|
220
221
|
}
|
|
221
222
|
}
|
|
222
223
|
|
|
224
|
+
|
|
223
225
|
private updateStats(entry: EventLogEntry): void {
|
|
224
226
|
let stats = this.statsCache.get(entry.date);
|
|
225
227
|
if (!stats) {
|
|
@@ -228,8 +230,6 @@ export class EventLog {
|
|
|
228
230
|
}
|
|
229
231
|
|
|
230
232
|
if (entry.type === 'tool_call') {
|
|
231
|
-
|
|
232
|
-
const _data = entry.data as unknown as ToolCallEventData;
|
|
233
233
|
stats.tools.total++;
|
|
234
234
|
if (entry.category === 'success') stats.tools.success++;
|
|
235
235
|
else stats.tools.failure++;
|
|
@@ -349,7 +349,8 @@ export class EventLog {
|
|
|
349
349
|
.map((line) => {
|
|
350
350
|
try {
|
|
351
351
|
return JSON.parse(line) as EventLogEntry;
|
|
352
|
-
} catch {
|
|
352
|
+
} catch (err) {
|
|
353
|
+
this.logger?.warn?.(`[PD] Corrupted event line skipped: ${String(err).slice(0, 100)}`);
|
|
353
354
|
return null;
|
|
354
355
|
}
|
|
355
356
|
})
|
|
@@ -499,6 +500,7 @@ export class EventLog {
|
|
|
499
500
|
/**
|
|
500
501
|
* Aggregate empathy stats for a specific session.
|
|
501
502
|
*/
|
|
503
|
+
|
|
502
504
|
private aggregateSessionEmpathy(sessionId: string, result: EmpathyEventStats): void {
|
|
503
505
|
for (const entry of this.getMergedEvents()) {
|
|
504
506
|
if (entry.sessionId === sessionId && entry.type === 'pain_signal') {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Evolution Points System V2.0 - MVP
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Core Philosophy: Growth-driven替代Penalty-driven
|
|
5
5
|
* - 起点0分,只能增加,不扣分
|
|
6
6
|
* - 失败记录教训,不扣分
|
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
* - 5级成长路径:Seed → Forest
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
// V2 queue types require TaskKind/TaskPriority from trajectory-types
|
|
12
|
+
import type { TaskKind, TaskPriority } from './trajectory-types.js';
|
|
13
|
+
|
|
11
14
|
// ===== 等级定义 =====
|
|
12
15
|
|
|
13
16
|
|
|
@@ -464,3 +467,32 @@ export type EvolutionLoopEvent =
|
|
|
464
467
|
| { ts: string; type: 'principle_rolled_back'; data: PrincipleRolledBackData }
|
|
465
468
|
| { ts: string; type: 'circuit_breaker_opened'; data: CircuitBreakerOpenedData }
|
|
466
469
|
| { ts: string; type: 'legacy_import'; data: LegacyImportData };
|
|
470
|
+
|
|
471
|
+
// V2 Queue Types (moved from evolution-worker.ts for shared use)
|
|
472
|
+
export type QueueStatus = 'pending' | 'in_progress' | 'completed' | 'failed' | 'canceled';
|
|
473
|
+
export type TaskResolution = 'marker_detected' | 'auto_completed_timeout' | 'failed_max_retries' | 'runtime_unavailable' | 'canceled' | 'late_marker_principle_created' | 'late_marker_no_principle' | 'stub_fallback' | 'skipped_thin_violation' | 'success' | 'failure' | 'skipped';
|
|
474
|
+
|
|
475
|
+
export interface EvolutionQueueItem {
|
|
476
|
+
id: string;
|
|
477
|
+
taskKind: TaskKind;
|
|
478
|
+
priority: TaskPriority;
|
|
479
|
+
source: string;
|
|
480
|
+
traceId?: string;
|
|
481
|
+
task?: string;
|
|
482
|
+
score: number;
|
|
483
|
+
reason: string;
|
|
484
|
+
timestamp: string;
|
|
485
|
+
enqueued_at?: string;
|
|
486
|
+
started_at?: string;
|
|
487
|
+
completed_at?: string;
|
|
488
|
+
assigned_session_key?: string;
|
|
489
|
+
trigger_text_preview?: string;
|
|
490
|
+
status: QueueStatus;
|
|
491
|
+
resolution?: TaskResolution;
|
|
492
|
+
session_id?: string;
|
|
493
|
+
agent_id?: string;
|
|
494
|
+
retryCount: number;
|
|
495
|
+
maxRetries: number;
|
|
496
|
+
lastError?: string;
|
|
497
|
+
resultRef?: string;
|
|
498
|
+
}
|
|
@@ -405,7 +405,7 @@ export function computeConfigFingerprint(config: Partial<TrainingHyperparameters
|
|
|
405
405
|
*/
|
|
406
406
|
export function computeDatasetFingerprint(exportPath: string, sampleCount: number): string {
|
|
407
407
|
|
|
408
|
-
|
|
408
|
+
|
|
409
409
|
let contentHash: string;
|
|
410
410
|
try {
|
|
411
411
|
const content = fs.readFileSync(exportPath, 'utf-8');
|
|
@@ -342,7 +342,7 @@ function hasValidEvidenceSummary(parsed: unknown): boolean {
|
|
|
342
342
|
* Validate a single replay report file and return its category.
|
|
343
343
|
*/
|
|
344
344
|
function validateSingleReplayReport(reportPath: string): ReplayValidationCategory {
|
|
345
|
-
|
|
345
|
+
|
|
346
346
|
let rawContent: string;
|
|
347
347
|
try {
|
|
348
348
|
rawContent = fs.readFileSync(reportPath, 'utf-8');
|
|
@@ -350,7 +350,7 @@ function validateSingleReplayReport(reportPath: string): ReplayValidationCategor
|
|
|
350
350
|
return 'io_error';
|
|
351
351
|
}
|
|
352
352
|
|
|
353
|
-
|
|
353
|
+
|
|
354
354
|
let parsed: unknown;
|
|
355
355
|
try {
|
|
356
356
|
parsed = JSON.parse(rawContent);
|
|
@@ -366,7 +366,7 @@ function validateSingleReplayReport(reportPath: string): ReplayValidationCategor
|
|
|
366
366
|
return 'missing_evidence_summary';
|
|
367
367
|
}
|
|
368
368
|
|
|
369
|
-
|
|
369
|
+
|
|
370
370
|
const evidenceSummary = parsed.evidenceSummary;
|
|
371
371
|
if (parsed.overallDecision === 'pass' && evidenceSummary.totalSamples === 0) {
|
|
372
372
|
return 'unsupported_pass';
|
|
@@ -242,31 +242,31 @@ export function detectOpportunity(principleId: string, session: SessionEvents):
|
|
|
242
242
|
|
|
243
243
|
switch (principleId) {
|
|
244
244
|
case 'T-01':
|
|
245
|
-
|
|
245
|
+
|
|
246
246
|
return detectT01Opportunity(session);
|
|
247
247
|
case 'T-02':
|
|
248
|
-
|
|
248
|
+
|
|
249
249
|
return detectT02Opportunity(session);
|
|
250
250
|
case 'T-03':
|
|
251
|
-
|
|
251
|
+
|
|
252
252
|
return detectT03Opportunity(session);
|
|
253
253
|
case 'T-04':
|
|
254
|
-
|
|
254
|
+
|
|
255
255
|
return detectT04Opportunity(session);
|
|
256
256
|
case 'T-05':
|
|
257
|
-
|
|
257
|
+
|
|
258
258
|
return detectT05Opportunity(session);
|
|
259
259
|
case 'T-06':
|
|
260
|
-
|
|
260
|
+
|
|
261
261
|
return detectT06Opportunity(session);
|
|
262
262
|
case 'T-07':
|
|
263
|
-
|
|
263
|
+
|
|
264
264
|
return detectT07Opportunity(session);
|
|
265
265
|
case 'T-08':
|
|
266
|
-
|
|
266
|
+
|
|
267
267
|
return detectT08Opportunity(session);
|
|
268
268
|
case 'T-09':
|
|
269
|
-
|
|
269
|
+
|
|
270
270
|
return detectT09Opportunity(session);
|
|
271
271
|
default:
|
|
272
272
|
return { applicable: false, reason: `Unknown principle: ${principleId}` };
|
|
@@ -550,31 +550,31 @@ export function detectViolation(principleId: string, session: SessionEvents): Vi
|
|
|
550
550
|
|
|
551
551
|
switch (principleId) {
|
|
552
552
|
case 'T-01':
|
|
553
|
-
|
|
553
|
+
|
|
554
554
|
return detectT01Violation(session);
|
|
555
555
|
case 'T-02':
|
|
556
|
-
|
|
556
|
+
|
|
557
557
|
return detectT02Violation(session);
|
|
558
558
|
case 'T-03':
|
|
559
|
-
|
|
559
|
+
|
|
560
560
|
return detectT03Violation(session);
|
|
561
561
|
case 'T-04':
|
|
562
|
-
|
|
562
|
+
|
|
563
563
|
return detectT04Violation(session);
|
|
564
564
|
case 'T-05':
|
|
565
|
-
|
|
565
|
+
|
|
566
566
|
return detectT05Violation(session);
|
|
567
567
|
case 'T-06':
|
|
568
|
-
|
|
568
|
+
|
|
569
569
|
return detectT06Violation(session);
|
|
570
570
|
case 'T-07':
|
|
571
|
-
|
|
571
|
+
|
|
572
572
|
return detectT07Violation(session);
|
|
573
573
|
case 'T-08':
|
|
574
|
-
|
|
574
|
+
|
|
575
575
|
return detectT08Violation(session);
|
|
576
576
|
case 'T-09':
|
|
577
|
-
|
|
577
|
+
|
|
578
578
|
return detectT09Violation(session);
|
|
579
579
|
default:
|
|
580
580
|
console.warn(`[PD:Compliance] Unknown principle ID: ${principleId} — treating as no violation. Check for typos (P-001 vs P_001).`);
|
|
@@ -933,11 +933,11 @@ export function computeCompliance(
|
|
|
933
933
|
: 0;
|
|
934
934
|
|
|
935
935
|
// Compute violationTrend using windows
|
|
936
|
-
|
|
936
|
+
|
|
937
937
|
const violationTrend = computeViolationTrend(applicableSessions, windowSize);
|
|
938
938
|
|
|
939
939
|
// Build explanation
|
|
940
|
-
|
|
940
|
+
|
|
941
941
|
const explanation = buildExplanation(
|
|
942
942
|
principleId,
|
|
943
943
|
applicableOpportunityCount,
|
|
@@ -1009,7 +1009,7 @@ function computeViolationTrend(
|
|
|
1009
1009
|
* Builds a human-readable explanation for the compliance result.
|
|
1010
1010
|
*/
|
|
1011
1011
|
|
|
1012
|
-
|
|
1012
|
+
|
|
1013
1013
|
function buildExplanation(
|
|
1014
1014
|
principleId: string,
|
|
1015
1015
|
applicableOpportunityCount: number,
|
|
@@ -278,7 +278,7 @@ function isTooGeneric(text: string): boolean {
|
|
|
278
278
|
* @param artifact - The validated artifact from arbiter (passed = true)
|
|
279
279
|
* @returns ExecutabilityResult
|
|
280
280
|
*/
|
|
281
|
-
|
|
281
|
+
|
|
282
282
|
export function validateExecutability(artifact: {
|
|
283
283
|
badDecision: string;
|
|
284
284
|
betterDecision: string;
|
|
@@ -144,7 +144,7 @@ export function deriveReasoningChain(assistantTurns: NocturnalAssistantTurn[]):
|
|
|
144
144
|
// Without thinking tags we cannot extract a genuine reasoning trace, so
|
|
145
145
|
// we fall back to 'low' rather than misleading the downstream pipeline
|
|
146
146
|
// with activation derived from non-thinking patterns in the response text.
|
|
147
|
-
|
|
147
|
+
|
|
148
148
|
let confidenceSignal: "high" | "medium" | "low";
|
|
149
149
|
if (thinkingContent.length === 0) {
|
|
150
150
|
confidenceSignal = 'low';
|
|
@@ -213,7 +213,7 @@ export function deriveDecisionPoints(
|
|
|
213
213
|
|
|
214
214
|
// Binary search: find rightmost assistant turn with createdAt < tcTime
|
|
215
215
|
const findBeforeTurn = (tcTime: number): NocturnalAssistantTurn | undefined => {
|
|
216
|
-
|
|
216
|
+
|
|
217
217
|
let lo = 0, hi = sortedTurns.length - 1, result: NocturnalAssistantTurn | undefined;
|
|
218
218
|
while (lo <= hi) {
|
|
219
219
|
const mid = (lo + hi) >>> 1;
|
|
@@ -236,9 +236,9 @@ export function deriveDecisionPoints(
|
|
|
236
236
|
: '';
|
|
237
237
|
|
|
238
238
|
// On failure, find next assistant turn after tool call
|
|
239
|
-
|
|
239
|
+
|
|
240
240
|
let afterReflection: string | undefined;
|
|
241
|
-
|
|
241
|
+
|
|
242
242
|
let confidenceDelta: number | undefined;
|
|
243
243
|
|
|
244
244
|
if (tc.outcome === 'failure') {
|
|
@@ -85,7 +85,7 @@ function extractHelperUsage(sourceCode: string): string[] {
|
|
|
85
85
|
);
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
|
|
89
89
|
function validateMeta(meta: unknown): RuleImplementationValidationFailure[] {
|
|
90
90
|
if (!meta || typeof meta !== 'object') {
|
|
91
91
|
return [
|
|
@@ -54,7 +54,7 @@ async function safeTail(filePath: string): Promise<string[]> {
|
|
|
54
54
|
try {
|
|
55
55
|
// Check existence and stats asynchronously
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
let stat: fs.Stats;
|
|
59
59
|
try {
|
|
60
60
|
stat = await fsPromises.stat(filePath);
|
|
@@ -237,7 +237,7 @@ export async function extractRecentConversation(
|
|
|
237
237
|
/**
|
|
238
238
|
* Extracts failed tool call context with argument correlation.
|
|
239
239
|
*/
|
|
240
|
-
|
|
240
|
+
|
|
241
241
|
export async function extractFailedToolContext(
|
|
242
242
|
sessionId: string,
|
|
243
243
|
agentId: string,
|
|
@@ -4,7 +4,7 @@ import { reconcilePDTasks } from './pd-task-reconciler.js';
|
|
|
4
4
|
export const PDTaskService: OpenClawPluginService = {
|
|
5
5
|
id: 'principles-disciple-task-manager',
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
|
|
8
8
|
async start(ctx: OpenClawPluginServiceContext): Promise<void> {
|
|
9
9
|
const {workspaceDir} = ctx;
|
|
10
10
|
if (!workspaceDir) {
|
|
@@ -38,7 +38,7 @@ export interface PrincipleLifecycleAssessment {
|
|
|
38
38
|
routeRecommendation: InternalizationRouteRecommendation;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
|
|
42
42
|
function createValueMetrics(
|
|
43
43
|
principle: PrincipleLifecycleEvidence,
|
|
44
44
|
adherence: PrincipleAdherenceResult,
|
|
@@ -63,7 +63,7 @@ export function createDefaultPrincipleState(principleId: string): PrincipleTrain
|
|
|
63
63
|
|
|
64
64
|
export function loadStore(stateDir: string): PrincipleTrainingStore {
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
|
|
67
67
|
return ledgerTrainingStore(stateDir);
|
|
68
68
|
}
|
|
69
69
|
|
|
@@ -77,7 +77,7 @@ export function saveStore(stateDir: string, store: PrincipleTrainingStore): void
|
|
|
77
77
|
|
|
78
78
|
export async function loadStoreAsync(stateDir: string): Promise<PrincipleTrainingStore> {
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
|
|
81
81
|
return ledgerTrainingStore(stateDir);
|
|
82
82
|
}
|
|
83
83
|
|
|
@@ -50,7 +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
|
-
|
|
53
|
+
|
|
54
54
|
status: mapInternalizationStatusToPrincipleStatus(state.internalizationStatus),
|
|
55
55
|
priority: 'P1', // Default priority
|
|
56
56
|
scope: 'general',
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
|
|
1
2
|
/* global NodeJS */
|
|
2
3
|
import * as fs from 'fs';
|
|
3
4
|
import { isRisky } from '../utils/io.js';
|
|
@@ -95,7 +96,7 @@ export function getTargetFileLineCount(absoluteFilePath: string): number | null
|
|
|
95
96
|
* @returns Maximum allowed lines (at least minLines, at most maxLines if provided)
|
|
96
97
|
*/
|
|
97
98
|
|
|
98
|
-
|
|
99
|
+
|
|
99
100
|
export function calculatePercentageThreshold(
|
|
100
101
|
targetLineCount: number,
|
|
101
102
|
percentage: number,
|
package/src/core/rule-host.ts
CHANGED
|
@@ -202,7 +202,7 @@ let _cachedWorkspace: string | null = null;
|
|
|
202
202
|
*
|
|
203
203
|
* @param workspaceDir Optional. If provided, loads from that workspace's THINKING_OS.md.
|
|
204
204
|
*/
|
|
205
|
-
|
|
205
|
+
|
|
206
206
|
export function listThinkingModels(workspaceDir?: string): ThinkingModelDefinition[] {
|
|
207
207
|
const cacheKey = workspaceDir ?? '__global__';
|
|
208
208
|
if (_cachedDefinitions && _cachedWorkspace === cacheKey) {
|
|
@@ -45,7 +45,7 @@ export function parseThinkingOsMd(content: string): ThinkingOsDirective[] {
|
|
|
45
45
|
// Match all <directive ...> ... </directive> blocks
|
|
46
46
|
const directiveRegex = /<directive\s+([^>]*)>([\s\S]*?)<\/directive>/gi;
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
|
|
49
49
|
let _match: RegExpExecArray | null = null;
|
|
50
50
|
|
|
51
51
|
while ((_match = directiveRegex.exec(content)) !== null) {
|
package/src/core/trajectory.ts
CHANGED
package/src/hooks/bash-risk.ts
CHANGED
|
@@ -39,7 +39,7 @@ export type BashRiskLevel = 'safe' | 'dangerous' | 'normal';
|
|
|
39
39
|
* @returns The risk level: 'safe', 'dangerous', or 'normal'
|
|
40
40
|
*/
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
export function analyzeBashCommand(
|
|
44
44
|
command: string,
|
|
45
45
|
safePatterns: string[],
|
|
@@ -154,7 +154,7 @@ export interface DynamicThresholdConfig {
|
|
|
154
154
|
* @param config - Configuration with large_change_lines and ep_tier_multipliers
|
|
155
155
|
* @returns The adjusted threshold (minimum 0)
|
|
156
156
|
*/
|
|
157
|
-
|
|
157
|
+
|
|
158
158
|
export function calculateDynamicThreshold(
|
|
159
159
|
baseThreshold: number,
|
|
160
160
|
epTier: number,
|
|
@@ -127,7 +127,7 @@ This is enforced by P-03 (精确匹配前验证原则).`;
|
|
|
127
127
|
* This enforces P-03 at the tool layer
|
|
128
128
|
*/
|
|
129
129
|
|
|
130
|
-
|
|
130
|
+
|
|
131
131
|
export function handleEditVerification(
|
|
132
132
|
event: PluginHookBeforeToolCallEvent,
|
|
133
133
|
wctx: WorkspaceContext,
|
|
@@ -157,7 +157,7 @@ export function handleEditVerification(
|
|
|
157
157
|
|
|
158
158
|
// 2. Resolve and read file
|
|
159
159
|
|
|
160
|
-
|
|
160
|
+
|
|
161
161
|
let absolutePath: string;
|
|
162
162
|
try {
|
|
163
163
|
absolutePath = wctx.resolve(filePath);
|
|
@@ -225,7 +225,7 @@ export function handleEditVerification(
|
|
|
225
225
|
|
|
226
226
|
// 3. Read current file content with improved error handling
|
|
227
227
|
|
|
228
|
-
|
|
228
|
+
|
|
229
229
|
let currentContent: string;
|
|
230
230
|
try {
|
|
231
231
|
currentContent = fs.readFileSync(absolutePath, 'utf-8');
|
package/src/hooks/gate.ts
CHANGED
|
@@ -135,7 +135,7 @@ export function handleBeforeToolCall(
|
|
|
135
135
|
|
|
136
136
|
if (mutationMatch) {
|
|
137
137
|
|
|
138
|
-
|
|
138
|
+
|
|
139
139
|
filePath = mutationMatch[1];
|
|
140
140
|
} else {
|
|
141
141
|
const hasRiskPath = profile.risk_paths.some(rp => command.includes(rp));
|
|
@@ -169,36 +169,36 @@ export function handleBeforeToolCall(
|
|
|
169
169
|
toolName: event.toolName,
|
|
170
170
|
normalizedPath: relPath,
|
|
171
171
|
|
|
172
|
-
|
|
172
|
+
|
|
173
173
|
paramsSummary: _extractParamsSummary(event.params),
|
|
174
174
|
},
|
|
175
175
|
workspace: {
|
|
176
176
|
isRiskPath: risky,
|
|
177
177
|
|
|
178
|
-
|
|
178
|
+
|
|
179
179
|
planStatus: _getPlanStatus(ctx.workspaceDir),
|
|
180
180
|
|
|
181
|
-
|
|
181
|
+
|
|
182
182
|
hasPlanFile: _hasPlanFile(ctx.workspaceDir),
|
|
183
183
|
},
|
|
184
184
|
session: {
|
|
185
185
|
sessionId: ctx.sessionId,
|
|
186
186
|
|
|
187
|
-
|
|
187
|
+
|
|
188
188
|
currentGfi: _getCurrentGfi(ctx.sessionId),
|
|
189
189
|
|
|
190
|
-
|
|
190
|
+
|
|
191
191
|
recentThinking: _hasRecentThinking(ctx.sessionId),
|
|
192
192
|
},
|
|
193
193
|
evolution: {
|
|
194
194
|
|
|
195
|
-
|
|
195
|
+
|
|
196
196
|
epTier: _getEpTier(wctx.workspaceDir),
|
|
197
197
|
},
|
|
198
198
|
derived: {
|
|
199
199
|
estimatedLineChanges: estimateLineChanges({ toolName: event.toolName, params: event.params }),
|
|
200
200
|
|
|
201
|
-
|
|
201
|
+
|
|
202
202
|
bashRisk: _getBashRisk(event, profile),
|
|
203
203
|
},
|
|
204
204
|
};
|
package/src/hooks/gfi-gate.ts
CHANGED
|
@@ -48,7 +48,7 @@ export interface GfiGateConfig {
|
|
|
48
48
|
* Internal helper to call the shared block helper with gfi-gate source tag.
|
|
49
49
|
*/
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
function block(
|
|
53
53
|
wctx: WorkspaceContext,
|
|
54
54
|
filePath: string,
|
|
@@ -70,7 +70,7 @@ function block(
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
|
|
74
74
|
export function checkGfiGate(
|
|
75
75
|
event: PluginHookBeforeToolCallEvent,
|
|
76
76
|
wctx: WorkspaceContext,
|
|
@@ -66,7 +66,7 @@ export type LifecycleIntent = 'promote' | 'disable' | 'rollback' | null;
|
|
|
66
66
|
* Detect implementation lifecycle intent from user message.
|
|
67
67
|
* Returns the detected intent type or null.
|
|
68
68
|
*/
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
export function detectLifecycleIntent(message: string): LifecycleIntent {
|
|
71
71
|
// Check promote patterns
|
|
72
72
|
for (const p of PROMOTE_PATTERNS_EN) {
|