@clawos-dev/clawd 0.2.517 → 0.2.519
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 +27 -22
- package/dist/cli.cjs +312 -205
- package/dist/dispatch/mcp-server.cjs +27 -22
- package/dist/persona-defaults/persona-app-builder/.claude/skills/app-builder-projects/SKILL.md +2 -2
- package/dist/persona-defaults/persona-app-builder/.mcp.json +1 -1
- package/dist/persona-defaults/persona-app-builder/CLAUDE.md +1 -1
- package/dist/persona-defaults/persona-dataclaw-builder/.claude/skills/app-builder-projects/SKILL.md +2 -2
- package/dist/persona-defaults/persona-dataclaw-builder/.mcp.json +1 -1
- package/dist/persona-defaults/persona-dataclaw-builder/CLAUDE.md +1 -1
- package/dist/pi-mcp-bridge/extension.cjs +3 -1
- package/dist/share-ui/assets/{guest-fV-R3Vmz.js → guest-CqC7os4f.js} +49 -49
- package/dist/share-ui/guest.html +1 -1
- package/package.json +2 -1
package/dist/cli.cjs
CHANGED
|
@@ -5950,6 +5950,27 @@ var init_contact_handshake = __esm({
|
|
|
5950
5950
|
}
|
|
5951
5951
|
});
|
|
5952
5952
|
|
|
5953
|
+
// ../protocol/src/github-auth-schemas.ts
|
|
5954
|
+
var GithubAuthStatusSchema, GithubAuthAuthorizeArgsSchema, GithubAuthOauthStartArgsSchema;
|
|
5955
|
+
var init_github_auth_schemas = __esm({
|
|
5956
|
+
"../protocol/src/github-auth-schemas.ts"() {
|
|
5957
|
+
"use strict";
|
|
5958
|
+
init_zod();
|
|
5959
|
+
GithubAuthStatusSchema = external_exports.discriminatedUnion("status", [
|
|
5960
|
+
external_exports.object({ status: external_exports.literal("authorized"), login: external_exports.string().min(1), source: external_exports.enum(["git", "file"]) }).strict(),
|
|
5961
|
+
external_exports.object({ status: external_exports.literal("missing") }).strict(),
|
|
5962
|
+
external_exports.object({ status: external_exports.literal("invalid"), message: external_exports.string().min(1) }).strict(),
|
|
5963
|
+
external_exports.object({ status: external_exports.literal("pending"), authUrl: external_exports.string().url() }).strict()
|
|
5964
|
+
]);
|
|
5965
|
+
GithubAuthAuthorizeArgsSchema = external_exports.object({
|
|
5966
|
+
token: external_exports.string().min(1)
|
|
5967
|
+
}).strict();
|
|
5968
|
+
GithubAuthOauthStartArgsSchema = external_exports.object({
|
|
5969
|
+
returnTo: external_exports.string().url().optional()
|
|
5970
|
+
}).strict();
|
|
5971
|
+
}
|
|
5972
|
+
});
|
|
5973
|
+
|
|
5953
5974
|
// ../protocol/src/environment-schemas.ts
|
|
5954
5975
|
function connectorBlockers(c2) {
|
|
5955
5976
|
if (!c2.credentialSource) return [`\u8FDE\u63A5\u5668 ${c2.name} \u8FD8\u6CA1\u9009\u7528\u8C01\u7684\u8D26\u53F7`];
|
|
@@ -6077,11 +6098,12 @@ function cloudEngineOk(tool) {
|
|
|
6077
6098
|
function repoSlug(url) {
|
|
6078
6099
|
return url.trim().replace(/^git@[^:]+:/, "").replace(/^https?:\/\/[^/]+\//, "").replace(/\.git$/, "");
|
|
6079
6100
|
}
|
|
6080
|
-
var DeployFileSchema, SCAN_BASE_KINDS, ScanBaseKindSchema, DeployScanStatusSchema, DeployScanSchema, DeployRepoSchema,
|
|
6101
|
+
var DeployFileSchema, SCAN_BASE_KINDS, ScanBaseKindSchema, DeployScanStatusSchema, DeployScanSchema, DeployRepoSchema, DeploySecretPresenceSchema, DEPLOY_STAGE_STATUSES, DeployStageStatusSchema, DEPLOY_STAGE_KEYS, DeployStageKeySchema, DeployJobSchema, DeployRunSchema, DeployStateSchema, DeployReleaseResultSchema, DeployPersonaArgsSchema, DeployStartArgsSchema, DeployPatchArgsSchema, DeployPutSecretArgsSchema, DeployRerunJobArgsSchema, DeployReportFindingArgsSchema, DeployFinishScanArgsSchema, PERSONA_REPO_ORG;
|
|
6081
6102
|
var init_deploy_schemas = __esm({
|
|
6082
6103
|
"../protocol/src/deploy-schemas.ts"() {
|
|
6083
6104
|
"use strict";
|
|
6084
6105
|
init_zod();
|
|
6106
|
+
init_github_auth_schemas();
|
|
6085
6107
|
init_environment_schemas();
|
|
6086
6108
|
DeployFileSchema = external_exports.object({
|
|
6087
6109
|
version: external_exports.literal(1),
|
|
@@ -6148,12 +6170,6 @@ var init_deploy_schemas = __esm({
|
|
|
6148
6170
|
/** 本地领先远端几个提交 */
|
|
6149
6171
|
ahead: external_exports.number()
|
|
6150
6172
|
}).strict();
|
|
6151
|
-
DeployGithubStatusSchema = external_exports.discriminatedUnion("status", [
|
|
6152
|
-
external_exports.object({ status: external_exports.literal("authorized"), login: external_exports.string().min(1), source: external_exports.enum(["git", "file"]) }).strict(),
|
|
6153
|
-
external_exports.object({ status: external_exports.literal("missing") }).strict(),
|
|
6154
|
-
external_exports.object({ status: external_exports.literal("invalid"), message: external_exports.string().min(1) }).strict(),
|
|
6155
|
-
external_exports.object({ status: external_exports.literal("pending"), authUrl: external_exports.string().url() }).strict()
|
|
6156
|
-
]);
|
|
6157
6173
|
DeploySecretPresenceSchema = external_exports.object({
|
|
6158
6174
|
env: external_exports.string().min(1),
|
|
6159
6175
|
setAt: external_exports.number().optional()
|
|
@@ -6183,8 +6199,8 @@ var init_deploy_schemas = __esm({
|
|
|
6183
6199
|
}).strict();
|
|
6184
6200
|
DeployStateSchema = external_exports.object({
|
|
6185
6201
|
personaId: external_exports.string().min(1),
|
|
6186
|
-
/** 本机 GitHub
|
|
6187
|
-
github:
|
|
6202
|
+
/** 本机 GitHub 身份(机器级,githubAuth:* 的同一份;上云页顶上那张卡用)。老 daemon 不给(可选只为兼容),UI 缺席时按未知处理 */
|
|
6203
|
+
github: GithubAuthStatusSchema.optional(),
|
|
6188
6204
|
repo: DeployRepoSchema.optional(),
|
|
6189
6205
|
file: DeployFileSchema.optional(),
|
|
6190
6206
|
scan: DeployScanSchema.optional(),
|
|
@@ -6229,14 +6245,6 @@ var init_deploy_schemas = __esm({
|
|
|
6229
6245
|
// 环境变量名 → 值。key 必须是该 secret 声明过的 env 之一,handler 校验。
|
|
6230
6246
|
values: external_exports.record(external_exports.string(), external_exports.string())
|
|
6231
6247
|
}).strict();
|
|
6232
|
-
DeployGithubAuthorizeArgsSchema = external_exports.object({
|
|
6233
|
-
personaId: external_exports.string().min(1),
|
|
6234
|
-
token: external_exports.string().min(1)
|
|
6235
|
-
}).strict();
|
|
6236
|
-
DeployGithubOauthStartArgsSchema = external_exports.object({
|
|
6237
|
-
personaId: external_exports.string().min(1),
|
|
6238
|
-
returnTo: external_exports.string().url().optional()
|
|
6239
|
-
}).strict();
|
|
6240
6248
|
DeployRerunJobArgsSchema = external_exports.object({
|
|
6241
6249
|
personaId: external_exports.string().min(1),
|
|
6242
6250
|
/** GitHub 的 job databaseId。**是数字**——字符串会在拼命令时静默出错 */
|
|
@@ -8672,6 +8680,7 @@ var init_methods = __esm({
|
|
|
8672
8680
|
init_attachment_schemas();
|
|
8673
8681
|
init_contact_handshake();
|
|
8674
8682
|
init_deploy_schemas();
|
|
8683
|
+
init_github_auth_schemas();
|
|
8675
8684
|
init_contact_remote_access();
|
|
8676
8685
|
init_cloud_connector_schemas();
|
|
8677
8686
|
init_contact();
|
|
@@ -8909,13 +8918,18 @@ var init_methods = __esm({
|
|
|
8909
8918
|
summary: "\u539F\u6837\u91CD\u8DD1\u6700\u65B0\u90A3\u6761\u6D41\u6C34\u7EBF\u91CC\u5931\u8D25\u7684\u67D0\u4E00\u6BB5\uFF08GitHub REST rerun job\uFF09\u3002**\u540C\u4E00\u4E2A commit\u3001\u540C\u4E00\u4EFD\u8F93\u5165**\uFF0C\u4E0D\u4EA7\u751F\u65B0\u63D0\u4EA4\u2014\u2014\u6539\u4E86 persona \u5185\u5BB9\u6216\u51ED\u636E\u8981\u8D70 deploy:release\u3002jobId \u5FC5\u987B\u5C5E\u4E8E\u6700\u65B0\u90A3\u6761 run\uFF1Bowner-only",
|
|
8910
8919
|
args: DeployRerunJobArgsSchema
|
|
8911
8920
|
},
|
|
8912
|
-
|
|
8913
|
-
|
|
8914
|
-
|
|
8921
|
+
// ---- githubAuth:*(本机 GitHub 身份,机器级;spec 2026-09-15-github-auth-unify-design §4.3)----
|
|
8922
|
+
"githubAuth:get": {
|
|
8923
|
+
summary: "\u672C\u673A\u7684 GitHub \u8EAB\u4EFD\uFF1Aauthorized\uFF08@login\uFF0C\u6765\u81EA git \u51ED\u636E\u5B58\u50A8 / \u672C\u673A\u51ED\u636E\u8868\uFF09/ missing / invalid\uFF08GitHub \u4E0D\u8BA4\uFF09/ pending\uFF08\u7B49 GitHub \u8DF3\u56DE\u4E2D\u5FC3\uFF09\u3002\u8BBE\u7F6E\u9875\u300C\u8D26\u53F7\u300D\u3001\u4E0A\u4E91\u9875\u9876\u4E0A\u90A3\u5F20\u5361\u3001PR \u6536\u4EF6\u7BB1\u90FD\u770B\u5B83\uFF1Bpending \u671F\u9875\u9762\u6BCF 2 \u79D2\u8F6E\u8BE2\uFF0Cdaemon \u987A\u624B\u5411\u4E2D\u5FC3\u9886 token\u3002\u65E0\u53C2\u6570",
|
|
8924
|
+
args: NO_ARGS
|
|
8915
8925
|
},
|
|
8916
|
-
"
|
|
8917
|
-
summary: "\
|
|
8918
|
-
args:
|
|
8926
|
+
"githubAuth:oauthStart": {
|
|
8927
|
+
summary: "\u8BBE\u7F6E\u9875\u300C\u5173\u8054 GitHub\u300D\uFF1Adaemon \u5E26\u672C\u673A\u767B\u5F55\u51ED\u8BC1\u5411\u4E2D\u5FC3\u8981\u4E00\u6761 GitHub OAuth \u6388\u6743\u94FE\u63A5\u5E76\u56DE\u5728\u72B6\u6001\uFF08pending\uFF09\u91CC\uFF0C\u9875\u9762\u6253\u5F00\u5B83\uFF1B\u7528\u6237\u5728 GitHub \u70B9\u540C\u610F\u540E\u56DE\u8DF3\u4E2D\u5FC3\uFF0C\u4E2D\u5FC3\u6362\u597D token \u5B58\u4E00\u4EFD\uFF0Cdaemon \u5728\u4E4B\u540E\u7684 githubAuth:get \u91CC\u9886\u56DE\u6765\u5B58\u8FDB\u672C\u673A git\u3002\u4E2D\u5FC3\u5DF2\u6709\u672C\u4EBA\u7684 token \u65F6\u4E0D\u8DF3 GitHub\uFF0C\u76F4\u63A5\u9886\uFF1B\u8981\u767B\u5F55\u98DE\u4E66\uFF1Bowner-only",
|
|
8928
|
+
args: GithubAuthOauthStartArgsSchema
|
|
8929
|
+
},
|
|
8930
|
+
"githubAuth:authorize": {
|
|
8931
|
+
summary: "\u628A\u7528\u6237\u7C98\u7684 GitHub token \u5B58\u6210\u672C\u673A\u8EAB\u4EFD\uFF08\u70B9\u94FE\u63A5\u8D70\u4E0D\u901A\u65F6\u7684\u9000\u8DEF\uFF09\uFF1A\u5148 GET /user \u9A8C\u8BC1\uFF0C\u518D git credential approve \u4EA4\u7ED9 git \u7684 helper \u5B58\uFF08git \u6CA1\u914D helper \u65F6\u9000\u5230\u672C\u673A\u51ED\u636E\u8868 secrets/github.env\uFF09\u3002\u5165\u53C2\u4E0D\u8FDB\u65E5\u5FD7\u3001\u54CD\u5E94\u4E0D\u56DE\u663E token\uFF1Bowner-only",
|
|
8932
|
+
args: GithubAuthAuthorizeArgsSchema
|
|
8919
8933
|
},
|
|
8920
8934
|
// ---- cloud:connectors:*(云 persona 卡片上的连接器;design 2026-09-11-mcp-connector §3.8)----
|
|
8921
8935
|
"cloud:connectors:list": {
|
|
@@ -9592,6 +9606,7 @@ var init_runtime = __esm({
|
|
|
9592
9606
|
init_environment_schemas();
|
|
9593
9607
|
init_cloud_connector_schemas();
|
|
9594
9608
|
init_deploy_schemas();
|
|
9609
|
+
init_github_auth_schemas();
|
|
9595
9610
|
init_persona_schemas();
|
|
9596
9611
|
init_persona_mode();
|
|
9597
9612
|
init_attachment_schemas();
|
|
@@ -54810,19 +54825,25 @@ var DEFAULT_TIMEOUT_MS2 = 15e3;
|
|
|
54810
54825
|
var MAX_BUFFER = 4 * 1024 * 1024;
|
|
54811
54826
|
function createGhRunner(defaults) {
|
|
54812
54827
|
const baseTimeoutMs = defaults?.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
54828
|
+
const spawn14 = defaults?.execFile ?? import_node_child_process7.execFile;
|
|
54813
54829
|
return {
|
|
54814
54830
|
run(args, opts) {
|
|
54831
|
+
const token = defaults?.token?.();
|
|
54815
54832
|
return new Promise((resolve9, reject) => {
|
|
54816
|
-
(
|
|
54833
|
+
spawn14(
|
|
54817
54834
|
"gh",
|
|
54818
54835
|
args,
|
|
54819
|
-
{
|
|
54836
|
+
{
|
|
54837
|
+
timeout: opts?.timeoutMs ?? baseTimeoutMs,
|
|
54838
|
+
maxBuffer: MAX_BUFFER,
|
|
54839
|
+
env: { ...process.env, ...token ? { GH_TOKEN: token } : {} }
|
|
54840
|
+
},
|
|
54820
54841
|
(err, stdout, stderr) => {
|
|
54821
|
-
if (!err) return resolve9(stdout);
|
|
54842
|
+
if (!err) return resolve9(String(stdout));
|
|
54822
54843
|
if (err.code === "ENOENT") {
|
|
54823
54844
|
return reject(new GhError("gh-missing", "GitHub CLI (gh) \u672A\u5B89\u88C5"));
|
|
54824
54845
|
}
|
|
54825
|
-
const detail = (stderr ?? "").trim();
|
|
54846
|
+
const detail = String(stderr ?? "").trim();
|
|
54826
54847
|
reject(new GhError("gh-error", detail !== "" ? detail : err.message, detail));
|
|
54827
54848
|
}
|
|
54828
54849
|
);
|
|
@@ -58949,8 +58970,8 @@ function createGithubApi(args) {
|
|
|
58949
58970
|
}
|
|
58950
58971
|
|
|
58951
58972
|
// src/deploy/github-auth.ts
|
|
58952
|
-
var
|
|
58953
|
-
var
|
|
58973
|
+
var GITHUB_TOKEN_FILE = "github.env";
|
|
58974
|
+
var GITHUB_TOKEN_VAR = "GITHUB_TOKEN";
|
|
58954
58975
|
var HOST = "github.com";
|
|
58955
58976
|
var TIMEOUT_MS2 = 15e3;
|
|
58956
58977
|
var record3 = (fields) => `${Object.entries(fields).map(([k3, v3]) => `${k3}=${v3}`).join("\n")}
|
|
@@ -59580,8 +59601,7 @@ var invalid = (msg) => new ClawdError(ERROR_CODES.VALIDATION_ERROR, `VALIDATION_
|
|
|
59580
59601
|
function wrongEngine(tool) {
|
|
59581
59602
|
return cloudEngineOk(tool) ? void 0 : `\u5F15\u64CE\u662F ${tool || "claude"}\uFF0C\u4E91\u4E0A\u53EA\u8DD1 Codex\u2014\u2014\u53BB persona \u8BBE\u7F6E\u91CC\u628A\u5F15\u64CE\u5207\u6210 Codex\uFF0C\u518D\u9009\u4E2A\u6A21\u578B`;
|
|
59582
59603
|
}
|
|
59583
|
-
var NO_GITHUB_AUTH = "\u8FD8\u6CA1\
|
|
59584
|
-
var OAUTH_PENDING_MS = 10 * 6e4;
|
|
59604
|
+
var NO_GITHUB_AUTH = "\u8FD8\u6CA1\u5173\u8054 GitHub\uFF1A\u5728\u8BBE\u7F6E \u2192 \u8D26\u53F7\uFF08\u6216\u4E0A\u4E91\u9875\u9876\u4E0A\u90A3\u5F20\u5361\uFF09\u91CC\u70B9\u300C\u5173\u8054 GitHub\u300D";
|
|
59585
59605
|
function toClawdError(err) {
|
|
59586
59606
|
if (err instanceof ClawdError) return err;
|
|
59587
59607
|
if (err instanceof RepoError || err instanceof GithubApiError) return new ClawdError(ERROR_CODES.INTERNAL, err.message);
|
|
@@ -59597,62 +59617,11 @@ function buildDeployHandlers(deps) {
|
|
|
59597
59617
|
const cacheMs = deps.secretsCacheMs ?? SECRETS_CACHE_MS;
|
|
59598
59618
|
const secretsCache = /* @__PURE__ */ new Map();
|
|
59599
59619
|
const runCache = /* @__PURE__ */ new Map();
|
|
59600
|
-
|
|
59601
|
-
let pendingOauth = null;
|
|
59602
|
-
let staleCenterToken;
|
|
59603
|
-
async function adoptToken(token) {
|
|
59604
|
-
await deps.github.store(token);
|
|
59605
|
-
githubStatusCache.clear();
|
|
59606
|
-
secretsCache.clear();
|
|
59607
|
-
pendingOauth = null;
|
|
59608
|
-
}
|
|
59609
|
-
async function claimCenterToken() {
|
|
59610
|
-
let got;
|
|
59611
|
-
try {
|
|
59612
|
-
got = await deps.github.oauth.token();
|
|
59613
|
-
} catch {
|
|
59614
|
-
return false;
|
|
59615
|
-
}
|
|
59616
|
-
if (!got || got.token === staleCenterToken) return false;
|
|
59617
|
-
try {
|
|
59618
|
-
await deps.github.api(got.token).whoami();
|
|
59619
|
-
} catch (err) {
|
|
59620
|
-
if (err instanceof GithubApiError && err.status === 401) staleCenterToken = got.token;
|
|
59621
|
-
return false;
|
|
59622
|
-
}
|
|
59623
|
-
await adoptToken(got.token);
|
|
59624
|
-
return true;
|
|
59625
|
-
}
|
|
59626
|
-
async function settlePendingOauth() {
|
|
59627
|
-
if (!pendingOauth) return;
|
|
59628
|
-
if (deps.now() > pendingOauth.expiresAt) {
|
|
59629
|
-
pendingOauth = null;
|
|
59630
|
-
return;
|
|
59631
|
-
}
|
|
59632
|
-
try {
|
|
59633
|
-
await claimCenterToken();
|
|
59634
|
-
} catch {
|
|
59635
|
-
pendingOauth = null;
|
|
59636
|
-
}
|
|
59637
|
-
}
|
|
59620
|
+
deps.githubIdentity.onChange(() => secretsCache.clear());
|
|
59638
59621
|
async function requireGithub() {
|
|
59639
|
-
const auth = await deps.
|
|
59622
|
+
const auth = await deps.githubIdentity.refresh();
|
|
59640
59623
|
if (!auth) throw new ClawdError(ERROR_CODES.INTERNAL, NO_GITHUB_AUTH);
|
|
59641
|
-
return { auth, api: deps.
|
|
59642
|
-
}
|
|
59643
|
-
async function githubStatus(auth) {
|
|
59644
|
-
if (!auth) return { status: "missing" };
|
|
59645
|
-
const hit = githubStatusCache.get(auth.token);
|
|
59646
|
-
if (hit && deps.now() - hit.at < cacheMs) return hit.status;
|
|
59647
|
-
let status;
|
|
59648
|
-
try {
|
|
59649
|
-
const { login } = await deps.github.api(auth.token).whoami();
|
|
59650
|
-
status = { status: "authorized", login, source: auth.source };
|
|
59651
|
-
} catch (err) {
|
|
59652
|
-
status = { status: "invalid", message: err instanceof Error ? err.message : String(err) };
|
|
59653
|
-
}
|
|
59654
|
-
githubStatusCache.set(auth.token, { at: deps.now(), status });
|
|
59655
|
-
return status;
|
|
59624
|
+
return { auth, api: deps.githubApi(auth.token) };
|
|
59656
59625
|
}
|
|
59657
59626
|
function mustPersona(personaId2) {
|
|
59658
59627
|
if (!deps.hasPersona(personaId2)) {
|
|
@@ -59670,11 +59639,9 @@ function buildDeployHandlers(deps) {
|
|
|
59670
59639
|
async function stateOf(personaId2) {
|
|
59671
59640
|
const dir = deps.personaDir(personaId2);
|
|
59672
59641
|
const repo2 = await repoInfo(deps.exec, dir);
|
|
59673
|
-
await
|
|
59674
|
-
const auth =
|
|
59675
|
-
const
|
|
59676
|
-
const github = pendingOauth && current.status !== "authorized" ? { status: "pending", authUrl: pendingOauth.authUrl } : current;
|
|
59677
|
-
const api = auth ? deps.github.api(auth.token) : void 0;
|
|
59642
|
+
const github = await deps.githubIdentity.status();
|
|
59643
|
+
const auth = deps.githubIdentity.cached();
|
|
59644
|
+
const api = auth ? deps.githubApi(auth.token) : void 0;
|
|
59678
59645
|
let file;
|
|
59679
59646
|
let fileError;
|
|
59680
59647
|
try {
|
|
@@ -59944,33 +59911,6 @@ function buildDeployHandlers(deps) {
|
|
|
59944
59911
|
}
|
|
59945
59912
|
return view(personaId2);
|
|
59946
59913
|
};
|
|
59947
|
-
const githubAuthorize = async (frame, _client, ctx) => {
|
|
59948
|
-
ensureOwner(ctx);
|
|
59949
|
-
const args = parseArgs2(DeployGithubAuthorizeArgsSchema, frame, "deploy:githubAuthorize");
|
|
59950
|
-
mustPersona(args.personaId);
|
|
59951
|
-
const token = args.token.trim();
|
|
59952
|
-
try {
|
|
59953
|
-
await deps.github.api(token).whoami();
|
|
59954
|
-
} catch (err) {
|
|
59955
|
-
throw invalid(`GitHub \u4E0D\u8BA4\u8FD9\u4E2A token\uFF1A${err instanceof Error ? err.message : String(err)}`);
|
|
59956
|
-
}
|
|
59957
|
-
await adoptToken(token);
|
|
59958
|
-
return view(args.personaId);
|
|
59959
|
-
};
|
|
59960
|
-
const githubOauthStart = async (frame, _client, ctx) => {
|
|
59961
|
-
ensureOwner(ctx);
|
|
59962
|
-
const args = parseArgs2(DeployGithubOauthStartArgsSchema, frame, "deploy:githubOauthStart");
|
|
59963
|
-
mustPersona(args.personaId);
|
|
59964
|
-
const local = await deps.github.resolve();
|
|
59965
|
-
if (!local && await claimCenterToken()) return view(args.personaId);
|
|
59966
|
-
try {
|
|
59967
|
-
staleCenterToken = (await deps.github.oauth.token())?.token;
|
|
59968
|
-
} catch {
|
|
59969
|
-
}
|
|
59970
|
-
const { authUrl } = await deps.github.oauth.start(args.returnTo);
|
|
59971
|
-
pendingOauth = { authUrl, expiresAt: deps.now() + OAUTH_PENDING_MS };
|
|
59972
|
-
return view(args.personaId);
|
|
59973
|
-
};
|
|
59974
59914
|
return {
|
|
59975
59915
|
"deploy:start": start,
|
|
59976
59916
|
"deploy:get": get,
|
|
@@ -59979,9 +59919,156 @@ function buildDeployHandlers(deps) {
|
|
|
59979
59919
|
"deploy:reportFinding": reportFinding,
|
|
59980
59920
|
"deploy:finishScan": finishScan,
|
|
59981
59921
|
"deploy:release": releaseHandler,
|
|
59982
|
-
"deploy:rerunJob": rerunJobHandler
|
|
59983
|
-
|
|
59984
|
-
|
|
59922
|
+
"deploy:rerunJob": rerunJobHandler
|
|
59923
|
+
};
|
|
59924
|
+
}
|
|
59925
|
+
|
|
59926
|
+
// src/github/identity.ts
|
|
59927
|
+
var GithubTokenRejected = class extends Error {
|
|
59928
|
+
};
|
|
59929
|
+
var STATUS_CACHE_MS = 2e4;
|
|
59930
|
+
var OAUTH_PENDING_MS = 10 * 6e4;
|
|
59931
|
+
function secretsWithGithubIdentity(secrets, auth) {
|
|
59932
|
+
return auth ? { ...secrets, GITHUB_TOKEN: auth.token } : secrets;
|
|
59933
|
+
}
|
|
59934
|
+
function createGithubIdentity(deps) {
|
|
59935
|
+
const cacheMs = deps.statusCacheMs ?? STATUS_CACHE_MS;
|
|
59936
|
+
let auth;
|
|
59937
|
+
let seq = 0;
|
|
59938
|
+
const statusCache = /* @__PURE__ */ new Map();
|
|
59939
|
+
let pendingOauth = null;
|
|
59940
|
+
let staleCenterToken;
|
|
59941
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
59942
|
+
async function refresh() {
|
|
59943
|
+
const mine = ++seq;
|
|
59944
|
+
const resolved = await deps.resolve();
|
|
59945
|
+
if (mine === seq) auth = resolved;
|
|
59946
|
+
return resolved;
|
|
59947
|
+
}
|
|
59948
|
+
async function whoami(a2) {
|
|
59949
|
+
const hit = statusCache.get(a2.token);
|
|
59950
|
+
if (hit && deps.now() - hit.at < cacheMs) return hit.status;
|
|
59951
|
+
let status2;
|
|
59952
|
+
try {
|
|
59953
|
+
const { login } = await deps.api(a2.token).whoami();
|
|
59954
|
+
status2 = { status: "authorized", login, source: a2.source };
|
|
59955
|
+
} catch (err) {
|
|
59956
|
+
status2 = { status: "invalid", message: err instanceof Error ? err.message : String(err) };
|
|
59957
|
+
}
|
|
59958
|
+
statusCache.set(a2.token, { at: deps.now(), status: status2 });
|
|
59959
|
+
return status2;
|
|
59960
|
+
}
|
|
59961
|
+
async function adopt(token) {
|
|
59962
|
+
auth = await deps.store(token);
|
|
59963
|
+
seq++;
|
|
59964
|
+
statusCache.clear();
|
|
59965
|
+
pendingOauth = null;
|
|
59966
|
+
for (const cb of listeners) cb();
|
|
59967
|
+
}
|
|
59968
|
+
async function claimCenterToken() {
|
|
59969
|
+
let got;
|
|
59970
|
+
try {
|
|
59971
|
+
got = await deps.oauth.token();
|
|
59972
|
+
} catch {
|
|
59973
|
+
return false;
|
|
59974
|
+
}
|
|
59975
|
+
if (!got || got.token === staleCenterToken) return false;
|
|
59976
|
+
try {
|
|
59977
|
+
await deps.api(got.token).whoami();
|
|
59978
|
+
} catch (err) {
|
|
59979
|
+
if (err instanceof GithubApiError && err.status === 401) staleCenterToken = got.token;
|
|
59980
|
+
return false;
|
|
59981
|
+
}
|
|
59982
|
+
await adopt(got.token);
|
|
59983
|
+
return true;
|
|
59984
|
+
}
|
|
59985
|
+
async function settlePendingOauth() {
|
|
59986
|
+
if (!pendingOauth) return;
|
|
59987
|
+
if (deps.now() > pendingOauth.expiresAt) {
|
|
59988
|
+
pendingOauth = null;
|
|
59989
|
+
return;
|
|
59990
|
+
}
|
|
59991
|
+
try {
|
|
59992
|
+
await claimCenterToken();
|
|
59993
|
+
} catch (err) {
|
|
59994
|
+
deps.logger?.warn("github.identity.claim-failed", { message: err instanceof Error ? err.message : String(err) });
|
|
59995
|
+
pendingOauth = null;
|
|
59996
|
+
}
|
|
59997
|
+
}
|
|
59998
|
+
async function status() {
|
|
59999
|
+
await settlePendingOauth();
|
|
60000
|
+
const a2 = await refresh();
|
|
60001
|
+
const current = a2 ? await whoami(a2) : { status: "missing" };
|
|
60002
|
+
return pendingOauth && current.status !== "authorized" ? { status: "pending", authUrl: pendingOauth.authUrl } : current;
|
|
60003
|
+
}
|
|
60004
|
+
return {
|
|
60005
|
+
cached: () => auth,
|
|
60006
|
+
refresh,
|
|
60007
|
+
status,
|
|
60008
|
+
adopt,
|
|
60009
|
+
async authorize(raw) {
|
|
60010
|
+
const token = raw.trim();
|
|
60011
|
+
try {
|
|
60012
|
+
await deps.api(token).whoami();
|
|
60013
|
+
} catch (err) {
|
|
60014
|
+
throw new GithubTokenRejected(`GitHub \u4E0D\u8BA4\u8FD9\u4E2A token\uFF1A${err instanceof Error ? err.message : String(err)}`);
|
|
60015
|
+
}
|
|
60016
|
+
await adopt(token);
|
|
60017
|
+
return status();
|
|
60018
|
+
},
|
|
60019
|
+
/**
|
|
60020
|
+
* 本机还没有身份时先问中心有没有本人现成的 token(换台机器授权过 / 上次跳回来了但 daemon 没轮到):
|
|
60021
|
+
* 有且 GitHub 认就直接领、不跳 GitHub。本机已有身份(能用的 = 用户要换一个;失效的 = 要重新授权,而中心那份就是这把死的)
|
|
60022
|
+
* 一律跳 GitHub 重来。进 pending 之后每次 status() 顺手问一次中心领没领到。
|
|
60023
|
+
*/
|
|
60024
|
+
async oauthStart(returnTo) {
|
|
60025
|
+
const local = await refresh();
|
|
60026
|
+
if (!local && await claimCenterToken()) return status();
|
|
60027
|
+
try {
|
|
60028
|
+
staleCenterToken = (await deps.oauth.token())?.token;
|
|
60029
|
+
} catch {
|
|
60030
|
+
}
|
|
60031
|
+
const { authUrl } = await deps.oauth.start(returnTo);
|
|
60032
|
+
pendingOauth = { authUrl, expiresAt: deps.now() + OAUTH_PENDING_MS };
|
|
60033
|
+
return status();
|
|
60034
|
+
},
|
|
60035
|
+
onChange(cb) {
|
|
60036
|
+
listeners.add(cb);
|
|
60037
|
+
return () => {
|
|
60038
|
+
listeners.delete(cb);
|
|
60039
|
+
};
|
|
60040
|
+
}
|
|
60041
|
+
};
|
|
60042
|
+
}
|
|
60043
|
+
|
|
60044
|
+
// src/handlers/github-auth.ts
|
|
60045
|
+
init_protocol();
|
|
60046
|
+
function ensureOwner2(ctx) {
|
|
60047
|
+
if (!ctx || ctx.principal.kind !== "owner") {
|
|
60048
|
+
throw new ClawdError(ERROR_CODES.UNAUTHORIZED, "UNAUTHORIZED: githubAuth:* requires owner ctx");
|
|
60049
|
+
}
|
|
60050
|
+
}
|
|
60051
|
+
function buildGithubAuthHandlers(deps) {
|
|
60052
|
+
const get = async () => ({ response: await deps.identity.status() });
|
|
60053
|
+
const oauthStart = async (frame, _client, ctx) => {
|
|
60054
|
+
ensureOwner2(ctx);
|
|
60055
|
+
const args = parseArgs2(GithubAuthOauthStartArgsSchema, frame, "githubAuth:oauthStart");
|
|
60056
|
+
return { response: await deps.identity.oauthStart(args.returnTo) };
|
|
60057
|
+
};
|
|
60058
|
+
const authorize = async (frame, _client, ctx) => {
|
|
60059
|
+
ensureOwner2(ctx);
|
|
60060
|
+
const args = parseArgs2(GithubAuthAuthorizeArgsSchema, frame, "githubAuth:authorize");
|
|
60061
|
+
try {
|
|
60062
|
+
return { response: await deps.identity.authorize(args.token) };
|
|
60063
|
+
} catch (err) {
|
|
60064
|
+
if (err instanceof GithubTokenRejected) throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `VALIDATION_ERROR: ${err.message}`);
|
|
60065
|
+
throw err;
|
|
60066
|
+
}
|
|
60067
|
+
};
|
|
60068
|
+
return {
|
|
60069
|
+
"githubAuth:get": get,
|
|
60070
|
+
"githubAuth:oauthStart": oauthStart,
|
|
60071
|
+
"githubAuth:authorize": authorize
|
|
59985
60072
|
};
|
|
59986
60073
|
}
|
|
59987
60074
|
|
|
@@ -62208,23 +62295,23 @@ async function centralConnectorFill(opts) {
|
|
|
62208
62295
|
});
|
|
62209
62296
|
if (body.ok !== true) throw new CentralClientError("BAD_RESPONSE", "connectors/fields: server did not ack ok");
|
|
62210
62297
|
}
|
|
62211
|
-
async function
|
|
62212
|
-
const body = await centralRequest(opts, "/api/persona-cloud/github
|
|
62298
|
+
async function centralGithubAuthOauthStart(opts) {
|
|
62299
|
+
const body = await centralRequest(opts, "/api/persona-cloud/github/oauth/start", {
|
|
62213
62300
|
method: "POST",
|
|
62214
62301
|
bearer: opts.ttcJwt,
|
|
62215
62302
|
body: { provider: opts.provider, ...opts.returnTo ? { returnTo: opts.returnTo } : {} }
|
|
62216
62303
|
});
|
|
62217
|
-
if (typeof body.authUrl !== "string" || !body.authUrl) throw new CentralClientError("BAD_RESPONSE", "github
|
|
62304
|
+
if (typeof body.authUrl !== "string" || !body.authUrl) throw new CentralClientError("BAD_RESPONSE", "github/oauth/start: missing authUrl");
|
|
62218
62305
|
return { authUrl: body.authUrl };
|
|
62219
62306
|
}
|
|
62220
|
-
async function
|
|
62221
|
-
const body = await centralRequest(opts, "/api/persona-cloud/github
|
|
62307
|
+
async function centralGithubAuthToken(opts) {
|
|
62308
|
+
const body = await centralRequest(opts, "/api/persona-cloud/github/oauth/token", {
|
|
62222
62309
|
method: "POST",
|
|
62223
62310
|
bearer: opts.ttcJwt,
|
|
62224
62311
|
body: { provider: opts.provider }
|
|
62225
62312
|
});
|
|
62226
62313
|
if (body.token === null || body.token === void 0) return void 0;
|
|
62227
|
-
if (typeof body.token !== "string" || !body.token) throw new CentralClientError("BAD_RESPONSE", "github
|
|
62314
|
+
if (typeof body.token !== "string" || !body.token) throw new CentralClientError("BAD_RESPONSE", "github/oauth/token: malformed token");
|
|
62228
62315
|
return { token: body.token, login: typeof body.login === "string" ? body.login : "" };
|
|
62229
62316
|
}
|
|
62230
62317
|
|
|
@@ -65815,6 +65902,31 @@ async function importZip(buf, root) {
|
|
|
65815
65902
|
}
|
|
65816
65903
|
}
|
|
65817
65904
|
|
|
65905
|
+
// src/feishu-auth/login-callback.ts
|
|
65906
|
+
function parseLoginCallbackQuery(url) {
|
|
65907
|
+
return {
|
|
65908
|
+
token: url.searchParams.get("token") ?? "",
|
|
65909
|
+
state: url.searchParams.get("state") ?? "",
|
|
65910
|
+
expiresAt: url.searchParams.get("expires_at")
|
|
65911
|
+
};
|
|
65912
|
+
}
|
|
65913
|
+
function escapeHtml(s2) {
|
|
65914
|
+
return s2.replace(/[&<>"']/g, (c2) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c2]);
|
|
65915
|
+
}
|
|
65916
|
+
function renderLoginCallbackPage(result, successTagline) {
|
|
65917
|
+
const style = (color) => `<style>body{font-family:-apple-system,sans-serif;padding:48px;color:${color}}</style>`;
|
|
65918
|
+
if (result.ok) {
|
|
65919
|
+
return {
|
|
65920
|
+
status: 200,
|
|
65921
|
+
html: `<!doctype html><meta charset="utf-8"><title>clawd</title>${style("#222")}<h2>${escapeHtml(successTagline)}</h2><p>\u8EAB\u4EFD\uFF1A${escapeHtml(result.identity.displayName)}</p><script>setTimeout(()=>window.close(),1500)</script>`
|
|
65922
|
+
};
|
|
65923
|
+
}
|
|
65924
|
+
return {
|
|
65925
|
+
status: 400,
|
|
65926
|
+
html: `<!doctype html><meta charset="utf-8"><title>clawd</title>${style("#922")}<h2>\u767B\u5F55\u5931\u8D25</h2><p>${escapeHtml(result.reason)}</p>`
|
|
65927
|
+
};
|
|
65928
|
+
}
|
|
65929
|
+
|
|
65818
65930
|
// src/transport/http-router.ts
|
|
65819
65931
|
var RPC_BODY_MAX_BYTES = 1 * 1024 * 1024;
|
|
65820
65932
|
var SHARE_UI_ASSETS_PREFIX = "/share-ui/assets/";
|
|
@@ -65954,14 +66066,10 @@ function createHttpRouter(deps) {
|
|
|
65954
66066
|
sendJson(res, 501, { code: "NOT_IMPLEMENTED", message: "feishu login not wired" });
|
|
65955
66067
|
return true;
|
|
65956
66068
|
}
|
|
65957
|
-
const result = await deps.feishuLogin.handleLoginCallback(
|
|
65958
|
-
|
|
65959
|
-
|
|
65960
|
-
|
|
65961
|
-
});
|
|
65962
|
-
const html = result.ok ? `<!doctype html><meta charset="utf-8"><title>clawd</title><style>body{font-family:-apple-system,sans-serif;padding:48px;color:#222}</style><h2>\u767B\u5F55\u6210\u529F\uFF0C\u53EF\u5173\u95ED\u6B64\u9875\u3002</h2><p>\u8EAB\u4EFD\uFF1A${escapeHtml(result.identity.displayName)}</p><script>setTimeout(()=>window.close(),1500)</script>` : `<!doctype html><meta charset="utf-8"><title>clawd</title><style>body{font-family:-apple-system,sans-serif;padding:48px;color:#922}</style><h2>\u767B\u5F55\u5931\u8D25</h2><p>${escapeHtml(result.reason)}</p>`;
|
|
65963
|
-
res.writeHead(result.ok ? 200 : 400, { "Content-Type": "text/html; charset=utf-8" });
|
|
65964
|
-
res.end(html);
|
|
66069
|
+
const result = await deps.feishuLogin.handleLoginCallback(parseLoginCallbackQuery(url));
|
|
66070
|
+
const page = renderLoginCallbackPage(result, "\u767B\u5F55\u6210\u529F\uFF0C\u53EF\u5173\u95ED\u6B64\u9875\u3002");
|
|
66071
|
+
res.writeHead(page.status, { "Content-Type": "text/html; charset=utf-8" });
|
|
66072
|
+
res.end(page.html);
|
|
65965
66073
|
return true;
|
|
65966
66074
|
}
|
|
65967
66075
|
if (url.pathname === "/share/exchange" && req.method === "OPTIONS") {
|
|
@@ -66353,9 +66461,6 @@ function parseUrl(rawUrl) {
|
|
|
66353
66461
|
return null;
|
|
66354
66462
|
}
|
|
66355
66463
|
}
|
|
66356
|
-
function escapeHtml(s2) {
|
|
66357
|
-
return s2.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
66358
|
-
}
|
|
66359
66464
|
function sendJson(res, status, body, extraHeaders) {
|
|
66360
66465
|
res.writeHead(status, {
|
|
66361
66466
|
"Content-Type": "application/json; charset=utf-8",
|
|
@@ -67767,7 +67872,7 @@ async function syncOrgMesh(deps) {
|
|
|
67767
67872
|
|
|
67768
67873
|
// src/handlers/device.ts
|
|
67769
67874
|
init_protocol();
|
|
67770
|
-
function
|
|
67875
|
+
function ensureOwner3(ctx) {
|
|
67771
67876
|
if (!ctx || ctx.principal.kind !== "owner") {
|
|
67772
67877
|
throw new ClawdError(ERROR_CODES.UNAUTHORIZED, "UNAUTHORIZED: device:* requires owner ctx");
|
|
67773
67878
|
}
|
|
@@ -67862,14 +67967,14 @@ function createConnectToDevice(deps) {
|
|
|
67862
67967
|
function buildDeviceHandlers(deps) {
|
|
67863
67968
|
const connectToDevice = createConnectToDevice(deps);
|
|
67864
67969
|
const list = async (_frame, _client, ctx) => {
|
|
67865
|
-
|
|
67970
|
+
ensureOwner3(ctx);
|
|
67866
67971
|
const devices = await deps.listDevices().catch(rethrowLoginExpired);
|
|
67867
67972
|
return {
|
|
67868
67973
|
response: { type: "device:list:ok", devices }
|
|
67869
67974
|
};
|
|
67870
67975
|
};
|
|
67871
67976
|
const connect = async (frame, _client, ctx) => {
|
|
67872
|
-
|
|
67977
|
+
ensureOwner3(ctx);
|
|
67873
67978
|
const { type: _t2, requestId: _r2, ...rest } = frame;
|
|
67874
67979
|
const args = DeviceConnectArgsSchema.parse(rest);
|
|
67875
67980
|
const contact = await connectToDevice(args);
|
|
@@ -67884,7 +67989,7 @@ function buildDeviceHandlers(deps) {
|
|
|
67884
67989
|
};
|
|
67885
67990
|
};
|
|
67886
67991
|
const connections = async (_frame, client, ctx) => {
|
|
67887
|
-
|
|
67992
|
+
ensureOwner3(ctx);
|
|
67888
67993
|
const entries = deps.listOwnerConnections();
|
|
67889
67994
|
return {
|
|
67890
67995
|
response: {
|
|
@@ -69609,7 +69714,7 @@ function upsertPeerContact(args) {
|
|
|
69609
69714
|
}
|
|
69610
69715
|
|
|
69611
69716
|
// src/handlers/contact.ts
|
|
69612
|
-
function
|
|
69717
|
+
function ensureOwner4(ctx) {
|
|
69613
69718
|
if (!ctx || ctx.principal.kind !== "owner") {
|
|
69614
69719
|
throw new ClawdError(
|
|
69615
69720
|
ERROR_CODES.UNAUTHORIZED,
|
|
@@ -69619,7 +69724,7 @@ function ensureOwner3(ctx) {
|
|
|
69619
69724
|
}
|
|
69620
69725
|
function buildContactHandlers(deps) {
|
|
69621
69726
|
const list = async (_frame, _client, ctx) => {
|
|
69622
|
-
|
|
69727
|
+
ensureOwner4(ctx);
|
|
69623
69728
|
return {
|
|
69624
69729
|
response: {
|
|
69625
69730
|
type: "contact:list:ok",
|
|
@@ -69628,7 +69733,7 @@ function buildContactHandlers(deps) {
|
|
|
69628
69733
|
};
|
|
69629
69734
|
};
|
|
69630
69735
|
const pin = async (frame, _client, ctx) => {
|
|
69631
|
-
|
|
69736
|
+
ensureOwner4(ctx);
|
|
69632
69737
|
const args = parseArgs2(ContactPinArgsSchema, frame, "contact:pin");
|
|
69633
69738
|
const pinnedAt = args.pinned ? deps.now() : null;
|
|
69634
69739
|
const hit = deps.store.setPin(args.deviceId, pinnedAt);
|
|
@@ -69652,7 +69757,7 @@ function buildContactHandlers(deps) {
|
|
|
69652
69757
|
};
|
|
69653
69758
|
};
|
|
69654
69759
|
const setNote = async (frame, _client, ctx) => {
|
|
69655
|
-
|
|
69760
|
+
ensureOwner4(ctx);
|
|
69656
69761
|
const args = parseArgs2(ContactSetNoteArgsSchema, frame, "contact:setNote");
|
|
69657
69762
|
const hit = deps.store.setNote(args.deviceId, args.note);
|
|
69658
69763
|
if (!hit) {
|
|
@@ -69675,13 +69780,13 @@ function buildContactHandlers(deps) {
|
|
|
69675
69780
|
};
|
|
69676
69781
|
};
|
|
69677
69782
|
const orgPeers = async (_frame, _client, ctx) => {
|
|
69678
|
-
|
|
69783
|
+
ensureOwner4(ctx);
|
|
69679
69784
|
return {
|
|
69680
69785
|
response: { type: "org:peers:ok", peers: getCachedOrgPeers() }
|
|
69681
69786
|
};
|
|
69682
69787
|
};
|
|
69683
69788
|
const remove = async (frame, _client, ctx) => {
|
|
69684
|
-
|
|
69789
|
+
ensureOwner4(ctx);
|
|
69685
69790
|
const args = parseArgs2(ContactRemoveArgsSchema, frame, "contact:remove");
|
|
69686
69791
|
deps.store.removeByDeviceId(args.deviceId);
|
|
69687
69792
|
deps.broadcast({
|
|
@@ -69755,7 +69860,7 @@ function buildContactHandlers(deps) {
|
|
|
69755
69860
|
|
|
69756
69861
|
// src/handlers/contact-remote-access.ts
|
|
69757
69862
|
init_protocol();
|
|
69758
|
-
function
|
|
69863
|
+
function ensureOwner5(ctx) {
|
|
69759
69864
|
if (!ctx || ctx.principal.kind !== "owner") {
|
|
69760
69865
|
throw new ClawdError(
|
|
69761
69866
|
ERROR_CODES.UNAUTHORIZED,
|
|
@@ -69765,7 +69870,7 @@ function ensureOwner4(ctx) {
|
|
|
69765
69870
|
}
|
|
69766
69871
|
function buildContactRemoteAccessHandlers(deps) {
|
|
69767
69872
|
const setRemoteAccess = async (frame, _client, ctx) => {
|
|
69768
|
-
|
|
69873
|
+
ensureOwner5(ctx);
|
|
69769
69874
|
const args = parseArgs2(ContactSetRemoteAccessArgsSchema, frame, "contact:setRemoteAccess");
|
|
69770
69875
|
const hit = deps.store.setRemoteAccess(args.deviceId, {
|
|
69771
69876
|
remoteAccessAllowed: args.remoteAccessAllowed
|
|
@@ -69925,7 +70030,7 @@ function buildFeishuAuthHandlers(deps) {
|
|
|
69925
70030
|
|
|
69926
70031
|
// src/handlers/cloud-connectors.ts
|
|
69927
70032
|
init_protocol();
|
|
69928
|
-
function
|
|
70033
|
+
function ensureOwner6(ctx) {
|
|
69929
70034
|
if (!ctx || ctx.principal.kind !== "owner") {
|
|
69930
70035
|
throw new ClawdError(ERROR_CODES.UNAUTHORIZED, "UNAUTHORIZED: cloud:connectors:* requires owner ctx");
|
|
69931
70036
|
}
|
|
@@ -69945,7 +70050,7 @@ function buildCloudConnectorsHandlers(deps) {
|
|
|
69945
70050
|
return { gatewayPersonaId: persona.cloud.personaId, connectors: all.filter((c2) => c2.credentialSource === "personal") };
|
|
69946
70051
|
}
|
|
69947
70052
|
const list = async (frame, _client, ctx) => {
|
|
69948
|
-
|
|
70053
|
+
ensureOwner6(ctx);
|
|
69949
70054
|
const { personaId: personaId2 } = parseArgs2(CloudConnectorsListArgsSchema, frame, "cloud:connectors:list");
|
|
69950
70055
|
const { gatewayPersonaId, connectors } = await personalConnectors(personaId2);
|
|
69951
70056
|
if (connectors.length === 0) return { response: { type: "cloud:connectors:list:ok", connectors: [] } };
|
|
@@ -69956,7 +70061,7 @@ function buildCloudConnectorsHandlers(deps) {
|
|
|
69956
70061
|
return { response: { type: "cloud:connectors:list:ok", connectors: parsed.data.connectors } };
|
|
69957
70062
|
};
|
|
69958
70063
|
const fill = async (frame, _client, ctx) => {
|
|
69959
|
-
|
|
70064
|
+
ensureOwner6(ctx);
|
|
69960
70065
|
const args = parseArgs2(CloudConnectorFillArgsSchema, frame, "cloud:connectors:fill");
|
|
69961
70066
|
const { connectors } = await personalConnectors(args.personaId);
|
|
69962
70067
|
const connector = connectors.find((c2) => c2.name === args.name);
|
|
@@ -70027,8 +70132,6 @@ var METHOD_GRANT_MAP = {
|
|
|
70027
70132
|
"deploy:finishScan": ADMIN_ANY,
|
|
70028
70133
|
"deploy:release": ADMIN_ANY,
|
|
70029
70134
|
"deploy:rerunJob": ADMIN_ANY,
|
|
70030
|
-
"deploy:githubAuthorize": ADMIN_ANY,
|
|
70031
|
-
"deploy:githubOauthStart": ADMIN_ANY,
|
|
70032
70135
|
// cloud:connectors:*(云 persona 卡片上的连接器;design 2026-09-11-mcp-connector):
|
|
70033
70136
|
// 拿本机登录凭证向中心代查 / 代填使用者本人的凭据,guest 一律够不着
|
|
70034
70137
|
"cloud:connectors:list": ADMIN_ANY,
|
|
@@ -70117,7 +70220,11 @@ var METHOD_GRANT_MAP = {
|
|
|
70117
70220
|
"project:create": ADMIN_ANY,
|
|
70118
70221
|
"project:patch": ADMIN_ANY,
|
|
70119
70222
|
"project:reveal": ADMIN_ANY,
|
|
70120
|
-
//
|
|
70223
|
+
// githubAuth:*(本机 GitHub 身份,机器级;spec 2026-09-15-github-auth-unify):关联 / 粘 token 只认人手,guest 够不着
|
|
70224
|
+
"githubAuth:get": ADMIN_ANY,
|
|
70225
|
+
"githubAuth:oauthStart": ADMIN_ANY,
|
|
70226
|
+
"githubAuth:authorize": ADMIN_ANY,
|
|
70227
|
+
// github:*(PR 收件箱,spec 2026-08-11):凭据是 githubAuth 那份身份(GH_TOKEN),owner-only 一刀切
|
|
70121
70228
|
"github:status": ADMIN_ANY,
|
|
70122
70229
|
"github:prList": ADMIN_ANY,
|
|
70123
70230
|
"github:prDetail": ADMIN_ANY,
|
|
@@ -70229,8 +70336,8 @@ var HUMAN_ONLY_METHODS = [
|
|
|
70229
70336
|
"deploy:release",
|
|
70230
70337
|
"deploy:putSecret",
|
|
70231
70338
|
"deploy:rerunJob",
|
|
70232
|
-
"
|
|
70233
|
-
"
|
|
70339
|
+
"githubAuth:oauthStart",
|
|
70340
|
+
"githubAuth:authorize"
|
|
70234
70341
|
];
|
|
70235
70342
|
var HUMAN_ONLY = new Set(HUMAN_ONLY_METHODS);
|
|
70236
70343
|
function isHumanOnlyDenied(method, transport) {
|
|
@@ -70273,7 +70380,7 @@ function computeMethodAccess(args) {
|
|
|
70273
70380
|
}
|
|
70274
70381
|
|
|
70275
70382
|
// src/version.ts
|
|
70276
|
-
var version = "0.2.
|
|
70383
|
+
var version = "0.2.519".length > 0 ? "0.2.519" : "dev";
|
|
70277
70384
|
|
|
70278
70385
|
// src/cli-probe/probe.ts
|
|
70279
70386
|
var fs77 = __toESM(require("fs"), 1);
|
|
@@ -71830,9 +71937,8 @@ function parsePrDetailResponse(json, repoRef) {
|
|
|
71830
71937
|
}
|
|
71831
71938
|
|
|
71832
71939
|
// src/handlers/github.ts
|
|
71833
|
-
var HOSTNAME = "github.com";
|
|
71834
71940
|
function buildGithubHandlers(deps) {
|
|
71835
|
-
const { gh } = deps;
|
|
71941
|
+
const { gh, identity } = deps;
|
|
71836
71942
|
return {
|
|
71837
71943
|
"github:status": async () => {
|
|
71838
71944
|
try {
|
|
@@ -71843,13 +71949,9 @@ function buildGithubHandlers(deps) {
|
|
|
71843
71949
|
}
|
|
71844
71950
|
throw err;
|
|
71845
71951
|
}
|
|
71846
|
-
|
|
71847
|
-
|
|
71848
|
-
|
|
71849
|
-
return { response: { installed: true, authenticated: false } };
|
|
71850
|
-
}
|
|
71851
|
-
const login = (await gh.run(["api", "user", "--jq", ".login"])).trim();
|
|
71852
|
-
const response = { installed: true, authenticated: true, login };
|
|
71952
|
+
const st2 = await identity.status();
|
|
71953
|
+
if (st2.status !== "authorized") return { response: { installed: true, authenticated: false } };
|
|
71954
|
+
const response = { installed: true, authenticated: true, login: st2.login };
|
|
71853
71955
|
return { response };
|
|
71854
71956
|
},
|
|
71855
71957
|
"github:prList": async (frame) => {
|
|
@@ -71937,7 +72039,7 @@ function buildGithubHandlers(deps) {
|
|
|
71937
72039
|
|
|
71938
72040
|
// src/handlers/visitor.ts
|
|
71939
72041
|
init_protocol();
|
|
71940
|
-
function
|
|
72042
|
+
function ensureOwner7(ctx) {
|
|
71941
72043
|
if (!ctx || ctx.principal.kind !== "owner") {
|
|
71942
72044
|
throw new ClawdError(
|
|
71943
72045
|
ERROR_CODES.UNAUTHORIZED,
|
|
@@ -71947,7 +72049,7 @@ function ensureOwner6(ctx) {
|
|
|
71947
72049
|
}
|
|
71948
72050
|
function buildVisitorHandlers(deps) {
|
|
71949
72051
|
const list = async (_frame, _client, ctx) => {
|
|
71950
|
-
|
|
72052
|
+
ensureOwner7(ctx);
|
|
71951
72053
|
return {
|
|
71952
72054
|
response: {
|
|
71953
72055
|
type: "visitor:list",
|
|
@@ -72265,7 +72367,7 @@ function buildMethodHandlers(deps) {
|
|
|
72265
72367
|
ownerIdProvider: deps.shiftOwnerIdProvider,
|
|
72266
72368
|
now: () => Date.now()
|
|
72267
72369
|
}),
|
|
72268
|
-
...buildGithubHandlers({ gh: deps.ghRunner }),
|
|
72370
|
+
...buildGithubHandlers({ gh: deps.ghRunner, identity: deps.githubIdentity }),
|
|
72269
72371
|
...buildVisitorHandlers({ visitorStore: deps.visitorStore })
|
|
72270
72372
|
};
|
|
72271
72373
|
handlers["meta:methods"] = buildMetaMethodsHandler({
|
|
@@ -73084,13 +73186,46 @@ async function startDaemon(config) {
|
|
|
73084
73186
|
const secretsBundleRoot = findSecretsBundleRoot(logger);
|
|
73085
73187
|
const localSecretsDir = import_node_path79.default.join(config.dataDir, LOCAL_SECRETS_DIRNAME);
|
|
73086
73188
|
const readSecrets = () => readSecretTable({ bundleRoot: secretsBundleRoot, overrideDir: localSecretsDir, logger });
|
|
73189
|
+
const githubIdentity = createGithubIdentity({
|
|
73190
|
+
resolve: () => resolveGithubAuth({ exec: runCommand, fileToken: () => readSecrets()[GITHUB_TOKEN_VAR] }),
|
|
73191
|
+
store: (token) => storeGithubAuth({
|
|
73192
|
+
exec: runCommand,
|
|
73193
|
+
token,
|
|
73194
|
+
writeFileToken: (t2) => {
|
|
73195
|
+
upsertEnvFileVar(import_node_path79.default.join(localSecretsDir, GITHUB_TOKEN_FILE), GITHUB_TOKEN_VAR, t2);
|
|
73196
|
+
logger.warn("github.identity.token-in-file", { reason: "git \u6CA1\u914D credential helper\uFF0Ctoken \u843D\u672C\u673A\u51ED\u636E\u8868", file: GITHUB_TOKEN_FILE });
|
|
73197
|
+
}
|
|
73198
|
+
}),
|
|
73199
|
+
api: (token) => createGithubApi({ token }),
|
|
73200
|
+
oauth: {
|
|
73201
|
+
start: async (returnTo) => {
|
|
73202
|
+
const r2 = ownerIdentityStore.read();
|
|
73203
|
+
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");
|
|
73204
|
+
try {
|
|
73205
|
+
return await centralGithubAuthOauthStart({ api: config.clawosApi ?? DEFAULT_CLAWOS_API, ttcJwt: r2.ttcToken, provider: r2.identity.provider, ...returnTo ? { returnTo } : {} });
|
|
73206
|
+
} catch (err) {
|
|
73207
|
+
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)}`);
|
|
73208
|
+
}
|
|
73209
|
+
},
|
|
73210
|
+
token: async () => {
|
|
73211
|
+
const r2 = ownerIdentityStore.read();
|
|
73212
|
+
if (!r2) return void 0;
|
|
73213
|
+
return centralGithubAuthToken({ api: config.clawosApi ?? DEFAULT_CLAWOS_API, ttcJwt: r2.ttcToken, provider: r2.identity.provider });
|
|
73214
|
+
}
|
|
73215
|
+
},
|
|
73216
|
+
now: () => Date.now(),
|
|
73217
|
+
logger
|
|
73218
|
+
});
|
|
73219
|
+
void githubIdentity.refresh();
|
|
73087
73220
|
let refreshAppBuilderMcpConfig;
|
|
73088
73221
|
const resolvePersonaMcpConfig = (personaId2) => {
|
|
73089
73222
|
refreshAppBuilderMcpConfig?.(personaId2);
|
|
73223
|
+
const secrets = secretsWithGithubIdentity(readSecrets(), githubIdentity.cached());
|
|
73224
|
+
void githubIdentity.refresh();
|
|
73090
73225
|
return renderPersonaMcpSecrets({
|
|
73091
73226
|
personaId: personaId2,
|
|
73092
73227
|
personaDir: import_node_path79.default.join(config.dataDir, "personas", personaId2),
|
|
73093
|
-
secrets
|
|
73228
|
+
secrets,
|
|
73094
73229
|
outDir: import_node_path79.default.join(config.dataDir, "persona-mcp"),
|
|
73095
73230
|
logger
|
|
73096
73231
|
});
|
|
@@ -73928,8 +74063,9 @@ async function startDaemon(config) {
|
|
|
73928
74063
|
// daemon 稳定身份),跟我们 ShiftStore boot 时用的 provider 一致。
|
|
73929
74064
|
shiftStore,
|
|
73930
74065
|
shiftOwnerIdProvider: () => ownerPrincipalId,
|
|
73931
|
-
// PR 收件箱:github:* handler spawn 本机 gh CLI
|
|
73932
|
-
ghRunner: createGhRunner(),
|
|
74066
|
+
// PR 收件箱:github:* handler spawn 本机 gh CLI,凭据是 clawd 的 GitHub 身份(GH_TOKEN),没有才是 gh 自己的登录态
|
|
74067
|
+
ghRunner: createGhRunner({ token: () => githubIdentity.cached()?.token }),
|
|
74068
|
+
githubIdentity,
|
|
73933
74069
|
// persona web 分享:visitor:list owner RPC 读访客名单(同 exchange upsert 的实例)
|
|
73934
74070
|
visitorStore
|
|
73935
74071
|
})
|
|
@@ -74044,38 +74180,8 @@ async function startDaemon(config) {
|
|
|
74044
74180
|
return p3 ? { ...p3.tool ? { tool: p3.tool } : {}, ...p3.model ? { model: p3.model } : {} } : void 0;
|
|
74045
74181
|
},
|
|
74046
74182
|
exec: runCommand,
|
|
74047
|
-
|
|
74048
|
-
|
|
74049
|
-
// 授权时先交给 git 存,git 没配 helper 才写 <dataDir>/secrets/github-deploy.env。顺序 / 退路的规则在 github-auth.ts,有测试
|
|
74050
|
-
github: {
|
|
74051
|
-
resolve: () => resolveGithubAuth({ exec: runCommand, fileToken: () => readSecrets()[DEPLOY_TOKEN_VAR] }),
|
|
74052
|
-
store: (token) => storeGithubAuth({
|
|
74053
|
-
exec: runCommand,
|
|
74054
|
-
token,
|
|
74055
|
-
writeFileToken: (t2) => {
|
|
74056
|
-
upsertEnvFileVar(import_node_path79.default.join(localSecretsDir, DEPLOY_TOKEN_FILE), DEPLOY_TOKEN_VAR, t2);
|
|
74057
|
-
logger.warn("deploy.github.token-in-file", { reason: "git \u6CA1\u914D credential helper\uFF0Ctoken \u843D\u672C\u673A\u51ED\u636E\u8868", file: DEPLOY_TOKEN_FILE });
|
|
74058
|
-
}
|
|
74059
|
-
}),
|
|
74060
|
-
api: (token) => createGithubApi({ token }),
|
|
74061
|
-
// 点链接的 OAuth 经中心(spec §8):登录凭证只在 daemon 内部传给中心,与 cloudConnectors 同一条纪律
|
|
74062
|
-
oauth: {
|
|
74063
|
-
start: async (returnTo) => {
|
|
74064
|
-
const r2 = ownerIdentityStore.read();
|
|
74065
|
-
if (!r2) throw new ClawdError(ERROR_CODES.FEISHU_LOGIN_REQUIRED, "FEISHU_LOGIN_REQUIRED: \u8FD8\u6CA1\u767B\u5F55\u98DE\u4E66\uFF0C\u7528 GitHub \u6388\u6743\u8981\u7ECF\u4E2D\u5FC3\uFF1B\u5148\u767B\u5F55\uFF0C\u6216\u5728\u5361\u7247\u4E0A\u624B\u52A8\u7C98 token");
|
|
74066
|
-
try {
|
|
74067
|
-
return await centralGithubDeployOauthStart({ api: config.clawosApi ?? DEFAULT_CLAWOS_API, ttcJwt: r2.ttcToken, provider: r2.identity.provider, ...returnTo ? { returnTo } : {} });
|
|
74068
|
-
} catch (err) {
|
|
74069
|
-
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)}`);
|
|
74070
|
-
}
|
|
74071
|
-
},
|
|
74072
|
-
token: async () => {
|
|
74073
|
-
const r2 = ownerIdentityStore.read();
|
|
74074
|
-
if (!r2) return void 0;
|
|
74075
|
-
return centralGithubDeployToken({ api: config.clawosApi ?? DEFAULT_CLAWOS_API, ttcJwt: r2.ttcToken, provider: r2.identity.provider });
|
|
74076
|
-
}
|
|
74077
|
-
}
|
|
74078
|
-
},
|
|
74183
|
+
githubIdentity,
|
|
74184
|
+
githubApi: (token) => createGithubApi({ token }),
|
|
74079
74185
|
org: PERSONA_REPO_ORG,
|
|
74080
74186
|
now: () => Date.now(),
|
|
74081
74187
|
startScan: (personaId2, scanBase) => {
|
|
@@ -74122,6 +74228,7 @@ async function startDaemon(config) {
|
|
|
74122
74228
|
}
|
|
74123
74229
|
});
|
|
74124
74230
|
Object.assign(handlers, deployHandlers);
|
|
74231
|
+
Object.assign(handlers, buildGithubAuthHandlers({ identity: githubIdentity }));
|
|
74125
74232
|
const shiftSpawnFn = createShiftSpawnFn({ sessionManager: manager });
|
|
74126
74233
|
const shiftScheduler = createShiftScheduler({
|
|
74127
74234
|
store: shiftStore,
|