nikou-cli 0.1.0 → 0.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.
- package/README.md +21 -0
- package/dist/ai-hook.d.ts +1 -0
- package/dist/ai-hook.js +12 -0
- package/dist/chunk-F3EPGM5N.js +25 -0
- package/dist/index.js +127 -39
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -165,6 +165,19 @@ Hook 模式包含一个主节点和多个从节点:
|
|
|
165
165
|
nikou-cli hook init
|
|
166
166
|
```
|
|
167
167
|
|
|
168
|
+
安装后也可以用 `ai-hook` 入口完成 Hook 初始化与启动:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
ai-hook init
|
|
172
|
+
ai-hook
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
初始化时会提示主节点地址:如果旧配置里已有主节点,直接回车沿用;没有默认值时输入 IP 或域名即可。`ai-hook` 默认等价于 `nikou-cli hook worker codex`;如需 Claude:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
ai-hook claude --model opus
|
|
179
|
+
```
|
|
180
|
+
|
|
168
181
|
配置默认写入:
|
|
169
182
|
|
|
170
183
|
```text
|
|
@@ -254,6 +267,14 @@ nikou-cli hook worker claude \
|
|
|
254
267
|
--max-budget-usd 5
|
|
255
268
|
```
|
|
256
269
|
|
|
270
|
+
使用 `ai-hook` 入口时,默认启动 Codex Worker;第一个参数可指定引擎:
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
ai-hook
|
|
274
|
+
ai-hook claude --model sonnet
|
|
275
|
+
ai-hook gemini
|
|
276
|
+
```
|
|
277
|
+
|
|
257
278
|
也可以通过 `--` 传递底层工具参数:
|
|
258
279
|
|
|
259
280
|
```bash
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/ai-hook.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// src/cli-entry.ts
|
|
2
|
+
import path from "path";
|
|
3
|
+
var AI_HOOK_COMMAND_NAMES = /* @__PURE__ */ new Set(["ai-hook", "ai-hook.cmd", "ai-hook.exe"]);
|
|
4
|
+
var HOOK_SUBCOMMANDS = /* @__PURE__ */ new Set(["master", "init", "worker", "log", "help"]);
|
|
5
|
+
function normalizeCliArgs(commandPath, args) {
|
|
6
|
+
const commandName = path.basename(commandPath || "");
|
|
7
|
+
if (!AI_HOOK_COMMAND_NAMES.has(commandName)) {
|
|
8
|
+
return args;
|
|
9
|
+
}
|
|
10
|
+
const [firstArg = "", ...restArgs] = args;
|
|
11
|
+
if (firstArg === "hook") {
|
|
12
|
+
return args;
|
|
13
|
+
}
|
|
14
|
+
if (HOOK_SUBCOMMANDS.has(firstArg)) {
|
|
15
|
+
return ["hook", ...args];
|
|
16
|
+
}
|
|
17
|
+
if (!firstArg || firstArg.startsWith("-")) {
|
|
18
|
+
return ["hook", "worker", "codex", ...args];
|
|
19
|
+
}
|
|
20
|
+
return ["hook", "worker", firstArg, ...restArgs];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export {
|
|
24
|
+
normalizeCliArgs
|
|
25
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
normalizeCliArgs
|
|
4
|
+
} from "./chunk-F3EPGM5N.js";
|
|
2
5
|
|
|
3
6
|
// src/index.ts
|
|
4
7
|
import { Command } from "commander";
|
|
@@ -14361,6 +14364,105 @@ function countObjectKeys(value) {
|
|
|
14361
14364
|
return Object.keys(value).length;
|
|
14362
14365
|
}
|
|
14363
14366
|
|
|
14367
|
+
// src/hook/init/hook-init-normalizer.ts
|
|
14368
|
+
var DEFAULT_MASTER_HOST_ENV = "NIKOU_HOOK_MASTER_HOST";
|
|
14369
|
+
function resolveHookSection2(config) {
|
|
14370
|
+
return config.hook ?? config.ai_hook ?? config.aiHook ?? {};
|
|
14371
|
+
}
|
|
14372
|
+
function resolveConfiguredMasterHost(config) {
|
|
14373
|
+
const hook2 = resolveHookSection2(config);
|
|
14374
|
+
return String(hook2.master_host || hook2.masterHost || "").trim();
|
|
14375
|
+
}
|
|
14376
|
+
function mergeHookInitMasterHost(config, masterHost) {
|
|
14377
|
+
const host = String(masterHost || "").trim();
|
|
14378
|
+
if (!host) {
|
|
14379
|
+
return config;
|
|
14380
|
+
}
|
|
14381
|
+
return {
|
|
14382
|
+
...config,
|
|
14383
|
+
hook: {
|
|
14384
|
+
...config.hook ?? config.ai_hook ?? config.aiHook ?? {},
|
|
14385
|
+
master_host: host
|
|
14386
|
+
}
|
|
14387
|
+
};
|
|
14388
|
+
}
|
|
14389
|
+
function resolveContextConfigFromHook(hook2) {
|
|
14390
|
+
return {
|
|
14391
|
+
enabled: parseBoolean(
|
|
14392
|
+
hook2.context_enabled ?? hook2.contextEnabled,
|
|
14393
|
+
DEFAULT_CONTEXT_CONFIG.enabled
|
|
14394
|
+
),
|
|
14395
|
+
timeoutMs: parsePositiveInt(
|
|
14396
|
+
hook2.context_timeout_ms ?? hook2.contextTimeoutMs,
|
|
14397
|
+
DEFAULT_CONTEXT_CONFIG.timeoutMs
|
|
14398
|
+
),
|
|
14399
|
+
threadMax: parsePositiveInt(
|
|
14400
|
+
hook2.context_thread_max ?? hook2.contextThreadMax,
|
|
14401
|
+
DEFAULT_CONTEXT_CONFIG.threadMax
|
|
14402
|
+
),
|
|
14403
|
+
chatRecentMax: parsePositiveInt(
|
|
14404
|
+
hook2.context_chat_recent_max ?? hook2.contextChatRecentMax,
|
|
14405
|
+
DEFAULT_CONTEXT_CONFIG.chatRecentMax
|
|
14406
|
+
),
|
|
14407
|
+
userRecentMax: parsePositiveInt(
|
|
14408
|
+
hook2.context_user_recent_max ?? hook2.contextUserRecentMax,
|
|
14409
|
+
DEFAULT_CONTEXT_CONFIG.userRecentMax
|
|
14410
|
+
),
|
|
14411
|
+
userRecentWindowMin: parsePositiveInt(
|
|
14412
|
+
hook2.context_user_recent_window_min ?? hook2.contextUserRecentWindowMin,
|
|
14413
|
+
DEFAULT_CONTEXT_CONFIG.userRecentWindowMin
|
|
14414
|
+
),
|
|
14415
|
+
maxChars: parsePositiveInt(
|
|
14416
|
+
hook2.context_max_chars ?? hook2.contextMaxChars,
|
|
14417
|
+
DEFAULT_CONTEXT_CONFIG.maxChars
|
|
14418
|
+
),
|
|
14419
|
+
logVerbose: parseBoolean(
|
|
14420
|
+
hook2.context_log_verbose ?? hook2.contextLogVerbose,
|
|
14421
|
+
DEFAULT_CONTEXT_CONFIG.logVerbose
|
|
14422
|
+
)
|
|
14423
|
+
};
|
|
14424
|
+
}
|
|
14425
|
+
function resolveDefaultMasterHost(env = process.env) {
|
|
14426
|
+
return String(env[DEFAULT_MASTER_HOST_ENV] || "").trim();
|
|
14427
|
+
}
|
|
14428
|
+
function normalizeHookInitConfig(config, defaults = {}) {
|
|
14429
|
+
const hook2 = resolveHookSection2(config);
|
|
14430
|
+
const appId = String(config.feishu?.app_id || config.feishu?.appId || config.feishu?.appid || "").trim();
|
|
14431
|
+
const appSecret = String(
|
|
14432
|
+
config.feishu?.app_secret || config.feishu?.appSecret || config.feishu?.appsecret || ""
|
|
14433
|
+
).trim();
|
|
14434
|
+
const masterHost = resolveConfiguredMasterHost(config) || String(defaults.defaultMasterHost || "").trim();
|
|
14435
|
+
const masterPort = parsePositiveInt(hook2.master_port ?? hook2.masterPort, DEFAULT_MASTER_PORT);
|
|
14436
|
+
const sharedSecret = String(hook2.shared_secret || hook2.sharedSecret || appSecret || "").trim();
|
|
14437
|
+
const bindAllowedUserIds = parseUserIdList(hook2.bind_allowed_user_ids ?? hook2.bindAllowedUserIds);
|
|
14438
|
+
const missing = [];
|
|
14439
|
+
if (!appId) missing.push("feishu.app_id");
|
|
14440
|
+
if (!appSecret) missing.push("feishu.app_secret");
|
|
14441
|
+
if (!masterHost) missing.push(`hook.master_host \u6216 ${DEFAULT_MASTER_HOST_ENV}`);
|
|
14442
|
+
if (!sharedSecret) missing.push("hook.shared_secret");
|
|
14443
|
+
if (bindAllowedUserIds.length === 0) missing.push("hook.bind_allowed_user_ids");
|
|
14444
|
+
if (missing.length > 0) {
|
|
14445
|
+
throw new Error(`\u521D\u59CB\u5316\u6240\u9700\u914D\u7F6E\u7F3A\u5931: ${missing.join(", ")}`);
|
|
14446
|
+
}
|
|
14447
|
+
return {
|
|
14448
|
+
feishuAppId: appId,
|
|
14449
|
+
feishuAppSecret: appSecret,
|
|
14450
|
+
masterHost,
|
|
14451
|
+
masterPort,
|
|
14452
|
+
sharedSecret,
|
|
14453
|
+
bindAllowedUserIds,
|
|
14454
|
+
botName: String(hook2.bot_name || hook2.botName || "").trim() || void 0,
|
|
14455
|
+
claimTimeoutMs: parsePositiveInt(hook2.claim_timeout_ms ?? hook2.claimTimeoutMs, 1e4),
|
|
14456
|
+
relayHeartbeatIntervalMs: parsePositiveInt(hook2.relay_heartbeat_interval_ms ?? hook2.relayHeartbeatIntervalMs, 3e4),
|
|
14457
|
+
relayHeartbeatTimeoutMs: parsePositiveInt(hook2.relay_heartbeat_timeout_ms ?? hook2.relayHeartbeatTimeoutMs, 9e4),
|
|
14458
|
+
slaveConnectTimeoutMs: parsePositiveInt(hook2.slave_connect_timeout_ms ?? hook2.slaveConnectTimeoutMs, 5e3),
|
|
14459
|
+
reconnectIntervalMs: parsePositiveInt(hook2.reconnect_interval_ms ?? hook2.reconnectIntervalMs, 3e3),
|
|
14460
|
+
authCliAuthSecret: String(config.auth?.cli_auth_secret || "").trim() || void 0,
|
|
14461
|
+
authApiUrl: String(config.auth?.api_url || "").trim() || void 0,
|
|
14462
|
+
contextConfig: resolveContextConfigFromHook(hook2)
|
|
14463
|
+
};
|
|
14464
|
+
}
|
|
14465
|
+
|
|
14364
14466
|
// src/hook/init/hook-init-command.ts
|
|
14365
14467
|
var BOT_OPTIONS = [{ label: "\u59AE\u853B", value: "\u59AE\u853B" }];
|
|
14366
14468
|
var DEPLOYMENT_OPTIONS = [
|
|
@@ -14374,7 +14476,6 @@ var HookInitCommand = class {
|
|
|
14374
14476
|
async run() {
|
|
14375
14477
|
this.ensureInteractiveTerminal();
|
|
14376
14478
|
const source = this.resolveSourceConfig();
|
|
14377
|
-
const normalized = this.normalizeSourceConfig(source.config);
|
|
14378
14479
|
const migration = loadLegacyMigrationResult(this.logger);
|
|
14379
14480
|
const existingAggregateConfig = this.readJson(DEFAULT_CONFIG_PATH);
|
|
14380
14481
|
const existingMasterConfig = this.readJson(MASTER_CONFIG_PATH);
|
|
@@ -14386,6 +14487,10 @@ var HookInitCommand = class {
|
|
|
14386
14487
|
this.printEnvironmentSummary(source.path, { existingAggregateConfig, existingMasterConfig, existingWorkerConfig }, migration.summary);
|
|
14387
14488
|
const botName = await this.askChoice(rl, "\u7B2C\u4E00\u6B65\uFF1A\u9009\u62E9\u98DE\u4E66\u673A\u5668\u4EBA", BOT_OPTIONS, 0);
|
|
14388
14489
|
await this.askChoice(rl, "\u7B2C\u4E8C\u6B65\uFF1A\u9009\u62E9\u90E8\u7F72\u65B9\u5F0F", DEPLOYMENT_OPTIONS, 0);
|
|
14490
|
+
const masterHost = await this.askMasterHost(rl, source.config);
|
|
14491
|
+
const normalized = this.normalizeSourceConfig(
|
|
14492
|
+
mergeHookInitMasterHost(source.config, masterHost)
|
|
14493
|
+
);
|
|
14389
14494
|
const nextMasterConfig = this.buildMasterConfigPayload(normalized, botName);
|
|
14390
14495
|
const nextWorkerConfig = this.buildWorkerConfigPayload(normalized, botName);
|
|
14391
14496
|
const nextWorkerState = this.buildSeedWorkerState({
|
|
@@ -14452,44 +14557,9 @@ var HookInitCommand = class {
|
|
|
14452
14557
|
throw new Error(`\u672A\u627E\u5230\u53EF\u521D\u59CB\u5316\u7684\u914D\u7F6E\u6E90\uFF0C\u8BF7\u5148\u51C6\u5907 ${LEGACY_CONFIG_PATH}\u3001${DEFAULT_CONFIG_PATH} \u6216\u89D2\u8272\u914D\u7F6E\u6587\u4EF6`);
|
|
14453
14558
|
}
|
|
14454
14559
|
normalizeSourceConfig(config) {
|
|
14455
|
-
|
|
14456
|
-
|
|
14457
|
-
|
|
14458
|
-
config.feishu?.app_secret || config.feishu?.appSecret || config.feishu?.appsecret || ""
|
|
14459
|
-
).trim();
|
|
14460
|
-
const masterHost = String(hook2.master_host || hook2.masterHost || "").trim();
|
|
14461
|
-
const masterPort = parsePositiveInt(hook2.master_port ?? hook2.masterPort, 19732);
|
|
14462
|
-
const sharedSecret = String(hook2.shared_secret || hook2.sharedSecret || appSecret || "").trim();
|
|
14463
|
-
const bindAllowedUserIds = parseUserIdList(hook2.bind_allowed_user_ids ?? hook2.bindAllowedUserIds);
|
|
14464
|
-
const missing = [];
|
|
14465
|
-
if (!appId) missing.push("feishu.app_id");
|
|
14466
|
-
if (!appSecret) missing.push("feishu.app_secret");
|
|
14467
|
-
if (!masterHost) missing.push("hook.master_host");
|
|
14468
|
-
if (!sharedSecret) missing.push("hook.shared_secret");
|
|
14469
|
-
if (bindAllowedUserIds.length === 0) missing.push("hook.bind_allowed_user_ids");
|
|
14470
|
-
if (missing.length > 0) {
|
|
14471
|
-
throw new Error(`\u521D\u59CB\u5316\u6240\u9700\u914D\u7F6E\u7F3A\u5931: ${missing.join(", ")}`);
|
|
14472
|
-
}
|
|
14473
|
-
return {
|
|
14474
|
-
feishuAppId: appId,
|
|
14475
|
-
feishuAppSecret: appSecret,
|
|
14476
|
-
masterHost,
|
|
14477
|
-
masterPort,
|
|
14478
|
-
sharedSecret,
|
|
14479
|
-
bindAllowedUserIds,
|
|
14480
|
-
botName: String(hook2.bot_name || hook2.botName || "").trim() || void 0,
|
|
14481
|
-
claimTimeoutMs: parsePositiveInt(hook2.claim_timeout_ms ?? hook2.claimTimeoutMs, 1e4),
|
|
14482
|
-
relayHeartbeatIntervalMs: parsePositiveInt(hook2.relay_heartbeat_interval_ms ?? hook2.relayHeartbeatIntervalMs, 3e4),
|
|
14483
|
-
relayHeartbeatTimeoutMs: parsePositiveInt(hook2.relay_heartbeat_timeout_ms ?? hook2.relayHeartbeatTimeoutMs, 9e4),
|
|
14484
|
-
slaveConnectTimeoutMs: parsePositiveInt(hook2.slave_connect_timeout_ms ?? hook2.slaveConnectTimeoutMs, 5e3),
|
|
14485
|
-
reconnectIntervalMs: parsePositiveInt(hook2.reconnect_interval_ms ?? hook2.reconnectIntervalMs, 3e3),
|
|
14486
|
-
authCliAuthSecret: String(config.auth?.cli_auth_secret || "").trim() || void 0,
|
|
14487
|
-
authApiUrl: String(config.auth?.api_url || "").trim() || void 0,
|
|
14488
|
-
contextConfig: resolveContextConfig(config)
|
|
14489
|
-
};
|
|
14490
|
-
}
|
|
14491
|
-
resolveHookSection(config) {
|
|
14492
|
-
return config.hook ?? config.ai_hook ?? config.aiHook ?? {};
|
|
14560
|
+
return normalizeHookInitConfig(config, {
|
|
14561
|
+
defaultMasterHost: resolveDefaultMasterHost()
|
|
14562
|
+
});
|
|
14493
14563
|
}
|
|
14494
14564
|
printEnvironmentSummary(sourcePath, existingConfig, migrationSummary) {
|
|
14495
14565
|
console.log(chalk9.bold("\nHook \u521D\u59CB\u5316\u5411\u5BFC\n"));
|
|
@@ -14537,6 +14607,19 @@ var HookInitCommand = class {
|
|
|
14537
14607
|
console.log(chalk9.yellow("\u8BF7\u8F93\u5165 y \u6216 n\u3002\n"));
|
|
14538
14608
|
}
|
|
14539
14609
|
}
|
|
14610
|
+
async askMasterHost(rl, config) {
|
|
14611
|
+
const defaultHost = resolveConfiguredMasterHost(config) || resolveDefaultMasterHost();
|
|
14612
|
+
while (true) {
|
|
14613
|
+
const label = defaultHost ? `\u7B2C\u4E09\u6B65\uFF1A\u4E3B\u8282\u70B9\u5730\u5740 [\u9ED8\u8BA4 ${defaultHost}]: ` : "\u7B2C\u4E09\u6B65\uFF1A\u4E3B\u8282\u70B9\u5730\u5740: ";
|
|
14614
|
+
const answer = (await rl.question(chalk9.dim(label))).trim();
|
|
14615
|
+
const resolved = answer || defaultHost;
|
|
14616
|
+
if (resolved) {
|
|
14617
|
+
console.log("");
|
|
14618
|
+
return resolved;
|
|
14619
|
+
}
|
|
14620
|
+
console.log(chalk9.yellow("\u4E3B\u8282\u70B9\u5730\u5740\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u8BF7\u8F93\u5165 IP \u6216\u57DF\u540D\u3002\n"));
|
|
14621
|
+
}
|
|
14622
|
+
}
|
|
14540
14623
|
buildMasterConfigPayload(normalized, botName) {
|
|
14541
14624
|
return {
|
|
14542
14625
|
feishu: {
|
|
@@ -15139,4 +15222,9 @@ hook.command("worker").argument("[engine]", "codex|gemini|claude", "codex").desc
|
|
|
15139
15222
|
hook.command("log").argument("[query]", "\u53EF\u9009\uFF0CtraceId / messageId / \u5173\u952E\u5B57").description("\u67E5\u770B\u672C\u673A agent-block hook master/worker \u65E5\u5FD7").option("--worker", "\u53EA\u770B worker \u65E5\u5FD7", false).option("--slave", "\u53EA\u770B worker \u65E5\u5FD7\uFF08\u517C\u5BB9\u65E7 ai-hook \u4E60\u60EF\uFF09", false).option("--master", "\u53EA\u770B master \u65E5\u5FD7", false).option("-n, --lines <lines>", "\u9ED8\u8BA4\u8FD4\u56DE\u6700\u8FD1\u591A\u5C11\u884C\uFF0C\u9ED8\u8BA4 200").option("-f, --follow", "\u6301\u7EED\u8DDF\u968F\u65E5\u5FD7\u8F93\u51FA\uFF0C\u7B49\u4EF7 tail -f", false).option("-c, --context <lines>", "\u5E26 query \u65F6\u8FD4\u56DE\u524D\u540E\u6587\uFF0C\u9ED8\u8BA4 20").action(async (query, options) => {
|
|
15140
15223
|
await hookLogAction(query, options);
|
|
15141
15224
|
});
|
|
15225
|
+
process.argv = [
|
|
15226
|
+
process.argv[0],
|
|
15227
|
+
process.argv[1],
|
|
15228
|
+
...normalizeCliArgs(process.argv[1], process.argv.slice(2))
|
|
15229
|
+
];
|
|
15142
15230
|
program.parse();
|
package/package.json
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nikou-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Install Agent Skills and MCP servers, and run distributed AI hook workers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"nikou-cli": "dist/index.js"
|
|
7
|
+
"nikou-cli": "dist/index.js",
|
|
8
|
+
"ai-hook": "dist/ai-hook.js"
|
|
8
9
|
},
|
|
9
10
|
"files": [
|
|
10
11
|
"dist"
|
|
11
12
|
],
|
|
12
13
|
"scripts": {
|
|
13
|
-
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
14
|
+
"build": "tsup src/index.ts src/ai-hook.ts --format esm --dts --clean",
|
|
14
15
|
"dev": "tsup src/index.ts --format esm --watch",
|
|
15
16
|
"test": "tsx --test test/**/*.test.ts",
|
|
16
17
|
"privacy-scan": "node scripts/privacy-scan.mjs",
|