agentloom 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,15 +1,16 @@
1
1
  # agentloom
2
2
 
3
- `agentloom` is a unified CLI for managing agent definitions and MCP configuration across multiple AI coding tools.
3
+ `agentloom` is a unified CLI for managing agent definitions and MCP configuration across multiple AI coding tools — Cursor, Claude, Copilot, Codex, OpenCode, Gemini, and Pi.
4
4
 
5
- It uses `.agents` as the canonical source of truth and syncs provider-native files for:
5
+ For monorepo-level documentation and architecture context, see the [root README](../../README.md).
6
6
 
7
- - Cursor
8
- - Claude
9
- - Codex
10
- - OpenCode
11
- - Gemini
12
- - Copilot
7
+ ## Getting started
8
+
9
+ ```bash
10
+ npx agentloom init
11
+ ```
12
+
13
+ That's all you need. Agentloom picks up your existing provider configs, migrates them into a unified `.agents/` directory, and syncs everything back out to all your tools. From here on, manage your agents, commands, skills, and MCP servers in one place and run `agentloom sync` whenever you make changes.
13
14
 
14
15
  ## Install
15
16
 
@@ -54,6 +55,7 @@ Global scope uses `~/.agents` with the same file layout.
54
55
  - `agentloom add <source>`
55
56
  - `agentloom find <query>`
56
57
  - `agentloom update [source]`
58
+ - `agentloom upgrade`
57
59
  - `agentloom sync`
58
60
  - `agentloom delete <source|name>`
59
61
 
@@ -117,6 +119,7 @@ agentloom --help
117
119
  agentloom find --help
118
120
  agentloom add --help
119
121
  agentloom update --help
122
+ agentloom upgrade --help
120
123
  agentloom sync --help
121
124
  agentloom delete --help
122
125
  agentloom agent --help
@@ -130,12 +133,16 @@ agentloom mcp server --help
130
133
 
131
134
  ### Version update notice
132
135
 
133
- `agentloom` now performs a best-effort npm version check and shows an update hint when a newer release is available.
136
+ `agentloom` performs best-effort npm version checks and upgrades when a newer release is available.
134
137
 
135
- - check is cached (`~/.agents/.agentloom-version-cache.json`)
136
- - check runs at most once every 12 hours
137
- - check is skipped in non-interactive sessions
138
- - disable via:
138
+ - checks are cached (`~/.agents/.agentloom-version-cache.json`)
139
+ - check/upgrade attempts run at most once every 2 hours per detected version
140
+ - in interactive TTY sessions, agentloom asks before upgrading
141
+ - in non-interactive sessions, upgrades run without prompts
142
+ - after an approved upgrade, the original command is re-run automatically
143
+ - if running from `npx`, auto-upgrade re-runs with `npx agentloom@<latest>`
144
+ - manual upgrade command: `agentloom upgrade`
145
+ - disable auto checks via:
139
146
 
