loadout-ai 0.5.8 → 0.6.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 (59) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/MASTER_PLAN.md +9 -9
  3. package/README.md +84 -121
  4. package/catalog/discovered.json +59800 -10065
  5. package/catalog/packages.json +4 -3
  6. package/dist/src/cli.js +26 -2979
  7. package/dist/src/commands/agents.js +168 -0
  8. package/dist/src/commands/catalog.js +708 -0
  9. package/dist/src/commands/health.js +98 -0
  10. package/dist/src/commands/inventory.js +417 -0
  11. package/dist/src/commands/lifecycle.js +411 -0
  12. package/dist/src/commands/mcp.js +424 -0
  13. package/dist/src/commands/setup.js +67 -0
  14. package/dist/src/commands/sharing.js +358 -0
  15. package/dist/src/commands/support.js +246 -0
  16. package/dist/src/core/active-limit.js +2 -0
  17. package/dist/src/core/active-policy.js +2 -1
  18. package/dist/src/core/catalog-install.js +47 -10
  19. package/dist/src/core/catalog.js +15 -96
  20. package/dist/src/core/cli-guide.js +43 -37
  21. package/dist/src/core/completion.js +2 -20
  22. package/dist/src/core/doctor.js +73 -24
  23. package/dist/src/core/github.js +3 -2
  24. package/dist/src/core/handoff.js +161 -0
  25. package/dist/src/core/health-score-evidence.js +2 -2
  26. package/dist/src/core/health.js +83 -0
  27. package/dist/src/core/install.js +8 -3
  28. package/dist/src/core/loadout-card.js +14 -2
  29. package/dist/src/core/review-queue.js +7 -2
  30. package/dist/src/core/route.js +248 -0
  31. package/dist/src/core/skill-inventory.js +3 -3
  32. package/dist/src/core/skills.js +6 -7
  33. package/dist/src/core/source.js +10 -3
  34. package/dist/src/core/upgrade.js +10 -9
  35. package/docs/ACTIVE_SET.md +1 -1
  36. package/docs/ACTIVE_SET_POLICY.md +1 -1
  37. package/docs/CATALOG.md +2 -2
  38. package/docs/DEMO_SCRIPT.md +5 -5
  39. package/docs/DISCOVERED.md +250 -253
  40. package/docs/RELEASE_REVIEW.md +28 -143
  41. package/docs/SUBMISSION_COPY.md +4 -4
  42. package/docs/UPSTREAM_LICENSE_DECISIONS.md +19 -12
  43. package/docs/USER_TEST_GUIDE.md +1 -1
  44. package/docs/evidence/readme-claims.json +2 -14
  45. package/package.json +4 -3
  46. package/dist/src/core/benchmark-campaign.js +0 -496
  47. package/dist/src/core/benchmark-evidence.js +0 -458
  48. package/dist/src/core/benchmark-fixtures.js +0 -1157
  49. package/dist/src/core/benchmark-runner.js +0 -301
  50. package/dist/src/core/benchmark-trust.js +0 -795
  51. package/dist/src/core/catalog-release.js +0 -287
  52. package/dist/src/core/compatibility-intelligence.js +0 -465
  53. package/dist/src/core/ecosystem-import.js +0 -1072
  54. package/dist/src/core/head-to-head.js +0 -437
  55. package/dist/src/core/intelligence-feed-build.js +0 -59
  56. package/dist/src/core/intelligence-feed.js +0 -353
  57. package/dist/src/core/registry-api.js +0 -97
  58. package/dist/src/core/release-claims.js +0 -175
  59. package/dist/src/core/signing.js +0 -115
@@ -62,19 +62,18 @@ export async function discoverSkillDirectories(root, options = {}) {
62
62
  // are validated as content, not recursively treated as additional skills.
63
63
  return;
64
64
  }
