loadout-ai 0.5.7 → 0.5.9

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 (54) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/MASTER_PLAN.md +22 -22
  3. package/README.md +29 -18
  4. package/catalog/discovered.json +56105 -9991
  5. package/catalog/packages.json +2 -1
  6. package/dist/src/cli.js +26 -2978
  7. package/dist/src/commands/agents.js +168 -0
  8. package/dist/src/commands/catalog.js +578 -0
  9. package/dist/src/commands/health.js +98 -0
  10. package/dist/src/commands/inventory.js +416 -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 +226 -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 +57 -13
  19. package/dist/src/core/catalog.js +2 -96
  20. package/dist/src/core/cli-guide.js +39 -34
  21. package/dist/src/core/completion.js +2 -20
  22. package/dist/src/core/github.js +3 -2
  23. package/dist/src/core/health-score-evidence.js +2 -2
  24. package/dist/src/core/health.js +83 -0
  25. package/dist/src/core/install.js +8 -3
  26. package/dist/src/core/loadout-card.js +14 -2
  27. package/dist/src/core/skill-inventory.js +3 -3
  28. package/dist/src/core/skills.js +6 -7
  29. package/dist/src/core/source.js +10 -3
  30. package/dist/src/core/upgrade.js +10 -9
  31. package/docs/ACTIVE_SET.md +1 -1
  32. package/docs/ACTIVE_SET_POLICY.md +1 -1
  33. package/docs/DEMO_SCRIPT.md +23 -22
  34. package/docs/DISCOVERED.md +249 -253
  35. package/docs/RELEASE_REVIEW.md +28 -143
  36. package/docs/SUBMISSION_COPY.md +90 -0
  37. package/docs/UPSTREAM_LICENSE_DECISIONS.md +32 -0
  38. package/docs/USER_TEST_GUIDE.md +1 -1
  39. package/docs/evidence/readme-claims.json +2 -14
  40. package/package.json +4 -3
  41. package/dist/src/core/benchmark-campaign.js +0 -496
  42. package/dist/src/core/benchmark-evidence.js +0 -458
  43. package/dist/src/core/benchmark-fixtures.js +0 -1157
  44. package/dist/src/core/benchmark-runner.js +0 -301
  45. package/dist/src/core/benchmark-trust.js +0 -795
  46. package/dist/src/core/catalog-release.js +0 -287
  47. package/dist/src/core/compatibility-intelligence.js +0 -465
  48. package/dist/src/core/ecosystem-import.js +0 -1072
  49. package/dist/src/core/head-to-head.js +0 -437
  50. package/dist/src/core/intelligence-feed-build.js +0 -59
  51. package/dist/src/core/intelligence-feed.js +0 -353
  52. package/dist/src/core/registry-api.js +0 -97
  53. package/dist/src/core/release-claims.js +0 -175
  54. package/dist/src/core/signing.js +0 -115
