engine7 7.1.58 → 7.1.60

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/dist/cli.mjs CHANGED
@@ -9422,13 +9422,17 @@ function isDestructiveCommand(command) {
9422
9422
  function sanitizeEnv(env) {
9423
9423
  const result = {};
9424
9424
  for (const [k, v] of Object.entries(env)) {
9425
+ if (ENV_ALLOW_KEYS.includes(k)) {
9426
+ result[k] = v;
9427
+ continue;
9428
+ }
9425
9429
  if (!BLOCKED_ENV_KEYS.some((b) => k.toUpperCase().includes(b))) {
9426
9430
  result[k] = v;
9427
9431
  }
9428
9432
  }
9429
9433
  return result;
9430
9434
  }
9431
- var DANGEROUS_COMMANDS, DESTRUCTIVE_PATTERNS, BLOCKED_ENV_KEYS;
9435
+ var DANGEROUS_COMMANDS, DESTRUCTIVE_PATTERNS, BLOCKED_ENV_KEYS, ENV_ALLOW_KEYS;
9432
9436
  var init_bashSecurity = __esm({
9433
9437
  "src/tools/BashTool/bashSecurity.ts"() {
9434
9438
  "use strict";
@@ -9479,6 +9483,7 @@ var init_bashSecurity = __esm({
9479
9483
  "PASSWORD",
9480
9484
  "PRIVATE_KEY"
9481
9485
  ];
9486
+ ENV_ALLOW_KEYS = ["MULTICA_TOKEN"];
9482
9487
  }
9483
9488
  });
9484
9489
 
@@ -12267,8 +12272,14 @@ var init_my_eyes = __esm({
12267
12272
  return { content: "Error: my_eyes \u672A\u914D\u7F6E\u3002\u8BF7\u5728 config.tools.my_eyes.model \u8BBE\u7F6E\uFF08\u683C\u5F0F\uFF1Aprovider/model\uFF09\u3002", isError: true };
12268
12273
  }
12269
12274
  const slashIdx = modelRef.indexOf("/");
12275
+ const providerId = modelRef.slice(0, slashIdx);
12270
12276
  const modelId = modelRef.slice(slashIdx + 1);
12271
- const provider = ctx.provider;
12277
+ const providerCfg = (liveConfig.get("providers") || {})[providerId];
12278
+ if (!providerCfg) {
12279
+ return { content: `Error: tools.my_eyes.model \u7684 provider "${providerId}" \u4E0D\u5B58\u5728\u4E8E providers \u914D\u7F6E\u3002\u68C0\u67E5 config \u91CC models.providers.${providerId}\u3002`, isError: true };
12280
+ }
12281
+ const { createProvider: createProvider2 } = await Promise.resolve().then(() => (init_provider_factory(), provider_factory_exports));
12282
+ const provider = createProvider2(providerCfg);
12272
12283
  if (!provider?.streamChat) {
12273
12284
  return { content: "Error: provider \u4E0D\u53EF\u7528\u3002", isError: true };
12274
12285
  }
@@ -12776,6 +12787,115 @@ async function wavToOggOpus(wavPath) {
12776
12787
  fs18.unlinkSync(wavPath);
12777
12788
  return oggPath;
12778
12789
  }
12790
+ async function sendVoiceToMulticaIssue(text, issueId, opts) {
12791
+ const vc = liveConfig.get("tools.my_voice");
12792
+ let audioPath = "";
12793
+ let actualEngine = opts.engine || vc?.provider || "edge";
12794
+ try {
12795
+ if (actualEngine === "qwen3-3060" && vc?.url) {
12796
+ try {
12797
+ const { oggPath } = await ttsQwen3Opus(text, { url: vc.url, voice: vc.voice, lang: vc.lang });
12798
+ audioPath = oggPath;
12799
+ } catch (e) {
12800
+ console.warn(`[my-voice:multaca] qwen3 opus failed (${e.message}), trying PCM`);
12801
+ const pcmChunks = [];
12802
+ await ttsQwen3Local(text, { url: vc.url, voice: vc.voice, lang: vc.lang }, (pcm2) => pcmChunks.push(pcm2));
12803
+ const pcm = Buffer.concat(pcmChunks);
12804
+ fs18.mkdirSync(VOICE_DIR, { recursive: true });
12805
+ const wavPath = path19.join(VOICE_DIR, `tts_mc_${Date.now()}.wav`);
12806
+ const header = Buffer.alloc(44);
12807
+ header.write("RIFF", 0);
12808
+ header.writeUInt32LE(36 + pcm.length, 4);
12809
+ header.write("WAVE", 8);
12810
+ header.write("fmt ", 12);
12811
+ header.writeUInt32LE(16, 16);
12812
+ header.writeUInt16LE(1, 20);
12813
+ header.writeUInt16LE(1, 22);
12814
+ header.writeUInt32LE(24e3, 24);
12815
+ header.writeUInt32LE(48e3, 28);
12816
+ header.writeUInt16LE(2, 32);
12817
+ header.writeUInt16LE(16, 34);
12818
+ header.write("data", 36);
12819
+ header.writeUInt32LE(pcm.length, 40);
12820
+ fs18.writeFileSync(wavPath, Buffer.concat([header, pcm]));
12821
+ audioPath = wavPath;
12822
+ }
12823
+ } else if (actualEngine === "cosyvoice" && vc?.apiKey) {
12824
+ audioPath = await ttsCosyvoice(text, vc.apiKey, vc.model || "cosyvoice-v1", vc.voice, vc.workspaceId, vc.instruction);
12825
+ } else if (actualEngine === "gptsovits") {
12826
+ audioPath = await ttsGptsovits(text);
12827
+ } else {
12828
+ audioPath = await ttsEdge(text);
12829
+ actualEngine = "edge";
12830
+ }
12831
+ } catch (e) {
12832
+ return { content: `\u8BED\u97F3\u751F\u6210\u5931\u8D25\uFF08headless\u2192multaca\uFF09\uFF1A${e.message}\u3002\u8BF7\u7528\u6587\u5B57\u56DE\u590D\u4EE3\u66FF\u3002`, isError: true };
12833
+ }
12834
+ if (!audioPath || !fs18.existsSync(audioPath)) {
12835
+ return { content: "\u8BED\u97F3\u751F\u6210\u5931\u8D25\uFF08headless\u2192multaca\uFF09\uFF1ATTS \u672A\u4EA7\u51FA\u6587\u4EF6\u3002\u8BF7\u7528\u6587\u5B57\u56DE\u590D\u4EE3\u66FF\u3002", isError: true };
12836
+ }
12837
+ if (audioPath.endsWith(".wav")) {
12838
+ try {
12839
+ audioPath = await wavToOggOpus(audioPath);
12840
+ } catch (e) {
12841
+ console.warn(`[my-voice:multaca] opus encode failed (${e.message}), attaching wav`);
12842
+ }
12843
+ }
12844
+ const ext = path19.extname(audioPath).toLowerCase();
12845
+ const sizeKB = fs18.statSync(audioPath).size / 1024;
12846
+ const voiceFile = `voice_${Date.now()}${ext}`;
12847
+ const cwdCopy = path19.join(process.cwd(), voiceFile);
12848
+ try {
12849
+ fs18.copyFileSync(audioPath, cwdCopy);
12850
+ } catch (e) {
12851
+ try {
12852
+ fs18.unlinkSync(audioPath);
12853
+ } catch {
12854
+ }
12855
+ return { content: `\u8BED\u97F3\u6302\u8F7D\u5931\u8D25\uFF08\u62F7\u8D1D\u5230\u5DE5\u4F5C\u76EE\u5F55\uFF09\uFF1A${e.message}`, isError: true };
12856
+ }
12857
+ try {
12858
+ fs18.unlinkSync(audioPath);
12859
+ } catch {
12860
+ }
12861
+ const content = opts.caption || `\u{1F399}\uFE0F \u8BED\u97F3\u6D88\u606F\uFF08${text.length} \u5B57\uFF09`;
12862
+ try {
12863
+ const { execFile: execFile3 } = await import("node:child_process");
12864
+ const { promisify: promisify3 } = await import("node:util");
12865
+ const execFileA = promisify3(execFile3);
12866
+ const { stdout } = await execFileA("multica", [
12867
+ "issue",
12868
+ "comment",
12869
+ "add",
12870
+ issueId,
12871
+ "--content",
12872
+ content,
12873
+ "--attachment",
12874
+ voiceFile,
12875
+ "--output",
12876
+ "json"
12877
+ ], { timeout: 6e4 });
12878
+ let ok = false;
12879
+ try {
12880
+ const parsed = JSON.parse(stdout);
12881
+ ok = !!(parsed?.comment_id || parsed?.id || parsed?.attachments && parsed.attachments.length > 0);
12882
+ } catch {
12883
+ ok = stdout.includes("Comment added");
12884
+ }
12885
+ if (!ok) throw new Error(`unexpected CLI output: ${String(stdout).slice(0, 200)}`);
12886
+ try {
12887
+ fs18.unlinkSync(cwdCopy);
12888
+ } catch {
12889
+ }
12890
+ return { content: `Voice sent to multaca issue ${issueId}! (${actualEngine}, ${sizeKB.toFixed(0)}KB, \u9644\u4EF6\u5DF2\u6302\u5230\u8BC4\u8BBA\u2014\u2014\u5728 multaca \u5BA2\u6237\u7AEF\u64AD\u653E)` };
12891
+ } catch (e) {
12892
+ try {
12893
+ fs18.unlinkSync(cwdCopy);
12894
+ } catch {
12895
+ }
12896
+ return { content: `\u8BED\u97F3\u6302\u5230 multaca issue \u5931\u8D25\uFF1A${e.message}\u3002\u8BF7\u7528\u6587\u5B57\u56DE\u590D\u4EE3\u66FF\u3002`, isError: true };
12897
+ }
12898
+ }
12779
12899
  var execFileAsync, VOICE_DIR, _pyCache, GPTSOVITS_API, GPTSOVITS_REF_WAV, GPTSOVITS_REF_TEXT, GPTSOVITS_REF_LANG, EDGE_VOICE;
12780
12900
  var init_my_voice = __esm({
12781
12901
  "src/tools/my-voice.ts"() {
@@ -12801,7 +12921,8 @@ var init_my_voice = __esm({
12801
12921
  text: { type: "string", description: "What to say (Chinese text)." },
12802
12922
  engine: { type: "string", enum: ["cosyvoice", "gptsovits", "qwen3-3060", "edge"], description: "TTS engine. cosyvoice = \u767E\u70BCAPI (default if configured), gptsovits = local voice clone, qwen3-3060 = \u672C\u5730 GGML Q8_0 (3060), edge = backup." },
12803
12923
  channel: { type: "string", enum: ["weixin", "feishu", "discord"], description: "Target channel. Default: current channel." },
12804
- to: { type: "string", description: "Recipient ID. \u5FAE\u4FE1\u683C\u5F0F o\u5F00\u5934@im.wechat\u7ED3\u5C3E\uFF0C\u98DE\u4E66\u683C\u5F0F ou_\u5F00\u5934 open_id\u3002\u4E0D\u786E\u5B9A\u5C31\u5148 read prompts/contacts.md \u67E5\u6536\u4EF6\u4EBA ID\u3002" },
12924
+ to: { type: "string", description: "Recipient ID. \u5FAE\u4FE1\u683C\u5F0F o\u5F00\u5934@im.wechat\u7ED3\u5C3E\uFF0C\u98DE\u4E66\u683C\u5F0F ou_\u5F00\u5934 open_id\u3002\u4E0D\u786E\u5B9A\u5C31\u5148 read prompts/contacts.md \u67E5\u6536\u4EF6\u4EBA ID\u3002multaca \u4EFB\u52A1\u91CC\u4E0D\u9700\u8981\u586B to\u2014\u2014\u8BED\u97F3\u4F1A\u6302\u5230\u5F53\u524D issue \u8BC4\u8BBA\uFF0C\u586B issueId \u6307\u5B9A\u76EE\u6807 issue\u3002" },
12925
+ issueId: { type: "string", description: 'multaca headless \u4E13\u7528\uFF1A\u76EE\u6807 issue ID\uFF08\u4EFB\u52A1 prompt \u91CC\u7684 "Your assigned issue ID"\uFF09\u3002\u666E\u901A\u98DE\u4E66/\u5FAE\u4FE1\u573A\u666F\u4E0D\u8981\u586B\u3002' },
12805
12926
  caption: { type: "string", description: "Optional text to accompany the voice message." }
12806
12927
  },
12807
12928
  required: ["text"]
@@ -12812,7 +12933,17 @@ var init_my_voice = __esm({
12812
12933
  const requestedEngine = args.engine || "";
12813
12934
  const caption = args.caption || "";
12814
12935
  const mgr = ctx.channelManager;
12815
- if (!mgr) return { content: "\u53D1\u9001\u5931\u8D25: \u6CA1\u6709 ChannelManager", isError: true };
12936
+ if (!mgr) {
12937
+ const multicaTaskId = process.env.MULTICA_TASK_ID || "";
12938
+ const issueId = args.issueId || multicaTaskId;
12939
+ if (multicaTaskId && issueId) {
12940
+ return await sendVoiceToMulticaIssue(text, issueId, { engine: requestedEngine, caption });
12941
+ }
12942
+ return {
12943
+ content: "\u8BED\u97F3\u672A\u53D1\u9001\uFF1A\u5F53\u524D\u662F\u65E0\u6E20\u9053\u73AF\u5883\uFF08headless/CLI\uFF09\uFF0C\u4E14\u6CA1\u6709 multaca \u4EFB\u52A1\u4E0A\u4E0B\u6587\uFF08MULTICA_TASK_ID\uFF09\u6216 issueId\u3002\u6CA1\u6709\u53EF\u7528\u7684\u53D1\u9001\u51FA\u53E3\uFF0C\u8BF7\u7528\u6587\u5B57\u56DE\u590D\u4EE3\u66FF\u3002",
12944
+ isError: true
12945
+ };
12946
+ }
12816
12947
  const resolvedChannelRaw = args.channel || (ctx.channel === "deskBuddy" ? "feishu" : ctx.channel) || "feishu";
12817
12948
  const resolvedChannel = resolvedChannelRaw === "weixin" ? "wechat" : resolvedChannelRaw;
12818
12949
  let target = args.to || ctx.channelTarget || ctx.from;
@@ -19561,6 +19692,7 @@ function parseCcRunArgs(argv) {
19561
19692
  verbose: false,
19562
19693
  sessionId: "",
19563
19694
  maxTurns: void 0,
19695
+ noRecall: false,
19564
19696
  stateDir: "",
19565
19697
  configName: "",
19566
19698
  agentName: ""
@@ -19595,6 +19727,8 @@ function parseCcRunArgs(argv) {
19595
19727
  args.sessionId = takeValue();
19596
19728
  } else if (a === "--max-turns") {
19597
19729
  args.maxTurns = parseInt(takeValue(), 10) || void 0;
19730
+ } else if (a === "--no-recall") {
19731
+ args.noRecall = true;
19598
19732
  } else if (a === "--state-dir") {
19599
19733
  args.stateDir = takeValue().trim();
19600
19734
  } else if (a === "--config") {
@@ -19734,6 +19868,8 @@ async function runQuery(args) {
19734
19868
  await Promise.resolve().then(() => (init_tools_bundle(), tools_bundle_exports));
19735
19869
  const { registry: registry2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
19736
19870
  registry2.config = config;
19871
+ const { liveConfig: liveConfig2 } = await Promise.resolve().then(() => (init_live(), live_exports));
19872
+ liveConfig2.init(config);
19737
19873
  const { handleQuery: handleQuery2 } = await Promise.resolve().then(() => (init_handle_query(), handle_query_exports));
19738
19874
  const deps = {
19739
19875
  engine,
@@ -19772,8 +19908,8 @@ async function runQuery(args) {
19772
19908
  // channelTarget
19773
19909
  void 0,
19774
19910
  // inboundMeta
19775
- void 0,
19776
- // skipRecall
19911
+ args.noRecall || /quick-create assistant/i.test(args.prompt),
19912
+ // skipRecall(--no-recall 或建单任务自动跳过:daemon 拼的 quick-create prompt 是机械转述,recall sideQuery 在子进程里拖 30-65s)
19777
19913
  "cc-run"
19778
19914
  // source
19779
19915
  );