evolclaw 3.1.2 → 3.1.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.
@@ -92,22 +92,12 @@ export class SessionManager {
92
92
  *
93
93
  * 这样保持兼容:不知道 channelType 的 caller 仍可以用 (channel, channelId) 调用。
94
94
  */
95
- resolveChatDir(channel, channelId) {
96
- // 优先尝试从已有目录里找
97
- const dirs = scanChatDirs(this.sessionsDir);
98
- for (const d of dirs) {
99
- if (d.channelId !== channelId)
100
- continue;
101
- // 验证 active.json 或 meta 文件里 channel(实例名)匹配
102
- const active = readJsonFile(path.join(d.dirPath, 'active.json'));
103
- if (active && active.channel === channel)
104
- return d.dirPath;
105
- // 没 active.json 时,看 channelType 是否能匹配 channel
106
- if (!active && d.channelType === channel)
107
- return d.dirPath;
95
+ resolveChatDir(channel, channelId, channelType, selfId) {
96
+ // 必须有明确 channelType 才能确定路径
97
+ if (!channelType) {
98
+ throw new Error(`[SessionManager] resolveChatDir requires channelType. Got channel="${channel}" channelId="${channelId}". Caller must pass channelType (e.g. 'aun', 'feishu').`);
108
99
  }
109
- // Fallback:按 channel channelType 创建(旧路径布局兼容)
110
- return chatDirPath(this.sessionsDir, channel, channelId);
100
+ return chatDirPath(this.sessionsDir, channelType, channelId, selfId);
111
101
  }
112
102
  /**
113
103
  * 给定明确的 channelType + selfId 时直接计算路径(不扫描)。
@@ -117,7 +107,7 @@ export class SessionManager {
117
107
  if (channelType) {
118
108
  return chatDirPath(this.sessionsDir, channelType, channelId, selfId);
119
109
  }
120
- return this.resolveChatDir(channel, channelId);
110
+ return this.resolveChatDirSafe(channel, channelId);
121
111
  }
122
112
  resolveChatDirFromSession(session) {
123
113
  const channelType = session.channelType || session.channel;
@@ -128,25 +118,129 @@ export class SessionManager {
128
118
  return this.resolveChatDirFromSession(session);
129
119
  }
130
120
  /** Like resolveChatDir but also ensures the dir + _threads + _trash exist. */
131
- ensureResolvedChatDir(channel, channelId) {
132
- const dir = this.resolveChatDir(channel, channelId);
121
+ ensureResolvedChatDir(channel, channelId, channelType, selfId) {
122
+ const dir = this.resolveChatDir(channel, channelId, channelType, selfId);
133
123
  fs.mkdirSync(dir, { recursive: true });
134
124
  fs.mkdirSync(path.join(dir, '_threads'), { recursive: true });
135
125
  fs.mkdirSync(path.join(dir, '_trash'), { recursive: true });
136
126
  return dir;
137
127
  }
138
128
  /** 推断给定 chat 的 channelType(优先取 active.json)。无活跃时回落到 channel 实例名。 */
139
- inferChannelType(channel, channelId) {
140
- const active = this.readActive(channel, channelId);
141
- return active?.channelType || channel;
129
+ inferChannelType(channel, channelId, chatDir) {
130
+ if (chatDir) {
131
+ const active = readJsonFile(path.join(chatDir, 'active.json'));
132
+ if (active?.channelType)
133
+ return active.channelType;
134
+ }
135
+ // 扫描已有目录
136
+ const dirs = scanChatDirs(this.sessionsDir);
137
+ for (const d of dirs) {
138
+ if (d.channelId !== channelId)
139
+ continue;
140
+ const active = readJsonFile(path.join(d.dirPath, 'active.json'));
141
+ if (active && active.channel === channel && active.channelType)
142
+ return active.channelType;
143
+ }
144
+ throw new Error(`[SessionManager] Cannot infer channelType for channel="${channel}" channelId="${channelId}". No existing session found.`);
142
145
  }
143
146
  /** 从 active 推断 selfId(已有 session 的复用) */
144
- inferSelfId(channel, channelId) {
145
- const active = this.readActive(channel, channelId);
146
- return active?.selfId;
147
+ inferSelfId(channel, channelId, chatDir) {
148
+ if (chatDir) {
149
+ const active = readJsonFile(path.join(chatDir, 'active.json'));
150
+ if (active?.selfId)
151
+ return active.selfId;
152
+ }
153
+ // 扫描已有目录
154
+ const dirs = scanChatDirs(this.sessionsDir);
155
+ for (const d of dirs) {
156
+ if (d.channelId !== channelId)
157
+ continue;
158
+ const active = readJsonFile(path.join(d.dirPath, 'active.json'));
159
+ if (active && active.channel === channel)
160
+ return active.selfId || undefined;
161
+ }
162
+ return undefined;
163
+ }
164
+ /**
165
+ * 扫描已有 chat 目录,找到匹配 channel+channelId 的目录并返回其 chatDir 路径。
166
+ * 用于不知道 channelType/selfId 的 caller 在调用 resolveChatDir 前定位已有目录。
167
+ */
168
+ findExistingChatDir(channel, channelId) {
169
+ const dirs = scanChatDirs(this.sessionsDir);
170
+ for (const d of dirs) {
171
+ if (d.channelId !== channelId)
172
+ continue;
173
+ const active = readJsonFile(path.join(d.dirPath, 'active.json'));
174
+ if (active && active.channel === channel)
175
+ return d.dirPath;
176
+ // 即使没有 active.json,也检查 meta 文件
177
+ const metaFiles = scanMetaFiles(d.dirPath);
178
+ for (const mf of metaFiles) {
179
+ const meta = readLastJsonlLine(path.join(d.dirPath, mf));
180
+ if (meta && meta.channel === channel)
181
+ return d.dirPath;
182
+ }
183
+ // 仅 thread session 场景:主目录无 active.json 也无 main meta,但 _threads/ 有内容
184
+ const threadsDir = path.join(d.dirPath, '_threads');
185
+ if (fs.existsSync(threadsDir)) {
186
+ const threadMetas = scanMetaFiles(threadsDir);
187
+ for (const mf of threadMetas) {
188
+ const meta = readLastJsonlLine(path.join(threadsDir, mf));
189
+ if (meta && meta.channel === channel)
190
+ return d.dirPath;
191
+ }
192
+ }
193
+ }
194
+ return undefined;
195
+ }
196
+ /**
197
+ * 安全版 resolveChatDir:先尝试用提供的 channelType/selfId,
198
+ * 如果没有则扫描已有目录推断。用于操作已有 session 的公共方法。
199
+ */
200
+ resolveChatDirSafe(channel, channelId, channelType, selfId) {
201
+ if (channelType) {
202
+ return this.resolveChatDir(channel, channelId, channelType, selfId);
203
+ }
204
+ // 尝试从已有目录推断
205
+ const existingDir = this.findExistingChatDir(channel, channelId);
206
+ if (existingDir)
207
+ return existingDir;
208
+ throw new Error(`[SessionManager] Cannot resolve chat dir for channel="${channel}" channelId="${channelId}". No channelType provided and no existing session found.`);
147
209
  }
148
- readActive(channel, channelId) {
149
- const dir = this.resolveChatDir(channel, channelId);
210
+ /**
211
+ * 安全版 ensureResolvedChatDir:先尝试用提供的 channelType/selfId,
212
+ * 如果没有则扫描已有目录推断。确保目录存在。
213
+ */
214
+ ensureResolvedChatDirSafe(channel, channelId, channelType, selfId) {
215
+ if (channelType) {
216
+ return this.ensureResolvedChatDir(channel, channelId, channelType, selfId);
217
+ }
218
+ // 尝试从已有目录推断
219
+ const existingDir = this.findExistingChatDir(channel, channelId);
220
+ if (existingDir) {
221
+ // 确保子目录存在
222
+ fs.mkdirSync(existingDir, { recursive: true });
223
+ fs.mkdirSync(path.join(existingDir, '_threads'), { recursive: true });
224
+ fs.mkdirSync(path.join(existingDir, '_trash'), { recursive: true });
225
+ return existingDir;
226
+ }
227
+ // 回退:推断 channelType 和 selfId
228
+ const inferredType = this.inferChannelType(channel, channelId);
229
+ const inferredSelfId = this.inferSelfId(channel, channelId);
230
+ return this.ensureResolvedChatDir(channel, channelId, inferredType, inferredSelfId);
231
+ }
232
+ readActive(channel, channelId, channelType, selfId) {
233
+ let dir;
234
+ try {
235
+ dir = this.resolveChatDir(channel, channelId, channelType, selfId);
236
+ }
237
+ catch {
238
+ // channelType not provided — try to find existing dir
239
+ const existingDir = this.findExistingChatDir(channel, channelId);
240
+ if (!existingDir)
241
+ return undefined;
242
+ dir = existingDir;
243
+ }
150
244
  const file = readJsonFile(path.join(dir, 'active.json'));
151
245
  if (!file)
152
246
  return undefined;
@@ -157,8 +251,17 @@ export class SessionManager {
157
251
  const file = sessionToFile(session);
158
252
  atomicWriteJson(path.join(dir, 'active.json'), file);
159
253
  }
160
- clearActive(channel, channelId) {
161
- const dir = this.resolveChatDir(channel, channelId);
254
+ clearActive(channel, channelId, channelType, selfId) {
255
+ let dir;
256
+ try {
257
+ dir = this.resolveChatDir(channel, channelId, channelType, selfId);
258
+ }
259
+ catch {
260
+ const existingDir = this.findExistingChatDir(channel, channelId);
261
+ if (!existingDir)
262
+ return;
263
+ dir = existingDir;
264
+ }
162
265
  const activePath = path.join(dir, 'active.json');
163
266
  try {
164
267
  fs.unlinkSync(activePath);
@@ -459,7 +562,7 @@ export class SessionManager {
459
562
  return session;
460
563
  }
461
564
  // Find existing session for default project path
462
- const chatDir = this.resolveChatDir(channel, channelId);
565
+ const chatDir = this.resolveChatDir(channel, channelId, channelType, selfId);
463
566
  const allSessions = this.findAllSessionsInChat(chatDir, false);
464
567
  const existing = allSessions
465
568
  .filter(s => s.projectPath === defaultProjectPath && !s.threadId)
@@ -543,7 +646,7 @@ export class SessionManager {
543
646
  // 优先使用精确路径(channelType + selfId),避免 fallback 到错误目录
544
647
  const chatDir = (channelType && selfId)
545
648
  ? (() => { const d = chatDirPath(this.sessionsDir, channelType, channelId, selfId); fs.mkdirSync(d, { recursive: true }); fs.mkdirSync(path.join(d, '_threads'), { recursive: true }); return d; })()
546
- : this.ensureResolvedChatDir(channelType || channel, channelId);
649
+ : this.ensureResolvedChatDirSafe(channel, channelId, channelType);
547
650
  const threadIndex = readThreadIndex(chatDir);
548
651
  const existingMetaId = threadIndex[threadId];
549
652
  if (existingMetaId) {
@@ -560,7 +663,7 @@ export class SessionManager {
560
663
  }
561
664
  }
562
665
  // Inherit project path & chatType from active main session
563
- const activeMain = this.readActive(channel, channelId);
666
+ const activeMain = this.readActive(channel, channelId, channelType, selfId);
564
667
  const projectPath = (activeMain && !activeMain.threadId ? activeMain.projectPath : undefined) || defaultProjectPath;
565
668
  const inheritedChatType = (activeMain && !activeMain.threadId ? activeMain.chatType : undefined) || 'private';
566
669
  const session = {
@@ -597,7 +700,7 @@ export class SessionManager {
597
700
  const agentId = currentAgentId || 'claude';
598
701
  logger.info(`[SessionManager] switchProject: channel=${channel} channelId=${channelId} newPath=${newProjectPath} agent=${agentId}`);
599
702
  const inheritedChatType = this.getActiveChatType(channel, channelId);
600
- const chatDir = this.ensureResolvedChatDir(channel, channelId);
703
+ const chatDir = this.ensureResolvedChatDirSafe(channel, channelId);
601
704
  const allSessions = this.findAllSessionsInChat(chatDir, false);
602
705
  const target = allSessions
603
706
  .filter(s => s.projectPath === newProjectPath && (s.agentId || 'claude') === agentId && !s.threadId)
@@ -660,7 +763,7 @@ export class SessionManager {
660
763
  }
661
764
  async switchAgent(channel, channelId, projectPath, newAgentId) {
662
765
  const inheritedChatType = this.getActiveChatType(channel, channelId);
663
- const chatDir = this.ensureResolvedChatDir(channel, channelId);
766
+ const chatDir = this.ensureResolvedChatDirSafe(channel, channelId);
664
767
  const allSessions = this.findAllSessionsInChat(chatDir, false);
665
768
  const target = allSessions
666
769
  .filter(s => s.projectPath === projectPath && (s.agentId || 'claude') === newAgentId && !s.threadId)
@@ -748,7 +851,13 @@ export class SessionManager {
748
851
  return this.readActive(channel, channelId);
749
852
  }
750
853
  async getThreadSession(channel, channelId, threadId) {
751
- const chatDir = this.resolveChatDir(channel, channelId);
854
+ let chatDir;
855
+ try {
856
+ chatDir = this.resolveChatDirSafe(channel, channelId);
857
+ }
858
+ catch {
859
+ return undefined;
860
+ }
752
861
  const threadIndex = readThreadIndex(chatDir);
753
862
  const metaId = threadIndex[threadId];
754
863
  if (!metaId)
@@ -761,12 +870,24 @@ export class SessionManager {
761
870
  return { ...session, agentSessionId: validSessionId };
762
871
  }
763
872
  async listSessions(channel, channelId) {
764
- const chatDir = this.resolveChatDir(channel, channelId);
873
+ let chatDir;
874
+ try {
875
+ chatDir = this.resolveChatDirSafe(channel, channelId);
876
+ }
877
+ catch {
878
+ return [];
879
+ }
765
880
  const sessions = this.findAllSessionsInChat(chatDir, true);
766
881
  return sessions.sort((a, b) => b.updatedAt - a.updatedAt);
767
882
  }
768
883
  async getSessionByProjectPath(channel, channelId, projectPath) {
769
- const chatDir = this.resolveChatDir(channel, channelId);
884
+ let chatDir;
885
+ try {
886
+ chatDir = this.resolveChatDirSafe(channel, channelId);
887
+ }
888
+ catch {
889
+ return undefined;
890
+ }
770
891
  const sessions = this.findAllSessionsInChat(chatDir, false);
771
892
  const matched = sessions.filter(s => s.projectPath === projectPath);
772
893
  if (matched.length === 0)
@@ -781,12 +902,24 @@ export class SessionManager {
781
902
  return matched[0];
782
903
  }
783
904
  async getSessionByName(channel, channelId, name) {
784
- const chatDir = this.resolveChatDir(channel, channelId);
905
+ let chatDir;
906
+ try {
907
+ chatDir = this.resolveChatDirSafe(channel, channelId);
908
+ }
909
+ catch {
910
+ return undefined;
911
+ }
785
912
  const sessions = this.findAllSessionsInChat(chatDir, true);
786
913
  return sessions.find(s => s.name === name);
787
914
  }
788
915
  async switchToSession(channel, channelId, targetSessionId) {
789
- const chatDir = this.resolveChatDir(channel, channelId);
916
+ let chatDir;
917
+ try {
918
+ chatDir = this.resolveChatDirSafe(channel, channelId);
919
+ }
920
+ catch {
921
+ return null;
922
+ }
790
923
  const sessions = this.findAllSessionsInChat(chatDir, true);
791
924
  const target = sessions.find(s => s.id === targetSessionId);
792
925
  if (!target)
@@ -903,12 +1036,22 @@ export class SessionManager {
903
1036
  }
904
1037
  async createNewSession(channel, channelId, projectPath, name, agentId) {
905
1038
  const inheritedChatType = this.getActiveChatType(channel, channelId);
1039
+ let inferredType;
1040
+ let inferredSelfId;
1041
+ try {
1042
+ inferredType = this.inferChannelType(channel, channelId);
1043
+ inferredSelfId = this.inferSelfId(channel, channelId);
1044
+ }
1045
+ catch {
1046
+ inferredType = channel;
1047
+ inferredSelfId = undefined;
1048
+ }
906
1049
  const session = {
907
1050
  id: generateSessionId(),
908
1051
  channel,
909
- channelType: this.inferChannelType(channel, channelId),
1052
+ channelType: inferredType,
910
1053
  channelId,
911
- selfId: this.inferSelfId(channel, channelId),
1054
+ selfId: inferredSelfId,
912
1055
  projectPath,
913
1056
  threadId: '',
914
1057
  agentId: agentId || 'claude',
@@ -1000,7 +1143,7 @@ export class SessionManager {
1000
1143
  return adapter.listSdkSessions(projectPath);
1001
1144
  }
1002
1145
  async getSessionByUuidPrefix(channel, channelId, uuidPrefix) {
1003
- const chatDir = this.resolveChatDir(channel, channelId);
1146
+ const chatDir = this.resolveChatDirSafe(channel, channelId);
1004
1147
  const sessions = this.findAllSessionsInChat(chatDir, true);
1005
1148
  const matched = sessions.filter(s => s.agentSessionId && s.agentSessionId.startsWith(uuidPrefix));
1006
1149
  if (matched.length === 0)
@@ -1046,7 +1189,7 @@ export class SessionManager {
1046
1189
  }
1047
1190
  // ─── Health status ───
1048
1191
  healthFilePath(channel, channelId) {
1049
- return path.join(this.ensureResolvedChatDir(channel, channelId), 'health.jsonl');
1192
+ return path.join(this.ensureResolvedChatDirSafe(channel, channelId), 'health.jsonl');
1050
1193
  }
1051
1194
  /** Find the chat dir containing a given session id */
1052
1195
  chatDirForSession(sessionId) {
@@ -71,9 +71,9 @@
71
71
  "description": "渠道层:我通过什么通信"
72
72
  },
73
73
  {
74
- "id": "runtime",
74
+ "id": "eckruntime",
75
75
  "type": "file",
76
- "file": "$PACKAGE_ROOT/kits/templates/system-fragments/runtime.md",
76
+ "file": "$PACKAGE_ROOT/kits/templates/system-fragments/eckruntime.md",
77
77
  "order": 60,
78
78
  "needsInjection": true,
79
79
  "when": "always",
@@ -92,4 +92,4 @@
92
92
  "description": "Base Agent 特定配置"
93
93
  }
94
94
  ]
95
- }
95
+ }
@@ -18,6 +18,7 @@
18
18
  | `$KITS_RULES` | `$KITS/rules` | 自动载入部分(本目录) |
19
19
  | `$KITS_DOCS` | `$KITS/docs` | 按需载入文档 |
20
20
  | `$KITS_TEMPLATES` | `$KITS/templates` | prompt 模板 |
21
+ | `$KITS_FRAGMENTS` | `$KITS_TEMPLATES/system-fragments` | ECK 动态注入 fragment 模板 |
21
22
  | `$ECK` | `$EVOLCLAW_HOME/eck` | 运行时配置 |
22
23
  | `$AGENTS_DIR` | `$EVOLCLAW_HOME/agents` | per-agent 数据根 |
23
24
  | `$AGENT_DIR` | `$AGENTS_DIR/<self-aid>` | 当前 agent 根 |
@@ -13,29 +13,15 @@
13
13
 
14
14
  与其他主体通信时,**必须调用 CLI 命令**发消息,不要把输出当成发送给对方的内容。
15
15
 
16
- ### 必须使用 `ec msg send`(首选)
16
+ 当前渠道的发消息命令已在上下文中注入(见 `[aun]` 或对应渠道块)。
17
17
 
18
- ```bash
19
- # 明文
20
- ec msg send <self-aid> <to-aid> "<text>"
21
-
22
- # 密文
23
- ec msg send <self-aid> <to-aid> "<text>" --encrypt
24
- ```
25
-
26
- `<self-aid>` 是注入上下文里的 selfAid,`<to-aid>` 是 peerKey 解析出的对端 AID。
27
-
28
- ### 仅在无法获取 selfAid 时才用 `ec ctl send`
18
+ ### 仅在无法获取 self-aid 时才用 `ec ctl send`
29
19
 
30
20
  ```bash
31
21
  ec ctl send "<text>"
32
22
  ec ctl send --encrypt "<text>"
33
23
  ```
34
24
 
35
- ### 加密策略
36
-
37
- 对端发来密文消息时回复必须加密;明文消息默认明文回复。
38
-
39
25
  ### 命令返回值
40
26
 
41
27
  - 成功:`ok` 或包含 `✓ 已发送 ...` 的输出(exit 0)
@@ -43,8 +29,6 @@ ec ctl send --encrypt "<text>"
43
29
 
44
30
  发送成功后**继续后续处理**。一次任务可能发 0 到多条消息,不要因为看到"已发送"就反复发送同一条消息。
45
31
 
46
- 不同渠道有不同的命令行工具,使用方式参见各渠道文档。
47
-
48
32
  ## Agent 管理命令
49
33
 
50
34
  `evolclaw agent` — agent 全生命周期管理。
@@ -1,2 +1,2 @@
1
- [Base Agent]
2
- 当前基座:{{baseAgentName}}({{baseAgent}})
1
+ [baseagent]
2
+ base-agent: {{baseAgentName}}
@@ -1,10 +1,19 @@
1
- [渠道层]
2
- 通信渠道:{{channel}}
3
-
4
- {{?canSendFile}}
5
- [文件发送] 当前渠道支持文件发送
6
- {{/}}
7
-
8
- {{?capabilities}}
9
- [渠道能力] {{capabilities}}
1
+ [channel]
2
+ channel: {{channel}}
3
+ {{?peerId}}
4
+ {{?channel=aun}}
5
+ ec msg send {{selfAid}} {{peerId}} "<text>" [--encrypt] [--file <path> --as image|video|voice|file] [--link <url> --title "<title>"] [--payload '<json>']
6
+ encrypt: 跟随对端消息加密状态(密文回密文,明文回明文);本端主动发时依据会话 encrypt 配置(待实现)
7
+ {{/}}
8
+ {{?channel!=aun}}
9
+ aun 渠道:回复由 evolclaw 自动完成,无需调用 CLI
10
+ {{/}}
11
+ {{/}}
12
+ {{?groupId}}
13
+ {{?channel=aun}}
14
+ ec group send {{selfAid}} {{groupId}} "<text>" [--file <path> --as image|video|voice|file] [--mention <aid>]
15
+ {{/}}
16
+ {{?channel!=aun}}
17
+ 非 aun 渠道:回复由 evolclaw 自动完成,无需调用 CLI
18
+ {{/}}
10
19
  {{/}}
@@ -0,0 +1,14 @@
1
+ [runtime]
2
+ project: {{project}}
3
+ {{?sessionName}}
4
+ session-name: {{sessionName}}
5
+ {{/}}
6
+ chatmode: {{chatmode}}
7
+ chatType: {{chatType}}
8
+ {{?readonly}}
9
+ readonly: true — 禁止修改项目文件,如需生成文件请写入 .evolclaw/tmp/
10
+ {{/}}
11
+ {{?chatmode=proactive}}
12
+ proactive-send: evolclaw ctl send "<text>"
13
+ proactive-file: evolclaw ctl file <path>
14
+ {{/}}
@@ -1,12 +1,11 @@
1
- [身份层]
1
+ [identity]
2
2
  {{?selfAid}}
3
- 我是 {{selfName}} ({{selfAid}})
3
+ self-name: {{selfName}}
4
+ self-aid: {{selfAid}}
4
5
  {{/}}
5
-
6
6
  {{?hasPersona}}
7
- [人格] 已加载 persona.md 行为规范
7
+ persona: loaded
8
8
  {{/}}
9
-
10
9
  {{?hasWorkingMemory}}
11
- [当前关注] 已加载 working memory
10
+ working-memory: loaded
12
11
  {{/}}
@@ -1,9 +1,11 @@
1
1
  {{?peerKey}}
2
- [关系层]
3
- 对话者:{{peerName}} ({{peerId}}),权限:{{peerRole}}
4
- 对端标识:{{peerKey}}
2
+ [relation]
3
+ peer-name: {{peerName}}
4
+ peer-aid: {{peerId}}
5
+ peer-role: {{peerRole}}
6
+ peer-key: {{peerKey}}
5
7
  {{/}}
6
8
  {{?groupId}}
7
- [关系层]
8
- 群组:{{groupId}}
9
+ [relation]
10
+ group-id: {{groupId}}
9
11
  {{/}}
@@ -1,5 +1,4 @@
1
- [环境层]
2
- 聊天类型:{{chatType}}
1
+ [venue]
3
2
  {{?venueUid}}
4
- 环境标识:{{venueUid}}
3
+ venue-id: {{venueUid}}
5
4
  {{/}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "evolclaw",
3
- "version": "3.1.2",
3
+ "version": "3.1.3",
4
4
  "description": "Lightweight AI Agent gateway connecting Claude Agent SDK to messaging channels (Feishu, ACP) with multi-project session management",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,19 +0,0 @@
1
- [运行时]
2
- 项目:{{project}}
3
- {{?sessionName}}
4
- 会话名称:{{sessionName}}
5
- {{/}}
6
-
7
- 会话模式:{{sessionMode}}
8
-
9
- {{?readonly}}
10
- ⚠️ 只读模式:禁止修改项目文件。如需生成文件供用户下载,请写入 .evolclaw/tmp/ 目录。
11
- {{/}}
12
-
13
- {{?sessionMode=proactive}}
14
- [Proactive 模式] 你的所有文本输出都会被静默丢弃,用户永远看不到。唯一能让用户收到消息的方式:
15
- 调用 Bash 工具执行命令:evolclaw ctl send "<消息内容>"
16
- 发送文件:evolclaw ctl file <路径>
17
- 可多次调用发送多条消息,如果不想回复停止调用即可。
18
- 禁止使用 AskUserQuestion 和 ExitPlanMode 工具——proactive 模式下应由你主动用 ctl send 与用户沟通。
19
- {{/}}