@clawos-dev/clawd 0.2.517 → 0.2.518
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 +283 -194
- 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/share-ui/assets/{guest-fV-R3Vmz.js → guest-CqC7os4f.js} +49 -49
- package/dist/share-ui/guest.html +1 -1
- package/package.json +1 -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
|
|
8925
|
+
},
|
|
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
|
|
8915
8929
|
},
|
|
8916
|
-
"
|
|
8917
|
-
summary: "\
|
|
8918
|
-
args:
|
|
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
|
|
|
@@ -67767,7 +67854,7 @@ async function syncOrgMesh(deps) {
|
|
|
67767
67854
|
|
|
67768
67855
|
// src/handlers/device.ts
|
|
67769
67856
|
init_protocol();
|
|
67770
|
-
function
|
|
67857
|
+
function ensureOwner3(ctx) {
|
|
67771
67858
|
if (!ctx || ctx.principal.kind !== "owner") {
|
|
67772
67859
|
throw new ClawdError(ERROR_CODES.UNAUTHORIZED, "UNAUTHORIZED: device:* requires owner ctx");
|
|
67773
67860
|
}
|
|
@@ -67862,14 +67949,14 @@ function createConnectToDevice(deps) {
|
|
|
67862
67949
|
function buildDeviceHandlers(deps) {
|
|
67863
67950
|
const connectToDevice = createConnectToDevice(deps);
|
|
67864
67951
|
const list = async (_frame, _client, ctx) => {
|
|
67865
|
-
|
|
67952
|
+
ensureOwner3(ctx);
|
|
67866
67953
|
const devices = await deps.listDevices().catch(rethrowLoginExpired);
|
|
67867
67954
|
return {
|
|
67868
67955
|
response: { type: "device:list:ok", devices }
|
|
67869
67956
|
};
|
|
67870
67957
|
};
|
|
67871
67958
|
const connect = async (frame, _client, ctx) => {
|
|
67872
|
-
|
|
67959
|
+
ensureOwner3(ctx);
|
|
67873
67960
|
const { type: _t2, requestId: _r2, ...rest } = frame;
|
|
67874
67961
|
const args = DeviceConnectArgsSchema.parse(rest);
|
|
67875
67962
|
const contact = await connectToDevice(args);
|
|
@@ -67884,7 +67971,7 @@ function buildDeviceHandlers(deps) {
|
|
|
67884
67971
|
};
|
|
67885
67972
|
};
|
|
67886
67973
|
const connections = async (_frame, client, ctx) => {
|
|
67887
|
-
|
|
67974
|
+
ensureOwner3(ctx);
|
|
67888
67975
|
const entries = deps.listOwnerConnections();
|
|
67889
67976
|
return {
|
|
67890
67977
|
response: {
|
|
@@ -69609,7 +69696,7 @@ function upsertPeerContact(args) {
|
|
|
69609
69696
|
}
|
|
69610
69697
|
|
|
69611
69698
|
// src/handlers/contact.ts
|
|
69612
|
-
function
|
|
69699
|
+
function ensureOwner4(ctx) {
|
|
69613
69700
|
if (!ctx || ctx.principal.kind !== "owner") {
|
|
69614
69701
|
throw new ClawdError(
|
|
69615
69702
|
ERROR_CODES.UNAUTHORIZED,
|
|
@@ -69619,7 +69706,7 @@ function ensureOwner3(ctx) {
|
|
|
69619
69706
|
}
|
|
69620
69707
|
function buildContactHandlers(deps) {
|
|
69621
69708
|
const list = async (_frame, _client, ctx) => {
|
|
69622
|
-
|
|
69709
|
+
ensureOwner4(ctx);
|
|
69623
69710
|
return {
|
|
69624
69711
|
response: {
|
|
69625
69712
|
type: "contact:list:ok",
|
|
@@ -69628,7 +69715,7 @@ function buildContactHandlers(deps) {
|
|
|
69628
69715
|
};
|
|
69629
69716
|
};
|
|
69630
69717
|
const pin = async (frame, _client, ctx) => {
|
|
69631
|
-
|
|
69718
|
+
ensureOwner4(ctx);
|
|
69632
69719
|
const args = parseArgs2(ContactPinArgsSchema, frame, "contact:pin");
|
|
69633
69720
|
const pinnedAt = args.pinned ? deps.now() : null;
|
|
69634
69721
|
const hit = deps.store.setPin(args.deviceId, pinnedAt);
|
|
@@ -69652,7 +69739,7 @@ function buildContactHandlers(deps) {
|
|
|
69652
69739
|
};
|
|
69653
69740
|
};
|
|
69654
69741
|
const setNote = async (frame, _client, ctx) => {
|
|
69655
|
-
|
|
69742
|
+
ensureOwner4(ctx);
|
|
69656
69743
|
const args = parseArgs2(ContactSetNoteArgsSchema, frame, "contact:setNote");
|
|
69657
69744
|
const hit = deps.store.setNote(args.deviceId, args.note);
|
|
69658
69745
|
if (!hit) {
|
|
@@ -69675,13 +69762,13 @@ function buildContactHandlers(deps) {
|
|
|
69675
69762
|
};
|
|
69676
69763
|
};
|
|
69677
69764
|
const orgPeers = async (_frame, _client, ctx) => {
|
|
69678
|
-
|
|
69765
|
+
ensureOwner4(ctx);
|
|
69679
69766
|
return {
|
|
69680
69767
|
response: { type: "org:peers:ok", peers: getCachedOrgPeers() }
|
|
69681
69768
|
};
|
|
69682
69769
|
};
|
|
69683
69770
|
const remove = async (frame, _client, ctx) => {
|
|
69684
|
-
|
|
69771
|
+
ensureOwner4(ctx);
|
|
69685
69772
|
const args = parseArgs2(ContactRemoveArgsSchema, frame, "contact:remove");
|
|
69686
69773
|
deps.store.removeByDeviceId(args.deviceId);
|
|
69687
69774
|
deps.broadcast({
|
|
@@ -69755,7 +69842,7 @@ function buildContactHandlers(deps) {
|
|
|
69755
69842
|
|
|
69756
69843
|
// src/handlers/contact-remote-access.ts
|
|
69757
69844
|
init_protocol();
|
|
69758
|
-
function
|
|
69845
|
+
function ensureOwner5(ctx) {
|
|
69759
69846
|
if (!ctx || ctx.principal.kind !== "owner") {
|
|
69760
69847
|
throw new ClawdError(
|
|
69761
69848
|
ERROR_CODES.UNAUTHORIZED,
|
|
@@ -69765,7 +69852,7 @@ function ensureOwner4(ctx) {
|
|
|
69765
69852
|
}
|
|
69766
69853
|
function buildContactRemoteAccessHandlers(deps) {
|
|
69767
69854
|
const setRemoteAccess = async (frame, _client, ctx) => {
|
|
69768
|
-
|
|
69855
|
+
ensureOwner5(ctx);
|
|
69769
69856
|
const args = parseArgs2(ContactSetRemoteAccessArgsSchema, frame, "contact:setRemoteAccess");
|
|
69770
69857
|
const hit = deps.store.setRemoteAccess(args.deviceId, {
|
|
69771
69858
|
remoteAccessAllowed: args.remoteAccessAllowed
|
|
@@ -69925,7 +70012,7 @@ function buildFeishuAuthHandlers(deps) {
|
|
|
69925
70012
|
|
|
69926
70013
|
// src/handlers/cloud-connectors.ts
|
|
69927
70014
|
init_protocol();
|
|
69928
|
-
function
|
|
70015
|
+
function ensureOwner6(ctx) {
|
|
69929
70016
|
if (!ctx || ctx.principal.kind !== "owner") {
|
|
69930
70017
|
throw new ClawdError(ERROR_CODES.UNAUTHORIZED, "UNAUTHORIZED: cloud:connectors:* requires owner ctx");
|
|
69931
70018
|
}
|
|
@@ -69945,7 +70032,7 @@ function buildCloudConnectorsHandlers(deps) {
|
|
|
69945
70032
|
return { gatewayPersonaId: persona.cloud.personaId, connectors: all.filter((c2) => c2.credentialSource === "personal") };
|
|
69946
70033
|
}
|
|
69947
70034
|
const list = async (frame, _client, ctx) => {
|
|
69948
|
-
|
|
70035
|
+
ensureOwner6(ctx);
|
|
69949
70036
|
const { personaId: personaId2 } = parseArgs2(CloudConnectorsListArgsSchema, frame, "cloud:connectors:list");
|
|
69950
70037
|
const { gatewayPersonaId, connectors } = await personalConnectors(personaId2);
|
|
69951
70038
|
if (connectors.length === 0) return { response: { type: "cloud:connectors:list:ok", connectors: [] } };
|
|
@@ -69956,7 +70043,7 @@ function buildCloudConnectorsHandlers(deps) {
|
|
|
69956
70043
|
return { response: { type: "cloud:connectors:list:ok", connectors: parsed.data.connectors } };
|
|
69957
70044
|
};
|
|
69958
70045
|
const fill = async (frame, _client, ctx) => {
|
|
69959
|
-
|
|
70046
|
+
ensureOwner6(ctx);
|
|
69960
70047
|
const args = parseArgs2(CloudConnectorFillArgsSchema, frame, "cloud:connectors:fill");
|
|
69961
70048
|
const { connectors } = await personalConnectors(args.personaId);
|
|
69962
70049
|
const connector = connectors.find((c2) => c2.name === args.name);
|
|
@@ -70027,8 +70114,6 @@ var METHOD_GRANT_MAP = {
|
|
|
70027
70114
|
"deploy:finishScan": ADMIN_ANY,
|
|
70028
70115
|
"deploy:release": ADMIN_ANY,
|
|
70029
70116
|
"deploy:rerunJob": ADMIN_ANY,
|
|
70030
|
-
"deploy:githubAuthorize": ADMIN_ANY,
|
|
70031
|
-
"deploy:githubOauthStart": ADMIN_ANY,
|
|
70032
70117
|
// cloud:connectors:*(云 persona 卡片上的连接器;design 2026-09-11-mcp-connector):
|
|
70033
70118
|
// 拿本机登录凭证向中心代查 / 代填使用者本人的凭据,guest 一律够不着
|
|
70034
70119
|
"cloud:connectors:list": ADMIN_ANY,
|
|
@@ -70117,7 +70202,11 @@ var METHOD_GRANT_MAP = {
|
|
|
70117
70202
|
"project:create": ADMIN_ANY,
|
|
70118
70203
|
"project:patch": ADMIN_ANY,
|
|
70119
70204
|
"project:reveal": ADMIN_ANY,
|
|
70120
|
-
//
|
|
70205
|
+
// githubAuth:*(本机 GitHub 身份,机器级;spec 2026-09-15-github-auth-unify):关联 / 粘 token 只认人手,guest 够不着
|
|
70206
|
+
"githubAuth:get": ADMIN_ANY,
|
|
70207
|
+
"githubAuth:oauthStart": ADMIN_ANY,
|
|
70208
|
+
"githubAuth:authorize": ADMIN_ANY,
|
|
70209
|
+
// github:*(PR 收件箱,spec 2026-08-11):凭据是 githubAuth 那份身份(GH_TOKEN),owner-only 一刀切
|
|
70121
70210
|
"github:status": ADMIN_ANY,
|
|
70122
70211
|
"github:prList": ADMIN_ANY,
|
|
70123
70212
|
"github:prDetail": ADMIN_ANY,
|
|
@@ -70229,8 +70318,8 @@ var HUMAN_ONLY_METHODS = [
|
|
|
70229
70318
|
"deploy:release",
|
|
70230
70319
|
"deploy:putSecret",
|
|
70231
70320
|
"deploy:rerunJob",
|
|
70232
|
-
"
|
|
70233
|
-
"
|
|
70321
|
+
"githubAuth:oauthStart",
|
|
70322
|
+
"githubAuth:authorize"
|
|
70234
70323
|
];
|
|
70235
70324
|
var HUMAN_ONLY = new Set(HUMAN_ONLY_METHODS);
|
|
70236
70325
|
function isHumanOnlyDenied(method, transport) {
|
|
@@ -70273,7 +70362,7 @@ function computeMethodAccess(args) {
|
|
|
70273
70362
|
}
|
|
70274
70363
|
|
|
70275
70364
|
// src/version.ts
|
|
70276
|
-
var version = "0.2.
|
|
70365
|
+
var version = "0.2.518".length > 0 ? "0.2.518" : "dev";
|
|
70277
70366
|
|
|
70278
70367
|
// src/cli-probe/probe.ts
|
|
70279
70368
|
var fs77 = __toESM(require("fs"), 1);
|
|
@@ -71830,9 +71919,8 @@ function parsePrDetailResponse(json, repoRef) {
|
|
|
71830
71919
|
}
|
|
71831
71920
|
|
|
71832
71921
|
// src/handlers/github.ts
|
|
71833
|
-
var HOSTNAME = "github.com";
|
|
71834
71922
|
function buildGithubHandlers(deps) {
|
|
71835
|
-
const { gh } = deps;
|
|
71923
|
+
const { gh, identity } = deps;
|
|
71836
71924
|
return {
|
|
71837
71925
|
"github:status": async () => {
|
|
71838
71926
|
try {
|
|
@@ -71843,13 +71931,9 @@ function buildGithubHandlers(deps) {
|
|
|
71843
71931
|
}
|
|
71844
71932
|
throw err;
|
|
71845
71933
|
}
|
|
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 };
|
|
71934
|
+
const st2 = await identity.status();
|
|
71935
|
+
if (st2.status !== "authorized") return { response: { installed: true, authenticated: false } };
|
|
71936
|
+
const response = { installed: true, authenticated: true, login: st2.login };
|
|
71853
71937
|
return { response };
|
|
71854
71938
|
},
|
|
71855
71939
|
"github:prList": async (frame) => {
|
|
@@ -71937,7 +72021,7 @@ function buildGithubHandlers(deps) {
|
|
|
71937
72021
|
|
|
71938
72022
|
// src/handlers/visitor.ts
|
|
71939
72023
|
init_protocol();
|
|
71940
|
-
function
|
|
72024
|
+
function ensureOwner7(ctx) {
|
|
71941
72025
|
if (!ctx || ctx.principal.kind !== "owner") {
|
|
71942
72026
|
throw new ClawdError(
|
|
71943
72027
|
ERROR_CODES.UNAUTHORIZED,
|
|
@@ -71947,7 +72031,7 @@ function ensureOwner6(ctx) {
|
|
|
71947
72031
|
}
|
|
71948
72032
|
function buildVisitorHandlers(deps) {
|
|
71949
72033
|
const list = async (_frame, _client, ctx) => {
|
|
71950
|
-
|
|
72034
|
+
ensureOwner7(ctx);
|
|
71951
72035
|
return {
|
|
71952
72036
|
response: {
|
|
71953
72037
|
type: "visitor:list",
|
|
@@ -72265,7 +72349,7 @@ function buildMethodHandlers(deps) {
|
|
|
72265
72349
|
ownerIdProvider: deps.shiftOwnerIdProvider,
|
|
72266
72350
|
now: () => Date.now()
|
|
72267
72351
|
}),
|
|
72268
|
-
...buildGithubHandlers({ gh: deps.ghRunner }),
|
|
72352
|
+
...buildGithubHandlers({ gh: deps.ghRunner, identity: deps.githubIdentity }),
|
|
72269
72353
|
...buildVisitorHandlers({ visitorStore: deps.visitorStore })
|
|
72270
72354
|
};
|
|
72271
72355
|
handlers["meta:methods"] = buildMetaMethodsHandler({
|
|
@@ -73084,13 +73168,46 @@ async function startDaemon(config) {
|
|
|
73084
73168
|
const secretsBundleRoot = findSecretsBundleRoot(logger);
|
|
73085
73169
|
const localSecretsDir = import_node_path79.default.join(config.dataDir, LOCAL_SECRETS_DIRNAME);
|
|
73086
73170
|
const readSecrets = () => readSecretTable({ bundleRoot: secretsBundleRoot, overrideDir: localSecretsDir, logger });
|
|
73171
|
+
const githubIdentity = createGithubIdentity({
|
|
73172
|
+
resolve: () => resolveGithubAuth({ exec: runCommand, fileToken: () => readSecrets()[GITHUB_TOKEN_VAR] }),
|
|
73173
|
+
store: (token) => storeGithubAuth({
|
|
73174
|
+
exec: runCommand,
|
|
73175
|
+
token,
|
|
73176
|
+
writeFileToken: (t2) => {
|
|
73177
|
+
upsertEnvFileVar(import_node_path79.default.join(localSecretsDir, GITHUB_TOKEN_FILE), GITHUB_TOKEN_VAR, t2);
|
|
73178
|
+
logger.warn("github.identity.token-in-file", { reason: "git \u6CA1\u914D credential helper\uFF0Ctoken \u843D\u672C\u673A\u51ED\u636E\u8868", file: GITHUB_TOKEN_FILE });
|
|
73179
|
+
}
|
|
73180
|
+
}),
|
|
73181
|
+
api: (token) => createGithubApi({ token }),
|
|
73182
|
+
oauth: {
|
|
73183
|
+
start: async (returnTo) => {
|
|
73184
|
+
const r2 = ownerIdentityStore.read();
|
|
73185
|
+
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");
|
|
73186
|
+
try {
|
|
73187
|
+
return await centralGithubAuthOauthStart({ api: config.clawosApi ?? DEFAULT_CLAWOS_API, ttcJwt: r2.ttcToken, provider: r2.identity.provider, ...returnTo ? { returnTo } : {} });
|
|
73188
|
+
} catch (err) {
|
|
73189
|
+
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)}`);
|
|
73190
|
+
}
|
|
73191
|
+
},
|
|
73192
|
+
token: async () => {
|
|
73193
|
+
const r2 = ownerIdentityStore.read();
|
|
73194
|
+
if (!r2) return void 0;
|
|
73195
|
+
return centralGithubAuthToken({ api: config.clawosApi ?? DEFAULT_CLAWOS_API, ttcJwt: r2.ttcToken, provider: r2.identity.provider });
|
|
73196
|
+
}
|
|
73197
|
+
},
|
|
73198
|
+
now: () => Date.now(),
|
|
73199
|
+
logger
|
|
73200
|
+
});
|
|
73201
|
+
void githubIdentity.refresh();
|
|
73087
73202
|
let refreshAppBuilderMcpConfig;
|
|
73088
73203
|
const resolvePersonaMcpConfig = (personaId2) => {
|
|
73089
73204
|
refreshAppBuilderMcpConfig?.(personaId2);
|
|
73205
|
+
const secrets = secretsWithGithubIdentity(readSecrets(), githubIdentity.cached());
|
|
73206
|
+
void githubIdentity.refresh();
|
|
73090
73207
|
return renderPersonaMcpSecrets({
|
|
73091
73208
|
personaId: personaId2,
|
|
73092
73209
|
personaDir: import_node_path79.default.join(config.dataDir, "personas", personaId2),
|
|
73093
|
-
secrets
|
|
73210
|
+
secrets,
|
|
73094
73211
|
outDir: import_node_path79.default.join(config.dataDir, "persona-mcp"),
|
|
73095
73212
|
logger
|
|
73096
73213
|
});
|
|
@@ -73928,8 +74045,9 @@ async function startDaemon(config) {
|
|
|
73928
74045
|
// daemon 稳定身份),跟我们 ShiftStore boot 时用的 provider 一致。
|
|
73929
74046
|
shiftStore,
|
|
73930
74047
|
shiftOwnerIdProvider: () => ownerPrincipalId,
|
|
73931
|
-
// PR 收件箱:github:* handler spawn 本机 gh CLI
|
|
73932
|
-
ghRunner: createGhRunner(),
|
|
74048
|
+
// PR 收件箱:github:* handler spawn 本机 gh CLI,凭据是 clawd 的 GitHub 身份(GH_TOKEN),没有才是 gh 自己的登录态
|
|
74049
|
+
ghRunner: createGhRunner({ token: () => githubIdentity.cached()?.token }),
|
|
74050
|
+
githubIdentity,
|
|
73933
74051
|
// persona web 分享:visitor:list owner RPC 读访客名单(同 exchange upsert 的实例)
|
|
73934
74052
|
visitorStore
|
|
73935
74053
|
})
|
|
@@ -74044,38 +74162,8 @@ async function startDaemon(config) {
|
|
|
74044
74162
|
return p3 ? { ...p3.tool ? { tool: p3.tool } : {}, ...p3.model ? { model: p3.model } : {} } : void 0;
|
|
74045
74163
|
},
|
|
74046
74164
|
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
|
-
},
|
|
74165
|
+
githubIdentity,
|
|
74166
|
+
githubApi: (token) => createGithubApi({ token }),
|
|
74079
74167
|
org: PERSONA_REPO_ORG,
|
|
74080
74168
|
now: () => Date.now(),
|
|
74081
74169
|
startScan: (personaId2, scanBase) => {
|
|
@@ -74122,6 +74210,7 @@ async function startDaemon(config) {
|
|
|
74122
74210
|
}
|
|
74123
74211
|
});
|
|
74124
74212
|
Object.assign(handlers, deployHandlers);
|
|
74213
|
+
Object.assign(handlers, buildGithubAuthHandlers({ identity: githubIdentity }));
|
|
74125
74214
|
const shiftSpawnFn = createShiftSpawnFn({ sessionManager: manager });
|
|
74126
74215
|
const shiftScheduler = createShiftScheduler({
|
|
74127
74216
|
store: shiftStore,
|