agentsys 5.4.1 → 5.6.4
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/.claude-plugin/marketplace.json +36 -3
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +11 -0
- package/README.md +187 -17
- package/lib/adapter-transforms.js +1 -366
- package/lib/binary/index.js +398 -0
- package/lib/binary/version.js +16 -0
- package/lib/collectors/git.js +139 -0
- package/lib/collectors/index.js +10 -1
- package/lib/cross-platform/index.js +3 -13
- package/lib/discovery/index.js +1 -48
- package/lib/index.js +2 -0
- package/lib/patterns/cli-enhancers.js +2 -11
- package/lib/platform/state-dir.js +2 -16
- package/package.json +1 -1
- package/scripts/gen-adapters.js +4 -2
- package/scripts/generate-docs.js +122 -31
- package/scripts/validate-counts.js +1 -1
- package/scripts/validate-cross-platform-docs.js +5 -2
- package/site/content.json +76 -51
|
@@ -297,375 +297,10 @@ function transformForCodex(content, options) {
|
|
|
297
297
|
return content;
|
|
298
298
|
}
|
|
299
299
|
|
|
300
|
-
/**
|
|
301
|
-
* Transform content for Cursor (.mdc rule files).
|
|
302
|
-
*
|
|
303
|
-
* MDC format uses YAML frontmatter with `description`, `globs`, and
|
|
304
|
-
* `alwaysApply` fields followed by a markdown body.
|
|
305
|
-
*
|
|
306
|
-
* @param {string} content - Source markdown content (may have frontmatter)
|
|
307
|
-
* @param {Object} options
|
|
308
|
-
* @param {string} options.description - Rule description
|
|
309
|
-
* @param {string} options.pluginInstallPath - Absolute path to plugin install dir
|
|
310
|
-
* @param {string} [options.globs] - Optional glob pattern for file matching
|
|
311
|
-
* @param {boolean} [options.alwaysApply] - Whether rule always applies (default true)
|
|
312
|
-
* @returns {string} Transformed MDC content
|
|
313
|
-
*/
|
|
314
|
-
function transformRuleForCursor(content, options) {
|
|
315
|
-
const { description = '', pluginInstallPath, globs = '', alwaysApply = true } = options;
|
|
316
|
-
|
|
317
|
-
// Strip control characters and escape description for YAML
|
|
318
|
-
const cleanDescription = description.replace(/[\x00-\x1f\x7f]/g, ' ');
|
|
319
|
-
const escapedDescription = cleanDescription.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
320
|
-
const yamlDescription = `"${escapedDescription}"`;
|
|
321
|
-
|
|
322
|
-
// Build MDC frontmatter
|
|
323
|
-
let frontmatter = `---\ndescription: ${yamlDescription}\n`;
|
|
324
|
-
if (globs) {
|
|
325
|
-
frontmatter += `globs: ${JSON.stringify(globs)}\n`;
|
|
326
|
-
}
|
|
327
|
-
frontmatter += `alwaysApply: ${alwaysApply}\n---\n`;
|
|
328
|
-
|
|
329
|
-
// Strip existing frontmatter if present
|
|
330
|
-
if (content.startsWith('---')) {
|
|
331
|
-
content = content.replace(/^---\n[\s\S]*?\n---\n?/, '');
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
content = frontmatter + content;
|
|
335
|
-
|
|
336
|
-
// Replace PLUGIN_ROOT paths with actual install path
|
|
337
|
-
// Use function replacement to avoid $ pattern interpretation in replacement string
|
|
338
|
-
content = content.replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g, () => pluginInstallPath);
|
|
339
|
-
content = content.replace(/\$CLAUDE_PLUGIN_ROOT/g, () => pluginInstallPath);
|
|
340
|
-
content = content.replace(/\$\{PLUGIN_ROOT\}/g, () => pluginInstallPath);
|
|
341
|
-
content = content.replace(/\$PLUGIN_ROOT/g, () => pluginInstallPath);
|
|
342
|
-
|
|
343
|
-
// Strip Claude-specific syntax: Task tool calls (handles one level of nested braces)
|
|
344
|
-
content = content.replace(/await\s+Task\s*\(\s*\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}\s*\);?/g, (match) => {
|
|
345
|
-
const agentMatch = match.match(/subagent_type:\s*["'](?:[^"':]+:)?([^"']+)["']/);
|
|
346
|
-
if (agentMatch) {
|
|
347
|
-
return `Invoke the ${agentMatch[1]} agent`;
|
|
348
|
-
}
|
|
349
|
-
return '';
|
|
350
|
-
});
|
|
351
|
-
|
|
352
|
-
// Strip require() statements
|
|
353
|
-
content = content.replace(/(?:const|let|var)\s+\{?[^}=\n]+\}?\s*=\s*require\s*\([^)]+\);?/g, '');
|
|
354
|
-
content = content.replace(/require\s*\(['"][^'"]+['"]\)/g, '');
|
|
355
|
-
|
|
356
|
-
// Strip plugin namespacing (e.g. next-task:agent-name -> agent-name)
|
|
357
|
-
content = content.replace(/(?:next-task|deslop|ship|sync-docs|audit-project|enhance|perf|repo-map|drift-detect|consult|debate|learn|web-ctl):([a-z][a-z0-9-]*)/g, '$1');
|
|
358
|
-
|
|
359
|
-
return content;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
/**
|
|
363
|
-
* Transform skill content for Cursor.
|
|
364
|
-
*
|
|
365
|
-
* Minimal transform - Cursor reads SKILL.md frontmatter natively so we
|
|
366
|
-
* preserve it. Only replaces PLUGIN_ROOT paths and strips namespace prefixes.
|
|
367
|
-
*
|
|
368
|
-
* @param {string} content - Source SKILL.md content
|
|
369
|
-
* @param {Object} options
|
|
370
|
-
* @param {string} options.pluginInstallPath - Absolute path to plugin install dir
|
|
371
|
-
* @returns {string} Transformed skill content
|
|
372
|
-
*/
|
|
373
|
-
function transformSkillForCursor(content, options) {
|
|
374
|
-
const { pluginInstallPath } = options;
|
|
375
|
-
|
|
376
|
-
// Replace PLUGIN_ROOT paths with actual install path
|
|
377
|
-
content = content.replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g, () => pluginInstallPath);
|
|
378
|
-
content = content.replace(/\$CLAUDE_PLUGIN_ROOT/g, () => pluginInstallPath);
|
|
379
|
-
content = content.replace(/\$\{PLUGIN_ROOT\}/g, () => pluginInstallPath);
|
|
380
|
-
content = content.replace(/\$PLUGIN_ROOT/g, () => pluginInstallPath);
|
|
381
|
-
|
|
382
|
-
// Strip plugin namespacing (e.g. next-task:agent-name -> agent-name)
|
|
383
|
-
content = content.replace(/(?:next-task|deslop|ship|sync-docs|audit-project|enhance|perf|repo-map|drift-detect|consult|debate|learn|web-ctl):([a-z][a-z0-9-]*)/g, '$1');
|
|
384
|
-
|
|
385
|
-
return content;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
/**
|
|
389
|
-
* Transform command content for Cursor.
|
|
390
|
-
*
|
|
391
|
-
* Light transform - strips frontmatter, replaces PLUGIN_ROOT paths,
|
|
392
|
-
* removes require() statements and Task() calls, strips namespace prefixes.
|
|
393
|
-
*
|
|
394
|
-
* @param {string} content - Source command markdown content
|
|
395
|
-
* @param {Object} options
|
|
396
|
-
* @param {string} options.pluginInstallPath - Absolute path to plugin install dir
|
|
397
|
-
* @returns {string} Transformed command content
|
|
398
|
-
*/
|
|
399
|
-
function transformCommandForCursor(content, options) {
|
|
400
|
-
const { pluginInstallPath } = options;
|
|
401
|
-
|
|
402
|
-
// Strip existing frontmatter if present
|
|
403
|
-
if (content.startsWith('---')) {
|
|
404
|
-
content = content.replace(/^---\n[\s\S]*?\n---\n?/, '');
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
// Replace PLUGIN_ROOT paths with actual install path
|
|
408
|
-
content = content.replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g, () => pluginInstallPath);
|
|
409
|
-
content = content.replace(/\$CLAUDE_PLUGIN_ROOT/g, () => pluginInstallPath);
|
|
410
|
-
content = content.replace(/\$\{PLUGIN_ROOT\}/g, () => pluginInstallPath);
|
|
411
|
-
content = content.replace(/\$PLUGIN_ROOT/g, () => pluginInstallPath);
|
|
412
|
-
|
|
413
|
-
// Strip require() statements
|
|
414
|
-
content = content.replace(/(?:const|let|var)\s+\{?[^}=\n]+\}?\s*=\s*require\s*\([^)]+\);?/g, '');
|
|
415
|
-
content = content.replace(/require\s*\(['"][^'"]+['"]\)/g, '');
|
|
416
|
-
|
|
417
|
-
// Strip Claude-specific syntax: Task tool calls (handles one level of nested braces)
|
|
418
|
-
content = content.replace(/await\s+Task\s*\(\s*\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}\s*\);?/g, (match) => {
|
|
419
|
-
const agentMatch = match.match(/subagent_type:\s*["'](?:[^"':]+:)?([^"']+)["']/);
|
|
420
|
-
if (agentMatch) {
|
|
421
|
-
return `Invoke the ${agentMatch[1]} agent`;
|
|
422
|
-
}
|
|
423
|
-
return '';
|
|
424
|
-
});
|
|
425
|
-
|
|
426
|
-
// Strip plugin namespacing (e.g. next-task:agent-name -> agent-name)
|
|
427
|
-
content = content.replace(/(?:next-task|deslop|ship|sync-docs|audit-project|enhance|perf|repo-map|drift-detect|consult|debate|learn|web-ctl):([a-z][a-z0-9-]*)/g, '$1');
|
|
428
|
-
|
|
429
|
-
return content;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
/**
|
|
433
|
-
* Transform skill content for Kiro.
|
|
434
|
-
*
|
|
435
|
-
* Minimal transform - Kiro reads standard SKILL.md format natively so we
|
|
436
|
-
* preserve it. Only replaces PLUGIN_ROOT paths and strips namespace prefixes.
|
|
437
|
-
*
|
|
438
|
-
* @param {string} content - Source SKILL.md content
|
|
439
|
-
* @param {Object} options
|
|
440
|
-
* @param {string} options.pluginInstallPath - Absolute path to plugin install dir
|
|
441
|
-
* @returns {string} Transformed skill content
|
|
442
|
-
*/
|
|
443
|
-
function transformSkillForKiro(content, options) {
|
|
444
|
-
const { pluginInstallPath } = options;
|
|
445
|
-
|
|
446
|
-
content = content.replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g, () => pluginInstallPath);
|
|
447
|
-
content = content.replace(/\$CLAUDE_PLUGIN_ROOT/g, () => pluginInstallPath);
|
|
448
|
-
content = content.replace(/\$\{PLUGIN_ROOT\}/g, () => pluginInstallPath);
|
|
449
|
-
content = content.replace(/\$PLUGIN_ROOT/g, () => pluginInstallPath);
|
|
450
|
-
|
|
451
|
-
content = content.replace(/(?:next-task|deslop|ship|sync-docs|audit-project|enhance|perf|repo-map|drift-detect|consult|debate|learn|web-ctl):([a-z][a-z0-9-]*)/g, '$1');
|
|
452
|
-
|
|
453
|
-
return content;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
/**
|
|
457
|
-
* Transform command content for Kiro prompt files.
|
|
458
|
-
*
|
|
459
|
-
* Strips existing frontmatter, prepends inclusion: manual frontmatter,
|
|
460
|
-
* replaces PLUGIN_ROOT paths, removes require()/Task() calls, strips namespaces.
|
|
461
|
-
*/
|
|
462
|
-
function transformCommandForKiro(content, options) {
|
|
463
|
-
const { pluginInstallPath, name = '', description = '' } = options;
|
|
464
|
-
|
|
465
|
-
if (content.startsWith('---')) {
|
|
466
|
-
content = content.replace(/^---\n[\s\S]*?\n---\n?/, '');
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
const cleanDescription = description.replace(/[\x00-\x1f\x7f]/g, ' ');
|
|
470
|
-
const escapedDescription = cleanDescription.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
471
|
-
let frontmatter = '---\n';
|
|
472
|
-
frontmatter += 'inclusion: manual\n';
|
|
473
|
-
if (name) frontmatter += `name: "${name}"\n`;
|
|
474
|
-
if (description) frontmatter += `description: "${escapedDescription}"\n`;
|
|
475
|
-
frontmatter += '---\n';
|
|
476
|
-
|
|
477
|
-
content = frontmatter + content;
|
|
478
|
-
|
|
479
|
-
content = content.replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g, () => pluginInstallPath);
|
|
480
|
-
content = content.replace(/\$CLAUDE_PLUGIN_ROOT/g, () => pluginInstallPath);
|
|
481
|
-
content = content.replace(/\$\{PLUGIN_ROOT\}/g, () => pluginInstallPath);
|
|
482
|
-
content = content.replace(/\$PLUGIN_ROOT/g, () => pluginInstallPath);
|
|
483
|
-
|
|
484
|
-
content = content.replace(/(?:const|let|var)\s+\{?[^}=\n]+\}?\s*=\s*require\s*\([^)]+\);?/g, '');
|
|
485
|
-
content = content.replace(/require\s*\(['"][^'"]+['"]\)/g, '');
|
|
486
|
-
|
|
487
|
-
// Transform code blocks containing Promise.all + Task() (parallel reviewer spawns).
|
|
488
|
-
// The bare Task() regex below can't reach inside fenced code blocks.
|
|
489
|
-
// Fence boundaries must be at line start (^```) to avoid matching backtick
|
|
490
|
-
// template literals inside the code as false fence endings.
|
|
491
|
-
content = content.replace(/^```(?:javascript|js)?\n([\s\S]*?)^```$/gm, (fullBlock, codeContent) => {
|
|
492
|
-
if (!codeContent.includes('Promise.all') || !codeContent.includes('Task(')) return fullBlock;
|
|
493
|
-
// Use lazy [\s\S]*? for the template literal body: it stops at the first backtick and
|
|
494
|
-
// naturally matches any character including standalone $ (e.g. $100, $BUDGET).
|
|
495
|
-
const taskMatches = [...codeContent.matchAll(/Task\s*\(\s*\{[\s\S]*?subagent_type:\s*['"](?:[^"':]+:)?([^'"]+)['"][\s\S]*?prompt:\s*`([\s\S]*?)`/gs)];
|
|
496
|
-
if (taskMatches.length < 2) return fullBlock;
|
|
497
|
-
|
|
498
|
-
const delegations = taskMatches.map(m => {
|
|
499
|
-
const agent = m[1];
|
|
500
|
-
const promptFirstLine = m[2].split('\n').find(l => l.trim()) || '';
|
|
501
|
-
return `Delegate to the \`${agent}\` subagent:\n> ${promptFirstLine.trim()}`;
|
|
502
|
-
});
|
|
503
|
-
|
|
504
|
-
let result = delegations.join('\n\n');
|
|
505
|
-
|
|
506
|
-
const hasReviewKeyword = delegations.some(d =>
|
|
507
|
-
/review|quality|security|performance|test|coverage/i.test(d)
|
|
508
|
-
);
|
|
509
|
-
if (delegations.length >= 4 && hasReviewKeyword) {
|
|
510
|
-
result = `**Review phase (Kiro - max 4 agents, fallback to 2 sequential):**\n\nTry delegating to these subagents (experimental parallel spawning):\n\n${result}\n\nIf parallel spawning is unavailable, run 2 combined reviewers sequentially:\n1. Delegate to the \`reviewer-quality-security\` subagent (code quality + security)\n2. Then delegate to the \`reviewer-perf-test\` subagent (performance + test coverage)\n\nAggregate all findings from whichever execution path succeeded.`;
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
return result;
|
|
514
|
-
});
|
|
515
|
-
|
|
516
|
-
// Transform bare Task() calls outside code blocks
|
|
517
|
-
content = content.replace(/await\s+Task\s*\(\s*\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}\s*\);?/g, (match) => {
|
|
518
|
-
const agentMatch = match.match(/subagent_type:\s*["'](?:[^"':]+:)?([^"']+)["']/);
|
|
519
|
-
const promptMatch = match.match(/prompt:\s*[`"']([\s\S]*?)[`"']/);
|
|
520
|
-
if (agentMatch) {
|
|
521
|
-
const agentName = agentMatch[1];
|
|
522
|
-
const prompt = promptMatch ? promptMatch[1].replace(/\\n/g, '\n').trim() : '';
|
|
523
|
-
if (prompt) {
|
|
524
|
-
return `Delegate to the \`${agentName}\` subagent:\n> ${prompt.split('\n')[0]}`;
|
|
525
|
-
}
|
|
526
|
-
return `Delegate to the \`${agentName}\` subagent.`;
|
|
527
|
-
}
|
|
528
|
-
return '';
|
|
529
|
-
});
|
|
530
|
-
|
|
531
|
-
// Transform AskUserQuestion to markdown prompt for Kiro chat
|
|
532
|
-
content = content.replace(/(?:await\s+)?AskUserQuestion\s*\(\s*\{[\s\S]*?\}\s*\);?/g, (match) => {
|
|
533
|
-
const questionMatch = match.match(/question:\s*["'`]([\s\S]*?)["'`]/);
|
|
534
|
-
const question = questionMatch ? questionMatch[1] : 'Please choose:';
|
|
535
|
-
const optionMatches = [...match.matchAll(/label:\s*["'`]([^"'`]+)["'`][\s\S]*?description:\s*["'`]([^"'`]+)["'`]/g)];
|
|
536
|
-
if (optionMatches.length > 0) {
|
|
537
|
-
const options = optionMatches.map((m, i) => `${i + 1}. **${m[1]}** - ${m[2]}`).join('\n');
|
|
538
|
-
return `**${question}**\n\n${options}\n\nReply with the number or name of your choice.`;
|
|
539
|
-
}
|
|
540
|
-
return `**${question}**\n\nReply in chat with your choice.`;
|
|
541
|
-
});
|
|
542
|
-
|
|
543
|
-
content = content.replace(/(?:next-task|deslop|ship|sync-docs|audit-project|enhance|perf|repo-map|drift-detect|consult|debate|learn|web-ctl):([a-z][a-z0-9-]*)/g, '$1');
|
|
544
|
-
|
|
545
|
-
// Batch parallel reviewer delegations for Kiro's agent limit.
|
|
546
|
-
// Detects 4+ consecutive "Delegate to" lines with review-related names
|
|
547
|
-
// and rewrites as try-4-then-fallback-to-2 pattern.
|
|
548
|
-
const reviewerBatchPattern = /((?:Delegate to the `[^`]*` subagent[^\n]*\n){4,})/g;
|
|
549
|
-
content = content.replace(reviewerBatchPattern, (block) => {
|
|
550
|
-
const delegations = block.match(/Delegate to the `([^`]+)` subagent/g) || [];
|
|
551
|
-
if (delegations.length < 4) return block;
|
|
552
|
-
|
|
553
|
-
const hasReviewKeyword = delegations.some(d =>
|
|
554
|
-
/review|quality|security|performance|test|coverage/i.test(d)
|
|
555
|
-
);
|
|
556
|
-
if (!hasReviewKeyword) return block;
|
|
557
|
-
|
|
558
|
-
return `**Review phase (Kiro - max 4 agents, fallback to 2 sequential):**
|
|
559
|
-
|
|
560
|
-
Try delegating to these subagents (experimental parallel spawning):
|
|
561
|
-
${block}
|
|
562
|
-
If parallel spawning is unavailable, run 2 combined reviewers sequentially:
|
|
563
|
-
1. Delegate to the \`reviewer-quality-security\` subagent (code quality + security)
|
|
564
|
-
2. Then delegate to the \`reviewer-perf-test\` subagent (performance + test coverage)
|
|
565
|
-
|
|
566
|
-
Aggregate all findings from whichever execution path succeeded.\n`;
|
|
567
|
-
});
|
|
568
|
-
|
|
569
|
-
return content;
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
/**
|
|
573
|
-
* Transform agent markdown+frontmatter to Kiro JSON format.
|
|
574
|
-
*
|
|
575
|
-
* Parses frontmatter for name/description/model/tools, uses body as prompt.
|
|
576
|
-
* Returns a JSON string matching Kiro's agent schema.
|
|
577
|
-
*/
|
|
578
|
-
function transformAgentForKiro(content, options) {
|
|
579
|
-
const { pluginInstallPath } = options || {};
|
|
580
|
-
|
|
581
|
-
const frontmatter = discovery.parseFrontmatter(content);
|
|
582
|
-
let body = content;
|
|
583
|
-
if (content.startsWith('---')) {
|
|
584
|
-
const endIdx = content.indexOf('\n---', 3);
|
|
585
|
-
if (endIdx !== -1) {
|
|
586
|
-
body = content.substring(endIdx + 4).replace(/^\n/, '');
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
if (pluginInstallPath) {
|
|
591
|
-
body = body.replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g, () => pluginInstallPath);
|
|
592
|
-
body = body.replace(/\$CLAUDE_PLUGIN_ROOT/g, () => pluginInstallPath);
|
|
593
|
-
body = body.replace(/\$\{PLUGIN_ROOT\}/g, () => pluginInstallPath);
|
|
594
|
-
body = body.replace(/\$PLUGIN_ROOT/g, () => pluginInstallPath);
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
body = body.replace(/(?:next-task|deslop|ship|sync-docs|audit-project|enhance|perf|repo-map|drift-detect|consult|debate|learn|web-ctl):([a-z][a-z0-9-]*)/g, '$1');
|
|
598
|
-
|
|
599
|
-
const agent = {
|
|
600
|
-
name: frontmatter.name || '',
|
|
601
|
-
description: frontmatter.description || '',
|
|
602
|
-
prompt: body.trim()
|
|
603
|
-
};
|
|
604
|
-
|
|
605
|
-
if (frontmatter.tools) {
|
|
606
|
-
// parseFrontmatter returns arrays for YAML list syntax, string for inline
|
|
607
|
-
const toolItems = Array.isArray(frontmatter.tools)
|
|
608
|
-
? frontmatter.tools.map(t => t.toLowerCase())
|
|
609
|
-
: [frontmatter.tools.toLowerCase()];
|
|
610
|
-
const toolStr = toolItems.join(' ');
|
|
611
|
-
const tools = [];
|
|
612
|
-
if (toolStr.includes('read')) tools.push('read');
|
|
613
|
-
if (toolStr.includes('edit') || toolStr.includes('write')) tools.push('write');
|
|
614
|
-
if (toolStr.includes('bash') || toolStr.includes('shell')) tools.push('shell');
|
|
615
|
-
if (toolStr.includes('glob')) tools.push('read');
|
|
616
|
-
if (toolStr.includes('grep')) tools.push('read');
|
|
617
|
-
if (toolStr.includes('task') || toolStr.includes('agent')) tools.push('shell');
|
|
618
|
-
if (toolStr.includes('web') || toolStr.includes('fetch')) tools.push('shell');
|
|
619
|
-
if (toolStr.includes('notebook')) tools.push('write');
|
|
620
|
-
if (toolStr.includes('lsp')) tools.push('read');
|
|
621
|
-
const deduped = [...new Set(tools)];
|
|
622
|
-
agent.tools = deduped.length > 0 ? deduped : ['read'];
|
|
623
|
-
} else {
|
|
624
|
-
agent.tools = ['read'];
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
agent.resources = ['file://.kiro/prompts/**/*.md'];
|
|
628
|
-
|
|
629
|
-
return JSON.stringify(agent, null, 2);
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
/**
|
|
633
|
-
* Generate a combined reviewer agent JSON for Kiro's 4-agent limit.
|
|
634
|
-
* Merges multiple review responsibilities into a single agent.
|
|
635
|
-
*
|
|
636
|
-
* @param {Array<{name: string, focus: string}>} roles - Review passes to combine
|
|
637
|
-
* @param {string} name - Agent name
|
|
638
|
-
* @param {string} description - Agent description
|
|
639
|
-
* @returns {string} JSON string for .kiro/agents/*.json
|
|
640
|
-
*/
|
|
641
|
-
function generateCombinedReviewerAgent(roles, name, description) {
|
|
642
|
-
const sections = roles.map(r =>
|
|
643
|
-
`## ${r.name} Review\n\nFocus: ${r.focus}`
|
|
644
|
-
).join('\n\n---\n\n');
|
|
645
|
-
|
|
646
|
-
const agent = {
|
|
647
|
-
name,
|
|
648
|
-
description,
|
|
649
|
-
prompt: `You are a combined code reviewer covering multiple review passes in a single session.\n\n${sections}\n\nFor each file you review, check ALL of the above review dimensions. Return findings as a JSON array with objects containing: pass (which review), file, line, severity (critical/high/medium/low), description, suggestion.`,
|
|
650
|
-
tools: ['read'],
|
|
651
|
-
resources: ['file://.kiro/prompts/**/*.md'],
|
|
652
|
-
};
|
|
653
|
-
|
|
654
|
-
return JSON.stringify(agent, null, 2);
|
|
655
|
-
}
|
|
656
|
-
|
|
657
300
|
module.exports = {
|
|
658
301
|
transformBodyForOpenCode,
|
|
659
302
|
transformCommandFrontmatterForOpenCode,
|
|
660
303
|
transformAgentFrontmatterForOpenCode,
|
|
661
304
|
transformSkillBodyForOpenCode,
|
|
662
|
-
transformForCodex
|
|
663
|
-
transformRuleForCursor,
|
|
664
|
-
transformSkillForCursor,
|
|
665
|
-
transformCommandForCursor,
|
|
666
|
-
transformForCursor: transformRuleForCursor,
|
|
667
|
-
transformSkillForKiro,
|
|
668
|
-
transformCommandForKiro,
|
|
669
|
-
transformAgentForKiro,
|
|
670
|
-
generateCombinedReviewerAgent
|
|
305
|
+
transformForCodex
|
|
671
306
|
};
|