principles-disciple 1.11.0 → 1.13.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/CHANGELOG.md +26 -0
- package/README.md +66 -0
- package/esbuild.config.js +1 -1
- package/openclaw.plugin.json +4 -4
- package/package.json +2 -3
- package/run-nocturnal.mjs +30 -0
- package/scripts/db-migrate.mjs +170 -0
- package/scripts/sync-plugin.mjs +250 -6
- package/src/commands/archive-impl.ts +136 -0
- package/src/commands/capabilities.ts +4 -2
- package/src/commands/context.ts +5 -1
- package/src/commands/disable-impl.ts +151 -0
- package/src/commands/evolution-status.ts +64 -19
- package/src/commands/export.ts +8 -6
- package/src/commands/focus.ts +8 -20
- package/src/commands/nocturnal-review.ts +5 -7
- package/src/commands/nocturnal-rollout.ts +1 -12
- package/src/commands/nocturnal-train.ts +21 -47
- package/src/commands/pain.ts +10 -5
- package/src/commands/principle-rollback.ts +4 -2
- package/src/commands/promote-impl.ts +274 -0
- package/src/commands/rollback-impl.ts +234 -0
- package/src/commands/rollback.ts +6 -3
- package/src/commands/samples.ts +2 -0
- package/src/commands/thinking-os.ts +3 -4
- package/src/commands/workflow-debug.ts +2 -1
- package/src/config/errors.ts +1 -0
- package/src/core/AGENTS.md +34 -0
- package/src/core/adaptive-thresholds.ts +4 -3
- package/src/core/code-implementation-storage.ts +241 -0
- package/src/core/config.ts +5 -2
- package/src/core/control-ui-db.ts +29 -10
- package/src/core/detection-funnel.ts +12 -7
- package/src/core/diagnostician-task-store.ts +156 -0
- package/src/core/dictionary.ts +4 -4
- package/src/core/empathy-keyword-matcher.ts +7 -3
- package/src/core/empathy-types.ts +13 -2
- package/src/core/event-log.ts +14 -6
- package/src/core/evolution-engine.ts +27 -31
- package/src/core/evolution-logger.ts +3 -2
- package/src/core/evolution-reducer.ts +110 -31
- package/src/core/evolution-types.ts +10 -0
- package/src/core/external-training-contract.ts +1 -0
- package/src/core/focus-history.ts +38 -24
- package/src/core/hygiene/tracker.ts +10 -6
- package/src/core/init.ts +5 -2
- package/src/core/migration.ts +3 -3
- package/src/core/model-deployment-registry.ts +6 -4
- package/src/core/model-training-registry.ts +5 -3
- package/src/core/nocturnal-arbiter.ts +13 -14
- package/src/core/nocturnal-artifact-lineage.ts +117 -0
- package/src/core/nocturnal-artificer.ts +257 -0
- package/src/core/nocturnal-candidate-scoring.ts +4 -2
- package/src/core/nocturnal-compliance.ts +67 -19
- package/src/core/nocturnal-dataset.ts +95 -2
- package/src/core/nocturnal-executability.ts +2 -3
- package/src/core/nocturnal-export.ts +6 -3
- package/src/core/nocturnal-rule-implementation-validator.ts +245 -0
- package/src/core/nocturnal-trajectory-extractor.ts +10 -3
- package/src/core/nocturnal-trinity.ts +319 -61
- package/src/core/pain-context-extractor.ts +29 -15
- package/src/core/pain.ts +7 -5
- package/src/core/path-resolver.ts +16 -15
- package/src/core/paths.ts +2 -1
- package/src/core/pd-task-reconciler.ts +463 -0
- package/src/core/pd-task-service.ts +42 -0
- package/src/core/pd-task-store.ts +77 -0
- package/src/core/pd-task-types.ts +128 -0
- package/src/core/principle-internalization/deprecated-readiness.ts +91 -0
- package/src/core/principle-internalization/internalization-routing-policy.ts +208 -0
- package/src/core/principle-internalization/lifecycle-metrics.ts +149 -0
- package/src/core/principle-internalization/lifecycle-read-model.ts +243 -0
- package/src/core/principle-internalization/lifecycle-refresh.ts +11 -0
- package/src/core/principle-internalization/principle-lifecycle-service.ts +167 -0
- package/src/core/principle-training-state.ts +95 -370
- package/src/core/principle-tree-ledger.ts +733 -0
- package/src/core/principle-tree-migration.ts +195 -0
- package/src/core/profile.ts +3 -1
- package/src/core/promotion-gate.ts +14 -18
- package/src/core/replay-engine.ts +562 -0
- package/src/core/risk-calculator.ts +6 -4
- package/src/core/rule-host-helpers.ts +39 -0
- package/src/core/rule-host-types.ts +82 -0
- package/src/core/rule-host.ts +245 -0
- package/src/core/rule-implementation-runtime.ts +38 -0
- package/src/core/schema/db-types.ts +16 -0
- package/src/core/schema/index.ts +26 -0
- package/src/core/schema/migration-runner.ts +207 -0
- package/src/core/schema/migrations/001-init-trajectory.ts +211 -0
- package/src/core/schema/migrations/002-init-central.ts +122 -0
- package/src/core/schema/migrations/003-init-workflow.ts +55 -0
- package/src/core/schema/migrations/004-add-thinking-and-gfi.ts +74 -0
- package/src/core/schema/migrations/index.ts +31 -0
- package/src/core/schema/schema-definitions.ts +650 -0
- package/src/core/session-tracker.ts +6 -4
- package/src/core/shadow-observation-registry.ts +6 -3
- package/src/core/system-logger.ts +2 -2
- package/src/core/thinking-models.ts +182 -46
- package/src/core/thinking-os-parser.ts +156 -0
- package/src/core/training-program.ts +7 -7
- package/src/core/trajectory.ts +42 -36
- package/src/core/workspace-context.ts +77 -11
- package/src/core/workspace-dir-validation.ts +152 -0
- package/src/hooks/AGENTS.md +31 -0
- package/src/hooks/bash-risk.ts +3 -1
- package/src/hooks/edit-verification.ts +9 -5
- package/src/hooks/gate-block-helper.ts +5 -1
- package/src/hooks/gate.ts +152 -5
- package/src/hooks/gfi-gate.ts +9 -2
- package/src/hooks/lifecycle-routing.ts +124 -0
- package/src/hooks/lifecycle.ts +12 -12
- package/src/hooks/llm.ts +17 -109
- package/src/hooks/message-sanitize.ts +5 -3
- package/src/hooks/pain.ts +19 -15
- package/src/hooks/progressive-trust-gate.ts +7 -1
- package/src/hooks/prompt.ts +169 -60
- package/src/hooks/subagent.ts +5 -4
- package/src/hooks/thinking-checkpoint.ts +2 -0
- package/src/hooks/trajectory-collector.ts +15 -12
- package/src/http/principles-console-route.ts +31 -68
- package/src/i18n/commands.ts +2 -2
- package/src/index.ts +130 -40
- package/src/service/central-database.ts +131 -43
- package/src/service/central-health-service.ts +47 -0
- package/src/service/central-overview-service.ts +135 -0
- package/src/service/central-sync-service.ts +87 -0
- package/src/service/control-ui-query-service.ts +46 -36
- package/src/service/event-log-auditor.ts +261 -0
- package/src/service/evolution-query-service.ts +23 -22
- package/src/service/evolution-worker.ts +565 -261
- package/src/service/health-query-service.ts +213 -36
- package/src/service/nocturnal-runtime.ts +8 -4
- package/src/service/nocturnal-service.ts +503 -59
- package/src/service/nocturnal-target-selector.ts +5 -7
- package/src/service/runtime-summary-service.ts +2 -1
- package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +25 -336
- package/src/service/subagent-workflow/dynamic-timeout.ts +30 -0
- package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +48 -386
- package/src/service/subagent-workflow/index.ts +2 -0
- package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +169 -284
- package/src/service/subagent-workflow/runtime-direct-driver.ts +114 -16
- package/src/service/subagent-workflow/subagent-error-utils.ts +25 -0
- package/src/service/subagent-workflow/types.ts +9 -4
- package/src/service/subagent-workflow/workflow-manager-base.ts +573 -0
- package/src/service/subagent-workflow/workflow-store.ts +71 -11
- package/src/service/trajectory-service.ts +2 -1
- package/src/tools/critique-prompt.ts +1 -1
- package/src/tools/deep-reflect.ts +175 -209
- package/src/tools/model-index.ts +2 -1
- package/src/types/event-types.ts +2 -2
- package/src/types/principle-tree-schema.ts +29 -23
- package/src/utils/file-lock.ts +5 -3
- package/src/utils/io.ts +5 -2
- package/src/utils/nlp.ts +5 -46
- package/src/utils/node-vm-polyfill.ts +11 -0
- package/src/utils/plugin-logger.ts +2 -0
- package/src/utils/retry.ts +572 -0
- package/src/utils/subagent-probe.ts +1 -1
- package/templates/langs/en/core/AGENTS.md +0 -13
- package/templates/langs/en/core/SOUL.md +1 -31
- package/templates/langs/en/core/TOOLS.md +0 -4
- package/templates/langs/en/principles/THINKING_OS.md +77 -0
- package/templates/langs/en/skills/admin/SKILL.md +0 -1
- package/templates/langs/en/skills/evolution-framework-update/SKILL.md +1 -1
- package/templates/langs/en/skills/pd-diagnostician/SKILL.md +18 -5
- package/templates/langs/zh/core/AGENTS.md +0 -22
- package/templates/langs/zh/core/SOUL.md +1 -31
- package/templates/langs/zh/core/TOOLS.md +0 -4
- package/templates/langs/zh/principles/THINKING_OS.md +77 -0
- package/templates/langs/zh/skills/admin/SKILL.md +0 -1
- package/templates/langs/zh/skills/evolution-framework-update/SKILL.md +1 -1
- package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +25 -4
- package/tests/commands/evolution-status.test.ts +119 -0
- package/tests/commands/implementation-lifecycle.test.ts +362 -0
- package/tests/core/code-implementation-storage.test.ts +398 -0
- package/tests/core/evolution-reducer.detector-metadata.test.ts +28 -28
- package/tests/core/nocturnal-artifact-lineage.test.ts +53 -0
- package/tests/core/nocturnal-artificer.test.ts +241 -0
- package/tests/core/nocturnal-compliance-p-principles.test.ts +133 -0
- package/tests/core/nocturnal-rule-implementation-validator.test.ts +127 -0
- package/tests/core/pd-task-store.test.ts +126 -0
- package/tests/core/principle-internalization/deprecated-readiness.test.ts +193 -0
- package/tests/core/principle-internalization/internalization-routing-policy.test.ts +212 -0
- package/tests/core/principle-internalization/lifecycle-metrics.test.ts +350 -0
- package/tests/core/principle-internalization/principle-lifecycle-service.test.ts +211 -0
- package/tests/core/principle-training-state.test.ts +228 -1
- package/tests/core/principle-tree-ledger.test.ts +423 -0
- package/tests/core/regression-v1-9-1.test.ts +265 -0
- package/tests/core/replay-engine.test.ts +234 -0
- package/tests/core/rule-host-helpers.test.ts +120 -0
- package/tests/core/rule-host.test.ts +389 -0
- package/tests/core/rule-implementation-runtime.test.ts +64 -0
- package/tests/core/workspace-context.test.ts +53 -0
- package/tests/core/workspace-dir-validation.test.ts +272 -0
- package/tests/hooks/gate-rule-host-pipeline.test.ts +385 -0
- package/tests/hooks/pain.test.ts +74 -10
- package/tests/hooks/prompt.test.ts +63 -1
- package/tests/integration/principle-lifecycle.e2e.test.ts +197 -0
- package/tests/integration/tool-hooks-workspace-dir.e2e.test.ts +211 -0
- package/tests/service/data-endpoints-regression.test.ts +834 -0
- package/tests/service/evolution-worker.test.ts +0 -123
- package/tests/service/nocturnal-service-code-candidate.test.ts +330 -0
- package/tests/utils/nlp.test.ts +1 -19
- package/tests/utils/retry.test.ts +327 -0
- package/ui/src/App.tsx +1 -1
- package/ui/src/api.ts +4 -0
- package/ui/src/charts.tsx +366 -0
- package/ui/src/components/WorkspaceConfig.tsx +107 -75
- package/ui/src/i18n/ui.ts +89 -31
- package/ui/src/pages/EvolutionPage.tsx +1 -1
- package/ui/src/pages/OverviewPage.tsx +441 -81
- package/ui/src/pages/ThinkingModelsPage.tsx +287 -69
- package/ui/src/styles.css +43 -0
- package/ui/src/types.ts +17 -1
- package/src/agents/nocturnal-dreamer.md +0 -152
- package/src/agents/nocturnal-philosopher.md +0 -138
- package/src/agents/nocturnal-reflector.md +0 -126
- package/src/agents/nocturnal-scribe.md +0 -164
- package/templates/workspace/.principles/00-kernel.md +0 -51
- package/templates/workspace/.principles/DECISION_POLICY.json +0 -44
- package/templates/workspace/.principles/PRINCIPLES.md +0 -20
- package/templates/workspace/.principles/PROFILE.json +0 -54
- package/templates/workspace/.principles/PROFILE.schema.json +0 -56
- package/templates/workspace/.principles/THINKING_OS.md +0 -64
- package/templates/workspace/.principles/THINKING_OS_ARCHIVE.md +0 -7
- package/templates/workspace/.principles/THINKING_OS_CANDIDATES.md +0 -9
- package/templates/workspace/.principles/models/_INDEX.md +0 -27
- package/templates/workspace/.principles/models/first_principles.md +0 -62
- package/templates/workspace/.principles/models/marketing_4p.md +0 -52
- package/templates/workspace/.principles/models/porter_five.md +0 -63
- package/templates/workspace/.principles/models/swot.md +0 -60
- package/templates/workspace/.principles/models/user_story_map.md +0 -63
- package/templates/workspace/.state/WORKBOARD.json +0 -4
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ControlUiDatabase } from '../core/control-ui-db.js';
|
|
2
|
-
import { getThinkingModel, listThinkingModels } from '../core/thinking-models.js';
|
|
2
|
+
import { getThinkingModel, listThinkingModels, getThinkingModelDefinitions } from '../core/thinking-models.js';
|
|
3
3
|
import { WorkspaceContext } from '../core/workspace-context.js';
|
|
4
4
|
|
|
5
5
|
/** Time window (in minutes) for querying principle events related to a sample */
|
|
@@ -22,33 +22,35 @@ export interface OverviewResponse {
|
|
|
22
22
|
gateBlocks: number;
|
|
23
23
|
taskOutcomes: number;
|
|
24
24
|
};
|
|
25
|
-
dailyTrend:
|
|
25
|
+
dailyTrend: {
|
|
26
26
|
day: string;
|
|
27
27
|
toolCalls: number;
|
|
28
28
|
failures: number;
|
|
29
29
|
userCorrections: number;
|
|
30
30
|
thinkingTurns: number;
|
|
31
|
-
}
|
|
32
|
-
topRegressions:
|
|
31
|
+
}[];
|
|
32
|
+
topRegressions: {
|
|
33
33
|
toolName: string;
|
|
34
34
|
errorType: string;
|
|
35
35
|
occurrences: number;
|
|
36
|
-
}
|
|
36
|
+
}[];
|
|
37
37
|
sampleQueue: {
|
|
38
38
|
counters: Record<string, number>;
|
|
39
|
-
preview:
|
|
39
|
+
preview: {
|
|
40
40
|
sampleId: string;
|
|
41
41
|
sessionId: string;
|
|
42
42
|
qualityScore: number;
|
|
43
43
|
reviewStatus: string;
|
|
44
44
|
createdAt: string;
|
|
45
|
-
}
|
|
45
|
+
}[];
|
|
46
46
|
};
|
|
47
47
|
thinkingSummary: {
|
|
48
48
|
activeModels: number;
|
|
49
49
|
dormantModels: number;
|
|
50
50
|
effectiveModels: number;
|
|
51
51
|
coverageRate: number;
|
|
52
|
+
modelBreakdown?: { modelId: string; hits: number }[];
|
|
53
|
+
modelDefinitions?: { modelId: string; name: string; description: string }[];
|
|
52
54
|
};
|
|
53
55
|
}
|
|
54
56
|
|
|
@@ -64,7 +66,7 @@ export interface SampleListFilters {
|
|
|
64
66
|
|
|
65
67
|
export interface SamplesResponse {
|
|
66
68
|
counters: Record<string, number>;
|
|
67
|
-
items:
|
|
69
|
+
items: {
|
|
68
70
|
sampleId: string;
|
|
69
71
|
sessionId: string;
|
|
70
72
|
reviewStatus: string;
|
|
@@ -74,7 +76,7 @@ export interface SamplesResponse {
|
|
|
74
76
|
createdAt: string;
|
|
75
77
|
updatedAt: string;
|
|
76
78
|
diffExcerpt: string;
|
|
77
|
-
}
|
|
79
|
+
}[];
|
|
78
80
|
pagination: {
|
|
79
81
|
page: number;
|
|
80
82
|
pageSize: number;
|
|
@@ -102,13 +104,13 @@ export interface SampleDetailResponse {
|
|
|
102
104
|
correctionCue: string | null;
|
|
103
105
|
createdAt: string;
|
|
104
106
|
};
|
|
105
|
-
recoveryToolSpan:
|
|
106
|
-
relatedPrinciples:
|
|
107
|
+
recoveryToolSpan: { id: number; toolName: string }[];
|
|
108
|
+
relatedPrinciples: {
|
|
107
109
|
principleId: string | null;
|
|
108
110
|
eventType: string;
|
|
109
111
|
createdAt: string;
|
|
110
|
-
}
|
|
111
|
-
relatedThinkingHits:
|
|
112
|
+
}[];
|
|
113
|
+
relatedThinkingHits: {
|
|
112
114
|
id: number;
|
|
113
115
|
modelId: string;
|
|
114
116
|
modelName: string;
|
|
@@ -116,12 +118,12 @@ export interface SampleDetailResponse {
|
|
|
116
118
|
scenarios: string[];
|
|
117
119
|
createdAt: string;
|
|
118
120
|
triggerExcerpt: string;
|
|
119
|
-
}
|
|
120
|
-
reviewHistory:
|
|
121
|
+
}[];
|
|
122
|
+
reviewHistory: {
|
|
121
123
|
reviewStatus: string;
|
|
122
124
|
note: string | null;
|
|
123
125
|
createdAt: string;
|
|
124
|
-
}
|
|
126
|
+
}[];
|
|
125
127
|
}
|
|
126
128
|
|
|
127
129
|
export interface ThinkingModelSummary {
|
|
@@ -148,24 +150,24 @@ export interface ThinkingOverviewResponse {
|
|
|
148
150
|
coverageRate: number;
|
|
149
151
|
};
|
|
150
152
|
topModels: ThinkingModelSummary[];
|
|
151
|
-
dormantModels:
|
|
153
|
+
dormantModels: {
|
|
152
154
|
modelId: string;
|
|
153
155
|
name: string;
|
|
154
156
|
description: string;
|
|
155
|
-
}
|
|
157
|
+
}[];
|
|
156
158
|
effectiveModels: ThinkingModelSummary[];
|
|
157
|
-
scenarioMatrix:
|
|
159
|
+
scenarioMatrix: {
|
|
158
160
|
modelId: string;
|
|
159
161
|
modelName: string;
|
|
160
162
|
scenario: string;
|
|
161
163
|
hits: number;
|
|
162
|
-
}
|
|
163
|
-
coverageTrend:
|
|
164
|
+
}[];
|
|
165
|
+
coverageTrend: {
|
|
164
166
|
day: string;
|
|
165
167
|
assistantTurns: number;
|
|
166
168
|
thinkingTurns: number;
|
|
167
169
|
coverageRate: number;
|
|
168
|
-
}
|
|
170
|
+
}[];
|
|
169
171
|
}
|
|
170
172
|
|
|
171
173
|
export interface ThinkingModelDetailResponse {
|
|
@@ -177,14 +179,14 @@ export interface ThinkingModelDetailResponse {
|
|
|
177
179
|
coverageRate: number;
|
|
178
180
|
recommendation: 'reinforce' | 'rework' | 'archive';
|
|
179
181
|
};
|
|
180
|
-
usageTrend:
|
|
182
|
+
usageTrend: {
|
|
181
183
|
day: string;
|
|
182
184
|
hits: number;
|
|
183
|
-
}
|
|
184
|
-
scenarioDistribution:
|
|
185
|
+
}[];
|
|
186
|
+
scenarioDistribution: {
|
|
185
187
|
scenario: string;
|
|
186
188
|
hits: number;
|
|
187
|
-
}
|
|
189
|
+
}[];
|
|
188
190
|
outcomeStats: {
|
|
189
191
|
events: number;
|
|
190
192
|
successRate: number;
|
|
@@ -193,16 +195,16 @@ export interface ThinkingModelDetailResponse {
|
|
|
193
195
|
correctionRate: number;
|
|
194
196
|
correctionSampleRate: number;
|
|
195
197
|
};
|
|
196
|
-
recentEvents:
|
|
198
|
+
recentEvents: {
|
|
197
199
|
id: number;
|
|
198
200
|
createdAt: string;
|
|
199
201
|
matchedPattern: string;
|
|
200
202
|
scenarios: string[];
|
|
201
203
|
triggerExcerpt: string;
|
|
202
|
-
toolContext:
|
|
203
|
-
painContext:
|
|
204
|
-
principleContext:
|
|
205
|
-
}
|
|
204
|
+
toolContext: { toolName: string; outcome: string; errorType?: string | null }[];
|
|
205
|
+
painContext: { source: string; score: number }[];
|
|
206
|
+
principleContext: { principleId: string | null; eventType: string }[];
|
|
207
|
+
}[];
|
|
206
208
|
}
|
|
207
209
|
|
|
208
210
|
function parseJson<T>(raw: string | null | undefined, fallback: T): T {
|
|
@@ -253,7 +255,7 @@ export class ControlUiQueryService {
|
|
|
253
255
|
this.uiDb.dispose();
|
|
254
256
|
}
|
|
255
257
|
|
|
256
|
-
getOverview(days
|
|
258
|
+
getOverview(days = 30): OverviewResponse {
|
|
257
259
|
const stats = this.trajectory.getDataStats();
|
|
258
260
|
const regressionRows = this.uiDb.all<{
|
|
259
261
|
tool_name: string;
|
|
@@ -313,6 +315,12 @@ export class ControlUiQueryService {
|
|
|
313
315
|
painRate: roundRate(Number(row.pain_windows), Number(row.events)),
|
|
314
316
|
correctionRate: roundRate(Number(row.correction_windows), Number(row.events)),
|
|
315
317
|
}) === 'reinforce').length;
|
|
318
|
+
const modelBreakdown = this.uiDb.all<{ modelId: string; hits: number }>(`
|
|
319
|
+
SELECT model_id as modelId, COUNT(*) as hits
|
|
320
|
+
FROM thinking_model_events
|
|
321
|
+
GROUP BY model_id
|
|
322
|
+
ORDER BY hits DESC
|
|
323
|
+
`).map(row => ({ modelId: row.modelId, hits: Number(row.hits) }));
|
|
316
324
|
const dailyTrend = this.uiDb.all<{
|
|
317
325
|
day: string;
|
|
318
326
|
tool_calls: number;
|
|
@@ -385,6 +393,8 @@ export class ControlUiQueryService {
|
|
|
385
393
|
dormantModels: Math.max(0, listThinkingModels().length - activeModels),
|
|
386
394
|
effectiveModels: effectiveCount,
|
|
387
395
|
coverageRate: roundRate(coverageRow.thinking_turns, coverageRow.assistant_turns),
|
|
396
|
+
modelBreakdown,
|
|
397
|
+
modelDefinitions: getThinkingModelDefinitions(),
|
|
388
398
|
},
|
|
389
399
|
};
|
|
390
400
|
}
|
|
@@ -621,7 +631,7 @@ export class ControlUiQueryService {
|
|
|
621
631
|
correctionCue: row.user_correction_cue,
|
|
622
632
|
createdAt: row.user_created_at,
|
|
623
633
|
},
|
|
624
|
-
recoveryToolSpan: parseJson<
|
|
634
|
+
recoveryToolSpan: parseJson<{ id: number; toolName: string }[]>(row.recovery_tool_span_json, []),
|
|
625
635
|
relatedPrinciples: [
|
|
626
636
|
...seededPrincipleIds,
|
|
627
637
|
...relatedPrinciples.map((item) => ({
|
|
@@ -822,9 +832,9 @@ export class ControlUiQueryService {
|
|
|
822
832
|
matchedPattern: row.matched_pattern,
|
|
823
833
|
scenarios: parseJson<string[]>(row.scenario_json, []),
|
|
824
834
|
triggerExcerpt: row.trigger_excerpt,
|
|
825
|
-
toolContext: parseJson<
|
|
826
|
-
painContext: parseJson<
|
|
827
|
-
principleContext: parseJson<
|
|
835
|
+
toolContext: parseJson<{ toolName: string; outcome: string; errorType?: string | null }[]>(row.tool_context_json, []),
|
|
836
|
+
painContext: parseJson<{ source: string; score: number }[]>(row.pain_context_json, []),
|
|
837
|
+
principleContext: parseJson<{ principleId: string | null; eventType: string }[]>(row.principle_context_json, []),
|
|
828
838
|
})),
|
|
829
839
|
};
|
|
830
840
|
}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EventLog Auditor — Search and verify events across all .state directories
|
|
3
|
+
*
|
|
4
|
+
* This tool addresses a common debugging issue where hook events may be
|
|
5
|
+
* written to the wrong .state directory due to workspaceDir resolution bugs.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* const report = await auditEventLogs(openclawDir, ['after_tool_call', 'before_tool_call']);
|
|
9
|
+
* console.log(report.summary);
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import * as fs from 'fs';
|
|
13
|
+
import * as path from 'path';
|
|
14
|
+
import * as os from 'os';
|
|
15
|
+
|
|
16
|
+
interface EventLogEntry {
|
|
17
|
+
ts: string;
|
|
18
|
+
date: string;
|
|
19
|
+
type: string;
|
|
20
|
+
category: string;
|
|
21
|
+
sessionId?: string;
|
|
22
|
+
data: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface LocationReport {
|
|
26
|
+
path: string;
|
|
27
|
+
lastModified: Date | null;
|
|
28
|
+
totalEntries: number;
|
|
29
|
+
hookCounts: Record<string, number>;
|
|
30
|
+
recentEntries: EventLogEntry[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface AuditReport {
|
|
34
|
+
searchedPaths: string[];
|
|
35
|
+
locations: LocationReport[];
|
|
36
|
+
primaryPath: string | null;
|
|
37
|
+
misplacedEvents: { path: string; entries: EventLogEntry[] }[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Find all events.jsonl files under a directory tree.
|
|
42
|
+
*/
|
|
43
|
+
function findEventLogs(baseDir: string, maxDepth = 4): string[] {
|
|
44
|
+
const results: string[] = [];
|
|
45
|
+
|
|
46
|
+
function scan(dir: string, depth: number): void {
|
|
47
|
+
if (depth > maxDepth) return;
|
|
48
|
+
try {
|
|
49
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
50
|
+
for (const entry of entries) {
|
|
51
|
+
if (entry.name === 'events.jsonl') {
|
|
52
|
+
results.push(path.join(dir, entry.name));
|
|
53
|
+
} else if (entry.isDirectory() && !entry.name.startsWith('.')) {
|
|
54
|
+
scan(path.join(dir, entry.name), depth + 1);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
} catch {
|
|
58
|
+
// Permission denied or directory doesn't exist
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
scan(baseDir, 0);
|
|
63
|
+
return results;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Find events.jsonl in well-known locations.
|
|
68
|
+
*/
|
|
69
|
+
function findKnownEventLogPaths(): string[] {
|
|
70
|
+
const homeDir = os.homedir();
|
|
71
|
+
const candidates: string[] = [];
|
|
72
|
+
|
|
73
|
+
// Common patterns
|
|
74
|
+
const patterns = [
|
|
75
|
+
path.join(homeDir, '.state', 'logs', 'events.jsonl'),
|
|
76
|
+
path.join(homeDir, '.openclaw', '.state', 'logs', 'events.jsonl'),
|
|
77
|
+
path.join(homeDir, '.openclaw', 'workspace-main', '.state', 'logs', 'events.jsonl'),
|
|
78
|
+
path.join(homeDir, '.openclaw', 'workspace-builder', '.state', 'logs', 'events.jsonl'),
|
|
79
|
+
path.join(homeDir, '.openclaw', 'workspace-pm', '.state', 'logs', 'events.jsonl'),
|
|
80
|
+
path.join(homeDir, '.openclaw', 'workspace-hr', '.state', 'logs', 'events.jsonl'),
|
|
81
|
+
path.join(homeDir, '.openclaw', 'workspace-repair', '.state', 'logs', 'events.jsonl'),
|
|
82
|
+
path.join(homeDir, '.openclaw', 'workspace-research', '.state', 'logs', 'events.jsonl'),
|
|
83
|
+
path.join(homeDir, '.openclaw', 'workspace-scout', '.state', 'logs', 'events.jsonl'),
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
for (const p of patterns) {
|
|
87
|
+
if (fs.existsSync(p)) {
|
|
88
|
+
candidates.push(p);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return candidates;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Read the last N entries from an events.jsonl file.
|
|
97
|
+
*/
|
|
98
|
+
function readRecentEntries(filePath: string, count = 50): EventLogEntry[] {
|
|
99
|
+
try {
|
|
100
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
101
|
+
const lines = content.trim().split('\n').filter(Boolean);
|
|
102
|
+
const recent = lines.slice(-count);
|
|
103
|
+
return recent.map(line => JSON.parse(line));
|
|
104
|
+
} catch {
|
|
105
|
+
return [];
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Count all hooks in the entire file (for summary).
|
|
111
|
+
*/
|
|
112
|
+
function countAllHooks(filePath: string): Record<string, number> {
|
|
113
|
+
const counts: Record<string, number> = {};
|
|
114
|
+
try {
|
|
115
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
116
|
+
const lines = content.trim().split('\n').filter(Boolean);
|
|
117
|
+
for (const line of lines) {
|
|
118
|
+
try {
|
|
119
|
+
const entry = JSON.parse(line) as EventLogEntry;
|
|
120
|
+
if (entry.type === 'hook_execution' && entry.data?.hook) {
|
|
121
|
+
const hook = entry.data.hook as string;
|
|
122
|
+
counts[hook] = (counts[hook] || 0) + 1;
|
|
123
|
+
}
|
|
124
|
+
} catch {
|
|
125
|
+
// Skip malformed lines
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
} catch {
|
|
129
|
+
// File doesn't exist or can't be read
|
|
130
|
+
}
|
|
131
|
+
return counts;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Audit all events.jsonl files.
|
|
136
|
+
*
|
|
137
|
+
* @param openclawDir - Base OpenClaw directory (e.g., ~/.openclaw)
|
|
138
|
+
* @param expectedToolHooks - Hook names that should appear in the primary workspace
|
|
139
|
+
*/
|
|
140
|
+
export async function auditEventLogs(
|
|
141
|
+
openclawDir: string,
|
|
142
|
+
expectedToolHooks: string[] = ['before_tool_call', 'after_tool_call'],
|
|
143
|
+
): Promise<AuditReport> {
|
|
144
|
+
const homeDir = os.homedir();
|
|
145
|
+
|
|
146
|
+
// Find all event logs
|
|
147
|
+
const knownPaths = findKnownEventLogPaths();
|
|
148
|
+
const scannedPaths = findEventLogs(homeDir, 4);
|
|
149
|
+
const allPaths = [...new Set([...knownPaths, ...scannedPaths])];
|
|
150
|
+
|
|
151
|
+
const locations: LocationReport[] = [];
|
|
152
|
+
let primaryPath: string | null = null;
|
|
153
|
+
|
|
154
|
+
for (const filePath of allPaths) {
|
|
155
|
+
try {
|
|
156
|
+
const stat = fs.statSync(filePath);
|
|
157
|
+
const allCounts = countAllHooks(filePath);
|
|
158
|
+
const recent = readRecentEntries(filePath, 30);
|
|
159
|
+
|
|
160
|
+
locations.push({
|
|
161
|
+
path: filePath,
|
|
162
|
+
lastModified: stat.mtime,
|
|
163
|
+
totalEntries: Object.values(allCounts).reduce((a, b) => a + b, 0),
|
|
164
|
+
hookCounts: allCounts,
|
|
165
|
+
recentEntries: recent,
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// Determine primary path (workspace-main or most recent)
|
|
169
|
+
if (filePath.includes('workspace-main') || filePath.includes('workspace-main')) {
|
|
170
|
+
primaryPath = filePath;
|
|
171
|
+
}
|
|
172
|
+
} catch {
|
|
173
|
+
// Skip unreadable files
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// If no primary found, use most recent
|
|
178
|
+
if (!primaryPath && locations.length > 0) {
|
|
179
|
+
locations.sort((a, b) => {
|
|
180
|
+
if (!a.lastModified) return 1;
|
|
181
|
+
if (!b.lastModified) return -1;
|
|
182
|
+
return b.lastModified.getTime() - a.lastModified.getTime();
|
|
183
|
+
});
|
|
184
|
+
primaryPath = locations[0].path;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Detect misplaced tool hook events
|
|
188
|
+
const misplacedEvents: { path: string; entries: EventLogEntry[] }[] = [];
|
|
189
|
+
for (const loc of locations) {
|
|
190
|
+
if (loc.path === primaryPath) continue;
|
|
191
|
+
|
|
192
|
+
const toolHookEntries = loc.recentEntries.filter(e =>
|
|
193
|
+
e.type === 'hook_execution' && expectedToolHooks.includes(e.data?.hook as string)
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
if (toolHookEntries.length > 0) {
|
|
197
|
+
misplacedEvents.push({ path: loc.path, entries: toolHookEntries });
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
searchedPaths: allPaths,
|
|
203
|
+
locations,
|
|
204
|
+
primaryPath,
|
|
205
|
+
misplacedEvents,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Format audit report for display.
|
|
211
|
+
*/
|
|
212
|
+
export function formatAuditReport(report: AuditReport): string {
|
|
213
|
+
const lines: string[] = [];
|
|
214
|
+
|
|
215
|
+
lines.push('=== Event Log Audit Report ===\n');
|
|
216
|
+
|
|
217
|
+
lines.push(`Searched ${report.searchedPaths.length} paths:\n`);
|
|
218
|
+
for (const p of report.searchedPaths) {
|
|
219
|
+
lines.push(` ${p}`);
|
|
220
|
+
}
|
|
221
|
+
lines.push('');
|
|
222
|
+
|
|
223
|
+
lines.push(`Primary: ${report.primaryPath ?? 'NOT FOUND'}\n`);
|
|
224
|
+
|
|
225
|
+
for (const loc of report.locations) {
|
|
226
|
+
const isPrimary = loc.path === report.primaryPath;
|
|
227
|
+
lines.push(`─── ${isPrimary ? '[PRIMARY]' : '[OTHER] '}${loc.path}`);
|
|
228
|
+
lines.push(` Last modified: ${loc.lastModified?.toISOString() ?? 'never'}`);
|
|
229
|
+
lines.push(` Hook counts:`);
|
|
230
|
+
|
|
231
|
+
const hooks = Object.entries(loc.hookCounts).sort((a, b) => b[1] - a[1]);
|
|
232
|
+
for (const [hook, count] of hooks) {
|
|
233
|
+
lines.push(` ${hook}: ${count}`);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (hooks.length === 0) {
|
|
237
|
+
lines.push(` (no hooks recorded)`);
|
|
238
|
+
}
|
|
239
|
+
lines.push('');
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (report.misplacedEvents.length > 0) {
|
|
243
|
+
lines.push('⚠️ MISPLACED tool hook events detected:');
|
|
244
|
+
for (const me of report.misplacedEvents) {
|
|
245
|
+
lines.push(`\n ${me.path}:`);
|
|
246
|
+
for (const entry of me.entries.slice(0, 5)) {
|
|
247
|
+
lines.push(` ${entry.ts} - ${entry.data.hook}`);
|
|
248
|
+
}
|
|
249
|
+
if (me.entries.length > 5) {
|
|
250
|
+
lines.push(` ... and ${me.entries.length - 5} more`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
lines.push('');
|
|
254
|
+
lines.push('This means tool hooks are writing events to the wrong .state directory.');
|
|
255
|
+
lines.push('Check workspaceDir resolution in the hook handler.');
|
|
256
|
+
} else {
|
|
257
|
+
lines.push('✅ No misplaced tool hook events detected.');
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return lines.join('\n');
|
|
261
|
+
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - getStats() - 获取统计数据
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import type { TrajectoryDatabase, EvolutionTaskRecord
|
|
11
|
+
import type { TrajectoryDatabase, EvolutionTaskRecord } from '../core/trajectory.js';
|
|
12
12
|
import { STAGE_LABELS, STAGE_COLORS } from '../core/evolution-logger.js';
|
|
13
13
|
|
|
14
14
|
export interface TaskListFilters {
|
|
@@ -27,7 +27,7 @@ export interface EventFilters {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
export interface TasksResponse {
|
|
30
|
-
items:
|
|
30
|
+
items: {
|
|
31
31
|
taskId: string;
|
|
32
32
|
traceId: string;
|
|
33
33
|
source: string;
|
|
@@ -41,7 +41,7 @@ export interface TasksResponse {
|
|
|
41
41
|
resolution: string | null;
|
|
42
42
|
eventCount: number;
|
|
43
43
|
createdAt: string;
|
|
44
|
-
}
|
|
44
|
+
}[];
|
|
45
45
|
pagination: {
|
|
46
46
|
page: number;
|
|
47
47
|
pageSize: number;
|
|
@@ -51,7 +51,7 @@ export interface TasksResponse {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
export interface EventsResponse {
|
|
54
|
-
items:
|
|
54
|
+
items: {
|
|
55
55
|
id: number;
|
|
56
56
|
traceId: string;
|
|
57
57
|
taskId: string | null;
|
|
@@ -63,7 +63,7 @@ export interface EventsResponse {
|
|
|
63
63
|
summary: string | null;
|
|
64
64
|
metadata: Record<string, unknown>;
|
|
65
65
|
createdAt: string;
|
|
66
|
-
}
|
|
66
|
+
}[];
|
|
67
67
|
pagination: {
|
|
68
68
|
limit: number;
|
|
69
69
|
offset: number;
|
|
@@ -88,7 +88,7 @@ export interface TraceDetailResponse {
|
|
|
88
88
|
createdAt: string;
|
|
89
89
|
updatedAt: string;
|
|
90
90
|
};
|
|
91
|
-
events:
|
|
91
|
+
events: {
|
|
92
92
|
id: number;
|
|
93
93
|
traceId: string;
|
|
94
94
|
taskId: string | null;
|
|
@@ -100,15 +100,15 @@ export interface TraceDetailResponse {
|
|
|
100
100
|
summary: string | null;
|
|
101
101
|
metadata: Record<string, unknown>;
|
|
102
102
|
createdAt: string;
|
|
103
|
-
}
|
|
104
|
-
timeline:
|
|
103
|
+
}[];
|
|
104
|
+
timeline: {
|
|
105
105
|
stage: string;
|
|
106
106
|
stageLabel: string;
|
|
107
107
|
stageColor: string;
|
|
108
108
|
timestamp: string;
|
|
109
109
|
message: string;
|
|
110
110
|
summary: string | null;
|
|
111
|
-
}
|
|
111
|
+
}[];
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
export interface EvolutionStatsResponse {
|
|
@@ -117,16 +117,16 @@ export interface EvolutionStatsResponse {
|
|
|
117
117
|
inProgress: number;
|
|
118
118
|
completed: number;
|
|
119
119
|
failed: number;
|
|
120
|
-
recentActivity:
|
|
120
|
+
recentActivity: {
|
|
121
121
|
day: string;
|
|
122
122
|
created: number;
|
|
123
123
|
completed: number;
|
|
124
|
-
}
|
|
125
|
-
stageDistribution:
|
|
124
|
+
}[];
|
|
125
|
+
stageDistribution: {
|
|
126
126
|
stage: string;
|
|
127
127
|
stageLabel: string;
|
|
128
128
|
count: number;
|
|
129
|
-
}
|
|
129
|
+
}[];
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
/**
|
|
@@ -154,6 +154,7 @@ export class EvolutionQueryService {
|
|
|
154
154
|
* 释放资源
|
|
155
155
|
* 注意:不关闭 trajectory,因为它是单例由 TrajectoryRegistry 管理
|
|
156
156
|
*/
|
|
157
|
+
/* eslint-disable @typescript-eslint/class-methods-use-this -- Reason: Delegates to TrajectoryRegistry lifecycle management */
|
|
157
158
|
dispose(): void {
|
|
158
159
|
// EvolutionQueryService 不拥有 trajectory,所以不关闭它
|
|
159
160
|
// trajectory 是由 TrajectoryRegistry 管理的单例
|
|
@@ -324,7 +325,7 @@ export class EvolutionQueryService {
|
|
|
324
325
|
/**
|
|
325
326
|
* 获取统计数据
|
|
326
327
|
*/
|
|
327
|
-
getStats(days
|
|
328
|
+
getStats(days = 30): EvolutionStatsResponse {
|
|
328
329
|
// 获取基础统计
|
|
329
330
|
const stats = this.trajectory.getEvolutionStats();
|
|
330
331
|
|
|
@@ -340,21 +341,21 @@ export class EvolutionQueryService {
|
|
|
340
341
|
const activityByDay = new Map<string, { created: number; completed: number }>();
|
|
341
342
|
for (let i = 0; i < days; i++) {
|
|
342
343
|
const day = new Date(now.getTime() - i * 24 * 60 * 60 * 1000);
|
|
343
|
-
const dayStr = day.toISOString().split('T')
|
|
344
|
+
const [dayStr] = day.toISOString().split('T');
|
|
344
345
|
activityByDay.set(dayStr, { created: 0, completed: 0 });
|
|
345
346
|
}
|
|
346
347
|
|
|
347
348
|
for (const task of recentTasks) {
|
|
348
|
-
const createdDay = task.createdAt.split('T')
|
|
349
|
+
const [createdDay] = task.createdAt.split('T');
|
|
349
350
|
if (activityByDay.has(createdDay)) {
|
|
350
|
-
|
|
351
|
-
|
|
351
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Reason: has() check guarantees entry exists
|
|
352
|
+
activityByDay.get(createdDay)!.created++;
|
|
352
353
|
}
|
|
353
354
|
if (task.completedAt) {
|
|
354
|
-
const completedDay = task.completedAt.split('T')
|
|
355
|
+
const [completedDay] = task.completedAt.split('T');
|
|
355
356
|
if (activityByDay.has(completedDay)) {
|
|
356
|
-
|
|
357
|
-
|
|
357
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Reason: has() check guarantees entry exists
|
|
358
|
+
activityByDay.get(completedDay)!.completed++;
|
|
358
359
|
}
|
|
359
360
|
}
|
|
360
361
|
}
|
|
@@ -394,7 +395,7 @@ const serviceCache = new Map<string, EvolutionQueryService>();
|
|
|
394
395
|
*/
|
|
395
396
|
export function getEvolutionQueryService(trajectory: TrajectoryDatabase): EvolutionQueryService {
|
|
396
397
|
// 使用 trajectory 的 dbPath 作为缓存键
|
|
397
|
-
const cacheKey = (trajectory as
|
|
398
|
+
const cacheKey = (trajectory as unknown as { dbPath?: string }).dbPath || 'default';
|
|
398
399
|
const cached = serviceCache.get(cacheKey);
|
|
399
400
|
if (cached) {
|
|
400
401
|
return cached;
|