principles-disciple 1.5.4 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/dist/commands/context.d.ts +5 -0
  2. package/dist/commands/context.js +312 -0
  3. package/dist/commands/evolution-status.d.ts +4 -0
  4. package/dist/commands/evolution-status.js +138 -0
  5. package/dist/commands/export.d.ts +2 -0
  6. package/dist/commands/export.js +45 -0
  7. package/dist/commands/focus.d.ts +14 -0
  8. package/dist/commands/focus.js +582 -0
  9. package/dist/commands/pain.js +143 -6
  10. package/dist/commands/principle-rollback.d.ts +4 -0
  11. package/dist/commands/principle-rollback.js +22 -0
  12. package/dist/commands/rollback.d.ts +19 -0
  13. package/dist/commands/rollback.js +119 -0
  14. package/dist/commands/samples.d.ts +2 -0
  15. package/dist/commands/samples.js +55 -0
  16. package/dist/core/config.d.ts +37 -0
  17. package/dist/core/config.js +47 -0
  18. package/dist/core/control-ui-db.d.ts +68 -0
  19. package/dist/core/control-ui-db.js +274 -0
  20. package/dist/core/detection-funnel.d.ts +1 -1
  21. package/dist/core/detection-funnel.js +4 -0
  22. package/dist/core/dictionary.d.ts +2 -0
  23. package/dist/core/dictionary.js +13 -0
  24. package/dist/core/event-log.d.ts +22 -1
  25. package/dist/core/event-log.js +319 -0
  26. package/dist/core/evolution-engine.d.ts +5 -5
  27. package/dist/core/evolution-engine.js +18 -18
  28. package/dist/core/evolution-migration.d.ts +5 -0
  29. package/dist/core/evolution-migration.js +65 -0
  30. package/dist/core/evolution-reducer.d.ts +69 -0
  31. package/dist/core/evolution-reducer.js +369 -0
  32. package/dist/core/evolution-types.d.ts +103 -0
  33. package/dist/core/focus-history.d.ts +65 -0
  34. package/dist/core/focus-history.js +266 -0
  35. package/dist/core/init.js +30 -7
  36. package/dist/core/migration.js +0 -2
  37. package/dist/core/path-resolver.d.ts +3 -0
  38. package/dist/core/path-resolver.js +90 -31
  39. package/dist/core/paths.d.ts +7 -8
  40. package/dist/core/paths.js +48 -40
  41. package/dist/core/profile.js +1 -1
  42. package/dist/core/session-tracker.d.ts +4 -0
  43. package/dist/core/session-tracker.js +15 -0
  44. package/dist/core/thinking-models.d.ts +38 -0
  45. package/dist/core/thinking-models.js +170 -0
  46. package/dist/core/trajectory.d.ts +184 -0
  47. package/dist/core/trajectory.js +817 -0
  48. package/dist/core/trust-engine.d.ts +2 -0
  49. package/dist/core/trust-engine.js +30 -4
  50. package/dist/core/workspace-context.d.ts +13 -0
  51. package/dist/core/workspace-context.js +50 -7
  52. package/dist/hooks/gate.js +301 -30
  53. package/dist/hooks/llm.d.ts +8 -0
  54. package/dist/hooks/llm.js +347 -69
  55. package/dist/hooks/message-sanitize.d.ts +3 -0
  56. package/dist/hooks/message-sanitize.js +37 -0
  57. package/dist/hooks/pain.js +105 -5
  58. package/dist/hooks/prompt.d.ts +20 -11
  59. package/dist/hooks/prompt.js +558 -158
  60. package/dist/hooks/subagent.d.ts +9 -2
  61. package/dist/hooks/subagent.js +40 -3
  62. package/dist/http/principles-console-route.d.ts +2 -0
  63. package/dist/http/principles-console-route.js +257 -0
  64. package/dist/i18n/commands.js +48 -20
  65. package/dist/index.js +264 -8
  66. package/dist/service/control-ui-query-service.d.ts +217 -0
  67. package/dist/service/control-ui-query-service.js +537 -0
  68. package/dist/service/empathy-observer-manager.d.ts +42 -0
  69. package/dist/service/empathy-observer-manager.js +147 -0
  70. package/dist/service/evolution-worker.d.ts +10 -0
  71. package/dist/service/evolution-worker.js +156 -24
  72. package/dist/service/trajectory-service.d.ts +2 -0
  73. package/dist/service/trajectory-service.js +15 -0
  74. package/dist/tools/agent-spawn.d.ts +27 -6
  75. package/dist/tools/agent-spawn.js +339 -87
  76. package/dist/tools/deep-reflect.d.ts +27 -7
  77. package/dist/tools/deep-reflect.js +282 -113
  78. package/dist/types/event-types.d.ts +84 -2
  79. package/dist/types/event-types.js +33 -0
  80. package/dist/types.d.ts +52 -0
  81. package/dist/types.js +24 -1
  82. package/openclaw.plugin.json +43 -11
  83. package/package.json +16 -6
  84. package/templates/langs/zh/core/HEARTBEAT.md +28 -4
  85. package/templates/langs/zh/skills/pd-daily/SKILL.md +97 -13
  86. package/templates/pain_settings.json +54 -2
  87. package/templates/workspace/.principles/PROFILE.json +2 -0
  88. package/templates/workspace/okr/CURRENT_FOCUS.md +57 -0
