engine7 7.1.25 → 7.1.26

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.
Files changed (2) hide show
  1. package/dist/cli.mjs +192 -3
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -575,6 +575,157 @@ import * as path2 from "node:path";
575
575
  import * as fs2 from "node:fs";
576
576
  import * as readline from "node:readline";
577
577
  import { fileURLToPath } from "node:url";
578
+
579
+ // src/feishu-quick-register.ts
580
+ var ACCOUNTS_URL = {
581
+ feishu: "https://accounts.feishu.cn",
582
+ lark: "https://accounts.larksuite.com"
583
+ };
584
+ var REGISTRATION_PATH = "/oauth/v1/app/registration";
585
+ var REQUEST_TIMEOUT_MS = 1e4;
586
+ var DEFAULT_POLL_INTERVAL = 5;
587
+ async function postRegistration(domain, body) {
588
+ const url = `${ACCOUNTS_URL[domain]}${REGISTRATION_PATH}`;
589
+ const res = await fetch(url, {
590
+ method: "POST",
591
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
592
+ body: new URLSearchParams(body).toString(),
593
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
594
+ });
595
+ if (!res.ok) {
596
+ throw new Error(`\u98DE\u4E66\u6CE8\u518C\u63A5\u53E3\u8FD4\u56DE ${res.status}: ${await res.text()}`);
597
+ }
598
+ return res.json();
599
+ }
600
+ async function initRegistration(domain) {
601
+ const res = await postRegistration(domain, { action: "init" });
602
+ if (!res.supported_auth_methods?.includes("client_secret")) {
603
+ throw new Error("\u5F53\u524D\u98DE\u4E66\u73AF\u5883\u4E0D\u652F\u6301 client_secret \u8BA4\u8BC1\uFF0C\u65E0\u6CD5\u81EA\u52A8\u6CE8\u518C");
604
+ }
605
+ }
606
+ async function beginRegistration(domain) {
607
+ const res = await postRegistration(domain, {
608
+ action: "begin",
609
+ archetype: "PersonalAgent",
610
+ auth_method: "client_secret",
611
+ request_user_info: "open_id"
612
+ });
613
+ if (!res.device_code || !res.verification_uri_complete) {
614
+ throw new Error(`\u98DE\u4E66\u6CE8\u518C\u5931\u8D25: \u672A\u8FD4\u56DE device_code
615
+ ${JSON.stringify(res)}`);
616
+ }
617
+ return {
618
+ deviceCode: res.device_code,
619
+ qrUrl: res.verification_uri_complete,
620
+ userCode: res.user_code,
621
+ interval: res.interval ?? DEFAULT_POLL_INTERVAL,
622
+ expireIn: res.expire_in ?? 300
623
+ };
624
+ }
625
+ async function pollRegistration(domain, deviceCode, interval, deadline, onLog, signal) {
626
+ let currentInterval = interval;
627
+ let currentDomain = domain;
628
+ while (Date.now() < deadline) {
629
+ if (signal?.aborted) return null;
630
+ let res;
631
+ try {
632
+ res = await postRegistration(currentDomain, {
633
+ action: "poll",
634
+ device_code: deviceCode
635
+ });
636
+ } catch {
637
+ await sleep(currentInterval * 1e3);
638
+ continue;
639
+ }
640
+ if (res.user_info?.tenant_brand === "lark" && currentDomain === "feishu") {
641
+ currentDomain = "lark";
642
+ onLog?.("\u68C0\u6D4B\u5230 Lark \u8D26\u53F7\uFF0C\u5207\u6362\u57DF\u540D...");
643
+ continue;
644
+ }
645
+ if (res.client_id && res.client_secret) {
646
+ return {
647
+ appId: res.client_id,
648
+ appSecret: res.client_secret,
649
+ openId: res.user_info?.open_id,
650
+ domain: currentDomain
651
+ };
652
+ }
653
+ if (res.error) {
654
+ if (res.error === "authorization_pending") {
655
+ } else if (res.error === "slow_down") {
656
+ currentInterval += 5;
657
+ } else if (res.error === "access_denied") {
658
+ throw new Error("\u7528\u6237\u62D2\u7EDD\u4E86\u6388\u6743");
659
+ } else if (res.error === "expired_token") {
660
+ throw new Error("\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F");
661
+ } else {
662
+ throw new Error(`\u98DE\u4E66\u6CE8\u518C\u9519\u8BEF: ${res.error} \u2014 ${res.error_description ?? ""}`);
663
+ }
664
+ }
665
+ await sleep(currentInterval * 1e3);
666
+ }
667
+ return null;
668
+ }
669
+ async function registerFeishuApp(options = {}) {
670
+ const domain = options.domain ?? "feishu";
671
+ const timeoutSec = options.timeoutSec ?? 300;
672
+ const log = options.onLog ?? (() => {
673
+ });
674
+ log("\u68C0\u67E5\u98DE\u4E66\u73AF\u5883...");
675
+ await initRegistration(domain);
676
+ log("\u751F\u6210\u4E8C\u7EF4\u7801...");
677
+ const { deviceCode, qrUrl, interval, expireIn } = await beginRegistration(domain);
678
+ options.onQrCode?.(qrUrl);
679
+ log(`\u8BF7\u7528\u98DE\u4E66 App \u626B\u63CF\u4E8C\u7EF4\u7801\uFF08${expireIn}\u79D2\u540E\u8FC7\u671F\uFF09...`);
680
+ const deadline = Date.now() + Math.min(expireIn, timeoutSec) * 1e3;
681
+ const result = await pollRegistration(domain, deviceCode, interval, deadline, log, options.signal);
682
+ if (result) {
683
+ log(`\u2705 \u6CE8\u518C\u6210\u529F\uFF01App ID: ${result.appId}`);
684
+ } else {
685
+ log("\u23F0 \u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F");
686
+ }
687
+ return result;
688
+ }
689
+ function sleep(ms) {
690
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
691
+ }
692
+
693
+ // src/qr-render.ts
694
+ var qrcodeModule = null;
695
+ async function getQrModule() {
696
+ if (qrcodeModule) return qrcodeModule;
697
+ try {
698
+ qrcodeModule = await import("qrcode-terminal");
699
+ } catch {
700
+ try {
701
+ qrcodeModule = await import("qrcode");
702
+ } catch {
703
+ throw new Error("\u8BF7\u5148\u5B89\u88C5 qrcode-terminal: npm install qrcode-terminal");
704
+ }
705
+ }
706
+ return qrcodeModule;
707
+ }
708
+ async function renderQrTerminal(url, options) {
709
+ const mod = await getQrModule();
710
+ return new Promise((resolve2, reject) => {
711
+ try {
712
+ if (mod.generate) {
713
+ mod.generate(url, { small: options?.small ?? true }, (output) => {
714
+ resolve2(output);
715
+ });
716
+ } else if (mod.toString) {
717
+ const output = mod.toString(url, { type: "terminal", small: options?.small ?? true });
718
+ resolve2(output);
719
+ } else {
720
+ reject(new Error("\u4E0D\u652F\u6301\u7684\u4E8C\u7EF4\u7801\u5E93"));
721
+ }
722
+ } catch (err) {
723
+ reject(err);
724
+ }
725
+ });
726
+ }
727
+
728
+ // src/cli-init.ts
578
729
  var __filename = fileURLToPath(import.meta.url);
