@clawos-dev/clawd 0.2.459 → 0.2.461
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 +130 -1
- package/dist/cli.cjs +1257 -608
- package/dist/dispatch/mcp-server.cjs +53 -0
- package/dist/share-md-viewer-error.html +1 -1
- package/dist/share-md-viewer.html +1 -1
- package/dist/share-ui/assets/{guest-BJvgzqPz.js → guest-0upTtqLX.js} +116 -116
- package/dist/share-ui/assets/guest-B3t_VaRM.css +32 -0
- package/dist/share-ui/guest.html +2 -2
- package/package.json +1 -1
- package/dist/share-ui/assets/guest-Q6LcVR9h.css +0 -32
|
@@ -6893,6 +6893,7 @@ __export(mcp_server_exports, {
|
|
|
6893
6893
|
handleCreateProject: () => handleCreateProject,
|
|
6894
6894
|
handleListProjects: () => handleListProjects,
|
|
6895
6895
|
handlePublish: () => handlePublish,
|
|
6896
|
+
handleRemoveProject: () => handleRemoveProject,
|
|
6896
6897
|
handleReportStage: () => handleReportStage,
|
|
6897
6898
|
handleSetProdUrl: () => handleSetProdUrl,
|
|
6898
6899
|
handleStartDevServer: () => handleStartDevServer,
|
|
@@ -21361,6 +21362,19 @@ var DeployGapSchema = external_exports.object({
|
|
|
21361
21362
|
// 建议补的依赖:`cli:python3` 这种。拿不准就不给,让人自己决定。
|
|
21362
21363
|
suggest: external_exports.string().optional()
|
|
21363
21364
|
}).strict();
|
|
21365
|
+
var DeployPlacementSchema = external_exports.object({
|
|
21366
|
+
/** gateway 的公网地址(入口 A 直接 POST 它;入口 B 由设备目录下发 ws 地址) */
|
|
21367
|
+
gatewayUrl: external_exports.string().min(1),
|
|
21368
|
+
/** 服务设备 id:别人的 clawd 用 `device:connect { deviceId }` 就能连上,本机侧零改动 */
|
|
21369
|
+
serviceDeviceId: external_exports.string().min(1),
|
|
21370
|
+
/** 这次登记为正式的镜像 tag(= 试装通过的那个) */
|
|
21371
|
+
image: external_exports.string().min(1),
|
|
21372
|
+
/** 使用者自带的凭据名字(= 单据里 fulfillment 选了 'user' 的那些)。**只有名字** */
|
|
21373
|
+
userSecrets: external_exports.array(external_exports.string()).default([]),
|
|
21374
|
+
/** 是否进公共设备目录。false = 只有拿到 deviceId 的人连得上 */
|
|
21375
|
+
publicDirectory: external_exports.boolean(),
|
|
21376
|
+
deployedAt: external_exports.number()
|
|
21377
|
+
}).strict();
|
|
21364
21378
|
var DeployReceiptSchema = external_exports.object({
|
|
21365
21379
|
deployId: external_exports.string().min(1),
|
|
21366
21380
|
personaId: external_exports.string().min(1),
|
|
@@ -21386,6 +21400,23 @@ var DeployReceiptSchema = external_exports.object({
|
|
|
21386
21400
|
fulfillment: external_exports.record(external_exports.string(), FulfillmentSchema).default({}),
|
|
21387
21401
|
/** 试装失败时的缺口清单;成功或没试装过是空数组 */
|
|
21388
21402
|
gaps: external_exports.array(DeployGapSchema).default([]),
|
|
21403
|
+
/** 试装跑到第几轮了(每次 deploy:trial +1,上限 TRIAL_ROUND_MAX)。重扫清零 */
|
|
21404
|
+
trialRound: external_exports.number().default(0),
|
|
21405
|
+
/**
|
|
21406
|
+
* 试装当前在哪一步的一句人话(「在构镜像」「冒烟任务跑起来了」)。
|
|
21407
|
+
* 单据页要的是「到哪一步了」,不是逐 token 的过程——过程在 gateway 的任务台账里。
|
|
21408
|
+
*/
|
|
21409
|
+
trialStage: external_exports.string().optional(),
|
|
21410
|
+
/**
|
|
21411
|
+
* 上一次试装通过的时刻。**deploy:deploy 的前置**——没试装过不让部署,那正是试装存在的理由。
|
|
21412
|
+
* 试装通过后单据回 `ready` 而不是直接 `deployed`:试装的产物是一个用完即弃的镜像,
|
|
21413
|
+
* 部署的产物是一个别人能派活的服务,中间那次决定得留给人。
|
|
21414
|
+
*/
|
|
21415
|
+
trialPassedAt: external_exports.number().optional(),
|
|
21416
|
+
/** 试装通过的那个镜像 tag;deploy:deploy 登记的就是它,不重新构一遍 */
|
|
21417
|
+
trialImage: external_exports.string().optional(),
|
|
21418
|
+
/** 部署落点(status 是 deployed 才有) */
|
|
21419
|
+
placement: DeployPlacementSchema.optional(),
|
|
21389
21420
|
// 扫描 / 试装失败的原因(status 是 scanFailed / failed 时才有意义)
|
|
21390
21421
|
error: external_exports.string().optional(),
|
|
21391
21422
|
createdAt: external_exports.number(),
|
|
@@ -22071,6 +22102,21 @@ var TOPIC_DECISION_STATUS_RESOLVED = TOPIC_DECISION_STATUSES[1];
|
|
|
22071
22102
|
var TopicDecisionTypeSchema = external_exports.enum(TOPIC_DECISION_TYPES);
|
|
22072
22103
|
var TopicDecisionStatusSchema = external_exports.enum(TOPIC_DECISION_STATUSES);
|
|
22073
22104
|
var TopicDecisionSchema = external_exports.object({
|
|
22105
|
+
/**
|
|
22106
|
+
* 这条决策的标识,供后来的答复回指。可选:存量记录一条都没有,**不迁移**。
|
|
22107
|
+
*
|
|
22108
|
+
* 之所以要它——提问和答复是**两条**流水(`open` 一条、`resolved` 一条,见 `resolves`),
|
|
22109
|
+
* 两条之间没有任何关联时,展示层只能逐条渲染,于是**已经拍板完的待办永远挂在那儿**。
|
|
22110
|
+
*/
|
|
22111
|
+
id: nonBlank2.optional(),
|
|
22112
|
+
/**
|
|
22113
|
+
* 本条解决的是哪条决策(填对方的 `id`)。展示层据此把提问与答复合并成一行。
|
|
22114
|
+
*
|
|
22115
|
+
* **只关联、不改写**:不去改动已落盘那条 `open` 记录的 status。原地改写会丢掉
|
|
22116
|
+
* 「什么时候提出 / 什么时候解决」的双时间戳,也丢掉「Master 建议了什么 vs
|
|
22117
|
+
* 老板最终定了什么」的差异——而老板事后要看的恰恰是这个差异。合并只发生在展示层。
|
|
22118
|
+
*/
|
|
22119
|
+
resolves: nonBlank2.optional(),
|
|
22074
22120
|
type: TopicDecisionTypeSchema,
|
|
22075
22121
|
status: TopicDecisionStatusSchema,
|
|
22076
22122
|
question: nonBlank2,
|
|
@@ -23914,6 +23960,14 @@ var METHOD_DOCS = {
|
|
|
23914
23960
|
summary: "butler \u6536\u5C3E\uFF1A\u7ED9\u51FA\u5192\u70DF\u4EFB\u52A1\u4E0E\u5B58\u7591\u9879\uFF0C\u5355\u636E\u4ECE scanning \u8F6C draft\u3002\u6CA1\u8C03\u5230\u5B83\u5C31\u7B49\u4E8E\u6CA1\u626B\u5B8C\u2014\u2014butler \u4F1A\u8BDD\u7ED3\u675F\u65F6\u5355\u636E\u8FD8\u505C\u5728 scanning\uFF0Cdaemon \u636E\u6B64\u5224 scanFailed\uFF1Bowner-only",
|
|
23915
23961
|
args: DeployFinishScanArgsSchema
|
|
23916
23962
|
},
|
|
23963
|
+
"deploy:trial": {
|
|
23964
|
+
summary: "\u8D77\u4E00\u6B21\u8BD5\u88C5\uFF1A**\u4E00\u6B21\u5E26\u81EA\u6BC1\u7684\u771F\u90E8\u7F72**\u2014\u2014\u6309\u5355\u636E\u7684\u6E05\u5355\u6784\u955C\u50CF \u2192 \u63A8\u8FDB k3s \u2192 \u7ECF gateway \u6295\u5582\u5355\u636E\u4E0A\u90A3\u6761\u5192\u70DF\u4EFB\u52A1 \u2192 \u8BA9 persona \u7528\u81EA\u5DF1\u7684\u65B9\u5F0F\u5E72 \u2192 \u8DD1\u5B8C\u8BA9\u5B83\u628A\u5EFA\u51FA\u6765\u7684\u4E1C\u897F\u62C6\u6389\u3002\u524D\u7F6E\u662F `ready`\uFF08\u5C65\u7EA6\u90FD\u9009\u4E86\u3001\u9009\u4E86\u300C\u6211\u6765\u63D0\u4F9B\u300D\u7684\u51ED\u636E\u90FD\u586B\u9F50\u4E86\uFF09\uFF0C\u7F3A\u54EA\u6761\u4F1A\u5728\u9519\u8BEF\u91CC\u70B9\u540D\uFF1B\u8DD1\u51E0\u5341\u5206\u949F\uFF0C\u6240\u4EE5 RPC \u79D2\u56DE `trialing` \u6001\u5355\u636E\uFF0C\u7ED3\u679C\u7531\u540E\u53F0\u56DE\u5199\uFF08UI \u8F6E\u8BE2\uFF09\u3002\u901A\u8FC7 \u2192 \u56DE `ready` \u5E76\u8BB0\u4E0B trialPassedAt\uFF08\u90E8\u7F72\u662F\u4EBA\u7684\u7B2C\u4E8C\u6B21\u51B3\u5B9A\uFF09\uFF1B\u6CA1\u8FC7 \u2192 `failed` + gaps\uFF08agent \u7684\u4EBA\u8BDD\u9519\u56E0\uFF09\uFF0C\u6539\u5B8C\u6E05\u5355\u518D\u8C03\u4E00\u6B21\u5373\u53EF\u3002\u8F6E\u6B21\u6709\u4E0A\u9650\uFF1Bowner-only",
|
|
23965
|
+
args: DeployIdArgsSchema
|
|
23966
|
+
},
|
|
23967
|
+
"deploy:deploy": {
|
|
23968
|
+
summary: "\u628A\u8BD5\u88C5\u901A\u8FC7\u7684\u90A3\u4E2A\u955C\u50CF\u5728 gateway \u767B\u8BB0\u4E3A**\u6B63\u5F0F**\u90E8\u7F72\uFF1A\u4E4B\u540E\u522B\u4EBA\u7684 clawd \u6D3E\u6D3B\u7ED9\u8FD9\u4E2A\u670D\u52A1\u8BBE\u5907\uFF0C\u8D77\u7684\u5C31\u662F\u5B83\u3002\u524D\u7F6E\u662F\u8BD5\u88C5\u901A\u8FC7\u8FC7\uFF08\u6CA1\u9A8C\u8FC7\u4E0D\u8BA9\u53D1\uFF0C\u90A3\u6B63\u662F\u8BD5\u88C5\u5B58\u5728\u7684\u7406\u7531\uFF09\u3002\u56DE\u6765\u7684\u5355\u636E\u5E26 placement\u2014\u2014\u4E91\u4E0A\u5730\u5740 / \u670D\u52A1\u8BBE\u5907 id / \u8C01\u53EF\u8C03\u7528 / \u4F7F\u7528\u8005\u9700\u81EA\u5E26\u54EA\u4E9B\u51ED\u636E\uFF1Bowner-only",
|
|
23969
|
+
args: DeployIdArgsSchema
|
|
23970
|
+
},
|
|
23917
23971
|
"deploy:remove": {
|
|
23918
23972
|
summary: "\u5220\u6389\u4E00\u5F20\u90E8\u7F72\u5355\uFF0C\u8FDE\u5E26\u6E05\u6389\u5B83\u7684\u5168\u90E8\u51ED\u636E\u503C\uFF08\u503C\u4E0D\u8BE5\u6BD4\u5355\u636E\u6D3B\u5F97\u4E45\uFF09\uFF1Bowner-only",
|
|
23919
23973
|
args: DeployIdArgsSchema
|
|
@@ -24658,6 +24712,9 @@ var ProjectStore = class {
|
|
|
24658
24712
|
}
|
|
24659
24713
|
};
|
|
24660
24714
|
|
|
24715
|
+
// src/app-builder-plugin/core.ts
|
|
24716
|
+
var import_node_child_process3 = require("child_process");
|
|
24717
|
+
|
|
24661
24718
|
// src/app-builder-plugin/publish-registry.ts
|
|
24662
24719
|
var import_node_crypto = require("crypto");
|
|
24663
24720
|
var PublishJobRegistry = class {
|
|
@@ -25070,6 +25127,38 @@ async function createProjectOnDisk(args) {
|
|
|
25070
25127
|
}
|
|
25071
25128
|
return { project, projectDir: store.projectDir(name) };
|
|
25072
25129
|
}
|
|
25130
|
+
var REMOVE_TIMEOUT_MS = 10 * 6e4;
|
|
25131
|
+
async function runRemoveExtension(args) {
|
|
25132
|
+
const spawnFn = args.spawnImpl ?? import_node_child_process3.spawn;
|
|
25133
|
+
return await new Promise((resolve, reject) => {
|
|
25134
|
+
const child = spawnFn("bash", [args.script, args.projectDir, args.personaRoot], {
|
|
25135
|
+
// 凭据在 process.env 里(gateway → MCP server 的 per-server env → 本进程)
|
|
25136
|
+
env: process.env,
|
|
25137
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
25138
|
+
});
|
|
25139
|
+
let stdout = "";
|
|
25140
|
+
let stderr = "";
|
|
25141
|
+
child.stdout?.on("data", (d) => {
|
|
25142
|
+
stdout += d.toString("utf8");
|
|
25143
|
+
});
|
|
25144
|
+
child.stderr?.on("data", (d) => {
|
|
25145
|
+
stderr += d.toString("utf8");
|
|
25146
|
+
});
|
|
25147
|
+
const timer = setTimeout(() => {
|
|
25148
|
+
child.kill("SIGKILL");
|
|
25149
|
+
reject(new Error(`remove-extension timeout (>${REMOVE_TIMEOUT_MS}ms): ${args.projectDir}`));
|
|
25150
|
+
}, REMOVE_TIMEOUT_MS);
|
|
25151
|
+
child.on("error", (err) => {
|
|
25152
|
+
clearTimeout(timer);
|
|
25153
|
+
reject(new Error(`remove-extension spawn failed: ${err.message}`));
|
|
25154
|
+
});
|
|
25155
|
+
child.on("exit", (code) => {
|
|
25156
|
+
clearTimeout(timer);
|
|
25157
|
+
args.logger?.info("app-builder.remove.exit", { projectDir: args.projectDir, code });
|
|
25158
|
+
resolve({ code, stdout, stderr });
|
|
25159
|
+
});
|
|
25160
|
+
});
|
|
25161
|
+
}
|
|
25073
25162
|
|
|
25074
25163
|
// src/app-builder-plugin/mcp-server.ts
|
|
25075
25164
|
var LOG_PATH = process.env.CLAWD_APP_BUILDER_LOG;
|
|
@@ -25102,7 +25191,8 @@ function readEnv(env = process.env) {
|
|
|
25102
25191
|
...env.CLAWD_APP_BUILDER_TEMPLATE_DIR ? { templateDir: env.CLAWD_APP_BUILDER_TEMPLATE_DIR } : {},
|
|
25103
25192
|
...env.CLAWD_APP_BUILDER_SCAFFOLD_SCRIPT ? { scaffoldScript: env.CLAWD_APP_BUILDER_SCAFFOLD_SCRIPT } : {},
|
|
25104
25193
|
...env.CLAWD_APP_BUILDER_PUBLISH_SCRIPT ? { publishScript: env.CLAWD_APP_BUILDER_PUBLISH_SCRIPT } : {},
|
|
25105
|
-
...env.CLAWD_APP_BUILDER_PERSONA_ROOT ? { personaRoot: env.CLAWD_APP_BUILDER_PERSONA_ROOT } : {}
|
|
25194
|
+
...env.CLAWD_APP_BUILDER_PERSONA_ROOT ? { personaRoot: env.CLAWD_APP_BUILDER_PERSONA_ROOT } : {},
|
|
25195
|
+
...env.CLAWD_APP_BUILDER_REMOVE_SCRIPT ? { removeScript: env.CLAWD_APP_BUILDER_REMOVE_SCRIPT } : {}
|
|
25106
25196
|
};
|
|
25107
25197
|
}
|
|
25108
25198
|
function hasDaemon(env) {
|
|
@@ -25263,6 +25353,35 @@ ${outcome.errorSummary}`));
|
|
|
25263
25353
|
}
|
|
25264
25354
|
return await done;
|
|
25265
25355
|
}
|
|
25356
|
+
async function handleRemoveProject(input, ctx) {
|
|
25357
|
+
if (hasDaemon(ctx.env)) {
|
|
25358
|
+
return fail(
|
|
25359
|
+
'removeProject is cloud-only. On this host run the script yourself:\n bash "$HOME/.clawd/deploy-kit/scripts/remove-extension.sh" <projectDir> <personaRoot>'
|
|
25360
|
+
);
|
|
25361
|
+
}
|
|
25362
|
+
const { removeScript, personaRoot } = ctx.env;
|
|
25363
|
+
if (!removeScript) {
|
|
25364
|
+
return fail("removeProject: no daemon, and CLAWD_APP_BUILDER_REMOVE_SCRIPT is not set.");
|
|
25365
|
+
}
|
|
25366
|
+
const store = storeOf(ctx.env);
|
|
25367
|
+
try {
|
|
25368
|
+
const projectDir = store.projectDir(input.name);
|
|
25369
|
+
const r = await runRemoveExtension({
|
|
25370
|
+
script: removeScript,
|
|
25371
|
+
projectDir,
|
|
25372
|
+
personaRoot: personaRoot ?? "",
|
|
25373
|
+
logger: { info: (m, i) => log(m, i), warn: (m, i) => log(m, i) }
|
|
25374
|
+
});
|
|
25375
|
+
const text = `exit=${r.code}
|
|
25376
|
+
--- stdout ---
|
|
25377
|
+
${r.stdout}
|
|
25378
|
+
--- stderr ---
|
|
25379
|
+
${r.stderr}`;
|
|
25380
|
+
return r.code === 0 ? ok(text) : fail(text);
|
|
25381
|
+
} catch (err) {
|
|
25382
|
+
return fail(`removeProject failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
25383
|
+
}
|
|
25384
|
+
}
|
|
25266
25385
|
function registerTools(server, ctx) {
|
|
25267
25386
|
server.registerTool(
|
|
25268
25387
|
"createProject",
|
|
@@ -25338,6 +25457,15 @@ function registerTools(server, ctx) {
|
|
|
25338
25457
|
},
|
|
25339
25458
|
async (input) => handlePublish(input, ctx)
|
|
25340
25459
|
);
|
|
25460
|
+
server.registerTool(
|
|
25461
|
+
"removeProject",
|
|
25462
|
+
{
|
|
25463
|
+
title: "Tear down a published project",
|
|
25464
|
+
description: "Tear down everything a published project created (FC function / trigger / custom domain, plus the DROP statements for its Supabase tables). Cloud-only: on a host with a local daemon this returns the shell command to run yourself instead. Returns the script output verbatim \u2014 read it, it may ask you to run a few DROPs through the supabase MCP to finish the job.",
|
|
25465
|
+
inputSchema: { name: external_exports.string().min(1).describe("project name") }
|
|
25466
|
+
},
|
|
25467
|
+
async (input) => handleRemoveProject(input, ctx)
|
|
25468
|
+
);
|
|
25341
25469
|
}
|
|
25342
25470
|
async function main() {
|
|
25343
25471
|
const env = readEnv();
|
|
@@ -25364,6 +25492,7 @@ if (isMainModule) {
|
|
|
25364
25492
|
handleCreateProject,
|
|
25365
25493
|
handleListProjects,
|
|
25366
25494
|
handlePublish,
|
|
25495
|
+
handleRemoveProject,
|
|
25367
25496
|
handleReportStage,
|
|
25368
25497
|
handleSetProdUrl,
|
|
25369
25498
|
handleStartDevServer,
|