loadout-ai 0.6.0 → 0.7.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.
Files changed (103) hide show
  1. package/README.md +122 -19
  2. package/catalog/discovered.json +25557 -24308
  3. package/dist/src/cli.js +2 -2
  4. package/dist/src/commands/agents.js +6 -23
  5. package/dist/src/commands/catalog.js +130 -33
  6. package/dist/src/commands/health.js +6 -6
  7. package/dist/src/commands/inventory.js +19 -120
  8. package/dist/src/commands/lifecycle.js +13 -51
  9. package/dist/src/commands/mcp.js +10 -73
  10. package/dist/src/commands/setup.js +5 -5
  11. package/dist/src/commands/sharing.js +11 -108
  12. package/dist/src/commands/support.js +20 -9
  13. package/dist/src/core/{adapters.js → agents/adapters.js} +2 -2
  14. package/dist/src/core/{agent-inspection.js → agents/agent-inspection.js} +26 -6
  15. package/dist/src/core/{codex-mcp.js → agents/codex-mcp.js} +1 -1
  16. package/dist/src/core/{health-score-evidence.js → agents/health-score-evidence.js} +8 -8
  17. package/dist/src/core/{runtime-tools.js → agents/runtime-tools.js} +2 -2
  18. package/dist/src/core/{audit.js → catalog/audit.js} +4 -4
  19. package/dist/src/core/{catalog.js → catalog/catalog.js} +5 -5
  20. package/dist/src/core/{components.js → catalog/components.js} +2 -2
  21. package/dist/src/core/{conformance.js → catalog/conformance.js} +2 -2
  22. package/dist/src/core/{profiles.js → catalog/profiles.js} +2 -2
  23. package/dist/src/core/{provenance.js → catalog/provenance.js} +3 -3
  24. package/dist/src/core/{registry.js → catalog/registry.js} +1 -1
  25. package/dist/src/core/{skill-compare.js → catalog/skill-compare.js} +1 -1
  26. package/dist/src/core/{skill-inventory.js → catalog/skill-inventory.js} +3 -3
  27. package/dist/src/core/{skills.js → catalog/skills.js} +1 -1
  28. package/dist/src/core/{candidate-intelligence.js → discovery/candidate-intelligence.js} +6 -6
  29. package/dist/src/core/{discovery-connector.js → discovery/discovery-connector.js} +2 -2
  30. package/dist/src/core/{evaluate.js → discovery/evaluate.js} +2 -2
  31. package/dist/src/core/{mcp-registry-discovery.js → discovery/mcp-registry-discovery.js} +1 -1
  32. package/dist/src/core/{observations.js → discovery/observations.js} +3 -3
  33. package/dist/src/core/{review-queue.js → discovery/review-queue.js} +2 -2
  34. package/dist/src/core/{skills-sh-discovery.js → discovery/skills-sh-discovery.js} +1 -1
  35. package/dist/src/core/{adopt.js → install/adopt.js} +3 -3
  36. package/dist/src/core/{catalog-install.js → install/catalog-install.js} +11 -11
  37. package/dist/src/core/{file-lock.js → install/file-lock.js} +1 -1
  38. package/dist/src/core/{install.js → install/install.js} +5 -5
  39. package/dist/src/core/{package.js → install/package.js} +3 -3
  40. package/dist/src/core/{reconcile.js → install/reconcile.js} +5 -5
  41. package/dist/src/core/{remove.js → install/remove.js} +4 -4
  42. package/dist/src/core/{snapshot.js → install/snapshot.js} +1 -1
  43. package/dist/src/core/{source.js → install/source.js} +1 -1
  44. package/dist/src/core/{sync.js → install/sync.js} +9 -9
  45. package/dist/src/core/{transaction.js → install/transaction.js} +1 -1
  46. package/dist/src/core/{uninstall.js → install/uninstall.js} +4 -4
  47. package/dist/src/core/{update.js → install/update.js} +4 -4
  48. package/dist/src/core/{cli-guide.js → reporting/cli-guide.js} +29 -45
  49. package/dist/src/core/{doctor.js → reporting/doctor.js} +3 -6
  50. package/dist/src/core/{freshness-alerts.js → reporting/freshness-alerts.js} +5 -5
  51. package/dist/src/core/{health.js → reporting/health.js} +6 -6
  52. package/dist/src/core/{loadout-card.js → reporting/loadout-card.js} +1 -1
  53. package/dist/src/core/{readme-claims.js → reporting/readme-claims.js} +1 -1
  54. package/dist/src/core/{readme-facts.js → reporting/readme-facts.js} +2 -2
  55. package/dist/src/core/{share-report.js → reporting/share-report.js} +3 -3
  56. package/dist/src/core/{upgrade.js → reporting/upgrade.js} +7 -7
  57. package/dist/src/core/routing/first-party-skills.js +118 -0
  58. package/dist/src/core/{handoff.js → routing/handoff.js} +120 -3
  59. package/dist/src/core/{model-config.js → routing/model-config.js} +4 -4
  60. package/dist/src/core/{route.js → routing/route.js} +325 -34
  61. package/dist/src/core/{api.js → runtime/api.js} +4 -4
  62. package/dist/src/core/{canary.js → runtime/canary.js} +1 -1
  63. package/dist/src/core/{github.js → runtime/github.js} +1 -1
  64. package/dist/src/core/{mcp-recipes.js → runtime/mcp-recipes.js} +1 -1
  65. package/dist/src/core/{mcp.js → runtime/mcp.js} +2 -2
  66. package/dist/src/core/{scheduler.js → runtime/scheduler.js} +4 -4
  67. package/dist/src/core/{active-policy.js → workspace/active-policy.js} +2 -2
  68. package/dist/src/core/{active-set.js → workspace/active-set.js} +2 -2
  69. package/dist/src/core/{improve.js → workspace/improve.js} +3 -3
  70. package/dist/src/core/{manifest.js → workspace/manifest.js} +2 -2
  71. package/dist/src/core/{outcomes.js → workspace/outcomes.js} +3 -3
  72. package/dist/src/core/{portable.js → workspace/portable.js} +3 -3
  73. package/dist/src/core/{profile-state.js → workspace/profile-state.js} +1 -1
  74. package/dist/src/core/{recommend.js → workspace/recommend.js} +1 -1
  75. package/dist/src/core/{state.js → workspace/state.js} +3 -3
  76. package/docs/DISCOVERED.md +247 -246
  77. package/docs/evidence/readme-claims.json +22 -19
  78. package/package.json +2 -1
  79. package/skills/loadout-curator/SKILL.md +105 -0
  80. package/skills/loadout-router/SKILL.md +120 -0
  81. /package/dist/src/core/{agent-health-score.js → agents/agent-health-score.js} +0 -0
  82. /package/dist/src/core/{agent-versions.js → agents/agent-versions.js} +0 -0
  83. /package/dist/src/core/{conversion.js → agents/conversion.js} +0 -0
  84. /package/dist/src/core/{paths.js → agents/paths.js} +0 -0
  85. /package/dist/src/core/{runtime-tool-recipe.js → agents/runtime-tool-recipe.js} +0 -0
  86. /package/dist/src/core/{catalog-coverage.js → catalog/catalog-coverage.js} +0 -0
  87. /package/dist/src/core/{safety.js → catalog/safety.js} +0 -0
  88. /package/dist/src/core/{skill-security.js → catalog/skill-security.js} +0 -0
  89. /package/dist/src/core/{community.js → discovery/community.js} +0 -0
  90. /package/dist/src/core/{github-discovery.js → discovery/github-discovery.js} +0 -0
  91. /package/dist/src/core/{private-discovery.js → discovery/private-discovery.js} +0 -0
  92. /package/dist/src/core/{ranking.js → discovery/ranking.js} +0 -0
  93. /package/dist/src/core/{atomic-file.js → install/atomic-file.js} +0 -0
  94. /package/dist/src/core/{diff.js → install/diff.js} +0 -0
  95. /package/dist/src/core/{update-watch.js → install/update-watch.js} +0 -0
  96. /package/dist/src/core/{completion.js → reporting/completion.js} +0 -0
  97. /package/dist/src/core/{loadout-badge.js → reporting/loadout-badge.js} +0 -0
  98. /package/dist/src/core/{terminal.js → reporting/terminal.js} +0 -0
  99. /package/dist/src/core/{access.js → routing/access.js} +0 -0
  100. /package/dist/src/core/{credentials.js → routing/credentials.js} +0 -0
  101. /package/dist/src/core/{sandbox.js → runtime/sandbox.js} +0 -0
  102. /package/dist/src/core/{active-limit.js → workspace/active-limit.js} +0 -0
  103. /package/dist/src/core/{target-occupancy.js → workspace/target-occupancy.js} +0 -0
