dingtalk-wiki 1.2.3 → 1.2.5
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/index.js +85 -10
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -850,7 +850,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
850
850
|
properties: {
|
|
851
851
|
doc_key: {
|
|
852
852
|
type: 'string',
|
|
853
|
-
description: '
|
|
853
|
+
description: '文档标识。支持 wiki nodes 的 nodeId(dentryUuid)、docKey,或文档 URL。重要:create_wiki_doc 返回的 nodeId 不能用于内容读写,请使用 docKey 或 dentryUuid。若传入 create 的 nodeId,需额外提供 workspace_id 以自动查找'
|
|
854
|
+
},
|
|
855
|
+
workspace_id: {
|
|
856
|
+
type: 'string',
|
|
857
|
+
description: '知识库 ID(可选)。当 doc_key 来自 create_wiki_doc 返回的 nodeId 时,提供此参数可自动查找正确的 dentryUuid'
|
|
854
858
|
},
|
|
855
859
|
operator_id: {
|
|
856
860
|
type: 'string',
|
|
@@ -868,12 +872,16 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
868
872
|
properties: {
|
|
869
873
|
doc_key: {
|
|
870
874
|
type: 'string',
|
|
871
|
-
description: '
|
|
875
|
+
description: '文档标识。支持 wiki nodes 的 nodeId(dentryUuid)、docKey,或文档 URL。重要:create_wiki_doc 返回的 nodeId 不能用于内容读写,请使用 docKey 或 dentryUuid。若传入 create 的 nodeId,需额外提供 workspace_id 以自动查找'
|
|
872
876
|
},
|
|
873
877
|
content: {
|
|
874
878
|
type: 'string',
|
|
875
879
|
description: '要写入的 Markdown 内容'
|
|
876
880
|
},
|
|
881
|
+
workspace_id: {
|
|
882
|
+
type: 'string',
|
|
883
|
+
description: '知识库 ID(可选)。当 doc_key 来自 create_wiki_doc 返回的 nodeId 时,提供此参数可自动查找正确的 dentryUuid'
|
|
884
|
+
},
|
|
877
885
|
operator_id: {
|
|
878
886
|
type: 'string',
|
|
879
887
|
description: '操作者 unionid(不传则使用默认用户)'
|
|
@@ -1144,6 +1152,33 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1144
1152
|
};
|
|
1145
1153
|
});
|
|
1146
1154
|
|
|
1155
|
+
async function resolveDocKey(docKey, operatorId, dingtalkInstance) {
|
|
1156
|
+
const rawInput = docKey;
|
|
1157
|
+
|
|
1158
|
+
// 从 URL 中提取 ID
|
|
1159
|
+
const urlMatch = String(docKey).match(/\/i\/nodes\/([^\/\?#]+)/);
|
|
1160
|
+
docKey = urlMatch ? urlMatch[1] : docKey;
|
|
1161
|
+
|
|
1162
|
+
try {
|
|
1163
|
+
const nodeInfo = await dingtalkInstance.docRequest('GET', `/v2.0/wiki/nodes/${docKey}`, { operatorId });
|
|
1164
|
+
const node = nodeInfo.node || nodeInfo;
|
|
1165
|
+
|
|
1166
|
+
// wiki/nodes 的 nodeId = dentryUuid,直接可用
|
|
1167
|
+
// 但 node.document.docKey 可能是不同的值,优先使用
|
|
1168
|
+
if (node.document?.docKey) {
|
|
1169
|
+
return node.document.docKey;
|
|
1170
|
+
}
|
|
1171
|
+
// 部分响应直接把 docKey 放在顶层
|
|
1172
|
+
if (node.docKey) {
|
|
1173
|
+
return node.docKey;
|
|
1174
|
+
}
|
|
1175
|
+
} catch (e) {
|
|
1176
|
+
// 传入 create nodeId 时 wiki/nodes 会拒绝,静默 fallback
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
return docKey;
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1147
1182
|
// 工具调用处理
|
|
1148
1183
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
1149
1184
|
const { name, arguments: args } = request.params;
|
|
@@ -1297,11 +1332,14 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1297
1332
|
'',
|
|
1298
1333
|
`${typeIcon} ${name}`,
|
|
1299
1334
|
`🗂️ 类型: ${doc_type}`,
|
|
1300
|
-
`🆔 Node ID: ${doc.nodeId}
|
|
1335
|
+
`🆔 Node ID: ${doc.nodeId}`,
|
|
1301
1336
|
];
|
|
1302
1337
|
|
|
1303
1338
|
if (doc.docKey) {
|
|
1304
|
-
lines.push(`🔑 DocKey
|
|
1339
|
+
lines.push(`🔑 DocKey(用于内容读写): ${doc.docKey}`);
|
|
1340
|
+
}
|
|
1341
|
+
if (doc.dentryUuid) {
|
|
1342
|
+
lines.push(`📄 dentryUuid(用于内容读写): ${doc.dentryUuid}`);
|
|
1305
1343
|
}
|
|
1306
1344
|
if (doc.url) {
|
|
1307
1345
|
lines.push(`🔗 链接: ${doc.url}`);
|
|
@@ -1319,8 +1357,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1319
1357
|
url: doc.url || '',
|
|
1320
1358
|
type: doc_type,
|
|
1321
1359
|
});
|
|
1322
|
-
|
|
1323
|
-
|
|
1360
|
+
const contentId = doc.docKey || doc.dentryUuid || doc.nodeId;
|
|
1361
|
+
if (args.content && contentId) {
|
|
1362
|
+
dingtalk.docRequest('POST', `/v1.0/doc/suites/documents/${contentId}/overwriteContent`, {
|
|
1363
|
+
operatorId: opId,
|
|
1324
1364
|
data: { content: args.content, contentType: 'markdown' }
|
|
1325
1365
|
}).catch(() => {});
|
|
1326
1366
|
}
|
|
@@ -1557,11 +1597,29 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1557
1597
|
}
|
|
1558
1598
|
|
|
1559
1599
|
case 'get_wiki_doc_content': {
|
|
1560
|
-
const { doc_key: docKey, operator_id } = args;
|
|
1600
|
+
const { doc_key: docKey, workspace_id: workspaceId, operator_id } = args;
|
|
1561
1601
|
if (operator_id) {
|
|
1562
1602
|
dingtalk.setOperatorId(operator_id);
|
|
1563
1603
|
}
|
|
1564
|
-
|
|
1604
|
+
|
|
1605
|
+
let realDocKey = await resolveDocKey(docKey, operator_id || null, dingtalk);
|
|
1606
|
+
|
|
1607
|
+
// 如果 resolve 后值没变(可能是 create 返回的 nodeId),尝试搜索 API 查找
|
|
1608
|
+
if (realDocKey === docKey && workspaceId) {
|
|
1609
|
+
try {
|
|
1610
|
+
const searchRes = await dingtalk.docRequest('GET', `/v1.0/doc/docs`, {
|
|
1611
|
+
operatorId: operator_id || null,
|
|
1612
|
+
extraParams: { workspaceId, keyword: '', maxResults: 50 }
|
|
1613
|
+
});
|
|
1614
|
+
const docs = searchRes.docs || [];
|
|
1615
|
+
const matched = docs.find(d => d.nodeBO?.nodeId === docKey || d.nodeBO?.nodeId === realDocKey) || docs[0];
|
|
1616
|
+
if (matched?.nodeBO?.nodeId) {
|
|
1617
|
+
realDocKey = matched.nodeBO.nodeId;
|
|
1618
|
+
}
|
|
1619
|
+
} catch (e) { /* ignore */ }
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1622
|
+
const result = await dingtalk.docRequest('GET', `/v1.0/doc/suites/documents/${realDocKey}/blocks`, { operatorId: operator_id || null });
|
|
1565
1623
|
const blocks = result.result?.data || [];
|
|
1566
1624
|
let output = '';
|
|
1567
1625
|
blocks.forEach((block) => {
|
|
@@ -1580,11 +1638,28 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1580
1638
|
}
|
|
1581
1639
|
|
|
1582
1640
|
case 'update_wiki_doc_content': {
|
|
1583
|
-
const { doc_key: docKey, content, operator_id } = args;
|
|
1641
|
+
const { doc_key: docKey, content, workspace_id: workspaceId, operator_id } = args;
|
|
1584
1642
|
if (operator_id) {
|
|
1585
1643
|
dingtalk.setOperatorId(operator_id);
|
|
1586
1644
|
}
|
|
1587
|
-
|
|
1645
|
+
|
|
1646
|
+
let realDocKey = await resolveDocKey(docKey, operator_id || null, dingtalk);
|
|
1647
|
+
|
|
1648
|
+
if (realDocKey === docKey && workspaceId) {
|
|
1649
|
+
try {
|
|
1650
|
+
const searchRes = await dingtalk.docRequest('GET', `/v1.0/doc/docs`, {
|
|
1651
|
+
operatorId: operator_id || null,
|
|
1652
|
+
extraParams: { workspaceId, keyword: '', maxResults: 50 }
|
|
1653
|
+
});
|
|
1654
|
+
const docs = searchRes.docs || [];
|
|
1655
|
+
const matched = docs.find(d => d.nodeBO?.nodeId === docKey || d.nodeBO?.nodeId === realDocKey) || docs[0];
|
|
1656
|
+
if (matched?.nodeBO?.nodeId) {
|
|
1657
|
+
realDocKey = matched.nodeBO.nodeId;
|
|
1658
|
+
}
|
|
1659
|
+
} catch (e) { /* ignore */ }
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
await dingtalk.docRequest('POST', `/v1.0/doc/suites/documents/${realDocKey}/overwriteContent`, {
|
|
1588
1663
|
operatorId: operator_id || null,
|
|
1589
1664
|
data: { content, contentType: 'markdown' }
|
|
1590
1665
|
});
|