@clawos-dev/clawd 0.2.525 → 0.2.527
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/app-builder-plugin/mcp-server.cjs +15 -28
- package/dist/cli.cjs +123 -187
- package/dist/dispatch/mcp-server.cjs +15 -28
- package/dist/share-md-viewer-error.html +1 -1
- package/dist/share-md-viewer.html +1 -1
- package/dist/share-ui/assets/guest-CnDyufxk.css +32 -0
- package/dist/share-ui/assets/{guest-CqC7os4f.js → guest-DcCzHdsq.js} +132 -132
- package/dist/share-ui/guest.html +2 -2
- package/package.json +1 -1
- package/dist/share-ui/assets/guest-UkS4T7xe.css +0 -32
package/dist/cli.cjs
CHANGED
|
@@ -6098,7 +6098,7 @@ function cloudEngineOk(tool) {
|
|
|
6098
6098
|
function repoSlug(url) {
|
|
6099
6099
|
return url.trim().replace(/^git@[^:]+:/, "").replace(/^https?:\/\/[^/]+\//, "").replace(/\.git$/, "");
|
|
6100
6100
|
}
|
|
6101
|
-
var DeployFileSchema, SCAN_BASE_KINDS, ScanBaseKindSchema, DeployScanStatusSchema, DeployScanSchema, DeployRepoSchema, DeploySecretPresenceSchema, DEPLOY_STAGE_STATUSES, DeployStageStatusSchema, DEPLOY_STAGE_KEYS, DeployStageKeySchema, DeployJobSchema, DeployRunSchema, DeployStateSchema, DeployReleaseResultSchema, DeployPersonaArgsSchema,
|
|
6101
|
+
var DeployFileSchema, SCAN_BASE_KINDS, ScanBaseKindSchema, DeployScanStatusSchema, DeployScanSchema, DeployRepoSchema, DeploySecretPresenceSchema, DEPLOY_STAGE_STATUSES, DeployStageStatusSchema, DEPLOY_STAGE_KEYS, DeployStageKeySchema, DeployJobSchema, DeployRunSchema, DeployStateSchema, DeployReleaseResultSchema, DeployPersonaArgsSchema, DeployPatchArgsSchema, DeployPutSecretArgsSchema, DeployRerunJobArgsSchema, DeployReportFindingArgsSchema, DeployFinishScanArgsSchema, PERSONA_REPO_ORG;
|
|
6102
6102
|
var init_deploy_schemas = __esm({
|
|
6103
6103
|
"../protocol/src/deploy-schemas.ts"() {
|
|
6104
6104
|
"use strict";
|
|
@@ -6121,8 +6121,8 @@ var init_deploy_schemas = __esm({
|
|
|
6121
6121
|
/** 扫描时被告知的共享资产名单(判「扫描器后来长了新本事」用) */
|
|
6122
6122
|
scannedAssets: external_exports.array(external_exports.string()).default([]),
|
|
6123
6123
|
/**
|
|
6124
|
-
* 这次扫描是**对哪个 commit 的断言**。`deploy:
|
|
6125
|
-
*
|
|
6124
|
+
* 这次扫描是**对哪个 commit 的断言**。`deploy:release` 在起扫描之前会先把 persona 目录
|
|
6125
|
+
* 提交(只提交不推,推是发布末尾那一下的事),所以这个值一定是仓库里真实存在的一版。
|
|
6126
6126
|
*
|
|
6127
6127
|
* 有了它,「清单过没过时」才是个可判定的等式(`head === repo.head`),
|
|
6128
6128
|
* 而不是从 `dirty` / `ahead` 里猜——那两个字段判不出「清单是好几版之前扫的」。
|
|
@@ -6141,8 +6141,8 @@ var init_deploy_schemas = __esm({
|
|
|
6141
6141
|
*/
|
|
6142
6142
|
releasedHead: external_exports.string().min(1).optional(),
|
|
6143
6143
|
/**
|
|
6144
|
-
*
|
|
6145
|
-
*
|
|
6144
|
+
* 这次**实际**怎么扫的。档位由 daemon 定(有线上版本可比 + 有跑完的清单 → 软扫,否则硬扫),
|
|
6145
|
+
* 页面要显示的是真正发生的那个。
|
|
6146
6146
|
*
|
|
6147
6147
|
* `.default('hard')` 而不是必填:这个文件是 strict 解析的,存量记录没有这个字段,
|
|
6148
6148
|
* 定成必填会让 `readScan` 当场抛、上云页面直接打不开。而老记录确实都是从零扫的。
|
|
@@ -6217,20 +6217,17 @@ var init_deploy_schemas = __esm({
|
|
|
6217
6217
|
*/
|
|
6218
6218
|
fileError: external_exports.string().optional()
|
|
6219
6219
|
}).strict();
|
|
6220
|
-
DeployReleaseResultSchema = external_exports.
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6220
|
+
DeployReleaseResultSchema = external_exports.discriminatedUnion("outcome", [
|
|
6221
|
+
external_exports.object({
|
|
6222
|
+
outcome: external_exports.literal("pushed"),
|
|
6223
|
+
sha: external_exports.string().min(1),
|
|
6224
|
+
actionsUrl: external_exports.string().min(1)
|
|
6225
|
+
}).strict(),
|
|
6226
|
+
external_exports.object({ outcome: external_exports.literal("scanning") }).strict()
|
|
6227
|
+
]);
|
|
6224
6228
|
DeployPersonaArgsSchema = external_exports.object({
|
|
6225
6229
|
personaId: external_exports.string().min(1)
|
|
6226
6230
|
}).strict();
|
|
6227
|
-
DeployStartArgsSchema = DeployPersonaArgsSchema.extend({
|
|
6228
|
-
/**
|
|
6229
|
-
* 缺省 soft。真正用哪一档由 daemon 定(软扫比不了时会退硬扫),结果看 `DeployScan.baseKind`。
|
|
6230
|
-
* 复用上面那个中央定义的字面量,不在这里手抄一份。
|
|
6231
|
-
*/
|
|
6232
|
-
mode: ScanBaseKindSchema.optional()
|
|
6233
|
-
}).strict();
|
|
6234
6231
|
DeployPatchArgsSchema = external_exports.object({
|
|
6235
6232
|
personaId: external_exports.string().min(1),
|
|
6236
6233
|
patch: external_exports.object({
|
|
@@ -6450,7 +6447,7 @@ var init_feishu_auth = __esm({
|
|
|
6450
6447
|
// mirror peer sessions(远端会话镜像)
|
|
6451
6448
|
"peerSession:upsert",
|
|
6452
6449
|
"peerSession:remove",
|
|
6453
|
-
// 设备目录 + 连接(决策 #15:daemon 代理中心 server,需要 owner
|
|
6450
|
+
// 设备目录 + 连接(决策 #15:daemon 代理中心 server,需要 owner 的登录票)
|
|
6454
6451
|
"device:list",
|
|
6455
6452
|
"device:connect",
|
|
6456
6453
|
// iOS TestFlight 意向登记(需要 owner unionId 上报中心 server)
|
|
@@ -6520,13 +6517,7 @@ var init_feishu_auth = __esm({
|
|
|
6520
6517
|
* 设备属性,与登录态无关、登录登出不变。UI"我的设备标识"用它拼
|
|
6521
6518
|
* clawos://device/<deviceId>(替代旧的 unionId——不再向外暴露人的身份标识)。
|
|
6522
6519
|
*/
|
|
6523
|
-
deviceId: external_exports.string().min(1)
|
|
6524
|
-
/**
|
|
6525
|
-
* TTC JWT 过期时间(unix ms)。null = 登录回调未携带 expires_at;字段缺省 = 老 daemon。
|
|
6526
|
-
* 仅时间戳——token 本体永不出 ws(spec §9 不变)。UI 据此派生 过期/临期 提示
|
|
6527
|
-
* (见 spec 2026-08-17-ttc-jwt-expiry-ux-design §2)。
|
|
6528
|
-
*/
|
|
6529
|
-
ttcTokenExpiresAt: external_exports.number().nullable().optional()
|
|
6520
|
+
deviceId: external_exports.string().min(1)
|
|
6530
6521
|
});
|
|
6531
6522
|
AuthLogoutResponseSchema = external_exports.object({
|
|
6532
6523
|
type: external_exports.literal("auth:logout:ok")
|
|
@@ -8886,10 +8877,6 @@ var init_methods = __esm({
|
|
|
8886
8877
|
args: WorkspaceReadArgs
|
|
8887
8878
|
},
|
|
8888
8879
|
// ---- deploy:*(persona 上云:persona 目录 = git 仓库工作树,发布 = 推送触发仓库流水线)----
|
|
8889
|
-
"deploy:start": {
|
|
8890
|
-
summary: "\u5BF9\u67D0\u4E2A persona \u8D77\u4E00\u6B21\u4E0A\u4E91\u626B\u63CF\u3002**\u6CA1\u4ED3\u5E93\u5148\u5EFA\u4ED3**\uFF08GitHub REST \u5EFA\u5728\u7EC4\u7EC7\u4E0B\u3001\u79C1\u6709\uFF0Cgit \u63A8\u9996\u4E2A\u63D0\u4EA4\uFF1Btoken \u6765\u81EA\u672C\u673A git \u7684\u8EAB\u4EFD\uFF0C\u6CA1\u6388\u6743\u5148\u62D2\uFF09\uFF0C\u518D\u8D77 persona-butler \u7684\u626B\u63CF\u4F1A\u8BDD\uFF0C\u7ED3\u679C\u5199\u8FDB persona \u76EE\u5F55\u7684 .clawd/deploy.json \uFF08\u73AF\u5883\u6E05\u5355\uFF0C\u8FDB\u4ED3\u5E93\uFF09\u4E0E .clawd/deploy-scan.json\uFF08\u8BC1\u636E\uFF0C\u4E0D\u8FDB\u4ED3\u5E93\uFF09\u3002\u5DF2\u7ECF\u5728\u626B\u7684\u8BDD\u539F\u6837\u8FD4\u56DE\u3001\u4E0D\u8D77\u7B2C\u4E8C\u4E2A\u626B\u63CF\u4F1A\u8BDD\uFF1Bowner-only",
|
|
8891
|
-
args: DeployPersonaArgsSchema
|
|
8892
|
-
},
|
|
8893
8880
|
"deploy:get": {
|
|
8894
8881
|
summary: "\u4E0A\u4E91\u9875\u9762\u8981\u7684\u5168\u90E8\uFF1A\u4ED3\u5E93\u7ED1\u5B9A\u72B6\u6001\uFF08git \u73B0\u7B97\uFF09\u3001\u90E8\u7F72\u6587\u4EF6\u3001\u626B\u63CF\u8BB0\u5F55\u3001\u4ED3\u5E93 Secrets \u91CC\u5404\u53D8\u91CF\u540D\u586B\u8FC7\u6CA1\u6709\uFF08**\u53EA\u6709\u540D\u5B57\u548C\u65F6\u95F4\uFF0C\u6CA1\u6709\u503C**\uFF09\uFF1Bowner-only",
|
|
8895
8882
|
args: DeployPersonaArgsSchema
|
|
@@ -8911,7 +8898,7 @@ var init_methods = __esm({
|
|
|
8911
8898
|
args: DeployFinishScanArgsSchema
|
|
8912
8899
|
},
|
|
8913
8900
|
"deploy:release": {
|
|
8914
|
-
summary: "\u53D1\u5E03
|
|
8901
|
+
summary: "\u53D1\u5E03\u2014\u2014\u4E0A\u4E91\u552F\u4E00\u7684\u52A8\u4F5C\uFF0C\u626B\u63CF\u662F\u5B83\u7684\u7B2C\u4E00\u6BB5\u3002**\u6CA1\u4ED3\u5E93\u5148\u5EFA\u4ED3**\uFF08GitHub REST \u5EFA\u5728\u7EC4\u7EC7\u4E0B\u3001\u79C1\u6709\uFF0Cgit \u63A8\u9996\u4E2A\u63D0\u4EA4\uFF1Btoken \u6765\u81EA\u672C\u673A git \u7684\u8EAB\u4EFD\uFF0C\u6CA1\u6388\u6743\u5148\u62D2\uFF09\u3002\u6E05\u5355\u8FC7\u65F6\uFF08persona \u6539\u8FC7 / \u6CA1\u626B\u8FC7 / \u4E0A\u6B21\u626B\u5931\u8D25\uFF09\uFF1A\u5148\u628A persona \u76EE\u5F55\u63D0\u4EA4\u5230\u672C\u5730\uFF08\u4E0D\u63A8\uFF09\uFF0C\u8D77 persona-butler \u7684\u626B\u63CF\u4F1A\u8BDD\uFF0C\u56DE outcome=scanning\u2014\u2014\u7ED3\u679C\u5199\u8FDB .clawd/deploy.json\uFF08\u6E05\u5355\uFF0C\u8FDB\u4ED3\u5E93\uFF09\u4E0E .clawd/deploy-scan.json\uFF08\u8BC1\u636E\uFF0C\u4E0D\u8FDB\u4ED3\u5E93\uFF09\uFF0C\u6B63\u5728\u626B\u7684\u8BDD\u539F\u6837\u8FD4\u56DE\u4E0D\u8D77\u7B2C\u4E8C\u4E2A\u4F1A\u8BDD\u3002\u6E05\u5355\u65B0\u9C9C\uFF1A\u8FC7\u95F8\uFF08\u6BCF\u4E2A\u53D8\u91CF\u540D\u90FD\u5728 Secrets \u91CC\u3001\u8FDE\u63A5\u5668\u6765\u6E90\u70B9\u8FC7\u3001\u9009\u4E86\u6A21\u578B\uFF09\u2192 \u91CD\u5199 workflow \u6A21\u677F \u2192 git add -A \u2192 \u7A7A\u63D0\u4EA4\u4E5F\u5141\u8BB8 \u2192 push\uFF0C\u56DE outcome=pushed \u5E26 commit \u4E0E Actions \u5730\u5740\uFF1B\u4ED3\u5E93\u91CC\u7684\u6D41\u6C34\u7EBF\u63A5\u7740\u6784\u955C\u50CF\u3001\u8BD5\u8DD1\u3001\u767B\u8BB0\u3002owner-only",
|
|
8915
8902
|
args: DeployPersonaArgsSchema
|
|
8916
8903
|
},
|
|
8917
8904
|
"deploy:rerunJob": {
|
|
@@ -9309,7 +9296,7 @@ var init_methods = __esm({
|
|
|
9309
9296
|
args: NO_ARGS
|
|
9310
9297
|
},
|
|
9311
9298
|
"auth:getIdentity": {
|
|
9312
|
-
summary: "\u53D6\u672C\u673A owner \u7684\u98DE\u4E66\u8EAB\u4EFD\uFF08ownerId / provider / displayName / unionId\uFF09+ **\u672C\u673A deviceId**\uFF08\u8BBE\u5907\u5C5E\u6027\uFF0C\u4E0E\u767B\u5F55\u6001\u65E0\u5173\uFF1Bdevice:connect / contact:* / inbox:* \u7684\u4E3B\u952E\u90FD\u662F\u5B83\uFF09\uFF1B\u7EDD\u4E0D\u8FD4\u56DE
|
|
9299
|
+
summary: "\u53D6\u672C\u673A owner \u7684\u98DE\u4E66\u8EAB\u4EFD\uFF08ownerId / provider / displayName / unionId\uFF09+ **\u672C\u673A deviceId**\uFF08\u8BBE\u5907\u5C5E\u6027\uFF0C\u4E0E\u767B\u5F55\u6001\u65E0\u5173\uFF1Bdevice:connect / contact:* / inbox:* \u7684\u4E3B\u952E\u90FD\u662F\u5B83\uFF09\uFF1B\u7EDD\u4E0D\u8FD4\u56DE\u767B\u5F55\u7968",
|
|
9313
9300
|
args: NO_ARGS
|
|
9314
9301
|
},
|
|
9315
9302
|
"auth:logout": {
|
|
@@ -55209,7 +55196,7 @@ function fieldsOf(name, where, placeholders, warnings) {
|
|
|
55209
55196
|
const ok = [];
|
|
55210
55197
|
for (const p3 of uniq(placeholders)) {
|
|
55211
55198
|
if (ConnectorFieldSchema.safeParse(p3).success) ok.push(p3);
|
|
55212
|
-
else warnings.push(`MCP server\u300C${name}\u300D\u7684 ${where} \u91CC\u6709\u5360\u4F4D \${${p3}}\uFF0C\u53D8\u91CF\u540D\u4E0D\u5408\u5F62\u72B6\uFF08\u53EA\u80FD\u5927\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u4E0B\u5212\u7EBF\uFF0C\u5B57\u6BCD\u5F00\u5934\uFF09\uFF0C\u6CA1\u7B97\u8FDB\u8981\u586B\u7684\u53D8\u91CF\uFF1B\u6539\u540D\u540E\u91CD\u65B0\u626B\u63CF`);
|
|
55199
|
+
else warnings.push(`MCP server\u300C${name}\u300D\u7684 ${where} \u91CC\u6709\u5360\u4F4D \${${p3}}\uFF0C\u53D8\u91CF\u540D\u4E0D\u5408\u5F62\u72B6\uFF08\u53EA\u80FD\u5927\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u4E0B\u5212\u7EBF\uFF0C\u5B57\u6BCD\u5F00\u5934\uFF09\uFF0C\u6CA1\u7B97\u8FDB\u8981\u586B\u7684\u53D8\u91CF\uFF1B\u6539\u540D\u540E\u518D\u53D1\u5E03\u4E00\u6B21\uFF08\u4F1A\u91CD\u65B0\u626B\u63CF\uFF09`);
|
|
55213
55200
|
}
|
|
55214
55201
|
return ok;
|
|
55215
55202
|
}
|
|
@@ -55250,7 +55237,7 @@ function scanMcpConnectors(personaDir) {
|
|
|
55250
55237
|
for (const [name, raw] of Object.entries(servers)) {
|
|
55251
55238
|
const def = raw && typeof raw === "object" ? raw : {};
|
|
55252
55239
|
if (!ConnectorNameSchema.safeParse(name).success) {
|
|
55253
|
-
out.warnings.push(`MCP server\u300C${name}\u300D\u7684\u540D\u5B57\u4E0D\u5408\u5F62\u72B6\uFF08\u53EA\u80FD\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u77ED\u6A2A\u7EBF\uFF09\uFF0C\u6CA1\u5217\u8FDB\u6E05\u5355\uFF1B\u6539\u540D\u540E\u91CD\u65B0\u626B\u63CF`);
|
|
55240
|
+
out.warnings.push(`MCP server\u300C${name}\u300D\u7684\u540D\u5B57\u4E0D\u5408\u5F62\u72B6\uFF08\u53EA\u80FD\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u77ED\u6A2A\u7EBF\uFF09\uFF0C\u6CA1\u5217\u8FDB\u6E05\u5355\uFF1B\u6539\u540D\u540E\u518D\u53D1\u5E03\u4E00\u6B21\uFF08\u4F1A\u91CD\u65B0\u626B\u63CF\uFF09`);
|
|
55254
55241
|
continue;
|
|
55255
55242
|
}
|
|
55256
55243
|
const type = typeof def.type === "string" ? def.type.toLowerCase() : typeof def.url === "string" ? "http" : "stdio";
|
|
@@ -59358,7 +59345,7 @@ async function identityArgs(exec, dir) {
|
|
|
59358
59345
|
if (has(email) && has(name)) return [];
|
|
59359
59346
|
return ["-c", "user.name=clawd", "-c", "user.email=clawd@clawos.local"];
|
|
59360
59347
|
}
|
|
59361
|
-
async function
|
|
59348
|
+
async function writeGitignore(dir) {
|
|
59362
59349
|
const gi = import_node_path34.default.join(dir, ".gitignore");
|
|
59363
59350
|
let existing;
|
|
59364
59351
|
try {
|
|
@@ -59367,6 +59354,8 @@ async function writeTemplates(dir) {
|
|
|
59367
59354
|
existing = void 0;
|
|
59368
59355
|
}
|
|
59369
59356
|
await import_promises5.default.writeFile(gi, mergeGitignore(existing));
|
|
59357
|
+
}
|
|
59358
|
+
async function writeWorkflow(dir) {
|
|
59370
59359
|
const wf = import_node_path34.default.join(dir, WORKFLOW_PATH);
|
|
59371
59360
|
await import_promises5.default.mkdir(import_node_path34.default.dirname(wf), { recursive: true });
|
|
59372
59361
|
await import_promises5.default.writeFile(wf, WORKFLOW_TEMPLATE);
|
|
@@ -59405,7 +59394,8 @@ async function ensureRepo(exec, api, args) {
|
|
|
59405
59394
|
const { dir, org, personaId: personaId2 } = args;
|
|
59406
59395
|
const existing = await repoInfo(exec, dir);
|
|
59407
59396
|
if (existing) return { created: false, url: existing.url };
|
|
59408
|
-
await
|
|
59397
|
+
await writeGitignore(dir);
|
|
59398
|
+
await import_promises5.default.rm(import_node_path34.default.join(dir, WORKFLOW_PATH), { force: true });
|
|
59409
59399
|
let created;
|
|
59410
59400
|
try {
|
|
59411
59401
|
created = await createOrgRepo(exec, api, { dir, org, repoName: personaId2, message: "clawd: \u4E0A\u4E91", auth: args.auth });
|
|
@@ -59443,33 +59433,32 @@ async function hasCommit(exec, dir, sha) {
|
|
|
59443
59433
|
const r2 = await git(exec, dir, ["cat-file", "-e", `${sha}^{commit}`]);
|
|
59444
59434
|
return !r2.spawnError && r2.code === 0;
|
|
59445
59435
|
}
|
|
59446
|
-
async function
|
|
59436
|
+
async function commitAll(exec, args) {
|
|
59447
59437
|
await mustGit(exec, args.dir, ["add", "-A"], "\u6682\u5B58\u6587\u4EF6");
|
|
59448
59438
|
const staged = await git(exec, args.dir, ["diff", "--cached", "--quiet"]);
|
|
59449
59439
|
if (staged.code === 1) {
|
|
59450
59440
|
const identity = await identityArgs(exec, args.dir);
|
|
59451
59441
|
await mustGit(exec, args.dir, [...identity, "commit", "-m", args.message], "\u63D0\u4EA4");
|
|
59452
59442
|
}
|
|
59453
|
-
await gitPush(exec, args.dir, args.auth);
|
|
59454
59443
|
return mustGit(exec, args.dir, ["rev-parse", "HEAD"], "\u8BFB\u63D0\u4EA4");
|
|
59455
59444
|
}
|
|
59456
59445
|
async function release(exec, api, args) {
|
|
59457
59446
|
const info = await repoInfo(exec, args.dir);
|
|
59458
59447
|
if (!info) throw new RepoError("\u8FD8\u6CA1\u6709\u4ED3\u5E93\uFF0C\u5148\u70B9\u4E00\u6B21\u300C\u53D1\u5E03\u5230\u4E91\u4E0A\u300D\u5EFA\u4ED3");
|
|
59459
59448
|
await api.enableActions(repoSlug(info.url));
|
|
59460
|
-
await
|
|
59449
|
+
await writeGitignore(args.dir);
|
|
59450
|
+
await writeWorkflow(args.dir);
|
|
59461
59451
|
const identity = await identityArgs(exec, args.dir);
|
|
59462
59452
|
await mustGit(exec, args.dir, ["add", "-A"], "\u6682\u5B58\u6587\u4EF6");
|
|
59463
59453
|
const stamp = new Date(args.now()).toISOString();
|
|
59464
59454
|
await mustGit(exec, args.dir, [...identity, "commit", "--allow-empty", "-m", `clawd: \u53D1\u5E03 ${stamp}`], "\u63D0\u4EA4");
|
|
59465
59455
|
await gitPush(exec, args.dir, args.auth);
|
|
59466
59456
|
const sha = await mustGit(exec, args.dir, ["rev-parse", "HEAD"], "\u8BFB\u63D0\u4EA4");
|
|
59467
|
-
return { sha, actionsUrl: `https://github.com/${repoSlug(info.url)}/actions` };
|
|
59457
|
+
return { outcome: "pushed", sha, actionsUrl: `https://github.com/${repoSlug(info.url)}/actions` };
|
|
59468
59458
|
}
|
|
59469
59459
|
|
|
59470
59460
|
// src/deploy/scan-base.ts
|
|
59471
59461
|
function pickScanBase(args) {
|
|
59472
|
-
if (args.mode === "hard") return { kind: "hard" };
|
|
59473
59462
|
if (!args.hasUsableManifest || !args.releasedHead) return { kind: "hard" };
|
|
59474
59463
|
return { kind: "soft", base: args.releasedHead };
|
|
59475
59464
|
}
|
|
@@ -59563,7 +59552,7 @@ var STALE_ASSETS_NOTE_PREFIX = "\u3010\u4E0A\u4E91\u626B\u63CF\u3011";
|
|
|
59563
59552
|
function describeStaleAssets(stale) {
|
|
59564
59553
|
if (stale.length === 0) return void 0;
|
|
59565
59554
|
const plain = (s2) => s2.replace(/\*\*/g, "").replace(/\s+/g, " ").trim();
|
|
59566
|
-
return `${STALE_ASSETS_NOTE_PREFIX}\u8FD9\u6B21\u626B\u63CF\u7684\u65F6\u5019\uFF0C\u626B\u63CF\u5668\u8FD8\u4E0D\u77E5\u9053\u6709${stale.map((a2) => `\u300C${a2.name}\u300D`).join("\u3001")}\u8FD9${stale.length > 1 ? "\u51E0" : ""}\u9879\u5171\u4EAB\u8D44\u4EA7\uFF0C\u6240\u4EE5\u6E05\u5355\u91CC\u53EF\u80FD\u6F0F\u4E86\u58F0\u660E\u3002${stale.map((a2) => ` ${a2.name} \u662F\uFF1A${plain(a2.what)}`).join("")} \u7528\u5F97\u4E0A\u7684\u8BDD\uFF0C\u5728\u6E05\u5355\u91CC\u8865\u4E00\u6761 asset\
|
|
59555
|
+
return `${STALE_ASSETS_NOTE_PREFIX}\u8FD9\u6B21\u626B\u63CF\u7684\u65F6\u5019\uFF0C\u626B\u63CF\u5668\u8FD8\u4E0D\u77E5\u9053\u6709${stale.map((a2) => `\u300C${a2.name}\u300D`).join("\u3001")}\u8FD9${stale.length > 1 ? "\u51E0" : ""}\u9879\u5171\u4EAB\u8D44\u4EA7\uFF0C\u6240\u4EE5\u6E05\u5355\u91CC\u53EF\u80FD\u6F0F\u4E86\u58F0\u660E\u3002${stale.map((a2) => ` ${a2.name} \u662F\uFF1A${plain(a2.what)}`).join("")} \u7528\u5F97\u4E0A\u7684\u8BDD\uFF0C\u5728\u6E05\u5355\u91CC\u8865\u4E00\u6761 asset\u3002`;
|
|
59567
59556
|
}
|
|
59568
59557
|
function settleEndedScan(outcome, current, now) {
|
|
59569
59558
|
if (current?.status !== "scanning") return void 0;
|
|
@@ -59582,7 +59571,7 @@ function reconcileInterruptedScans(deps) {
|
|
|
59582
59571
|
...scan,
|
|
59583
59572
|
status: "failed",
|
|
59584
59573
|
finishedAt: deps.now,
|
|
59585
|
-
error: "daemon \u91CD\u542F\uFF0C\u626B\u63CF\u4F1A\u8BDD\u5DF2\u4E2D\u65AD\u2014\u2014\
|
|
59574
|
+
error: "daemon \u91CD\u542F\uFF0C\u626B\u63CF\u4F1A\u8BDD\u5DF2\u4E2D\u65AD\u2014\u2014\u518D\u70B9\u4E00\u6B21\u300C\u53D1\u5E03\u300D\u4F1A\u91CD\u65B0\u626B\u63CF"
|
|
59586
59575
|
});
|
|
59587
59576
|
flipped.push(personaId2);
|
|
59588
59577
|
}
|
|
@@ -59685,33 +59674,9 @@ function buildDeployHandlers(deps) {
|
|
|
59685
59674
|
const view = async (personaId2) => ({
|
|
59686
59675
|
response: { type: "deploy:state", ...await stateOf(personaId2) }
|
|
59687
59676
|
});
|
|
59688
|
-
|
|
59689
|
-
ensureOwner(ctx);
|
|
59690
|
-
const { personaId: personaId2, mode } = parseArgs2(DeployStartArgsSchema, frame, "deploy:start");
|
|
59691
|
-
const dir = mustPersona(personaId2);
|
|
59692
|
-
const wrong = wrongEngine(deps.personaEngine(personaId2)?.tool);
|
|
59693
|
-
if (wrong) throw invalid(wrong);
|
|
59694
|
-
const current = await readScan(dir);
|
|
59695
|
-
if (current?.status === "scanning") return view(personaId2);
|
|
59696
|
-
const { auth, api } = await requireGithub();
|
|
59697
|
-
if (!await repoInfo(deps.exec, dir)) {
|
|
59698
|
-
try {
|
|
59699
|
-
await ensureRepo(deps.exec, api, { dir, org: deps.org, personaId: personaId2, auth });
|
|
59700
|
-
} catch (err) {
|
|
59701
|
-
throw toClawdError(err);
|
|
59702
|
-
}
|
|
59703
|
-
secretsCache.delete(personaId2);
|
|
59704
|
-
}
|
|
59705
|
-
let head;
|
|
59706
|
-
try {
|
|
59707
|
-
head = await commitAndPush(deps.exec, { dir, message: `clawd: \u626B\u63CF\u524D\u843D\u5B58 ${new Date(deps.now()).toISOString()}`, auth });
|
|
59708
|
-
} catch (err) {
|
|
59709
|
-
throw toClawdError(err);
|
|
59710
|
-
}
|
|
59711
|
-
runCache.delete(personaId2);
|
|
59677
|
+
async function beginScan(personaId2, dir, current, head) {
|
|
59712
59678
|
const prevManifest = await readDeployFile(dir).catch(() => void 0);
|
|
59713
59679
|
const scanBase = pickScanBase({
|
|
59714
|
-
mode,
|
|
59715
59680
|
// **文件在 ≠ 清单能用**:硬扫一开头就写了一份空清单,那一轮没跑完(OTA 重启 / butler 崩,
|
|
59716
59681
|
// 见 scan-task.ts 的收尾判定)的话文件在、内容是空的。所以判据连上「上一轮扫完了」。
|
|
59717
59682
|
hasUsableManifest: prevManifest !== void 0 && current?.status === "done",
|
|
@@ -59762,8 +59727,7 @@ function buildDeployHandlers(deps) {
|
|
|
59762
59727
|
error: `\u8D77\u626B\u63CF\u4F1A\u8BDD\u5931\u8D25\uFF1A${started.error}`
|
|
59763
59728
|
});
|
|
59764
59729
|
}
|
|
59765
|
-
|
|
59766
|
-
};
|
|
59730
|
+
}
|
|
59767
59731
|
const get = async (frame, _client, ctx) => {
|
|
59768
59732
|
ensureOwner(ctx);
|
|
59769
59733
|
const { personaId: personaId2 } = parseArgs2(DeployPersonaArgsSchema, frame, "deploy:get");
|
|
@@ -59848,20 +59812,37 @@ function buildDeployHandlers(deps) {
|
|
|
59848
59812
|
ensureOwner(ctx);
|
|
59849
59813
|
const { personaId: personaId2 } = parseArgs2(DeployPersonaArgsSchema, frame, "deploy:release");
|
|
59850
59814
|
const dir = mustPersona(personaId2);
|
|
59851
|
-
const
|
|
59852
|
-
if (
|
|
59815
|
+
const wrong = wrongEngine(deps.personaEngine(personaId2)?.tool);
|
|
59816
|
+
if (wrong) throw invalid(wrong);
|
|
59817
|
+
const { auth, api } = await requireGithub();
|
|
59818
|
+
let repo2 = await repoInfo(deps.exec, dir);
|
|
59819
|
+
if (!repo2) {
|
|
59820
|
+
try {
|
|
59821
|
+
await ensureRepo(deps.exec, api, { dir, org: deps.org, personaId: personaId2, auth });
|
|
59822
|
+
} catch (err) {
|
|
59823
|
+
throw toClawdError(err);
|
|
59824
|
+
}
|
|
59825
|
+
secretsCache.delete(personaId2);
|
|
59826
|
+
repo2 = await repoInfo(deps.exec, dir);
|
|
59827
|
+
if (!repo2) throw new ClawdError(ERROR_CODES.INTERNAL, "\u4ED3\u5E93\u5EFA\u597D\u4E86\u4F46\u8BFB\u4E0D\u5230 origin");
|
|
59828
|
+
}
|
|
59853
59829
|
if (repo2.branch !== "main") throw invalid(`\u5F53\u524D\u5728\u5206\u652F ${repo2.branch}\uFF0C\u4ED3\u5E93\u91CC\u7684\u6D41\u6C34\u7EBF\u53EA\u8BA4 main\uFF1B\u5207\u56DE main \u518D\u53D1\u5E03`);
|
|
59830
|
+
const current = await readScan(dir);
|
|
59831
|
+
if (current?.status === "scanning") return { response: { type: "deploy:release", outcome: "scanning" } };
|
|
59832
|
+
const fileUsable = await readDeployFile(dir).then((f2) => f2 !== void 0).catch(() => false);
|
|
59833
|
+
if (!fileUsable || !isScanFresh(current, repo2)) {
|
|
59834
|
+
let head;
|
|
59835
|
+
try {
|
|
59836
|
+
head = await commitAll(deps.exec, { dir, message: `clawd: \u626B\u63CF\u524D\u843D\u5B58 ${new Date(deps.now()).toISOString()}` });
|
|
59837
|
+
} catch (err) {
|
|
59838
|
+
throw toClawdError(err);
|
|
59839
|
+
}
|
|
59840
|
+
runCache.delete(personaId2);
|
|
59841
|
+
await beginScan(personaId2, dir, current, head);
|
|
59842
|
+
return { response: { type: "deploy:release", outcome: "scanning" } };
|
|
59843
|
+
}
|
|
59854
59844
|
const file = await readDeployFile(dir);
|
|
59855
59845
|
if (!file) throw invalid("\u8FD8\u6CA1\u626B\u63CF\u51FA\u6E05\u5355");
|
|
59856
|
-
const scan = await readScan(dir);
|
|
59857
|
-
if (scan?.status === "scanning") throw invalid("\u626B\u63CF\u8FD8\u6CA1\u7ED3\u675F");
|
|
59858
|
-
if (scan?.status !== "done") throw invalid(scan?.status === "failed" ? "\u4E0A\u6B21\u626B\u63CF\u5931\u8D25\u4E86\uFF0C\u5148\u91CD\u65B0\u626B\u63CF" : "\u8FD8\u6CA1\u626B\u63CF\u8FC7\uFF0C\u5148\u626B\u63CF");
|
|
59859
|
-
if (!isScanFresh(scan, repo2)) {
|
|
59860
|
-
throw invalid(
|
|
59861
|
-
repo2.dirty ? "persona \u76EE\u5F55\u6709\u6539\u52A8\u8FD8\u6CA1\u626B\u8FC7\uFF0C\u5148\u91CD\u65B0\u626B\u63CF\u4E00\u6B21\uFF08\u6E05\u5355\u8981\u8DDF\u7740\u6539\u52A8\u8D70\uFF09" : "\u6E05\u5355\u662F\u66F4\u65E9\u90A3\u4E00\u7248\u626B\u51FA\u6765\u7684\uFF0C\u5148\u91CD\u65B0\u626B\u63CF\u4E00\u6B21"
|
|
59862
|
-
);
|
|
59863
|
-
}
|
|
59864
|
-
const { auth, api } = await requireGithub();
|
|
59865
59846
|
const blockers = [];
|
|
59866
59847
|
let present;
|
|
59867
59848
|
try {
|
|
@@ -59872,11 +59853,7 @@ function buildDeployHandlers(deps) {
|
|
|
59872
59853
|
const missing = requiredEnvNames(file).filter((e) => !present.has(e));
|
|
59873
59854
|
if (missing.length > 0) blockers.push(`${missing.join(" / ")} \u8FD8\u6CA1\u586B`);
|
|
59874
59855
|
for (const c2 of file.manifest.connectors) blockers.push(...connectorBlockers(c2));
|
|
59875
|
-
|
|
59876
|
-
const wrongTool = wrongEngine(engine?.tool);
|
|
59877
|
-
if (wrongTool) {
|
|
59878
|
-
blockers.push(wrongTool);
|
|
59879
|
-
} else if (!engine?.model) {
|
|
59856
|
+
if (!deps.personaEngine(personaId2)?.model) {
|
|
59880
59857
|
blockers.push("\u8FD8\u6CA1\u9009\u6A21\u578B\uFF08\u5207\u5F15\u64CE\u65F6\u4F1A\u6E05\u7A7A\uFF09\u2014\u2014\u53BB persona \u8BBE\u7F6E\u91CC\u9009\u4E00\u4E2A");
|
|
59881
59858
|
}
|
|
59882
59859
|
if (blockers.length > 0) throw invalid(`\u8FD8\u5DEE\uFF1A${blockers.join("\uFF1B")}`);
|
|
@@ -59912,7 +59889,6 @@ function buildDeployHandlers(deps) {
|
|
|
59912
59889
|
return view(personaId2);
|
|
59913
59890
|
};
|
|
59914
59891
|
return {
|
|
59915
|
-
"deploy:start": start,
|
|
59916
59892
|
"deploy:get": get,
|
|
59917
59893
|
"deploy:patch": patch,
|
|
59918
59894
|
"deploy:putSecret": putSecret,
|
|
@@ -62144,7 +62120,7 @@ async function centralRequest(opts, path101, init) {
|
|
|
62144
62120
|
}
|
|
62145
62121
|
clearTimeout(timer);
|
|
62146
62122
|
if (res.status === 401) {
|
|
62147
|
-
throw new CentralClientError("UNAUTHORIZED", "
|
|
62123
|
+
throw new CentralClientError("UNAUTHORIZED", "login pass rejected by center");
|
|
62148
62124
|
}
|
|
62149
62125
|
if (!res.ok) {
|
|
62150
62126
|
let detail = "";
|
|
@@ -62164,12 +62140,8 @@ async function centralRequest(opts, path101, init) {
|
|
|
62164
62140
|
async function centralExchange(opts) {
|
|
62165
62141
|
const body = await centralRequest(opts, "/api/clawd-identity/exchange", {
|
|
62166
62142
|
method: "POST",
|
|
62167
|
-
|
|
62168
|
-
|
|
62169
|
-
provider: opts.provider,
|
|
62170
|
-
deviceId: opts.deviceId,
|
|
62171
|
-
selfDeviceId: opts.selfDeviceId
|
|
62172
|
-
}
|
|
62143
|
+
bearer: opts.loginPass,
|
|
62144
|
+
body: { deviceId: opts.deviceId }
|
|
62173
62145
|
});
|
|
62174
62146
|
if (typeof body.token !== "string" || body.token.length === 0 || typeof body.ownerId !== "string" || typeof body.provider !== "string" || typeof body.displayName !== "string") {
|
|
62175
62147
|
throw new CentralClientError("BAD_RESPONSE", "exchange: missing token/ownerId/provider/displayName");
|
|
@@ -62189,10 +62161,8 @@ async function centralGetPublicKey(opts) {
|
|
|
62189
62161
|
async function centralUpsertDevice(opts) {
|
|
62190
62162
|
const body = await centralRequest(opts, "/api/clawd-identity/devices/self", {
|
|
62191
62163
|
method: "PUT",
|
|
62192
|
-
bearer: opts.
|
|
62164
|
+
bearer: opts.loginPass,
|
|
62193
62165
|
body: {
|
|
62194
|
-
deviceId: opts.deviceId,
|
|
62195
|
-
provider: opts.provider,
|
|
62196
62166
|
...opts.url ? { url: opts.url } : {},
|
|
62197
62167
|
...opts.name ? { name: opts.name } : {}
|
|
62198
62168
|
}
|
|
@@ -62200,10 +62170,7 @@ async function centralUpsertDevice(opts) {
|
|
|
62200
62170
|
if (body.ok !== true) {
|
|
62201
62171
|
throw new CentralClientError("BAD_RESPONSE", "upsertDevice: server did not ack ok");
|
|
62202
62172
|
}
|
|
62203
|
-
return {
|
|
62204
|
-
ok: true,
|
|
62205
|
-
...typeof body.loginPass === "string" && body.loginPass.length > 0 ? { loginPass: body.loginPass } : {}
|
|
62206
|
-
};
|
|
62173
|
+
return { ok: true };
|
|
62207
62174
|
}
|
|
62208
62175
|
async function centralPrincipalStatus(opts) {
|
|
62209
62176
|
const query = `provider=${encodeURIComponent(opts.provider)}&ownerId=${encodeURIComponent(opts.ownerId)}`;
|
|
@@ -62216,11 +62183,10 @@ async function centralPrincipalStatus(opts) {
|
|
|
62216
62183
|
return { active: body.active };
|
|
62217
62184
|
}
|
|
62218
62185
|
async function centralGetApiKey(opts) {
|
|
62219
|
-
const body = await centralRequest(
|
|
62220
|
-
|
|
62221
|
-
|
|
62222
|
-
|
|
62223
|
-
);
|
|
62186
|
+
const body = await centralRequest(opts, "/api/persona-cloud/api-key", {
|
|
62187
|
+
method: "GET",
|
|
62188
|
+
bearer: opts.loginPass
|
|
62189
|
+
});
|
|
62224
62190
|
if (body.apiKey !== null && typeof body.apiKey !== "string") {
|
|
62225
62191
|
throw new CentralClientError("BAD_RESPONSE", "api-key: apiKey must be string or null");
|
|
62226
62192
|
}
|
|
@@ -62234,8 +62200,7 @@ async function centralGetApiKey(opts) {
|
|
|
62234
62200
|
async function centralIssueApiKey(opts) {
|
|
62235
62201
|
const body = await centralRequest(opts, "/api/persona-cloud/api-key", {
|
|
62236
62202
|
method: "POST",
|
|
62237
|
-
bearer: opts.
|
|
62238
|
-
body: { provider: opts.provider }
|
|
62203
|
+
bearer: opts.loginPass
|
|
62239
62204
|
});
|
|
62240
62205
|
if (typeof body.apiKey !== "string" || body.apiKey.length === 0) {
|
|
62241
62206
|
throw new CentralClientError("BAD_RESPONSE", "api-key: missing apiKey");
|
|
@@ -62250,11 +62215,10 @@ async function centralIssueApiKey(opts) {
|
|
|
62250
62215
|
};
|
|
62251
62216
|
}
|
|
62252
62217
|
async function centralListDevices(opts) {
|
|
62253
|
-
const body = await centralRequest(
|
|
62254
|
-
|
|
62255
|
-
|
|
62256
|
-
|
|
62257
|
-
);
|
|
62218
|
+
const body = await centralRequest(opts, "/api/clawd-identity/devices", {
|
|
62219
|
+
method: "GET",
|
|
62220
|
+
bearer: opts.loginPass
|
|
62221
|
+
});
|
|
62258
62222
|
if (!Array.isArray(body.devices)) {
|
|
62259
62223
|
throw new CentralClientError("BAD_RESPONSE", "devices: missing devices array");
|
|
62260
62224
|
}
|
|
@@ -62271,8 +62235,8 @@ async function centralListDevices(opts) {
|
|
|
62271
62235
|
async function centralConnectorsMine(opts) {
|
|
62272
62236
|
const body = await centralRequest(opts, "/api/persona-cloud/connectors/mine", {
|
|
62273
62237
|
method: "POST",
|
|
62274
|
-
bearer: opts.
|
|
62275
|
-
body: {
|
|
62238
|
+
bearer: opts.loginPass,
|
|
62239
|
+
body: { personaId: opts.personaId, connectors: opts.connectors }
|
|
62276
62240
|
});
|
|
62277
62241
|
if (!Array.isArray(body.connectors)) throw new CentralClientError("BAD_RESPONSE", "connectors/mine: missing connectors array");
|
|
62278
62242
|
return { connectors: body.connectors };
|
|
@@ -62280,16 +62244,16 @@ async function centralConnectorsMine(opts) {
|
|
|
62280
62244
|
async function centralConnectorFill(opts) {
|
|
62281
62245
|
const body = await centralRequest(opts, "/api/persona-cloud/connectors/fields", {
|
|
62282
62246
|
method: "PUT",
|
|
62283
|
-
bearer: opts.
|
|
62284
|
-
body: {
|
|
62247
|
+
bearer: opts.loginPass,
|
|
62248
|
+
body: { connector: opts.connector, values: opts.values }
|
|
62285
62249
|
});
|
|
62286
62250
|
if (body.ok !== true) throw new CentralClientError("BAD_RESPONSE", "connectors/fields: server did not ack ok");
|
|
62287
62251
|
}
|
|
62288
62252
|
async function centralGithubAuthOauthStart(opts) {
|
|
62289
62253
|
const body = await centralRequest(opts, "/api/persona-cloud/github/oauth/start", {
|
|
62290
62254
|
method: "POST",
|
|
62291
|
-
bearer: opts.
|
|
62292
|
-
body: {
|
|
62255
|
+
bearer: opts.loginPass,
|
|
62256
|
+
body: { ...opts.returnTo ? { returnTo: opts.returnTo } : {} }
|
|
62293
62257
|
});
|
|
62294
62258
|
if (typeof body.authUrl !== "string" || !body.authUrl) throw new CentralClientError("BAD_RESPONSE", "github/oauth/start: missing authUrl");
|
|
62295
62259
|
return { authUrl: body.authUrl };
|
|
@@ -62297,8 +62261,8 @@ async function centralGithubAuthOauthStart(opts) {
|
|
|
62297
62261
|
async function centralGithubAuthToken(opts) {
|
|
62298
62262
|
const body = await centralRequest(opts, "/api/persona-cloud/github/oauth/token", {
|
|
62299
62263
|
method: "POST",
|
|
62300
|
-
bearer: opts.
|
|
62301
|
-
body: {
|
|
62264
|
+
bearer: opts.loginPass,
|
|
62265
|
+
body: {}
|
|
62302
62266
|
});
|
|
62303
62267
|
if (body.token === null || body.token === void 0) return void 0;
|
|
62304
62268
|
if (typeof body.token !== "string" || !body.token) throw new CentralClientError("BAD_RESPONSE", "github/oauth/token: malformed token");
|
|
@@ -62337,10 +62301,10 @@ var CloudGatewayClient = class {
|
|
|
62337
62301
|
deps;
|
|
62338
62302
|
fetchImpl;
|
|
62339
62303
|
async credentials() {
|
|
62340
|
-
const
|
|
62341
|
-
if (!
|
|
62304
|
+
const loginPass = this.deps.getLoginPass();
|
|
62305
|
+
if (!loginPass) throw new ClawdError(ERROR_CODES.FEISHU_LOGIN_REQUIRED, "\u8FD8\u6CA1\u767B\u5F55\u98DE\u4E66\uFF0C\u4E91\u4E0A persona \u7528\u4E0D\u4E86");
|
|
62342
62306
|
const get = this.deps.getApiKey ?? ((args) => centralGetApiKey({ api: this.deps.centralApi ?? "", fetchImpl: this.fetchImpl, ...args }));
|
|
62343
|
-
const { apiKey, gatewayUrl } = await get({
|
|
62307
|
+
const { apiKey, gatewayUrl } = await get({ loginPass });
|
|
62344
62308
|
if (!apiKey) throw new Error("\u8FD8\u6CA1\u751F\u6210\u4E91 persona \u7684\u8C03\u7528 key\uFF0C\u53BB\u300C\u8BBE\u7F6E \u2192 \u4E91\u4E0A persona\u300D\u751F\u6210\u4E00\u628A");
|
|
62345
62309
|
if (!gatewayUrl) throw new Error("\u4E2D\u5FC3\u6CA1\u914D\u4E91 gateway \u5730\u5740\uFF08gatewayUrl \u4E3A\u7A7A\uFF09");
|
|
62346
62310
|
return { apiKey, gatewayUrl: trimSlash(gatewayUrl) };
|
|
@@ -65896,8 +65860,7 @@ async function importZip(buf, root) {
|
|
|
65896
65860
|
function parseLoginCallbackQuery(url) {
|
|
65897
65861
|
return {
|
|
65898
65862
|
token: url.searchParams.get("token") ?? "",
|
|
65899
|
-
state: url.searchParams.get("state") ?? ""
|
|
65900
|
-
expiresAt: url.searchParams.get("expires_at")
|
|
65863
|
+
state: url.searchParams.get("state") ?? ""
|
|
65901
65864
|
};
|
|
65902
65865
|
}
|
|
65903
65866
|
function escapeHtml(s2) {
|
|
@@ -67558,7 +67521,7 @@ var OwnerIdentityStore = class {
|
|
|
67558
67521
|
return null;
|
|
67559
67522
|
}
|
|
67560
67523
|
const r2 = parsed;
|
|
67561
|
-
if (!r2.identity || typeof r2.identity.ownerId !== "string" || r2.identity.ownerId.length === 0 || typeof r2.identity.provider !== "string" || r2.identity.provider.length === 0 || typeof r2.identity.displayName !== "string" || r2.identity.displayName.length === 0 || typeof r2.
|
|
67524
|
+
if (!r2.identity || typeof r2.identity.ownerId !== "string" || r2.identity.ownerId.length === 0 || typeof r2.identity.provider !== "string" || r2.identity.provider.length === 0 || typeof r2.identity.displayName !== "string" || r2.identity.displayName.length === 0 || typeof r2.loginPass !== "string" || r2.loginPass.length === 0) {
|
|
67562
67525
|
return null;
|
|
67563
67526
|
}
|
|
67564
67527
|
return {
|
|
@@ -67569,10 +67532,8 @@ var OwnerIdentityStore = class {
|
|
|
67569
67532
|
...typeof r2.identity.avatarUrl === "string" ? { avatarUrl: r2.identity.avatarUrl } : {},
|
|
67570
67533
|
...typeof r2.identity.unionId === "string" ? { unionId: r2.identity.unionId } : {}
|
|
67571
67534
|
},
|
|
67572
|
-
|
|
67573
|
-
|
|
67574
|
-
loginAt: typeof r2.loginAt === "string" ? r2.loginAt : (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
67575
|
-
...typeof r2.loginPass === "string" && r2.loginPass.length > 0 ? { loginPass: r2.loginPass } : {}
|
|
67535
|
+
loginPass: r2.loginPass,
|
|
67536
|
+
loginAt: typeof r2.loginAt === "string" ? r2.loginAt : (/* @__PURE__ */ new Date(0)).toISOString()
|
|
67576
67537
|
};
|
|
67577
67538
|
}
|
|
67578
67539
|
write(record4) {
|
|
@@ -67649,13 +67610,10 @@ var LoginFlow = class {
|
|
|
67649
67610
|
reason: `device_binding upsert failed: ${err.message}`
|
|
67650
67611
|
};
|
|
67651
67612
|
}
|
|
67652
|
-
const expiresAtNum = params.expiresAt ? Number.parseInt(params.expiresAt, 10) : NaN;
|
|
67653
67613
|
this.deps.store.write({
|
|
67654
67614
|
identity,
|
|
67655
|
-
|
|
67656
|
-
|
|
67657
|
-
loginAt: new Date(now).toISOString(),
|
|
67658
|
-
...loginPass ? { loginPass } : {}
|
|
67615
|
+
loginPass,
|
|
67616
|
+
loginAt: new Date(now).toISOString()
|
|
67659
67617
|
});
|
|
67660
67618
|
return { ok: true, identity };
|
|
67661
67619
|
}
|
|
@@ -67765,7 +67723,10 @@ async function upsertDeviceBinding(opts) {
|
|
|
67765
67723
|
body = await res.json();
|
|
67766
67724
|
} catch {
|
|
67767
67725
|
}
|
|
67768
|
-
|
|
67726
|
+
if (typeof body.loginPass !== "string" || body.loginPass.length === 0) {
|
|
67727
|
+
throw new DeviceBindingClientError("BAD_RESPONSE", "center did not issue a login pass (api too old?)");
|
|
67728
|
+
}
|
|
67729
|
+
return { loginPass: body.loginPass };
|
|
67769
67730
|
}
|
|
67770
67731
|
|
|
67771
67732
|
// src/contact/org-mesh.ts
|
|
@@ -67872,7 +67833,7 @@ function rethrowLoginExpired(e) {
|
|
|
67872
67833
|
if (e instanceof CentralClientError && e.code === "UNAUTHORIZED") {
|
|
67873
67834
|
throw new ClawdError(
|
|
67874
67835
|
ERROR_CODES.VALIDATION_ERROR,
|
|
67875
|
-
`${LOGIN_EXPIRED_ERROR_MARKER}: \u767B\u5F55\
|
|
67836
|
+
`${LOGIN_EXPIRED_ERROR_MARKER}: \u767B\u5F55\u7968\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55`
|
|
67876
67837
|
);
|
|
67877
67838
|
}
|
|
67878
67839
|
throw e;
|
|
@@ -69974,9 +69935,7 @@ function buildFeishuAuthHandlers(deps) {
|
|
|
69974
69935
|
type: "auth:getIdentity:ok",
|
|
69975
69936
|
identity: record4 ? record4.identity : null,
|
|
69976
69937
|
// 决策 #15:设备属性,与登录态无关——UI"分享我的 Hub 标识"用
|
|
69977
|
-
deviceId: deps.deviceId
|
|
69978
|
-
// 过期时间戳(仅时间戳,token 本体永不出 ws)——UI 派生 过期/临期 提示
|
|
69979
|
-
ttcTokenExpiresAt: record4 ? record4.ttcTokenExpiresAt : null
|
|
69938
|
+
deviceId: deps.deviceId
|
|
69980
69939
|
}
|
|
69981
69940
|
};
|
|
69982
69941
|
};
|
|
@@ -69996,7 +69955,7 @@ function buildFeishuAuthHandlers(deps) {
|
|
|
69996
69955
|
"\u8FD8\u6CA1\u767B\u5F55\u98DE\u4E66\uFF0C\u62FF\u4E0D\u5230\u4E91 persona \u7684\u8C03\u7528 key"
|
|
69997
69956
|
);
|
|
69998
69957
|
}
|
|
69999
|
-
return {
|
|
69958
|
+
return { loginPass: record4.loginPass };
|
|
70000
69959
|
}
|
|
70001
69960
|
const apiKeyGet = async () => {
|
|
70002
69961
|
const { apiKey, createdAt, gatewayUrl } = await deps.apiKeyClient.get(requireLogin());
|
|
@@ -70029,9 +69988,9 @@ function ensureOwner6(ctx) {
|
|
|
70029
69988
|
var invalid2 = (msg) => new ClawdError(ERROR_CODES.VALIDATION_ERROR, `VALIDATION_ERROR: ${msg}`);
|
|
70030
69989
|
function buildCloudConnectorsHandlers(deps) {
|
|
70031
69990
|
function requireLogin() {
|
|
70032
|
-
const
|
|
70033
|
-
if (!
|
|
70034
|
-
return
|
|
69991
|
+
const loginPass = deps.getLoginPass();
|
|
69992
|
+
if (!loginPass) throw new ClawdError(ERROR_CODES.FEISHU_LOGIN_REQUIRED, "FEISHU_LOGIN_REQUIRED: \u8FD8\u6CA1\u767B\u5F55\u98DE\u4E66\uFF0C\u4E91\u4E0A persona \u7684\u8FDE\u63A5\u5668\u7528\u4E0D\u4E86");
|
|
69993
|
+
return { loginPass };
|
|
70035
69994
|
}
|
|
70036
69995
|
async function personalConnectors(personaId2) {
|
|
70037
69996
|
const persona = deps.getPersona(personaId2);
|
|
@@ -70115,7 +70074,6 @@ var METHOD_GRANT_MAP = {
|
|
|
70115
70074
|
"visitor:list": ADMIN_ANY,
|
|
70116
70075
|
// deploy:*(persona 上云):全部 owner-only。里面有凭据录入口、建仓和推送,
|
|
70117
70076
|
// guest 不该看见更不该动。
|
|
70118
|
-
"deploy:start": ADMIN_ANY,
|
|
70119
70077
|
"deploy:get": ADMIN_ANY,
|
|
70120
70078
|
"deploy:patch": ADMIN_ANY,
|
|
70121
70079
|
"deploy:putSecret": ADMIN_ANY,
|
|
@@ -70317,13 +70275,12 @@ var METHOD_GRANT_MAP = {
|
|
|
70317
70275
|
"auth:apiKey:get": ADMIN_ANY,
|
|
70318
70276
|
"auth:apiKey:regenerate": ADMIN_ANY,
|
|
70319
70277
|
// ---- device:* 设备目录 + 连接(决策 #15,owner-only) ----
|
|
70320
|
-
// 设备目录 / 连接都是 owner
|
|
70278
|
+
// 设备目录 / 连接都是 owner 本机操作(用本机登录票找中心 server),guest 不可调
|
|
70321
70279
|
"device:list": ADMIN_ANY,
|
|
70322
70280
|
"device:connect": ADMIN_ANY,
|
|
70323
70281
|
"device:connections": ADMIN_ANY
|
|
70324
70282
|
};
|
|
70325
70283
|
var HUMAN_ONLY_METHODS = [
|
|
70326
|
-
"deploy:start",
|
|
70327
70284
|
"deploy:release",
|
|
70328
70285
|
"deploy:putSecret",
|
|
70329
70286
|
"deploy:rerunJob",
|
|
@@ -70371,7 +70328,7 @@ function computeMethodAccess(args) {
|
|
|
70371
70328
|
}
|
|
70372
70329
|
|
|
70373
70330
|
// src/version.ts
|
|
70374
|
-
var version = "0.2.
|
|
70331
|
+
var version = "0.2.527".length > 0 ? "0.2.527" : "dev";
|
|
70375
70332
|
|
|
70376
70333
|
// src/cli-probe/probe.ts
|
|
70377
70334
|
var fs77 = __toESM(require("fs"), 1);
|
|
@@ -73032,8 +72989,8 @@ async function startDaemon(config) {
|
|
|
73032
72989
|
});
|
|
73033
72990
|
},
|
|
73034
72991
|
// 验票第二段(spec 2026-08-28):本地验签只证明"票是中心签的",这一步问中心
|
|
73035
|
-
// "持票人还在职吗"。token
|
|
73036
|
-
//
|
|
72992
|
+
// "持票人还在职吗"。token 不再过期,撤销全靠它。端点无鉴权——不带本机登录票,
|
|
72993
|
+
// 本机没登录也能验别人的票。
|
|
73037
72994
|
checkPrincipalActive: async (provider, ownerId2) => {
|
|
73038
72995
|
const r2 = await centralPrincipalStatus({
|
|
73039
72996
|
api: config.clawosApi ?? DEFAULT_CLAWOS_API,
|
|
@@ -73183,7 +73140,7 @@ async function startDaemon(config) {
|
|
|
73183
73140
|
const r2 = ownerIdentityStore.read();
|
|
73184
73141
|
if (!r2) throw new ClawdError(ERROR_CODES.FEISHU_LOGIN_REQUIRED, "FEISHU_LOGIN_REQUIRED: \u8FD8\u6CA1\u767B\u5F55\u98DE\u4E66\uFF0C\u5173\u8054 GitHub \u8981\u7ECF\u4E2D\u5FC3\uFF1B\u5148\u767B\u5F55\uFF0C\u6216\u5728\u5361\u7247\u4E0A\u624B\u52A8\u7C98 token");
|
|
73185
73142
|
try {
|
|
73186
|
-
return await centralGithubAuthOauthStart({ api: config.clawosApi ?? DEFAULT_CLAWOS_API,
|
|
73143
|
+
return await centralGithubAuthOauthStart({ api: config.clawosApi ?? DEFAULT_CLAWOS_API, loginPass: r2.loginPass, ...returnTo ? { returnTo } : {} });
|
|
73187
73144
|
} catch (err) {
|
|
73188
73145
|
throw new ClawdError(ERROR_CODES.INTERNAL, `\u5411\u4E2D\u5FC3\u8981 GitHub \u6388\u6743\u94FE\u63A5\u6CA1\u6210\uFF1A${err instanceof Error ? err.message : String(err)}`);
|
|
73189
73146
|
}
|
|
@@ -73191,7 +73148,7 @@ async function startDaemon(config) {
|
|
|
73191
73148
|
token: async () => {
|
|
73192
73149
|
const r2 = ownerIdentityStore.read();
|
|
73193
73150
|
if (!r2) return void 0;
|
|
73194
|
-
return centralGithubAuthToken({ api: config.clawosApi ?? DEFAULT_CLAWOS_API,
|
|
73151
|
+
return centralGithubAuthToken({ api: config.clawosApi ?? DEFAULT_CLAWOS_API, loginPass: r2.loginPass });
|
|
73195
73152
|
}
|
|
73196
73153
|
},
|
|
73197
73154
|
now: () => Date.now(),
|
|
@@ -73593,10 +73550,7 @@ async function startDaemon(config) {
|
|
|
73593
73550
|
screenIdleProbeLogger
|
|
73594
73551
|
}) : new ClaudeAdapter({ logger, historyReader: new ClaudeHistoryReader() });
|
|
73595
73552
|
const cloudGateway = new CloudGatewayClient({
|
|
73596
|
-
|
|
73597
|
-
const r2 = ownerIdentityStore.read();
|
|
73598
|
-
return r2 ? { ttcToken: r2.ttcToken, provider: r2.identity.provider } : null;
|
|
73599
|
-
},
|
|
73553
|
+
getLoginPass: () => ownerIdentityStore.read()?.loginPass ?? null,
|
|
73600
73554
|
centralApi: config.clawosApi ?? DEFAULT_CLAWOS_API,
|
|
73601
73555
|
logger
|
|
73602
73556
|
});
|
|
@@ -73701,24 +73655,15 @@ async function startDaemon(config) {
|
|
|
73701
73655
|
const record4 = ownerIdentityStore.read();
|
|
73702
73656
|
if (!record4) return;
|
|
73703
73657
|
try {
|
|
73704
|
-
|
|
73658
|
+
await centralUpsertDevice({
|
|
73705
73659
|
api: config.clawosApi ?? DEFAULT_CLAWOS_API,
|
|
73706
|
-
|
|
73707
|
-
provider: record4.identity.provider,
|
|
73708
|
-
deviceId: authFile.deviceId,
|
|
73660
|
+
loginPass: record4.loginPass,
|
|
73709
73661
|
url: currentTunnelUrl ?? void 0,
|
|
73710
73662
|
name: ownerDisplayName
|
|
73711
73663
|
});
|
|
73712
|
-
if (r2.loginPass) {
|
|
73713
|
-
const latest = ownerIdentityStore.read();
|
|
73714
|
-
if (latest && latest.ttcToken === record4.ttcToken && latest.loginPass !== r2.loginPass) {
|
|
73715
|
-
ownerIdentityStore.write({ ...latest, loginPass: r2.loginPass });
|
|
73716
|
-
}
|
|
73717
|
-
}
|
|
73718
73664
|
logger.info("device registered to central server", {
|
|
73719
73665
|
deviceId: authFile.deviceId,
|
|
73720
|
-
url: currentTunnelUrl ?? "(none)"
|
|
73721
|
-
loginPass: r2.loginPass ? "issued" : "absent"
|
|
73666
|
+
url: currentTunnelUrl ?? "(none)"
|
|
73722
73667
|
});
|
|
73723
73668
|
} catch (err) {
|
|
73724
73669
|
logger.warn("device register failed (best-effort)", { err: err.message });
|
|
@@ -73728,7 +73673,7 @@ async function startDaemon(config) {
|
|
|
73728
73673
|
const runOrgMesh = async () => {
|
|
73729
73674
|
if (!feishuActive || orgMeshInFlight) return;
|
|
73730
73675
|
const record4 = ownerIdentityStore.read();
|
|
73731
|
-
if (!record4
|
|
73676
|
+
if (!record4) return;
|
|
73732
73677
|
const loginPass = record4.loginPass;
|
|
73733
73678
|
orgMeshInFlight = true;
|
|
73734
73679
|
try {
|
|
@@ -73776,10 +73721,8 @@ async function startDaemon(config) {
|
|
|
73776
73721
|
}
|
|
73777
73722
|
return centralExchange({
|
|
73778
73723
|
api: config.clawosApi ?? DEFAULT_CLAWOS_API,
|
|
73779
|
-
|
|
73780
|
-
|
|
73781
|
-
deviceId,
|
|
73782
|
-
selfDeviceId: authFile.deviceId
|
|
73724
|
+
loginPass: record4.loginPass,
|
|
73725
|
+
deviceId
|
|
73783
73726
|
});
|
|
73784
73727
|
},
|
|
73785
73728
|
listDevices: async () => {
|
|
@@ -73789,8 +73732,7 @@ async function startDaemon(config) {
|
|
|
73789
73732
|
}
|
|
73790
73733
|
return centralListDevices({
|
|
73791
73734
|
api: config.clawosApi ?? DEFAULT_CLAWOS_API,
|
|
73792
|
-
|
|
73793
|
-
provider: record4.identity.provider
|
|
73735
|
+
loginPass: record4.loginPass
|
|
73794
73736
|
});
|
|
73795
73737
|
},
|
|
73796
73738
|
connectRemote,
|
|
@@ -73821,8 +73763,7 @@ async function startDaemon(config) {
|
|
|
73821
73763
|
});
|
|
73822
73764
|
logger.info("device-binding upsert succeeded", {
|
|
73823
73765
|
deviceId: opts.deviceId,
|
|
73824
|
-
unionId: opts.identity.unionId
|
|
73825
|
-
loginPass: r2.loginPass ? "issued" : "absent"
|
|
73766
|
+
unionId: opts.identity.unionId
|
|
73826
73767
|
});
|
|
73827
73768
|
return r2;
|
|
73828
73769
|
} catch (err) {
|
|
@@ -73964,8 +73905,8 @@ async function startDaemon(config) {
|
|
|
73964
73905
|
// 联系人列表 store(device:connect 出站 / contact:handshake 入站落同一 store)
|
|
73965
73906
|
contactStore,
|
|
73966
73907
|
// contact:handshake 换票(spec 2026-07-22;2026-08-17 起硬失败,不再是回填):
|
|
73967
|
-
//
|
|
73968
|
-
// 契约(ContactHandlerDeps.exchangeToken):null =
|
|
73908
|
+
// 用本机登录票换 aud=对方设备 的票,现读 ownerIdentityStore(热切换后用新身份)。
|
|
73909
|
+
// 契约(ContactHandlerDeps.exchangeToken):null = 本机登录问题(未登录),
|
|
73969
73910
|
// 其他失败原样抛给 handler——两种都会让握手硬失败,只是给对端的错误文案不同。
|
|
73970
73911
|
exchangeToken: async (targetDeviceId) => {
|
|
73971
73912
|
const record4 = ownerIdentityStore.read();
|
|
@@ -73973,10 +73914,8 @@ async function startDaemon(config) {
|
|
|
73973
73914
|
try {
|
|
73974
73915
|
const r2 = await centralExchange({
|
|
73975
73916
|
api: config.clawosApi ?? DEFAULT_CLAWOS_API,
|
|
73976
|
-
|
|
73977
|
-
provider: record4.identity.provider,
|
|
73917
|
+
loginPass: record4.loginPass,
|
|
73978
73918
|
deviceId: targetDeviceId,
|
|
73979
|
-
selfDeviceId: authFile.deviceId,
|
|
73980
73919
|
// 换票在握手关键路径上(硬失败),对端 connect-remote RPC_TIMEOUT_MS=5s:
|
|
73981
73920
|
// 必须在其内失败/成功,否则对端先超时不落库、本机后换票成功落库 → 反向半连,
|
|
73982
73921
|
// 破坏「两侧都不落库」不变量。4s 留 1s 余量给 ws 往返
|
|
@@ -74029,21 +73968,18 @@ async function startDaemon(config) {
|
|
|
74029
73968
|
}
|
|
74030
73969
|
},
|
|
74031
73970
|
// 云 persona 卡片上的连接器区(design 2026-09-11-mcp-connector §3.8):装了什么以 gateway 登记行为真源,
|
|
74032
|
-
//
|
|
73971
|
+
// 连没连上问中心。登录票只在 daemon 内部传给中心,与 apiKeyClient 同一条纪律。
|
|
74033
73972
|
cloudConnectors: {
|
|
74034
73973
|
getPersona: (personaId2) => personaRegistry.get(personaId2),
|
|
74035
73974
|
gatewayConnectors: (gatewayPersonaId) => cloudGateway.personaConnectors(gatewayPersonaId),
|
|
74036
|
-
|
|
74037
|
-
const r2 = ownerIdentityStore.read();
|
|
74038
|
-
return r2 ? { ttcJwt: r2.ttcToken, provider: r2.identity.provider } : null;
|
|
74039
|
-
},
|
|
73975
|
+
getLoginPass: () => ownerIdentityStore.read()?.loginPass ?? null,
|
|
74040
73976
|
central: {
|
|
74041
73977
|
mine: (args) => centralConnectorsMine({ api: config.clawosApi ?? DEFAULT_CLAWOS_API, ...args }),
|
|
74042
73978
|
fill: (args) => centralConnectorFill({ api: config.clawosApi ?? DEFAULT_CLAWOS_API, ...args })
|
|
74043
73979
|
}
|
|
74044
73980
|
},
|
|
74045
73981
|
// 设备目录 + 连接(决策 #15:daemon 代理中心 server)。
|
|
74046
|
-
// exchange/listDevices
|
|
73982
|
+
// exchange/listDevices 包掉本机登录票(每次现读 store——热切换后立即用新身份);
|
|
74047
73983
|
// dispatcher 的 FEISHU_GATED_METHODS gate 已保证未登录时这些 RPC 到不了 handler,
|
|
74048
73984
|
// 这里的 FEISHU_LOGIN_REQUIRED 抛错只是防御纵深。
|
|
74049
73985
|
feishuDevice: feishuDeviceDeps,
|