@@ -1,67 +1,75 @@
1
1
  import * as path from 'path';
2
+ const posixJoin = (...parts) => path.posix.join(...parts);
3
+ function isWindowsPath(input) {
4
+ return /^[A-Za-z]:[\\/]/.test(input) || input.startsWith('\\\\');
5
+ }
6
+ function joinWorkspacePath(workspaceDir, relativePath) {
7
+ if (isWindowsPath(workspaceDir)) {
8
+ return path.win32.join(workspaceDir, relativePath);
9
+ }
10
+ if (workspaceDir.startsWith('/')) {
11
+ return path.posix.join(workspaceDir, relativePath);
12
+ }
13
+ return path.join(workspaceDir, relativePath);
14
+ }
2
15
  /**
3
16
  * Principles Disciple Directory Constants
4
17
  * Establishing a logical separation between Identity, State, and Memory.
5
18
  */
6
19
  export const PD_DIRS = {
7
- /** 🧬 Core configuration, identity, and kernel rules (hidden) */
8
20
  IDENTITY: '.principles',
9
- /** 🧠 Deep Reflection mental models */
10
- MODELS: path.join('.principles', 'models'),
11
- /** ⚡ Volatile operational data, queues, and task status (hidden) */
21
+ MODELS: posixJoin('.principles', 'models'),
12
22
  STATE: '.state',
13
- /** 💾 Historical records, logs, and long-term memory */
14
23
  MEMORY: 'memory',
15
- /** 🎯 Strategic objectives and focus areas */
16
- OKR: path.join('memory', 'okr'),
17
- /** 📁 Internal logs directory */
18
- LOGS: path.join('memory', 'logs'),
19
- /** 🧠 Session persistence directory */
20
- SESSIONS: path.join('.state', 'sessions'),
21
- /** 🩹 Semantic pain samples for L3 retrieval */
22
- PAIN_SAMPLES: path.join('memory', 'pain'),
24
+ OKR: posixJoin('memory', 'okr'),
25
+ LOGS: posixJoin('memory', 'logs'),
26
+ SESSIONS: posixJoin('.state', 'sessions'),
27
+ PAIN_SAMPLES: posixJoin('memory', 'pain'),
28
+ LOCKS: posixJoin('memory', '.locks'),
23
29
  };
24
30
  /**
25
31
  * Standard File Path Mappings
26
32
  */