@@ -0,0 +1,168 @@
1
+ import { detectAgents, parseAgentSelection } from "../core/paths.js";
2
+ import { DEFAULT_ACTIVE_SKILL_LIMIT } from "../core/active-limit.js";
3
+ import { resolve } from "node:path";
4
+ import { writeFileAtomically } from "../core/atomic-file.js";
5
+ import { applyActivationChange, formatActivationPlan, planActivationChange, } from "../core/active-set.js";
6
+ import { applyProjectActivation, formatProjectActivation, planProjectActivation, } from "../core/active-policy.js";
7
+ import { applyNativeSchedulerBundle, formatNativeScheduler, planNativeScheduler, } from "../core/scheduler.js";
8
+ import { REVIEWED_RUNTIME_TOOLS, applyRuntimeToolPlan, formatRuntimeToolPlan, planRuntimeTool, } from "../core/runtime-tools.js";
9
+ import { buildLoadoutCard } from "../core/loadout-card.js";
10
+ import { buildLoadoutBadge, formatLoadoutBadgeUsage, parseLoadoutBadgeMetric, } from "../core/loadout-badge.js";
11
+ import { collectOption, durableSchedulerLauncher } from "./support.js";
12
+ export function registerAgents(program) {
13
+ for (const workflow of ["activate", "optimize"]) {
14
+ program
15
+ .command(workflow)
16
+ .description(workflow === "activate"
17
+ ? "Select and activate inspected library skills for a project"
18
+ : "Scan a project and propose rule-selected inspected active-set additions")
19
+ .option("--project <path>", "project directory to scan", ".")
20
+ .option("--agents <ids>", "comma-separated agent ids")
21
+ .option("--limit <count>", `maximum active skills per agent (recommended default: ${DEFAULT_ACTIVE_SKILL_LIMIT})`, String(DEFAULT_ACTIVE_SKILL_LIMIT))
22
+ .option("--pin <selector>", "always prioritize package/skill or skill", collectOption, [])
23
+ .option("--yes", "apply the proposed activation transaction")
24
+ .option("--json", "emit machine-readable JSON")
25
+ .action(async (options) => {
26
+ const agents = options.agents
27
+ ?.split(",")
28
+ .map((value) => value.trim())
29
+ .filter(Boolean);
30
+ const plan = await planProjectActivation(options.project, {
31
+ ...(agents?.length ? { agents } : {}),
32
+ limit: Number(options.limit),
33
+ pins: options.pin,
34
+ });
35
+ if (!options.yes) {
36
+ console.log(options.json
37
+ ? JSON.stringify(plan, null, 2)
38
+ : `${formatProjectActivation(plan)}\nDry run only. Re-run with --yes to activate this reviewed set.`);
39
+ return;
40
+ }
41
+ const snapshotId = await applyProjectActivation(plan);
42
+ console.log(options.json
43
+ ? JSON.stringify({ plan, snapshotId }, null, 2)
44
+ : `${formatProjectActivation(plan)}\nApplied and verified. Snapshot: ${snapshotId}\nRollback: loadout rollback --snapshot ${snapshotId}`);
45
+ });
46
+ }
47
+ for (const action of [
48
+ "enable",
49
+ "disable",
50
+ ]) {
51
+ program
52
+ .command(action)
53
+ .description(`${action === "enable" ? "Activate" : "Deactivate"} Loadout-managed skills without deleting the reviewed-library copy`)
54
+ .argument("<packages...>", "one or more managed package ids")
55
+ .option("--agents <ids>", "comma-separated agent ids")
56
+ .option("--yes", "apply the transaction; otherwise show a plan")
57
+ .option("--json", "emit machine-readable JSON")
58
+ .action(async (packageIds, options) => {
59
+ const agents = options.agents
60
+ ?.split(",")
61
+ .map((value) => value.trim())
62
+ .filter(Boolean);
63
+ if (agents?.length) {
64
+ const known = new Set((await detectAgents()).map((agent) => agent.id));
65
+ const unknown = agents.filter((agent) => !known.has(agent));
66
+ if (unknown.length)
67
+ throw new Error(`Unknown agent id(s): ${unknown.join(", ")}`);
68
+ }
69
+ const plan = await planActivationChange(action, packageIds, {
70
+ ...(agents?.length ? { agents } : {}),
71
+ });
72
+ if (!options.yes) {
73
+ console.log(options.json
74
+ ? JSON.stringify(plan, null, 2)
75
+ : `${formatActivationPlan(plan)}\nDry run only. Re-run with --yes to apply this exact transaction.`);
76
+ return;
77
+ }
78
+ const snapshotId = await applyActivationChange(plan);
79
+ console.log(options.json
80
+ ? JSON.stringify({ plan, snapshotId }, null, 2)
81
+ : `${formatActivationPlan(plan)}\nApplied. Snapshot: ${snapshotId}`);
82
+ });
83
+ }
84
+ program
85
+ .command("autopilot")
86
+ .description("Preview or enable both daily read-only discovery and update radar jobs")
87
+ .option("--time <HH:MM>", "local daily check time", "09:00")
88
+ .option("--remove", "remove both daily radar jobs")
89
+ .option("--yes", "apply both native scheduler changes atomically")
90
+ .option("--json", "emit machine-readable JSON")
91
+ .action(async (options) => {
92
+ const action = options.remove
93
+ ? "unschedule"
94
+ : "schedule";
95
+ const plans = ["updates", "discovery"].map((job) => planNativeScheduler(action, {
96
+ time: options.time,
97
+ launcher: durableSchedulerLauncher(),
98
+ job,
99
+ }));
100
+ if (!options.yes) {
101
+ console.log(options.json
102
+ ? JSON.stringify({ action, plans }, null, 2)
103
+ : `${plans.map(formatNativeScheduler).join("\n\n")}\n\nDry run only. Re-run with --yes to ${options.remove ? "remove" : "enable"} both read-only jobs.`);
104
+ return;
105
+ }
106
+ const snapshotId = await applyNativeSchedulerBundle(plans);
107
+ console.log(options.json
108
+ ? JSON.stringify({ action, plans, snapshotId }, null, 2)
109
+ : `Loadout Autopilot ${options.remove ? "removed" : "enabled"}: daily update radar + multi-source candidate discovery.\nNo scheduled command can install, promote, or execute a candidate. Snapshot: ${snapshotId}`);
110
+ });
111
+ program
112
+ .command("badge")
113
+ .description("Generate telemetry-free Shields endpoint JSON from the local privacy-safe card")
114
+ .option("--metric <metric>", "evidence, active-skills, managed-packages, or mcp", "evidence")
115
+ .option("--output <path>", "write endpoint JSON to this path")
116
+ .action(async (options) => {
117
+ const badge = buildLoadoutBadge(await buildLoadoutCard(), parseLoadoutBadgeMetric(options.metric));
118
+ if (!options.output)
119
+ return console.log(JSON.stringify(badge, null, 2));
120
+ const output = resolve(options.output);
121
+ await writeFileAtomically(output, `${JSON.stringify(badge, null, 2)}\n`);
122
+ console.log(formatLoadoutBadgeUsage(output));
123
+ });
124
+ program
125
+ .command("tool")
126
+ .description("Preview, install, or remove an explicitly reviewed runtime-tool recipe")
127
+ .argument("[id]", "runtime tool id; omit to list reviewed recipes")
128
+ .option("--agents <ids>", "comma-separated target agent ids")
129
+ .option("--remove", "restore pre-install agent state and remove the runtime")
130
+ .option("--yes", "apply the exact displayed plan")
131
+ .option("--approve-risk", "approve installing and running the exact reviewed external artifact")
132
+ .option("--json", "emit machine-readable JSON")
133
+ .action(async (id, options) => {
134
+ if (!id) {
135
+ if (options.remove || options.yes || options.approveRisk)
136
+ throw new Error("Select a runtime tool id for this operation");
137
+ const listed = REVIEWED_RUNTIME_TOOLS.map((recipe) => ({
138
+ id: recipe.id,
139
+ displayName: recipe.displayName,
140
+ version: recipe.version,
141
+ source: recipe.source,
142
+ artifactSha256: recipe.artifactSha256,
143
+ }));
144
+ console.log(options.json
145
+ ? JSON.stringify(listed, null, 2)
146
+ : listed
147
+ .map((recipe) => `${recipe.id} — ${recipe.displayName} ${recipe.version} — ${recipe.source}`)
148
+ .join("\n"));
149
+ return;
150
+ }
151
+ const plan = await planRuntimeTool(id, {
152
+ action: options.remove ? "remove" : "install",
153
+ requestedAgents: parseAgentSelection(options.agents),
154
+ });
155
+ if (!options.yes) {
156
+ console.log(options.json
157
+ ? JSON.stringify(plan, null, 2)
158
+ : `${formatRuntimeToolPlan(plan)}\n\nDry run only. Re-run with --yes --approve-risk to apply this exact runtime recipe.`);
159
+ return;
160
+ }
161
+ if (!options.approveRisk)
162
+ throw new Error("Runtime tool changes require --approve-risk after reviewing the preview");
163
+ const result = await applyRuntimeToolPlan(plan, { approveRisk: true });
164
+ console.log(options.json
165
+ ? JSON.stringify({ plan, result }, null, 2)
166
+ : `${plan.recipe.displayName} ${result.action === "install" ? "installed and registered" : "removed and prior agent state restored"}. Snapshot: ${result.snapshotId}`);
167
+ });
168
+ }