@@ -1,8 +1,8 @@
1
- import { parseAgentSelection } from "../core/paths.js";
2
- import { formatHealthReport } from "../core/health.js";
3
- import { applyUpgrade, formatUpgradePlan, planUpgrade, summarizeUpgradePlan, } from "../core/upgrade.js";
4
- import { parseModelApiAccess } from "../core/access.js";
5
- import { ADVANCED_GUIDE } from "../core/cli-guide.js";
1
+ import { parseAgentSelection } from "../core/agents/paths.js";
2
+ import { formatHealthReport } from "../core/reporting/health.js";
3
+ import { applyUpgrade, formatUpgradePlan, planUpgrade, summarizeUpgradePlan, } from "../core/reporting/upgrade.js";
4
+ import { parseModelApiAccess } from "../core/routing/access.js";
5
+ import { ADVANCED_GUIDE } from "../core/reporting/cli-guide.js";
6
6
  import { collectOption, setupSelection, printSetupProgress, runSetup, printBeginnerGuide, } from "./support.js";
7
7
  export function registerSetup(program) {
8
8
  program
@@ -1,18 +1,15 @@
1
- import { loadEffectiveCatalog } from "../core/catalog.js";
2
- import { detectAgents, parseAgentSelection } from "../core/paths.js";
3
- import { readFile } from "node:fs/promises";
1
+ import { loadEffectiveCatalog } from "../core/catalog/catalog.js";
2
+ import { parseAgentSelection } from "../core/agents/paths.js";
4
3
  import { resolve } from "node:path";
5
- import { addManifestPackage, initManifest, readManifest, removeManifestPackage, writeLockfile, } from "../core/manifest.js";
6
- import { readInstallState } from "../core/state.js";
7
- import { createPackage, packPackage, publishLocalPackage, publishRemotePackage, searchLocalRegistry, } from "../core/registry.js";
8
- import { auditLoadout, formatAuditReport } from "../core/audit.js";
9
- import { applyPortableImport, exportPortableLoadout, planPortableImport, } from "../core/portable.js";
10
- import { writeFileAtomically } from "../core/atomic-file.js";
11
- import { buildLibraryStateReport, formatLibrarySummary, formatLibraryStateReport, } from "../core/active-set.js";
12
- import { buildPrivacySafeReport, formatPrivacySafeReport, parsePrivacySafeLoadoutReport, writePrivacySafeReport, } from "../core/share-report.js";
13
- import { readLocalOutcomes, recordLocalOutcome, } from "../core/outcomes.js";
14
- import { createCredentialResolver } from "../core/credentials.js";
15
- import { buildLoadoutCard, compareLoadoutReports, formatLoadoutCard, formatLoadoutComparison, } from "../core/loadout-card.js";
4
+ import { addManifestPackage, initManifest, readManifest, removeManifestPackage, writeLockfile, } from "../core/workspace/manifest.js";
5
+ import { readInstallState } from "../core/workspace/state.js";
6
+ import { createPackage, searchLocalRegistry, } from "../core/catalog/registry.js";
7
+ import { auditLoadout, formatAuditReport } from "../core/catalog/audit.js";
8
+ import { applyPortableImport, exportPortableLoadout, planPortableImport, } from "../core/workspace/portable.js";
9
+ import { writeFileAtomically } from "../core/install/atomic-file.js";
10
+ import { buildLibraryStateReport, formatLibrarySummary, formatLibraryStateReport, } from "../core/workspace/active-set.js";
11
+ import { buildPrivacySafeReport, formatPrivacySafeReport, writePrivacySafeReport, } from "../core/reporting/share-report.js";
12
+ import { buildLoadoutCard, formatLoadoutCard, } from "../core/reporting/loadout-card.js";
16
13
  export function registerSharing(program) {
17
14
  program
18
15
  .command("init")
@@ -89,54 +86,6 @@ export function registerSharing(program) {
89
86
  const descriptor = await createPackage(directory, options);
90
87
  console.log(`Created ${descriptor.name}@${descriptor.version} in ${directory}.`);
91
88
  });
92
- program
93
- .command("pack")
94
- .description("Validate a package and print its deterministic inventory digest")
95
- .argument("[directory]", "package directory", ".")
96
- .option("--json", "emit machine-readable JSON")
97
- .action(async (directory, options) => {
98
- const packed = await packPackage(directory);
99
- console.log(options.json
100
- ? JSON.stringify(packed, null, 2)
101
- : `${packed.descriptor.name}@${packed.descriptor.version} — ${packed.files.length} file(s) — sha256:${packed.digest}`);
102
- });
103
- program
104
- .command("publish")
105
- .description("Publish an immutable package version to a local or remote Loadout registry")
106
- .argument("[directory]", "package directory", ".")
107
- .option("--local", "publish to the local registry")
108
- .option("--registry-url <url>", "remote registry base URL")
109
- .option("--credential-keychain <service>", "resolve the remote registry token from the OS credential store")
110
- .option("--credential-account <account>", "OS credential account")
111
- .option("--approve-risk", "explicitly approve publishing scripts, hooks, or binaries")
112
- .action(async (directory, options) => {
113
- if (Number(Boolean(options.local)) +
114
- Number(Boolean(options.registryUrl)) !==
115
- 1)
116
- throw new Error("Choose exactly one destination: --local or --registry-url");
117
- if (options.local) {
118
- if (options.credentialKeychain)
119
- throw new Error("Local publishing does not require a credential");
120
- const packed = await publishLocalPackage(directory, {
121
- approveRisk: options.approveRisk,
122
- });
123
- console.log(`Published ${packed.descriptor.name}@${packed.descriptor.version} with digest ${packed.digest}.`);
124
- return;
125
- }
126
- const token = await createCredentialResolver()(options.credentialKeychain
127
- ? {
128
- kind: "os-keychain",
129
- service: options.credentialKeychain,
130
- ...(options.credentialAccount
131
- ? { account: options.credentialAccount }
132
- : {}),
133
- }
134
- : { kind: "environment", name: "LOADOUT_REGISTRY_TOKEN" });
135
- if (!token)
136
- throw new Error("Remote publishing credential did not resolve; set LOADOUT_REGISTRY_TOKEN or use --credential-keychain");
137
- const published = await publishRemotePackage(directory, options.registryUrl, token, { approveRisk: options.approveRisk });
138
- console.log(`Published ${published.name}@${published.version} with digest ${published.digest}.`);
139
- });
140
89
  program
141
90
  .command("search")
142
91
  .description("Search the bundled catalog and local registry")
@@ -283,39 +232,6 @@ export function registerSharing(program) {
283
232
  ? JSON.stringify(report, null, 2)
284
233
  : formatPrivacySafeReport(report));
285
234
  });
