agentsys 5.2.0 → 5.3.0
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 +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/AGENTS.md +5 -3
- package/CHANGELOG.md +27 -1
- package/README.md +6 -5
- package/agent-knowledge/AGENTS.md +32 -2
- package/agent-knowledge/acp-with-codex-gemini-copilot-claude.md +504 -0
- package/agent-knowledge/kiro-supervised-autopilot.md +400 -0
- package/agent-knowledge/resources/acp-with-codex-gemini-copilot-claude-sources.json +408 -0
- package/agent-knowledge/resources/kiro-supervised-autopilot-sources.json +135 -0
- package/bin/cli.js +305 -58
- package/lib/adapter-transforms.js +196 -1
- package/lib/cross-platform/index.js +9 -3
- package/lib/discovery/index.js +22 -0
- package/lib/platform/state-dir.js +16 -2
- package/package.json +1 -1
- package/scripts/dev-install.js +137 -1
- package/scripts/gen-adapters.js +66 -4
- package/site/content.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -22,7 +22,7 @@ const discovery = require('../lib/discovery');
|
|
|
22
22
|
const transforms = require('../lib/adapter-transforms');
|
|
23
23
|
|
|
24
24
|
// Valid tool names
|
|
25
|
-
const VALID_TOOLS = ['claude', 'opencode', 'codex', 'cursor'];
|
|
25
|
+
const VALID_TOOLS = ['claude', 'opencode', 'codex', 'cursor', 'kiro'];
|
|
26
26
|
|
|
27
27
|
function getInstallDir() {
|
|
28
28
|
const home = process.env.HOME || process.env.USERPROFILE;
|
|
@@ -231,18 +231,60 @@ function loadMarketplace() {
|
|
|
231
231
|
}
|
|
232
232
|
|
|
233
233
|
/**
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
234
|
+
* Normalize marketplace plugin source entries.
|
|
235
|
+
*
|
|
236
|
+
* Supported formats:
|
|
237
|
+
* - string URL/path (legacy)
|
|
238
|
+
* - object: { source: "url", url: "..." } (current)
|
|
239
|
+
* - object: { source: "path", path: "..." } (local/bundled)
|
|
240
|
+
*
|
|
241
|
+
* @param {string|Object} source
|
|
242
|
+
* @returns {{type: 'remote'|'local', value: string}|null}
|
|
238
243
|
*/
|
|
239
|
-
function
|
|
240
|
-
if (
|
|
241
|
-
|
|
242
|
-
|
|
244
|
+
function resolvePluginSource(source) {
|
|
245
|
+
if (typeof source === 'string') {
|
|
246
|
+
const value = source.trim();
|
|
247
|
+
if (!value) return null;
|
|
248
|
+
if (value.startsWith('./') || value.startsWith('../')) {
|
|
249
|
+
return { type: 'local', value };
|
|
250
|
+
}
|
|
251
|
+
return { type: 'remote', value };
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (!source || typeof source !== 'object') return null;
|
|
255
|
+
|
|
256
|
+
const sourceType = typeof source.source === 'string' ? source.source.toLowerCase() : null;
|
|
257
|
+
|
|
258
|
+
if ((sourceType === 'path' || sourceType === 'local') && typeof source.path === 'string') {
|
|
259
|
+
return { type: 'local', value: source.path };
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (sourceType === 'url' && typeof source.url === 'string') {
|
|
263
|
+
return { type: 'remote', value: source.url };
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Backward/forward-compatible fallbacks
|
|
267
|
+
if (typeof source.path === 'string') {
|
|
268
|
+
return { type: 'local', value: source.path };
|
|
269
|
+
}
|
|
270
|
+
if (typeof source.url === 'string') {
|
|
271
|
+
return { type: 'remote', value: source.url };
|
|
272
|
+
}
|
|
273
|
+
|
|
243
274
|
return null;
|
|
244
275
|
}
|
|
245
276
|
|
|
277
|
+
/**
|
|
278
|
+
* Backward-compatible helper returning only the source URL/path value.
|
|
279
|
+
*
|
|
280
|
+
* @param {string|Object} source
|
|
281
|
+
* @returns {string|null}
|
|
282
|
+
*/
|
|
283
|
+
function resolveSourceUrl(source) {
|
|
284
|
+
const normalized = resolvePluginSource(source);
|
|
285
|
+
return normalized ? normalized.value : null;
|
|
286
|
+
}
|
|
287
|
+
|
|
246
288
|
/**
|
|
247
289
|
* Resolve plugin dependencies transitively.
|
|
248
290
|
*
|
|
@@ -313,45 +355,72 @@ async function fetchPlugin(name, source, version) {
|
|
|
313
355
|
}
|
|
314
356
|
}
|
|
315
357
|
|
|
358
|
+
const parsedSource = parseGitHubSource(source, version, name);
|
|
359
|
+
const owner = parsedSource.owner;
|
|
360
|
+
const repo = parsedSource.repo;
|
|
361
|
+
|
|
362
|
+
const refCandidates = parsedSource.explicitRef
|
|
363
|
+
? [parsedSource.ref]
|
|
364
|
+
: [parsedSource.ref, version, 'main', 'master'];
|
|
365
|
+
|
|
366
|
+
let lastError = null;
|
|
367
|
+
for (const ref of [...new Set(refCandidates.filter(Boolean))]) {
|
|
368
|
+
const tarballUrl = `https://api.github.com/repos/${owner}/${repo}/tarball/${ref}`;
|
|
369
|
+
|
|
370
|
+
try {
|
|
371
|
+
console.log(` Fetching ${name}@${version} from ${owner}/${repo} (${ref})...`);
|
|
372
|
+
|
|
373
|
+
// Clean and recreate
|
|
374
|
+
if (fs.existsSync(pluginDir)) {
|
|
375
|
+
fs.rmSync(pluginDir, { recursive: true, force: true });
|
|
376
|
+
}
|
|
377
|
+
fs.mkdirSync(pluginDir, { recursive: true });
|
|
378
|
+
|
|
379
|
+
// Download and extract tarball
|
|
380
|
+
await downloadAndExtractTarball(tarballUrl, pluginDir);
|
|
381
|
+
|
|
382
|
+
// Write version marker
|
|
383
|
+
fs.writeFileSync(versionFile, version);
|
|
384
|
+
return pluginDir;
|
|
385
|
+
} catch (err) {
|
|
386
|
+
lastError = err;
|
|
387
|
+
const isNotFound = /HTTP 404/.test(err.message);
|
|
388
|
+
if (isNotFound && !parsedSource.explicitRef) {
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
throw err;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
throw new Error(
|
|
396
|
+
`Unable to fetch ${name} from ${owner}/${repo}. Tried refs: ${[...new Set(refCandidates.filter(Boolean))].join(', ')}. Last error: ${lastError ? lastError.message : 'unknown error'}`
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Parse GitHub source URL formats and normalize repo name.
|
|
402
|
+
*
|
|
403
|
+
* @param {string} source
|
|
404
|
+
* @param {string} version
|
|
405
|
+
* @param {string} [name]
|
|
406
|
+
* @returns {{owner: string, repo: string, ref: string, explicitRef: boolean}}
|
|
407
|
+
*/
|
|
408
|
+
function parseGitHubSource(source, version, name = 'plugin') {
|
|
316
409
|
// Parse source formats:
|
|
317
410
|
// "https://github.com/owner/repo" or "https://github.com/owner/repo#ref"
|
|
318
411
|
// "github:owner/repo" or "github:owner/repo#ref"
|
|
319
|
-
let owner, repo, ref;
|
|
320
412
|
const urlMatch = source.match(/github\.com\/([^/]+)\/([^/#]+)(?:#(.+))?/);
|
|
321
413
|
const shortMatch = !urlMatch && source.match(/^github:([^/]+)\/([^#]+)(?:#(.+))?$/);
|
|
322
414
|
const match = urlMatch || shortMatch;
|
|
323
415
|
if (!match) {
|
|
324
416
|
throw new Error(`Unsupported source format for ${name}: ${source}`);
|
|
325
417
|
}
|
|
326
|
-
owner = match[1];
|
|
327
|
-
repo = match[2].replace(/\.git$/, '');
|
|
328
|
-
ref = match[3] || `v${version}`;
|
|
329
|
-
|
|
330
|
-
console.log(` Fetching ${name}@${version} from ${owner}/${repo}...`);
|
|
331
|
-
|
|
332
|
-
// Clean and recreate
|
|
333
|
-
if (fs.existsSync(pluginDir)) {
|
|
334
|
-
fs.rmSync(pluginDir, { recursive: true, force: true });
|
|
335
|
-
}
|
|
336
|
-
fs.mkdirSync(pluginDir, { recursive: true });
|
|
337
|
-
|
|
338
|
-
// Download and extract tarball, falling back to main branch if version tag 404s
|
|
339
|
-
const tarballUrl = `https://api.github.com/repos/${owner}/${repo}/tarball/${ref}`;
|
|
340
|
-
try {
|
|
341
|
-
await downloadAndExtractTarball(tarballUrl, pluginDir);
|
|
342
|
-
} catch (err) {
|
|
343
|
-
if (ref !== 'main' && err.message && err.message.includes('404')) {
|
|
344
|
-
const mainUrl = `https://api.github.com/repos/${owner}/${repo}/tarball/main`;
|
|
345
|
-
await downloadAndExtractTarball(mainUrl, pluginDir);
|
|
346
|
-
} else {
|
|
347
|
-
throw err;
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
418
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
419
|
+
const owner = match[1];
|
|
420
|
+
const repo = match[2].replace(/\.git$/, '');
|
|
421
|
+
const explicitRef = Boolean(match[3]);
|
|
422
|
+
const ref = match[3] || `v${version}`;
|
|
423
|
+
return { owner, repo, ref, explicitRef };
|
|
355
424
|
}
|
|
356
425
|
|
|
357
426
|
/**
|
|
@@ -470,16 +539,17 @@ async function fetchExternalPlugins(pluginNames, marketplace) {
|
|
|
470
539
|
const plugin = pluginMap[name];
|
|
471
540
|
if (!plugin) continue;
|
|
472
541
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
542
|
+
const source = resolvePluginSource(plugin.source);
|
|
543
|
+
|
|
544
|
+
// Local/bundled plugin, no external fetch needed
|
|
545
|
+
if (!source || source.type === 'local') {
|
|
476
546
|
// Bundled plugin, no fetch needed
|
|
477
547
|
fetched.push(name);
|
|
478
548
|
continue;
|
|
479
549
|
}
|
|
480
550
|
|
|
481
551
|
try {
|
|
482
|
-
await fetchPlugin(name,
|
|
552
|
+
await fetchPlugin(name, source.value, plugin.version);
|
|
483
553
|
fetched.push(name);
|
|
484
554
|
} catch (err) {
|
|
485
555
|
failed.push(name);
|
|
@@ -493,6 +563,8 @@ async function fetchExternalPlugins(pluginNames, marketplace) {
|
|
|
493
563
|
console.error(`\n [WARN] Missing dependencies: ${missingDeps.join(', ')}`);
|
|
494
564
|
console.error(` Some plugins may not work correctly without their dependencies.`);
|
|
495
565
|
}
|
|
566
|
+
|
|
567
|
+
throw new Error(`Failed to fetch ${failed.length} plugin(s): ${failed.join(', ')}`);
|
|
496
568
|
}
|
|
497
569
|
|
|
498
570
|
return fetched;
|
|
@@ -786,10 +858,13 @@ function loadComponents(pluginDir) {
|
|
|
786
858
|
if (fs.existsSync(componentsPath)) {
|
|
787
859
|
try {
|
|
788
860
|
const data = JSON.parse(fs.readFileSync(componentsPath, 'utf8'));
|
|
861
|
+
const normalize = (arr) => (arr || []).map(item =>
|
|
862
|
+
typeof item === 'string' ? { name: item } : item
|
|
863
|
+
);
|
|
789
864
|
return {
|
|
790
|
-
agents: data.agents
|
|
791
|
-
skills: data.skills
|
|
792
|
-
commands: data.commands
|
|
865
|
+
agents: normalize(data.agents),
|
|
866
|
+
skills: normalize(data.skills),
|
|
867
|
+
commands: normalize(data.commands)
|
|
793
868
|
};
|
|
794
869
|
} catch {
|
|
795
870
|
// Fall through to filesystem scan
|
|
@@ -874,6 +949,9 @@ function detectInstalledPlatforms() {
|
|
|
874
949
|
// Cursor rules are project-scoped; detect only if Cursor rules/commands/skills exist in CWD
|
|
875
950
|
const cursorDir = path.join(process.cwd(), '.cursor');
|
|
876
951
|
if (fs.existsSync(path.join(cursorDir, 'rules')) || fs.existsSync(path.join(cursorDir, 'commands')) || fs.existsSync(path.join(cursorDir, 'skills'))) platforms.push('cursor');
|
|
952
|
+
// Kiro is project-scoped; detect if .kiro/ directory exists in CWD
|
|
953
|
+
const kiroDir = path.join(process.cwd(), '.kiro');
|
|
954
|
+
if (fs.existsSync(path.join(kiroDir, 'steering')) || fs.existsSync(path.join(kiroDir, 'skills')) || fs.existsSync(path.join(kiroDir, 'agents'))) platforms.push('kiro');
|
|
877
955
|
return platforms;
|
|
878
956
|
}
|
|
879
957
|
|
|
@@ -914,12 +992,15 @@ async function installPlugin(nameWithVersion, args) {
|
|
|
914
992
|
// Fetch all
|
|
915
993
|
for (const depName of toFetch) {
|
|
916
994
|
const dep = pluginMap[depName];
|
|
917
|
-
|
|
918
|
-
|
|
995
|
+
if (!dep) continue;
|
|
996
|
+
|
|
997
|
+
const source = resolvePluginSource(dep.source);
|
|
998
|
+
if (!source || source.type === 'local') continue;
|
|
999
|
+
|
|
919
1000
|
checkCoreCompat(dep);
|
|
920
1001
|
const ver = depName === name && requestedVersion ? requestedVersion : dep.version;
|
|
921
1002
|
try {
|
|
922
|
-
await fetchPlugin(depName,
|
|
1003
|
+
await fetchPlugin(depName, source.value, ver);
|
|
923
1004
|
} catch (err) {
|
|
924
1005
|
console.error(` [ERROR] Failed to fetch ${depName}: ${err.message}`);
|
|
925
1006
|
}
|
|
@@ -967,7 +1048,7 @@ async function installPlugin(nameWithVersion, args) {
|
|
|
967
1048
|
|
|
968
1049
|
// Use cache as install source
|
|
969
1050
|
const installDir = getInstallDir();
|
|
970
|
-
const needsLocal = platforms.includes('opencode') || platforms.includes('codex') || platforms.includes('cursor');
|
|
1051
|
+
const needsLocal = platforms.includes('opencode') || platforms.includes('codex') || platforms.includes('cursor') || platforms.includes('kiro');
|
|
971
1052
|
if (needsLocal && !fs.existsSync(path.join(installDir, 'lib'))) {
|
|
972
1053
|
// Need local install for transforms
|
|
973
1054
|
cleanOldInstallation(installDir);
|
|
@@ -1004,6 +1085,9 @@ async function installPlugin(nameWithVersion, args) {
|
|
|
1004
1085
|
if (platforms.includes('cursor') && installDir) {
|
|
1005
1086
|
installForCursor(installDir, { filter });
|
|
1006
1087
|
}
|
|
1088
|
+
if (platforms.includes('kiro') && installDir) {
|
|
1089
|
+
installForKiro(installDir, { filter });
|
|
1090
|
+
}
|
|
1007
1091
|
|
|
1008
1092
|
// Record in installed.json
|
|
1009
1093
|
for (const depName of toFetch) {
|
|
@@ -1615,6 +1699,158 @@ function installForCursor(installDir, options = {}) {
|
|
|
1615
1699
|
return true;
|
|
1616
1700
|
}
|
|
1617
1701
|
|
|
1702
|
+
function installForKiro(installDir, options = {}) {
|
|
1703
|
+
console.log('\n[INSTALL] Installing for Kiro...\n');
|
|
1704
|
+
const { filter = null } = options;
|
|
1705
|
+
const cwd = process.cwd();
|
|
1706
|
+
|
|
1707
|
+
// Create target directories (all project-scoped)
|
|
1708
|
+
const skillsDir = path.join(cwd, '.kiro', 'skills');
|
|
1709
|
+
const steeringDir = path.join(cwd, '.kiro', 'steering');
|
|
1710
|
+
const agentsDir = path.join(cwd, '.kiro', 'agents');
|
|
1711
|
+
fs.mkdirSync(skillsDir, { recursive: true });
|
|
1712
|
+
fs.mkdirSync(steeringDir, { recursive: true });
|
|
1713
|
+
fs.mkdirSync(agentsDir, { recursive: true });
|
|
1714
|
+
|
|
1715
|
+
// Cleanup old agentsys steering files (only those matching known commands)
|
|
1716
|
+
const steeringMappingsForCleanup = discovery.getKiroSteeringMappings(installDir);
|
|
1717
|
+
const knownSteeringFiles = new Set(steeringMappingsForCleanup.map(([name]) => `${name}.md`));
|
|
1718
|
+
for (const f of fs.readdirSync(steeringDir).filter(f => f.endsWith('.md'))) {
|
|
1719
|
+
if (knownSteeringFiles.has(f)) {
|
|
1720
|
+
fs.unlinkSync(path.join(steeringDir, f));
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
// Collect known skill names from discovery before cleanup
|
|
1725
|
+
const pluginDirs = discovery.discoverPlugins(installDir);
|
|
1726
|
+
const knownSkillNames = new Set();
|
|
1727
|
+
for (const pluginName of pluginDirs) {
|
|
1728
|
+
const srcSkillsDir = path.join(installDir, 'plugins', pluginName, 'skills');
|
|
1729
|
+
if (!fs.existsSync(srcSkillsDir)) continue;
|
|
1730
|
+
for (const d of fs.readdirSync(srcSkillsDir, { withFileTypes: true })) {
|
|
1731
|
+
if (d.isDirectory() && /^[a-zA-Z0-9_-]+$/.test(d.name)) knownSkillNames.add(d.name);
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1735
|
+
// Cleanup old agentsys skill dirs (only known names, preserve user-created skills)
|
|
1736
|
+
for (const entry of fs.readdirSync(skillsDir, { withFileTypes: true })) {
|
|
1737
|
+
if (entry.isDirectory() && knownSkillNames.has(entry.name)) {
|
|
1738
|
+
fs.rmSync(path.join(skillsDir, entry.name), { recursive: true, force: true });
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
// Cleanup old agentsys agent JSON files (only those matching known agents)
|
|
1743
|
+
const knownAgentFiles = new Set();
|
|
1744
|
+
for (const pluginName of pluginDirs) {
|
|
1745
|
+
const srcAgentsDir = path.join(installDir, 'plugins', pluginName, 'agents');
|
|
1746
|
+
if (!fs.existsSync(srcAgentsDir)) continue;
|
|
1747
|
+
for (const f of fs.readdirSync(srcAgentsDir).filter(f => f.endsWith('.md'))) {
|
|
1748
|
+
knownAgentFiles.add(f.replace(/\.md$/, '.json'));
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
for (const f of fs.readdirSync(agentsDir).filter(f => f.endsWith('.json'))) {
|
|
1752
|
+
if (knownAgentFiles.has(f)) {
|
|
1753
|
+
fs.unlinkSync(path.join(agentsDir, f));
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1757
|
+
// Install skills
|
|
1758
|
+
let skillCount = 0;
|
|
1759
|
+
for (const pluginName of pluginDirs) {
|
|
1760
|
+
const srcSkillsDir = path.join(installDir, 'plugins', pluginName, 'skills');
|
|
1761
|
+
if (!fs.existsSync(srcSkillsDir)) continue;
|
|
1762
|
+
const entries = fs.readdirSync(srcSkillsDir, { withFileTypes: true }).filter(d => d.isDirectory());
|
|
1763
|
+
for (const entry of entries) {
|
|
1764
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(entry.name)) continue;
|
|
1765
|
+
if (filter && filter.skills && filter.skills.length > 0 && !filter.skills.includes(entry.name)) continue;
|
|
1766
|
+
const srcPath = path.join(srcSkillsDir, entry.name, 'SKILL.md');
|
|
1767
|
+
if (!fs.existsSync(srcPath)) continue;
|
|
1768
|
+
const destDir = path.join(skillsDir, entry.name);
|
|
1769
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
1770
|
+
let content = fs.readFileSync(srcPath, 'utf8');
|
|
1771
|
+
content = transforms.transformSkillForKiro(content, {
|
|
1772
|
+
pluginInstallPath: path.join(installDir, 'plugins', pluginName)
|
|
1773
|
+
});
|
|
1774
|
+
fs.writeFileSync(path.join(destDir, 'SKILL.md'), content);
|
|
1775
|
+
skillCount++;
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
// Install commands as steering files
|
|
1780
|
+
const steeringMappings = discovery.getKiroSteeringMappings(installDir);
|
|
1781
|
+
let steeringCount = 0;
|
|
1782
|
+
for (const [steeringName, plugin, sourceFile, description] of steeringMappings) {
|
|
1783
|
+
if (filter && filter.commands && filter.commands.length > 0) {
|
|
1784
|
+
if (!filter.commands.includes(steeringName)) continue;
|
|
1785
|
+
}
|
|
1786
|
+
const srcPath = path.join(installDir, 'plugins', plugin, 'commands', sourceFile);
|
|
1787
|
+
if (!fs.existsSync(srcPath)) {
|
|
1788
|
+
console.log(` [WARN] Source file not found: ${srcPath}`);
|
|
1789
|
+
continue;
|
|
1790
|
+
}
|
|
1791
|
+
let content = fs.readFileSync(srcPath, 'utf8');
|
|
1792
|
+
content = transforms.transformCommandForKiro(content, {
|
|
1793
|
+
pluginInstallPath: path.join(installDir, 'plugins', plugin),
|
|
1794
|
+
name: steeringName,
|
|
1795
|
+
description
|
|
1796
|
+
});
|
|
1797
|
+
fs.writeFileSync(path.join(steeringDir, `${steeringName}.md`), content);
|
|
1798
|
+
steeringCount++;
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
// Install agents as JSON files
|
|
1802
|
+
let agentCount = 0;
|
|
1803
|
+
for (const pluginName of pluginDirs) {
|
|
1804
|
+
const srcAgentsDir = path.join(installDir, 'plugins', pluginName, 'agents');
|
|
1805
|
+
if (!fs.existsSync(srcAgentsDir)) continue;
|
|
1806
|
+
const agentFiles = fs.readdirSync(srcAgentsDir).filter(f => f.endsWith('.md'));
|
|
1807
|
+
for (const agentFile of agentFiles) {
|
|
1808
|
+
const agentName = agentFile.replace(/\.md$/, '');
|
|
1809
|
+
if (filter && filter.agents && filter.agents.length > 0 && !filter.agents.includes(agentName)) continue;
|
|
1810
|
+
const srcPath = path.join(srcAgentsDir, agentFile);
|
|
1811
|
+
let content = fs.readFileSync(srcPath, 'utf8');
|
|
1812
|
+
const jsonContent = transforms.transformAgentForKiro(content, {
|
|
1813
|
+
pluginInstallPath: path.join(installDir, 'plugins', pluginName)
|
|
1814
|
+
});
|
|
1815
|
+
fs.writeFileSync(path.join(agentsDir, `${agentName}.json`), jsonContent);
|
|
1816
|
+
agentCount++;
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
// Generate combined reviewer agents for Kiro's 4-agent experimental limit.
|
|
1821
|
+
// These are fallback agents that merge 2 review passes into 1 agent session.
|
|
1822
|
+
const combinedReviewers = [
|
|
1823
|
+
{
|
|
1824
|
+
name: 'reviewer-quality-security',
|
|
1825
|
+
description: 'Combined code quality and security reviewer for Kiro',
|
|
1826
|
+
roles: [
|
|
1827
|
+
{ name: 'Code Quality', focus: 'Error handling, maintainability, naming, duplication, dead code, logging quality' },
|
|
1828
|
+
{ name: 'Security', focus: 'Auth vulnerabilities, input validation, injection risks, secrets exposure, OWASP top 10' },
|
|
1829
|
+
]
|
|
1830
|
+
},
|
|
1831
|
+
{
|
|
1832
|
+
name: 'reviewer-perf-test',
|
|
1833
|
+
description: 'Combined performance and test coverage reviewer for Kiro',
|
|
1834
|
+
roles: [
|
|
1835
|
+
{ name: 'Performance', focus: 'Hot paths, algorithmic complexity, unnecessary allocations, N+1 queries, caching opportunities' },
|
|
1836
|
+
{ name: 'Test Coverage', focus: 'Missing tests, edge cases, assertion quality, test isolation, mock correctness' },
|
|
1837
|
+
]
|
|
1838
|
+
},
|
|
1839
|
+
];
|
|
1840
|
+
for (const cr of combinedReviewers) {
|
|
1841
|
+
const json = transforms.generateCombinedReviewerAgent(cr.roles, cr.name, cr.description);
|
|
1842
|
+
fs.writeFileSync(path.join(agentsDir, `${cr.name}.json`), json);
|
|
1843
|
+
agentCount++;
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1846
|
+
console.log(`\n[OK] Kiro installation complete!`);
|
|
1847
|
+
console.log(` Skills: ${skillCount} installed to ${skillsDir}`);
|
|
1848
|
+
console.log(` Steering: ${steeringCount} installed to ${steeringDir}`);
|
|
1849
|
+
console.log(` Agents: ${agentCount} installed to ${agentsDir} (includes 2 combined reviewers)`);
|
|
1850
|
+
console.log(' All content is project-scoped under .kiro/.\n');
|
|
1851
|
+
return true;
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1618
1854
|
function removeInstallation() {
|
|
1619
1855
|
const installDir = getInstallDir();
|
|
1620
1856
|
|
|
@@ -1632,6 +1868,7 @@ function removeInstallation() {
|
|
|
1632
1868
|
console.log(' - OpenCode: Remove files under ~/.config/opencode/ (commands/*.md, agents/*.md, skills/*/SKILL.md) and ~/.config/opencode/plugins/agentsys.ts');
|
|
1633
1869
|
console.log(' - Codex: Remove ~/.codex/skills/*/');
|
|
1634
1870
|
console.log(' - Cursor: Remove .cursor/skills/, .cursor/commands/, and .cursor/rules/agentsys-*.mdc from your project');
|
|
1871
|
+
console.log(' - Kiro: Remove .kiro/skills/, .kiro/steering/, and .kiro/agents/ from your project');
|
|
1635
1872
|
}
|
|
1636
1873
|
|
|
1637
1874
|
function printSubcommandHelp(subcommand) {
|
|
@@ -1652,7 +1889,7 @@ Examples:
|
|
|
1652
1889
|
agentsys install perf@1.2.0 Install perf at version 1.2.0
|
|
1653
1890
|
|
|
1654
1891
|
Options:
|
|
1655
|
-
--tool <name> Install for a specific platform (claude, opencode, codex, cursor)
|
|
1892
|
+
--tool <name> Install for a specific platform (claude, opencode, codex, cursor, kiro)
|
|
1656
1893
|
--tools <list> Install for multiple platforms (comma-separated)
|
|
1657
1894
|
|
|
1658
1895
|
Notes:
|
|
@@ -1746,7 +1983,7 @@ agentsys v${VERSION} - Workflow automation for AI coding assistants
|
|
|
1746
1983
|
|
|
1747
1984
|
Usage:
|
|
1748
1985
|
agentsys Interactive installer (select platforms)
|
|
1749
|
-
agentsys --tool <name> Install for single tool (claude, opencode, codex, cursor)
|
|
1986
|
+
agentsys --tool <name> Install for single tool (claude, opencode, codex, cursor, kiro)
|
|
1750
1987
|
agentsys --tools <list> Install for multiple tools (comma-separated)
|
|
1751
1988
|
agentsys --only <plugins> Install only specified plugins (comma-separated, resolves deps)
|
|
1752
1989
|
agentsys --development Development mode: install to ~/.claude/plugins
|
|
@@ -1773,7 +2010,7 @@ Non-Interactive Examples:
|
|
|
1773
2010
|
agentsys --tool claude # Install for Claude Code only
|
|
1774
2011
|
agentsys --tool opencode # Install for OpenCode only
|
|
1775
2012
|
agentsys --tools "claude,opencode" # Install for both
|
|
1776
|
-
agentsys --tools claude,opencode,codex,cursor # Install for all
|
|
2013
|
+
agentsys --tools claude,opencode,codex,cursor,kiro # Install for all
|
|
1777
2014
|
agentsys --only next-task # Install next-task + its dependencies
|
|
1778
2015
|
agentsys --only "next-task,perf" # Install specific plugins + deps
|
|
1779
2016
|
|
|
@@ -1793,7 +2030,8 @@ Supported Platforms:
|
|
|
1793
2030
|
claude - Claude Code (marketplace install or development mode)
|
|
1794
2031
|
opencode - OpenCode (local commands + native plugin)
|
|
1795
2032
|
codex - Codex CLI (local skills)
|
|
1796
|
-
cursor - Cursor (project-scoped
|
|
2033
|
+
cursor - Cursor (project-scoped skills + commands)
|
|
2034
|
+
kiro - Kiro (project-scoped steering + skills + agents)
|
|
1797
2035
|
|
|
1798
2036
|
Install: npm install -g agentsys && agentsys
|
|
1799
2037
|
Update: npm update -g agentsys && agentsys
|
|
@@ -1899,7 +2137,8 @@ async function main() {
|
|
|
1899
2137
|
{ value: 'claude', label: 'Claude Code' },
|
|
1900
2138
|
{ value: 'opencode', label: 'OpenCode' },
|
|
1901
2139
|
{ value: 'codex', label: 'Codex CLI' },
|
|
1902
|
-
{ value: 'cursor', label: 'Cursor' }
|
|
2140
|
+
{ value: 'cursor', label: 'Cursor' },
|
|
2141
|
+
{ value: 'kiro', label: 'Kiro' }
|
|
1903
2142
|
];
|
|
1904
2143
|
|
|
1905
2144
|
selected = await multiSelect(
|
|
@@ -1928,10 +2167,8 @@ async function main() {
|
|
|
1928
2167
|
if (entry) checkCoreCompat(entry);
|
|
1929
2168
|
}
|
|
1930
2169
|
|
|
1931
|
-
await fetchExternalPlugins(pluginNames, marketplace);
|
|
1932
|
-
|
|
1933
2170
|
// Only copy to ~/.agentsys if OpenCode, Codex, or Cursor selected (they need local files)
|
|
1934
|
-
const needsLocalInstall = selected.includes('opencode') || selected.includes('codex') || selected.includes('cursor');
|
|
2171
|
+
const needsLocalInstall = selected.includes('opencode') || selected.includes('codex') || selected.includes('cursor') || selected.includes('kiro');
|
|
1935
2172
|
let installDir = null;
|
|
1936
2173
|
|
|
1937
2174
|
if (needsLocalInstall) {
|
|
@@ -1941,6 +2178,8 @@ async function main() {
|
|
|
1941
2178
|
installDependencies(installDir);
|
|
1942
2179
|
}
|
|
1943
2180
|
|
|
2181
|
+
await fetchExternalPlugins(pluginNames, marketplace);
|
|
2182
|
+
|
|
1944
2183
|
// Install for each platform
|
|
1945
2184
|
const failedPlatforms = [];
|
|
1946
2185
|
for (const platform of selected) {
|
|
@@ -1969,6 +2208,11 @@ async function main() {
|
|
|
1969
2208
|
failedPlatforms.push('cursor');
|
|
1970
2209
|
}
|
|
1971
2210
|
break;
|
|
2211
|
+
case 'kiro':
|
|
2212
|
+
if (!installForKiro(installDir)) {
|
|
2213
|
+
failedPlatforms.push('kiro');
|
|
2214
|
+
}
|
|
2215
|
+
break;
|
|
1972
2216
|
}
|
|
1973
2217
|
}
|
|
1974
2218
|
|
|
@@ -2020,5 +2264,8 @@ module.exports = {
|
|
|
2020
2264
|
loadComponents,
|
|
2021
2265
|
resolveComponent,
|
|
2022
2266
|
buildFilterFromComponent,
|
|
2023
|
-
|
|
2267
|
+
resolvePluginSource,
|
|
2268
|
+
parseGitHubSource,
|
|
2269
|
+
installForCursor,
|
|
2270
|
+
installForKiro
|
|
2024
2271
|
};
|