larkway 0.3.11 → 0.3.13

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/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  You @ the bot in a Feishu thread. It runs on your machine — reading your real codebase, executing commands, opening MRs — and posts the result back. You define what the agent knows and what it can do. Larkway just carries the messages.
10
10
 
11
- **Current release: v0.3.11**
11
+ **Current release: v0.3.13**
12
12
 
13
13
  ---
14
14
 
package/README.zh.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  你在飞书话题里 @ bot,它在你的机器上运行——读真实代码库、执行命令、开 MR——把结果贴回飞书。你定义 agent 知道什么、能做什么。Larkway 只负责传递消息。
10
10
 
11
- **当前版本:v0.3.11**
11
+ **当前版本:v0.3.13**
12
12
 
13
13
  ---
14
14
 
package/dist/cli/index.js CHANGED
@@ -120481,6 +120481,7 @@ function renderAgentsMd(input) {
120481
120481
  "",
120482
120482
  "## Workspace Contract",
120483
120483
  "",
120484
+ "- \u5F00\u573A\u4E0D\u53EF\u8DF3\u8FC7:\u56DE\u5E94 owner \u524D,\u5148 Read `memory/index.md`,\u5E76\u6309\u76F8\u5173\u6027 Read \u76F8\u5173 category \u6587\u4EF6,\u518D\u5F00\u59CB\u5E72\u6D3B(\u9632\u6B62\u65B0 session \u5931\u5FC6)\u3002",
120484
120485
  "- Larkway is a thin Feishu bridge. It passes scene/context pointers; you decide what to inspect and what work to do.",
120485
120486
  "- Each Feishu topic is one task session under `sessions/<thread_id>/`.",
120486
120487
  "- Keep durable notes, repo clones, session summaries, and permission decisions inside this workspace.",
@@ -120800,6 +120801,75 @@ async function ensureAgentWorkspace(input) {
120800
120801
  path7.join(input.workspacePath, "permissions-granted.md"),
120801
120802
  renderPermissionsGranted(input)
120802
120803
  );
120804
+ await ensureMemoryScaffold(input.workspacePath);
120805
+ }
120806
+ var MEMORY_CATEGORY_FILES = [
120807
+ {
120808
+ name: "preferences.md",
120809
+ title: "Owner Preferences",
120810
+ purpose: "owner \u6216\u56E2\u961F\u957F\u671F\u504F\u597D(\u6C47\u62A5\u683C\u5F0F\u3001\u9ED8\u8BA4\u8BED\u8A00\u3001\u9A8C\u8BC1\u504F\u597D\u7B49)\u3002"
120811
+ },
120812
+ {
120813
+ name: "reusable-knowledge.md",
120814
+ title: "Reusable Knowledge",
120815
+ purpose: "\u591A\u4E2A session \u540E\u6C89\u6DC0\u51FA\u7684\u53EF\u590D\u7528\u7ECF\u9A8C\u3001\u5E38\u89C1\u5751\u3001\u65B9\u6848\u5224\u65AD\u3002"
120816
+ },
120817
+ {
120818
+ name: "workflows.md",
120819
+ title: "Workflows",
120820
+ purpose: "\u8FD9\u4E2A Agent \u81EA\u5DF1\u7684\u957F\u671F\u5DE5\u4F5C\u65B9\u5F0F(\u9879\u76EE repo \u7684\u5DE5\u7A0B\u89C4\u8303\u4ECD\u5199\u8FDB\u9879\u76EE repo)\u3002"
120821
+ },
120822
+ {
120823
+ name: "decisions.md",
120824
+ title: "Decisions",
120825
+ purpose: "\u957F\u671F\u51B3\u7B56\u8BB0\u5F55,\u4F8B\u5982\u4E3A\u4EC0\u4E48\u67D0\u6743\u9650\u5FC5\u987B\u4EBA\u5DE5\u786E\u8BA4\u3002"
120826
+ },
120827
+ {
120828
+ name: "assets.md",
120829
+ title: "Assets",
120830
+ purpose: "\u957F\u671F\u56FE\u7247/\u622A\u56FE/\u9644\u4EF6\u7684\u7D22\u5F15,\u53EA\u8BB0\u5F15\u7528\u548C\u7528\u9014,\u4E0D\u5185\u8054\u5927\u6587\u4EF6(\u5B9E\u4F53\u653E assets/)\u3002"
120831
+ }
120832
+ ];
120833
+ function renderMemoryIndex() {
120834
+ return [
120835
+ "# Memory Index",
120836
+ "",
120837
+ "\u8FD9\u662F\u8DE8 session \u957F\u671F\u8BB0\u5FC6\u3002\u65B0 session \u8D77\u624B\u5148\u8BFB\u8FD9\u91CC,\u628A\u8FC7\u5F80\u79EF\u7D2F\u62C9\u8D77\u6765\u3002",
120838
+ "Larkway \u53EA\u521D\u59CB\u5316\u7A7A\u5BB9\u5668;\u63D0\u70BC\u3001\u5206\u7C7B\u3001\u5199\u5165\u6B63\u6587\u90FD\u7531\u4F60(Agent)\u5728 owner \u786E\u8BA4\u540E\u5B8C\u6210\u3002",
120839
+ "",
120840
+ "## \u5206\u7C7B\u6587\u4EF6",
120841
+ "",
120842
+ ...MEMORY_CATEGORY_FILES.map((f) => `- \`${f.name}\` \u2014 ${f.purpose}`),
120843
+ "",
120844
+ "## \u7EF4\u62A4\u89C4\u5219",
120845
+ "",
120846
+ "- \u70ED\u8DEF\u5F84(\u6BCF\u8F6E)\u53EA\u505A\u52A0\u6CD5:\u628A\u5019\u9009\u5199\u8FDB session \u7684 `memory-candidates.md`,\u6216\u5F80 category \u6587\u4EF6\u8FFD\u52A0\u65B0\u6761\u76EE;\u4E0D\u5728\u70ED\u8DEF\u5F84\u6539\u5199/\u5220\u9664\u5DF2\u6709\u6761\u76EE\u3002",
120847
+ "- \u6539\u5199\u3001\u5220\u9664\u3001\u89E3\u51B3\u51B2\u7A81 \u2192 \u63A8\u8FDF\u5230 owner \u663E\u5F0F\u8BF4\u300C\u6574\u7406\u8BB0\u5FC6\u300D\u65F6\u79BB\u7EBF\u505A\u3002UPDATE/DELETE \u7684\u65E7\u6761\u76EE\u79FB `archive/`(\u6CE8\u4E00\u53E5\u539F\u56E0+\u5BF9\u5E94 commit),\u4E0D\u624B\u5199 superseded \u6233,\u4E0D\u7269\u7406\u5220;archive/ \u7684\u957F\u671F\u6E05\u7406\u4EA4\u7ED9 git history\u3002",
120848
+ "- \u88C1\u51B3\u4EE5 source \u4F18\u5148:user \u4EB2\u53E3\u8BF4\u7684 >> agent \u63A8\u65AD;\u51B2\u7A81\u65F6\u4FDD\u7559\u65E7\u7684 user \u6761\u76EE,\u628A\u65B0\u63A8\u65AD\u964D\u7EA7\u4E3A candidate\u3002\u540C source \u5185 recency \u4EE5 git \u5386\u53F2\u4E3A\u51C6,\u4E0D\u624B\u5199\u65E5\u671F\u6233\u3002",
120849
+ "- \u53EA\u6709\u8DE8 session \u8FD8\u4F1A\u7528\u5230\u7684\u624D\u8FDB\u8FD9\u91CC(\u5355\u6B21\u4EFB\u52A1\u7559\u5728 session summary)\u3002\u672C\u6587\u4EF6\u4FDD\u6301\u7B80\u77ED(\u2264~50 \u884C),\u4E0D\u653E changelog/\u7EDF\u8BA1\u3002",
120850
+ ""
120851
+ ].join("\n");
120852
+ }
120853
+ function renderMemoryCategorySkeleton(title) {
120854
+ return [
120855
+ `# ${title}`,
120856
+ "",
120857
+ "\u5199\u524D\u5148\u8BFB\u672C\u6587\u4EF6;\u6709\u76F8\u540C/\u76F8\u5173\u6761\u76EE\u5C31 NOOP \u4E0D\u91CD\u590D\u5199(\u6539\u5199\u3001\u5220\u9664\u3001\u79FB archive \u7559\u5230 owner \u8BF4\u300C\u6574\u7406\u8BB0\u5FC6\u300D\u65F6\u7684\u79BB\u7EBF\u6B65\u9AA4);\u4FE1\u53F7\u4E0D\u8DE8 session \u590D\u7528\u5C31\u4E0D\u5199\u3002",
120858
+ ""
120859
+ ].join("\n");
120860
+ }
120861
+ async function ensureMemoryScaffold(workspacePath) {
120862
+ const memoryDir = path7.join(workspacePath, "memory");
120863
+ await fs.mkdir(memoryDir, { recursive: true });
120864
+ await fs.mkdir(path7.join(memoryDir, "assets"), { recursive: true });
120865
+ await fs.mkdir(path7.join(memoryDir, "archive"), { recursive: true });
120866
+ await writeIfMissing(path7.join(memoryDir, "index.md"), renderMemoryIndex());
120867
+ for (const file of MEMORY_CATEGORY_FILES) {
120868
+ await writeIfMissing(
120869
+ path7.join(memoryDir, file.name),
120870
+ renderMemoryCategorySkeleton(file.title)
120871
+ );
120872
+ }
120803
120873
  }
