nikou-cli 0.1.7 → 0.1.8
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/README.md +2 -0
- package/dist/index.js +85 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -162,6 +162,8 @@ Hook 支持三种启动模式:
|
|
|
162
162
|
|
|
163
163
|
主节点负责连接聊天平台、接收消息、维护 Worker 列表并分发任务。从节点负责连接主节点,收到任务后调用 Codex、Claude 或 Gemini 执行。
|
|
164
164
|
|
|
165
|
+
群聊发送 `@机器人 绑定: <目录>` 时,主节点会先检查当前用户是否已经绑定该目录;已有绑定会直接返回结果,未绑定则只把路径校验任务发给该用户自己的在线 Worker。一个群可以保留多个用户、多个目录的 Agent 绑定,绑定指令不会广播给其他 Worker 抢占。
|
|
166
|
+
|
|
165
167
|
### 初始化配置
|
|
166
168
|
|
|
167
169
|
```bash
|
package/dist/index.js
CHANGED
|
@@ -3041,7 +3041,10 @@ var TaskManager = class {
|
|
|
3041
3041
|
}
|
|
3042
3042
|
if (task.status !== "pending") {
|
|
3043
3043
|
this.logger.info(
|
|
3044
|
-
formatTraceLog(
|
|
3044
|
+
formatTraceLog(
|
|
3045
|
+
task.traceId,
|
|
3046
|
+
`\u8BA4\u9886\u88AB\u62D2\u7EDD\uFF1A\u4EFB\u52A1\u5DF2\u88AB\u8BA4\u9886 claimed_worker=${task.claimedWorkerId || "-"}, rejected_worker=${workerMeta.workerId}`
|
|
3047
|
+
)
|
|
3045
3048
|
);
|
|
3046
3049
|
return false;
|
|
3047
3050
|
}
|
|
@@ -4028,6 +4031,15 @@ var ChatBindingRegistry = class {
|
|
|
4028
4031
|
getByKey(chatId, bindingKey) {
|
|
4029
4032
|
return this.bindings.get(normalize2(chatId))?.get(normalize2(bindingKey)) || null;
|
|
4030
4033
|
}
|
|
4034
|
+
/** 按群、绑定用户和目录查找普通绑定,供绑定指令做幂等校验。 */
|
|
4035
|
+
getNormalBinding(chatId, ownerUserId, dirPath) {
|
|
4036
|
+
const owner = normalize2(ownerUserId);
|
|
4037
|
+
const dir = normalize2(dirPath);
|
|
4038
|
+
if (!owner || !dir) {
|
|
4039
|
+
return null;
|
|
4040
|
+
}
|
|
4041
|
+
return this.listByChat(chatId).find((binding) => binding.kind === "normal" && binding.ownerUserId === owner && binding.dirPath === dir) || null;
|
|
4042
|
+
}
|
|
4031
4043
|
/** 返回全部绑定记录(扁平) */
|
|
4032
4044
|
list() {
|
|
4033
4045
|
const all = [];
|
|
@@ -5356,9 +5368,17 @@ var HookMasterCommand = class {
|
|
|
5356
5368
|
const bindCmd = parseBindingCommand(text);
|
|
5357
5369
|
if (bindCmd.matched) {
|
|
5358
5370
|
this.logger.info(formatMasterTraceLog(messageId, `\u4E3B\u8282\u70B9\u547D\u4E2D\u7ED1\u5B9A\u6307\u4EE4: chat_id=${chatId}, target=${bindCmd.target}`));
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5371
|
+
await this.handleBindCommand({
|
|
5372
|
+
data,
|
|
5373
|
+
message,
|
|
5374
|
+
chatId,
|
|
5375
|
+
chatType,
|
|
5376
|
+
messageId,
|
|
5377
|
+
senderId,
|
|
5378
|
+
senderOpenId,
|
|
5379
|
+
target: bindCmd.target
|
|
5380
|
+
});
|
|
5381
|
+
return;
|
|
5362
5382
|
}
|
|
5363
5383
|
const stopCmd = parseStopCommand(text);
|
|
5364
5384
|
if (stopCmd.matched) {
|
|
@@ -5378,8 +5398,7 @@ var HookMasterCommand = class {
|
|
|
5378
5398
|
chatType,
|
|
5379
5399
|
senderId,
|
|
5380
5400
|
senderOpenId,
|
|
5381
|
-
text
|
|
5382
|
-
isBindingCommand: bindCmd.matched
|
|
5401
|
+
text
|
|
5383
5402
|
});
|
|
5384
5403
|
}
|
|
5385
5404
|
async dispatchFeishuTask(input) {
|
|
@@ -5409,10 +5428,6 @@ var HookMasterCommand = class {
|
|
|
5409
5428
|
} else {
|
|
5410
5429
|
this.logger.warn(formatMasterTraceLog(input.messageId, `\u5355\u804A\u4EFB\u52A1\u672A\u5339\u914D\u5230\u4ECE\u8282\u70B9: task_id=${task.taskId}, requester=${input.senderId || "-"}, chat_id=${input.chatId || "-"}`));
|
|
5411
5430
|
}
|
|
5412
|
-
} else if (input.isBindingCommand) {
|
|
5413
|
-
this.wsServer.broadcast(buildTaskOffer(task, eventKey, input.data));
|
|
5414
|
-
delivered = this.wsServer.getWorkerCount();
|
|
5415
|
-
this.logger.info(formatMasterTraceLog(input.messageId, `\u7ED1\u5B9A\u6307\u4EE4\u5DF2\u5E7F\u64AD\u7ED9\u4ECE\u8282\u70B9\u5339\u914D\u76EE\u5F55: task_id=${task.taskId}, chat_id=${input.chatId || "-"}, delivered=${delivered}, message_id=${input.messageId}`));
|
|
5416
5431
|
} else {
|
|
5417
5432
|
await this.groupRouteDispatcher?.dispatch(task, input.text);
|
|
5418
5433
|
return;
|
|
@@ -5433,16 +5448,54 @@ var HookMasterCommand = class {
|
|
|
5433
5448
|
() => this.messageResponder?.replyNoWorker(task)
|
|
5434
5449
|
);
|
|
5435
5450
|
}
|
|
5436
|
-
handleBindCommand(
|
|
5451
|
+
async handleBindCommand(input) {
|
|
5452
|
+
const { chatId, messageId, senderId, target } = input;
|
|
5453
|
+
const replyInThread = resolveReplyInThread(input.message);
|
|
5437
5454
|
if (this.bindAllowedUserIds.length > 0 && !this.bindAllowedUserIds.includes(senderId)) {
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
message_id: messageId
|
|
5441
|
-
}));
|
|
5442
|
-
return false;
|
|
5455
|
+
await this.messageResponder?.replyText(chatId, "\u7ED1\u5B9A\u5931\u8D25\uFF1A\u5F53\u524D\u7528\u6237\u4E0D\u5728\u7ED1\u5B9A\u767D\u540D\u5355", messageId, replyInThread);
|
|
5456
|
+
return;
|
|
5443
5457
|
}
|
|
5444
|
-
|
|
5445
|
-
|
|
5458
|
+
if (!target) {
|
|
5459
|
+
await this.messageResponder?.replyText(chatId, "\u7ED1\u5B9A\u5931\u8D25\uFF1A\u8BF7\u6307\u5B9A\u7ED1\u5B9A\u8DEF\u5F84", messageId, replyInThread);
|
|
5460
|
+
return;
|
|
5461
|
+
}
|
|
5462
|
+
const existing = this.chatBindingRegistry.getNormalBinding(chatId, senderId, target);
|
|
5463
|
+
if (existing) {
|
|
5464
|
+
this.logger.info(formatMasterTraceLog(messageId, `\u4E3B\u8282\u70B9\u547D\u4E2D\u5DF2\u6709\u7FA4\u804A\u7ED1\u5B9A: chat_id=${chatId}, worker=${existing.workerId}, owner_user_id=${senderId}, dir=${target}`));
|
|
5465
|
+
await this.messageResponder?.replyText(chatId, `\u5DF2\u7ED1\u5B9A\u5230: ${target}`, messageId, replyInThread);
|
|
5466
|
+
return;
|
|
5467
|
+
}
|
|
5468
|
+
if (!this.taskManager || !this.wsServer) {
|
|
5469
|
+
return;
|
|
5470
|
+
}
|
|
5471
|
+
const workerId = this.workerRegistry.getWorkerIdByOwner(senderId);
|
|
5472
|
+
if (!workerId) {
|
|
5473
|
+
this.logger.warn(formatMasterTraceLog(messageId, `\u7ED1\u5B9A\u5931\u8D25\uFF0C\u672A\u627E\u5230\u53D1\u8D77\u4EBA\u7684\u5728\u7EBF\u4ECE\u8282\u70B9: chat_id=${chatId}, owner_user_id=${senderId}, dir=${target}`));
|
|
5474
|
+
await this.messageResponder?.replyText(chatId, "\u7ED1\u5B9A\u5931\u8D25\uFF1A\u672A\u627E\u5230\u4F60\u7684\u5728\u7EBF\u4ECE\u8282\u70B9\uFF0C\u8BF7\u5148\u542F\u52A8 ai-hook", messageId, replyInThread);
|
|
5475
|
+
return;
|
|
5476
|
+
}
|
|
5477
|
+
const eventKey = "im.message.receive_v1";
|
|
5478
|
+
const task = this.taskManager.createTaskRecord(input.data, messageId, eventKey, {
|
|
5479
|
+
chatId,
|
|
5480
|
+
chatType: input.chatType,
|
|
5481
|
+
requesterUserId: senderId,
|
|
5482
|
+
requesterOpenId: input.senderOpenId,
|
|
5483
|
+
responseMode: "card",
|
|
5484
|
+
routeMode: "direct_group",
|
|
5485
|
+
replyInThread
|
|
5486
|
+
});
|
|
5487
|
+
task.targetWorkerId = workerId;
|
|
5488
|
+
const delivered = this.wsServer.sendTo(workerId, buildTaskOffer(task, eventKey, input.data));
|
|
5489
|
+
if (!delivered) {
|
|
5490
|
+
this.taskManager.cleanupTask(task.taskId);
|
|
5491
|
+
await this.messageResponder?.replyText(chatId, "\u7ED1\u5B9A\u5931\u8D25\uFF1A\u4F60\u7684\u4ECE\u8282\u70B9\u5F53\u524D\u4E0D\u53EF\u7528\uFF0C\u8BF7\u91CD\u65B0\u542F\u52A8 ai-hook", messageId, replyInThread);
|
|
5492
|
+
return;
|
|
5493
|
+
}
|
|
5494
|
+
this.logger.info(formatMasterTraceLog(messageId, `\u7ED1\u5B9A\u6307\u4EE4\u5DF2\u5B9A\u5411\u4E0B\u53D1: task_id=${task.taskId}, chat_id=${chatId}, owner_user_id=${senderId}, worker=${workerId}, dir=${target}`));
|
|
5495
|
+
this.taskManager.scheduleClaimTimeout(
|
|
5496
|
+
task.taskId,
|
|
5497
|
+
() => this.messageResponder?.replyText(chatId, "\u7ED1\u5B9A\u5931\u8D25\uFF1A\u4ECE\u8282\u70B9\u54CD\u5E94\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5", messageId, replyInThread)
|
|
5498
|
+
);
|
|
5446
5499
|
}
|
|
5447
5500
|
async handleBotMenuEvent(data) {
|
|
5448
5501
|
const event = data?.event || data;
|
|
@@ -8329,7 +8382,6 @@ ${question}` : question;
|
|
|
8329
8382
|
if (!fs14.existsSync(bindTarget)) {
|
|
8330
8383
|
return { ...baseTask, canHandle: true, type: "quick_result", quickResult: `\u8DEF\u5F84\u4E0D\u5B58\u5728: ${bindTarget}` };
|
|
8331
8384
|
}
|
|
8332
|
-
this.stateManager.rebindChatToDir(message.chatId, bindTarget);
|
|
8333
8385
|
const bindAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8334
8386
|
const pathDisplay = resolveCardPathDisplay(bindTarget);
|
|
8335
8387
|
this.logger.info(formatTraceLog(baseTask.traceId, `\u7ED1\u5B9A\u6210\u529F: chatId=${message.chatId} -> ${bindTarget}`));
|
|
@@ -9956,6 +10008,7 @@ var SlaveRelayClient = class {
|
|
|
9956
10008
|
if (!chatId || !dirPath) {
|
|
9957
10009
|
return;
|
|
9958
10010
|
}
|
|
10011
|
+
this.stateManager.rebindChatToDir(chatId, dirPath);
|
|
9959
10012
|
this.send({
|
|
9960
10013
|
type: "binding_update",
|
|
9961
10014
|
worker_id: this.workerId,
|
|
@@ -14011,6 +14064,7 @@ import { execFile, spawn as spawn4 } from "child_process";
|
|
|
14011
14064
|
import { createRequire } from "module";
|
|
14012
14065
|
import { promisify } from "util";
|
|
14013
14066
|
var execFileAsync = promisify(execFile);
|
|
14067
|
+
var MISSING_CLI_AUTH_SECRET_ERROR = "\u672A\u914D\u7F6E CLI_AUTH_SECRET\uFF0C\u65E0\u6CD5\u62C9\u53D6 Nacos \u540C\u6B65\u8BA1\u5212";
|
|
14014
14068
|
var NacosSubscriptionSyncCoordinator = class {
|
|
14015
14069
|
logger;
|
|
14016
14070
|
workerId;
|
|
@@ -14019,12 +14073,15 @@ var NacosSubscriptionSyncCoordinator = class {
|
|
|
14019
14073
|
daemon = null;
|
|
14020
14074
|
running = false;
|
|
14021
14075
|
stopped = false;
|
|
14076
|
+
missingCliAuthSecretWarned = false;
|
|
14022
14077
|
status;
|
|
14078
|
+
resolveAuthRuntimeConfig;
|
|
14023
14079
|
statePath = path26.join(os16.homedir(), ".nikou-block", "worker", "nacos-subscriptions.json");
|
|
14024
14080
|
constructor(options) {
|
|
14025
14081
|
this.logger = options.logger;
|
|
14026
14082
|
this.workerId = options.workerId;
|
|
14027
14083
|
this.config = options.config;
|
|
14084
|
+
this.resolveAuthRuntimeConfig = options.resolveAuthRuntimeConfig || resolveCliAuthRuntimeConfig;
|
|
14028
14085
|
this.status = {
|
|
14029
14086
|
enabled: this.config.enabled,
|
|
14030
14087
|
configured: false,
|
|
@@ -14092,15 +14149,20 @@ var NacosSubscriptionSyncCoordinator = class {
|
|
|
14092
14149
|
} catch (error) {
|
|
14093
14150
|
const message = error instanceof Error ? error.message : String(error);
|
|
14094
14151
|
this.status.lastError = message;
|
|
14095
|
-
|
|
14152
|
+
if (message !== MISSING_CLI_AUTH_SECRET_ERROR || !this.missingCliAuthSecretWarned) {
|
|
14153
|
+
this.logger.warn(`Nacos Skill \u8BA2\u9605\u540C\u6B65\u5931\u8D25: ${message}`);
|
|
14154
|
+
}
|
|
14155
|
+
if (message === MISSING_CLI_AUTH_SECRET_ERROR) {
|
|
14156
|
+
this.missingCliAuthSecretWarned = true;
|
|
14157
|
+
}
|
|
14096
14158
|
} finally {
|
|
14097
14159
|
this.running = false;
|
|
14098
14160
|
}
|
|
14099
14161
|
}
|
|
14100
14162
|
async fetchPlan() {
|
|
14101
|
-
const runtime =
|
|
14163
|
+
const runtime = this.resolveAuthRuntimeConfig();
|
|
14102
14164
|
if (!runtime.cliAuthSecret) {
|
|
14103
|
-
throw new Error(
|
|
14165
|
+
throw new Error(MISSING_CLI_AUTH_SECRET_ERROR);
|
|
14104
14166
|
}
|
|
14105
14167
|
const response = await fetch(`${runtime.apiUrl}/worker-skills/nacos-sync/plan`, {
|
|
14106
14168
|
method: "POST",
|
|
@@ -14115,7 +14177,7 @@ var NacosSubscriptionSyncCoordinator = class {
|
|
|
14115
14177
|
}
|
|
14116
14178
|
async report(results) {
|
|
14117
14179
|
if (!results.length) return;
|
|
14118
|
-
const runtime =
|
|
14180
|
+
const runtime = this.resolveAuthRuntimeConfig();
|
|
14119
14181
|
const response = await fetch(`${runtime.apiUrl}/worker-skills/nacos-sync/report`, {
|
|
14120
14182
|
method: "POST",
|
|
14121
14183
|
headers: { "Content-Type": "application/json" },
|