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/ai-router-client.js +55 -0
- package/lib/client-policy.js +13 -1
- package/lib/client.js +314 -23
- package/lib/index.js +310 -4
- package/lib/managed-mcp.js +334 -0
- package/lib/types/ai-router-client.d.ts +70 -0
- package/lib/types/client/contracts.d.ts +25 -0
- package/lib/types/client/controller.d.ts +13 -0
- package/lib/types/client/daily-card.d.ts +32 -1
- package/lib/types/client/managed-mcp.d.ts +133 -0
- package/lib/types/client/session-cost.d.ts +19 -13
- package/lib/types/client/styles.d.ts +10 -2
- package/lib/types/client/types.d.ts +7 -1
- package/lib/types/client-policy.d.ts +8 -0
- package/lib/types/index.d.ts +12 -3
- package/lib/types/managed-mcp.d.ts +177 -0
- package/package.json +1 -1
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.
|
|
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)
|
|
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) => {
|