agentloom 0.1.0 → 0.1.1

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.
Files changed (51) hide show
  1. package/README.md +91 -72
  2. package/bin/cli.mjs +3 -2
  3. package/dist/cli.d.ts +1 -0
  4. package/dist/cli.js +149 -17
  5. package/dist/commands/add.d.ts +7 -0
  6. package/dist/commands/add.js +122 -31
  7. package/dist/commands/agent.d.ts +2 -0
  8. package/dist/commands/agent.js +85 -0
  9. package/dist/commands/command.d.ts +2 -0
  10. package/dist/commands/command.js +98 -0
  11. package/dist/commands/delete.d.ts +9 -0
  12. package/dist/commands/delete.js +444 -0
  13. package/dist/commands/entity-utils.d.ts +13 -0
  14. package/dist/commands/entity-utils.js +58 -0
  15. package/dist/commands/find.d.ts +21 -0
  16. package/dist/commands/find.js +944 -0
  17. package/dist/commands/mcp.js +133 -55
  18. package/dist/commands/skills.d.ts +2 -1
  19. package/dist/commands/skills.js +105 -9
  20. package/dist/commands/sync.d.ts +6 -0
  21. package/dist/commands/sync.js +12 -10
  22. package/dist/commands/update.d.ts +7 -0
  23. package/dist/commands/update.js +286 -21
  24. package/dist/core/argv.d.ts +2 -1
  25. package/dist/core/argv.js +42 -2
  26. package/dist/core/commands.d.ts +13 -0
  27. package/dist/core/commands.js +65 -0
  28. package/dist/core/copy.d.ts +6 -0
  29. package/dist/core/copy.js +126 -65
  30. package/dist/core/importer.d.ts +28 -1
  31. package/dist/core/importer.js +1104 -41
  32. package/dist/core/lockfile.js +86 -3
  33. package/dist/core/manage-agents-bootstrap.d.ts +10 -0
  34. package/dist/core/manage-agents-bootstrap.js +40 -0
  35. package/dist/core/manifest.js +7 -1
  36. package/dist/core/router.d.ts +16 -0
  37. package/dist/core/router.js +66 -0
  38. package/dist/core/scope.d.ts +1 -1
  39. package/dist/core/scope.js +12 -8
  40. package/dist/core/settings.d.ts +4 -3
  41. package/dist/core/settings.js +10 -8
  42. package/dist/core/skills.d.ts +23 -0
  43. package/dist/core/skills.js +328 -0
  44. package/dist/core/sources.d.ts +3 -1
  45. package/dist/core/sources.js +31 -1
  46. package/dist/core/telemetry.d.ts +26 -0
  47. package/dist/core/telemetry.js +124 -0
  48. package/dist/sync/index.d.ts +7 -1
  49. package/dist/sync/index.js +395 -131
  50. package/dist/types.d.ts +16 -1
  51. package/package.json +5 -4
@@ -1,8 +1,12 @@
1
1
  import { getStringArrayFlag, parseProvidersFlag } from "../core/argv.js";
2
- import { formatUsageError, getMcpAddHelpText, getMcpDeleteHelpText, getMcpHelpText, getMcpListHelpText, } from "../core/copy.js";
2
+ import { formatUsageError, getMcpAddHelpText, getMcpDeleteHelpText, getMcpHelpText, getMcpListHelpText, getMcpServerHelpText, } from "../core/copy.js";
3
3
  import { readCanonicalMcp, writeCanonicalMcp } from "../core/mcp.js";
