duclaw-cli 1.9.13 → 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 +312 -129
- package/dist/main.js +1 -1
- package/dist/worker-main.js +1 -1
- package/package.json +1 -1
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.
|
|
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
|
|
32291
|
+
const dirname8 = sp.dirname(file);
|
|
32292
32292
|
const basename4 = sp.basename(file);
|
|
32293
|
-
const parent = this.fsw._getWatchedDir(
|
|
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(
|
|
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
|
|
33283
|
-
var
|
|
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, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
42582
|
+
var import_node_crypto9 = require("node:crypto");
|
|
42401
42583
|
|
|
42402
42584
|
// src/department/mailbox/mailbox.ts
|
|
42403
|
-
var
|
|
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
|
|
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,
|
|
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
|
|
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,
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
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,
|
|
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),
|
|
@@ -43967,13 +44149,13 @@ ${replies}`;
|
|
|
43967
44149
|
};
|
|
43968
44150
|
|
|
43969
44151
|
// src/department/learning.ts
|
|
43970
|
-
var
|
|
43971
|
-
var
|
|
43972
|
-
var
|
|
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
|
|
43976
|
-
var
|
|
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 =
|
|
44003
|
-
const target =
|
|
44004
|
-
if (target !==
|
|
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 =
|
|
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 =
|
|
44082
|
-
if (!target.startsWith(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,
|
|
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 =
|
|
44102
|
-
if (!(0,
|
|
44103
|
-
const entries = (0,
|
|
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 =
|
|
44112
|
-
const skillMdPath =
|
|
44113
|
-
if (!(0,
|
|
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,
|
|
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,
|
|
44303
|
+
const raw2 = (0, import_node_fs4.readFileSync)(skillMdPath, `utf-8`);
|
|
44122
44304
|
const documentResult = validateSkillDocument({
|
|
44123
|
-
skillName: options.expectedName ??
|
|
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,
|
|
44357
|
+
var ensureDir = (dir) => (0, import_node_fs5.mkdirSync)(dir, { recursive: true });
|
|
44176
44358
|
var readJsonArray = (filePath) => {
|
|
44177
|
-
if (!(0,
|
|
44178
|
-
return JSON.parse((0,
|
|
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(
|
|
44182
|
-
(0,
|
|
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
|
|
44367
|
+
return import_node_path15.default.join(getDepartmentWorkSpaceDir(departmentName), "department-memory.json");
|
|
44186
44368
|
};
|
|
44187
44369
|
var departmentSkillPath = (departmentName) => {
|
|
44188
|
-
return
|
|
44370
|
+
return import_node_path15.default.join(getDepartmentWorkSpaceDir(departmentName), "department-skills.json");
|
|
44189
44371
|
};
|
|
44190
44372
|
var departmentSkillDir = (departmentName, skillName) => {
|
|
44191
|
-
return assertSafeSkillTarget(
|
|
44373
|
+
return assertSafeSkillTarget(import_node_path15.default.join(getDepartmentWorkSpaceDir(departmentName), "skills"), skillName);
|
|
44192
44374
|
};
|
|
44193
44375
|
var proposalsPath = () => {
|
|
44194
|
-
return
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
44495
|
+
id: (0, import_node_crypto11.randomUUID)().slice(0, 8),
|
|
44314
44496
|
status: "pending",
|
|
44315
44497
|
createdAt: Date.now()
|
|
44316
44498
|
};
|
|
@@ -44669,8 +44851,8 @@ var mailboxFollowup = {
|
|
|
44669
44851
|
|
|
44670
44852
|
// src/tools/tools/Bash.ts
|
|
44671
44853
|
var import_node_child_process = require("node:child_process");
|
|
44672
|
-
var
|
|
44673
|
-
var
|
|
44854
|
+
var import_node_crypto12 = require("node:crypto");
|
|
44855
|
+
var import_node_fs6 = require("node:fs");
|
|
44674
44856
|
var DESCRIPTION30 = `\u5728\u7CFB\u7EDF shell \u4E2D\u6267\u884C\u547D\u4EE4\u3002
|
|
44675
44857
|
|
|
44676
44858
|
\u7528\u9014\uFF1A
|
|
@@ -44710,7 +44892,7 @@ var sessions = /* @__PURE__ */ new Map();
|
|
|
44710
44892
|
function findExecutableShell2() {
|
|
44711
44893
|
for (const shell of SHELL_CANDIDATES2) {
|
|
44712
44894
|
try {
|
|
44713
|
-
(0,
|
|
44895
|
+
(0, import_node_fs6.accessSync)(shell, import_node_fs6.constants.X_OK);
|
|
44714
44896
|
return shell;
|
|
44715
44897
|
} catch {
|
|
44716
44898
|
}
|
|
@@ -44719,11 +44901,11 @@ function findExecutableShell2() {
|
|
|
44719
44901
|
}
|
|
44720
44902
|
function validateCwd(cwd) {
|
|
44721
44903
|
try {
|
|
44722
|
-
const stat11 = (0,
|
|
44904
|
+
const stat11 = (0, import_node_fs6.statSync)(cwd);
|
|
44723
44905
|
if (!stat11.isDirectory()) {
|
|
44724
44906
|
return `[bash] \u9519\u8BEF: cwd \u4E0D\u662F\u76EE\u5F55: ${cwd}`;
|
|
44725
44907
|
}
|
|
44726
|
-
(0,
|
|
44908
|
+
(0, import_node_fs6.accessSync)(cwd, import_node_fs6.constants.R_OK | import_node_fs6.constants.X_OK);
|
|
44727
44909
|
return null;
|
|
44728
44910
|
} catch (err) {
|
|
44729
44911
|
const code = err.code;
|
|
@@ -44966,7 +45148,7 @@ var bashTool = {
|
|
|
44966
45148
|
stdio: ["pipe", "pipe", "pipe"],
|
|
44967
45149
|
detached: process.platform !== "win32"
|
|
44968
45150
|
});
|
|
44969
|
-
const id = (0,
|
|
45151
|
+
const id = (0, import_node_crypto12.randomUUID)().slice(0, 8);
|
|
44970
45152
|
const session = {
|
|
44971
45153
|
id,
|
|
44972
45154
|
command,
|
|
@@ -45733,10 +45915,10 @@ var readDreamHistoryLimit = () => {
|
|
|
45733
45915
|
};
|
|
45734
45916
|
|
|
45735
45917
|
// src/skillForge/SkillForgeEngine.ts
|
|
45736
|
-
var
|
|
45918
|
+
var import_node_fs7 = require("node:fs");
|
|
45737
45919
|
var import_node_os2 = require("node:os");
|
|
45738
|
-
var
|
|
45739
|
-
var
|
|
45920
|
+
var import_node_path16 = require("node:path");
|
|
45921
|
+
var import_node_crypto13 = require("node:crypto");
|
|
45740
45922
|
var SkillForgeEngine = class {
|
|
45741
45923
|
proposalStorage;
|
|
45742
45924
|
draftRoot;
|
|
@@ -45744,8 +45926,8 @@ var SkillForgeEngine = class {
|
|
|
45744
45926
|
constructor(deps) {
|
|
45745
45927
|
this.proposalStorage = deps.proposalStorage;
|
|
45746
45928
|
const opt = deps.options ?? {};
|
|
45747
|
-
this.draftRoot = opt.draftRoot ?? (0,
|
|
45748
|
-
this.skillsInstallDir = opt.skillsInstallDir ?? (0,
|
|
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");
|
|
45749
45931
|
}
|
|
45750
45932
|
// ---------- 公开方法 ----------
|
|
45751
45933
|
/**
|
|
@@ -45770,14 +45952,14 @@ ${formatSkillValidationIssues(validation)}`);
|
|
|
45770
45952
|
if (pending.some((p) => p.skillName === skillName)) {
|
|
45771
45953
|
return null;
|
|
45772
45954
|
}
|
|
45773
|
-
const id = (0,
|
|
45774
|
-
const draftDir = (0,
|
|
45775
|
-
(0,
|
|
45776
|
-
(0,
|
|
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");
|
|
45777
45959
|
const directoryValidation = validateSkillDirectory(draftDir, { expectedName: skillName });
|
|
45778
45960
|
if (!directoryValidation.ok) {
|
|
45779
45961
|
try {
|
|
45780
|
-
(0,
|
|
45962
|
+
(0, import_node_fs7.rmSync)(draftDir, { recursive: true, force: true });
|
|
45781
45963
|
} catch {
|
|
45782
45964
|
}
|
|
45783
45965
|
throw new Error(`[skillForge] Skill \u76EE\u5F55\u6821\u9A8C\u5931\u8D25\uFF1A
|
|
@@ -45812,26 +45994,26 @@ ${formatSkillValidationIssues(validation)}`);
|
|
|
45812
45994
|
}
|
|
45813
45995
|
const target = assertSafeSkillTarget(this.skillsInstallDir, proposal.skillName);
|
|
45814
45996
|
let installedTarget = target;
|
|
45815
|
-
if ((0,
|
|
45997
|
+
if ((0, import_node_fs7.existsSync)(target)) {
|
|
45816
45998
|
const alt = target + "-" + proposalId;
|
|
45817
|
-
(0,
|
|
45818
|
-
(0,
|
|
45999
|
+
(0, import_node_fs7.mkdirSync)(alt, { recursive: true });
|
|
46000
|
+
(0, import_node_fs7.cpSync)(proposal.draftDir, alt, { recursive: true });
|
|
45819
46001
|
installedTarget = alt;
|
|
45820
46002
|
} else {
|
|
45821
|
-
(0,
|
|
45822
|
-
(0,
|
|
46003
|
+
(0, import_node_fs7.mkdirSync)(target, { recursive: true });
|
|
46004
|
+
(0, import_node_fs7.cpSync)(proposal.draftDir, target, { recursive: true });
|
|
45823
46005
|
}
|
|
45824
46006
|
const smokeTest = smokeTestSkillDirectory(installedTarget, { expectedName: proposal.skillName });
|
|
45825
46007
|
if (!smokeTest.ok) {
|
|
45826
46008
|
try {
|
|
45827
|
-
(0,
|
|
46009
|
+
(0, import_node_fs7.rmSync)(installedTarget, { recursive: true, force: true });
|
|
45828
46010
|
} catch {
|
|
45829
46011
|
}
|
|
45830
46012
|
throw new Error(`[skillForge] Skill smoke test \u5931\u8D25\uFF0C\u5DF2\u56DE\u6EDA\u843D\u5730\u76EE\u5F55\uFF1A
|
|
45831
46013
|
${formatSkillValidationIssues(smokeTest)}`);
|
|
45832
46014
|
}
|
|
45833
46015
|
try {
|
|
45834
|
-
(0,
|
|
46016
|
+
(0, import_node_fs7.rmSync)(proposal.draftDir, { recursive: true, force: true });
|
|
45835
46017
|
} catch {
|
|
45836
46018
|
}
|
|
45837
46019
|
await this.removeProposal(userId, proposalId);
|
|
@@ -45843,7 +46025,7 @@ ${formatSkillValidationIssues(smokeTest)}`);
|
|
|
45843
46025
|
const proposal = list.find((p) => p.id === proposalId);
|
|
45844
46026
|
if (!proposal) return null;
|
|
45845
46027
|
try {
|
|
45846
|
-
(0,
|
|
46028
|
+
(0, import_node_fs7.rmSync)(proposal.draftDir, { recursive: true, force: true });
|
|
45847
46029
|
} catch {
|
|
45848
46030
|
}
|
|
45849
46031
|
await this.removeProposal(userId, proposalId);
|
|
@@ -46052,7 +46234,7 @@ var skillForgeDrop = (engine) => ({
|
|
|
46052
46234
|
});
|
|
46053
46235
|
|
|
46054
46236
|
// src/memory/MemoryEngine.ts
|
|
46055
|
-
var
|
|
46237
|
+
var import_node_crypto14 = require("node:crypto");
|
|
46056
46238
|
var MemoryEngine = class {
|
|
46057
46239
|
storage;
|
|
46058
46240
|
recallIndexStorage;
|
|
@@ -46080,7 +46262,7 @@ var MemoryEngine = class {
|
|
|
46080
46262
|
}
|
|
46081
46263
|
const now = Date.now();
|
|
46082
46264
|
const memory = {
|
|
46083
|
-
id: (0,
|
|
46265
|
+
id: (0, import_node_crypto14.randomBytes)(4).toString("hex"),
|
|
46084
46266
|
userId,
|
|
46085
46267
|
title,
|
|
46086
46268
|
content,
|
|
@@ -46732,13 +46914,13 @@ var COMPANY_VALUES_PROMPT = `<\u516C\u53F8\u5171\u540C\u4FE1\u5FF5>
|
|
|
46732
46914
|
</\u516C\u53F8\u5171\u540C\u4FE1\u5FF5>`;
|
|
46733
46915
|
|
|
46734
46916
|
// src/agent/outboundDedup.ts
|
|
46735
|
-
var
|
|
46917
|
+
var import_node_crypto15 = require("node:crypto");
|
|
46736
46918
|
var DEFAULT_WINDOW_MS = 15e3;
|
|
46737
46919
|
var recentSends = /* @__PURE__ */ new Map();
|
|
46738
46920
|
var lastSweepAt = 0;
|
|
46739
46921
|
var normalize3 = (text2) => text2.replace(/\s+/g, " ").trim();
|
|
46740
46922
|
var keyFor = (userId, normalized) => {
|
|
46741
|
-
const hash = (0,
|
|
46923
|
+
const hash = (0, import_node_crypto15.createHash)("sha1").update(normalized).digest("hex");
|
|
46742
46924
|
return `${userId}::${hash}`;
|
|
46743
46925
|
};
|
|
46744
46926
|
var sweep = (now, windowMs) => {
|
|
@@ -46786,12 +46968,12 @@ var isAbortError2 = (error) => {
|
|
|
46786
46968
|
return error.name === "AbortError" || error.message.includes("aborted") || error.message.includes("AbortError");
|
|
46787
46969
|
};
|
|
46788
46970
|
var llmRequestIdForTurn = (request, messages, system, tools) => {
|
|
46789
|
-
const hash = (0,
|
|
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);
|
|
46790
46972
|
return `dreq_${hash}`;
|
|
46791
46973
|
};
|
|
46792
46974
|
var getDefaultAgentConfig = (tools, systemPrompt) => {
|
|
46793
46975
|
loadEnv();
|
|
46794
|
-
(0,
|
|
46976
|
+
(0, import_node_fs8.mkdirSync)(DEFAULT_WORKSPACE_PATH, { recursive: true });
|
|
46795
46977
|
let system = ``;
|
|
46796
46978
|
if (!systemPrompt) {
|
|
46797
46979
|
system = `
|
|
@@ -47024,7 +47206,8 @@ var createAgent = (config2 = getDefaultAgentConfig()) => {
|
|
|
47024
47206
|
if (config2.workspacePath && !request.defaultWorkDir) {
|
|
47025
47207
|
request.defaultWorkDir = config2.workspacePath;
|
|
47026
47208
|
}
|
|
47027
|
-
const { userId,
|
|
47209
|
+
const { userId, job } = request;
|
|
47210
|
+
const content = attachRecentAttachmentContext(request, request.content);
|
|
47028
47211
|
const internalOnly = request.metadata?.internalOnly === true;
|
|
47029
47212
|
const injectedEventIds = /* @__PURE__ */ new Set();
|
|
47030
47213
|
const interruptQueuedEventIds = /* @__PURE__ */ new Set();
|
|
@@ -51866,7 +52049,7 @@ var cors = (options) => {
|
|
|
51866
52049
|
|
|
51867
52050
|
// src/server/index.ts
|
|
51868
52051
|
var import_promises14 = require("node:fs/promises");
|
|
51869
|
-
var
|
|
52052
|
+
var import_node_path20 = __toESM(require("node:path"));
|
|
51870
52053
|
|
|
51871
52054
|
// src/git/worktree.ts
|
|
51872
52055
|
var import_child_process2 = require("child_process");
|
|
@@ -53211,8 +53394,8 @@ mailboxRoutes.get("/mailbox/summary", (c) => {
|
|
|
53211
53394
|
|
|
53212
53395
|
// src/server/routes/memory.ts
|
|
53213
53396
|
var import_redis4 = __toESM(require_dist2());
|
|
53214
|
-
var
|
|
53215
|
-
var
|
|
53397
|
+
var import_node_fs9 = require("node:fs");
|
|
53398
|
+
var import_node_path17 = __toESM(require("node:path"));
|
|
53216
53399
|
var memoryEngineSingleton = null;
|
|
53217
53400
|
var dreamStorageSingleton = null;
|
|
53218
53401
|
var dreamHistoryStorageSingleton = null;
|
|
@@ -53312,12 +53495,12 @@ var addPlausibleUserId = (set, userId) => {
|
|
|
53312
53495
|
if (normalized && isPlausibleUserId(normalized)) set.add(normalized);
|
|
53313
53496
|
};
|
|
53314
53497
|
var readJsonFilesFromDir = (dir) => {
|
|
53315
|
-
if (!(0,
|
|
53498
|
+
if (!(0, import_node_fs9.existsSync)(dir)) return [];
|
|
53316
53499
|
const result = [];
|
|
53317
|
-
for (const file of (0,
|
|
53500
|
+
for (const file of (0, import_node_fs9.readdirSync)(dir)) {
|
|
53318
53501
|
if (!file.endsWith(".json")) continue;
|
|
53319
53502
|
try {
|
|
53320
|
-
result.push(JSON.parse((0,
|
|
53503
|
+
result.push(JSON.parse((0, import_node_fs9.readFileSync)(import_node_path17.default.join(dir, file), "utf-8")));
|
|
53321
53504
|
} catch (err) {
|
|
53322
53505
|
console.warn(`[memoryRoutes] \u8DF3\u8FC7\u65E0\u6CD5\u89E3\u6790\u7684\u672C\u5730\u4E0A\u4E0B\u6587\u6587\u4EF6 ${file}: ${err.message}`);
|
|
53323
53506
|
}
|
|
@@ -53325,13 +53508,13 @@ var readJsonFilesFromDir = (dir) => {
|
|
|
53325
53508
|
return result;
|
|
53326
53509
|
};
|
|
53327
53510
|
var extractFileBackedStorageKeysForTest = (dataDir) => {
|
|
53328
|
-
const kvRoot =
|
|
53329
|
-
if (!(0,
|
|
53511
|
+
const kvRoot = import_node_path17.default.join(dataDir, "kv");
|
|
53512
|
+
if (!(0, import_node_fs9.existsSync)(kvRoot)) return [];
|
|
53330
53513
|
const keys = [];
|
|
53331
|
-
for (const prefixDir of (0,
|
|
53332
|
-
const absolutePrefixDir =
|
|
53333
|
-
if (!(0,
|
|
53334
|
-
for (const file of (0,
|
|
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)) {
|
|
53335
53518
|
if (!file.endsWith(".json")) continue;
|
|
53336
53519
|
try {
|
|
53337
53520
|
const logicalKey = Buffer.from(file.replace(/\.json$/, ""), "base64url").toString("utf8");
|
|
@@ -53349,12 +53532,12 @@ var collectLocalConversationUserIds = () => {
|
|
|
53349
53532
|
};
|
|
53350
53533
|
var extractLocalConversationUserIdsForTest = (homeDir) => {
|
|
53351
53534
|
const userIds = /* @__PURE__ */ new Set();
|
|
53352
|
-
for (const context of readJsonFilesFromDir(
|
|
53535
|
+
for (const context of readJsonFilesFromDir(import_node_path17.default.join(homeDir, "goal-context"))) {
|
|
53353
53536
|
addPlausibleUserId(userIds, context.threadId);
|
|
53354
53537
|
addPlausibleUserId(userIds, context.originUserId);
|
|
53355
53538
|
if (context.goalId) addPlausibleUserId(userIds, `kanban:goal:${context.goalId}`);
|
|
53356
53539
|
}
|
|
53357
|
-
for (const goal of readJsonFilesFromDir(
|
|
53540
|
+
for (const goal of readJsonFilesFromDir(import_node_path17.default.join(homeDir, "tasks"))) {
|
|
53358
53541
|
if (goal.id) addPlausibleUserId(userIds, `kanban:goal:${goal.id}`);
|
|
53359
53542
|
}
|
|
53360
53543
|
return userIds;
|
|
@@ -53771,7 +53954,7 @@ ${item.dreamContent}` : item.dreamContent).join("\n\n");
|
|
|
53771
53954
|
});
|
|
53772
53955
|
|
|
53773
53956
|
// src/server/routes/tools.ts
|
|
53774
|
-
var
|
|
53957
|
+
var import_node_path18 = __toESM(require("node:path"));
|
|
53775
53958
|
var toolRoutes = new Hono2();
|
|
53776
53959
|
var listActiveDepartmentSkills = () => {
|
|
53777
53960
|
return listDepartments().flatMap(
|
|
@@ -53782,7 +53965,7 @@ var listActiveDepartmentSkills = () => {
|
|
|
53782
53965
|
scope: "department",
|
|
53783
53966
|
departmentName: department.name,
|
|
53784
53967
|
detail: () => {
|
|
53785
|
-
const skillDir =
|
|
53968
|
+
const skillDir = import_node_path18.default.join(getDepartmentWorkSpaceDir(department.name), "skills", skill.skillName);
|
|
53786
53969
|
return `Base directory for this skill: ${skillDir}
|
|
53787
53970
|
|
|
53788
53971
|
${skill.skillMd}`;
|
|
@@ -53871,7 +54054,7 @@ var systemRoutes = new Hono2();
|
|
|
53871
54054
|
var startTime = Date.now();
|
|
53872
54055
|
systemRoutes.get("/system/info", (c) => {
|
|
53873
54056
|
return c.json({
|
|
53874
|
-
version: true ? "1.9.
|
|
54057
|
+
version: true ? "1.9.14" : "unknown",
|
|
53875
54058
|
uptime: Math.floor((Date.now() - startTime) / 1e3),
|
|
53876
54059
|
env: process.env.NODE_ENV || "development",
|
|
53877
54060
|
nodeVersion: process.version
|
|
@@ -53879,9 +54062,9 @@ systemRoutes.get("/system/info", (c) => {
|
|
|
53879
54062
|
});
|
|
53880
54063
|
|
|
53881
54064
|
// src/server/routes/mobile.ts
|
|
53882
|
-
var
|
|
54065
|
+
var import_node_crypto17 = require("node:crypto");
|
|
53883
54066
|
var import_promises13 = require("node:fs/promises");
|
|
53884
|
-
var
|
|
54067
|
+
var import_node_path19 = __toESM(require("node:path"));
|
|
53885
54068
|
var mobileRoutes = new Hono2();
|
|
53886
54069
|
var resolveMobileUserId = (body, headerUserId) => {
|
|
53887
54070
|
return body.userId?.trim() || headerUserId?.trim() || "ios:local-user";
|
|
@@ -53923,12 +54106,12 @@ ${goal.tasks.map((task) => `- [${task.status}] ${task.subject}`).join("\n")}` :
|
|
|
53923
54106
|
return lines.join("\n");
|
|
53924
54107
|
};
|
|
53925
54108
|
var sanitizeFileName = (fileName) => {
|
|
53926
|
-
const cleaned =
|
|
54109
|
+
const cleaned = import_node_path19.default.basename(fileName).replace(/[^\w.\-()\u4e00-\u9fa5 ]+/g, "_").trim();
|
|
53927
54110
|
return cleaned || `attachment-${Date.now()}`;
|
|
53928
54111
|
};
|
|
53929
54112
|
var inferAttachmentType2 = (mimeType = "", fileName = "") => {
|
|
53930
54113
|
if (mimeType.startsWith("image/")) return "image";
|
|
53931
|
-
const ext =
|
|
54114
|
+
const ext = import_node_path19.default.extname(fileName).toLowerCase();
|
|
53932
54115
|
if ([".png", ".jpg", ".jpeg", ".gif", ".webp"].includes(ext)) return "image";
|
|
53933
54116
|
return "file";
|
|
53934
54117
|
};
|
|
@@ -53983,11 +54166,11 @@ mobileRoutes.post("/mobile/attachments", async (c) => {
|
|
|
53983
54166
|
const fileName = sanitizeFileName(body.fileName || `attachment-${Date.now()}`);
|
|
53984
54167
|
const mimeType = body.mimeType || "application/octet-stream";
|
|
53985
54168
|
const type = inferAttachmentType2(mimeType, fileName);
|
|
53986
|
-
const attachmentId = (0,
|
|
54169
|
+
const attachmentId = (0, import_node_crypto17.randomUUID)();
|
|
53987
54170
|
const buffer = Buffer.from(dataBase64, "base64");
|
|
53988
|
-
const dir =
|
|
54171
|
+
const dir = import_node_path19.default.join(getDuclawWorkspaceDir(), mobileUserId, "mobile", type === "image" ? "images" : "files");
|
|
53989
54172
|
await (0, import_promises13.mkdir)(dir, { recursive: true });
|
|
53990
|
-
const localPath =
|
|
54173
|
+
const localPath = import_node_path19.default.join(dir, `${attachmentId}-${fileName}`);
|
|
53991
54174
|
await (0, import_promises13.writeFile)(localPath, buffer);
|
|
53992
54175
|
const attachment = saveMobileAttachment({
|
|
53993
54176
|
id: attachmentId,
|
|
@@ -54015,7 +54198,7 @@ mobileRoutes.post("/mobile/messages", async (c) => {
|
|
|
54015
54198
|
}
|
|
54016
54199
|
const mobileUserId = resolveMobileUserId(body, c.req.header("x-user-id"));
|
|
54017
54200
|
const threadId = resolveThreadId(body.goalId, mobileUserId);
|
|
54018
|
-
const requestId = body.clientMessageId?.trim() || (0,
|
|
54201
|
+
const requestId = body.clientMessageId?.trim() || (0, import_node_crypto17.randomUUID)();
|
|
54019
54202
|
const agentText = body.contextText?.trim() || text2;
|
|
54020
54203
|
const attachmentContent = buildContentWithAttachments(agentText, attachments);
|
|
54021
54204
|
const content = buildGoalPrompt(body.goalId, attachmentContent.content);
|
|
@@ -54206,7 +54389,7 @@ function createServer() {
|
|
|
54206
54389
|
app.route("/api", mobileRoutes);
|
|
54207
54390
|
app.use("/*", serveStatic({ root: webDistRoot }));
|
|
54208
54391
|
app.get("/*", async (c) => {
|
|
54209
|
-
const indexHtml = await (0, import_promises14.readFile)(
|
|
54392
|
+
const indexHtml = await (0, import_promises14.readFile)(import_node_path20.default.join(webDistRoot, "index.html"), "utf8");
|
|
54210
54393
|
const tenantId = c.req.header("x-tenant-id");
|
|
54211
54394
|
const assetBase = tenantId ? `/t/${tenantId}` : "";
|
|
54212
54395
|
const html = indexHtml.replaceAll('"./', `"${assetBase}/`);
|
|
@@ -54233,10 +54416,10 @@ function shouldStartCoreChannelGateways(env = process.env) {
|
|
|
54233
54416
|
}
|
|
54234
54417
|
|
|
54235
54418
|
// src/runtime/saasAssets.ts
|
|
54236
|
-
var
|
|
54419
|
+
var import_node_fs10 = require("node:fs");
|
|
54237
54420
|
var import_promises15 = require("node:fs/promises");
|
|
54238
54421
|
var import_node_os3 = require("node:os");
|
|
54239
|
-
var
|
|
54422
|
+
var import_node_path21 = __toESM(require("node:path"));
|
|
54240
54423
|
var MAX_CONTEXT_ASSETS = Number(process.env.DUCLAW_SAAS_ASSET_CONTEXT_LIMIT ?? 1e3);
|
|
54241
54424
|
var MAX_SKILL_ASSETS = Number(process.env.DUCLAW_SAAS_ASSET_SKILL_LIMIT ?? 200);
|
|
54242
54425
|
async function restoreSaasRuntimeAssets(reason) {
|
|
@@ -54266,8 +54449,8 @@ async function restoreSaasRuntimeAssets(reason) {
|
|
|
54266
54449
|
async function restoreContextAsset(context, overwrite) {
|
|
54267
54450
|
const target = contextPathForSourceKey(context.sourceKey);
|
|
54268
54451
|
if (!target) return false;
|
|
54269
|
-
if (!overwrite && (0,
|
|
54270
|
-
await (0, import_promises15.mkdir)(
|
|
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 });
|
|
54271
54454
|
await (0, import_promises15.writeFile)(target, JSON.stringify(context.payload), "utf8");
|
|
54272
54455
|
return true;
|
|
54273
54456
|
}
|
|
@@ -54275,8 +54458,8 @@ async function restoreSkillAsset(skill, overwrite) {
|
|
|
54275
54458
|
if (!skill.skillMd) return false;
|
|
54276
54459
|
const target = safeSkillTargetPath(skill.sourcePath, skill.skillName);
|
|
54277
54460
|
if (!target) return false;
|
|
54278
|
-
if (!overwrite && (0,
|
|
54279
|
-
await (0, import_promises15.mkdir)(
|
|
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 });
|
|
54280
54463
|
await (0, import_promises15.writeFile)(target, skill.skillMd, "utf8");
|
|
54281
54464
|
return true;
|
|
54282
54465
|
}
|
|
@@ -54309,30 +54492,30 @@ function runtimeAssetClient() {
|
|
|
54309
54492
|
function contextPathForSourceKey(sourceKey) {
|
|
54310
54493
|
if (sourceKey.startsWith("agent:")) {
|
|
54311
54494
|
const logicalKey = sourceKey.slice("agent:".length);
|
|
54312
|
-
return
|
|
54495
|
+
return import_node_path21.default.join(getDuclawDataDir(), "kv", "agent", `${Buffer.from(logicalKey).toString("base64url")}.json`);
|
|
54313
54496
|
}
|
|
54314
54497
|
if (sourceKey.startsWith("goal-context:")) {
|
|
54315
|
-
return
|
|
54498
|
+
return import_node_path21.default.join(getDuclawHomeDir(), "goal-context", `${sourceKey.slice("goal-context:".length)}.json`);
|
|
54316
54499
|
}
|
|
54317
54500
|
if (sourceKey.startsWith("tasks:")) {
|
|
54318
|
-
return
|
|
54501
|
+
return import_node_path21.default.join(getDuclawHomeDir(), "tasks", `${sourceKey.slice("tasks:".length)}.json`);
|
|
54319
54502
|
}
|
|
54320
54503
|
return null;
|
|
54321
54504
|
}
|
|
54322
54505
|
function safeSkillTargetPath(sourcePath, skillName) {
|
|
54323
|
-
const allowedRoots = skillRoots().map((root) =>
|
|
54324
|
-
const normalized =
|
|
54325
|
-
if (allowedRoots.some((root) => normalized ===
|
|
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"))) {
|
|
54326
54509
|
return normalized;
|
|
54327
54510
|
}
|
|
54328
54511
|
const safeName = skillName.replace(/[^a-zA-Z0-9._-]/g, "-").slice(0, 120) || "imported-skill";
|
|
54329
|
-
return
|
|
54512
|
+
return import_node_path21.default.join("/home/user/app/skills", safeName, "SKILL.md");
|
|
54330
54513
|
}
|
|
54331
54514
|
function skillRoots() {
|
|
54332
54515
|
return [
|
|
54333
54516
|
"/home/user/app/skills",
|
|
54334
|
-
|
|
54335
|
-
|
|
54517
|
+
import_node_path21.default.join(getDuclawHomeDir(), "skills"),
|
|
54518
|
+
import_node_path21.default.join((0, import_node_os3.homedir)(), ".agents", "skills")
|
|
54336
54519
|
];
|
|
54337
54520
|
}
|
|
54338
54521
|
|