120804
120874
 
120805
120875
  // src/cli/commands/init.ts
package/dist/main.js CHANGED
@@ -113270,6 +113270,9 @@ function senderOpenIdOf(senderId) {
113270
113270
  return "";
113271
113271
  }
113272
113272
 
113273
+ // src/claude/prompt.ts
113274
+ import { readFileSync as readFileSync2 } from "node:fs";
113275
+
113273
113276
  // src/agent/triggerFacts.ts
113274
113277
  function stringField2(value) {
113275
113278
  return typeof value === "string" && value.length > 0 ? value : void 0;
@@ -113306,6 +113309,23 @@ function deriveTriggerFacts(parsed, isNewThread, larkCliProfile) {
113306
113309
  }
113307
113310
 
113308
113311
  // src/claude/prompt.ts
113312
+ var MEMORY_CATEGORY_FILE_NAMES = [
113313
+ "preferences.md",
113314
+ "reusable-knowledge.md",
113315
+ "workflows.md",
113316
+ "decisions.md",
113317
+ "assets.md"
113318
+ ];
113319
+ var MEMORY_FILE_LINE_LIMIT = 200;
113320
+ function statMemoryLines(filePath) {
113321
+ try {
113322
+ const text = readFileSync2(filePath, "utf8");
113323
+ if (text.length === 0) return 0;
113324
+ return (text.match(/\n/g)?.length ?? 0) + (text.endsWith("\n") ? 0 : 1);
113325
+ } catch {
113326
+ return 0;
113327
+ }
113328
+ }
113309
113329
  function csv(items) {
113310
113330
  return items.length > 0 ? items.join(",") : "(none)";
113311
113331
  }
@@ -113427,6 +113447,8 @@ function renderWorkspaceBlock(primarySlug, primaryCachePath, defaultBranch, extr
113427
113447
  }
113428
113448
  function renderAgentWorkspaceBlock(conventions, extraRepos) {
113429
113449
  const summaryFilePath = conventions.workspaceSessionPath ? `${conventions.workspaceSessionPath}/summary.md` : void 0;
113450
+ const memoryDir = conventions.agentWorkspacePath ? `${conventions.agentWorkspacePath}/memory` : void 0;
113451
+ const memoryIndex = memoryDir ? `${memoryDir}/index.md` : void 0;
113430
113452
  const lines = [
113431
113453
  "<agent-workspace>",
113432
113454
  "Larkway \u662F thin bridge:\u5B83\u53EA\u628A\u98DE\u4E66\u89E6\u53D1\u573A\u666F\u548C\u672C\u5730\u8DEF\u5F84\u6307\u9488\u4EA4\u7ED9\u4F60,\u4E0D\u66FF\u4F60\u7F16\u6392\u4EFB\u52A1\u3002",
@@ -113435,12 +113457,29 @@ function renderAgentWorkspaceBlock(conventions, extraRepos) {
113435
113457
  `- summary_file_path: ${summaryFilePath ?? "(topic_session_path)/summary.md"}`,
113436
113458
  `- state_file_path: ${conventions.stateFilePath}`,
113437
113459
  `- workspace_repos_dir: ${conventions.workspaceReposPath}`,
113460
+ `- memory_dir: ${memoryDir ?? "(agent_workspace_path)/memory"}`,
113461
+ `- memory_index: ${memoryIndex ?? "(memory_dir)/index.md"}`,
113438
113462
  "- \u4E00\u4E2A\u98DE\u4E66\u8BDD\u9898 = \u4E00\u4E2A task/session\u3002\u8BDD\u9898\u5185\u7EED\u63A5\u65F6,\u7EE7\u7EED\u4F7F\u7528\u540C\u4E00\u4E2A topic_session_path\u3002",
113439
113463
  "- \u7FA4\u91CC @ \u4F60\u65F6,bridge \u4F1A\u62C9\u8D77/\u5173\u8054\u4E00\u4E2A\u8BDD\u9898;\u662F\u5426\u8BFB\u53D6\u7FA4\u5386\u53F2\u3001\u8BDD\u9898\u5386\u53F2\u3001\u9644\u4EF6\u3001\u6587\u6863,\u7531\u4F60\u6839\u636E\u4EFB\u52A1\u81EA\u884C\u51B3\u5B9A\u3002",
113440
113464
  "- \u4E0D\u8981\u5047\u8BBE bridge \u5DF2\u7ECF clone/fetch/worktree/pnpm install;\u9700\u8981\u4EE3\u7801\u65F6,\u4F60\u5728 workspace \u91CC\u81EA\u5DF1 clone/branch/install/test\u3002",
113441
113465
  "- summary.md \u662F\u4F60\u7EF4\u62A4\u672C\u8BDD\u9898\u6458\u8981\u3001\u51B3\u7B56\u548C\u4E0B\u4E00\u6B65 notes \u7684\u5730\u65B9;bridge \u53EA\u521B\u5EFA\u5360\u4F4D,\u4E0D\u66FF\u4F60\u603B\u7ED3\u3002",
113442
- "- \u4F18\u5148\u8BFB\u53D6 workspace \u5185\u7684 AGENTS.md\u3001CLAUDE.md(\u5982\u5B58\u5728)\u3001permissions-request.md\u3001permissions-granted.md\u3002"
113466
+ "- \u8D77\u624B\u5148\u8BFB memory/index.md \u62C9\u8D77\u8DE8 session \u957F\u671F\u8BB0\u5FC6(preferences / reusable-knowledge / workflows / decisions / assets),\u518D\u8BFB workspace \u5185\u7684 AGENTS.md\u3001CLAUDE.md(\u5982\u5B58\u5728)\u3001permissions-request.md\u3001permissions-granted.md\u3002",
113467
+ "- \u672C session \u91CC\u8DE8 session \u53EF\u590D\u7528\u7684\u5185\u5BB9,\u5148\u8BB0\u5230 topic_session_path/memory-candidates.md;owner \u786E\u8BA4\u540E,\u7531\u4F60\u5199\u8FDB memory/<category>.md\u3002",
113468
+ "- \u70ED\u8DEF\u5F84(\u6BCF\u8F6E)\u53EA\u5141\u8BB8 ADD / NOOP:\u628A\u5019\u9009 append \u5230 memory-candidates.md,\u6216\u5F80 category \u6587\u4EF6\u8FFD\u52A0\u65B0\u6761\u76EE;\u4E0D\u5728\u70ED\u8DEF\u5F84\u505A UPDATE/DELETE/\u6539\u5199\u5DF2\u6709\u6761\u76EE\u3002",
113469
+ "- \u6539\u5199\u3001\u5220\u9664\u3001\u89E3\u51B3\u51B2\u7A81 \u2192 \u63A8\u8FDF\u5230 owner \u663E\u5F0F\u8BF4\u300C\u6574\u7406\u8BB0\u5FC6\u300D\u65F6\u7684\u79BB\u7EBF\u6B65\u9AA4\u505A\u3002\u5931\u6548/\u88AB\u63A8\u7FFB\u7684\u6761\u76EE\u79FB memory/archive/(\u6CE8\u4E00\u53E5\u539F\u56E0),\u4E0D\u7269\u7406\u5220\u3002",
113470
+ "- \u79BB\u7EBF\u6574\u7406/\u6539\u5199\u5DF2\u6709\u8BB0\u5FC6\u524D,\u5148\u7528 rg \u5728 sessions/*/transcript.md \u6838\u5230\u6765\u6E90\u884C;commit/\u7B14\u8BB0\u5F15\u7528\u8BE5\u884C;\u6838\u4E0D\u5230\u6765\u6E90\u7684\u7ED3\u8BBA\u964D\u7EA7\u4E3A candidate,\u4E0D\u5199\u8FDB\u6B63\u6587\u3002(\u5355 agent \u81EA\u5DF1\u505A,\u522B spawn \u522B\u7684 agent\u3002)",
113471
+ "- \u53EA\u6709\u8DE8 session \u8FD8\u4F1A\u518D\u7528\u5230\u7684\u624D\u8FDB memory/(\u5355\u6B21\u4EFB\u52A1\u7559\u5728 summary,\u968F session \u8FC7\u671F);\u65B0\u589E\u3001\u4EE5\u53CA\u4F1A\u6539\u53D8\u884C\u4E3A\u6216\u8FB9\u754C\u7684\u6539\u5199/\u5220\u9664\u90FD\u8981 owner \u786E\u8BA4\u3002"
113443
113472
  ];
113473
+ if (memoryDir) {
113474
+ for (const fileName of MEMORY_CATEGORY_FILE_NAMES) {
113475
+ const count = statMemoryLines(`${memoryDir}/${fileName}`);
113476
+ if (count > MEMORY_FILE_LINE_LIMIT) {
113477
+ lines.push(
113478
+ `- \u26A0\uFE0F ${fileName} \u5DF2 ${count} \u884C,\u8D85\u9650\u2014\u2014\u4E0B\u6B21\u300C\u6574\u7406\u8BB0\u5FC6\u300D\u65F6\u5148\u84B8\u998F\u538B\u7F29\u3002`
113479
+ );
113480
+ }
113481
+ }
113482
+ }
113444
113483
  if (conventions.defaultProjectSlug) {
113445
113484
  lines.push("");
113446
113485
  lines.push("Repo pointers(\u53EA\u662F\u6307\u9488,\u4E0D\u662F\u5DF2\u51C6\u5907\u597D\u7684 clone):");
@@ -113717,6 +113756,15 @@ function renderSummaryPlaceholder() {
113717
113756
  ""
113718
113757
  ].join("\n");
113719
113758
  }
113759
+ function renderMemoryCandidatesPlaceholder() {
113760
+ return [
113761
+ "# Memory Candidates",
113762
+ "",
113763
+ "\u672C session \u91CC\u503C\u5F97\u63D0\u5347\u4E3A\u8DE8 session \u957F\u671F\u8BB0\u5FC6\u7684\u5019\u9009,\u8BB0\u5728\u8FD9\u3002",
113764
+ "owner \u786E\u8BA4\u540E,\u7531\u4F60(Agent)\u5199\u8FDB ../../memory/<category>.md\u3002",
113765
+ ""
113766
+ ].join("\n");
113767
+ }
113720
113768
  function indentBlock(value) {
113721
113769
  const trimmed = value.trim();
113722
113770
  if (!trimmed) return " (empty)";
@@ -113772,6 +113820,10 @@ function renderTranscriptEntry(input) {
113772
113820
  async function ensureSessionArtifacts(input) {
113773
113821
  await fs.mkdir(input.sessionPath, { recursive: true });
113774
113822
  await writeIfMissing(path4.join(input.sessionPath, "summary.md"), renderSummaryPlaceholder());
113823
+ await writeIfMissing(
113824
+ path4.join(input.sessionPath, "memory-candidates.md"),
113825
+ renderMemoryCandidatesPlaceholder()
113826
+ );
113775
113827
  await fs.appendFile(
113776
113828
  path4.join(input.sessionPath, "transcript.md"),
113777
113829
  `${renderTranscriptEntry(input)}
@@ -113852,6 +113904,7 @@ function renderAgentsMd(input) {
113852
113904
  "",
113853
113905
  "## Workspace Contract",
113854
113906
  "",
113907
+ "- \u5F00\u573A\u4E0D\u53EF\u8DF3\u8FC7:\u56DE\u5E94 owner \u524D,\u5148 Read `memory/index.md`,\u5E76\u6309\u76F8\u5173\u6027 Read \u76F8\u5173 category \u6587\u4EF6,\u518D\u5F00\u59CB\u5E72\u6D3B(\u9632\u6B62\u65B0 session \u5931\u5FC6)\u3002",
113855
113908
  "- Larkway is a thin Feishu bridge. It passes scene/context pointers; you decide what to inspect and what work to do.",
113856
113909
  "- Each Feishu topic is one task session under `sessions/<thread_id>/`.",
113857
113910
  "- Keep durable notes, repo clones, session summaries, and permission decisions inside this workspace.",
@@ -114018,6 +114071,75 @@ async function ensureAgentWorkspace(input) {
114018
114071
  path5.join(input.workspacePath, "permissions-granted.md"),
114019
114072
  renderPermissionsGranted(input)
114020
114073
  );
114074
+ await ensureMemoryScaffold(input.workspacePath);
114075
+ }
114076
+ var MEMORY_CATEGORY_FILES = [
114077
+ {
114078
+ name: "preferences.md",
114079
+ title: "Owner Preferences",
114080
+ purpose: "owner \u6216\u56E2\u961F\u957F\u671F\u504F\u597D(\u6C47\u62A5\u683C\u5F0F\u3001\u9ED8\u8BA4\u8BED\u8A00\u3001\u9A8C\u8BC1\u504F\u597D\u7B49)\u3002"
114081
+ },
114082
+ {
114083
+ name: "reusable-knowledge.md",
114084
+ title: "Reusable Knowledge",
114085
+ purpose: "\u591A\u4E2A session \u540E\u6C89\u6DC0\u51FA\u7684\u53EF\u590D\u7528\u7ECF\u9A8C\u3001\u5E38\u89C1\u5751\u3001\u65B9\u6848\u5224\u65AD\u3002"
114086
+ },
114087
+ {
114088
+ name: "workflows.md",
114089
+ title: "Workflows",
114090
+ purpose: "\u8FD9\u4E2A Agent \u81EA\u5DF1\u7684\u957F\u671F\u5DE5\u4F5C\u65B9\u5F0F(\u9879\u76EE repo \u7684\u5DE5\u7A0B\u89C4\u8303\u4ECD\u5199\u8FDB\u9879\u76EE repo)\u3002"
114091
+ },
114092
+ {
114093
+ name: "decisions.md",
114094
+ title: "Decisions",
114095
+ purpose: "\u957F\u671F\u51B3\u7B56\u8BB0\u5F55,\u4F8B\u5982\u4E3A\u4EC0\u4E48\u67D0\u6743\u9650\u5FC5\u987B\u4EBA\u5DE5\u786E\u8BA4\u3002"
114096
+ },
114097
+ {
114098
+ name: "assets.md",
114099
+ title: "Assets",
114100
+ purpose: "\u957F\u671F\u56FE\u7247/\u622A\u56FE/\u9644\u4EF6\u7684\u7D22\u5F15,\u53EA\u8BB0\u5F15\u7528\u548C\u7528\u9014,\u4E0D\u5185\u8054\u5927\u6587\u4EF6(\u5B9E\u4F53\u653E assets/)\u3002"
114101
+ }
114102
+ ];
114103
+ function renderMemoryIndex() {
114104
+ return [
114105
+ "# Memory Index",
114106
+ "",
114107
+ "\u8FD9\u662F\u8DE8 session \u957F\u671F\u8BB0\u5FC6\u3002\u65B0 session \u8D77\u624B\u5148\u8BFB\u8FD9\u91CC,\u628A\u8FC7\u5F80\u79EF\u7D2F\u62C9\u8D77\u6765\u3002",
114108
+ "Larkway \u53EA\u521D\u59CB\u5316\u7A7A\u5BB9\u5668;\u63D0\u70BC\u3001\u5206\u7C7B\u3001\u5199\u5165\u6B63\u6587\u90FD\u7531\u4F60(Agent)\u5728 owner \u786E\u8BA4\u540E\u5B8C\u6210\u3002",
114109
+ "",
114110
+ "## \u5206\u7C7B\u6587\u4EF6",
114111
+ "",
114112
+ ...MEMORY_CATEGORY_FILES.map((f) => `- \`${f.name}\` \u2014 ${f.purpose}`),
114113
+ "",
114114
+ "## \u7EF4\u62A4\u89C4\u5219",
114115
+ "",
114116
+ "- \u70ED\u8DEF\u5F84(\u6BCF\u8F6E)\u53EA\u505A\u52A0\u6CD5:\u628A\u5019\u9009\u5199\u8FDB session \u7684 `memory-candidates.md`,\u6216\u5F80 category \u6587\u4EF6\u8FFD\u52A0\u65B0\u6761\u76EE;\u4E0D\u5728\u70ED\u8DEF\u5F84\u6539\u5199/\u5220\u9664\u5DF2\u6709\u6761\u76EE\u3002",
114117
+ "- \u6539\u5199\u3001\u5220\u9664\u3001\u89E3\u51B3\u51B2\u7A81 \u2192 \u63A8\u8FDF\u5230 owner \u663E\u5F0F\u8BF4\u300C\u6574\u7406\u8BB0\u5FC6\u300D\u65F6\u79BB\u7EBF\u505A\u3002UPDATE/DELETE \u7684\u65E7\u6761\u76EE\u79FB `archive/`(\u6CE8\u4E00\u53E5\u539F\u56E0+\u5BF9\u5E94 commit),\u4E0D\u624B\u5199 superseded \u6233,\u4E0D\u7269\u7406\u5220;archive/ \u7684\u957F\u671F\u6E05\u7406\u4EA4\u7ED9 git history\u3002",
114118
+ "- \u88C1\u51B3\u4EE5 source \u4F18\u5148:user \u4EB2\u53E3\u8BF4\u7684 >> agent \u63A8\u65AD;\u51B2\u7A81\u65F6\u4FDD\u7559\u65E7\u7684 user \u6761\u76EE,\u628A\u65B0\u63A8\u65AD\u964D\u7EA7\u4E3A candidate\u3002\u540C source \u5185 recency \u4EE5 git \u5386\u53F2\u4E3A\u51C6,\u4E0D\u624B\u5199\u65E5\u671F\u6233\u3002",
114119
+ "- \u53EA\u6709\u8DE8 session \u8FD8\u4F1A\u7528\u5230\u7684\u624D\u8FDB\u8FD9\u91CC(\u5355\u6B21\u4EFB\u52A1\u7559\u5728 session summary)\u3002\u672C\u6587\u4EF6\u4FDD\u6301\u7B80\u77ED(\u2264~50 \u884C),\u4E0D\u653E changelog/\u7EDF\u8BA1\u3002",
114120
+ ""
114121
+ ].join("\n");
114122
+ }
114123
+ function renderMemoryCategorySkeleton(title) {
114124
+ return [
114125
+ `# ${title}`,
114126
+ "",
114127
+ "\u5199\u524D\u5148\u8BFB\u672C\u6587\u4EF6;\u6709\u76F8\u540C/\u76F8\u5173\u6761\u76EE\u5C31 NOOP \u4E0D\u91CD\u590D\u5199(\u6539\u5199\u3001\u5220\u9664\u3001\u79FB archive \u7559\u5230 owner \u8BF4\u300C\u6574\u7406\u8BB0\u5FC6\u300D\u65F6\u7684\u79BB\u7EBF\u6B65\u9AA4);\u4FE1\u53F7\u4E0D\u8DE8 session \u590D\u7528\u5C31\u4E0D\u5199\u3002",
114128
+ ""
114129
+ ].join("\n");
114130
+ }
114131
+ async function ensureMemoryScaffold(workspacePath) {
114132
+ const memoryDir = path5.join(workspacePath, "memory");
114133
+ await fs2.mkdir(memoryDir, { recursive: true });
114134
+ await fs2.mkdir(path5.join(memoryDir, "assets"), { recursive: true });
114135
+ await fs2.mkdir(path5.join(memoryDir, "archive"), { recursive: true });
114136
+ await writeIfMissing2(path5.join(memoryDir, "index.md"), renderMemoryIndex());
114137
+ for (const file of MEMORY_CATEGORY_FILES) {
114138
+ await writeIfMissing2(
114139
+ path5.join(memoryDir, file.name),
114140
+ renderMemoryCategorySkeleton(file.title)
114141
+ );
114142
+ }
114021
114143
  }
114022
114144
 
114023
114145
  // src/bridge/stateFile.ts
@@ -118944,18 +119066,8 @@ var CodexRunner = class {
118944
119066
  // src/lark/profileBootstrap.ts
118945
119067
  import { spawnSync } from "node:child_process";
118946
119068
  function ensureLarkCliProfile(botId, profileName, appId, appSecret, _spawnSync = spawnSync, _console = console) {
118947
- try {
118948
- const showResult = _spawnSync("lark-cli", ["config", "show", "--profile", profileName], {
118949
- encoding: "utf-8",
118950
- timeout: 5e3
118951
- });
118952
- if (showResult.status === 0 && typeof showResult.stdout === "string" && showResult.stdout.includes(appId)) {
118953
- return;
118954
- }
118955
- } catch {
118956
- }
118957
119069
  _console.log(
118958
- `[larkway] bot "${botId}": creating lark-cli profile "${profileName}" for app ${appId.slice(0, 8)}\u2026`
119070
+ `[larkway] bot "${botId}": provisioning lark-cli profile "${profileName}" for app ${appId.slice(0, 8)}\u2026`
118959
119071
  );
118960
119072
  try {
118961
119073
  const initResult = _spawnSync(
@@ -118968,11 +119080,11 @@ function ensureLarkCliProfile(botId, profileName, appId, appSecret, _spawnSync =
118968
119080
  }
118969
119081
  );
118970
119082
  if (initResult.status === 0) {
118971
- _console.log(`[larkway] bot "${botId}": lark-cli profile "${profileName}" created/updated OK.`);
119083
+ _console.log(`[larkway] bot "${botId}": lark-cli profile "${profileName}" provisioned OK.`);
118972
119084
  } else {
118973
119085
  const stderr = typeof initResult.stderr === "string" ? initResult.stderr.trim() : "";
118974
119086
  _console.warn(
118975
- `[larkway] WARNING: bot "${botId}" failed to create lark-cli profile "${profileName}" (exit ${initResult.status}${stderr ? `: ${stderr}` : ""}). Multi-bot lark-cli calls may use the wrong app credentials. Fix: lark-cli config init --app-id ${appId} --app-secret-stdin --name ${profileName}`
119087
+ `[larkway] WARNING: bot "${botId}" failed to provision lark-cli profile "${profileName}" (exit ${initResult.status}${stderr ? `: ${stderr}` : ""}). Multi-bot lark-cli calls may use the wrong app credentials. Fix: lark-cli config init --app-id ${appId} --app-secret-stdin --name ${profileName}`
118976
119088
  );
118977
119089
  }
118978
119090
  } catch (err) {
@@ -119289,13 +119401,7 @@ async function runV2Mode({
119289
119401
  );
119290
119402
  }
119291
119403
  const larkCliProfile = deriveLarkCliProfile(bot.lark_cli_profile, bot.app_id);
119292
- if (healthyBots.length > 1) {
119293
- ensureLarkCliProfile(bot.id, larkCliProfile, bot.app_id, appSecret);
119294
- } else {
119295
- if (bot.lark_cli_profile) {
119296
- ensureLarkCliProfile(bot.id, larkCliProfile, bot.app_id, appSecret);
119297
- }
119298
- }
119404
+ ensureLarkCliProfile(bot.id, larkCliProfile, bot.app_id, appSecret);
119299
119405
  const botDir = resolveLarkwayDir(bot.id);
119300
119406
  const sharedReposDir = path13.join(larkwayHome(), "repos");
119301
119407
  const worktreesDir = path13.join(botDir, "worktrees");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "larkway",
3
- "version": "0.3.11",
3
+ "version": "0.3.13",
4
4
  "description": "Thin bridge: Feishu thread to local Claude Code CLI",
5
5
  "license": "MIT",
6
6
  "author": "Chuck Wu (chuckwu0)",