evolclaw 2.7.0 → 2.7.1
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/agents/claude-runner.js +2 -1
- package/dist/core/message/message-processor.js +3 -4
- package/dist/core/session/session-manager.js +4 -3
- package/dist/index.js +1 -1
- package/dist/templates/prompts.md +4 -4
- package/dist/types.js +2 -1
- package/dist/utils/cross-platform.js +23 -12
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { query, forkSession as sdkForkSession, getSessionMessages as sdkGetSessionMessages } from '@anthropic-ai/claude-agent-sdk';
|
|
2
2
|
import { ensureDir, resolveAnthropicConfig } from '../config.js';
|
|
3
|
+
import { DEFAULT_PERMISSION_MODE } from '../types.js';
|
|
3
4
|
import path from 'path';
|
|
4
5
|
import fs from 'fs';
|
|
5
6
|
import os from 'os';
|
|
@@ -72,7 +73,7 @@ export class AgentRunner {
|
|
|
72
73
|
apiKey;
|
|
73
74
|
model;
|
|
74
75
|
effort;
|
|
75
|
-
permissionMode =
|
|
76
|
+
permissionMode = DEFAULT_PERMISSION_MODE;
|
|
76
77
|
baseUrl;
|
|
77
78
|
config;
|
|
78
79
|
activeSessions = new Map();
|
|
@@ -8,6 +8,7 @@ import { StreamIdleMonitor } from './stream-idle-monitor.js';
|
|
|
8
8
|
import { logger } from '../../utils/logger.js';
|
|
9
9
|
import { getErrorMessage, classifyError, ErrorType, ERROR_PREFIX, isInfraError, prefixErrorType, isRetryableError } from '../../utils/error-utils.js';
|
|
10
10
|
import { summarizeToolInput } from '../permission.js';
|
|
11
|
+
import { DEFAULT_PERMISSION_MODE } from '../../types.js';
|
|
11
12
|
import { getOwner } from '../../config.js';
|
|
12
13
|
import { getPackageRoot, resolveRoot } from '../../paths.js';
|
|
13
14
|
import { renderPromptSection } from '../../prompts/templates.js';
|
|
@@ -385,10 +386,8 @@ export class MessageProcessor {
|
|
|
385
386
|
? (sessionKey) => this.messageQueue.cancelIntercept(sessionKey)
|
|
386
387
|
: undefined,
|
|
387
388
|
});
|
|
388
|
-
// 设置 per-session
|
|
389
|
-
|
|
390
|
-
const defaultPermMode = role === 'owner' ? 'bypass' : 'auto';
|
|
391
|
-
agent.setMode(session.metadata?.permissionMode ?? defaultPermMode);
|
|
389
|
+
// 设置 per-session 权限模式(默认 bypass,所有角色统一)
|
|
390
|
+
agent.setMode(session.metadata?.permissionMode ?? DEFAULT_PERMISSION_MODE);
|
|
392
391
|
// 标记会话为处理中(实时持久化,重启后可恢复)
|
|
393
392
|
this.sessionManager.markProcessing(session.id);
|
|
394
393
|
logger.info(`[MessageProcessor] session ${session.id} marked as processing task=${taskId}`);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import { DEFAULT_PERMISSION_MODE } from '../../types.js';
|
|
2
3
|
import { ensureDir } from '../../config.js';
|
|
3
4
|
import { resolvePaths } from '../../paths.js';
|
|
4
5
|
import { logger } from '../../utils/logger.js';
|
|
@@ -471,7 +472,7 @@ export class SessionManager {
|
|
|
471
472
|
session.identity = this.resolveIdentity(channel, userId);
|
|
472
473
|
// 新话题会话补写默认权限模式
|
|
473
474
|
if (session.metadata && !session.metadata.permissionMode) {
|
|
474
|
-
session.metadata.permissionMode =
|
|
475
|
+
session.metadata.permissionMode = DEFAULT_PERMISSION_MODE;
|
|
475
476
|
this.db.prepare(`UPDATE sessions SET metadata = ?, updated_at = ? WHERE id = ?`)
|
|
476
477
|
.run(JSON.stringify(session.metadata), Date.now(), session.id);
|
|
477
478
|
}
|
|
@@ -580,9 +581,9 @@ export class SessionManager {
|
|
|
580
581
|
updatedAt: Date.now()
|
|
581
582
|
};
|
|
582
583
|
session.identity = this.resolveIdentity(channel, userId);
|
|
583
|
-
//
|
|
584
|
+
// 写入默认权限模式(统一 bypass,只在首次创建时设置)
|
|
584
585
|
if (!sessionMetadata.permissionMode) {
|
|
585
|
-
sessionMetadata.permissionMode =
|
|
586
|
+
sessionMetadata.permissionMode = DEFAULT_PERMISSION_MODE;
|
|
586
587
|
}
|
|
587
588
|
this.insertSession(session);
|
|
588
589
|
this.eventBus.publish({
|
package/dist/index.js
CHANGED
|
@@ -239,7 +239,7 @@ async function main() {
|
|
|
239
239
|
peerId: peerId || '', peerName, messageId, mentions, threadId,
|
|
240
240
|
// 只在话题场景(threadId 有值)才设置 replyContext;
|
|
241
241
|
// 纯引用回复(rootId 有值但无 threadId)不设置,避免所有回复都带引用头
|
|
242
|
-
replyContext: threadId ? { replyToMessageId: rootId, replyInThread: true } : undefined,
|
|
242
|
+
replyContext: threadId ? { replyToMessageId: rootId ?? threadId, replyInThread: true } : undefined,
|
|
243
243
|
});
|
|
244
244
|
}), (channelId, text, replyContext) => inst.channel.sendMessage(channelId, text, {
|
|
245
245
|
replyToMessageId: replyContext?.replyToMessageId,
|
|
@@ -18,10 +18,10 @@
|
|
|
18
18
|
|
|
19
19
|
## proactive
|
|
20
20
|
|
|
21
|
-
[Proactive 模式]
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
[Proactive 模式] 你的所有文本输出都会被静默丢弃,用户永远看不到。唯一能让用户收到消息的方式:
|
|
22
|
+
调用 Bash 工具执行命令 :evolclaw ctl send "<消息内容>"
|
|
23
|
+
发送文件: evolclaw ctl file <路径>
|
|
24
|
+
可多次调用发送多条消息 ,如果不想回复停止调用即可。
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
---
|
package/dist/types.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// ── Channel config types ──
|
|
2
2
|
// Single-object form: `name` is optional (defaults to channel type name).
|
|
3
3
|
// Array form: `name` is required to distinguish instances.
|
|
4
|
-
|
|
4
|
+
/** Default permission mode applied to new sessions. Change here to affect all roles. */
|
|
5
|
+
export const DEFAULT_PERMISSION_MODE = 'bypass';
|
|
@@ -152,25 +152,36 @@ export function tailFile(filePath) {
|
|
|
152
152
|
child.on('exit', (code) => process.exit(code || 0));
|
|
153
153
|
return { abort: () => child.kill() };
|
|
154
154
|
}
|
|
155
|
-
// Windows: Node.js-based implementation
|
|
155
|
+
// Windows: Node.js-based implementation using stat polling
|
|
156
|
+
// (fs.watch / ReadDirectoryChangesW is unreliable for cross-process appends)
|
|
156
157
|
// Output last 20 lines of existing content
|
|
157
158
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
158
159
|
const lines = content.split('\n');
|
|
159
160
|
const lastLines = lines.slice(-20);
|
|
160
161
|
process.stdout.write(lastLines.join('\n'));
|
|
161
162
|
let position = fs.statSync(filePath).size;
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
163
|
+
const listener = () => {
|
|
164
|
+
try {
|
|
165
|
+
const stat = fs.statSync(filePath);
|
|
166
|
+
if (stat.size < position) {
|
|
167
|
+
// File was truncated (log rotation) — reset and re-read from start
|
|
168
|
+
position = 0;
|
|
169
|
+
}
|
|
170
|
+
if (stat.size > position) {
|
|
171
|
+
const fd = fs.openSync(filePath, 'r');
|
|
172
|
+
const buffer = Buffer.alloc(stat.size - position);
|
|
173
|
+
fs.readSync(fd, buffer, 0, buffer.length, position);
|
|
174
|
+
fs.closeSync(fd);
|
|
175
|
+
process.stdout.write(buffer.toString('utf-8'));
|
|
176
|
+
position = stat.size;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
// File may be briefly unavailable during rotation — ignore and retry next tick
|
|
171
181
|
}
|
|
172
|
-
}
|
|
173
|
-
|
|
182
|
+
};
|
|
183
|
+
fs.watchFile(filePath, { interval: 500, persistent: true }, listener);
|
|
184
|
+
return { abort: () => fs.unwatchFile(filePath, listener) };
|
|
174
185
|
}
|
|
175
186
|
/**
|
|
176
187
|
* Resolve file path from import.meta.url (cross-platform safe).
|
package/package.json
CHANGED