@clawos-dev/clawd 0.2.249 → 0.2.251

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.
@@ -3227,8 +3227,8 @@ var require_utils = __commonJS({
3227
3227
  }
3228
3228
  return ind;
3229
3229
  }
3230
- function removeDotSegments(path2) {
3231
- let input = path2;
3230
+ function removeDotSegments(path4) {
3231
+ let input = path4;
3232
3232
  const output = [];
3233
3233
  let nextSlash = -1;
3234
3234
  let len = 0;
@@ -3480,8 +3480,8 @@ var require_schemes = __commonJS({
3480
3480
  wsComponent.secure = void 0;
3481
3481
  }
3482
3482
  if (wsComponent.resourceName) {
3483
- const [path2, query] = wsComponent.resourceName.split("?");
3484
- wsComponent.path = path2 && path2 !== "/" ? path2 : void 0;
3483
+ const [path4, query] = wsComponent.resourceName.split("?");
3484
+ wsComponent.path = path4 && path4 !== "/" ? path4 : void 0;
3485
3485
  wsComponent.query = query;
3486
3486
  wsComponent.resourceName = void 0;
3487
3487
  }
@@ -6874,12 +6874,12 @@ var require_dist = __commonJS({
6874
6874
  throw new Error(`Unknown format "${name}"`);
6875
6875
  return f;
6876
6876
  };
6877
- function addFormats(ajv, list, fs4, exportName) {
6877
+ function addFormats(ajv, list, fs6, exportName) {
6878
6878
  var _a;
6879
6879
  var _b;
6880
6880
  (_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
6881
6881
  for (const f of list)
6882
- ajv.addFormat(f, fs4[f]);
6882
+ ajv.addFormat(f, fs6[f]);
6883
6883
  }
6884
6884
  module2.exports = exports2 = formatsPlugin;
6885
6885
  Object.defineProperty(exports2, "__esModule", { value: true });
@@ -6895,7 +6895,7 @@ __export(mcp_server_exports, {
6895
6895
  handlePersonaDispatchToolCall: () => handlePersonaDispatchToolCall
6896
6896
  });
6897
6897
  module.exports = __toCommonJS(mcp_server_exports);
6898
- var import_node_fs3 = __toESM(require("fs"), 1);
6898
+ var import_node_fs5 = __toESM(require("fs"), 1);
6899
6899
 
6900
6900
  // ../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
6901
6901
  var external_exports = {};
@@ -7375,8 +7375,8 @@ function getErrorMap() {
7375
7375
 
7376
7376
  // ../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
7377
7377
  var makeIssue = (params) => {
7378
- const { data, path: path2, errorMaps, issueData } = params;
7379
- const fullPath = [...path2, ...issueData.path || []];
7378
+ const { data, path: path4, errorMaps, issueData } = params;
7379
+ const fullPath = [...path4, ...issueData.path || []];
7380
7380
  const fullIssue = {
7381
7381
  ...issueData,
7382
7382
  path: fullPath
@@ -7492,11 +7492,11 @@ var errorUtil;
7492
7492
 
7493
7493
  // ../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
7494
7494
  var ParseInputLazyPath = class {
7495
- constructor(parent, value, path2, key) {
7495
+ constructor(parent, value, path4, key) {
7496
7496
  this._cachedPath = [];
7497
7497
  this.parent = parent;
7498
7498
  this.data = value;
7499
- this._path = path2;
7499
+ this._path = path4;
7500
7500
  this._key = key;
7501
7501
  }
7502
7502
  get path() {
@@ -11133,10 +11133,10 @@ function assignProp(target, prop, value) {
11133
11133
  configurable: true
11134
11134
  });
11135
11135
  }
11136
- function getElementAtPath(obj, path2) {
11137
- if (!path2)
11136
+ function getElementAtPath(obj, path4) {
11137
+ if (!path4)
11138
11138
  return obj;
11139
- return path2.reduce((acc, key) => acc?.[key], obj);
11139
+ return path4.reduce((acc, key) => acc?.[key], obj);
11140
11140
  }
11141
11141
  function promiseAllObject(promisesObj) {
11142
11142
  const keys = Object.keys(promisesObj);
@@ -11456,11 +11456,11 @@ function aborted(x, startIndex = 0) {
11456
11456
  }
11457
11457
  return false;
11458
11458
  }
11459
- function prefixIssues(path2, issues) {
11459
+ function prefixIssues(path4, issues) {
11460
11460
  return issues.map((iss) => {
11461
11461
  var _a;
11462
11462
  (_a = iss).path ?? (_a.path = []);
11463
- iss.path.unshift(path2);
11463
+ iss.path.unshift(path4);
11464
11464
  return iss;
11465
11465
  });
11466
11466
  }
@@ -22708,7 +22708,12 @@ var DispatchOutcomeSchema = external_exports.discriminatedUnion("kind", [
22708
22708
  })
22709
22709
  ]);
22710
22710
  var DispatchRunArgsSchema = external_exports.object({
22711
- targetPersona: external_exports.string().min(1),
22711
+ // 新开必填;续派(dispatchId 非空)时可省略——targetPersonaId 从台账行取。
22712
+ targetPersona: external_exports.string().min(1).optional(),
22713
+ // 续派(spec 2026-07-21,单 dispatchId 语义:一件事一行一 id):非空 = 把 prompt
22714
+ // 作为新 turn 打进该 dispatch 的原 worker session 接着干(台账行复位 running)。
22715
+ // 省略 = 新开一件事,daemon 铸新 id。
22716
+ dispatchId: external_exports.string().min(1).optional(),
22712
22717
  prompt: external_exports.string(),
22713
22718
  // 跨设备 dispatch:非空 = A 角色,转发到该 contact deviceId 的 peer daemon;
22714
22719
  // 省略 = 本地 dispatch / B 角色本地执行。A 转发给 B 时 body 不带此字段。
@@ -22718,6 +22723,10 @@ var DispatchRunArgsSchema = external_exports.object({
22718
22723
  // tools/claude.ts CLAUDE_MODEL_IDS);handler 层做二次校验,非法值 fail-fast。
22719
22724
  // protocol 层保持 string 便于未来跨 tool 扩展(届时 union 收合法字面量)。
22720
22725
  model: external_exports.string().min(1).optional()
22726
+ }).refine((v) => v.targetPersona !== void 0 || v.dispatchId !== void 0, {
22727
+ message: "either targetPersona (new dispatch) or dispatchId (follow-up) is required"
22728
+ }).refine((v) => !(v.dispatchId !== void 0 && v.targetDeviceId !== void 0), {
22729
+ message: "cross-device dispatch cannot be continued (dispatchId + targetDeviceId are mutually exclusive)"
22721
22730
  });
22722
22731
  var DispatchCompleteArgsSchema = external_exports.object({
22723
22732
  dispatchId: external_exports.string().min(1),
@@ -22895,11 +22904,11 @@ Diff.prototype = {
22895
22904
  }
22896
22905
  }
22897
22906
  },
22898
- addToPath: function addToPath(path2, added, removed, oldPosInc, options) {
22899
- var last = path2.lastComponent;
22907
+ addToPath: function addToPath(path4, added, removed, oldPosInc, options) {
22908
+ var last = path4.lastComponent;
22900
22909
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
22901
22910
  return {
22902
- oldPos: path2.oldPos + oldPosInc,
22911
+ oldPos: path4.oldPos + oldPosInc,
22903
22912
  lastComponent: {
22904
22913
  count: last.count + 1,
22905
22914
  added,
@@ -22909,7 +22918,7 @@ Diff.prototype = {
22909
22918
  };
22910
22919
  } else {
22911
22920
  return {
22912
- oldPos: path2.oldPos + oldPosInc,
22921
+ oldPos: path4.oldPos + oldPosInc,
22913
22922
  lastComponent: {
22914
22923
  count: 1,
22915
22924
  added,
@@ -23404,6 +23413,80 @@ var CLAUDE_CAPABILITIES = {
23404
23413
  ]
23405
23414
  };
23406
23415
 
23416
+ // src/tools/codex.ts
23417
+ var import_node_child_process5 = require("child_process");
23418
+ var import_node_fs4 = __toESM(require("fs"), 1);
23419
+
23420
+ // src/tools/codex-session.ts
23421
+ var import_node_child_process4 = require("child_process");
23422
+ var import_node_path3 = __toESM(require("path"), 1);
23423
+
23424
+ // src/tools/codex-app-server-client.ts
23425
+ var import_node_readline = require("readline");
23426
+
23427
+ // src/tools/codex-mcp-config.ts
23428
+ var import_node_fs3 = __toESM(require("fs"), 1);
23429
+ var import_node_path2 = __toESM(require("path"), 1);
23430
+
23431
+ // src/tools/codex-features.ts
23432
+ var import_node_child_process3 = require("child_process");
23433
+
23434
+ // src/tools/codex.ts
23435
+ var CODEX_MODEL_IDS = ["gpt-5.5", "gpt-5.4", "gpt-5.4-mini"];
23436
+ var CODEX_MODELS = [
23437
+ { id: "", label: "Default", description: "codex config.toml \u9ED8\u8BA4", contextWindowSize: 258400, default: true },
23438
+ { id: "gpt-5.5", label: "GPT-5.5", description: "Frontier model for complex coding", contextWindowSize: 258400 },
23439
+ { id: "gpt-5.4", label: "GPT-5.4", contextWindowSize: 258400 },
23440
+ { id: "gpt-5.4-mini", label: "GPT-5.4-Mini", contextWindowSize: 258400 }
23441
+ ];
23442
+ var CODEX_EFFORTS = [
23443
+ { value: "low", label: "Low", description: "Fast responses with lighter reasoning" },
23444
+ { value: "medium", label: "Medium", description: "Balances speed and reasoning depth for everyday tasks" },
23445
+ { value: "high", label: "High", description: "Greater reasoning depth for complex problems" },
23446
+ { value: "xhigh", label: "Extra high", description: "Extra high reasoning depth for complex problems" }
23447
+ ];
23448
+ var CODEX_APPROVAL_PRESETS = [
23449
+ { id: "untrusted", label: "Ask for approval", description: "\u51E0\u4E4E\u6BCF\u6761\u547D\u4EE4\u90FD\u95EE\u4F60\uFF08\u6700\u8C28\u614E\uFF09" },
23450
+ { 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" },
23451
+ { id: "never", label: "Full Access", description: "\u4ECE\u4E0D\u8BE2\u95EE\uFF0C\u81EA\u4E3B\u6267\u884C" }
23452
+ ];
23453
+ var CODEX_CAPABILITIES = {
23454
+ tool: "codex",
23455
+ toolSessionIdLabel: "Codex Thread ID",
23456
+ models: CODEX_MODELS,
23457
+ permissionModes: CODEX_APPROVAL_PRESETS,
23458
+ // codex 不支持这些 clawd 功能(rewind 无 file-snapshot / 无子 agent / 无 TUI pty /
23459
+ // 无 observe 推送 / 无文件分享 / fork 是 claude jsonl 专用);UI 据此 gate 入口。
23460
+ features: { rewind: false, subagents: false, tui: false, observe: false, fileSharing: false, fork: false },
23461
+ configSchema: [
23462
+ {
23463
+ name: "model",
23464
+ type: "select",
23465
+ label: "Model",
23466
+ scope: "core",
23467
+ options: CODEX_MODELS.map((m) => ({ value: m.id, label: m.label, description: m.description })),
23468
+ default: ""
23469
+ },
23470
+ {
23471
+ name: "permissionMode",
23472
+ type: "select",
23473
+ label: "Approval",
23474
+ scope: "core",
23475
+ options: CODEX_APPROVAL_PRESETS.map((m) => ({ value: m.id, label: m.label, description: m.description })),
23476
+ default: "on-request"
23477
+ },
23478
+ {
23479
+ name: "effort",
23480
+ type: "select",
23481
+ label: "Reasoning effort",
23482
+ scope: "tool-specific",
23483
+ // 渲染在 Advanced 区(与 claude effort 一致)
23484
+ options: CODEX_EFFORTS,
23485
+ default: "medium"
23486
+ }
23487
+ ]
23488
+ };
23489
+
23407
23490
  // src/dispatch/mcp-server.ts
23408
23491
  var DISPATCH_LOG = process.env.CLAWD_DISPATCH_LOG;
23409
23492
  function log(msg, info) {
@@ -23411,7 +23494,7 @@ function log(msg, info) {
23411
23494
  `;
23412
23495
  if (DISPATCH_LOG) {
23413
23496
  try {
23414
- import_node_fs3.default.appendFileSync(DISPATCH_LOG, line);
23497
+ import_node_fs5.default.appendFileSync(DISPATCH_LOG, line);
23415
23498
  return;
23416
23499
  } catch {
23417
23500
  }
@@ -23425,6 +23508,7 @@ async function handlePersonaDispatchToolCall(input, ctx) {
23425
23508
  const f = ctx.fetch ?? fetch;
23426
23509
  log("personaDispatch tool entered", {
23427
23510
  targetPersona: input.targetPersona,
23511
+ dispatchId: input.dispatchId,
23428
23512
  promptLen: input.prompt.length,
23429
23513
  sessionId: ctx.sessionId,
23430
23514
  daemonUrl: ctx.daemonUrl
@@ -23452,8 +23536,11 @@ async function handlePersonaDispatchToolCall(input, ctx) {
23452
23536
  "x-clawd-session-id": ctx.sessionId
23453
23537
  },
23454
23538
  body: JSON.stringify({
23455
- targetPersona: input.targetPersona,
23539
+ // 续派时可省 targetPersona(daemon 从台账取)
23540
+ ...input.targetPersona ? { targetPersona: input.targetPersona } : {},
23456
23541
  prompt: input.prompt,
23542
+ // 续派(spec 2026-07-21):非空 = 把 prompt 打进该 dispatch 的原 worker session。
23543
+ ...input.dispatchId ? { dispatchId: input.dispatchId } : {},
23457
23544
  // 跨设备:非空时透传,daemon run handler 据此走 A 角色转发分支。
23458
23545
  ...input.targetDeviceId ? { targetDeviceId: input.targetDeviceId } : {},
23459
23546
  // T-20: 可选 override B session 使用的 claude 模型;MCP tool 层已 enum 校验,
@@ -23487,12 +23574,13 @@ async function handlePersonaDispatchToolCall(input, ctx) {
23487
23574
  };
23488
23575
  }
23489
23576
  const dispatchId = json.result.dispatchId;
23490
- log("personaDispatch submitted", { dispatchId });
23577
+ log("personaDispatch submitted", { dispatchId, followUp: Boolean(input.dispatchId) });
23578
+ const head = input.dispatchId ? `Follow-up sent for dispatch ${dispatchId} \u2014 the new instruction was delivered into the same worker session.` : `Task dispatched to ${input.targetPersona} (dispatchId=${dispatchId}).`;
23491
23579
  return {
23492
23580
  content: [
23493
23581
  {
23494
23582
  type: "text",
23495
- text: `Task dispatched to ${input.targetPersona} (dispatchId=${dispatchId}). The result will be delivered back into this session when the target persona finishes \u2014 you do NOT need to wait or poll. Tell the user the task has been delegated and end your turn. Use personaDispatchList only if the user later asks about progress.`
23583
+ text: `${head} The result will be delivered back into this session when the target persona finishes \u2014 you do NOT need to wait or poll. Tell the user the task has been delegated and end your turn. Use personaDispatchList only if the user later asks about progress.`
23496
23584
  }
23497
23585
  ]
23498
23586
  };
@@ -23619,9 +23707,14 @@ async function main() {
23619
23707
  "personaDispatch",
23620
23708
  {
23621
23709
  title: "Dispatch task to another persona",
23622
- description: "Delegate a task to another clawd persona. Use this when the user message contains `@persona/<id>` to hand the task off to that persona. Returns immediately with a dispatchId; the result will be delivered back into your session automatically when the target persona finishes \u2014 do not wait or poll. Use personaDispatchList to check progress if asked.",
23710
+ description: "Delegate a task to another clawd persona. Use this when the user message contains `@persona/<id>` to hand the task off to that persona. Returns immediately with a dispatchId; the result will be delivered back into your session automatically when the target persona finishes \u2014 do not wait or poll. To continue an existing dispatched task (follow-up instruction into the same worker session), pass its dispatchId and omit targetPersona. Use personaDispatchList to check progress if asked.",
23623
23711
  inputSchema: {
23624
- targetPersona: external_exports.string().describe("persona id (e.g. persona-app-builder)"),
23712
+ targetPersona: external_exports.string().optional().describe(
23713
+ "persona id (e.g. persona-app-builder); omit when continuing an existing dispatch via dispatchId"
23714
+ ),
23715
+ dispatchId: external_exports.string().optional().describe(
23716
+ "continue an existing dispatched task: the prompt is delivered into the same worker session as a new turn (context preserved); model cannot be changed on follow-up (the worker session keeps its original model)"
23717
+ ),
23625
23718
  prompt: external_exports.string().describe(
23626
23719
  "the task to perform, with the @persona/<id> token stripped out"
23627
23720
  ),
@@ -23629,9 +23722,10 @@ async function main() {
23629
23722
  "contact deviceId of the remote device when delegating cross-device (omit for a local persona)"
23630
23723
  ),
23631
23724
  // T-20: dispatch model override. Enum 走 MCP tool JSON schema 硬约束,
23632
- // caller LLM 只能从可选值挑,避免瞎填历史模型名。
23633
- model: external_exports.enum(CLAUDE_MODEL_IDS).optional().describe(
23634
- "override the target persona's default claude model. Omit to use the persona default. Allowed: " + CLAUDE_MODEL_IDS.join(" / ") + "."
23725
+ // caller LLM 只能从可选值挑,避免瞎填历史模型名。claude / codex 两表 union——
23726
+ // 精确校验(按 target persona tool 选表)在 daemon handler 层做(fail-fast)。
23727
+ model: external_exports.enum([...CLAUDE_MODEL_IDS, ...CODEX_MODEL_IDS]).optional().describe(
23728
+ "override the target persona's default model. Omit to use the persona default. Claude personas: " + CLAUDE_MODEL_IDS.join(" / ") + ". Codex personas: " + CODEX_MODEL_IDS.join(" / ") + "."
23635
23729
  )
23636
23730
  }
23637
23731
  },
@@ -290,7 +290,7 @@ await app.listen(Number(process.env.CLAWD_PREVIEW_PORT));
290
290
  - 引入新数据表 / 迁移 / 新接口 / 新认证流程
291
291
  - 预估 ≥ 3 个非平凡步骤
292
292
 
293
- **简单任务(TodoWrite 跟踪即可)**:单文件改动、文案/样式/配置调整、删 dead code、单点 bug 修复。
293
+ **简单任务(TodoWrite 跟踪即可;codex 会话没有 TodoWrite,用内置 plan 工具同样效果)**:单文件改动、文案/样式/配置调整、删 dead code、单点 bug 修复。
294
294
 
295
295
  判不准时倾向走 superpowers。
296
296
 
@@ -21,9 +21,12 @@ clawd daemon 启动 / 刷新时扫 `~/.clawd/personas/`,凡是含 `.clawd/pers
21
21
  ~/.clawd/personas/<persona-id>/
22
22
  .clawd/
23
23
  persona.json # 元信息(必需)
24
- sandbox-settings.json # 沙箱配置(必需,用 daemon 默认模板原样)
24
+ sandbox-settings.json # 沙箱配置(必需,用 daemon 默认模板原样,claude 会话用)
25
+ codex-sandbox.json # codex 沙箱配置(可不写,daemon 启动 migrate 会补默认断网版)
25
26
  CLAUDE.md # 人设(必需)
26
- .claude/skills/ # 可选,老板要装的 skill 会在这里
27
+ AGENTS.md # 人设镜像(必需,内容与 CLAUDE.md 完全一致——claude 读
28
+ # CLAUDE.md、codex 读 AGENTS.md,写完 CLAUDE.md 原样复制一份)
29
+ .claude/skills/ # 可选,老板要装的 skill 会在这里(两种 agent 都认这个目录)
27
30
  ```
28
31
 
29
32
  # 工作流(轻互动模式,默认)
@@ -98,7 +101,7 @@ mkdir -p ~/.clawd/personas/$ID/.clawd || { echo "sandbox 拦了,需要 owner
98
101
 
99
102
  **`CLAUDE.md`** —— 人格文件,这是真正的"灵魂"。**风格灵活**,每个 persona 应该长得不一样,按老板需求 / 你对人设的理解写。但保底要有这几块:
100
103
 
101
- 1. **第一句**:定位("你是老板的 xxx 助手"),让任何打开它的 Claude Code 一秒进入角色
104
+ 1. **第一句**:定位("你是老板的 xxx 助手"),让任何打开它的 agent(Claude Code / Codex)一秒进入角色
102
105
  2. **何时找它**:trigger 场景(老板会在什么情况下切到这个 persona)
103
106
  3. **工作方式 / 边界**:它该做什么、不做什么;该问还是该先做;有没有红线
104
107
  4. **行为规范**:跟老板对话的风格(简洁 vs 详细、是否质疑老板的判断、要不要解释思路)
@@ -66,7 +66,7 @@ clawd 的 OwnerProfile 是 `~/.clawd/profile.json`,schema v1 只有一个字
66
66
  - **clawos 仓库本地路径**:<absolute-path>
67
67
  ```
68
68
 
69
- 这样下次会话 Claude Code 加载 CLAUDE.md 时会直接看到这条,不必再探测/问。
69
+ 这样下次会话 agent 加载人格文件(Claude Code CLAUDE.md / Codex 读 AGENTS.md,clawd 双写保持一致)时会直接看到这条,不必再探测/问。
70
70
 
71
71
  两步都跑完后简短确认一下,进入正常工作。
72
72
 
@@ -106,7 +106,7 @@ clawd 的 OwnerProfile 是 `~/.clawd/profile.json`,schema v1 只有一个字
106
106
 
107
107
  老板问"clawd 是什么 / 有什么亮点 / 我能拿它做什么"时,对着下面讲,按相关度挑 3-5 条即可,不用全列。每条都是**用户能直接感知**的功能,不是内部机制。
108
108
 
109
- clawd 一句话:**它是 ClawOS 里的一个 Extension —— 在 ClawOS 桌面端装上 clawd 之后,您的 Claude Code 就长出多个"AI 助手分身",能用、能分享、能远程接,每个分身都有自己的记忆和性格。**
109
+ clawd 一句话:**它是 ClawOS 里的一个 Extension —— 在 ClawOS 桌面端装上 clawd 之后,您的 AI 编码助手(Claude Code / Codex 都支持)就长出多个"AI 助手分身",能用、能分享、能远程接,每个分身都有自己的记忆和性格。**
110
110
 
111
111
  亮点清单:
112
112
 
@@ -114,7 +114,7 @@ clawd 一句话:**它是 ClawOS 里的一个 Extension —— 在 ClawOS 桌
114
114
  2. **多个 AI 助手并存** —— 您可以自己再创建任意多个 AI 助手(每个叫一个 persona),每个有不同的性格、工作记忆、技能包,互相不串台
115
115
  3. **把助手分享给朋友** —— 一键给某个助手生成"邀请码",朋友拿这个码就能连进来跟它聊天;朋友只能在助手的小房间里活动,碰不到您电脑上其他文件(操作系统级隔离)
116
116
  4. **每个朋友一份独立对话** —— 朋友 A 和朋友 B 即使用同一个助手聊,对话历史也是各自一份,互相看不到
117
- 5. **远程接入您的本机 AI** —— 一行命令开一条公网隧道,您手机上、外网都能连回家里电脑的 Claude Code,不用部署服务器
117
+ 5. **远程接入您的本机 AI** —— 一行命令开一条公网隧道,您手机上、外网都能连回家里电脑的 AI 助手,不用部署服务器
118
118
  6. **临时借身份**(`@persona/xxx`) —— 当前对话里想让另一个助手客串一句话,输入框 `@` 一下选它,不用切会话
119
119
  7. **对话能分叉 / 回滚** —— 任何一条 AI 的回答都能 fork 出新会话分支,或者把会话回滚到之前某一步重来
120
120
  8. **助手按需装技能包** —— 每个助手第一次会话会引导您一键装它需要的技能(比如「调研员」引导装 deep-research,「知识库管理员」引导装 karpathy-llm-wiki,「飞书助理」引导装 larksuite/cli 整套 24 个 skill),走标准 skills 渠道、可独立升级,您也可以给自己建的助手装 skill
@@ -88,7 +88,7 @@ cd ~/.clawd/personas/persona-feishu-assistant
88
88
  npx skills add larksuite/cli -a claude-code --copy -y
89
89
  ```
90
90
 
91
- `-a claude-code --copy` 让 25 个 skill 直接拷到 `.claude/skills/` 下,不走 `.agents/skills/` 这条 universal canonical 路径 —— Claude Code 原生只识别 `.claude/skills/`,这样 persona 目录最干净。只有这个 persona 看得见。
91
+ `-a claude-code --copy` 让 25 个 skill 直接拷到 `.claude/skills/` 下,不走 `.agents/skills/` 这条 universal canonical 路径 —— persona 目录最干净,且 clawd 对两种 agent 都认这个目录(claude 原生识别;codex 会话由 daemon 注入 extraRoots 同样识别)。只有这个 persona 看得见。
92
92
 
93
93
  装完 `ls .claude/skills/` 应该能看到 `lark-shared` / `lark-calendar` / `lark-im` 等 25 项。
94
94