@phnx-labs/agents-cli 1.20.51 → 1.20.53
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 +71 -0
- package/README.md +12 -0
- package/dist/bin/agents +0 -0
- package/dist/commands/browser.js +215 -7
- package/dist/commands/cloud.d.ts +3 -0
- package/dist/commands/cloud.js +8 -1
- package/dist/commands/events.d.ts +1 -1
- package/dist/commands/events.js +2 -3
- package/dist/commands/exec.js +82 -3
- package/dist/commands/factory.js +8 -0
- package/dist/commands/feed.d.ts +38 -0
- package/dist/commands/feed.js +274 -0
- package/dist/commands/logs.d.ts +5 -1
- package/dist/commands/logs.js +248 -3
- package/dist/commands/mcp.js +7 -0
- package/dist/commands/memory.d.ts +9 -0
- package/dist/commands/memory.js +164 -0
- package/dist/commands/message.d.ts +11 -6
- package/dist/commands/message.js +140 -5
- package/dist/commands/routines.js +12 -0
- package/dist/commands/secrets-migrate.d.ts +2 -1
- package/dist/commands/secrets-migrate.js +88 -13
- package/dist/commands/secrets.d.ts +22 -0
- package/dist/commands/secrets.js +176 -42
- package/dist/commands/sessions.js +10 -1
- package/dist/commands/teams.js +4 -0
- package/dist/commands/worktree.js +4 -2
- package/dist/index.js +21 -22
- package/dist/lib/agents.js +249 -17
- package/dist/lib/answer-router.d.ts +75 -0
- package/dist/lib/answer-router.js +149 -0
- package/dist/lib/ask-classifier.d.ts +71 -0
- package/dist/lib/ask-classifier.js +197 -0
- package/dist/lib/browser/login-detection.d.ts +94 -0
- package/dist/lib/browser/login-detection.js +274 -0
- package/dist/lib/browser/profiles.d.ts +17 -8
- package/dist/lib/browser/profiles.js +27 -8
- package/dist/lib/browser/secret-ref.d.ts +10 -0
- package/dist/lib/browser/secret-ref.js +14 -0
- package/dist/lib/browser/service.js +14 -12
- package/dist/lib/cloud/antigravity.d.ts +0 -2
- package/dist/lib/cloud/antigravity.js +2 -17
- package/dist/lib/cloud/codex.js +3 -18
- package/dist/lib/cloud/rush.d.ts +15 -0
- package/dist/lib/cloud/rush.js +10 -16
- package/dist/lib/cloud/stream.js +2 -0
- package/dist/lib/cloud/types.d.ts +21 -0
- package/dist/lib/cloud/types.js +81 -0
- package/dist/lib/crabbox/cli.d.ts +1 -1
- package/dist/lib/crabbox/cli.js +12 -2
- package/dist/lib/crabbox/lease.d.ts +19 -0
- package/dist/lib/crabbox/lease.js +22 -11
- package/dist/lib/crabbox/progress.d.ts +62 -0
- package/dist/lib/crabbox/progress.js +129 -0
- package/dist/lib/crabbox/runtimes.d.ts +38 -1
- package/dist/lib/crabbox/runtimes.js +98 -5
- package/dist/lib/daemon.d.ts +12 -9
- package/dist/lib/daemon.js +32 -17
- package/dist/lib/events.d.ts +31 -5
- package/dist/lib/events.js +291 -101
- package/dist/lib/exec.js +20 -1
- package/dist/lib/feed-outcome.d.ts +101 -0
- package/dist/lib/feed-outcome.js +244 -0
- package/dist/lib/feed-policy.d.ts +30 -0
- package/dist/lib/feed-policy.js +133 -0
- package/dist/lib/feed.d.ts +180 -0
- package/dist/lib/feed.js +627 -0
- package/dist/lib/git.d.ts +17 -1
- package/dist/lib/git.js +20 -1
- package/dist/lib/hooks.js +529 -14
- package/dist/lib/hosts/passthrough.d.ts +3 -3
- package/dist/lib/hosts/passthrough.js +3 -3
- package/dist/lib/mailbox-gc.d.ts +22 -0
- package/dist/lib/mailbox-gc.js +161 -0
- package/dist/lib/mailbox.d.ts +26 -2
- package/dist/lib/mailbox.js +80 -5
- package/dist/lib/mcp.js +82 -0
- package/dist/lib/memory.d.ts +55 -0
- package/dist/lib/memory.js +274 -0
- package/dist/lib/notify.d.ts +16 -0
- package/dist/lib/notify.js +61 -0
- package/dist/lib/operator.d.ts +26 -0
- package/dist/lib/operator.js +107 -0
- package/dist/lib/plugins.d.ts +35 -0
- package/dist/lib/plugins.js +217 -0
- package/dist/lib/remote-agents-json.d.ts +14 -0
- package/dist/lib/remote-agents-json.js +94 -0
- package/dist/lib/resources/mcp.js +44 -0
- package/dist/lib/resources/memory.d.ts +15 -0
- package/dist/lib/resources/memory.js +46 -0
- package/dist/lib/resources/types.d.ts +2 -2
- package/dist/lib/rotate.js +2 -0
- package/dist/lib/runner.d.ts +43 -0
- package/dist/lib/runner.js +323 -74
- package/dist/lib/sandbox.js +6 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/secrets/agent.d.ts +21 -0
- package/dist/lib/secrets/agent.js +63 -1
- package/dist/lib/secrets/bundles.d.ts +33 -1
- package/dist/lib/secrets/bundles.js +76 -21
- package/dist/lib/secrets/icloud-import.d.ts +79 -0
- package/dist/lib/secrets/icloud-import.js +203 -0
- package/dist/lib/secrets/index.d.ts +142 -2
- package/dist/lib/secrets/index.js +695 -30
- package/dist/lib/secrets/remote.js +1 -1
- package/dist/lib/secrets/sync.js +1 -1
- package/dist/lib/session/active.d.ts +18 -0
- package/dist/lib/session/active.js +47 -17
- package/dist/lib/session/db.d.ts +9 -1
- package/dist/lib/session/db.js +18 -3
- package/dist/lib/session/discover.d.ts +13 -0
- package/dist/lib/session/discover.js +32 -2
- package/dist/lib/session/parse.d.ts +8 -0
- package/dist/lib/session/parse.js +42 -21
- package/dist/lib/session/remote-active.js +8 -89
- package/dist/lib/session/state.d.ts +11 -0
- package/dist/lib/session/state.js +50 -1
- package/dist/lib/session/tail.d.ts +23 -4
- package/dist/lib/session/tail.js +34 -16
- package/dist/lib/session/throughput.d.ts +30 -0
- package/dist/lib/session/throughput.js +86 -0
- package/dist/lib/shim-heal.d.ts +12 -3
- package/dist/lib/shim-heal.js +12 -6
- package/dist/lib/staleness/detectors/subagents.js +57 -3
- package/dist/lib/staleness/writers/hooks.js +7 -3
- package/dist/lib/staleness/writers/subagents.js +37 -6
- package/dist/lib/startup/command-registry.d.ts +2 -0
- package/dist/lib/startup/command-registry.js +4 -0
- package/dist/lib/state.d.ts +2 -0
- package/dist/lib/state.js +25 -8
- package/dist/lib/subagents.d.ts +52 -0
- package/dist/lib/subagents.js +315 -12
- package/dist/lib/teams/agents.js +6 -3
- package/dist/lib/teams/worktree.d.ts +8 -0
- package/dist/lib/teams/worktree.js +8 -0
- package/dist/lib/types.d.ts +20 -2
- package/dist/lib/versions.js +38 -48
- package/dist/lib/whats-new.d.ts +5 -3
- package/dist/lib/whats-new.js +25 -5
- package/package.json +4 -3
- package/scripts/postinstall.js +61 -1
package/dist/lib/state.js
CHANGED
|
@@ -89,6 +89,7 @@ const TEAMS_AGENTS_DIR = path.join(HISTORY_DIR, 'teams', 'agents');
|
|
|
89
89
|
const BACKUPS_DIR = path.join(HISTORY_DIR, 'backups');
|
|
90
90
|
const TRASH_DIR = path.join(HISTORY_DIR, 'trash');
|
|
91
91
|
const MAILBOX_DIR = path.join(HISTORY_DIR, 'mailbox');
|
|
92
|
+
const FEED_DIR = path.join(HISTORY_DIR, 'feed');
|
|
92
93
|
// Cache bucket (regenerable).
|
|
93
94
|
const SHIMS_DIR = path.join(CACHE_DIR, 'shims');
|
|
94
95
|
const HOOK_SHIMS_DIR = path.join(SHIMS_DIR, 'hooks');
|
|
@@ -313,6 +314,8 @@ export function getProjectRoutinesDir(cwd = process.cwd()) {
|
|
|
313
314
|
export function getRunsDir() { return RUNS_DIR; }
|
|
314
315
|
/** Root for per-agent mailboxes (~/.agents/.history/mailbox/). */
|
|
315
316
|
export function getMailboxRootDir() { return MAILBOX_DIR; }
|
|
317
|
+
/** Root for open-block feed records (~/.agents/.history/feed/). */
|
|
318
|
+
export function getFeedDir() { return FEED_DIR; }
|
|
316
319
|
/** Path to installed agent CLI binaries (~/.agents/.history/versions/). */
|
|
317
320
|
export function getVersionsDir() { return VERSIONS_DIR; }
|
|
318
321
|
/** Path to version-switching shim scripts (~/.agents/.cache/shims/). */
|
|
@@ -569,25 +572,35 @@ function writeIfChanged(filePath, content) {
|
|
|
569
572
|
/**
|
|
570
573
|
* Partition the in-memory Meta across three files by sync-domain:
|
|
571
574
|
* - central `~/.agents/agents.yaml` — portable, everything else
|
|
572
|
-
* - device `~/.agents/devices/<machine>/agents.yaml` — `agents:` pins
|
|
575
|
+
* - device `~/.agents/devices/<machine>/agents.yaml` — `agents:` pins +
|
|
576
|
+
* `defaultBrowserProfile:` (both per-device)
|
|
573
577
|
* - history `~/.agents/.history/version-resources.json` — `versions:` (machine-local)
|
|
574
578
|
* All callers funnel through writeMeta → here, so nothing else changes. Empty
|
|
575
579
|
* `agents:` / `versions:` are not written (no empty committed files).
|
|
576
580
|
*/
|
|
577
581
|
function writeMetaUnlocked(meta) {
|
|
578
|
-
const { agents, versions, ...central } = meta;
|
|
582
|
+
const { agents, versions, defaultBrowserProfile, ...central } = meta;
|
|
579
583
|
// Write the machine-local files FIRST, then strip central — so a crash mid-write
|
|
580
584
|
// never removes pins/versions from central before they're persisted elsewhere.
|
|
581
585
|
const devicePath = getDeviceMetaPath();
|
|
582
|
-
|
|
586
|
+
const hasAgents = !!agents && Object.keys(agents).length > 0;
|
|
587
|
+
const hasDefaultBrowser = !!defaultBrowserProfile;
|
|
588
|
+
if (hasAgents || hasDefaultBrowser) {
|
|
589
|
+
// Device-local doc carries `agents:` pins and `defaultBrowserProfile:` — both
|
|
590
|
+
// are per-machine and must never land in central agents.yaml (which syncs).
|
|
591
|
+
const deviceDoc = {};
|
|
592
|
+
if (hasAgents)
|
|
593
|
+
deviceDoc.agents = agents;
|
|
594
|
+
if (hasDefaultBrowser)
|
|
595
|
+
deviceDoc.defaultBrowserProfile = defaultBrowserProfile;
|
|
583
596
|
fs.mkdirSync(path.dirname(devicePath), { recursive: true });
|
|
584
|
-
writeIfChanged(devicePath, META_HEADER + yaml.stringify(
|
|
597
|
+
writeIfChanged(devicePath, META_HEADER + yaml.stringify(deviceDoc));
|
|
585
598
|
}
|
|
586
599
|
else if (fs.existsSync(devicePath)) {
|
|
587
|
-
// Every
|
|
588
|
-
// write — otherwise the stale device file survives and
|
|
589
|
-
// re-applies the removed pin on the next read,
|
|
590
|
-
// (e.g. a
|
|
600
|
+
// Every device-local value was cleared. Persist the emptied doc instead of
|
|
601
|
+
// skipping the write — otherwise the stale device file survives and
|
|
602
|
+
// overlayMachineLocal re-applies the removed pin/default on the next read,
|
|
603
|
+
// leaving a dangling value (e.g. a default pointing at a deleted profile).
|
|
591
604
|
writeIfChanged(devicePath, META_HEADER + yaml.stringify({ agents: {} }));
|
|
592
605
|
}
|
|
593
606
|
if (versions && Object.keys(versions).length > 0) {
|
|
@@ -602,6 +615,8 @@ function writeMetaUnlocked(meta) {
|
|
|
602
615
|
* Overlay this machine's local state onto a central-portable Meta:
|
|
603
616
|
* - `agents:` from the device file (device wins; the union both preserves the
|
|
604
617
|
* one-level merge and self-heals a pre-migration central that still has pins)
|
|
618
|
+
* - `defaultBrowserProfile:` from the device file (device is the sole source;
|
|
619
|
+
* the field is stripped from central on write, so nothing to merge against)
|
|
605
620
|
* - `versions:` from the history JSON (wholesale replace; falls back to
|
|
606
621
|
* whatever central carried when the history file doesn't exist yet)
|
|
607
622
|
*/
|
|
@@ -612,6 +627,8 @@ function overlayMachineLocal(meta) {
|
|
|
612
627
|
const dm = yaml.parse(fs.readFileSync(devicePath, 'utf-8'));
|
|
613
628
|
if (dm?.agents)
|
|
614
629
|
meta.agents = { ...meta.agents, ...dm.agents };
|
|
630
|
+
if (dm?.defaultBrowserProfile)
|
|
631
|
+
meta.defaultBrowserProfile = dm.defaultBrowserProfile;
|
|
615
632
|
}
|
|
616
633
|
catch { /* ignore malformed device file */ }
|
|
617
634
|
}
|
package/dist/lib/subagents.d.ts
CHANGED
|
@@ -56,6 +56,57 @@ export declare function transformSubagentForClaude(subagentDir: string): string;
|
|
|
56
56
|
* See https://docs.factory.ai/cli/configuration/custom-droids.
|
|
57
57
|
*/
|
|
58
58
|
export declare function transformSubagentForDroid(subagentDir: string): string;
|
|
59
|
+
/**
|
|
60
|
+
* Transform a subagent into an OpenCode agent markdown file.
|
|
61
|
+
*
|
|
62
|
+
* OpenCode loads agents from ~/.config/opencode/agents/*.md (global) with
|
|
63
|
+
* YAML frontmatter (description required; mode: subagent for invocable
|
|
64
|
+
* subagents) and a prompt body. File stem becomes the agent name.
|
|
65
|
+
* https://opencode.ai/docs/agents/
|
|
66
|
+
*/
|
|
67
|
+
export declare function transformSubagentForOpenCode(subagentDir: string): string;
|
|
68
|
+
/** Managed parent agent file for Kimi (underscore prefix avoids clobbering a user subagent named agents-cli). */
|
|
69
|
+
export declare const KIMI_SUBAGENTS_PARENT_FILE = "_agents-cli.yaml";
|
|
70
|
+
export interface KimiSubagentFiles {
|
|
71
|
+
/** Agent YAML content (uses system_prompt_path, not inline system_prompt). */
|
|
72
|
+
yaml: string;
|
|
73
|
+
/** Markdown body written next to the YAML and referenced by system_prompt_path. */
|
|
74
|
+
systemPrompt: string;
|
|
75
|
+
/** Sibling prompt filename, e.g. `reviewer.system.md`. */
|
|
76
|
+
systemPromptFileName: string;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Transform a subagent into Kimi Code agent files.
|
|
80
|
+
*
|
|
81
|
+
* Kimi's schema (agentspec) only accepts `system_prompt_path` (path relative to
|
|
82
|
+
* the agent YAML) — there is no inline `system_prompt` key. We write:
|
|
83
|
+
* ~/.kimi-code/agents/<name>.yaml — agent YAML
|
|
84
|
+
* ~/.kimi-code/agents/<name>.system.md — system prompt body
|
|
85
|
+
* plus a managed parent `_agents-cli.yaml` that lists them under agent.subagents
|
|
86
|
+
* for `kimi --agent-file …/_agents-cli.yaml`.
|
|
87
|
+
* https://moonshotai.github.io/kimi-cli/en/customization/agents.html
|
|
88
|
+
*/
|
|
89
|
+
export declare function transformSubagentForKimi(subagentDir: string, fileBaseName: string): KimiSubagentFiles;
|
|
90
|
+
/**
|
|
91
|
+
* Build the managed parent agent YAML that declares all installed subagents
|
|
92
|
+
* so `kimi --agent-file ~/.kimi-code/agents/_agents-cli.yaml` can launch them.
|
|
93
|
+
*/
|
|
94
|
+
export declare function buildKimiSubagentsParentYaml(entries: Array<{
|
|
95
|
+
name: string;
|
|
96
|
+
description: string;
|
|
97
|
+
relativePath: string;
|
|
98
|
+
}>): string;
|
|
99
|
+
/** Write a Kimi subagent YAML + sibling system-prompt md into agentsDir. */
|
|
100
|
+
export declare function writeKimiSubagentFiles(agentsDir: string, subagentDir: string, name: string): void;
|
|
101
|
+
/**
|
|
102
|
+
* Transform a subagent into a Codex custom-agent TOML file.
|
|
103
|
+
*
|
|
104
|
+
* Codex loads standalone TOML under ~/.codex/agents/*.toml. Required fields:
|
|
105
|
+
* name, description, developer_instructions. Optional model maps from our
|
|
106
|
+
* frontmatter when present.
|
|
107
|
+
* https://developers.openai.com/codex/subagents (custom agents section)
|
|
108
|
+
*/
|
|
109
|
+
export declare function transformSubagentForCodex(subagentDir: string): string;
|
|
59
110
|
/**
|
|
60
111
|
* Sync a subagent to an OpenClaw workspace
|
|
61
112
|
* Copies full directory, renames AGENT.md to AGENTS.md
|
|
@@ -85,6 +136,7 @@ export declare function subagentContentMatches(installedDir: string, sourceDir:
|
|
|
85
136
|
/**
|
|
86
137
|
* List subagents installed to a specific agent's home
|
|
87
138
|
* Claude: scans ~/.claude/agents/{name}.md
|
|
139
|
+
* Kimi: scans ~/.kimi-code/agents/{name}.yaml (+ sibling .system.md)
|
|
88
140
|
* OpenClaw: scans ~/.openclaw/{name}/AGENTS.md
|
|
89
141
|
*/
|
|
90
142
|
export declare function listSubagentsForAgent(agentId: AgentId, home: string): InstalledSubagent[];
|
package/dist/lib/subagents.js
CHANGED
|
@@ -262,6 +262,153 @@ export function transformSubagentForDroid(subagentDir) {
|
|
|
262
262
|
}
|
|
263
263
|
return result;
|
|
264
264
|
}
|
|
265
|
+
/**
|
|
266
|
+
* Transform a subagent into an OpenCode agent markdown file.
|
|
267
|
+
*
|
|
268
|
+
* OpenCode loads agents from ~/.config/opencode/agents/*.md (global) with
|
|
269
|
+
* YAML frontmatter (description required; mode: subagent for invocable
|
|
270
|
+
* subagents) and a prompt body. File stem becomes the agent name.
|
|
271
|
+
* https://opencode.ai/docs/agents/
|
|
272
|
+
*/
|
|
273
|
+
export function transformSubagentForOpenCode(subagentDir) {
|
|
274
|
+
const agentMd = path.join(subagentDir, 'AGENT.md');
|
|
275
|
+
const frontmatter = parseSubagentFrontmatter(agentMd);
|
|
276
|
+
const body = getSubagentBody(agentMd);
|
|
277
|
+
if (!frontmatter) {
|
|
278
|
+
throw new Error(`Invalid AGENT.md in ${subagentDir}`);
|
|
279
|
+
}
|
|
280
|
+
const fm = {
|
|
281
|
+
description: frontmatter.description,
|
|
282
|
+
mode: 'subagent',
|
|
283
|
+
};
|
|
284
|
+
if (frontmatter.model)
|
|
285
|
+
fm.model = frontmatter.model;
|
|
286
|
+
let systemPrompt = body.trim();
|
|
287
|
+
const files = fs.readdirSync(subagentDir)
|
|
288
|
+
.filter(f => f.endsWith('.md') && f !== 'AGENT.md')
|
|
289
|
+
.sort();
|
|
290
|
+
for (const file of files) {
|
|
291
|
+
const content = fs.readFileSync(path.join(subagentDir, file), 'utf-8').trim();
|
|
292
|
+
const sectionName = file.replace('.md', '');
|
|
293
|
+
const title = sectionName.charAt(0).toUpperCase() + sectionName.slice(1).toLowerCase();
|
|
294
|
+
systemPrompt += `\n\n## ${title}\n\n${content}`;
|
|
295
|
+
}
|
|
296
|
+
return `---\n${yaml.stringify(fm).trim()}\n---\n\n${systemPrompt}\n`;
|
|
297
|
+
}
|
|
298
|
+
/** Managed parent agent file for Kimi (underscore prefix avoids clobbering a user subagent named agents-cli). */
|
|
299
|
+
export const KIMI_SUBAGENTS_PARENT_FILE = '_agents-cli.yaml';
|
|
300
|
+
/**
|
|
301
|
+
* Transform a subagent into Kimi Code agent files.
|
|
302
|
+
*
|
|
303
|
+
* Kimi's schema (agentspec) only accepts `system_prompt_path` (path relative to
|
|
304
|
+
* the agent YAML) — there is no inline `system_prompt` key. We write:
|
|
305
|
+
* ~/.kimi-code/agents/<name>.yaml — agent YAML
|
|
306
|
+
* ~/.kimi-code/agents/<name>.system.md — system prompt body
|
|
307
|
+
* plus a managed parent `_agents-cli.yaml` that lists them under agent.subagents
|
|
308
|
+
* for `kimi --agent-file …/_agents-cli.yaml`.
|
|
309
|
+
* https://moonshotai.github.io/kimi-cli/en/customization/agents.html
|
|
310
|
+
*/
|
|
311
|
+
export function transformSubagentForKimi(subagentDir, fileBaseName) {
|
|
312
|
+
const agentMd = path.join(subagentDir, 'AGENT.md');
|
|
313
|
+
const frontmatter = parseSubagentFrontmatter(agentMd);
|
|
314
|
+
const body = getSubagentBody(agentMd);
|
|
315
|
+
if (!frontmatter) {
|
|
316
|
+
throw new Error(`Invalid AGENT.md in ${subagentDir}`);
|
|
317
|
+
}
|
|
318
|
+
let systemPrompt = body.trim();
|
|
319
|
+
const files = fs.readdirSync(subagentDir)
|
|
320
|
+
.filter(f => f.endsWith('.md') && f !== 'AGENT.md')
|
|
321
|
+
.sort();
|
|
322
|
+
for (const file of files) {
|
|
323
|
+
const content = fs.readFileSync(path.join(subagentDir, file), 'utf-8').trim();
|
|
324
|
+
const sectionName = file.replace('.md', '');
|
|
325
|
+
const title = sectionName.charAt(0).toUpperCase() + sectionName.slice(1).toLowerCase();
|
|
326
|
+
systemPrompt += `\n\n## ${title}\n\n${content}`;
|
|
327
|
+
}
|
|
328
|
+
const systemPromptFileName = `${fileBaseName}.system.md`;
|
|
329
|
+
const doc = {
|
|
330
|
+
version: 1,
|
|
331
|
+
agent: {
|
|
332
|
+
extend: 'default',
|
|
333
|
+
name: frontmatter.name,
|
|
334
|
+
description: frontmatter.description,
|
|
335
|
+
system_prompt_path: `./${systemPromptFileName}`,
|
|
336
|
+
},
|
|
337
|
+
};
|
|
338
|
+
if (frontmatter.model) {
|
|
339
|
+
doc.agent.model = frontmatter.model;
|
|
340
|
+
}
|
|
341
|
+
return {
|
|
342
|
+
yaml: yaml.stringify(doc),
|
|
343
|
+
systemPrompt,
|
|
344
|
+
systemPromptFileName,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Build the managed parent agent YAML that declares all installed subagents
|
|
349
|
+
* so `kimi --agent-file ~/.kimi-code/agents/_agents-cli.yaml` can launch them.
|
|
350
|
+
*/
|
|
351
|
+
export function buildKimiSubagentsParentYaml(entries) {
|
|
352
|
+
const subagents = {};
|
|
353
|
+
for (const e of entries) {
|
|
354
|
+
subagents[e.name] = { path: e.relativePath, description: e.description };
|
|
355
|
+
}
|
|
356
|
+
return yaml.stringify({
|
|
357
|
+
version: 1,
|
|
358
|
+
agent: {
|
|
359
|
+
extend: 'default',
|
|
360
|
+
name: 'agents-cli',
|
|
361
|
+
description: 'Managed parent agent listing agents-cli synced subagents',
|
|
362
|
+
subagents,
|
|
363
|
+
},
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
/** Write a Kimi subagent YAML + sibling system-prompt md into agentsDir. */
|
|
367
|
+
export function writeKimiSubagentFiles(agentsDir, subagentDir, name) {
|
|
368
|
+
const { yaml: yml, systemPrompt, systemPromptFileName } = transformSubagentForKimi(subagentDir, name);
|
|
369
|
+
fs.mkdirSync(agentsDir, { recursive: true });
|
|
370
|
+
fs.writeFileSync(safeJoin(agentsDir, `${name}.yaml`), yml);
|
|
371
|
+
fs.writeFileSync(safeJoin(agentsDir, systemPromptFileName), systemPrompt);
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Transform a subagent into a Codex custom-agent TOML file.
|
|
375
|
+
*
|
|
376
|
+
* Codex loads standalone TOML under ~/.codex/agents/*.toml. Required fields:
|
|
377
|
+
* name, description, developer_instructions. Optional model maps from our
|
|
378
|
+
* frontmatter when present.
|
|
379
|
+
* https://developers.openai.com/codex/subagents (custom agents section)
|
|
380
|
+
*/
|
|
381
|
+
export function transformSubagentForCodex(subagentDir) {
|
|
382
|
+
const agentMd = path.join(subagentDir, 'AGENT.md');
|
|
383
|
+
const frontmatter = parseSubagentFrontmatter(agentMd);
|
|
384
|
+
const body = getSubagentBody(agentMd);
|
|
385
|
+
if (!frontmatter) {
|
|
386
|
+
throw new Error(`Invalid AGENT.md in ${subagentDir}`);
|
|
387
|
+
}
|
|
388
|
+
// Append other .md files into the developer_instructions body.
|
|
389
|
+
let instructions = body.trim();
|
|
390
|
+
const files = fs.readdirSync(subagentDir)
|
|
391
|
+
.filter(f => f.endsWith('.md') && f !== 'AGENT.md')
|
|
392
|
+
.sort();
|
|
393
|
+
for (const file of files) {
|
|
394
|
+
const content = fs.readFileSync(path.join(subagentDir, file), 'utf-8').trim();
|
|
395
|
+
const sectionName = file.replace('.md', '');
|
|
396
|
+
const title = sectionName.charAt(0).toUpperCase() + sectionName.slice(1).toLowerCase();
|
|
397
|
+
instructions += `\n\n## ${title}\n\n${content}`;
|
|
398
|
+
}
|
|
399
|
+
// Escape TOML multi-line string (""") content — only """ needs escaping.
|
|
400
|
+
const safeInstructions = instructions.replace(/"""/g, '\\"""');
|
|
401
|
+
const safeName = frontmatter.name.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
402
|
+
const safeDesc = frontmatter.description.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
403
|
+
let toml = `name = "${safeName}"\n`;
|
|
404
|
+
toml += `description = "${safeDesc}"\n`;
|
|
405
|
+
if (frontmatter.model) {
|
|
406
|
+
const safeModel = String(frontmatter.model).replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
407
|
+
toml += `model = "${safeModel}"\n`;
|
|
408
|
+
}
|
|
409
|
+
toml += `developer_instructions = """\n${safeInstructions}\n"""\n`;
|
|
410
|
+
return toml;
|
|
411
|
+
}
|
|
265
412
|
/**
|
|
266
413
|
* Sync a subagent to an OpenClaw workspace
|
|
267
414
|
* Copies full directory, renames AGENT.md to AGENTS.md
|
|
@@ -291,9 +438,10 @@ export function syncSubagentToOpenclaw(subagentDir, targetDir) {
|
|
|
291
438
|
* Install a subagent to a specific agent's home
|
|
292
439
|
*/
|
|
293
440
|
export function installSubagentToAgent(subagentDir, subagentName, agent, agentHome) {
|
|
294
|
-
if (agent === 'claude') {
|
|
295
|
-
// Claude: flatten to single .md
|
|
296
|
-
|
|
441
|
+
if (agent === 'claude' || agent === 'grok') {
|
|
442
|
+
// Claude / Grok: flatten to single .md under ~/.claude/agents or ~/.grok/agents
|
|
443
|
+
// Grok discovers user agent defs from ~/.grok/agents/*.md (same shape as Claude).
|
|
444
|
+
const agentsDir = path.join(agentHome, agent === 'grok' ? '.grok' : '.claude', 'agents');
|
|
297
445
|
if (!fs.existsSync(agentsDir)) {
|
|
298
446
|
fs.mkdirSync(agentsDir, { recursive: true });
|
|
299
447
|
}
|
|
@@ -306,6 +454,44 @@ export function installSubagentToAgent(subagentDir, subagentName, agent, agentHo
|
|
|
306
454
|
return { success: false, error: String(err) };
|
|
307
455
|
}
|
|
308
456
|
}
|
|
457
|
+
else if (agent === 'codex') {
|
|
458
|
+
// Codex: standalone TOML under ~/.codex/agents/<name>.toml
|
|
459
|
+
const agentsDir = path.join(agentHome, '.codex', 'agents');
|
|
460
|
+
if (!fs.existsSync(agentsDir)) {
|
|
461
|
+
fs.mkdirSync(agentsDir, { recursive: true });
|
|
462
|
+
}
|
|
463
|
+
try {
|
|
464
|
+
const toml = transformSubagentForCodex(subagentDir);
|
|
465
|
+
fs.writeFileSync(safeJoin(agentsDir, `${subagentName}.toml`), toml);
|
|
466
|
+
return { success: true };
|
|
467
|
+
}
|
|
468
|
+
catch (err) {
|
|
469
|
+
return { success: false, error: String(err) };
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
else if (agent === 'kimi') {
|
|
473
|
+
// Kimi: YAML + sibling system-prompt md under ~/.kimi-code/agents/
|
|
474
|
+
try {
|
|
475
|
+
writeKimiSubagentFiles(path.join(agentHome, '.kimi-code', 'agents'), subagentDir, subagentName);
|
|
476
|
+
return { success: true };
|
|
477
|
+
}
|
|
478
|
+
catch (err) {
|
|
479
|
+
return { success: false, error: String(err) };
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
else if (agent === 'opencode') {
|
|
483
|
+
// OpenCode: markdown agents under ~/.config/opencode/agents/
|
|
484
|
+
const agentsDir = path.join(agentHome, '.config', 'opencode', 'agents');
|
|
485
|
+
if (!fs.existsSync(agentsDir))
|
|
486
|
+
fs.mkdirSync(agentsDir, { recursive: true });
|
|
487
|
+
try {
|
|
488
|
+
fs.writeFileSync(safeJoin(agentsDir, `${subagentName}.md`), transformSubagentForOpenCode(subagentDir));
|
|
489
|
+
return { success: true };
|
|
490
|
+
}
|
|
491
|
+
catch (err) {
|
|
492
|
+
return { success: false, error: String(err) };
|
|
493
|
+
}
|
|
494
|
+
}
|
|
309
495
|
else if (agent === 'openclaw') {
|
|
310
496
|
// OpenClaw: copy full directory
|
|
311
497
|
const targetDir = safeJoin(path.join(agentHome, '.openclaw'), subagentName);
|
|
@@ -321,13 +507,37 @@ export function installSubagentToAgent(subagentDir, subagentName, agent, agentHo
|
|
|
321
507
|
*/
|
|
322
508
|
export function removeSubagentFromAgent(subagentName, agent, agentHome) {
|
|
323
509
|
try {
|
|
324
|
-
if (agent === 'claude') {
|
|
325
|
-
const
|
|
510
|
+
if (agent === 'claude' || agent === 'grok') {
|
|
511
|
+
const agentsRoot = agent === 'grok' ? '.grok' : '.claude';
|
|
512
|
+
const targetPath = safeJoin(path.join(agentHome, agentsRoot, 'agents'), `${subagentName}.md`);
|
|
513
|
+
if (fs.existsSync(targetPath)) {
|
|
514
|
+
fs.unlinkSync(targetPath);
|
|
515
|
+
}
|
|
516
|
+
return { success: true };
|
|
517
|
+
}
|
|
518
|
+
else if (agent === 'codex') {
|
|
519
|
+
const targetPath = safeJoin(path.join(agentHome, '.codex', 'agents'), `${subagentName}.toml`);
|
|
326
520
|
if (fs.existsSync(targetPath)) {
|
|
327
521
|
fs.unlinkSync(targetPath);
|
|
328
522
|
}
|
|
329
523
|
return { success: true };
|
|
330
524
|
}
|
|
525
|
+
else if (agent === 'kimi') {
|
|
526
|
+
const agentsDir = path.join(agentHome, '.kimi-code', 'agents');
|
|
527
|
+
const targetPath = safeJoin(agentsDir, `${subagentName}.yaml`);
|
|
528
|
+
const promptPath = safeJoin(agentsDir, `${subagentName}.system.md`);
|
|
529
|
+
if (fs.existsSync(targetPath))
|
|
530
|
+
fs.unlinkSync(targetPath);
|
|
531
|
+
if (fs.existsSync(promptPath))
|
|
532
|
+
fs.unlinkSync(promptPath);
|
|
533
|
+
return { success: true };
|
|
534
|
+
}
|
|
535
|
+
else if (agent === 'opencode') {
|
|
536
|
+
const targetPath = safeJoin(path.join(agentHome, '.config', 'opencode', 'agents'), `${subagentName}.md`);
|
|
537
|
+
if (fs.existsSync(targetPath))
|
|
538
|
+
fs.unlinkSync(targetPath);
|
|
539
|
+
return { success: true };
|
|
540
|
+
}
|
|
331
541
|
else if (agent === 'openclaw') {
|
|
332
542
|
const targetDir = safeJoin(path.join(agentHome, '.openclaw'), subagentName);
|
|
333
543
|
if (fs.existsSync(targetDir)) {
|
|
@@ -373,13 +583,14 @@ export function subagentContentMatches(installedDir, sourceDir) {
|
|
|
373
583
|
/**
|
|
374
584
|
* List subagents installed to a specific agent's home
|
|
375
585
|
* Claude: scans ~/.claude/agents/{name}.md
|
|
586
|
+
* Kimi: scans ~/.kimi-code/agents/{name}.yaml (+ sibling .system.md)
|
|
376
587
|
* OpenClaw: scans ~/.openclaw/{name}/AGENTS.md
|
|
377
588
|
*/
|
|
378
589
|
export function listSubagentsForAgent(agentId, home) {
|
|
379
590
|
const subagents = [];
|
|
380
|
-
if (agentId === 'claude') {
|
|
381
|
-
// Claude: flat .md files in agents/
|
|
382
|
-
const agentsDir = path.join(home, '.claude', 'agents');
|
|
591
|
+
if (agentId === 'claude' || agentId === 'grok') {
|
|
592
|
+
// Claude / Grok: flat .md files in agents/
|
|
593
|
+
const agentsDir = path.join(home, agentId === 'grok' ? '.grok' : '.claude', 'agents');
|
|
383
594
|
if (!fs.existsSync(agentsDir))
|
|
384
595
|
return subagents;
|
|
385
596
|
for (const file of fs.readdirSync(agentsDir)) {
|
|
@@ -400,6 +611,51 @@ export function listSubagentsForAgent(agentId, home) {
|
|
|
400
611
|
});
|
|
401
612
|
}
|
|
402
613
|
}
|
|
614
|
+
else if (agentId === 'kimi') {
|
|
615
|
+
// Kimi: flat YAML under .kimi-code/agents/ (exclude managed parent _*.yaml)
|
|
616
|
+
const agentsDir = path.join(home, '.kimi-code', 'agents');
|
|
617
|
+
if (!fs.existsSync(agentsDir))
|
|
618
|
+
return subagents;
|
|
619
|
+
for (const file of fs.readdirSync(agentsDir)) {
|
|
620
|
+
if (!file.endsWith('.yaml') || file.startsWith('_'))
|
|
621
|
+
continue;
|
|
622
|
+
const filePath = path.join(agentsDir, file);
|
|
623
|
+
if (!fs.statSync(filePath).isFile())
|
|
624
|
+
continue;
|
|
625
|
+
const name = file.replace(/\.yaml$/, '');
|
|
626
|
+
let description = '';
|
|
627
|
+
try {
|
|
628
|
+
const parsed = yaml.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
629
|
+
description = parsed?.agent?.description ?? '';
|
|
630
|
+
}
|
|
631
|
+
catch { /* leave description empty */ }
|
|
632
|
+
const files = [file];
|
|
633
|
+
const promptFile = `${name}.system.md`;
|
|
634
|
+
if (fs.existsSync(path.join(agentsDir, promptFile)))
|
|
635
|
+
files.push(promptFile);
|
|
636
|
+
subagents.push({
|
|
637
|
+
name,
|
|
638
|
+
path: filePath,
|
|
639
|
+
files,
|
|
640
|
+
frontmatter: { name, description },
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
else if (agentId === 'opencode') {
|
|
645
|
+
const agentsDir = path.join(home, '.config', 'opencode', 'agents');
|
|
646
|
+
if (!fs.existsSync(agentsDir))
|
|
647
|
+
return subagents;
|
|
648
|
+
for (const file of fs.readdirSync(agentsDir)) {
|
|
649
|
+
if (!file.endsWith('.md'))
|
|
650
|
+
continue;
|
|
651
|
+
const filePath = path.join(agentsDir, file);
|
|
652
|
+
if (!fs.statSync(filePath).isFile())
|
|
653
|
+
continue;
|
|
654
|
+
const name = file.replace(/\.md$/, '');
|
|
655
|
+
const frontmatter = parseSubagentFrontmatter(filePath) ?? { name, description: '' };
|
|
656
|
+
subagents.push({ name, path: filePath, files: [file], frontmatter });
|
|
657
|
+
}
|
|
658
|
+
}
|
|
403
659
|
else if (agentId === 'openclaw') {
|
|
404
660
|
// OpenClaw: directories with AGENTS.md
|
|
405
661
|
const openclawDir = path.join(home, '.openclaw');
|
|
@@ -462,8 +718,8 @@ export function diffVersionSubagents(agent, version) {
|
|
|
462
718
|
}
|
|
463
719
|
}
|
|
464
720
|
// Check what's installed
|
|
465
|
-
if (agent === 'claude') {
|
|
466
|
-
const agentsDir = path.join(versionHome, '.claude', 'agents');
|
|
721
|
+
if (agent === 'claude' || agent === 'grok') {
|
|
722
|
+
const agentsDir = path.join(versionHome, agent === 'grok' ? '.grok' : '.claude', 'agents');
|
|
467
723
|
if (fs.existsSync(agentsDir)) {
|
|
468
724
|
for (const file of fs.readdirSync(agentsDir)) {
|
|
469
725
|
if (!file.endsWith('.md'))
|
|
@@ -475,6 +731,31 @@ export function diffVersionSubagents(agent, version) {
|
|
|
475
731
|
}
|
|
476
732
|
}
|
|
477
733
|
}
|
|
734
|
+
else if (agent === 'kimi') {
|
|
735
|
+
const agentsDir = path.join(versionHome, '.kimi-code', 'agents');
|
|
736
|
+
if (fs.existsSync(agentsDir)) {
|
|
737
|
+
for (const file of fs.readdirSync(agentsDir)) {
|
|
738
|
+
if (!file.endsWith('.yaml') || file.startsWith('_'))
|
|
739
|
+
continue;
|
|
740
|
+
const name = path.basename(file, '.yaml');
|
|
741
|
+
if (!discovered.has(name)) {
|
|
742
|
+
orphans.push(name);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
else if (agent === 'opencode') {
|
|
748
|
+
const agentsDir = path.join(versionHome, '.config', 'opencode', 'agents');
|
|
749
|
+
if (fs.existsSync(agentsDir)) {
|
|
750
|
+
for (const file of fs.readdirSync(agentsDir)) {
|
|
751
|
+
if (!file.endsWith('.md'))
|
|
752
|
+
continue;
|
|
753
|
+
const name = path.basename(file, '.md');
|
|
754
|
+
if (!discovered.has(name))
|
|
755
|
+
orphans.push(name);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
}
|
|
478
759
|
else if (agent === 'openclaw') {
|
|
479
760
|
const openclawDir = path.join(versionHome, '.openclaw');
|
|
480
761
|
if (fs.existsSync(openclawDir)) {
|
|
@@ -516,8 +797,30 @@ export function removeSubagentFromVersion(agent, version, subagentName) {
|
|
|
516
797
|
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
517
798
|
const trashDir = path.join(getTrashSubagentsDir(), agent, version, subagentName);
|
|
518
799
|
try {
|
|
519
|
-
if (agent === 'claude') {
|
|
520
|
-
const
|
|
800
|
+
if (agent === 'claude' || agent === 'grok') {
|
|
801
|
+
const agentsRoot = agent === 'grok' ? '.grok' : '.claude';
|
|
802
|
+
const targetPath = path.join(versionHome, agentsRoot, 'agents', `${subagentName}.md`);
|
|
803
|
+
if (fs.existsSync(targetPath)) {
|
|
804
|
+
fs.mkdirSync(trashDir, { recursive: true, mode: 0o700 });
|
|
805
|
+
fs.renameSync(targetPath, path.join(trashDir, `${subagentName}.md.${stamp}`));
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
else if (agent === 'kimi') {
|
|
809
|
+
const agentsDir = path.join(versionHome, '.kimi-code', 'agents');
|
|
810
|
+
const yamlPath = path.join(agentsDir, `${subagentName}.yaml`);
|
|
811
|
+
const promptPath = path.join(agentsDir, `${subagentName}.system.md`);
|
|
812
|
+
if (fs.existsSync(yamlPath) || fs.existsSync(promptPath)) {
|
|
813
|
+
fs.mkdirSync(trashDir, { recursive: true, mode: 0o700 });
|
|
814
|
+
if (fs.existsSync(yamlPath)) {
|
|
815
|
+
fs.renameSync(yamlPath, path.join(trashDir, `${subagentName}.yaml.${stamp}`));
|
|
816
|
+
}
|
|
817
|
+
if (fs.existsSync(promptPath)) {
|
|
818
|
+
fs.renameSync(promptPath, path.join(trashDir, `${subagentName}.system.md.${stamp}`));
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
else if (agent === 'opencode') {
|
|
823
|
+
const targetPath = path.join(versionHome, '.config', 'opencode', 'agents', `${subagentName}.md`);
|
|
521
824
|
if (fs.existsSync(targetPath)) {
|
|
522
825
|
fs.mkdirSync(trashDir, { recursive: true, mode: 0o700 });
|
|
523
826
|
fs.renameSync(targetPath, path.join(trashDir, `${subagentName}.md.${stamp}`));
|
package/dist/lib/teams/agents.js
CHANGED
|
@@ -1693,6 +1693,7 @@ export class AgentManager {
|
|
|
1693
1693
|
];
|
|
1694
1694
|
if (model)
|
|
1695
1695
|
args.push('--model', model);
|
|
1696
|
+
args.push('--env', 'AGENTS_RUNTIME=teams');
|
|
1696
1697
|
return args;
|
|
1697
1698
|
}
|
|
1698
1699
|
buildCommand(agentType, prompt, mode, model, cwd = null, sessionId = null, effort = 'medium', version = null, profileName = null) {
|
|
@@ -1704,9 +1705,11 @@ export class AgentManager {
|
|
|
1704
1705
|
];
|
|
1705
1706
|
if (cwd)
|
|
1706
1707
|
cmd.push('--cwd', cwd);
|
|
1707
|
-
// Pin
|
|
1708
|
-
//
|
|
1709
|
-
|
|
1708
|
+
// Pin the session UUID to our agent_id so buildExecEnv keys
|
|
1709
|
+
// AGENTS_MAILBOX_DIR by the same id mailboxIdForActiveSession returns.
|
|
1710
|
+
// Claude also forwards --session-id to its CLI (unified identity);
|
|
1711
|
+
// other agents ignore the flag but still get the correct mailbox dir.
|
|
1712
|
+
if (sessionId) {
|
|
1710
1713
|
cmd.push('--session-id', sessionId);
|
|
1711
1714
|
}
|
|
1712
1715
|
// Claude: grant access to the teammate's working directory.
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if `dir` is inside a git repository (**async, worktree-correct**).
|
|
3
|
+
*
|
|
4
|
+
* Shells out to `git rev-parse --git-dir`, so it returns true from any
|
|
5
|
+
* subdirectory and for linked worktrees. Distinct from the synchronous,
|
|
6
|
+
* root-only `isGitRepo` in `lib/git.ts` (a `.git`-existence check): different
|
|
7
|
+
* semantics, so the two are intentionally **not** merged.
|
|
8
|
+
*/
|
|
1
9
|
export declare function isGitRepo(dir: string): Promise<boolean>;
|
|
2
10
|
export declare function getGitRoot(dir: string): Promise<string>;
|
|
3
11
|
/**
|
|
@@ -11,6 +11,14 @@ import * as path from 'path';
|
|
|
11
11
|
import { safeJoin } from '../paths.js';
|
|
12
12
|
const execFileAsync = promisify(execFile);
|
|
13
13
|
const WORKTREE_NAME_RE = /^[A-Za-z0-9_-]+$/;
|
|
14
|
+
/**
|
|
15
|
+
* Check if `dir` is inside a git repository (**async, worktree-correct**).
|
|
16
|
+
*
|
|
17
|
+
* Shells out to `git rev-parse --git-dir`, so it returns true from any
|
|
18
|
+
* subdirectory and for linked worktrees. Distinct from the synchronous,
|
|
19
|
+
* root-only `isGitRepo` in `lib/git.ts` (a `.git`-existence check): different
|
|
20
|
+
* semantics, so the two are intentionally **not** merged.
|
|
21
|
+
*/
|
|
14
22
|
export async function isGitRepo(dir) {
|
|
15
23
|
try {
|
|
16
24
|
await execFileAsync('git', ['rev-parse', '--git-dir'], { cwd: dir });
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { CloudProviderId } from './cloud/types.js';
|
|
9
9
|
/** Unique identifier for a supported AI coding agent. */
|
|
10
|
-
export type AgentId = 'claude' | 'codex' | 'gemini' | 'cursor' | 'opencode' | 'openclaw' | 'copilot' | 'amp' | 'kiro' | 'goose' | 'antigravity' | 'grok' | 'kimi' | 'droid';
|
|
10
|
+
export type AgentId = 'claude' | 'codex' | 'gemini' | 'cursor' | 'opencode' | 'openclaw' | 'copilot' | 'amp' | 'kiro' | 'goose' | 'antigravity' | 'grok' | 'kimi' | 'droid' | 'hermes' | 'forge';
|
|
11
11
|
/** How `agents run <agent>` chooses an installed version when none is pinned. */
|
|
12
12
|
export type RunStrategy = 'pinned' | 'available' | 'balanced';
|
|
13
13
|
/** Per-agent run strategy config. */
|
|
@@ -148,6 +148,12 @@ export interface AgentConfig {
|
|
|
148
148
|
subagents: Capability;
|
|
149
149
|
rules: RulesCapability;
|
|
150
150
|
workflows: Capability;
|
|
151
|
+
/**
|
|
152
|
+
* Portable knowledge-store memory (`agents memory` / ~/.agents/memory/).
|
|
153
|
+
* Distinct from `rules` (instructions). When true, sync fans facts into
|
|
154
|
+
* the agent version home (see memoryTargetDir).
|
|
155
|
+
*/
|
|
156
|
+
memory: Capability;
|
|
151
157
|
/**
|
|
152
158
|
* Permission modes this agent natively supports. Modes outside this set
|
|
153
159
|
* are gated by buildExecCommand: `auto` silently degrades to `edit`,
|
|
@@ -177,7 +183,7 @@ export type RulesCapability = false | {
|
|
|
177
183
|
file: string;
|
|
178
184
|
};
|
|
179
185
|
/** Names of every gateable capability on AgentConfig. */
|
|
180
|
-
export type CapabilityName = 'hooks' | 'mcp' | 'mcpHttp' | 'mcpHeaders' | 'allowlist' | 'skills' | 'commands' | 'plugins' | 'subagents' | 'rules' | 'workflows';
|
|
186
|
+
export type CapabilityName = 'hooks' | 'mcp' | 'mcpHttp' | 'mcpHeaders' | 'allowlist' | 'skills' | 'commands' | 'plugins' | 'subagents' | 'rules' | 'workflows' | 'memory';
|
|
181
187
|
/**
|
|
182
188
|
* Permission modes controlling agent autonomy.
|
|
183
189
|
* plan read-only investigation; no writes, no shell side-effects
|
|
@@ -516,6 +522,8 @@ export interface DiscoveredPlugin {
|
|
|
516
522
|
commands: string[];
|
|
517
523
|
/** Subagent .md files in the plugin's agents/ directory (names without extension). */
|
|
518
524
|
agentDefs: string[];
|
|
525
|
+
/** Memory fact basenames from the plugin's memory/ directory (without .md). */
|
|
526
|
+
memory: string[];
|
|
519
527
|
/** Executable files in the plugin's bin/ directory. */
|
|
520
528
|
bin: string[];
|
|
521
529
|
/** MCP server names parsed from .mcp.json. */
|
|
@@ -652,6 +660,16 @@ export interface Meta {
|
|
|
652
660
|
* lives separately in ~/.agents/.cache/browser/<profile>/.
|
|
653
661
|
*/
|
|
654
662
|
browser?: Record<string, BrowserProfileConfig>;
|
|
663
|
+
/**
|
|
664
|
+
* Device-local pointer: the browser profile `agents browser start` resolves to
|
|
665
|
+
* when no `--profile` is passed (and what an explicit `--profile default`
|
|
666
|
+
* re-points to). Stored per-machine in `~/.agents/devices/<machine>/agents.yaml`,
|
|
667
|
+
* NOT central — the target profile may carry machine-local logins, so the choice
|
|
668
|
+
* must not ride `agents repo push/pull` to other machines. Unset = auto-detect an
|
|
669
|
+
* installed Chromium-family browser (legacy behavior). Set via
|
|
670
|
+
* `agents browser profiles set-default <name>`.
|
|
671
|
+
*/
|
|
672
|
+
defaultBrowserProfile?: string;
|
|
655
673
|
/**
|
|
656
674
|
* Agent-host registry keyed by host name (`agents hosts`). Portable user
|
|
657
675
|
* config synced with `agents repo push/pull`. For `ssh-config` hosts this is
|