hiwork-core 0.0.8 → 0.0.11

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/lib/index.js CHANGED
@@ -3137,7 +3137,7 @@ function isUnloading(ctx) {
3137
3137
  }
3138
3138
 
3139
3139
  // src/version.ts
3140
- var PKG_VERSION = false ? "dev" : "0.0.8";
3140
+ var PKG_VERSION = false ? "dev" : "0.0.11";
3141
3141
 
3142
3142
  // src/ai-router-client.ts
3143
3143
  var AUTH_AUTHORIZE_PATH = "/api/auth/authorize";
@@ -3150,6 +3150,8 @@ var ME_KEY_RECHARGES_PATH = "/api/me/key/recharges";
3150
3150
  var ME_COST_ESTIMATE_PATH = "/api/me/cost-estimate";
3151
3151
  var ME_DAILY_QUOTE_PATH = "/api/me/daily-quote";
3152
3152
  var ME_DAILY_QUOTE_RANDOM_PATH = "/api/me/daily-quote/random";
3153
+ var ME_MCP_ASSIGNMENTS_PATH = "/api/me/mcp-assignments";
3154
+ var ME_MCP_ASSERTIONS_PATH = "/api/me/mcp-assertions";
3153
3155
  var DEFAULT_CLIENT_ID = "hiwork-desktop";
3154
3156
  var DEFAULT_REDIRECT_URI = "hiwork://auth/callback";