140
147
  ```bash
141
148
  AGENTLOOM_DISABLE_UPDATE_NOTIFIER=1
package/dist/cli.js CHANGED
@@ -5,9 +5,11 @@ import { runAddCommand } from "./commands/add.js";
5
5
  import { runCommandCommand } from "./commands/command.js";
6
6
  import { runDeleteCommand } from "./commands/delete.js";
7
7
  import { runFindCommand } from "./commands/find.js";
8
+ import { runInitCommand } from "./commands/init.js";
8
9
  import { runMcpCommand } from "./commands/mcp.js";
9
10
  import { runSkillCommand } from "./commands/skills.js";
10
11
  import { runSyncCommand } from "./commands/sync.js";
12
+ import { runUpgradeCommand } from "./commands/upgrade.js";
11
13
  import { runUpdateCommand } from "./commands/update.js";
12
14
  import { formatUnknownCommandError, getRootHelpText } from "./core/copy.js";
13
15
  import { maybePromptManageAgentsBootstrap } from "./core/manage-agents-bootstrap.js";
@@ -35,23 +37,24 @@ export async function runCli(argv) {
35
37
  }
36
38
  const parsed = parseArgs(argv);
37
39
  const cwd = process.cwd();
38
- const shouldBootstrapManageAgents = await maybePromptManageAgentsBootstrap({
39
- command,
40
- help: Boolean(parsed.help),
41
- yes: Boolean(parsed.yes),
42
- cwd,
43
- });
44
40
  const route = parseCommandRoute(argv);
45
41
  if (!parsed.help) {
46
42
  await maybeNotifyVersionUpdate({
47
43
  command,
44
+ argv,
48
45
  currentVersion: version,
49
46
  });
50
47
  }
51
48
  if (!route) {
52
49
  throw new Error(formatUnknownCommandError(command));
53
50
  }
54
- await runRoutedCommand(route, parsed, cwd, command);
51
+ const shouldBootstrapManageAgents = await maybePromptManageAgentsBootstrap({
52
+ command,
53
+ help: Boolean(parsed.help),
54
+ yes: Boolean(parsed.yes),
55
+ cwd,
56
+ });
57
+ await runRoutedCommand(route, parsed, cwd, command, version);
55
58
  if (shouldBootstrapManageAgents) {
56
59
  const bootstrapArgs = buildManageAgentsBootstrapArgs(parsed, cwd);
57
60
  await runSkillCommand(parseArgs(bootstrapArgs), cwd);
@@ -60,7 +63,7 @@ export async function runCli(argv) {
60
63
  function printHelp() {
61
64
  console.log(getRootHelpText());
62
65
  }
63
- async function runRoutedCommand(route, parsed, cwd, command) {
66
+ async function runRoutedCommand(route, parsed, cwd, command, version) {
64
67
  if (!route) {
65
68
  throw new Error(formatUnknownCommandError(command));
66
69
  }
@@ -75,12 +78,18 @@ async function runRoutedCommand(route, parsed, cwd, command) {
75
78
  case "update":
76
79
  await runUpdateCommand(parsed, cwd);
77
80
  return;
81
+ case "upgrade":
82
+ await runUpgradeCommand(parsed, version);
83
+ return;
78
84
  case "sync":
79
85
  await runSyncCommand(parsed, cwd);
80
86
  return;
81
87
  case "delete":
82
88
  await runDeleteCommand(parsed, cwd);
83
89
  return;
90
+ case "init":
91
+ await runInitCommand(parsed, cwd);
92
+ return;
84
93
  default:
85
94
  throw new Error(formatUnknownCommandError(command));
86
95
  }
@@ -0,0 +1,2 @@
1
+ import type { ParsedArgs } from "minimist";
2
+ export declare function runInitCommand(argv: ParsedArgs, cwd: string): Promise<void>;
@@ -0,0 +1,14 @@
1
+ import { getInitHelpText } from "../core/copy.js";
2
+ import { runScopedSyncCommand } from "./sync.js";
3
+ export async function runInitCommand(argv, cwd) {
4
+ if (argv.help) {
5
+ console.log(getInitHelpText());
6
+ return;
7
+ }
8
+ await runScopedSyncCommand({
9
+ argv,
10
+ cwd,
11
+ target: "all",
12
+ skipSync: Boolean(argv["no-sync"]),
13
+ });
14
+ }
@@ -1,3 +1,4 @@
1
+ import { ALL_PROVIDERS } from "../types.js";
1
2
  import { getStringArrayFlag, parseProvidersFlag } from "../core/argv.js";
2
3
  import { formatUsageError, getMcpAddHelpText, getMcpDeleteHelpText, getMcpHelpText, getMcpListHelpText, getMcpServerHelpText, } from "../core/copy.js";
3
4
  import { readCanonicalMcp, writeCanonicalMcp } from "../core/mcp.js";
@@ -244,15 +245,7 @@ function runMcpAdd(paths, argv, name) {
244
245
  }
245
246
  else {
246
247
  const providerMap = {};
247
- const allProviders = [
248
- "cursor",
249
- "claude",
250
- "codex",
251
- "opencode",
252
- "gemini",
253
- "copilot",
254
- ];
255
- for (const provider of allProviders) {
248
+ for (const provider of ALL_PROVIDERS) {
256
249
  providerMap[provider] = providers.includes(provider)
257
250
  ? { ...baseConfig }
258
251
  : false;
@@ -1,12 +1,11 @@
1
1
  import path from "node:path";
2
- import { parseProvidersFlag } from "../core/argv.js";
3
2
  import { formatUsageError } from "../core/copy.js";
4
- import { applySkillProviderSideEffects, parseSkillsDir, } from "../core/skills.js";
5
- import { formatSyncSummary, resolveProvidersForSync, syncFromCanonical, } from "../sync/index.js";
3
+ import { parseSkillsDir } from "../core/skills.js";
6
4
  import { runScopedAddCommand } from "./add.js";
7
5
  import { runScopedDeleteCommand } from "./delete.js";
8
- import { getNonInteractiveMode, resolvePathsForCommand, } from "./entity-utils.js";
6
+ import { resolvePathsForCommand } from "./entity-utils.js";
9
7
  import { runScopedFindCommand } from "./find.js";
8
+ import { runScopedSyncCommand } from "./sync.js";
10
9
  import { runScopedUpdateCommand } from "./update.js";
11
10
  export async function runSkillCommand(argv, cwd) {
12
11
  const action = argv._[1];
@@ -79,29 +78,9 @@ export async function runSkillCommand(argv, cwd) {
79
78
  });
80
79
  return;
81
80
  }
82
- 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"]),
81
+ await runScopedSyncCommand({
82
+ argv,
83
+ cwd,
104
84
  target: "skill",
105
85
  });
106
- console.log(formatSyncSummary(summary, paths.agentsRoot));
107
86
  }
@@ -5,4 +5,5 @@ export declare function runScopedSyncCommand(options: {
5
5
  argv: ParsedArgs;
6
6
  cwd: string;
7
7
  target: EntityType | "all";
8
+ skipSync?: boolean;
8
9
  }): Promise<void>;
@@ -1,7 +1,11 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
1
4
  import { parseProvidersFlag } from "../core/argv.js";
2
5
  import { getSyncHelpText } from "../core/copy.js";
6
+ import { formatMigrationSummary, initializeCanonicalLayout, migrateProviderStateToCanonical, MigrationConflictError, } from "../core/migration.js";
3
7
  import { getNonInteractiveMode, resolvePathsForCommand, } from "./entity-utils.js";
4
- import { formatSyncSummary, syncFromCanonical } from "../sync/index.js";
8
+ import { formatSyncSummary, resolveProvidersForSync, syncFromCanonical, } from "../sync/index.js";
5
9
  export async function runSyncCommand(argv, cwd) {
6
10
  if (argv.help) {
7
11
  console.log(getSyncHelpText());
@@ -14,14 +18,81 @@ export async function runSyncCommand(argv, cwd) {
14
18
  });
15
19
  }
16
20
  export async function runScopedSyncCommand(options) {
17
- const paths = await resolvePathsForCommand(options.argv, options.cwd);
18
- const summary = await syncFromCanonical({
19
- paths,
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,
25
- });
26
- console.log(formatSyncSummary(summary, paths.agentsRoot));
21
+ const nonInteractive = getNonInteractiveMode(options.argv);
22
+ let cleanupDryRunPaths;
23
+ try {
24
+ const paths = await resolvePathsForCommand(options.argv, options.cwd);
25
+ const explicitProviders = parseProvidersFlag(options.argv.providers);
26
+ const providers = await resolveProvidersForSync({
27
+ paths,
28
+ explicitProviders,
29
+ nonInteractive,
30
+ });
31
+ const dryRun = Boolean(options.argv["dry-run"]);
32
+ const effectivePaths = dryRun
33
+ ? createDryRunCanonicalPaths(paths)
34
+ : { paths, cleanup: undefined };
35
+ cleanupDryRunPaths = effectivePaths.cleanup;
36
+ initializeCanonicalLayout(effectivePaths.paths, providers);
37
+ const migrationSummary = await migrateProviderStateToCanonical({
38
+ paths: effectivePaths.paths,
39
+ providers,
40
+ target: options.target,
41
+ yes: Boolean(options.argv.yes),
42
+ nonInteractive,
43
+ dryRun,
44
+ materializeCanonical: dryRun,
45
+ });
46
+ console.log(formatMigrationSummary(migrationSummary));
47
+ if (options.skipSync) {
48
+ return;
49
+ }
50
+ const syncSummary = await syncFromCanonical({
51
+ paths: effectivePaths.paths,
52
+ providers,
53
+ yes: Boolean(options.argv.yes),
54
+ nonInteractive,
55
+ dryRun,
56
+ target: options.target,
57
+ });
58
+ console.log("");
59
+ console.log(formatSyncSummary(syncSummary, paths.agentsRoot));
60
+ }
61
+ catch (error) {
62
+ if (error instanceof MigrationConflictError) {
63
+ console.error(error.message);
64
+ process.exit(2);
65
+ }
66
+ throw error;
67
+ }
68
+ finally {
69
+ cleanupDryRunPaths?.();
70
+ }
71
+ }
72
+ function createDryRunCanonicalPaths(paths) {
73
+ const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "agentloom-dry-run-"));
74
+ const tempAgentsRoot = path.join(tempRoot, ".agents");
75
+ if (fs.existsSync(paths.agentsRoot) &&
76
+ fs.statSync(paths.agentsRoot).isDirectory()) {
77
+ fs.cpSync(paths.agentsRoot, tempAgentsRoot, {
78
+ recursive: true,
79
+ force: true,
80
+ });
81
+ }
82
+ return {
83
+ paths: {
84
+ ...paths,
85
+ agentsRoot: tempAgentsRoot,
86
+ agentsDir: path.join(tempAgentsRoot, "agents"),
87
+ commandsDir: path.join(tempAgentsRoot, "commands"),
88
+ skillsDir: path.join(tempAgentsRoot, "skills"),
89
+ mcpPath: path.join(tempAgentsRoot, "mcp.json"),
90
+ lockPath: path.join(tempAgentsRoot, "agents.lock.json"),
91
+ settingsPath: path.join(tempAgentsRoot, "settings.local.json"),
92
+ manifestPath: path.join(tempAgentsRoot, ".sync-manifest.json"),
93
+ },
94
+ cleanup() {
95
+ fs.rmSync(tempRoot, { recursive: true, force: true });
96
+ },
97
+ };
27
98
  }
@@ -0,0 +1,2 @@
1
+ import type { ParsedArgs } from "minimist";
2
+ export declare function runUpgradeCommand(argv: ParsedArgs, currentVersion: string): Promise<void>;
@@ -0,0 +1,19 @@
1
+ import { getUpgradeHelpText } from "../core/copy.js";
2
+ import { upgradeToLatest } from "../core/version-notifier.js";
3
+ export async function runUpgradeCommand(argv, currentVersion) {
4
+ if (argv.help) {
5
+ console.log(getUpgradeHelpText());
6
+ return;
7
+ }
8
+ const result = await upgradeToLatest({ currentVersion });
9
+ if (result === "updated")
10
+ return;
11
+ if (result === "already-latest") {
12
+ console.log(`agentloom ${currentVersion} is already up to date.`);
13
+ return;
14
+ }
15
+ if (result === "unavailable") {
16
+ throw new Error("Unable to reach npm to check the latest agentloom release.");
17
+ }
18
+ throw new Error("Automatic upgrade failed.");
19
+ }
package/dist/core/argv.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import minimist from "minimist";
2
+ import { ALL_PROVIDERS } from "../types.js";
2
3
  export function parseArgs(argv) {
3
4
  const parsed = minimist(argv, {
4
5
  boolean: ["global", "local", "yes", "no-sync", "dry-run", "json", "help"],
@@ -50,16 +51,11 @@ export function parseProvidersFlag(input) {
50
51
  .map((item) => item.toLowerCase());
51
52
  const validProviders = [];
52
53
  for (const provider of parsed) {
53
- if (provider === "cursor" ||
54
- provider === "claude" ||
55
- provider === "codex" ||
56
- provider === "opencode" ||
57
- provider === "gemini" ||
58
- provider === "copilot") {
54
+ if (ALL_PROVIDERS.includes(provider)) {
59
55
  validProviders.push(provider);
60
56
  continue;
61
57
  }
62
- throw new Error(`Unknown provider: ${provider}. Expected one of: cursor, claude, codex, opencode, gemini, copilot.`);
58
+ throw new Error(`Unknown provider: ${provider}. Expected one of: ${ALL_PROVIDERS.join(", ")}.`);
63
59
  }
64
60
  return [...new Set(validProviders)];
65
61
  }
@@ -7,7 +7,9 @@ export declare function getRootHelpText(): string;
7
7
  export declare function getFindHelpText(): string;
8
8
  export declare function getAddHelpText(): string;
9
9
  export declare function getUpdateHelpText(): string;
10
+ export declare function getUpgradeHelpText(): string;
10
11
  export declare function getSyncHelpText(): string;
12
+ export declare function getInitHelpText(): string;
11
13
  export declare function getCommandHelpText(): string;
12
14
  export declare function getCommandAddHelpText(): string;
13
15
  export declare function getCommandListHelpText(): string;
package/dist/core/copy.js CHANGED
@@ -1,4 +1,5 @@
1
- const PROVIDERS_CSV = "cursor,claude,codex,opencode,gemini,copilot";
1
+ import { ALL_PROVIDERS } from "../types.js";
2
+ const PROVIDERS_CSV = ALL_PROVIDERS.join(",");
2
3
  export function getRootHelpText() {
3
4
  return `agentloom - unified canonical agent package manager
