duclaw-cli 1.9.12 → 1.9.14

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/bundle.js CHANGED
@@ -30242,7 +30242,7 @@ function printHelp() {
30242
30242
  `);
30243
30243
  }
30244
30244
  function printVersion() {
30245
- console.log(`duclaw-cli v${true ? "1.9.12" : "unknown"}`);
30245
+ console.log(`duclaw-cli v${true ? "1.9.14" : "unknown"}`);
30246
30246
  }
30247
30247
  function getDuclawTemplate() {
30248
30248
  return {
@@ -32288,9 +32288,9 @@ var NodeFsHandler = class {
32288
32288
  if (this.fsw.closed) {
32289
32289
  return;
32290
32290
  }
32291
- const dirname7 = sp.dirname(file);
32291
+ const dirname8 = sp.dirname(file);
32292
32292
  const basename4 = sp.basename(file);
32293
- const parent = this.fsw._getWatchedDir(dirname7);
32293
+ const parent = this.fsw._getWatchedDir(dirname8);
32294
32294
  let prevStats = stats;
32295
32295
  if (parent.has(basename4))
32296
32296
  return;
@@ -32317,7 +32317,7 @@ var NodeFsHandler = class {
32317
32317
  prevStats = newStats2;
32318
32318
  }
32319
32319
  } catch (error) {
32320
- this.fsw._remove(dirname7, basename4);
32320
+ this.fsw._remove(dirname8, basename4);
32321
32321
  }
32322
32322
  } else if (parent.has(basename4)) {
32323
32323
  const at = newStats.atimeMs;
@@ -33279,8 +33279,8 @@ var chokidar_default = { watch, FSWatcher };
33279
33279
  var import_node_cron = __toESM(require_node_cron());
33280
33280
 
33281
33281
  // src/agent/createAgent.ts
33282
- var import_node_crypto15 = require("node:crypto");
33283
- var import_node_fs7 = require("node:fs");
33282
+ var import_node_crypto16 = require("node:crypto");
33283
+ var import_node_fs8 = require("node:fs");
33284
33284
 
33285
33285
  // src/background/BackgroundManager.ts
33286
33286
  var import_child_process = require("child_process");
@@ -41627,6 +41627,183 @@ async function parseResponseJson(response) {
41627
41627
  }
41628
41628
  }
41629
41629
 
41630
+ // src/attachments/attachmentContext.ts
41631
+ var import_node_crypto4 = require("node:crypto");
41632
+ var import_node_fs3 = require("node:fs");
41633
+ var import_node_path12 = require("node:path");
41634
+ var MAX_ATTACHMENT_RECORDS = 100;
41635
+ var RECENT_ATTACHMENT_LIMIT = 5;
41636
+ function makeAttachmentId(input) {
41637
+ const raw2 = [
41638
+ input.userId,
41639
+ input.platform,
41640
+ input.messageId,
41641
+ input.resourceKey,
41642
+ input.kind
41643
+ ].join(":");
41644
+ const digest = (0, import_node_crypto4.createHash)("sha256").update(raw2).digest("hex").slice(0, 16);
41645
+ return `att_${input.kind === "image" ? "img" : "file"}_${digest}`;
41646
+ }
41647
+ function indexPath(userId) {
41648
+ return (0, import_node_path12.join)(getDuclawWorkspaceDir(), userId, "attachments", "index.json");
41649
+ }
41650
+ function readIndex(userId) {
41651
+ const filePath = indexPath(userId);
41652
+ if (!(0, import_node_fs3.existsSync)(filePath)) return [];
41653
+ try {
41654
+ const parsed = JSON.parse((0, import_node_fs3.readFileSync)(filePath, "utf8"));
41655
+ return Array.isArray(parsed) ? parsed.filter(isAttachmentRecord) : [];
41656
+ } catch (error) {
41657
+ console.warn(`[attachments] failed to read attachment index: ${error.message}`);
41658
+ return [];
41659
+ }
41660
+ }
41661
+ function writeIndex(userId, records) {
41662
+ const filePath = indexPath(userId);
41663
+ (0, import_node_fs3.mkdirSync)((0, import_node_path12.dirname)(filePath), { recursive: true });
41664
+ (0, import_node_fs3.writeFileSync)(filePath, JSON.stringify(records.slice(0, MAX_ATTACHMENT_RECORDS), null, 2));
41665
+ }
41666
+ function isAttachmentRecord(value) {
41667
+ const record = value;
41668
+ return Boolean(record) && typeof record.id === "string" && (record.kind === "image" || record.kind === "file") && typeof record.userId === "string" && typeof record.pathOrUrl === "string";
41669
+ }
41670
+ function stringValue2(value) {
41671
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
41672
+ }
41673
+ function attachmentKind(value) {
41674
+ const type = stringValue2(value.type);
41675
+ const mimeType = stringValue2(value.mimeType);
41676
+ const name = stringValue2(value.name) ?? stringValue2(value.path) ?? stringValue2(value.url) ?? "";
41677
+ if (type === "image" || mimeType?.startsWith("image/") || /\.(png|jpe?g|gif|webp)$/i.test(name)) {
41678
+ return "image";
41679
+ }
41680
+ return "file";
41681
+ }
41682
+ function xmlEscape(value) {
41683
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
41684
+ }
41685
+ function upsertAttachments(userId, records) {
41686
+ if (records.length === 0) return;
41687
+ const existing = readIndex(userId);
41688
+ const byId = /* @__PURE__ */ new Map();
41689
+ for (const record of [...records, ...existing]) {
41690
+ if (!byId.has(record.id)) byId.set(record.id, record);
41691
+ }
41692
+ writeIndex(userId, Array.from(byId.values()).sort((a, b) => b.receivedAt.localeCompare(a.receivedAt)));
41693
+ }
41694
+ function listRecentAttachments(userId, limit = RECENT_ATTACHMENT_LIMIT) {
41695
+ return readIndex(userId).sort((a, b) => b.receivedAt.localeCompare(a.receivedAt)).slice(0, limit);
41696
+ }
41697
+ function resolveAttachmentPathOrUrl(userId, attachmentId) {
41698
+ return readIndex(userId).find((record) => record.id === attachmentId)?.pathOrUrl;
41699
+ }
41700
+ function collectAttachmentsFromRequest(request) {
41701
+ const metadata = request.metadata ?? {};
41702
+ const platform = request.platform || "unknown";
41703
+ const messageId = request.requestId;
41704
+ const receivedAt = (/* @__PURE__ */ new Date()).toISOString();
41705
+ const records = [];
41706
+ const seen = /* @__PURE__ */ new Set();
41707
+ const addRecord = (input) => {
41708
+ if (!input.pathOrUrl) return;
41709
+ const id = makeAttachmentId({
41710
+ userId: request.userId,
41711
+ platform,
41712
+ messageId,
41713
+ resourceKey: input.resourceKey,
41714
+ kind: input.kind
41715
+ });
41716
+ if (seen.has(id)) return;
41717
+ seen.add(id);
41718
+ records.push({
41719
+ id,
41720
+ kind: input.kind,
41721
+ platform,
41722
+ userId: request.userId,
41723
+ messageId,
41724
+ resourceKey: input.resourceKey,
41725
+ pathOrUrl: input.pathOrUrl,
41726
+ name: input.name,
41727
+ mimeType: input.mimeType,
41728
+ source: input.source,
41729
+ receivedAt
41730
+ });
41731
+ };
41732
+ const imageUrl = stringValue2(metadata.imageUrl);
41733
+ const imageKey = stringValue2(metadata.imageKey);
41734
+ if (imageUrl && imageKey) {
41735
+ addRecord({
41736
+ kind: "image",
41737
+ resourceKey: imageKey,
41738
+ pathOrUrl: imageUrl,
41739
+ source: `${platform}_metadata`
41740
+ });
41741
+ }
41742
+ const fileUrl = stringValue2(metadata.fileUrl);
41743
+ const fileName = stringValue2(metadata.fileName);
41744
+ if (fileUrl && fileName) {
41745
+ addRecord({
41746
+ kind: "file",
41747
+ resourceKey: fileName,
41748
+ pathOrUrl: fileUrl,
41749
+ name: fileName,
41750
+ source: `${platform}_metadata`
41751
+ });
41752
+ }
41753
+ const attachments = Array.isArray(metadata.attachments) ? metadata.attachments : [];
41754
+ for (const attachment of attachments) {
41755
+ const resourceKey = stringValue2(attachment.id) ?? stringValue2(attachment.name);
41756
+ const pathOrUrl = stringValue2(attachment.url) ?? stringValue2(attachment.path);
41757
+ if (!resourceKey || !pathOrUrl) continue;
41758
+ addRecord({
41759
+ kind: attachmentKind(attachment),
41760
+ resourceKey,
41761
+ pathOrUrl,
41762
+ name: stringValue2(attachment.name),
41763
+ mimeType: stringValue2(attachment.mimeType),
41764
+ source: `${platform}_attachment`
41765
+ });
41766
+ }
41767
+ return records;
41768
+ }
41769
+ function buildAttachmentContextXml(records) {
41770
+ if (records.length === 0) return "";
41771
+ const lines = [
41772
+ `<recent-attachments>`,
41773
+ ` <system-note>Use attachment_id when referring to these attachments. Do not invent or reproduce long URLs; tools can resolve the real file source from attachment_id.</system-note>`
41774
+ ];
41775
+ for (const record of records) {
41776
+ lines.push(` <${record.kind} id="${xmlEscape(record.id)}">`);
41777
+ lines.push(` <source>${xmlEscape(record.source ?? record.platform)}</source>`);
41778
+ lines.push(` <message_id>${xmlEscape(record.messageId)}</message_id>`);
41779
+ lines.push(` <resource_key>${xmlEscape(record.resourceKey)}</resource_key>`);
41780
+ if (record.name) lines.push(` <name>${xmlEscape(record.name)}</name>`);
41781
+ if (record.mimeType) lines.push(` <mime_type>${xmlEscape(record.mimeType)}</mime_type>`);
41782
+ lines.push(` <received_at>${xmlEscape(record.receivedAt)}</received_at>`);
41783
+ lines.push(` </${record.kind}>`);
41784
+ }
41785
+ lines.push(`</recent-attachments>`);
41786
+ return lines.join("\n");
41787
+ }
41788
+ function attachRecentAttachmentContext(request, content) {
41789
+ const current = collectAttachmentsFromRequest(request);
41790
+ if (current.length > 0) {
41791
+ upsertAttachments(request.userId, current);
41792
+ request.metadata = {
41793
+ ...request.metadata ?? {},
41794
+ attachmentIds: current.map((record) => record.id),
41795
+ attachmentId: current[0]?.id
41796
+ };
41797
+ }
41798
+ const context = buildAttachmentContextXml(listRecentAttachments(request.userId));
41799
+ if (!context) return content;
41800
+ return `${content}
41801
+
41802
+ <system-reminder>
41803
+ ${context}
41804
+ </system-reminder>`;
41805
+ }
41806
+
41630
41807
  // src/tools/tools/ImageUnderstand.ts
41631
41808
  var guessMediaTypeFromData = (base64Data) => {
41632
41809
  if (base64Data.startsWith("/9j/")) return "image/jpeg";
@@ -41722,6 +41899,10 @@ var imageUnderstand = {
41722
41899
  type: `string`,
41723
41900
  description: `\u56FE\u7247\u7684\u8BBF\u95EEurl\u6216base64\u7F16\u7801\u5185\u5BB9\u3002\u5F53\u7528\u6237\u76F4\u63A5\u53D1\u9001\u56FE\u7247\u65F6\u6B64\u53C2\u6570\u53EF\u7701\u7565,\u5DE5\u5177\u4F1A\u81EA\u52A8\u4ECE\u4E0A\u4E0B\u6587\u83B7\u53D6\u56FE\u7247\u3002`
41724
41901
  },
41902
+ attachment_id: {
41903
+ type: `string`,
41904
+ description: `\u6700\u8FD1\u9644\u4EF6\u4E0A\u4E0B\u6587\u4E2D\u7684\u77ED\u9644\u4EF6 ID\uFF0C\u4F8B\u5982 att_img_xxx\u3002\u4F18\u5148\u4F7F\u7528\u5B83\u5F15\u7528\u5386\u53F2\u56FE\u7247\uFF0C\u4E0D\u8981\u624B\u5199\u957F URL\u3002`
41905
+ },
41725
41906
  prompt: {
41726
41907
  type: `string`,
41727
41908
  description: `prompt\u5B57\u6BB5\u7528\u6765\u63CF\u8FF0\u6587\u5B57\u6307\u4EE4,\u4F8B\u5982"\u63CF\u8FF0\u56FE\u7247\u5185\u5BB9"`
@@ -41730,7 +41911,8 @@ var imageUnderstand = {
41730
41911
  required: [`prompt`]
41731
41912
  },
41732
41913
  async execute(input, userRequest) {
41733
- const imageSource = userRequest?.metadata?.imageUrl || input.image_url;
41914
+ const attachmentId = typeof input.attachment_id === "string" ? input.attachment_id.trim() : "";
41915
+ const imageSource = userRequest?.metadata?.imageUrl || (attachmentId && userRequest?.userId ? resolveAttachmentPathOrUrl(userRequest.userId, attachmentId) : void 0) || input.image_url;
41734
41916
  if (!imageSource) {
41735
41917
  throw new Error(`[ImageUnderstand] \u672A\u63D0\u4F9B\u56FE\u7247: \u8BF7\u4F20\u5165 image_url \u53C2\u6570\u6216\u901A\u8FC7\u6D88\u606F\u53D1\u9001\u56FE\u7247`);
41736
41918
  }
@@ -41783,7 +41965,7 @@ var imageUnderstand = {
41783
41965
 
41784
41966
  // src/tools/tools/ImageGenerate.ts
41785
41967
  var import_promises12 = require("node:fs/promises");
41786
- var import_node_path12 = __toESM(require("node:path"));
41968
+ var import_node_path13 = __toESM(require("node:path"));
41787
41969
  var DEFAULT_BASE_URL = "https://direct.shanyiapi.com";
41788
41970
  var DEFAULT_MODEL = "gpt-image-2";
41789
41971
  var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([403, 429, 500, 502, 503, 504, 524]);
@@ -41810,7 +41992,7 @@ function extensionFromContentType(contentType) {
41810
41992
  }
41811
41993
  function extensionFromUrl(url) {
41812
41994
  try {
41813
- const ext = import_node_path12.default.extname(new URL(url).pathname).toLowerCase();
41995
+ const ext = import_node_path13.default.extname(new URL(url).pathname).toLowerCase();
41814
41996
  if ([".png", ".jpg", ".jpeg", ".webp", ".gif"].includes(ext)) return ext;
41815
41997
  } catch {
41816
41998
  return "";
@@ -41943,7 +42125,7 @@ var imageGenerate = {
41943
42125
  requestId: generated.requestId
41944
42126
  }, null, 2);
41945
42127
  }
41946
- const outDir = import_node_path12.default.join(getEffectiveCwd(userRequest), "imagegen");
42128
+ const outDir = import_node_path13.default.join(getEffectiveCwd(userRequest), "imagegen");
41947
42129
  await (0, import_promises12.mkdir)(outDir, { recursive: true });
41948
42130
  const stem = sanitizeName(String(input.filenameStem || prompt));
41949
42131
  const savedFiles = [];
@@ -41952,7 +42134,7 @@ var imageGenerate = {
41952
42134
  const image = item.url ? await downloadImage(item.url, timeoutMs) : item.b64_json ? decodeBase64Image(item.b64_json) : null;
41953
42135
  if (!image) continue;
41954
42136
  const fileName = `${stem}-${index + 1}${image.extension}`;
41955
- const filePath = import_node_path12.default.join(outDir, fileName);
42137
+ const filePath = import_node_path13.default.join(outDir, fileName);
41956
42138
  await (0, import_promises12.writeFile)(filePath, image.buffer);
41957
42139
  savedFiles.push({ filePath, fileName });
41958
42140
  }
@@ -42397,10 +42579,10 @@ var goalDelete = {
42397
42579
  };
42398
42580
 
42399
42581
  // src/tools/tools/department/DepartmentCreate.ts
42400
- var import_node_crypto8 = require("node:crypto");
42582
+ var import_node_crypto9 = require("node:crypto");
42401
42583
 
42402
42584
  // src/department/mailbox/mailbox.ts
42403
- var import_node_crypto7 = require("node:crypto");
42585
+ var import_node_crypto8 = require("node:crypto");
42404
42586
 
42405
42587
  // src/agent/interruptRegistry.ts
42406
42588
  var registry = /* @__PURE__ */ new Map();
@@ -42451,7 +42633,7 @@ var drainInterrupts = (userId) => {
42451
42633
  };
42452
42634
 
42453
42635
  // src/agent/events.ts
42454
- var import_node_crypto4 = require("node:crypto");
42636
+ var import_node_crypto5 = require("node:crypto");
42455
42637
  var rowToEvent = (row) => ({
42456
42638
  id: row.id,
42457
42639
  userId: row.userId,
@@ -42468,7 +42650,7 @@ var rowToEvent = (row) => ({
42468
42650
  var recordAgentEvent = (input) => {
42469
42651
  const db3 = createSqliteDB();
42470
42652
  const now = Date.now();
42471
- const id = `evt_${(0, import_node_crypto4.randomUUID)().slice(0, 12)}`;
42653
+ const id = `evt_${(0, import_node_crypto5.randomUUID)().slice(0, 12)}`;
42472
42654
  const payloadJson = JSON.stringify(input.payload);
42473
42655
  db3.prepare(`
42474
42656
  INSERT INTO agent_events (
@@ -42599,7 +42781,7 @@ ${ceoFollowupInstruction}
42599
42781
  };
42600
42782
 
42601
42783
  // src/department/mailbox/events.ts
42602
- var import_node_crypto5 = require("node:crypto");
42784
+ var import_node_crypto6 = require("node:crypto");
42603
42785
  var parseDetail = (detailJson) => {
42604
42786
  if (!detailJson) return void 0;
42605
42787
  try {
@@ -42640,7 +42822,7 @@ var mapMailboxEventRow = (row) => {
42640
42822
  var recordMailboxEvent = (input) => {
42641
42823
  const db3 = createSqliteDB();
42642
42824
  const event = {
42643
- id: (0, import_node_crypto5.randomUUID)().slice(0, 12),
42825
+ id: (0, import_node_crypto6.randomUUID)().slice(0, 12),
42644
42826
  messageId: input.messageId,
42645
42827
  mailboxId: input.mailboxId,
42646
42828
  actorMailboxId: input.actorMailboxId,
@@ -42924,7 +43106,7 @@ var deleteDepartmentMemberById = (departmentName, memberId) => {
42924
43106
  };
42925
43107
 
42926
43108
  // src/department/mailbox/ceoFollowup.ts
42927
- var import_node_crypto6 = require("node:crypto");
43109
+ var import_node_crypto7 = require("node:crypto");
42928
43110
  var rowToFollowup = (row) => ({
42929
43111
  id: row.id,
42930
43112
  sourceMessageId: row.sourceMessageId,
@@ -42971,7 +43153,7 @@ var enqueueCeoFollowupFromMailbox = (message) => {
42971
43153
  if (!message.originUserId || !message.originPlatform) return null;
42972
43154
  const db3 = createSqliteDB();
42973
43155
  const now = Date.now();
42974
- const id = `cfu_${(0, import_node_crypto6.randomUUID)().slice(0, 12)}`;
43156
+ const id = `cfu_${(0, import_node_crypto7.randomUUID)().slice(0, 12)}`;
42975
43157
  db3.prepare(`
42976
43158
  INSERT INTO ceo_followups (
42977
43159
  id,
@@ -43301,7 +43483,7 @@ var recordMailboxReceivedAgentEvent = (msg) => {
43301
43483
  };
43302
43484
  var sendMessage2 = (fromMailboxId, toMailboxId, content, options) => {
43303
43485
  const db3 = createSqliteDB();
43304
- const id = (0, import_node_crypto7.randomUUID)().slice(0, 8);
43486
+ const id = (0, import_node_crypto8.randomUUID)().slice(0, 8);
43305
43487
  const threadId = options?.threadId || id;
43306
43488
  const workItemContext = resolveWorkItemContext(fromMailboxId, toMailboxId, id, options);
43307
43489
  const stmt = db3.prepare(`insert into mailbox (
@@ -43444,7 +43626,7 @@ var departmentCreate = {
43444
43626
  return `[departmentCreate] \u4E0D\u5B58\u5728 id=${sourceGoalId} \u7684\u76EE\u6807`;
43445
43627
  }
43446
43628
  let departmentDefinition = {
43447
- id: (0, import_node_crypto8.randomUUID)().slice(0, 8),
43629
+ id: (0, import_node_crypto9.randomUUID)().slice(0, 8),
43448
43630
  name,
43449
43631
  charter,
43450
43632
  sourceGoalId,
@@ -43711,7 +43893,7 @@ var departmentList = {
43711
43893
  };
43712
43894
 
43713
43895
  // src/tools/tools/department/DepartmentMemberCreate.ts
43714
- var import_node_crypto9 = require("node:crypto");
43896
+ var import_node_crypto10 = require("node:crypto");
43715
43897
  var DESCRIPTION25 = `
43716
43898
  \u521B\u5EFA\u90E8\u95E8\u6210\u5458\u3002
43717
43899
 
@@ -43777,7 +43959,7 @@ var departmentMemberCreate = {
43777
43959
  }
43778
43960
  }
43779
43961
  let departmentMember = {
43780
- id: (0, import_node_crypto9.randomUUID)().slice(0, 8),
43962
+ id: (0, import_node_crypto10.randomUUID)().slice(0, 8),
43781
43963
  name,
43782
43964
  departmentId: department.id,
43783
43965
  mailBoxId: getMailBoxId(department.name, name),
@@ -43940,10 +44122,10 @@ var checkDepartmentReplies = {
43940
44122
  ``,
43941
44123
  `\u51E0\u53E5\u63D0\u9192\uFF1A`,
43942
44124
  `- \u8FD9\u4E0D\u4EE3\u8868\u8981\u4F60\u4EB2\u81EA\u4E0B\u573A read/bash/\u6D4B\u8BD5/\u6539\u4EE3\u7801\u2014\u2014\u56E2\u961F\u6CA1\u56DE\uFF0C\u4E0D\u662F\u4F60\u8BE5\u63A5\u624B\u7684\u4FE1\u53F7\u3002`,
43943
- `- \u8001\u677F\u8981\u662F\u6B63\u7B49\u7740\uFF0C\u5148\u7528 send_message \u5982\u5B9E\u8DDF\u4ED6\u8BF4\u4E00\u53E5\u201C\u8D1F\u8D23\u4EBA\u8FD8\u5728\u5904\u7406\uFF0C\u6211\u62FF\u5230\u7ED3\u679C\u5C31\u540C\u6B65\u201D\u3002`,
44125
+ `- \u8001\u677F\u8981\u662F\u6B63\u7B49\u7740\uFF0C\u5148\u7528 send_message \u5982\u5B9E\u8DDF\u4ED6\u8BF4\u4E00\u53E5\u201C\u5DF2\u5B89\u6392\u7ED9\u8D1F\u8D23\u4EBA\u5904\u7406\uFF0C\u6211\u7B49\u56DE\u4FE1\u540E\u540C\u6B65\u201D\u3002`,
43944
44126
  `- \u5982\u679C\u4EFB\u52A1\u521A\u6D3E\u51FA\u53BB\uFF0C\u4E0D\u8981\u5728\u540C\u4E00\u8F6E\u9A6C\u4E0A\u50AC\u529E\uFF1B\u7ED9\u8D1F\u8D23\u4EBA\u5408\u7406\u5904\u7406\u65F6\u95F4\u3002`,
43945
- `- \u5DF2\u7ECF\u7B49\u4E86\u4E00\u9635\u3001\u8001\u677F\u53C8\u8FFD\u95EE\uFF0C\u6216\u53D1\u73B0\u660E\u786E\u98CE\u9669\u65F6\uFF0C\u518D\u7528 mailbox_followup \u6216 department_communicate \u53BB\u95EE\u5BF9\u5E94 Department Head \u771F\u5B9E\u8FDB\u5C55\u3001\u5361\u5728\u54EA\u3001\u5927\u6982\u4EC0\u4E48\u65F6\u5019\u597D\u3002`,
43946
- `- \u522B\u5728\u8FD9\u4E00\u8F6E\u91CC\u53CD\u590D\u7A7A\u67E5 check_department_replies\uFF1B\u7B49\u56E2\u961F\u56DE\u4FE1\u3001\u8001\u677F\u8FFD\u95EE\u6216\u50AC\u529E\u6709\u4E86\u56DE\u97F3\uFF0C\u518D\u6765\u770B\u3002`
44127
+ `- \u5DF2\u7ECF\u7B49\u4E86\u4E00\u9635\u3001\u8001\u677F\u53C8\u8FFD\u95EE\uFF0C\u6216\u53D1\u73B0\u660E\u786E\u98CE\u9669\u65F6\uFF0C\u518D\u7528 mailbox_followup \u53BB\u8865\u5145\u4E0A\u4E0B\u6587\u6216\u8BE2\u95EE\u5BF9\u5E94 Department Head \u7684\u771F\u5B9E\u72B6\u6001\u3002`,
44128
+ `- \u522B\u5728\u8FD9\u4E00\u8F6E\u91CC\u53CD\u590D\u7A7A\u67E5 check_department_replies\uFF1B\u7B49\u56E2\u961F\u56DE\u4FE1\u3001\u8001\u677F\u8FFD\u95EE\u6216\u786E\u6709\u65B0\u80CC\u666F\uFF0C\u518D\u6765\u770B\u3002`
43947
44129
  ].join("\n");
43948
44130
  }
43949
44131
  const updateStmt = db3.prepare(`UPDATE mailbox SET status = 'read' WHERE id = ?`);
@@ -43967,13 +44149,13 @@ ${replies}`;
43967
44149
  };
43968
44150
 
43969
44151
  // src/department/learning.ts
43970
- var import_node_fs4 = require("node:fs");
43971
- var import_node_path14 = __toESM(require("node:path"));
43972
- var import_node_crypto10 = require("node:crypto");
44152
+ var import_node_fs5 = require("node:fs");
44153
+ var import_node_path15 = __toESM(require("node:path"));
44154
+ var import_node_crypto11 = require("node:crypto");
43973
44155
 
43974
44156
  // src/skill/SkillValidator.ts
43975
- var import_node_fs3 = require("node:fs");
43976
- var import_node_path13 = __toESM(require("node:path"));
44157
+ var import_node_fs4 = require("node:fs");
44158
+ var import_node_path14 = __toESM(require("node:path"));
43977
44159
  var SKILL_NAME_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/;
43978
44160
  var REQUIRED_SECTIONS = [
43979
44161
  /(^|\n)##\s+(when to use|何时使用|trigger|triggers)\b/i,
@@ -43999,9 +44181,9 @@ var assertSafeSkillTarget = (rootDir, skillName) => {
43999
44181
  if (!isValidSkillName(skillName)) {
44000
44182
  throw new Error(`Invalid skill name "${skillName}". Use lowercase letters, digits, and single hyphens only.`);
44001
44183
  }
44002
- const root = import_node_path13.default.resolve(rootDir);
44003
- const target = import_node_path13.default.resolve(root, skillName);
44004
- if (target !== import_node_path13.default.join(root, skillName) || !target.startsWith(root + import_node_path13.default.sep)) {
44184
+ const root = import_node_path14.default.resolve(rootDir);
44185
+ const target = import_node_path14.default.resolve(root, skillName);
44186
+ if (target !== import_node_path14.default.join(root, skillName) || !target.startsWith(root + import_node_path14.default.sep)) {
44005
44187
  throw new Error(`Invalid skill install target for "${skillName}".`);
44006
44188
  }
44007
44189
  return target;
@@ -44074,14 +44256,14 @@ var validateSkillDocument = (input) => {
44074
44256
  }
44075
44257
  }
44076
44258
  if (input.baseDir) {
44077
- const normalizedBase = import_node_path13.default.resolve(input.baseDir);
44259
+ const normalizedBase = import_node_path14.default.resolve(input.baseDir);
44078
44260
  for (const match2 of parsed.body.matchAll(/\]\(([^)]+)\)/g)) {
44079
44261
  const href = match2[1].trim();
44080
44262
  if (!href || /^[a-z][a-z0-9+.-]*:/i.test(href) || href.startsWith(`#`)) continue;
44081
- const target = import_node_path13.default.resolve(normalizedBase, href.split(`#`)[0]);
44082
- if (!target.startsWith(normalizedBase + import_node_path13.default.sep) && target !== normalizedBase) {
44263
+ const target = import_node_path14.default.resolve(normalizedBase, href.split(`#`)[0]);
44264
+ if (!target.startsWith(normalizedBase + import_node_path14.default.sep) && target !== normalizedBase) {
44083
44265
  addError(errors, `unsafe_reference`, `Relative link "${href}" escapes the skill directory.`);
44084
- } else if (!(0, import_node_fs3.existsSync)(target)) {
44266
+ } else if (!(0, import_node_fs4.existsSync)(target)) {
44085
44267
  addError(errors, `missing_reference`, `Relative link "${href}" does not exist in the skill directory.`);
44086
44268
  }
44087
44269
  }
@@ -44098,9 +44280,9 @@ var mergeIssues = (target, source) => {
44098
44280
  target.warnings.push(...source.warnings);
44099
44281
  };
44100
44282
  var validateScriptsDirectory = (skillDir, warnings) => {
44101
- const scriptsDir = import_node_path13.default.join(skillDir, `scripts`);
44102
- if (!(0, import_node_fs3.existsSync)(scriptsDir)) return;
44103
- const entries = (0, import_node_fs3.readdirSync)(scriptsDir, { withFileTypes: true }).filter((entry) => entry.isFile());
44283
+ const scriptsDir = import_node_path14.default.join(skillDir, `scripts`);
44284
+ if (!(0, import_node_fs4.existsSync)(scriptsDir)) return;
44285
+ const entries = (0, import_node_fs4.readdirSync)(scriptsDir, { withFileTypes: true }).filter((entry) => entry.isFile());
44104
44286
  if (entries.length === 0) {
44105
44287
  addWarning(warnings, `empty_scripts_dir`, `scripts/ exists but contains no files.`);
44106
44288
  }
@@ -44108,19 +44290,19 @@ var validateScriptsDirectory = (skillDir, warnings) => {
44108
44290
  var validateSkillDirectory = (skillDir, options = {}) => {
44109
44291
  const errors = [];
44110
44292
  const warnings = [];
44111
- const normalizedSkillDir = import_node_path13.default.resolve(skillDir);
44112
- const skillMdPath = import_node_path13.default.join(normalizedSkillDir, `SKILL.md`);
44113
- if (!(0, import_node_fs3.existsSync)(normalizedSkillDir) || !(0, import_node_fs3.statSync)(normalizedSkillDir).isDirectory()) {
44293
+ const normalizedSkillDir = import_node_path14.default.resolve(skillDir);
44294
+ const skillMdPath = import_node_path14.default.join(normalizedSkillDir, `SKILL.md`);
44295
+ if (!(0, import_node_fs4.existsSync)(normalizedSkillDir) || !(0, import_node_fs4.statSync)(normalizedSkillDir).isDirectory()) {
44114
44296
  addError(errors, `missing_skill_dir`, `Skill directory does not exist: ${normalizedSkillDir}`);
44115
44297
  return { ok: false, errors, warnings, skillDir: normalizedSkillDir, skillMdPath };
44116
44298
  }
44117
- if (!(0, import_node_fs3.existsSync)(skillMdPath) || !(0, import_node_fs3.statSync)(skillMdPath).isFile()) {
44299
+ if (!(0, import_node_fs4.existsSync)(skillMdPath) || !(0, import_node_fs4.statSync)(skillMdPath).isFile()) {
44118
44300
  addError(errors, `missing_skill_md`, `Skill directory must contain SKILL.md.`);
44119
44301
  return { ok: false, errors, warnings, skillDir: normalizedSkillDir, skillMdPath };
44120
44302
  }
44121
- const raw2 = (0, import_node_fs3.readFileSync)(skillMdPath, `utf-8`);
44303
+ const raw2 = (0, import_node_fs4.readFileSync)(skillMdPath, `utf-8`);
44122
44304
  const documentResult = validateSkillDocument({
44123
- skillName: options.expectedName ?? import_node_path13.default.basename(normalizedSkillDir),
44305
+ skillName: options.expectedName ?? import_node_path14.default.basename(normalizedSkillDir),
44124
44306
  skillMd: raw2,
44125
44307
  baseDir: normalizedSkillDir
44126
44308
  });
@@ -44172,26 +44354,26 @@ var formatSkillValidationIssues = (result) => {
44172
44354
  };
44173
44355
 
44174
44356
  // src/department/learning.ts
44175
- var ensureDir = (dir) => (0, import_node_fs4.mkdirSync)(dir, { recursive: true });
44357
+ var ensureDir = (dir) => (0, import_node_fs5.mkdirSync)(dir, { recursive: true });
44176
44358
  var readJsonArray = (filePath) => {
44177
- if (!(0, import_node_fs4.existsSync)(filePath)) return [];
44178
- return JSON.parse((0, import_node_fs4.readFileSync)(filePath, "utf-8"));
44359
+ if (!(0, import_node_fs5.existsSync)(filePath)) return [];
44360
+ return JSON.parse((0, import_node_fs5.readFileSync)(filePath, "utf-8"));
44179
44361
  };
44180
44362
  var writeJsonArray = (filePath, records) => {
44181
- ensureDir(import_node_path14.default.dirname(filePath));
44182
- (0, import_node_fs4.writeFileSync)(filePath, JSON.stringify(records, null, " "), "utf-8");
44363
+ ensureDir(import_node_path15.default.dirname(filePath));
44364
+ (0, import_node_fs5.writeFileSync)(filePath, JSON.stringify(records, null, " "), "utf-8");
44183
44365
  };
44184
44366
  var departmentMemoryPath = (departmentName) => {
44185
- return import_node_path14.default.join(getDepartmentWorkSpaceDir(departmentName), "department-memory.json");
44367
+ return import_node_path15.default.join(getDepartmentWorkSpaceDir(departmentName), "department-memory.json");
44186
44368
  };
44187
44369
  var departmentSkillPath = (departmentName) => {
44188
- return import_node_path14.default.join(getDepartmentWorkSpaceDir(departmentName), "department-skills.json");
44370
+ return import_node_path15.default.join(getDepartmentWorkSpaceDir(departmentName), "department-skills.json");
44189
44371
  };
44190
44372
  var departmentSkillDir = (departmentName, skillName) => {
44191
- return assertSafeSkillTarget(import_node_path14.default.join(getDepartmentWorkSpaceDir(departmentName), "skills"), skillName);
44373
+ return assertSafeSkillTarget(import_node_path15.default.join(getDepartmentWorkSpaceDir(departmentName), "skills"), skillName);
44192
44374
  };
44193
44375
  var proposalsPath = () => {
44194
- return import_node_path14.default.join(getDepartmentBaseDir(), "department-proposals.json");
44376
+ return import_node_path15.default.join(getDepartmentBaseDir(), "department-proposals.json");
44195
44377
  };
44196
44378
  var getDepartmentNameForHead = (request) => {
44197
44379
  const mailboxId = request?.departmentAgentId;
@@ -44207,7 +44389,7 @@ var listDepartmentMemories = (departmentName) => {
44207
44389
  var createDepartmentMemory = (departmentName, input) => {
44208
44390
  const now = Date.now();
44209
44391
  const memory = {
44210
- id: (0, import_node_crypto10.randomUUID)().slice(0, 8),
44392
+ id: (0, import_node_crypto11.randomUUID)().slice(0, 8),
44211
44393
  departmentName,
44212
44394
  title: input.title,
44213
44395
  content: input.content,
@@ -44258,7 +44440,7 @@ ${formatSkillValidationIssues(validation)}`);
44258
44440
  }
44259
44441
  const now = Date.now();
44260
44442
  const skill = {
44261
- id: (0, import_node_crypto10.randomUUID)().slice(0, 8),
44443
+ id: (0, import_node_crypto11.randomUUID)().slice(0, 8),
44262
44444
  departmentName,
44263
44445
  skillName: input.skillName,
44264
44446
  description: input.description,
@@ -44289,7 +44471,7 @@ var keepDepartmentSkill = (departmentName, id) => {
44289
44471
  ${formatSkillValidationIssues(validation)}`);
44290
44472
  }
44291
44473
  ensureDir(skillDir);
44292
- (0, import_node_fs4.writeFileSync)(import_node_path14.default.join(skillDir, "SKILL.md"), records[idx].skillMd, "utf-8");
44474
+ (0, import_node_fs5.writeFileSync)(import_node_path15.default.join(skillDir, "SKILL.md"), records[idx].skillMd, "utf-8");
44293
44475
  const smokeTest = smokeTestSkillDirectory(skillDir, { expectedName: records[idx].skillName });
44294
44476
  if (!smokeTest.ok) {
44295
44477
  throw new Error(`[departmentSkill] Skill smoke test \u5931\u8D25\uFF1A
@@ -44310,7 +44492,7 @@ var createDepartmentProposal = (input) => {
44310
44492
  const records = readJsonArray(proposalsPath());
44311
44493
  const proposal = {
44312
44494
  ...input,
44313
- id: (0, import_node_crypto10.randomUUID)().slice(0, 8),
44495
+ id: (0, import_node_crypto11.randomUUID)().slice(0, 8),
44314
44496
  status: "pending",
44315
44497
  createdAt: Date.now()
44316
44498
  };
@@ -44554,14 +44736,14 @@ var getCeoNudgeCooldownMs = () => {
44554
44736
  var DESCRIPTION29 = `
44555
44737
  \u5728\u5F53\u524D mailbox \u7EBF\u7A0B\u4E2D\u8FFD\u52A0\u4E00\u6761\u8865\u5145\u6D88\u606F\uFF0C\u4F46\u4E0D\u7ED3\u675F\u539F\u6D88\u606F\u7684\u5904\u7406\u3002
44556
44738
 
44557
- \u5B83\u5728\u7EC4\u7EC7\u91CC\u7684\u542B\u4E49\u66F4\u63A5\u8FD1\u201C\u540C\u4E00\u4EF6\u4E8B\u7684\u7EE7\u7EED\u6C9F\u901A\u201D\uFF1A\u8BA9\u5BF9\u65B9\u77E5\u9053\u4F60\u5DF2\u7ECF\u5B89\u6392\u3001\u6B63\u5728\u7B49\u8C01\u3001\u50AC\u4E86\u8C01\u3001\u76EE\u524D\u770B\u5230\u4E86\u54EA\u4E9B\u90E8\u5206\u7ED3\u679C\uFF0C\u6216\u9700\u8981\u5BF9\u65B9\u8865\u5145\u4EC0\u4E48\u3002
44558
- \u7279\u522B\u662F\u7ED9 CEO/manager \u540C\u6B65\u201C\u5DF2\u59D4\u6D3E\u3001\u6B63\u5728\u68C0\u67E5\u3001\u7B49\u5F85\u4E0B\u5C5E\u7ED3\u679C\u3001\u5DF2\u50AC\u4FC3\u201D\u8FD9\u7C7B\u8FDB\u5EA6\u65F6\uFF0C\u4F18\u5148\u4F7F\u7528\u5B83\uFF1B\u7B49\u4F60\u9A8C\u6536\u5B8C\u771F\u5B9E\u7ED3\u679C\u3001\u53EF\u4EE5\u4EA4\u4ED8\u6700\u7EC8\u7ED3\u8BBA\u65F6\uFF0C\u518D\u4F7F\u7528 reply_mailbox\u3002
44739
+ \u5B83\u5728\u7EC4\u7EC7\u91CC\u7684\u542B\u4E49\u66F4\u63A5\u8FD1\u201C\u540C\u4E00\u4EF6\u4E8B\u7684\u7EE7\u7EED\u6C9F\u901A\u201D\uFF1A\u8865\u5145\u65B0\u80CC\u666F\u3001\u540C\u6B65\u5F53\u524D\u72B6\u6001\u3001\u8BF4\u660E\u6B63\u5728\u7B49\u5F85\u54EA\u90E8\u5206\u7ED3\u679C\uFF0C\u6216\u9700\u8981\u5BF9\u65B9\u8865\u5145\u4EC0\u4E48\u3002
44740
+ \u7279\u522B\u662F\u7ED9 CEO/manager \u540C\u6B65\u201C\u5DF2\u59D4\u6D3E\u3001\u6B63\u5728\u68C0\u67E5\u3001\u7B49\u5F85\u4E0B\u5C5E\u7ED3\u679C\u3001\u5DF2\u6709\u90E8\u5206\u53D1\u73B0\u201D\u8FD9\u7C7B\u8FDB\u5EA6\u65F6\uFF0C\u4F18\u5148\u4F7F\u7528\u5B83\uFF1B\u7B49\u4F60\u9A8C\u6536\u5B8C\u771F\u5B9E\u7ED3\u679C\u3001\u53EF\u4EE5\u4EA4\u4ED8\u6700\u7EC8\u7ED3\u8BBA\u65F6\uFF0C\u518D\u4F7F\u7528 reply_mailbox\u3002
44559
44741
 
44560
44742
  \u9002\u7528\u573A\u666F\uFF1A
44561
44743
  - \u540C\u6B65\u9636\u6BB5\u6027\u8FDB\u5C55
44562
44744
  - \u4E3B\u52A8\u8FFD\u95EE\u6F84\u6E05\u4FE1\u606F
44563
44745
  - \u5148\u53D1\u51FA\u90E8\u5206\u7ED3\u679C\uFF0C\u7A0D\u540E\u7EE7\u7EED\u8865\u5145
44564
- - \u544A\u77E5\u4E0A\u6E38\u5DF2\u5B89\u6392\u4E0B\u5C5E\u3001\u6B63\u5728\u7B49\u5F85\u4E0B\u5C5E\u7ED3\u679C\uFF0C\u6216\u5DF2\u7ECF\u50AC\u529E
44746
+ - \u544A\u77E5\u4E0A\u6E38\u5DF2\u5B89\u6392\u4E0B\u5C5E\u3001\u6B63\u5728\u7B49\u5F85\u4E0B\u5C5E\u7ED3\u679C\uFF0C\u6216\u5DF2\u6709\u90E8\u5206\u53D1\u73B0
44565
44747
  - CEO \u6536\u5230\u67D0\u4E2A\u90E8\u95E8\u6210\u5458\u7684\u7ED3\u679C\u540E\uFF0C\u82E5\u7528\u6237\u7EE7\u7EED\u63D0\u4FEE\u6539\u610F\u89C1\u3001bug \u53CD\u9988\u3001\u6253\u4E0D\u5F00\u7B49\u95EE\u9898\uFF0C\u5E94\u4F18\u5148\u5BF9\u8BE5\u6210\u5458\u4E0A\u4E00\u6761\u76F8\u5173\u56DE\u4FE1\u8C03\u7528 mailbox_followup\uFF0C\u628A\u53CD\u9988\u6CBF\u539F\u7EBF\u7A0B\u53D1\u56DE\u539F\u8D23\u4EFB\u4EBA
44566
44748
 
44567
44749
  \u53C2\u6570\uFF1A
@@ -44573,6 +44755,7 @@ var DESCRIPTION29 = `
44573
44755
  - \u6B64\u5DE5\u5177\u4E0D\u4F1A\u4FEE\u6539\u539F\u6D88\u606F\u72B6\u6001
44574
44756
  - \u5982\u679C\u4F60\u5DF2\u7ECF\u5F62\u6210\u5BF9\u5F53\u524D\u6D88\u606F\u7684\u6B63\u5F0F\u7B54\u590D\uFF0C\u5E94\u4F7F\u7528 reply_mailbox
44575
44757
  - \u5BF9 CEO \u800C\u8A00\uFF0C\u8FD9\u901A\u5E38\u662F\u201C\u628A\u8FD4\u5DE5\u9700\u6C42\u9000\u56DE\u539F\u8D23\u4EFB\u6210\u5458\u201D\u7684\u9996\u9009\u5DE5\u5177\uFF0C\u800C\u4E0D\u662F\u81EA\u5DF1\u76F4\u63A5\u91CD\u505A
44758
+ - \u5BF9 CEO \u800C\u8A00\uFF0C\u521A\u59D4\u6D3E\u540E\u4E0D\u8981\u7528\u6B64\u5DE5\u5177\u50AC\u8D1F\u8D23\u4EBA\uFF0C\u4E5F\u4E0D\u8981\u5BF9\u8001\u677F\u8BF4\u201C\u6211\u53BB\u50AC/\u5DF2\u50AC/\u4F1A\u76EF\u7740\u201D\u3002\u9ED8\u8BA4\u53EA\u540C\u6B65\u201C\u5DF2\u5B89\u6392\uFF0C\u7B49\u56DE\u4FE1\u540E\u540C\u6B65\u201D\u3002
44576
44759
  `;
44577
44760
  var looksLikeCeoNudge = (content, kind) => {
44578
44761
  if (kind === `nudge`) return true;
@@ -44668,8 +44851,8 @@ var mailboxFollowup = {
44668
44851
 
44669
44852
  // src/tools/tools/Bash.ts
44670
44853
  var import_node_child_process = require("node:child_process");
44671
- var import_node_crypto11 = require("node:crypto");
44672
- var import_node_fs5 = require("node:fs");
44854
+ var import_node_crypto12 = require("node:crypto");
44855
+ var import_node_fs6 = require("node:fs");
44673
44856
  var DESCRIPTION30 = `\u5728\u7CFB\u7EDF shell \u4E2D\u6267\u884C\u547D\u4EE4\u3002
44674
44857
 
44675
44858
  \u7528\u9014\uFF1A
@@ -44709,7 +44892,7 @@ var sessions = /* @__PURE__ */ new Map();
44709
44892
  function findExecutableShell2() {
44710
44893
  for (const shell of SHELL_CANDIDATES2) {
44711
44894
  try {
44712
- (0, import_node_fs5.accessSync)(shell, import_node_fs5.constants.X_OK);
44895
+ (0, import_node_fs6.accessSync)(shell, import_node_fs6.constants.X_OK);
44713
44896
  return shell;
44714
44897
  } catch {
44715
44898
  }
@@ -44718,11 +44901,11 @@ function findExecutableShell2() {
44718
44901
  }
44719
44902
  function validateCwd(cwd) {
44720
44903
  try {
44721
- const stat11 = (0, import_node_fs5.statSync)(cwd);
44904
+ const stat11 = (0, import_node_fs6.statSync)(cwd);
44722
44905
  if (!stat11.isDirectory()) {
44723
44906
  return `[bash] \u9519\u8BEF: cwd \u4E0D\u662F\u76EE\u5F55: ${cwd}`;
44724
44907
  }
44725
- (0, import_node_fs5.accessSync)(cwd, import_node_fs5.constants.R_OK | import_node_fs5.constants.X_OK);
44908
+ (0, import_node_fs6.accessSync)(cwd, import_node_fs6.constants.R_OK | import_node_fs6.constants.X_OK);
44726
44909
  return null;
44727
44910
  } catch (err) {
44728
44911
  const code = err.code;
@@ -44965,7 +45148,7 @@ var bashTool = {
44965
45148
  stdio: ["pipe", "pipe", "pipe"],
44966
45149
  detached: process.platform !== "win32"
44967
45150
  });
44968
- const id = (0, import_node_crypto11.randomUUID)().slice(0, 8);
45151
+ const id = (0, import_node_crypto12.randomUUID)().slice(0, 8);
44969
45152
  const session = {
44970
45153
  id,
44971
45154
  command,
@@ -45732,10 +45915,10 @@ var readDreamHistoryLimit = () => {
45732
45915
  };
45733
45916
 
45734
45917
  // src/skillForge/SkillForgeEngine.ts
45735
- var import_node_fs6 = require("node:fs");
45918
+ var import_node_fs7 = require("node:fs");
45736
45919
  var import_node_os2 = require("node:os");
45737
- var import_node_path15 = require("node:path");
45738
- var import_node_crypto12 = require("node:crypto");
45920
+ var import_node_path16 = require("node:path");
45921
+ var import_node_crypto13 = require("node:crypto");
45739
45922
  var SkillForgeEngine = class {
45740
45923
  proposalStorage;
45741
45924
  draftRoot;
@@ -45743,8 +45926,8 @@ var SkillForgeEngine = class {
45743
45926
  constructor(deps) {
45744
45927
  this.proposalStorage = deps.proposalStorage;
45745
45928
  const opt = deps.options ?? {};
45746
- this.draftRoot = opt.draftRoot ?? (0, import_node_path15.join)((0, import_node_os2.homedir)(), ".duclaw", "skill-proposals");
45747
- this.skillsInstallDir = opt.skillsInstallDir ?? (0, import_node_path15.join)((0, import_node_os2.homedir)(), ".agents", "skills");
45929
+ this.draftRoot = opt.draftRoot ?? (0, import_node_path16.join)((0, import_node_os2.homedir)(), ".duclaw", "skill-proposals");
45930
+ this.skillsInstallDir = opt.skillsInstallDir ?? (0, import_node_path16.join)((0, import_node_os2.homedir)(), ".agents", "skills");
45748
45931
  }
45749
45932
  // ---------- 公开方法 ----------
45750
45933
  /**
@@ -45769,14 +45952,14 @@ ${formatSkillValidationIssues(validation)}`);
45769
45952
  if (pending.some((p) => p.skillName === skillName)) {
45770
45953
  return null;
45771
45954
  }
45772
- const id = (0, import_node_crypto12.randomBytes)(4).toString("hex");
45773
- const draftDir = (0, import_node_path15.join)(this.draftRoot, userId, id);
45774
- (0, import_node_fs6.mkdirSync)(draftDir, { recursive: true });
45775
- (0, import_node_fs6.writeFileSync)((0, import_node_path15.join)(draftDir, "SKILL.md"), skillMd, "utf-8");
45955
+ const id = (0, import_node_crypto13.randomBytes)(4).toString("hex");
45956
+ const draftDir = (0, import_node_path16.join)(this.draftRoot, userId, id);
45957
+ (0, import_node_fs7.mkdirSync)(draftDir, { recursive: true });
45958
+ (0, import_node_fs7.writeFileSync)((0, import_node_path16.join)(draftDir, "SKILL.md"), skillMd, "utf-8");
45776
45959
  const directoryValidation = validateSkillDirectory(draftDir, { expectedName: skillName });
45777
45960
  if (!directoryValidation.ok) {
45778
45961
  try {
45779
- (0, import_node_fs6.rmSync)(draftDir, { recursive: true, force: true });
45962
+ (0, import_node_fs7.rmSync)(draftDir, { recursive: true, force: true });
45780
45963
  } catch {
45781
45964
  }
45782
45965
  throw new Error(`[skillForge] Skill \u76EE\u5F55\u6821\u9A8C\u5931\u8D25\uFF1A
@@ -45811,26 +45994,26 @@ ${formatSkillValidationIssues(validation)}`);
45811
45994
  }
45812
45995
  const target = assertSafeSkillTarget(this.skillsInstallDir, proposal.skillName);
45813
45996
  let installedTarget = target;
45814
- if ((0, import_node_fs6.existsSync)(target)) {
45997
+ if ((0, import_node_fs7.existsSync)(target)) {
45815
45998
  const alt = target + "-" + proposalId;
45816
- (0, import_node_fs6.mkdirSync)(alt, { recursive: true });
45817
- (0, import_node_fs6.cpSync)(proposal.draftDir, alt, { recursive: true });
45999
+ (0, import_node_fs7.mkdirSync)(alt, { recursive: true });
46000
+ (0, import_node_fs7.cpSync)(proposal.draftDir, alt, { recursive: true });
45818
46001
  installedTarget = alt;
45819
46002
  } else {
45820
- (0, import_node_fs6.mkdirSync)(target, { recursive: true });
45821
- (0, import_node_fs6.cpSync)(proposal.draftDir, target, { recursive: true });
46003
+ (0, import_node_fs7.mkdirSync)(target, { recursive: true });
46004
+ (0, import_node_fs7.cpSync)(proposal.draftDir, target, { recursive: true });
45822
46005
  }
45823
46006
  const smokeTest = smokeTestSkillDirectory(installedTarget, { expectedName: proposal.skillName });
45824
46007
  if (!smokeTest.ok) {
45825
46008
  try {
45826
- (0, import_node_fs6.rmSync)(installedTarget, { recursive: true, force: true });
46009
+ (0, import_node_fs7.rmSync)(installedTarget, { recursive: true, force: true });
45827
46010
  } catch {
45828
46011
  }
45829
46012
  throw new Error(`[skillForge] Skill smoke test \u5931\u8D25\uFF0C\u5DF2\u56DE\u6EDA\u843D\u5730\u76EE\u5F55\uFF1A
45830
46013
  ${formatSkillValidationIssues(smokeTest)}`);
45831
46014
  }
45832
46015
  try {
45833
- (0, import_node_fs6.rmSync)(proposal.draftDir, { recursive: true, force: true });
46016
+ (0, import_node_fs7.rmSync)(proposal.draftDir, { recursive: true, force: true });
45834
46017
  } catch {
45835
46018
  }
45836
46019
  await this.removeProposal(userId, proposalId);
@@ -45842,7 +46025,7 @@ ${formatSkillValidationIssues(smokeTest)}`);
45842
46025
  const proposal = list.find((p) => p.id === proposalId);
45843
46026
  if (!proposal) return null;
45844
46027
  try {
45845
- (0, import_node_fs6.rmSync)(proposal.draftDir, { recursive: true, force: true });
46028
+ (0, import_node_fs7.rmSync)(proposal.draftDir, { recursive: true, force: true });
45846
46029
  } catch {
45847
46030
  }
45848
46031
  await this.removeProposal(userId, proposalId);
@@ -46051,7 +46234,7 @@ var skillForgeDrop = (engine) => ({
46051
46234
  });
46052
46235
 
46053
46236
  // src/memory/MemoryEngine.ts
46054
- var import_node_crypto13 = require("node:crypto");
46237
+ var import_node_crypto14 = require("node:crypto");
46055
46238
  var MemoryEngine = class {
46056
46239
  storage;
46057
46240
  recallIndexStorage;
@@ -46079,7 +46262,7 @@ var MemoryEngine = class {
46079
46262
  }
46080
46263
  const now = Date.now();
46081
46264
  const memory = {
46082
- id: (0, import_node_crypto13.randomBytes)(4).toString("hex"),
46265
+ id: (0, import_node_crypto14.randomBytes)(4).toString("hex"),
46083
46266
  userId,
46084
46267
  title,
46085
46268
  content,
@@ -46731,13 +46914,13 @@ var COMPANY_VALUES_PROMPT = `<\u516C\u53F8\u5171\u540C\u4FE1\u5FF5>
46731
46914
  </\u516C\u53F8\u5171\u540C\u4FE1\u5FF5>`;
46732
46915
 
46733
46916
  // src/agent/outboundDedup.ts
46734
- var import_node_crypto14 = require("node:crypto");
46917
+ var import_node_crypto15 = require("node:crypto");
46735
46918
  var DEFAULT_WINDOW_MS = 15e3;
46736
46919
  var recentSends = /* @__PURE__ */ new Map();
46737
46920
  var lastSweepAt = 0;
46738
46921
  var normalize3 = (text2) => text2.replace(/\s+/g, " ").trim();
46739
46922
  var keyFor = (userId, normalized) => {
46740
- const hash = (0, import_node_crypto14.createHash)("sha1").update(normalized).digest("hex");
46923
+ const hash = (0, import_node_crypto15.createHash)("sha1").update(normalized).digest("hex");
46741
46924
  return `${userId}::${hash}`;
46742
46925
  };
46743
46926
  var sweep = (now, windowMs) => {
@@ -46785,12 +46968,12 @@ var isAbortError2 = (error) => {
46785
46968
  return error.name === "AbortError" || error.message.includes("aborted") || error.message.includes("AbortError");
46786
46969
  };
46787
46970
  var llmRequestIdForTurn = (request, messages, system, tools) => {
46788
- const hash = (0, import_node_crypto15.createHash)("sha256").update(request.requestId).update("\0").update(system).update("\0").update(JSON.stringify(messages)).update("\0").update(JSON.stringify(tools.map((tool) => tool.name).sort())).digest("hex").slice(0, 40);
46971
+ const hash = (0, import_node_crypto16.createHash)("sha256").update(request.requestId).update("\0").update(system).update("\0").update(JSON.stringify(messages)).update("\0").update(JSON.stringify(tools.map((tool) => tool.name).sort())).digest("hex").slice(0, 40);
46789
46972
  return `dreq_${hash}`;
46790
46973
  };
46791
46974
  var getDefaultAgentConfig = (tools, systemPrompt) => {
46792
46975
  loadEnv();
46793
- (0, import_node_fs7.mkdirSync)(DEFAULT_WORKSPACE_PATH, { recursive: true });
46976
+ (0, import_node_fs8.mkdirSync)(DEFAULT_WORKSPACE_PATH, { recursive: true });
46794
46977
  let system = ``;
46795
46978
  if (!systemPrompt) {
46796
46979
  system = `
@@ -46832,13 +47015,15 @@ ${RUNTIME_PROCESS_SAFETY_PROMPT}
46832
47015
 
46833
47016
  \u516C\u53F8\u91CC\u6709\u5404\u4E2A\u90E8\u95E8\u548C\u5B83\u4EEC\u7684\u8D1F\u8D23\u4EBA\uFF08Department Head\uFF09\u3002\u4E13\u4E1A\u7684\u6D3B\u2014\u2014\u5199\u4EE3\u7801\u3001\u8BFB\u4EE3\u7801\u5B9A\u4F4D\u95EE\u9898\u3001\u6539\u6587\u4EF6\u3001\u8DD1\u6D4B\u8BD5\u3001\u8C03\u8BD5\u3001\u90E8\u7F72\uFF0C\u5904\u7406\u6570\u636E/\u6587\u6863/\u97F3\u89C6\u9891/\u56FE\u7247\uFF0C\u67E5\u8BC1\u5916\u90E8 API\uFF0C\u751F\u6210\u590D\u6742\u4EA7\u7269\u7B49\u2014\u2014\u4F60\u7684\u7B2C\u4E00\u53CD\u5E94\u662F\u627E\u5BF9\u5E94\u56E2\u961F\u7684 Head\uFF0C\u800C\u4E0D\u662F\u81EA\u5DF1\u4E0A\u624B\u3002\u4F60\u80FD\u770B\u5230\u7684\u53EA\u6709\u90E8\u95E8\u548C\u5B83\u4EEC\u7684 Head\uFF1BExecutor \u7531\u5404 Head \u81EA\u5DF1\u7BA1\u7406\uFF0C\u9ED8\u8BA4\u4E0D\u5728\u4F60\u7684\u89C6\u91CE\u91CC\u3002
46834
47017
 
46835
- \u4F60\u548C\u56E2\u961F\u534F\u4F5C\u7684\u65B9\u5F0F\u5F88\u81EA\u7136\uFF1A\u9700\u8981\u56E2\u961F\u505A\u4E8B\uFF0C\u5C31\u7ED9\u5BF9\u5E94 Head \u53D1\u6D88\u606F\uFF08department_communicate\uFF09\uFF1B\u6709\u65B0\u7684\u80CC\u666F\u3001\u4FEE\u6B63\u8981\u6C42\u3001\u7528\u6237\u53CD\u9988\u6216\u5DF2\u7ECF\u8FC7\u4E86\u5408\u7406\u7B49\u5F85\u65F6\u95F4\u518D\u60F3\u50AC\u4E00\u4E0B\uFF0C\u7528 mailbox_followup \u63A5\u56DE\u539F\u6765\u7684\u7EBF\u7A0B\uFF1B\u60F3\u770B\u56E2\u961F\u56DE\u4E86\u4EC0\u4E48\uFF0C\u7528 check_department_replies \u6536\u4E00\u4E0B\u3002\u7EC4\u7EC7\u91CC\u8FD8\u6CA1\u6709\u5BF9\u53E3\u7684\u56E2\u961F\u65F6\uFF0C\u4F60\u624D\u5F20\u7F57\u7740\u5EFA\u90E8\u95E8\u3001\u62DB Head\uFF08\u5EFA\u597D\u90E8\u95E8\u5148\u7528 department_member_create \u51FA\u4E00\u4E2A Head\uFF0C\u518D\u628A\u5177\u4F53\u4EFB\u52A1\u6D3E\u7ED9\u4ED6\uFF09\u3002
47018
+ \u4F60\u548C\u56E2\u961F\u534F\u4F5C\u7684\u65B9\u5F0F\u5F88\u81EA\u7136\uFF1A\u9700\u8981\u56E2\u961F\u505A\u4E8B\uFF0C\u5C31\u7ED9\u5BF9\u5E94 Head \u53D1\u6D88\u606F\uFF08department_communicate\uFF09\uFF1B\u6709\u65B0\u7684\u80CC\u666F\u3001\u4FEE\u6B63\u8981\u6C42\u3001\u7528\u6237\u53CD\u9988\uFF0C\u6216\u5DF2\u7ECF\u8FC7\u4E86\u5408\u7406\u7B49\u5F85\u65F6\u95F4\u4E14\u786E\u5B9E\u9700\u8981\u8865\u5145\u8BE2\u95EE\u65F6\uFF0C\u7528 mailbox_followup \u63A5\u56DE\u539F\u6765\u7684\u7EBF\u7A0B\uFF1B\u60F3\u770B\u56E2\u961F\u56DE\u4E86\u4EC0\u4E48\uFF0C\u7528 check_department_replies \u6536\u4E00\u4E0B\u3002\u7EC4\u7EC7\u91CC\u8FD8\u6CA1\u6709\u5BF9\u53E3\u7684\u56E2\u961F\u65F6\uFF0C\u4F60\u624D\u5F20\u7F57\u7740\u5EFA\u90E8\u95E8\u3001\u62DB Head\uFF08\u5EFA\u597D\u90E8\u95E8\u5148\u7528 department_member_create \u51FA\u4E00\u4E2A Head\uFF0C\u518D\u628A\u5177\u4F53\u4EFB\u52A1\u6D3E\u7ED9\u4ED6\uFF09\u3002
46836
47019
 
46837
47020
  \u8001\u677F\u95EE\u4F60\u4EFB\u4F55\u4E8B\u2014\u2014\u5305\u62EC\u201C\u73B0\u5728\u8FDB\u5EA6\u5982\u4F55\u201D\u201C\u6D4B\u8BD5\u5F97\u600E\u4E48\u6837\u201D\u201C\u90A3\u8FB9\u9760\u8C31\u5417\u201D\u201C\u5361\u5728\u54EA\u4E86\u201D\u8FD9\u7C7B\u2014\u2014\u4F60\u7ED9\u7684\u90FD\u662F\u4F60\u5411\u56E2\u961F\u6838\u5B9E\u8FC7\u7684\u771F\u5B9E\u60C5\u51B5\uFF0C\u7EDD\u4E0D\u662F\u51ED\u5370\u8C61\u7F16\u51FA\u6765\u7684\u3002\u5982\u679C\u8FD9\u4F1A\u513F\u8FD8\u6CA1\u62FF\u5230\u51C6\u4FE1\uFF0C\u4F60\u5B81\u53EF\u5148\u56DE\u8001\u677F\u4E00\u53E5\u201C\u6211\u53BB\u8DDF\u56E2\u961F\u786E\u8BA4\uFF0C\u7A0D\u540E\u7ED9\u4F60\u56DE\u201D\uFF0C\u4E5F\u4E0D\u7CCA\u5F04\u4E00\u4E2A\u7B54\u6848\u3002\u5728\u4F60\u628A\u771F\u5B9E\u7ED3\u8BBA\u4EA4\u5230\u8001\u677F\u624B\u4E0A\u4E4B\u524D\uFF0C\u8FD9\u4EF6\u4E8B\u5BF9\u4F60\u90FD\u6CA1\u7B97\u5B8C\u3002
46838
47021
 
46839
47022
  \u67D0\u4E2A Head \u5DF2\u7ECF\u8D1F\u8D23\u7684\u4EA7\u51FA\uFF0C\u540E\u7EED\u7684\u8FD4\u5DE5\u3001bug \u4FEE\u590D\u3001\u201C\u6253\u4E0D\u5F00\u201D\u201C\u5E2E\u6211\u6539\u4E00\u4E0B\u201D\u201C\u518D\u51FA\u4E00\u7248\u201D\uFF0C\u9ED8\u8BA4\u8FD8\u5F52\u4ED6\u2014\u2014\u4F60\u987A\u7740\u539F\u6765\u7684\u7EBF\u7A0B\u628A\u53CD\u9988\u8FFD\u52A0\u7ED9\u4ED6\uFF08mailbox_followup\uFF09\uFF0C\u800C\u4E0D\u662F\u81EA\u5DF1\u63A5\u624B\u91CD\u505A\u3002
46840
47023
 
46841
- \u53EA\u6709\u8FD9\u51E0\u79CD\u60C5\u51B5\u4F60\u624D\u81EA\u5DF1\u4E0A\u624B\uFF1A\u8001\u677F\u660E\u786E\u8981\u4F60\u4EB2\u81EA\u505A\u3001\u7EC4\u7EC7\u91CC\u786E\u5B9E\u6CA1\u6709\u4E5F\u6765\u4E0D\u53CA\u7EC4\u5EFA\u5BF9\u53E3\u56E2\u961F\u3001\u6216\u56E2\u961F\u660E\u786E\u505A\u4E0D\u6210\u4E14\u8001\u677F\u540C\u610F\u4F60\u63A5\u7BA1\u3002\u9664\u6B64\u4E4B\u5916\uFF0C\u56E2\u961F\u56DE\u5F97\u6162\u3001\u6682\u65F6\u6CA1\u56DE\u3001check \u8FD8\u6CA1\u7ED3\u679C\uFF0C\u90FD\u4E0D\u662F\u4F60\u4E0B\u573A\u5E72\u6D3B\u7684\u7406\u7531\u3002\u521A\u628A\u4EFB\u52A1\u6D3E\u51FA\u53BB\u65F6\uFF0C\u4E0D\u8981\u7ACB\u523B\u50AC\u529E\uFF0C\u4E5F\u4E0D\u8981\u5728\u540C\u4E00\u8F6E\u8FDE\u7EED\u8FFD\u95EE\uFF1B\u8BE5\u505A\u7684\u662F\u5982\u5B9E\u8DDF\u8001\u677F\u8BF4\u201C\u5DF2\u5B89\u6392\u56E2\u961F\u5904\u7406\uFF0C\u6211\u62FF\u5230\u7ED3\u679C\u5C31\u540C\u6B65\u201D\uFF0C\u7136\u540E\u628A\u8FD9\u4E00\u8F6E\u6536\u4F4F\u3002\u53EA\u6709\u5DF2\u7ECF\u7B49\u5F85\u8FC7\u5408\u7406\u65F6\u95F4\u3001\u8001\u677F\u53C8\u8FFD\u95EE\u8FDB\u5EA6\u3001\u6216\u4F60\u53D1\u73B0\u660E\u786E\u98CE\u9669/\u963B\u585E\u65F6\uFF0C\u624D\u6CBF\u539F\u7EBF\u7A0B\u9002\u5EA6\u50AC\u8D1F\u8D23\u4EBA\u3002
47024
+ \u53EA\u6709\u8FD9\u51E0\u79CD\u60C5\u51B5\u4F60\u624D\u81EA\u5DF1\u4E0A\u624B\uFF1A\u8001\u677F\u660E\u786E\u8981\u4F60\u4EB2\u81EA\u505A\u3001\u7EC4\u7EC7\u91CC\u786E\u5B9E\u6CA1\u6709\u4E5F\u6765\u4E0D\u53CA\u7EC4\u5EFA\u5BF9\u53E3\u56E2\u961F\u3001\u6216\u56E2\u961F\u660E\u786E\u505A\u4E0D\u6210\u4E14\u8001\u677F\u540C\u610F\u4F60\u63A5\u7BA1\u3002\u9664\u6B64\u4E4B\u5916\uFF0C\u56E2\u961F\u56DE\u5F97\u6162\u3001\u6682\u65F6\u6CA1\u56DE\u3001check \u8FD8\u6CA1\u7ED3\u679C\uFF0C\u90FD\u4E0D\u662F\u4F60\u4E0B\u573A\u5E72\u6D3B\u7684\u7406\u7531\u3002\u521A\u628A\u4EFB\u52A1\u6D3E\u51FA\u53BB\u65F6\uFF0C\u4E0D\u8981\u7ACB\u523B\u50AC\u529E\uFF0C\u4E5F\u4E0D\u8981\u5728\u540C\u4E00\u8F6E\u8FDE\u7EED\u8FFD\u95EE\uFF1B\u8BE5\u505A\u7684\u662F\u5982\u5B9E\u8DDF\u8001\u677F\u8BF4\u201C\u5DF2\u5B89\u6392\u56E2\u961F\u5904\u7406\uFF0C\u6211\u62FF\u5230\u7ED3\u679C\u5C31\u540C\u6B65\u201D\uFF0C\u7136\u540E\u628A\u8FD9\u4E00\u8F6E\u6536\u4F4F\u3002\u53EA\u6709\u5DF2\u7ECF\u7B49\u5F85\u8FC7\u5408\u7406\u65F6\u95F4\u3001\u8001\u677F\u53C8\u8FFD\u95EE\u8FDB\u5EA6\u3001\u6216\u4F60\u53D1\u73B0\u660E\u786E\u98CE\u9669/\u963B\u585E\u65F6\uFF0C\u624D\u6CBF\u539F\u7EBF\u7A0B\u9002\u5EA6\u8BE2\u95EE\u8D1F\u8D23\u4EBA\u3002
47025
+
47026
+ \u5BF9\u8001\u677F\u6C47\u62A5\u65F6\u4E0D\u8981\u4F7F\u7528\u201C\u6211\u53BB\u50AC\u4E00\u4E0B / \u6211\u4F1A\u76EF\u7740 / \u5DF2\u7ECF\u50AC\u4E86 / \u7EE7\u7EED\u50AC\u8D1F\u8D23\u4EBA / \u8BA9\u4ED6\u5C3D\u5FEB\u56DE\u590D\u201D\u8FD9\u7C7B\u7BA1\u7406\u538B\u8FEB\u8BDD\u672F\u3002\u9ED8\u8BA4\u4F7F\u7528\u514B\u5236\u8868\u8FF0\uFF1A\u201C\u5DF2\u5B89\u6392\u7ED9\u8D1F\u8D23\u4EBA\u5904\u7406\uFF0C\u6211\u7B49\u56DE\u4FE1\u540E\u540C\u6B65\u201D\uFF1B\u9664\u975E\u786E\u5B9E\u5DF2\u7ECF\u8FC7\u4E86\u5408\u7406\u7B49\u5F85\u65F6\u95F4\u5E76\u4E14\u53D1\u751F\u4E86\u65B0\u7684\u8FFD\u95EE\u6216\u98CE\u9669\uFF0C\u5426\u5219\u4E0D\u8981\u6697\u793A\u4F60\u6B63\u5728\u50AC\u4EBA\u3002
46842
47027
 
46843
47028
  \u5F02\u5E38\u7B80\u5355\u3001\u4F4E\u98CE\u9669\u3001\u4E00\u4E24\u6B65\u5C31\u80FD\u5B8C\u6210\u7684\u5C0F\u4E8B\uFF08\u7B80\u5355\u95EE\u7B54\u3001\u89E3\u91CA\u5DF2\u6709\u4FE1\u606F\u3001\u770B\u4E2A\u5217\u8868\u3001\u67E5\u4E2A\u72B6\u6001\u3001\u8BFB\u4E00\u5C0F\u6BB5\u6587\u4EF6\uFF09\uFF0C\u4F60\u53EF\u4EE5\u987A\u624B\u81EA\u5DF1\u505A\uFF0C\u4E0D\u5FC5\u4EC0\u4E48\u90FD\u7EC4\u7EC7\u5316\u3002
46844
47029
  </\u4F60\u7684\u8EAB\u4EFD>
@@ -47021,7 +47206,8 @@ var createAgent = (config2 = getDefaultAgentConfig()) => {
47021
47206
  if (config2.workspacePath && !request.defaultWorkDir) {
47022
47207
  request.defaultWorkDir = config2.workspacePath;
47023
47208
  }
47024
- const { userId, content, job } = request;
47209
+ const { userId, job } = request;
47210
+ const content = attachRecentAttachmentContext(request, request.content);
47025
47211
  const internalOnly = request.metadata?.internalOnly === true;
47026
47212
  const injectedEventIds = /* @__PURE__ */ new Set();
47027
47213
  const interruptQueuedEventIds = /* @__PURE__ */ new Set();
@@ -48151,7 +48337,7 @@ var DESCRIPTION42 = `
48151
48337
  \u6B63\u5F0F\u56DE\u590D\u4E00\u5C01\u90AE\u4EF6\u3002\u5BF9\u5F53\u524D\u6D88\u606F\u5F62\u6210\u53EF\u4EE5\u4EA4\u4ED8\u7ED9\u5BF9\u65B9\u7684\u6700\u7EC8\u7ED3\u8BBA\u540E\uFF0C\u4F7F\u7528\u6B64\u5DE5\u5177\u5C06\u7ED3\u679C\u53D1\u56DE\u7ED9\u90AE\u4EF6\u53D1\u9001\u8005\uFF0C\u5E76\u7ED3\u675F\u8FD9\u5C01\u6D88\u606F\u7684\u5904\u7406\u3002
48152
48338
 
48153
48339
  \u5B83\u5728\u7EC4\u7EC7\u91CC\u7684\u542B\u4E49\u66F4\u63A5\u8FD1\u201C\u6211\u5DF2\u7ECF\u628A\u8FD9\u4EF6\u4E8B\u9A8C\u6536\u6E05\u695A\uFF0C\u53EF\u4EE5\u7ED9\u4F60\u4E00\u4E2A\u7ED3\u8BBA\u201D\uFF0C\u800C\u4E0D\u662F\u666E\u901A\u804A\u5929\u56DE\u590D\u3002
48154
- \u5982\u679C\u53EA\u662F\u540C\u6B65\u9636\u6BB5\u6027\u8FDB\u5C55\u3001\u8BF4\u660E\u5DF2\u5B89\u6392\u4E0B\u5C5E\u3001\u8FD8\u5728\u7B49\u5F85\u6267\u884C\u7ED3\u679C\u3001\u50AC\u529E\u3001\u8865\u5145\u4E0A\u4E0B\u6587\u6216\u5148\u7ED9\u90E8\u5206\u53D1\u73B0\uFF0C\u5E94\u4F7F\u7528 mailbox_followup\uFF0C\u8BA9\u539F\u90AE\u4EF6\u7EE7\u7EED\u4FDD\u6301\u672A\u5B8C\u5F85\u7EED\u3002
48340
+ \u5982\u679C\u53EA\u662F\u540C\u6B65\u9636\u6BB5\u6027\u8FDB\u5C55\u3001\u8BF4\u660E\u5DF2\u5B89\u6392\u4E0B\u5C5E\u3001\u8FD8\u5728\u7B49\u5F85\u6267\u884C\u7ED3\u679C\u3001\u8865\u5145\u4E0A\u4E0B\u6587\u3001\u8BE2\u95EE\u72B6\u6001\u6216\u5148\u7ED9\u90E8\u5206\u53D1\u73B0\uFF0C\u5E94\u4F7F\u7528 mailbox_followup\uFF0C\u8BA9\u539F\u90AE\u4EF6\u7EE7\u7EED\u4FDD\u6301\u672A\u5B8C\u5F85\u7EED\u3002
48155
48341
 
48156
48342
  \u53C2\u6570\uFF1A
48157
48343
  - message_id: \u8981\u56DE\u590D\u7684\u90AE\u4EF6 id\uFF08\u4ECE list_mailbox \u6216 get_mailbox \u4E2D\u83B7\u53D6\uFF09
@@ -48773,6 +48959,7 @@ var createDepartmentAgentTools = () => {
48773
48959
  registerTool(registry2, webSearchTool);
48774
48960
  registerTool(registry2, webFetchTool);
48775
48961
  registerTool(registry2, imageUnderstand);
48962
+ registerTool(registry2, imageGenerate);
48776
48963
  registerTool(registry2, goalCreate);
48777
48964
  registerTool(registry2, goalGet);
48778
48965
  registerTool(registry2, goalList);
@@ -48812,7 +48999,7 @@ var getDepartmentAgentConfig = (tools, memberFocusOn, workspacePath, departmentN
48812
48999
 
48813
49000
  \u8C01\u628A\u4E8B\u4EA4\u7ED9\u4F60\u3001\u8C01\u6765\u95EE\u4F60\uFF08\u901A\u5E38\u662F CEO\uFF09\uFF0C\u4F60\u5C31\u6B20\u4ED6\u4E00\u4E2A\u4EA4\u4EE3\u3002\u5728\u4F60\u628A\u6838\u5B9E\u8FC7\u7684\u771F\u5B9E\u7ED3\u8BBA\u4EA4\u56DE\u5230\u95EE\u4F60\u7684\u4EBA\u624B\u4E0A\u4E4B\u524D\uFF0C\u8FD9\u4EF6\u4E8B\u5BF9\u4F60\u90FD\u6CA1\u7B97\u5B8C\u2014\u2014\u4F60\u987A\u7740\u539F\u6765\u90A3\u5C01\u8BF7\u6C42\u7684\u7EBF\u7A0B\uFF0C\u7528\u5B83\u7684 message_id \u56DE\u7ED9\u4E0A\u6E38\uFF08reply_mailbox \u6216 mailbox_followup\uFF09\uFF1B\u53EA\u56DE\u590D Executor \u4E0D\u7B49\u4E8E\u5411\u4E0A\u6E38\u4EA4\u4EE3\u4E86\uFF0C\u90A3\u6837 CEO \u548C\u8001\u677F\u90A3\u8FB9\u6536\u4E0D\u5230\u3002\u4E0A\u6E38\u518D\u6765\u50AC\u540C\u4E00\u4EF6\u4E8B\uFF0C\u54EA\u6015\u4F60\u624B\u91CC\u5DF2\u7ECF\u6709\u6700\u7EC8\u62A5\u544A\uFF0C\u4E5F\u7167\u6837\u628A\u62A5\u544A\u6216\u7B80\u660E\u72B6\u6001\u56DE\u7ED9\u4ED6\u3002
48814
49001
 
48815
- Executor \u56DE\u5F97\u6162\u3001\u6682\u65F6\u6CA1\u56DE\uFF0C\u4E0D\u662F\u4F60\u81EA\u5DF1\u4E0B\u573A\u91CD\u505A\u7684\u7406\u7531\u2014\u2014\u8BE5\u505A\u7684\u662F mailbox_followup \u50AC\u4E00\u4E0B\uFF0C\u5E76\u5982\u5B9E\u8DDF\u4E0A\u6E38\u8BF4\u8FD8\u5728\u7B49\u6267\u884C\u7ED3\u679C\u3002\u7ED9\u4E0A\u6E38\u540C\u6B65\u201C\u5DF2\u5B89\u6392\u3001\u8FD8\u5728\u7B49\u3001\u5DF2\u50AC\u4FC3\u3001\u5DF2\u6709\u90E8\u5206\u53D1\u73B0\u201D\u8FD9\u7C7B\u8FDB\u5C55\uFF0C\u7528 mailbox_followup\uFF1B\u7B49\u4F60\u9A8C\u6536\u5B8C\u771F\u5B9E\u7ED3\u679C\u3001\u53EF\u4EE5\u7ED9\u51FA\u6700\u7EC8\u6C47\u603B\u65F6\uFF0C\u518D\u7528 reply_mailbox \u6B63\u5F0F\u4EA4\u4ED8\u7ED3\u8BBA\u3002\u53EA\u6709\u4E0A\u6E38\u660E\u786E\u8981\u4F60\u4EB2\u81EA\u505A\u3001\u90E8\u95E8\u91CC\u786E\u5B9E\u6CA1\u6709\u4E5F\u6765\u4E0D\u53CA\u7EC4\u5EFA\u5408\u9002\u7684 Executor\u3001\u6216 Executor \u660E\u786E\u505A\u4E0D\u6210\u4E14\u4E0A\u6E38\u540C\u610F\u4F60\u63A5\u7BA1\u65F6\uFF0C\u4F60\u624D\u81EA\u5DF1\u4E0A\u624B\u90A3\u4E9B\u6267\u884C\u7C7B\u5DE5\u5177\u3002` : `\u4F60\u662F\u6267\u884C\u8005\uFF08Executor\uFF09\u3002\u522B\u4EBA\uFF08\u901A\u5E38\u662F\u4F60\u7684\u90E8\u95E8\u8D1F\u8D23\u4EBA\uFF09\u628A\u5177\u4F53\u4EFB\u52A1\u6D3E\u7ED9\u4F60\uFF0C\u4F60\u5C31\u7528\u81EA\u5DF1\u7684\u4E13\u4E1A\u80FD\u529B\u548C\u5DE5\u5177\u628A\u5B83\u505A\u51FA\u6765\uFF0C\u518D\u5982\u5B9E\u628A\u7ED3\u679C\u56DE\u7ED9\u95EE\u4F60\u7684\u4EBA\u3002\u4F60\u4E13\u6CE8\u505A\u4E8B\uFF0C\u4E0D\u53BB\u67E5\u770B\u6574\u4E2A\u90E8\u95E8\u6210\u5458\u540D\u518C\uFF0C\u4E5F\u4E0D\u521B\u5EFA\u6210\u5458\u2014\u2014\u7EC4\u5EFA\u56E2\u961F\u662F\u8D1F\u8D23\u4EBA\u7684\u4E8B\u3002`;
49002
+ Executor \u56DE\u5F97\u6162\u3001\u6682\u65F6\u6CA1\u56DE\uFF0C\u4E0D\u662F\u4F60\u81EA\u5DF1\u4E0B\u573A\u91CD\u505A\u7684\u7406\u7531\u2014\u2014\u8BE5\u505A\u7684\u662F\u7ED9\u4E0B\u5C5E\u5408\u7406\u5904\u7406\u65F6\u95F4\uFF1B\u5982\u679C\u786E\u6709\u65B0\u80CC\u666F\u3001\u660E\u786E\u98CE\u9669\u6216\u5DF2\u7ECF\u8FC7\u4E86\u5408\u7406\u7B49\u5F85\u65F6\u95F4\uFF0C\u518D\u7528 mailbox_followup \u8865\u5145\u4E0A\u4E0B\u6587\u6216\u8BE2\u95EE\u771F\u5B9E\u72B6\u6001\uFF0C\u5E76\u5982\u5B9E\u8DDF\u4E0A\u6E38\u8BF4\u8FD8\u5728\u7B49\u6267\u884C\u7ED3\u679C\u3002\u7ED9\u4E0A\u6E38\u540C\u6B65\u201C\u5DF2\u5B89\u6392\u3001\u8FD8\u5728\u7B49\u3001\u5DF2\u6709\u90E8\u5206\u53D1\u73B0\u201D\u8FD9\u7C7B\u8FDB\u5C55\uFF0C\u7528 mailbox_followup\uFF1B\u7B49\u4F60\u9A8C\u6536\u5B8C\u771F\u5B9E\u7ED3\u679C\u3001\u53EF\u4EE5\u7ED9\u51FA\u6700\u7EC8\u6C47\u603B\u65F6\uFF0C\u518D\u7528 reply_mailbox \u6B63\u5F0F\u4EA4\u4ED8\u7ED3\u8BBA\u3002\u53EA\u6709\u4E0A\u6E38\u660E\u786E\u8981\u4F60\u4EB2\u81EA\u505A\u3001\u90E8\u95E8\u91CC\u786E\u5B9E\u6CA1\u6709\u4E5F\u6765\u4E0D\u53CA\u7EC4\u5EFA\u5408\u9002\u7684 Executor\u3001\u6216 Executor \u660E\u786E\u505A\u4E0D\u6210\u4E14\u4E0A\u6E38\u540C\u610F\u4F60\u63A5\u7BA1\u65F6\uFF0C\u4F60\u624D\u81EA\u5DF1\u4E0A\u624B\u90A3\u4E9B\u6267\u884C\u7C7B\u5DE5\u5177\u3002` : `\u4F60\u662F\u6267\u884C\u8005\uFF08Executor\uFF09\u3002\u522B\u4EBA\uFF08\u901A\u5E38\u662F\u4F60\u7684\u90E8\u95E8\u8D1F\u8D23\u4EBA\uFF09\u628A\u5177\u4F53\u4EFB\u52A1\u6D3E\u7ED9\u4F60\uFF0C\u4F60\u5C31\u7528\u81EA\u5DF1\u7684\u4E13\u4E1A\u80FD\u529B\u548C\u5DE5\u5177\u628A\u5B83\u505A\u51FA\u6765\uFF0C\u518D\u5982\u5B9E\u628A\u7ED3\u679C\u56DE\u7ED9\u95EE\u4F60\u7684\u4EBA\u3002\u4F60\u4E13\u6CE8\u505A\u4E8B\uFF0C\u4E0D\u53BB\u67E5\u770B\u6574\u4E2A\u90E8\u95E8\u6210\u5458\u540D\u518C\uFF0C\u4E5F\u4E0D\u521B\u5EFA\u6210\u5458\u2014\u2014\u7EC4\u5EFA\u56E2\u961F\u662F\u8D1F\u8D23\u4EBA\u7684\u4E8B\u3002`;
48816
49003
  const defaultSystemPrompt = `
48817
49004
  ${COMPANY_VALUES_PROMPT}
48818
49005
 
@@ -48841,8 +49028,8 @@ ${workspacePath ? `
48841
49028
  \u4F60\u901A\u8FC7\u90AE\u7BB1\u548C\u540C\u4E8B\u534F\u4F5C\u3002\u6536\u5230\u65B0\u90AE\u4EF6\u63D0\u9192\u540E\uFF0C\u7528 list_mailbox \u770B\u770B\u6709\u54EA\u4E9B\u5F85\u5904\u7406\u7684\u90AE\u4EF6\uFF0C\u6311\u4E00\u5C01\u7528 get_mailbox \u9886\u53D6\u5E76\u8BFB\u5168\u6587\uFF0C\u628A\u5B83\u505A\u5B8C\u6216\u95EE\u6E05\u695A\uFF0C\u518D\u56DE\u590D\u3002\u5904\u7406\u5B8C\u4E00\u5C01\u7EE7\u7EED list_mailbox \u770B\u4E0B\u4E00\u5C01\u3002
48842
49029
 
48843
49030
  \u51E0\u4E2A\u5DE5\u5177\u7684\u542B\u4E49\u8981\u5206\u6E05\uFF0C\u522B\u53EA\u7528\u81EA\u7136\u8BED\u8A00\u8BF4\u8BF4\u5C31\u7B97\u6570\uFF1A
48844
- - mailbox_followup(message_id, content)\uFF1A\u5728\u540C\u4E00\u7EBF\u7A0B\u91CC\u7EE7\u7EED\u6C9F\u901A\u2014\u2014\u540C\u6B65\u8FDB\u5C55\u3001\u8865\u5145\u7ED3\u679C\u3001\u8FFD\u95EE\u6216\u50AC\u529E\uFF1B\u53EF\u4EE5\u591A\u6B21\uFF0C\u4E0D\u4F1A\u7ED3\u675F\u8FD9\u5C01\u90AE\u4EF6\u3002
48845
- - reply_mailbox(message_id, content)\uFF1A\u4F60\u5BF9\u8FD9\u5C01\u90AE\u4EF6\u5DF2\u7ECF\u5F62\u6210\u53EF\u4EE5\u4EA4\u4ED8\u7ED9\u5BF9\u65B9\u7684\u6B63\u5F0F\u7ED3\u8BBA\uFF0C\u56DE\u590D\u5E76\u7ED3\u675F\u5B83\u3002\u6BCF\u5C01\u90AE\u4EF6\u7528\u5B83\u81EA\u5DF1\u7684 message_id \u56DE\u590D\uFF0C\u522B\u62FF\u4E00\u6BB5\u8BDD\u540C\u65F6\u5145\u5F53\u591A\u5C01\u90AE\u4EF6\u7684\u7B54\u590D\u3002\u8FD8\u5728\u7B49\u5F85\u4E0B\u6E38\u3001\u53EA\u662F\u540C\u6B65\u5B89\u6392\u6216\u50AC\u529E\u65F6\uFF0C\u4E0D\u8981\u7528\u5B83\u7ED3\u675F\u4E0A\u6E38\u8BF7\u6C42\u3002
49031
+ - mailbox_followup(message_id, content)\uFF1A\u5728\u540C\u4E00\u7EBF\u7A0B\u91CC\u7EE7\u7EED\u6C9F\u901A\u2014\u2014\u540C\u6B65\u8FDB\u5C55\u3001\u8865\u5145\u7ED3\u679C\u3001\u8865\u5145\u4E0A\u4E0B\u6587\u6216\u8BE2\u95EE\u72B6\u6001\uFF1B\u53EF\u4EE5\u591A\u6B21\uFF0C\u4E0D\u4F1A\u7ED3\u675F\u8FD9\u5C01\u90AE\u4EF6\u3002
49032
+ - reply_mailbox(message_id, content)\uFF1A\u4F60\u5BF9\u8FD9\u5C01\u90AE\u4EF6\u5DF2\u7ECF\u5F62\u6210\u53EF\u4EE5\u4EA4\u4ED8\u7ED9\u5BF9\u65B9\u7684\u6B63\u5F0F\u7ED3\u8BBA\uFF0C\u56DE\u590D\u5E76\u7ED3\u675F\u5B83\u3002\u6BCF\u5C01\u90AE\u4EF6\u7528\u5B83\u81EA\u5DF1\u7684 message_id \u56DE\u590D\uFF0C\u522B\u62FF\u4E00\u6BB5\u8BDD\u540C\u65F6\u5145\u5F53\u591A\u5C01\u90AE\u4EF6\u7684\u7B54\u590D\u3002\u8FD8\u5728\u7B49\u5F85\u4E0B\u6E38\u3001\u53EA\u662F\u540C\u6B65\u5B89\u6392\u6216\u8BE2\u95EE\u72B6\u6001\u65F6\uFF0C\u4E0D\u8981\u7528\u5B83\u7ED3\u675F\u4E0A\u6E38\u8BF7\u6C42\u3002
48846
49033
  - discard_mailbox(message_id, reason)\uFF1A\u53EA\u6709\u5F53\u8FD9\u5C01\u90AE\u4EF6\u786E\u5B9E\u65E0\u9700\u4E1A\u52A1\u56DE\u590D\uFF08\u7EAF\u56DE\u6267\u3001\u91CD\u590D\u901A\u77E5\u3001\u5DF2\u88AB\u5176\u4ED6\u90AE\u4EF6\u8986\u76D6\uFF09\u65F6\u624D\u7528\uFF1B\u5B83\u4F1A\u7ED3\u675F\u90AE\u4EF6\uFF0C\u4F46\u4E0D\u4F1A\u7ED9\u53D1\u9001\u8005\u56DE\u4FE1\u3002
48847
49034
  - \u9700\u8981\u4E3B\u52A8\u8054\u7CFB\u522B\u7684\u90E8\u95E8\u6210\u5458\uFF0C\u7528 department_communicate\u3002
48848
49035
 
@@ -51862,7 +52049,7 @@ var cors = (options) => {
51862
52049
 
51863
52050
  // src/server/index.ts
51864
52051
  var import_promises14 = require("node:fs/promises");
51865
- var import_node_path19 = __toESM(require("node:path"));
52052
+ var import_node_path20 = __toESM(require("node:path"));
51866
52053
 
51867
52054
  // src/git/worktree.ts
51868
52055
  var import_child_process2 = require("child_process");
@@ -53207,8 +53394,8 @@ mailboxRoutes.get("/mailbox/summary", (c) => {
53207
53394
 
53208
53395
  // src/server/routes/memory.ts
53209
53396
  var import_redis4 = __toESM(require_dist2());
53210
- var import_node_fs8 = require("node:fs");
53211
- var import_node_path16 = __toESM(require("node:path"));
53397
+ var import_node_fs9 = require("node:fs");
53398
+ var import_node_path17 = __toESM(require("node:path"));
53212
53399
  var memoryEngineSingleton = null;
53213
53400
  var dreamStorageSingleton = null;
53214
53401
  var dreamHistoryStorageSingleton = null;
@@ -53308,12 +53495,12 @@ var addPlausibleUserId = (set, userId) => {
53308
53495
  if (normalized && isPlausibleUserId(normalized)) set.add(normalized);
53309
53496
  };
53310
53497
  var readJsonFilesFromDir = (dir) => {
53311
- if (!(0, import_node_fs8.existsSync)(dir)) return [];
53498
+ if (!(0, import_node_fs9.existsSync)(dir)) return [];
53312
53499
  const result = [];
53313
- for (const file of (0, import_node_fs8.readdirSync)(dir)) {
53500
+ for (const file of (0, import_node_fs9.readdirSync)(dir)) {
53314
53501
  if (!file.endsWith(".json")) continue;
53315
53502
  try {
53316
- result.push(JSON.parse((0, import_node_fs8.readFileSync)(import_node_path16.default.join(dir, file), "utf-8")));
53503
+ result.push(JSON.parse((0, import_node_fs9.readFileSync)(import_node_path17.default.join(dir, file), "utf-8")));
53317
53504
  } catch (err) {
53318
53505
  console.warn(`[memoryRoutes] \u8DF3\u8FC7\u65E0\u6CD5\u89E3\u6790\u7684\u672C\u5730\u4E0A\u4E0B\u6587\u6587\u4EF6 ${file}: ${err.message}`);
53319
53506
  }
@@ -53321,13 +53508,13 @@ var readJsonFilesFromDir = (dir) => {
53321
53508
  return result;
53322
53509
  };
53323
53510
  var extractFileBackedStorageKeysForTest = (dataDir) => {
53324
- const kvRoot = import_node_path16.default.join(dataDir, "kv");
53325
- if (!(0, import_node_fs8.existsSync)(kvRoot)) return [];
53511
+ const kvRoot = import_node_path17.default.join(dataDir, "kv");
53512
+ if (!(0, import_node_fs9.existsSync)(kvRoot)) return [];
53326
53513
  const keys = [];
53327
- for (const prefixDir of (0, import_node_fs8.readdirSync)(kvRoot)) {
53328
- const absolutePrefixDir = import_node_path16.default.join(kvRoot, prefixDir);
53329
- if (!(0, import_node_fs8.existsSync)(absolutePrefixDir)) continue;
53330
- for (const file of (0, import_node_fs8.readdirSync)(absolutePrefixDir)) {
53514
+ for (const prefixDir of (0, import_node_fs9.readdirSync)(kvRoot)) {
53515
+ const absolutePrefixDir = import_node_path17.default.join(kvRoot, prefixDir);
53516
+ if (!(0, import_node_fs9.existsSync)(absolutePrefixDir)) continue;
53517
+ for (const file of (0, import_node_fs9.readdirSync)(absolutePrefixDir)) {
53331
53518
  if (!file.endsWith(".json")) continue;
53332
53519
  try {
53333
53520
  const logicalKey = Buffer.from(file.replace(/\.json$/, ""), "base64url").toString("utf8");
@@ -53345,12 +53532,12 @@ var collectLocalConversationUserIds = () => {
53345
53532
  };
53346
53533
  var extractLocalConversationUserIdsForTest = (homeDir) => {
53347
53534
  const userIds = /* @__PURE__ */ new Set();
53348
- for (const context of readJsonFilesFromDir(import_node_path16.default.join(homeDir, "goal-context"))) {
53535
+ for (const context of readJsonFilesFromDir(import_node_path17.default.join(homeDir, "goal-context"))) {
53349
53536
  addPlausibleUserId(userIds, context.threadId);
53350
53537
  addPlausibleUserId(userIds, context.originUserId);
53351
53538
  if (context.goalId) addPlausibleUserId(userIds, `kanban:goal:${context.goalId}`);
53352
53539
  }
53353
- for (const goal of readJsonFilesFromDir(import_node_path16.default.join(homeDir, "tasks"))) {
53540
+ for (const goal of readJsonFilesFromDir(import_node_path17.default.join(homeDir, "tasks"))) {
53354
53541
  if (goal.id) addPlausibleUserId(userIds, `kanban:goal:${goal.id}`);
53355
53542
  }
53356
53543
  return userIds;
@@ -53767,7 +53954,7 @@ ${item.dreamContent}` : item.dreamContent).join("\n\n");
53767
53954
  });
53768
53955
 
53769
53956
  // src/server/routes/tools.ts
53770
- var import_node_path17 = __toESM(require("node:path"));
53957
+ var import_node_path18 = __toESM(require("node:path"));
53771
53958
  var toolRoutes = new Hono2();
53772
53959
  var listActiveDepartmentSkills = () => {
53773
53960
  return listDepartments().flatMap(
@@ -53778,7 +53965,7 @@ var listActiveDepartmentSkills = () => {
53778
53965
  scope: "department",
53779
53966
  departmentName: department.name,
53780
53967
  detail: () => {
53781
- const skillDir = import_node_path17.default.join(getDepartmentWorkSpaceDir(department.name), "skills", skill.skillName);
53968
+ const skillDir = import_node_path18.default.join(getDepartmentWorkSpaceDir(department.name), "skills", skill.skillName);
53782
53969
  return `Base directory for this skill: ${skillDir}
53783
53970
 
53784
53971
  ${skill.skillMd}`;
@@ -53867,7 +54054,7 @@ var systemRoutes = new Hono2();
53867
54054
  var startTime = Date.now();
53868
54055
  systemRoutes.get("/system/info", (c) => {
53869
54056
  return c.json({
53870
- version: true ? "1.9.12" : "unknown",
54057
+ version: true ? "1.9.14" : "unknown",
53871
54058
  uptime: Math.floor((Date.now() - startTime) / 1e3),
53872
54059
  env: process.env.NODE_ENV || "development",
53873
54060
  nodeVersion: process.version
@@ -53875,9 +54062,9 @@ systemRoutes.get("/system/info", (c) => {
53875
54062
  });
53876
54063
 
53877
54064
  // src/server/routes/mobile.ts
53878
- var import_node_crypto16 = require("node:crypto");
54065
+ var import_node_crypto17 = require("node:crypto");
53879
54066
  var import_promises13 = require("node:fs/promises");
53880
- var import_node_path18 = __toESM(require("node:path"));
54067
+ var import_node_path19 = __toESM(require("node:path"));
53881
54068
  var mobileRoutes = new Hono2();
53882
54069
  var resolveMobileUserId = (body, headerUserId) => {
53883
54070
  return body.userId?.trim() || headerUserId?.trim() || "ios:local-user";
@@ -53919,12 +54106,12 @@ ${goal.tasks.map((task) => `- [${task.status}] ${task.subject}`).join("\n")}` :
53919
54106
  return lines.join("\n");
53920
54107
  };
53921
54108
  var sanitizeFileName = (fileName) => {
53922
- const cleaned = import_node_path18.default.basename(fileName).replace(/[^\w.\-()\u4e00-\u9fa5 ]+/g, "_").trim();
54109
+ const cleaned = import_node_path19.default.basename(fileName).replace(/[^\w.\-()\u4e00-\u9fa5 ]+/g, "_").trim();
53923
54110
  return cleaned || `attachment-${Date.now()}`;
53924
54111
  };
53925
54112
  var inferAttachmentType2 = (mimeType = "", fileName = "") => {
53926
54113
  if (mimeType.startsWith("image/")) return "image";
53927
- const ext = import_node_path18.default.extname(fileName).toLowerCase();
54114
+ const ext = import_node_path19.default.extname(fileName).toLowerCase();
53928
54115
  if ([".png", ".jpg", ".jpeg", ".gif", ".webp"].includes(ext)) return "image";
53929
54116
  return "file";
53930
54117
  };
@@ -53979,11 +54166,11 @@ mobileRoutes.post("/mobile/attachments", async (c) => {
53979
54166
  const fileName = sanitizeFileName(body.fileName || `attachment-${Date.now()}`);
53980
54167
  const mimeType = body.mimeType || "application/octet-stream";
53981
54168
  const type = inferAttachmentType2(mimeType, fileName);
53982
- const attachmentId = (0, import_node_crypto16.randomUUID)();
54169
+ const attachmentId = (0, import_node_crypto17.randomUUID)();
53983
54170
  const buffer = Buffer.from(dataBase64, "base64");
53984
- const dir = import_node_path18.default.join(getDuclawWorkspaceDir(), mobileUserId, "mobile", type === "image" ? "images" : "files");
54171
+ const dir = import_node_path19.default.join(getDuclawWorkspaceDir(), mobileUserId, "mobile", type === "image" ? "images" : "files");
53985
54172
  await (0, import_promises13.mkdir)(dir, { recursive: true });
53986
- const localPath = import_node_path18.default.join(dir, `${attachmentId}-${fileName}`);
54173
+ const localPath = import_node_path19.default.join(dir, `${attachmentId}-${fileName}`);
53987
54174
  await (0, import_promises13.writeFile)(localPath, buffer);
53988
54175
  const attachment = saveMobileAttachment({
53989
54176
  id: attachmentId,
@@ -54011,7 +54198,7 @@ mobileRoutes.post("/mobile/messages", async (c) => {
54011
54198
  }
54012
54199
  const mobileUserId = resolveMobileUserId(body, c.req.header("x-user-id"));
54013
54200
  const threadId = resolveThreadId(body.goalId, mobileUserId);
54014
- const requestId = body.clientMessageId?.trim() || (0, import_node_crypto16.randomUUID)();
54201
+ const requestId = body.clientMessageId?.trim() || (0, import_node_crypto17.randomUUID)();
54015
54202
  const agentText = body.contextText?.trim() || text2;
54016
54203
  const attachmentContent = buildContentWithAttachments(agentText, attachments);
54017
54204
  const content = buildGoalPrompt(body.goalId, attachmentContent.content);
@@ -54202,7 +54389,7 @@ function createServer() {
54202
54389
  app.route("/api", mobileRoutes);
54203
54390
  app.use("/*", serveStatic({ root: webDistRoot }));
54204
54391
  app.get("/*", async (c) => {
54205
- const indexHtml = await (0, import_promises14.readFile)(import_node_path19.default.join(webDistRoot, "index.html"), "utf8");
54392
+ const indexHtml = await (0, import_promises14.readFile)(import_node_path20.default.join(webDistRoot, "index.html"), "utf8");
54206
54393
  const tenantId = c.req.header("x-tenant-id");
54207
54394
  const assetBase = tenantId ? `/t/${tenantId}` : "";
54208
54395
  const html = indexHtml.replaceAll('"./', `"${assetBase}/`);
@@ -54229,10 +54416,10 @@ function shouldStartCoreChannelGateways(env = process.env) {
54229
54416
  }
54230
54417
 
54231
54418
  // src/runtime/saasAssets.ts
54232
- var import_node_fs9 = require("node:fs");
54419
+ var import_node_fs10 = require("node:fs");
54233
54420
  var import_promises15 = require("node:fs/promises");
54234
54421
  var import_node_os3 = require("node:os");
54235
- var import_node_path20 = __toESM(require("node:path"));
54422
+ var import_node_path21 = __toESM(require("node:path"));
54236
54423
  var MAX_CONTEXT_ASSETS = Number(process.env.DUCLAW_SAAS_ASSET_CONTEXT_LIMIT ?? 1e3);
54237
54424
  var MAX_SKILL_ASSETS = Number(process.env.DUCLAW_SAAS_ASSET_SKILL_LIMIT ?? 200);
54238
54425
  async function restoreSaasRuntimeAssets(reason) {
@@ -54262,8 +54449,8 @@ async function restoreSaasRuntimeAssets(reason) {
54262
54449
  async function restoreContextAsset(context, overwrite) {
54263
54450
  const target = contextPathForSourceKey(context.sourceKey);
54264
54451
  if (!target) return false;
54265
- if (!overwrite && (0, import_node_fs9.existsSync)(target)) return false;
54266
- await (0, import_promises15.mkdir)(import_node_path20.default.dirname(target), { recursive: true });
54452
+ if (!overwrite && (0, import_node_fs10.existsSync)(target)) return false;
54453
+ await (0, import_promises15.mkdir)(import_node_path21.default.dirname(target), { recursive: true });
54267
54454
  await (0, import_promises15.writeFile)(target, JSON.stringify(context.payload), "utf8");
54268
54455
  return true;
54269
54456
  }
@@ -54271,8 +54458,8 @@ async function restoreSkillAsset(skill, overwrite) {
54271
54458
  if (!skill.skillMd) return false;
54272
54459
  const target = safeSkillTargetPath(skill.sourcePath, skill.skillName);
54273
54460
  if (!target) return false;
54274
- if (!overwrite && (0, import_node_fs9.existsSync)(target)) return false;
54275
- await (0, import_promises15.mkdir)(import_node_path20.default.dirname(target), { recursive: true });
54461
+ if (!overwrite && (0, import_node_fs10.existsSync)(target)) return false;
54462
+ await (0, import_promises15.mkdir)(import_node_path21.default.dirname(target), { recursive: true });
54276
54463
  await (0, import_promises15.writeFile)(target, skill.skillMd, "utf8");
54277
54464
  return true;
54278
54465
  }
@@ -54305,30 +54492,30 @@ function runtimeAssetClient() {
54305
54492
  function contextPathForSourceKey(sourceKey) {
54306
54493
  if (sourceKey.startsWith("agent:")) {
54307
54494
  const logicalKey = sourceKey.slice("agent:".length);
54308
- return import_node_path20.default.join(getDuclawDataDir(), "kv", "agent", `${Buffer.from(logicalKey).toString("base64url")}.json`);
54495
+ return import_node_path21.default.join(getDuclawDataDir(), "kv", "agent", `${Buffer.from(logicalKey).toString("base64url")}.json`);
54309
54496
  }
54310
54497
  if (sourceKey.startsWith("goal-context:")) {
54311
- return import_node_path20.default.join(getDuclawHomeDir(), "goal-context", `${sourceKey.slice("goal-context:".length)}.json`);
54498
+ return import_node_path21.default.join(getDuclawHomeDir(), "goal-context", `${sourceKey.slice("goal-context:".length)}.json`);
54312
54499
  }
54313
54500
  if (sourceKey.startsWith("tasks:")) {
54314
- return import_node_path20.default.join(getDuclawHomeDir(), "tasks", `${sourceKey.slice("tasks:".length)}.json`);
54501
+ return import_node_path21.default.join(getDuclawHomeDir(), "tasks", `${sourceKey.slice("tasks:".length)}.json`);
54315
54502
  }
54316
54503
  return null;
54317
54504
  }
54318
54505
  function safeSkillTargetPath(sourcePath, skillName) {
54319
- const allowedRoots = skillRoots().map((root) => import_node_path20.default.resolve(root));
54320
- const normalized = import_node_path20.default.resolve(sourcePath);
54321
- if (allowedRoots.some((root) => normalized === import_node_path20.default.join(root, import_node_path20.default.basename(import_node_path20.default.dirname(normalized)), "SKILL.md"))) {
54506
+ const allowedRoots = skillRoots().map((root) => import_node_path21.default.resolve(root));
54507
+ const normalized = import_node_path21.default.resolve(sourcePath);
54508
+ if (allowedRoots.some((root) => normalized === import_node_path21.default.join(root, import_node_path21.default.basename(import_node_path21.default.dirname(normalized)), "SKILL.md"))) {
54322
54509
  return normalized;
54323
54510
  }
54324
54511
  const safeName = skillName.replace(/[^a-zA-Z0-9._-]/g, "-").slice(0, 120) || "imported-skill";
54325
- return import_node_path20.default.join("/home/user/app/skills", safeName, "SKILL.md");
54512
+ return import_node_path21.default.join("/home/user/app/skills", safeName, "SKILL.md");
54326
54513
  }
54327
54514
  function skillRoots() {
54328
54515
  return [
54329
54516
  "/home/user/app/skills",
54330
- import_node_path20.default.join(getDuclawHomeDir(), "skills"),
54331
- import_node_path20.default.join((0, import_node_os3.homedir)(), ".agents", "skills")
54517
+ import_node_path21.default.join(getDuclawHomeDir(), "skills"),
54518
+ import_node_path21.default.join((0, import_node_os3.homedir)(), ".agents", "skills")
54332
54519
  ];
54333
54520
  }
54334
54521