principles-disciple 1.7.1 → 1.7.2
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/constants/tools.d.ts +17 -0
- package/dist/constants/tools.js +54 -0
- package/dist/core/event-log.d.ts +4 -0
- package/dist/core/event-log.js +62 -118
- package/dist/core/evolution-engine.d.ts +3 -4
- package/dist/core/evolution-engine.js +60 -118
- package/dist/core/migration.js +1 -1
- package/dist/core/session-tracker.d.ts +1 -0
- package/dist/core/session-tracker.js +39 -11
- package/dist/core/trust-engine.d.ts +1 -2
- package/dist/core/trust-engine.js +4 -23
- package/dist/hooks/gate.js +4 -25
- package/dist/hooks/prompt.js +12 -1
- package/dist/hooks/subagent.js +109 -63
- package/dist/service/control-ui-query-service.d.ts +2 -0
- package/dist/service/control-ui-query-service.js +2 -0
- package/dist/service/evolution-worker.d.ts +12 -8
- package/dist/service/evolution-worker.js +153 -123
- package/dist/service/runtime-summary-service.d.ts +4 -0
- package/dist/service/runtime-summary-service.js +43 -4
- package/dist/tools/agent-spawn.js +23 -0
- package/dist/utils/file-lock.d.ts +7 -0
- package/dist/utils/file-lock.js +66 -27
- package/openclaw.plugin.json +13 -12
- package/package.json +1 -1
package/dist/utils/file-lock.js
CHANGED
|
@@ -10,6 +10,16 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import * as fs from 'fs';
|
|
12
12
|
import * as path from 'path';
|
|
13
|
+
export class LockAcquisitionError extends Error {
|
|
14
|
+
filePath;
|
|
15
|
+
lockPath;
|
|
16
|
+
constructor(message, filePath, lockPath) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = 'LockAcquisitionError';
|
|
19
|
+
this.filePath = filePath;
|
|
20
|
+
this.lockPath = lockPath;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
13
23
|
/** 默认锁选项 */
|
|
14
24
|
const DEFAULT_OPTIONS = {
|
|
15
25
|
maxRetries: 50,
|
|
@@ -134,15 +144,39 @@ function calculateBackoff(attempt, baseMs, maxMs) {
|
|
|
134
144
|
const jitter = exponentialDelay * 0.2 * Math.random();
|
|
135
145
|
return Math.floor(exponentialDelay + jitter);
|
|
136
146
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
147
|
+
function sleep(ms) {
|
|
148
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
149
|
+
}
|
|
140
150
|
function sleepSync(ms) {
|
|
141
151
|
const end = Date.now() + ms;
|
|
142
152
|
while (Date.now() < end) {
|
|
143
|
-
// busy wait
|
|
153
|
+
// busy wait for synchronous retry
|
|
144
154
|
}
|
|
145
155
|
}
|
|
156
|
+
function buildLockError(filePath, lockPath) {
|
|
157
|
+
const holderPid = readLockPid(lockPath);
|
|
158
|
+
const holderStatus = holderPid !== null
|
|
159
|
+
? (isProcessAlive(holderPid) ? `alive (PID ${holderPid})` : `dead (PID ${holderPid})`)
|
|
160
|
+
: 'unknown';
|
|
161
|
+
return new LockAcquisitionError(`Failed to acquire lock for ${filePath}. Lock holder: ${holderStatus}.`, filePath, lockPath);
|
|
162
|
+
}
|
|
163
|
+
function tryAcquireWithStaleCleanup(filePath, opts, pid) {
|
|
164
|
+
const lockPath = filePath + opts.lockSuffix;
|
|
165
|
+
if (tryAcquireLock(lockPath, pid)) {
|
|
166
|
+
const actualPid = readLockPid(lockPath);
|
|
167
|
+
if (actualPid === pid) {
|
|
168
|
+
return { lockPath, pid, acquiredAt: Date.now() };
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
cleanupStaleLock(lockPath, opts.lockStaleMs);
|
|
172
|
+
if (tryAcquireLock(lockPath, pid)) {
|
|
173
|
+
const actualPid = readLockPid(lockPath);
|
|
174
|
+
if (actualPid === pid) {
|
|
175
|
+
return { lockPath, pid, acquiredAt: Date.now() };
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
146
180
|
/**
|
|
147
181
|
* 获取文件锁
|
|
148
182
|
*
|
|
@@ -153,37 +187,33 @@ function sleepSync(ms) {
|
|
|
153
187
|
*/
|
|
154
188
|
export function acquireLock(filePath, options = {}) {
|
|
155
189
|
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
156
|
-
const lockPath = filePath + opts.lockSuffix;
|
|
157
190
|
const pid = process.pid;
|
|
158
191
|
for (let attempt = 0; attempt < opts.maxRetries; attempt++) {
|
|
159
|
-
|
|
160
|
-
if (
|
|
161
|
-
|
|
162
|
-
const actualPid = readLockPid(lockPath);
|
|
163
|
-
if (actualPid === pid) {
|
|
164
|
-
return {
|
|
165
|
-
lockPath,
|
|
166
|
-
pid,
|
|
167
|
-
acquiredAt: Date.now(),
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
// PID 不匹配,说明被其他进程抢占,继续重试
|
|
192
|
+
const ctx = tryAcquireWithStaleCleanup(filePath, opts, pid);
|
|
193
|
+
if (ctx) {
|
|
194
|
+
return ctx;
|
|
171
195
|
}
|
|
172
|
-
// 3. 获取失败,检查是否需要清理过期锁
|
|
173
|
-
cleanupStaleLock(lockPath, opts.lockStaleMs);
|
|
174
|
-
// 4. 计算退避时间并等待
|
|
175
196
|
if (attempt < opts.maxRetries - 1) {
|
|
176
197
|
const delay = calculateBackoff(attempt, opts.baseRetryDelayMs, opts.maxRetryDelayMs);
|
|
177
198
|
sleepSync(delay);
|
|
178
199
|
}
|
|
179
200
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
201
|
+
throw buildLockError(filePath, filePath + opts.lockSuffix);
|
|
202
|
+
}
|
|
203
|
+
export async function acquireLockAsync(filePath, options = {}) {
|
|
204
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
205
|
+
const pid = process.pid;
|
|
206
|
+
for (let attempt = 0; attempt < opts.maxRetries; attempt++) {
|
|
207
|
+
const ctx = tryAcquireWithStaleCleanup(filePath, opts, pid);
|
|
208
|
+
if (ctx) {
|
|
209
|
+
return ctx;
|
|
210
|
+
}
|
|
211
|
+
if (attempt < opts.maxRetries - 1) {
|
|
212
|
+
const delay = calculateBackoff(attempt, opts.baseRetryDelayMs, opts.maxRetryDelayMs);
|
|
213
|
+
await sleep(delay);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
throw buildLockError(filePath, filePath + opts.lockSuffix);
|
|
187
217
|
}
|
|
188
218
|
/**
|
|
189
219
|
* 释放文件锁
|
|
@@ -210,6 +240,15 @@ export function withLock(filePath, fn, options = {}) {
|
|
|
210
240
|
releaseLock(ctx);
|
|
211
241
|
}
|
|
212
242
|
}
|
|
243
|
+
export async function withLockAsync(filePath, fn, options = {}) {
|
|
244
|
+
const ctx = await acquireLockAsync(filePath, options);
|
|
245
|
+
try {
|
|
246
|
+
return await fn();
|
|
247
|
+
}
|
|
248
|
+
finally {
|
|
249
|
+
releaseLock(ctx);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
213
252
|
/**
|
|
214
253
|
* 异步版本的文件锁(使用 Promise 链)
|
|
215
254
|
*
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
2
|
"id": "principles-disciple",
|
|
3
3
|
"name": "Principles Disciple",
|
|
4
4
|
"description": "Evolutionary programming agent framework with strategic guardrails and reflection loops.",
|
|
5
|
-
"version": "1.7.
|
|
5
|
+
"version": "1.7.2",
|
|
6
6
|
"skills": [
|
|
7
7
|
"./skills"
|
|
8
8
|
],
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"zh"
|
|
18
18
|
],
|
|
19
19
|
"default": "zh",
|
|
20
|
-
"description": "
|
|
20
|
+
"description": "绯荤粺鎻愮ず璇嶅拰浜や簰璇█ (榛樿鎺ㄨ崘: zh)"
|
|
21
21
|
},
|
|
22
22
|
"auditLevel": {
|
|
23
23
|
"type": "string",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"high"
|
|
28
28
|
],
|
|
29
29
|
"default": "medium",
|
|
30
|
-
"description": "
|
|
30
|
+
"description": "瀹夊叏闃茬垎绾у埆锛歕n- low: 鏋佸妯″紡锛屽嚑涔庝笉鎷︽埅锛孉I 鍙互鑷敱椋炵繑銆俓n- medium (鎺ㄨ崘): 骞宠 妯″紡锛屽厑璁?AI 澶ц儐灏濊瘯锛屼絾鎷︽埅姣佺伃鎬ф搷浣溿€俓n- high: 涓ユ牸妯″紡锛屾墍鏈夊ぇ鑼冨洿淇敼閮介渶瑕佷綘鏄庣‘鎺堟潈銆?
|
|
31
31
|
},
|
|
32
32
|
"riskPaths": {
|
|
33
33
|
"type": "array",
|
|
@@ -35,17 +35,17 @@
|
|
|
35
35
|
"type": "string"
|
|
36
36
|
},
|
|
37
37
|
"default": [],
|
|
38
|
-
"description": "
|
|
38
|
+
"description": "鑷畾涔夐珮鍗辩洰褰曪紙渚嬪 .git/, prod_db/锛夈€侫I 璇曞浘淇敼杩欎簺鐩綍鍓嶏紝灏嗚寮哄埗鎷︽埅骞惰姹傚嚭鍏峰畨鍏ㄨ鍒掋€?
|
|
39
39
|
},
|
|
40
40
|
"deep_reflection": {
|
|
41
41
|
"type": "object",
|
|
42
42
|
"additionalProperties": false,
|
|
43
|
-
"description": "
|
|
43
|
+
"description": "褰?AI 閬囧埌澶嶆潅闂鎴栬繛缁姤閿欐椂锛屾槸鍚﹀厑璁稿畠鍋滀笅鏉ヨ繘琛屾繁搴﹁嚜鎴戝弽鎬濓紵",
|
|
44
44
|
"properties": {
|
|
45
45
|
"enabled": {
|
|
46
46
|
"type": "boolean",
|
|
47
47
|
"default": true,
|
|
48
|
-
"description": "
|
|
48
|
+
"description": "寮€鍚?AI 娣卞害鍙嶆€濆姛鑳?
|
|
49
49
|
},
|
|
50
50
|
"mode": {
|
|
51
51
|
"type": "string",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"forced"
|
|
55
55
|
],
|
|
56
56
|
"default": "auto",
|
|
57
|
-
"description": "auto:
|
|
57
|
+
"description": "auto: 閬囧埌鍥伴毦鑷姩瑙﹀彂; forced: 姣忔鍥炵瓟鍓嶉兘寮哄埗鍙嶆€?鏋佽€楁椂闂达紝涓嶆帹鑽?"
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
}
|
|
@@ -62,17 +62,18 @@
|
|
|
62
62
|
},
|
|
63
63
|
"uiHints": {
|
|
64
64
|
"language": {
|
|
65
|
-
"label": "
|
|
65
|
+
"label": "浜や簰璇█"
|
|
66
66
|
},
|
|
67
67
|
"auditLevel": {
|
|
68
|
-
"label": "
|
|
68
|
+
"label": "闃茬垎鎷︽埅绾у埆",
|
|
69
69
|
"placeholder": "medium"
|
|
70
70
|
},
|
|
71
71
|
"riskPaths": {
|
|
72
|
-
"label": "
|
|
72
|
+
"label": "鈽狅笍 缁濆楂樺嵄鐩綍 (绌鸿〃绀轰笉璁鹃檺)"
|
|
73
73
|
},
|
|
74
74
|
"deep_reflection": {
|
|
75
|
-
"label": "
|
|
75
|
+
"label": "馃挕 AI 娣卞害鍙嶆€濆姛鑳?
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
|
+
|