@phnx-labs/agents-cli 1.20.58 → 1.20.60
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/CHANGELOG.md +23 -1
- package/README.md +15 -7
- package/dist/bin/agents +0 -0
- package/dist/commands/exec.js +39 -2
- package/dist/commands/output.d.ts +19 -0
- package/dist/commands/output.js +333 -0
- package/dist/commands/secrets.js +6 -6
- package/dist/index.js +2 -1
- package/dist/lib/agents.js +19 -13
- package/dist/lib/hosts/dispatch.d.ts +36 -0
- package/dist/lib/hosts/dispatch.js +40 -2
- package/dist/lib/hosts/passthrough.js +1 -0
- package/dist/lib/mcp.js +1 -1
- package/dist/lib/output/git-output.d.ts +74 -0
- package/dist/lib/output/git-output.js +213 -0
- package/dist/lib/permissions.d.ts +26 -5
- package/dist/lib/permissions.js +212 -37
- package/dist/lib/plugins.d.ts +8 -0
- package/dist/lib/plugins.js +108 -0
- package/dist/lib/project-root.js +2 -1
- package/dist/lib/resources/mcp.js +1 -1
- package/dist/lib/resources/permissions.d.ts +1 -1
- package/dist/lib/resources/permissions.js +8 -2
- package/dist/lib/resources/skills.js +6 -1
- package/dist/lib/resources/types.d.ts +1 -1
- package/dist/lib/routines.d.ts +16 -0
- package/dist/lib/routines.js +46 -1
- package/dist/lib/secrets/remote.d.ts +7 -2
- package/dist/lib/secrets/remote.js +11 -10
- package/dist/lib/session/db.d.ts +3 -0
- package/dist/lib/session/db.js +20 -4
- package/dist/lib/session/discover.d.ts +2 -0
- package/dist/lib/session/discover.js +40 -4
- package/dist/lib/session/types.d.ts +2 -0
- package/dist/lib/shims.js +13 -3
- package/dist/lib/skills.js +14 -1
- package/dist/lib/staleness/detectors/permissions.js +50 -3
- package/dist/lib/staleness/detectors/subagents.js +31 -12
- package/dist/lib/staleness/detectors/workflows.js +33 -0
- package/dist/lib/staleness/writers/commands.js +3 -3
- package/dist/lib/staleness/writers/subagents.js +13 -5
- package/dist/lib/startup/command-registry.d.ts +1 -0
- package/dist/lib/startup/command-registry.js +2 -0
- package/dist/lib/subagents.d.ts +11 -1
- package/dist/lib/subagents.js +117 -26
- package/dist/lib/versions.js +12 -2
- package/dist/lib/workflows.d.ts +5 -3
- package/dist/lib/workflows.js +246 -9
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Subagents detector. Claude: flat .md files under `<agentDir>/agents/`.
|
|
2
|
+
* Subagents detector. Claude/Gemini/Grok: flat .md files under `<agentDir>/agents/`.
|
|
3
3
|
* Codex: flat .toml files under `<versionHome>/.codex/agents/`.
|
|
4
4
|
* Droid: flat .md files under `<versionHome>/.factory/droids/`.
|
|
5
5
|
* OpenClaw: subdirectories containing AGENTS.md under `<versionHome>/.openclaw/`.
|
|
@@ -29,6 +29,9 @@ function buildClaudeDetector() {
|
|
|
29
29
|
function buildGrokDetector() {
|
|
30
30
|
return buildFlatMdAgentsDetector('grok', '.grok');
|
|
31
31
|
}
|
|
32
|
+
function buildGeminiDetector() {
|
|
33
|
+
return buildFlatMdAgentsDetector('gemini', '.gemini');
|
|
34
|
+
}
|
|
32
35
|
function buildCodexDetector() {
|
|
33
36
|
return {
|
|
34
37
|
kind: 'subagents',
|
|
@@ -85,32 +88,32 @@ function buildOpenclawDetector() {
|
|
|
85
88
|
},
|
|
86
89
|
};
|
|
87
90
|
}
|
|
88
|
-
function
|
|
91
|
+
function buildKimiDetector() {
|
|
89
92
|
return {
|
|
90
93
|
kind: 'subagents',
|
|
91
|
-
agent: '
|
|
94
|
+
agent: 'kimi',
|
|
92
95
|
list({ versionHome }) {
|
|
93
|
-
const agentsDir = path.join(versionHome, '.
|
|
96
|
+
const agentsDir = path.join(versionHome, '.kimi-code', 'agents');
|
|
94
97
|
if (!fs.existsSync(agentsDir))
|
|
95
98
|
return [];
|
|
99
|
+
// Parent is `_agents-cli.yaml` (underscore-prefixed reserved name).
|
|
96
100
|
return fs.readdirSync(agentsDir)
|
|
97
|
-
.filter(f => f.endsWith('.
|
|
98
|
-
.map(f => f.replace(
|
|
101
|
+
.filter(f => f.endsWith('.yaml') && !f.startsWith('_'))
|
|
102
|
+
.map(f => f.replace(/\.yaml$/, ''));
|
|
99
103
|
},
|
|
100
104
|
};
|
|
101
105
|
}
|
|
102
|
-
function
|
|
106
|
+
function buildKiroDetector() {
|
|
103
107
|
return {
|
|
104
108
|
kind: 'subagents',
|
|
105
|
-
agent: '
|
|
109
|
+
agent: 'kiro',
|
|
106
110
|
list({ versionHome }) {
|
|
107
|
-
const agentsDir = path.join(versionHome, '.
|
|
111
|
+
const agentsDir = path.join(versionHome, '.kiro', 'agents');
|
|
108
112
|
if (!fs.existsSync(agentsDir))
|
|
109
113
|
return [];
|
|
110
|
-
// Parent is `_agents-cli.yaml` (underscore-prefixed reserved name).
|
|
111
114
|
return fs.readdirSync(agentsDir)
|
|
112
|
-
.filter(f => f.endsWith('.
|
|
113
|
-
.map(f => f.replace(/\.
|
|
115
|
+
.filter(f => f.endsWith('.json'))
|
|
116
|
+
.map(f => f.replace(/\.json$/, ''));
|
|
114
117
|
},
|
|
115
118
|
};
|
|
116
119
|
}
|
|
@@ -128,13 +131,29 @@ function buildOpenCodeDetector() {
|
|
|
128
131
|
},
|
|
129
132
|
};
|
|
130
133
|
}
|
|
134
|
+
function buildAntigravityDetector() {
|
|
135
|
+
return {
|
|
136
|
+
kind: 'subagents',
|
|
137
|
+
agent: 'antigravity',
|
|
138
|
+
list({ versionHome }) {
|
|
139
|
+
const agentsDir = path.join(versionHome, '.gemini', 'config', 'agents');
|
|
140
|
+
if (!fs.existsSync(agentsDir))
|
|
141
|
+
return [];
|
|
142
|
+
return fs.readdirSync(agentsDir, { withFileTypes: true })
|
|
143
|
+
.filter(d => d.isDirectory() && fs.existsSync(path.join(agentsDir, d.name, 'agent.md')))
|
|
144
|
+
.map(d => d.name);
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
}
|
|
131
148
|
const handlers = {
|
|
132
149
|
claude: buildClaudeDetector,
|
|
133
150
|
copilot: buildCopilotDetector,
|
|
151
|
+
gemini: buildGeminiDetector,
|
|
134
152
|
grok: buildGrokDetector,
|
|
135
153
|
codex: buildCodexDetector,
|
|
136
154
|
kimi: buildKimiDetector,
|
|
137
155
|
opencode: buildOpenCodeDetector,
|
|
156
|
+
antigravity: buildAntigravityDetector,
|
|
138
157
|
droid: buildDroidDetector,
|
|
139
158
|
openclaw: buildOpenclawDetector,
|
|
140
159
|
kiro: buildKiroDetector,
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import * as fs from 'fs';
|
|
6
6
|
import * as path from 'path';
|
|
7
|
+
import * as yaml from 'yaml';
|
|
7
8
|
import { capableAgents } from '../../capabilities.js';
|
|
8
9
|
import { lazyAgentMap } from '../writers/lazy-map.js';
|
|
9
10
|
function buildWorkflowsDetector(agent) {
|
|
@@ -11,6 +12,38 @@ function buildWorkflowsDetector(agent) {
|
|
|
11
12
|
kind: 'workflows',
|
|
12
13
|
agent,
|
|
13
14
|
list({ versionHome }) {
|
|
15
|
+
if (agent === 'kimi') {
|
|
16
|
+
const skillsDir = path.join(versionHome, '.kimi-code', 'skills');
|
|
17
|
+
if (!fs.existsSync(skillsDir))
|
|
18
|
+
return [];
|
|
19
|
+
return fs.readdirSync(skillsDir, { withFileTypes: true })
|
|
20
|
+
.filter(d => d.isDirectory() && fs.existsSync(path.join(skillsDir, d.name, 'SKILL.md')))
|
|
21
|
+
.filter(d => {
|
|
22
|
+
try {
|
|
23
|
+
const skill = fs.readFileSync(path.join(skillsDir, d.name, 'SKILL.md'), 'utf-8');
|
|
24
|
+
const lines = skill.split('\n');
|
|
25
|
+
if (lines[0] !== '---')
|
|
26
|
+
return false;
|
|
27
|
+
const endIndex = lines.slice(1).findIndex(l => l === '---');
|
|
28
|
+
if (endIndex < 0)
|
|
29
|
+
return false;
|
|
30
|
+
const parsed = yaml.parse(lines.slice(1, endIndex + 1).join('\n'));
|
|
31
|
+
return parsed?.type === 'flow' && parsed.agents_workflow === d.name;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
.map(d => d.name);
|
|
38
|
+
}
|
|
39
|
+
if (agent === 'goose') {
|
|
40
|
+
const recipesDir = path.join(versionHome, '.config', 'goose', 'recipes');
|
|
41
|
+
if (!fs.existsSync(recipesDir))
|
|
42
|
+
return [];
|
|
43
|
+
return fs.readdirSync(recipesDir, { withFileTypes: true })
|
|
44
|
+
.filter(d => d.isFile() && d.name.endsWith('.yaml') && !d.name.startsWith('.'))
|
|
45
|
+
.map(d => d.name.slice(0, -'.yaml'.length));
|
|
46
|
+
}
|
|
14
47
|
const workflowsDir = path.join(versionHome, 'workflows');
|
|
15
48
|
if (!fs.existsSync(workflowsDir))
|
|
16
49
|
return [];
|
|
@@ -36,10 +36,10 @@ function buildCommandsWriter(agent) {
|
|
|
36
36
|
const agentDir = path.join(versionHome, agentConfigDirName(agent));
|
|
37
37
|
const commandsAsSkills = shouldInstallCommandAsSkill(agent, version);
|
|
38
38
|
const supportsCommands = supports(agent, 'commands', version).ok;
|
|
39
|
-
//
|
|
40
|
-
//
|
|
39
|
+
// Version-gated agents (e.g. goose skills >= 1.25.0) are registered but
|
|
40
|
+
// may be called at a version too old for both paths — skip gracefully.
|
|
41
41
|
if (!commandsAsSkills && !supportsCommands) {
|
|
42
|
-
|
|
42
|
+
return { synced: [] };
|
|
43
43
|
}
|
|
44
44
|
const skillRoots = trustedSkillRoots();
|
|
45
45
|
const commandsTarget = path.join(agentDir, agentConfig.commandsSubdir);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Subagents writer. Claude
|
|
3
|
-
* under
|
|
2
|
+
* Subagents writer. Claude/Gemini/Grok flatten each subagent into a single
|
|
3
|
+
* .md file under their native agents directory. Codex writes TOML under
|
|
4
|
+
* `.codex/agents/`.
|
|
4
5
|
* Droid (Factory AI) flattens each into a custom droid .md under
|
|
5
6
|
* `<versionHome>/.factory/droids/`. OpenClaw copies the full subagent
|
|
6
7
|
* directory (with AGENT.md renamed to AGENTS.md) into
|
|
@@ -13,7 +14,7 @@
|
|
|
13
14
|
import * as fs from 'fs';
|
|
14
15
|
import * as path from 'path';
|
|
15
16
|
import { capableAgents } from '../../capabilities.js';
|
|
16
|
-
import { listInstalledSubagents, transformSubagentForClaude, transformSubagentForCodex, transformSubagentForCopilot, writeKimiSubagentFiles, buildKimiSubagentsParentYaml, KIMI_SUBAGENTS_PARENT_FILE, transformSubagentForOpenCode, transformSubagentForDroid, transformSubagentForKiro, syncSubagentToOpenclaw, parseSubagentFrontmatter, } from '../../subagents.js';
|
|
17
|
+
import { listInstalledSubagents, transformSubagentForClaude, transformSubagentForCodex, transformSubagentForCopilot, writeKimiSubagentFiles, buildKimiSubagentsParentYaml, KIMI_SUBAGENTS_PARENT_FILE, transformSubagentForOpenCode, transformSubagentForAntigravity, transformSubagentForDroid, transformSubagentForKiro, syncSubagentToOpenclaw, parseSubagentFrontmatter, } from '../../subagents.js';
|
|
17
18
|
import { safeJoin } from '../../paths.js';
|
|
18
19
|
import { lazyAgentMap } from './lazy-map.js';
|
|
19
20
|
function buildSubagentsWriter(agent) {
|
|
@@ -29,8 +30,9 @@ function buildSubagentsWriter(agent) {
|
|
|
29
30
|
if (!sub)
|
|
30
31
|
continue;
|
|
31
32
|
try {
|
|
32
|
-
if (agent === 'claude' || agent === 'grok') {
|
|
33
|
-
const
|
|
33
|
+
if (agent === 'claude' || agent === 'gemini' || agent === 'grok') {
|
|
34
|
+
const agentsRoot = agent === 'grok' ? '.grok' : agent === 'gemini' ? '.gemini' : '.claude';
|
|
35
|
+
const agentsDir = path.join(versionHome, agentsRoot, 'agents');
|
|
34
36
|
fs.mkdirSync(agentsDir, { recursive: true });
|
|
35
37
|
fs.writeFileSync(safeJoin(agentsDir, `${sub.name}.md`), transformSubagentForClaude(sub.path));
|
|
36
38
|
synced.push(sub.name);
|
|
@@ -51,6 +53,12 @@ function buildSubagentsWriter(agent) {
|
|
|
51
53
|
fs.writeFileSync(safeJoin(agentsDir, `${sub.name}.md`), transformSubagentForOpenCode(sub.path));
|
|
52
54
|
synced.push(sub.name);
|
|
53
55
|
}
|
|
56
|
+
else if (agent === 'antigravity') {
|
|
57
|
+
const agentDir = safeJoin(path.join(versionHome, '.gemini', 'config', 'agents'), sub.name);
|
|
58
|
+
fs.mkdirSync(agentDir, { recursive: true });
|
|
59
|
+
fs.writeFileSync(safeJoin(agentDir, 'agent.md'), transformSubagentForAntigravity(sub.path));
|
|
60
|
+
synced.push(sub.name);
|
|
61
|
+
}
|
|
54
62
|
else if (agent === 'droid') {
|
|
55
63
|
const droidsDir = path.join(versionHome, '.factory', 'droids');
|
|
56
64
|
fs.mkdirSync(droidsDir, { recursive: true });
|
|
@@ -65,6 +65,7 @@ export declare const loadDrive: ModuleLoader;
|
|
|
65
65
|
export declare const loadFactory: ModuleLoader;
|
|
66
66
|
export declare const loadUsage: ModuleLoader;
|
|
67
67
|
export declare const loadCost: ModuleLoader;
|
|
68
|
+
export declare const loadOutput: ModuleLoader;
|
|
68
69
|
export declare const loadBudget: ModuleLoader;
|
|
69
70
|
export declare const loadAlias: ModuleLoader;
|
|
70
71
|
export declare const loadPty: ModuleLoader;
|
|
@@ -43,6 +43,7 @@ export const loadDrive = async () => (await import('../../commands/drive.js')).r
|
|
|
43
43
|
export const loadFactory = async () => (await import('../../commands/factory.js')).registerFactoryCommands;
|
|
44
44
|
export const loadUsage = async () => (await import('../../commands/usage.js')).registerUsageCommand;
|
|
45
45
|
export const loadCost = async () => (await import('../../commands/cost.js')).registerCostCommand;
|
|
46
|
+
export const loadOutput = async () => (await import('../../commands/output.js')).registerOutputCommand;
|
|
46
47
|
export const loadBudget = async () => (await import('../../commands/budget.js')).registerBudgetCommand;
|
|
47
48
|
export const loadAlias = async () => (await import('../../commands/alias.js')).registerAliasCommand;
|
|
48
49
|
export const loadPty = async () => (await import('../../commands/pty.js')).registerPtyCommands;
|
|
@@ -137,6 +138,7 @@ export const COMMAND_LOADERS = {
|
|
|
137
138
|
factory: [loadFactory],
|
|
138
139
|
usage: [loadUsage],
|
|
139
140
|
cost: [loadCost],
|
|
141
|
+
output: [loadOutput],
|
|
140
142
|
budget: [loadBudget],
|
|
141
143
|
alias: [loadAlias],
|
|
142
144
|
pty: [loadPty],
|
package/dist/lib/subagents.d.ts
CHANGED
|
@@ -68,6 +68,15 @@ export declare function transformSubagentForDroid(subagentDir: string): string;
|
|
|
68
68
|
* See GitHub docs for custom agents.
|
|
69
69
|
*/
|
|
70
70
|
export declare const transformSubagentForCopilot: typeof transformSubagentForDroid;
|
|
71
|
+
/**
|
|
72
|
+
* Transform a subagent into Antigravity's custom-agent markdown shape.
|
|
73
|
+
*
|
|
74
|
+
* Antigravity exposes custom agents as Markdown files with YAML frontmatter,
|
|
75
|
+
* close to Gemini CLI subagents. Keep portable frontmatter fields and flatten
|
|
76
|
+
* sibling markdown files into the prompt body like the other markdown-backed
|
|
77
|
+
* agents.
|
|
78
|
+
*/
|
|
79
|
+
export declare function transformSubagentForAntigravity(subagentDir: string): string;
|
|
71
80
|
/**
|
|
72
81
|
* Transform a subagent into an OpenCode agent markdown file.
|
|
73
82
|
*
|
|
@@ -157,8 +166,9 @@ export declare function removeSubagentFromAgent(subagentName: string, agent: Age
|
|
|
157
166
|
export declare function subagentContentMatches(installedDir: string, sourceDir: string): boolean;
|
|
158
167
|
/**
|
|
159
168
|
* List subagents installed to a specific agent's home
|
|
160
|
-
* Claude: scans ~/.
|
|
169
|
+
* Claude/Gemini/Grok: scans ~/.{agent}/agents/{name}.md
|
|
161
170
|
* Kimi: scans ~/.kimi-code/agents/{name}.yaml (+ sibling .system.md)
|
|
171
|
+
* Kiro: scans ~/.kiro/agents/{name}.json
|
|
162
172
|
* OpenClaw: scans ~/.openclaw/{name}/AGENTS.md
|
|
163
173
|
*/
|
|
164
174
|
export declare function listSubagentsForAgent(agentId: AgentId, home: string): InstalledSubagent[];
|
package/dist/lib/subagents.js
CHANGED
|
@@ -274,6 +274,39 @@ export function transformSubagentForDroid(subagentDir) {
|
|
|
274
274
|
* See GitHub docs for custom agents.
|
|
275
275
|
*/
|
|
276
276
|
export const transformSubagentForCopilot = transformSubagentForDroid;
|
|
277
|
+
/**
|
|
278
|
+
* Transform a subagent into Antigravity's custom-agent markdown shape.
|
|
279
|
+
*
|
|
280
|
+
* Antigravity exposes custom agents as Markdown files with YAML frontmatter,
|
|
281
|
+
* close to Gemini CLI subagents. Keep portable frontmatter fields and flatten
|
|
282
|
+
* sibling markdown files into the prompt body like the other markdown-backed
|
|
283
|
+
* agents.
|
|
284
|
+
*/
|
|
285
|
+
export function transformSubagentForAntigravity(subagentDir) {
|
|
286
|
+
const agentMd = path.join(subagentDir, 'AGENT.md');
|
|
287
|
+
const frontmatter = parseSubagentFrontmatter(agentMd);
|
|
288
|
+
const body = getSubagentBody(agentMd);
|
|
289
|
+
if (!frontmatter) {
|
|
290
|
+
throw new Error(`Invalid AGENT.md in ${subagentDir}`);
|
|
291
|
+
}
|
|
292
|
+
const frontmatterYaml = yaml.stringify({
|
|
293
|
+
name: frontmatter.name,
|
|
294
|
+
description: frontmatter.description,
|
|
295
|
+
kind: 'local',
|
|
296
|
+
...(frontmatter.model && { model: frontmatter.model }),
|
|
297
|
+
}).trim();
|
|
298
|
+
let result = `---\n${frontmatterYaml}\n---\n\n${body}`;
|
|
299
|
+
const files = fs.readdirSync(subagentDir)
|
|
300
|
+
.filter(f => f.endsWith('.md') && f !== 'AGENT.md')
|
|
301
|
+
.sort();
|
|
302
|
+
for (const file of files) {
|
|
303
|
+
const content = fs.readFileSync(path.join(subagentDir, file), 'utf-8').trim();
|
|
304
|
+
const sectionName = file.replace('.md', '');
|
|
305
|
+
const title = sectionName.charAt(0).toUpperCase() + sectionName.slice(1).toLowerCase();
|
|
306
|
+
result += `\n\n## ${title}\n\n${content}`;
|
|
307
|
+
}
|
|
308
|
+
return `${result.trim()}\n`;
|
|
309
|
+
}
|
|
277
310
|
/**
|
|
278
311
|
* Transform a subagent into an OpenCode agent markdown file.
|
|
279
312
|
*
|
|
@@ -393,21 +426,10 @@ export function writeKimiSubagentFiles(agentsDir, subagentDir, name) {
|
|
|
393
426
|
export function transformSubagentForCodex(subagentDir) {
|
|
394
427
|
const agentMd = path.join(subagentDir, 'AGENT.md');
|
|
395
428
|
const frontmatter = parseSubagentFrontmatter(agentMd);
|
|
396
|
-
const body = getSubagentBody(agentMd);
|
|
397
429
|
if (!frontmatter) {
|
|
398
430
|
throw new Error(`Invalid AGENT.md in ${subagentDir}`);
|
|
399
431
|
}
|
|
400
|
-
|
|
401
|
-
let instructions = body.trim();
|
|
402
|
-
const files = fs.readdirSync(subagentDir)
|
|
403
|
-
.filter(f => f.endsWith('.md') && f !== 'AGENT.md')
|
|
404
|
-
.sort();
|
|
405
|
-
for (const file of files) {
|
|
406
|
-
const content = fs.readFileSync(path.join(subagentDir, file), 'utf-8').trim();
|
|
407
|
-
const sectionName = file.replace('.md', '');
|
|
408
|
-
const title = sectionName.charAt(0).toUpperCase() + sectionName.slice(1).toLowerCase();
|
|
409
|
-
instructions += `\n\n## ${title}\n\n${content}`;
|
|
410
|
-
}
|
|
432
|
+
const instructions = flattenSubagentInstructions(subagentDir);
|
|
411
433
|
// Escape TOML multi-line string (""") content — only """ needs escaping.
|
|
412
434
|
const safeInstructions = instructions.replace(/"""/g, '\\"""');
|
|
413
435
|
const safeName = frontmatter.name.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
@@ -421,6 +443,19 @@ export function transformSubagentForCodex(subagentDir) {
|
|
|
421
443
|
toml += `developer_instructions = """\n${safeInstructions}\n"""\n`;
|
|
422
444
|
return toml;
|
|
423
445
|
}
|
|
446
|
+
function flattenSubagentInstructions(subagentDir) {
|
|
447
|
+
let instructions = getSubagentBody(path.join(subagentDir, 'AGENT.md')).trim();
|
|
448
|
+
const files = fs.readdirSync(subagentDir)
|
|
449
|
+
.filter(f => f.endsWith('.md') && f !== 'AGENT.md')
|
|
450
|
+
.sort();
|
|
451
|
+
for (const file of files) {
|
|
452
|
+
const content = fs.readFileSync(path.join(subagentDir, file), 'utf-8').trim();
|
|
453
|
+
const sectionName = file.replace('.md', '');
|
|
454
|
+
const title = sectionName.charAt(0).toUpperCase() + sectionName.slice(1).toLowerCase();
|
|
455
|
+
instructions += `\n\n## ${title}\n\n${content}`;
|
|
456
|
+
}
|
|
457
|
+
return instructions;
|
|
458
|
+
}
|
|
424
459
|
/**
|
|
425
460
|
* Transform a subagent into a Kiro CLI custom-agent JSON file.
|
|
426
461
|
*
|
|
@@ -487,10 +522,10 @@ export function syncSubagentToOpenclaw(subagentDir, targetDir) {
|
|
|
487
522
|
* Install a subagent to a specific agent's home
|
|
488
523
|
*/
|
|
489
524
|
export function installSubagentToAgent(subagentDir, subagentName, agent, agentHome) {
|
|
490
|
-
if (agent === 'claude' || agent === 'grok') {
|
|
491
|
-
// Claude / Grok: flatten to single .md under
|
|
492
|
-
|
|
493
|
-
const agentsDir = path.join(agentHome,
|
|
525
|
+
if (agent === 'claude' || agent === 'gemini' || agent === 'grok') {
|
|
526
|
+
// Claude / Gemini / Grok: flatten to single .md under the native agents dir.
|
|
527
|
+
const agentsRoot = agent === 'grok' ? '.grok' : agent === 'gemini' ? '.gemini' : '.claude';
|
|
528
|
+
const agentsDir = path.join(agentHome, agentsRoot, 'agents');
|
|
494
529
|
if (!fs.existsSync(agentsDir)) {
|
|
495
530
|
fs.mkdirSync(agentsDir, { recursive: true });
|
|
496
531
|
}
|
|
@@ -541,6 +576,19 @@ export function installSubagentToAgent(subagentDir, subagentName, agent, agentHo
|
|
|
541
576
|
return { success: false, error: String(err) };
|
|
542
577
|
}
|
|
543
578
|
}
|
|
579
|
+
else if (agent === 'antigravity') {
|
|
580
|
+
// Antigravity: custom-agent markdown under ~/.gemini/config/agents/<name>/agent.md.
|
|
581
|
+
const agentDir = safeJoin(path.join(agentHome, '.gemini', 'config', 'agents'), subagentName);
|
|
582
|
+
if (!fs.existsSync(agentDir))
|
|
583
|
+
fs.mkdirSync(agentDir, { recursive: true });
|
|
584
|
+
try {
|
|
585
|
+
fs.writeFileSync(safeJoin(agentDir, 'agent.md'), transformSubagentForAntigravity(subagentDir));
|
|
586
|
+
return { success: true };
|
|
587
|
+
}
|
|
588
|
+
catch (err) {
|
|
589
|
+
return { success: false, error: String(err) };
|
|
590
|
+
}
|
|
591
|
+
}
|
|
544
592
|
else if (agent === 'openclaw') {
|
|
545
593
|
// OpenClaw: copy full directory
|
|
546
594
|
const targetDir = safeJoin(path.join(agentHome, '.openclaw'), subagentName);
|
|
@@ -571,8 +619,8 @@ export function installSubagentToAgent(subagentDir, subagentName, agent, agentHo
|
|
|
571
619
|
*/
|
|
572
620
|
export function removeSubagentFromAgent(subagentName, agent, agentHome) {
|
|
573
621
|
try {
|
|
574
|
-
if (agent === 'claude' || agent === 'grok') {
|
|
575
|
-
const agentsRoot = agent === 'grok' ? '.grok' : '.claude';
|
|
622
|
+
if (agent === 'claude' || agent === 'gemini' || agent === 'grok') {
|
|
623
|
+
const agentsRoot = agent === 'grok' ? '.grok' : agent === 'gemini' ? '.gemini' : '.claude';
|
|
576
624
|
const targetPath = safeJoin(path.join(agentHome, agentsRoot, 'agents'), `${subagentName}.md`);
|
|
577
625
|
if (fs.existsSync(targetPath)) {
|
|
578
626
|
fs.unlinkSync(targetPath);
|
|
@@ -602,6 +650,12 @@ export function removeSubagentFromAgent(subagentName, agent, agentHome) {
|
|
|
602
650
|
fs.unlinkSync(targetPath);
|
|
603
651
|
return { success: true };
|
|
604
652
|
}
|
|
653
|
+
else if (agent === 'antigravity') {
|
|
654
|
+
const targetDir = safeJoin(path.join(agentHome, '.gemini', 'config', 'agents'), subagentName);
|
|
655
|
+
if (fs.existsSync(targetDir))
|
|
656
|
+
fs.rmSync(targetDir, { recursive: true, force: true });
|
|
657
|
+
return { success: true };
|
|
658
|
+
}
|
|
605
659
|
else if (agent === 'openclaw') {
|
|
606
660
|
const targetDir = safeJoin(path.join(agentHome, '.openclaw'), subagentName);
|
|
607
661
|
if (fs.existsSync(targetDir)) {
|
|
@@ -653,15 +707,17 @@ export function subagentContentMatches(installedDir, sourceDir) {
|
|
|
653
707
|
// source of truth.
|
|
654
708
|
/**
|
|
655
709
|
* List subagents installed to a specific agent's home
|
|
656
|
-
* Claude: scans ~/.
|
|
710
|
+
* Claude/Gemini/Grok: scans ~/.{agent}/agents/{name}.md
|
|
657
711
|
* Kimi: scans ~/.kimi-code/agents/{name}.yaml (+ sibling .system.md)
|
|
712
|
+
* Kiro: scans ~/.kiro/agents/{name}.json
|
|
658
713
|
* OpenClaw: scans ~/.openclaw/{name}/AGENTS.md
|
|
659
714
|
*/
|
|
660
715
|
export function listSubagentsForAgent(agentId, home) {
|
|
661
716
|
const subagents = [];
|
|
662
|
-
if (agentId === 'claude' || agentId === 'grok') {
|
|
663
|
-
// Claude / Grok: flat .md files in agents/
|
|
664
|
-
const
|
|
717
|
+
if (agentId === 'claude' || agentId === 'gemini' || agentId === 'grok') {
|
|
718
|
+
// Claude / Gemini / Grok: flat .md files in agents/
|
|
719
|
+
const agentsRoot = agentId === 'grok' ? '.grok' : agentId === 'gemini' ? '.gemini' : '.claude';
|
|
720
|
+
const agentsDir = path.join(home, agentsRoot, 'agents');
|
|
665
721
|
if (!fs.existsSync(agentsDir))
|
|
666
722
|
return subagents;
|
|
667
723
|
for (const file of fs.readdirSync(agentsDir)) {
|
|
@@ -727,6 +783,20 @@ export function listSubagentsForAgent(agentId, home) {
|
|
|
727
783
|
subagents.push({ name, path: filePath, files: [file], frontmatter });
|
|
728
784
|
}
|
|
729
785
|
}
|
|
786
|
+
else if (agentId === 'antigravity') {
|
|
787
|
+
const agentsDir = path.join(home, '.gemini', 'config', 'agents');
|
|
788
|
+
if (!fs.existsSync(agentsDir))
|
|
789
|
+
return subagents;
|
|
790
|
+
for (const entry of fs.readdirSync(agentsDir, { withFileTypes: true })) {
|
|
791
|
+
if (!entry.isDirectory())
|
|
792
|
+
continue;
|
|
793
|
+
const filePath = path.join(agentsDir, entry.name, 'agent.md');
|
|
794
|
+
if (!fs.existsSync(filePath) || !fs.statSync(filePath).isFile())
|
|
795
|
+
continue;
|
|
796
|
+
const frontmatter = parseSubagentFrontmatter(filePath) ?? { name: entry.name, description: '' };
|
|
797
|
+
subagents.push({ name: entry.name, path: filePath, files: ['agent.md'], frontmatter });
|
|
798
|
+
}
|
|
799
|
+
}
|
|
730
800
|
else if (agentId === 'copilot') {
|
|
731
801
|
// Copilot: flat `<name>.agent.md` files under ~/.copilot/agents/
|
|
732
802
|
const agentsDir = path.join(home, '.copilot', 'agents');
|
|
@@ -837,8 +907,9 @@ export function diffVersionSubagents(agent, version) {
|
|
|
837
907
|
}
|
|
838
908
|
}
|
|
839
909
|
// Check what's installed
|
|
840
|
-
if (agent === 'claude' || agent === 'grok') {
|
|
841
|
-
const
|
|
910
|
+
if (agent === 'claude' || agent === 'gemini' || agent === 'grok') {
|
|
911
|
+
const agentsRoot = agent === 'grok' ? '.grok' : agent === 'gemini' ? '.gemini' : '.claude';
|
|
912
|
+
const agentsDir = path.join(versionHome, agentsRoot, 'agents');
|
|
842
913
|
if (fs.existsSync(agentsDir)) {
|
|
843
914
|
for (const file of fs.readdirSync(agentsDir)) {
|
|
844
915
|
if (!file.endsWith('.md'))
|
|
@@ -875,6 +946,19 @@ export function diffVersionSubagents(agent, version) {
|
|
|
875
946
|
}
|
|
876
947
|
}
|
|
877
948
|
}
|
|
949
|
+
else if (agent === 'antigravity') {
|
|
950
|
+
const agentsDir = path.join(versionHome, '.gemini', 'config', 'agents');
|
|
951
|
+
if (fs.existsSync(agentsDir)) {
|
|
952
|
+
for (const entry of fs.readdirSync(agentsDir, { withFileTypes: true })) {
|
|
953
|
+
if (!entry.isDirectory())
|
|
954
|
+
continue;
|
|
955
|
+
if (!fs.existsSync(path.join(agentsDir, entry.name, 'agent.md')))
|
|
956
|
+
continue;
|
|
957
|
+
if (!discovered.has(entry.name))
|
|
958
|
+
orphans.push(entry.name);
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
}
|
|
878
962
|
else if (agent === 'openclaw') {
|
|
879
963
|
const openclawDir = path.join(versionHome, '.openclaw');
|
|
880
964
|
if (fs.existsSync(openclawDir)) {
|
|
@@ -929,8 +1013,8 @@ export function removeSubagentFromVersion(agent, version, subagentName) {
|
|
|
929
1013
|
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
930
1014
|
const trashDir = path.join(getTrashSubagentsDir(), agent, version, subagentName);
|
|
931
1015
|
try {
|
|
932
|
-
if (agent === 'claude' || agent === 'grok') {
|
|
933
|
-
const agentsRoot = agent === 'grok' ? '.grok' : '.claude';
|
|
1016
|
+
if (agent === 'claude' || agent === 'gemini' || agent === 'grok') {
|
|
1017
|
+
const agentsRoot = agent === 'grok' ? '.grok' : agent === 'gemini' ? '.gemini' : '.claude';
|
|
934
1018
|
const targetPath = path.join(versionHome, agentsRoot, 'agents', `${subagentName}.md`);
|
|
935
1019
|
if (fs.existsSync(targetPath)) {
|
|
936
1020
|
fs.mkdirSync(trashDir, { recursive: true, mode: 0o700 });
|
|
@@ -958,6 +1042,13 @@ export function removeSubagentFromVersion(agent, version, subagentName) {
|
|
|
958
1042
|
fs.renameSync(targetPath, path.join(trashDir, `${subagentName}.md.${stamp}`));
|
|
959
1043
|
}
|
|
960
1044
|
}
|
|
1045
|
+
else if (agent === 'antigravity') {
|
|
1046
|
+
const targetDir = path.join(versionHome, '.gemini', 'config', 'agents', subagentName);
|
|
1047
|
+
if (fs.existsSync(targetDir)) {
|
|
1048
|
+
fs.mkdirSync(trashDir, { recursive: true, mode: 0o700 });
|
|
1049
|
+
fs.renameSync(targetDir, path.join(trashDir, stamp));
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
961
1052
|
else if (agent === 'copilot') {
|
|
962
1053
|
const targetPath = path.join(versionHome, '.copilot', 'agents', `${subagentName}.agent.md`);
|
|
963
1054
|
if (fs.existsSync(targetPath)) {
|
package/dist/lib/versions.js
CHANGED
|
@@ -2462,9 +2462,14 @@ export function syncResourcesToVersion(agent, version, selection, options = {})
|
|
|
2462
2462
|
// reads only user + system layers (project excluded for the same defense
|
|
2463
2463
|
// as commands/skills/hooks).
|
|
2464
2464
|
const subagentsWriter = getWriter('subagents', agent);
|
|
2465
|
-
const
|
|
2465
|
+
const subagentsGate = supports(agent, 'subagents', version);
|
|
2466
|
+
const subagentsRequested = selection
|
|
2466
2467
|
? resolveSelection(selection.subagents, available.subagents)
|
|
2467
2468
|
: (subagentsWriter ? available.subagents : []);
|
|
2469
|
+
const subagentsToSync = subagentsGate.ok ? subagentsRequested : [];
|
|
2470
|
+
if (subagentsRequested.length > 0 && !subagentsGate.ok) {
|
|
2471
|
+
console.warn(explainSkip(agent, 'subagents', subagentsGate, version) + ' -- skipped');
|
|
2472
|
+
}
|
|
2468
2473
|
if (subagentsToSync.length > 0 && subagentsWriter) {
|
|
2469
2474
|
const r = subagentsWriter.write({ version, versionHome, selection: subagentsToSync, cwd });
|
|
2470
2475
|
result.subagents.push(...r.synced);
|
|
@@ -2499,9 +2504,14 @@ export function syncResourcesToVersion(agent, version, selection, options = {})
|
|
|
2499
2504
|
}
|
|
2500
2505
|
// Sync workflows — dispatch through WRITERS.workflows.
|
|
2501
2506
|
const workflowsWriter = getWriter('workflows', agent);
|
|
2502
|
-
const
|
|
2507
|
+
const workflowsGate = supports(agent, 'workflows', version);
|
|
2508
|
+
const workflowsRequested = selection
|
|
2503
2509
|
? resolveSelection(selection.workflows, available.workflows)
|
|
2504
2510
|
: (workflowsWriter ? available.workflows : []);
|
|
2511
|
+
const workflowsToSync = workflowsGate.ok ? workflowsRequested : [];
|
|
2512
|
+
if (workflowsRequested.length > 0 && !workflowsGate.ok) {
|
|
2513
|
+
console.warn(explainSkip(agent, 'workflows', workflowsGate, version) + ' -- skipped');
|
|
2514
|
+
}
|
|
2505
2515
|
if (workflowsToSync.length > 0 && workflowsWriter) {
|
|
2506
2516
|
const r = workflowsWriter.write({ version, versionHome, selection: workflowsToSync, cwd });
|
|
2507
2517
|
result.workflows.push(...r.synced);
|
package/dist/lib/workflows.d.ts
CHANGED
|
@@ -263,6 +263,8 @@ export declare function resolveAllowedSubagents(available: string[], allowedAgen
|
|
|
263
263
|
export declare function pruneStaleWorkflowSubagents(sharedAgentsDir: string, workflowSubagentFiles: string[], allowedStems: string[]): string[];
|
|
264
264
|
/** Count subagent .md files in a workflow's subagents/ directory. */
|
|
265
265
|
export declare function countWorkflowSubagents(workflowDir: string): number;
|
|
266
|
+
/** Convert a canonical agents-cli workflow bundle into a Kimi flow skill. */
|
|
267
|
+
export declare function transformWorkflowForKimi(workflowPath: string, name: string): string;
|
|
266
268
|
/**
|
|
267
269
|
* Resolve an `agents run <workflow>` reference.
|
|
268
270
|
*
|
|
@@ -291,10 +293,10 @@ export declare function removeWorkflow(name: string): {
|
|
|
291
293
|
success: boolean;
|
|
292
294
|
error?: string;
|
|
293
295
|
};
|
|
294
|
-
/** List workflow names synced into a specific agent version home
|
|
295
|
-
export declare function listWorkflowsForAgent(
|
|
296
|
+
/** List workflow names synced into a specific agent version home. */
|
|
297
|
+
export declare function listWorkflowsForAgent(agent: AgentId, versionHome: string): string[];
|
|
296
298
|
/** Copy a workflow directory into a version home at {versionHome}/workflows/<name>/. */
|
|
297
|
-
export declare function syncWorkflowToVersion(workflowPath: string, name: string,
|
|
299
|
+
export declare function syncWorkflowToVersion(workflowPath: string, name: string, agent: AgentId, versionHome: string): {
|
|
298
300
|
success: boolean;
|
|
299
301
|
error?: string;
|
|
300
302
|
};
|