engine7 7.1.94 → 7.1.96

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
@@ -18320,7 +18320,8 @@ function buildLightHistory(history, opts) {
18320
18320
  function buildLightStablePrompt(workspace, mode, opts) {
18321
18321
  const lp = liveConfig.get(`channels.${mode}.liveSystemPrompt`);
18322
18322
  const parts = [];
18323
- for (const f of lp?.files ?? ["SOUL.md"]) {
18323
+ const files = lp?.files ?? (mode === "emotion" ? ["SOUL.md", "EMOTION.md"] : ["SOUL.md"]);
18324
+ for (const f of files) {
18324
18325
  try {
18325
18326
  parts.push(readFileSync22(join29(workspace, f), "utf-8").trim());
18326
18327
  } catch {
@@ -18343,7 +18344,7 @@ function buildLightStablePrompt(workspace, mode, opts) {
18343
18344
  ].join("\n"));
18344
18345
  }
18345
18346
  const built = parts.join("\n\n");
18346
- console.log(`[light-stable] mode=${mode} files=[${(lp?.files ?? ["SOUL.md"]).join(",")}] ~${Math.round(built.length / 3)} tokens`);
18347
+ console.log(`[light-stable] mode=${mode} files=[${files.join(",")}] ~${Math.round(built.length / 3)} tokens`);
18347
18348
  return built;
18348
18349
  }
18349
18350
  var init_light_mode = __esm({
@@ -27228,12 +27229,17 @@ var init_cli_doctor = __esm({
27228
27229
  var provision_free_exports = {};
27229
27230
  __export(provision_free_exports, {
27230
27231
  loadOrCreateInstallIdentity: () => loadOrCreateInstallIdentity,
27231
- provisionFreeToken: () => provisionFreeToken
27232
+ provisionFreeToken: () => provisionFreeToken,
27233
+ readInstallIdentity: () => readInstallIdentity,
27234
+ writeIdentityContactEmail: () => writeIdentityContactEmail
27232
27235
  });
27233
27236
  import { randomBytes as randomBytes6, randomUUID as randomUUID9 } from "node:crypto";
27234
27237
  import { chmodSync as chmodSync2, existsSync as existsSync31, mkdirSync as mkdirSync19, readFileSync as readFileSync39, writeFileSync as writeFileSync20 } from "node:fs";
27235
27238
  import { dirname as dirname12, join as join49 } from "node:path";
27236
27239
  import { fileURLToPath as fileURLToPath6 } from "node:url";
27240
+ function readContactEmailOf(parsed) {
27241
+ return typeof parsed?.contactEmail === "string" ? parsed.contactEmail.trim() : "";
27242
+ }
27237
27243
  function loadOrCreateInstallIdentity(stateDir) {
27238
27244
  const file2 = join49(stateDir, IDENTITY_FILE);
27239
27245
  if (existsSync31(file2)) {
@@ -27248,7 +27254,12 @@ function loadOrCreateInstallIdentity(stateDir) {
27248
27254
  if (typeof parsed?.installId !== "string" || typeof parsed?.installSecret !== "string") {
27249
27255
  throw new Error(`${IDENTITY_FILE} \u7F3A installId / installSecret \u5B57\u6BB5`);
27250
27256
  }
27251
- return { installId: parsed.installId, installSecret: parsed.installSecret };
27257
+ const email = readContactEmailOf(parsed);
27258
+ return {
27259
+ installId: parsed.installId,
27260
+ installSecret: parsed.installSecret,
27261
+ ...email ? { contactEmail: email } : {}
27262
+ };
27252
27263
  }
27253
27264
  const identity = {
27254
27265
  // 服务端校验 installId 长度为 8..36、只允许字母数字和连字符;uuid 正好符合
@@ -27264,6 +27275,32 @@ function loadOrCreateInstallIdentity(stateDir) {
27264
27275
  }
27265
27276
  return identity;
27266
27277
  }
27278
+ function readInstallIdentity(stateDir) {
27279
+ try {
27280
+ const parsed = JSON.parse(readFileSync39(join49(stateDir, IDENTITY_FILE), "utf8"));
27281
+ if (typeof parsed?.installId !== "string" || typeof parsed?.installSecret !== "string") return null;
27282
+ const email = readContactEmailOf(parsed);
27283
+ return {
27284
+ installId: parsed.installId,
27285
+ installSecret: parsed.installSecret,
27286
+ ...email ? { contactEmail: email } : {}
27287
+ };
27288
+ } catch {
27289
+ return null;
27290
+ }
27291
+ }
27292
+ function writeIdentityContactEmail(stateDir, email) {
27293
+ const identity = loadOrCreateInstallIdentity(stateDir);
27294
+ const trimmed = email.trim();
27295
+ const next = { ...identity, contactEmail: trimmed };
27296
+ const file2 = join49(stateDir, IDENTITY_FILE);
27297
+ mkdirSync19(stateDir, { recursive: true });
27298
+ writeFileSync20(file2, JSON.stringify(next, null, 2) + "\n", { mode: 384 });
27299
+ try {
27300
+ chmodSync2(file2, 384);
27301
+ } catch {
27302
+ }
27303
+ }
27267
27304
  function readEngineVersion() {
27268
27305
  try {
27269
27306
  return JSON.parse(readFileSync39(join49(dirname12(__filename), "..", "package.json"), "utf8")).version || "unknown";
@@ -27278,7 +27315,14 @@ async function provisionFreeToken(opts) {
27278
27315
  const res = await doFetch(url, {
27279
27316
  method: "POST",
27280
27317
  headers: { "Content-Type": "application/json" },
27281
- body: JSON.stringify({ ...identity, engineVersion: readEngineVersion() })
27318
+ // 显式列字段,**不要用 `...identity` 展开**:InstallIdentity 加了 contactEmail
27319
+ // 之后,展开会把邮箱也发到发号端点——协议悄悄变了,而服务端只认这三个字段。
27320
+ // (provision-free.test.ts 里有一条断言守这个。)
27321
+ body: JSON.stringify({
27322
+ installId: identity.installId,
27323
+ installSecret: identity.installSecret,
27324
+ engineVersion: readEngineVersion()
27325
+ })
27282
27326
  });
27283
27327
  const text = await res.text();
27284
27328
  let body;
@@ -28165,6 +28209,13 @@ import * as fs2 from "node:fs";
28165
28209
  // src/cli-init-config.ts
28166
28210
  import * as path2 from "node:path";
28167
28211
  var SCHEMA_VERSION = 1;
28212
+ var FREE_TIER_RELAY_URL = "https://www.twinsun.top:8866";
28213
+ function isFreeTier(v) {
28214
+ return v.freeTier === true || v.primaryProvider === "7yi";
28215
+ }
28216
+ function resolveRelayUrl(relayArg, env = process.env) {
28217
+ return (relayArg || "").trim() || (env.E7_RELAY_URL || "").trim() || FREE_TIER_RELAY_URL;
28218
+ }
28168
28219
  var DEFAULT_PRIMARY_MODEL = {
28169
28220
  dashscope: "dashscope/qwen3.8-max",
28170
28221
  minimax: "minimax/MiniMax-M3",
@@ -28245,7 +28296,13 @@ var PROVIDER_DEFS = {
28245
28296
  // 引擎免费档的中转站。baseUrl 是兜底值——真正的权威值来自领号响应
28246
28297
  // (服务端按请求 Host 自报地址),由安装器作为 customBaseUrl 下发。
28247
28298
  // 这样挪机器、换域名只改服务端,不用重发安装包。
28248
- baseUrl: "https://www.twinsun.top/v1",
28299
+ //
28300
+ // ⚠️ 0921 修:这里原本写的是 `https://www.twinsun.top/v1`(443),而 **443 上不是
28301
+ // 中转站**(实测回的是另一个服务的 FastAPI 404)。安装器那条路每次都会下发
28302
+ // customBaseUrl 把它盖掉,所以正式装机撞不到;但**终端向导选 7yi 时不问 baseUrl**,
28303
+ // 直接落到这个兜底值——于是命令行用户拿到的是「号领到了、引擎起来了、一发消息就废」。
28304
+ // 用常量拼,别再手写一遍(漏端口就是这个坑)。
28305
+ baseUrl: `${FREE_TIER_RELAY_URL}/v1`,
28249
28306
  api: "anthropic",
28250
28307
  models: [
28251
28308
  // ⚠️ contextWindow **不能照抄 1000000**。
@@ -28365,9 +28422,9 @@ function generateConfig(v) {
28365
28422
  // 自拍(§4.3):免费档必须显式写 provider:'relay'。不写的话 getProvider()
28366
28423
  // 会落回默认值 'fal',而免费装机没有 fal key——第一次自拍就失败。
28367
28424
  // 非免费档只在用户真给了形象时才写这个块,且不替他决定 provider。
28368
- ...v.freeTier || v.selfiePhotoRelPath || v.selfiePortraitDesc ? {
28425
+ ...isFreeTier(v) || v.selfiePhotoRelPath || v.selfiePortraitDesc ? {
28369
28426
  my_selfie: {
28370
- ...v.freeTier ? { provider: "relay" } : {},
28427
+ ...isFreeTier(v) ? { provider: "relay" } : {},
28371
28428
  ...v.selfiePhotoRelPath ? { references: [{ name: "portrait", path: v.selfiePhotoRelPath }] } : {},
28372
28429
  // 只在没有照片时才写描述——两个都给的话以照片为准,写进去会让人以为
28373
28430
  // 描述也生效了(冷启读的就是这个键)
@@ -28415,7 +28472,7 @@ function generateConfig(v) {
28415
28472
  debounceMs: 5e3,
28416
28473
  // 免费档的装机目标是「能对话、能看图、能自拍」,这两个 flag 默认 false
28417
28474
  // (src/config/features.ts)。显式打开,它们是声明这两件事的地方。
28418
- ...v.freeTier ? { selfie: true, eyes: true } : {}
28475
+ ...isFreeTier(v) ? { selfie: true, eyes: true } : {}
28419
28476
  }
28420
28477
  }
28421
28478
  },
@@ -28581,6 +28638,13 @@ function validate(a) {
28581
28638
  if (a.timezone !== void 0 && !isValidTimezone(a.timezone)) {
28582
28639
  throw new Error(`timezone \u975E\u6CD5: ${a.timezone}\uFF08\u8981 IANA \u540D\uFF0C\u5982 Asia/Shanghai\u3001Europe/Malta\uFF09`);
28583
28640
  }
28641
+ if (a.contactEmail !== void 0 && a.contactEmail !== null && a.contactEmail !== "") {
28642
+ if (typeof a.contactEmail !== "string") throw new Error("contactEmail \u5FC5\u987B\u662F\u5B57\u7B26\u4E32");
28643
+ const t = a.contactEmail.trim();
28644
+ if (t && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t)) {
28645
+ throw new Error(`contactEmail \u4E0D\u662F\u5408\u6CD5\u90AE\u7BB1: ${t}`);
28646
+ }
28647
+ }
28584
28648
  if (a.feishu?.mode !== void 0 && !VALID_CHANNEL_MODES.includes(a.feishu.mode)) {
28585
28649
  throw new Error(`feishu.mode \u975E\u6CD5: ${a.feishu.mode}\uFF08\u53EF\u9009: ${VALID_CHANNEL_MODES.join(" / ")}\uFF09`);
28586
28650
  }
@@ -28609,6 +28673,11 @@ function loadInitAnswers(filePath) {
28609
28673
  throw new Error(`answers \u6587\u4EF6\u4E0D\u662F\u5408\u6CD5 JSON: ${e.message}`);
28610
28674
  }
28611
28675
  validate(parsed);
28676
+ if (typeof parsed.contactEmail === "string") {
28677
+ const t = parsed.contactEmail.trim();
28678
+ if (t) parsed.contactEmail = t;
28679
+ else delete parsed.contactEmail;
28680
+ }
28612
28681
  return parsed;
28613
28682
  }
28614
28683
  function buildConfigValuesFromAnswers(stateDir, a, existing = {}) {
@@ -29399,16 +29468,16 @@ async function main() {
29399
29468
  }
29400
29469
  if (subcommand === "provision-free") {
29401
29470
  let relay = "";
29471
+ let relayFromArg = false;
29402
29472
  let stateDir = "";
29403
29473
  for (let i = 1; i < args.length; i++) {
29404
- if (args[i] === "--relay" && args[i + 1]) relay = args[++i].trim();
29405
- else if (args[i] === "--state-dir" && args[i + 1]) stateDir = args[++i].trim();
29406
- }
29407
- if (!relay) {
29408
- console.error("\u7528\u6CD5\uFF1Aengine7 provision-free --relay <\u4E2D\u8F6C\u7AD9\u5730\u5740> --state-dir <\u76EE\u5F55>");
29409
- console.error(" --relay \u662F\u5B89\u88C5\u5668\u4E0B\u53D1\u7684\u9886\u53F7\u5730\u5740\uFF0C\u4E0D\u662F\u6A21\u578B baseUrl\uFF08\u540E\u8005\u4EE5\u9886\u53F7\u54CD\u5E94\u4E3A\u51C6\uFF09");
29410
- process.exit(1);
29474
+ if (args[i] === "--relay" && args[i + 1]) {
29475
+ relay = args[++i].trim();
29476
+ relayFromArg = true;
29477
+ } else if (args[i] === "--state-dir" && args[i + 1]) stateDir = args[++i].trim();
29411
29478
  }
29479
+ relay = resolveRelayUrl(relay, process.env);
29480
+ if (!relayFromArg) console.error(` \u4E2D\u8F6C\u7AD9: ${relay}\uFF08\u8981\u6362\u5730\u5740\u7528 --relay <\u5730\u5740>\uFF09`);
29412
29481
  const { resolveStateDirFromArgs: resolveStateDirFromArgs2 } = await Promise.resolve().then(() => (init_cli_doctor(), cli_doctor_exports));
29413
29482
  stateDir = stateDir ? path33.resolve(stateDir) : resolveStateDirFromArgs2(args.slice(1));
29414
29483
  try {
@@ -30225,11 +30294,17 @@ WantedBy=default.target`;
30225
30294
  values = await interactiveConfig(rl, getDefaultValues(opts.stateDir));
30226
30295
  rl.close();
30227
30296
  }
30228
- if (values.freeTier) {
30297
+ {
30298
+ const { loadOrCreateInstallIdentity: loadOrCreateInstallIdentity2, writeIdentityContactEmail: writeIdentityContactEmail2 } = await Promise.resolve().then(() => (init_provision_free(), provision_free_exports));
30299
+ loadOrCreateInstallIdentity2(opts.stateDir);
30300
+ const contactEmail = (answers?.contactEmail || "").trim();
30301
+ if (contactEmail) writeIdentityContactEmail2(opts.stateDir, contactEmail);
30302
+ }
30303
+ if (isFreeTier(values)) {
30229
30304
  const envName = values.primaryProvider.toUpperCase().replace(/[^A-Z0-9_]/g, "_") + "_API_KEY";
30230
30305
  if (!readSecretsValue(opts.stateDir, envName)) {
30231
30306
  throw new Error(
30232
- `\u514D\u8D39\u6863\u7F3A\u5C11\u4EE4\u724C\uFF1Asecrets \u91CC\u6CA1\u6709 ${envName}\u3002\u8BF7\u5148\u6267\u884C engine7 provision-free --relay <\u4E2D\u8F6C\u7AD9\u5730\u5740> --state-dir ${opts.stateDir} \u9886\u53F7\uFF0C\u518D\u8DD1 init\u3002`
30307
+ `\u514D\u8D39\u6863\u7F3A\u5C11\u4EE4\u724C\uFF1Asecrets \u91CC\u6CA1\u6709 ${envName}\u3002\u8BF7\u5148\u6267\u884C engine7 provision-free --state-dir ${opts.stateDir} \u9886\u53F7\uFF0C\u518D\u8DD1 init\u3002`
30233
30308
  );
30234
30309
  }
30235
30310
  }