65
+ // This loop only runs for directories that are NOT a skill root (a SKILL.md
66
+ // directory returns above). Symlinks encountered while walking the repository
67
+ // tree toward skill roots are skipped. Symlinks *inside* a skill package are
68
+ // rejected by validateSkillDirectory -> scanSkillSecurity at the return above,
69
+ // which fails closed on any nested symlink before the package is copied.
65
70
  for (const entry of entries) {
66
71
  if (entry === ".git" || entry === "node_modules")
67
72
  continue;
68
73
  const child = join(directory, entry);
69
74
  const childStat = await lstat(child);
70
- // Repositories may contain unrelated symlinked documentation or metadata.
71
- // Ignore those while walking, but validate and reject symlinks inside an
72
- // actual skill directory before it is copied.
73
- if (childStat.isSymbolicLink()) {
74
- if (entries.includes("SKILL.md"))
75
- throw new Error(`Refusing symlink in skill package: ${child}`);
75
+ if (childStat.isSymbolicLink())
76
76
  continue;
77
- }
78
77
  // Files such as a root-level SKILL.md are not directories to recurse into.
79
78
  if (childStat.isDirectory())
80
79
  await visit(child, depth + 1);
@@ -302,8 +302,15 @@ function normalizeGitUrl(input) {
302
302
  }
303
303
  /** Fetch a generic Git source without running repository hooks or lifecycle scripts. */
304
304
  export async function fetchGitSnapshot(input, options = {}) {
305
- if (options.maxBytes !== undefined || options.maxFiles !== undefined)
306
- throw new Error("Pre-check size/file bounds are supported only for public GitHub owner/repository sources; refusing an unbounded generic Git clone");
305
+ // A generic Git host has no cheap pre-clone tree API, so size cannot be
306
+ // checked before fetching the way the GitHub path does. Enforce a bound
307
+ // AFTER a shallow clone instead of refusing bounded requests, giving parity
308
+ // with the catalog path and a default ceiling against an adversarial repo.
309
+ const boundedOptions = {
310
+ ...options,
311
+ maxBytes: options.maxBytes ?? 128 * 1024 * 1024,
312
+ maxFiles: options.maxFiles ?? 20_000,
313
+ };
307
314
  const url = normalizeGitUrl(input);
308
315
  const temporary = await mkdtemp(join(tmpdir(), "loadout-git-"));
309
316
  try {
@@ -320,7 +327,7 @@ export async function fetchGitSnapshot(input, options = {}) {
320
327
  const commit = stdout.trim();
321
328
  if (!/^[0-9a-f]{40}$/i.test(commit))
322
329
  throw new Error("Git returned an invalid commit");
323
- await enforceRepositoryBounds(temporary, options);
330
+ await enforceRepositoryBounds(temporary, boundedOptions);
324
331
  const key = createHash("sha256").update(url).digest("hex");
325
332
  const cachePath = join(loadoutHome(), "cache", "git", key, commit);
326
333
  await ensureDirectory(join(loadoutHome(), "cache", "git", key));
@@ -1,5 +1,6 @@
1
1
  import { buildAdapterCapabilityGaps, } from "./adapters.js";
2
- import { applyPreparedCatalogInstall, formatPreparedCatalogInstall, prepareCatalogInstall, RECOMMENDED_ACTIVE_SKILL_LIMIT, } from "./catalog-install.js";
2
+ import { applyPreparedCatalogInstall, formatPreparedCatalogInstall, prepareCatalogInstall, } from "./catalog-install.js";
3
+ import { DEFAULT_ACTIVE_SKILL_LIMIT } from "./active-limit.js";
3
4
  import { loadEffectiveCatalog } from "./catalog.js";
4
5
  import { buildHealthReport, formatHealthReport } from "./health.js";
5
6
  import { buildLocalAgentHealthScores } from "./health-score-evidence.js";
@@ -80,23 +81,23 @@ export async function planUpgrade(selection, options = {}) {
80
81
  const activeSet = selection.mode === "maximum"
81
82
  ? {
82
83
  policy: "disabled-library",
83
- recommendedLimit: RECOMMENDED_ACTIVE_SKILL_LIMIT,
84
+ recommendedLimit: DEFAULT_ACTIVE_SKILL_LIMIT,
84
85
  plannedDirectoriesPerAgent,
85
- exceedsRecommendedLimit: plannedDirectoriesPerAgent > RECOMMENDED_ACTIVE_SKILL_LIMIT,
86
+ exceedsRecommendedLimit: plannedDirectoriesPerAgent > DEFAULT_ACTIVE_SKILL_LIMIT,
86
87
  explanation: "Maximum stores reviewed skills in the disabled library; it does not expose the full library to agent context.",
87
- nextCommand: `loadout optimize --project ${project.root} --limit ${RECOMMENDED_ACTIVE_SKILL_LIMIT}`,
88
+ nextCommand: `loadout optimize --project ${project.root} --limit ${DEFAULT_ACTIVE_SKILL_LIMIT}`,
88
89
  }
89
90
  : {
90
91
  policy: "bounded-active",
91
- recommendedLimit: RECOMMENDED_ACTIVE_SKILL_LIMIT,
92
+ recommendedLimit: DEFAULT_ACTIVE_SKILL_LIMIT,
92
93
  plannedDirectoriesPerAgent,
93
- exceedsRecommendedLimit: plannedDirectoriesPerAgent > RECOMMENDED_ACTIVE_SKILL_LIMIT,
94
- explanation: plannedDirectoriesPerAgent <= RECOMMENDED_ACTIVE_SKILL_LIMIT
94
+ exceedsRecommendedLimit: plannedDirectoriesPerAgent > DEFAULT_ACTIVE_SKILL_LIMIT,
95
+ explanation: plannedDirectoriesPerAgent <= DEFAULT_ACTIVE_SKILL_LIMIT
95
96
  ? "The prepared profile stays within the recommended active-set ceiling."
96
97
  : "The prepared profile exceeds the recommended active-set ceiling; use Stable or project optimization before treating it as a daily active set.",
97
- ...(plannedDirectoriesPerAgent > RECOMMENDED_ACTIVE_SKILL_LIMIT
98
+ ...(plannedDirectoriesPerAgent > DEFAULT_ACTIVE_SKILL_LIMIT
98
99
  ? {
99
- nextCommand: `loadout optimize --project ${project.root} --limit ${RECOMMENDED_ACTIVE_SKILL_LIMIT}`,
100
+ nextCommand: `loadout optimize --project ${project.root} --limit ${DEFAULT_ACTIVE_SKILL_LIMIT}`,
100
101
  }
101
102
  : {}),
102
103
  };
@@ -45,7 +45,7 @@ loadout library
45
45
  loadout disable <package-or-package/skill> [more-selectors] [--agents codex,claude-code]
46
46
  loadout disable <package-or-package/skill> --yes
47
47
  loadout enable <package-or-package/skill> --yes
48
- loadout activate --project . --limit 40
48
+ loadout activate --project . --limit 30
49
49
  loadout optimize --project .
50
50
  loadout rollback --snapshot <id>
51
51
  ```
@@ -34,7 +34,7 @@ filled with fake benchmark or feedback data.
34
34
  ## Commands
35
35
 
36
36
  ```bash
37
- loadout activate --project . --limit 40
37
+ loadout activate --project . --limit 30
38
38
  loadout activate --project . --pin openai-skills/playwright
39
39
  loadout optimize --project .
40
40
  loadout optimize --project . --yes
package/docs/CATALOG.md CHANGED
@@ -27,10 +27,10 @@ The machine-readable catalog remains the source of truth. Run `loadout catalog -
27
27
  | [Anthropic Skills](https://github.com/anthropics/skills) | `anthropic-skills` | agent-skills | `skill` | **Review required** | [`9d2f1ae18723`](https://github.com/anthropics/skills/tree/9d2f1ae187231d8199c64b5b762e1bdf2244733d) |
28
28
  | [Agent Skills Marketplace](https://github.com/wshobson/agents) | `wshobson-agents` | agent-skills | `skill`, `plugin` | `MIT` | [`b6af37110581`](https://github.com/wshobson/agents/tree/b6af3711058190e4b5c5274b9758498fe626ec5a) |
29
29
  | [Vercel Agent Skills](https://github.com/vercel-labs/agent-skills) | `vercel-agent-skills` | frontend-development | `skill` | **Review required** | [`f8a72b960372`](https://github.com/vercel-labs/agent-skills/tree/f8a72b9603728bb92a217a879b7e62e43ad76c81) |
30
- | [Vercel Skills](https://github.com/vercel-labs/skills) | `vercel-skills` | skill-discovery | `skill` | **Review required** | [`5527c09adc36`](https://github.com/vercel-labs/skills/tree/5527c09adc367612b0bffd9c80e3bc28a6b01b6d) |
30
+ | [Vercel Skills](https://github.com/vercel-labs/skills) | `vercel-skills` | skill-discovery | `skill` | `MIT` | [`5527c09adc36`](https://github.com/vercel-labs/skills/tree/5527c09adc367612b0bffd9c80e3bc28a6b01b6d) |
31
31
  | [Cloudflare MCP Server](https://github.com/cloudflare/mcp-server-cloudflare) | `cloudflare-mcp-server` | cloud-platform | `mcp` | `Apache-2.0` | [`52c633e37684`](https://github.com/cloudflare/mcp-server-cloudflare/tree/52c633e37684fadb94ae236f74909b9bbefc0db8) |
32
32
  | [Supabase MCP](https://github.com/supabase/mcp) | `supabase-mcp` | database | `mcp` | `Apache-2.0` | [`9f0396a1b367`](https://github.com/supabase/mcp/tree/9f0396a1b367dfa6a424f4686a21701c8f05b1c3) |
33
- | [Sentry MCP](https://github.com/getsentry/sentry-mcp) | `sentry-mcp` | observability | `skill`, `mcp` | **Review required** | [`ce099fd25197`](https://github.com/getsentry/sentry-mcp/tree/ce099fd251973774116749016847b78a6049ba0a) |
33
+ | [Sentry MCP](https://github.com/getsentry/sentry-mcp) | `sentry-mcp` | observability | `skill`, `mcp` | `FSL-1.1-ALv2` | [`ce099fd25197`](https://github.com/getsentry/sentry-mcp/tree/ce099fd251973774116749016847b78a6049ba0a) |
34
34
  | [Exa MCP Server](https://github.com/exa-labs/exa-mcp-server) | `exa-mcp-server` | web-research | `skill`, `mcp`, `plugin` | `MIT` | [`8823cbea80b6`](https://github.com/exa-labs/exa-mcp-server/tree/8823cbea80b6ec5999c6217cccd91660fe953b97) |
35
35
  | [Firecrawl MCP Server](https://github.com/firecrawl/firecrawl-mcp-server) | `firecrawl-mcp-server` | web-research | `mcp` | `MIT` | [`3eb1115b1f28`](https://github.com/firecrawl/firecrawl-mcp-server/tree/3eb1115b1f2883ff2fb74e61b5c4acf5a9ac0fb0) |
36
36
  | [Azure DevOps MCP](https://github.com/microsoft/azure-devops-mcp) | `azure-devops-mcp` | devops | `mcp` | `MIT` | [`0a08dc649c95`](https://github.com/microsoft/azure-devops-mcp/tree/0a08dc649c951208eda942154c66187dec9985bd) |
@@ -10,7 +10,7 @@ not show the retired dashboard. The final YouTube upload must be public.
10
10
  2. Confirm the release and product health:
11
11
 
12
12
  ```bash
13
- npm install --global loadout-ai@0.5.8
13
+ npm install --global loadout-ai@0.5.9
14
14
  hash -r
15
15
  loadout --version
16
16
  loadout health
@@ -113,14 +113,14 @@ loadout install --mode custom --package humanizer --agents codex
113
113
 
114
114
  ```bash
115
115
  loadout update
116
- loadout discover --limit 5
116
+ loadout candidate list --limit 5
117
117
  ```
118
118
 
119
119
  **Say:**
120
120
 
121
- > Update checks managed pinned sources without silently changing them. Discovery
122
- > watches a wider ecosystem and queues new projects for review, so something going
123
- > viral can be noticed quickly without being trusted blindly.
121
+ > Update checks managed pinned sources without silently changing them. The discovery
122
+ > feed watches a wider ecosystem and ranks new projects for review. A repository can
123
+ > be noticed quickly without being trusted or installed blindly.
124
124
 
125
125
  ### 2:25 to 2:48: Codex, GPT-5.6, and close
126
126