4
- import { resolveScope } from "../core/scope.js";
5
- import { formatSyncSummary, syncFromCanonical } from "../sync/index.js";
4
+ import { runScopedAddCommand } from "./add.js";
5
+ import { runScopedDeleteCommand } from "./delete.js";
6
+ import { resolvePathsForCommand } from "./entity-utils.js";
7
+ import { runScopedFindCommand } from "./find.js";
8
+ import { runScopedSyncCommand } from "./sync.js";
9
+ import { runScopedUpdateCommand } from "./update.js";
6
10
  export async function runMcpCommand(argv, cwd) {
7
11
  const action = argv._[1];
8
12
  if (argv.help) {
@@ -18,79 +22,153 @@ export async function runMcpCommand(argv, cwd) {
18
22
  console.log(getMcpDeleteHelpText());
19
23
  return;
20
24
  }
25
+ if (action === "server") {
26
+ console.log(getMcpServerHelpText());
27
+ return;
28
+ }
21
29
  console.log(getMcpHelpText());
22
30
  return;
23
31
  }
24
- if (action !== "add" && action !== "list" && action !== "delete") {
32
+ if (!action) {
33
+ console.log(getMcpHelpText());
34
+ return;
35
+ }
36
+ if (action === "server") {
37
+ await runMcpServerCommand(argv, cwd);
38
+ return;
39
+ }
40
+ if (action !== "add" &&
41
+ action !== "list" &&
42
+ action !== "delete" &&
43
+ action !== "find" &&
44
+ action !== "update" &&
45
+ action !== "sync") {
25
46
  throw new Error(formatUsageError({
26
47
  issue: "Invalid mcp command.",
27
- usage: "agentloom mcp <add|list|delete> [options]",
28
- example: "agentloom mcp add browser --command npx --arg browser-tools-mcp",
48
+ usage: "agentloom mcp <add|list|delete|find|update|sync> [options]",
49
+ example: "agentloom mcp add farnoodma/agents --mcps browser",
29
50
  }));
30
51
  }
31
- const nonInteractive = !(process.stdin.isTTY && process.stdout.isTTY);
32
- const paths = await resolveScope({
52
+ if (action === "list") {
53
+ const paths = await resolvePathsForCommand(argv, cwd);
54
+ runMcpList(paths, Boolean(argv.json));
55
+ return;
56
+ }
57
+ if (action === "add") {
58
+ await runScopedAddCommand({
59
+ argv,
60
+ cwd,
61
+ entity: "mcp",
62
+ sourceIndex: 2,
63
+ });
64
+ return;
65
+ }
66
+ if (action === "delete") {
67
+ await runScopedDeleteCommand({
68
+ argv,
69
+ cwd,
70
+ entity: "mcp",
71
+ sourceIndex: 2,
72
+ });
73
+ return;
74
+ }
75
+ if (action === "find") {
76
+ await runScopedFindCommand(argv, "mcp");
77
+ return;
78
+ }
79
+ if (action === "update") {
80
+ await runScopedUpdateCommand({
81
+ argv,
82
+ cwd,
83
+ entity: "mcp",
84
+ sourceIndex: 2,
85
+ });
86
+ return;
87
+ }
88
+ await runScopedSyncCommand({
89
+ argv,
33
90
  cwd,
34
- global: Boolean(argv.global),
35
- local: Boolean(argv.local),
36
- interactive: !nonInteractive,
91
+ target: "mcp",
37
92
  });
93
+ }
94
+ async function runMcpServerCommand(argv, cwd) {
95
+ const action = argv._[2];
96
+ if (argv.help || !action) {
97
+ console.log(getMcpServerHelpText());
98
+ return;
99
+ }
100
+ if (action !== "add" && action !== "list" && action !== "delete") {
101
+ throw new Error(formatUsageError({
102
+ issue: "Invalid mcp server command.",
103
+ usage: "agentloom mcp server <add|list|delete> [options]",
104
+ example: "agentloom mcp server add browser --command npx --arg browser-tools-mcp",
105
+ }));
106
+ }
107
+ const nonInteractive = !(process.stdin.isTTY && process.stdout.isTTY);
108
+ const paths = await resolvePathsForCommand(argv, cwd);
38
109
  if (action === "list") {
110
+ if (argv.help) {
111
+ console.log(getMcpListHelpText());
112
+ return;
113
+ }
39
114
  runMcpList(paths, Boolean(argv.json));
40
115
  return;
41
116
  }
42
117
  if (action === "add") {
43
- const name = argv._[2];
118
+ if (argv.help) {
119
+ console.log(getMcpAddHelpText());
120
+ return;
121
+ }
122
+ const name = argv._[3];
44
123
  if (typeof name !== "string" || !name.trim()) {
45
124
  throw new Error(formatUsageError({
46
125
  issue: "Missing required MCP server name.",
47
- usage: "agentloom mcp add <name> (--url <url> | --command <cmd>) [options]",
48
- example: "agentloom mcp add browser --command npx --arg browser-tools-mcp",
126
+ usage: "agentloom mcp server add <name> (--url <url> | --command <cmd>) [options]",
127
+ example: "agentloom mcp server add browser --command npx --arg browser-tools-mcp",
49
128
  }));
50
129
  }
51
130
  runMcpAdd(paths, argv, name.trim());
52
131
  if (!argv["no-sync"]) {
53
- const summary = await syncFromCanonical({
54
- paths,
55
- providers: parseProvidersFlag(argv.providers),
56
- yes: Boolean(argv.yes),
57
- nonInteractive,
132
+ await runScopedSyncCommand({
133
+ argv,
134
+ cwd,
135
+ target: "mcp",
58
136
  });
59
- console.log("");
60
- console.log(formatSyncSummary(summary, paths.agentsRoot));
61
137
  }
62
138
  return;
63
139
  }
64
- if (action === "delete") {
65
- const name = argv._[2];
66
- if (typeof name !== "string" || !name.trim()) {
67
- throw new Error(formatUsageError({
68
- issue: "Missing required MCP server name.",
69
- usage: "agentloom mcp delete <name> [options]",
70
- example: "agentloom mcp delete browser",
71
- }));
72
- }
73
- const mcp = readCanonicalMcp(paths);
74
- if (!(name in mcp.mcpServers)) {
75
- throw new Error(formatUsageError({
76
- issue: `MCP server "${name}" was not found in canonical config.`,
77
- usage: "agentloom mcp list [--json] [--local|--global]",
78
- example: "agentloom mcp list --json",
79
- }));
80
- }
81
- delete mcp.mcpServers[name];
82
- writeCanonicalMcp(paths, mcp);
83
- console.log(`Deleted MCP server: ${name}`);
84
- if (!argv["no-sync"]) {
85
- const summary = await syncFromCanonical({
86
- paths,
87
- providers: parseProvidersFlag(argv.providers),
88
- yes: Boolean(argv.yes),
89
- nonInteractive,
90
- });
91
- console.log("");
92
- console.log(formatSyncSummary(summary, paths.agentsRoot));
93
- }
140
+ if (argv.help) {
141
+ console.log(getMcpDeleteHelpText());
142
+ return;
143
+ }
144
+ const name = argv._[3];
145
+ if (typeof name !== "string" || !name.trim()) {
146
+ throw new Error(formatUsageError({
147
+ issue: "Missing required MCP server name.",
148
+ usage: "agentloom mcp server delete <name> [options]",
149
+ example: "agentloom mcp server delete browser",
150
+ }));
151
+ }
152
+ const mcp = readCanonicalMcp(paths);
153
+ if (!(name in mcp.mcpServers)) {
154
+ throw new Error(formatUsageError({
155
+ issue: `MCP server "${name}" was not found in canonical config.`,
156
+ usage: "agentloom mcp server list [--json] [--local|--global]",
157
+ example: "agentloom mcp server list --json",
158
+ }));
159
+ }
160
+ delete mcp.mcpServers[name];
161
+ writeCanonicalMcp(paths, mcp);
162
+ console.log(`Deleted MCP server: ${name}`);
163
+ if (!argv["no-sync"]) {
164
+ await runScopedSyncCommand({
165
+ argv,
166
+ cwd,
167
+ target: "mcp",
168
+ });
169
+ }
170
+ if (!nonInteractive) {
171
+ return;
94
172
  }
95
173
  }
96
174
  function runMcpList(paths, asJson) {
@@ -132,8 +210,8 @@ function runMcpAdd(paths, argv, name) {
132
210
  if (!baseConfig.url && !baseConfig.command) {
133
211
  throw new Error(formatUsageError({
134
212
  issue: "Missing MCP transport. Use --url or --command.",
135
- usage: "agentloom mcp add <name> (--url <url> | --command <cmd>) [options]",
136
- example: "agentloom mcp add browser --command npx --arg browser-tools-mcp",
213
+ usage: "agentloom mcp server add <name> (--url <url> | --command <cmd>) [options]",
214
+ example: "agentloom mcp server add browser --command npx --arg browser-tools-mcp",
137
215
  }));
138
216
  }
139
217
  const args = getStringArrayFlag(argv.arg);
@@ -148,8 +226,8 @@ function runMcpAdd(paths, argv, name) {
148
226
  if (separator <= 0) {
149
227
  throw new Error(formatUsageError({
150
228
  issue: `Invalid --env value "${pair}".`,
151
- usage: "agentloom mcp add <name> ... --env KEY=VALUE [--env KEY2=VALUE2]",
152
- example: "agentloom mcp add browser --command npx --env API_KEY=secret",
229
+ usage: "agentloom mcp server add <name> ... --env KEY=VALUE [--env KEY2=VALUE2]",
230
+ example: "agentloom mcp server add browser --command npx --env API_KEY=secret",
153
231
  }));
154
232
  }
155
233
  const key = pair.slice(0, separator).trim();
@@ -1 +1,2 @@
1
- export declare function runSkillsPassthrough(args: string[]): never;
1
+ import type { ParsedArgs } from "minimist";
2
+ export declare function runSkillCommand(argv: ParsedArgs, cwd: string): Promise<void>;
@@ -1,11 +1,107 @@
1
- import { spawnSync } from "node:child_process";
2
- export function runSkillsPassthrough(args) {
3
- const child = spawnSync("npx", ["skills", ...args], {
4
- stdio: "inherit",
5
- shell: false,
6
- });
7
- if (child.error) {
8
- throw child.error;
1
+ import path from "node:path";
2
+ import { parseProvidersFlag } from "../core/argv.js";
3
+ import { formatUsageError } from "../core/copy.js";
4
+ import { applySkillProviderSideEffects, parseSkillsDir, } from "../core/skills.js";
5
+ import { formatSyncSummary, resolveProvidersForSync, syncFromCanonical, } from "../sync/index.js";
6
+ import { runScopedAddCommand } from "./add.js";
7
+ import { runScopedDeleteCommand } from "./delete.js";
8
+ import { getNonInteractiveMode, resolvePathsForCommand, } from "./entity-utils.js";
9
+ import { runScopedFindCommand } from "./find.js";
10
+ import { runScopedUpdateCommand } from "./update.js";
11
+ export async function runSkillCommand(argv, cwd) {
12
+ const action = argv._[1];
13
+ if (argv.help || !action) {
14
+ console.log("Usage:\n agentloom skill <add|list|delete|find|update|sync> [options]");
15
+ return;
16
+ }
17
+ if (action !== "add" &&
18
+ action !== "list" &&
19
+ action !== "delete" &&
20
+ action !== "find" &&
21
+ action !== "update" &&
22
+ action !== "sync") {
23
+ throw new Error(formatUsageError({
24
+ issue: "Invalid skill command.",
25
+ usage: "agentloom skill <add|list|delete|find|update|sync> [options]",
26
+ example: "agentloom skill add farnoodma/agents",
27
+ }));
28
+ }
29
+ if (action === "add") {
30
+ await runScopedAddCommand({
31
+ argv,
32
+ cwd,
33
+ entity: "skill",
34
+ sourceIndex: 2,
35
+ });
36
+ return;
37
+ }
38
+ if (action === "list") {
39
+ const paths = await resolvePathsForCommand(argv, cwd);
40
+ const skills = parseSkillsDir(paths.skillsDir);
41
+ if (Boolean(argv.json)) {
42
+ console.log(JSON.stringify({
43
+ version: 1,
44
+ skills: skills.map((skill) => ({
45
+ name: skill.name,
46
+ directory: path.basename(skill.sourcePath),
47
+ })),
48
+ }, null, 2));
49
+ return;
50
+ }
51
+ if (skills.length === 0) {
52
+ console.log("No canonical skills configured.");
53
+ return;
54
+ }
55
+ for (const skill of skills) {
56
+ console.log(`${skill.name} (${path.basename(skill.sourcePath)})`);
57
+ }
58
+ return;
59
+ }
60
+ if (action === "delete") {
61
+ await runScopedDeleteCommand({
62
+ argv,
63
+ cwd,
64
+ entity: "skill",
65
+ sourceIndex: 2,
66
+ });
67
+ return;
9
68
  }
10
- process.exit(child.status ?? 1);
69
+ if (action === "find") {
70
+ await runScopedFindCommand(argv, "skill");
71
+ return;
72
+ }
73
+ if (action === "update") {
74
+ await runScopedUpdateCommand({
75
+ argv,
76
+ cwd,
77
+ entity: "skill",
78
+ sourceIndex: 2,
79
+ });
80
+ return;
81
+ }
82
+ const paths = await resolvePathsForCommand(argv, cwd);
83
+ const nonInteractive = getNonInteractiveMode(argv);
84
+ const explicitProviders = parseProvidersFlag(argv.providers);
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"]),
104
+ target: "skill",
105
+ });
106
+ console.log(formatSyncSummary(summary, paths.agentsRoot));
11
107
  }
@@ -1,2 +1,8 @@
1
1
  import type { ParsedArgs } from "minimist";
2
+ import type { EntityType } from "../types.js";
2
3
  export declare function runSyncCommand(argv: ParsedArgs, cwd: string): Promise<void>;
4
+ export declare function runScopedSyncCommand(options: {
5
+ argv: ParsedArgs;
6
+ cwd: string;
7
+ target: EntityType | "all";
8
+ }): Promise<void>;
@@ -1,25 +1,27 @@
1
1
  import { parseProvidersFlag } from "../core/argv.js";
2
2
  import { getSyncHelpText } from "../core/copy.js";
3
- import { resolveScope } from "../core/scope.js";
3
+ import { getNonInteractiveMode, resolvePathsForCommand, } from "./entity-utils.js";
4
4
  import { formatSyncSummary, syncFromCanonical } from "../sync/index.js";
5
5
  export async function runSyncCommand(argv, cwd) {
6
6
  if (argv.help) {
7
7
  console.log(getSyncHelpText());
8
8
  return;
9
9
  }
10
- const nonInteractive = !(process.stdin.isTTY && process.stdout.isTTY);
11
- const paths = await resolveScope({
10
+ await runScopedSyncCommand({
11
+ argv,
12
12
  cwd,
13
- global: Boolean(argv.global),
14
- local: Boolean(argv.local),
15
- interactive: !nonInteractive,
13
+ target: "all",
16
14
  });
15
+ }
16
+ export async function runScopedSyncCommand(options) {
17
+ const paths = await resolvePathsForCommand(options.argv, options.cwd);
17
18
  const summary = await syncFromCanonical({
18
19
  paths,
19
- providers: parseProvidersFlag(argv.providers),
20
- yes: Boolean(argv.yes),
21
- nonInteractive,
22
- dryRun: Boolean(argv["dry-run"]),
20
+ providers: parseProvidersFlag(options.argv.providers),
21
+ yes: Boolean(options.argv.yes),
22
+ nonInteractive: getNonInteractiveMode(options.argv),
23
+ dryRun: Boolean(options.argv["dry-run"]),
24
+ target: options.target,
23
25
  });
24
26
  console.log(formatSyncSummary(summary, paths.agentsRoot));
25
27
  }
@@ -1,2 +1,9 @@
1
1
  import type { ParsedArgs } from "minimist";
2
+ import type { EntityType } from "../types.js";
2
3
  export declare function runUpdateCommand(argv: ParsedArgs, cwd: string): Promise<void>;
4
+ export declare function runScopedUpdateCommand(options: {
5
+ argv: ParsedArgs;
6
+ cwd: string;
7
+ entity: EntityType;
8
+ sourceIndex: number;
9
+ }): Promise<void>;