@cleocode/caamp 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -2,157 +2,584 @@
2
2
  * CAAMP - Central AI Agent Managed Packages
3
3
  * Core type definitions
4
4
  */
5
+ /**
6
+ * Supported configuration file formats.
7
+ *
8
+ * - `"json"` - Standard JSON
9
+ * - `"jsonc"` - JSON with comments (comment-preserving via jsonc-parser)
10
+ * - `"yaml"` - YAML (via js-yaml)
11
+ * - `"toml"` - TOML (via @iarna/toml)
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * const format: ConfigFormat = "jsonc";
16
+ * ```
17
+ */
5
18
  type ConfigFormat = "json" | "jsonc" | "yaml" | "toml";
19
+ /**
20
+ * MCP server transport protocol type.
21
+ *
22
+ * - `"stdio"` - Standard input/output (local process)
23
+ * - `"sse"` - Server-Sent Events (remote)
24
+ * - `"http"` - HTTP/Streamable HTTP (remote)
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const transport: TransportType = "stdio";
29
+ * ```
30
+ */
6
31
  type TransportType = "stdio" | "sse" | "http";
32
+ /**
33
+ * Method used to detect whether an AI agent is installed on the system.
34
+ *
35
+ * - `"binary"` - Check if a CLI binary exists on PATH
36
+ * - `"directory"` - Check if known config/data directories exist
37
+ * - `"appBundle"` - Check for macOS .app bundle in /Applications
38
+ * - `"flatpak"` - Check for Flatpak installation on Linux
39
+ */
7
40
  type DetectionMethod = "binary" | "directory" | "appBundle" | "flatpak";
41
+ /**
42
+ * Configuration for detecting whether a provider is installed.
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * const config: DetectionConfig = {
47
+ * methods: ["binary", "directory"],
48
+ * binary: "claude",
49
+ * directories: ["~/.config/claude"],
50
+ * };
51
+ * ```
52
+ */
8
53
  interface DetectionConfig {
54
+ /** Detection methods to try, in order. */
9
55
  methods: DetectionMethod[];
56
+ /** Binary name to look up on PATH (for `"binary"` method). */
10
57
  binary?: string;
58
+ /** Directories to check for existence (for `"directory"` method). */
11
59
  directories?: string[];
60
+ /** macOS .app bundle name (for `"appBundle"` method). */
12
61
  appBundle?: string;
62
+ /** Flatpak application ID (for `"flatpak"` method). */
13
63
  flatpakId?: string;
14
64
  }
65
+ /**
66
+ * Priority tier for a provider, used for sorting and default selection.
67
+ *
68
+ * - `"high"` - Major, widely-used agents
69
+ * - `"medium"` - Established but less common agents
70
+ * - `"low"` - Niche or experimental agents
71
+ */
15
72
  type ProviderPriority = "high" | "medium" | "low";
73
+ /**
74
+ * Lifecycle status of a provider in the registry.
75
+ *
76
+ * - `"active"` - Fully supported
77
+ * - `"beta"` - Supported but may have rough edges
78
+ * - `"deprecated"` - Still present but no longer recommended
79
+ * - `"planned"` - Not yet implemented
80
+ */
16
81
  type ProviderStatus = "active" | "beta" | "deprecated" | "planned";
82
+ /**
83
+ * A resolved AI agent provider definition with platform-specific paths.
84
+ *
85
+ * Providers are loaded from `providers/registry.json` and resolved at runtime
86
+ * to expand platform-specific path variables (`$HOME`, `$CONFIG`, etc.).
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * const provider = getProvider("claude-code");
91
+ * if (provider) {
92
+ * console.log(provider.configPathGlobal);
93
+ * }
94
+ * ```
95
+ */
17
96
  interface Provider {
97
+ /** Unique provider identifier (e.g. `"claude-code"`). */
18
98
  id: string;
99
+ /** Human-readable tool name (e.g. `"Claude Code"`). */
19
100
  toolName: string;
101
+ /** Vendor/company name (e.g. `"Anthropic"`). */
20
102
  vendor: string;
103
+ /** CLI flag name for `--agent` selection. */
21
104
  agentFlag: string;
105
+ /** Alternative names that resolve to this provider. */
22
106
  aliases: string[];
107
+ /** Resolved global instruction file directory path. */
23
108
  pathGlobal: string;
109
+ /** Project-relative instruction file directory path. */
24
110
  pathProject: string;
111
+ /** Instruction file name (e.g. `"CLAUDE.md"`, `"AGENTS.md"`). */
25
112
  instructFile: string;
113
+ /** Dot-notation key path for MCP server config (e.g. `"mcpServers"`). */
26
114
  configKey: string;
115
+ /** Config file format used by this provider. */
27
116
  configFormat: ConfigFormat;
117
+ /** Resolved global config file path. */
28
118
  configPathGlobal: string;
119
+ /** Project-relative config file path, or `null` if unsupported. */
29
120
  configPathProject: string | null;
121
+ /** Resolved global skills directory path. */
30
122
  pathSkills: string;
123
+ /** Project-relative skills directory path. */
31
124
  pathProjectSkills: string;
125
+ /** Detection configuration for auto-discovering this provider. */
32
126
  detection: DetectionConfig;
127
+ /** MCP transport protocols this provider supports. */
33
128
  supportedTransports: TransportType[];
129
+ /** Whether the provider supports custom HTTP headers for remote MCP servers. */
34
130
  supportsHeaders: boolean;
131
+ /** Priority tier for sorting and default selection. */
35
132
  priority: ProviderPriority;
133
+ /** Lifecycle status in the registry. */
36
134
  status: ProviderStatus;
135
+ /** Whether the provider is compatible with the Agent Skills standard. */
37
136
  agentSkillsCompatible: boolean;
38
137
  }
138
+ /**
139
+ * Canonical MCP server configuration.
140
+ *
141
+ * Represents either a remote server (via `url`) or a local stdio process
142
+ * (via `command` + `args`). This canonical format is transformed to
143
+ * provider-specific shapes before writing to config files.
144
+ *
145
+ * @example
146
+ * ```typescript
147
+ * // Remote server
148
+ * const remote: McpServerConfig = {
149
+ * type: "http",
150
+ * url: "https://mcp.example.com/sse",
151
+ * };
152
+ *
153
+ * // Local stdio server
154
+ * const local: McpServerConfig = {
155
+ * command: "npx",
156
+ * args: ["-y", "@modelcontextprotocol/server-filesystem"],
157
+ * };
158
+ * ```
159
+ */
39
160
  interface McpServerConfig {
161
+ /** Transport type (`"stdio"`, `"sse"`, or `"http"`). */
40
162
  type?: TransportType;
163
+ /** URL for remote MCP servers. */
41
164
  url?: string;
165
+ /** HTTP headers for remote MCP servers. */
42
166
  headers?: Record<string, string>;
167
+ /** Command to run for stdio MCP servers. */
43
168
  command?: string;
169
+ /** Arguments for the stdio command. */
44
170
  args?: string[];
171
+ /** Environment variables for the stdio process. */
45
172
  env?: Record<string, string>;
46
173
  }
174
+ /**
175
+ * Classified type of an MCP server or skill source.
176
+ *
177
+ * - `"remote"` - HTTP/HTTPS URL to a remote MCP server
178
+ * - `"package"` - npm package name
179
+ * - `"command"` - Shell command string
180
+ * - `"github"` - GitHub repository (URL or shorthand)
181
+ * - `"gitlab"` - GitLab repository URL
182
+ * - `"local"` - Local filesystem path
183
+ */
47
184
  type SourceType = "remote" | "package" | "command" | "github" | "gitlab" | "local";
185
+ /**
186
+ * Result of parsing a source string into its typed components.
187
+ *
188
+ * @example
189
+ * ```typescript
190
+ * const parsed: ParsedSource = {
191
+ * type: "github",
192
+ * value: "https://github.com/owner/repo",
193
+ * inferredName: "repo",
194
+ * owner: "owner",
195
+ * repo: "repo",
196
+ * };
197
+ * ```
198
+ */
48
199
  interface ParsedSource {
200
+ /** Classified source type. */
49
201
  type: SourceType;
202
+ /** Original or normalized source value. */
50
203
  value: string;
204
+ /** Display name inferred from the source. */
51
205
  inferredName: string;
206
+ /** Repository owner (for GitHub/GitLab sources). */
52
207
  owner?: string;
208
+ /** Repository name (for GitHub/GitLab sources). */
53
209
  repo?: string;
210
+ /** Path within the repository (for GitHub/GitLab sources). */
54
211
  path?: string;
212
+ /** Git ref / branch / tag (for GitHub/GitLab sources). */
55
213
  ref?: string;
56
214
  }
215
+ /**
216
+ * Metadata extracted from a SKILL.md frontmatter.
217
+ *
218
+ * @example
219
+ * ```typescript
220
+ * const meta: SkillMetadata = {
221
+ * name: "my-skill",
222
+ * description: "A useful skill for code generation",
223
+ * version: "1.0.0",
224
+ * };
225
+ * ```
226
+ */
57
227
  interface SkillMetadata {
228
+ /** Skill name (lowercase, hyphens only). */
58
229
  name: string;
230
+ /** Human-readable description. */
59
231
  description: string;
232
+ /** SPDX license identifier. */
60
233
  license?: string;
234
+ /** Compatibility notes (e.g. agent versions). */
61
235
  compatibility?: string;
236
+ /** Arbitrary key-value metadata. */
62
237
  metadata?: Record<string, string>;
238
+ /** List of tools the skill is allowed to use. */
63
239
  allowedTools?: string[];
240
+ /** Semantic version string. */
64
241
  version?: string;
65
242
  }
243
+ /**
244
+ * A discovered skill entry with its location and metadata.
245
+ *
246
+ * @example
247
+ * ```typescript
248
+ * const entry: SkillEntry = {
249
+ * name: "my-skill",
250
+ * scopedName: "my-skill",
251
+ * path: "/home/user/.agents/skills/my-skill",
252
+ * metadata: { name: "my-skill", description: "A skill" },
253
+ * };
254
+ * ```
255
+ */
66
256
  interface SkillEntry {
257
+ /** Skill name. */
67
258
  name: string;
259
+ /** Scoped name (may include marketplace scope). */
68
260
  scopedName: string;
261
+ /** Absolute path to the skill directory. */
69
262
  path: string;
263
+ /** Parsed SKILL.md frontmatter metadata. */
70
264
  metadata: SkillMetadata;
265
+ /** Original source from which the skill was installed. */
71
266
  source?: string;
72
267
  }
268
+ /**
269
+ * A single entry in the CAAMP lock file tracking an installed skill or MCP server.
270
+ *
271
+ * @example
272
+ * ```typescript
273
+ * const entry: LockEntry = {
274
+ * name: "my-skill",
275
+ * scopedName: "my-skill",
276
+ * source: "https://github.com/owner/repo",
277
+ * sourceType: "github",
278
+ * installedAt: "2025-01-15T10:30:00.000Z",
279
+ * agents: ["claude-code", "cursor"],
280
+ * canonicalPath: "/home/user/.agents/skills/my-skill",
281
+ * isGlobal: true,
282
+ * };
283
+ * ```
284
+ */
73
285
  interface LockEntry {
286
+ /** Skill or server name. */
74
287
  name: string;
288
+ /** Scoped name (may include marketplace scope). */
75
289
  scopedName: string;
290
+ /** Original source string. */
76
291
  source: string;
292
+ /** Classified source type. */
77
293
  sourceType: SourceType;
294
+ /** Version string or commit SHA. */
78
295
  version?: string;
296
+ /** ISO 8601 timestamp of first installation. */
79
297
  installedAt: string;
298
+ /** ISO 8601 timestamp of last update. */
80
299
  updatedAt?: string;
300
+ /** Provider IDs this entry is linked to. */
81
301
  agents: string[];
302
+ /** Absolute path to canonical installation. */
82
303
  canonicalPath: string;
304
+ /** Whether this was installed globally. */
83
305
  isGlobal: boolean;
306
+ /** Project directory (for project-scoped installs). */
84
307
  projectDir?: string;
85
308
  }
