principles-disciple 1.7.1 → 1.7.3
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 +3 -3
- 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
|
@@ -2,7 +2,7 @@
|
|
|
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.3",
|
|
6
6
|
"skills": [
|
|
7
7
|
"./skills"
|
|
8
8
|
],
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"forced"
|
|
55
55
|
],
|
|
56
56
|
"default": "auto",
|
|
57
|
-
"description": "auto: 遇到困难自动触发; forced: 每次回答前都强制反思(极耗时间,不推荐)"
|
|
57
|
+
"description": "auto: 遇到困难自动触发; forced: 每次回答前都强制反思 (极耗时间,不推荐)"
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
}
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"placeholder": "medium"
|
|
70
70
|
},
|
|
71
71
|
"riskPaths": {
|
|
72
|
-
"label": "
|
|
72
|
+
"label": "⚠️ 绝对高危目录 (空表示不设限)"
|
|
73
73
|
},
|
|
74
74
|
"deep_reflection": {
|
|
75
75
|
"label": "💡 AI 深度反思功能"
|