@clawos-dev/clawd 0.2.437 → 0.2.439
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/cli.cjs +211 -20
- package/dist/dispatch/mcp-server.cjs +40 -11
- package/dist/share-md-viewer-error.html +1 -1
- package/dist/share-md-viewer.html +1 -1
- package/dist/share-ui/assets/{guest-Bla3ZVYP.js → guest-CaPkO7XV.js} +130 -130
- package/dist/share-ui/assets/guest-DO5eviOK.css +32 -0
- package/dist/share-ui/guest.html +2 -2
- package/package.json +1 -1
- package/dist/share-ui/assets/guest-BYFRrJkW.css +0 -32
package/dist/cli.cjs
CHANGED
|
@@ -6944,13 +6944,14 @@ var init_github = __esm({
|
|
|
6944
6944
|
});
|
|
6945
6945
|
|
|
6946
6946
|
// ../protocol/src/lark-bot-schemas.ts
|
|
6947
|
-
var LarkBotPersonaArgs, LarkBotUnbindArgs, LarkBotStatusArgs, LarkBotProvisionArgs, LarkBotProvisionCancelArgs, LARK_BOT_PROVISION_ERROR_REASONS, LarkBotProvisionErrorReasonSchema, LarkBotBindManualArgs, LarkBotGroupSchema, LarkBotStatusResultSchema, LarkBotStateFrameSchema;
|
|
6947
|
+
var LarkBotPersonaArgs, LarkBotUnbindArgs, LarkBotUpgradeArgs, LarkBotStatusArgs, LarkBotProvisionArgs, LarkBotProvisionCancelArgs, LARK_BOT_PROVISION_ERROR_REASONS, LarkBotProvisionErrorReasonSchema, LarkBotBindManualArgs, LarkBotGroupSchema, LarkBotStatusResultSchema, LarkBotStateFrameSchema;
|
|
6948
6948
|
var init_lark_bot_schemas = __esm({
|
|
6949
6949
|
"../protocol/src/lark-bot-schemas.ts"() {
|
|
6950
6950
|
"use strict";
|
|
6951
6951
|
init_zod();
|
|
6952
6952
|
LarkBotPersonaArgs = external_exports.object({ personaId: external_exports.string().min(1) });
|
|
6953
6953
|
LarkBotUnbindArgs = LarkBotPersonaArgs;
|
|
6954
|
+
LarkBotUpgradeArgs = external_exports.object({ personaId: external_exports.string().min(1) });
|
|
6954
6955
|
LarkBotStatusArgs = LarkBotPersonaArgs;
|
|
6955
6956
|
LarkBotProvisionArgs = LarkBotPersonaArgs;
|
|
6956
6957
|
LarkBotProvisionCancelArgs = LarkBotPersonaArgs;
|
|
@@ -6984,7 +6985,21 @@ var init_lark_bot_schemas = __esm({
|
|
|
6984
6985
|
qrUrl: external_exports.string().optional(),
|
|
6985
6986
|
/** provision 失败后的 unbound 帧携带;正常 unbound 无此字段 */
|
|
6986
6987
|
errorReason: LarkBotProvisionErrorReasonSchema.optional(),
|
|
6987
|
-
groups: external_exports.array(LarkBotGroupSchema)
|
|
6988
|
+
groups: external_exports.array(LarkBotGroupSchema),
|
|
6989
|
+
/**
|
|
6990
|
+
* bound 态:该 bot 实际授予的 scope 缺了 LARK_PROVISION_ADDONS 里声明的项
|
|
6991
|
+
* (spec 2026-09-01)——addons 是扫码时一次性写进飞书应用配置的,后来新增的
|
|
6992
|
+
* scope / 事件对存量 bot 不生效,不提示的话用户只会觉得「功能没生效」。
|
|
6993
|
+
* 判定真源是飞书回读的 granted scopes,不落库任何版本号。
|
|
6994
|
+
*/
|
|
6995
|
+
needsUpgrade: external_exports.boolean().optional(),
|
|
6996
|
+
/**
|
|
6997
|
+
* bound 态叠加:正在扫码更新授权(spec 2026-09-01)。
|
|
6998
|
+
* **不复用 provisioning 态**——升级期间 bot 仍在正常服务(长连接不断、群照常响应),
|
|
6999
|
+
* 降级成 provisioning 会丢掉 botName / groups,UI 上像是断了。
|
|
7000
|
+
* 有值即渲染二维码弹层;升级结束(成功或取消)该字段消失。
|
|
7001
|
+
*/
|
|
7002
|
+
upgradeQrUrl: external_exports.string().optional()
|
|
6988
7003
|
});
|
|
6989
7004
|
LarkBotStateFrameSchema = LarkBotStatusResultSchema.extend({
|
|
6990
7005
|
personaId: external_exports.string().min(1)
|
|
@@ -7036,7 +7051,7 @@ var init_onboarding_schemas = __esm({
|
|
|
7036
7051
|
});
|
|
7037
7052
|
|
|
7038
7053
|
// ../protocol/src/persona-schemas.ts
|
|
7039
|
-
var PersonaFileSchema, PersonaSkillSummarySchema, PersonaPluginSummarySchema, PersonaSandboxSettingsSchema, PersonaInfoResponseSchema, PersonaCreateArgsSchema, PersonaIdArgsSchema, PersonaUpdateArgsSchema
|
|
7054
|
+
var PersonaFileSchema, PersonaSkillSummarySchema, PersonaPluginSummarySchema, CodexSandboxSettingsSchema, PersonaSandboxSettingsSchema, PersonaInfoResponseSchema, PersonaCreateArgsSchema, PersonaIdArgsSchema, PersonaUpdateArgsSchema;
|
|
7040
7055
|
var init_persona_schemas = __esm({
|
|
7041
7056
|
"../protocol/src/persona-schemas.ts"() {
|
|
7042
7057
|
"use strict";
|
|
@@ -7069,6 +7084,17 @@ var init_persona_schemas = __esm({
|
|
|
7069
7084
|
// settings.json 中 enabledPlugins 的 key,例如 'superpowers@claude-plugins-official'
|
|
7070
7085
|
id: external_exports.string().min(1)
|
|
7071
7086
|
});
|
|
7087
|
+
CodexSandboxSettingsSchema = external_exports.object({
|
|
7088
|
+
// 额外可写的绝对路径或 ~ 路径(pnpm 工具链等);workspace(cwd) 和 userWorkDir 由 daemon 自动加,不用列。
|
|
7089
|
+
writableRoots: external_exports.array(external_exports.string()).optional(),
|
|
7090
|
+
// 禁读 glob(相对 workspace root 或绝对),如 ".secrets/**"、"**/*.env"。
|
|
7091
|
+
denyRead: external_exports.array(external_exports.string()).optional(),
|
|
7092
|
+
// true → 网络全放(*);false → 断网。**缺省等于联网**:daemon 写入的默认值是 network:true
|
|
7093
|
+
// (对齐 claude guest 一贯的域名全放,见 spec 2026-09-01-codex-guest-network §1.3),
|
|
7094
|
+
// 且 manager / UI 读到 undefined 时都回落 true —— 两侧必须同向,否则出现
|
|
7095
|
+
// 「卡片显示开、实际断网」的幽灵态。
|
|
7096
|
+
network: external_exports.boolean().optional()
|
|
7097
|
+
}).strict();
|
|
7072
7098
|
PersonaSandboxSettingsSchema = external_exports.object({
|
|
7073
7099
|
permissions: external_exports.object({
|
|
7074
7100
|
defaultMode: external_exports.string().optional(),
|
|
@@ -7117,7 +7143,10 @@ var init_persona_schemas = __esm({
|
|
|
7117
7143
|
skills: external_exports.array(PersonaSkillSummarySchema).optional(),
|
|
7118
7144
|
// 仅 'persona:get' 携带;空数组 = 没启用任何插件 / settings.json 不存在;undefined = 不在该响应类型上
|
|
7119
7145
|
plugins: external_exports.array(PersonaPluginSummarySchema).optional(),
|
|
7120
|
-
sandboxSettings: PersonaSandboxSettingsSchema.nullable().optional()
|
|
7146
|
+
sandboxSettings: PersonaSandboxSettingsSchema.nullable().optional(),
|
|
7147
|
+
// 仅 'persona:get' 携带;null = codex-sandbox.json 不存在 / parse 失败。
|
|
7148
|
+
// UI 的「访客联网」开关读它(见 PersonaCardSettings)。
|
|
7149
|
+
codexSandbox: CodexSandboxSettingsSchema.nullable().optional()
|
|
7121
7150
|
});
|
|
7122
7151
|
PersonaCreateArgsSchema = external_exports.object({
|
|
7123
7152
|
// persona 身份。daemon 拼成 personaId = `persona-<slug>`——前缀由 daemon 拥有,调用方只给后半段,
|
|
@@ -7149,17 +7178,13 @@ var init_persona_schemas = __esm({
|
|
|
7149
7178
|
personalityLocal: external_exports.string().optional(),
|
|
7150
7179
|
public: external_exports.boolean().optional(),
|
|
7151
7180
|
// pass `null` to clear; daemon strips the field from PersonaFile on null
|
|
7152
|
-
iconKey: external_exports.string().nullable().optional()
|
|
7181
|
+
iconKey: external_exports.string().nullable().optional(),
|
|
7182
|
+
// codex guest 沙箱(落盘 .clawd/codex-sandbox.json,不在 PersonaFile 里)。与 personality
|
|
7183
|
+
// 同款分层写:handler 剥出来单独落盘,且**局部合并**——只带 network 的 patch 不能抹掉
|
|
7184
|
+
// owner 手配的 writableRoots / denyRead。
|
|
7185
|
+
codexSandbox: CodexSandboxSettingsSchema.optional()
|
|
7153
7186
|
}).strict()
|
|
7154
7187
|
}).strict();
|
|
7155
|
-
CodexSandboxSettingsSchema = external_exports.object({
|
|
7156
|
-
// 额外可写的绝对路径或 ~ 路径(pnpm 工具链等);workspace(cwd) 和 userWorkDir 由 daemon 自动加,不用列。
|
|
7157
|
-
writableRoots: external_exports.array(external_exports.string()).optional(),
|
|
7158
|
-
// 禁读 glob(相对 workspace root 或绝对),如 ".secrets/**"、"**/*.env"。
|
|
7159
|
-
denyRead: external_exports.array(external_exports.string()).optional(),
|
|
7160
|
-
// true → 网络全放(*);缺省/false → 断网。
|
|
7161
|
-
network: external_exports.boolean().optional()
|
|
7162
|
-
}).strict();
|
|
7163
7188
|
}
|
|
7164
7189
|
});
|
|
7165
7190
|
|
|
@@ -8712,6 +8737,10 @@ var init_methods = __esm({
|
|
|
8712
8737
|
summary: "\u89E3\u7ED1 persona \u7684\u98DE\u4E66 bot\uFF08\u5220\u4E91\u7AEF\u7ED1\u5B9A + \u65AD\u957F\u8FDE\u63A5\uFF0C\u98DE\u4E66\u4FA7 app \u4FDD\u7559\uFF09\uFF1Bowner-only",
|
|
8713
8738
|
args: LarkBotUnbindArgs
|
|
8714
8739
|
},
|
|
8740
|
+
"larkBot:upgrade": {
|
|
8741
|
+
summary: "\u626B\u7801\u66F4\u65B0\u5DF2\u7ED1\u5B9A bot \u7684\u6388\u6743\uFF08\u8865\u540E\u6765\u65B0\u589E\u7684 scope / \u4E8B\u4EF6\uFF09\uFF1B\u5168\u7A0B\u4FDD\u6301 bound\uFF0Cbot \u4E0D\u65AD\u8FDE\uFF1Bowner-only",
|
|
8742
|
+
args: LarkBotUpgradeArgs
|
|
8743
|
+
},
|
|
8715
8744
|
"larkBot:status": {
|
|
8716
8745
|
summary: "\u67E5 persona \u7684\u98DE\u4E66 bot \u72B6\u6001\uFF08unbound/bound/broken + \u670D\u52A1\u4E2D\u7FA4\u6E05\u5355\uFF09\uFF1Bowner-only",
|
|
8717
8746
|
args: LarkBotStatusArgs
|
|
@@ -47040,7 +47069,7 @@ var SessionManager = class {
|
|
|
47040
47069
|
subSessionMeta.codexSandbox = {
|
|
47041
47070
|
writableRoots: [subSessionMeta.userWorkDir, ...(codexCfg?.writableRoots ?? []).map(expand)],
|
|
47042
47071
|
denyRead: codexCfg?.denyRead ?? [],
|
|
47043
|
-
network: codexCfg?.network ??
|
|
47072
|
+
network: codexCfg?.network ?? true
|
|
47044
47073
|
};
|
|
47045
47074
|
}
|
|
47046
47075
|
if (subSessionMeta?.personaMode === "owner" && file.projectPath) {
|
|
@@ -49778,6 +49807,24 @@ var PersonaManager = class {
|
|
|
49778
49807
|
return this.deps.store.readEnabledPlugins(personaId2);
|
|
49779
49808
|
}
|
|
49780
49809
|
/** 读 sandbox-settings.json;不存在 / 损坏返回 null。供 persona:get handler 拼响应。 */
|
|
49810
|
+
/** 读 codex guest 沙箱配置(`.clawd/codex-sandbox.json`);缺失 / 坏 → null。透传给 handler 拼响应。 */
|
|
49811
|
+
readCodexSandboxSettings(personaId2) {
|
|
49812
|
+
return this.deps.store.readCodexSandboxSettings(personaId2);
|
|
49813
|
+
}
|
|
49814
|
+
/**
|
|
49815
|
+
* 局部合并写 codex guest 沙箱配置,返回合并后的全量。
|
|
49816
|
+
*
|
|
49817
|
+
* **必须是合并不是覆盖**:UI 的「访客联网」开关只发 `{network}`,整体覆盖会静默抹掉 owner
|
|
49818
|
+
* 手配的 writableRoots / denyRead(丢的是安全边界,且用户不会立刻发现)。
|
|
49819
|
+
* 不走 PersonaManager.update 是因为它管的是 PersonaFile meta + 人格两层文本,
|
|
49820
|
+
* 而这份配置是另一个文件、另一套 schema。
|
|
49821
|
+
*/
|
|
49822
|
+
mergeCodexSandbox(personaId2, patch) {
|
|
49823
|
+
if (!this.deps.registry.get(personaId2)) throw new Error(`persona not found: ${personaId2}`);
|
|
49824
|
+
const merged = { ...this.deps.store.readCodexSandboxSettings(personaId2) ?? {}, ...patch };
|
|
49825
|
+
this.deps.store.writeCodexSandboxSettings(personaId2, merged);
|
|
49826
|
+
return merged;
|
|
49827
|
+
}
|
|
49781
49828
|
readSandboxSettings(personaId2) {
|
|
49782
49829
|
return this.deps.store.readSandboxSettings(personaId2);
|
|
49783
49830
|
}
|
|
@@ -50179,13 +50226,15 @@ function migrateAgentsMirror(args) {
|
|
|
50179
50226
|
}
|
|
50180
50227
|
if (mirrored > 0) args.logger.info("persona.agents-mirror.done", { mirrored });
|
|
50181
50228
|
}
|
|
50229
|
+
var PKG_CACHE_ROOTS = ["~/Library/pnpm", "~/.local/share/pnpm", "~/.local/state/pnpm", "~/.npm", "~/.pnpm-store"];
|
|
50230
|
+
var CODEX_SANDBOX_DEFAULT = { writableRoots: [...PKG_CACHE_ROOTS], denyRead: [], network: true };
|
|
50182
50231
|
function migrateCodexSandbox(args) {
|
|
50183
50232
|
const entries = args.entries ?? DEFAULT_PERSONAS;
|
|
50184
50233
|
let n = 0;
|
|
50185
50234
|
for (const personaId2 of args.store.list()) {
|
|
50186
50235
|
if (args.store.readCodexSandboxSettings(personaId2)) continue;
|
|
50187
50236
|
try {
|
|
50188
|
-
const def = entries.find((e) => e.personaId === personaId2)?.codexSandbox ??
|
|
50237
|
+
const def = entries.find((e) => e.personaId === personaId2)?.codexSandbox ?? CODEX_SANDBOX_DEFAULT;
|
|
50189
50238
|
args.store.writeCodexSandboxSettings(personaId2, def);
|
|
50190
50239
|
n++;
|
|
50191
50240
|
args.logger.info("persona.codex-sandbox.synced", { personaId: personaId2 });
|
|
@@ -54030,6 +54079,7 @@ function buildShiftInternalHandlers(deps) {
|
|
|
54030
54079
|
init_protocol();
|
|
54031
54080
|
var PROVISION_ERROR_SET = new Set(LARK_BOT_PROVISION_ERROR_REASONS);
|
|
54032
54081
|
var PROVISION_POLL_INTERVAL_MS = 2e3;
|
|
54082
|
+
var UPGRADE_POLL_MAX_FAILURES = 5;
|
|
54033
54083
|
var PROVISION_MAX_CONSECUTIVE_FAILURES = 5;
|
|
54034
54084
|
var PROVISION_POLL_MAX_MS = 60 * 60 * 1e3;
|
|
54035
54085
|
function normalizeProvisionReason(reason) {
|
|
@@ -54043,6 +54093,7 @@ function buildLarkBotHandlers(deps) {
|
|
|
54043
54093
|
const sleep2 = deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
54044
54094
|
const pollIntervalMs = deps.pollIntervalMs ?? PROVISION_POLL_INTERVAL_MS;
|
|
54045
54095
|
const inFlight = /* @__PURE__ */ new Map();
|
|
54096
|
+
const upgradeInFlight = /* @__PURE__ */ new Map();
|
|
54046
54097
|
const groupsOf = (personaId2) => {
|
|
54047
54098
|
const removed = new Set(deps.store.read(personaId2)?.removedChatIds ?? []);
|
|
54048
54099
|
return deps.listLarkSessions(personaId2).filter((g2) => !removed.has(g2.chatId));
|
|
@@ -54141,8 +54192,121 @@ function buildLarkBotHandlers(deps) {
|
|
|
54141
54192
|
void runProvisionPolling(personaId2, provisionId);
|
|
54142
54193
|
return { response: { type: "larkBot:provision:ok" } };
|
|
54143
54194
|
};
|
|
54195
|
+
const runUpgradePolling = async (personaId2) => {
|
|
54196
|
+
const backToBound = (needsUpgrade) => {
|
|
54197
|
+
upgradeInFlight.delete(personaId2);
|
|
54198
|
+
const fresh = deps.store.read(personaId2);
|
|
54199
|
+
if (!fresh) {
|
|
54200
|
+
emit(personaId2, { state: "unbound", groups: [] });
|
|
54201
|
+
return;
|
|
54202
|
+
}
|
|
54203
|
+
emit(personaId2, {
|
|
54204
|
+
state: "bound",
|
|
54205
|
+
appId: fresh.appId,
|
|
54206
|
+
botName: fresh.botName,
|
|
54207
|
+
...needsUpgrade ? { needsUpgrade: true } : {},
|
|
54208
|
+
groups: groupsOf(personaId2)
|
|
54209
|
+
});
|
|
54210
|
+
};
|
|
54211
|
+
const startedAt = now();
|
|
54212
|
+
let failures = 0;
|
|
54213
|
+
for (; ; ) {
|
|
54214
|
+
await sleep2(pollIntervalMs);
|
|
54215
|
+
const entry = upgradeInFlight.get(personaId2);
|
|
54216
|
+
if (!entry || entry.cancelled) return;
|
|
54217
|
+
if (now() - startedAt >= PROVISION_POLL_MAX_MS) {
|
|
54218
|
+
deps.logger?.warn(`larkBot upgrade poll deadline exceeded: ${personaId2}`);
|
|
54219
|
+
backToBound(true);
|
|
54220
|
+
return;
|
|
54221
|
+
}
|
|
54222
|
+
let stillNeeds;
|
|
54223
|
+
try {
|
|
54224
|
+
const binding = (await deps.cloud.listBindings()).find((b2) => b2.personaId === personaId2);
|
|
54225
|
+
if (!binding) {
|
|
54226
|
+
backToBound(false);
|
|
54227
|
+
return;
|
|
54228
|
+
}
|
|
54229
|
+
stillNeeds = binding.needsUpgrade !== false;
|
|
54230
|
+
failures = 0;
|
|
54231
|
+
if (!upgradeInFlight.get(personaId2) || upgradeInFlight.get(personaId2)?.cancelled) return;
|
|
54232
|
+
} catch (err) {
|
|
54233
|
+
failures += 1;
|
|
54234
|
+
deps.logger?.warn(`larkBot upgrade poll failed (${failures}): ${err.message}`);
|
|
54235
|
+
if (failures >= UPGRADE_POLL_MAX_FAILURES) {
|
|
54236
|
+
backToBound(true);
|
|
54237
|
+
return;
|
|
54238
|
+
}
|
|
54239
|
+
await sleep2(pollIntervalMs * 2 ** failures);
|
|
54240
|
+
continue;
|
|
54241
|
+
}
|
|
54242
|
+
if (!stillNeeds) {
|
|
54243
|
+
backToBound(false);
|
|
54244
|
+
return;
|
|
54245
|
+
}
|
|
54246
|
+
}
|
|
54247
|
+
};
|
|
54248
|
+
const upgrade = async (frame) => {
|
|
54249
|
+
const { personaId: personaId2 } = parseArgs2(LarkBotUpgradeArgs, frame, "larkBot:upgrade");
|
|
54250
|
+
const meta = deps.store.read(personaId2);
|
|
54251
|
+
if (!meta) throw new Error(`larkBot not bound: ${personaId2}`);
|
|
54252
|
+
if (inFlight.has(personaId2) || upgradeInFlight.has(personaId2)) {
|
|
54253
|
+
throw new Error(`larkBot provision already in flight: ${personaId2}`);
|
|
54254
|
+
}
|
|
54255
|
+
upgradeInFlight.set(personaId2, { provisionId: "", qrUrl: "", cancelled: false });
|
|
54256
|
+
let provisionId;
|
|
54257
|
+
let qrUrl;
|
|
54258
|
+
try {
|
|
54259
|
+
;
|
|
54260
|
+
({ provisionId, qrUrl } = await deps.cloud.provisionUpgrade({ personaId: personaId2 }));
|
|
54261
|
+
} catch (err) {
|
|
54262
|
+
upgradeInFlight.delete(personaId2);
|
|
54263
|
+
throw err;
|
|
54264
|
+
}
|
|
54265
|
+
const placeholder = upgradeInFlight.get(personaId2);
|
|
54266
|
+
if (!placeholder || placeholder.cancelled) {
|
|
54267
|
+
upgradeInFlight.delete(personaId2);
|
|
54268
|
+
void deps.cloud.provisionCancel(provisionId).catch(
|
|
54269
|
+
(err) => deps.logger?.warn(`larkBot upgrade cancel-during-begin: ${err.message}`)
|
|
54270
|
+
);
|
|
54271
|
+
return { response: { type: "larkBot:upgrade:ok" } };
|
|
54272
|
+
}
|
|
54273
|
+
upgradeInFlight.set(personaId2, { provisionId, qrUrl, cancelled: false });
|
|
54274
|
+
emit(personaId2, {
|
|
54275
|
+
state: "bound",
|
|
54276
|
+
appId: meta.appId,
|
|
54277
|
+
botName: meta.botName,
|
|
54278
|
+
needsUpgrade: true,
|
|
54279
|
+
upgradeQrUrl: qrUrl,
|
|
54280
|
+
groups: groupsOf(personaId2)
|
|
54281
|
+
});
|
|
54282
|
+
void runUpgradePolling(personaId2);
|
|
54283
|
+
return { response: { type: "larkBot:upgrade:ok" } };
|
|
54284
|
+
};
|
|
54144
54285
|
const provisionCancel = async (frame) => {
|
|
54145
54286
|
const { personaId: personaId2 } = parseArgs2(LarkBotProvisionCancelArgs, frame, "larkBot:provisionCancel");
|
|
54287
|
+
const upgrading = upgradeInFlight.get(personaId2);
|
|
54288
|
+
if (upgrading) {
|
|
54289
|
+
upgrading.cancelled = true;
|
|
54290
|
+
upgradeInFlight.delete(personaId2);
|
|
54291
|
+
if (upgrading.provisionId) {
|
|
54292
|
+
await deps.cloud.provisionCancel(upgrading.provisionId).catch(
|
|
54293
|
+
(err) => deps.logger?.warn(`larkBot upgrade cancel cloud failed: ${err.message}`)
|
|
54294
|
+
);
|
|
54295
|
+
}
|
|
54296
|
+
const meta = deps.store.read(personaId2);
|
|
54297
|
+
emit(
|
|
54298
|
+
personaId2,
|
|
54299
|
+
meta ? {
|
|
54300
|
+
state: "bound",
|
|
54301
|
+
appId: meta.appId,
|
|
54302
|
+
botName: meta.botName,
|
|
54303
|
+
// 取消了就是没升成,提示条留着
|
|
54304
|
+
needsUpgrade: true,
|
|
54305
|
+
groups: groupsOf(personaId2)
|
|
54306
|
+
} : { state: "unbound", groups: [] }
|
|
54307
|
+
);
|
|
54308
|
+
return { response: { type: "larkBot:provisionCancel:ok" } };
|
|
54309
|
+
}
|
|
54146
54310
|
const entry = inFlight.get(personaId2);
|
|
54147
54311
|
if (!entry) throw new Error(`larkBot provision not in flight: ${personaId2}`);
|
|
54148
54312
|
entry.cancelled = true;
|
|
@@ -54182,6 +54346,7 @@ function buildLarkBotHandlers(deps) {
|
|
|
54182
54346
|
const ownerId = deps.getOwnerId();
|
|
54183
54347
|
if (!ownerId) throw new Error("larkBot bind requires feishu login (owner identity)");
|
|
54184
54348
|
const name = botName ?? deps.getPersonaName(personaId2) ?? personaId2;
|
|
54349
|
+
upgradeInFlight.delete(personaId2);
|
|
54185
54350
|
await deps.cloud.bind({ personaId: personaId2, appId, appSecret, botName: name, tunnelUrl, ownerId });
|
|
54186
54351
|
deps.store.write(personaId2, { appId, botName: name, boundAt: now() });
|
|
54187
54352
|
emit(personaId2, { state: "bound", appId, botName: name, groups: groupsOf(personaId2) });
|
|
@@ -54189,6 +54354,7 @@ function buildLarkBotHandlers(deps) {
|
|
|
54189
54354
|
};
|
|
54190
54355
|
const unbind = async (frame) => {
|
|
54191
54356
|
const { personaId: personaId2 } = parseArgs2(LarkBotUnbindArgs, frame, "larkBot:unbind");
|
|
54357
|
+
upgradeInFlight.delete(personaId2);
|
|
54192
54358
|
const meta = deps.store.read(personaId2);
|
|
54193
54359
|
if (!meta) throw new Error(`larkBot not bound: ${personaId2}`);
|
|
54194
54360
|
try {
|
|
@@ -54214,6 +54380,8 @@ function buildLarkBotHandlers(deps) {
|
|
|
54214
54380
|
}
|
|
54215
54381
|
};
|
|
54216
54382
|
}
|
|
54383
|
+
const upgrading = upgradeInFlight.get(personaId2);
|
|
54384
|
+
const upgradingQr = upgrading && !upgrading.cancelled ? upgrading.qrUrl : void 0;
|
|
54217
54385
|
const meta = deps.store.read(personaId2);
|
|
54218
54386
|
let cloudReachable = false;
|
|
54219
54387
|
let cloudBinding;
|
|
@@ -54235,7 +54403,10 @@ function buildLarkBotHandlers(deps) {
|
|
|
54235
54403
|
state: broken2 ? "broken" : "bound",
|
|
54236
54404
|
appId: cloudBinding.appId,
|
|
54237
54405
|
botName: cloudBinding.botName,
|
|
54406
|
+
...upgradingQr ? { needsUpgrade: true, upgradeQrUrl: upgradingQr } : {},
|
|
54238
54407
|
...broken2 ? { brokenReason: cloudBinding.brokenReason ?? "unknown" } : {},
|
|
54408
|
+
// 云端判定(它持有飞书回读的 granted scopes),daemon 只透传(spec 2026-09-01)
|
|
54409
|
+
...cloudBinding.needsUpgrade ? { needsUpgrade: true } : {},
|
|
54239
54410
|
groups: groupsOf(personaId2)
|
|
54240
54411
|
};
|
|
54241
54412
|
return { response: { type: "larkBot:status:ok", ...result2 } };
|
|
@@ -54262,7 +54433,10 @@ function buildLarkBotHandlers(deps) {
|
|
|
54262
54433
|
state: broken ? "broken" : "bound",
|
|
54263
54434
|
appId: cloudBinding?.appId ?? meta.appId,
|
|
54264
54435
|
botName: cloudBinding?.botName ?? meta.botName,
|
|
54436
|
+
...upgradingQr ? { needsUpgrade: true, upgradeQrUrl: upgradingQr } : {},
|
|
54265
54437
|
...broken ? { brokenReason: cloudBinding?.brokenReason ?? "unknown" } : {},
|
|
54438
|
+
// 云端不可达时 cloudBinding 为空 → 不提示升级(宁可不提示也不误报)
|
|
54439
|
+
...cloudBinding?.needsUpgrade ? { needsUpgrade: true } : {},
|
|
54266
54440
|
groups: groupsOf(personaId2)
|
|
54267
54441
|
};
|
|
54268
54442
|
return { response: { type: "larkBot:status:ok", ...result } };
|
|
@@ -54272,7 +54446,8 @@ function buildLarkBotHandlers(deps) {
|
|
|
54272
54446
|
"larkBot:provisionCancel": provisionCancel,
|
|
54273
54447
|
"larkBot:bindManual": bindManual,
|
|
54274
54448
|
"larkBot:unbind": unbind,
|
|
54275
|
-
"larkBot:status": status
|
|
54449
|
+
"larkBot:status": status,
|
|
54450
|
+
"larkBot:upgrade": upgrade
|
|
54276
54451
|
};
|
|
54277
54452
|
}
|
|
54278
54453
|
async function refreshTunnelUrlOnStartup(deps) {
|
|
@@ -54392,6 +54567,10 @@ function createLarkBotCloudClient(opts) {
|
|
|
54392
54567
|
const json = await request("POST", "/api/lark-bot/provision", { ...args });
|
|
54393
54568
|
return { provisionId: String(json.provisionId), qrUrl: String(json.qrUrl) };
|
|
54394
54569
|
},
|
|
54570
|
+
async provisionUpgrade(args) {
|
|
54571
|
+
const json = await request("POST", "/api/lark-bot/upgrade", { ...args });
|
|
54572
|
+
return { provisionId: String(json.provisionId), qrUrl: String(json.qrUrl) };
|
|
54573
|
+
},
|
|
54395
54574
|
async provisionStatus(provisionId) {
|
|
54396
54575
|
const json = await request("GET", `/api/lark-bot/provision/${encodeURIComponent(provisionId)}`);
|
|
54397
54576
|
if (json.state === "success") {
|
|
@@ -62521,6 +62700,7 @@ var METHOD_GRANT_MAP = {
|
|
|
62521
62700
|
"larkBot:bindManual": ADMIN_ANY,
|
|
62522
62701
|
"larkBot:unbind": ADMIN_ANY,
|
|
62523
62702
|
"larkBot:status": ADMIN_ANY,
|
|
62703
|
+
"larkBot:upgrade": ADMIN_ANY,
|
|
62524
62704
|
// ---- onboarding:* / tools:probe / session:externalScan(首启 wizard,owner-only)----
|
|
62525
62705
|
"onboarding:complete": ADMIN_ANY,
|
|
62526
62706
|
"onboarding:iosInterest": ADMIN_ANY,
|
|
@@ -62657,7 +62837,7 @@ function computeMethodAccess(args) {
|
|
|
62657
62837
|
}
|
|
62658
62838
|
|
|
62659
62839
|
// src/version.ts
|
|
62660
|
-
var version = "0.2.
|
|
62840
|
+
var version = "0.2.439".length > 0 ? "0.2.439" : "dev";
|
|
62661
62841
|
|
|
62662
62842
|
// src/cli-probe/probe.ts
|
|
62663
62843
|
var fs65 = __toESM(require("fs"), 1);
|
|
@@ -62821,6 +63001,7 @@ function buildPersonaHandlers(deps) {
|
|
|
62821
63001
|
const skills = personaManager.listSkills(args.personaId);
|
|
62822
63002
|
const plugins = personaManager.listEnabledPlugins(args.personaId);
|
|
62823
63003
|
const sandboxSettings = personaManager.readSandboxSettings(args.personaId);
|
|
63004
|
+
const codexSandbox = personaManager.readCodexSandboxSettings(args.personaId);
|
|
62824
63005
|
return {
|
|
62825
63006
|
response: {
|
|
62826
63007
|
type: "persona:info",
|
|
@@ -62830,16 +63011,26 @@ function buildPersonaHandlers(deps) {
|
|
|
62830
63011
|
personalityManaged,
|
|
62831
63012
|
skills,
|
|
62832
63013
|
plugins,
|
|
62833
|
-
sandboxSettings
|
|
63014
|
+
sandboxSettings,
|
|
63015
|
+
codexSandbox
|
|
62834
63016
|
}
|
|
62835
63017
|
};
|
|
62836
63018
|
};
|
|
62837
63019
|
const update = async (frame) => {
|
|
62838
63020
|
const { type: _type, requestId: _requestId, ...rest } = frame;
|
|
62839
63021
|
const args = parseArgs2(PersonaUpdateArgsSchema, frame, "persona:update");
|
|
62840
|
-
const { personality, personalityLocal, ...metaPatch } = args.patch;
|
|
63022
|
+
const { personality, personalityLocal, codexSandbox, ...metaPatch } = args.patch;
|
|
62841
63023
|
const persona = personaManager.update(args.personaId, metaPatch, { personality, personalityLocal });
|
|
62842
|
-
|
|
63024
|
+
const mergedCodexSandbox = codexSandbox ? personaManager.mergeCodexSandbox(args.personaId, codexSandbox) : void 0;
|
|
63025
|
+
return {
|
|
63026
|
+
response: {
|
|
63027
|
+
type: "persona:info",
|
|
63028
|
+
...persona,
|
|
63029
|
+
// 只在本次确实动过时回带,让调用方拿到合并后的真值而不用再 get 一次;
|
|
63030
|
+
// 没动就不带(与 personality 等分层字段同口径:persona:update 的响应是 meta 视图)。
|
|
63031
|
+
...mergedCodexSandbox ? { codexSandbox: mergedCodexSandbox } : {}
|
|
63032
|
+
}
|
|
63033
|
+
};
|
|
62843
63034
|
};
|
|
62844
63035
|
const del = async (frame) => {
|
|
62845
63036
|
const args = parseArgs2(PersonaIdArgsSchema, frame, "persona:delete");
|
|
@@ -22118,6 +22118,7 @@ var GithubPrRequestReviewersArgs = external_exports.object({
|
|
|
22118
22118
|
// ../protocol/src/lark-bot-schemas.ts
|
|
22119
22119
|
var LarkBotPersonaArgs = external_exports.object({ personaId: external_exports.string().min(1) });
|
|
22120
22120
|
var LarkBotUnbindArgs = LarkBotPersonaArgs;
|
|
22121
|
+
var LarkBotUpgradeArgs = external_exports.object({ personaId: external_exports.string().min(1) });
|
|
22121
22122
|
var LarkBotStatusArgs = LarkBotPersonaArgs;
|
|
22122
22123
|
var LarkBotProvisionArgs = LarkBotPersonaArgs;
|
|
22123
22124
|
var LarkBotProvisionCancelArgs = LarkBotPersonaArgs;
|
|
@@ -22151,7 +22152,21 @@ var LarkBotStatusResultSchema = external_exports.object({
|
|
|
22151
22152
|
qrUrl: external_exports.string().optional(),
|
|
22152
22153
|
/** provision 失败后的 unbound 帧携带;正常 unbound 无此字段 */
|
|
22153
22154
|
errorReason: LarkBotProvisionErrorReasonSchema.optional(),
|
|
22154
|
-
groups: external_exports.array(LarkBotGroupSchema)
|
|
22155
|
+
groups: external_exports.array(LarkBotGroupSchema),
|
|
22156
|
+
/**
|
|
22157
|
+
* bound 态:该 bot 实际授予的 scope 缺了 LARK_PROVISION_ADDONS 里声明的项
|
|
22158
|
+
* (spec 2026-09-01)——addons 是扫码时一次性写进飞书应用配置的,后来新增的
|
|
22159
|
+
* scope / 事件对存量 bot 不生效,不提示的话用户只会觉得「功能没生效」。
|
|
22160
|
+
* 判定真源是飞书回读的 granted scopes,不落库任何版本号。
|
|
22161
|
+
*/
|
|
22162
|
+
needsUpgrade: external_exports.boolean().optional(),
|
|
22163
|
+
/**
|
|
22164
|
+
* bound 态叠加:正在扫码更新授权(spec 2026-09-01)。
|
|
22165
|
+
* **不复用 provisioning 态**——升级期间 bot 仍在正常服务(长连接不断、群照常响应),
|
|
22166
|
+
* 降级成 provisioning 会丢掉 botName / groups,UI 上像是断了。
|
|
22167
|
+
* 有值即渲染二维码弹层;升级结束(成功或取消)该字段消失。
|
|
22168
|
+
*/
|
|
22169
|
+
upgradeQrUrl: external_exports.string().optional()
|
|
22155
22170
|
});
|
|
22156
22171
|
var LarkBotStateFrameSchema = LarkBotStatusResultSchema.extend({
|
|
22157
22172
|
personaId: external_exports.string().min(1)
|
|
@@ -22222,6 +22237,17 @@ var PersonaPluginSummarySchema = external_exports.object({
|
|
|
22222
22237
|
// settings.json 中 enabledPlugins 的 key,例如 'superpowers@claude-plugins-official'
|
|
22223
22238
|
id: external_exports.string().min(1)
|
|
22224
22239
|
});
|
|
22240
|
+
var CodexSandboxSettingsSchema = external_exports.object({
|
|
22241
|
+
// 额外可写的绝对路径或 ~ 路径(pnpm 工具链等);workspace(cwd) 和 userWorkDir 由 daemon 自动加,不用列。
|
|
22242
|
+
writableRoots: external_exports.array(external_exports.string()).optional(),
|
|
22243
|
+
// 禁读 glob(相对 workspace root 或绝对),如 ".secrets/**"、"**/*.env"。
|
|
22244
|
+
denyRead: external_exports.array(external_exports.string()).optional(),
|
|
22245
|
+
// true → 网络全放(*);false → 断网。**缺省等于联网**:daemon 写入的默认值是 network:true
|
|
22246
|
+
// (对齐 claude guest 一贯的域名全放,见 spec 2026-09-01-codex-guest-network §1.3),
|
|
22247
|
+
// 且 manager / UI 读到 undefined 时都回落 true —— 两侧必须同向,否则出现
|
|
22248
|
+
// 「卡片显示开、实际断网」的幽灵态。
|
|
22249
|
+
network: external_exports.boolean().optional()
|
|
22250
|
+
}).strict();
|
|
22225
22251
|
var PersonaSandboxSettingsSchema = external_exports.object({
|
|
22226
22252
|
permissions: external_exports.object({
|
|
22227
22253
|
defaultMode: external_exports.string().optional(),
|
|
@@ -22270,7 +22296,10 @@ var PersonaInfoResponseSchema = PersonaFileSchema.extend({
|
|
|
22270
22296
|
skills: external_exports.array(PersonaSkillSummarySchema).optional(),
|
|
22271
22297
|
// 仅 'persona:get' 携带;空数组 = 没启用任何插件 / settings.json 不存在;undefined = 不在该响应类型上
|
|
22272
22298
|
plugins: external_exports.array(PersonaPluginSummarySchema).optional(),
|
|
22273
|
-
sandboxSettings: PersonaSandboxSettingsSchema.nullable().optional()
|
|
22299
|
+
sandboxSettings: PersonaSandboxSettingsSchema.nullable().optional(),
|
|
22300
|
+
// 仅 'persona:get' 携带;null = codex-sandbox.json 不存在 / parse 失败。
|
|
22301
|
+
// UI 的「访客联网」开关读它(见 PersonaCardSettings)。
|
|
22302
|
+
codexSandbox: CodexSandboxSettingsSchema.nullable().optional()
|
|
22274
22303
|
});
|
|
22275
22304
|
var PersonaCreateArgsSchema = external_exports.object({
|
|
22276
22305
|
// persona 身份。daemon 拼成 personaId = `persona-<slug>`——前缀由 daemon 拥有,调用方只给后半段,
|
|
@@ -22302,17 +22331,13 @@ var PersonaUpdateArgsSchema = external_exports.object({
|
|
|
22302
22331
|
personalityLocal: external_exports.string().optional(),
|
|
22303
22332
|
public: external_exports.boolean().optional(),
|
|
22304
22333
|
// pass `null` to clear; daemon strips the field from PersonaFile on null
|
|
22305
|
-
iconKey: external_exports.string().nullable().optional()
|
|
22334
|
+
iconKey: external_exports.string().nullable().optional(),
|
|
22335
|
+
// codex guest 沙箱(落盘 .clawd/codex-sandbox.json,不在 PersonaFile 里)。与 personality
|
|
22336
|
+
// 同款分层写:handler 剥出来单独落盘,且**局部合并**——只带 network 的 patch 不能抹掉
|
|
22337
|
+
// owner 手配的 writableRoots / denyRead。
|
|
22338
|
+
codexSandbox: CodexSandboxSettingsSchema.optional()
|
|
22306
22339
|
}).strict()
|
|
22307
22340
|
}).strict();
|
|
22308
|
-
var CodexSandboxSettingsSchema = external_exports.object({
|
|
22309
|
-
// 额外可写的绝对路径或 ~ 路径(pnpm 工具链等);workspace(cwd) 和 userWorkDir 由 daemon 自动加,不用列。
|
|
22310
|
-
writableRoots: external_exports.array(external_exports.string()).optional(),
|
|
22311
|
-
// 禁读 glob(相对 workspace root 或绝对),如 ".secrets/**"、"**/*.env"。
|
|
22312
|
-
denyRead: external_exports.array(external_exports.string()).optional(),
|
|
22313
|
-
// true → 网络全放(*);缺省/false → 断网。
|
|
22314
|
-
network: external_exports.boolean().optional()
|
|
22315
|
-
}).strict();
|
|
22316
22341
|
|
|
22317
22342
|
// ../protocol/src/events.ts
|
|
22318
22343
|
var SESSION_STATUS_VALUES = [
|
|
@@ -23772,6 +23797,10 @@ var METHOD_DOCS = {
|
|
|
23772
23797
|
summary: "\u89E3\u7ED1 persona \u7684\u98DE\u4E66 bot\uFF08\u5220\u4E91\u7AEF\u7ED1\u5B9A + \u65AD\u957F\u8FDE\u63A5\uFF0C\u98DE\u4E66\u4FA7 app \u4FDD\u7559\uFF09\uFF1Bowner-only",
|
|
23773
23798
|
args: LarkBotUnbindArgs
|
|
23774
23799
|
},
|
|
23800
|
+
"larkBot:upgrade": {
|
|
23801
|
+
summary: "\u626B\u7801\u66F4\u65B0\u5DF2\u7ED1\u5B9A bot \u7684\u6388\u6743\uFF08\u8865\u540E\u6765\u65B0\u589E\u7684 scope / \u4E8B\u4EF6\uFF09\uFF1B\u5168\u7A0B\u4FDD\u6301 bound\uFF0Cbot \u4E0D\u65AD\u8FDE\uFF1Bowner-only",
|
|
23802
|
+
args: LarkBotUpgradeArgs
|
|
23803
|
+
},
|
|
23775
23804
|
"larkBot:status": {
|
|
23776
23805
|
summary: "\u67E5 persona \u7684\u98DE\u4E66 bot \u72B6\u6001\uFF08unbound/bound/broken + \u670D\u52A1\u4E2D\u7FA4\u6E05\u5355\uFF09\uFF1Bowner-only",
|
|
23777
23806
|
args: LarkBotStatusArgs
|