309
+ /**
310
+ * The CAAMP lock file structure, stored at `~/.agents/.caamp-lock.json`.
311
+ *
312
+ * Tracks all installed skills and MCP servers along with their sources,
313
+ * versions, and linked agents.
314
+ *
315
+ * @example
316
+ * ```typescript
317
+ * const lock: CaampLockFile = {
318
+ * version: 1,
319
+ * skills: {},
320
+ * mcpServers: {},
321
+ * lastSelectedAgents: ["claude-code"],
322
+ * };
323
+ * ```
324
+ */
86
325
  interface CaampLockFile {
326
+ /** Lock file schema version. */
87
327
  version: 1;
328
+ /** Installed skills keyed by name. */
88
329
  skills: Record<string, LockEntry>;
330
+ /** Installed MCP servers keyed by name. */
89
331
  mcpServers: Record<string, LockEntry>;
332
+ /** Last selected agent IDs for UX persistence. */
90
333
  lastSelectedAgents?: string[];
91
334
  }
335
+ /**
336
+ * A skill listing from a marketplace search result.
337
+ *
338
+ * @example
339
+ * ```typescript
340
+ * const skill: MarketplaceSkill = {
341
+ * id: "abc123",
342
+ * name: "my-skill",
343
+ * scopedName: "@author/my-skill",
344
+ * description: "A useful skill",
345
+ * author: "author",
346
+ * stars: 42,
347
+ * forks: 5,
348
+ * githubUrl: "https://github.com/author/my-skill",
349
+ * repoFullName: "author/my-skill",
350
+ * path: "/",
351
+ * hasContent: true,
352
+ * };
353
+ * ```
354
+ */
92
355
  interface MarketplaceSkill {
356
+ /** Unique marketplace identifier. */
93
357
  id: string;
358
+ /** Skill name. */
94
359
  name: string;
360
+ /** Scoped name (e.g. `"@author/my-skill"`). */
95
361
  scopedName: string;
362
+ /** Short description. */
96
363
  description: string;
364
+ /** Author / publisher name. */
97
365
  author: string;
366
+ /** GitHub star count. */
98
367
  stars: number;
368
+ /** GitHub fork count. */
99
369
  forks: number;
370
+ /** GitHub repository URL. */
100
371
  githubUrl: string;
372
+ /** Full `owner/repo` name. */
101
373
  repoFullName: string;
374
+ /** Path within the repository. */
102
375
  path: string;
376
+ /** Optional category tag. */
103
377
  category?: string;
378
+ /** Whether SKILL.md content was fetched. */
104
379
  hasContent: boolean;
105
380
  }
381
+ /**
382
+ * Paginated search results from a marketplace API.
383
+ *
384
+ * @example
385
+ * ```typescript
386
+ * const result: MarketplaceSearchResult = {
387
+ * skills: [],
388
+ * total: 0,
389
+ * limit: 20,
390
+ * offset: 0,
391
+ * };
392
+ * ```
393
+ */
106
394
  interface MarketplaceSearchResult {
395
+ /** Array of matching skills. */
107
396
  skills: MarketplaceSkill[];
397
+ /** Total number of matching results. */
108
398
  total: number;
399
+ /** Maximum results per page. */
109
400
  limit: number;
401
+ /** Offset into the result set. */
110
402
  offset: number;
111
403
  }
404
+ /**
405
+ * Severity level for a security audit finding.
406
+ *
407
+ * Ordered from most to least severe: `"critical"` > `"high"` > `"medium"` > `"low"` > `"info"`.
408
+ */
112
409
  type AuditSeverity = "critical" | "high" | "medium" | "low" | "info";
410
+ /**
411
+ * A security audit rule definition with a regex pattern to match against skill content.
412
+ *
413
+ * @example
414
+ * ```typescript
415
+ * const rule: AuditRule = {
416
+ * id: "SEC001",
417
+ * name: "shell-injection",
418
+ * description: "Potential shell injection vector",
419
+ * severity: "critical",
420
+ * category: "injection",
421
+ * pattern: /rm\s+-rf\s+\//,
422
+ * };
423
+ * ```
424
+ */
113
425
  interface AuditRule {
426
+ /** Unique rule identifier (e.g. `"SEC001"`). */
114
427
  id: string;
428
+ /** Rule name. */
115
429
  name: string;
430
+ /** Human-readable description of what the rule detects. */
116
431
  description: string;
432
+ /** Severity level of findings from this rule. */
117
433
  severity: AuditSeverity;
434
+ /** Category grouping (e.g. `"injection"`, `"exfiltration"`). */
118
435
  category: string;
436
+ /** Regex pattern to match against each line of content. */
119
437
  pattern: RegExp;
120
438
  }
439
+ /**
440
+ * A single finding from a security audit scan, with line-level location.
441
+ *
442
+ * @example
443
+ * ```typescript
444
+ * const finding: AuditFinding = {
445
+ * rule: myRule,
446
+ * line: 42,
447
+ * column: 10,
448
+ * match: "rm -rf /",
449
+ * context: "Execute: rm -rf / to clean up",
450
+ * };
451
+ * ```
452
+ */
121
453
  interface AuditFinding {
454
+ /** The rule that triggered this finding. */
122
455
  rule: AuditRule;
456
+ /** Line number (1-based). */
123
457
  line: number;
458
+ /** Column number (1-based). */
124
459
  column: number;
460
+ /** The matched text. */
125
461
  match: string;
462
+ /** The full line of text for context. */
126
463
  context: string;
127
464
  }
465
+ /**
466
+ * Aggregate audit result for a single file.
467
+ *
468
+ * Includes a security score (100 = clean, 0 = very dangerous) and a pass/fail
469
+ * status based on the presence of critical or high severity findings.
470
+ *
471
+ * @example
472
+ * ```typescript
473
+ * const result: AuditResult = {
474
+ * file: "/path/to/SKILL.md",
475
+ * findings: [],
476
+ * score: 100,
477
+ * passed: true,
478
+ * };
479
+ * ```
480
+ */
128
481
  interface AuditResult {
482
+ /** Path to the scanned file. */
129
483
  file: string;
484
+ /** All findings for this file. */
130
485
  findings: AuditFinding[];
486
+ /** Security score from 0 (dangerous) to 100 (clean). */
131
487
  score: number;
488
+ /** Whether the file passed the audit (no critical/high findings). */
132
489
  passed: boolean;
133
490
  }
491
+ /**
492
+ * Status of a CAAMP injection block in an instruction file.
493
+ *
494
+ * - `"current"` - Injection block exists and matches expected content
495
+ * - `"outdated"` - Injection block exists but content differs
496
+ * - `"missing"` - Instruction file does not exist
497
+ * - `"none"` - File exists but has no CAAMP injection block
498
+ */
134
499
  type InjectionStatus = "current" | "outdated" | "missing" | "none";
500
+ /**
501
+ * Result of checking a single instruction file for CAAMP injection status.
502
+ *
503
+ * @example
504
+ * ```typescript
505
+ * const check: InjectionCheckResult = {
506
+ * file: "/project/CLAUDE.md",
507
+ * provider: "claude-code",
508
+ * status: "current",
509
+ * fileExists: true,
510
+ * };
511
+ * ```
512
+ */
135
513
  interface InjectionCheckResult {
514
+ /** Absolute path to the instruction file. */
136
515
  file: string;
516
+ /** Provider ID that owns this instruction file. */
137
517
  provider: string;
518
+ /** Current injection status. */
138
519
  status: InjectionStatus;
520
+ /** Whether the instruction file exists on disk. */
139
521
  fileExists: boolean;
140
522
  }
523
+ /**
524
+ * An MCP server entry read from a provider's config file.
525
+ *
526
+ * Returned by {@link listMcpServers} and {@link listAllMcpServers}.
527
+ *
528
+ * @example
529
+ * ```typescript
530
+ * const entry: McpServerEntry = {
531
+ * name: "filesystem",
532
+ * providerId: "claude-code",
533
+ * providerName: "Claude Code",
534
+ * scope: "project",
535
+ * configPath: "/project/.claude/settings.json",
536
+ * config: { command: "npx", args: ["-y", "@mcp/server-filesystem"] },
537
+ * };
538
+ * ```
539
+ */
141
540
  interface McpServerEntry {
541
+ /** Server name (the key in the config file). */
142
542
  name: string;
543
+ /** Provider ID that owns this config file. */
143
544
  providerId: string;
545
+ /** Human-readable provider name. */
144
546
  providerName: string;
547
+ /** Whether from project or global config. */
145
548
  scope: "project" | "global";
549
+ /** Absolute path to the config file. */
146
550
  configPath: string;
551
+ /** Raw server configuration object. */
147
552
  config: Record<string, unknown>;
148
553
  }
554
+ /**
555
+ * Global CLI options shared across all CAAMP commands.
556
+ *
557
+ * @example
558
+ * ```typescript
559
+ * const opts: GlobalOptions = {
560
+ * agent: ["claude-code", "cursor"],
561
+ * global: true,
562
+ * json: true,
563
+ * };
564
+ * ```
565
+ */
149
566
  interface GlobalOptions {
567
+ /** Target agent IDs (repeatable). */
150
568
  agent?: string[];
569
+ /** Operate on global config instead of project. */
151
570
  global?: boolean;
571
+ /** Skip confirmation prompts. */
152
572
  yes?: boolean;
573
+ /** Target all detected agents. */
153
574
  all?: boolean;
575
+ /** Output as JSON. */
154
576
  json?: boolean;
577
+ /** Preview changes without writing. */
155
578
  dryRun?: boolean;
579
+ /** Enable debug logging. */
580
+ verbose?: boolean;
581
+ /** Suppress non-error output. */
582
+ quiet?: boolean;
156
583
  }
157
584
 
158
585
  /**
@@ -162,19 +589,95 @@ interface GlobalOptions {
162
589
  * by checking binaries, directories, app bundles, and flatpak.
163
590
  */
164
591
 
592
+ /**
593
+ * Result of detecting whether a provider is installed on the system.
594
+ *
595
+ * @example
596
+ * ```typescript
597
+ * const result = detectProvider(provider);
598
+ * if (result.installed) {
599
+ * console.log(`Found via: ${result.methods.join(", ")}`);
600
+ * }
601
+ * ```
602
+ */
165
603
  interface DetectionResult {
604
+ /** The provider that was checked. */
166
605
  provider: Provider;
606
+ /** Whether the provider was detected as installed. */
167
607
  installed: boolean;
608
+ /** Detection methods that matched (e.g. `["binary", "directory"]`). */
168
609
  methods: string[];
610
+ /** Whether the provider has project-level config in the current directory. */
169
611
  projectDetected: boolean;
170
612
  }
171
- /** Detect if a single provider is installed */
613
+ /**
614
+ * Detect if a single provider is installed on the system.
615
+ *
616
+ * Checks each detection method configured for the provider (binary, directory,
617
+ * appBundle, flatpak) and returns which methods matched.
618
+ *
619
+ * @param provider - The provider to detect
620
+ * @returns Detection result with installation status and matched methods
621
+ *
622
+ * @example
623
+ * ```typescript
624
+ * const provider = getProvider("claude-code")!;
625
+ * const result = detectProvider(provider);
626
+ * if (result.installed) {
627
+ * console.log(`Claude Code found via: ${result.methods.join(", ")}`);
628
+ * }
629
+ * ```
630
+ */
172
631
  declare function detectProvider(provider: Provider): DetectionResult;
173
- /** Detect all installed providers */
632
+ /**
633
+ * Detect all registered providers and return their installation status.
634
+ *
635
+ * Runs detection for every provider in the registry.
636
+ *
637
+ * @returns Array of detection results for all providers
638
+ *
639
+ * @example
640
+ * ```typescript
641
+ * const results = detectAllProviders();
642
+ * const installed = results.filter(r => r.installed);
643
+ * console.log(`${installed.length} agents detected`);
644
+ * ```
645
+ */
174
646
  declare function detectAllProviders(): DetectionResult[];