286
- program
287
- .command("outcomes")
288
- .description("Show privacy-safe local outcome signals; never uploads project or prompt data")
289
- .option("--json", "emit machine-readable JSON")
290
- .action(async (options) => {
291
- const store = await readLocalOutcomes();
292
- console.log(options.json
293
- ? JSON.stringify(store, null, 2)
294
- : [
295
- `Local outcomes: ${store.events.length}`,
296
- ...store.events.map((event) => `${event.recordedAt} — ${event.selector} — ${event.agent}/${event.taskFamily} — ${event.result}`),
297
- "Privacy: local only; no project names, paths, prompts, code, filenames, or secrets.",
298
- ].join("\n"));
299
- });
300
- program
301
- .command("outcome")
302
- .description("Record an explicit local, agent/task-scoped skill outcome")
303
- .argument("<selector>", "exact package/skill selector")
304
- .requiredOption("--agent <id>", "agent id")
305
- .requiredOption("--task <family>", "general, frontend, testing, javascript, python, backend, security, or documentation")
306
- .requiredOption("--result <value>", "accept, reject, success, failure, activation, disable, or rollback")
307
- .action(async (selector, options) => {
308
- const knownAgents = new Set((await detectAgents()).map((agent) => agent.id));
309
- if (!knownAgents.has(options.agent))
310
- throw new Error(`Unknown agent id: ${options.agent}`);
311
- const event = await recordLocalOutcome({
312
- selector,
313
- agent: options.agent,
314
- taskFamily: options.task,
315
- result: options.result,
316
- });
317
- console.log(`Recorded local outcome ${event.id}. No project, prompt, or source data was stored.`);
318
- });
319
235
  program
