@clawos-dev/clawd 0.2.482 → 0.2.483
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 +37 -0
- package/dist/cli.cjs +164 -14
- package/dist/dispatch/mcp-server.cjs +37 -0
- package/dist/share-md-viewer-error.html +1 -1
- package/dist/share-md-viewer.html +1 -1
- package/dist/share-ui/assets/{guest-Dq7_X2SL.js → guest-DJeF4_0c.js} +116 -116
- package/dist/share-ui/assets/guest-DfB6GnKj.css +32 -0
- package/dist/share-ui/guest.html +2 -2
- package/package.json +1 -1
- package/dist/share-ui/assets/guest-Ct-libAx.css +0 -32
|
@@ -21374,6 +21374,29 @@ var DeploySecretPresenceSchema = external_exports.object({
|
|
|
21374
21374
|
env: external_exports.string().min(1),
|
|
21375
21375
|
setAt: external_exports.number().optional()
|
|
21376
21376
|
}).strict();
|
|
21377
|
+
var DEPLOY_STAGE_STATUSES = ["pending", "running", "done", "failed", "waiting", "skipped"];
|
|
21378
|
+
var DeployStageStatusSchema = external_exports.enum(DEPLOY_STAGE_STATUSES);
|
|
21379
|
+
var DEPLOY_STAGE_KEYS = ["build", "smoke", "deploy"];
|
|
21380
|
+
var DeployStageKeySchema = external_exports.enum(DEPLOY_STAGE_KEYS);
|
|
21381
|
+
var DeployJobSchema = external_exports.object({
|
|
21382
|
+
key: DeployStageKeySchema,
|
|
21383
|
+
status: DeployStageStatusSchema,
|
|
21384
|
+
/** 这个 job 在 GitHub 上的页面。还没跑起来的段没有 */
|
|
21385
|
+
url: external_exports.string().optional(),
|
|
21386
|
+
/** GitHub 的 job databaseId,`gh run rerun --job` 要用。还没跑起来的段没有 */
|
|
21387
|
+
jobId: external_exports.number().optional(),
|
|
21388
|
+
startedAt: external_exports.number().optional(),
|
|
21389
|
+
completedAt: external_exports.number().optional()
|
|
21390
|
+
}).strict();
|
|
21391
|
+
var DeployRunSchema = external_exports.object({
|
|
21392
|
+
runId: external_exports.number(),
|
|
21393
|
+
headSha: external_exports.string().min(1),
|
|
21394
|
+
/** run 整体只有三态。**别跟 job 的六态混用**:run 没有「跳过」也没有「等审批」 */
|
|
21395
|
+
status: external_exports.enum(["queued", "running", "completed"]),
|
|
21396
|
+
htmlUrl: external_exports.string().min(1),
|
|
21397
|
+
/** run 刚入队时可能一条都还没有 */
|
|
21398
|
+
jobs: external_exports.array(DeployJobSchema)
|
|
21399
|
+
}).strict();
|
|
21377
21400
|
var DeployStateSchema = external_exports.object({
|
|
21378
21401
|
personaId: external_exports.string().min(1),
|
|
21379
21402
|
repo: DeployRepoSchema.optional(),
|
|
@@ -21381,6 +21404,11 @@ var DeployStateSchema = external_exports.object({
|
|
|
21381
21404
|
scan: DeployScanSchema.optional(),
|
|
21382
21405
|
/** 没仓库时缺席(查不了) */
|
|
21383
21406
|
secrets: external_exports.array(DeploySecretPresenceSchema).optional(),
|
|
21407
|
+
/**
|
|
21408
|
+
* 最新那次流水线走到哪了。**缺席是常态**:没推过、gh 查不到、仓库还没有 run,
|
|
21409
|
+
* 都不该让整页打不开——同 `secrets` 的处理。
|
|
21410
|
+
*/
|
|
21411
|
+
run: DeployRunSchema.optional(),
|
|
21384
21412
|
/**
|
|
21385
21413
|
* `.clawd/deploy.json` 读不出来(人手改坏了)时的人话。有它就没有 `file`。
|
|
21386
21414
|
* 页面据此给一条能走的路(重新扫描会整份重写),而不是白屏。
|
|
@@ -21408,6 +21436,11 @@ var DeployPutSecretArgsSchema = external_exports.object({
|
|
|
21408
21436
|
// 环境变量名 → 值。key 必须是该 secret 声明过的 env 之一,handler 校验。
|
|
21409
21437
|
values: external_exports.record(external_exports.string(), external_exports.string())
|
|
21410
21438
|
}).strict();
|
|
21439
|
+
var DeployRerunJobArgsSchema = external_exports.object({
|
|
21440
|
+
personaId: external_exports.string().min(1),
|
|
21441
|
+
/** GitHub 的 job databaseId。**是数字**——字符串会在拼命令时静默出错 */
|
|
21442
|
+
jobId: external_exports.number()
|
|
21443
|
+
}).strict();
|
|
21411
21444
|
var DeployReportFindingArgsSchema = external_exports.object({
|
|
21412
21445
|
personaId: external_exports.string().min(1),
|
|
21413
21446
|
kind: external_exports.enum(["cli", "secret", "asset"]),
|
|
@@ -23923,6 +23956,10 @@ var METHOD_DOCS = {
|
|
|
23923
23956
|
summary: "\u53D1\u5E03 = \u63D0\u4EA4\u5E76\u63A8\u9001\u5230\u4ED3\u5E93\uFF1A\u91CD\u5199 workflow \u6A21\u677F \u2192 git add -A \u2192 \u7A7A\u63D0\u4EA4\u4E5F\u5141\u8BB8 \u2192 push\u3002\u4ED3\u5E93\u91CC\u7684\u6D41\u6C34\u7EBF\u63A5\u7740\u6784\u955C\u50CF\u3001\u5728\u96C6\u7FA4\u4E0A\u771F\u8D77\u4E00\u6B21\u3001\u767B\u8BB0\u6210\u6B63\u5F0F\uFF0C\u8FDB\u5EA6\u5728 GitHub Actions \u770B\u3002\u524D\u7F6E\uFF1A\u5DF2\u7ED1\u5B9A\u4ED3\u5E93\u3001\u6709\u6E05\u5355\u3001\u6BCF\u4E2A\u53D8\u91CF\u540D\u90FD\u5728 Secrets \u91CC\uFF1Bowner-only",
|
|
23924
23957
|
args: DeployPersonaArgsSchema
|
|
23925
23958
|
},
|
|
23959
|
+
"deploy:rerunJob": {
|
|
23960
|
+
summary: "\u539F\u6837\u91CD\u8DD1\u6700\u65B0\u90A3\u6761\u6D41\u6C34\u7EBF\u91CC\u5931\u8D25\u7684\u67D0\u4E00\u6BB5\uFF08gh run 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",
|
|
23961
|
+
args: DeployRerunJobArgsSchema
|
|
23962
|
+
},
|
|
23926
23963
|
"shift:list": {
|
|
23927
23964
|
summary: "\u5217\u51FA owner \u7684\u5168\u90E8 shift\uFF08\u6392\u73ED\uFF09\uFF0C\u7ED9 UI \u65E5\u5386\u6E32\u67D3\u7528\uFF1Bowner-only",
|
|
23928
23965
|
args: NO_ARGS
|
package/dist/cli.cjs
CHANGED
|
@@ -6025,7 +6025,7 @@ var init_environment_schemas = __esm({
|
|
|
6025
6025
|
function repoSlug(url) {
|
|
6026
6026
|
return url.trim().replace(/^git@[^:]+:/, "").replace(/^https?:\/\/[^/]+\//, "").replace(/\.git$/, "");
|
|
6027
6027
|
}
|
|
6028
|
-
var DeployFileSchema, DeployScanStatusSchema, DeployScanSchema, DeployRepoSchema, DeploySecretPresenceSchema, DeployStateSchema, DeployReleaseResultSchema, DeployPersonaArgsSchema, DeployPatchArgsSchema, DeployPutSecretArgsSchema, DeployReportFindingArgsSchema, DeployFinishScanArgsSchema, PERSONA_REPO_ORG;
|
|
6028
|
+
var DeployFileSchema, DeployScanStatusSchema, DeployScanSchema, DeployRepoSchema, DeploySecretPresenceSchema, DEPLOY_STAGE_STATUSES, DeployStageStatusSchema, DEPLOY_STAGE_KEYS, DeployStageKeySchema, DeployJobSchema, DeployRunSchema, DeployStateSchema, DeployReleaseResultSchema, DeployPersonaArgsSchema, DeployPatchArgsSchema, DeployPutSecretArgsSchema, DeployRerunJobArgsSchema, DeployReportFindingArgsSchema, DeployFinishScanArgsSchema, PERSONA_REPO_ORG;
|
|
6029
6029
|
var init_deploy_schemas = __esm({
|
|
6030
6030
|
"../protocol/src/deploy-schemas.ts"() {
|
|
6031
6031
|
"use strict";
|
|
@@ -6061,6 +6061,29 @@ var init_deploy_schemas = __esm({
|
|
|
6061
6061
|
env: external_exports.string().min(1),
|
|
6062
6062
|
setAt: external_exports.number().optional()
|
|
6063
6063
|
}).strict();
|
|
6064
|
+
DEPLOY_STAGE_STATUSES = ["pending", "running", "done", "failed", "waiting", "skipped"];
|
|
6065
|
+
DeployStageStatusSchema = external_exports.enum(DEPLOY_STAGE_STATUSES);
|
|
6066
|
+
DEPLOY_STAGE_KEYS = ["build", "smoke", "deploy"];
|
|
6067
|
+
DeployStageKeySchema = external_exports.enum(DEPLOY_STAGE_KEYS);
|
|
6068
|
+
DeployJobSchema = external_exports.object({
|
|
6069
|
+
key: DeployStageKeySchema,
|
|
6070
|
+
status: DeployStageStatusSchema,
|
|
6071
|
+
/** 这个 job 在 GitHub 上的页面。还没跑起来的段没有 */
|
|
6072
|
+
url: external_exports.string().optional(),
|
|
6073
|
+
/** GitHub 的 job databaseId,`gh run rerun --job` 要用。还没跑起来的段没有 */
|
|
6074
|
+
jobId: external_exports.number().optional(),
|
|
6075
|
+
startedAt: external_exports.number().optional(),
|
|
6076
|
+
completedAt: external_exports.number().optional()
|
|
6077
|
+
}).strict();
|
|
6078
|
+
DeployRunSchema = external_exports.object({
|
|
6079
|
+
runId: external_exports.number(),
|
|
6080
|
+
headSha: external_exports.string().min(1),
|
|
6081
|
+
/** run 整体只有三态。**别跟 job 的六态混用**:run 没有「跳过」也没有「等审批」 */
|
|
6082
|
+
status: external_exports.enum(["queued", "running", "completed"]),
|
|
6083
|
+
htmlUrl: external_exports.string().min(1),
|
|
6084
|
+
/** run 刚入队时可能一条都还没有 */
|
|
6085
|
+
jobs: external_exports.array(DeployJobSchema)
|
|
6086
|
+
}).strict();
|
|
6064
6087
|
DeployStateSchema = external_exports.object({
|
|
6065
6088
|
personaId: external_exports.string().min(1),
|
|
6066
6089
|
repo: DeployRepoSchema.optional(),
|
|
@@ -6068,6 +6091,11 @@ var init_deploy_schemas = __esm({
|
|
|
6068
6091
|
scan: DeployScanSchema.optional(),
|
|
6069
6092
|
/** 没仓库时缺席(查不了) */
|
|
6070
6093
|
secrets: external_exports.array(DeploySecretPresenceSchema).optional(),
|
|
6094
|
+
/**
|
|
6095
|
+
* 最新那次流水线走到哪了。**缺席是常态**:没推过、gh 查不到、仓库还没有 run,
|
|
6096
|
+
* 都不该让整页打不开——同 `secrets` 的处理。
|
|
6097
|
+
*/
|
|
6098
|
+
run: DeployRunSchema.optional(),
|
|
6071
6099
|
/**
|
|
6072
6100
|
* `.clawd/deploy.json` 读不出来(人手改坏了)时的人话。有它就没有 `file`。
|
|
6073
6101
|
* 页面据此给一条能走的路(重新扫描会整份重写),而不是白屏。
|
|
@@ -6095,6 +6123,11 @@ var init_deploy_schemas = __esm({
|
|
|
6095
6123
|
// 环境变量名 → 值。key 必须是该 secret 声明过的 env 之一,handler 校验。
|
|
6096
6124
|
values: external_exports.record(external_exports.string(), external_exports.string())
|
|
6097
6125
|
}).strict();
|
|
6126
|
+
DeployRerunJobArgsSchema = external_exports.object({
|
|
6127
|
+
personaId: external_exports.string().min(1),
|
|
6128
|
+
/** GitHub 的 job databaseId。**是数字**——字符串会在拼命令时静默出错 */
|
|
6129
|
+
jobId: external_exports.number()
|
|
6130
|
+
}).strict();
|
|
6098
6131
|
DeployReportFindingArgsSchema = external_exports.object({
|
|
6099
6132
|
personaId: external_exports.string().min(1),
|
|
6100
6133
|
kind: external_exports.enum(["cli", "secret", "asset"]),
|
|
@@ -8875,6 +8908,10 @@ var init_methods = __esm({
|
|
|
8875
8908
|
summary: "\u53D1\u5E03 = \u63D0\u4EA4\u5E76\u63A8\u9001\u5230\u4ED3\u5E93\uFF1A\u91CD\u5199 workflow \u6A21\u677F \u2192 git add -A \u2192 \u7A7A\u63D0\u4EA4\u4E5F\u5141\u8BB8 \u2192 push\u3002\u4ED3\u5E93\u91CC\u7684\u6D41\u6C34\u7EBF\u63A5\u7740\u6784\u955C\u50CF\u3001\u5728\u96C6\u7FA4\u4E0A\u771F\u8D77\u4E00\u6B21\u3001\u767B\u8BB0\u6210\u6B63\u5F0F\uFF0C\u8FDB\u5EA6\u5728 GitHub Actions \u770B\u3002\u524D\u7F6E\uFF1A\u5DF2\u7ED1\u5B9A\u4ED3\u5E93\u3001\u6709\u6E05\u5355\u3001\u6BCF\u4E2A\u53D8\u91CF\u540D\u90FD\u5728 Secrets \u91CC\uFF1Bowner-only",
|
|
8876
8909
|
args: DeployPersonaArgsSchema
|
|
8877
8910
|
},
|
|
8911
|
+
"deploy:rerunJob": {
|
|
8912
|
+
summary: "\u539F\u6837\u91CD\u8DD1\u6700\u65B0\u90A3\u6761\u6D41\u6C34\u7EBF\u91CC\u5931\u8D25\u7684\u67D0\u4E00\u6BB5\uFF08gh run 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",
|
|
8913
|
+
args: DeployRerunJobArgsSchema
|
|
8914
|
+
},
|
|
8878
8915
|
"shift:list": {
|
|
8879
8916
|
summary: "\u5217\u51FA owner \u7684\u5168\u90E8 shift\uFF08\u6392\u73ED\uFF09\uFF0C\u7ED9 UI \u65E5\u5386\u6E32\u67D3\u7528\uFF1Bowner-only",
|
|
8880
8917
|
args: NO_ARGS
|
|
@@ -54780,7 +54817,9 @@ var L = [
|
|
|
54780
54817
|
"",
|
|
54781
54818
|
"jobs:",
|
|
54782
54819
|
" build:",
|
|
54783
|
-
|
|
54820
|
+
// name 就是段 key:daemon 按 jobs API 回的 name 认段(那接口不返回 job 的 key)。
|
|
54821
|
+
// 中文说明归 clawd 的上云页面,这里保持机器好认。
|
|
54822
|
+
" name: build",
|
|
54784
54823
|
" runs-on: ubuntu-latest",
|
|
54785
54824
|
" timeout-minutes: 30",
|
|
54786
54825
|
" outputs:",
|
|
@@ -54886,7 +54925,7 @@ var L = [
|
|
|
54886
54925
|
' run: docker push "$REGISTRY/$IMAGE_NAME:${{ steps.plan.outputs.tag }}"',
|
|
54887
54926
|
"",
|
|
54888
54927
|
" smoke:",
|
|
54889
|
-
" name: smoke
|
|
54928
|
+
" name: smoke",
|
|
54890
54929
|
" needs: build",
|
|
54891
54930
|
" runs-on: ubuntu-latest",
|
|
54892
54931
|
" timeout-minutes: 20",
|
|
@@ -54917,7 +54956,7 @@ var L = [
|
|
|
54917
54956
|
" --run-number '${{ github.run_number }}'",
|
|
54918
54957
|
"",
|
|
54919
54958
|
" deploy:",
|
|
54920
|
-
" name: deploy
|
|
54959
|
+
" name: deploy",
|
|
54921
54960
|
" needs: [build, smoke]",
|
|
54922
54961
|
" runs-on: ubuntu-latest",
|
|
54923
54962
|
" # \u4ED3\u5E93\u914D\u4E86 production \u73AF\u5883\u7684\u300C\u987B\u5BA1\u6838\u4EBA\u6279\u51C6\u300D\uFF0Cjob \u5C31\u505C\u5728\u8FD9\u91CC\u7B49\u4EBA\u70B9\uFF1B\u6CA1\u914D\u5C31\u76F4\u63A5\u8FC7\u3002",
|
|
@@ -55110,8 +55149,8 @@ async function listSecrets(exec, dir) {
|
|
|
55110
55149
|
throw new RepoError(`gh secret list \u56DE\u7684\u4E0D\u662F JSON\uFF1A${tail(r.stdout, 200)}`);
|
|
55111
55150
|
}
|
|
55112
55151
|
return rows.filter((x) => typeof x.name === "string" && x.name.length > 0).map((x) => {
|
|
55113
|
-
const
|
|
55114
|
-
return { env: x.name, ...Number.isFinite(
|
|
55152
|
+
const at2 = x.updatedAt ? Date.parse(x.updatedAt) : Number.NaN;
|
|
55153
|
+
return { env: x.name, ...Number.isFinite(at2) ? { setAt: at2 } : {} };
|
|
55115
55154
|
});
|
|
55116
55155
|
}
|
|
55117
55156
|
async function release(exec, args) {
|
|
@@ -55127,6 +55166,83 @@ async function release(exec, args) {
|
|
|
55127
55166
|
return { sha, actionsUrl: `https://github.com/${repoSlug(info.url)}/actions` };
|
|
55128
55167
|
}
|
|
55129
55168
|
|
|
55169
|
+
// src/deploy/run-status.ts
|
|
55170
|
+
init_protocol();
|
|
55171
|
+
var TIMEOUT_MS = 8e3;
|
|
55172
|
+
var pipelineJobKey = (name) => DEPLOY_STAGE_KEYS.find((k2) => name === k2 || name.startsWith(`${k2} `));
|
|
55173
|
+
function stageStatusOf(status, conclusion) {
|
|
55174
|
+
if (status === "queued" || status === "requested" || status === "pending") return "pending";
|
|
55175
|
+
if (status === "waiting") return "waiting";
|
|
55176
|
+
if (status === "in_progress") return "running";
|
|
55177
|
+
if (conclusion === "success") return "done";
|
|
55178
|
+
if (conclusion === "skipped") return "skipped";
|
|
55179
|
+
return "failed";
|
|
55180
|
+
}
|
|
55181
|
+
function runStatusOf(status) {
|
|
55182
|
+
if (status === "completed") return "completed";
|
|
55183
|
+
if (status === "queued" || status === "waiting" || status === "requested" || status === "pending") return "queued";
|
|
55184
|
+
return "running";
|
|
55185
|
+
}
|
|
55186
|
+
async function ghJson(exec, path97) {
|
|
55187
|
+
const r = await exec("gh", ["api", path97], { timeoutMs: TIMEOUT_MS });
|
|
55188
|
+
if (r.spawnError || r.code !== 0) return void 0;
|
|
55189
|
+
try {
|
|
55190
|
+
return JSON.parse(r.stdout);
|
|
55191
|
+
} catch {
|
|
55192
|
+
return void 0;
|
|
55193
|
+
}
|
|
55194
|
+
}
|
|
55195
|
+
function at(iso) {
|
|
55196
|
+
if (typeof iso !== "string") return void 0;
|
|
55197
|
+
const ms = Date.parse(iso);
|
|
55198
|
+
return Number.isNaN(ms) ? void 0 : ms;
|
|
55199
|
+
}
|
|
55200
|
+
function toJob(raw) {
|
|
55201
|
+
const name = typeof raw.name === "string" ? raw.name : "";
|
|
55202
|
+
const key = pipelineJobKey(name);
|
|
55203
|
+
if (key === void 0) return void 0;
|
|
55204
|
+
const startedAt = at(raw.started_at);
|
|
55205
|
+
const completedAt = at(raw.completed_at);
|
|
55206
|
+
return {
|
|
55207
|
+
key,
|
|
55208
|
+
status: stageStatusOf(String(raw.status ?? ""), typeof raw.conclusion === "string" ? raw.conclusion : null),
|
|
55209
|
+
...typeof raw.html_url === "string" ? { url: raw.html_url } : {},
|
|
55210
|
+
...typeof raw.id === "number" ? { jobId: raw.id } : {},
|
|
55211
|
+
...startedAt !== void 0 ? { startedAt } : {},
|
|
55212
|
+
...completedAt !== void 0 ? { completedAt } : {}
|
|
55213
|
+
};
|
|
55214
|
+
}
|
|
55215
|
+
async function latestRun(exec, slug) {
|
|
55216
|
+
const listed = await ghJson(exec, `/repos/${slug}/actions/runs?per_page=1`);
|
|
55217
|
+
const raw = listed?.workflow_runs?.[0];
|
|
55218
|
+
if (!raw || typeof raw.id !== "number" || typeof raw.head_sha !== "string" || typeof raw.html_url !== "string") {
|
|
55219
|
+
return void 0;
|
|
55220
|
+
}
|
|
55221
|
+
const runId = raw.id;
|
|
55222
|
+
const listedJobs = await ghJson(exec, `/repos/${slug}/actions/runs/${runId}/jobs`);
|
|
55223
|
+
const rawJobs = listedJobs?.jobs ?? [];
|
|
55224
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
55225
|
+
for (const rawJob of rawJobs) {
|
|
55226
|
+
const job = toJob(rawJob);
|
|
55227
|
+
if (job) byKey.set(job.key, job);
|
|
55228
|
+
}
|
|
55229
|
+
return {
|
|
55230
|
+
runId,
|
|
55231
|
+
headSha: raw.head_sha,
|
|
55232
|
+
status: runStatusOf(String(raw.status ?? "")),
|
|
55233
|
+
htmlUrl: raw.html_url,
|
|
55234
|
+
// 按流水线的顺序排,不跟着 GitHub 返回的顺序走
|
|
55235
|
+
jobs: DEPLOY_STAGE_KEYS.map((k2) => byKey.get(k2)).filter((j) => j !== void 0)
|
|
55236
|
+
};
|
|
55237
|
+
}
|
|
55238
|
+
async function rerunJob(exec, slug, runId, jobId) {
|
|
55239
|
+
const r = await exec("gh", ["run", "rerun", String(runId), "--job", String(jobId), "--repo", slug], {
|
|
55240
|
+
timeoutMs: TIMEOUT_MS
|
|
55241
|
+
});
|
|
55242
|
+
if (r.spawnError) throw new Error(`\u672C\u673A\u8DD1\u4E0D\u4E86 gh\uFF1A${r.spawnError}`);
|
|
55243
|
+
if (r.code !== 0) throw new Error((r.stderr || r.stdout).trim().slice(-400) || `gh \u9000\u51FA\u7801 ${r.code}`);
|
|
55244
|
+
}
|
|
55245
|
+
|
|
55130
55246
|
// src/deploy/scan-task.ts
|
|
55131
55247
|
var import_node_path32 = __toESM(require("path"), 1);
|
|
55132
55248
|
var BUTLER_PERSONA_ID = "persona-clawd-butler";
|
|
@@ -55177,6 +55293,7 @@ function reconcileInterruptedScans(deps) {
|
|
|
55177
55293
|
|
|
55178
55294
|
// src/handlers/deploy.ts
|
|
55179
55295
|
var SECRETS_CACHE_MS = 2e4;
|
|
55296
|
+
var RUN_CACHE_MS = 4e3;
|
|
55180
55297
|
function ensureOwner(ctx) {
|
|
55181
55298
|
if (!ctx || ctx.principal.kind !== "owner") {
|
|
55182
55299
|
throw new ClawdError(ERROR_CODES.UNAUTHORIZED, "UNAUTHORIZED: deploy:* requires owner ctx");
|
|
@@ -55197,6 +55314,7 @@ function mustBeScanning(scan, method) {
|
|
|
55197
55314
|
function buildDeployHandlers(deps) {
|
|
55198
55315
|
const cacheMs = deps.secretsCacheMs ?? SECRETS_CACHE_MS;
|
|
55199
55316
|
const secretsCache = /* @__PURE__ */ new Map();
|
|
55317
|
+
const runCache = /* @__PURE__ */ new Map();
|
|
55200
55318
|
function mustPersona(personaId2) {
|
|
55201
55319
|
if (!deps.hasPersona(personaId2)) {
|
|
55202
55320
|
throw new ClawdError(ERROR_CODES.PERSONA_NOT_FOUND, `PERSONA_NOT_FOUND: \u6CA1\u6709\u8FD9\u4E2A persona\uFF08${personaId2}\uFF09`);
|
|
@@ -55227,12 +55345,20 @@ function buildDeployHandlers(deps) {
|
|
|
55227
55345
|
scan = { ...scan, notes: stale ? [...kept, stale] : kept };
|
|
55228
55346
|
}
|
|
55229
55347
|
let secrets;
|
|
55348
|
+
let run;
|
|
55230
55349
|
if (repo2) {
|
|
55231
55350
|
try {
|
|
55232
55351
|
secrets = await cachedSecrets(personaId2, dir);
|
|
55233
55352
|
} catch {
|
|
55234
55353
|
secrets = void 0;
|
|
55235
55354
|
}
|
|
55355
|
+
const hit = runCache.get(personaId2);
|
|
55356
|
+
if (hit && deps.now() - hit.at < RUN_CACHE_MS) {
|
|
55357
|
+
run = hit.run;
|
|
55358
|
+
} else {
|
|
55359
|
+
run = await latestRun(deps.exec, repoSlug(repo2.url));
|
|
55360
|
+
runCache.set(personaId2, { at: deps.now(), run });
|
|
55361
|
+
}
|
|
55236
55362
|
}
|
|
55237
55363
|
return {
|
|
55238
55364
|
personaId: personaId2,
|
|
@@ -55240,6 +55366,7 @@ function buildDeployHandlers(deps) {
|
|
|
55240
55366
|
...file ? { file } : {},
|
|
55241
55367
|
...scan ? { scan } : {},
|
|
55242
55368
|
...secrets ? { secrets } : {},
|
|
55369
|
+
...run ? { run } : {},
|
|
55243
55370
|
...fileError ? { fileError } : {}
|
|
55244
55371
|
};
|
|
55245
55372
|
}
|
|
@@ -55390,11 +55517,32 @@ function buildDeployHandlers(deps) {
|
|
|
55390
55517
|
if (blockers.length > 0) throw invalid(`\u8FD8\u5DEE\uFF1A${blockers.join("\uFF1B")}`);
|
|
55391
55518
|
try {
|
|
55392
55519
|
const result = await release(deps.exec, { dir, now: deps.now });
|
|
55520
|
+
runCache.delete(personaId2);
|
|
55393
55521
|
return { response: { type: "deploy:release", ...result } };
|
|
55394
55522
|
} catch (err) {
|
|
55395
55523
|
throw toClawdError(err);
|
|
55396
55524
|
}
|
|
55397
55525
|
};
|
|
55526
|
+
const rerunJobHandler = async (frame, _client, ctx) => {
|
|
55527
|
+
ensureOwner(ctx);
|
|
55528
|
+
const { personaId: personaId2, jobId } = parseArgs2(DeployRerunJobArgsSchema, frame, "deploy:rerunJob");
|
|
55529
|
+
const dir = mustPersona(personaId2);
|
|
55530
|
+
const repo2 = await repoInfo(deps.exec, dir);
|
|
55531
|
+
if (!repo2) throw invalid("\u8FD8\u6CA1\u6709\u4ED3\u5E93\uFF0C\u5148\u70B9\u4E00\u6B21\u300C\u53D1\u5E03\u5230\u4E91\u4E0A\u300D\u5EFA\u4ED3");
|
|
55532
|
+
const slug = repoSlug(repo2.url);
|
|
55533
|
+
const run = await latestRun(deps.exec, slug);
|
|
55534
|
+
if (!run) throw invalid("\u67E5\u4E0D\u5230\u8FD9\u4E2A\u4ED3\u5E93\u4E0A\u7684\u6D41\u6C34\u7EBF\uFF08gh \u6CA1\u54CD\u5E94\uFF0C\u6216\u8005\u8FD8\u6CA1\u8DD1\u8FC7\uFF09");
|
|
55535
|
+
if (!run.jobs.some((j) => j.jobId === jobId)) {
|
|
55536
|
+
throw invalid("\u8FD9\u4E00\u6BB5\u4E0D\u5728\u6700\u65B0\u90A3\u6761\u6D41\u6C34\u7EBF\u91CC\u4E86\uFF0C\u5237\u65B0\u4E00\u4E0B\u518D\u91CD\u8BD5");
|
|
55537
|
+
}
|
|
55538
|
+
try {
|
|
55539
|
+
await rerunJob(deps.exec, slug, run.runId, jobId);
|
|
55540
|
+
runCache.delete(personaId2);
|
|
55541
|
+
} catch (err) {
|
|
55542
|
+
throw new ClawdError(ERROR_CODES.INTERNAL, err instanceof Error ? err.message : String(err));
|
|
55543
|
+
}
|
|
55544
|
+
return view(personaId2);
|
|
55545
|
+
};
|
|
55398
55546
|
return {
|
|
55399
55547
|
"deploy:start": start,
|
|
55400
55548
|
"deploy:get": get,
|
|
@@ -55402,7 +55550,8 @@ function buildDeployHandlers(deps) {
|
|
|
55402
55550
|
"deploy:putSecret": putSecret,
|
|
55403
55551
|
"deploy:reportFinding": reportFinding,
|
|
55404
55552
|
"deploy:finishScan": finishScan,
|
|
55405
|
-
"deploy:release": releaseHandler
|
|
55553
|
+
"deploy:release": releaseHandler,
|
|
55554
|
+
"deploy:rerunJob": rerunJobHandler
|
|
55406
55555
|
};
|
|
55407
55556
|
}
|
|
55408
55557
|
|
|
@@ -62418,9 +62567,9 @@ function lineToSearchableText(raw) {
|
|
|
62418
62567
|
function escapeRegExp(s) {
|
|
62419
62568
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
62420
62569
|
}
|
|
62421
|
-
function makeSnippet(text,
|
|
62422
|
-
const from = Math.max(0,
|
|
62423
|
-
const to = Math.min(text.length,
|
|
62570
|
+
function makeSnippet(text, at2, needleLength) {
|
|
62571
|
+
const from = Math.max(0, at2 - SNIPPET_PAD);
|
|
62572
|
+
const to = Math.min(text.length, at2 + needleLength + SNIPPET_PAD);
|
|
62424
62573
|
const body = text.slice(from, to).replace(/\s+/g, " ").trim();
|
|
62425
62574
|
return `${from > 0 ? "\u2026 " : ""}${body}${to < text.length ? " \u2026" : ""}`;
|
|
62426
62575
|
}
|
|
@@ -62448,9 +62597,9 @@ function searchTranscriptFile(file, query) {
|
|
|
62448
62597
|
}
|
|
62449
62598
|
const text = lineToSearchableText(parsed);
|
|
62450
62599
|
if (text === null) continue;
|
|
62451
|
-
const
|
|
62452
|
-
if (
|
|
62453
|
-
return makeSnippet(text,
|
|
62600
|
+
const at2 = text.toLowerCase().indexOf(query.toLowerCase());
|
|
62601
|
+
if (at2 < 0) continue;
|
|
62602
|
+
return makeSnippet(text, at2, query.length);
|
|
62454
62603
|
}
|
|
62455
62604
|
return null;
|
|
62456
62605
|
}
|
|
@@ -64153,6 +64302,7 @@ var METHOD_GRANT_MAP = {
|
|
|
64153
64302
|
"deploy:reportFinding": ADMIN_ANY,
|
|
64154
64303
|
"deploy:finishScan": ADMIN_ANY,
|
|
64155
64304
|
"deploy:release": ADMIN_ANY,
|
|
64305
|
+
"deploy:rerunJob": ADMIN_ANY,
|
|
64156
64306
|
// ---- session:* / chat:* 业务方法(v2 Phase 8 两层模型)----
|
|
64157
64307
|
// dispatcher 不验资源,handler 内按 ctx + frame.args 反查 ownerPersonaId 调 assertGrant。
|
|
64158
64308
|
// owner 自动通过(ctx 自带 '*':'admin' grant 一切 match);guest 在被授权 persona 内可调。
|
|
@@ -64401,7 +64551,7 @@ function computeMethodAccess(args) {
|
|
|
64401
64551
|
}
|
|
64402
64552
|
|
|
64403
64553
|
// src/version.ts
|
|
64404
|
-
var version = "0.2.
|
|
64554
|
+
var version = "0.2.483".length > 0 ? "0.2.483" : "dev";
|
|
64405
64555
|
|
|
64406
64556
|
// src/cli-probe/probe.ts
|
|
64407
64557
|
var fs70 = __toESM(require("fs"), 1);
|
|
@@ -21367,6 +21367,29 @@ var DeploySecretPresenceSchema = external_exports.object({
|
|
|
21367
21367
|
env: external_exports.string().min(1),
|
|
21368
21368
|
setAt: external_exports.number().optional()
|
|
21369
21369
|
}).strict();
|
|
21370
|
+
var DEPLOY_STAGE_STATUSES = ["pending", "running", "done", "failed", "waiting", "skipped"];
|
|
21371
|
+
var DeployStageStatusSchema = external_exports.enum(DEPLOY_STAGE_STATUSES);
|
|
21372
|
+
var DEPLOY_STAGE_KEYS = ["build", "smoke", "deploy"];
|
|
21373
|
+
var DeployStageKeySchema = external_exports.enum(DEPLOY_STAGE_KEYS);
|
|
21374
|
+
var DeployJobSchema = external_exports.object({
|
|
21375
|
+
key: DeployStageKeySchema,
|
|
21376
|
+
status: DeployStageStatusSchema,
|
|
21377
|
+
/** 这个 job 在 GitHub 上的页面。还没跑起来的段没有 */
|
|
21378
|
+
url: external_exports.string().optional(),
|
|
21379
|
+
/** GitHub 的 job databaseId,`gh run rerun --job` 要用。还没跑起来的段没有 */
|
|
21380
|
+
jobId: external_exports.number().optional(),
|
|
21381
|
+
startedAt: external_exports.number().optional(),
|
|
21382
|
+
completedAt: external_exports.number().optional()
|
|
21383
|
+
}).strict();
|
|
21384
|
+
var DeployRunSchema = external_exports.object({
|
|
21385
|
+
runId: external_exports.number(),
|
|
21386
|
+
headSha: external_exports.string().min(1),
|
|
21387
|
+
/** run 整体只有三态。**别跟 job 的六态混用**:run 没有「跳过」也没有「等审批」 */
|
|
21388
|
+
status: external_exports.enum(["queued", "running", "completed"]),
|
|
21389
|
+
htmlUrl: external_exports.string().min(1),
|
|
21390
|
+
/** run 刚入队时可能一条都还没有 */
|
|
21391
|
+
jobs: external_exports.array(DeployJobSchema)
|
|
21392
|
+
}).strict();
|
|
21370
21393
|
var DeployStateSchema = external_exports.object({
|
|
21371
21394
|
personaId: external_exports.string().min(1),
|
|
21372
21395
|
repo: DeployRepoSchema.optional(),
|
|
@@ -21374,6 +21397,11 @@ var DeployStateSchema = external_exports.object({
|
|
|
21374
21397
|
scan: DeployScanSchema.optional(),
|
|
21375
21398
|
/** 没仓库时缺席(查不了) */
|
|
21376
21399
|
secrets: external_exports.array(DeploySecretPresenceSchema).optional(),
|
|
21400
|
+
/**
|
|
21401
|
+
* 最新那次流水线走到哪了。**缺席是常态**:没推过、gh 查不到、仓库还没有 run,
|
|
21402
|
+
* 都不该让整页打不开——同 `secrets` 的处理。
|
|
21403
|
+
*/
|
|
21404
|
+
run: DeployRunSchema.optional(),
|
|
21377
21405
|
/**
|
|
21378
21406
|
* `.clawd/deploy.json` 读不出来(人手改坏了)时的人话。有它就没有 `file`。
|
|
21379
21407
|
* 页面据此给一条能走的路(重新扫描会整份重写),而不是白屏。
|
|
@@ -21401,6 +21429,11 @@ var DeployPutSecretArgsSchema = external_exports.object({
|
|
|
21401
21429
|
// 环境变量名 → 值。key 必须是该 secret 声明过的 env 之一,handler 校验。
|
|
21402
21430
|
values: external_exports.record(external_exports.string(), external_exports.string())
|
|
21403
21431
|
}).strict();
|
|
21432
|
+
var DeployRerunJobArgsSchema = external_exports.object({
|
|
21433
|
+
personaId: external_exports.string().min(1),
|
|
21434
|
+
/** GitHub 的 job databaseId。**是数字**——字符串会在拼命令时静默出错 */
|
|
21435
|
+
jobId: external_exports.number()
|
|
21436
|
+
}).strict();
|
|
21404
21437
|
var DeployReportFindingArgsSchema = external_exports.object({
|
|
21405
21438
|
personaId: external_exports.string().min(1),
|
|
21406
21439
|
kind: external_exports.enum(["cli", "secret", "asset"]),
|
|
@@ -23915,6 +23948,10 @@ var METHOD_DOCS = {
|
|
|
23915
23948
|
summary: "\u53D1\u5E03 = \u63D0\u4EA4\u5E76\u63A8\u9001\u5230\u4ED3\u5E93\uFF1A\u91CD\u5199 workflow \u6A21\u677F \u2192 git add -A \u2192 \u7A7A\u63D0\u4EA4\u4E5F\u5141\u8BB8 \u2192 push\u3002\u4ED3\u5E93\u91CC\u7684\u6D41\u6C34\u7EBF\u63A5\u7740\u6784\u955C\u50CF\u3001\u5728\u96C6\u7FA4\u4E0A\u771F\u8D77\u4E00\u6B21\u3001\u767B\u8BB0\u6210\u6B63\u5F0F\uFF0C\u8FDB\u5EA6\u5728 GitHub Actions \u770B\u3002\u524D\u7F6E\uFF1A\u5DF2\u7ED1\u5B9A\u4ED3\u5E93\u3001\u6709\u6E05\u5355\u3001\u6BCF\u4E2A\u53D8\u91CF\u540D\u90FD\u5728 Secrets \u91CC\uFF1Bowner-only",
|
|
23916
23949
|
args: DeployPersonaArgsSchema
|
|
23917
23950
|
},
|
|
23951
|
+
"deploy:rerunJob": {
|
|
23952
|
+
summary: "\u539F\u6837\u91CD\u8DD1\u6700\u65B0\u90A3\u6761\u6D41\u6C34\u7EBF\u91CC\u5931\u8D25\u7684\u67D0\u4E00\u6BB5\uFF08gh run 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",
|
|
23953
|
+
args: DeployRerunJobArgsSchema
|
|
23954
|
+
},
|
|
23918
23955
|
"shift:list": {
|
|
23919
23956
|
summary: "\u5217\u51FA owner \u7684\u5168\u90E8 shift\uFF08\u6392\u73ED\uFF09\uFF0C\u7ED9 UI \u65E5\u5386\u6E32\u67D3\u7528\uFF1Bowner-only",
|
|
23920
23957
|
args: NO_ARGS
|