175
- /** Get only installed providers */
647
+ /**
648
+ * Get only providers that are currently installed on the system.
649
+ *
650
+ * Convenience wrapper that filters {@link detectAllProviders} results to only
651
+ * those with `installed === true`.
652
+ *
653
+ * @returns Array of installed provider definitions
654
+ *
655
+ * @example
656
+ * ```typescript
657
+ * const installed = getInstalledProviders();
658
+ * console.log(installed.map(p => p.toolName).join(", "));
659
+ * ```
660
+ */
176
661
  declare function getInstalledProviders(): Provider[];
177
- /** Detect providers with project-level presence */
662
+ /**
663
+ * Detect all providers and enrich results with project-level presence.
664
+ *
665
+ * Extends {@link detectAllProviders} by also checking whether each provider
666
+ * has a project-level config file in the given directory.
667
+ *
668
+ * @param projectDir - Absolute path to the project directory to check
669
+ * @returns Array of detection results with `projectDetected` populated
670
+ *
671
+ * @example
672
+ * ```typescript
673
+ * const results = detectProjectProviders("/home/user/my-project");
674
+ * for (const r of results) {
675
+ * if (r.projectDetected) {
676
+ * console.log(`${r.provider.toolName} has project config`);
677
+ * }
678
+ * }
679
+ * ```
680
+ */
178
681
  declare function detectProjectProviders(projectDir: string): DetectionResult[];
179
682
 
180
683
  /**
@@ -184,18 +687,94 @@ declare function detectProjectProviders(projectDir: string): DetectionResult[];
184
687
  * handling per-agent formats, keys, and transformations.
185
688
  */
186
689
 
690
+ /**
691
+ * Result of installing an MCP server configuration to a single provider.
692
+ *
693
+ * @example
694
+ * ```typescript
695
+ * const result = await installMcpServer(provider, "my-server", config);
696
+ * if (result.success) {
697
+ * console.log(`Written to ${result.configPath}`);
698
+ * }
699
+ * ```
700
+ */
187
701
  interface InstallResult {
702
+ /** The provider the config was written to. */
188
703
  provider: Provider;
704
+ /** Whether project or global scope was used. */
189
705
  scope: "project" | "global";
706
+ /** Absolute path to the config file that was written. */
190
707
  configPath: string;
708
+ /** Whether the write succeeded. */
191
709
  success: boolean;
710
+ /** Error message if the write failed. */
192
711
  error?: string;
193
712
  }
194
- /** Install an MCP server config for a single provider */
713
+ /**
714
+ * Install an MCP server configuration for a single provider.
715
+ *
716
+ * Applies provider-specific transforms (e.g. Goose, Zed, Codex) and writes
717
+ * the config to the provider's config file in the specified scope.
718
+ *
719
+ * @param provider - Target provider to write config for
720
+ * @param serverName - Name/key for the MCP server entry
721
+ * @param config - Canonical MCP server configuration
722
+ * @param scope - Whether to write to project or global config (default: `"project"`)
723
+ * @param projectDir - Project directory path (defaults to `process.cwd()`)
724
+ * @returns Install result with success status and config path
725
+ *
726
+ * @example
727
+ * ```typescript
728
+ * const provider = getProvider("claude-code")!;
729
+ * const result = await installMcpServer(provider, "filesystem", {
730
+ * command: "npx",
731
+ * args: ["-y", "@modelcontextprotocol/server-filesystem"],
732
+ * });
733
+ * ```
734
+ */
195
735
  declare function installMcpServer(provider: Provider, serverName: string, config: McpServerConfig, scope?: "project" | "global", projectDir?: string): Promise<InstallResult>;
196
- /** Install an MCP server config for multiple providers */
736
+ /**
737
+ * Install an MCP server configuration to multiple providers.
738
+ *
739
+ * Calls {@link installMcpServer} for each provider sequentially and collects results.
740
+ *
741
+ * @param providers - Array of target providers
742
+ * @param serverName - Name/key for the MCP server entry
743
+ * @param config - Canonical MCP server configuration
744
+ * @param scope - Whether to write to project or global config (default: `"project"`)
745
+ * @param projectDir - Project directory path (defaults to `process.cwd()`)
746
+ * @returns Array of install results, one per provider
747
+ *
748
+ * @example
749
+ * ```typescript
750
+ * const providers = getInstalledProviders();
751
+ * const results = await installMcpServerToAll(providers, "my-server", config);
752
+ * const successes = results.filter(r => r.success);
753
+ * ```
754
+ */
197
755
  declare function installMcpServerToAll(providers: Provider[], serverName: string, config: McpServerConfig, scope?: "project" | "global", projectDir?: string): Promise<InstallResult[]>;