320
236
  .command("share")
321
237
  .description("Write the privacy-safe Loadout report to a JSON artifact")
@@ -342,17 +258,4 @@ export function registerSharing(program) {
342
258
  }
343
259
  console.log(options.json ? JSON.stringify(card, null, 2) : markdown);
344
260
  });
345
- program
346
- .command("compare-loadouts")
347
- .description("Compare aggregate counts from two explicit privacy-safe Loadout reports")
348
- .argument("<left>", "earlier privacy-safe report JSON")
349
- .argument("<right>", "later privacy-safe report JSON")
350
- .option("--json", "emit machine-readable count deltas")
351
- .action(async (left, right, options) => {
352
- const [before, after] = await Promise.all([left, right].map(async (path) => parsePrivacySafeLoadoutReport(JSON.parse(await readFile(resolve(path), "utf8")))));
353
- const comparison = compareLoadoutReports(before, after);
354
- console.log(options.json
355
- ? JSON.stringify(comparison, null, 2)
356
- : formatLoadoutComparison(comparison));
357
- });
358
261
  }
@@ -1,12 +1,12 @@
1
1
  import { createInterface } from "node:readline/promises";
2
2
  import { createRequire } from "node:module";
3
- import { detectAgents, parseAgentSelection } from "../core/paths.js";
3
+ import { detectAgents, parseAgentSelection } from "../core/agents/paths.js";
4
4
  import { dirname, join, resolve } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
- import { applyPreparedCatalogInstall, formatCatalogApplyGuidance, formatPreparedCatalogInstall, prepareCatalogInstall, } from "../core/catalog-install.js";
7
- import { formatInstalledSkillInventory, scanInstalledSkills, } from "../core/skill-inventory.js";
8
- import { interactiveModelApiAccess, parseModelApiAccess, } from "../core/access.js";
9
- import { BEGINNER_GUIDE } from "../core/cli-guide.js";
6
+ import { applyPreparedCatalogInstall, formatCatalogApplyGuidance, formatPreparedCatalogInstall, prepareCatalogInstall, } from "../core/install/catalog-install.js";
7
+ import { formatInstalledSkillInventory, scanInstalledSkills, } from "../core/catalog/skill-inventory.js";
8
+ import { interactiveModelApiAccess, parseModelApiAccess, } from "../core/routing/access.js";
9
+ import { BEGINNER_GUIDE } from "../core/reporting/cli-guide.js";
10
10
  export const collectOption = (value, previous = []) => [...previous, value];
