nikou-cli 0.1.5 → 0.1.6
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 +59 -5
- package/dist/ai-hook.js +1 -1
- package/dist/{chunk-F3EPGM5N.js → chunk-OQQEIFQV.js} +1 -1
- package/dist/index.js +630 -216
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
normalizeCliArgs
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-OQQEIFQV.js";
|
|
5
5
|
|
|
6
6
|
// src/index.ts
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -463,17 +463,17 @@ var TOOL_CONFIG = {
|
|
|
463
463
|
gemini: { filePath: join6(homedir(), ".gemini", "settings.json"), format: "json", jsonPath: ["mcpServers"] },
|
|
464
464
|
opencode: { filePath: join6(homedir(), ".config", "opencode", "opencode.json"), format: "json", jsonPath: ["mcp"] }
|
|
465
465
|
};
|
|
466
|
-
function readJsonFile(
|
|
467
|
-
if (!existsSync5(
|
|
466
|
+
function readJsonFile(path30) {
|
|
467
|
+
if (!existsSync5(path30)) return {};
|
|
468
468
|
try {
|
|
469
|
-
return JSON.parse(readFileSync4(
|
|
469
|
+
return JSON.parse(readFileSync4(path30, "utf-8"));
|
|
470
470
|
} catch {
|
|
471
471
|
return {};
|
|
472
472
|
}
|
|
473
473
|
}
|
|
474
|
-
function writeJsonFile(
|
|
475
|
-
mkdirSync4(dirname2(
|
|
476
|
-
writeFileSync3(
|
|
474
|
+
function writeJsonFile(path30, data) {
|
|
475
|
+
mkdirSync4(dirname2(path30), { recursive: true });
|
|
476
|
+
writeFileSync3(path30, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
477
477
|
}
|
|
478
478
|
function getNestedObj(root, keys) {
|
|
479
479
|
let cur = root;
|
|
@@ -500,10 +500,10 @@ function extractServerFromContent(content, jsonPath) {
|
|
|
500
500
|
return null;
|
|
501
501
|
}
|
|
502
502
|
}
|
|
503
|
-
function readTomlFile(
|
|
504
|
-
if (!existsSync5(
|
|
503
|
+
function readTomlFile(path30) {
|
|
504
|
+
if (!existsSync5(path30)) return "";
|
|
505
505
|
try {
|
|
506
|
-
return readFileSync4(
|
|
506
|
+
return readFileSync4(path30, "utf-8");
|
|
507
507
|
} catch {
|
|
508
508
|
return "";
|
|
509
509
|
}
|
|
@@ -549,9 +549,9 @@ function tomlListServers(toml) {
|
|
|
549
549
|
}
|
|
550
550
|
return results;
|
|
551
551
|
}
|
|
552
|
-
function backupFile(
|
|
553
|
-
if (existsSync5(
|
|
554
|
-
copyFileSync(
|
|
552
|
+
function backupFile(path30) {
|
|
553
|
+
if (existsSync5(path30)) {
|
|
554
|
+
copyFileSync(path30, path30 + ".bak");
|
|
555
555
|
}
|
|
556
556
|
}
|
|
557
557
|
function writeMcpToTool(toolId, serverName, variantContent, force) {
|
|
@@ -1538,6 +1538,19 @@ function resolveContextConfig(config) {
|
|
|
1538
1538
|
)
|
|
1539
1539
|
};
|
|
1540
1540
|
}
|
|
1541
|
+
function resolveNacosSkillSyncConfig(config) {
|
|
1542
|
+
const raw = config.nacos_skill_sync ?? config.nacosSkillSync ?? {};
|
|
1543
|
+
return {
|
|
1544
|
+
enabled: parseBoolean(raw.enabled, true),
|
|
1545
|
+
profile: String(raw.profile || "nikou-block").trim(),
|
|
1546
|
+
label: String(raw.label || "latest").trim(),
|
|
1547
|
+
interval: String(raw.interval || "30s").trim(),
|
|
1548
|
+
plan_poll_interval_ms: parsePositiveInt(raw.plan_poll_interval_ms ?? raw.planPollIntervalMs, 6e4),
|
|
1549
|
+
planPollIntervalMs: parsePositiveInt(raw.plan_poll_interval_ms ?? raw.planPollIntervalMs, 6e4),
|
|
1550
|
+
auto_upload: parseBoolean(raw.auto_upload ?? raw.autoUpload, false),
|
|
1551
|
+
autoUpload: parseBoolean(raw.auto_upload ?? raw.autoUpload, false)
|
|
1552
|
+
};
|
|
1553
|
+
}
|
|
1541
1554
|
function resolveMasterConfig(config, overrides = {}) {
|
|
1542
1555
|
const hook2 = resolveHookSection(config);
|
|
1543
1556
|
const feishuConfig = extractFeishuConfig(config);
|
|
@@ -2582,7 +2595,7 @@ var CardStreamUpdater = class {
|
|
|
2582
2595
|
lastTokenUsage = "";
|
|
2583
2596
|
sequence = 1;
|
|
2584
2597
|
flushTimer = null;
|
|
2585
|
-
|
|
2598
|
+
flushPromise = null;
|
|
2586
2599
|
disposed = false;
|
|
2587
2600
|
constructor(larkClient, cardId, taskId, logger3, intervalMs = CARD_STREAM_INTERVAL_MS) {
|
|
2588
2601
|
this.larkClient = larkClient;
|
|
@@ -2670,8 +2683,19 @@ ${incoming}`, CARD_STREAM_STDOUT_MAX_LENGTH);
|
|
|
2670
2683
|
}, this.intervalMs);
|
|
2671
2684
|
}
|
|
2672
2685
|
async flush() {
|
|
2673
|
-
if (this.disposed
|
|
2674
|
-
this.
|
|
2686
|
+
if (this.disposed) return;
|
|
2687
|
+
if (this.flushPromise) {
|
|
2688
|
+
await this.flushPromise;
|
|
2689
|
+
return;
|
|
2690
|
+
}
|
|
2691
|
+
this.flushPromise = this.flushNow();
|
|
2692
|
+
try {
|
|
2693
|
+
await this.flushPromise;
|
|
2694
|
+
} finally {
|
|
2695
|
+
this.flushPromise = null;
|
|
2696
|
+
}
|
|
2697
|
+
}
|
|
2698
|
+
async flushNow() {
|
|
2675
2699
|
try {
|
|
2676
2700
|
const tokenKey = JSON.stringify(this.tokenUsage);
|
|
2677
2701
|
const needsFullUpdate = this.lastSession !== this.sessionBuffer || this.lastPath !== this.pathBuffer || this.lastHostName !== this.hostName || this.lastStopResult !== this.stopResultBuffer || this.lastDisableStop !== this.stopDisabled || this.lastTokenUsage !== tokenKey;
|
|
@@ -2703,8 +2727,6 @@ ${incoming}`, CARD_STREAM_STDOUT_MAX_LENGTH);
|
|
|
2703
2727
|
}
|
|
2704
2728
|
} catch (error) {
|
|
2705
2729
|
this.logger.warn(`\u5361\u7247\u5237\u65B0\u5931\u8D25: ${formatCardUpdateError(error)}`);
|
|
2706
|
-
} finally {
|
|
2707
|
-
this.flushing = false;
|
|
2708
2730
|
}
|
|
2709
2731
|
}
|
|
2710
2732
|
// ─── 飞书 API 调用 ──────────────────────────────
|
|
@@ -2814,19 +2836,64 @@ ${incoming}`, CARD_STREAM_STDOUT_MAX_LENGTH);
|
|
|
2814
2836
|
clearTimeout(this.flushTimer);
|
|
2815
2837
|
this.flushTimer = null;
|
|
2816
2838
|
}
|
|
2817
|
-
this.
|
|
2839
|
+
if (this.flushPromise) {
|
|
2840
|
+
await this.flushPromise;
|
|
2841
|
+
}
|
|
2818
2842
|
await this.flush();
|
|
2819
2843
|
this.disposed = true;
|
|
2820
2844
|
}
|
|
2821
2845
|
};
|
|
2822
2846
|
|
|
2847
|
+
// src/hook/message-content-parser.ts
|
|
2848
|
+
function parseContent(content) {
|
|
2849
|
+
if (content && typeof content === "object" && !Array.isArray(content)) {
|
|
2850
|
+
return content;
|
|
2851
|
+
}
|
|
2852
|
+
if (typeof content !== "string") {
|
|
2853
|
+
return {};
|
|
2854
|
+
}
|
|
2855
|
+
try {
|
|
2856
|
+
const parsed = JSON.parse(content);
|
|
2857
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
2858
|
+
} catch {
|
|
2859
|
+
return {};
|
|
2860
|
+
}
|
|
2861
|
+
}
|
|
2862
|
+
function extractFeishuPostText(content) {
|
|
2863
|
+
const parsed = parseContent(content);
|
|
2864
|
+
const title = String(parsed.title || "").trim();
|
|
2865
|
+
const rows = Array.isArray(parsed.content) ? parsed.content : Array.isArray(parsed.content_v2) ? parsed.content_v2 : [];
|
|
2866
|
+
const parts = [];
|
|
2867
|
+
if (title) {
|
|
2868
|
+
parts.push(title);
|
|
2869
|
+
}
|
|
2870
|
+
rows.forEach((row) => {
|
|
2871
|
+
if (!Array.isArray(row)) {
|
|
2872
|
+
return;
|
|
2873
|
+
}
|
|
2874
|
+
row.forEach((item) => {
|
|
2875
|
+
const block = item;
|
|
2876
|
+
const tag = String(block.tag || "").trim();
|
|
2877
|
+
if ((tag === "text" || tag === "a") && block.text) {
|
|
2878
|
+
parts.push(String(block.text));
|
|
2879
|
+
return;
|
|
2880
|
+
}
|
|
2881
|
+
if (tag === "at") {
|
|
2882
|
+
const name = String(block.user_name || block.name || "").replace(/^@/, "").trim();
|
|
2883
|
+
parts.push(name ? `@${name}` : "@");
|
|
2884
|
+
}
|
|
2885
|
+
});
|
|
2886
|
+
});
|
|
2887
|
+
return parts.join("").replace(/\s+/g, " ").trim();
|
|
2888
|
+
}
|
|
2889
|
+
|
|
2823
2890
|
// src/hook/master/message-parser.ts
|
|
2824
2891
|
function extractMessageText(message) {
|
|
2825
2892
|
const content = message?.content || message?.body?.content;
|
|
2826
2893
|
if (!content) return "";
|
|
2827
2894
|
try {
|
|
2828
2895
|
const parsed = typeof content === "string" ? JSON.parse(content) : content;
|
|
2829
|
-
const text = String(parsed?.text || "") ||
|
|
2896
|
+
const text = String(parsed?.text || "") || extractFeishuPostText(parsed);
|
|
2830
2897
|
return stripMentions(text, message);
|
|
2831
2898
|
} catch {
|
|
2832
2899
|
return stripMentions(String(content || ""), message);
|
|
@@ -2858,47 +2925,6 @@ function isMentionBot(message, botName) {
|
|
|
2858
2925
|
return name === botName || name === DEFAULT_BOT_NAME;
|
|
2859
2926
|
});
|
|
2860
2927
|
}
|
|
2861
|
-
function extractPostText(content) {
|
|
2862
|
-
const parsed = parseContent(content);
|
|
2863
|
-
const title = String(parsed?.title || "").trim();
|
|
2864
|
-
const rows = Array.isArray(parsed?.content) ? parsed.content : [];
|
|
2865
|
-
const parts = [];
|
|
2866
|
-
if (title) {
|
|
2867
|
-
parts.push(title);
|
|
2868
|
-
}
|
|
2869
|
-
rows.forEach((row) => {
|
|
2870
|
-
if (!Array.isArray(row)) {
|
|
2871
|
-
return;
|
|
2872
|
-
}
|
|
2873
|
-
row.forEach((item) => {
|
|
2874
|
-
const block = item;
|
|
2875
|
-
const tag = String(block?.tag || "").trim();
|
|
2876
|
-
if ((tag === "text" || tag === "a") && block?.text) {
|
|
2877
|
-
parts.push(String(block.text));
|
|
2878
|
-
return;
|
|
2879
|
-
}
|
|
2880
|
-
if (tag === "at") {
|
|
2881
|
-
const name = String(block.user_name || block.name || "").replace(/^@/, "").trim();
|
|
2882
|
-
parts.push(name ? `@${name}` : "@");
|
|
2883
|
-
}
|
|
2884
|
-
});
|
|
2885
|
-
});
|
|
2886
|
-
return parts.join("").replace(/\s+/g, " ").trim();
|
|
2887
|
-
}
|
|
2888
|
-
function parseContent(content) {
|
|
2889
|
-
if (content && typeof content === "object" && !Array.isArray(content)) {
|
|
2890
|
-
return content;
|
|
2891
|
-
}
|
|
2892
|
-
if (typeof content !== "string") {
|
|
2893
|
-
return {};
|
|
2894
|
-
}
|
|
2895
|
-
try {
|
|
2896
|
-
const parsed = JSON.parse(content);
|
|
2897
|
-
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
2898
|
-
} catch {
|
|
2899
|
-
return {};
|
|
2900
|
-
}
|
|
2901
|
-
}
|
|
2902
2928
|
function stripMentions(text, message) {
|
|
2903
2929
|
let cleaned = String(text || "");
|
|
2904
2930
|
const mentions = Array.isArray(message?.mentions) ? message.mentions : [];
|
|
@@ -5275,13 +5301,20 @@ var HookMasterCommand = class {
|
|
|
5275
5301
|
onCardAction: (data) => this.handleCardActionTrigger(data)
|
|
5276
5302
|
});
|
|
5277
5303
|
this.startBindWhitelistWatcher();
|
|
5278
|
-
this.
|
|
5304
|
+
if (this.options.manageProcessSignals !== false) {
|
|
5305
|
+
this.setupExitHandlers();
|
|
5306
|
+
}
|
|
5279
5307
|
this.heartbeatTimer = setInterval(() => {
|
|
5280
5308
|
this.stateManager?.updateHeartbeat();
|
|
5281
5309
|
}, HEARTBEAT_INTERVAL_MS);
|
|
5282
5310
|
this.logger.info(
|
|
5283
5311
|
`\u4E3B\u8282\u70B9\u542F\u52A8\u5B8C\u6210 host=${masterConfig.masterHost} port=${masterConfig.masterPort}`
|
|
5284
5312
|
);
|
|
5313
|
+
return {
|
|
5314
|
+
masterHost: masterConfig.masterHost,
|
|
5315
|
+
masterPort: masterConfig.masterPort,
|
|
5316
|
+
sharedSecret: masterConfig.sharedSecret
|
|
5317
|
+
};
|
|
5285
5318
|
}
|
|
5286
5319
|
async handleFeishuMessage(data) {
|
|
5287
5320
|
const message = resolveEventMessage(data);
|
|
@@ -5772,34 +5805,34 @@ var HookMasterCommand = class {
|
|
|
5772
5805
|
});
|
|
5773
5806
|
}
|
|
5774
5807
|
setupExitHandlers() {
|
|
5775
|
-
const cleanup2 = async (signal) => {
|
|
5776
|
-
this.logger.info(`\u6536\u5230\u4FE1\u53F7 ${signal}\uFF0C\u6B63\u5728\u5173\u95ED...`);
|
|
5777
|
-
if (this.heartbeatTimer) {
|
|
5778
|
-
clearInterval(this.heartbeatTimer);
|
|
5779
|
-
this.heartbeatTimer = null;
|
|
5780
|
-
}
|
|
5781
|
-
if (this.bindWhitelistWatchTimer) {
|
|
5782
|
-
clearInterval(this.bindWhitelistWatchTimer);
|
|
5783
|
-
this.bindWhitelistWatchTimer = null;
|
|
5784
|
-
}
|
|
5785
|
-
this.groupRouteDispatcher?.clear();
|
|
5786
|
-
this.wsServer?.stop();
|
|
5787
|
-
this.stateManager?.update({
|
|
5788
|
-
status: "stopped",
|
|
5789
|
-
stoppedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5790
|
-
lastSignal: signal
|
|
5791
|
-
});
|
|
5792
|
-
await this.usageRecorder.close();
|
|
5793
|
-
};
|
|
5794
5808
|
process4.on("SIGINT", async () => {
|
|
5795
|
-
await
|
|
5809
|
+
await this.stop("SIGINT");
|
|
5796
5810
|
process4.exit(0);
|
|
5797
5811
|
});
|
|
5798
5812
|
process4.on("SIGTERM", async () => {
|
|
5799
|
-
await
|
|
5813
|
+
await this.stop("SIGTERM");
|
|
5800
5814
|
process4.exit(0);
|
|
5801
5815
|
});
|
|
5802
5816
|
}
|
|
5817
|
+
async stop(signal = "manual") {
|
|
5818
|
+
this.logger.info(`\u6536\u5230\u4FE1\u53F7 ${signal}\uFF0C\u6B63\u5728\u5173\u95ED...`);
|
|
5819
|
+
if (this.heartbeatTimer) {
|
|
5820
|
+
clearInterval(this.heartbeatTimer);
|
|
5821
|
+
this.heartbeatTimer = null;
|
|
5822
|
+
}
|
|
5823
|
+
if (this.bindWhitelistWatchTimer) {
|
|
5824
|
+
clearInterval(this.bindWhitelistWatchTimer);
|
|
5825
|
+
this.bindWhitelistWatchTimer = null;
|
|
5826
|
+
}
|
|
5827
|
+
this.groupRouteDispatcher?.clear();
|
|
5828
|
+
this.wsServer?.stop();
|
|
5829
|
+
this.stateManager?.update({
|
|
5830
|
+
status: "stopped",
|
|
5831
|
+
stoppedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5832
|
+
lastSignal: signal
|
|
5833
|
+
});
|
|
5834
|
+
await this.usageRecorder.close();
|
|
5835
|
+
}
|
|
5803
5836
|
};
|
|
5804
5837
|
|
|
5805
5838
|
// src/hook/logger.ts
|
|
@@ -5920,8 +5953,8 @@ async function hookMasterAction(options) {
|
|
|
5920
5953
|
|
|
5921
5954
|
// src/hook/worker/worker-command.ts
|
|
5922
5955
|
import process10 from "process";
|
|
5923
|
-
import
|
|
5924
|
-
import
|
|
5956
|
+
import os17 from "os";
|
|
5957
|
+
import path27 from "path";
|
|
5925
5958
|
import * as lark3 from "@larksuiteoapi/node-sdk";
|
|
5926
5959
|
|
|
5927
5960
|
// src/hook/worker/runners/codex-runner.ts
|
|
@@ -7657,7 +7690,7 @@ var MessageReceiveStrategy = class {
|
|
|
7657
7690
|
if (!raw) return "";
|
|
7658
7691
|
try {
|
|
7659
7692
|
const parsed = JSON.parse(raw);
|
|
7660
|
-
const text = String(parsed?.text || "");
|
|
7693
|
+
const text = String(parsed?.text || "") || extractFeishuPostText(parsed);
|
|
7661
7694
|
return this.stripMentions(text, message);
|
|
7662
7695
|
} catch {
|
|
7663
7696
|
return this.stripMentions(String(raw), message);
|
|
@@ -7665,25 +7698,7 @@ var MessageReceiveStrategy = class {
|
|
|
7665
7698
|
}
|
|
7666
7699
|
extractPostText(messageLike) {
|
|
7667
7700
|
const raw = messageLike?.content || messageLike?.body?.content;
|
|
7668
|
-
|
|
7669
|
-
try {
|
|
7670
|
-
const parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
|
|
7671
|
-
const blocks = parsed?.content || [];
|
|
7672
|
-
const parts = [];
|
|
7673
|
-
blocks.forEach((row) => {
|
|
7674
|
-
(row || []).forEach((item) => {
|
|
7675
|
-
if ((item?.tag === "text" || item?.tag === "a") && item?.text) {
|
|
7676
|
-
parts.push(String(item.text));
|
|
7677
|
-
}
|
|
7678
|
-
if (item?.tag === "at") {
|
|
7679
|
-
parts.push(String(item.user_name || item.name || ""));
|
|
7680
|
-
}
|
|
7681
|
-
});
|
|
7682
|
-
});
|
|
7683
|
-
return parts.join("").replace(/\s+/g, " ").trim();
|
|
7684
|
-
} catch {
|
|
7685
|
-
return "";
|
|
7686
|
-
}
|
|
7701
|
+
return extractFeishuPostText(raw);
|
|
7687
7702
|
}
|
|
7688
7703
|
stripMentions(text, message) {
|
|
7689
7704
|
let cleaned = String(text || "");
|
|
@@ -10496,6 +10511,7 @@ var LocalBrowserWsServer = class {
|
|
|
10496
10511
|
workerId;
|
|
10497
10512
|
workerType;
|
|
10498
10513
|
larkClient;
|
|
10514
|
+
getNacosSyncStatus;
|
|
10499
10515
|
wss = null;
|
|
10500
10516
|
profile;
|
|
10501
10517
|
startTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -10505,6 +10521,7 @@ var LocalBrowserWsServer = class {
|
|
|
10505
10521
|
this.workerId = options.workerId;
|
|
10506
10522
|
this.workerType = options.workerType;
|
|
10507
10523
|
this.larkClient = options.larkClient;
|
|
10524
|
+
this.getNacosSyncStatus = options.getNacosSyncStatus;
|
|
10508
10525
|
}
|
|
10509
10526
|
async start() {
|
|
10510
10527
|
if (this.wss) {
|
|
@@ -10685,7 +10702,8 @@ var LocalBrowserWsServer = class {
|
|
|
10685
10702
|
cliTools: {
|
|
10686
10703
|
codex: this.detectCliTool("codex"),
|
|
10687
10704
|
claude: this.detectCliTool("claude")
|
|
10688
|
-
}
|
|
10705
|
+
},
|
|
10706
|
+
nacosSync: this.getNacosSyncStatus?.() ?? null
|
|
10689
10707
|
}
|
|
10690
10708
|
});
|
|
10691
10709
|
}
|
|
@@ -13974,6 +13992,263 @@ var OwnerNotifyService = class {
|
|
|
13974
13992
|
}
|
|
13975
13993
|
};
|
|
13976
13994
|
|
|
13995
|
+
// src/hook/worker/nacos-subscription-sync.ts
|
|
13996
|
+
import fs27 from "fs";
|
|
13997
|
+
import os16 from "os";
|
|
13998
|
+
import path26 from "path";
|
|
13999
|
+
import { execFile, spawn as spawn4 } from "child_process";
|
|
14000
|
+
import { createRequire } from "module";
|
|
14001
|
+
import { promisify } from "util";
|
|
14002
|
+
var execFileAsync = promisify(execFile);
|
|
14003
|
+
var NacosSubscriptionSyncCoordinator = class {
|
|
14004
|
+
logger;
|
|
14005
|
+
workerId;
|
|
14006
|
+
config;
|
|
14007
|
+
timer = null;
|
|
14008
|
+
daemon = null;
|
|
14009
|
+
running = false;
|
|
14010
|
+
stopped = false;
|
|
14011
|
+
status;
|
|
14012
|
+
statePath = path26.join(os16.homedir(), ".nikou-block", "worker", "nacos-subscriptions.json");
|
|
14013
|
+
constructor(options) {
|
|
14014
|
+
this.logger = options.logger;
|
|
14015
|
+
this.workerId = options.workerId;
|
|
14016
|
+
this.config = options.config;
|
|
14017
|
+
this.status = {
|
|
14018
|
+
enabled: this.config.enabled,
|
|
14019
|
+
configured: false,
|
|
14020
|
+
profile: this.config.profile,
|
|
14021
|
+
label: this.config.label,
|
|
14022
|
+
daemonRunning: false,
|
|
14023
|
+
totalSkills: 0,
|
|
14024
|
+
synced: 0,
|
|
14025
|
+
pending: 0,
|
|
14026
|
+
conflicts: 0,
|
|
14027
|
+
failed: 0
|
|
14028
|
+
};
|
|
14029
|
+
}
|
|
14030
|
+
start() {
|
|
14031
|
+
if (!this.config.enabled || this.timer) return;
|
|
14032
|
+
void this.syncOnce();
|
|
14033
|
+
this.timer = setInterval(() => {
|
|
14034
|
+
void this.syncOnce();
|
|
14035
|
+
}, this.config.plan_poll_interval_ms);
|
|
14036
|
+
}
|
|
14037
|
+
async stop() {
|
|
14038
|
+
this.stopped = true;
|
|
14039
|
+
if (this.timer) {
|
|
14040
|
+
clearInterval(this.timer);
|
|
14041
|
+
this.timer = null;
|
|
14042
|
+
}
|
|
14043
|
+
if (this.daemon) {
|
|
14044
|
+
this.daemon.kill("SIGTERM");
|
|
14045
|
+
this.daemon = null;
|
|
14046
|
+
this.status.daemonRunning = false;
|
|
14047
|
+
}
|
|
14048
|
+
}
|
|
14049
|
+
getStatus() {
|
|
14050
|
+
return { ...this.status };
|
|
14051
|
+
}
|
|
14052
|
+
async syncOnce() {
|
|
14053
|
+
if (this.running || this.stopped) return;
|
|
14054
|
+
this.running = true;
|
|
14055
|
+
try {
|
|
14056
|
+
const plan = await this.fetchPlan();
|
|
14057
|
+
this.status.enabled = plan.nacos.enabled;
|
|
14058
|
+
this.status.host = plan.nacos.host;
|
|
14059
|
+
this.status.profile = plan.nacos.profile || this.config.profile;
|
|
14060
|
+
this.status.label = plan.nacos.label || this.config.label;
|
|
14061
|
+
this.status.lastPlanAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
14062
|
+
if (!plan.nacos.enabled) {
|
|
14063
|
+
this.status.configured = false;
|
|
14064
|
+
this.status.totalSkills = 0;
|
|
14065
|
+
this.status.pending = 0;
|
|
14066
|
+
return;
|
|
14067
|
+
}
|
|
14068
|
+
await this.configureProfile(plan);
|
|
14069
|
+
await this.ensureMode(plan);
|
|
14070
|
+
this.ensureDaemon(plan);
|
|
14071
|
+
const results = [];
|
|
14072
|
+
for (const skill of plan.skills) {
|
|
14073
|
+
const result = await this.syncSkill(plan, skill);
|
|
14074
|
+
results.push(result);
|
|
14075
|
+
}
|
|
14076
|
+
await this.report(results);
|
|
14077
|
+
this.persistManagedState(plan.skills);
|
|
14078
|
+
this.applySummary(results);
|
|
14079
|
+
this.status.lastSyncAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
14080
|
+
this.status.lastError = void 0;
|
|
14081
|
+
} catch (error) {
|
|
14082
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
14083
|
+
this.status.lastError = message;
|
|
14084
|
+
this.logger.warn(`Nacos Skill \u8BA2\u9605\u540C\u6B65\u5931\u8D25: ${message}`);
|
|
14085
|
+
} finally {
|
|
14086
|
+
this.running = false;
|
|
14087
|
+
}
|
|
14088
|
+
}
|
|
14089
|
+
async fetchPlan() {
|
|
14090
|
+
const runtime = resolveCliAuthRuntimeConfig();
|
|
14091
|
+
if (!runtime.cliAuthSecret) {
|
|
14092
|
+
throw new Error("\u672A\u914D\u7F6E CLI_AUTH_SECRET\uFF0C\u65E0\u6CD5\u62C9\u53D6 Nacos \u540C\u6B65\u8BA1\u5212");
|
|
14093
|
+
}
|
|
14094
|
+
const response = await fetch(`${runtime.apiUrl}/worker-skills/nacos-sync/plan`, {
|
|
14095
|
+
method: "POST",
|
|
14096
|
+
headers: { "Content-Type": "application/json" },
|
|
14097
|
+
body: JSON.stringify({ secret: runtime.cliAuthSecret, workerId: this.workerId })
|
|
14098
|
+
});
|
|
14099
|
+
if (!response.ok) {
|
|
14100
|
+
const text = await response.text().catch(() => "");
|
|
14101
|
+
throw new Error(`\u62C9\u53D6 Nacos \u540C\u6B65\u8BA1\u5212\u5931\u8D25: ${response.status} ${text}`);
|
|
14102
|
+
}
|
|
14103
|
+
return await response.json();
|
|
14104
|
+
}
|
|
14105
|
+
async report(results) {
|
|
14106
|
+
if (!results.length) return;
|
|
14107
|
+
const runtime = resolveCliAuthRuntimeConfig();
|
|
14108
|
+
const response = await fetch(`${runtime.apiUrl}/worker-skills/nacos-sync/report`, {
|
|
14109
|
+
method: "POST",
|
|
14110
|
+
headers: { "Content-Type": "application/json" },
|
|
14111
|
+
body: JSON.stringify({ secret: runtime.cliAuthSecret, workerId: this.workerId, results })
|
|
14112
|
+
});
|
|
14113
|
+
if (!response.ok) {
|
|
14114
|
+
const text = await response.text().catch(() => "");
|
|
14115
|
+
throw new Error(`\u4E0A\u62A5 Nacos \u540C\u6B65\u72B6\u6001\u5931\u8D25: ${response.status} ${text}`);
|
|
14116
|
+
}
|
|
14117
|
+
}
|
|
14118
|
+
async configureProfile(plan) {
|
|
14119
|
+
const nacos = plan.nacos;
|
|
14120
|
+
const profile = nacos.profile || this.config.profile;
|
|
14121
|
+
const args = [
|
|
14122
|
+
"profile",
|
|
14123
|
+
"set",
|
|
14124
|
+
profile,
|
|
14125
|
+
`host=${nacos.serverHost || this.parseHost(nacos.host).host}`,
|
|
14126
|
+
`port=${nacos.port || this.parseHost(nacos.host).port}`,
|
|
14127
|
+
`scheme=${nacos.scheme || this.parseHost(nacos.host).scheme}`,
|
|
14128
|
+
`namespace=${nacos.namespace || "public"}`,
|
|
14129
|
+
`auth-type=${nacos.authType || "none"}`
|
|
14130
|
+
];
|
|
14131
|
+
if (nacos.username) args.push(`username=${nacos.username}`);
|
|
14132
|
+
if (nacos.password) args.push(`password=${nacos.password}`);
|
|
14133
|
+
await this.run(args);
|
|
14134
|
+
this.status.configured = true;
|
|
14135
|
+
}
|
|
14136
|
+
async ensureMode(plan) {
|
|
14137
|
+
await this.run(["skill-sync", "mode", "nacos", "--profile", plan.nacos.profile || this.config.profile, "--switch-profile"]);
|
|
14138
|
+
}
|
|
14139
|
+
ensureDaemon(plan) {
|
|
14140
|
+
if (this.daemon && !this.daemon.killed) return;
|
|
14141
|
+
const args = [
|
|
14142
|
+
"skill-sync",
|
|
14143
|
+
"start",
|
|
14144
|
+
"--foreground",
|
|
14145
|
+
"--non-interactive",
|
|
14146
|
+
"--profile",
|
|
14147
|
+
plan.nacos.profile || this.config.profile,
|
|
14148
|
+
"--label",
|
|
14149
|
+
plan.nacos.label || this.config.label,
|
|
14150
|
+
"--interval",
|
|
14151
|
+
this.config.interval,
|
|
14152
|
+
"--switch-profile"
|
|
14153
|
+
];
|
|
14154
|
+
if (!this.config.auto_upload) {
|
|
14155
|
+
args.push("--no-auto-upload");
|
|
14156
|
+
}
|
|
14157
|
+
const bin = this.resolveNacosCliBin();
|
|
14158
|
+
this.daemon = spawn4(bin, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
14159
|
+
this.status.daemonRunning = true;
|
|
14160
|
+
this.daemon.stdout?.on("data", (chunk) => this.logger.debug(`nacos-cli: ${String(chunk).trim()}`));
|
|
14161
|
+
this.daemon.stderr?.on("data", (chunk) => this.logger.warn(`nacos-cli: ${String(chunk).trim()}`));
|
|
14162
|
+
this.daemon.once("exit", (code, signal) => {
|
|
14163
|
+
this.status.daemonRunning = false;
|
|
14164
|
+
this.daemon = null;
|
|
14165
|
+
if (!this.stopped) {
|
|
14166
|
+
this.status.lastError = `Nacos daemon \u5DF2\u9000\u51FA: code=${code ?? "-"}, signal=${signal ?? "-"}`;
|
|
14167
|
+
}
|
|
14168
|
+
});
|
|
14169
|
+
}
|
|
14170
|
+
async syncSkill(plan, skill) {
|
|
14171
|
+
try {
|
|
14172
|
+
await this.run([
|
|
14173
|
+
"skill-sync",
|
|
14174
|
+
skill.status === "pending_remove" ? "remove" : "add",
|
|
14175
|
+
skill.nacosSkillName,
|
|
14176
|
+
"--profile",
|
|
14177
|
+
plan.nacos.profile || this.config.profile,
|
|
14178
|
+
"--switch-profile",
|
|
14179
|
+
...skill.status === "pending_remove" ? [] : ["--non-interactive"]
|
|
14180
|
+
]);
|
|
14181
|
+
return {
|
|
14182
|
+
resourceId: skill.resourceId,
|
|
14183
|
+
nacosSkillName: skill.nacosSkillName,
|
|
14184
|
+
desiredVersionKey: skill.desiredVersionKey,
|
|
14185
|
+
status: skill.status === "pending_remove" ? "removed" : "synced",
|
|
14186
|
+
message: "Nacos Skill Sync \u6267\u884C\u6210\u529F"
|
|
14187
|
+
};
|
|
14188
|
+
} catch (error) {
|
|
14189
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
14190
|
+
const status = /conflict|冲突/i.test(message) ? "conflict" : "failed";
|
|
14191
|
+
return {
|
|
14192
|
+
resourceId: skill.resourceId,
|
|
14193
|
+
nacosSkillName: skill.nacosSkillName,
|
|
14194
|
+
desiredVersionKey: skill.desiredVersionKey,
|
|
14195
|
+
status,
|
|
14196
|
+
message
|
|
14197
|
+
};
|
|
14198
|
+
}
|
|
14199
|
+
}
|
|
14200
|
+
async run(args) {
|
|
14201
|
+
const bin = this.resolveNacosCliBin();
|
|
14202
|
+
const result = await execFileAsync(bin, args, { timeout: 6e4, maxBuffer: 1024 * 1024 * 2 });
|
|
14203
|
+
return `${result.stdout ?? ""}${result.stderr ?? ""}`.trim();
|
|
14204
|
+
}
|
|
14205
|
+
resolveNacosCliBin() {
|
|
14206
|
+
try {
|
|
14207
|
+
const require2 = createRequire(import.meta.url);
|
|
14208
|
+
const pkgPath = require2.resolve("@nacos-group/cli/package.json");
|
|
14209
|
+
return path26.join(path26.dirname(pkgPath), "bin", "cli.js");
|
|
14210
|
+
} catch {
|
|
14211
|
+
return "nacos-cli";
|
|
14212
|
+
}
|
|
14213
|
+
}
|
|
14214
|
+
applySummary(results) {
|
|
14215
|
+
this.status.totalSkills = results.length;
|
|
14216
|
+
this.status.synced = results.filter((item) => item.status === "synced" || item.status === "removed").length;
|
|
14217
|
+
this.status.pending = results.filter((item) => item.status.startsWith("pending")).length;
|
|
14218
|
+
this.status.conflicts = results.filter((item) => item.status === "conflict").length;
|
|
14219
|
+
this.status.failed = results.filter((item) => item.status === "failed").length;
|
|
14220
|
+
}
|
|
14221
|
+
persistManagedState(skills) {
|
|
14222
|
+
try {
|
|
14223
|
+
fs27.mkdirSync(path26.dirname(this.statePath), { recursive: true });
|
|
14224
|
+
fs27.writeFileSync(this.statePath, JSON.stringify({
|
|
14225
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14226
|
+
skills: skills.map((item) => ({
|
|
14227
|
+
resourceId: item.resourceId,
|
|
14228
|
+
nacosSkillName: item.nacosSkillName,
|
|
14229
|
+
desiredLabel: item.desiredLabel,
|
|
14230
|
+
desiredVersionKey: item.desiredVersionKey,
|
|
14231
|
+
status: item.status
|
|
14232
|
+
}))
|
|
14233
|
+
}, null, 2));
|
|
14234
|
+
} catch (error) {
|
|
14235
|
+
this.logger.warn(`\u5199\u5165 Nacos \u8BA2\u9605\u72B6\u6001\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`);
|
|
14236
|
+
}
|
|
14237
|
+
}
|
|
14238
|
+
parseHost(raw) {
|
|
14239
|
+
try {
|
|
14240
|
+
const url = new URL(raw.includes("://") ? raw : `http://${raw}`);
|
|
14241
|
+
return {
|
|
14242
|
+
scheme: url.protocol.replace(":", "") || "http",
|
|
14243
|
+
host: url.hostname,
|
|
14244
|
+
port: url.port || (url.protocol === "https:" ? "443" : "8848")
|
|
14245
|
+
};
|
|
14246
|
+
} catch {
|
|
14247
|
+
return { scheme: "http", host: raw.replace(/^https?:\/\//, ""), port: "8848" };
|
|
14248
|
+
}
|
|
14249
|
+
}
|
|
14250
|
+
};
|
|
14251
|
+
|
|
13977
14252
|
// src/hook/worker/worker-command.ts
|
|
13978
14253
|
var HookWorkerCommand = class {
|
|
13979
14254
|
logger;
|
|
@@ -13982,11 +14257,21 @@ var HookWorkerCommand = class {
|
|
|
13982
14257
|
localBrowserWs = null;
|
|
13983
14258
|
reminderService = null;
|
|
13984
14259
|
ownerNotifyService = null;
|
|
14260
|
+
nacosSyncCoordinator = null;
|
|
13985
14261
|
heartbeatTimer = null;
|
|
13986
14262
|
stateManager = null;
|
|
14263
|
+
stopped = false;
|
|
14264
|
+
stoppedPromise;
|
|
14265
|
+
resolveStopped = () => void 0;
|
|
13987
14266
|
constructor(logger3, options = {}) {
|
|
13988
14267
|
this.logger = logger3;
|
|
13989
14268
|
this.options = options;
|
|
14269
|
+
this.stoppedPromise = new Promise((resolve3) => {
|
|
14270
|
+
this.resolveStopped = resolve3;
|
|
14271
|
+
});
|
|
14272
|
+
}
|
|
14273
|
+
waitUntilStopped() {
|
|
14274
|
+
return this.stoppedPromise;
|
|
13990
14275
|
}
|
|
13991
14276
|
async start() {
|
|
13992
14277
|
const existingPid = findRunningAiHookProcess(process10.pid);
|
|
@@ -14009,6 +14294,7 @@ var HookWorkerCommand = class {
|
|
|
14009
14294
|
});
|
|
14010
14295
|
const bindAllowedUserIds = resolveBindAllowedUserIds(config);
|
|
14011
14296
|
const contextConfig = resolveContextConfig(config);
|
|
14297
|
+
const nacosSyncConfig = resolveNacosSkillSyncConfig(config);
|
|
14012
14298
|
const opsUserName = resolveOpsUserName();
|
|
14013
14299
|
const larkClient = new lark3.Client({
|
|
14014
14300
|
appId: feishuConfig.appId,
|
|
@@ -14074,13 +14360,20 @@ var HookWorkerCommand = class {
|
|
|
14074
14360
|
config: this.options.runnerConfig || {}
|
|
14075
14361
|
});
|
|
14076
14362
|
this.logger.info(`\u5F15\u64CE\u5DF2\u521B\u5EFA: engine=${engine}, \u53EF\u7528\u5F15\u64CE=[${registry.list().join(", ")}]`);
|
|
14363
|
+
this.nacosSyncCoordinator = new NacosSubscriptionSyncCoordinator({
|
|
14364
|
+
logger: this.logger,
|
|
14365
|
+
workerId: ownerUserId || `worker-${process10.pid}`,
|
|
14366
|
+
config: nacosSyncConfig
|
|
14367
|
+
});
|
|
14077
14368
|
this.localBrowserWs = new LocalBrowserWsServer({
|
|
14078
14369
|
logger: this.logger,
|
|
14079
14370
|
workerId: ownerUserId || `worker-${process10.pid}`,
|
|
14080
14371
|
workerType: "tooling-cli",
|
|
14081
|
-
larkClient
|
|
14372
|
+
larkClient,
|
|
14373
|
+
getNacosSyncStatus: () => this.nacosSyncCoordinator?.getStatus() ?? null
|
|
14082
14374
|
});
|
|
14083
14375
|
await this.localBrowserWs.start();
|
|
14376
|
+
this.nacosSyncCoordinator.start();
|
|
14084
14377
|
const hostProfileService = new HostProfileService({
|
|
14085
14378
|
logger: this.logger,
|
|
14086
14379
|
ownerUserId,
|
|
@@ -14109,7 +14402,7 @@ var HookWorkerCommand = class {
|
|
|
14109
14402
|
const requesterPersonaService = new RequesterPersonaService({
|
|
14110
14403
|
logger: this.logger,
|
|
14111
14404
|
larkClient,
|
|
14112
|
-
rootDir: process10.env.HOOK_REQUESTER_PERSONA_DIR ||
|
|
14405
|
+
rootDir: process10.env.HOOK_REQUESTER_PERSONA_DIR || path27.join(os17.homedir(), "ops", "ai-hook", "persona")
|
|
14113
14406
|
});
|
|
14114
14407
|
const taskExecutor = new TaskExecutor({
|
|
14115
14408
|
logger: this.logger,
|
|
@@ -14166,17 +14459,19 @@ var HookWorkerCommand = class {
|
|
|
14166
14459
|
await this.relayClient.startAndWait();
|
|
14167
14460
|
await reminderService.start();
|
|
14168
14461
|
await this.ownerNotifyService.notifyOnline();
|
|
14169
|
-
|
|
14170
|
-
|
|
14171
|
-
|
|
14172
|
-
|
|
14173
|
-
|
|
14174
|
-
|
|
14175
|
-
|
|
14176
|
-
|
|
14177
|
-
|
|
14178
|
-
|
|
14179
|
-
|
|
14462
|
+
if (this.options.manageProcessSignals !== false) {
|
|
14463
|
+
const gracefulExit = async (signal) => {
|
|
14464
|
+
this.logger.info(`\u6536\u5230 ${signal}\uFF0C\u6B63\u5728\u505C\u6B62\u4ECE\u8282\u70B9...`);
|
|
14465
|
+
await this.stop(signal);
|
|
14466
|
+
process10.exit(0);
|
|
14467
|
+
};
|
|
14468
|
+
process10.on("SIGINT", () => {
|
|
14469
|
+
void gracefulExit("SIGINT");
|
|
14470
|
+
});
|
|
14471
|
+
process10.on("SIGTERM", () => {
|
|
14472
|
+
void gracefulExit("SIGTERM");
|
|
14473
|
+
});
|
|
14474
|
+
}
|
|
14180
14475
|
this.heartbeatTimer = setInterval(() => {
|
|
14181
14476
|
stateManager.updateHeartbeat();
|
|
14182
14477
|
}, HEARTBEAT_INTERVAL_MS);
|
|
@@ -14186,6 +14481,10 @@ var HookWorkerCommand = class {
|
|
|
14186
14481
|
}
|
|
14187
14482
|
/** 停止从节点 */
|
|
14188
14483
|
async stop(signal) {
|
|
14484
|
+
if (this.stopped) {
|
|
14485
|
+
return;
|
|
14486
|
+
}
|
|
14487
|
+
this.stopped = true;
|
|
14189
14488
|
if (this.heartbeatTimer) {
|
|
14190
14489
|
clearInterval(this.heartbeatTimer);
|
|
14191
14490
|
this.heartbeatTimer = null;
|
|
@@ -14194,6 +14493,10 @@ var HookWorkerCommand = class {
|
|
|
14194
14493
|
this.localBrowserWs.stop();
|
|
14195
14494
|
this.localBrowserWs = null;
|
|
14196
14495
|
}
|
|
14496
|
+
if (this.nacosSyncCoordinator) {
|
|
14497
|
+
await this.nacosSyncCoordinator.stop();
|
|
14498
|
+
this.nacosSyncCoordinator = null;
|
|
14499
|
+
}
|
|
14197
14500
|
if (this.reminderService) {
|
|
14198
14501
|
this.reminderService.stop();
|
|
14199
14502
|
this.reminderService = null;
|
|
@@ -14219,10 +14522,65 @@ var HookWorkerCommand = class {
|
|
|
14219
14522
|
slaveConnectionStatus: "offline"
|
|
14220
14523
|
});
|
|
14221
14524
|
}
|
|
14525
|
+
this.resolveStopped();
|
|
14222
14526
|
}
|
|
14223
14527
|
};
|
|
14224
14528
|
|
|
14225
|
-
// src/commands/hook/
|
|
14529
|
+
// src/commands/hook/worker-options.ts
|
|
14530
|
+
var WORKER_BOOLEAN_OPTIONS = /* @__PURE__ */ new Set([
|
|
14531
|
+
"--verbose"
|
|
14532
|
+
]);
|
|
14533
|
+
var WORKER_VALUE_OPTIONS = /* @__PURE__ */ new Set([
|
|
14534
|
+
"--master-host",
|
|
14535
|
+
"--master-port",
|
|
14536
|
+
"--shared-secret",
|
|
14537
|
+
"--claim-timeout-ms",
|
|
14538
|
+
"--connect-timeout-ms",
|
|
14539
|
+
"--model",
|
|
14540
|
+
"--fallback-model",
|
|
14541
|
+
"--permission-mode",
|
|
14542
|
+
"--max-budget-usd",
|
|
14543
|
+
"--settings",
|
|
14544
|
+
"--mcp-config",
|
|
14545
|
+
"--add-dir",
|
|
14546
|
+
"--system-prompt",
|
|
14547
|
+
"--append-system-prompt",
|
|
14548
|
+
"--agent",
|
|
14549
|
+
"--agents",
|
|
14550
|
+
"--tools",
|
|
14551
|
+
"--allowedTools",
|
|
14552
|
+
"--disallowedTools"
|
|
14553
|
+
]);
|
|
14554
|
+
function resolveWorkerPassthroughArgs(engine, commandName = "worker", rawArgs = process.argv.slice(2)) {
|
|
14555
|
+
const commandIndex = rawArgs.findIndex((item, index) => item === commandName && rawArgs[index - 1] === "hook");
|
|
14556
|
+
if (commandIndex < 0) {
|
|
14557
|
+
return [];
|
|
14558
|
+
}
|
|
14559
|
+
const tail = rawArgs.slice(commandIndex + 1);
|
|
14560
|
+
const args = tail[0] === commandName ? tail.slice(1) : tail;
|
|
14561
|
+
const normalizedEngine = String(engine || "codex").trim();
|
|
14562
|
+
const scanArgs = args[0] === normalizedEngine ? args.slice(1) : args;
|
|
14563
|
+
const passthroughArgs = [];
|
|
14564
|
+
for (let index = 0; index < scanArgs.length; index += 1) {
|
|
14565
|
+
const item = scanArgs[index];
|
|
14566
|
+
if (item === "--") {
|
|
14567
|
+
passthroughArgs.push(...scanArgs.slice(index + 1));
|
|
14568
|
+
break;
|
|
14569
|
+
}
|
|
14570
|
+
const key = item.includes("=") ? item.split("=")[0] : item;
|
|
14571
|
+
if (WORKER_BOOLEAN_OPTIONS.has(key)) {
|
|
14572
|
+
continue;
|
|
14573
|
+
}
|
|
14574
|
+
if (WORKER_VALUE_OPTIONS.has(key)) {
|
|
14575
|
+
if (!item.includes("=")) {
|
|
14576
|
+
index += 1;
|
|
14577
|
+
}
|
|
14578
|
+
continue;
|
|
14579
|
+
}
|
|
14580
|
+
passthroughArgs.push(item);
|
|
14581
|
+
}
|
|
14582
|
+
return passthroughArgs;
|
|
14583
|
+
}
|
|
14226
14584
|
function normalizeClaudeArgs(options) {
|
|
14227
14585
|
const args = [];
|
|
14228
14586
|
const pushPair = (flag, value) => {
|
|
@@ -14254,6 +14612,8 @@ function normalizeClaudeArgs(options) {
|
|
|
14254
14612
|
});
|
|
14255
14613
|
return args;
|
|
14256
14614
|
}
|
|
14615
|
+
|
|
14616
|
+
// src/commands/hook/hook-worker.ts
|
|
14257
14617
|
async function hookWorkerAction(engine, options) {
|
|
14258
14618
|
const logger3 = createLogger("worker", options.verbose === true);
|
|
14259
14619
|
const normalizedEngine = (engine || "codex").toLowerCase();
|
|
@@ -14263,10 +14623,12 @@ async function hookWorkerAction(engine, options) {
|
|
|
14263
14623
|
masterPort: parsePositiveInt(options.masterPort, 0) || void 0,
|
|
14264
14624
|
sharedSecret: options.sharedSecret,
|
|
14265
14625
|
connectTimeoutMs: parsePositiveInt(options.connectTimeoutMs, 0) || void 0,
|
|
14266
|
-
runnerConfig: normalizedEngine === "claude" ? { claudeArgs: normalizeClaudeArgs(options) } : {}
|
|
14626
|
+
runnerConfig: normalizedEngine === "claude" ? { claudeArgs: normalizeClaudeArgs(options) } : {},
|
|
14627
|
+
manageProcessSignals: true
|
|
14267
14628
|
});
|
|
14268
14629
|
try {
|
|
14269
14630
|
await command.start();
|
|
14631
|
+
await command.waitUntilStopped();
|
|
14270
14632
|
} catch (error) {
|
|
14271
14633
|
const msg = error instanceof Error ? error.message : String(error);
|
|
14272
14634
|
logger3.error(`\u4ECE\u8282\u70B9\u542F\u52A8\u5931\u8D25: ${msg}`);
|
|
@@ -14274,23 +14636,98 @@ async function hookWorkerAction(engine, options) {
|
|
|
14274
14636
|
}
|
|
14275
14637
|
}
|
|
14276
14638
|
|
|
14639
|
+
// src/commands/hook/hook-local.ts
|
|
14640
|
+
function resolveLocalWorkerMasterHost(masterHost) {
|
|
14641
|
+
const host = String(masterHost || "").trim();
|
|
14642
|
+
if (host === "0.0.0.0" || host === "::" || host === "[::]") {
|
|
14643
|
+
return "127.0.0.1";
|
|
14644
|
+
}
|
|
14645
|
+
return host;
|
|
14646
|
+
}
|
|
14647
|
+
function resolveLocalWorkerOverrides(runtime) {
|
|
14648
|
+
return {
|
|
14649
|
+
masterHost: resolveLocalWorkerMasterHost(runtime.masterHost),
|
|
14650
|
+
masterPort: runtime.masterPort,
|
|
14651
|
+
sharedSecret: runtime.sharedSecret
|
|
14652
|
+
};
|
|
14653
|
+
}
|
|
14654
|
+
async function hookLocalAction(engine, options) {
|
|
14655
|
+
const localLogger = createLogger("local", options.verbose === true);
|
|
14656
|
+
const masterLogger = createLogger("master");
|
|
14657
|
+
const workerLogger = createLogger("worker", options.verbose === true);
|
|
14658
|
+
const normalizedEngine = (engine || "codex").toLowerCase();
|
|
14659
|
+
const master = new HookMasterCommand({
|
|
14660
|
+
logger: masterLogger,
|
|
14661
|
+
masterHost: options.masterHost,
|
|
14662
|
+
masterPort: parsePositiveInt(options.masterPort, 0) || void 0,
|
|
14663
|
+
sharedSecret: options.sharedSecret,
|
|
14664
|
+
claimTimeoutMs: parsePositiveInt(options.claimTimeoutMs, 0) || void 0,
|
|
14665
|
+
manageProcessSignals: false
|
|
14666
|
+
});
|
|
14667
|
+
let worker = null;
|
|
14668
|
+
let stopping = false;
|
|
14669
|
+
const stopAll = async (signal) => {
|
|
14670
|
+
if (stopping) {
|
|
14671
|
+
return;
|
|
14672
|
+
}
|
|
14673
|
+
stopping = true;
|
|
14674
|
+
localLogger.info(`\u6536\u5230 ${signal}\uFF0C\u6B63\u5728\u505C\u6B62\u672C\u673A\u4E00\u4F53\u8282\u70B9...`);
|
|
14675
|
+
if (worker) {
|
|
14676
|
+
await worker.stop(signal);
|
|
14677
|
+
worker = null;
|
|
14678
|
+
}
|
|
14679
|
+
await master.stop(signal);
|
|
14680
|
+
};
|
|
14681
|
+
process.on("SIGINT", async () => {
|
|
14682
|
+
await stopAll("SIGINT");
|
|
14683
|
+
process.exit(0);
|
|
14684
|
+
});
|
|
14685
|
+
process.on("SIGTERM", async () => {
|
|
14686
|
+
await stopAll("SIGTERM");
|
|
14687
|
+
process.exit(0);
|
|
14688
|
+
});
|
|
14689
|
+
try {
|
|
14690
|
+
const runtime = await master.start();
|
|
14691
|
+
const workerOverrides = resolveLocalWorkerOverrides(runtime);
|
|
14692
|
+
worker = new HookWorkerCommand(workerLogger, {
|
|
14693
|
+
engine: normalizedEngine,
|
|
14694
|
+
masterHost: workerOverrides.masterHost,
|
|
14695
|
+
masterPort: workerOverrides.masterPort,
|
|
14696
|
+
sharedSecret: workerOverrides.sharedSecret,
|
|
14697
|
+
connectTimeoutMs: parsePositiveInt(options.connectTimeoutMs, 0) || void 0,
|
|
14698
|
+
runnerConfig: normalizedEngine === "claude" ? { claudeArgs: normalizeClaudeArgs(options) } : {},
|
|
14699
|
+
manageProcessSignals: false
|
|
14700
|
+
});
|
|
14701
|
+
await worker.start();
|
|
14702
|
+
localLogger.info(
|
|
14703
|
+
`\u672C\u673A\u4E00\u4F53\u8282\u70B9\u542F\u52A8\u5B8C\u6210 | engine=${normalizedEngine} | master=${workerOverrides.masterHost}:${workerOverrides.masterPort}`
|
|
14704
|
+
);
|
|
14705
|
+
await worker.waitUntilStopped();
|
|
14706
|
+
} catch (error) {
|
|
14707
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
14708
|
+
localLogger.error(`\u672C\u673A\u4E00\u4F53\u8282\u70B9\u542F\u52A8\u5931\u8D25: ${msg}`);
|
|
14709
|
+
await stopAll("startup_error");
|
|
14710
|
+
process.exit(1);
|
|
14711
|
+
}
|
|
14712
|
+
}
|
|
14713
|
+
|
|
14277
14714
|
// src/hook/init/hook-init-command.ts
|
|
14278
|
-
import
|
|
14279
|
-
import
|
|
14280
|
-
import
|
|
14715
|
+
import fs29 from "fs";
|
|
14716
|
+
import os18 from "os";
|
|
14717
|
+
import path28 from "path";
|
|
14281
14718
|
import process11 from "process";
|
|
14282
14719
|
import { createInterface as createInterface3 } from "readline/promises";
|
|
14283
14720
|
import chalk9 from "chalk";
|
|
14284
14721
|
|
|
14285
14722
|
// src/hook/init/legacy-ai-hook-migrator.ts
|
|
14286
|
-
import
|
|
14723
|
+
import fs28 from "fs";
|
|
14287
14724
|
function loadLegacyMigrationResult(logger3) {
|
|
14288
14725
|
const sourcePath = LEGACY_STATE_PATH;
|
|
14289
|
-
if (!
|
|
14726
|
+
if (!fs28.existsSync(sourcePath)) {
|
|
14290
14727
|
return { state: null, summary: null };
|
|
14291
14728
|
}
|
|
14292
14729
|
try {
|
|
14293
|
-
const parsed = parseJsonWithLineComments(
|
|
14730
|
+
const parsed = parseJsonWithLineComments(fs28.readFileSync(sourcePath, "utf-8"), sourcePath);
|
|
14294
14731
|
if (!parsed || typeof parsed !== "object") {
|
|
14295
14732
|
return { state: null, summary: null };
|
|
14296
14733
|
}
|
|
@@ -14318,6 +14755,7 @@ function countObjectKeys(value) {
|
|
|
14318
14755
|
|
|
14319
14756
|
// src/hook/init/hook-init-normalizer.ts
|
|
14320
14757
|
var DEFAULT_MASTER_HOST_ENV = "NIKOU_HOOK_MASTER_HOST";
|
|
14758
|
+
var LOCAL_MASTER_HOST = "127.0.0.1";
|
|
14321
14759
|
function resolveHookSection2(config) {
|
|
14322
14760
|
return config.hook ?? config.ai_hook ?? config.aiHook ?? {};
|
|
14323
14761
|
}
|
|
@@ -14377,6 +14815,15 @@ function resolveContextConfigFromHook(hook2) {
|
|
|
14377
14815
|
function resolveDefaultMasterHost(env = process.env) {
|
|
14378
14816
|
return String(env[DEFAULT_MASTER_HOST_ENV] || "").trim();
|
|
14379
14817
|
}
|
|
14818
|
+
function resolveHookInitDeploymentDefaults(config, env = process.env) {
|
|
14819
|
+
const configuredHost = resolveConfiguredMasterHost(config);
|
|
14820
|
+
const envHost = resolveDefaultMasterHost(env);
|
|
14821
|
+
const masterHost = configuredHost || envHost || LOCAL_MASTER_HOST;
|
|
14822
|
+
return {
|
|
14823
|
+
deploymentMode: isLocalHost(masterHost) ? "local" : "slave",
|
|
14824
|
+
masterHost
|
|
14825
|
+
};
|
|
14826
|
+
}
|
|
14380
14827
|
function normalizeHookInitConfig(config, defaults = {}) {
|
|
14381
14828
|
const hook2 = resolveHookSection2(config);
|
|
14382
14829
|
const appId = String(config.feishu?.app_id || config.feishu?.appId || config.feishu?.appid || "").trim();
|
|
@@ -14418,7 +14865,8 @@ function normalizeHookInitConfig(config, defaults = {}) {
|
|
|
14418
14865
|
// src/hook/init/hook-init-command.ts
|
|
14419
14866
|
var BOT_OPTIONS = [{ label: "\u59AE\u853B", value: "\u59AE\u853B" }];
|
|
14420
14867
|
var DEPLOYMENT_OPTIONS = [
|
|
14421
|
-
{ label: "\
|
|
14868
|
+
{ label: "\u672C\u673A\u4E00\u4F53", value: "local", description: "\u540C\u4E00\u53F0\u673A\u5668\u542F\u52A8\u4E3B\u8282\u70B9\u548C\u672C\u5730\u4ECE\u8282\u70B9" },
|
|
14869
|
+
{ label: "\u4ECE\u8282\u70B9", value: "slave", description: "\u8FDE\u63A5\u5DF2\u6709\u8FDC\u7AEF\u4E3B\u8282\u70B9" }
|
|
14422
14870
|
];
|
|
14423
14871
|
var HookInitCommand = class {
|
|
14424
14872
|
constructor(logger3) {
|
|
@@ -14432,14 +14880,22 @@ var HookInitCommand = class {
|
|
|
14432
14880
|
const existingAggregateConfig = this.readJson(DEFAULT_CONFIG_PATH);
|
|
14433
14881
|
const existingMasterConfig = this.readJson(MASTER_CONFIG_PATH);
|
|
14434
14882
|
const existingWorkerConfig = this.readJson(WORKER_CONFIG_PATH);
|
|
14435
|
-
const existingWorkerStatePath =
|
|
14883
|
+
const existingWorkerStatePath = path28.join(STATE_DIR, "worker.json");
|
|
14436
14884
|
const existingWorkerState = this.readJson(existingWorkerStatePath);
|
|
14437
14885
|
const rl = createInterface3({ input: process11.stdin, output: process11.stdout });
|
|
14438
14886
|
try {
|
|
14439
14887
|
this.printEnvironmentSummary(source.path, { existingAggregateConfig, existingMasterConfig, existingWorkerConfig }, migration.summary);
|
|
14440
14888
|
const botName = await this.askChoice(rl, "\u7B2C\u4E00\u6B65\uFF1A\u9009\u62E9\u98DE\u4E66\u673A\u5668\u4EBA", BOT_OPTIONS, 0);
|
|
14441
|
-
|
|
14442
|
-
const
|
|
14889
|
+
const deploymentDefaults = resolveHookInitDeploymentDefaults(source.config);
|
|
14890
|
+
const deploymentDefaultIndex = DEPLOYMENT_OPTIONS.findIndex((item) => item.value === deploymentDefaults.deploymentMode);
|
|
14891
|
+
const deploymentMode = await this.askChoice(
|
|
14892
|
+
rl,
|
|
14893
|
+
"\u7B2C\u4E8C\u6B65\uFF1A\u9009\u62E9\u90E8\u7F72\u65B9\u5F0F",
|
|
14894
|
+
DEPLOYMENT_OPTIONS,
|
|
14895
|
+
deploymentDefaultIndex >= 0 ? deploymentDefaultIndex : 0
|
|
14896
|
+
);
|
|
14897
|
+
const defaultMasterHost = deploymentMode === "local" ? LOCAL_MASTER_HOST : deploymentDefaults.masterHost;
|
|
14898
|
+
const masterHost = await this.askMasterHost(rl, source.config, defaultMasterHost);
|
|
14443
14899
|
const normalized = this.normalizeSourceConfig(
|
|
14444
14900
|
mergeHookInitMasterHost(source.config, masterHost)
|
|
14445
14901
|
);
|
|
@@ -14448,6 +14904,7 @@ var HookInitCommand = class {
|
|
|
14448
14904
|
const nextWorkerState = this.buildSeedWorkerState({
|
|
14449
14905
|
botName,
|
|
14450
14906
|
configPath: WORKER_CONFIG_PATH,
|
|
14907
|
+
deploymentMode,
|
|
14451
14908
|
normalized,
|
|
14452
14909
|
existingWorkerState,
|
|
14453
14910
|
legacyState: migration.state
|
|
@@ -14456,6 +14913,7 @@ var HookInitCommand = class {
|
|
|
14456
14913
|
nextMasterConfig,
|
|
14457
14914
|
nextWorkerConfig,
|
|
14458
14915
|
nextWorkerState,
|
|
14916
|
+
deploymentMode,
|
|
14459
14917
|
sourcePath: source.path,
|
|
14460
14918
|
migrationSummary: migration.summary,
|
|
14461
14919
|
existingAggregateConfig,
|
|
@@ -14480,7 +14938,10 @@ var HookInitCommand = class {
|
|
|
14480
14938
|
console.log(chalk9.dim(`\u4E3B\u8282\u70B9\u914D\u7F6E: ${MASTER_CONFIG_PATH}`));
|
|
14481
14939
|
console.log(chalk9.dim(`\u4ECE\u8282\u70B9\u914D\u7F6E: ${WORKER_CONFIG_PATH}`));
|
|
14482
14940
|
console.log(chalk9.dim(`\u72B6\u6001\u6587\u4EF6: ${existingWorkerStatePath}`));
|
|
14483
|
-
|
|
14941
|
+
const nextCommand = deploymentMode === "local" ? "ai-hook local" : "nikou-cli hook worker codex";
|
|
14942
|
+
console.log(chalk9.dim(`
|
|
14943
|
+
\u4E0B\u4E00\u6B65: ${nextCommand}
|
|
14944
|
+
`));
|
|
14484
14945
|
} finally {
|
|
14485
14946
|
rl.close();
|
|
14486
14947
|
}
|
|
@@ -14493,11 +14954,11 @@ var HookInitCommand = class {
|
|
|
14493
14954
|
resolveSourceConfig() {
|
|
14494
14955
|
const candidates = [LEGACY_CONFIG_PATH, DEFAULT_CONFIG_PATH, MASTER_CONFIG_PATH, WORKER_CONFIG_PATH];
|
|
14495
14956
|
for (const candidate of candidates) {
|
|
14496
|
-
if (!
|
|
14957
|
+
if (!fs29.existsSync(candidate)) {
|
|
14497
14958
|
continue;
|
|
14498
14959
|
}
|
|
14499
14960
|
try {
|
|
14500
|
-
const parsed = parseJsonWithLineComments(
|
|
14961
|
+
const parsed = parseJsonWithLineComments(fs29.readFileSync(candidate, "utf-8"), candidate);
|
|
14501
14962
|
if (parsed && typeof parsed === "object") {
|
|
14502
14963
|
return { config: parsed, path: candidate };
|
|
14503
14964
|
}
|
|
@@ -14559,8 +15020,8 @@ var HookInitCommand = class {
|
|
|
14559
15020
|
console.log(chalk9.yellow("\u8BF7\u8F93\u5165 y \u6216 n\u3002\n"));
|
|
14560
15021
|
}
|
|
14561
15022
|
}
|
|
14562
|
-
async askMasterHost(rl, config) {
|
|
14563
|
-
const defaultHost = resolveConfiguredMasterHost(config) || resolveDefaultMasterHost();
|
|
15023
|
+
async askMasterHost(rl, config, fallbackHost) {
|
|
15024
|
+
const defaultHost = fallbackHost || resolveConfiguredMasterHost(config) || resolveDefaultMasterHost();
|
|
14564
15025
|
while (true) {
|
|
14565
15026
|
const label = defaultHost ? `\u7B2C\u4E09\u6B65\uFF1A\u4E3B\u8282\u70B9\u5730\u5740 [\u9ED8\u8BA4 ${defaultHost}]: ` : "\u7B2C\u4E09\u6B65\uFF1A\u4E3B\u8282\u70B9\u5730\u5740: ";
|
|
14566
15027
|
const answer = (await rl.question(chalk9.dim(label))).trim();
|
|
@@ -14650,7 +15111,7 @@ var HookInitCommand = class {
|
|
|
14650
15111
|
contextConfig: params.normalized.contextConfig,
|
|
14651
15112
|
slaveConnectionStatus: "offline",
|
|
14652
15113
|
status: "stopped",
|
|
14653
|
-
lastCommand: "nikou-cli hook worker codex"
|
|
15114
|
+
lastCommand: params.deploymentMode === "local" ? "ai-hook local" : "nikou-cli hook worker codex"
|
|
14654
15115
|
});
|
|
14655
15116
|
const mergedState = mergeWorkerState(
|
|
14656
15117
|
initialState,
|
|
@@ -14661,7 +15122,7 @@ var HookInitCommand = class {
|
|
|
14661
15122
|
mergedState.initializedAt = now;
|
|
14662
15123
|
mergedState.initMode = "interactive";
|
|
14663
15124
|
mergedState.migration = params.legacyState ? {
|
|
14664
|
-
source:
|
|
15125
|
+
source: path28.join(os18.homedir(), "ops", "ai-hook.json"),
|
|
14665
15126
|
migratedAt: now,
|
|
14666
15127
|
legacyBindingsCount: countObjectKeys2(params.legacyState.bindings),
|
|
14667
15128
|
legacyChatIndexCount: countObjectKeys2(params.legacyState.chatIndex),
|
|
@@ -14682,10 +15143,10 @@ var HookInitCommand = class {
|
|
|
14682
15143
|
console.log(chalk9.dim(`- \u4ECE\u8282\u70B9\u914D\u7F6E: ${WORKER_CONFIG_PATH}`));
|
|
14683
15144
|
console.log(chalk9.dim(`- \u98DE\u4E66 AppId: ${String(params.nextMasterConfig.feishu?.app_id || "")}`));
|
|
14684
15145
|
console.log(chalk9.dim(`- \u673A\u5668\u4EBA: ${String(masterHook.bot_name || workerHook.bot_name || "")}`));
|
|
14685
|
-
console.log(chalk9.dim(`- \u90E8\u7F72\u65B9\u5F0F: \u4ECE\u8282\u70B9`));
|
|
15146
|
+
console.log(chalk9.dim(`- \u90E8\u7F72\u65B9\u5F0F: ${params.deploymentMode === "local" ? "\u672C\u673A\u4E00\u4F53" : "\u4ECE\u8282\u70B9"}`));
|
|
14686
15147
|
console.log(chalk9.dim(`- \u4E3B\u8282\u70B9: ${String(masterHook.master_host || "")}:${String(masterHook.master_port || "")}`));
|
|
14687
15148
|
console.log(chalk9.dim(`- \u4E3B\u8282\u70B9\u767D\u540D\u5355\u6570\u91CF: ${Array.isArray(masterHook.bind_allowed_user_ids) ? masterHook.bind_allowed_user_ids.length : 0}`));
|
|
14688
|
-
console.log(chalk9.dim(`- \u79CD\u5B50\u72B6\u6001: ${
|
|
15149
|
+
console.log(chalk9.dim(`- \u79CD\u5B50\u72B6\u6001: ${path28.join(STATE_DIR, "worker.json")}`));
|
|
14689
15150
|
console.log(chalk9.dim(`- \u8FC1\u79FB\u540E\u7FA4\u7ED1\u5B9A\u6570: ${Object.keys(params.nextWorkerState.bindings || {}).length}`));
|
|
14690
15151
|
console.log(chalk9.dim(`- \u8FC1\u79FB\u540E chatIndex \u6570: ${Object.keys(params.nextWorkerState.chatIndex || {}).length}`));
|
|
14691
15152
|
console.log(chalk9.dim(`- \u8FC1\u79FB\u540E P2P \u4F1A\u8BDD\u6570: ${countObjectKeys2(params.nextWorkerState.p2pSessions)}`));
|
|
@@ -14711,28 +15172,28 @@ var HookInitCommand = class {
|
|
|
14711
15172
|
});
|
|
14712
15173
|
}
|
|
14713
15174
|
backupIfNeeded(targetPath, prefix) {
|
|
14714
|
-
if (!
|
|
15175
|
+
if (!fs29.existsSync(targetPath)) {
|
|
14715
15176
|
return;
|
|
14716
15177
|
}
|
|
14717
|
-
const backupDir =
|
|
15178
|
+
const backupDir = path28.join(STATE_DIR, "backups");
|
|
14718
15179
|
ensureDirExists(backupDir);
|
|
14719
15180
|
const fileName = `${prefix}.${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.json`;
|
|
14720
|
-
|
|
15181
|
+
fs29.copyFileSync(targetPath, path28.join(backupDir, fileName));
|
|
14721
15182
|
}
|
|
14722
15183
|
readJson(filePath) {
|
|
14723
|
-
if (!
|
|
15184
|
+
if (!fs29.existsSync(filePath)) {
|
|
14724
15185
|
return null;
|
|
14725
15186
|
}
|
|
14726
15187
|
try {
|
|
14727
|
-
const parsed = parseJsonWithLineComments(
|
|
15188
|
+
const parsed = parseJsonWithLineComments(fs29.readFileSync(filePath, "utf-8"), filePath);
|
|
14728
15189
|
return parsed && typeof parsed === "object" ? parsed : null;
|
|
14729
15190
|
} catch {
|
|
14730
15191
|
return null;
|
|
14731
15192
|
}
|
|
14732
15193
|
}
|
|
14733
15194
|
writeJson(filePath, value) {
|
|
14734
|
-
ensureDirExists(
|
|
14735
|
-
|
|
15195
|
+
ensureDirExists(path28.dirname(filePath));
|
|
15196
|
+
fs29.writeFileSync(filePath, JSON.stringify(value, null, 2));
|
|
14736
15197
|
}
|
|
14737
15198
|
};
|
|
14738
15199
|
function countObjectKeys2(value) {
|
|
@@ -14756,12 +15217,12 @@ async function hookInitAction() {
|
|
|
14756
15217
|
}
|
|
14757
15218
|
|
|
14758
15219
|
// src/commands/hook/hook-log.ts
|
|
14759
|
-
import
|
|
15220
|
+
import fs31 from "fs";
|
|
14760
15221
|
import chalk10 from "chalk";
|
|
14761
15222
|
|
|
14762
15223
|
// src/hook/log-searcher.ts
|
|
14763
|
-
import
|
|
14764
|
-
import
|
|
15224
|
+
import fs30 from "fs";
|
|
15225
|
+
import path29 from "path";
|
|
14765
15226
|
function normalizeString(value) {
|
|
14766
15227
|
if (value === null || value === void 0) {
|
|
14767
15228
|
return "";
|
|
@@ -14799,8 +15260,8 @@ var HookLogSearcher = class {
|
|
|
14799
15260
|
logPaths;
|
|
14800
15261
|
constructor(options = {}) {
|
|
14801
15262
|
this.logPaths = {
|
|
14802
|
-
master: options.masterPath ||
|
|
14803
|
-
worker: options.workerPath ||
|
|
15263
|
+
master: options.masterPath || path29.join(LOGS_DIR, "master", "ai-hook-master.service.log"),
|
|
15264
|
+
worker: options.workerPath || path29.join(LOGS_DIR, "worker", "ai-hook-worker.service.log")
|
|
14804
15265
|
};
|
|
14805
15266
|
}
|
|
14806
15267
|
resolveScope(scope) {
|
|
@@ -14863,7 +15324,7 @@ var HookLogSearcher = class {
|
|
|
14863
15324
|
}
|
|
14864
15325
|
searchSingleFile(role, query = {}, options = {}) {
|
|
14865
15326
|
const filePath = this.logPaths[role];
|
|
14866
|
-
if (!filePath || !
|
|
15327
|
+
if (!filePath || !fs30.existsSync(filePath)) {
|
|
14867
15328
|
return {
|
|
14868
15329
|
role,
|
|
14869
15330
|
path: filePath,
|
|
@@ -14874,7 +15335,7 @@ var HookLogSearcher = class {
|
|
|
14874
15335
|
lines: []
|
|
14875
15336
|
};
|
|
14876
15337
|
}
|
|
14877
|
-
const raw =
|
|
15338
|
+
const raw = fs30.readFileSync(filePath, "utf8");
|
|
14878
15339
|
const lines = raw.split(/\r?\n/);
|
|
14879
15340
|
if (lines.length > 0 && lines[lines.length - 1] === "") {
|
|
14880
15341
|
lines.pop();
|
|
@@ -14992,7 +15453,7 @@ function buildFollowState(file) {
|
|
|
14992
15453
|
return {
|
|
14993
15454
|
role: file.role,
|
|
14994
15455
|
path: file.path,
|
|
14995
|
-
offset:
|
|
15456
|
+
offset: fs31.existsSync(file.path) ? fs31.statSync(file.path).size : 0,
|
|
14996
15457
|
remainder: ""
|
|
14997
15458
|
};
|
|
14998
15459
|
}
|
|
@@ -15019,10 +15480,10 @@ function flushChunk(state, chunk, queryText) {
|
|
|
15019
15480
|
output.forEach((line) => console.log(line));
|
|
15020
15481
|
}
|
|
15021
15482
|
function readAppendedChunk(state, queryText) {
|
|
15022
|
-
if (!
|
|
15483
|
+
if (!fs31.existsSync(state.path)) {
|
|
15023
15484
|
return;
|
|
15024
15485
|
}
|
|
15025
|
-
const stat =
|
|
15486
|
+
const stat = fs31.statSync(state.path);
|
|
15026
15487
|
if (stat.size < state.offset) {
|
|
15027
15488
|
state.offset = 0;
|
|
15028
15489
|
state.remainder = "";
|
|
@@ -15030,15 +15491,15 @@ function readAppendedChunk(state, queryText) {
|
|
|
15030
15491
|
if (stat.size === state.offset) {
|
|
15031
15492
|
return;
|
|
15032
15493
|
}
|
|
15033
|
-
const fd =
|
|
15494
|
+
const fd = fs31.openSync(state.path, "r");
|
|
15034
15495
|
try {
|
|
15035
15496
|
const length = stat.size - state.offset;
|
|
15036
15497
|
const buffer = Buffer.alloc(length);
|
|
15037
|
-
|
|
15498
|
+
fs31.readSync(fd, buffer, 0, length, state.offset);
|
|
15038
15499
|
state.offset = stat.size;
|
|
15039
15500
|
flushChunk(state, buffer.toString("utf8"), queryText);
|
|
15040
15501
|
} finally {
|
|
15041
|
-
|
|
15502
|
+
fs31.closeSync(fd);
|
|
15042
15503
|
}
|
|
15043
15504
|
}
|
|
15044
15505
|
async function followLogs(queryText, options = {}) {
|
|
@@ -15079,60 +15540,6 @@ async function hookLogAction(query = "", options = {}) {
|
|
|
15079
15540
|
|
|
15080
15541
|
// src/index.ts
|
|
15081
15542
|
var DEFAULT_DEST = ".agents/skills";
|
|
15082
|
-
var WORKER_BOOLEAN_OPTIONS = /* @__PURE__ */ new Set([
|
|
15083
|
-
"--verbose"
|
|
15084
|
-
]);
|
|
15085
|
-
var WORKER_VALUE_OPTIONS = /* @__PURE__ */ new Set([
|
|
15086
|
-
"--master-host",
|
|
15087
|
-
"--master-port",
|
|
15088
|
-
"--shared-secret",
|
|
15089
|
-
"--connect-timeout-ms",
|
|
15090
|
-
"--model",
|
|
15091
|
-
"--fallback-model",
|
|
15092
|
-
"--permission-mode",
|
|
15093
|
-
"--max-budget-usd",
|
|
15094
|
-
"--settings",
|
|
15095
|
-
"--mcp-config",
|
|
15096
|
-
"--add-dir",
|
|
15097
|
-
"--system-prompt",
|
|
15098
|
-
"--append-system-prompt",
|
|
15099
|
-
"--agent",
|
|
15100
|
-
"--agents",
|
|
15101
|
-
"--tools",
|
|
15102
|
-
"--allowedTools",
|
|
15103
|
-
"--disallowedTools"
|
|
15104
|
-
]);
|
|
15105
|
-
function resolveWorkerPassthroughArgs(engine) {
|
|
15106
|
-
const rawArgs = process.argv.slice(2);
|
|
15107
|
-
const workerIndex = rawArgs.findIndex((item, index) => item === "worker" && rawArgs[index - 1] === "hook");
|
|
15108
|
-
if (workerIndex < 0) {
|
|
15109
|
-
return [];
|
|
15110
|
-
}
|
|
15111
|
-
const tail = rawArgs.slice(workerIndex + 1);
|
|
15112
|
-
const args = tail[0] === "worker" ? tail.slice(1) : tail;
|
|
15113
|
-
const normalizedEngine = String(engine || "codex").trim();
|
|
15114
|
-
const scanArgs = args[0] === normalizedEngine ? args.slice(1) : args;
|
|
15115
|
-
const passthroughArgs = [];
|
|
15116
|
-
for (let index = 0; index < scanArgs.length; index += 1) {
|
|
15117
|
-
const item = scanArgs[index];
|
|
15118
|
-
if (item === "--") {
|
|
15119
|
-
passthroughArgs.push(...scanArgs.slice(index + 1));
|
|
15120
|
-
break;
|
|
15121
|
-
}
|
|
15122
|
-
const key = item.includes("=") ? item.split("=")[0] : item;
|
|
15123
|
-
if (WORKER_BOOLEAN_OPTIONS.has(key)) {
|
|
15124
|
-
continue;
|
|
15125
|
-
}
|
|
15126
|
-
if (WORKER_VALUE_OPTIONS.has(key)) {
|
|
15127
|
-
if (!item.includes("=")) {
|
|
15128
|
-
index += 1;
|
|
15129
|
-
}
|
|
15130
|
-
continue;
|
|
15131
|
-
}
|
|
15132
|
-
passthroughArgs.push(item);
|
|
15133
|
-
}
|
|
15134
|
-
return passthroughArgs;
|
|
15135
|
-
}
|
|
15136
15543
|
var program = new Command();
|
|
15137
15544
|
program.name("nikou-cli").description("CLI to install and manage Agent Skills from GitHub repos").version("0.1.0");
|
|
15138
15545
|
program.command("add").argument("<source>", 'GitHub repo in "owner/repo" format (e.g., vercel-labs/agent-skills)').description("Install skill(s) from a GitHub repository").option("-p, --path <path>", "Specific subfolder path in the repo").option("-d, --dest <dir>", "Destination directory", DEFAULT_DEST).option("-b, --branch <branch>", "Git branch", "main").option("-f, --force", "Overwrite existing skills", false).action(async (source, options) => {
|
|
@@ -15161,16 +15568,23 @@ mcp.command("search").argument("<keyword>", "Search keyword").description("Searc
|
|
|
15161
15568
|
await mcpSearchCommand(keyword, options);
|
|
15162
15569
|
});
|
|
15163
15570
|
var hook = program.command("hook").description("\u4E3B\u4ECE\u8282\u70B9\u4EFB\u52A1\u5206\u53D1\u4E0E\u6267\u884C\uFF08\u98DE\u4E66\u96C6\u6210\uFF09");
|
|
15571
|
+
function addWorkerRuntimeOptions(command) {
|
|
15572
|
+
return command.allowUnknownOption(true).allowExcessArguments(true).option("--verbose", "\u5F00\u542F\u8C03\u8BD5\u65E5\u5FD7", false).option("--connect-timeout-ms <ms>", "\u4ECE\u8282\u70B9\u8FDE\u63A5\u4E3B\u8282\u70B9\u8D85\u65F6\u6BEB\u79D2\u6570").option("--model <model>", "Claude \u6A21\u578B").option("--fallback-model <model>", "Claude fallback \u6A21\u578B").option("--permission-mode <mode>", "Claude \u6743\u9650\u6A21\u5F0F").option("--max-budget-usd <usd>", "Claude \u6700\u5927\u9884\u7B97").option("--settings <path>", "Claude settings \u6587\u4EF6").option("--mcp-config <path>", "Claude MCP \u914D\u7F6E").option("--add-dir <path>", "Claude \u989D\u5916\u53EF\u8BBF\u95EE\u76EE\u5F55").option("--system-prompt <prompt>", "Claude system prompt").option("--append-system-prompt <prompt>", "Claude \u8FFD\u52A0 system prompt").option("--agent <agent>", "Claude agent").option("--agents <agents>", "Claude agents").option("--tools <tools>", "Claude tools").option("--allowedTools <tools>", "Claude allowedTools").option("--disallowedTools <tools>", "Claude disallowedTools");
|
|
15573
|
+
}
|
|
15164
15574
|
hook.command("master").description("\u542F\u52A8\u4E3B\u8282\u70B9\uFF1A\u63A5\u6536\u98DE\u4E66\u6D88\u606F\u5E76\u5206\u53D1\u4EFB\u52A1\u7ED9\u4ECE\u8282\u70B9").option("--master-host <host>", "\u4E3B\u8282\u70B9\u76D1\u542C\u5730\u5740").option("--master-port <port>", "\u4E3B\u8282\u70B9\u7AEF\u53E3\uFF08\u9ED8\u8BA4 19732\uFF09").option("--shared-secret <secret>", "\u4E3B\u4ECE\u901A\u4FE1\u9274\u6743\u5BC6\u94A5").option("--claim-timeout-ms <ms>", "\u4EFB\u52A1\u8BA4\u9886\u8D85\u65F6\u6BEB\u79D2\u6570").action(async (options) => {
|
|
15165
15575
|
await hookMasterAction(options);
|
|
15166
15576
|
});
|
|
15167
15577
|
hook.command("init").description("\u4EA4\u4E92\u5F0F\u521D\u59CB\u5316 Hook \u4ECE\u8282\u70B9\u914D\u7F6E\u4E0E\u5386\u53F2\u72B6\u6001\u8FC1\u79FB").action(async () => {
|
|
15168
15578
|
await hookInitAction();
|
|
15169
15579
|
});
|
|
15170
|
-
hook.command("worker").argument("[engine]", "codex|gemini|claude", "codex").description("\u542F\u52A8\u4ECE\u8282\u70B9\uFF1A\u8FDE\u63A5\u4E3B\u8282\u70B9\u540E\u6267\u884C\u5DE5\u5177\u4EFB\u52A1").
|
|
15171
|
-
const passthroughArgs = resolveWorkerPassthroughArgs(engine);
|
|
15580
|
+
addWorkerRuntimeOptions(hook.command("worker").argument("[engine]", "codex|gemini|claude", "codex").description("\u542F\u52A8\u4ECE\u8282\u70B9\uFF1A\u8FDE\u63A5\u4E3B\u8282\u70B9\u540E\u6267\u884C\u5DE5\u5177\u4EFB\u52A1").option("--master-host <host>", "\u4E3B\u8282\u70B9\u5730\u5740\uFF08IP \u6216\u57DF\u540D\uFF09").option("--master-port <port>", "\u4E3B\u8282\u70B9\u7AEF\u53E3").option("--shared-secret <secret>", "\u4E3B\u4ECE\u901A\u4FE1\u9274\u6743\u5BC6\u94A5")).action(async (engine, options) => {
|
|
15581
|
+
const passthroughArgs = resolveWorkerPassthroughArgs(engine, "worker");
|
|
15172
15582
|
await hookWorkerAction(engine, { ...options, passthroughArgs });
|
|
15173
15583
|
});
|
|
15584
|
+
addWorkerRuntimeOptions(hook.command("local").argument("[engine]", "codex|gemini|claude", "codex").description("\u542F\u52A8\u672C\u673A\u4E00\u4F53\u8282\u70B9\uFF1A\u540C\u4E00\u8FDB\u7A0B\u5185\u542F\u52A8\u4E3B\u8282\u70B9\u548C\u672C\u5730\u4ECE\u8282\u70B9").option("--master-host <host>", "\u4E3B\u8282\u70B9\u76D1\u542C\u5730\u5740").option("--master-port <port>", "\u4E3B\u8282\u70B9\u7AEF\u53E3\uFF08\u9ED8\u8BA4 19732\uFF09").option("--shared-secret <secret>", "\u4E3B\u4ECE\u901A\u4FE1\u9274\u6743\u5BC6\u94A5").option("--claim-timeout-ms <ms>", "\u4EFB\u52A1\u8BA4\u9886\u8D85\u65F6\u6BEB\u79D2\u6570")).action(async (engine, options) => {
|
|
15585
|
+
const passthroughArgs = resolveWorkerPassthroughArgs(engine, "local");
|
|
15586
|
+
await hookLocalAction(engine, { ...options, passthroughArgs });
|
|
15587
|
+
});
|
|
15174
15588
|
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) => {
|
|
15175
15589
|
await hookLogAction(query, options);
|
|
15176
15590
|
});
|