198
- /** Build a canonical MCP server config from parsed source */
756
+ /**
757
+ * Build a canonical {@link McpServerConfig} from a parsed source.
758
+ *
759
+ * Maps source types to appropriate transport configurations:
760
+ * - `"remote"` sources become HTTP/SSE configs with a `url`
761
+ * - `"package"` sources become `npx -y <package>` stdio configs
762
+ * - All others are treated as shell commands split into `command` + `args`
763
+ *
764
+ * @param source - Parsed source with `type` and `value`
765
+ * @param transport - Override transport type for remote sources (default: `"http"`)
766
+ * @param headers - Optional HTTP headers for remote servers
767
+ * @returns Canonical MCP server configuration
768
+ *
769
+ * @example
770
+ * ```typescript
771
+ * buildServerConfig({ type: "package", value: "@mcp/server-fs" });
772
+ * // { command: "npx", args: ["-y", "@mcp/server-fs"] }
773
+ *
774
+ * buildServerConfig({ type: "remote", value: "https://mcp.example.com" });
775
+ * // { type: "http", url: "https://mcp.example.com" }
776
+ * ```
777
+ */
199
778
  declare function buildServerConfig(source: {
200
779
  type: string;
201
780
  value: string;
@@ -208,21 +787,83 @@ declare function buildServerConfig(source: {
208
787
  * and symlinked to each target agent's skills directory.
209
788
  */
210
789
 
790
+ /**
791
+ * Result of installing a skill to the canonical location and linking to agents.
792
+ *
793
+ * @example
794
+ * ```typescript
795
+ * const result = await installSkill(sourcePath, "my-skill", providers, true);
796
+ * if (result.success) {
797
+ * console.log(`Installed to ${result.canonicalPath}`);
798
+ * console.log(`Linked to: ${result.linkedAgents.join(", ")}`);
799
+ * }
800
+ * ```
801
+ */
211
802
  interface SkillInstallResult {
803
+ /** Skill name. */
212
804
  name: string;
805
+ /** Absolute path to the canonical installation directory. */
213
806
  canonicalPath: string;
807
+ /** Provider IDs that were successfully linked. */
214
808
  linkedAgents: string[];
809
+ /** Error messages from failed link operations. */
215
810
  errors: string[];
811
+ /** Whether at least one agent was successfully linked. */
216
812
  success: boolean;
217
813
  }
218
- /** Install a skill from a local path to canonical + link to agents */
814
+ /**
815
+ * Install a skill from a local path to the canonical location and link to agents.
816
+ *
817
+ * Copies the skill directory to `~/.agents/skills/<name>/` and creates symlinks
818
+ * (or copies on Windows) from each provider's skills directory to the canonical path.
819
+ *
820
+ * @param sourcePath - Local path to the skill directory to install
821
+ * @param skillName - Name for the installed skill
822
+ * @param providers - Target providers to link the skill to
823
+ * @param isGlobal - Whether to link to global or project skill directories
824
+ * @param projectDir - Project directory (defaults to `process.cwd()`)
825
+ * @returns Install result with linked agents and any errors
826
+ *
827
+ * @example
828
+ * ```typescript
829
+ * const result = await installSkill("/tmp/my-skill", "my-skill", providers, true);
830
+ * ```
831
+ */
219
832
  declare function installSkill(sourcePath: string, skillName: string, providers: Provider[], isGlobal: boolean, projectDir?: string): Promise<SkillInstallResult>;
220
- /** Remove a skill from canonical location and all agent symlinks */
833
+ /**
834
+ * Remove a skill from the canonical location and all agent symlinks.
835
+ *
836
+ * Removes symlinks from each provider's skills directory and then removes the
837
+ * canonical copy from `~/.agents/skills/<name>/`.
838
+ *
839
+ * @param skillName - Name of the skill to remove
840
+ * @param providers - Providers to unlink the skill from
841
+ * @param isGlobal - Whether to target global or project skill directories
842
+ * @param projectDir - Project directory (defaults to `process.cwd()`)
843
+ * @returns Object with arrays of successfully removed provider IDs and error messages
844
+ *
845
+ * @example
846
+ * ```typescript
847
+ * const { removed, errors } = await removeSkill("my-skill", providers, true);
848
+ * ```
849
+ */
221
850
  declare function removeSkill(skillName: string, providers: Provider[], isGlobal: boolean, projectDir?: string): Promise<{
222
851
  removed: string[];
223
852
  errors: string[];
224
853
  }>;
225
- /** List all canonically installed skills */
854
+ /**
855
+ * List all skills installed in the canonical directory (`~/.agents/skills/`).
856
+ *
857
+ * Returns the directory names of all skills, which correspond to skill names.
858
+ *
859
+ * @returns Array of skill names
860
+ *
861
+ * @example
862
+ * ```typescript
863
+ * const skills = await listCanonicalSkills();
864
+ * // ["my-skill", "another-skill"]
865
+ * ```
866
+ */
226
867
  declare function listCanonicalSkills(): Promise<string[]>;
227
868
 
228
869
  /**
@@ -230,19 +871,326 @@ declare function listCanonicalSkills(): Promise<string[]>;
230
871
  *
231
872
  * Validates skill files against the Agent Skills standard.
232
873
  */
874
+ /**
875
+ * A single validation issue found during SKILL.md validation.
876
+ *
877
+ * @example
878
+ * ```typescript
879
+ * const issue: ValidationIssue = {
880
+ * level: "error",
881
+ * field: "name",
882
+ * message: "Missing required field: name",
883
+ * };
884
+ * ```
885
+ */
233
886
  interface ValidationIssue {
887
+ /** Severity: `"error"` causes validation failure, `"warning"` does not. */
234
888
  level: "error" | "warning";
889
+ /** The field or section that triggered the issue. */
235
890
  field: string;
891
+ /** Human-readable description of the issue. */
236
892
  message: string;
237
893
  }
894
+ /**
895
+ * Result of validating a SKILL.md file against the Agent Skills standard.
896
+ *
897
+ * @example
898
+ * ```typescript
899
+ * const result = await validateSkill("/path/to/SKILL.md");
900
+ * if (!result.valid) {
901
+ * for (const issue of result.issues) {
902
+ * console.log(`[${issue.level}] ${issue.field}: ${issue.message}`);
903
+ * }
904
+ * }
905
+ * ```
906
+ */
238
907
  interface ValidationResult {
908
+ /** Whether the skill passed validation (no error-level issues). */
239
909
  valid: boolean;
910
+ /** All issues found during validation. */
240
911
  issues: ValidationIssue[];
912
+ /** Parsed frontmatter metadata, or `null` if parsing failed. */
241
913
  metadata: Record<string, unknown> | null;
242
914
  }
243
- /** Validate a SKILL.md file */
915
+ /**
916
+ * Validate a SKILL.md file against the Agent Skills standard.
917
+ *
918
+ * Checks for required frontmatter fields (`name`, `description`), validates
919
+ * naming conventions, enforces length limits, checks for reserved names,
920
+ * and warns about long skill bodies.
921
+ *
922
+ * @param filePath - Absolute path to the SKILL.md file to validate
923
+ * @returns Validation result with issues and parsed metadata
924
+ *
925
+ * @example
926
+ * ```typescript
927
+ * const result = await validateSkill("/path/to/SKILL.md");
928
+ * console.log(result.valid ? "Valid" : `${result.issues.length} issues found`);
929
+ * ```
930
+ */
244
931
  declare function validateSkill(filePath: string): Promise<ValidationResult>;
245
932
 
933
+ /**
934
+ * Marketplace types shared between adapters
935
+ */
936
+ interface MarketplaceAdapter {
937
+ name: string;
938
+ search(query: string, limit?: number): Promise<MarketplaceResult[]>;
939
+ getSkill(scopedName: string): Promise<MarketplaceResult | null>;
940
+ }
941
+ interface MarketplaceResult {
942
+ name: string;
943
+ scopedName: string;
944
+ description: string;
945
+ author: string;
946
+ stars: number;
947
+ githubUrl: string;
948
+ repoFullName: string;
949
+ path: string;
950
+ source: string;
951
+ }
952
+
953
+ declare const RECOMMENDATION_ERROR_CODES: {
954
+ readonly QUERY_INVALID: "E_SKILLS_QUERY_INVALID";
955
+ readonly NO_MATCHES: "E_SKILLS_NO_MATCHES";
956
+ readonly SOURCE_UNAVAILABLE: "E_SKILLS_SOURCE_UNAVAILABLE";
957
+ readonly CRITERIA_CONFLICT: "E_SKILLS_CRITERIA_CONFLICT";
958
+ };
959
+ type RecommendationErrorCode = (typeof RECOMMENDATION_ERROR_CODES)[keyof typeof RECOMMENDATION_ERROR_CODES];
960
+ interface RecommendationValidationIssue {
961
+ code: RecommendationErrorCode;
962
+ field: "query" | "mustHave" | "prefer" | "exclude";
963
+ message: string;
964
+ }
965
+ interface RecommendationValidationResult {
966
+ valid: boolean;
967
+ issues: RecommendationValidationIssue[];
968
+ }
969
+ interface RecommendationCriteriaInput {
970
+ query?: string;
971
+ mustHave?: string | string[];
972
+ prefer?: string | string[];
973
+ exclude?: string | string[];
974
+ }
975
+ interface NormalizedRecommendationCriteria {
976
+ query: string;
977
+ queryTokens: string[];
978
+ mustHave: string[];
979
+ prefer: string[];
980
+ exclude: string[];
981
+ }
982
+ type RecommendationReasonCode = "MATCH_TOPIC_GITBOOK" | "HAS_GIT_SYNC" | "HAS_API_WORKFLOW" | "PENALTY_LEGACY_CLI" | "MUST_HAVE_MATCH" | "MISSING_MUST_HAVE" | "PREFER_MATCH" | "QUERY_MATCH" | "STAR_SIGNAL" | "METADATA_SIGNAL" | "MODERN_MARKER" | "LEGACY_MARKER" | "EXCLUDE_MATCH";
983
+ interface RecommendationReason {
984
+ code: RecommendationReasonCode;
985
+ detail?: string;
986
+ }
987
+ interface RecommendationScoreBreakdown {
988
+ mustHave: number;
989
+ prefer: number;
990
+ query: number;
991
+ stars: number;
992
+ metadata: number;
993
+ modernity: number;
994
+ exclusionPenalty: number;
995
+ total: number;
996
+ }
997
+ interface RankedSkillRecommendation {
998
+ skill: MarketplaceResult;
999
+ score: number;
1000
+ reasons: RecommendationReason[];
1001
+ tradeoffs: string[];
1002
+ excluded: boolean;
1003
+ breakdown?: RecommendationScoreBreakdown;
1004
+ }
1005
+ interface RecommendationOptions {
1006
+ top?: number;
1007
+ includeDetails?: boolean;
1008
+ weights?: Partial<RecommendationWeights>;
1009
+ modernMarkers?: string[];
1010
+ legacyMarkers?: string[];
1011
+ }
1012
+ interface RecommendationWeights {
1013
+ mustHaveMatch: number;
1014
+ preferMatch: number;
1015
+ queryTokenMatch: number;
1016
+ starsFactor: number;
1017
+ metadataBoost: number;
1018
+ modernMarkerBoost: number;
1019
+ legacyMarkerPenalty: number;
1020
+ excludePenalty: number;
1021
+ missingMustHavePenalty: number;
1022
+ }
1023
+ interface RecommendSkillsResult {
1024
+ criteria: NormalizedRecommendationCriteria;
1025
+ ranking: RankedSkillRecommendation[];
1026
+ }
1027
+ declare function tokenizeCriteriaValue(value: string): string[];
1028
+ declare function validateRecommendationCriteria(input: RecommendationCriteriaInput): RecommendationValidationResult;
1029
+ declare function normalizeRecommendationCriteria(input: RecommendationCriteriaInput): NormalizedRecommendationCriteria;
1030
+ declare function scoreSkillRecommendation(skill: MarketplaceResult, criteria: NormalizedRecommendationCriteria, options?: RecommendationOptions): RankedSkillRecommendation;
1031
+ declare function recommendSkills$1(skills: MarketplaceResult[], criteriaInput: RecommendationCriteriaInput, options?: RecommendationOptions): RecommendSkillsResult;
1032
+ declare const rankSkills: typeof recommendSkills$1;
1033
+
1034
+ /**
1035
+ * Advanced orchestration helpers for multi-provider operations.
1036
+ *
1037
+ * These helpers compose CAAMP's lower-level APIs into production patterns:
1038
+ * tier-based targeting, conflict-aware installs, and rollback-capable batches.
1039
+ */
1040
+
1041
+ type Scope = "project" | "global";
1042
+ /**
1043
+ * Filter providers by minimum priority and return them in deterministic tier order.
1044
+ *
1045
+ * `minimumPriority = "medium"` returns `high` + `medium`.
1046
+ */
1047
+ declare function selectProvidersByMinimumPriority(providers: Provider[], minimumPriority?: ProviderPriority): Provider[];
1048
+ /**
1049
+ * Single MCP operation entry used by batch orchestration.
1050
+ */
1051
+ interface McpBatchOperation {
1052
+ serverName: string;
1053
+ config: McpServerConfig;
1054
+ scope?: Scope;
1055
+ }
1056
+ /**
1057
+ * Single skill operation entry used by batch orchestration.
1058
+ */
1059
+ interface SkillBatchOperation {
1060
+ sourcePath: string;
1061
+ skillName: string;
1062
+ isGlobal?: boolean;
1063
+ }
1064
+ /**
1065
+ * Options for rollback-capable batch installation.
1066
+ */
1067
+ interface BatchInstallOptions {
1068
+ providers?: Provider[];
1069
+ minimumPriority?: ProviderPriority;
1070
+ mcp?: McpBatchOperation[];
1071
+ skills?: SkillBatchOperation[];
1072
+ projectDir?: string;
1073
+ }
1074
+ /**
1075
+ * Result of rollback-capable batch installation.
1076
+ */
1077
+ interface BatchInstallResult {
1078
+ success: boolean;
1079
+ providerIds: string[];
1080
+ mcpApplied: number;
1081
+ skillsApplied: number;
1082
+ rollbackPerformed: boolean;
1083
+ rollbackErrors: string[];
1084
+ error?: string;
1085
+ }
1086
+ /**
1087
+ * Install multiple MCP servers and skills across filtered providers with rollback.
1088
+ *
1089
+ * Rollback behavior:
1090
+ * - MCP config files are restored exactly from snapshots.
1091
+ * - Skill state is restored for canonical skill dirs and targeted provider link paths.
1092
+ */
1093
+ declare function installBatchWithRollback(options: BatchInstallOptions): Promise<BatchInstallResult>;
1094
+ /**
1095
+ * Conflict policy when applying MCP install plans.
1096
+ */
1097
+ type ConflictPolicy = "fail" | "skip" | "overwrite";
1098
+ /**
1099
+ * MCP conflict code.
1100
+ */
1101
+ type McpConflictCode = "unsupported-transport" | "unsupported-headers" | "existing-mismatch";
1102
+ /**
1103
+ * Conflict detected during preflight.
1104
+ */
1105
+ interface McpConflict {
1106
+ providerId: string;
1107
+ serverName: string;
1108
+ scope: Scope;
1109
+ code: McpConflictCode;
1110
+ message: string;
1111
+ }
1112
+ /**
1113
+ * Result from applying install plan with conflict policy.
1114
+ */
1115
+ interface McpPlanApplyResult {
1116
+ conflicts: McpConflict[];
1117
+ applied: InstallResult[];
1118
+ skipped: Array<{
1119
+ providerId: string;
1120
+ serverName: string;
1121
+ scope: Scope;
1122
+ reason: McpConflictCode;
1123
+ }>;
1124
+ }
1125
+ /**
1126
+ * Preflight conflict detection for MCP install plans across providers.
1127
+ */
1128
+ declare function detectMcpConfigConflicts(providers: Provider[], operations: McpBatchOperation[], projectDir?: string): Promise<McpConflict[]>;
1129
+ /**
1130
+ * Apply MCP install plan with a conflict policy.
1131
+ */
1132
+ declare function applyMcpInstallWithPolicy(providers: Provider[], operations: McpBatchOperation[], policy?: ConflictPolicy, projectDir?: string): Promise<McpPlanApplyResult>;
1133
+ /**
1134
+ * Result of a single-operation instruction update across providers.
1135
+ */
1136
+ interface InstructionUpdateSummary {
1137
+ scope: Scope;
1138
+ updatedFiles: number;
1139
+ actions: Array<{
1140
+ file: string;
1141
+ action: "created" | "added" | "updated";
1142
+ providers: string[];
1143
+ configFormats: ConfigFormat[];
1144
+ }>;
1145
+ }
1146
+ /**
1147
+ * Update instruction files across providers as a single operation.
1148
+ *
1149
+ * Works the same regardless of provider config format (JSON/YAML/TOML/JSONC)
1150
+ * because instruction files are handled through CAAMP markers.
1151
+ */
1152
+ declare function updateInstructionsSingleOperation(providers: Provider[], content: string, scope?: Scope, projectDir?: string): Promise<InstructionUpdateSummary>;
1153
+ /**
1154
+ * Request payload for dual-scope provider configuration.
1155
+ */
1156
+ interface DualScopeConfigureOptions {
1157
+ globalMcp?: Array<{
1158
+ serverName: string;
1159
+ config: McpServerConfig;
1160
+ }>;
1161
+ projectMcp?: Array<{
1162
+ serverName: string;
1163
+ config: McpServerConfig;
1164
+ }>;
1165
+ instructionContent?: string | {
1166
+ global?: string;
1167
+ project?: string;
1168
+ };
1169
+ projectDir?: string;
1170
+ }
1171
+ /**
1172
+ * Result of dual-scope provider configuration.
1173
+ */
1174
+ interface DualScopeConfigureResult {
1175
+ providerId: string;
1176
+ configPaths: {
1177
+ global: string | null;
1178
+ project: string | null;
1179
+ };
1180
+ mcp: {
1181
+ global: InstallResult[];
1182
+ project: InstallResult[];
1183
+ };
1184
+ instructions: {
1185
+ global?: Map<string, "created" | "added" | "updated">;
1186
+ project?: Map<string, "created" | "added" | "updated">;
1187
+ };
1188
+ }
1189
+ /**
1190
+ * Configure both global and project-level settings for one provider in one call.
1191
+ */
1192
+ declare function configureProviderGlobalAndProject(provider: Provider, options: DualScopeConfigureOptions): Promise<DualScopeConfigureResult>;
1193
+
246
1194
  /**
247
1195
  * Provider registry loader
248
1196
  *
@@ -250,23 +1198,121 @@ declare function validateSkill(filePath: string): Promise<ValidationResult>;
250
1198
  * platform-specific paths at runtime.
251
1199
  */
252
1200
 
253
- /** Get all providers */
1201
+ /**
1202
+ * Retrieve all registered providers with resolved platform paths.
1203
+ *
1204
+ * Providers are lazily loaded from `providers/registry.json` on first call
1205
+ * and cached for subsequent calls.
1206
+ *
1207
+ * @returns Array of all provider definitions
1208
+ *
1209
+ * @example
1210
+ * ```typescript
1211
+ * const providers = getAllProviders();
1212
+ * console.log(`${providers.length} providers registered`);
1213
+ * ```
1214
+ */
254
1215
  declare function getAllProviders(): Provider[];
255
- /** Get a provider by ID or alias */
1216
+ /**
1217
+ * Look up a provider by its ID or any of its aliases.
1218
+ *
1219
+ * @param idOrAlias - Provider ID (e.g. `"claude-code"`) or alias (e.g. `"claude"`)
1220
+ * @returns The matching provider, or `undefined` if not found
1221
+ *
1222
+ * @example
1223
+ * ```typescript
1224
+ * const provider = getProvider("claude");
1225
+ * // Returns the claude-code provider via alias resolution
1226
+ * ```
1227
+ */
256
1228
  declare function getProvider(idOrAlias: string): Provider | undefined;
257
- /** Resolve an alias to provider ID */
1229
+ /**
1230
+ * Resolve an alias to its canonical provider ID.
1231
+ *
1232
+ * If the input is already a canonical ID (or unrecognized), it is returned as-is.
1233
+ *
1234
+ * @param idOrAlias - Provider ID or alias to resolve
1235
+ * @returns The canonical provider ID
1236
+ *
1237
+ * @example
1238
+ * ```typescript
1239
+ * resolveAlias("claude"); // "claude-code"
1240
+ * resolveAlias("claude-code"); // "claude-code"
1241
+ * resolveAlias("unknown"); // "unknown"
1242
+ * ```
1243
+ */
258
1244
  declare function resolveAlias(idOrAlias: string): string;
259
- /** Get providers by priority tier */
1245
+ /**
1246
+ * Filter providers by their priority tier.
1247
+ *
1248
+ * @param priority - Priority level to filter by (`"high"`, `"medium"`, or `"low"`)
1249
+ * @returns Array of providers matching the given priority
1250
+ *
1251
+ * @example
1252
+ * ```typescript
1253
+ * const highPriority = getProvidersByPriority("high");
1254
+ * ```
1255
+ */
260
1256
  declare function getProvidersByPriority(priority: ProviderPriority): Provider[];
261
- /** Get providers by status */
1257
+ /**
1258
+ * Filter providers by their lifecycle status.
1259
+ *
1260
+ * @param status - Status to filter by (`"active"`, `"beta"`, `"deprecated"`, or `"planned"`)
1261
+ * @returns Array of providers matching the given status
1262
+ *
1263
+ * @example
1264
+ * ```typescript
1265
+ * const active = getProvidersByStatus("active");
1266
+ * ```
1267
+ */
262
1268
  declare function getProvidersByStatus(status: ProviderStatus): Provider[];
263
- /** Get providers that use a specific instruction file */
1269
+ /**
1270
+ * Filter providers that use a specific instruction file.
1271
+ *
1272
+ * Multiple providers often share the same instruction file (e.g. many use `"AGENTS.md"`).
1273
+ *
1274
+ * @param file - Instruction file name (e.g. `"CLAUDE.md"`, `"AGENTS.md"`)
1275
+ * @returns Array of providers that use the given instruction file
1276
+ *
1277
+ * @example
1278
+ * ```typescript
1279
+ * const claudeProviders = getProvidersByInstructFile("CLAUDE.md");
1280
+ * ```
1281
+ */
264
1282
  declare function getProvidersByInstructFile(file: string): Provider[];
265
- /** Get all unique instruction files */
1283
+ /**
1284
+ * Get the set of all unique instruction file names across all providers.
1285
+ *
1286
+ * @returns Array of unique instruction file names (e.g. `["CLAUDE.md", "AGENTS.md", "GEMINI.md"]`)
1287
+ *
1288
+ * @example
1289
+ * ```typescript
1290
+ * const files = getInstructionFiles();
1291
+ * // ["CLAUDE.md", "AGENTS.md", "GEMINI.md"]
1292
+ * ```
1293
+ */
266
1294
  declare function getInstructionFiles(): string[];
267
- /** Get provider count */
1295
+ /**
1296
+ * Get the total number of registered providers.
1297
+ *
1298
+ * @returns Count of providers in the registry
1299
+ *
1300
+ * @example
1301
+ * ```typescript
1302
+ * console.log(`Registry has ${getProviderCount()} providers`);
1303
+ * ```
1304
+ */
268
1305
  declare function getProviderCount(): number;
269
- /** Get registry version */
1306
+ /**
1307
+ * Get the semantic version string of the provider registry.
1308
+ *
1309
+ * @returns Version string from `providers/registry.json` (e.g. `"1.0.0"`)
1310
+ *
1311
+ * @example
1312
+ * ```typescript
1313
+ * console.log(`Registry version: ${getRegistryVersion()}`);
1314
+ * ```
1315
+ */
270
1316
  declare function getRegistryVersion(): string;
271
1317
 
272
1318
  /**
@@ -276,9 +1322,42 @@ declare function getRegistryVersion(): string;
276
1322
  * GitLab URLs, local paths, or shell commands.
277
1323
  */
278
1324
 
279
- /** Parse a source string into a typed ParsedSource */
1325
+ /**
1326
+ * Parse and classify a source string into a typed {@link ParsedSource}.
1327
+ *
1328
+ * Supports GitHub URLs, GitLab URLs, GitHub shorthand (`owner/repo`),
1329
+ * HTTP URLs (remote MCP servers), npm package names, local paths, and
1330
+ * shell commands as a fallback.
1331
+ *
1332
+ * @param input - Raw source string to classify
1333
+ * @returns Parsed source with type, value, and inferred name
1334
+ *
1335
+ * @example
1336
+ * ```typescript
1337
+ * parseSource("owner/repo");
1338
+ * // { type: "github", value: "https://github.com/owner/repo", inferredName: "repo", ... }
1339
+ *
1340
+ * parseSource("https://mcp.example.com/sse");
1341
+ * // { type: "remote", value: "https://mcp.example.com/sse", inferredName: "example" }
1342
+ *
1343
+ * parseSource("@modelcontextprotocol/server-filesystem");
1344
+ * // { type: "package", value: "@modelcontextprotocol/server-filesystem", inferredName: "filesystem" }
1345
+ * ```
1346
+ */
280
1347
  declare function parseSource(input: string): ParsedSource;
281
- /** Check if source looks like an MCP marketplace scoped name (@author/name) */
1348
+ /**
1349
+ * Check if a source string looks like a marketplace scoped name (`@author/name`).
1350
+ *
1351
+ * @param input - Source string to check
1352
+ * @returns `true` if the input matches the `@scope/name` pattern
1353
+ *
1354
+ * @example
1355
+ * ```typescript
1356
+ * isMarketplaceScoped("@anthropic/my-skill"); // true
1357
+ * isMarketplaceScoped("my-skill"); // false
1358
+ * isMarketplaceScoped("owner/repo"); // false
1359
+ * ```
1360
+ */
282
1361
  declare function isMarketplaceScoped(input: string): boolean;
283
1362
 
284
1363
  /**
@@ -287,13 +1366,72 @@ declare function isMarketplaceScoped(input: string): boolean;
287
1366
  * Scans directories for SKILL.md files and parses their frontmatter.
288
1367
  */
289
1368
 
290
- /** Parse a SKILL.md file and extract metadata */
1369
+ /**
1370
+ * Parse a SKILL.md file and extract its frontmatter metadata.
1371
+ *
1372
+ * Reads the file, parses YAML frontmatter via `gray-matter`, and maps the
1373
+ * fields to a {@link SkillMetadata} object. Returns `null` if the file cannot
1374
+ * be read or lacks required `name` and `description` fields.
1375
+ *
1376
+ * @param filePath - Absolute path to the SKILL.md file
1377
+ * @returns Parsed metadata, or `null` if invalid
1378
+ *
1379
+ * @example
1380
+ * ```typescript
1381
+ * const meta = await parseSkillFile("/path/to/SKILL.md");
1382
+ * if (meta) {
1383
+ * console.log(`${meta.name}: ${meta.description}`);
1384
+ * }
1385
+ * ```
1386
+ */
291
1387
  declare function parseSkillFile(filePath: string): Promise<SkillMetadata | null>;
292
- /** Discover a skill at a given path (directory containing SKILL.md) */
1388
+ /**
1389
+ * Discover a single skill at a given directory path.
1390
+ *
1391
+ * Checks for a `SKILL.md` file in the directory and parses its metadata.
1392
+ *
1393
+ * @param skillDir - Absolute path to a skill directory (containing SKILL.md)
1394
+ * @returns Skill entry with metadata, or `null` if no valid SKILL.md exists
1395
+ *
1396
+ * @example
1397
+ * ```typescript
1398
+ * const skill = await discoverSkill("/home/user/.agents/skills/my-skill");
1399
+ * if (skill) {
1400
+ * console.log(`Found: ${skill.name}`);
1401
+ * }
1402
+ * ```
1403
+ */
293
1404
  declare function discoverSkill(skillDir: string): Promise<SkillEntry | null>;
294
- /** Scan a directory for skill directories (each containing SKILL.md) */
1405
+ /**
1406
+ * Scan a directory for skill subdirectories, each containing a SKILL.md file.
1407
+ *
1408
+ * Iterates over directories and symlinks in `rootDir` and calls
1409
+ * {@link discoverSkill} on each.
1410
+ *
1411
+ * @param rootDir - Absolute path to a skills root directory to scan
1412
+ * @returns Array of discovered skill entries
1413
+ *
1414
+ * @example
1415
+ * ```typescript
1416
+ * const skills = await discoverSkills("/home/user/.agents/skills");
1417
+ * console.log(`Found ${skills.length} skills`);
1418
+ * ```
1419
+ */
295
1420
  declare function discoverSkills(rootDir: string): Promise<SkillEntry[]>;
296
1421
 
1422
+ interface SearchSkillsOptions {
1423
+ limit?: number;
1424
+ }
1425
+ interface RecommendSkillsQueryOptions extends RecommendationOptions {
1426
+ limit?: number;
1427
+ }
1428
+ declare function formatSkillRecommendations(result: RecommendSkillsResult, opts: {
1429
+ mode: "human" | "json";
1430
+ details?: boolean;
1431
+ }): string | Record<string, unknown>;
1432
+ declare function searchSkills(query: string, options?: SearchSkillsOptions): Promise<MarketplaceResult[]>;
1433
+ declare function recommendSkills(query: string, criteria: Omit<RecommendationCriteriaInput, "query">, options?: RecommendSkillsQueryOptions): Promise<RecommendSkillsResult>;
1434
+
297
1435
  /**
298
1436
  * Security scanning engine for SKILL.md files
299
1437
  *
@@ -301,11 +1439,55 @@ declare function discoverSkills(rootDir: string): Promise<SkillEntry[]>;
301
1439
  * and produces findings with line-level precision.
302
1440
  */
303
1441
 
304
- /** Scan a single file against all rules */
1442
+ /**
1443
+ * Scan a single file against security audit rules.
1444
+ *
1445
+ * Checks each line of the file against all active rules and produces findings
1446
+ * with line-level precision. Calculates a security score (100 = clean, 0 = dangerous)
1447
+ * based on severity-weighted penalties.
1448
+ *
1449
+ * @param filePath - Absolute path to the file to scan
1450
+ * @param rules - Custom rules to scan against (defaults to the built-in 46+ rules)
1451
+ * @returns Audit result with findings, score, and pass/fail status
1452
+ *
1453
+ * @example
1454
+ * ```typescript
1455
+ * const result = await scanFile("/path/to/SKILL.md");
1456
+ * console.log(`Score: ${result.score}/100, Passed: ${result.passed}`);
1457
+ * ```
1458
+ */
305
1459
  declare function scanFile(filePath: string, rules?: AuditRule[]): Promise<AuditResult>;
306
- /** Scan a directory of skills */
1460
+ /**
1461
+ * Scan a directory of skills for security issues.
1462
+ *
1463
+ * Iterates over skill subdirectories and scans each `SKILL.md` file found.
1464
+ *
1465
+ * @param dirPath - Absolute path to the skills directory to scan
1466
+ * @returns Array of audit results, one per scanned SKILL.md
1467
+ *
1468
+ * @example
1469
+ * ```typescript
1470
+ * const results = await scanDirectory("/home/user/.agents/skills");
1471
+ * const failing = results.filter(r => !r.passed);
1472
+ * ```
1473
+ */
307
1474
  declare function scanDirectory(dirPath: string): Promise<AuditResult[]>;
308
- /** Format findings as SARIF (Static Analysis Results Interchange Format) */
1475
+ /**
1476
+ * Convert audit results to SARIF 2.1.0 format (Static Analysis Results Interchange Format).
1477
+ *
1478
+ * Produces a standards-compliant SARIF document suitable for CI/CD integration
1479
+ * and code scanning tools (e.g. GitHub Code Scanning).
1480
+ *
1481
+ * @param results - Array of audit results to convert
1482
+ * @returns SARIF 2.1.0 JSON object
1483
+ *
1484
+ * @example
1485
+ * ```typescript
1486
+ * const results = await scanDirectory("/path/to/skills");
1487
+ * const sarif = toSarif(results);
1488
+ * writeFileSync("audit.sarif", JSON.stringify(sarif, null, 2));
1489
+ * ```
1490
+ */
309
1491
  declare function toSarif(results: AuditResult[]): object;
310
1492
 
311
1493
  /**
@@ -315,7 +1497,24 @@ declare function toSarif(results: AuditResult[]): object;
315
1497
  * These transforms handle agents with non-standard schemas.
316
1498
  */
317
1499
 
318
- /** Get the transform function for a provider, or undefined for passthrough */
1500
+ /**
1501
+ * Get the config transform function for a provider, or `undefined` for passthrough.
1502
+ *
1503
+ * Providers with non-standard MCP config schemas (Goose, Zed, OpenCode, Codex, Cursor)
1504
+ * require transforms to convert the canonical {@link McpServerConfig} into their
1505
+ * provider-specific format.
1506
+ *
1507
+ * @param providerId - Provider ID to look up (e.g. `"goose"`, `"zed"`)
1508
+ * @returns Transform function, or `undefined` if the provider uses the canonical format
1509
+ *
1510
+ * @example
1511
+ * ```typescript
1512
+ * const transform = getTransform("goose");
1513
+ * if (transform) {
1514
+ * const gooseConfig = transform("my-server", canonicalConfig);
1515
+ * }
1516
+ * ```
1517
+ */
319
1518
  declare function getTransform(providerId: string): ((name: string, config: McpServerConfig) => unknown) | undefined;
320
1519
 
321
1520
  /**
@@ -325,15 +1524,87 @@ declare function getTransform(providerId: string): ((name: string, config: McpSe
325
1524
  * Provides the programmatic API that CLI commands delegate to.
326
1525
  */
327
1526
 
328
- /** Resolve the config file path for a provider and scope */
1527
+ /**
1528
+ * Resolve the absolute config file path for a provider and scope.
1529
+ *
1530
+ * For project scope, joins the project directory with the provider's relative
1531
+ * config path. For global scope, returns the provider's global config path.
1532
+ *
1533
+ * @param provider - Provider to resolve config path for
1534
+ * @param scope - Whether to resolve project or global config path
1535
+ * @param projectDir - Project directory (defaults to `process.cwd()`)
1536
+ * @returns Absolute config file path, or `null` if the provider does not support the given scope
1537
+ *
1538
+ * @example
1539
+ * ```typescript
1540
+ * const path = resolveConfigPath(provider, "project", "/home/user/my-project");
1541
+ * // "/home/user/my-project/.claude/settings.json"
1542
+ * ```
1543
+ */
329
1544
  declare function resolveConfigPath(provider: Provider, scope: "project" | "global", projectDir?: string): string | null;
330
- /** List MCP servers configured for a single provider */
1545
+ /**
1546
+ * List MCP servers configured for a single provider.
1547
+ *
1548
+ * Reads the provider's config file, extracts the MCP servers section using the
1549
+ * provider's `configKey`, and returns each server entry with metadata.
1550
+ *
1551
+ * @param provider - Provider whose config file to read
1552
+ * @param scope - Whether to read project or global config
1553
+ * @param projectDir - Project directory (defaults to `process.cwd()`)
1554
+ * @returns Array of MCP server entries found in the config file
1555
+ *
1556
+ * @example
1557
+ * ```typescript
1558
+ * const servers = await listMcpServers(provider, "project");
1559
+ * for (const s of servers) {
1560
+ * console.log(`${s.name} (${s.scope})`);
1561
+ * }
1562
+ * ```
1563
+ */
331
1564
  declare function listMcpServers(provider: Provider, scope: "project" | "global", projectDir?: string): Promise<McpServerEntry[]>;
332
- /** List MCP servers across all given providers, deduplicating by config path */
1565
+ /**
1566
+ * List MCP servers across all given providers, deduplicating by config path.
1567
+ *
1568
+ * Multiple providers may share the same config file. This function ensures each
1569
+ * config file is read only once to avoid duplicate entries.
1570
+ *
1571
+ * @param providers - Array of providers to query
1572
+ * @param scope - Whether to read project or global config
1573
+ * @param projectDir - Project directory (defaults to `process.cwd()`)
1574
+ * @returns Combined array of MCP server entries from all providers
1575
+ *
1576
+ * @example
1577
+ * ```typescript
1578
+ * const allServers = await listAllMcpServers(getInstalledProviders(), "global");
1579
+ * ```
1580
+ */
333
1581
  declare function listAllMcpServers(providers: Provider[], scope: "project" | "global", projectDir?: string): Promise<McpServerEntry[]>;
334
- /** Remove an MCP server entry from a provider's config file */
1582
+ /**
1583
+ * Remove an MCP server entry from a provider's config file.
1584
+ *
1585
+ * @param provider - Provider whose config file to modify
1586
+ * @param serverName - Name/key of the MCP server to remove
1587
+ * @param scope - Whether to modify project or global config
1588
+ * @param projectDir - Project directory (defaults to `process.cwd()`)
1589
+ * @returns `true` if the entry was removed, `false` if no config path exists
1590
+ *
1591
+ * @example
1592
+ * ```typescript
1593
+ * const removed = await removeMcpServer(provider, "my-server", "project");
1594
+ * ```
1595
+ */
335
1596
  declare function removeMcpServer(provider: Provider, serverName: string, scope: "project" | "global", projectDir?: string): Promise<boolean>;
336
1597
 
1598
+ /**
1599
+ * Shared lock file utilities
1600
+ *
1601
+ * Single source of truth for reading/writing ~/.agents/.caamp-lock.json.
1602
+ * Both MCP and skills lock modules import from here.
1603
+ */
1604
+
1605
+ /** Read the lock file */
1606
+ declare function readLockFile(): Promise<CaampLockFile>;
1607
+
337
1608
  /**
338
1609
  * MCP lock file management
339
1610
  *
@@ -341,17 +1612,74 @@ declare function removeMcpServer(provider: Provider, serverName: string, scope:
341
1612
  * Stored at ~/.agents/.caamp-lock.json (shared with skills lock).
342
1613
  */
343
1614
 
344
- /** Read the lock file */
345
- declare function readLockFile(): Promise<CaampLockFile>;
346
- /** Record an MCP server installation */
1615
+ /**
1616
+ * Record an MCP server installation in the lock file.
1617
+ *
1618
+ * Creates or updates an entry in `lock.mcpServers`. If the server already exists,
1619
+ * the agent list is merged and `updatedAt` is refreshed while `installedAt` is preserved.
1620
+ *
1621
+ * @param serverName - Name/key of the MCP server
1622
+ * @param source - Original source string
1623
+ * @param sourceType - Classified source type
1624
+ * @param agents - Provider IDs the server was installed to
1625
+ * @param isGlobal - Whether this is a global installation
1626
+ *
1627
+ * @example
1628
+ * ```typescript
1629
+ * await recordMcpInstall("filesystem", "@mcp/server-fs", "package", ["claude-code"], true);
1630
+ * ```
1631
+ */
347
1632
  declare function recordMcpInstall(serverName: string, source: string, sourceType: SourceType, agents: string[], isGlobal: boolean): Promise<void>;
348
- /** Remove an MCP server from the lock file */
1633
+ /**
1634
+ * Remove an MCP server entry from the lock file.
1635
+ *
1636
+ * @param serverName - Name/key of the MCP server to remove
1637
+ * @returns `true` if the entry was found and removed, `false` if not found
1638
+ *
1639
+ * @example
1640
+ * ```typescript
1641
+ * const removed = await removeMcpFromLock("filesystem");
1642
+ * ```
1643
+ */
349
1644
  declare function removeMcpFromLock(serverName: string): Promise<boolean>;
350
- /** Get all tracked MCP servers */
1645
+ /**
1646
+ * Get all MCP servers tracked in the lock file.
1647
+ *
1648
+ * @returns Record of server name to lock entry
1649
+ *
1650
+ * @example
1651
+ * ```typescript
1652
+ * const servers = await getTrackedMcpServers();
1653
+ * for (const [name, entry] of Object.entries(servers)) {
1654
+ * console.log(`${name}: installed ${entry.installedAt}`);
1655
+ * }
1656
+ * ```
1657
+ */
351
1658
  declare function getTrackedMcpServers(): Promise<Record<string, LockEntry>>;
352
- /** Save last selected agents for UX */
1659
+ /**
1660
+ * Save the last selected agent IDs to the lock file for UX persistence.
1661
+ *
1662
+ * Used to remember the user's agent selection between CLI invocations.
1663
+ *
1664
+ * @param agents - Array of provider IDs to remember
1665
+ *
1666
+ * @example
1667
+ * ```typescript
1668
+ * await saveLastSelectedAgents(["claude-code", "cursor"]);
1669
+ * ```
1670
+ */
353
1671
  declare function saveLastSelectedAgents(agents: string[]): Promise<void>;
354
- /** Get last selected agents */
1672
+ /**
1673
+ * Retrieve the last selected agent IDs from the lock file.
1674
+ *
1675
+ * @returns Array of provider IDs, or `undefined` if none were saved
1676
+ *
1677
+ * @example
1678
+ * ```typescript
1679
+ * const agents = await getLastSelectedAgents();
1680
+ * // ["claude-code", "cursor"] or undefined
1681
+ * ```
1682
+ */
355
1683
  declare function getLastSelectedAgents(): Promise<string[] | undefined>;
356
1684
 
357
1685
  /**
@@ -360,13 +1688,75 @@ declare function getLastSelectedAgents(): Promise<string[] | undefined>;
360
1688
  * Shares the same lock file as MCP (~/.agents/.caamp-lock.json).
361
1689
  */
362
1690
 
363
- /** Record a skill installation */
1691
+ /**
1692
+ * Record a skill installation in the lock file.
1693
+ *
1694
+ * Creates or updates an entry in `lock.skills`. If the skill already exists,
1695
+ * the agent list is merged and `updatedAt` is refreshed while `installedAt` is preserved.
1696
+ *
1697
+ * @param skillName - Skill name
1698
+ * @param scopedName - Scoped name (may include marketplace scope)
1699
+ * @param source - Original source string
1700
+ * @param sourceType - Classified source type
1701
+ * @param agents - Provider IDs the skill was linked to
1702
+ * @param canonicalPath - Absolute path to the canonical installation
1703
+ * @param isGlobal - Whether this is a global installation
1704
+ * @param projectDir - Project directory (for project-scoped installs)
1705
+ * @param version - Version string or commit SHA
1706
+ *
1707
+ * @example
1708
+ * ```typescript
1709
+ * await recordSkillInstall(
1710
+ * "my-skill", "my-skill", "owner/repo", "github",
1711
+ * ["claude-code"], "/home/user/.agents/skills/my-skill", true,
1712
+ * );
1713
+ * ```
1714
+ */
364
1715
  declare function recordSkillInstall(skillName: string, scopedName: string, source: string, sourceType: SourceType, agents: string[], canonicalPath: string, isGlobal: boolean, projectDir?: string, version?: string): Promise<void>;
365
- /** Remove a skill from the lock file */
1716
+ /**
1717
+ * Remove a skill entry from the lock file.
1718
+ *
1719
+ * @param skillName - Name of the skill to remove
1720
+ * @returns `true` if the entry was found and removed, `false` if not found
1721
+ *
1722
+ * @example
1723
+ * ```typescript
1724
+ * const removed = await removeSkillFromLock("my-skill");
1725
+ * ```
1726
+ */
366
1727
  declare function removeSkillFromLock(skillName: string): Promise<boolean>;
367
- /** Get all tracked skills */
1728
+ /**
1729
+ * Get all skills tracked in the lock file.
1730
+ *
1731
+ * @returns Record of skill name to lock entry
1732
+ *
1733
+ * @example
1734
+ * ```typescript
1735
+ * const skills = await getTrackedSkills();
1736
+ * for (const [name, entry] of Object.entries(skills)) {
1737
+ * console.log(`${name}: ${entry.source}`);
1738
+ * }
1739
+ * ```
1740
+ */
368
1741
  declare function getTrackedSkills(): Promise<Record<string, LockEntry>>;
369
- /** Check if a skill has updates available (comparing version/hash) */
1742
+ /**
1743
+ * Check if a skill has updates available by comparing the installed version
1744
+ * against the latest remote commit SHA.
1745
+ *
1746
+ * Only supports GitHub and GitLab sources. Returns `"unknown"` for local,
1747
+ * package, or other source types.
1748
+ *
1749
+ * @param skillName - Name of the installed skill to check
1750
+ * @returns Object with update status, current version, and latest version
1751
+ *
1752
+ * @example
1753
+ * ```typescript
1754
+ * const update = await checkSkillUpdate("my-skill");
1755
+ * if (update.hasUpdate) {
1756
+ * console.log(`Update available: ${update.currentVersion} -> ${update.latestVersion}`);
1757
+ * }
1758
+ * ```
1759
+ */
370
1760
  declare function checkSkillUpdate(skillName: string): Promise<{
371
1761
  hasUpdate: boolean;
372
1762
  currentVersion?: string;
@@ -374,26 +1764,6 @@ declare function checkSkillUpdate(skillName: string): Promise<{
374
1764
  status: "up-to-date" | "update-available" | "unknown";
375
1765
  }>;
376
1766
 
377
- /**
378
- * Marketplace types shared between adapters
379
- */
380
- interface MarketplaceAdapter {
381
- name: string;
382
- search(query: string, limit?: number): Promise<MarketplaceResult[]>;
383
- getSkill(scopedName: string): Promise<MarketplaceResult | null>;
384
- }
385
- interface MarketplaceResult {
386
- name: string;
387
- scopedName: string;
388
- description: string;
389
- author: string;
390
- stars: number;
391
- githubUrl: string;
392
- repoFullName: string;
393
- path: string;
394
- source: string;
395
- }
396
-
397
1767
  /**
398
1768
  * Unified marketplace client
399
1769
  *
@@ -401,12 +1771,68 @@ interface MarketplaceResult {
401
1771
  * deduplicates, and sorts by relevance.
402
1772
  */
403
1773
 
1774
+ /**
1775
+ * Unified marketplace client that aggregates results from multiple marketplace adapters.
1776
+ *
1777
+ * Queries all configured marketplaces in parallel, deduplicates results by scoped name,
1778
+ * and sorts by star count.
1779
+ *
1780
+ * @example
1781
+ * ```typescript
1782
+ * const client = new MarketplaceClient();
1783
+ * const results = await client.search("filesystem");
1784
+ * for (const r of results) {
1785
+ * console.log(`${r.scopedName} (${r.stars} stars)`);
1786
+ * }
1787
+ * ```
1788
+ */
404
1789
  declare class MarketplaceClient {
405
1790
  private adapters;
1791
+ /**
1792
+ * Create a new marketplace client.
1793
+ *
1794
+ * @param adapters - Custom marketplace adapters (defaults to agentskills.in and skills.sh)
1795
+ *
1796
+ * @example
1797
+ * ```typescript
1798
+ * // Use default adapters
1799
+ * const client = new MarketplaceClient();
1800
+ *
1801
+ * // Use custom adapters
1802
+ * const client = new MarketplaceClient([myAdapter]);
1803
+ * ```
1804
+ */
406
1805
  constructor(adapters?: MarketplaceAdapter[]);
407
- /** Search all marketplaces and deduplicate results */
1806
+ /**
1807
+ * Search all marketplaces and return deduplicated, sorted results.
1808
+ *
1809
+ * Queries all adapters in parallel and deduplicates by `scopedName`,
1810
+ * keeping the entry with the highest star count. Results are sorted by
1811
+ * stars descending.
1812
+ *
1813
+ * @param query - Search query string
1814
+ * @param limit - Maximum number of results to return (default: 20)
1815
+ * @returns Deduplicated and sorted marketplace results
1816
+ *
1817
+ * @example
1818
+ * ```typescript
1819
+ * const results = await client.search("code review", 10);
1820
+ * ```
1821
+ */
408
1822
  search(query: string, limit?: number): Promise<MarketplaceResult[]>;
409
- /** Get a specific skill by scoped name */
1823
+ /**
1824
+ * Get a specific skill by its scoped name from any marketplace.
1825
+ *
1826
+ * Tries each adapter in order and returns the first match.
1827
+ *
1828
+ * @param scopedName - Scoped skill name (e.g. `"@author/my-skill"`)
1829
+ * @returns The marketplace result, or `null` if not found in any marketplace
1830
+ *
1831
+ * @example
1832
+ * ```typescript
1833
+ * const skill = await client.getSkill("@anthropic/memory");
1834
+ * ```
1835
+ */
410
1836
  getSkill(scopedName: string): Promise<MarketplaceResult | null>;
411
1837
  }
412
1838
 
@@ -417,15 +1843,99 @@ declare class MarketplaceClient {
417
1843
  * (CLAUDE.md, AGENTS.md, GEMINI.md).
418
1844
  */
419
1845
 
420
- /** Check if a file has a CAAMP injection block */
1846
+ /**
1847
+ * Check the status of a CAAMP injection block in an instruction file.
1848
+ *
1849
+ * Returns the injection status:
1850
+ * - `"missing"` - File does not exist
1851
+ * - `"none"` - File exists but has no CAAMP markers
1852
+ * - `"current"` - CAAMP block exists and matches expected content (or no expected content given)
1853
+ * - `"outdated"` - CAAMP block exists but differs from expected content
1854
+ *
1855
+ * @param filePath - Absolute path to the instruction file
1856
+ * @param expectedContent - Optional expected content to compare against
1857
+ * @returns The injection status
1858
+ *
1859
+ * @example
1860
+ * ```typescript
1861
+ * const status = await checkInjection("/project/CLAUDE.md", expectedContent);
1862
+ * if (status === "outdated") {
1863
+ * console.log("CAAMP injection needs updating");
1864
+ * }
1865
+ * ```
1866
+ */
421
1867
  declare function checkInjection(filePath: string, expectedContent?: string): Promise<InjectionStatus>;
422
- /** Inject content into a file */
1868
+ /**
1869
+ * Inject content into an instruction file between CAAMP markers.
1870
+ *
1871
+ * Behavior depends on the file state:
1872
+ * - File does not exist: creates the file with the injection block
1873
+ * - File exists without markers: prepends the injection block
1874
+ * - File exists with markers: replaces the existing injection block
1875
+ *
1876
+ * @param filePath - Absolute path to the instruction file
1877
+ * @param content - Content to inject between CAAMP markers
1878
+ * @returns Action taken: `"created"`, `"added"`, or `"updated"`
1879
+ *
1880
+ * @example
1881
+ * ```typescript
1882
+ * const action = await inject("/project/CLAUDE.md", "## My Config\nSome content");
1883
+ * console.log(`File ${action}`);
1884
+ * ```
1885
+ */
423
1886
  declare function inject(filePath: string, content: string): Promise<"created" | "added" | "updated">;
424
- /** Remove the CAAMP injection block from a file */
1887
+ /**
1888
+ * Remove the CAAMP injection block from an instruction file.
1889
+ *
1890
+ * If removing the block would leave the file empty, the file is deleted entirely.
1891
+ *
1892
+ * @param filePath - Absolute path to the instruction file
1893
+ * @returns `true` if a CAAMP block was found and removed, `false` otherwise
1894
+ *
1895
+ * @example
1896
+ * ```typescript
1897
+ * const removed = await removeInjection("/project/CLAUDE.md");
1898
+ * ```
1899
+ */
425
1900
  declare function removeInjection(filePath: string): Promise<boolean>;
426
- /** Check injection status across all providers' instruction files */
1901
+ /**
1902
+ * Check injection status across all providers' instruction files.
1903
+ *
1904
+ * Deduplicates by file path since multiple providers may share the same
1905
+ * instruction file (e.g. many providers use `AGENTS.md`).
1906
+ *
1907
+ * @param providers - Array of providers to check
1908
+ * @param projectDir - Absolute path to the project directory
1909
+ * @param scope - Whether to check project or global instruction files
1910
+ * @param expectedContent - Optional expected content to compare against
1911
+ * @returns Array of injection check results, one per unique instruction file
1912
+ *
1913
+ * @example
1914
+ * ```typescript
1915
+ * const results = await checkAllInjections(providers, "/project", "project");
1916
+ * const outdated = results.filter(r => r.status === "outdated");
1917
+ * ```
1918
+ */
427
1919
  declare function checkAllInjections(providers: Provider[], projectDir: string, scope: "project" | "global", expectedContent?: string): Promise<InjectionCheckResult[]>;
428
- /** Inject content into all providers' instruction files */
1920
+ /**
1921
+ * Inject content into all providers' instruction files.
1922
+ *
1923
+ * Deduplicates by file path to avoid injecting the same file multiple times.
1924
+ *
1925
+ * @param providers - Array of providers to inject into
1926
+ * @param projectDir - Absolute path to the project directory
1927
+ * @param scope - Whether to target project or global instruction files
1928
+ * @param content - Content to inject between CAAMP markers
1929
+ * @returns Map of file path to action taken (`"created"`, `"added"`, or `"updated"`)
1930
+ *
1931
+ * @example
1932
+ * ```typescript
1933
+ * const results = await injectAll(providers, "/project", "project", content);
1934
+ * for (const [file, action] of results) {
1935
+ * console.log(`${file}: ${action}`);
1936
+ * }
1937
+ * ```
1938
+ */
429
1939
  declare function injectAll(providers: Provider[], projectDir: string, scope: "project" | "global", content: string): Promise<Map<string, "created" | "added" | "updated">>;
430
1940
 
431
1941
  /**
@@ -434,33 +1944,207 @@ declare function injectAll(providers: Provider[], projectDir: string, scope: "pr
434
1944
  * Generates injection content based on provider capabilities.
435
1945
  */
436
1946
 
437
- /** Generate a standard CAAMP injection block */
1947
+ /**
1948
+ * Generate a standard CAAMP injection block for instruction files.
1949
+ *
1950
+ * Produces markdown content suitable for injection between CAAMP markers.
1951
+ * Optionally includes MCP server and custom content sections.
1952
+ *
1953
+ * @param options - Optional configuration for the generated content
1954
+ * @param options.mcpServerName - MCP server name to include a server section
1955
+ * @param options.customContent - Additional custom markdown content to append
1956
+ * @returns Generated markdown string
1957
+ *
1958
+ * @example
1959
+ * ```typescript
1960
+ * const content = generateInjectionContent({ mcpServerName: "filesystem" });
1961
+ * ```
1962
+ */
438
1963
  declare function generateInjectionContent(options?: {
439
1964
  mcpServerName?: string;
440
1965
  customContent?: string;
441
1966
  }): string;
442
- /** Group providers by instruction file */
1967
+ /**
1968
+ * Group providers by their instruction file name.
1969
+ *
1970
+ * Useful for determining which providers share the same instruction file
1971
+ * (e.g. multiple providers using `AGENTS.md`).
1972
+ *
1973
+ * @param providers - Array of providers to group
1974
+ * @returns Map from instruction file name to array of providers using that file
1975
+ *
1976
+ * @example
1977
+ * ```typescript
1978
+ * const groups = groupByInstructFile(getAllProviders());
1979
+ * for (const [file, providers] of groups) {
1980
+ * console.log(`${file}: ${providers.map(p => p.id).join(", ")}`);
1981
+ * }
1982
+ * ```
1983
+ */
443
1984
  declare function groupByInstructFile(providers: Provider[]): Map<string, Provider[]>;
444
1985
 
445
1986
  /**
446
1987
  * Format utility functions
447
1988
  */
448
- /** Deep merge two objects, source wins on conflict */
1989
+ /**
1990
+ * Deep merge two objects, with `source` values winning on conflict.
1991
+ *
1992
+ * Recursively merges nested plain objects. Arrays and non-object values from
1993
+ * `source` overwrite `target` values.
1994
+ *
1995
+ * @param target - Base object to merge into
1996
+ * @param source - Object with values that take precedence
1997
+ * @returns A new merged object (does not mutate inputs)
1998
+ *
1999
+ * @example
2000
+ * ```typescript
2001
+ * deepMerge({ a: 1, b: { c: 2 } }, { b: { d: 3 } });
2002
+ * // { a: 1, b: { c: 2, d: 3 } }
2003
+ * ```
2004
+ */
449
2005
  declare function deepMerge(target: Record<string, unknown>, source: Record<string, unknown>): Record<string, unknown>;
450
- /** Get a nested value using dot-notation key path */
2006
+ /**
2007
+ * Get a nested value from an object using a dot-notation key path.
2008
+ *
2009
+ * @param obj - Object to traverse
2010
+ * @param keyPath - Dot-separated key path (e.g. `"mcpServers"` or `"a.b.c"`)
2011
+ * @returns The value at the key path, or `undefined` if not found
2012
+ *
2013
+ * @example
2014
+ * ```typescript
2015
+ * getNestedValue({ a: { b: { c: 42 } } }, "a.b.c"); // 42
2016
+ * getNestedValue({ a: 1 }, "a.b"); // undefined
2017
+ * ```
2018
+ */
451
2019
  declare function getNestedValue(obj: Record<string, unknown>, keyPath: string): unknown;
452
- /** Ensure parent directories exist */
2020
+ /**
2021
+ * Ensure that the parent directories of a file path exist.
2022
+ *
2023
+ * Creates directories recursively if they do not exist.
2024
+ *
2025
+ * @param filePath - Absolute path to a file (parent directories will be created)
2026
+ *
2027
+ * @example
2028
+ * ```typescript
2029
+ * await ensureDir("/path/to/new/dir/file.json");
2030
+ * // /path/to/new/dir/ now exists
2031
+ * ```
2032
+ */
453
2033
  declare function ensureDir(filePath: string): Promise<void>;
454
2034
 
455
2035
  /**
456
2036
  * Format router - dispatches config reads/writes to format-specific handlers
457
2037
  */
458
2038
 
459
- /** Read a config file in the specified format */
2039
+ /**
2040
+ * Read and parse a config file in the specified format.
2041
+ *
2042
+ * Dispatches to the appropriate format handler (JSON/JSONC, YAML, or TOML).
2043
+ *
2044
+ * @param filePath - Absolute path to the config file
2045
+ * @param format - Config file format
2046
+ * @returns Parsed config object
2047
+ * @throws If the file cannot be read or the format is unsupported
2048
+ *
2049
+ * @example
2050
+ * ```typescript
2051
+ * const config = await readConfig("/path/to/config.json", "jsonc");
2052
+ * ```
2053
+ */
460
2054
  declare function readConfig(filePath: string, format: ConfigFormat): Promise<Record<string, unknown>>;
461
- /** Write a config file in the specified format, preserving existing content */
2055
+ /**
2056
+ * Write a server entry to a config file, preserving existing content.
2057
+ *
2058
+ * Dispatches to the appropriate format handler. For JSONC files, comments are
2059
+ * preserved using `jsonc-parser`.
2060
+ *
2061
+ * @param filePath - Absolute path to the config file
2062
+ * @param format - Config file format
2063
+ * @param key - Dot-notation key path to the servers section (e.g. `"mcpServers"`)
2064
+ * @param serverName - Name/key for the server entry
2065
+ * @param serverConfig - Server configuration object to write
2066
+ * @throws If the format is unsupported
2067
+ *
2068
+ * @example
2069
+ * ```typescript
2070
+ * await writeConfig("/path/to/config.json", "jsonc", "mcpServers", "my-server", config);
2071
+ * ```
2072
+ */
462
2073
  declare function writeConfig(filePath: string, format: ConfigFormat, key: string, serverName: string, serverConfig: unknown): Promise<void>;
463
- /** Remove a server entry from a config file in the specified format */
2074
+ /**
2075
+ * Remove a server entry from a config file in the specified format.
2076
+ *
2077
+ * @param filePath - Absolute path to the config file
2078
+ * @param format - Config file format
2079
+ * @param key - Dot-notation key path to the servers section
2080
+ * @param serverName - Name/key of the server entry to remove
2081
+ * @returns `true` if the entry was removed, `false` otherwise
2082
+ * @throws If the format is unsupported
2083
+ *
2084
+ * @example
2085
+ * ```typescript
2086
+ * const removed = await removeConfig("/path/to/config.json", "jsonc", "mcpServers", "my-server");
2087
+ * ```
2088
+ */
464
2089
  declare function removeConfig(filePath: string, format: ConfigFormat, key: string, serverName: string): Promise<boolean>;
465
2090
 
466
- export { type AuditFinding, type AuditResult, type AuditRule, type AuditSeverity, type CaampLockFile, type ConfigFormat, type DetectionResult, type GlobalOptions, type InjectionCheckResult, type InjectionStatus, type InstallResult, type LockEntry, MarketplaceClient, type MarketplaceSearchResult, type MarketplaceSkill, type McpServerConfig, type McpServerEntry, type ParsedSource, type Provider, type SkillEntry, type SkillInstallResult, type SkillMetadata, type SourceType, type TransportType, type ValidationIssue, type ValidationResult, buildServerConfig, checkAllInjections, checkInjection, checkSkillUpdate, deepMerge, detectAllProviders, detectProjectProviders, detectProvider, discoverSkill, discoverSkills, ensureDir, generateInjectionContent, getAllProviders, getInstalledProviders, getInstructionFiles, getLastSelectedAgents, getNestedValue, getProvider, getProviderCount, getProvidersByInstructFile, getProvidersByPriority, getProvidersByStatus, getRegistryVersion, getTrackedMcpServers, getTrackedSkills, getTransform, groupByInstructFile, inject, injectAll, installMcpServer, installMcpServerToAll, installSkill, isMarketplaceScoped, listAllMcpServers, listCanonicalSkills, listMcpServers, parseSkillFile, parseSource, readConfig, readLockFile, recordMcpInstall, recordSkillInstall, removeConfig, removeInjection, removeMcpFromLock, removeMcpServer, removeSkill, removeSkillFromLock, resolveAlias, resolveConfigPath, saveLastSelectedAgents, scanDirectory, scanFile, toSarif, validateSkill, writeConfig };
2091
+ /**
2092
+ * Simple logger with verbose/quiet mode support.
2093
+ *
2094
+ * - verbose: enables debug output to stderr
2095
+ * - quiet: suppresses info and warn output (errors always shown)
2096
+ */
2097
+ /**
2098
+ * Enable or disable verbose (debug) logging mode.
2099
+ *
2100
+ * When enabled, debug messages are written to stderr.
2101
+ *
2102
+ * @param v - `true` to enable verbose mode, `false` to disable
2103
+ *
2104
+ * @example
2105
+ * ```typescript
2106
+ * setVerbose(true);
2107
+ * ```
2108
+ */
2109
+ declare function setVerbose(v: boolean): void;
2110
+ /**
2111
+ * Enable or disable quiet mode.
2112
+ *
2113
+ * When enabled, info and warning messages are suppressed. Errors are always shown.
2114
+ *
2115
+ * @param q - `true` to enable quiet mode, `false` to disable
2116
+ *
2117
+ * @example
2118
+ * ```typescript
2119
+ * setQuiet(true);
2120
+ * ```
2121
+ */
2122
+ declare function setQuiet(q: boolean): void;
2123
+ /**
2124
+ * Check if verbose (debug) logging is currently enabled.
2125
+ *
2126
+ * @returns `true` if verbose mode is active
2127
+ *
2128
+ * @example
2129
+ * ```typescript
2130
+ * if (isVerbose()) {
2131
+ * console.error("Extra debug info");
2132
+ * }
2133
+ * ```
2134
+ */
2135
+ declare function isVerbose(): boolean;
2136
+ /**
2137
+ * Check if quiet mode is currently enabled.
2138
+ *
2139
+ * @returns `true` if quiet mode is active
2140
+ *
2141
+ * @example
2142
+ * ```typescript
2143
+ * if (!isQuiet()) {
2144
+ * console.log("Status message");
2145
+ * }
2146
+ * ```
2147
+ */
2148
+ declare function isQuiet(): boolean;
2149
+
2150
+ export { type AuditFinding, type AuditResult, type AuditRule, type AuditSeverity, type BatchInstallOptions, type BatchInstallResult, type CaampLockFile, type ConfigFormat, type ConflictPolicy, type DetectionResult, type DualScopeConfigureOptions, type DualScopeConfigureResult, type GlobalOptions, type InjectionCheckResult, type InjectionStatus, type InstallResult, type InstructionUpdateSummary, type LockEntry, MarketplaceClient, type MarketplaceResult, type MarketplaceSearchResult, type MarketplaceSkill, type McpBatchOperation, type McpConflict, type McpConflictCode, type McpPlanApplyResult, type McpServerConfig, type McpServerEntry, type NormalizedRecommendationCriteria, type ParsedSource, type Provider, type ProviderPriority, type ProviderStatus, RECOMMENDATION_ERROR_CODES, type RankedSkillRecommendation, type RecommendSkillsResult, type RecommendationCriteriaInput, type RecommendationErrorCode, type RecommendationOptions, type RecommendationReason, type RecommendationReasonCode, type RecommendationScoreBreakdown, type RecommendationValidationIssue, type RecommendationValidationResult, type RecommendationWeights, type SkillBatchOperation, type SkillEntry, type SkillInstallResult, type SkillMetadata, type SourceType, type TransportType, type ValidationIssue, type ValidationResult, applyMcpInstallWithPolicy, buildServerConfig, checkAllInjections, checkInjection, checkSkillUpdate, configureProviderGlobalAndProject, deepMerge, detectAllProviders, detectMcpConfigConflicts, detectProjectProviders, detectProvider, discoverSkill, discoverSkills, ensureDir, formatSkillRecommendations, generateInjectionContent, getAllProviders, getInstalledProviders, getInstructionFiles, getLastSelectedAgents, getNestedValue, getProvider, getProviderCount, getProvidersByInstructFile, getProvidersByPriority, getProvidersByStatus, getRegistryVersion, getTrackedMcpServers, getTrackedSkills, getTransform, groupByInstructFile, inject, injectAll, installBatchWithRollback, installMcpServer, installMcpServerToAll, installSkill, isMarketplaceScoped, isQuiet, isVerbose, listAllMcpServers, listCanonicalSkills, listMcpServers, normalizeRecommendationCriteria, parseSkillFile, parseSource, rankSkills, readConfig, readLockFile, recommendSkills, recordMcpInstall, recordSkillInstall, removeConfig, removeInjection, removeMcpFromLock, removeMcpServer, removeSkill, removeSkillFromLock, resolveAlias, resolveConfigPath, saveLastSelectedAgents, scanDirectory, scanFile, scoreSkillRecommendation, searchSkills, selectProvidersByMinimumPriority, setQuiet, setVerbose, toSarif, tokenizeCriteriaValue, updateInstructionsSingleOperation, validateRecommendationCriteria, validateSkill, writeConfig };