4
5
 
@@ -8,9 +9,11 @@ Usage:
8
9
 
9
10
  Aggregate commands:
10
11
  add <source> Import agents/commands/mcp/skills from a source
12
+ init Bootstrap canonical files, migrate providers, then sync
11
13
  find <query> Search remote + local entities
12
14
  update [source] Refresh lockfile-managed imports
13
- sync Generate provider-specific outputs
15
+ upgrade Install the latest CLI release
16
+ sync Migrate provider configs then generate provider outputs
14
17
  delete <source|name> Delete imported entities by source or name
15
18
 
16
19
  Entity commands:
@@ -111,8 +114,20 @@ Example:
111
114
  agentloom update farnoodma/agents --providers codex,cursor
112
115
  `;
113
116
  }
117
+ export function getUpgradeHelpText() {
118
+ return `Install the latest agentloom release.
119
+
120
+ Usage:
121
+ agentloom upgrade
122
+
123
+ Behavior:
124
+ - Checks npm for the newest published version
125
+ - Upgrades immediately without interactive prompts
126
+ - Reports when the current version is already up to date
127
+ `;
128
+ }
114
129
  export function getSyncHelpText() {
115
- return `Generate provider-specific files from canonical .agents data.
130
+ return `Migrate provider configs into canonical .agents data, then generate provider-specific outputs.
116
131
 
117
132
  Usage:
118
133
  agentloom sync [options]
@@ -125,6 +140,20 @@ Options:
125
140
  --dry-run Show file changes without writing
126
141
  `;
