@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.
@@ -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 logFile = path3.join(logsDir, `delegate-${slug}.log`);
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: ${(/* @__PURE__ */ new Date()).toISOString()}
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 : extractAdfText(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"}`;
@@ -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, validatePath, sanitizeOutput } from './security.js';
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 logFile = path.join(logsDir, `delegate-${slug}.log`);
37
- const header = `Agent: ${agent}\nDate: ${new Date().toISOString()}\n${'─'.repeat(60)}\n\n`;
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', () => { });
@@ -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
- : extractAdfText(ticket.fields.description)}
289
+ : adfToMarkdown(ticket.fields.description)}
313
290
 
314
291
  ### Labels
315
292
  ${ticket.fields.labels?.join(', ') || 'None'}`;
@@ -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, FORBIDDEN_DIRS } from './config.js';
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
+ }
@@ -1,4 +1 @@
1
- /**
2
- * Utility functions for agent-kit
3
- */
4
1
  export declare function getWorkspaceRoot(): string;
@@ -1,6 +1,3 @@
1
- /**
2
- * Utility functions for agent-kit
3
- */
4
1
  export function getWorkspaceRoot() {
5
2
  return (process.env.WORKSPACE_DIR ||
6
3
  process.env.CLAUDE_WORKSPACE ||
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanhnd/agent-kit",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "description": "Super Engineer - Team of AI Agents for software development (Claude Code Plugin)",
5
5
  "type": "module",
6
6
  "main": "dist/kit-server.js",
File without changes