3155
3157
  var GatewayError = class extends Error {
@@ -3308,6 +3310,45 @@ var AiRouterClient = class {
3308
3310
  if (!res.ok) throw new GatewayError("GATEWAY_UNREACHABLE", `\u7F51\u5173\u8FD4\u56DE\u9519\u8BEF\uFF08HTTP ${res.status}\uFF09`, res.status);
3309
3311
  return await parseMeJson(res);
3310
3312
  }
3313
+ /**
3314
+ * GET /api/me/mcp-assignments:管理员下发给当前账号的 MCP 清单。
3315
+ *
3316
+ * 不复用 {@link getMeJson}:那条路径把 403 映射成 `NO_KEY_ASSIGNED`(「尚未被分配
3317
+ * 虚拟 KEY」),而本端点的鉴权只有会话——一个还没被分配 Key 的账号照样应该有
3318
+ * 清单(分 MCP 与分 Key 是两件事)。沿用它的 403 文案会把「没有 Key」错报成原因。
3319
+ */
3320
+ async getMyMcpAssignments(sessionCookie) {
3321
+ const res = await this.requestOrUnreachable(ME_MCP_ASSIGNMENTS_PATH, { method: "GET", sessionCookie });
3322
+ if (res.status === 401) throw new GatewayError("SESSION_EXPIRED", "\u7F51\u5173\u4F1A\u8BDD\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55", 401);
3323
+ if (!res.ok) throw new GatewayError("GATEWAY_UNREACHABLE", `\u7F51\u5173\u8FD4\u56DE\u9519\u8BEF\uFF08HTTP ${res.status}\uFF09`, res.status);
3324
+ return await parseMeJson(res);
3325
+ }
3326
+ /**
3327
+ * POST /api/me/mcp-assertions:为某条分配签一张 120 秒断言。
3328
+ *
3329
+ * 三种拒绝各有确定含义(服务端 handler 的 404/409/503),必须分开映射——否则
3330
+ * 客户端只会看到一句「取断言失败」,既分不清「被撤销了」(该卸连接)还是
3331
+ * 「服务停用了」(该重试)还是「部署没配私钥」(找管理员)。
3332
+ */
3333
+ async issueMyMcpAssertion(sessionCookie, assignmentId) {
3334
+ const res = await this.requestOrUnreachable(ME_MCP_ASSERTIONS_PATH, {
3335
+ method: "POST",
3336
+ sessionCookie,
3337
+ body: { assignmentId }
3338
+ });
3339
+ if (res.status === 401) throw new GatewayError("SESSION_EXPIRED", "\u7F51\u5173\u4F1A\u8BDD\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55", 401);
3340
+ if (res.status === 400 || res.status === 404) {
3341
+ throw new GatewayError("MCP_ASSIGNMENT_GONE", "\u8FD9\u6761\u5206\u914D\u5DF2\u5931\u6548\uFF0C\u7A0D\u540E\u540C\u6B65\u4F1A\u91CD\u65B0\u6838\u5BF9", res.status);
3342
+ }
3343
+ if (res.status === 409) {
3344
+ throw new GatewayError("MCP_NOT_DELIVERABLE", "\u8BE5 MCP \u670D\u52A1\u5F53\u524D\u4E0D\u53EF\u4E0B\u53D1\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458", 409);
3345
+ }
3346
+ if (res.status === 503) {
3347
+ throw new GatewayError("MCP_ASSERTION_DISABLED", "\u672C\u90E8\u7F72\u672A\u542F\u7528 MCP \u65AD\u8A00\u7B7E\u53D1\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458", 503);
3348
+ }
3349
+ if (!res.ok) throw new GatewayError("GATEWAY_UNREACHABLE", `\u7F51\u5173\u8FD4\u56DE\u9519\u8BEF\uFF08HTTP ${res.status}\uFF09`, res.status);
3350
+ return await parseMeJson(res);
3351
+ }
3311
3352
  /**
3312
3353
  * /api/me 自助端点的 GET 公共路径:网络异常 → GATEWAY_UNREACHABLE,
3313
3354
  * 401/403/400 映射为稳定 code,响应体非 JSON 时不把原文带进异常。
@@ -3766,6 +3807,7 @@ async function completeBrowserLogin(input, opts) {
3766
3807
  var DEFAULT_LOGIN_MODE = "both";
3767
3808
  var CLIENT_POLICY_PATH = "/api/client/policy";
3768
3809
  var CLIENT_POLICY_TIMEOUT_MS = 5e3;
3810
+ var DEFAULT_PASSWORD_LOGIN = true;
3769
3811
  function buildClientPolicyURL(opts) {
3770
3812
  const baseURL = typeof opts.baseURL === "string" ? opts.baseURL.trim().replace(/\/+$/, "") : "";
3771
3813
  if (baseURL === "") return void 0;
@@ -3783,6 +3825,11 @@ function parseLoginMode(payload) {
3783
3825
  const value = payload.loginMode;
3784
3826
  return value === "browser" || value === "form" || value === "both" ? value : void 0;
3785
3827
  }
3828
+ function parsePasswordLogin(payload) {
3829
+ if (typeof payload !== "object" || payload === null) return DEFAULT_PASSWORD_LOGIN;
3830
+ const value = payload.passwordLogin;
3831
+ return typeof value === "boolean" ? value : DEFAULT_PASSWORD_LOGIN;
3832
+ }
3786
3833
  async function fetchClientPolicy(opts) {
3787
3834
  const url = buildClientPolicyURL(opts);
3788
3835
  if (url === void 0) return void 0;
@@ -3800,7 +3847,7 @@ async function fetchClientPolicy(opts) {
3800
3847
  return void 0;
3801
3848
  }
3802
3849
  const loginMode = parseLoginMode(payload);
3803
- return loginMode === void 0 ? void 0 : { loginMode };
3850
+ return loginMode === void 0 ? void 0 : { loginMode, passwordLogin: parsePasswordLogin(payload) };
3804
3851
  } catch {
3805
3852
  return void 0;
3806
3853
  }
@@ -4401,6 +4448,232 @@ function registerUsageRpc(ctx, deps) {
4401
4448
  };
4402
4449
  }
4403
4450
 
4451
+ // src/managed-mcp.ts
4452
+ var MANAGED_MCP_RPC_CHANNEL = "/hiwork-managed-mcp";
4453
+ var MANAGED_MCP_RPC_ENDPOINTS = ["snapshot", "refresh", "assertion"];
4454
+ var MANAGED_MCP_REFRESH_INTERVAL_MS = 30 * 6e4;
4455
+ var ManagedMcpRequestError = class extends Error {
4456
+ constructor(code, message) {
4457
+ super(message);
4458
+ this.code = code;
4459
+ this.name = "ManagedMcpRequestError";
4460
+ }
4461
+ };
4462
+ var MANAGED_MCP_MESSAGE_FALLBACK = {
4463
+ SESSION_EXPIRED: "\u767B\u5F55\u72B6\u6001\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55",
4464
+ GATEWAY_UNREACHABLE: "\u7F51\u5173\u6682\u65F6\u4E0D\u53EF\u7528\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",
4465
+ MCP_ASSIGNMENT_GONE: "\u8FD9\u6761\u5206\u914D\u5DF2\u5931\u6548\uFF0C\u7A0D\u540E\u540C\u6B65\u4F1A\u91CD\u65B0\u6838\u5BF9",
4466
+ MCP_NOT_DELIVERABLE: "\u8BE5 MCP \u670D\u52A1\u5F53\u524D\u4E0D\u53EF\u4E0B\u53D1\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458",
4467
+ MCP_ASSERTION_DISABLED: "\u672C\u90E8\u7F72\u672A\u542F\u7528 MCP \u65AD\u8A00\u7B7E\u53D1\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458",
4468
+ NO_KEY_ASSIGNED: "\u5F53\u524D\u8D26\u53F7\u5C1A\u672A\u88AB\u5206\u914D\u865A\u62DF KEY\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458"
4469
+ };
4470
+ var MANAGED_MCP_GENERIC_FAILURE_MESSAGE = "MCP \u6E05\u5355\u6682\u65F6\u65E0\u6CD5\u83B7\u53D6\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5";
4471
+ var MANAGED_MCP_SESSION_EXPIRED_MESSAGE = "\u767B\u5F55\u72B6\u6001\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55";
4472
+ function displayManagedMcpMessage(code, message) {
4473
+ const text = typeof message === "string" ? message.trim() : "";
4474
+ if (text === "") return MANAGED_MCP_MESSAGE_FALLBACK[code] ?? MANAGED_MCP_GENERIC_FAILURE_MESSAGE;
4475
+ const leaksImplementationDetail = /https?:\/\//i.test(text) || /\bHTTP\s*\d{3}\b/i.test(text) || /\bbaseURL\b/i.test(text);
4476
+ if (leaksImplementationDetail) return MANAGED_MCP_MESSAGE_FALLBACK[code] ?? MANAGED_MCP_GENERIC_FAILURE_MESSAGE;
4477
+ return text;
4478
+ }
4479
+ var ASSIGNMENT_ID_PATTERN = /^[0-9a-fA-F-]{1,64}$/;
4480
+ function parseManagedMcpPayload(endpoint, raw) {
4481
+ if (raw === void 0 || raw === null) {
4482
+ if (endpoint === "assertion") throw new ManagedMcpRequestError("bad-request", "\u53D6\u65AD\u8A00\u8BF7\u6C42\u7F3A\u5C11 assignmentId\u3002");
4483
+ return {};
4484
+ }
4485
+ if (typeof raw !== "object" || Array.isArray(raw)) {
4486
+ throw new ManagedMcpRequestError("bad-request", "MCP \u6E05\u5355\u8BF7\u6C42\u53C2\u6570\u4E0D\u5408\u6CD5\u3002");
4487
+ }
4488
+ const record = raw;
4489
+ const keys = Object.keys(record);
4490
+ if (endpoint !== "assertion") {
4491
+ if (keys.length > 0) throw new ManagedMcpRequestError("bad-request", `MCP \u6E05\u5355\u8BF7\u6C42\u5305\u542B\u672A\u77E5\u5B57\u6BB5 '${keys[0]}'\u3002`);
4492
+ return {};
4493
+ }
4494
+ for (const key of keys) {
4495
+ if (key !== "assignmentId") throw new ManagedMcpRequestError("bad-request", `\u53D6\u65AD\u8A00\u8BF7\u6C42\u5305\u542B\u672A\u77E5\u5B57\u6BB5 '${key}'\u3002`);
4496
+ }
4497
+ const rawId = record["assignmentId"];
4498
+ if (typeof rawId !== "string" || !ASSIGNMENT_ID_PATTERN.test(rawId.trim())) {
4499
+ throw new ManagedMcpRequestError("bad-request", "\u53D6\u65AD\u8A00\u8BF7\u6C42\u7684 assignmentId \u4E0D\u5408\u6CD5\u3002");
4500
+ }
4501
+ return { assignmentId: rawId.trim() };
4502
+ }
4503
+ function isManagedMcpRpcEndpoint(endpoint) {
4504
+ return MANAGED_MCP_RPC_ENDPOINTS.includes(endpoint);
4505
+ }
4506
+ function textOrUndefined(value) {
4507
+ return typeof value === "string" && value.trim() !== "" ? value : void 0;
4508
+ }
4509
+ function normalizeAssignment(raw, log) {
4510
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return void 0;
4511
+ const record = raw;
4512
+ const assignmentId = textOrUndefined(record["assignmentId"]);
4513
+ const serverName = textOrUndefined(record["serverName"]);
4514
+ const url = textOrUndefined(record["url"]);
4515
+ const transport = textOrUndefined(record["transport"]);
4516
+ const authRaw = record["auth"];
4517
+ const auth = typeof authRaw === "object" && authRaw !== null && !Array.isArray(authRaw) ? authRaw : void 0;
4518
+ const kind = textOrUndefined(auth?.["kind"]);
4519
+ const mintUrl = textOrUndefined(auth?.["mintUrl"]);
4520
+ if (assignmentId === void 0 || serverName === void 0 || url === void 0 || transport === void 0 || kind === void 0 || mintUrl === void 0) {
4521
+ log?.("hiwork-core: MCP \u6E05\u5355\u91CC\u6709\u4E00\u6761\u7ED3\u6784\u4E0D\u5B8C\u6574\u7684\u5206\u914D\uFF0C\u5DF2\u8DF3\u8FC7");
4522
+ return void 0;
4523
+ }
4524
+ const revision = record["revision"];
4525
+ return {
4526
+ assignmentId,
4527
+ revision: typeof revision === "number" && Number.isFinite(revision) ? revision : 0,
4528
+ slug: textOrUndefined(record["slug"]) ?? serverName,
4529
+ displayName: textOrUndefined(record["displayName"]) ?? serverName,
4530
+ serverName,
4531
+ transport,
4532
+ url,
4533
+ extraHeaders: stringMap(record["extraHeaders"]),
4534
+ auth: { kind, mintUrl, revokeUrl: textOrUndefined(auth?.["revokeUrl"]) ?? "" },
4535
+ updatedAt: textOrUndefined(record["updatedAt"]) ?? ""
4536
+ };
4537
+ }
4538
+ function stringMap(raw) {
4539
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return {};
4540
+ const out = {};
4541
+ for (const [key, value] of Object.entries(raw)) {
4542
+ if (typeof value === "string") out[key] = value;
4543
+ }
4544
+ return out;
4545
+ }
4546
+ function failureOf(error) {
4547
+ if (error instanceof ManagedMcpRequestError) return { code: error.code, message: error.message, details: {} };
4548
+ if (error instanceof GatewayError) {
4549
+ return { code: error.code, message: displayManagedMcpMessage(error.code, error.message), details: {} };
4550
+ }
4551
+ return { code: "internal", message: MANAGED_MCP_GENERIC_FAILURE_MESSAGE, details: {} };
4552
+ }
4553
+ var ManagedMcpStore = class {
4554
+ constructor(deps, now = () => Date.now()) {
4555
+ this.deps = deps;
4556
+ this.now = now;
4557
+ }
4558
+ cached;
4559
+ lastError;
4560
+ inFlight;
4561
+ /**
4562
+ * 当前缓存(同步读,不发请求)。从没成功过返回 undefined;
4563
+ * 最近一次失败会以 `stale + lastError` 标注在上一次成功的结果上。
4564
+ */
4565
+ peek() {
4566
+ if (this.cached === void 0) return void 0;
4567
+ return this.lastError === void 0 ? this.cached : { ...this.cached, stale: true, lastError: this.lastError };
4568
+ }
4569
+ /**
4570
+ * 去网关拉一次清单并更新缓存。失败时抛异常,且**缓存原样保留**。
4571
+ *
4572
+ * 并发调用合并成一次请求:后台预热与客户端手动同步撞在一起时不必打两遍网关。
4573
+ */
4574
+ async load() {
4575
+ if (this.inFlight !== void 0) return await this.inFlight;
4576
+ const task = this.fetchOnce();
4577
+ this.inFlight = task;
4578
+ try {
4579
+ return await task;
4580
+ } finally {
4581
+ this.inFlight = void 0;
4582
+ }
4583
+ }
4584
+ async fetchOnce() {
4585
+ try {
4586
+ const sessionCookie = await this.deps.resolveSession();
4587
+ if (sessionCookie === void 0 || sessionCookie === "") {
4588
+ throw new GatewayError("SESSION_EXPIRED", MANAGED_MCP_SESSION_EXPIRED_MESSAGE);
4589
+ }
4590
+ const gateway = this.deps.gateway();
4591
+ if (gateway === void 0) {
4592
+ throw new GatewayError("GATEWAY_UNREACHABLE", "\u7F51\u5173\u5730\u5740\u672A\u914D\u7F6E\uFF0C\u8BF7\u5148\u5728\u300C\u7F51\u5173\u6A21\u578B\u300D\u91CC\u5B8C\u6210\u767B\u5F55");
4593
+ }
4594
+ const view = await gateway.getMyMcpAssignments(sessionCookie);
4595
+ const assignments = [];
4596
+ for (const item of Array.isArray(view?.assignments) ? view.assignments : []) {
4597
+ const normalized = normalizeAssignment(item, this.deps.log);
4598
+ if (normalized !== void 0) assignments.push(normalized);
4599
+ }
4600
+ const snapshot = {
4601
+ revision: typeof view?.revision === "number" && Number.isFinite(view.revision) ? view.revision : 0,
4602
+ fetchedAt: new Date(this.now()).toISOString(),
4603
+ assignments,
4604
+ stale: false
4605
+ };
4606
+ this.cached = snapshot;
4607
+ this.lastError = void 0;
4608
+ return snapshot;
4609
+ } catch (error) {
4610
+ this.lastError = failureOf(error);
4611
+ throw error;
4612
+ }
4613
+ }
4614
+ };
4615
+ function isAborted4(signal) {
4616
+ return signal?.aborted === true;
4617
+ }
4618
+ async function handleManagedMcpEndpoint(endpoint, rawPayload, deps, store, signal) {
4619
+ try {
4620
+ if (isAborted4(signal)) return failure4("cancelled", "MCP \u6E05\u5355\u8BF7\u6C42\u5DF2\u53D6\u6D88\u3002");
4621
+ if (!isManagedMcpRpcEndpoint(endpoint)) {
4622
+ throw new ManagedMcpRequestError("bad-request", `\u672A\u77E5\u7684 MCP \u6E05\u5355\u7AEF\u70B9 '${endpoint}'`);
4623
+ }
4624
+ const payload = parseManagedMcpPayload(endpoint, rawPayload);
4625
+ if (endpoint === "assertion") {
4626
+ const assignmentId = payload.assignmentId;
4627
+ if (assignmentId === void 0) throw new ManagedMcpRequestError("bad-request", "\u53D6\u65AD\u8A00\u8BF7\u6C42\u7F3A\u5C11 assignmentId\u3002");
4628
+ return await handleAssertion(assignmentId, deps, signal);
4629
+ }
4630
+ const cached = store.peek();
4631
+ if (endpoint === "snapshot" && cached !== void 0) return { ok: true, value: cached };
4632
+ return { ok: true, value: await store.load() };
4633
+ } catch (error) {
4634
+ deps.log?.(`hiwork-core: MCP \u6E05\u5355 RPC '${endpoint}' \u5931\u8D25\uFF08${error instanceof Error ? error.name : typeof error}\uFF09`);
4635
+ return { ok: false, error: failureOf(error) };
4636
+ }
4637
+ }
4638
+ async function handleAssertion(assignmentId, deps, signal) {
4639
+ const sessionCookie = await deps.resolveSession();
4640
+ if (sessionCookie === void 0 || sessionCookie === "") {
4641
+ return failure4("SESSION_EXPIRED", MANAGED_MCP_SESSION_EXPIRED_MESSAGE);
4642
+ }
4643
+ const gateway = deps.gateway();
4644
+ if (gateway === void 0) {
4645
+ return failure4("GATEWAY_UNREACHABLE", "\u7F51\u5173\u5730\u5740\u672A\u914D\u7F6E\uFF0C\u8BF7\u5148\u5728\u300C\u7F51\u5173\u6A21\u578B\u300D\u91CC\u5B8C\u6210\u767B\u5F55");
4646
+ }
4647
+ if (isAborted4(signal)) return failure4("cancelled", "MCP \u6E05\u5355\u8BF7\u6C42\u5DF2\u53D6\u6D88\u3002");
4648
+ const ticket = await gateway.issueMyMcpAssertion(sessionCookie, assignmentId);
4649
+ const assertion = textOrUndefined(ticket?.assertion);
4650
+ const mintUrl = textOrUndefined(ticket?.mintUrl);
4651
+ if (assertion === void 0 || mintUrl === void 0) {
4652
+ deps.log?.("hiwork-core: \u53D6\u65AD\u8A00\u6536\u5230\u65E0\u6548\u54CD\u5E94\uFF08\u7F3A assertion / mintUrl\uFF09");
4653
+ return failure4("internal", MANAGED_MCP_GENERIC_FAILURE_MESSAGE);
4654
+ }
4655
+ return {
4656
+ ok: true,
4657
+ value: {
4658
+ assertion,
4659
+ mintUrl,
4660
+ revokeUrl: textOrUndefined(ticket?.revokeUrl) ?? "",
4661
+ expiresAt: textOrUndefined(ticket?.expiresAt) ?? "",
4662
+ serverName: textOrUndefined(ticket?.serverName) ?? ""
4663
+ }
4664
+ };
4665
+ }
4666
+ function failure4(code, message) {
4667
+ return { ok: false, error: { code, message, details: {} } };
4668
+ }
4669
+ function registerManagedMcpRpc(ctx, deps, store) {
4670
+ const handler = (endpoint, payload, signal) => handleManagedMcpEndpoint(endpoint, payload, deps, store, signal);
4671
+ const remove = ctx.connection.rpc.handle(MANAGED_MCP_RPC_CHANNEL, handler, { authority: "loopback" });
4672
+ return async () => {
4673
+ await remove();
4674
+ };
4675
+ }
4676
+
4404
4677
  // src/index.ts
