agentloom 0.1.1 → 0.1.3
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/README.md +9 -8
- package/dist/cli.js +5 -1
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +14 -0
- package/dist/commands/mcp.js +2 -9
- package/dist/commands/skills.js +6 -27
- package/dist/commands/sync.d.ts +1 -0
- package/dist/commands/sync.js +82 -11
- package/dist/core/argv.js +3 -7
- package/dist/core/copy.d.ts +1 -0
- package/dist/core/copy.js +19 -3
- package/dist/core/migration.d.ts +28 -0
- package/dist/core/migration.js +809 -0
- package/dist/core/provider-paths.d.ts +16 -0
- package/dist/core/provider-paths.js +154 -0
- package/dist/core/router.d.ts +1 -1
- package/dist/core/router.js +1 -0
- package/dist/core/skills.js +2 -16
- package/dist/core/version-notifier.d.ts +1 -0
- package/dist/core/version-notifier.js +22 -4
- package/dist/sync/index.js +27 -104
- package/dist/types.d.ts +2 -1
- package/dist/types.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
# agentloom
|
|
2
2
|
|
|
3
|
-
`agentloom` is a unified CLI for managing agent definitions and MCP configuration across multiple AI coding tools.
|
|
3
|
+
`agentloom` is a unified CLI for managing agent definitions and MCP configuration across multiple AI coding tools — Cursor, Claude, Copilot, Codex, OpenCode, Gemini, and Pi.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
For monorepo-level documentation and architecture context, see the [root README](../../README.md).
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
## Getting started
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx agentloom init
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
That's all you need. Agentloom picks up your existing provider configs, migrates them into a unified `.agents/` directory, and syncs everything back out to all your tools. From here on, manage your agents, commands, skills, and MCP servers in one place and run `agentloom sync` whenever you make changes.
|
|
13
14
|
|
|
14
15
|
## Install
|
|
15
16
|
|
package/dist/cli.js
CHANGED
|
@@ -5,6 +5,7 @@ import { runAddCommand } from "./commands/add.js";
|
|
|
5
5
|
import { runCommandCommand } from "./commands/command.js";
|
|
6
6
|
import { runDeleteCommand } from "./commands/delete.js";
|
|
7
7
|
import { runFindCommand } from "./commands/find.js";
|
|
8
|
+
import { runInitCommand } from "./commands/init.js";
|
|
8
9
|
import { runMcpCommand } from "./commands/mcp.js";
|
|
9
10
|
import { runSkillCommand } from "./commands/skills.js";
|
|
10
11
|
import { runSyncCommand } from "./commands/sync.js";
|
|
@@ -54,7 +55,7 @@ export async function runCli(argv) {
|
|
|
54
55
|
await runRoutedCommand(route, parsed, cwd, command);
|
|
55
56
|
if (shouldBootstrapManageAgents) {
|
|
56
57
|
const bootstrapArgs = buildManageAgentsBootstrapArgs(parsed, cwd);
|
|
57
|
-
await
|
|
58
|
+
await runSkillCommand(parseArgs(bootstrapArgs), cwd);
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
function printHelp() {
|
|
@@ -81,6 +82,9 @@ async function runRoutedCommand(route, parsed, cwd, command) {
|
|
|
81
82
|
case "delete":
|
|
82
83
|
await runDeleteCommand(parsed, cwd);
|
|
83
84
|
return;
|
|
85
|
+
case "init":
|
|
86
|
+
await runInitCommand(parsed, cwd);
|
|
87
|
+
return;
|
|
84
88
|
default:
|
|
85
89
|
throw new Error(formatUnknownCommandError(command));
|
|
86
90
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { getInitHelpText } from "../core/copy.js";
|
|
2
|
+
import { runScopedSyncCommand } from "./sync.js";
|
|
3
|
+
export async function runInitCommand(argv, cwd) {
|
|
4
|
+
if (argv.help) {
|
|
5
|
+
console.log(getInitHelpText());
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
await runScopedSyncCommand({
|
|
9
|
+
argv,
|
|
10
|
+
cwd,
|
|
11
|
+
target: "all",
|
|
12
|
+
skipSync: Boolean(argv["no-sync"]),
|
|
13
|
+
});
|
|
14
|
+
}
|
package/dist/commands/mcp.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ALL_PROVIDERS } from "../types.js";
|
|
1
2
|
import { getStringArrayFlag, parseProvidersFlag } from "../core/argv.js";
|
|
2
3
|
import { formatUsageError, getMcpAddHelpText, getMcpDeleteHelpText, getMcpHelpText, getMcpListHelpText, getMcpServerHelpText, } from "../core/copy.js";
|
|
3
4
|
import { readCanonicalMcp, writeCanonicalMcp } from "../core/mcp.js";
|
|
@@ -244,15 +245,7 @@ function runMcpAdd(paths, argv, name) {
|
|
|
244
245
|
}
|
|
245
246
|
else {
|
|
246
247
|
const providerMap = {};
|
|
247
|
-
const
|
|
248
|
-
"cursor",
|
|
249
|
-
"claude",
|
|
250
|
-
"codex",
|
|
251
|
-
"opencode",
|
|
252
|
-
"gemini",
|
|
253
|
-
"copilot",
|
|
254
|
-
];
|
|
255
|
-
for (const provider of allProviders) {
|
|
248
|
+
for (const provider of ALL_PROVIDERS) {
|
|
256
249
|
providerMap[provider] = providers.includes(provider)
|
|
257
250
|
? { ...baseConfig }
|
|
258
251
|
: false;
|
package/dist/commands/skills.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { parseProvidersFlag } from "../core/argv.js";
|
|
3
2
|
import { formatUsageError } from "../core/copy.js";
|
|
4
|
-
import {
|
|
5
|
-
import { formatSyncSummary, resolveProvidersForSync, syncFromCanonical, } from "../sync/index.js";
|
|
3
|
+
import { parseSkillsDir } from "../core/skills.js";
|
|
6
4
|
import { runScopedAddCommand } from "./add.js";
|
|
7
5
|
import { runScopedDeleteCommand } from "./delete.js";
|
|
8
|
-
import {
|
|
6
|
+
import { resolvePathsForCommand } from "./entity-utils.js";
|
|
9
7
|
import { runScopedFindCommand } from "./find.js";
|
|
8
|
+
import { runScopedSyncCommand } from "./sync.js";
|
|
10
9
|
import { runScopedUpdateCommand } from "./update.js";
|
|
11
10
|
export async function runSkillCommand(argv, cwd) {
|
|
12
11
|
const action = argv._[1];
|
|
@@ -79,29 +78,9 @@ export async function runSkillCommand(argv, cwd) {
|
|
|
79
78
|
});
|
|
80
79
|
return;
|
|
81
80
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const providers = await resolveProvidersForSync({
|
|
86
|
-
paths,
|
|
87
|
-
explicitProviders,
|
|
88
|
-
nonInteractive,
|
|
89
|
-
});
|
|
90
|
-
applySkillProviderSideEffects({
|
|
91
|
-
paths,
|
|
92
|
-
providers,
|
|
93
|
-
dryRun: Boolean(argv["dry-run"]),
|
|
94
|
-
warn(message) {
|
|
95
|
-
console.warn(`Warning: ${message}`);
|
|
96
|
-
},
|
|
97
|
-
});
|
|
98
|
-
const summary = await syncFromCanonical({
|
|
99
|
-
paths,
|
|
100
|
-
providers,
|
|
101
|
-
yes: Boolean(argv.yes),
|
|
102
|
-
nonInteractive,
|
|
103
|
-
dryRun: Boolean(argv["dry-run"]),
|
|
81
|
+
await runScopedSyncCommand({
|
|
82
|
+
argv,
|
|
83
|
+
cwd,
|
|
104
84
|
target: "skill",
|
|
105
85
|
});
|
|
106
|
-
console.log(formatSyncSummary(summary, paths.agentsRoot));
|
|
107
86
|
}
|
package/dist/commands/sync.d.ts
CHANGED
package/dist/commands/sync.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
1
4
|
import { parseProvidersFlag } from "../core/argv.js";
|
|
2
5
|
import { getSyncHelpText } from "../core/copy.js";
|
|
6
|
+
import { formatMigrationSummary, initializeCanonicalLayout, migrateProviderStateToCanonical, MigrationConflictError, } from "../core/migration.js";
|
|
3
7
|
import { getNonInteractiveMode, resolvePathsForCommand, } from "./entity-utils.js";
|
|
4
|
-
import { formatSyncSummary, syncFromCanonical } from "../sync/index.js";
|
|
8
|
+
import { formatSyncSummary, resolveProvidersForSync, syncFromCanonical, } from "../sync/index.js";
|
|
5
9
|
export async function runSyncCommand(argv, cwd) {
|
|
6
10
|
if (argv.help) {
|
|
7
11
|
console.log(getSyncHelpText());
|
|
@@ -14,14 +18,81 @@ export async function runSyncCommand(argv, cwd) {
|
|
|
14
18
|
});
|
|
15
19
|
}
|
|
16
20
|
export async function runScopedSyncCommand(options) {
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
const nonInteractive = getNonInteractiveMode(options.argv);
|
|
22
|
+
let cleanupDryRunPaths;
|
|
23
|
+
try {
|
|
24
|
+
const paths = await resolvePathsForCommand(options.argv, options.cwd);
|
|
25
|
+
const explicitProviders = parseProvidersFlag(options.argv.providers);
|
|
26
|
+
const providers = await resolveProvidersForSync({
|
|
27
|
+
paths,
|
|
28
|
+
explicitProviders,
|
|
29
|
+
nonInteractive,
|
|
30
|
+
});
|
|
31
|
+
const dryRun = Boolean(options.argv["dry-run"]);
|
|
32
|
+
const effectivePaths = dryRun
|
|
33
|
+
? createDryRunCanonicalPaths(paths)
|
|
34
|
+
: { paths, cleanup: undefined };
|
|
35
|
+
cleanupDryRunPaths = effectivePaths.cleanup;
|
|
36
|
+
initializeCanonicalLayout(effectivePaths.paths, providers);
|
|
37
|
+
const migrationSummary = await migrateProviderStateToCanonical({
|
|
38
|
+
paths: effectivePaths.paths,
|
|
39
|
+
providers,
|
|
40
|
+
target: options.target,
|
|
41
|
+
yes: Boolean(options.argv.yes),
|
|
42
|
+
nonInteractive,
|
|
43
|
+
dryRun,
|
|
44
|
+
materializeCanonical: dryRun,
|
|
45
|
+
});
|
|
46
|
+
console.log(formatMigrationSummary(migrationSummary));
|
|
47
|
+
if (options.skipSync) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const syncSummary = await syncFromCanonical({
|
|
51
|
+
paths: effectivePaths.paths,
|
|
52
|
+
providers,
|
|
53
|
+
yes: Boolean(options.argv.yes),
|
|
54
|
+
nonInteractive,
|
|
55
|
+
dryRun,
|
|
56
|
+
target: options.target,
|
|
57
|
+
});
|
|
58
|
+
console.log("");
|
|
59
|
+
console.log(formatSyncSummary(syncSummary, paths.agentsRoot));
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
if (error instanceof MigrationConflictError) {
|
|
63
|
+
console.error(error.message);
|
|
64
|
+
process.exit(2);
|
|
65
|
+
}
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
cleanupDryRunPaths?.();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function createDryRunCanonicalPaths(paths) {
|
|
73
|
+
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "agentloom-dry-run-"));
|
|
74
|
+
const tempAgentsRoot = path.join(tempRoot, ".agents");
|
|
75
|
+
if (fs.existsSync(paths.agentsRoot) &&
|
|
76
|
+
fs.statSync(paths.agentsRoot).isDirectory()) {
|
|
77
|
+
fs.cpSync(paths.agentsRoot, tempAgentsRoot, {
|
|
78
|
+
recursive: true,
|
|
79
|
+
force: true,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
paths: {
|
|
84
|
+
...paths,
|
|
85
|
+
agentsRoot: tempAgentsRoot,
|
|
86
|
+
agentsDir: path.join(tempAgentsRoot, "agents"),
|
|
87
|
+
commandsDir: path.join(tempAgentsRoot, "commands"),
|
|
88
|
+
skillsDir: path.join(tempAgentsRoot, "skills"),
|
|
89
|
+
mcpPath: path.join(tempAgentsRoot, "mcp.json"),
|
|
90
|
+
lockPath: path.join(tempAgentsRoot, "agents.lock.json"),
|
|
91
|
+
settingsPath: path.join(tempAgentsRoot, "settings.local.json"),
|
|
92
|
+
manifestPath: path.join(tempAgentsRoot, ".sync-manifest.json"),
|
|
93
|
+
},
|
|
94
|
+
cleanup() {
|
|
95
|
+
fs.rmSync(tempRoot, { recursive: true, force: true });
|
|
96
|
+
},
|
|
97
|
+
};
|
|
27
98
|
}
|
package/dist/core/argv.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import minimist from "minimist";
|
|
2
|
+
import { ALL_PROVIDERS } from "../types.js";
|
|
2
3
|
export function parseArgs(argv) {
|
|
3
4
|
const parsed = minimist(argv, {
|
|
4
5
|
boolean: ["global", "local", "yes", "no-sync", "dry-run", "json", "help"],
|
|
@@ -50,16 +51,11 @@ export function parseProvidersFlag(input) {
|
|
|
50
51
|
.map((item) => item.toLowerCase());
|
|
51
52
|
const validProviders = [];
|
|
52
53
|
for (const provider of parsed) {
|
|
53
|
-
if (provider
|
|
54
|
-
provider === "claude" ||
|
|
55
|
-
provider === "codex" ||
|
|
56
|
-
provider === "opencode" ||
|
|
57
|
-
provider === "gemini" ||
|
|
58
|
-
provider === "copilot") {
|
|
54
|
+
if (ALL_PROVIDERS.includes(provider)) {
|
|
59
55
|
validProviders.push(provider);
|
|
60
56
|
continue;
|
|
61
57
|
}
|
|
62
|
-
throw new Error(`Unknown provider: ${provider}. Expected one of:
|
|
58
|
+
throw new Error(`Unknown provider: ${provider}. Expected one of: ${ALL_PROVIDERS.join(", ")}.`);
|
|
63
59
|
}
|
|
64
60
|
return [...new Set(validProviders)];
|
|
65
61
|
}
|
package/dist/core/copy.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare function getFindHelpText(): string;
|
|
|
8
8
|
export declare function getAddHelpText(): string;
|
|
9
9
|
export declare function getUpdateHelpText(): string;
|
|
10
10
|
export declare function getSyncHelpText(): string;
|
|
11
|
+
export declare function getInitHelpText(): string;
|
|
11
12
|
export declare function getCommandHelpText(): string;
|
|
12
13
|
export declare function getCommandAddHelpText(): string;
|
|
13
14
|
export declare function getCommandListHelpText(): string;
|
package/dist/core/copy.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { ALL_PROVIDERS } from "../types.js";
|
|
2
|
+
const PROVIDERS_CSV = ALL_PROVIDERS.join(",");
|
|
2
3
|
export function getRootHelpText() {
|
|
3
4
|
return `agentloom - unified canonical agent package manager
|
|
4
5
|
|
|
@@ -8,9 +9,10 @@ Usage:
|
|
|
8
9
|
|
|
9
10
|
Aggregate commands:
|
|
10
11
|
add <source> Import agents/commands/mcp/skills from a source
|
|
12
|
+
init Bootstrap canonical files, migrate providers, then sync
|
|
11
13
|
find <query> Search remote + local entities
|
|
12
14
|
update [source] Refresh lockfile-managed imports
|
|
13
|
-
sync
|
|
15
|
+
sync Migrate provider configs then generate provider outputs
|
|
14
16
|
delete <source|name> Delete imported entities by source or name
|
|
15
17
|
|
|
16
18
|
Entity commands:
|
|
@@ -112,7 +114,7 @@ Example:
|
|
|
112
114
|
`;
|
|
113
115
|
}
|
|
114
116
|
export function getSyncHelpText() {
|
|
115
|
-
return `
|
|
117
|
+
return `Migrate provider configs into canonical .agents data, then generate provider-specific outputs.
|
|
116
118
|
|
|
117
119
|
Usage:
|
|
118
120
|
agentloom sync [options]
|
|
@@ -125,6 +127,20 @@ Options:
|
|
|
125
127
|
--dry-run Show file changes without writing
|
|
126
128
|
`;
|
|
127
129
|
}
|
|
130
|
+
export function getInitHelpText() {
|
|
131
|
+
return `Bootstrap canonical .agents files, migrate provider configs into canonical state, and sync providers.
|
|
132
|
+
|
|
133
|
+
Usage:
|
|
134
|
+
agentloom init [options]
|
|
135
|
+
|
|
136
|
+
Options:
|
|
137
|
+
--local | --global Choose canonical scope (interactive prompts when omitted)
|
|
138
|
+
--providers <csv> Limit providers (${PROVIDERS_CSV})
|
|
139
|
+
--yes Skip interactive conflict prompts and fail fast in non-interactive flows
|
|
140
|
+
--no-sync Skip sync after canonical bootstrap + migration
|
|
141
|
+
--dry-run Show planned migration/sync changes without writing
|
|
142
|
+
`;
|
|
143
|
+
}
|
|
128
144
|
export function getCommandHelpText() {
|
|
129
145
|
return `Manage canonical command entities.
|
|
130
146
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { EntityType, Provider, ScopePaths } from "../types.js";
|
|
2
|
+
export interface MigrationOptions {
|
|
3
|
+
paths: ScopePaths;
|
|
4
|
+
providers: Provider[];
|
|
5
|
+
target: EntityType | "all";
|
|
6
|
+
yes?: boolean;
|
|
7
|
+
nonInteractive?: boolean;
|
|
8
|
+
dryRun?: boolean;
|
|
9
|
+
materializeCanonical?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface MigrationEntitySummary {
|
|
12
|
+
detected: number;
|
|
13
|
+
imported: number;
|
|
14
|
+
conflicts: number;
|
|
15
|
+
skipped: number;
|
|
16
|
+
}
|
|
17
|
+
export interface MigrationSummary {
|
|
18
|
+
providers: Provider[];
|
|
19
|
+
target: EntityType | "all";
|
|
20
|
+
entities: Record<EntityType, MigrationEntitySummary>;
|
|
21
|
+
}
|
|
22
|
+
export declare class MigrationConflictError extends Error {
|
|
23
|
+
constructor(message: string);
|
|
24
|
+
}
|
|
25
|
+
export declare function createEmptyMigrationSummary(providers: Provider[], target: EntityType | "all"): MigrationSummary;
|
|
26
|
+
export declare function initializeCanonicalLayout(paths: ScopePaths, providers?: Provider[]): void;
|
|
27
|
+
export declare function migrateProviderStateToCanonical(options: MigrationOptions): Promise<MigrationSummary>;
|
|
28
|
+
export declare function formatMigrationSummary(summary: MigrationSummary): string;
|