@dai_ming/plugin-deliverables 1.1.5 → 1.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -47,9 +47,9 @@ deliverables__upload_deliverable
47
47
  配置字段:
48
48
 
49
49
  - `kbBaseUrl` — 知识库 API 内部地址(Pod 内通信)
50
- - `kbPublicUrl` — 用户可见的预览链接地址
51
50
 
52
- 环境变量 `KNOWLEDGE_DB_URL` / `KNOWLEDGE_DB_PUBLIC_URL` 可覆盖配置文件值。`KNOWLEDGE_DB_API_KEY` 仅通过环境变量配置(默认 `kb-agent-key-2025`)。
51
+ 环境变量 `KNOWLEDGE_DB_URL` 可覆盖配置文件值。`KNOWLEDGE_DB_API_KEY` 仅通过环境变量配置(默认 `kb-agent-key-2025`)。
52
+ IM 交付物链接信任校验使用固定前缀规则:`https://uniclaw-ai-kb`、`http://knowledge-db` 或 `http://localhost`。
53
53
 
54
54
  ## 发布
55
55
 
@@ -1,4 +1,3 @@
1
1
  {
2
- "kbBaseUrl": "http://knowledge-db:8080/api/v1",
3
- "kbPublicUrl": "https://uniclaw-ai-kb.csaiagent.com/api/v1"
2
+ "kbBaseUrl": "http://knowledge-db:8080/api/v1"
4
3
  }
@@ -1,4 +1,3 @@
1
1
  {
2
- "kbBaseUrl": "http://knowledge-db:8080/api/v1",
3
- "kbPublicUrl": "https://uniclaw-ai-kb.csagentai.com/api/v1"
2
+ "kbBaseUrl": "http://knowledge-db:8080/api/v1"
4
3
  }
@@ -1,4 +1,3 @@
1
1
  {
2
- "kbBaseUrl": "http://knowledge-db:8080/api/v1",
3
- "kbPublicUrl": "https://uniclaw-ai-kb.csjkagent.com/api/v1"
2
+ "kbBaseUrl": "http://knowledge-db:8080/api/v1"
4
3
  }
package/index.js CHANGED
@@ -54,7 +54,7 @@ const AUTO_UPLOAD_MAX_FILES = 8;
54
54
  const AUTO_UPLOAD_MAX_BYTES = 200 * 1024 * 1024;
55
55
  const AUTO_UPLOAD_SCAN_MAX_ENTRIES = 4000;
56
56
  const AUTO_UPLOAD_SCAN_DEPTH = 5;
57
- const DELIVERABLE_KB_PATH_RE = /\/documents\/content\b/u;
57
+ const DELIVERABLE_KB_PATH_RE = /\/documents\/(?:content|preview)(?:\/|$)/u;
58
58
  const DELIVERABLE_LINK_PREFIX_RE =
59
59
  /^\s*(?:[-*+]\s+)?(?:预览链接|下载链接|文件列表|项目入口|在线预览|在线体验|目录链接)\s*[::]/u;
60
60
  const DELIVERABLE_LINK_LABEL_RE =
@@ -715,11 +715,6 @@ function kbBaseURL() {
715
715
  return (process.env.KNOWLEDGE_DB_URL || cfg.kbBaseUrl || DEFAULT_KB_BASE_URL).replace(/\/$/, "");
716
716
  }
717
717
 
718
- function kbPublicURL() {
719
- const cfg = loadDeliverableConfig();
720
- return (process.env.KNOWLEDGE_DB_PUBLIC_URL || cfg.kbPublicUrl || process.env.KNOWLEDGE_DB_URL || cfg.kbBaseUrl || DEFAULT_KB_BASE_URL).replace(/\/$/, "");
721
- }
722
-
723
718
  function kbApiKey() {
724
719
  return process.env.KNOWLEDGE_DB_API_KEY || DEFAULT_KB_API_KEY;
725
720
  }
@@ -729,28 +724,80 @@ function kbUploadPath(groupId, groupName) {
729
724
  const gname = gid === DEFAULT_GROUP_ID
730
725
  ? DEFAULT_GROUP_NAME
731
726
  : trimString(groupName) || gid;
732
- return "/" + gname + "/raw";
727
+ return "/" + gname + "/raw/交付物";
733
728
  }
734
729
 