27
33
  export const PD_FILES = {
28
- // Identity Layer
29
- PROFILE: path.join(PD_DIRS.IDENTITY, 'PROFILE.json'),
30
- PRINCIPLES: path.join(PD_DIRS.IDENTITY, 'PRINCIPLES.md'),
31
- THINKING_OS: path.join(PD_DIRS.IDENTITY, 'THINKING_OS.md'),
32
- KERNEL: path.join(PD_DIRS.IDENTITY, '00-kernel.md'),
33
- DECISION_POLICY: path.join(PD_DIRS.IDENTITY, 'DECISION_POLICY.json'),
34
+ PROFILE: posixJoin(PD_DIRS.IDENTITY, 'PROFILE.json'),
35
+ PRINCIPLES: posixJoin(PD_DIRS.IDENTITY, 'PRINCIPLES.md'),
36
+ THINKING_OS: posixJoin(PD_DIRS.IDENTITY, 'THINKING_OS.md'),
37
+ KERNEL: posixJoin(PD_DIRS.IDENTITY, '00-kernel.md'),
38
+ DECISION_POLICY: posixJoin(PD_DIRS.IDENTITY, 'DECISION_POLICY.json'),
34
39
  MODELS_DIR: PD_DIRS.MODELS,
35
- // State Layer
36
40
  STATE_DIR: PD_DIRS.STATE,
37
- EVOLUTION_QUEUE: path.join(PD_DIRS.STATE, 'evolution_queue.json'),
38
- EVOLUTION_DIRECTIVE: path.join(PD_DIRS.STATE, 'evolution_directive.json'),
39
- WORKBOARD: path.join(PD_DIRS.STATE, 'WORKBOARD.json'),
40
- AGENT_SCORECARD: path.join(PD_DIRS.STATE, 'AGENT_SCORECARD.json'),
41
- PAIN_FLAG: path.join(PD_DIRS.STATE, '.pain_flag'),
42
- SYSTEM_CAPABILITIES: path.join(PD_DIRS.STATE, 'SYSTEM_CAPABILITIES.json'),
43
- PAIN_SETTINGS: path.join(PD_DIRS.STATE, 'pain_settings.json'),
44
- PAIN_CANDIDATES: path.join(PD_DIRS.STATE, 'pain_candidates.json'),
45
- THINKING_OS_USAGE: path.join(PD_DIRS.STATE, 'thinking_os_usage.json'),
41
+ EVOLUTION_QUEUE: posixJoin(PD_DIRS.STATE, 'evolution_queue.json'),
42
+ EVOLUTION_DIRECTIVE: posixJoin(PD_DIRS.STATE, 'evolution_directive.json'),
43
+ WORKBOARD: posixJoin(PD_DIRS.STATE, 'WORKBOARD.json'),
44
+ AGENT_SCORECARD: posixJoin(PD_DIRS.STATE, 'AGENT_SCORECARD.json'),
45
+ PAIN_FLAG: posixJoin(PD_DIRS.STATE, '.pain_flag'),
46
+ SYSTEM_CAPABILITIES: posixJoin(PD_DIRS.STATE, 'SYSTEM_CAPABILITIES.json'),
47
+ PAIN_SETTINGS: posixJoin(PD_DIRS.STATE, 'pain_settings.json'),
48
+ PAIN_CANDIDATES: posixJoin(PD_DIRS.STATE, 'pain_candidates.json'),
49
+ THINKING_OS_USAGE: posixJoin(PD_DIRS.STATE, 'thinking_os_usage.json'),
50
+ TRAJECTORY_DB: posixJoin(PD_DIRS.STATE, 'trajectory.db'),
51
+ TRAJECTORY_BLOBS_DIR: posixJoin(PD_DIRS.STATE, 'blobs'),
52
+ EXPORTS_DIR: posixJoin(PD_DIRS.STATE, 'exports'),
46
53
  SESSION_DIR: PD_DIRS.SESSIONS,
47
- DICTIONARY: path.join(PD_DIRS.STATE, 'pain_dictionary.json'),
48
- // Workflow Layer (Project Root)
54
+ DICTIONARY: posixJoin(PD_DIRS.STATE, 'pain_dictionary.json'),
55
+ PRINCIPLE_BLACKLIST: posixJoin(PD_DIRS.STATE, 'principle_blacklist.json'),
49
56
  PLAN: 'PLAN.md',
50
57
  MEMORY_MD: 'MEMORY.md',
51
58
  HEARTBEAT: 'HEARTBEAT.md',
52
- // Memory Layer
53
- SYSTEM_LOG: path.join(PD_DIRS.LOGS, 'SYSTEM.log'),
54
- REFLECTION_LOG: path.join(PD_DIRS.MEMORY, 'reflection-log.md'),
55
- USER_CONTEXT: path.join(PD_DIRS.MEMORY, 'USER_CONTEXT.md'),
59
+ SYSTEM_LOG: posixJoin(PD_DIRS.LOGS, 'SYSTEM.log'),
60
+ REFLECTION_LOG: posixJoin(PD_DIRS.MEMORY, 'reflection-log.md'),
61
+ USER_CONTEXT: posixJoin(PD_DIRS.MEMORY, 'USER_CONTEXT.md'),
56
62
  OKR_DIR: PD_DIRS.OKR,
57
- CURRENT_FOCUS: path.join(PD_DIRS.OKR, 'CURRENT_FOCUS.md'),
58
- WEEK_STATE: path.join(PD_DIRS.OKR, 'WEEK_STATE.json'),
59
- THINKING_OS_CANDIDATES: path.join(PD_DIRS.MEMORY, 'THINKING_OS_CANDIDATES.md'),
60
- SEMANTIC_PAIN: path.join(PD_DIRS.PAIN_SAMPLES, 'confusion_samples.md'),
63
+ CURRENT_FOCUS: posixJoin(PD_DIRS.OKR, 'CURRENT_FOCUS.md'),
64
+ WEEK_STATE: posixJoin(PD_DIRS.OKR, 'WEEK_STATE.json'),
65
+ THINKING_OS_CANDIDATES: posixJoin(PD_DIRS.MEMORY, 'THINKING_OS_CANDIDATES.md'),
66
+ SEMANTIC_PAIN: posixJoin(PD_DIRS.PAIN_SAMPLES, 'confusion_samples.md'),
67
+ EVOLUTION_STREAM: posixJoin(PD_DIRS.MEMORY, 'evolution.jsonl'),
68
+ EVOLUTION_LOCK: posixJoin(PD_DIRS.LOCKS, 'evolution'),
61
69
  };
