principles-disciple 1.7.4 → 1.7.6
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/dist/commands/evolution-status.js +32 -44
- package/dist/commands/focus.js +30 -155
- package/dist/config/defaults/runtime.d.ts +40 -0
- package/dist/config/defaults/runtime.js +44 -0
- package/dist/config/errors.d.ts +84 -0
- package/dist/config/errors.js +94 -0
- package/dist/config/index.d.ts +7 -0
- package/dist/config/index.js +7 -0
- package/dist/constants/diagnostician.d.ts +12 -0
- package/dist/constants/diagnostician.js +56 -0
- package/dist/constants/tools.d.ts +2 -2
- package/dist/constants/tools.js +1 -1
- package/dist/core/config.d.ts +12 -0
- package/dist/core/config.js +7 -0
- package/dist/core/control-ui-db.d.ts +27 -0
- package/dist/core/control-ui-db.js +18 -0
- package/dist/core/evolution-engine.js +1 -1
- package/dist/core/focus-history.d.ts +92 -0
- package/dist/core/focus-history.js +490 -0
- package/dist/core/init.js +2 -2
- package/dist/core/path-resolver.js +2 -1
- package/dist/core/profile.js +1 -1
- package/dist/core/trajectory.d.ts +60 -0
- package/dist/core/trajectory.js +72 -2
- package/dist/hooks/bash-risk.d.ts +57 -0
- package/dist/hooks/bash-risk.js +137 -0
- package/dist/hooks/edit-verification.d.ts +62 -0
- package/dist/hooks/edit-verification.js +256 -0
- package/dist/hooks/gate-block-helper.d.ts +44 -0
- package/dist/hooks/gate-block-helper.js +119 -0
- package/dist/hooks/gate.d.ts +18 -0
- package/dist/hooks/gate.js +63 -752
- package/dist/hooks/gfi-gate.d.ts +40 -0
- package/dist/hooks/gfi-gate.js +112 -0
- package/dist/hooks/progressive-trust-gate.d.ts +79 -0
- package/dist/hooks/progressive-trust-gate.js +242 -0
- package/dist/hooks/prompt.js +83 -28
- package/dist/hooks/subagent.js +1 -2
- package/dist/hooks/thinking-checkpoint.d.ts +37 -0
- package/dist/hooks/thinking-checkpoint.js +51 -0
- package/dist/http/principles-console-route.d.ts +7 -0
- package/dist/http/principles-console-route.js +255 -3
- package/dist/index.js +0 -2
- package/dist/service/central-database.d.ts +104 -0
- package/dist/service/central-database.js +649 -0
- package/dist/service/control-ui-query-service.d.ts +1 -1
- package/dist/service/control-ui-query-service.js +3 -3
- package/dist/service/evolution-query-service.d.ts +1 -1
- package/dist/service/evolution-query-service.js +5 -5
- package/dist/service/evolution-worker.d.ts +10 -0
- package/dist/service/evolution-worker.js +10 -6
- package/dist/service/phase3-input-filter.d.ts +57 -0
- package/dist/service/phase3-input-filter.js +93 -3
- package/dist/service/runtime-summary-service.d.ts +34 -0
- package/dist/service/runtime-summary-service.js +93 -1
- package/dist/tools/deep-reflect.js +1 -2
- package/dist/types/event-types.d.ts +2 -0
- package/dist/types/runtime-summary.d.ts +54 -0
- package/dist/types/runtime-summary.js +1 -0
- package/dist/utils/subagent-probe.d.ts +11 -0
- package/dist/utils/subagent-probe.js +46 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +2 -1
- package/templates/langs/en/core/AGENTS.md +1 -1
- package/templates/langs/en/core/TOOLS.md +1 -1
- package/templates/langs/zh/core/AGENTS.md +1 -1
- package/templates/langs/zh/core/TOOLS.md +1 -1
- package/{agents/auditor.md → templates/langs/zh/skills/pd-auditor/SKILL.md} +3 -3
- package/{agents/diagnostician.md → templates/langs/zh/skills/pd-diagnostician/SKILL.md} +39 -29
- package/{agents/explorer.md → templates/langs/zh/skills/pd-explorer/SKILL.md} +3 -3
- package/{agents/implementer.md → templates/langs/zh/skills/pd-implementer/SKILL.md} +3 -3
- package/{agents/planner.md → templates/langs/zh/skills/pd-planner/SKILL.md} +3 -3
- package/{agents/reporter.md → templates/langs/zh/skills/pd-reporter/SKILL.md} +3 -3
- package/{agents/reviewer.md → templates/langs/zh/skills/pd-reviewer/SKILL.md} +3 -3
- package/dist/core/agent-loader.d.ts +0 -44
- package/dist/core/agent-loader.js +0 -147
- package/dist/tools/agent-spawn.d.ts +0 -54
- package/dist/tools/agent-spawn.js +0 -456
|
@@ -1,24 +1,6 @@
|
|
|
1
1
|
import { EvolutionReducerImpl } from '../core/evolution-reducer.js';
|
|
2
2
|
import { normalizeLanguage } from '../i18n/commands.js';
|
|
3
3
|
import { RuntimeSummaryService } from '../service/runtime-summary-service.js';
|
|
4
|
-
function formatAge(ageSeconds, lang) {
|
|
5
|
-
if (ageSeconds === null) {
|
|
6
|
-
return '--';
|
|
7
|
-
}
|
|
8
|
-
if (ageSeconds < 60) {
|
|
9
|
-
return lang === 'zh' ? `${ageSeconds} \u79d2` : `${ageSeconds}s`;
|
|
10
|
-
}
|
|
11
|
-
const minutes = Math.floor(ageSeconds / 60);
|
|
12
|
-
if (minutes < 60) {
|
|
13
|
-
return lang === 'zh' ? `${minutes} \u5206\u949f` : `${minutes}m`;
|
|
14
|
-
}
|
|
15
|
-
const hours = Math.floor(minutes / 60);
|
|
16
|
-
if (hours < 24) {
|
|
17
|
-
return lang === 'zh' ? `${hours} \u5c0f\u65f6` : `${hours}h`;
|
|
18
|
-
}
|
|
19
|
-
const days = Math.floor(hours / 24);
|
|
20
|
-
return lang === 'zh' ? `${days} \u5929` : `${days}d`;
|
|
21
|
-
}
|
|
22
4
|
function formatNumber(value) {
|
|
23
5
|
if (value === null || Number.isNaN(value)) {
|
|
24
6
|
return '--';
|
|
@@ -45,6 +27,7 @@ function buildEnglishOutput(workspaceDir, sessionId, warnings, stats, summary) {
|
|
|
45
27
|
'',
|
|
46
28
|
'Control Plane',
|
|
47
29
|
`- Legacy Trust: ${formatNumber(summary.legacyTrust.score)}/100 (stage ${formatStage(summary.legacyTrust.stage)}, legacy/frozen, ${summary.legacyTrust.rewardPolicy})`,
|
|
30
|
+
`- Runtime Trust Truth: score ${formatNumber(summary.runtime.currentTrustScore)}, classification ${summary.runtime.workspaceState.trustClassification}, frozen ${summary.runtime.workspaceState.frozen === null ? '--' : String(summary.runtime.workspaceState.frozen)}`,
|
|
48
31
|
`- Session GFI: current ${formatNumber(summary.gfi.current)}, peak ${formatNumber(summary.gfi.peak)} (${summary.gfi.dataQuality})`,
|
|
49
32
|
`- GFI Sources: ${formatSources(summary.gfi.sources)}`,
|
|
50
33
|
`- Pain Flag: ${summary.pain.activeFlag ? 'active' : 'inactive'}${summary.pain.activeFlagSource ? ` (${summary.pain.activeFlagSource})` : ''}`,
|
|
@@ -53,9 +36,11 @@ function buildEnglishOutput(workspaceDir, sessionId, warnings, stats, summary) {
|
|
|
53
36
|
'',
|
|
54
37
|
'Evolution',
|
|
55
38
|
`- Queue: pending ${summary.evolution.queue.pending}, in_progress ${summary.evolution.queue.inProgress}, completed ${summary.evolution.queue.completed} (${summary.evolution.dataQuality})`,
|
|
56
|
-
`- Directive
|
|
57
|
-
`-
|
|
58
|
-
`-
|
|
39
|
+
`- Legacy Directive File: ${summary.phase3.legacyDirectiveFilePresent ? 'present' : 'missing'} (compatibility-only display artifact)`,
|
|
40
|
+
`- Note: Legacy directive file is NOT a truth source for Phase 3 eligibility. Queue is the only authoritative execution truth source.`,
|
|
41
|
+
`- Active Evolution Task: ${summary.evolution.directive.taskPreview ?? '--'}`,
|
|
42
|
+
`- Phase 3: ready ${summary.phase3.phase3ShadowEligible ? 'yes' : 'no'}, queueTruthReady ${summary.phase3.queueTruthReady ? 'yes' : 'no'}, trustInputReady ${summary.phase3.trustInputReady ? 'yes' : 'no'}, eligible ${summary.phase3.evolutionEligible}, reference_only ${summary.phase3.evolutionReferenceOnly}, rejected ${summary.phase3.evolutionRejected}${summary.phase3.evolutionReferenceOnlyReasons.length > 0 ? ` (reference ${summary.phase3.evolutionReferenceOnlyReasons.slice(0, 2).join(', ')})` : ''}${summary.phase3.evolutionRejectedReasons.length > 0 ? ` (${summary.phase3.evolutionRejectedReasons.slice(0, 3).join(', ')})` : ''}${summary.phase3.trustRejectedReasons.length > 0 ? `; trust ${summary.phase3.trustRejectedReasons.slice(0, 2).join(', ')}` : ''}`,
|
|
43
|
+
`- Phase 3 Legacy Directive File: ${summary.phase3.directiveStatus} (${summary.phase3.directiveIgnoredReason})`,
|
|
59
44
|
'',
|
|
60
45
|
'Principles',
|
|
61
46
|
`- candidate principles: ${stats.candidateCount}`,
|
|
@@ -79,34 +64,37 @@ function buildEnglishOutput(workspaceDir, sessionId, warnings, stats, summary) {
|
|
|
79
64
|
}
|
|
80
65
|
function buildChineseOutput(workspaceDir, sessionId, warnings, stats, summary) {
|
|
81
66
|
const lines = [
|
|
82
|
-
'
|
|
67
|
+
'进化状态',
|
|
83
68
|
'================',
|
|
84
69
|
'',
|
|
85
|
-
'
|
|
86
|
-
`- Legacy Trust: ${formatNumber(summary.legacyTrust.score)}/100
|
|
87
|
-
`-
|
|
88
|
-
`- GFI
|
|
89
|
-
`-
|
|
90
|
-
`-
|
|
91
|
-
`-
|
|
70
|
+
'控制面',
|
|
71
|
+
`- Legacy Trust: ${formatNumber(summary.legacyTrust.score)}/100(阶段 ${formatStage(summary.legacyTrust.stage)},legacy/frozen,${summary.legacyTrust.rewardPolicy})`,
|
|
72
|
+
`- Runtime Trust Truth: score ${formatNumber(summary.runtime.currentTrustScore)},classification ${summary.runtime.workspaceState.trustClassification},frozen ${summary.runtime.workspaceState.frozen === null ? '--' : String(summary.runtime.workspaceState.frozen)}`,
|
|
73
|
+
`- 会话 GFI: 当前 ${formatNumber(summary.gfi.current)},峰值 ${formatNumber(summary.gfi.peak)}(${summary.gfi.dataQuality})`,
|
|
74
|
+
`- GFI 来源: ${formatSources(summary.gfi.sources)}`,
|
|
75
|
+
`- Pain Flag: ${summary.pain.activeFlag ? 'active' : 'inactive'}${summary.pain.activeFlagSource ? `(${summary.pain.activeFlagSource})` : ''}`,
|
|
76
|
+
`- 最近 Pain 信号: ${summary.pain.lastSignal ? `${summary.pain.lastSignal.source}${summary.pain.lastSignal.reason ? ` - ${summary.pain.lastSignal.reason}` : ''}` : '--'}`,
|
|
77
|
+
`- Gate 事件: block ${formatNumber(summary.gate.recentBlocks)},bypass ${formatNumber(summary.gate.recentBypasses)}(${summary.gate.dataQuality})`,
|
|
92
78
|
'',
|
|
93
|
-
'
|
|
94
|
-
`-
|
|
95
|
-
`- Directive
|
|
96
|
-
`-
|
|
97
|
-
`-
|
|
79
|
+
'进化',
|
|
80
|
+
`- 队列: pending ${summary.evolution.queue.pending},in_progress ${summary.evolution.queue.inProgress},completed ${summary.evolution.queue.completed}(${summary.evolution.dataQuality})`,
|
|
81
|
+
`- Legacy Directive File: ${summary.phase3.legacyDirectiveFilePresent ? 'present' : 'missing'} (兼容仅显示产物)`,
|
|
82
|
+
`- 注:Legacy directive file 不是 Phase 3 合格性的真实源。队列是唯一权威的执行真实源。`,
|
|
83
|
+
`- Active Evolution Task: ${summary.evolution.directive.taskPreview ?? '--'}`,
|
|
84
|
+
`- Phase 3: ready ${summary.phase3.phase3ShadowEligible ? 'yes' : 'no'},queueTruthReady ${summary.phase3.queueTruthReady ? 'yes' : 'no'},trustInputReady ${summary.phase3.trustInputReady ? 'yes' : 'no'},eligible ${summary.phase3.evolutionEligible},reference_only ${summary.phase3.evolutionReferenceOnly},rejected ${summary.phase3.evolutionRejected}${summary.phase3.evolutionReferenceOnlyReasons.length > 0 ? `(reference ${summary.phase3.evolutionReferenceOnlyReasons.slice(0, 2).join(', ')})` : ''}${summary.phase3.evolutionRejectedReasons.length > 0 ? `(${summary.phase3.evolutionRejectedReasons.slice(0, 3).join(', ')})` : ''}${summary.phase3.trustRejectedReasons.length > 0 ? `;trust ${summary.phase3.trustRejectedReasons.slice(0, 2).join(', ')}` : ''}`,
|
|
85
|
+
`- Phase 3 Legacy Directive File: ${summary.phase3.directiveStatus} (${summary.phase3.directiveIgnoredReason})`,
|
|
98
86
|
'',
|
|
99
|
-
'
|
|
100
|
-
`-
|
|
101
|
-
`-
|
|
102
|
-
`-
|
|
103
|
-
`-
|
|
104
|
-
`-
|
|
87
|
+
'原则统计',
|
|
88
|
+
`- 候选原则: ${stats.candidateCount}`,
|
|
89
|
+
`- 观察期原则: ${stats.probationCount}`,
|
|
90
|
+
`- 生效原则: ${stats.activeCount}`,
|
|
91
|
+
`- 已废弃原则: ${stats.deprecatedCount}`,
|
|
92
|
+
`- 最近晋升: ${stats.lastPromotedAt ?? '无'}`,
|
|
105
93
|
'',
|
|
106
|
-
'
|
|
107
|
-
`-
|
|
108
|
-
`- Session: ${sessionId ?? '--'}
|
|
109
|
-
`-
|
|
94
|
+
'元数据',
|
|
95
|
+
`- 工作区: ${workspaceDir}`,
|
|
96
|
+
`- Session: ${sessionId ?? '--'}(${summary.metadata.selectedSessionReason})`,
|
|
97
|
+
`- 生成时间: ${summary.metadata.generatedAt}`,
|
|
110
98
|
];
|
|
111
99
|
if (warnings.length > 0) {
|
|
112
100
|
lines.push('', '警告');
|
package/dist/commands/focus.js
CHANGED
|
@@ -9,10 +9,8 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import * as fs from 'fs';
|
|
11
11
|
import * as path from 'path';
|
|
12
|
-
import { randomUUID } from 'node:crypto';
|
|
13
12
|
import { WorkspaceContext } from '../core/workspace-context.js';
|
|
14
|
-
import { getHistoryDir, backupToHistory, cleanupHistory, extractVersion, extractDate, } from '../core/focus-history.js';
|
|
15
|
-
import { createAgentSpawnTool } from '../tools/agent-spawn.js';
|
|
13
|
+
import { getHistoryDir, backupToHistory, cleanupHistory, extractVersion, extractDate, extractMilestones, archiveMilestonesToDaily, cleanupStaleInfo, } from '../core/focus-history.js';
|
|
16
14
|
/**
|
|
17
15
|
* 清理 Markdown 代码块围栏
|
|
18
16
|
* 移除开头的 ```lang 和结尾的 ```
|
|
@@ -45,10 +43,14 @@ function getWorkspaceDir(ctx) {
|
|
|
45
43
|
* - 移除:当前任务中已完成的项(- [x])超过 3 个时
|
|
46
44
|
* - 移除:P0 章节如果全部完成
|
|
47
45
|
* - 保留:参考章节
|
|
46
|
+
* - 清理:Working Memory 超过 10 条记录时保留最近 10 条
|
|
47
|
+
* - 验证:文件引用指向不存在的文件时移除
|
|
48
48
|
*/
|
|
49
|
-
function compressFocusContent(content) {
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
function compressFocusContent(content, workspaceDir) {
|
|
50
|
+
// 首先使用 cleanupStaleInfo 进行基础清理
|
|
51
|
+
let result = cleanupStaleInfo(content, workspaceDir);
|
|
52
|
+
const lines = result.split('\n');
|
|
53
|
+
const output = [];
|
|
52
54
|
let currentSection = '';
|
|
53
55
|
let inP0Section = false;
|
|
54
56
|
let p0AllCompleted = true;
|
|
@@ -59,7 +61,7 @@ function compressFocusContent(content) {
|
|
|
59
61
|
if (inP0Section && p0Lines.length > 0) {
|
|
60
62
|
if (!skipIfCompleted || !p0AllCompleted) {
|
|
61
63
|
// P0 有未完成任务,保留 P0 内容
|
|
62
|
-
|
|
64
|
+
output.push(...p0Lines);
|
|
63
65
|
}
|
|
64
66
|
// 重置状态
|
|
65
67
|
p0Lines = [];
|
|
@@ -86,7 +88,7 @@ function compressFocusContent(content) {
|
|
|
86
88
|
// 离开 P0 章节
|
|
87
89
|
flushP0Lines(true); // P0 完成时跳过,未完成时保留
|
|
88
90
|
currentSection = 'current';
|
|
89
|
-
|
|
91
|
+
output.push(line);
|
|
90
92
|
continue;
|
|
91
93
|
}
|
|
92
94
|
else if (/^#{1,3}\s*.*当前任务|🔄/.test(trimmedLine)) {
|
|
@@ -120,11 +122,11 @@ function compressFocusContent(content) {
|
|
|
120
122
|
}
|
|
121
123
|
}
|
|
122
124
|
}
|
|
123
|
-
|
|
125
|
+
output.push(line);
|
|
124
126
|
}
|
|
125
127
|
// 循环结束后,刷新剩余的 P0 章节
|
|
126
128
|
flushP0Lines(false); // 保留未完成的 P0
|
|
127
|
-
return
|
|
129
|
+
return output.join('\n');
|
|
128
130
|
}
|
|
129
131
|
/**
|
|
130
132
|
* 显示 CURRENT_FOCUS 状态
|
|
@@ -237,144 +239,26 @@ async function compressFocus(workspaceDir, isZh, api) {
|
|
|
237
239
|
? `✅ 当前文件仅 ${oldLines} 行,无需压缩\n\n💡 文件少于 40 行时不建议压缩`
|
|
238
240
|
: `✅ Current file has only ${oldLines} lines, no need to compress\n\n💡 Compression not recommended for files under 40 lines`;
|
|
239
241
|
}
|
|
240
|
-
//
|
|
242
|
+
// 1. 提取里程碑
|
|
243
|
+
const milestones = extractMilestones(oldContent);
|
|
244
|
+
// 2. 归档里程碑到 daily memory(而非 MEMORY.md)
|
|
245
|
+
const archivePath = archiveMilestonesToDaily(workspaceDir, milestones, oldVersion);
|
|
246
|
+
const milestonesArchived = archivePath !== null;
|
|
247
|
+
// 3. 备份当前版本
|
|
241
248
|
const backupPath = backupToHistory(focusPath, oldContent);
|
|
242
|
-
// 清理过期历史
|
|
249
|
+
// 4. 清理过期历史
|
|
243
250
|
cleanupHistory(focusPath);
|
|
244
|
-
//
|
|
245
|
-
// 获取 MEMORY.md 路径
|
|
246
|
-
const memoryPath = wctx.resolve('MEMORY_MD');
|
|
247
|
-
const compressPrompt = isZh
|
|
248
|
-
? `你是一个专业的项目文档压缩助手。请压缩以下 CURRENT_FOCUS.md 文件内容。
|
|
249
|
-
|
|
250
|
-
**重要:在压缩前,你需要提取重要里程碑信息!**
|
|
251
|
-
|
|
252
|
-
**第一步:提取里程碑**
|
|
253
|
-
从原始内容中识别已完成的里程碑,这些信息需要保存到记忆文件中。
|
|
254
|
-
|
|
255
|
-
**第二步:压缩文件**
|
|
256
|
-
压缩规则:
|
|
257
|
-
1. 保留标题、元数据行(版本、状态、日期)
|
|
258
|
-
2. 保留"📍 状态快照"章节(完整)
|
|
259
|
-
3. 保留"➡️ 下一步"章节(完整,这是最重要的信息)
|
|
260
|
-
4. 保留"📎 参考"章节(完整)
|
|
261
|
-
5. 对于"🔄 当前任务"章节:
|
|
262
|
-
- 如果 P0/P1 等子章节全部完成,合并为简短"已完成里程碑"列表(最多5项)
|
|
263
|
-
- 保留所有未完成任务(- [ ])
|
|
264
|
-
- 已完成任务最多保留 3 个最近的,其余移除
|
|
265
|
-
6. 移除重复信息和冗余描述
|
|
266
|
-
7. 保持 Markdown 格式和语义连贯
|
|
267
|
-
|
|
268
|
-
**目标:** 将文件压缩到 40 行以内。
|
|
269
|
-
|
|
270
|
-
**原始内容:**
|
|
271
|
-
\`\`\`markdown
|
|
272
|
-
${oldContent}
|
|
273
|
-
\`\`\`
|
|
274
|
-
|
|
275
|
-
**输出格式(必须严格遵循):**
|
|
276
|
-
\`\`\`
|
|
277
|
-
===MEMORY===
|
|
278
|
-
[需要追加到 memory/MEMORY.md 的里程碑内容,格式:]
|
|
279
|
-
## {YYYY-MM-DD} 里程碑
|
|
280
|
-
- [里程碑1]
|
|
281
|
-
- [里程碑2]
|
|
282
|
-
...
|
|
283
|
-
===COMPRESSED===
|
|
284
|
-
[压缩后的 CURRENT_FOCUS.md 内容]
|
|
285
|
-
\`\`\`
|
|
286
|
-
|
|
287
|
-
如果没有需要记录的里程碑,===MEMORY=== 部分留空。`
|
|
288
|
-
: `You are a professional project document compression assistant. Please compress the following CURRENT_FOCUS.md file.
|
|
289
|
-
|
|
290
|
-
**IMPORTANT: Extract milestones before compression!**
|
|
291
|
-
|
|
292
|
-
**Step 1: Extract Milestones**
|
|
293
|
-
Identify completed milestones from the original content that should be saved to memory.
|
|
294
|
-
|
|
295
|
-
**Step 2: Compress File**
|
|
296
|
-
Compression Rules:
|
|
297
|
-
1. Keep title, metadata lines (version, status, date)
|
|
298
|
-
2. Keep "📍 Status Snapshot" section (complete)
|
|
299
|
-
3. Keep "➡️ Next Steps" section (complete, this is the most important)
|
|
300
|
-
4. Keep "📎 References" section (complete)
|
|
301
|
-
5. For "🔄 Current Tasks" section:
|
|
302
|
-
- If P0/P1 subsections are all completed, merge into a short "Completed Milestones" list (max 5 items)
|
|
303
|
-
- Keep all incomplete tasks (- [ ])
|
|
304
|
-
- Keep at most 3 recent completed tasks, remove the rest
|
|
305
|
-
6. Remove duplicate info and redundant descriptions
|
|
306
|
-
7. Maintain Markdown format and semantic coherence
|
|
307
|
-
|
|
308
|
-
**Goal:** Compress the file to under 40 lines.
|
|
309
|
-
|
|
310
|
-
**Original Content:**
|
|
311
|
-
\`\`\`markdown
|
|
312
|
-
${oldContent}
|
|
313
|
-
\`\`\`
|
|
314
|
-
|
|
315
|
-
**Output Format (must follow strictly):**
|
|
316
|
-
\`\`\`
|
|
317
|
-
===MEMORY===
|
|
318
|
-
[Content to append to memory/MEMORY.md, format:]
|
|
319
|
-
## {YYYY-MM-DD} Milestones
|
|
320
|
-
- [milestone 1]
|
|
321
|
-
- [milestone 2]
|
|
322
|
-
...
|
|
323
|
-
===COMPRESSED===
|
|
324
|
-
[Compressed CURRENT_FOCUS.md content]
|
|
325
|
-
\`\`\`
|
|
326
|
-
|
|
327
|
-
If no milestones to record, leave ===MEMORY=== section empty.`;
|
|
251
|
+
// 5. 压缩内容
|
|
328
252
|
let compressedContent;
|
|
329
|
-
let usedAI = false;
|
|
330
|
-
let memoryUpdated = false;
|
|
331
253
|
try {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
const result = await tool.execute(`focus-compress-${randomUUID()}`, {
|
|
335
|
-
agentType: 'reporter', // 使用 reporter 类型,适合总结和压缩
|
|
336
|
-
task: compressPrompt,
|
|
337
|
-
});
|
|
338
|
-
// 解析输出,提取 MEMORY 和 COMPRESSED 部分
|
|
339
|
-
const resultText = result?.content?.[0]?.text || '';
|
|
340
|
-
if (resultText.trim()) {
|
|
341
|
-
const memoryMatch = resultText.match(/===MEMORY===([\s\S]*?)===COMPRESSED===/);
|
|
342
|
-
const compressedMatch = resultText.match(/===COMPRESSED===([\s\S]*?)$/);
|
|
343
|
-
if (compressedMatch && compressedMatch[1].trim()) {
|
|
344
|
-
// 清理 Markdown 代码块围栏
|
|
345
|
-
compressedContent = stripMarkdownFence(compressedMatch[1]);
|
|
346
|
-
usedAI = true;
|
|
347
|
-
// 写入记忆文件(MEMORY.md 在根目录,无需创建目录)
|
|
348
|
-
if (memoryMatch && memoryMatch[1].trim()) {
|
|
349
|
-
// 清理 Markdown 代码块围栏
|
|
350
|
-
const memoryContent = stripMarkdownFence(memoryMatch[1]);
|
|
351
|
-
// 追加到 MEMORY.md
|
|
352
|
-
const existingMemory = fs.existsSync(memoryPath)
|
|
353
|
-
? fs.readFileSync(memoryPath, 'utf-8')
|
|
354
|
-
: '';
|
|
355
|
-
const newMemory = existingMemory
|
|
356
|
-
? `${existingMemory}\n\n${memoryContent}`
|
|
357
|
-
: memoryContent;
|
|
358
|
-
fs.writeFileSync(memoryPath, newMemory, 'utf-8');
|
|
359
|
-
memoryUpdated = true;
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
else {
|
|
363
|
-
// 无法解析输出,回退到简单压缩
|
|
364
|
-
compressedContent = compressFocusContent(oldContent);
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
else {
|
|
368
|
-
// 子智能体返回空,回退到简单压缩
|
|
369
|
-
compressedContent = compressFocusContent(oldContent);
|
|
370
|
-
}
|
|
254
|
+
compressedContent = compressFocusContent(oldContent, workspaceDir);
|
|
255
|
+
api.logger?.info?.(`[PD:Focus] Compressed CURRENT_FOCUS from ${oldLines} lines`);
|
|
371
256
|
}
|
|
372
257
|
catch (error) {
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
compressedContent = compressFocusContent(oldContent);
|
|
258
|
+
api.logger?.error?.(`[PD:Focus] Compression failed: ${String(error)}`);
|
|
259
|
+
compressedContent = oldContent;
|
|
376
260
|
}
|
|
377
|
-
// 更新版本号和日期
|
|
261
|
+
// 6. 更新版本号和日期
|
|
378
262
|
const versionParts = oldVersion.split('.');
|
|
379
263
|
const majorVersion = parseInt(versionParts[0], 10) || 1;
|
|
380
264
|
const newVersion = `${majorVersion + 1}`;
|
|
@@ -385,17 +269,10 @@ If no milestones to record, leave ===MEMORY=== section empty.`;
|
|
|
385
269
|
const newLines = newContent.split('\n').length;
|
|
386
270
|
const savedLines = oldLines - newLines;
|
|
387
271
|
fs.writeFileSync(focusPath, newContent, 'utf-8');
|
|
388
|
-
const
|
|
272
|
+
const milestoneNote = milestonesArchived
|
|
389
273
|
? isZh
|
|
390
|
-
?
|
|
391
|
-
:
|
|
392
|
-
: isZh
|
|
393
|
-
? '📋 使用规则压缩'
|
|
394
|
-
: '📋 Rule-based compression';
|
|
395
|
-
const memoryNote = memoryUpdated
|
|
396
|
-
? isZh
|
|
397
|
-
? '📝 已将里程碑写入 MEMORY.md'
|
|
398
|
-
: '📝 Milestones saved to MEMORY.md'
|
|
274
|
+
? `📝 里程碑已归档到 memory/${today}.md`
|
|
275
|
+
: `📝 Milestones archived to memory/${today}.md`
|
|
399
276
|
: '';
|
|
400
277
|
if (isZh) {
|
|
401
278
|
return `✅ **压缩完成**
|
|
@@ -409,8 +286,7 @@ If no milestones to record, leave ===MEMORY=== section empty.`;
|
|
|
409
286
|
| 节省 | ${savedLines} 行 |
|
|
410
287
|
| 备份文件 | ${backupPath ? path.basename(backupPath) : '已存在'} |
|
|
411
288
|
|
|
412
|
-
${
|
|
413
|
-
|
|
289
|
+
${milestoneNote ? `${milestoneNote}\n` : ''}
|
|
414
290
|
💡 已压缩版本已备份到历史目录
|
|
415
291
|
💡 输入 \`/pd-focus history\` 查看所有历史版本`;
|
|
416
292
|
}
|
|
@@ -425,8 +301,7 @@ ${methodNote}${memoryNote ? `\n${memoryNote}` : ''}
|
|
|
425
301
|
| Saved | ${savedLines} lines |
|
|
426
302
|
| Backup File | ${backupPath ? path.basename(backupPath) : 'exists'} |
|
|
427
303
|
|
|
428
|
-
${
|
|
429
|
-
|
|
304
|
+
${milestoneNote ? `${milestoneNote}\n` : ''}
|
|
430
305
|
💡 Compressed version backed up to history
|
|
431
306
|
💡 Type \`/pd-focus history\` to view all versions`;
|
|
432
307
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized Runtime Defaults
|
|
3
|
+
*
|
|
4
|
+
* All runtime-related constants that were previously scattered across modules.
|
|
5
|
+
* Centralizing these makes it easier to tune behavior and understand limits.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Trajectory gate block retry settings
|
|
9
|
+
* Used when trajectory recording fails and needs to retry
|
|
10
|
+
*/
|
|
11
|
+
export declare const TRAJECTORY_GATE_BLOCK_RETRY_DELAY_MS = 250;
|
|
12
|
+
export declare const TRAJECTORY_GATE_BLOCK_MAX_RETRIES = 3;
|
|
13
|
+
/**
|
|
14
|
+
* Thinking checkpoint defaults (P-10)
|
|
15
|
+
*/
|
|
16
|
+
export declare const THINKING_CHECKPOINT_WINDOW_MS: number;
|
|
17
|
+
export declare const THINKING_CHECKPOINT_DEFAULT_HIGH_RISK_TOOLS: readonly ["run_shell_command", "delete_file", "move_file"];
|
|
18
|
+
/**
|
|
19
|
+
* Large change threshold for GFI gate adjustments
|
|
20
|
+
*/
|
|
21
|
+
export declare const GFI_LARGE_CHANGE_LINES = 50;
|
|
22
|
+
/**
|
|
23
|
+
* Agent spawn GFI threshold (critically high = no spawn)
|
|
24
|
+
*/
|
|
25
|
+
export declare const AGENT_SPAWN_GFI_THRESHOLD = 90;
|
|
26
|
+
/**
|
|
27
|
+
* Evolution worker polling intervals
|
|
28
|
+
*/
|
|
29
|
+
export declare const EVOLUTION_WORKER_POLL_INTERVAL_MS: number;
|
|
30
|
+
export declare const EVOLUTION_QUEUE_BATCH_SIZE = 10;
|
|
31
|
+
/**
|
|
32
|
+
* Session tracker settings
|
|
33
|
+
*/
|
|
34
|
+
export declare const SESSION_TOKEN_WARNING_THRESHOLD = 8000;
|
|
35
|
+
export declare const SESSION_MAX_IDLE_MS: number;
|
|
36
|
+
/**
|
|
37
|
+
* Event log buffer settings
|
|
38
|
+
*/
|
|
39
|
+
export declare const EVENT_LOG_BUFFER_SIZE = 20;
|
|
40
|
+
export declare const EVENT_LOG_FLUSH_INTERVAL_MS: number;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized Runtime Defaults
|
|
3
|
+
*
|
|
4
|
+
* All runtime-related constants that were previously scattered across modules.
|
|
5
|
+
* Centralizing these makes it easier to tune behavior and understand limits.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Trajectory gate block retry settings
|
|
9
|
+
* Used when trajectory recording fails and needs to retry
|
|
10
|
+
*/
|
|
11
|
+
export const TRAJECTORY_GATE_BLOCK_RETRY_DELAY_MS = 250;
|
|
12
|
+
export const TRAJECTORY_GATE_BLOCK_MAX_RETRIES = 3;
|
|
13
|
+
/**
|
|
14
|
+
* Thinking checkpoint defaults (P-10)
|
|
15
|
+
*/
|
|
16
|
+
export const THINKING_CHECKPOINT_WINDOW_MS = 5 * 60 * 1000; // 5 minutes
|
|
17
|
+
export const THINKING_CHECKPOINT_DEFAULT_HIGH_RISK_TOOLS = [
|
|
18
|
+
'run_shell_command',
|
|
19
|
+
'delete_file',
|
|
20
|
+
'move_file',
|
|
21
|
+
];
|
|
22
|
+
/**
|
|
23
|
+
* Large change threshold for GFI gate adjustments
|
|
24
|
+
*/
|
|
25
|
+
export const GFI_LARGE_CHANGE_LINES = 50;
|
|
26
|
+
/**
|
|
27
|
+
* Agent spawn GFI threshold (critically high = no spawn)
|
|
28
|
+
*/
|
|
29
|
+
export const AGENT_SPAWN_GFI_THRESHOLD = 90;
|
|
30
|
+
/**
|
|
31
|
+
* Evolution worker polling intervals
|
|
32
|
+
*/
|
|
33
|
+
export const EVOLUTION_WORKER_POLL_INTERVAL_MS = 15 * 60 * 1000; // 15 minutes
|
|
34
|
+
export const EVOLUTION_QUEUE_BATCH_SIZE = 10;
|
|
35
|
+
/**
|
|
36
|
+
* Session tracker settings
|
|
37
|
+
*/
|
|
38
|
+
export const SESSION_TOKEN_WARNING_THRESHOLD = 8000;
|
|
39
|
+
export const SESSION_MAX_IDLE_MS = 30 * 60 * 1000; // 30 minutes
|
|
40
|
+
/**
|
|
41
|
+
* Event log buffer settings
|
|
42
|
+
*/
|
|
43
|
+
export const EVENT_LOG_BUFFER_SIZE = 20;
|
|
44
|
+
export const EVENT_LOG_FLUSH_INTERVAL_MS = 30 * 1000; // 30 seconds
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain-Specific Errors for Principles Disciple
|
|
3
|
+
*
|
|
4
|
+
* These errors provide semantic meaning to failure modes,
|
|
5
|
+
* making it easier to distinguish between:
|
|
6
|
+
* - Lock contention (resource busy)
|
|
7
|
+
* - Parse/validation failures
|
|
8
|
+
* - Derived state mismatches
|
|
9
|
+
* - Configuration issues
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Base class for all Principles Disciple errors
|
|
13
|
+
*/
|
|
14
|
+
export declare class PdError extends Error {
|
|
15
|
+
readonly code: string;
|
|
16
|
+
constructor(message: string, code: string, options?: {
|
|
17
|
+
cause?: unknown;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Thrown when a resource lock cannot be acquired
|
|
22
|
+
* (e.g., queue, trajectory, evolution file)
|
|
23
|
+
*/
|
|
24
|
+
export declare class LockUnavailableError extends PdError {
|
|
25
|
+
constructor(resource: string, scope: string, options?: {
|
|
26
|
+
cause?: unknown;
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Thrown when a path key cannot be resolved
|
|
31
|
+
*/
|
|
32
|
+
export declare class PathResolutionError extends PdError {
|
|
33
|
+
constructor(key: string, options?: {
|
|
34
|
+
cause?: unknown;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Thrown when a workspace cannot be found
|
|
39
|
+
*/
|
|
40
|
+
export declare class WorkspaceNotFoundError extends PdError {
|
|
41
|
+
constructor(workspace: string, options?: {
|
|
42
|
+
cause?: unknown;
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Thrown when a required sample cannot be found
|
|
47
|
+
*/
|
|
48
|
+
export declare class SampleNotFoundError extends PdError {
|
|
49
|
+
constructor(sampleId: string, options?: {
|
|
50
|
+
cause?: unknown;
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Thrown when configuration is invalid or missing required fields
|
|
55
|
+
*/
|
|
56
|
+
export declare class ConfigurationError extends PdError {
|
|
57
|
+
constructor(message: string, options?: {
|
|
58
|
+
cause?: unknown;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Thrown when prompt/logger dependencies are unavailable
|
|
63
|
+
*/
|
|
64
|
+
export declare class DependencyError extends PdError {
|
|
65
|
+
constructor(component: string, message: string, options?: {
|
|
66
|
+
cause?: unknown;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Thrown when evolution worker encounters a processing error
|
|
71
|
+
*/
|
|
72
|
+
export declare class EvolutionProcessingError extends PdError {
|
|
73
|
+
constructor(message: string, options?: {
|
|
74
|
+
cause?: unknown;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Thrown when trajectory operations fail
|
|
79
|
+
*/
|
|
80
|
+
export declare class TrajectoryError extends PdError {
|
|
81
|
+
constructor(message: string, options?: {
|
|
82
|
+
cause?: unknown;
|
|
83
|
+
});
|
|
84
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain-Specific Errors for Principles Disciple
|
|
3
|
+
*
|
|
4
|
+
* These errors provide semantic meaning to failure modes,
|
|
5
|
+
* making it easier to distinguish between:
|
|
6
|
+
* - Lock contention (resource busy)
|
|
7
|
+
* - Parse/validation failures
|
|
8
|
+
* - Derived state mismatches
|
|
9
|
+
* - Configuration issues
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Base class for all Principles Disciple errors
|
|
13
|
+
*/
|
|
14
|
+
export class PdError extends Error {
|
|
15
|
+
code;
|
|
16
|
+
constructor(message, code, options) {
|
|
17
|
+
super(message, options);
|
|
18
|
+
this.code = code;
|
|
19
|
+
this.name = 'PdError';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Thrown when a resource lock cannot be acquired
|
|
24
|
+
* (e.g., queue, trajectory, evolution file)
|
|
25
|
+
*/
|
|
26
|
+
export class LockUnavailableError extends PdError {
|
|
27
|
+
constructor(resource, scope, options) {
|
|
28
|
+
super(`[PD:Lock] ${scope}: queue lock unavailable for ${resource}`, 'LOCK_UNAVAILABLE', options);
|
|
29
|
+
this.name = 'LockUnavailableError';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Thrown when a path key cannot be resolved
|
|
34
|
+
*/
|
|
35
|
+
export class PathResolutionError extends PdError {
|
|
36
|
+
constructor(key, options) {
|
|
37
|
+
super(`[PD:Path] Unknown path key: ${key}`, 'PATH_RESOLUTION_ERROR', options);
|
|
38
|
+
this.name = 'PathResolutionError';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Thrown when a workspace cannot be found
|
|
43
|
+
*/
|
|
44
|
+
export class WorkspaceNotFoundError extends PdError {
|
|
45
|
+
constructor(workspace, options) {
|
|
46
|
+
super(`[PD:Workspace] Workspace not found: ${workspace}`, 'WORKSPACE_NOT_FOUND', options);
|
|
47
|
+
this.name = 'WorkspaceNotFoundError';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Thrown when a required sample cannot be found
|
|
52
|
+
*/
|
|
53
|
+
export class SampleNotFoundError extends PdError {
|
|
54
|
+
constructor(sampleId, options) {
|
|
55
|
+
super(`[PD:Sample] Correction sample not found: ${sampleId}`, 'SAMPLE_NOT_FOUND', options);
|
|
56
|
+
this.name = 'SampleNotFoundError';
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Thrown when configuration is invalid or missing required fields
|
|
61
|
+
*/
|
|
62
|
+
export class ConfigurationError extends PdError {
|
|
63
|
+
constructor(message, options) {
|
|
64
|
+
super(`[PD:Config] ${message}`, 'CONFIGURATION_ERROR', options);
|
|
65
|
+
this.name = 'ConfigurationError';
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Thrown when prompt/logger dependencies are unavailable
|
|
70
|
+
*/
|
|
71
|
+
export class DependencyError extends PdError {
|
|
72
|
+
constructor(component, message, options) {
|
|
73
|
+
super(`[PD:${component}] ${message}`, 'DEPENDENCY_ERROR', options);
|
|
74
|
+
this.name = 'DependencyError';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Thrown when evolution worker encounters a processing error
|
|
79
|
+
*/
|
|
80
|
+
export class EvolutionProcessingError extends PdError {
|
|
81
|
+
constructor(message, options) {
|
|
82
|
+
super(`[PD:Evolution] ${message}`, 'EVOLUTION_PROCESSING_ERROR', options);
|
|
83
|
+
this.name = 'EvolutionProcessingError';
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Thrown when trajectory operations fail
|
|
88
|
+
*/
|
|
89
|
+
export class TrajectoryError extends PdError {
|
|
90
|
+
constructor(message, options) {
|
|
91
|
+
super(`[PD:Trajectory] ${message}`, 'TRAJECTORY_ERROR', options);
|
|
92
|
+
this.name = 'TrajectoryError';
|
|
93
|
+
}
|
|
94
|
+
}
|