11
11
  export function parseMcpCredentialMappings(recipe, mappings, account) {
12
12
  const references = {};
@@ -105,7 +105,16 @@ export async function runSetup(options) {
105
105
  try {
106
106
  if (!mode) {
107
107
  if (!interactive) {
108
- console.log("Pick a loadout to preview: `loadout setup --mode stable` (recommended), `--mode power` (broader), or `--mode maximum` (full library, activate per project). Nothing installs until you add --yes.");
108
+ console.log([
109
+ "Pick a loadout to preview:",
110
+ " --mode stable 4 reviewed sources, 30 skills, all active (recommended)",
111
+ " --mode power 8 sources, 56 skills, all active",
112
+ " --mode maximum every reviewed source, downloaded but DISABLED; a project",
113
+ " activates what it needs with `loadout optimize --project .`",
114
+ " --mode custom --package <id>, one or more",
115
+ "",
116
+ "Nothing installs until you add --yes.",
117
+ ].join("\n"));
109
118
  return;
110
119
  }
111
120
  reader = createInterface({
@@ -114,9 +123,11 @@ export async function runSetup(options) {
114
123
  });
115
124
  const answer = (await reader.question([
116
125
  "Choose a loadout:",
117
- " [1] Stable — a small, reviewed set of everyday skills (recommended)",
118
- " [2] Power — a broader daily-driver set",
119
- " [3] Maximum — download the full reviewed library, activate per project later",
126
+ " [1] Stable — 4 reviewed sources, 30 skills, all active (recommended)",
127
+ " [2] Power — 8 sources, 56 skills, all active",
128
+ " [3] Maximum — download every reviewed source, but leave it DISABLED.",
129
+ " Nothing reaches your prompts until a project activates",
130
+ " it with `loadout optimize --project .`. Costs disk, not context.",
120
131
  " [4] Custom — pick exact package ids",
121
132
  "> ",
122
133
  ].join("\n"))).trim();
@@ -1,6 +1,6 @@
1
1
  import { dirname, join } from "node:path";
2
- import { planSkillInstall } from "./skills.js";
3
- import { formatTerminalTable } from "./terminal.js";
2
+ import { planSkillInstall } from "../catalog/skills.js";
3
+ import { formatTerminalTable } from "../reporting/terminal.js";
4
4
  /**
5
5
  * Rules shared by the CLI, planner, and documentation. A capability only
6
6
  * changes state when it is native or has this explicitly tested adaptation.
@@ -136,15 +136,35 @@ export async function inspectAgent(agent) {
136
136
  export async function inspectAgents(agents) {
137
137
  return Promise.all(agents.map(inspectAgent));
138
138
  }
139
- export function formatAgentInventory(inventory) {
139
+ /**
140
+ * One agent's inventory. The default is a two-line summary: what is installed
141
+ * and which component kinds the adapter supports. Adapter internals — the
142
+ * per-kind compatibility notes and the paths that do not exist yet — are only
143
+ * useful when diagnosing, so they stay behind `details`.
144
+ */
145
+ export function formatAgentInventory(inventory, options = {}) {
140
146
  const lines = [
141
147
  `${inventory.agent.installed ? "✓" : "○"} ${inventory.agent.displayName}`,
142
148
  ];
143
- for (const component of inventory.components) {
144
- const state = component.scanned
145
- ? `${component.directoryExists ? `${component.entries.length} filesystem item(s)` : "not created"} — ${component.directory}`
146
- : (component.note ?? "not inspected");
147
- lines.push(` ${component.type}: ${component.compatibility}; ${state}`);
149
+ if (options.details) {
150
+ for (const component of inventory.components) {
151
+ const state = component.scanned
152
+ ? `${component.directoryExists ? `${component.entries.length} filesystem item(s)` : "not created"} — ${component.directory}`
153
+ : (component.note ?? "not inspected");
154
+ lines.push(` ${component.type}: ${component.compatibility}; ${state}`);
155
+ }
156
+ }
157
+ else {
158
+ const items = inventory.components
159
+ .filter((component) => component.scanned && component.directoryExists)
160
+ .reduce((total, component) => total + component.entries.length, 0);
161
+ const supported = inventory.components
162
+ .filter((component) => component.compatibility !== "unsupported")
163
+ .map((component) => component.type);
164
+ const skills = inventory.components.find((component) => component.type === "skill");
165
+ if (skills?.directory)
166
+ lines.push(` ${skills.directory}`);
167
+ lines.push(` ${items} items | supports: ${supported.join(", ")}`);
148
168
  }
149
169
  for (const warning of inventory.warnings)
150
170
  lines.push(` ! ${warning}`);
@@ -2,7 +2,7 @@ import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
2
2
  import { basename, dirname, join, resolve } from "node:path";
3
3
  import { createHash, randomUUID } from "node:crypto";
4
4
  import { loadoutHome, userHome } from "./paths.js";
5
- import { runMutationTransaction } from "./transaction.js";
5
+ import { runMutationTransaction } from "../install/transaction.js";
6
6
  function safeName(name) {
7
7
  if (!/^[A-Za-z0-9._-]{1,128}$/.test(name))
8
8
  throw new Error("MCP server name may contain only letters, numbers, ., _, and -");
@@ -1,16 +1,16 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { readFile, readdir } from "node:fs/promises";
3
3
  import { buildAgentHealthScore, } from "./agent-health-score.js";
4
- import { DEFAULT_ACTIVE_SKILL_LIMIT } from "./active-limit.js";
5
- import { managedFileReadPath } from "./active-set.js";
4
+ import { DEFAULT_ACTIVE_SKILL_LIMIT } from "../workspace/active-limit.js";
5
+ import { managedFileReadPath } from "../workspace/active-set.js";
6
6
  import { adapterCapabilities } from "./adapters.js";
7
- import { loadEffectiveCatalog } from "./catalog.js";
7
+ import { loadEffectiveCatalog } from "../catalog/catalog.js";
8
8
  import { detectAgents } from "./paths.js";
9
- import { readLocalOutcomes } from "./outcomes.js";
10
- import { readSnapshot } from "./snapshot.js";
11
- import { scanInstalledSkills } from "./skill-inventory.js";
12
- import { readInstallState } from "./state.js";
13
- import { transactionRoot } from "./transaction.js";
9
+ import { readLocalOutcomes } from "../workspace/outcomes.js";
10
+ import { readSnapshot } from "../install/snapshot.js";
11
+ import { scanInstalledSkills } from "../catalog/skill-inventory.js";
12
+ import { readInstallState } from "../workspace/state.js";
13
+ import { transactionRoot } from "../install/transaction.js";
14
14
  function freshness(pkg, asOf) {
15
15
  const observed = pkg?.pushedAt ?? pkg?.lastUpdatedAt;
16
16
  if (!observed)
@@ -2,10 +2,10 @@ import { execFile } from "node:child_process";
2
2
  import { access, readFile, readdir, rm } from "node:fs/promises";
3
3
  import { join } from "node:path";
4
4
  import { promisify } from "node:util";
5
- import { writeFileAtomically } from "./atomic-file.js";
5
+ import { writeFileAtomically } from "../install/atomic-file.js";
6
6
  import { detectAgents, loadoutHome, userHome } from "./paths.js";
7
7
  import { parseRuntimeToolRecipe, renderRuntimeRecipeValue, resolveRuntimeRecipePath, } from "./runtime-tool-recipe.js";
8
- import { createSnapshot, readSnapshot, recordSnapshotPostMutationState, restoreSnapshot, } from "./snapshot.js";
8
+ import { createSnapshot, readSnapshot, recordSnapshotPostMutationState, restoreSnapshot, } from "../install/snapshot.js";
9
9
  const execFileAsync = promisify(execFile);
10
10
  function deepFreeze(value) {
11
11
  if (value && typeof value === "object" && !Object.isFrozen(value)) {
@@ -1,10 +1,10 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { readFile } from "node:fs/promises";
3
3
  import { resolve } from "node:path";
4
- import { formatSchemaError, loadoutLockfileSchema } from "../shared/schemas.js";
5
- import { readManifest } from "./manifest.js";
6
- import { readInstallState } from "./state.js";
7
- import { managedFileReadPath } from "./active-set.js";
4
+ import { formatSchemaError, loadoutLockfileSchema, } from "../../shared/schemas.js";
5
+ import { readManifest } from "../workspace/manifest.js";
6
+ import { readInstallState } from "../workspace/state.js";
7
+ import { managedFileReadPath } from "../workspace/active-set.js";
8
8
  export function parseLockfile(value) {
9
9
  const result = loadoutLockfileSchema.safeParse(value);
10
10
  if (!result.success)
@@ -2,12 +2,12 @@ import { existsSync } from "node:fs";
2
2
  import { mkdir, readFile, writeFile } from "node:fs/promises";
3
3
  import { dirname, join } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
- import { catalogSchema, formatSchemaError } from "../shared/schemas.js";
6
- import { fetchGitHubMetadata } from "./github.js";
7
- import { loadoutHome } from "./paths.js";
8
- import { compareCatalogPackages, explainCatalogScore } from "./ranking.js";
5
+ import { catalogSchema, formatSchemaError } from "../../shared/schemas.js";
6
+ import { fetchGitHubMetadata, } from "../runtime/github.js";
7
+ import { loadoutHome } from "../agents/paths.js";
8
+ import { compareCatalogPackages, explainCatalogScore, } from "../discovery/ranking.js";
9
9
  import { resolveCatalogProfile } from "./profiles.js";
10
- import { recordCatalogObservations } from "./observations.js";
10
+ import { recordCatalogObservations } from "../discovery/observations.js";
11
11
  const cachedCatalogPath = () => join(loadoutHome(), "catalog.json");
12
12
  function bundledCatalogPath() {
13
13
  const moduleDirectory = dirname(fileURLToPath(import.meta.url));
@@ -1,7 +1,7 @@
1
1
  import { lstat, readdir } from "node:fs/promises";
2
2
  import { isAbsolute, join, relative, resolve, sep } from "node:path";
3
- import { buildSkillPlan } from "./install.js";
4
- import { adapterCapabilities, agentComponentDirectory } from "./adapters.js";
3
+ import { buildSkillPlan } from "../install/install.js";
4
+ import { adapterCapabilities, agentComponentDirectory, } from "../agents/adapters.js";
5
5
  const RESOURCE_DIRECTORIES = new Map([
6
6
  ["rules", "rule"],
7
7
  ["commands", "command"],
@@ -1,5 +1,5 @@
1
- import { ADAPTER_CAPABILITIES, agentComponentDirectory } from "./adapters.js";
2
- import { AGENT_DEFINITIONS, agentSkillsDirectory } from "./paths.js";
1
+ import { ADAPTER_CAPABILITIES, agentComponentDirectory, } from "../agents/adapters.js";
2
+ import { AGENT_DEFINITIONS, agentSkillsDirectory } from "../agents/paths.js";
3
3
  const PLATFORM_BY_RUNNER = {
4
4
  "ubuntu-latest": "linux",
5
5
  "macos-latest": "macos",
@@ -1,4 +1,4 @@
1
- import { compareCatalogPackages } from "./ranking.js";
1
+ import { compareCatalogPackages } from "../discovery/ranking.js";
2
2
  /**
3
3
  * Stable is Loadout's bounded policy-selected daily driver: broad enough to improve normal
4
4
  * engineering work immediately, but bounded at skill granularity and restricted
@@ -247,7 +247,7 @@ export function resolveCatalogProfile(packages, selection, families = CATALOG_CO
247
247
  warnings.push(`Custom selection retains the soft overlap in ${family.label}. Review ${names} before installation.`);
248
248
  }
249
249
  else {
250
- warnings.push(`${selection.mode === "power" ? "Power Boost" : "Maximum Library"} retains the soft overlap in ${family.label}. Loadout policy orders ${primary.displayName} first; review each package before installation.`);
250
+ warnings.push(`${selection.mode === "power" ? "Power" : "Maximum"} retains the soft overlap in ${family.label}. Loadout policy orders ${primary.displayName} first; review each package before installation.`);
251
251
  }
252
252
  }
253
253
  return {
@@ -2,10 +2,10 @@ import { createHash } from "node:crypto";
2
2
  import { readFile } from "node:fs/promises";
3
3
  import { dirname, join, relative, resolve, sep } from "node:path";
4
4
  import { loadEffectiveCatalog } from "./catalog.js";
5
- import { ensureDirectory, loadoutHome } from "./paths.js";
5
+ import { ensureDirectory, loadoutHome } from "../agents/paths.js";
6
6
  import { discoverSkillDirectories } from "./skills.js";
7
- import { fetchRepositorySnapshot, } from "./source.js";
8
- import { writeFileAtomically } from "./atomic-file.js";
7
+ import { fetchRepositorySnapshot, } from "../install/source.js";
8
+ import { writeFileAtomically } from "../install/atomic-file.js";
9
9
  const catalogSkillIndexPath = () => join(loadoutHome(), "provenance", "catalog-skills.json");
10
10
  function immutableCatalogDigest(catalog) {
11
11
  const evidence = catalog
@@ -1,7 +1,7 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { cp, lstat, mkdir, readFile, readdir, rm, writeFile, } from "node:fs/promises";
3
3
  import { join, relative, resolve, sep } from "node:path";
4
- import { loadoutHome } from "./paths.js";
4
+ import { loadoutHome } from "../agents/paths.js";
5
5
  import { analyzeUpdateSafety } from "./safety.js";
6
6
  const NAME = /^[a-z0-9][a-z0-9._-]*$/;
7
7
  const VERSION = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?$/;
@@ -1,5 +1,5 @@
1
1
  import { basename } from "node:path";
2
- import { explainCatalogScore } from "./ranking.js";
2
+ import { explainCatalogScore } from "../discovery/ranking.js";
3
3
  const STOP_WORDS = new Set([
4
4
  "a",
5
5
  "an",
@@ -1,9 +1,9 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { lstat, readFile, readdir } from "node:fs/promises";
3
3
  import { join, relative, resolve, sep } from "node:path";
4
- import { DEFAULT_ACTIVE_SKILL_LIMIT } from "./active-limit.js";
5
- import { readInstallState } from "./state.js";
6
- import { listInstalledRuntimeToolSkillTargets, } from "./runtime-tools.js";
4
+ import { DEFAULT_ACTIVE_SKILL_LIMIT } from "../workspace/active-limit.js";
5
+ import { readInstallState } from "../workspace/state.js";
6
+ import { listInstalledRuntimeToolSkillTargets, } from "../agents/runtime-tools.js";
7
7
  const MAX_SCAN_DEPTH = 6;
8
8
  function cleanFrontmatterValue(value) {
9
9
  if (!value)
@@ -1,6 +1,6 @@
1
1
  import { cp, lstat, readdir, readFile, rm } from "node:fs/promises";
2
2
  import { dirname, join, relative, resolve, sep } from "node:path";
3
- import { ensureDirectory } from "./paths.js";
3
+ import { ensureDirectory } from "../agents/paths.js";
4
4
  import { assertSkillSecurity, scanSkillSecurity } from "./skill-security.js";
5
5
  export async function discoverSkillDirectories(root, options = {}) {
6
6
  const result = [];
@@ -4,13 +4,13 @@ import { readFile, stat } from "node:fs/promises";
4
4
  import { dirname, join, resolve } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { isDeepStrictEqual } from "node:util";
7
- import { writeFileAtomically } from "./atomic-file.js";
8
- import { loadEffectiveCatalog, validateCatalog } from "./catalog.js";
7
+ import { writeFileAtomically } from "../install/atomic-file.js";
8
+ import { loadEffectiveCatalog, validateCatalog } from "../catalog/catalog.js";
9
9
  import { evaluatePackage } from "./evaluate.js";
10
- import { inspectPackage } from "./package.js";
11
- import { ensureDirectory, loadoutHome } from "./paths.js";
12
- import { fetchRepositorySnapshot, normalizeRepository, } from "./source.js";
13
- import { safeTerminalText } from "./terminal.js";
10
+ import { inspectPackage } from "../install/package.js";
11
+ import { ensureDirectory, loadoutHome } from "../agents/paths.js";
12
+ import { fetchRepositorySnapshot, normalizeRepository, } from "../install/source.js";
13
+ import { safeTerminalText } from "../reporting/terminal.js";
14
14
  const dossierDirectory = () => join(loadoutHome(), "candidates");
15
15
  const sourceVerifiedDossiers = new WeakMap();
16
16
  function installabilityFor(components) {
@@ -1,7 +1,7 @@
1
1
  import { readFile, stat } from "node:fs/promises";
2
2
  import { dirname } from "node:path";
3
- import { writeFileAtomically } from "./atomic-file.js";
4
- import { ensureDirectory } from "./paths.js";
3
+ import { writeFileAtomically } from "../install/atomic-file.js";
4
+ import { ensureDirectory } from "../agents/paths.js";
5
5
  export class ConnectorRequestError extends Error {
6
6
  status;
7
7
  retryAfterSeconds;
@@ -1,5 +1,5 @@
1
- import { inspectPackage } from "./package.js";
2
- import { analyzeUpdateSafety } from "./safety.js";
1
+ import { inspectPackage } from "../install/package.js";
2
+ import { analyzeUpdateSafety } from "../catalog/safety.js";
3
3
  function statusFor(findings) {
4
4
  if (findings.some((finding) => finding.category === "secret" || finding.category === "instruction"))
5
5
  return "blocked";
@@ -1,6 +1,6 @@
1
1
  import { join } from "node:path";
2
2
  import { ConnectorRequestError, fetchBoundedJson, rateLimitFromHeaders, readDiscoveryConnectorCache, writeDiscoveryConnectorCache, } from "./discovery-connector.js";
3
- import { loadoutHome } from "./paths.js";
3
+ import { loadoutHome } from "../agents/paths.js";
4
4
  const SOURCE = "official-mcp-registry";
5
5
  const API = "https://registry.modelcontextprotocol.io/v0.1/servers";
6
6
  const ATTRIBUTION = "https://registry.modelcontextprotocol.io/docs";
@@ -1,8 +1,8 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
- import { fetchGitHubReleaseMetadata, } from "./github.js";
4
- import { writeFileAtomically } from "./atomic-file.js";
5
- import { loadoutHome } from "./paths.js";
3
+ import { fetchGitHubReleaseMetadata, } from "../runtime/github.js";
4
+ import { writeFileAtomically } from "../install/atomic-file.js";
5
+ import { loadoutHome } from "../agents/paths.js";
6
6
  const MAX_OBSERVATIONS_PER_REPOSITORY = 90;
7
7
  function observationPath(repository) {
8
8
  return join(loadoutHome(), "observations", `${repository.replace("/", "__")}.json`);
@@ -1,7 +1,7 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { dirname, join } from "node:path";
3
- import { writeFileAtomically } from "./atomic-file.js";
4
- import { ensureDirectory, loadoutHome } from "./paths.js";
3
+ import { writeFileAtomically } from "../install/atomic-file.js";
4
+ import { ensureDirectory, loadoutHome } from "../agents/paths.js";
5
5
  const queuePath = () => join(loadoutHome(), "review-queue.json");
6
6
  function isQueue(value) {
7
7
  if (!value || typeof value !== "object" || Array.isArray(value))
@@ -1,6 +1,6 @@
1
1
  import { join } from "node:path";
2
2
  import { ConnectorRequestError, fetchBoundedJson, rateLimitFromHeaders, readDiscoveryConnectorCache, writeDiscoveryConnectorCache, } from "./discovery-connector.js";
3
- import { loadoutHome } from "./paths.js";
3
+ import { loadoutHome } from "../agents/paths.js";
4
4
  const SOURCE = "skills-sh";
5
5
  const API = "https://skills.sh/api/v1/skills";
6
6
  const ATTRIBUTION = "https://skills.sh/docs/api";
@@ -1,9 +1,9 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { lstat, readFile, readdir } from "node:fs/promises";
3
3
  import { basename, isAbsolute, join, posix, relative, sep } from "node:path";
4
- import { enrichInventoryWithProvenance } from "./provenance.js";
5
- import { scanInstalledSkills } from "./skill-inventory.js";
6
- import { installStatePath, recordInstall } from "./state.js";
4
+ import { enrichInventoryWithProvenance } from "../catalog/provenance.js";
5
+ import { scanInstalledSkills } from "../catalog/skill-inventory.js";
6
+ import { installStatePath, recordInstall } from "../workspace/state.js";
7
7
  import { runMutationTransaction } from "./transaction.js";
8
8
  const issuedAdoptionPlans = new WeakMap();
9
9
  function safeRelativePath(root, path) {
@@ -1,13 +1,13 @@
1
- import { DEFAULT_ACTIVE_SKILL_LIMIT } from "./active-limit.js";
2
- import { loadEffectiveCatalog } from "./catalog.js";
3
- import { detectAgents } from "./paths.js";
4
- import { isStableSkillSelected, isPowerSkillSelected, resolveCatalogProfile, } from "./profiles.js";
1
+ import { DEFAULT_ACTIVE_SKILL_LIMIT } from "../workspace/active-limit.js";
2
+ import { loadEffectiveCatalog, } from "../catalog/catalog.js";
3
+ import { detectAgents } from "../agents/paths.js";
4
+ import { isStableSkillSelected, isPowerSkillSelected, resolveCatalogProfile, } from "../catalog/profiles.js";
5
5
  import { applySkillLibraryBatch, applySkillInstallBatch, buildSkillPlan, installedAgents, planManagedProfileReconciliation, } from "./install.js";
6
6
  import { fetchRepositorySnapshot, } from "./source.js";
7
- import { analyzeInstallPlanSafety, } from "./safety.js";
8
- import { formatModelApiAccess } from "./access.js";
9
- import { recordInstalledProfile } from "./profile-state.js";
10
- import { readInstallState } from "./state.js";
7
+ import { analyzeInstallPlanSafety, } from "../catalog/safety.js";
8
+ import { formatModelApiAccess, } from "../routing/access.js";
9
+ import { recordInstalledProfile } from "../workspace/profile-state.js";
10
+ import { readInstallState } from "../workspace/state.js";
11
11
  async function parallelMap(values, concurrency, worker) {
12
12
  const results = new Array(values.length);
13
13
  let cursor = 0;
@@ -240,11 +240,11 @@ export function formatPreparedCatalogInstall(prepared, options = {}) {
240
240
  const quarantined = prepared.skipped.filter((item) => item.kind === "quarantined");
241
241
  const retired = prepared.reconciliation?.obsoleteUnits ?? [];
242
242
  const modeLabel = prepared.selection.mode === "maximum"
243
- ? "Maximum Library"
243
+ ? "Maximum"
244
244
  : prepared.selection.mode === "power"
245
- ? "Power Boost"
245
+ ? "Power"
246
246
  : prepared.selection.mode === "stable"
247
- ? "Stable Boost"
247
+ ? "Stable"
248
248
  : "Custom";
249
249
  const lines = [
250
250
  `Loadout: ${modeLabel}`,
@@ -1,7 +1,7 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { mkdir, open, readFile, rename, rm, stat, utimes, } from "node:fs/promises";
3
3
  import { dirname } from "node:path";
4
- import { ensureDirectory } from "./paths.js";
4
+ import { ensureDirectory } from "../agents/paths.js";
5
5
  const wait = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));
6
6
  function parseOwner(content) {
7
7
  try {
@@ -1,12 +1,12 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { cp, lstat, rm } from "node:fs/promises";
3
3
  import { basename, dirname, isAbsolute, join, posix, relative, win32, } from "node:path";
4
- import { ensureDirectory, loadoutHome } from "./paths.js";
5
- import { planAdapterSkillInstall } from "./adapters.js";
6
- import { applySkillPlan, detectInstallConflicts } from "./skills.js";
7
- import { activationLibraryPath, installStatePath, recordInstall, recordInstallBatch, recordLibraryInstallBatch, readInstallState, hashDirectory, writeInstallState, } from "./state.js";
4
+ import { ensureDirectory, loadoutHome } from "../agents/paths.js";
5
+ import { planAdapterSkillInstall } from "../agents/adapters.js";
6
+ import { applySkillPlan, detectInstallConflicts } from "../catalog/skills.js";
7
+ import { activationLibraryPath, installStatePath, recordInstall, recordInstallBatch, recordLibraryInstallBatch, readInstallState, hashDirectory, writeInstallState, } from "../workspace/state.js";
8
8
  import { runMutationTransaction } from "./transaction.js";
9
- import { inspectTargetOccupancy } from "./target-occupancy.js";
9
+ import { inspectTargetOccupancy } from "../workspace/target-occupancy.js";
10
10
  export function installedAgents(agents, requested) {
11
11
  const available = agents.filter((agent) => agent.installed);
12
12
  if (!requested || requested.length === 0)