@clawos-dev/clawd 0.2.277 → 0.2.279

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 CHANGED
@@ -6779,7 +6779,7 @@ var init_principal = __esm({
6779
6779
  });
6780
6780
 
6781
6781
  // ../protocol/src/schemas.ts
6782
- var SessionStatusSchema, UsageSchema, ContextUsageSchema, sessionMetaShape, SessionMetaSchema, ModelInfoSchema, ModeInfoSchema, ConfigFieldSchemaSchema, CapabilitiesGetArgs, ToolFeaturesSchema, CapabilitiesResponseSchema, AllowRuleSchema, SessionFileSchema, ParsedEventBase, HistoryUserMetaSchema, SubagentToolStatsSchema, StructuredPatchHunkSchema, ToolResultExtraSchema, MemoryEntrySchema, AskQuestionOptionSchema, AskQuestionItemSchema, ParsedEventSchema, SessionCreateArgs, SessionListArgs, SessionIdArgs, SessionUpdateArgs, SessionSendArgs, SessionInterruptArgs, SessionRewindArgs, SessionRewindResponseSchema, SessionRewindDiffArgs, RewindDiffHunkSchema, RewindDiffFileSchema, SessionRewindDiffResponseSchema, SessionRewindableMessageIdsArgs, SessionRewindableMessageIdsResponseSchema, SessionResumeArgs, SessionForkArgs, SessionForkResponseSchema, SessionObserveArgs, SessionEventsArgs, PermissionRespondArgs, HistoryListArgs, HistoryReadArgs, HistorySubagentsArgs, HistorySubagentReadArgs, WorkspaceListArgs, WorkspaceReadArgs, SkillsListArgs, SkillEntrySchema, AgentEntrySchema, AgentsListArgs, AgentsListResponseSchema, SessionCurrentTurnSenderArgs, SessionSubscribeArgs, SessionPinArgs, PeerSessionUpsertArgs, PeerSessionUpsertResponseSchema, PeerSessionRemoveArgs, PeerSessionRemoveResponseSchema, SessionReorderPinsArgs, GitRootArgs, GitRootResponseSchema, GitBranchArgs, GitBranchResponseSchema, GitBranchesArgs, GitBranchesResponseSchema, HistoryRecentDirsArgs, RecentDirEntrySchema, HistoryRecentDirsResponseSchema, SessionQuestionFrameSchema, SessionQuestionClearedFrameSchema, AnswerQuestionArgs, AnswerQuestionResponseSchema, CancelQuestionArgs, CancelQuestionResponseSchema, ClientInfoSchema, AuthRequestFrameSchema, AuthOkFrameSchema, DeviceConnectionEntrySchema, DeviceConnectionsResponseSchema, TunnelReadyEventSchema, TunnelExitedEventSchema, TunnelUnavailableEventSchema, InfoRunningSessionSchema, InfoResponseSchema, PROJECT_PORT_MIN, PROJECT_PORT_MAX, projectNameRegex, DEFAULT_DEV_COMMAND, ProjectMetadataSchema, PROJECT_STAGE_VALUES, ProjectStageSchema, ProjectWithStatusSchema, ListProjectsArgsSchema, ListProjectsResultSchema, GetProjectArgsSchema, GetProjectResultSchema, CreateProjectArgsSchema, CreateProjectResultSchema, DeleteProjectArgsSchema, DeleteProjectResultSchema, UpdateProjectPortArgsSchema, UpdateProjectPortResultSchema, SetProdUrlArgsSchema, SetProdUrlResultSchema, StartDevServerArgsSchema, StartDevServerResultSchema, ASSISTANT_REPORTABLE_STAGES, ReportStageArgsSchema, ReportStageResultSchema, StopDevServerArgsSchema, StopDevServerResultSchema, AppBuilderProjectUpdatedEventSchema, PublishArgsSchema, PublishResultSchema, DismissPublishJobArgsSchema, DismissPublishJobResultSchema, AppBuilderPublishProgressEventSchema, AppBuilderPublishFailedEventSchema;
6782
+ var SessionStatusSchema, UsageSchema, ContextUsageSchema, sessionMetaShape, SessionMetaSchema, SelectOptionSchema, ModelInfoSchema, ModeInfoSchema, ConfigFieldSchemaSchema, CapabilitiesGetArgs, ToolFeaturesSchema, CapabilitiesResponseSchema, AllowRuleSchema, SessionFileSchema, ParsedEventBase, HistoryUserMetaSchema, SubagentToolStatsSchema, StructuredPatchHunkSchema, ToolResultExtraSchema, MemoryEntrySchema, AskQuestionOptionSchema, AskQuestionItemSchema, ParsedEventSchema, SessionCreateArgs, SessionImportExternalArgs, SessionListArgs, SessionIdArgs, SessionUpdateArgs, SessionSendArgs, SessionInterruptArgs, SessionRewindArgs, SessionRewindResponseSchema, SessionRewindDiffArgs, RewindDiffHunkSchema, RewindDiffFileSchema, SessionRewindDiffResponseSchema, SessionRewindableMessageIdsArgs, SessionRewindableMessageIdsResponseSchema, SessionResumeArgs, SessionForkArgs, SessionForkResponseSchema, SessionObserveArgs, SessionEventsArgs, PermissionRespondArgs, HistoryListArgs, HistoryReadArgs, HistorySubagentsArgs, HistorySubagentReadArgs, WorkspaceListArgs, WorkspaceReadArgs, SkillsListArgs, SkillEntrySchema, AgentEntrySchema, AgentsListArgs, AgentsListResponseSchema, SessionCurrentTurnSenderArgs, SessionSubscribeArgs, SessionPinArgs, PeerSessionUpsertArgs, PeerSessionUpsertResponseSchema, PeerSessionRemoveArgs, PeerSessionRemoveResponseSchema, SessionReorderPinsArgs, GitRootArgs, GitRootResponseSchema, GitBranchArgs, GitBranchResponseSchema, GitBranchesArgs, GitBranchesResponseSchema, HistoryRecentDirsArgs, RecentDirEntrySchema, HistoryRecentDirsResponseSchema, SessionQuestionFrameSchema, SessionQuestionClearedFrameSchema, AnswerQuestionArgs, AnswerQuestionResponseSchema, CancelQuestionArgs, CancelQuestionResponseSchema, ClientInfoSchema, AuthRequestFrameSchema, AuthOkFrameSchema, DeviceConnectionEntrySchema, DeviceConnectionsResponseSchema, TunnelReadyEventSchema, TunnelExitedEventSchema, TunnelUnavailableEventSchema, InfoRunningSessionSchema, InfoResponseSchema, PROJECT_PORT_MIN, PROJECT_PORT_MAX, projectNameRegex, DEFAULT_DEV_COMMAND, ProjectMetadataSchema, PROJECT_STAGE_VALUES, ProjectStageSchema, ProjectWithStatusSchema, ListProjectsArgsSchema, ListProjectsResultSchema, GetProjectArgsSchema, GetProjectResultSchema, CreateProjectArgsSchema, CreateProjectResultSchema, DeleteProjectArgsSchema, DeleteProjectResultSchema, UpdateProjectPortArgsSchema, UpdateProjectPortResultSchema, SetProdUrlArgsSchema, SetProdUrlResultSchema, StartDevServerArgsSchema, StartDevServerResultSchema, ASSISTANT_REPORTABLE_STAGES, ReportStageArgsSchema, ReportStageResultSchema, StopDevServerArgsSchema, StopDevServerResultSchema, AppBuilderProjectUpdatedEventSchema, PublishArgsSchema, PublishResultSchema, DismissPublishJobArgsSchema, DismissPublishJobResultSchema, AppBuilderPublishProgressEventSchema, AppBuilderPublishFailedEventSchema;
6783
6783
  var init_schemas = __esm({
6784
6784
  "../protocol/src/schemas.ts"() {
6785
6785
  "use strict";
@@ -6808,12 +6808,22 @@ var init_schemas = __esm({
6808
6808
  contextWindowSize: external_exports.number().int().positive().optional()
6809
6809
  };
6810
6810
  SessionMetaSchema = external_exports.object(sessionMetaShape);
6811
+ SelectOptionSchema = external_exports.object({
6812
+ value: external_exports.string(),
6813
+ label: external_exports.string(),
6814
+ description: external_exports.string().optional()
6815
+ });
6811
6816
  ModelInfoSchema = external_exports.object({
6812
6817
  id: external_exports.string().min(1),
6813
6818
  label: external_exports.string().min(1),
6814
6819
  description: external_exports.string().optional(),
6815
6820
  contextWindowSize: external_exports.number().int().positive(),
6816
- default: external_exports.boolean().optional()
6821
+ default: external_exports.boolean().optional(),
6822
+ // 该模型支持的 reasoning effort 档位(codex:per-model,gpt-5.6 系有 max/ultra、5.5 只有四档)。
6823
+ // 缺省 = 该 tool 的 effort 与模型无关(claude 即此情形),消费方回落到 configSchema 里
6824
+ // name==='effort' 那条字段的 options。
6825
+ efforts: external_exports.array(SelectOptionSchema).optional(),
6826
+ defaultEffort: external_exports.string().optional()
6817
6827
  });
6818
6828
  ModeInfoSchema = external_exports.object({
6819
6829
  id: external_exports.string().min(1),
@@ -6825,13 +6835,7 @@ var init_schemas = __esm({
6825
6835
  type: external_exports.enum(["string", "select", "toggle"]),
6826
6836
  label: external_exports.string().min(1),
6827
6837
  description: external_exports.string().optional(),
6828
- options: external_exports.array(
6829
- external_exports.object({
6830
- value: external_exports.string(),
6831
- label: external_exports.string(),
6832
- description: external_exports.string().optional()
6833
- })
6834
- ).optional(),
6838
+ options: external_exports.array(SelectOptionSchema).optional(),
6835
6839
  default: external_exports.unknown().optional(),
6836
6840
  scope: external_exports.enum(["core", "tool-specific"])
6837
6841
  });
@@ -7225,6 +7229,16 @@ var init_schemas = __esm({
7225
7229
  }).refine((args) => args.cwd != null || args.ownerPersonaId != null, {
7226
7230
  message: "cwd \u4E0E ownerPersonaId \u81F3\u5C11\u4F20\u4E00\u4E2A"
7227
7231
  });
7232
+ SessionImportExternalArgs = external_exports.object({
7233
+ cwd: external_exports.string().min(1),
7234
+ tool: external_exports.string().min(1),
7235
+ toolSessionId: external_exports.string().min(1),
7236
+ label: external_exports.string().optional(),
7237
+ iconKey: external_exports.string().optional(),
7238
+ createdAt: external_exports.string().datetime(),
7239
+ updatedAt: external_exports.string().datetime(),
7240
+ ownerPersonaId: external_exports.string().min(1).optional()
7241
+ });
7228
7242
  SessionListArgs = external_exports.object({
7229
7243
  /** true = 只返回 mirror(originOwnerPrincipalId 非空,即「我在朋友 daemon 上创建」的本机存证)。 */
7230
7244
  originOnly: external_exports.boolean().optional(),
@@ -7801,6 +7815,10 @@ var init_methods = __esm({
7801
7815
  anyOf: [{ required: ["cwd"] }, { required: ["ownerPersonaId"] }]
7802
7816
  }
7803
7817
  },
7818
+ "session:importExternal": {
7819
+ summary: "\u628A Claude Code / Codex \u65E2\u6709\u5386\u53F2\u4F1A\u8BDD\u5BFC\u5165\u4E3A clawd \u5F15\u7528\uFF1A\u53EA\u5199 SessionFile\uFF0C\u4E0D\u62C9\u8D77 runner\uFF0C\u4E0D\u6539\u539F\u59CB transcript\uFF1B\u6309 toolSessionId \u8DE8 owned scope \u53BB\u91CD\uFF0C\u65B0\u5BFC\u5165\u4F1A\u5E7F\u64AD session:info",
7820
+ args: SessionImportExternalArgs
7821
+ },
7804
7822
  "session:list": {
7805
7823
  summary: "\u5217\u51FA\u5F53\u524D\u8EAB\u4EFD\u53EF\u89C1\u7684\u4F1A\u8BDD\uFF08owner \u5168\u91CF\uFF1Bguest \u9650\u88AB\u6388\u6743 persona\uFF09",
7806
7824
  args: SessionListArgs
@@ -45963,6 +45981,41 @@ var SessionManager = class {
45963
45981
  const written = this.storeFor(scope).write(file);
45964
45982
  return { response: written, broadcast: [] };
45965
45983
  }
45984
+ importExternal(args, creatorPrincipalId, creatorDisplayName, creatorFeishuUnionId) {
45985
+ const existing = this.listAllOwned().find((file2) => file2.toolSessionId === args.toolSessionId);
45986
+ if (existing) {
45987
+ return {
45988
+ response: { ...existing, alreadyLinked: true },
45989
+ broadcast: []
45990
+ };
45991
+ }
45992
+ try {
45993
+ const stat = import_node_fs9.default.statSync(args.cwd);
45994
+ if (!stat.isDirectory()) throw new Error("not dir");
45995
+ } catch {
45996
+ throw new ClawdError(ERROR_CODES.INVALID_CWD, `cwd not a directory: ${args.cwd}`);
45997
+ }
45998
+ this.deps.getAdapter(args.tool);
45999
+ const file = {
46000
+ sessionId: newSessionId(),
46001
+ cwd: args.cwd,
46002
+ tool: args.tool,
46003
+ toolSessionId: args.toolSessionId,
46004
+ label: args.label,
46005
+ iconKey: args.iconKey,
46006
+ ownerPersonaId: args.ownerPersonaId,
46007
+ creatorPrincipalId,
46008
+ creatorDisplayName,
46009
+ ...creatorFeishuUnionId ? { creatorFeishuUnionId } : {},
46010
+ createdAt: args.createdAt,
46011
+ updatedAt: args.updatedAt
46012
+ };
46013
+ const written = this.writeOwned(file);
46014
+ return {
46015
+ response: written,
46016
+ broadcast: [{ frame: { type: "session:info", ...written }, target: "all" }]
46017
+ };
46018
+ }
45966
46019
  pin(args) {
45967
46020
  const existing = this.getFile(args.sessionId);
45968
46021
  const pinnedAt = args.pinned ? (this.deps.now ?? Date.now)() : null;
@@ -48657,7 +48710,7 @@ function createVisitorStore(opts) {
48657
48710
  init_claude();
48658
48711
 
48659
48712
  // src/tools/codex.ts
48660
- var import_node_child_process5 = require("child_process");
48713
+ var import_node_child_process6 = require("child_process");
48661
48714
  var import_node_fs18 = __toESM(require("fs"), 1);
48662
48715
 
48663
48716
  // src/tools/codex-session.ts
@@ -49158,29 +49211,110 @@ function createCodexSession(ctx, sink, deps = {}) {
49158
49211
  };
49159
49212
  }
49160
49213
 
49214
+ // src/tools/codex-app-server-query.ts
49215
+ var import_node_child_process5 = require("child_process");
49216
+ var DEFAULT_CODEX_QUERY_TIMEOUT_MS = 8e3;
49217
+ async function queryCodexAppServer(cwd, method, params, deps = {}) {
49218
+ const cmd = process.env.CODEX_BIN ?? "codex";
49219
+ const args = ["app-server", "--listen", "stdio://"];
49220
+ const proc = deps.spawnOverride ? deps.spawnOverride(cmd, args, cwd) : (0, import_node_child_process5.spawn)(cmd, args, { cwd, env: process.env, stdio: ["pipe", "pipe", "pipe"] });
49221
+ const client = new CodexAppServerClient(proc, {});
49222
+ const timeoutMs = deps.timeoutMs ?? DEFAULT_CODEX_QUERY_TIMEOUT_MS;
49223
+ let timer;
49224
+ const timeout = new Promise((_2, reject) => {
49225
+ timer = setTimeout(
49226
+ () => reject(new Error(`codex app-server ${method} timed out after ${timeoutMs}ms`)),
49227
+ timeoutMs
49228
+ );
49229
+ proc.on(
49230
+ "error",
49231
+ (err) => reject(new Error(`codex app-server spawn failed: ${err.message}`))
49232
+ );
49233
+ });
49234
+ try {
49235
+ await Promise.race([
49236
+ (async () => {
49237
+ await client.request("initialize", {
49238
+ clientInfo: { name: "clawd", title: "clawd", version: "0" },
49239
+ capabilities: null
49240
+ });
49241
+ client.notify("initialized", {});
49242
+ })(),
49243
+ timeout
49244
+ ]);
49245
+ deps.beforeRequest?.(client);
49246
+ return await Promise.race([client.request(method, params), timeout]);
49247
+ } finally {
49248
+ if (timer) clearTimeout(timer);
49249
+ if (proc.exitCode === null && proc.signalCode === null) proc.kill("SIGTERM");
49250
+ }
49251
+ }
49252
+
49253
+ // src/tools/codex-model-list.ts
49254
+ var CODEX_CONTEXT_WINDOW = 258400;
49255
+ var EFFORT_LABELS = {
49256
+ low: "Low",
49257
+ medium: "Medium",
49258
+ high: "High",
49259
+ xhigh: "Extra high",
49260
+ max: "Max",
49261
+ ultra: "Ultra"
49262
+ };
49263
+ var CODEX_DEFAULT_MODEL_ENTRY = {
49264
+ id: "",
49265
+ label: "Default",
49266
+ description: "codex config.toml \u9ED8\u8BA4",
49267
+ contextWindowSize: CODEX_CONTEXT_WINDOW,
49268
+ default: true
49269
+ };
49270
+ function mapModelList(raw) {
49271
+ if (!raw || typeof raw !== "object") throw new Error("model/list: response is not an object");
49272
+ const data = raw.data;
49273
+ if (!Array.isArray(data)) throw new Error("model/list: `data` is not an array");
49274
+ const models = [CODEX_DEFAULT_MODEL_ENTRY];
49275
+ for (const item of data) {
49276
+ if (!item || typeof item !== "object") throw new Error("model/list: entry is not an object");
49277
+ const e = item;
49278
+ if (typeof e.id !== "string" || e.id === "") throw new Error("model/list: entry missing `id`");
49279
+ if (e.hidden === true) continue;
49280
+ const efforts = Array.isArray(e.supportedReasoningEfforts) ? e.supportedReasoningEfforts.filter((x) => x && typeof x.reasoningEffort === "string").map((x) => {
49281
+ const value = x.reasoningEffort;
49282
+ return {
49283
+ value,
49284
+ label: EFFORT_LABELS[value] ?? value,
49285
+ ...typeof x.description === "string" ? { description: x.description } : {}
49286
+ };
49287
+ }) : void 0;
49288
+ models.push({
49289
+ id: e.id,
49290
+ label: typeof e.displayName === "string" && e.displayName ? e.displayName : e.id,
49291
+ ...typeof e.description === "string" ? { description: e.description } : {},
49292
+ contextWindowSize: CODEX_CONTEXT_WINDOW,
49293
+ ...efforts && efforts.length > 0 ? { efforts } : {},
49294
+ ...typeof e.defaultReasoningEffort === "string" ? { defaultEffort: e.defaultReasoningEffort } : {}
49295
+ });
49296
+ }
49297
+ return models;
49298
+ }
49299
+
49161
49300
  // src/tools/codex.ts
49162
- var CODEX_MODEL_IDS = ["gpt-5.5", "gpt-5.4", "gpt-5.4-mini"];
49163
- var CODEX_MODELS = [
49164
- { id: "", label: "Default", description: "codex config.toml \u9ED8\u8BA4", contextWindowSize: 258400, default: true },
49165
- { id: "gpt-5.5", label: "GPT-5.5", description: "Frontier model for complex coding", contextWindowSize: 258400 },
49166
- { id: "gpt-5.4", label: "GPT-5.4", contextWindowSize: 258400 },
49167
- { id: "gpt-5.4-mini", label: "GPT-5.4-Mini", contextWindowSize: 258400 }
49168
- ];
49301
+ init_claude();
49169
49302
  var CODEX_EFFORTS = [
49170
49303
  { value: "low", label: "Low", description: "Fast responses with lighter reasoning" },
49171
49304
  { value: "medium", label: "Medium", description: "Balances speed and reasoning depth for everyday tasks" },
49172
49305
  { value: "high", label: "High", description: "Greater reasoning depth for complex problems" },
49173
- { value: "xhigh", label: "Extra high", description: "Extra high reasoning depth for complex problems" }
49306
+ { value: "xhigh", label: "Extra high", description: "Extra high reasoning depth for complex problems" },
49307
+ { value: "max", label: "Max", description: "Maximum reasoning depth for the hardest problems" },
49308
+ { value: "ultra", label: "Ultra", description: "Maximum reasoning with automatic task delegation" }
49174
49309
  ];
49175
49310
  var CODEX_APPROVAL_PRESETS = [
49176
49311
  { id: "untrusted", label: "Ask for approval", description: "\u51E0\u4E4E\u6BCF\u6761\u547D\u4EE4\u90FD\u95EE\u4F60\uFF08\u6700\u8C28\u614E\uFF09" },
49177
49312
  { id: "on-request", label: "Approve for me", description: "\u6A21\u578B\u81EA\u5DF1\u5224\u65AD\uFF0C\u53EA\u5BF9\u9AD8\u98CE\u9669\u64CD\u4F5C\u95EE\u4F60\uFF08\u9ED8\u8BA4\uFF09" },
49178
49313
  { id: "never", label: "Full Access", description: "\u4ECE\u4E0D\u8BE2\u95EE\uFF0C\u81EA\u4E3B\u6267\u884C" }
49179
49314
  ];
49180
- var CODEX_CAPABILITIES = {
49315
+ var CODEX_CAPABILITIES_BASE = {
49181
49316
  tool: "codex",
49182
49317
  toolSessionIdLabel: "Codex Thread ID",
49183
- models: CODEX_MODELS,
49184
49318
  permissionModes: CODEX_APPROVAL_PRESETS,
49185
49319
  // codex 不支持这些 clawd 功能(rewind 无 file-snapshot / 无子 agent / 无 TUI pty /
49186
49320
  // 无 observe 推送 / 无文件分享 / fork 是 claude jsonl 专用);UI 据此 gate 入口。
@@ -49191,7 +49325,8 @@ var CODEX_CAPABILITIES = {
49191
49325
  type: "select",
49192
49326
  label: "Model",
49193
49327
  scope: "core",
49194
- options: CODEX_MODELS.map((m2) => ({ value: m2.id, label: m2.label, description: m2.description })),
49328
+ options: [],
49329
+ // 运行时填充,见 buildCapabilities
49195
49330
  default: ""
49196
49331
  },
49197
49332
  {
@@ -49213,14 +49348,25 @@ var CODEX_CAPABILITIES = {
49213
49348
  }
49214
49349
  ]
49215
49350
  };
49351
+ function buildCapabilities(models) {
49352
+ return {
49353
+ ...CODEX_CAPABILITIES_BASE,
49354
+ models,
49355
+ configSchema: CODEX_CAPABILITIES_BASE.configSchema.map(
49356
+ (f) => f.name === "model" ? { ...f, options: models.map((m2) => ({ value: m2.id, label: m2.label, description: m2.description })) } : f
49357
+ )
49358
+ };
49359
+ }
49216
49360
  function sanitizeCodexModel(model) {
49217
49361
  if (model === void 0) return void 0;
49218
- return CODEX_MODELS.some((m2) => m2.id === model) ? model : void 0;
49362
+ if (CLAUDE_MODEL_IDS.includes(model)) return void 0;
49363
+ if (model.startsWith("claude-")) return void 0;
49364
+ return model;
49219
49365
  }
49220
49366
  async function probeCodex(env = process.env) {
49221
49367
  if (env.CODEX_BIN && import_node_fs18.default.existsSync(env.CODEX_BIN)) return { available: true, path: env.CODEX_BIN };
49222
49368
  try {
49223
- const out = (0, import_node_child_process5.execFileSync)("which", ["codex"], { encoding: "utf8" }).trim();
49369
+ const out = (0, import_node_child_process6.execFileSync)("which", ["codex"], { encoding: "utf8" }).trim();
49224
49370
  if (out && import_node_fs18.default.existsSync(out)) return { available: true, path: out };
49225
49371
  } catch {
49226
49372
  }
@@ -49233,10 +49379,16 @@ var CodexAdapter = class {
49233
49379
  probeCache = null;
49234
49380
  logger;
49235
49381
  probeOverride;
49382
+ queryOverride;
49383
+ // capabilities 的进程级 memo。**回落结果同样被缓存**——否则 codex 没装时每次开弹窗都
49384
+ // spawn 一次必然失败的子进程。代价是装好 codex 后要重启 daemon 才恢复,与「codex 升级后
49385
+ // 要重启才更新模型表」是同一条语义。
49386
+ capsPromise;
49236
49387
  constructor(opts = {}) {
49237
49388
  this.logger = opts.logger;
49238
49389
  this.probeOverride = opts.probeOverride;
49239
49390
  this.historyReader = opts.historyReader;
49391
+ this.queryOverride = opts.queryOverride;
49240
49392
  }
49241
49393
  async probe() {
49242
49394
  if (this.probeCache) return this.probeCache;
@@ -49244,10 +49396,25 @@ var CodexAdapter = class {
49244
49396
  return this.probeCache;
49245
49397
  }
49246
49398
  async capabilities() {
49247
- return CODEX_CAPABILITIES;
49399
+ if (!this.capsPromise) this.capsPromise = this.loadCapabilities();
49400
+ return this.capsPromise;
49248
49401
  }
49249
- resolveContextWindow(modelId) {
49250
- return (CODEX_MODELS.find((m2) => m2.id === (modelId ?? "")) ?? CODEX_MODELS[0]).contextWindowSize;
49402
+ async loadCapabilities() {
49403
+ try {
49404
+ const raw = this.queryOverride ? await this.queryOverride() : await queryCodexAppServer(process.cwd(), "model/list", {});
49405
+ return buildCapabilities(mapModelList(raw));
49406
+ } catch (err) {
49407
+ this.logger?.warn?.(
49408
+ `codex model/list failed, falling back to config.toml default only: ${err.message}`
49409
+ );
49410
+ return buildCapabilities([CODEX_DEFAULT_MODEL_ENTRY]);
49411
+ }
49412
+ }
49413
+ // 纯函数、无 IO。所有 codex 模型共用同一静态窗口值(model/list 不给 contextWindow),
49414
+ // 真实窗口由运行时 modelContextWindow 事件覆盖(doc/knowledge/codex-integration.md §6),
49415
+ // 所以这里不需要模型表。
49416
+ resolveContextWindow(_modelId) {
49417
+ return CODEX_CONTEXT_WINDOW;
49251
49418
  }
49252
49419
  createSession(ctx, sink) {
49253
49420
  return createCodexSession({ ...ctx, model: sanitizeCodexModel(ctx.model) }, sink, { logger: this.logger });
@@ -51381,7 +51548,7 @@ function buildPersonaDispatchHandlers(deps) {
51381
51548
  if (args.model !== void 0) {
51382
51549
  const targetPersona2 = args.targetPersona ?? (args.dispatchId ? deps.store.get(args.dispatchId)?.targetPersonaId : void 0);
51383
51550
  const targetTool = (targetPersona2 ? deps.getPersonaTool?.(targetPersona2) : void 0) ?? "claude";
51384
- const allowed = targetTool === "codex" ? CODEX_MODEL_IDS : CLAUDE_MODEL_IDS;
51551
+ const allowed = targetTool === "codex" ? ((await deps.getCapabilities?.("codex"))?.models ?? []).map((m2) => m2.id).filter((id) => id !== "") : CLAUDE_MODEL_IDS;
51385
51552
  if (!allowed.includes(args.model)) {
51386
51553
  throw new ClawdError(
51387
51554
  ERROR_CODES.INVALID_PARAM,
@@ -51784,8 +51951,6 @@ async function forwardPeerExecToPeer(args) {
51784
51951
  }
51785
51952
 
51786
51953
  // src/tools/codex-history.ts
51787
- var import_node_child_process6 = require("child_process");
51788
- var DEFAULT_TIMEOUT_MS2 = 8e3;
51789
51954
  function rec2(v2) {
51790
51955
  return v2 && typeof v2 === "object" && !Array.isArray(v2) ? v2 : void 0;
51791
51956
  }
@@ -51844,34 +52009,6 @@ function threadItemToHistoryMessages(item) {
51844
52009
  return [];
51845
52010
  }
51846
52011
  }
51847
- async function queryCodexAppServer(cwd, method, params, deps) {
51848
- const cmd = process.env.CODEX_BIN ?? "codex";
51849
- const args = ["app-server", "--listen", "stdio://"];
51850
- const proc = deps.spawnOverride ? deps.spawnOverride(cmd, args, cwd) : (0, import_node_child_process6.spawn)(cmd, args, { cwd, env: process.env, stdio: ["pipe", "pipe", "pipe"] });
51851
- const client = new CodexAppServerClient(proc, {});
51852
- const timeoutMs = deps.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
51853
- let timer;
51854
- const timeout = new Promise((_2, reject) => {
51855
- timer = setTimeout(() => reject(new Error(`codex app-server ${method} timed out after ${timeoutMs}ms`)), timeoutMs);
51856
- proc.on("error", (err) => reject(new Error(`codex app-server spawn failed: ${err.message}`)));
51857
- });
51858
- try {
51859
- await Promise.race([
51860
- (async () => {
51861
- await client.request("initialize", {
51862
- clientInfo: { name: "clawd", title: "clawd", version: "0" },
51863
- capabilities: null
51864
- });
51865
- client.notify("initialized", {});
51866
- })(),
51867
- timeout
51868
- ]);
51869
- return await Promise.race([client.request(method, params), timeout]);
51870
- } finally {
51871
- if (timer) clearTimeout(timer);
51872
- if (proc.exitCode === null && proc.signalCode === null) proc.kill("SIGTERM");
51873
- }
51874
- }
51875
52012
  var CodexHistoryReader = class {
51876
52013
  deps;
51877
52014
  constructor(deps = {}) {
@@ -51953,9 +52090,7 @@ var CodexHistoryReader = class {
51953
52090
  };
51954
52091
 
51955
52092
  // src/tools/codex-skills.ts
51956
- var import_node_child_process7 = require("child_process");
51957
52093
  var import_node_path27 = __toESM(require("path"), 1);
51958
- var DEFAULT_TIMEOUT_MS3 = 8e3;
51959
52094
  function str3(v2) {
51960
52095
  return typeof v2 === "string" ? v2 : void 0;
51961
52096
  }
@@ -51985,34 +52120,17 @@ function mapSkillsListResponse(res) {
51985
52120
  return out;
51986
52121
  }
51987
52122
  async function listCodexSkills(cwd, deps = {}) {
51988
- const cmd = process.env.CODEX_BIN ?? "codex";
51989
- const args = ["app-server", "--listen", "stdio://"];
51990
- const proc = deps.spawnOverride ? deps.spawnOverride(cmd, args, cwd) : (0, import_node_child_process7.spawn)(cmd, args, { cwd, env: process.env, stdio: ["pipe", "pipe", "pipe"] });
51991
- const client = new CodexAppServerClient(proc, {});
51992
- const timeoutMs = deps.timeoutMs ?? DEFAULT_TIMEOUT_MS3;
51993
- let timer;
51994
- const timeout = new Promise((_2, reject) => {
51995
- timer = setTimeout(() => reject(new Error(`codex app-server skills/list timed out after ${timeoutMs}ms`)), timeoutMs);
51996
- proc.on("error", (err) => reject(new Error(`codex app-server spawn failed: ${err.message}`)));
52123
+ const res = await queryCodexAppServer(cwd, "skills/list", { cwds: [cwd] }, {
52124
+ spawnOverride: deps.spawnOverride,
52125
+ timeoutMs: deps.timeoutMs,
52126
+ // skills parity:codex 不扫 .claude/skills/【实测 0.138.0】,persona 惯例装那里——
52127
+ // 先写 extraRoots 再写 list(stdio 按写入顺序处理,fire-and-forget 不 await 回包;
52128
+ // codex-session.ts ready 序列同款,两处保持一致)。失败不阻塞 list。
52129
+ beforeRequest: (client) => {
52130
+ void client.request("skills/extraRoots/set", { extraRoots: [import_node_path27.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
52131
+ }
51997
52132
  });
51998
- try {
51999
- await Promise.race([
52000
- (async () => {
52001
- await client.request("initialize", {
52002
- clientInfo: { name: "clawd", title: "clawd", version: "0" },
52003
- capabilities: null
52004
- });
52005
- client.notify("initialized", {});
52006
- })(),
52007
- timeout
52008
- ]);
52009
- void client.request("skills/extraRoots/set", { extraRoots: [import_node_path27.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
52010
- const res = await Promise.race([client.request("skills/list", { cwds: [cwd] }), timeout]);
52011
- return mapSkillsListResponse(res);
52012
- } finally {
52013
- if (timer) clearTimeout(timer);
52014
- if (proc.exitCode === null && proc.signalCode === null) proc.kill("SIGTERM");
52015
- }
52133
+ return mapSkillsListResponse(res);
52016
52134
  }
52017
52135
 
52018
52136
  // src/workspace/browser.ts
@@ -55079,7 +55197,7 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
55079
55197
  var import_node_fs38 = __toESM(require("fs"), 1);
55080
55198
  var import_node_path42 = __toESM(require("path"), 1);
55081
55199
  var import_node_crypto9 = __toESM(require("crypto"), 1);
55082
- var import_node_child_process10 = require("child_process");
55200
+ var import_node_child_process9 = require("child_process");
55083
55201
 
55084
55202
  // src/tunnel/tunnel-store.ts
55085
55203
  var import_node_fs35 = __toESM(require("fs"), 1);
@@ -55215,7 +55333,7 @@ function escape(v2) {
55215
55333
  var import_node_fs36 = __toESM(require("fs"), 1);
55216
55334
  var import_node_os13 = __toESM(require("os"), 1);
55217
55335
  var import_node_path40 = __toESM(require("path"), 1);
55218
- var import_node_child_process8 = require("child_process");
55336
+ var import_node_child_process7 = require("child_process");
55219
55337
  var import_node_stream3 = require("stream");
55220
55338
  var import_promises5 = require("stream/promises");
55221
55339
  var FRPC_VERSION = "0.68.0";
@@ -55315,7 +55433,7 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
55315
55433
  import_node_fs36.default.mkdirSync(work, { recursive: true });
55316
55434
  try {
55317
55435
  await new Promise((resolve6, reject) => {
55318
- const proc = (0, import_node_child_process8.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
55436
+ const proc = (0, import_node_child_process7.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
55319
55437
  proc.on("error", reject);
55320
55438
  proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
55321
55439
  });
@@ -55333,7 +55451,7 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
55333
55451
  // src/tunnel/frpc-process.ts
55334
55452
  var import_node_fs37 = __toESM(require("fs"), 1);
55335
55453
  var import_node_path41 = __toESM(require("path"), 1);
55336
- var import_node_child_process9 = require("child_process");
55454
+ var import_node_child_process8 = require("child_process");
55337
55455
  function frpcPidFilePath(dataDir) {
55338
55456
  return import_node_path41.default.join(dataDir, "frpc.pid");
55339
55457
  }
@@ -55419,7 +55537,7 @@ async function killStaleFrpc(deps) {
55419
55537
  async function defaultScanFrpcPidsByCmdline(tomlPath, logger) {
55420
55538
  if (process.platform === "win32") return [];
55421
55539
  return new Promise((resolve6) => {
55422
- const ps = (0, import_node_child_process9.spawn)("ps", ["-axo", "pid=,command="], { stdio: ["ignore", "pipe", "ignore"] });
55540
+ const ps = (0, import_node_child_process8.spawn)("ps", ["-axo", "pid=,command="], { stdio: ["ignore", "pipe", "ignore"] });
55423
55541
  let buf = "";
55424
55542
  ps.stdout.on("data", (c) => {
55425
55543
  buf += c.toString();
@@ -55588,7 +55706,7 @@ var TunnelManager = class {
55588
55706
  logLevel: "info"
55589
55707
  });
55590
55708
  await import_node_fs38.default.promises.writeFile(tomlPath, toml, { mode: 384 });
55591
- const proc = (this.deps.spawnImpl ?? import_node_child_process10.spawn)(frpcBin, ["-c", tomlPath], {
55709
+ const proc = (this.deps.spawnImpl ?? import_node_child_process9.spawn)(frpcBin, ["-c", tomlPath], {
55592
55710
  stdio: ["ignore", "pipe", "pipe"]
55593
55711
  });
55594
55712
  const logDir = import_node_path42.default.join(this.deps.dataDir, "log");
@@ -56080,11 +56198,11 @@ var DeviceBindingClientError = class extends Error {
56080
56198
  code;
56081
56199
  cause;
56082
56200
  };
56083
- var DEFAULT_TIMEOUT_MS4 = 8e3;
56201
+ var DEFAULT_TIMEOUT_MS2 = 8e3;
56084
56202
  async function upsertDeviceBinding(opts) {
56085
56203
  const doFetch = opts.fetchImpl ?? fetch;
56086
56204
  const ac = new AbortController();
56087
- const timer = setTimeout(() => ac.abort(), opts.timeoutMs ?? DEFAULT_TIMEOUT_MS4);
56205
+ const timer = setTimeout(() => ac.abort(), opts.timeoutMs ?? DEFAULT_TIMEOUT_MS2);
56088
56206
  const body = { unionId: opts.unionId };
56089
56207
  if (opts.avatarUrl != null) body.avatarUrl = opts.avatarUrl;
56090
56208
  let res;
@@ -56332,6 +56450,31 @@ function buildSessionHandlers(deps) {
56332
56450
  );
56333
56451
  return { response: { type: "session:info", ...response }, broadcast };
56334
56452
  };
56453
+ const importExternal = async (frame, _client, ctx) => {
56454
+ if (ctx && ctx.principal.kind !== "owner") {
56455
+ throw new ClawdError(
56456
+ ERROR_CODES.UNAUTHORIZED,
56457
+ `principal ${ctx.principal.kind}:${ctx.principal.id} cannot session:importExternal`
56458
+ );
56459
+ }
56460
+ const args = SessionImportExternalArgs.parse(frame);
56461
+ if (args.ownerPersonaId) {
56462
+ const persona = deps.personaRegistry.get(args.ownerPersonaId);
56463
+ if (!persona) {
56464
+ throw new Error(`persona not found: ${args.ownerPersonaId}`);
56465
+ }
56466
+ }
56467
+ const creatorPrincipalId = ctx?.principal.id ?? ownerPrincipalId;
56468
+ const creatorDisplayName = ctx?.principal.displayName ?? "Owner";
56469
+ const creatorFeishuUnionId = ctx?.principal.feishuUnionId;
56470
+ const { response, broadcast } = manager.importExternal(
56471
+ args,
56472
+ creatorPrincipalId,
56473
+ creatorDisplayName,
56474
+ creatorFeishuUnionId
56475
+ );
56476
+ return { response: { type: "session:info", ...response }, broadcast };
56477
+ };
56335
56478
  const list = async (frame, _client, ctx) => {
56336
56479
  const args = SessionListArgs.parse(frame ?? {});
56337
56480
  const narrow = (sessions) => {
@@ -56650,6 +56793,7 @@ function buildSessionHandlers(deps) {
56650
56793
  };
56651
56794
  return {
56652
56795
  "session:create": create,
56796
+ "session:importExternal": importExternal,
56653
56797
  "session:list": list,
56654
56798
  "session:get": get,
56655
56799
  "session:update": update,
@@ -56987,11 +57131,11 @@ init_protocol();
56987
57131
  init_protocol();
56988
57132
 
56989
57133
  // src/workspace/git.ts
56990
- var import_node_child_process11 = require("child_process");
57134
+ var import_node_child_process10 = require("child_process");
56991
57135
  var import_node_fs43 = __toESM(require("fs"), 1);
56992
57136
  var import_node_path48 = __toESM(require("path"), 1);
56993
57137
  var import_node_util = require("util");
56994
- var pexec = (0, import_node_util.promisify)(import_node_child_process11.execFile);
57138
+ var pexec = (0, import_node_util.promisify)(import_node_child_process10.execFile);
56995
57139
  function normalizePath(p2) {
56996
57140
  const resolved = import_node_path48.default.resolve(p2);
56997
57141
  try {
@@ -57738,6 +57882,7 @@ var METHOD_GRANT_MAP = {
57738
57882
  // dispatcher 不验资源,handler 内按 ctx + frame.args 反查 ownerPersonaId 调 assertGrant。
57739
57883
  // owner 自动通过(ctx 自带 '*':'admin' grant 一切 match);guest 在被授权 persona 内可调。
57740
57884
  "session:create": CAPABILITY_SCOPED,
57885
+ "session:importExternal": CAPABILITY_SCOPED,
57741
57886
  "session:list": CAPABILITY_SCOPED,
57742
57887
  "session:get": CAPABILITY_SCOPED,
57743
57888
  "session:update": CAPABILITY_SCOPED,
@@ -57929,7 +58074,7 @@ function computeMethodAccess(args) {
57929
58074
  }
57930
58075
 
57931
58076
  // src/version.ts
57932
- var version = "0.2.277".length > 0 ? "0.2.277" : "dev";
58077
+ var version = "0.2.279".length > 0 ? "0.2.279" : "dev";
57933
58078
 
57934
58079
  // src/cli-probe/probe.ts
57935
58080
  var fs54 = __toESM(require("fs"), 1);
@@ -58945,7 +59090,7 @@ function buildExtensionHandlers(deps) {
58945
59090
 
58946
59091
  // src/app-builder/project-store.ts
58947
59092
  var import_node_fs44 = require("fs");
58948
- var import_node_child_process12 = require("child_process");
59093
+ var import_node_child_process11 = require("child_process");
58949
59094
  var import_node_path55 = require("path");
58950
59095
  init_protocol();
58951
59096
  var PROJECTS_DIR = "projects";
@@ -59050,7 +59195,7 @@ var ProjectStore = class {
59050
59195
  async scaffold(name, templateSrcDir, scaffoldScriptPath) {
59051
59196
  const destDir = this.projectDir(name);
59052
59197
  return await new Promise((resolve6, reject) => {
59053
- const child = (0, import_node_child_process12.spawn)("bash", [scaffoldScriptPath, name, templateSrcDir, destDir], {
59198
+ const child = (0, import_node_child_process11.spawn)("bash", [scaffoldScriptPath, name, templateSrcDir, destDir], {
59054
59199
  env: { ...process.env, PATH: process.env.PATH ?? "" },
59055
59200
  stdio: ["ignore", "pipe", "pipe"]
59056
59201
  });
@@ -59154,7 +59299,7 @@ var ProjectStore = class {
59154
59299
  };
59155
59300
 
59156
59301
  // src/app-builder/kill-port.ts
59157
- var import_node_child_process13 = require("child_process");
59302
+ var import_node_child_process12 = require("child_process");
59158
59303
  async function killPortOccupants(port, ownedPids, logger) {
59159
59304
  let pids;
59160
59305
  try {
@@ -59196,7 +59341,7 @@ async function killPortOccupants(port, ownedPids, logger) {
59196
59341
  }
59197
59342
  function listPidsOnPort(port) {
59198
59343
  return new Promise((resolve6, reject) => {
59199
- (0, import_node_child_process13.execFile)(
59344
+ (0, import_node_child_process12.execFile)(
59200
59345
  "lsof",
59201
59346
  ["-ti", `:${port}`],
59202
59347
  { timeout: 3e3 },
@@ -59268,7 +59413,7 @@ var PublishJobRegistry = class {
59268
59413
  };
59269
59414
 
59270
59415
  // src/app-builder/publish-job-runner.ts
59271
- var import_node_child_process14 = require("child_process");
59416
+ var import_node_child_process13 = require("child_process");
59272
59417
  var import_node_fs45 = require("fs");
59273
59418
  var import_node_path56 = require("path");
59274
59419
 
@@ -59297,7 +59442,7 @@ function tailStderrLines(buf, n) {
59297
59442
  // src/app-builder/publish-job-runner.ts
59298
59443
  async function startPublishJob(deps, args) {
59299
59444
  const { registry: registry2, projectDir } = deps;
59300
- const spawn13 = deps.spawnImpl ?? import_node_child_process14.spawn;
59445
+ const spawn12 = deps.spawnImpl ?? import_node_child_process13.spawn;
59301
59446
  if (registry2.has(args.name)) {
59302
59447
  return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
59303
59448
  }
@@ -59309,7 +59454,7 @@ async function startPublishJob(deps, args) {
59309
59454
  } catch {
59310
59455
  logStream = null;
59311
59456
  }
59312
- const child = spawn13("bash", [args.scriptPath, projDir, args.personaRoot ?? ""], {
59457
+ const child = spawn12("bash", [args.scriptPath, projDir, args.personaRoot ?? ""], {
59313
59458
  cwd: projDir,
59314
59459
  env: process.env,
59315
59460
  stdio: ["ignore", "pipe", "pipe"]
@@ -60184,15 +60329,15 @@ var import_node_crypto17 = require("crypto");
60184
60329
  init_protocol();
60185
60330
 
60186
60331
  // src/peer-ops/run-command.ts
60187
- var import_node_child_process15 = require("child_process");
60332
+ var import_node_child_process14 = require("child_process");
60188
60333
  var import_node_os21 = __toESM(require("os"), 1);
60189
- var DEFAULT_TIMEOUT_MS5 = 3e4;
60334
+ var DEFAULT_TIMEOUT_MS3 = 3e4;
60190
60335
  var MAX_TIMEOUT_MS = 3e5;
60191
60336
  var MAX_OUTPUT_BYTES = 1048576;
60192
60337
  function runCommand(command, opts = {}) {
60193
- const timeoutMs = Math.min(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS5, MAX_TIMEOUT_MS);
60338
+ const timeoutMs = Math.min(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS3, MAX_TIMEOUT_MS);
60194
60339
  return new Promise((resolve6) => {
60195
- const child = (0, import_node_child_process15.spawn)("bash", ["-c", command], { cwd: import_node_os21.default.homedir() });
60340
+ const child = (0, import_node_child_process14.spawn)("bash", ["-c", command], { cwd: import_node_os21.default.homedir() });
60196
60341
  const out = [];
60197
60342
  const err = [];
60198
60343
  let outBytes = 0;
@@ -60407,7 +60552,7 @@ function buildMethodHandlers(deps) {
60407
60552
  }
60408
60553
 
60409
60554
  // src/app-builder/dev-server-supervisor.ts
60410
- var import_node_child_process16 = require("child_process");
60555
+ var import_node_child_process15 = require("child_process");
60411
60556
  var import_node_events2 = require("events");
60412
60557
  var DEFAULT_READY_PATTERN = /Local:\s+https?:\/\/|Nest application successfully started|server listening on/i;
60413
60558
  var DevServerSupervisor = class extends import_node_events2.EventEmitter {
@@ -60444,7 +60589,7 @@ var DevServerSupervisor = class extends import_node_events2.EventEmitter {
60444
60589
  tunnelHost: args.tunnelHost,
60445
60590
  devCommand: cmd
60446
60591
  });
60447
- const child = (0, import_node_child_process16.spawn)("sh", ["-c", cmd], {
60592
+ const child = (0, import_node_child_process15.spawn)("sh", ["-c", cmd], {
60448
60593
  cwd: args.cwd,
60449
60594
  env,
60450
60595
  stdio: "pipe",
@@ -60696,7 +60841,7 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
60696
60841
  }
60697
60842
 
60698
60843
  // src/extension/runtime.ts
60699
- var import_node_child_process17 = require("child_process");
60844
+ var import_node_child_process16 = require("child_process");
60700
60845
  var import_node_path60 = __toESM(require("path"), 1);
60701
60846
  var import_promises12 = require("timers/promises");
60702
60847
 
@@ -60804,7 +60949,7 @@ var Runtime = class {
60804
60949
  CLAWOS_EXT_PORT: String(port),
60805
60950
  CLAWOS_EXT_ID: extId
60806
60951
  };
60807
- const child = (0, import_node_child_process17.spawn)("sh", ["-c", cmd], {
60952
+ const child = (0, import_node_child_process16.spawn)("sh", ["-c", cmd], {
60808
60953
  cwd: dir,
60809
60954
  env,
60810
60955
  stdio: ["ignore", "pipe", "pipe"],
@@ -61908,8 +62053,10 @@ async function startDaemon(config) {
61908
62053
  },
61909
62054
  // B 角色:判断 targetPersona 是否 public(跨设备授权边界,private 拒)。
61910
62055
  getPersonaPublic: (personaId2) => personaRegistry.get(personaId2)?.public ?? false,
61911
- // model 校验按 target persona 绑定 tool 选表(claude / codex 模型集不同)
61912
- getPersonaTool: (personaId2) => personaRegistry.get(personaId2)?.tool
62056
+ // model 校验按 target persona 绑定 tool 选来源(claude / codex 模型集不同)
62057
+ getPersonaTool: (personaId2) => personaRegistry.get(personaId2)?.tool,
62058
+ // codex 模型表是运行时查 model/list 来的,校验必须问 capabilities(manager 侧有进程级缓存)
62059
+ getCapabilities: (tool) => manager.getCapabilities(tool)
61913
62060
  });
61914
62061
  Object.assign(handlers, dispatchHandlers);
61915
62062
  const shiftHandlers = buildShiftInternalHandlers({