62
70
  /**
63
71
  * Resolves a PD file path within a given workspace.
64
72
  */
65
73
  export function resolvePdPath(workspaceDir, fileKey) {
66
- return path.join(workspaceDir, PD_FILES[fileKey]);
74
+ return joinWorkspacePath(workspaceDir, PD_FILES[fileKey]);
67
75
  }
@@ -51,7 +51,7 @@ export const PROFILE_DEFAULTS = {
51
51
  thinking_checkpoint: {
52
52
  enabled: false, // Default OFF to avoid blocking new users
53
53
  window_ms: 5 * 60 * 1000, // 5 minute window
54
- high_risk_tools: ['run_shell_command', 'delete_file', 'move_file', 'pd_spawn_agent'],
54
+ high_risk_tools: ['run_shell_command', 'delete_file', 'move_file', 'pd_run_worker'],
55
55
  },
56
56
  custom_guards: [],
57
57
  };
@@ -25,6 +25,7 @@ export interface SessionState {
25
25
  dailyPainSignals: number;
26
26
  dailyGfiPeak: number;
27
27
  lastThinkingTimestamp: number;
28
+ injectedProbationIds?: string[];
28
29
  }
29
30
  /**
30
31
  * Initialize persistence for session state.
@@ -58,6 +59,9 @@ export declare function recordThinkingCheckpoint(sessionId: string, workspaceDir
58
59
  */
59
60
  export declare function hasRecentThinking(sessionId: string, windowMs?: number): boolean;
60
61
  export declare function trackBlock(sessionId: string): SessionState;
62
+ export declare function setInjectedProbationIds(sessionId: string, ids: string[], workspaceDir?: string): SessionState;
63
+ export declare function getInjectedProbationIds(sessionId: string, workspaceDir?: string): string[];
64
+ export declare function clearInjectedProbationIds(sessionId: string, workspaceDir?: string): SessionState;
61
65
  export declare function getSession(sessionId: string): SessionState | undefined;
62
66
  export declare function clearSession(sessionId: string): void;
63
67
  export declare function garbageCollectSessions(): void;
@@ -115,6 +115,7 @@ function getOrCreateSession(sessionId, workspaceDir) {
115
115
  dailyPainSignals: 0,
116
116
  dailyGfiPeak: 0,
117
117
  lastThinkingTimestamp: 0,
118
+ injectedProbationIds: [],
118
119
  };
119
120
  sessions.set(sessionId, state);
120
121
  }
@@ -230,6 +231,20 @@ export function trackBlock(sessionId) {
230
231
  state.lastActivityAt = Date.now();
231
232
  return state;
232
233
  }
234
+ export function setInjectedProbationIds(sessionId, ids, workspaceDir) {
235
+ const state = getOrCreateSession(sessionId, workspaceDir);
236
+ state.injectedProbationIds = [...ids];
237
+ state.lastActivityAt = Date.now();
238
+ schedulePersistence(state);
239
+ return state;
240
+ }
241
+ export function getInjectedProbationIds(sessionId, workspaceDir) {
242
+ const state = getOrCreateSession(sessionId, workspaceDir);
243
+ return [...(state.injectedProbationIds || [])];
244
+ }
245
+ export function clearInjectedProbationIds(sessionId, workspaceDir) {
246
+ return setInjectedProbationIds(sessionId, [], workspaceDir);
247
+ }
233
248
  export function getSession(sessionId) {
234
249
  return sessions.get(sessionId);
235
250
  }