579
730
  var __dirname = path2.dirname(__filename);
580
731
  var SCHEMA_VERSION = 1;
@@ -747,9 +898,47 @@ async function interactiveConfig(rl, defaults) {
747
898
  const feishuAns = await ask(rl, "\u542F\u7528\u98DE\u4E66? (y/n)", "n");
748
899
  v.feishuEnabled = feishuAns.toLowerCase() === "y";
749
900
  if (v.feishuEnabled) {
750
- v.feishuAppId = await ask(rl, "\u98DE\u4E66 App ID");
751
- v.feishuAppSecret = await ask(rl, "\u98DE\u4E66 App Secret");
752
- v.feishuOpenId = await ask(rl, "\u4F60\u7684\u98DE\u4E66 open_id");
901
+ console.log("\n \u98DE\u4E66\u914D\u7F6E\u65B9\u5F0F\uFF1A");
902
+ console.log(" 1. \u626B\u7801\u81EA\u52A8\u521B\u5EFA\uFF08\u63A8\u8350\uFF0C30\u79D2\u641E\u5B9A\uFF09");
903
+ console.log(" 2. \u624B\u52A8\u8F93\u5165 App ID / App Secret");
904
+ const feishuMode = await ask(rl, "\u9009\u62E9 (1/2)", "1");
905
+ if (feishuMode === "1") {
906
+ console.log("\n\u{1F4DD} \u6B63\u5728\u751F\u6210\u98DE\u4E66\u4E8C\u7EF4\u7801...\n");
907
+ const result = await registerFeishuApp({
908
+ onLog: (msg) => console.log(` ${msg}`),
909
+ onQrCode: async (url) => {
910
+ try {
911
+ const qr = await renderQrTerminal(url, { small: true });
912
+ console.log(qr);
913
+ } catch {
914
+ console.log(`
915
+ \u8BF7\u5728\u624B\u673A\u6D4F\u89C8\u5668\u6253\u5F00\u6B64\u94FE\u63A5\u626B\u7801\uFF1A
916
+ ${url}
917
+ `);
918
+ }
919
+ }
920
+ });
921
+ if (result) {
922
+ v.feishuAppId = result.appId;
923
+ v.feishuAppSecret = result.appSecret;
924
+ v.feishuOpenId = result.openId || "";
925
+ console.log(`
926
+ \u2705 App ID: ${result.appId}`);
927
+ console.log(` \u2705 App Secret: ${result.appSecret.slice(0, 6)}...`);
928
+ if (result.openId) {
929
+ console.log(` \u2705 Open ID: ${result.openId}`);
930
+ }
931
+ } else {
932
+ console.log("\n \u26A0\uFE0F \u626B\u7801\u8D85\u65F6\u6216\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u8F93\u5165");
933
+ v.feishuAppId = await ask(rl, "\u98DE\u4E66 App ID");
934
+ v.feishuAppSecret = await ask(rl, "\u98DE\u4E66 App Secret");
935
+ v.feishuOpenId = await ask(rl, "\u4F60\u7684\u98DE\u4E66 open_id\uFF08\u56DE\u8F66\u8DF3\u8FC7\uFF09", "");
936
+ }
937
+ } else {
938
+ v.feishuAppId = await ask(rl, "\u98DE\u4E66 App ID");
939
+ v.feishuAppSecret = await ask(rl, "\u98DE\u4E66 App Secret");
940
+ v.feishuOpenId = await ask(rl, "\u4F60\u7684\u98DE\u4E66 open_id\uFF08\u56DE\u8F66\u8DF3\u8FC7\uFF09", "");
941
+ }
753
942
  }
754
943
  const tavilyKey = await ask(rl, "Tavily API Key\uFF08\u8054\u7F51\u641C\u7D22\uFF0C\u56DE\u8F66\u8DF3\u8FC7\uFF09", "");
755
944
  v.tavilyKey = tavilyKey;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "engine7",
3
- "version": "7.1.25",
3
+ "version": "7.1.26",
4
4
  "type": "module",
5
5
  "description": "Engine 7 — Self-hosted AI agent engine",
6
6
  "main": "dist/main.mjs",