735
- function kbPreviewURL(documentId, userId, groupId) {
736
- return kbPublicURL() + "/documents/content?user_id="
737
- + encodeURIComponent(trimString(userId) || "default")
738
- + "&group_id=" + encodeURIComponent(trimString(groupId) || DEFAULT_GROUP_ID)
739
- + "&id=" + encodeURIComponent(String(documentId));
730
+ function kbUploadItems(response) {
731
+ const data = (response && response.data) || response || {};
732
+ return Array.isArray(data.items) ? data.items : [];
740
733
  }
741
734
 
742
- function kbExtractDocumentId(response) {
735
+ function kbFirstSuccessfulUploadItem(response) {
736
+ const items = kbUploadItems(response);
737
+ if (items.length === 0) {
738
+ return null;
739
+ }
740
+ return items.find((item) => item && !item.error && item.document) || items[0] || null;
741
+ }
742
+
743
+ function kbExtractDocument(response) {
744
+ const item = kbFirstSuccessfulUploadItem(response);
745
+ if (item && item.document && typeof item.document === "object" && !Array.isArray(item.document)) {
746
+ return item.document;
747
+ }
743
748
  const data = (response && response.data) || response || {};
744
- const items = Array.isArray(data.items) ? data.items : [];
745
- if (items.length > 0 && items[0].document && items[0].document.id !== undefined) {
746
- return items[0].document.id;
749
+ if (data.document && typeof data.document === "object" && !Array.isArray(data.document)) {
750
+ return data.document;
747
751
  }
752
+ return data && typeof data === "object" && !Array.isArray(data) ? data : {};
753
+ }
754
+
755
+ function kbExtractDocumentId(response) {
756
+ const document = kbExtractDocument(response);
757
+ if (document.id !== undefined) {
758
+ return document.id;
759
+ }
760
+ const data = (response && response.data) || response || {};
748
761
  if (data.id !== undefined) {
749
762
  return data.id;
750
763
  }
751
764
  return null;
752
765
  }
753
766
 
767
+ function extractURLField(obj, keys) {
768
+ if (!obj || typeof obj !== "object" || Array.isArray(obj)) {
769
+ return "";
770
+ }
771
+ for (const key of keys) {
772
+ const value = obj[key];
773
+ if (isString(value) && value.trim()) {
774
+ return value.trim();
775
+ }
776
+ }
777
+ return "";
778
+ }
779
+
780
+ function kbExtractReturnedLinks(response) {
781
+ const item = kbFirstSuccessfulUploadItem(response) || {};
782
+ const document = kbExtractDocument(response);
783
+ return {
784
+ downloadURL:
785
+ extractURLField(document, ["download_url", "downloadURL"]) ||
786
+ extractURLField(item, ["download_url", "downloadURL"]),
787
+ previewURL:
788
+ extractURLField(document, ["preview_url", "previewURL"]) ||
789
+ extractURLField(item, ["preview_url", "previewURL"]),
790
+ };
791
+ }
792
+
793
+ function requireKBReturnedLink(response) {
794
+ const links = kbExtractReturnedLinks(response);
795
+ if (!links.previewURL && !links.downloadURL) {
796
+ throw new Error("kb upload response missing preview_url/download_url");
797
+ }
798
+ return links;
799
+ }
800
+
754
801
  function buildFileBuffersFromBody(body, isDirectory) {
755
802
  if (isDirectory && Array.isArray(body.files)) {
756
803
  return body.files.map((file) => ({
@@ -1185,8 +1232,9 @@ async function uploadDeliverable(args) {
1185
1232
  };
1186
1233
  const response = await kbMultipartUpload(fileBuffers, fields);
1187
1234
  const documentId = kbExtractDocumentId(response);
1188
- const previewURL = documentId ? kbPreviewURL(documentId, userId, groupId) : "";
1189
- const downloadURL = previewURL;
1235
+ const links = requireKBReturnedLink(response);
1236
+ const previewURL = links.previewURL || links.downloadURL;
1237
+ const downloadURL = links.downloadURL || previewURL;
1190
1238
  const replyMarkdown = buildReplyMarkdown({
1191
1239
  previewURL,
1192
1240
  downloadURL,
@@ -1255,12 +1303,14 @@ async function uploadCandidate(candidate, body) {
1255
1303
  path: uploadPath,
1256
1304
  });
1257
1305
  const documentId = kbExtractDocumentId(response);
1258
- const previewURL = documentId ? kbPreviewURL(documentId, userId, groupId) : "";
1306
+ const links = requireKBReturnedLink(response);
1307
+ const previewURL = links.previewURL || links.downloadURL;
1308
+ const downloadURL = links.downloadURL || previewURL;
1259
1309
  const result = {
1260
1310
  fileName,
1261
1311
  document_id: documentId,
1262
1312
  previewURL,
1263
- downloadURL: previewURL,
1313
+ downloadURL,
1264
1314
  };
1265
1315
  cache.set(cacheKey, { result, createdAt: Date.now() });
1266
1316
  return result;
@@ -1755,8 +1805,6 @@ function extractDeliverableURL(line) {
1755
1805
  function configuredKBHosts() {
1756
1806
  const cfg = loadDeliverableConfig();
1757
1807
  const values = [
1758
- process.env.KNOWLEDGE_DB_PUBLIC_URL,
1759
- cfg.kbPublicUrl,
1760
1808
  process.env.KNOWLEDGE_DB_URL,
1761
1809
  cfg.kbBaseUrl,
1762
1810
  DEFAULT_KB_BASE_URL,
@@ -1777,6 +1825,15 @@ function configuredKBHosts() {
1777
1825
  return hosts;
1778
1826
  }
1779
1827
 
1828
+ function isTrustedDeliverableURLPrefix(rawURL) {
1829
+ const normalized = String(rawURL || "").trim().toLowerCase();
1830
+ return (
1831
+ normalized.startsWith("https://uniclaw-ai-kb") ||
1832
+ normalized.startsWith("http://knowledge-db") ||
1833
+ normalized.startsWith("http://localhost")
1834
+ );
1835
+ }
1836
+
1780
1837
  function isTrustedDeliverableURL(rawURL) {
1781
1838
  if (!isString(rawURL) || !rawURL.trim()) {
1782
1839
  return false;
@@ -1790,6 +1847,9 @@ function isTrustedDeliverableURL(rawURL) {
1790
1847
  if (!DELIVERABLE_KB_PATH_RE.test(parsed.pathname)) {
1791
1848
  return false;
1792
1849
  }
1850
+ if (isTrustedDeliverableURLPrefix(rawURL)) {
1851
+ return true;
1852
+ }
1793
1853
  const hosts = configuredKBHosts();
1794
1854
  const host = parsed.host.toLowerCase();
1795
1855
  const hostname = parsed.hostname.toLowerCase();
@@ -1922,7 +1982,11 @@ function extractDeliverableIdentity(rawURL) {
1922
1982
  return "";
1923
1983
  }
1924
1984
  const docId = parsed.searchParams.get("id");
1925
- return docId ? String(docId) : "";
1985
+ if (docId) {
1986
+ return String(docId);
1987
+ }
1988
+ const match = parsed.pathname.match(/\/documents\/(?:content|preview)\/([^/]+)/u);
1989
+ return match && match[1] ? decodeURIComponent(match[1]) : "";
1926
1990
  }
1927
1991
 
1928
1992
  function selectPalzFileURL(linkItems) {
@@ -1939,8 +2003,8 @@ function selectPalzFileURL(linkItems) {
1939
2003
  if (identities.size !== 1) {
1940
2004
  return "";
1941
2005
  }
1942
- const download = linkItems.find((item) => /下载链接/u.test(String((item && item.line) || "")));
1943
- return (download && download.url) || linkItems[0].url || "";
2006
+ const preview = linkItems.find((item) => /预览链接/u.test(String((item && item.line) || "")));
2007
+ return (preview && preview.url) || linkItems[0].url || "";
1944
2008
  }
1945
2009
 
1946
2010
  function cloneBody(body, content, suffix) {
@@ -2217,10 +2281,11 @@ plugin.__test = {
2217
2281
  isOSSLikeURL,
2218
2282
  isTrustedDeliverableURL,
2219
2283
  kbExtractDocumentId,
2284
+ kbExtractReturnedLinks,
2220
2285
  kbMultipartUpload,
2221
- kbPreviewURL,
2222
2286
  kbUploadPath,
2223
2287
  loadDeliverableConfig,
2288
+ requireKBReturnedLink,
2224
2289
  selectPalzFileURL,
2225
2290
  splitDeliverableMessage,
2226
2291
  };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plugin-deliverables",
3
- "version": "1.1.5",
3
+ "version": "1.1.7",
4
4
  "npm_package": "@dai_ming/plugin-deliverables",
5
5
  "description": "Deliverables plugin: native upload tool + skill + AGENTS rules for AI-generated file uploads",
6
6
  "skills": {
@@ -2,7 +2,7 @@
2
2
  "id": "plugin-deliverables",
3
3
  "name": "Deliverables",
4
4
  "description": "Deliverables runtime guard for upload-first file delivery with Palz split-send diagnostics.",
5
- "version": "1.1.5",
5
+ "version": "1.1.7",
6
6
  "skills": ["./skills"],
7
7
  "configSchema": {
8
8
  "type": "object",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dai_ming/plugin-deliverables",
3
- "version": "1.1.5",
3
+ "version": "1.1.7",
4
4
  "description": "OpenClaw deliverables native plugin — upload AI-generated files to OSS and return shareable preview/download links",
5
5
  "keywords": [
6
6
  "openclaw",