@@ -0,0 +1,38 @@
1
+ export interface ThinkingModelDefinition {
2
+ id: string;
3
+ name: string;
4
+ description: string;
5
+ patterns: RegExp[];
6
+ baselineScenarios: string[];
7
+ }
8
+ export interface ThinkingModelMatch {
9
+ modelId: string;
10
+ matchedPattern: string;
11
+ }
12
+ export interface ThinkingScenarioContext {
13
+ recentToolCalls?: Array<{
14
+ toolName: string;
15
+ outcome: 'success' | 'failure' | 'blocked';
16
+ errorType?: string | null;
17
+ }>;
18
+ recentPainEvents?: Array<{
19
+ source: string;
20
+ score: number;
21
+ }>;
22
+ recentGateBlocks?: Array<{
23
+ toolName: string;
24
+ reason: string;
25
+ }>;
26
+ recentUserCorrections?: Array<{
27
+ correctionCue?: string | null;
28
+ }>;
29
+ recentPrincipleEvents?: Array<{
30
+ eventType: string;
31
+ principleId?: string | null;
32
+ }>;
33
+ }
34
+ export declare const THINKING_MODEL_MAP: Map<string, ThinkingModelDefinition>;
35
+ export declare function listThinkingModels(): ThinkingModelDefinition[];
36
+ export declare function getThinkingModel(modelId: string): ThinkingModelDefinition | undefined;
37
+ export declare function detectThinkingModelMatches(text: string): ThinkingModelMatch[];
38
+ export declare function deriveThinkingScenarios(modelId: string, context: ThinkingScenarioContext): string[];
@@ -0,0 +1,170 @@
1
+ const THINKING_MODELS = [
2
+ {
3
+ id: 'T-01',
4
+ name: 'Survey Before Acting',
5
+ description: 'Understand the structure first before making changes.',
6
+ baselineScenarios: ['exploration', 'discovery'],
7
+ patterns: [
8
+ /let me (first )?(understand|map|outline|survey|review the (structure|architecture|dependencies))/i,
9
+ /before (changing|editing|touching) anything/i,
10
+ /让我先(梳理|理解|看看|盘点).*(结构|架构|依赖|全貌)/i,
11
+ ],
12
+ },
13
+ {
14
+ id: 'T-02',
15
+ name: 'Respect Constraints',
16
+ description: 'Explicitly reason about contracts, tests, schemas, and requirements.',
17
+ baselineScenarios: ['constraint-check', 'contract-verification'],
18
+ patterns: [
19
+ /(type|test|contract|schema|interface) (constraint|requirement|check|validation)/i,
20
+ /we (must|need to) (respect|follow|adhere to) the/i,
21
+ /(必须|需要).*(遵守|符合|满足).*(类型|测试|契约|接口|规范)/i,
22
+ ],
23
+ },
24
+ {
25
+ id: 'T-03',
26
+ name: 'Evidence Over Assumption',
27
+ description: 'Use logs, code, and outputs before inferring causes.',
28
+ baselineScenarios: ['evidence-gathering', 'verification'],
29
+ patterns: [
30
+ /based on (the |this )?(evidence|logs?|output|error|stack trace|test result)/i,
31
+ /let me (check|verify|confirm|read|look at) (the |)(actual|source|code|file|log)/i,
32
+ /根据(日志|证据|输出|报错|堆栈|测试结果)/i,
33
+ ],
34
+ },
35
+ {
36
+ id: 'T-04',
37
+ name: 'Reversible First',
38
+ description: 'Prefer changes that are safe to roll back when risk is high.',
39
+ baselineScenarios: ['risk-management', 'reversibility'],
40
+ patterns: [
41
+ /this (is|would be) (irreversible|destructive|permanent|not easily undone)/i,
42
+ /(reversible|can be undone|safely roll back)/i,
43
+ /(不可逆|破坏性|无法回滚|可以回滚|安全撤销)/i,
44
+ ],
45
+ },
46
+ {
47
+ id: 'T-05',
48
+ name: 'Safety Rails',
49
+ description: 'Call out guardrails, prohibitions, and failure-prevention constraints.',
50
+ baselineScenarios: ['guardrails', 'safety-rails'],
51
+ patterns: [
52
+ /we (must|should) (not|never|avoid|prevent|ensure we don't)/i,
53
+ /(critical|important) (not to|that we don't|to avoid)/i,
54
+ /(绝不能|必须避免|不可|禁止|确保不会)/i,
55
+ ],
56
+ },
57
+ {
58
+ id: 'T-06',
59
+ name: 'Simplicity First',
60
+ description: 'Prefer the smallest understandable solution over over-engineering.',
61
+ baselineScenarios: ['simplification', 'pragmatism'],
62
+ patterns: [
63
+ /(simpl(er|est|ify)|minimal|straightforward|lean) (approach|solution|fix|implementation)/i,
64
+ /(simple is better|keep it simple|no need to over)/i,
65
+ /(最简|更简单|精简|没必要过度设计)/i,
66
+ ],
67
+ },
68
+ {
69
+ id: 'T-07',
70
+ name: 'Minimal Change Surface',
71
+ description: 'Limit the blast radius and touch only what is necessary.',
72
+ baselineScenarios: ['minimal-diff', 'blast-radius-control'],
73
+ patterns: [
74
+ /(minimal|smallest|narrowest|least) (change|diff|modification|impact)/i,
75
+ /only (change|modify|touch|edit) (the |what)/i,
76
+ /(最小改动|最小变更|只改|只动必要部分)/i,
77
+ ],
78
+ },
79
+ {
80
+ id: 'T-08',
81
+ name: 'Pain As Signal',
82
+ description: 'Treat failures and friction as clues to step back and rethink.',
83
+ baselineScenarios: ['reflection', 'pain-response'],
84
+ patterns: [
85
+ /this (error|failure|issue) (tells us|indicates|signals|suggests|means)/i,
86
+ /let me (stop|pause|step back|reconsider|rethink)/i,
87
+ /这个(错误|失败|问题).*(说明|意味着|提示)/i,
88
+ /让我(停下|暂停|退一步|重新考虑|重新审视)/i,
89
+ ],
90
+ },
91
+ {
92
+ id: 'T-09',
93
+ name: 'Divide And Conquer',
94
+ description: 'Split the task into smaller phases before execution.',
95
+ baselineScenarios: ['decomposition', 'phased-execution'],
96
+ patterns: [
97
+ /(break|split|decompose|divide) (this |the task |it )?(into|down)/i,
98
+ /(step 1|first,? (we|i|let's)|phase 1)/i,
99
+ /(拆分|分解|分步|分阶段|第一步)/i,
100
+ ],
101
+ },
102
+ ];
103
+ export const THINKING_MODEL_MAP = new Map(THINKING_MODELS.map((model) => [model.id, model]));
104
+ export function listThinkingModels() {
105
+ return THINKING_MODELS.slice();
106
+ }
107
+ export function getThinkingModel(modelId) {
108
+ return THINKING_MODEL_MAP.get(modelId);
109
+ }
110
+ export function detectThinkingModelMatches(text) {
111
+ if (!text)
112
+ return [];
113
+ const matches = [];
114
+ for (const model of THINKING_MODELS) {
115
+ for (const pattern of model.patterns) {
116
+ if (pattern.test(text)) {
117
+ matches.push({
118
+ modelId: model.id,
119
+ matchedPattern: pattern.source,
120
+ });
121
+ break;
122
+ }
123
+ }
124
+ }
125
+ return matches;
126
+ }
127
+ export function deriveThinkingScenarios(modelId, context) {
128
+ const scenarios = new Set(getThinkingModel(modelId)?.baselineScenarios ?? []);
129
+ if ((context.recentToolCalls ?? []).some((call) => call.outcome === 'failure')) {
130
+ scenarios.add('after-tool-failure');
131
+ }
132
+ // after-recovery: success that follows a failure (not just any success)
133
+ const calls = context.recentToolCalls ?? [];
134
+ const hasFailure = calls.some((call) => call.outcome === 'failure');
135
+ const hasSuccess = calls.some((call) => call.outcome === 'success');
136
+ if (hasFailure && hasSuccess) {
137
+ scenarios.add('after-recovery');
138
+ }
139
+ if ((context.recentToolCalls ?? []).some((call) => call.outcome === 'blocked')) {
140
+ scenarios.add('blocked-execution');
141
+ }
142
+ if ((context.recentToolCalls ?? []).some((call) => Boolean(call.errorType))) {
143
+ scenarios.add('incident-response');
144
+ }
145
+ if ((context.recentPainEvents ?? []).length > 0) {
146
+ scenarios.add('user-friction');
147
+ }
148
+ if ((context.recentGateBlocks ?? []).length > 0) {
149
+ scenarios.add('gate-block');
150
+ }
151
+ if ((context.recentUserCorrections ?? []).length > 0) {
152
+ scenarios.add('user-correction');
153
+ }
154
+ if ((context.recentPrincipleEvents ?? []).length > 0) {
155
+ scenarios.add('principle-feedback');
156
+ }
157
+ if (modelId === 'T-03') {
158
+ scenarios.add('root-cause-analysis');
159
+ }
160
+ if (modelId === 'T-04' || modelId === 'T-05') {
161
+ scenarios.add('risk-review');
162
+ }
163
+ if (modelId === 'T-08') {
164
+ scenarios.add('reflection-loop');
165
+ }
166
+ if (modelId === 'T-09') {
167
+ scenarios.add('task-planning');
168
+ }
169
+ return Array.from(scenarios);
170
+ }
@@ -0,0 +1,184 @@
1
+ export type CorrectionSampleReviewStatus = 'pending' | 'approved' | 'rejected';
2
+ export type CorrectionExportMode = 'raw' | 'redacted';
3
+ export interface TrajectoryDataStats {
4
+ dbPath: string;
5
+ dbSizeBytes: number;
6
+ assistantTurns: number;
7
+ userTurns: number;
8
+ toolCalls: number;
9
+ painEvents: number;
10
+ pendingSamples: number;
11
+ approvedSamples: number;
12
+ blobBytes: number;
13
+ lastIngestAt: string | null;
14
+ }
15
+ export interface TrajectoryAssistantTurnInput {
16
+ sessionId: string;
17
+ runId: string;
18
+ provider: string;
19
+ model: string;
20
+ rawText: string;
21
+ sanitizedText: string;
22
+ usageJson: unknown;
23
+ empathySignalJson: unknown;
24
+ createdAt?: string;
25
+ }
26
+ export interface TrajectoryUserTurnInput {
27
+ sessionId: string;
28
+ turnIndex: number;
29
+ rawText: string;
30
+ correctionDetected: boolean;
31
+ correctionCue?: string | null;
32
+ referencesAssistantTurnId?: number | null;
33
+ createdAt?: string;
34
+ }
35
+ export interface TrajectoryToolCallInput {
36
+ sessionId: string;
37
+ toolName: string;
38
+ outcome: 'success' | 'failure' | 'blocked';
39
+ durationMs?: number | null;
40
+ exitCode?: number | null;
41
+ errorType?: string | null;
42
+ errorMessage?: string | null;
43
+ gfiBefore?: number | null;
44
+ gfiAfter?: number | null;
45
+ paramsJson?: unknown;
46
+ createdAt?: string;
47
+ }
48
+ export interface TrajectoryPainEventInput {
49
+ sessionId: string;
50
+ source: string;
51
+ score: number;
52
+ reason?: string | null;
53
+ severity?: string | null;
54
+ origin?: string | null;
55
+ confidence?: number | null;
56
+ createdAt?: string;
57
+ }
58
+ export interface TrajectoryGateBlockInput {
59
+ sessionId?: string | null;
60
+ toolName: string;
61
+ filePath?: string | null;
62
+ reason: string;
63
+ planStatus?: string | null;
64
+ createdAt?: string;
65
+ }
66
+ export interface TrajectoryTrustChangeInput {
67
+ sessionId?: string | null;
68
+ previousScore: number;
69
+ newScore: number;
70
+ delta: number;
71
+ reason: string;
72
+ createdAt?: string;
73
+ }
74
+ export interface TrajectoryPrincipleEventInput {
75
+ principleId?: string | null;
76
+ eventType: string;
77
+ payload: unknown;
78
+ createdAt?: string;
79
+ }
80
+ export interface TrajectoryTaskOutcomeInput {
81
+ sessionId: string;
82
+ taskId?: string | null;
83
+ outcome: string;
84
+ summary?: string | null;
85
+ principleIdsJson?: unknown;
86
+ createdAt?: string;
87
+ }
88
+ export interface TrajectorySessionInput {
89
+ sessionId: string;
90
+ startedAt?: string;
91
+ }
92
+ export interface AssistantTurnRecord {
93
+ id: number;
94
+ sessionId: string;
95
+ runId: string;
96
+ provider: string;
97
+ model: string;
98
+ rawText: string;
99
+ sanitizedText: string;
100
+ blobRef: string | null;
101
+ createdAt: string;
102
+ }
103
+ export interface CorrectionSampleRecord {
104
+ sampleId: string;
105
+ sessionId: string;
106
+ badAssistantTurnId: number;
107
+ userCorrectionTurnId: number;
108
+ recoveryToolSpanJson: string;
109
+ diffExcerpt: string;
110
+ principleIdsJson: string;
111
+ qualityScore: number;
112
+ reviewStatus: CorrectionSampleReviewStatus;
113
+ exportMode: CorrectionExportMode;
114
+ createdAt: string;
115
+ updatedAt: string;
116
+ }
117
+ export interface TrajectoryExportResult {
118
+ filePath: string;
119
+ count: number;
120
+ mode?: CorrectionExportMode;
121
+ }
122
+ export interface TrajectoryDatabaseOptions {
123
+ workspaceDir: string;
124
+ blobInlineThresholdBytes?: number;
125
+ busyTimeoutMs?: number;
126
+ orphanBlobGraceDays?: number;
127
+ }
128
+ export declare class TrajectoryDatabase {
129
+ private readonly workspaceDir;
130
+ private readonly stateDir;
131
+ private readonly dbPath;
132
+ private readonly blobDir;
133
+ private readonly exportDir;
134
+ private readonly blobInlineThresholdBytes;
135
+ private readonly orphanBlobGraceMs;
136
+ private readonly db;
137
+ constructor(opts: TrajectoryDatabaseOptions);
138
+ dispose(): void;
139
+ recordSession(input: TrajectorySessionInput): void;
140
+ recordAssistantTurn(input: TrajectoryAssistantTurnInput): number;
141
+ recordUserTurn(input: TrajectoryUserTurnInput): number;
142
+ recordToolCall(input: TrajectoryToolCallInput): number;
143
+ recordPainEvent(input: TrajectoryPainEventInput): void;
144
+ recordGateBlock(input: TrajectoryGateBlockInput): void;
145
+ recordTrustChange(input: TrajectoryTrustChangeInput): void;
146
+ recordPrincipleEvent(input: TrajectoryPrincipleEventInput): void;
147
+ recordTaskOutcome(input: TrajectoryTaskOutcomeInput): void;
148
+ listAssistantTurns(sessionId: string): AssistantTurnRecord[];
149
+ listCorrectionSamples(status?: CorrectionSampleReviewStatus): CorrectionSampleRecord[];
150
+ reviewCorrectionSample(sampleId: string, status: Exclude<CorrectionSampleReviewStatus, 'pending'>, note?: string): CorrectionSampleRecord;
151
+ exportCorrections(opts: {
152
+ mode: CorrectionExportMode;
153
+ approvedOnly: boolean;
154
+ }): TrajectoryExportResult;
155
+ exportAnalytics(): TrajectoryExportResult;
156
+ getDataStats(): TrajectoryDataStats;
157
+ cleanupBlobStorage(): {
158
+ removedFiles: number;
159
+ reclaimedBytes: number;
160
+ };
161
+ private initSchema;
162
+ private importLegacyArtifacts;
163
+ private migrateSchema;
164
+ private dailyMetrics;
165
+ private importLegacySessions;
166
+ private importLegacyEvents;
167
+ private importLegacyEvolution;
168
+ private markImported;
169
+ private isImported;
170
+ private maybeCreateCorrectionSample;
171
+ private recordExportAudit;
172
+ private storeRawText;
173
+ private restoreRawText;
174
+ private computeBlobBytes;
175
+ private pruneUnreferencedBlobs;
176
+ private withWrite;
177
+ }
178
+ export declare class TrajectoryRegistry {
179
+ private static instances;
180
+ static get(workspaceDir: string, opts?: Omit<TrajectoryDatabaseOptions, 'workspaceDir'>): TrajectoryDatabase;
181
+ static dispose(workspaceDir: string): void;
182
+ static clear(): void;
183
+ static use<T>(workspaceDir: string, fn: (db: TrajectoryDatabase) => T, opts?: Omit<TrajectoryDatabaseOptions, 'workspaceDir'>): T;
184
+ }