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 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
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ normalizeCliArgs
4
+ } from "./chunk-F3EPGM5N.js";
5
+
6
+ // src/ai-hook.ts
7
+ process.argv = [
8
+ process.argv[0],
9
+ "ai-hook",
10
+ ...normalizeCliArgs("ai-hook", process.argv.slice(2))
11
+ ];
12
+ await import("./index.js");
@@ -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
- const hook2 = this.resolveHookSection(config);
14456
- const appId = String(config.feishu?.app_id || config.feishu?.appId || config.feishu?.appid || "").trim();
14457
- const appSecret = String(
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.0",
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",