127
142
  }
143
+ export function getInitHelpText() {
144
+ return `Bootstrap canonical .agents files, migrate provider configs into canonical state, and sync providers.
145
+
146
+ Usage:
147
+ agentloom init [options]
148
+
149
+ Options:
150
+ --local | --global Choose canonical scope (interactive prompts when omitted)
151
+ --providers <csv> Limit providers (${PROVIDERS_CSV})
152
+ --yes Skip interactive conflict prompts and fail fast in non-interactive flows
153
+ --no-sync Skip sync after canonical bootstrap + migration
154
+ --dry-run Show planned migration/sync changes without writing
155
+ `;
156
+ }
128
157
  export function getCommandHelpText() {
129
158
  return `Manage canonical command entities.
130
159
 
@@ -1,3 +1,4 @@
1
+ import path from "node:path";
1
2
  import { readJsonIfExists, writeJsonAtomic } from "./fs.js";
2
3
  const EMPTY_LOCK = {
3
4
  version: 1,
@@ -10,7 +11,7 @@ export function readLockfile(paths) {
10
11
  }
11
12
  return {
12
13
  version: 1,
13
- entries: lock.entries.map((entry) => ({
14
+ entries: lock.entries.map((entry) => normalizeLockEntryForRuntime(paths, {
14
15
  ...entry,
15
16
  importedAgents: Array.isArray(entry.importedAgents)
16
17
  ? entry.importedAgents
@@ -66,7 +67,10 @@ function normalizeRenameMap(value) {
66
67
  return Object.keys(normalized).length > 0 ? normalized : undefined;
67
68
  }
68
69
  export function writeLockfile(paths, lockfile) {
69
- writeJsonAtomic(paths.lockPath, lockfile);
70
+ writeJsonAtomic(paths.lockPath, {
71
+ version: 1,
72
+ entries: lockfile.entries.map((entry) => normalizeLockEntryForDisk(paths, entry)),
73
+ });
70
74
  }
71
75
  export function upsertLockEntry(lockfile, entry) {
72
76
  const index = lockfile.entries.findIndex((item) => item.source === entry.source &&
@@ -106,3 +110,31 @@ function normalizeSelectionForKey(value) {
106
110
  ...new Set(value.map((item) => item.trim().toLowerCase()).filter(Boolean)),
107
111
  ].sort();
108
112
  }
113
+ function normalizeLockEntryForRuntime(paths, entry) {
114
+ if (paths.scope !== "local" || entry.sourceType !== "local") {
115
+ return entry;
116
+ }
117
+ if (path.isAbsolute(entry.source)) {
118
+ return entry;
119
+ }
120
+ return {
121
+ ...entry,
122
+ source: path.resolve(paths.workspaceRoot, entry.source),
123
+ };
124
+ }
125
+ function normalizeLockEntryForDisk(paths, entry) {
126
+ if (paths.scope !== "local" || entry.sourceType !== "local") {
127
+ return entry;
128
+ }
129
+ if (!path.isAbsolute(entry.source)) {
130
+ return {
131
+ ...entry,
132
+ source: entry.source || ".",
133
+ };
134
+ }
135
+ const relativeSource = path.relative(paths.workspaceRoot, entry.source);
136
+ return {
137
+ ...entry,
138
+ source: relativeSource || ".",
139
+ };
140
+ }
@@ -9,6 +9,7 @@ const SKIP_COMMANDS = new Set([
9
9
  "version",
10
10
  "--version",
11
11
  "-v",
12
+ "upgrade",
12
13
  ]);
13
14
  export function getGlobalManageAgentsSkillPath(homeDir = os.homedir()) {
14
15
  return path.join(homeDir, ".agents", "skills", "manage-agents", "SKILL.md");
@@ -0,0 +1,28 @@
1
+ import type { EntityType, Provider, ScopePaths } from "../types.js";
2
+ export interface MigrationOptions {
3
+ paths: ScopePaths;
4
+ providers: Provider[];
5
+ target: EntityType | "all";
6
+ yes?: boolean;
7
+ nonInteractive?: boolean;
8
+ dryRun?: boolean;
9
+ materializeCanonical?: boolean;
10
+ }
11
+ export interface MigrationEntitySummary {
12
+ detected: number;
13
+ imported: number;
14
+ conflicts: number;
15
+ skipped: number;
16
+ }
17
+ export interface MigrationSummary {
18
+ providers: Provider[];
19
+ target: EntityType | "all";
20
+ entities: Record<EntityType, MigrationEntitySummary>;
21
+ }
22
+ export declare class MigrationConflictError extends Error {
23
+ constructor(message: string);
24
+ }
25
+ export declare function createEmptyMigrationSummary(providers: Provider[], target: EntityType | "all"): MigrationSummary;
26
+ export declare function initializeCanonicalLayout(paths: ScopePaths, providers?: Provider[]): void;
27
+ export declare function migrateProviderStateToCanonical(options: MigrationOptions): Promise<MigrationSummary>;
28
+ export declare function formatMigrationSummary(summary: MigrationSummary): string;