@hanhnd/agent-kit 1.0.11 → 1.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/kit-server.js +131 -26
- package/dist/tools/agent.js +5 -4
- package/dist/tools/core.js +1 -1
- package/dist/tools/integration.js +3 -26
- package/dist/tools/security.js +2 -2
- package/dist/utils/parser.d.ts +1 -0
- package/dist/utils/parser.js +126 -0
- package/dist/{utils.d.ts → utils/utils.d.ts} +0 -3
- package/dist/{utils.js → utils/utils.js} +0 -3
- package/package.json +1 -1
- /package/dist/{credentials.d.ts → utils/credentials.d.ts} +0 -0
- /package/dist/{credentials.js → utils/credentials.js} +0 -0
package/dist/kit-server.js
CHANGED
|
@@ -20993,7 +20993,7 @@ var StdioServerTransport = class {
|
|
|
20993
20993
|
import * as fs from "fs";
|
|
20994
20994
|
import * as path from "path";
|
|
20995
20995
|
|
|
20996
|
-
// src/utils.ts
|
|
20996
|
+
// src/utils/utils.ts
|
|
20997
20997
|
function getWorkspaceRoot() {
|
|
20998
20998
|
return process.env.WORKSPACE_DIR || process.env.CLAUDE_WORKSPACE || process.env.GEMINI_WORKSPACE || process.env.INIT_CWD || process.env.PWD || process.cwd();
|
|
20999
20999
|
}
|
|
@@ -21097,9 +21097,7 @@ function validatePath(filePath, baseDir = process.cwd()) {
|
|
|
21097
21097
|
}
|
|
21098
21098
|
}
|
|
21099
21099
|
const fileName = path2.basename(resolved);
|
|
21100
|
-
const isExactForbidden = FORBIDDEN_FILES.some(
|
|
21101
|
-
(f) => fileName.toLowerCase() === f.toLowerCase()
|
|
21102
|
-
);
|
|
21100
|
+
const isExactForbidden = FORBIDDEN_FILES.some((f) => fileName.toLowerCase() === f.toLowerCase());
|
|
21103
21101
|
const isPatternForbidden = FORBIDDEN_PATTERNS.some((re) => re.test(fileName));
|
|
21104
21102
|
if (isExactForbidden || isPatternForbidden) {
|
|
21105
21103
|
throw new Error(`Access to sensitive file is FORBIDDEN: ${fileName}`);
|
|
@@ -21150,9 +21148,10 @@ function taskSlug(task) {
|
|
|
21150
21148
|
function initAgentLog(workspaceRoot, slug, agent) {
|
|
21151
21149
|
const logsDir = path3.join(workspaceRoot, ".agent-kit", "logs", "agents");
|
|
21152
21150
|
fs2.mkdirSync(logsDir, { recursive: true });
|
|
21153
|
-
const
|
|
21151
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
21152
|
+
const logFile = path3.join(logsDir, `delegate-${now}-${slug}.log`);
|
|
21154
21153
|
const header = `Agent: ${agent}
|
|
21155
|
-
Date: ${
|
|
21154
|
+
Date: ${now}
|
|
21156
21155
|
${"\u2500".repeat(60)}
|
|
21157
21156
|
|
|
21158
21157
|
`;
|
|
@@ -21305,7 +21304,7 @@ function registerAgentTools(server2) {
|
|
|
21305
21304
|
// src/tools/integration.ts
|
|
21306
21305
|
import { writeFileSync as writeFileSync3 } from "fs";
|
|
21307
21306
|
|
|
21308
|
-
// src/credentials.ts
|
|
21307
|
+
// src/utils/credentials.ts
|
|
21309
21308
|
import * as fs3 from "fs";
|
|
21310
21309
|
import * as os from "os";
|
|
21311
21310
|
import * as path4 from "path";
|
|
@@ -21365,6 +21364,130 @@ function getCredential(key) {
|
|
|
21365
21364
|
return loadCredentials()[key];
|
|
21366
21365
|
}
|
|
21367
21366
|
|
|
21367
|
+
// src/utils/parser.ts
|
|
21368
|
+
function adfToMarkdown(adf) {
|
|
21369
|
+
if (!adf || typeof adf !== "object") return "No description";
|
|
21370
|
+
const content = adf.content;
|
|
21371
|
+
if (!content || !Array.isArray(content)) return "No description";
|
|
21372
|
+
function renderNodes(nodes, listDepth = 0, parentType) {
|
|
21373
|
+
let result = "";
|
|
21374
|
+
if (!nodes || !Array.isArray(nodes)) return result;
|
|
21375
|
+
for (const node of nodes) {
|
|
21376
|
+
switch (node.type) {
|
|
21377
|
+
case "paragraph": {
|
|
21378
|
+
const text = renderNodes(node.content, listDepth, node.type);
|
|
21379
|
+
result += parentType === "listItem" ? text : text + "\n\n";
|
|
21380
|
+
break;
|
|
21381
|
+
}
|
|
21382
|
+
case "heading": {
|
|
21383
|
+
const level = node.attrs?.level || 1;
|
|
21384
|
+
result += "#".repeat(level) + " " + renderNodes(node.content, listDepth, node.type) + "\n\n";
|
|
21385
|
+
break;
|
|
21386
|
+
}
|
|
21387
|
+
case "text": {
|
|
21388
|
+
let text = node.text || "";
|
|
21389
|
+
if (node.marks) {
|
|
21390
|
+
for (const mark of node.marks) {
|
|
21391
|
+
switch (mark.type) {
|
|
21392
|
+
case "strong":
|
|
21393
|
+
text = `**${text}**`;
|
|
21394
|
+
break;
|
|
21395
|
+
case "em":
|
|
21396
|
+
text = `*${text}*`;
|
|
21397
|
+
break;
|
|
21398
|
+
case "code":
|
|
21399
|
+
text = `\`${text}\``;
|
|
21400
|
+
break;
|
|
21401
|
+
case "strike":
|
|
21402
|
+
text = `~~${text}~~`;
|
|
21403
|
+
break;
|
|
21404
|
+
case "link":
|
|
21405
|
+
text = `[${text}](${mark.attrs?.href})`;
|
|
21406
|
+
break;
|
|
21407
|
+
}
|
|
21408
|
+
}
|
|
21409
|
+
}
|
|
21410
|
+
result += text;
|
|
21411
|
+
break;
|
|
21412
|
+
}
|
|
21413
|
+
case "bulletList":
|
|
21414
|
+
case "orderedList":
|
|
21415
|
+
result += renderNodes(node.content, listDepth + 1, node.type);
|
|
21416
|
+
if (listDepth === 0) result += "\n";
|
|
21417
|
+
break;
|
|
21418
|
+
case "listItem": {
|
|
21419
|
+
const indent = " ".repeat(Math.max(0, listDepth - 1));
|
|
21420
|
+
const bullet = parentType === "orderedList" ? "1." : "-";
|
|
21421
|
+
const text = renderNodes(node.content, listDepth, node.type).trim();
|
|
21422
|
+
result += `${indent}${bullet} ${text}
|
|
21423
|
+
`;
|
|
21424
|
+
break;
|
|
21425
|
+
}
|
|
21426
|
+
case "blockquote":
|
|
21427
|
+
result += "> " + renderNodes(node.content, listDepth, node.type).trim().replace(/\n/g, "\n> ") + "\n\n";
|
|
21428
|
+
break;
|
|
21429
|
+
case "codeBlock":
|
|
21430
|
+
result += `\`\`\`${node.attrs?.language || ""}
|
|
21431
|
+
${renderNodes(node.content, listDepth, node.type).trim()}
|
|
21432
|
+
\`\`\`
|
|
21433
|
+
|
|
21434
|
+
`;
|
|
21435
|
+
break;
|
|
21436
|
+
case "rule":
|
|
21437
|
+
result += "---\n\n";
|
|
21438
|
+
break;
|
|
21439
|
+
case "hardBreak":
|
|
21440
|
+
result += "\n";
|
|
21441
|
+
break;
|
|
21442
|
+
case "table":
|
|
21443
|
+
result += renderTable(node.content);
|
|
21444
|
+
break;
|
|
21445
|
+
case "mention":
|
|
21446
|
+
result += `@${node.attrs?.text || node.attrs?.displayName || "user"}`;
|
|
21447
|
+
break;
|
|
21448
|
+
case "emoji":
|
|
21449
|
+
result += node.attrs?.text || "";
|
|
21450
|
+
break;
|
|
21451
|
+
case "inlineCard":
|
|
21452
|
+
case "blockCard":
|
|
21453
|
+
result += `[${node.attrs?.url}](${node.attrs?.url})`;
|
|
21454
|
+
if (node.type === "blockCard") result += "\n\n";
|
|
21455
|
+
break;
|
|
21456
|
+
case "mediaSingle":
|
|
21457
|
+
case "mediaInline":
|
|
21458
|
+
case "media":
|
|
21459
|
+
result += "[media omitted]";
|
|
21460
|
+
break;
|
|
21461
|
+
default:
|
|
21462
|
+
if (node.content) {
|
|
21463
|
+
result += renderNodes(node.content, listDepth, node.type);
|
|
21464
|
+
}
|
|
21465
|
+
break;
|
|
21466
|
+
}
|
|
21467
|
+
}
|
|
21468
|
+
return result;
|
|
21469
|
+
}
|
|
21470
|
+
function renderTable(rows) {
|
|
21471
|
+
if (!rows || !Array.isArray(rows)) return "";
|
|
21472
|
+
let result = "\n";
|
|
21473
|
+
let isFirstRow = true;
|
|
21474
|
+
for (const row of rows) {
|
|
21475
|
+
if (row.type !== "tableRow") continue;
|
|
21476
|
+
const cells = row.content || [];
|
|
21477
|
+
const rendered = cells.map(
|
|
21478
|
+
(c) => renderNodes(c.content).trim().replace(/\n+/g, " ").replace(/\|/g, "\\|")
|
|
21479
|
+
);
|
|
21480
|
+
result += "| " + rendered.join(" | ") + " |\n";
|
|
21481
|
+
if (isFirstRow) {
|
|
21482
|
+
result += "| " + cells.map(() => "---").join(" | ") + " |\n";
|
|
21483
|
+
isFirstRow = false;
|
|
21484
|
+
}
|
|
21485
|
+
}
|
|
21486
|
+
return result + "\n";
|
|
21487
|
+
}
|
|
21488
|
+
return renderNodes(content).trim() || "No description";
|
|
21489
|
+
}
|
|
21490
|
+
|
|
21368
21491
|
// src/tools/integration.ts
|
|
21369
21492
|
var BitbucketPrSchema = external_exports.object({
|
|
21370
21493
|
id: external_exports.number(),
|
|
@@ -21403,24 +21526,6 @@ var JiraTicketSchema = external_exports.object({
|
|
|
21403
21526
|
errorMessages: external_exports.array(external_exports.string()).optional(),
|
|
21404
21527
|
fields: JiraFieldsSchema
|
|
21405
21528
|
});
|
|
21406
|
-
function extractAdfText(adf) {
|
|
21407
|
-
if (!adf || typeof adf !== "object") return "No description";
|
|
21408
|
-
const content = adf.content;
|
|
21409
|
-
if (!content || !Array.isArray(content)) return "No description";
|
|
21410
|
-
const textParts = [];
|
|
21411
|
-
function extractText(nodes) {
|
|
21412
|
-
for (const node of nodes) {
|
|
21413
|
-
if (typeof node.text === "string") {
|
|
21414
|
-
textParts.push(node.text);
|
|
21415
|
-
}
|
|
21416
|
-
if (Array.isArray(node.content)) {
|
|
21417
|
-
extractText(node.content);
|
|
21418
|
-
}
|
|
21419
|
-
}
|
|
21420
|
-
}
|
|
21421
|
-
extractText(content);
|
|
21422
|
-
return textParts.join(" ") || "No description";
|
|
21423
|
-
}
|
|
21424
21529
|
function buildJiraBasicAuth() {
|
|
21425
21530
|
const email2 = getCredential("ATLASSIAN_USER_EMAIL");
|
|
21426
21531
|
const token = getCredential("ATLASSIAN_API_TOKEN");
|
|
@@ -21664,7 +21769,7 @@ ${ticket.errorMessages.join("\n")}`
|
|
|
21664
21769
|
**Type:** ${ticket.fields.issuetype?.name || "Unknown"}
|
|
21665
21770
|
|
|
21666
21771
|
### Description
|
|
21667
|
-
${typeof ticket.fields.description === "string" ? ticket.fields.description :
|
|
21772
|
+
${typeof ticket.fields.description === "string" ? ticket.fields.description : adfToMarkdown(ticket.fields.description)}
|
|
21668
21773
|
|
|
21669
21774
|
### Labels
|
|
21670
21775
|
${ticket.fields.labels?.join(", ") || "None"}`;
|
package/dist/tools/agent.js
CHANGED
|
@@ -7,8 +7,8 @@ import { randomUUID } from 'crypto';
|
|
|
7
7
|
import * as fs from 'fs';
|
|
8
8
|
import * as path from 'path';
|
|
9
9
|
import { z } from 'zod';
|
|
10
|
-
import { getWorkspaceRoot } from '../utils.js';
|
|
11
|
-
import { commandExists,
|
|
10
|
+
import { getWorkspaceRoot } from '../utils/utils.js';
|
|
11
|
+
import { commandExists, sanitizeOutput, validatePath } from './security.js';
|
|
12
12
|
// Configurable timeout via environment variable (default: 5 minutes)
|
|
13
13
|
const AGENT_TIMEOUT = parseInt(process.env.KIT_AGENT_TIMEOUT || '300000', 10);
|
|
14
14
|
const jobRegistry = new Map();
|
|
@@ -33,8 +33,9 @@ function taskSlug(task) {
|
|
|
33
33
|
function initAgentLog(workspaceRoot, slug, agent) {
|
|
34
34
|
const logsDir = path.join(workspaceRoot, '.agent-kit', 'logs', 'agents');
|
|
35
35
|
fs.mkdirSync(logsDir, { recursive: true });
|
|
36
|
-
const
|
|
37
|
-
const
|
|
36
|
+
const now = new Date().toISOString();
|
|
37
|
+
const logFile = path.join(logsDir, `delegate-${now}-${slug}.log`);
|
|
38
|
+
const header = `Agent: ${agent}\nDate: ${now}\n${'─'.repeat(60)}\n\n`;
|
|
38
39
|
fs.writeFileSync(logFile, header, 'utf-8');
|
|
39
40
|
const logStream = fs.createWriteStream(logFile, { flags: 'a' });
|
|
40
41
|
logStream.on('error', () => { });
|
package/dist/tools/core.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import * as fs from 'fs';
|
|
5
5
|
import * as path from 'path';
|
|
6
6
|
import { z } from 'zod';
|
|
7
|
-
import { getWorkspaceRoot } from '../utils.js';
|
|
7
|
+
import { getWorkspaceRoot } from '../utils/utils.js';
|
|
8
8
|
import { DEFAULT_EXTENSIONS } from './config.js';
|
|
9
9
|
/**
|
|
10
10
|
* Register core tools with MCP server
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { writeFileSync } from 'fs';
|
|
6
6
|
import { z } from 'zod';
|
|
7
|
-
import { getCredential } from '../credentials.js';
|
|
7
|
+
import { getCredential } from '../utils/credentials.js';
|
|
8
|
+
import { adfToMarkdown } from '../utils/parser.js';
|
|
8
9
|
import { sanitize } from './security.js';
|
|
9
10
|
// Zod schema for Bitbucket PR REST API response
|
|
10
11
|
const BitbucketPrSchema = z.object({
|
|
@@ -53,30 +54,6 @@ const JiraTicketSchema = z.object({
|
|
|
53
54
|
errorMessages: z.array(z.string()).optional(),
|
|
54
55
|
fields: JiraFieldsSchema,
|
|
55
56
|
});
|
|
56
|
-
/**
|
|
57
|
-
* Extract plain text from ADF (Atlassian Document Format) content
|
|
58
|
-
* Recursively walks the content tree to find text nodes
|
|
59
|
-
*/
|
|
60
|
-
function extractAdfText(adf) {
|
|
61
|
-
if (!adf || typeof adf !== 'object')
|
|
62
|
-
return 'No description';
|
|
63
|
-
const content = adf.content;
|
|
64
|
-
if (!content || !Array.isArray(content))
|
|
65
|
-
return 'No description';
|
|
66
|
-
const textParts = [];
|
|
67
|
-
function extractText(nodes) {
|
|
68
|
-
for (const node of nodes) {
|
|
69
|
-
if (typeof node.text === 'string') {
|
|
70
|
-
textParts.push(node.text);
|
|
71
|
-
}
|
|
72
|
-
if (Array.isArray(node.content)) {
|
|
73
|
-
extractText(node.content);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
extractText(content);
|
|
78
|
-
return textParts.join(' ') || 'No description';
|
|
79
|
-
}
|
|
80
57
|
function buildJiraBasicAuth() {
|
|
81
58
|
const email = getCredential('ATLASSIAN_USER_EMAIL');
|
|
82
59
|
const token = getCredential('ATLASSIAN_API_TOKEN');
|
|
@@ -309,7 +286,7 @@ ${pr.description || 'No description'}`;
|
|
|
309
286
|
### Description
|
|
310
287
|
${typeof ticket.fields.description === 'string'
|
|
311
288
|
? ticket.fields.description
|
|
312
|
-
:
|
|
289
|
+
: adfToMarkdown(ticket.fields.description)}
|
|
313
290
|
|
|
314
291
|
### Labels
|
|
315
292
|
${ticket.fields.labels?.join(', ') || 'None'}`;
|
package/dist/tools/security.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
import { execFileSync } from 'child_process';
|
|
6
6
|
import * as fs from 'fs';
|
|
7
7
|
import * as path from 'path';
|
|
8
|
-
import { getWorkspaceRoot } from '../utils.js';
|
|
9
|
-
import { FORBIDDEN_FILES, FORBIDDEN_PATTERNS
|
|
8
|
+
import { getWorkspaceRoot } from '../utils/utils.js';
|
|
9
|
+
import { FORBIDDEN_DIRS, FORBIDDEN_FILES, FORBIDDEN_PATTERNS } from './config.js';
|
|
10
10
|
/**
|
|
11
11
|
* Sanitize string for safe use with execFileSync
|
|
12
12
|
* Only removes dangerous shell operators - safe chars like !?#* are allowed
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function adfToMarkdown(adf: Record<string, unknown> | null | undefined): string;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
export function adfToMarkdown(adf) {
|
|
2
|
+
if (!adf || typeof adf !== 'object')
|
|
3
|
+
return 'No description';
|
|
4
|
+
const content = adf.content;
|
|
5
|
+
if (!content || !Array.isArray(content))
|
|
6
|
+
return 'No description';
|
|
7
|
+
function renderNodes(nodes, listDepth = 0, parentType) {
|
|
8
|
+
let result = '';
|
|
9
|
+
if (!nodes || !Array.isArray(nodes))
|
|
10
|
+
return result;
|
|
11
|
+
for (const node of nodes) {
|
|
12
|
+
switch (node.type) {
|
|
13
|
+
case 'paragraph': {
|
|
14
|
+
const text = renderNodes(node.content, listDepth, node.type);
|
|
15
|
+
result += parentType === 'listItem' ? text : text + '\n\n';
|
|
16
|
+
break;
|
|
17
|
+
}
|
|
18
|
+
case 'heading': {
|
|
19
|
+
const level = node.attrs?.level || 1;
|
|
20
|
+
result +=
|
|
21
|
+
'#'.repeat(level) + ' ' + renderNodes(node.content, listDepth, node.type) + '\n\n';
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
case 'text': {
|
|
25
|
+
let text = node.text || '';
|
|
26
|
+
if (node.marks) {
|
|
27
|
+
for (const mark of node.marks) {
|
|
28
|
+
switch (mark.type) {
|
|
29
|
+
case 'strong':
|
|
30
|
+
text = `**${text}**`;
|
|
31
|
+
break;
|
|
32
|
+
case 'em':
|
|
33
|
+
text = `*${text}*`;
|
|
34
|
+
break;
|
|
35
|
+
case 'code':
|
|
36
|
+
text = `\`${text}\``;
|
|
37
|
+
break;
|
|
38
|
+
case 'strike':
|
|
39
|
+
text = `~~${text}~~`;
|
|
40
|
+
break;
|
|
41
|
+
case 'link':
|
|
42
|
+
text = `[${text}](${mark.attrs?.href})`;
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
result += text;
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
case 'bulletList':
|
|
51
|
+
case 'orderedList':
|
|
52
|
+
result += renderNodes(node.content, listDepth + 1, node.type);
|
|
53
|
+
if (listDepth === 0)
|
|
54
|
+
result += '\n';
|
|
55
|
+
break;
|
|
56
|
+
case 'listItem': {
|
|
57
|
+
const indent = ' '.repeat(Math.max(0, listDepth - 1));
|
|
58
|
+
const bullet = parentType === 'orderedList' ? '1.' : '-';
|
|
59
|
+
const text = renderNodes(node.content, listDepth, node.type).trim();
|
|
60
|
+
result += `${indent}${bullet} ${text}\n`;
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
case 'blockquote':
|
|
64
|
+
result +=
|
|
65
|
+
'> ' +
|
|
66
|
+
renderNodes(node.content, listDepth, node.type).trim().replace(/\n/g, '\n> ') +
|
|
67
|
+
'\n\n';
|
|
68
|
+
break;
|
|
69
|
+
case 'codeBlock':
|
|
70
|
+
result += `\`\`\`${node.attrs?.language || ''}\n${renderNodes(node.content, listDepth, node.type).trim()}\n\`\`\`\n\n`;
|
|
71
|
+
break;
|
|
72
|
+
case 'rule':
|
|
73
|
+
result += '---\n\n';
|
|
74
|
+
break;
|
|
75
|
+
case 'hardBreak':
|
|
76
|
+
result += '\n';
|
|
77
|
+
break;
|
|
78
|
+
case 'table':
|
|
79
|
+
result += renderTable(node.content);
|
|
80
|
+
break;
|
|
81
|
+
case 'mention':
|
|
82
|
+
result += `@${node.attrs?.text || node.attrs?.displayName || 'user'}`;
|
|
83
|
+
break;
|
|
84
|
+
case 'emoji':
|
|
85
|
+
result += node.attrs?.text || '';
|
|
86
|
+
break;
|
|
87
|
+
case 'inlineCard':
|
|
88
|
+
case 'blockCard':
|
|
89
|
+
result += `[${node.attrs?.url}](${node.attrs?.url})`;
|
|
90
|
+
if (node.type === 'blockCard')
|
|
91
|
+
result += '\n\n';
|
|
92
|
+
break;
|
|
93
|
+
case 'mediaSingle':
|
|
94
|
+
case 'mediaInline':
|
|
95
|
+
case 'media':
|
|
96
|
+
result += '[media omitted]';
|
|
97
|
+
break;
|
|
98
|
+
default:
|
|
99
|
+
if (node.content) {
|
|
100
|
+
result += renderNodes(node.content, listDepth, node.type);
|
|
101
|
+
}
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
function renderTable(rows) {
|
|
108
|
+
if (!rows || !Array.isArray(rows))
|
|
109
|
+
return '';
|
|
110
|
+
let result = '\n';
|
|
111
|
+
let isFirstRow = true;
|
|
112
|
+
for (const row of rows) {
|
|
113
|
+
if (row.type !== 'tableRow')
|
|
114
|
+
continue;
|
|
115
|
+
const cells = row.content || [];
|
|
116
|
+
const rendered = cells.map((c) => renderNodes(c.content).trim().replace(/\n+/g, ' ').replace(/\|/g, '\\|'));
|
|
117
|
+
result += '| ' + rendered.join(' | ') + ' |\n';
|
|
118
|
+
if (isFirstRow) {
|
|
119
|
+
result += '| ' + cells.map(() => '---').join(' | ') + ' |\n';
|
|
120
|
+
isFirstRow = false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return result + '\n';
|
|
124
|
+
}
|
|
125
|
+
return renderNodes(content).trim() || 'No description';
|
|
126
|
+
}
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|