4405
4678
  var name = "hiwork-core";
4406
4679
  var inject = ["settings", "credentials", "workspaceRegistry", "connection"];
@@ -4422,6 +4695,7 @@ var Config = Schema.object({
4422
4695
  browserLogin: Schema.object({ authorizeUrl: Schema.string().required(), startedAt: Schema.string().required() }).default(void 0),
4423
4696
  // 三值枚举:非法值写入直接被 schema 拒绝(客户端还会再归一一次,双保险)。
4424
4697
  loginMode: Schema.union([Schema.const("browser"), Schema.const("form"), Schema.const("both")]),
4698
+ passwordLogin: Schema.boolean(),
4425
4699
  budgets: Schema.array(Schema.object({
4426
4700
  model_name: Schema.string().required(),
4427
4701
  total_budget: Schema.number(),
@@ -4593,6 +4867,7 @@ function registerIpcMessageHandler(ports) {
4593
4867
  }
4594
4868
  async function projectLoginMode(opts) {
4595
4869
  let loginMode = DEFAULT_LOGIN_MODE;
4870
+ let passwordLogin = DEFAULT_PASSWORD_LOGIN;
4596
4871
  try {
4597
4872
  const baseURL = opts.baseURL;
4598
4873
  if (baseURL !== void 0 && baseURL !== "") {
@@ -4605,13 +4880,16 @@ async function projectLoginMode(opts) {
4605
4880
  deviceId: device.deviceId,
4606
4881
  ...opts.timeoutMs === void 0 ? {} : { timeoutMs: opts.timeoutMs }
4607
4882
  });
4608
- if (policy !== void 0) loginMode = policy.loginMode;
4883
+ if (policy !== void 0) {
4884
+ loginMode = policy.loginMode;
4885
+ passwordLogin = policy.passwordLogin;
4886
+ }
4609
4887
  }
4610
4888
  } catch (error) {
4611
4889
  opts.log?.(`hiwork-core: \u5BA2\u6237\u7AEF\u7B56\u7565\u62C9\u53D6\u5931\u8D25\uFF0C\u767B\u5F55\u65B9\u5F0F\u56DE\u9000 both\uFF08${errorName(error)}\uFF09`);
4612
4890
  }
4613
4891
  try {
4614
- await opts.state.patch({ set: { loginMode } });
4892
+ await opts.state.patch({ set: { loginMode, passwordLogin } });
4615
4893
  } catch (error) {
4616
4894
  opts.log?.(`hiwork-core: \u5BA2\u6237\u7AEF\u7B56\u7565\u5199\u5165\u5931\u8D25\uFF08${errorName(error)}\uFF09`);
4617
4895
  }
@@ -4751,6 +5029,34 @@ function apply(ctx, config) {
4751
5029
  ctx.logger.warn(message);
4752
5030
  }
4753
5031
  }), "hiwork-core: daily rpc");
5032
+ const managedMcpDeps = {
5033
+ resolveSession: async () => (await ports.credentials.resolve(SESSION_REF))?.value,
5034
+ gateway: () => {
5035
+ const baseURL = current().baseURL;
5036
+ return baseURL === void 0 || baseURL === "" ? void 0 : gatewayFor(baseURL);
5037
+ },
5038
+ log: (message) => {
5039
+ ctx.logger.warn(message);
5040
+ }
5041
+ };
5042
+ const managedMcp = new ManagedMcpStore(managedMcpDeps);
5043
+ ctx.effect(
5044
+ () => registerManagedMcpRpc({ connection, logger: ctx.logger }, managedMcpDeps, managedMcp),
5045
+ "hiwork-core: managed mcp rpc"
5046
+ );
5047
+ ctx.effect(() => {
5048
+ const warm = () => {
5049
+ void managedMcp.load().catch((error) => {
5050
+ ctx.logger.warn(`hiwork-core: \u53D7\u7BA1 MCP \u6E05\u5355\u9884\u70ED\u5931\u8D25\uFF08${error instanceof Error ? error.name : typeof error}\uFF09`);
5051
+ });
5052
+ };
5053
+ warm();
5054
+ const timer = setInterval(warm, MANAGED_MCP_REFRESH_INTERVAL_MS);
5055
+ timer.unref?.();
5056
+ return () => {
5057
+ clearInterval(timer);
5058
+ };
5059
+ }, "hiwork-core: managed mcp warmup");
4754
5060
  ctx.effect(() => registerAppVersionRpc({ connection, logger: ctx.logger }, {
4755
5061
  appVersion: () => pushedAppVersion(),
4756
5062
  log: (message) => {