nikou-cli 0.1.5 → 0.1.7
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 +61 -5
- package/dist/ai-hook.js +1 -1
- package/dist/{chunk-F3EPGM5N.js → chunk-OQQEIFQV.js} +1 -1
- package/dist/index.js +719 -290
- 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) {
|
|
@@ -912,7 +912,7 @@ function pad3(str, width) {
|
|
|
912
912
|
|
|
913
913
|
// src/hook/master/master-command.ts
|
|
914
914
|
import * as lark2 from "@larksuiteoapi/node-sdk";
|
|
915
|
-
import
|
|
915
|
+
import fs7 from "fs";
|
|
916
916
|
import path8 from "path";
|
|
917
917
|
import process4 from "process";
|
|
918
918
|
|
|
@@ -975,7 +975,7 @@ var CARD_STREAM_STDOUT_MAX_LENGTH = 12e3;
|
|
|
975
975
|
var BIND_WHITELIST_REFRESH_MS = 5e3;
|
|
976
976
|
|
|
977
977
|
// src/hook/utils.ts
|
|
978
|
-
import
|
|
978
|
+
import fs from "fs";
|
|
979
979
|
import os2 from "os";
|
|
980
980
|
import path2 from "path";
|
|
981
981
|
import process2 from "process";
|
|
@@ -1029,9 +1029,9 @@ function resolveAiHookGuestPath() {
|
|
|
1029
1029
|
}
|
|
1030
1030
|
function resolveOpsUserName() {
|
|
1031
1031
|
const propsPath = path2.join(os2.homedir(), "ops", "ops_global.properties");
|
|
1032
|
-
if (!
|
|
1032
|
+
if (!fs.existsSync(propsPath)) return "\u672A\u77E5";
|
|
1033
1033
|
try {
|
|
1034
|
-
const lines =
|
|
1034
|
+
const lines = fs.readFileSync(propsPath, "utf-8").split(/\r?\n/);
|
|
1035
1035
|
for (const line of lines) {
|
|
1036
1036
|
const trimmed = line.trim();
|
|
1037
1037
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -1056,8 +1056,8 @@ function resolveCardPathDisplay(dirPath) {
|
|
|
1056
1056
|
return `${segments[segments.length - 2]}\\${segments[segments.length - 1]}`;
|
|
1057
1057
|
}
|
|
1058
1058
|
function ensureDirExists(dirPath) {
|
|
1059
|
-
if (!
|
|
1060
|
-
|
|
1059
|
+
if (!fs.existsSync(dirPath)) {
|
|
1060
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
1061
1061
|
}
|
|
1062
1062
|
}
|
|
1063
1063
|
function normalizeHost(value) {
|
|
@@ -1369,7 +1369,7 @@ function formatCompactTokenCount(value) {
|
|
|
1369
1369
|
}
|
|
1370
1370
|
|
|
1371
1371
|
// src/hook/config-loader.ts
|
|
1372
|
-
import
|
|
1372
|
+
import fs2 from "fs";
|
|
1373
1373
|
|
|
1374
1374
|
// src/hook/json-config.ts
|
|
1375
1375
|
function stripJsonLineComments(content) {
|
|
@@ -1413,7 +1413,7 @@ function parseJsonWithLineComments(content, filePath = "JSON \u914D\u7F6E") {
|
|
|
1413
1413
|
// src/hook/config-loader.ts
|
|
1414
1414
|
function resolveConfigPath(role = "worker") {
|
|
1415
1415
|
const configPath = role === "master" ? MASTER_CONFIG_PATH : WORKER_CONFIG_PATH;
|
|
1416
|
-
return
|
|
1416
|
+
return fs2.existsSync(configPath) ? configPath : null;
|
|
1417
1417
|
}
|
|
1418
1418
|
function loadRoleConfig(role) {
|
|
1419
1419
|
const configPath = resolveConfigPath(role);
|
|
@@ -1427,7 +1427,7 @@ function loadRoleConfig(role) {
|
|
|
1427
1427
|
` + sampleBody + "}"
|
|
1428
1428
|
);
|
|
1429
1429
|
}
|
|
1430
|
-
const raw =
|
|
1430
|
+
const raw = fs2.readFileSync(configPath, "utf-8");
|
|
1431
1431
|
const config = parseJsonWithLineComments(raw, configPath);
|
|
1432
1432
|
return { config, configPath };
|
|
1433
1433
|
}
|
|
@@ -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);
|
|
@@ -1584,7 +1597,7 @@ function resolveAuthConfig(config) {
|
|
|
1584
1597
|
}
|
|
1585
1598
|
|
|
1586
1599
|
// src/hook/state-manager.ts
|
|
1587
|
-
import
|
|
1600
|
+
import fs3 from "fs";
|
|
1588
1601
|
import path3 from "path";
|
|
1589
1602
|
import process3 from "process";
|
|
1590
1603
|
var StateManager = class {
|
|
@@ -1596,13 +1609,13 @@ var StateManager = class {
|
|
|
1596
1609
|
this.logger = logger3;
|
|
1597
1610
|
}
|
|
1598
1611
|
read() {
|
|
1599
|
-
if (!
|
|
1612
|
+
if (!fs3.existsSync(this.statePath)) {
|
|
1600
1613
|
this.state = null;
|
|
1601
1614
|
return null;
|
|
1602
1615
|
}
|
|
1603
1616
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
1604
1617
|
try {
|
|
1605
|
-
const raw =
|
|
1618
|
+
const raw = fs3.readFileSync(this.statePath, "utf-8");
|
|
1606
1619
|
this.state = JSON.parse(raw);
|
|
1607
1620
|
return this.state;
|
|
1608
1621
|
} catch (error) {
|
|
@@ -1621,13 +1634,13 @@ var StateManager = class {
|
|
|
1621
1634
|
const tempPath = `${this.statePath}.tmp.${process3.pid}`;
|
|
1622
1635
|
try {
|
|
1623
1636
|
ensureDirExists(path3.dirname(this.statePath));
|
|
1624
|
-
|
|
1625
|
-
|
|
1637
|
+
fs3.writeFileSync(tempPath, JSON.stringify(nextState, null, 4));
|
|
1638
|
+
fs3.renameSync(tempPath, this.statePath);
|
|
1626
1639
|
} catch (error) {
|
|
1627
1640
|
const msg = error instanceof Error ? error.message : String(error);
|
|
1628
1641
|
this.logger.warn(`\u5199\u5165\u72B6\u6001\u6587\u4EF6\u5931\u8D25: ${msg}`);
|
|
1629
1642
|
try {
|
|
1630
|
-
if (
|
|
1643
|
+
if (fs3.existsSync(tempPath)) fs3.unlinkSync(tempPath);
|
|
1631
1644
|
} catch (cleanupError) {
|
|
1632
1645
|
const cmsg = cleanupError instanceof Error ? cleanupError.message : String(cleanupError);
|
|
1633
1646
|
this.logger.warn(`\u6E05\u7406\u4E34\u65F6\u72B6\u6001\u6587\u4EF6\u5931\u8D25: ${cmsg}`);
|
|
@@ -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 : [];
|
|
@@ -3883,7 +3909,7 @@ var DirectWorkerRegistry = class {
|
|
|
3883
3909
|
};
|
|
3884
3910
|
|
|
3885
3911
|
// src/hook/master/routing/chat-binding-registry.ts
|
|
3886
|
-
import
|
|
3912
|
+
import fs4 from "fs";
|
|
3887
3913
|
import path4 from "path";
|
|
3888
3914
|
function normalize2(value) {
|
|
3889
3915
|
return String(value || "").trim();
|
|
@@ -3944,12 +3970,12 @@ var ChatBindingRegistry = class {
|
|
|
3944
3970
|
}
|
|
3945
3971
|
load() {
|
|
3946
3972
|
this.bindings.clear();
|
|
3947
|
-
if (!
|
|
3973
|
+
if (!fs4.existsSync(this.filePath)) {
|
|
3948
3974
|
this.save();
|
|
3949
3975
|
return;
|
|
3950
3976
|
}
|
|
3951
3977
|
try {
|
|
3952
|
-
const parsed = JSON.parse(
|
|
3978
|
+
const parsed = JSON.parse(fs4.readFileSync(this.filePath, "utf-8") || "{}");
|
|
3953
3979
|
for (const [chatId, value] of Object.entries(parsed.bindings || {})) {
|
|
3954
3980
|
const normalizedChatId = normalize2(chatId);
|
|
3955
3981
|
if (!normalizedChatId || !value || typeof value !== "object") {
|
|
@@ -3977,7 +4003,7 @@ var ChatBindingRegistry = class {
|
|
|
3977
4003
|
}
|
|
3978
4004
|
}
|
|
3979
4005
|
save() {
|
|
3980
|
-
|
|
4006
|
+
fs4.mkdirSync(path4.dirname(this.filePath), { recursive: true });
|
|
3981
4007
|
const bindings = {};
|
|
3982
4008
|
for (const [chatId, chatMap] of this.bindings.entries()) {
|
|
3983
4009
|
const serialized = {};
|
|
@@ -3986,7 +4012,7 @@ var ChatBindingRegistry = class {
|
|
|
3986
4012
|
}
|
|
3987
4013
|
bindings[chatId] = serialized;
|
|
3988
4014
|
}
|
|
3989
|
-
|
|
4015
|
+
fs4.writeFileSync(
|
|
3990
4016
|
this.filePath,
|
|
3991
4017
|
`${JSON.stringify({ version: 2, updatedAt: (/* @__PURE__ */ new Date()).toISOString(), bindings }, null, 2)}
|
|
3992
4018
|
`,
|
|
@@ -4110,7 +4136,7 @@ var ChatBindingRegistry = class {
|
|
|
4110
4136
|
};
|
|
4111
4137
|
|
|
4112
4138
|
// src/hook/master/routing/worker-diagnostics-registry.ts
|
|
4113
|
-
import
|
|
4139
|
+
import fs5 from "fs";
|
|
4114
4140
|
import path5 from "path";
|
|
4115
4141
|
function normalize3(value) {
|
|
4116
4142
|
return String(value || "").trim();
|
|
@@ -4135,12 +4161,12 @@ var WorkerDiagnosticsRegistry = class {
|
|
|
4135
4161
|
}
|
|
4136
4162
|
load() {
|
|
4137
4163
|
this.workers.clear();
|
|
4138
|
-
if (!
|
|
4164
|
+
if (!fs5.existsSync(this.filePath)) {
|
|
4139
4165
|
this.save();
|
|
4140
4166
|
return;
|
|
4141
4167
|
}
|
|
4142
4168
|
try {
|
|
4143
|
-
const parsed = JSON.parse(
|
|
4169
|
+
const parsed = JSON.parse(fs5.readFileSync(this.filePath, "utf-8") || "{}");
|
|
4144
4170
|
for (const [workerId, diagnostics] of Object.entries(safeObject(parsed.workers))) {
|
|
4145
4171
|
const normalizedWorkerId = normalize3(diagnostics.workerId || workerId);
|
|
4146
4172
|
const registryKey = buildRegistryKey({
|
|
@@ -4172,12 +4198,12 @@ var WorkerDiagnosticsRegistry = class {
|
|
|
4172
4198
|
}
|
|
4173
4199
|
}
|
|
4174
4200
|
save() {
|
|
4175
|
-
|
|
4201
|
+
fs5.mkdirSync(path5.dirname(this.filePath), { recursive: true });
|
|
4176
4202
|
const workers = {};
|
|
4177
4203
|
for (const [key, diagnostics] of this.workers.entries()) {
|
|
4178
4204
|
workers[key] = diagnostics;
|
|
4179
4205
|
}
|
|
4180
|
-
|
|
4206
|
+
fs5.writeFileSync(
|
|
4181
4207
|
this.filePath,
|
|
4182
4208
|
`${JSON.stringify({ version: 1, updatedAt: (/* @__PURE__ */ new Date()).toISOString(), workers }, null, 2)}
|
|
4183
4209
|
`,
|
|
@@ -4226,7 +4252,7 @@ var WorkerDiagnosticsRegistry = class {
|
|
|
4226
4252
|
};
|
|
4227
4253
|
|
|
4228
4254
|
// src/hook/master/master-event-utils.ts
|
|
4229
|
-
import
|
|
4255
|
+
import fs6 from "fs";
|
|
4230
4256
|
import os3 from "os";
|
|
4231
4257
|
import path6 from "path";
|
|
4232
4258
|
var VOPS_USER_CACHE_PATH = path6.join(os3.homedir(), "ops", "vops_user.json");
|
|
@@ -4313,11 +4339,11 @@ function isTaskOperatorMatched(task, operatorUserId, operatorOpenId) {
|
|
|
4313
4339
|
function resolveSenderNameFromCache(senderUserId, senderOpenId = "") {
|
|
4314
4340
|
const targetUserId = String(senderUserId || "").trim();
|
|
4315
4341
|
const targetOpenId = String(senderOpenId || "").trim();
|
|
4316
|
-
if (!targetUserId && !targetOpenId || !
|
|
4342
|
+
if (!targetUserId && !targetOpenId || !fs6.existsSync(VOPS_USER_CACHE_PATH)) {
|
|
4317
4343
|
return "";
|
|
4318
4344
|
}
|
|
4319
4345
|
try {
|
|
4320
|
-
const parsed = JSON.parse(
|
|
4346
|
+
const parsed = JSON.parse(fs6.readFileSync(VOPS_USER_CACHE_PATH, "utf-8"));
|
|
4321
4347
|
const entries = Array.isArray(parsed) ? parsed : [];
|
|
4322
4348
|
const matched = entries.find((item) => {
|
|
4323
4349
|
if (!item || typeof item !== "object" || item.__cacheType) {
|
|
@@ -5205,7 +5231,7 @@ var HookMasterCommand = class {
|
|
|
5205
5231
|
if (masterConfig.botName) {
|
|
5206
5232
|
this.botName = masterConfig.botName;
|
|
5207
5233
|
}
|
|
5208
|
-
const configStat =
|
|
5234
|
+
const configStat = fs7.statSync(configPath);
|
|
5209
5235
|
this.bindWhitelistConfigMtimeMs = Number(configStat.mtimeMs || 0);
|
|
5210
5236
|
this.chatBindingRegistry.load();
|
|
5211
5237
|
this.workerDiagnosticsRegistry.load();
|
|
@@ -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);
|
|
@@ -5720,8 +5753,8 @@ var HookMasterCommand = class {
|
|
|
5720
5753
|
}
|
|
5721
5754
|
refreshBindWhitelistIfNeeded() {
|
|
5722
5755
|
try {
|
|
5723
|
-
if (!this.configPath || !
|
|
5724
|
-
const stat =
|
|
5756
|
+
if (!this.configPath || !fs7.existsSync(this.configPath)) return;
|
|
5757
|
+
const stat = fs7.statSync(this.configPath);
|
|
5725
5758
|
const mtimeMs = Number(stat.mtimeMs || 0);
|
|
5726
5759
|
if (!mtimeMs || mtimeMs <= this.bindWhitelistConfigMtimeMs) return;
|
|
5727
5760
|
const { config } = loadMasterHstMcpConfig();
|
|
@@ -5772,42 +5805,42 @@ 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
|
|
5806
|
-
import
|
|
5839
|
+
import fs8 from "fs";
|
|
5807
5840
|
import path9 from "path";
|
|
5808
5841
|
function ensureLogsDir() {
|
|
5809
|
-
if (!
|
|
5810
|
-
|
|
5842
|
+
if (!fs8.existsSync(LOGS_DIR)) {
|
|
5843
|
+
fs8.mkdirSync(LOGS_DIR, { recursive: true });
|
|
5811
5844
|
}
|
|
5812
5845
|
}
|
|
5813
5846
|
function todaySuffix() {
|
|
@@ -5818,8 +5851,8 @@ function timestamp() {
|
|
|
5818
5851
|
}
|
|
5819
5852
|
function appendLine(filePath, line) {
|
|
5820
5853
|
try {
|
|
5821
|
-
|
|
5822
|
-
|
|
5854
|
+
fs8.mkdirSync(path9.dirname(filePath), { recursive: true });
|
|
5855
|
+
fs8.appendFileSync(filePath, line + "\n", "utf-8");
|
|
5823
5856
|
} catch {
|
|
5824
5857
|
}
|
|
5825
5858
|
}
|
|
@@ -5844,22 +5877,22 @@ function resolveServiceLogName(role) {
|
|
|
5844
5877
|
}
|
|
5845
5878
|
function ensureCurrentLogLink(currentPath, dailyPath) {
|
|
5846
5879
|
try {
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
if (
|
|
5851
|
-
const stat =
|
|
5880
|
+
fs8.mkdirSync(path9.dirname(currentPath), { recursive: true });
|
|
5881
|
+
fs8.mkdirSync(path9.dirname(dailyPath), { recursive: true });
|
|
5882
|
+
fs8.writeFileSync(dailyPath, "", { flag: "a" });
|
|
5883
|
+
if (fs8.existsSync(currentPath)) {
|
|
5884
|
+
const stat = fs8.lstatSync(currentPath);
|
|
5852
5885
|
if (!stat.isSymbolicLink()) {
|
|
5853
5886
|
const legacyDir = path9.join(path9.dirname(currentPath), "logs", "legacy");
|
|
5854
|
-
|
|
5887
|
+
fs8.mkdirSync(legacyDir, { recursive: true });
|
|
5855
5888
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
5856
|
-
|
|
5889
|
+
fs8.renameSync(currentPath, path9.join(legacyDir, `${path9.basename(currentPath)}.${stamp}`));
|
|
5857
5890
|
}
|
|
5858
5891
|
}
|
|
5859
|
-
|
|
5860
|
-
|
|
5892
|
+
fs8.rmSync(currentPath, { force: true });
|
|
5893
|
+
fs8.symlinkSync(dailyPath, currentPath);
|
|
5861
5894
|
} catch {
|
|
5862
|
-
|
|
5895
|
+
fs8.writeFileSync(currentPath, "", { flag: "a" });
|
|
5863
5896
|
}
|
|
5864
5897
|
}
|
|
5865
5898
|
function createLogger(name, verbose = false) {
|
|
@@ -5920,16 +5953,19 @@ 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
|
|
|
5960
|
+
// src/hook/worker/message-strategy.ts
|
|
5961
|
+
import fs14 from "fs";
|
|
5962
|
+
|
|
5927
5963
|
// src/hook/worker/runners/codex-runner.ts
|
|
5928
5964
|
import process7 from "process";
|
|
5929
5965
|
import { spawn, spawnSync as spawnSync4 } from "child_process";
|
|
5930
5966
|
|
|
5931
5967
|
// src/hook/runtime-env.ts
|
|
5932
|
-
import
|
|
5968
|
+
import fs9 from "fs";
|
|
5933
5969
|
import process5 from "process";
|
|
5934
5970
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
5935
5971
|
var HST_MCP_DISABLED_MODULES_ENV_KEY = "HST_MCP_DISABLED_MODULES";
|
|
@@ -5974,11 +6010,11 @@ function parseEnvFileContent(content = "") {
|
|
|
5974
6010
|
return env;
|
|
5975
6011
|
}
|
|
5976
6012
|
function loadRuntimeEnvFile(filePath = RUNTIME_ENV_PATH) {
|
|
5977
|
-
if (!filePath || !
|
|
6013
|
+
if (!filePath || !fs9.existsSync(filePath)) {
|
|
5978
6014
|
return {};
|
|
5979
6015
|
}
|
|
5980
6016
|
try {
|
|
5981
|
-
return parseEnvFileContent(
|
|
6017
|
+
return parseEnvFileContent(fs9.readFileSync(filePath, "utf-8"));
|
|
5982
6018
|
} catch {
|
|
5983
6019
|
return {};
|
|
5984
6020
|
}
|
|
@@ -5990,7 +6026,7 @@ function resolveUnixShell(baseEnv = process5.env) {
|
|
|
5990
6026
|
"/bin/bash",
|
|
5991
6027
|
"/bin/sh"
|
|
5992
6028
|
].filter(Boolean);
|
|
5993
|
-
return candidates.find((item) =>
|
|
6029
|
+
return candidates.find((item) => fs9.existsSync(item)) || "/bin/sh";
|
|
5994
6030
|
}
|
|
5995
6031
|
function parseNullSeparatedEnv(output = "") {
|
|
5996
6032
|
const env = {};
|
|
@@ -6111,23 +6147,23 @@ function buildHookRuntimeEnv(baseEnv = process5.env, {
|
|
|
6111
6147
|
}
|
|
6112
6148
|
|
|
6113
6149
|
// src/hook/worker/runners/command-resolver.ts
|
|
6114
|
-
import
|
|
6150
|
+
import fs10 from "fs";
|
|
6115
6151
|
import path10 from "path";
|
|
6116
6152
|
import process6 from "process";
|
|
6117
6153
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
6118
6154
|
function isExecutableFile(filePath) {
|
|
6119
|
-
if (!filePath || !
|
|
6155
|
+
if (!filePath || !fs10.existsSync(filePath)) {
|
|
6120
6156
|
return false;
|
|
6121
6157
|
}
|
|
6122
6158
|
try {
|
|
6123
|
-
const stat =
|
|
6159
|
+
const stat = fs10.statSync(filePath);
|
|
6124
6160
|
if (!stat.isFile()) {
|
|
6125
6161
|
return false;
|
|
6126
6162
|
}
|
|
6127
6163
|
if (process6.platform === "win32") {
|
|
6128
6164
|
return true;
|
|
6129
6165
|
}
|
|
6130
|
-
|
|
6166
|
+
fs10.accessSync(filePath, fs10.constants.X_OK);
|
|
6131
6167
|
return true;
|
|
6132
6168
|
} catch {
|
|
6133
6169
|
return false;
|
|
@@ -6672,7 +6708,7 @@ command=${execConfig.displayCommand}`));
|
|
|
6672
6708
|
};
|
|
6673
6709
|
|
|
6674
6710
|
// src/hook/context/identity-resolver.ts
|
|
6675
|
-
import
|
|
6711
|
+
import fs11 from "fs";
|
|
6676
6712
|
import os5 from "os";
|
|
6677
6713
|
import path11 from "path";
|
|
6678
6714
|
|
|
@@ -6877,12 +6913,12 @@ var IdentityResolver = class {
|
|
|
6877
6913
|
if (Array.isArray(this.cache)) {
|
|
6878
6914
|
return this.cache;
|
|
6879
6915
|
}
|
|
6880
|
-
if (!
|
|
6916
|
+
if (!fs11.existsSync(this.cachePath)) {
|
|
6881
6917
|
this.cache = [];
|
|
6882
6918
|
return this.cache;
|
|
6883
6919
|
}
|
|
6884
6920
|
try {
|
|
6885
|
-
const parsed = JSON.parse(
|
|
6921
|
+
const parsed = JSON.parse(fs11.readFileSync(this.cachePath, "utf-8"));
|
|
6886
6922
|
const input = Array.isArray(parsed) ? parsed : [];
|
|
6887
6923
|
this.cache = this.dedupeCacheEntries(input);
|
|
6888
6924
|
if (this.cache.length !== input.length) {
|
|
@@ -6899,7 +6935,7 @@ var IdentityResolver = class {
|
|
|
6899
6935
|
saveCache() {
|
|
6900
6936
|
try {
|
|
6901
6937
|
this.cache = this.dedupeCacheEntries(this.cache || []);
|
|
6902
|
-
|
|
6938
|
+
fs11.writeFileSync(this.cachePath, JSON.stringify(this.cache, null, 2));
|
|
6903
6939
|
} catch (error) {
|
|
6904
6940
|
const message = error instanceof Error ? error.message : String(error);
|
|
6905
6941
|
this.logger.warn(`\u5199\u5165 vops_user.json \u5931\u8D25: ${message}`);
|
|
@@ -7232,7 +7268,7 @@ var IdentityResolver = class {
|
|
|
7232
7268
|
};
|
|
7233
7269
|
|
|
7234
7270
|
// src/hook/prompt/nikou-prompt-store.ts
|
|
7235
|
-
import
|
|
7271
|
+
import fs12 from "fs";
|
|
7236
7272
|
import os6 from "os";
|
|
7237
7273
|
import path12 from "path";
|
|
7238
7274
|
|
|
@@ -7287,7 +7323,7 @@ function normalizeText2(value) {
|
|
|
7287
7323
|
return String(value || "").trim();
|
|
7288
7324
|
}
|
|
7289
7325
|
function ensureDir(dirPath) {
|
|
7290
|
-
|
|
7326
|
+
fs12.mkdirSync(dirPath, { recursive: true });
|
|
7291
7327
|
}
|
|
7292
7328
|
function parseFrontmatter(content) {
|
|
7293
7329
|
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
|
|
@@ -7334,18 +7370,18 @@ ${body}
|
|
|
7334
7370
|
` : "\n"}`;
|
|
7335
7371
|
}
|
|
7336
7372
|
function readTextFile(filePath) {
|
|
7337
|
-
if (!
|
|
7373
|
+
if (!fs12.existsSync(filePath)) {
|
|
7338
7374
|
return "";
|
|
7339
7375
|
}
|
|
7340
7376
|
try {
|
|
7341
|
-
return
|
|
7377
|
+
return fs12.readFileSync(filePath, "utf-8").trim();
|
|
7342
7378
|
} catch {
|
|
7343
7379
|
return "";
|
|
7344
7380
|
}
|
|
7345
7381
|
}
|
|
7346
7382
|
function writeTextFile(filePath, content) {
|
|
7347
7383
|
ensureDir(path12.dirname(filePath));
|
|
7348
|
-
|
|
7384
|
+
fs12.writeFileSync(filePath, content, "utf-8");
|
|
7349
7385
|
}
|
|
7350
7386
|
function buildPromptDefinitions() {
|
|
7351
7387
|
const roleDefinitions = Object.entries(REQUESTER_PERSONA_RULES.roles).map(([roleKey, roleConfig]) => ({
|
|
@@ -7406,7 +7442,7 @@ var NikouPromptStore = class {
|
|
|
7406
7442
|
return definition.defaultContent.trim();
|
|
7407
7443
|
}
|
|
7408
7444
|
readPromptFile(definition) {
|
|
7409
|
-
if (!
|
|
7445
|
+
if (!fs12.existsSync(definition.path)) {
|
|
7410
7446
|
const content = this.resolveBootstrapContent(definition);
|
|
7411
7447
|
const file = {
|
|
7412
7448
|
title: definition.title,
|
|
@@ -7417,7 +7453,7 @@ var NikouPromptStore = class {
|
|
|
7417
7453
|
this.syncLegacyFiles(definition, file);
|
|
7418
7454
|
return file;
|
|
7419
7455
|
}
|
|
7420
|
-
return parseFrontmatter(
|
|
7456
|
+
return parseFrontmatter(fs12.readFileSync(definition.path, "utf-8"));
|
|
7421
7457
|
}
|
|
7422
7458
|
syncLegacyFiles(definition, file) {
|
|
7423
7459
|
if (!definition.legacyPaths.length) {
|
|
@@ -7430,7 +7466,7 @@ var NikouPromptStore = class {
|
|
|
7430
7466
|
}
|
|
7431
7467
|
}
|
|
7432
7468
|
toSummary(definition, file) {
|
|
7433
|
-
const stat =
|
|
7469
|
+
const stat = fs12.existsSync(definition.path) ? fs12.statSync(definition.path) : null;
|
|
7434
7470
|
return {
|
|
7435
7471
|
id: definition.id,
|
|
7436
7472
|
kind: definition.kind,
|
|
@@ -7511,7 +7547,7 @@ var NikouPromptStore = class {
|
|
|
7511
7547
|
};
|
|
7512
7548
|
|
|
7513
7549
|
// src/hook/worker/task-route-binding.ts
|
|
7514
|
-
import
|
|
7550
|
+
import fs13 from "fs";
|
|
7515
7551
|
import path13 from "path";
|
|
7516
7552
|
function resolveTaskRouteDir(routeBinding, fallbackDir) {
|
|
7517
7553
|
if (routeBinding) {
|
|
@@ -7520,7 +7556,7 @@ function resolveTaskRouteDir(routeBinding, fallbackDir) {
|
|
|
7520
7556
|
return { dirPath: "", reason: "invalid_route_dir" };
|
|
7521
7557
|
}
|
|
7522
7558
|
try {
|
|
7523
|
-
if (!
|
|
7559
|
+
if (!fs13.statSync(dirPath2).isDirectory()) {
|
|
7524
7560
|
return { dirPath: "", reason: "invalid_route_dir" };
|
|
7525
7561
|
}
|
|
7526
7562
|
} catch {
|
|
@@ -7657,7 +7693,7 @@ var MessageReceiveStrategy = class {
|
|
|
7657
7693
|
if (!raw) return "";
|
|
7658
7694
|
try {
|
|
7659
7695
|
const parsed = JSON.parse(raw);
|
|
7660
|
-
const text = String(parsed?.text || "");
|
|
7696
|
+
const text = String(parsed?.text || "") || extractFeishuPostText(parsed);
|
|
7661
7697
|
return this.stripMentions(text, message);
|
|
7662
7698
|
} catch {
|
|
7663
7699
|
return this.stripMentions(String(raw), message);
|
|
@@ -7665,25 +7701,7 @@ var MessageReceiveStrategy = class {
|
|
|
7665
7701
|
}
|
|
7666
7702
|
extractPostText(messageLike) {
|
|
7667
7703
|
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
|
-
}
|
|
7704
|
+
return extractFeishuPostText(raw);
|
|
7687
7705
|
}
|
|
7688
7706
|
stripMentions(text, message) {
|
|
7689
7707
|
let cleaned = String(text || "");
|
|
@@ -8308,7 +8326,7 @@ ${question}` : question;
|
|
|
8308
8326
|
if (!bindTarget) {
|
|
8309
8327
|
return { ...baseTask, canHandle: true, type: "quick_result", quickResult: "\u8BF7\u6307\u5B9A\u7ED1\u5B9A\u8DEF\u5F84\uFF0C\u683C\u5F0F: \u7ED1\u5B9A:/path/to/project" };
|
|
8310
8328
|
}
|
|
8311
|
-
if (!
|
|
8329
|
+
if (!fs14.existsSync(bindTarget)) {
|
|
8312
8330
|
return { ...baseTask, canHandle: true, type: "quick_result", quickResult: `\u8DEF\u5F84\u4E0D\u5B58\u5728: ${bindTarget}` };
|
|
8313
8331
|
}
|
|
8314
8332
|
this.stateManager.rebindChatToDir(message.chatId, bindTarget);
|
|
@@ -9744,7 +9762,15 @@ var SlaveRelayClient = class {
|
|
|
9744
9762
|
this.resolvePendingClaim(packet.task_id, false);
|
|
9745
9763
|
break;
|
|
9746
9764
|
case "task_offer":
|
|
9747
|
-
this.handleTaskOffer(packet)
|
|
9765
|
+
void this.handleTaskOffer(packet).catch((error) => {
|
|
9766
|
+
const taskId = String(packet.task_id || "").trim();
|
|
9767
|
+
const traceId = resolveTraceId(taskId);
|
|
9768
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
9769
|
+
this.logger.error(formatTraceLog(
|
|
9770
|
+
traceId,
|
|
9771
|
+
`\u5904\u7406\u4EFB\u52A1 offer \u5931\u8D25: task_id=${taskId || "-"}, error=${message}`
|
|
9772
|
+
));
|
|
9773
|
+
});
|
|
9748
9774
|
break;
|
|
9749
9775
|
case "task_cancel": {
|
|
9750
9776
|
const cancelResult = this.taskExecutor.cancelTask(packet.task_id);
|
|
@@ -10496,6 +10522,7 @@ var LocalBrowserWsServer = class {
|
|
|
10496
10522
|
workerId;
|
|
10497
10523
|
workerType;
|
|
10498
10524
|
larkClient;
|
|
10525
|
+
getNacosSyncStatus;
|
|
10499
10526
|
wss = null;
|
|
10500
10527
|
profile;
|
|
10501
10528
|
startTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -10505,6 +10532,7 @@ var LocalBrowserWsServer = class {
|
|
|
10505
10532
|
this.workerId = options.workerId;
|
|
10506
10533
|
this.workerType = options.workerType;
|
|
10507
10534
|
this.larkClient = options.larkClient;
|
|
10535
|
+
this.getNacosSyncStatus = options.getNacosSyncStatus;
|
|
10508
10536
|
}
|
|
10509
10537
|
async start() {
|
|
10510
10538
|
if (this.wss) {
|
|
@@ -10685,7 +10713,8 @@ var LocalBrowserWsServer = class {
|
|
|
10685
10713
|
cliTools: {
|
|
10686
10714
|
codex: this.detectCliTool("codex"),
|
|
10687
10715
|
claude: this.detectCliTool("claude")
|
|
10688
|
-
}
|
|
10716
|
+
},
|
|
10717
|
+
nacosSync: this.getNacosSyncStatus?.() ?? null
|
|
10689
10718
|
}
|
|
10690
10719
|
});
|
|
10691
10720
|
}
|
|
@@ -13974,6 +14003,263 @@ var OwnerNotifyService = class {
|
|
|
13974
14003
|
}
|
|
13975
14004
|
};
|
|
13976
14005
|
|
|
14006
|
+
// src/hook/worker/nacos-subscription-sync.ts
|
|
14007
|
+
import fs27 from "fs";
|
|
14008
|
+
import os16 from "os";
|
|
14009
|
+
import path26 from "path";
|
|
14010
|
+
import { execFile, spawn as spawn4 } from "child_process";
|
|
14011
|
+
import { createRequire } from "module";
|
|
14012
|
+
import { promisify } from "util";
|
|
14013
|
+
var execFileAsync = promisify(execFile);
|
|
14014
|
+
var NacosSubscriptionSyncCoordinator = class {
|
|
14015
|
+
logger;
|
|
14016
|
+
workerId;
|
|
14017
|
+
config;
|
|
14018
|
+
timer = null;
|
|
14019
|
+
daemon = null;
|
|
14020
|
+
running = false;
|
|
14021
|
+
stopped = false;
|
|
14022
|
+
status;
|
|
14023
|
+
statePath = path26.join(os16.homedir(), ".nikou-block", "worker", "nacos-subscriptions.json");
|
|
14024
|
+
constructor(options) {
|
|
14025
|
+
this.logger = options.logger;
|
|
14026
|
+
this.workerId = options.workerId;
|
|
14027
|
+
this.config = options.config;
|
|
14028
|
+
this.status = {
|
|
14029
|
+
enabled: this.config.enabled,
|
|
14030
|
+
configured: false,
|
|
14031
|
+
profile: this.config.profile,
|
|
14032
|
+
label: this.config.label,
|
|
14033
|
+
daemonRunning: false,
|
|
14034
|
+
totalSkills: 0,
|
|
14035
|
+
synced: 0,
|
|
14036
|
+
pending: 0,
|
|
14037
|
+
conflicts: 0,
|
|
14038
|
+
failed: 0
|
|
14039
|
+
};
|
|
14040
|
+
}
|
|
14041
|
+
start() {
|
|
14042
|
+
if (!this.config.enabled || this.timer) return;
|
|
14043
|
+
void this.syncOnce();
|
|
14044
|
+
this.timer = setInterval(() => {
|
|
14045
|
+
void this.syncOnce();
|
|
14046
|
+
}, this.config.plan_poll_interval_ms);
|
|
14047
|
+
}
|
|
14048
|
+
async stop() {
|
|
14049
|
+
this.stopped = true;
|
|
14050
|
+
if (this.timer) {
|
|
14051
|
+
clearInterval(this.timer);
|
|
14052
|
+
this.timer = null;
|
|
14053
|
+
}
|
|
14054
|
+
if (this.daemon) {
|
|
14055
|
+
this.daemon.kill("SIGTERM");
|
|
14056
|
+
this.daemon = null;
|
|
14057
|
+
this.status.daemonRunning = false;
|
|
14058
|
+
}
|
|
14059
|
+
}
|
|
14060
|
+
getStatus() {
|
|
14061
|
+
return { ...this.status };
|
|
14062
|
+
}
|
|
14063
|
+
async syncOnce() {
|
|
14064
|
+
if (this.running || this.stopped) return;
|
|
14065
|
+
this.running = true;
|
|
14066
|
+
try {
|
|
14067
|
+
const plan = await this.fetchPlan();
|
|
14068
|
+
this.status.enabled = plan.nacos.enabled;
|
|
14069
|
+
this.status.host = plan.nacos.host;
|
|
14070
|
+
this.status.profile = plan.nacos.profile || this.config.profile;
|
|
14071
|
+
this.status.label = plan.nacos.label || this.config.label;
|
|
14072
|
+
this.status.lastPlanAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
14073
|
+
if (!plan.nacos.enabled) {
|
|
14074
|
+
this.status.configured = false;
|
|
14075
|
+
this.status.totalSkills = 0;
|
|
14076
|
+
this.status.pending = 0;
|
|
14077
|
+
return;
|
|
14078
|
+
}
|
|
14079
|
+
await this.configureProfile(plan);
|
|
14080
|
+
await this.ensureMode(plan);
|
|
14081
|
+
this.ensureDaemon(plan);
|
|
14082
|
+
const results = [];
|
|
14083
|
+
for (const skill of plan.skills) {
|
|
14084
|
+
const result = await this.syncSkill(plan, skill);
|
|
14085
|
+
results.push(result);
|
|
14086
|
+
}
|
|
14087
|
+
await this.report(results);
|
|
14088
|
+
this.persistManagedState(plan.skills);
|
|
14089
|
+
this.applySummary(results);
|
|
14090
|
+
this.status.lastSyncAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
14091
|
+
this.status.lastError = void 0;
|
|
14092
|
+
} catch (error) {
|
|
14093
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
14094
|
+
this.status.lastError = message;
|
|
14095
|
+
this.logger.warn(`Nacos Skill \u8BA2\u9605\u540C\u6B65\u5931\u8D25: ${message}`);
|
|
14096
|
+
} finally {
|
|
14097
|
+
this.running = false;
|
|
14098
|
+
}
|
|
14099
|
+
}
|
|
14100
|
+
async fetchPlan() {
|
|
14101
|
+
const runtime = resolveCliAuthRuntimeConfig();
|
|
14102
|
+
if (!runtime.cliAuthSecret) {
|
|
14103
|
+
throw new Error("\u672A\u914D\u7F6E CLI_AUTH_SECRET\uFF0C\u65E0\u6CD5\u62C9\u53D6 Nacos \u540C\u6B65\u8BA1\u5212");
|
|
14104
|
+
}
|
|
14105
|
+
const response = await fetch(`${runtime.apiUrl}/worker-skills/nacos-sync/plan`, {
|
|
14106
|
+
method: "POST",
|
|
14107
|
+
headers: { "Content-Type": "application/json" },
|
|
14108
|
+
body: JSON.stringify({ secret: runtime.cliAuthSecret, workerId: this.workerId })
|
|
14109
|
+
});
|
|
14110
|
+
if (!response.ok) {
|
|
14111
|
+
const text = await response.text().catch(() => "");
|
|
14112
|
+
throw new Error(`\u62C9\u53D6 Nacos \u540C\u6B65\u8BA1\u5212\u5931\u8D25: ${response.status} ${text}`);
|
|
14113
|
+
}
|
|
14114
|
+
return await response.json();
|
|
14115
|
+
}
|
|
14116
|
+
async report(results) {
|
|
14117
|
+
if (!results.length) return;
|
|
14118
|
+
const runtime = resolveCliAuthRuntimeConfig();
|
|
14119
|
+
const response = await fetch(`${runtime.apiUrl}/worker-skills/nacos-sync/report`, {
|
|
14120
|
+
method: "POST",
|
|
14121
|
+
headers: { "Content-Type": "application/json" },
|
|
14122
|
+
body: JSON.stringify({ secret: runtime.cliAuthSecret, workerId: this.workerId, results })
|
|
14123
|
+
});
|
|
14124
|
+
if (!response.ok) {
|
|
14125
|
+
const text = await response.text().catch(() => "");
|
|
14126
|
+
throw new Error(`\u4E0A\u62A5 Nacos \u540C\u6B65\u72B6\u6001\u5931\u8D25: ${response.status} ${text}`);
|
|
14127
|
+
}
|
|
14128
|
+
}
|
|
14129
|
+
async configureProfile(plan) {
|
|
14130
|
+
const nacos = plan.nacos;
|
|
14131
|
+
const profile = nacos.profile || this.config.profile;
|
|
14132
|
+
const args = [
|
|
14133
|
+
"profile",
|
|
14134
|
+
"set",
|
|
14135
|
+
profile,
|
|
14136
|
+
`host=${nacos.serverHost || this.parseHost(nacos.host).host}`,
|
|
14137
|
+
`port=${nacos.port || this.parseHost(nacos.host).port}`,
|
|
14138
|
+
`scheme=${nacos.scheme || this.parseHost(nacos.host).scheme}`,
|
|
14139
|
+
`namespace=${nacos.namespace || "public"}`,
|
|
14140
|
+
`auth-type=${nacos.authType || "none"}`
|
|
14141
|
+
];
|
|
14142
|
+
if (nacos.username) args.push(`username=${nacos.username}`);
|
|
14143
|
+
if (nacos.password) args.push(`password=${nacos.password}`);
|
|
14144
|
+
await this.run(args);
|
|
14145
|
+
this.status.configured = true;
|
|
14146
|
+
}
|
|
14147
|
+
async ensureMode(plan) {
|
|
14148
|
+
await this.run(["skill-sync", "mode", "nacos", "--profile", plan.nacos.profile || this.config.profile, "--switch-profile"]);
|
|
14149
|
+
}
|
|
14150
|
+
ensureDaemon(plan) {
|
|
14151
|
+
if (this.daemon && !this.daemon.killed) return;
|
|
14152
|
+
const args = [
|
|
14153
|
+
"skill-sync",
|
|
14154
|
+
"start",
|
|
14155
|
+
"--foreground",
|
|
14156
|
+
"--non-interactive",
|
|
14157
|
+
"--profile",
|
|
14158
|
+
plan.nacos.profile || this.config.profile,
|
|
14159
|
+
"--label",
|
|
14160
|
+
plan.nacos.label || this.config.label,
|
|
14161
|
+
"--interval",
|
|
14162
|
+
this.config.interval,
|
|
14163
|
+
"--switch-profile"
|
|
14164
|
+
];
|
|
14165
|
+
if (!this.config.auto_upload) {
|
|
14166
|
+
args.push("--no-auto-upload");
|
|
14167
|
+
}
|
|
14168
|
+
const bin = this.resolveNacosCliBin();
|
|
14169
|
+
this.daemon = spawn4(bin, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
14170
|
+
this.status.daemonRunning = true;
|
|
14171
|
+
this.daemon.stdout?.on("data", (chunk) => this.logger.debug(`nacos-cli: ${String(chunk).trim()}`));
|
|
14172
|
+
this.daemon.stderr?.on("data", (chunk) => this.logger.warn(`nacos-cli: ${String(chunk).trim()}`));
|
|
14173
|
+
this.daemon.once("exit", (code, signal) => {
|
|
14174
|
+
this.status.daemonRunning = false;
|
|
14175
|
+
this.daemon = null;
|
|
14176
|
+
if (!this.stopped) {
|
|
14177
|
+
this.status.lastError = `Nacos daemon \u5DF2\u9000\u51FA: code=${code ?? "-"}, signal=${signal ?? "-"}`;
|
|
14178
|
+
}
|
|
14179
|
+
});
|
|
14180
|
+
}
|
|
14181
|
+
async syncSkill(plan, skill) {
|
|
14182
|
+
try {
|
|
14183
|
+
await this.run([
|
|
14184
|
+
"skill-sync",
|
|
14185
|
+
skill.status === "pending_remove" ? "remove" : "add",
|
|
14186
|
+
skill.nacosSkillName,
|
|
14187
|
+
"--profile",
|
|
14188
|
+
plan.nacos.profile || this.config.profile,
|
|
14189
|
+
"--switch-profile",
|
|
14190
|
+
...skill.status === "pending_remove" ? [] : ["--non-interactive"]
|
|
14191
|
+
]);
|
|
14192
|
+
return {
|
|
14193
|
+
resourceId: skill.resourceId,
|
|
14194
|
+
nacosSkillName: skill.nacosSkillName,
|
|
14195
|
+
desiredVersionKey: skill.desiredVersionKey,
|
|
14196
|
+
status: skill.status === "pending_remove" ? "removed" : "synced",
|
|
14197
|
+
message: "Nacos Skill Sync \u6267\u884C\u6210\u529F"
|
|
14198
|
+
};
|
|
14199
|
+
} catch (error) {
|
|
14200
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
14201
|
+
const status = /conflict|冲突/i.test(message) ? "conflict" : "failed";
|
|
14202
|
+
return {
|
|
14203
|
+
resourceId: skill.resourceId,
|
|
14204
|
+
nacosSkillName: skill.nacosSkillName,
|
|
14205
|
+
desiredVersionKey: skill.desiredVersionKey,
|
|
14206
|
+
status,
|
|
14207
|
+
message
|
|
14208
|
+
};
|
|
14209
|
+
}
|
|
14210
|
+
}
|
|
14211
|
+
async run(args) {
|
|
14212
|
+
const bin = this.resolveNacosCliBin();
|
|
14213
|
+
const result = await execFileAsync(bin, args, { timeout: 6e4, maxBuffer: 1024 * 1024 * 2 });
|
|
14214
|
+
return `${result.stdout ?? ""}${result.stderr ?? ""}`.trim();
|
|
14215
|
+
}
|
|
14216
|
+
resolveNacosCliBin() {
|
|
14217
|
+
try {
|
|
14218
|
+
const require2 = createRequire(import.meta.url);
|
|
14219
|
+
const pkgPath = require2.resolve("@nacos-group/cli/package.json");
|
|
14220
|
+
return path26.join(path26.dirname(pkgPath), "bin", "cli.js");
|
|
14221
|
+
} catch {
|
|
14222
|
+
return "nacos-cli";
|
|
14223
|
+
}
|
|
14224
|
+
}
|
|
14225
|
+
applySummary(results) {
|
|
14226
|
+
this.status.totalSkills = results.length;
|
|
14227
|
+
this.status.synced = results.filter((item) => item.status === "synced" || item.status === "removed").length;
|
|
14228
|
+
this.status.pending = results.filter((item) => item.status.startsWith("pending")).length;
|
|
14229
|
+
this.status.conflicts = results.filter((item) => item.status === "conflict").length;
|
|
14230
|
+
this.status.failed = results.filter((item) => item.status === "failed").length;
|
|
14231
|
+
}
|
|
14232
|
+
persistManagedState(skills) {
|
|
14233
|
+
try {
|
|
14234
|
+
fs27.mkdirSync(path26.dirname(this.statePath), { recursive: true });
|
|
14235
|
+
fs27.writeFileSync(this.statePath, JSON.stringify({
|
|
14236
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14237
|
+
skills: skills.map((item) => ({
|
|
14238
|
+
resourceId: item.resourceId,
|
|
14239
|
+
nacosSkillName: item.nacosSkillName,
|
|
14240
|
+
desiredLabel: item.desiredLabel,
|
|
14241
|
+
desiredVersionKey: item.desiredVersionKey,
|
|
14242
|
+
status: item.status
|
|
14243
|
+
}))
|
|
14244
|
+
}, null, 2));
|
|
14245
|
+
} catch (error) {
|
|
14246
|
+
this.logger.warn(`\u5199\u5165 Nacos \u8BA2\u9605\u72B6\u6001\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`);
|
|
14247
|
+
}
|
|
14248
|
+
}
|
|
14249
|
+
parseHost(raw) {
|
|
14250
|
+
try {
|
|
14251
|
+
const url = new URL(raw.includes("://") ? raw : `http://${raw}`);
|
|
14252
|
+
return {
|
|
14253
|
+
scheme: url.protocol.replace(":", "") || "http",
|
|
14254
|
+
host: url.hostname,
|
|
14255
|
+
port: url.port || (url.protocol === "https:" ? "443" : "8848")
|
|
14256
|
+
};
|
|
14257
|
+
} catch {
|
|
14258
|
+
return { scheme: "http", host: raw.replace(/^https?:\/\//, ""), port: "8848" };
|
|
14259
|
+
}
|
|
14260
|
+
}
|
|
14261
|
+
};
|
|
14262
|
+
|
|
13977
14263
|
// src/hook/worker/worker-command.ts
|
|
13978
14264
|
var HookWorkerCommand = class {
|
|
13979
14265
|
logger;
|
|
@@ -13982,11 +14268,21 @@ var HookWorkerCommand = class {
|
|
|
13982
14268
|
localBrowserWs = null;
|
|
13983
14269
|
reminderService = null;
|
|
13984
14270
|
ownerNotifyService = null;
|
|
14271
|
+
nacosSyncCoordinator = null;
|
|
13985
14272
|
heartbeatTimer = null;
|
|
13986
14273
|
stateManager = null;
|
|
14274
|
+
stopped = false;
|
|
14275
|
+
stoppedPromise;
|
|
14276
|
+
resolveStopped = () => void 0;
|
|
13987
14277
|
constructor(logger3, options = {}) {
|
|
13988
14278
|
this.logger = logger3;
|
|
13989
14279
|
this.options = options;
|
|
14280
|
+
this.stoppedPromise = new Promise((resolve3) => {
|
|
14281
|
+
this.resolveStopped = resolve3;
|
|
14282
|
+
});
|
|
14283
|
+
}
|
|
14284
|
+
waitUntilStopped() {
|
|
14285
|
+
return this.stoppedPromise;
|
|
13990
14286
|
}
|
|
13991
14287
|
async start() {
|
|
13992
14288
|
const existingPid = findRunningAiHookProcess(process10.pid);
|
|
@@ -14009,6 +14305,7 @@ var HookWorkerCommand = class {
|
|
|
14009
14305
|
});
|
|
14010
14306
|
const bindAllowedUserIds = resolveBindAllowedUserIds(config);
|
|
14011
14307
|
const contextConfig = resolveContextConfig(config);
|
|
14308
|
+
const nacosSyncConfig = resolveNacosSkillSyncConfig(config);
|
|
14012
14309
|
const opsUserName = resolveOpsUserName();
|
|
14013
14310
|
const larkClient = new lark3.Client({
|
|
14014
14311
|
appId: feishuConfig.appId,
|
|
@@ -14074,13 +14371,20 @@ var HookWorkerCommand = class {
|
|
|
14074
14371
|
config: this.options.runnerConfig || {}
|
|
14075
14372
|
});
|
|
14076
14373
|
this.logger.info(`\u5F15\u64CE\u5DF2\u521B\u5EFA: engine=${engine}, \u53EF\u7528\u5F15\u64CE=[${registry.list().join(", ")}]`);
|
|
14374
|
+
this.nacosSyncCoordinator = new NacosSubscriptionSyncCoordinator({
|
|
14375
|
+
logger: this.logger,
|
|
14376
|
+
workerId: ownerUserId || `worker-${process10.pid}`,
|
|
14377
|
+
config: nacosSyncConfig
|
|
14378
|
+
});
|
|
14077
14379
|
this.localBrowserWs = new LocalBrowserWsServer({
|
|
14078
14380
|
logger: this.logger,
|
|
14079
14381
|
workerId: ownerUserId || `worker-${process10.pid}`,
|
|
14080
14382
|
workerType: "tooling-cli",
|
|
14081
|
-
larkClient
|
|
14383
|
+
larkClient,
|
|
14384
|
+
getNacosSyncStatus: () => this.nacosSyncCoordinator?.getStatus() ?? null
|
|
14082
14385
|
});
|
|
14083
14386
|
await this.localBrowserWs.start();
|
|
14387
|
+
this.nacosSyncCoordinator.start();
|
|
14084
14388
|
const hostProfileService = new HostProfileService({
|
|
14085
14389
|
logger: this.logger,
|
|
14086
14390
|
ownerUserId,
|
|
@@ -14109,7 +14413,7 @@ var HookWorkerCommand = class {
|
|
|
14109
14413
|
const requesterPersonaService = new RequesterPersonaService({
|
|
14110
14414
|
logger: this.logger,
|
|
14111
14415
|
larkClient,
|
|
14112
|
-
rootDir: process10.env.HOOK_REQUESTER_PERSONA_DIR ||
|
|
14416
|
+
rootDir: process10.env.HOOK_REQUESTER_PERSONA_DIR || path27.join(os17.homedir(), "ops", "ai-hook", "persona")
|
|
14113
14417
|
});
|
|
14114
14418
|
const taskExecutor = new TaskExecutor({
|
|
14115
14419
|
logger: this.logger,
|
|
@@ -14166,17 +14470,19 @@ var HookWorkerCommand = class {
|
|
|
14166
14470
|
await this.relayClient.startAndWait();
|
|
14167
14471
|
await reminderService.start();
|
|
14168
14472
|
await this.ownerNotifyService.notifyOnline();
|
|
14169
|
-
|
|
14170
|
-
|
|
14171
|
-
|
|
14172
|
-
|
|
14173
|
-
|
|
14174
|
-
|
|
14175
|
-
|
|
14176
|
-
|
|
14177
|
-
|
|
14178
|
-
|
|
14179
|
-
|
|
14473
|
+
if (this.options.manageProcessSignals !== false) {
|
|
14474
|
+
const gracefulExit = async (signal) => {
|
|
14475
|
+
this.logger.info(`\u6536\u5230 ${signal}\uFF0C\u6B63\u5728\u505C\u6B62\u4ECE\u8282\u70B9...`);
|
|
14476
|
+
await this.stop(signal);
|
|
14477
|
+
process10.exit(0);
|
|
14478
|
+
};
|
|
14479
|
+
process10.on("SIGINT", () => {
|
|
14480
|
+
void gracefulExit("SIGINT");
|
|
14481
|
+
});
|
|
14482
|
+
process10.on("SIGTERM", () => {
|
|
14483
|
+
void gracefulExit("SIGTERM");
|
|
14484
|
+
});
|
|
14485
|
+
}
|
|
14180
14486
|
this.heartbeatTimer = setInterval(() => {
|
|
14181
14487
|
stateManager.updateHeartbeat();
|
|
14182
14488
|
}, HEARTBEAT_INTERVAL_MS);
|
|
@@ -14186,6 +14492,10 @@ var HookWorkerCommand = class {
|
|
|
14186
14492
|
}
|
|
14187
14493
|
/** 停止从节点 */
|
|
14188
14494
|
async stop(signal) {
|
|
14495
|
+
if (this.stopped) {
|
|
14496
|
+
return;
|
|
14497
|
+
}
|
|
14498
|
+
this.stopped = true;
|
|
14189
14499
|
if (this.heartbeatTimer) {
|
|
14190
14500
|
clearInterval(this.heartbeatTimer);
|
|
14191
14501
|
this.heartbeatTimer = null;
|
|
@@ -14194,6 +14504,10 @@ var HookWorkerCommand = class {
|
|
|
14194
14504
|
this.localBrowserWs.stop();
|
|
14195
14505
|
this.localBrowserWs = null;
|
|
14196
14506
|
}
|
|
14507
|
+
if (this.nacosSyncCoordinator) {
|
|
14508
|
+
await this.nacosSyncCoordinator.stop();
|
|
14509
|
+
this.nacosSyncCoordinator = null;
|
|
14510
|
+
}
|
|
14197
14511
|
if (this.reminderService) {
|
|
14198
14512
|
this.reminderService.stop();
|
|
14199
14513
|
this.reminderService = null;
|
|
@@ -14219,10 +14533,65 @@ var HookWorkerCommand = class {
|
|
|
14219
14533
|
slaveConnectionStatus: "offline"
|
|
14220
14534
|
});
|
|
14221
14535
|
}
|
|
14536
|
+
this.resolveStopped();
|
|
14222
14537
|
}
|
|
14223
14538
|
};
|
|
14224
14539
|
|
|
14225
|
-
// src/commands/hook/
|
|
14540
|
+
// src/commands/hook/worker-options.ts
|
|
14541
|
+
var WORKER_BOOLEAN_OPTIONS = /* @__PURE__ */ new Set([
|
|
14542
|
+
"--verbose"
|
|
14543
|
+
]);
|
|
14544
|
+
var WORKER_VALUE_OPTIONS = /* @__PURE__ */ new Set([
|
|
14545
|
+
"--master-host",
|
|
14546
|
+
"--master-port",
|
|
14547
|
+
"--shared-secret",
|
|
14548
|
+
"--claim-timeout-ms",
|
|
14549
|
+
"--connect-timeout-ms",
|
|
14550
|
+
"--model",
|
|
14551
|
+
"--fallback-model",
|
|
14552
|
+
"--permission-mode",
|
|
14553
|
+
"--max-budget-usd",
|
|
14554
|
+
"--settings",
|
|
14555
|
+
"--mcp-config",
|
|
14556
|
+
"--add-dir",
|
|
14557
|
+
"--system-prompt",
|
|
14558
|
+
"--append-system-prompt",
|
|
14559
|
+
"--agent",
|
|
14560
|
+
"--agents",
|
|
14561
|
+
"--tools",
|
|
14562
|
+
"--allowedTools",
|
|
14563
|
+
"--disallowedTools"
|
|
14564
|
+
]);
|
|
14565
|
+
function resolveWorkerPassthroughArgs(engine, commandName = "worker", rawArgs = process.argv.slice(2)) {
|
|
14566
|
+
const commandIndex = rawArgs.findIndex((item, index) => item === commandName && rawArgs[index - 1] === "hook");
|
|
14567
|
+
if (commandIndex < 0) {
|
|
14568
|
+
return [];
|
|
14569
|
+
}
|
|
14570
|
+
const tail = rawArgs.slice(commandIndex + 1);
|
|
14571
|
+
const args = tail[0] === commandName ? tail.slice(1) : tail;
|
|
14572
|
+
const normalizedEngine = String(engine || "codex").trim();
|
|
14573
|
+
const scanArgs = args[0] === normalizedEngine ? args.slice(1) : args;
|
|
14574
|
+
const passthroughArgs = [];
|
|
14575
|
+
for (let index = 0; index < scanArgs.length; index += 1) {
|
|
14576
|
+
const item = scanArgs[index];
|
|
14577
|
+
if (item === "--") {
|
|
14578
|
+
passthroughArgs.push(...scanArgs.slice(index + 1));
|
|
14579
|
+
break;
|
|
14580
|
+
}
|
|
14581
|
+
const key = item.includes("=") ? item.split("=")[0] : item;
|
|
14582
|
+
if (WORKER_BOOLEAN_OPTIONS.has(key)) {
|
|
14583
|
+
continue;
|
|
14584
|
+
}
|
|
14585
|
+
if (WORKER_VALUE_OPTIONS.has(key)) {
|
|
14586
|
+
if (!item.includes("=")) {
|
|
14587
|
+
index += 1;
|
|
14588
|
+
}
|
|
14589
|
+
continue;
|
|
14590
|
+
}
|
|
14591
|
+
passthroughArgs.push(item);
|
|
14592
|
+
}
|
|
14593
|
+
return passthroughArgs;
|
|
14594
|
+
}
|
|
14226
14595
|
function normalizeClaudeArgs(options) {
|
|
14227
14596
|
const args = [];
|
|
14228
14597
|
const pushPair = (flag, value) => {
|
|
@@ -14254,6 +14623,8 @@ function normalizeClaudeArgs(options) {
|
|
|
14254
14623
|
});
|
|
14255
14624
|
return args;
|
|
14256
14625
|
}
|
|
14626
|
+
|
|
14627
|
+
// src/commands/hook/hook-worker.ts
|
|
14257
14628
|
async function hookWorkerAction(engine, options) {
|
|
14258
14629
|
const logger3 = createLogger("worker", options.verbose === true);
|
|
14259
14630
|
const normalizedEngine = (engine || "codex").toLowerCase();
|
|
@@ -14263,10 +14634,12 @@ async function hookWorkerAction(engine, options) {
|
|
|
14263
14634
|
masterPort: parsePositiveInt(options.masterPort, 0) || void 0,
|
|
14264
14635
|
sharedSecret: options.sharedSecret,
|
|
14265
14636
|
connectTimeoutMs: parsePositiveInt(options.connectTimeoutMs, 0) || void 0,
|
|
14266
|
-
runnerConfig: normalizedEngine === "claude" ? { claudeArgs: normalizeClaudeArgs(options) } : {}
|
|
14637
|
+
runnerConfig: normalizedEngine === "claude" ? { claudeArgs: normalizeClaudeArgs(options) } : {},
|
|
14638
|
+
manageProcessSignals: true
|
|
14267
14639
|
});
|
|
14268
14640
|
try {
|
|
14269
14641
|
await command.start();
|
|
14642
|
+
await command.waitUntilStopped();
|
|
14270
14643
|
} catch (error) {
|
|
14271
14644
|
const msg = error instanceof Error ? error.message : String(error);
|
|
14272
14645
|
logger3.error(`\u4ECE\u8282\u70B9\u542F\u52A8\u5931\u8D25: ${msg}`);
|
|
@@ -14274,23 +14647,98 @@ async function hookWorkerAction(engine, options) {
|
|
|
14274
14647
|
}
|
|
14275
14648
|
}
|
|
14276
14649
|
|
|
14650
|
+
// src/commands/hook/hook-local.ts
|
|
14651
|
+
function resolveLocalWorkerMasterHost(masterHost) {
|
|
14652
|
+
const host = String(masterHost || "").trim();
|
|
14653
|
+
if (host === "0.0.0.0" || host === "::" || host === "[::]") {
|
|
14654
|
+
return "127.0.0.1";
|
|
14655
|
+
}
|
|
14656
|
+
return host;
|
|
14657
|
+
}
|
|
14658
|
+
function resolveLocalWorkerOverrides(runtime) {
|
|
14659
|
+
return {
|
|
14660
|
+
masterHost: resolveLocalWorkerMasterHost(runtime.masterHost),
|
|
14661
|
+
masterPort: runtime.masterPort,
|
|
14662
|
+
sharedSecret: runtime.sharedSecret
|
|
14663
|
+
};
|
|
14664
|
+
}
|
|
14665
|
+
async function hookLocalAction(engine, options) {
|
|
14666
|
+
const localLogger = createLogger("local", options.verbose === true);
|
|
14667
|
+
const masterLogger = createLogger("master");
|
|
14668
|
+
const workerLogger = createLogger("worker", options.verbose === true);
|
|
14669
|
+
const normalizedEngine = (engine || "codex").toLowerCase();
|
|
14670
|
+
const master = new HookMasterCommand({
|
|
14671
|
+
logger: masterLogger,
|
|
14672
|
+
masterHost: options.masterHost,
|
|
14673
|
+
masterPort: parsePositiveInt(options.masterPort, 0) || void 0,
|
|
14674
|
+
sharedSecret: options.sharedSecret,
|
|
14675
|
+
claimTimeoutMs: parsePositiveInt(options.claimTimeoutMs, 0) || void 0,
|
|
14676
|
+
manageProcessSignals: false
|
|
14677
|
+
});
|
|
14678
|
+
let worker = null;
|
|
14679
|
+
let stopping = false;
|
|
14680
|
+
const stopAll = async (signal) => {
|
|
14681
|
+
if (stopping) {
|
|
14682
|
+
return;
|
|
14683
|
+
}
|
|
14684
|
+
stopping = true;
|
|
14685
|
+
localLogger.info(`\u6536\u5230 ${signal}\uFF0C\u6B63\u5728\u505C\u6B62\u672C\u673A\u4E00\u4F53\u8282\u70B9...`);
|
|
14686
|
+
if (worker) {
|
|
14687
|
+
await worker.stop(signal);
|
|
14688
|
+
worker = null;
|
|
14689
|
+
}
|
|
14690
|
+
await master.stop(signal);
|
|
14691
|
+
};
|
|
14692
|
+
process.on("SIGINT", async () => {
|
|
14693
|
+
await stopAll("SIGINT");
|
|
14694
|
+
process.exit(0);
|
|
14695
|
+
});
|
|
14696
|
+
process.on("SIGTERM", async () => {
|
|
14697
|
+
await stopAll("SIGTERM");
|
|
14698
|
+
process.exit(0);
|
|
14699
|
+
});
|
|
14700
|
+
try {
|
|
14701
|
+
const runtime = await master.start();
|
|
14702
|
+
const workerOverrides = resolveLocalWorkerOverrides(runtime);
|
|
14703
|
+
worker = new HookWorkerCommand(workerLogger, {
|
|
14704
|
+
engine: normalizedEngine,
|
|
14705
|
+
masterHost: workerOverrides.masterHost,
|
|
14706
|
+
masterPort: workerOverrides.masterPort,
|
|
14707
|
+
sharedSecret: workerOverrides.sharedSecret,
|
|
14708
|
+
connectTimeoutMs: parsePositiveInt(options.connectTimeoutMs, 0) || void 0,
|
|
14709
|
+
runnerConfig: normalizedEngine === "claude" ? { claudeArgs: normalizeClaudeArgs(options) } : {},
|
|
14710
|
+
manageProcessSignals: false
|
|
14711
|
+
});
|
|
14712
|
+
await worker.start();
|
|
14713
|
+
localLogger.info(
|
|
14714
|
+
`\u672C\u673A\u4E00\u4F53\u8282\u70B9\u542F\u52A8\u5B8C\u6210 | engine=${normalizedEngine} | master=${workerOverrides.masterHost}:${workerOverrides.masterPort}`
|
|
14715
|
+
);
|
|
14716
|
+
await worker.waitUntilStopped();
|
|
14717
|
+
} catch (error) {
|
|
14718
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
14719
|
+
localLogger.error(`\u672C\u673A\u4E00\u4F53\u8282\u70B9\u542F\u52A8\u5931\u8D25: ${msg}`);
|
|
14720
|
+
await stopAll("startup_error");
|
|
14721
|
+
process.exit(1);
|
|
14722
|
+
}
|
|
14723
|
+
}
|
|
14724
|
+
|
|
14277
14725
|
// src/hook/init/hook-init-command.ts
|
|
14278
|
-
import
|
|
14279
|
-
import
|
|
14280
|
-
import
|
|
14726
|
+
import fs29 from "fs";
|
|
14727
|
+
import os18 from "os";
|
|
14728
|
+
import path28 from "path";
|
|
14281
14729
|
import process11 from "process";
|
|
14282
14730
|
import { createInterface as createInterface3 } from "readline/promises";
|
|
14283
14731
|
import chalk9 from "chalk";
|
|
14284
14732
|
|
|
14285
14733
|
// src/hook/init/legacy-ai-hook-migrator.ts
|
|
14286
|
-
import
|
|
14734
|
+
import fs28 from "fs";
|
|
14287
14735
|
function loadLegacyMigrationResult(logger3) {
|
|
14288
14736
|
const sourcePath = LEGACY_STATE_PATH;
|
|
14289
|
-
if (!
|
|
14737
|
+
if (!fs28.existsSync(sourcePath)) {
|
|
14290
14738
|
return { state: null, summary: null };
|
|
14291
14739
|
}
|
|
14292
14740
|
try {
|
|
14293
|
-
const parsed = parseJsonWithLineComments(
|
|
14741
|
+
const parsed = parseJsonWithLineComments(fs28.readFileSync(sourcePath, "utf-8"), sourcePath);
|
|
14294
14742
|
if (!parsed || typeof parsed !== "object") {
|
|
14295
14743
|
return { state: null, summary: null };
|
|
14296
14744
|
}
|
|
@@ -14318,6 +14766,7 @@ function countObjectKeys(value) {
|
|
|
14318
14766
|
|
|
14319
14767
|
// src/hook/init/hook-init-normalizer.ts
|
|
14320
14768
|
var DEFAULT_MASTER_HOST_ENV = "NIKOU_HOOK_MASTER_HOST";
|
|
14769
|
+
var LOCAL_MASTER_HOST = "127.0.0.1";
|
|
14321
14770
|
function resolveHookSection2(config) {
|
|
14322
14771
|
return config.hook ?? config.ai_hook ?? config.aiHook ?? {};
|
|
14323
14772
|
}
|
|
@@ -14377,6 +14826,15 @@ function resolveContextConfigFromHook(hook2) {
|
|
|
14377
14826
|
function resolveDefaultMasterHost(env = process.env) {
|
|
14378
14827
|
return String(env[DEFAULT_MASTER_HOST_ENV] || "").trim();
|
|
14379
14828
|
}
|
|
14829
|
+
function resolveHookInitDeploymentDefaults(config, env = process.env) {
|
|
14830
|
+
const configuredHost = resolveConfiguredMasterHost(config);
|
|
14831
|
+
const envHost = resolveDefaultMasterHost(env);
|
|
14832
|
+
const masterHost = configuredHost || envHost || LOCAL_MASTER_HOST;
|
|
14833
|
+
return {
|
|
14834
|
+
deploymentMode: isLocalHost(masterHost) ? "local" : "slave",
|
|
14835
|
+
masterHost
|
|
14836
|
+
};
|
|
14837
|
+
}
|
|
14380
14838
|
function normalizeHookInitConfig(config, defaults = {}) {
|
|
14381
14839
|
const hook2 = resolveHookSection2(config);
|
|
14382
14840
|
const appId = String(config.feishu?.app_id || config.feishu?.appId || config.feishu?.appid || "").trim();
|
|
@@ -14392,7 +14850,9 @@ function normalizeHookInitConfig(config, defaults = {}) {
|
|
|
14392
14850
|
if (!appSecret) missing.push("feishu.app_secret");
|
|
14393
14851
|
if (!masterHost) missing.push(`hook.master_host \u6216 ${DEFAULT_MASTER_HOST_ENV}`);
|
|
14394
14852
|
if (!sharedSecret) missing.push("hook.shared_secret");
|
|
14395
|
-
if (bindAllowedUserIds.length === 0)
|
|
14853
|
+
if (defaults.deploymentMode !== "slave" && bindAllowedUserIds.length === 0) {
|
|
14854
|
+
missing.push("hook.bind_allowed_user_ids");
|
|
14855
|
+
}
|
|
14396
14856
|
if (missing.length > 0) {
|
|
14397
14857
|
throw new Error(`\u521D\u59CB\u5316\u6240\u9700\u914D\u7F6E\u7F3A\u5931: ${missing.join(", ")}`);
|
|
14398
14858
|
}
|
|
@@ -14418,7 +14878,8 @@ function normalizeHookInitConfig(config, defaults = {}) {
|
|
|
14418
14878
|
// src/hook/init/hook-init-command.ts
|
|
14419
14879
|
var BOT_OPTIONS = [{ label: "\u59AE\u853B", value: "\u59AE\u853B" }];
|
|
14420
14880
|
var DEPLOYMENT_OPTIONS = [
|
|
14421
|
-
{ label: "\
|
|
14881
|
+
{ label: "\u672C\u673A\u4E00\u4F53", value: "local", description: "\u540C\u4E00\u53F0\u673A\u5668\u542F\u52A8\u4E3B\u8282\u70B9\u548C\u672C\u5730\u4ECE\u8282\u70B9" },
|
|
14882
|
+
{ label: "\u4ECE\u8282\u70B9", value: "slave", description: "\u8FDE\u63A5\u5DF2\u6709\u8FDC\u7AEF\u4E3B\u8282\u70B9" }
|
|
14422
14883
|
];
|
|
14423
14884
|
var HookInitCommand = class {
|
|
14424
14885
|
constructor(logger3) {
|
|
@@ -14432,22 +14893,32 @@ var HookInitCommand = class {
|
|
|
14432
14893
|
const existingAggregateConfig = this.readJson(DEFAULT_CONFIG_PATH);
|
|
14433
14894
|
const existingMasterConfig = this.readJson(MASTER_CONFIG_PATH);
|
|
14434
14895
|
const existingWorkerConfig = this.readJson(WORKER_CONFIG_PATH);
|
|
14435
|
-
const existingWorkerStatePath =
|
|
14896
|
+
const existingWorkerStatePath = path28.join(STATE_DIR, "worker.json");
|
|
14436
14897
|
const existingWorkerState = this.readJson(existingWorkerStatePath);
|
|
14437
14898
|
const rl = createInterface3({ input: process11.stdin, output: process11.stdout });
|
|
14438
14899
|
try {
|
|
14439
14900
|
this.printEnvironmentSummary(source.path, { existingAggregateConfig, existingMasterConfig, existingWorkerConfig }, migration.summary);
|
|
14440
14901
|
const botName = await this.askChoice(rl, "\u7B2C\u4E00\u6B65\uFF1A\u9009\u62E9\u98DE\u4E66\u673A\u5668\u4EBA", BOT_OPTIONS, 0);
|
|
14441
|
-
|
|
14442
|
-
const
|
|
14902
|
+
const deploymentDefaults = resolveHookInitDeploymentDefaults(source.config);
|
|
14903
|
+
const deploymentDefaultIndex = DEPLOYMENT_OPTIONS.findIndex((item) => item.value === deploymentDefaults.deploymentMode);
|
|
14904
|
+
const deploymentMode = await this.askChoice(
|
|
14905
|
+
rl,
|
|
14906
|
+
"\u7B2C\u4E8C\u6B65\uFF1A\u9009\u62E9\u90E8\u7F72\u65B9\u5F0F",
|
|
14907
|
+
DEPLOYMENT_OPTIONS,
|
|
14908
|
+
deploymentDefaultIndex >= 0 ? deploymentDefaultIndex : 0
|
|
14909
|
+
);
|
|
14910
|
+
const defaultMasterHost = deploymentMode === "local" ? LOCAL_MASTER_HOST : deploymentDefaults.masterHost;
|
|
14911
|
+
const masterHost = await this.askMasterHost(rl, source.config, defaultMasterHost);
|
|
14443
14912
|
const normalized = this.normalizeSourceConfig(
|
|
14444
|
-
mergeHookInitMasterHost(source.config, masterHost)
|
|
14913
|
+
mergeHookInitMasterHost(source.config, masterHost),
|
|
14914
|
+
deploymentMode
|
|
14445
14915
|
);
|
|
14446
14916
|
const nextMasterConfig = this.buildMasterConfigPayload(normalized, botName);
|
|
14447
14917
|
const nextWorkerConfig = this.buildWorkerConfigPayload(normalized, botName);
|
|
14448
14918
|
const nextWorkerState = this.buildSeedWorkerState({
|
|
14449
14919
|
botName,
|
|
14450
14920
|
configPath: WORKER_CONFIG_PATH,
|
|
14921
|
+
deploymentMode,
|
|
14451
14922
|
normalized,
|
|
14452
14923
|
existingWorkerState,
|
|
14453
14924
|
legacyState: migration.state
|
|
@@ -14456,6 +14927,7 @@ var HookInitCommand = class {
|
|
|
14456
14927
|
nextMasterConfig,
|
|
14457
14928
|
nextWorkerConfig,
|
|
14458
14929
|
nextWorkerState,
|
|
14930
|
+
deploymentMode,
|
|
14459
14931
|
sourcePath: source.path,
|
|
14460
14932
|
migrationSummary: migration.summary,
|
|
14461
14933
|
existingAggregateConfig,
|
|
@@ -14480,7 +14952,10 @@ var HookInitCommand = class {
|
|
|
14480
14952
|
console.log(chalk9.dim(`\u4E3B\u8282\u70B9\u914D\u7F6E: ${MASTER_CONFIG_PATH}`));
|
|
14481
14953
|
console.log(chalk9.dim(`\u4ECE\u8282\u70B9\u914D\u7F6E: ${WORKER_CONFIG_PATH}`));
|
|
14482
14954
|
console.log(chalk9.dim(`\u72B6\u6001\u6587\u4EF6: ${existingWorkerStatePath}`));
|
|
14483
|
-
|
|
14955
|
+
const nextCommand = deploymentMode === "local" ? "ai-hook local" : "nikou-cli hook worker codex";
|
|
14956
|
+
console.log(chalk9.dim(`
|
|
14957
|
+
\u4E0B\u4E00\u6B65: ${nextCommand}
|
|
14958
|
+
`));
|
|
14484
14959
|
} finally {
|
|
14485
14960
|
rl.close();
|
|
14486
14961
|
}
|
|
@@ -14493,11 +14968,11 @@ var HookInitCommand = class {
|
|
|
14493
14968
|
resolveSourceConfig() {
|
|
14494
14969
|
const candidates = [LEGACY_CONFIG_PATH, DEFAULT_CONFIG_PATH, MASTER_CONFIG_PATH, WORKER_CONFIG_PATH];
|
|
14495
14970
|
for (const candidate of candidates) {
|
|
14496
|
-
if (!
|
|
14971
|
+
if (!fs29.existsSync(candidate)) {
|
|
14497
14972
|
continue;
|
|
14498
14973
|
}
|
|
14499
14974
|
try {
|
|
14500
|
-
const parsed = parseJsonWithLineComments(
|
|
14975
|
+
const parsed = parseJsonWithLineComments(fs29.readFileSync(candidate, "utf-8"), candidate);
|
|
14501
14976
|
if (parsed && typeof parsed === "object") {
|
|
14502
14977
|
return { config: parsed, path: candidate };
|
|
14503
14978
|
}
|
|
@@ -14508,9 +14983,10 @@ var HookInitCommand = class {
|
|
|
14508
14983
|
}
|
|
14509
14984
|
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`);
|
|
14510
14985
|
}
|
|
14511
|
-
normalizeSourceConfig(config) {
|
|
14986
|
+
normalizeSourceConfig(config, deploymentMode) {
|
|
14512
14987
|
return normalizeHookInitConfig(config, {
|
|
14513
|
-
defaultMasterHost: resolveDefaultMasterHost()
|
|
14988
|
+
defaultMasterHost: resolveDefaultMasterHost(),
|
|
14989
|
+
deploymentMode
|
|
14514
14990
|
});
|
|
14515
14991
|
}
|
|
14516
14992
|
printEnvironmentSummary(sourcePath, existingConfig, migrationSummary) {
|
|
@@ -14559,8 +15035,8 @@ var HookInitCommand = class {
|
|
|
14559
15035
|
console.log(chalk9.yellow("\u8BF7\u8F93\u5165 y \u6216 n\u3002\n"));
|
|
14560
15036
|
}
|
|
14561
15037
|
}
|
|
14562
|
-
async askMasterHost(rl, config) {
|
|
14563
|
-
const defaultHost = resolveConfiguredMasterHost(config) || resolveDefaultMasterHost();
|
|
15038
|
+
async askMasterHost(rl, config, fallbackHost) {
|
|
15039
|
+
const defaultHost = fallbackHost || resolveConfiguredMasterHost(config) || resolveDefaultMasterHost();
|
|
14564
15040
|
while (true) {
|
|
14565
15041
|
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
15042
|
const answer = (await rl.question(chalk9.dim(label))).trim();
|
|
@@ -14650,7 +15126,7 @@ var HookInitCommand = class {
|
|
|
14650
15126
|
contextConfig: params.normalized.contextConfig,
|
|
14651
15127
|
slaveConnectionStatus: "offline",
|
|
14652
15128
|
status: "stopped",
|
|
14653
|
-
lastCommand: "nikou-cli hook worker codex"
|
|
15129
|
+
lastCommand: params.deploymentMode === "local" ? "ai-hook local" : "nikou-cli hook worker codex"
|
|
14654
15130
|
});
|
|
14655
15131
|
const mergedState = mergeWorkerState(
|
|
14656
15132
|
initialState,
|
|
@@ -14661,7 +15137,7 @@ var HookInitCommand = class {
|
|
|
14661
15137
|
mergedState.initializedAt = now;
|
|
14662
15138
|
mergedState.initMode = "interactive";
|
|
14663
15139
|
mergedState.migration = params.legacyState ? {
|
|
14664
|
-
source:
|
|
15140
|
+
source: path28.join(os18.homedir(), "ops", "ai-hook.json"),
|
|
14665
15141
|
migratedAt: now,
|
|
14666
15142
|
legacyBindingsCount: countObjectKeys2(params.legacyState.bindings),
|
|
14667
15143
|
legacyChatIndexCount: countObjectKeys2(params.legacyState.chatIndex),
|
|
@@ -14682,10 +15158,10 @@ var HookInitCommand = class {
|
|
|
14682
15158
|
console.log(chalk9.dim(`- \u4ECE\u8282\u70B9\u914D\u7F6E: ${WORKER_CONFIG_PATH}`));
|
|
14683
15159
|
console.log(chalk9.dim(`- \u98DE\u4E66 AppId: ${String(params.nextMasterConfig.feishu?.app_id || "")}`));
|
|
14684
15160
|
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`));
|
|
15161
|
+
console.log(chalk9.dim(`- \u90E8\u7F72\u65B9\u5F0F: ${params.deploymentMode === "local" ? "\u672C\u673A\u4E00\u4F53" : "\u4ECE\u8282\u70B9"}`));
|
|
14686
15162
|
console.log(chalk9.dim(`- \u4E3B\u8282\u70B9: ${String(masterHook.master_host || "")}:${String(masterHook.master_port || "")}`));
|
|
14687
15163
|
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: ${
|
|
15164
|
+
console.log(chalk9.dim(`- \u79CD\u5B50\u72B6\u6001: ${path28.join(STATE_DIR, "worker.json")}`));
|
|
14689
15165
|
console.log(chalk9.dim(`- \u8FC1\u79FB\u540E\u7FA4\u7ED1\u5B9A\u6570: ${Object.keys(params.nextWorkerState.bindings || {}).length}`));
|
|
14690
15166
|
console.log(chalk9.dim(`- \u8FC1\u79FB\u540E chatIndex \u6570: ${Object.keys(params.nextWorkerState.chatIndex || {}).length}`));
|
|
14691
15167
|
console.log(chalk9.dim(`- \u8FC1\u79FB\u540E P2P \u4F1A\u8BDD\u6570: ${countObjectKeys2(params.nextWorkerState.p2pSessions)}`));
|
|
@@ -14711,28 +15187,28 @@ var HookInitCommand = class {
|
|
|
14711
15187
|
});
|
|
14712
15188
|
}
|
|
14713
15189
|
backupIfNeeded(targetPath, prefix) {
|
|
14714
|
-
if (!
|
|
15190
|
+
if (!fs29.existsSync(targetPath)) {
|
|
14715
15191
|
return;
|
|
14716
15192
|
}
|
|
14717
|
-
const backupDir =
|
|
15193
|
+
const backupDir = path28.join(STATE_DIR, "backups");
|
|
14718
15194
|
ensureDirExists(backupDir);
|
|
14719
15195
|
const fileName = `${prefix}.${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.json`;
|
|
14720
|
-
|
|
15196
|
+
fs29.copyFileSync(targetPath, path28.join(backupDir, fileName));
|
|
14721
15197
|
}
|
|
14722
15198
|
readJson(filePath) {
|
|
14723
|
-
if (!
|
|
15199
|
+
if (!fs29.existsSync(filePath)) {
|
|
14724
15200
|
return null;
|
|
14725
15201
|
}
|
|
14726
15202
|
try {
|
|
14727
|
-
const parsed = parseJsonWithLineComments(
|
|
15203
|
+
const parsed = parseJsonWithLineComments(fs29.readFileSync(filePath, "utf-8"), filePath);
|
|
14728
15204
|
return parsed && typeof parsed === "object" ? parsed : null;
|
|
14729
15205
|
} catch {
|
|
14730
15206
|
return null;
|
|
14731
15207
|
}
|
|
14732
15208
|
}
|
|
14733
15209
|
writeJson(filePath, value) {
|
|
14734
|
-
ensureDirExists(
|
|
14735
|
-
|
|
15210
|
+
ensureDirExists(path28.dirname(filePath));
|
|
15211
|
+
fs29.writeFileSync(filePath, JSON.stringify(value, null, 2));
|
|
14736
15212
|
}
|
|
14737
15213
|
};
|
|
14738
15214
|
function countObjectKeys2(value) {
|
|
@@ -14756,12 +15232,12 @@ async function hookInitAction() {
|
|
|
14756
15232
|
}
|
|
14757
15233
|
|
|
14758
15234
|
// src/commands/hook/hook-log.ts
|
|
14759
|
-
import
|
|
15235
|
+
import fs31 from "fs";
|
|
14760
15236
|
import chalk10 from "chalk";
|
|
14761
15237
|
|
|
14762
15238
|
// src/hook/log-searcher.ts
|
|
14763
|
-
import
|
|
14764
|
-
import
|
|
15239
|
+
import fs30 from "fs";
|
|
15240
|
+
import path29 from "path";
|
|
14765
15241
|
function normalizeString(value) {
|
|
14766
15242
|
if (value === null || value === void 0) {
|
|
14767
15243
|
return "";
|
|
@@ -14799,8 +15275,8 @@ var HookLogSearcher = class {
|
|
|
14799
15275
|
logPaths;
|
|
14800
15276
|
constructor(options = {}) {
|
|
14801
15277
|
this.logPaths = {
|
|
14802
|
-
master: options.masterPath ||
|
|
14803
|
-
worker: options.workerPath ||
|
|
15278
|
+
master: options.masterPath || path29.join(LOGS_DIR, "master", "ai-hook-master.service.log"),
|
|
15279
|
+
worker: options.workerPath || path29.join(LOGS_DIR, "worker", "ai-hook-worker.service.log")
|
|
14804
15280
|
};
|
|
14805
15281
|
}
|
|
14806
15282
|
resolveScope(scope) {
|
|
@@ -14863,7 +15339,7 @@ var HookLogSearcher = class {
|
|
|
14863
15339
|
}
|
|
14864
15340
|
searchSingleFile(role, query = {}, options = {}) {
|
|
14865
15341
|
const filePath = this.logPaths[role];
|
|
14866
|
-
if (!filePath || !
|
|
15342
|
+
if (!filePath || !fs30.existsSync(filePath)) {
|
|
14867
15343
|
return {
|
|
14868
15344
|
role,
|
|
14869
15345
|
path: filePath,
|
|
@@ -14874,7 +15350,7 @@ var HookLogSearcher = class {
|
|
|
14874
15350
|
lines: []
|
|
14875
15351
|
};
|
|
14876
15352
|
}
|
|
14877
|
-
const raw =
|
|
15353
|
+
const raw = fs30.readFileSync(filePath, "utf8");
|
|
14878
15354
|
const lines = raw.split(/\r?\n/);
|
|
14879
15355
|
if (lines.length > 0 && lines[lines.length - 1] === "") {
|
|
14880
15356
|
lines.pop();
|
|
@@ -14992,7 +15468,7 @@ function buildFollowState(file) {
|
|
|
14992
15468
|
return {
|
|
14993
15469
|
role: file.role,
|
|
14994
15470
|
path: file.path,
|
|
14995
|
-
offset:
|
|
15471
|
+
offset: fs31.existsSync(file.path) ? fs31.statSync(file.path).size : 0,
|
|
14996
15472
|
remainder: ""
|
|
14997
15473
|
};
|
|
14998
15474
|
}
|
|
@@ -15019,10 +15495,10 @@ function flushChunk(state, chunk, queryText) {
|
|
|
15019
15495
|
output.forEach((line) => console.log(line));
|
|
15020
15496
|
}
|
|
15021
15497
|
function readAppendedChunk(state, queryText) {
|
|
15022
|
-
if (!
|
|
15498
|
+
if (!fs31.existsSync(state.path)) {
|
|
15023
15499
|
return;
|
|
15024
15500
|
}
|
|
15025
|
-
const stat =
|
|
15501
|
+
const stat = fs31.statSync(state.path);
|
|
15026
15502
|
if (stat.size < state.offset) {
|
|
15027
15503
|
state.offset = 0;
|
|
15028
15504
|
state.remainder = "";
|
|
@@ -15030,15 +15506,15 @@ function readAppendedChunk(state, queryText) {
|
|
|
15030
15506
|
if (stat.size === state.offset) {
|
|
15031
15507
|
return;
|
|
15032
15508
|
}
|
|
15033
|
-
const fd =
|
|
15509
|
+
const fd = fs31.openSync(state.path, "r");
|
|
15034
15510
|
try {
|
|
15035
15511
|
const length = stat.size - state.offset;
|
|
15036
15512
|
const buffer = Buffer.alloc(length);
|
|
15037
|
-
|
|
15513
|
+
fs31.readSync(fd, buffer, 0, length, state.offset);
|
|
15038
15514
|
state.offset = stat.size;
|
|
15039
15515
|
flushChunk(state, buffer.toString("utf8"), queryText);
|
|
15040
15516
|
} finally {
|
|
15041
|
-
|
|
15517
|
+
fs31.closeSync(fd);
|
|
15042
15518
|
}
|
|
15043
15519
|
}
|
|
15044
15520
|
async function followLogs(queryText, options = {}) {
|
|
@@ -15079,60 +15555,6 @@ async function hookLogAction(query = "", options = {}) {
|
|
|
15079
15555
|
|
|
15080
15556
|
// src/index.ts
|
|
15081
15557
|
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
15558
|
var program = new Command();
|
|
15137
15559
|
program.name("nikou-cli").description("CLI to install and manage Agent Skills from GitHub repos").version("0.1.0");
|
|
15138
15560
|
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 +15583,23 @@ mcp.command("search").argument("<keyword>", "Search keyword").description("Searc
|
|
|
15161
15583
|
await mcpSearchCommand(keyword, options);
|
|
15162
15584
|
});
|
|
15163
15585
|
var hook = program.command("hook").description("\u4E3B\u4ECE\u8282\u70B9\u4EFB\u52A1\u5206\u53D1\u4E0E\u6267\u884C\uFF08\u98DE\u4E66\u96C6\u6210\uFF09");
|
|
15586
|
+
function addWorkerRuntimeOptions(command) {
|
|
15587
|
+
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");
|
|
15588
|
+
}
|
|
15164
15589
|
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
15590
|
await hookMasterAction(options);
|
|
15166
15591
|
});
|
|
15167
15592
|
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
15593
|
await hookInitAction();
|
|
15169
15594
|
});
|
|
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);
|
|
15595
|
+
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) => {
|
|
15596
|
+
const passthroughArgs = resolveWorkerPassthroughArgs(engine, "worker");
|
|
15172
15597
|
await hookWorkerAction(engine, { ...options, passthroughArgs });
|
|
15173
15598
|
});
|
|
15599
|
+
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) => {
|
|
15600
|
+
const passthroughArgs = resolveWorkerPassthroughArgs(engine, "local");
|
|
15601
|
+
await hookLocalAction(engine, { ...options, passthroughArgs });
|
|
15602
|
+
});
|
|
15174
15603
|
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
15604
|
await hookLogAction(query, options);
|
|
15176
15605
|
});
|