loadout-ai 0.5.9 → 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.
- package/README.md +181 -121
- package/catalog/discovered.json +28066 -23196
- package/catalog/packages.json +2 -2
- package/dist/src/cli.js +2 -2
- package/dist/src/commands/agents.js +6 -23
- package/dist/src/commands/catalog.js +254 -27
- package/dist/src/commands/health.js +6 -6
- package/dist/src/commands/inventory.js +21 -121
- package/dist/src/commands/lifecycle.js +13 -51
- package/dist/src/commands/mcp.js +10 -73
- package/dist/src/commands/setup.js +5 -5
- package/dist/src/commands/sharing.js +11 -108
- package/dist/src/commands/support.js +42 -11
- package/dist/src/core/{adapters.js → agents/adapters.js} +2 -2
- package/dist/src/core/{agent-inspection.js → agents/agent-inspection.js} +26 -6
- package/dist/src/core/{codex-mcp.js → agents/codex-mcp.js} +1 -1
- package/dist/src/core/{health-score-evidence.js → agents/health-score-evidence.js} +8 -8
- package/dist/src/core/{runtime-tools.js → agents/runtime-tools.js} +2 -2
- package/dist/src/core/{audit.js → catalog/audit.js} +4 -4
- package/dist/src/core/{catalog.js → catalog/catalog.js} +18 -5
- package/dist/src/core/{components.js → catalog/components.js} +2 -2
- package/dist/src/core/{conformance.js → catalog/conformance.js} +2 -2
- package/dist/src/core/{profiles.js → catalog/profiles.js} +2 -2
- package/dist/src/core/{provenance.js → catalog/provenance.js} +3 -3
- package/dist/src/core/{registry.js → catalog/registry.js} +1 -1
- package/dist/src/core/{skill-compare.js → catalog/skill-compare.js} +1 -1
- package/dist/src/core/{skill-inventory.js → catalog/skill-inventory.js} +3 -3
- package/dist/src/core/{skills.js → catalog/skills.js} +1 -1
- package/dist/src/core/{candidate-intelligence.js → discovery/candidate-intelligence.js} +6 -6
- package/dist/src/core/{discovery-connector.js → discovery/discovery-connector.js} +2 -2
- package/dist/src/core/{evaluate.js → discovery/evaluate.js} +2 -2
- package/dist/src/core/{mcp-registry-discovery.js → discovery/mcp-registry-discovery.js} +1 -1
- package/dist/src/core/{observations.js → discovery/observations.js} +3 -3
- package/dist/src/core/{review-queue.js → discovery/review-queue.js} +9 -4
- package/dist/src/core/{skills-sh-discovery.js → discovery/skills-sh-discovery.js} +1 -1
- package/dist/src/core/{adopt.js → install/adopt.js} +3 -3
- package/dist/src/core/{catalog-install.js → install/catalog-install.js} +11 -11
- package/dist/src/core/{file-lock.js → install/file-lock.js} +1 -1
- package/dist/src/core/{install.js → install/install.js} +5 -5
- package/dist/src/core/{package.js → install/package.js} +3 -3
- package/dist/src/core/{reconcile.js → install/reconcile.js} +5 -5
- package/dist/src/core/{remove.js → install/remove.js} +4 -4
- package/dist/src/core/{snapshot.js → install/snapshot.js} +1 -1
- package/dist/src/core/{source.js → install/source.js} +1 -1
- package/dist/src/core/{sync.js → install/sync.js} +9 -9
- package/dist/src/core/{transaction.js → install/transaction.js} +1 -1
- package/dist/src/core/{uninstall.js → install/uninstall.js} +4 -4
- package/dist/src/core/{update.js → install/update.js} +4 -4
- package/dist/src/core/reporting/cli-guide.js +103 -0
- package/dist/src/core/reporting/doctor.js +141 -0
- package/dist/src/core/{freshness-alerts.js → reporting/freshness-alerts.js} +5 -5
- package/dist/src/core/{health.js → reporting/health.js} +6 -6
- package/dist/src/core/{loadout-card.js → reporting/loadout-card.js} +1 -1
- package/dist/src/core/{readme-claims.js → reporting/readme-claims.js} +1 -1
- package/dist/src/core/{readme-facts.js → reporting/readme-facts.js} +2 -2
- package/dist/src/core/{share-report.js → reporting/share-report.js} +3 -3
- package/dist/src/core/{upgrade.js → reporting/upgrade.js} +7 -7
- package/dist/src/core/routing/first-party-skills.js +118 -0
- package/dist/src/core/routing/handoff.js +278 -0
- package/dist/src/core/{model-config.js → routing/model-config.js} +4 -4
- package/dist/src/core/routing/route.js +539 -0
- package/dist/src/core/{api.js → runtime/api.js} +4 -4
- package/dist/src/core/{canary.js → runtime/canary.js} +1 -1
- package/dist/src/core/{github.js → runtime/github.js} +1 -1
- package/dist/src/core/{mcp-recipes.js → runtime/mcp-recipes.js} +1 -1
- package/dist/src/core/{mcp.js → runtime/mcp.js} +2 -2
- package/dist/src/core/{scheduler.js → runtime/scheduler.js} +4 -4
- package/dist/src/core/{active-policy.js → workspace/active-policy.js} +2 -2
- package/dist/src/core/{active-set.js → workspace/active-set.js} +2 -2
- package/dist/src/core/{improve.js → workspace/improve.js} +3 -3
- package/dist/src/core/{manifest.js → workspace/manifest.js} +2 -2
- package/dist/src/core/{outcomes.js → workspace/outcomes.js} +3 -3
- package/dist/src/core/{portable.js → workspace/portable.js} +3 -3
- package/dist/src/core/{profile-state.js → workspace/profile-state.js} +1 -1
- package/dist/src/core/{recommend.js → workspace/recommend.js} +1 -1
- package/dist/src/core/{state.js → workspace/state.js} +3 -3
- package/docs/CATALOG.md +2 -2
- package/docs/DISCOVERED.md +249 -247
- package/docs/UPSTREAM_LICENSE_DECISIONS.md +19 -12
- package/docs/evidence/readme-claims.json +22 -19
- package/package.json +2 -1
- package/skills/loadout-curator/SKILL.md +105 -0
- package/skills/loadout-router/SKILL.md +120 -0
- package/dist/src/core/cli-guide.js +0 -118
- package/dist/src/core/doctor.js +0 -95
- /package/dist/src/core/{agent-health-score.js → agents/agent-health-score.js} +0 -0
- /package/dist/src/core/{agent-versions.js → agents/agent-versions.js} +0 -0
- /package/dist/src/core/{conversion.js → agents/conversion.js} +0 -0
- /package/dist/src/core/{paths.js → agents/paths.js} +0 -0
- /package/dist/src/core/{runtime-tool-recipe.js → agents/runtime-tool-recipe.js} +0 -0
- /package/dist/src/core/{catalog-coverage.js → catalog/catalog-coverage.js} +0 -0
- /package/dist/src/core/{safety.js → catalog/safety.js} +0 -0
- /package/dist/src/core/{skill-security.js → catalog/skill-security.js} +0 -0
- /package/dist/src/core/{community.js → discovery/community.js} +0 -0
- /package/dist/src/core/{github-discovery.js → discovery/github-discovery.js} +0 -0
- /package/dist/src/core/{private-discovery.js → discovery/private-discovery.js} +0 -0
- /package/dist/src/core/{ranking.js → discovery/ranking.js} +0 -0
- /package/dist/src/core/{atomic-file.js → install/atomic-file.js} +0 -0
- /package/dist/src/core/{diff.js → install/diff.js} +0 -0
- /package/dist/src/core/{update-watch.js → install/update-watch.js} +0 -0
- /package/dist/src/core/{completion.js → reporting/completion.js} +0 -0
- /package/dist/src/core/{loadout-badge.js → reporting/loadout-badge.js} +0 -0
- /package/dist/src/core/{terminal.js → reporting/terminal.js} +0 -0
- /package/dist/src/core/{access.js → routing/access.js} +0 -0
- /package/dist/src/core/{credentials.js → routing/credentials.js} +0 -0
- /package/dist/src/core/{sandbox.js → runtime/sandbox.js} +0 -0
- /package/dist/src/core/{active-limit.js → workspace/active-limit.js} +0 -0
- /package/dist/src/core/{target-occupancy.js → workspace/target-occupancy.js} +0 -0
|
@@ -1,20 +1,18 @@
|
|
|
1
|
-
import { loadEffectiveCatalog, } from "../core/catalog.js";
|
|
2
|
-
import { detectAgents, parseAgentSelection } from "../core/paths.js";
|
|
1
|
+
import { loadEffectiveCatalog, } from "../core/catalog/catalog.js";
|
|
2
|
+
import { detectAgents, parseAgentSelection } from "../core/agents/paths.js";
|
|
3
3
|
import { readFile } from "node:fs/promises";
|
|
4
4
|
import { resolve } from "node:path";
|
|
5
|
-
import { buildSkillPlan, applySkillInstall, installedAgents, } from "../core/install.js";
|
|
6
|
-
import { listSnapshotIds, readSnapshot, restoreSnapshot, summarizeSnapshot, } from "../core/snapshot.js";
|
|
7
|
-
import { fetchRepositorySnapshot } from "../core/source.js";
|
|
8
|
-
import { applyPackageUpdate, buildUpdatePlan, formatUpdatePlan, selectSafeAutomaticUpdates, } from "../core/update.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import { applyPreparedCatalogInstall, formatCatalogApplyGuidance, formatPreparedCatalogInstall, prepareCatalogInstall, } from "../core/catalog-install.js";
|
|
17
|
-
import { withMutationLock } from "../core/transaction.js";
|
|
5
|
+
import { buildSkillPlan, applySkillInstall, installedAgents, } from "../core/install/install.js";
|
|
6
|
+
import { listSnapshotIds, readSnapshot, restoreSnapshot, summarizeSnapshot, } from "../core/install/snapshot.js";
|
|
7
|
+
import { fetchRepositorySnapshot } from "../core/install/source.js";
|
|
8
|
+
import { applyPackageUpdate, buildUpdatePlan, formatUpdatePlan, selectSafeAutomaticUpdates, } from "../core/install/update.js";
|
|
9
|
+
import { readInstallState } from "../core/workspace/state.js";
|
|
10
|
+
import { evaluateInstalledProfile, formatInstalledProfileStatus, } from "../core/workspace/profile-state.js";
|
|
11
|
+
import { resolveCatalogProfile } from "../core/catalog/profiles.js";
|
|
12
|
+
import { compileConversion, } from "../core/agents/conversion.js";
|
|
13
|
+
import { writeFileAtomically } from "../core/install/atomic-file.js";
|
|
14
|
+
import { applyPreparedCatalogInstall, formatCatalogApplyGuidance, formatPreparedCatalogInstall, prepareCatalogInstall, } from "../core/install/catalog-install.js";
|
|
15
|
+
import { withMutationLock } from "../core/install/transaction.js";
|
|
18
16
|
import { setupSelection, printSetupProgress } from "./support.js";
|
|
19
17
|
export function registerLifecycle(program) {
|
|
20
18
|
program
|
|
@@ -372,40 +370,4 @@ export function registerLifecycle(program) {
|
|
|
372
370
|
? "Manual approval is required before using this artifact."
|
|
373
371
|
: "No additional approval is required."));
|
|
374
372
|
});
|
|
375
|
-
program
|
|
376
|
-
.command("canary")
|
|
377
|
-
.description("Run a static canary policy gate for a candidate without installing it")
|
|
378
|
-
.requiredOption("--source <directory>", "candidate package directory")
|
|
379
|
-
.requiredOption("--package <id>", "candidate package id")
|
|
380
|
-
.option("--repository <owner/repo>", "candidate repository")
|
|
381
|
-
.option("--commit <sha>", "candidate immutable commit")
|
|
382
|
-
.option("--approve", "approve promotion if a promotion callback is supplied")
|
|
383
|
-
.option("--allow-unready", "allow review findings in the static gate")
|
|
384
|
-
.option("--json", "emit machine-readable JSON")
|
|
385
|
-
.action(async (options) => {
|
|
386
|
-
const result = await runCanary({
|
|
387
|
-
packageId: options.package,
|
|
388
|
-
root: options.source,
|
|
389
|
-
...(options.repository ? { repository: options.repository } : {}),
|
|
390
|
-
...(options.commit ? { commit: options.commit } : {}),
|
|
391
|
-
}, { enabled: true, requireStaticReady: !options.allowUnready }, { approve: options.approve });
|
|
392
|
-
console.log(options.json
|
|
393
|
-
? JSON.stringify(result, null, 2)
|
|
394
|
-
: formatCanaryResult(result));
|
|
395
|
-
if (result.status === "blocked")
|
|
396
|
-
process.exitCode = 1;
|
|
397
|
-
});
|
|
398
|
-
program
|
|
399
|
-
.command("serve")
|
|
400
|
-
.description("Start a loopback-only read-only API for status, health, catalog, and updates")
|
|
401
|
-
.option("--port <port>", "TCP port (0 selects an available port)", "0")
|
|
402
|
-
.action(async (options) => {
|
|
403
|
-
const handle = await startApiServer({ port: Number(options.port) });
|
|
404
|
-
console.log(`Loadout API listening at http://${handle.host}:${handle.port}`);
|
|
405
|
-
await new Promise((resolve) => {
|
|
406
|
-
process.once("SIGINT", resolve);
|
|
407
|
-
process.once("SIGTERM", resolve);
|
|
408
|
-
});
|
|
409
|
-
await handle.close();
|
|
410
|
-
});
|
|
411
373
|
}
|
package/dist/src/commands/mcp.js
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import { userHome } from "../core/paths.js";
|
|
1
|
+
import { userHome } from "../core/agents/paths.js";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import { fetchRepositorySnapshot } from "../core/source.js";
|
|
5
|
-
import { discoverMcpManifests, summarizeMcpManifest, planMcpConfig, summarizeMcpConfigPlan, applyMcpConfigPlan, } from "../core/mcp.js";
|
|
6
|
-
import { REVIEWED_MCP_RECIPES, buildMcpRecipeServer, findMcpRecipe, formatMcpRecipePlan, planMcpRecipe, verifyMcpRecipe, verifyMcpRecipeConnection, } from "../core/mcp-recipes.js";
|
|
7
|
-
import { inspectPackage, formatPackageInspection } from "../core/package.js";
|
|
8
|
-
import { installStatePath, recordInstallTransaction, recordMcpInstall, } from "../core/state.js";
|
|
9
|
-
import { applyCodexMcpConfigPlan, codexMcpServerFingerprint, defaultCodexMcpConfigPath, planCodexMcpConfig, } from "../core/codex-mcp.js";
|
|
10
|
-
import { evaluatePackage, formatPackageEvaluation } from "../core/evaluate.js";
|
|
11
|
-
import { checkForUpdates, startUpdateWatcher } from "../core/update-watch.js";
|
|
12
|
-
import {
|
|
13
|
-
import { applyNativeScheduler, formatNativeScheduler, planNativeScheduler, } from "../core/scheduler.js";
|
|
4
|
+
import { fetchRepositorySnapshot } from "../core/install/source.js";
|
|
5
|
+
import { discoverMcpManifests, summarizeMcpManifest, planMcpConfig, summarizeMcpConfigPlan, applyMcpConfigPlan, } from "../core/runtime/mcp.js";
|
|
6
|
+
import { REVIEWED_MCP_RECIPES, buildMcpRecipeServer, findMcpRecipe, formatMcpRecipePlan, planMcpRecipe, verifyMcpRecipe, verifyMcpRecipeConnection, } from "../core/runtime/mcp-recipes.js";
|
|
7
|
+
import { inspectPackage, formatPackageInspection, } from "../core/install/package.js";
|
|
8
|
+
import { installStatePath, recordInstallTransaction, recordMcpInstall, } from "../core/workspace/state.js";
|
|
9
|
+
import { applyCodexMcpConfigPlan, codexMcpServerFingerprint, defaultCodexMcpConfigPath, planCodexMcpConfig, } from "../core/agents/codex-mcp.js";
|
|
10
|
+
import { evaluatePackage, formatPackageEvaluation, } from "../core/discovery/evaluate.js";
|
|
11
|
+
import { checkForUpdates, startUpdateWatcher, } from "../core/install/update-watch.js";
|
|
12
|
+
import { applyNativeScheduler, formatNativeScheduler, planNativeScheduler, } from "../core/runtime/scheduler.js";
|
|
14
13
|
import { collectOption, parseMcpCredentialMappings, durableSchedulerLauncher, } from "./support.js";
|
|
15
14
|
export function registerMcp(program) {
|
|
16
15
|
program
|
|
@@ -318,29 +317,6 @@ export function registerMcp(program) {
|
|
|
318
317
|
: `${formatNativeScheduler(plan)}\nApplied. Snapshot: ${snapshotId}`);
|
|
319
318
|
});
|
|
320
319
|
}
|
|
321
|
-
program
|
|
322
|
-
.command("sandbox-run")
|
|
323
|
-
.description("Run an explicitly approved command in a disposable networkless Docker sandbox")
|
|
324
|
-
.requiredOption("--source <directory>", "read-only source directory")
|
|
325
|
-
.requiredOption("--image <image>", "reviewed/pinned Docker image reference")
|
|
326
|
-
.requiredOption("--command <argument>", "command argument (repeatable; first is executable)", (value, previous = []) => [...previous, value], [])
|
|
327
|
-
.requiredOption("--approve-risk", "explicitly approve sandbox execution")
|
|
328
|
-
.option("--timeout <milliseconds>", "execution timeout", "120000")
|
|
329
|
-
.option("--json", "emit result JSON")
|
|
330
|
-
.action(async (options) => {
|
|
331
|
-
const result = await runDisposableSandbox({
|
|
332
|
-
sourceDirectory: options.source,
|
|
333
|
-
image: options.image,
|
|
334
|
-
command: options.command,
|
|
335
|
-
approveRisk: options.approveRisk,
|
|
336
|
-
timeoutMs: Number(options.timeout),
|
|
337
|
-
});
|
|
338
|
-
console.log(options.json
|
|
339
|
-
? JSON.stringify(result, null, 2)
|
|
340
|
-
: `Sandbox exited ${result.exitCode}\n${result.stdout}${result.stderr ? `\n${result.stderr}` : ""}`);
|
|
341
|
-
if (result.exitCode !== 0)
|
|
342
|
-
process.exitCode = result.exitCode;
|
|
343
|
-
});
|
|
344
320
|
program
|
|
345
321
|
.command("mcp-config")
|
|
346
322
|
.description("Plan or apply a safe MCP server configuration change (dry-run by default)")
|
|
@@ -382,43 +358,4 @@ export function registerMcp(program) {
|
|
|
382
358
|
const snapshot = await applyMcpConfigPlan(plan);
|
|
383
359
|
console.log(`Applied successfully. Snapshot: ${snapshot.rollbackSnapshotId}`);
|
|
384
360
|
});
|
|
385
|
-
program
|
|
386
|
-
.command("codex-mcp-config")
|
|
387
|
-
.description("Plan or add a Codex TOML MCP server (dry-run by default)")
|
|
388
|
-
.option("--config <path>", "Codex config.toml path", defaultCodexMcpConfigPath())
|
|
389
|
-
.requiredOption("--name <name>", "server name")
|
|
390
|
-
.option("--command <command>", "local server command")
|
|
391
|
-
.option("--url <url>", "remote MCP server URL")
|
|
392
|
-
.option("--arg <value>", "server argument (repeatable)", (value, previous = []) => [...previous, value], [])
|
|
393
|
-
.option("--env <NAME=VALUE>", "environment variable (repeatable; values are never printed)", (value, previous = []) => [...previous, value], [])
|
|
394
|
-
.option("--yes", "apply the change; without this flag only a plan is shown")
|
|
395
|
-
.action(async (options) => {
|
|
396
|
-
if ((options.command ? 1 : 0) + (options.url ? 1 : 0) !== 1)
|
|
397
|
-
throw new Error("Provide exactly one of --command or --url");
|
|
398
|
-
const env = {};
|
|
399
|
-
for (const item of options.env) {
|
|
400
|
-
const separator = item.indexOf("=");
|
|
401
|
-
if (separator <= 0)
|
|
402
|
-
throw new Error(`Invalid --env '${item}'; expected NAME=VALUE`);
|
|
403
|
-
const key = item.slice(0, separator);
|
|
404
|
-
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key))
|
|
405
|
-
throw new Error(`Invalid environment variable name '${key}'`);
|
|
406
|
-
env[key] = item.slice(separator + 1);
|
|
407
|
-
}
|
|
408
|
-
const server = {
|
|
409
|
-
name: options.name,
|
|
410
|
-
command: options.command,
|
|
411
|
-
url: options.url,
|
|
412
|
-
args: options.arg,
|
|
413
|
-
env,
|
|
414
|
-
sourcePath: options.config,
|
|
415
|
-
warnings: [],
|
|
416
|
-
};
|
|
417
|
-
const plan = await planCodexMcpConfig(options.config, server);
|
|
418
|
-
console.log(`Codex config: ${plan.path}\n - ${plan.summary}`);
|
|
419
|
-
if (!options.yes)
|
|
420
|
-
return console.log("Dry run only. Re-run with --yes to add this Codex MCP server.");
|
|
421
|
-
const snapshot = await applyCodexMcpConfigPlan(plan);
|
|
422
|
-
console.log(`Applied successfully. Snapshot: ${snapshot.rollbackSnapshotId}`);
|
|
423
|
-
});
|
|
424
361
|
}
|
|
@@ -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 {
|
|
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,
|
|
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,
|
|
13
|
-
import {
|
|
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,10 +1,12 @@
|
|
|
1
1
|
import { createInterface } from "node:readline/promises";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { detectAgents, parseAgentSelection } from "../core/agents/paths.js";
|
|
4
|
+
import { dirname, join, resolve } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
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";
|
|
8
10
|
export const collectOption = (value, previous = []) => [...previous, value];
|
|
9
11
|
export function parseMcpCredentialMappings(recipe, mappings, account) {
|
|
10
12
|
const references = {};
|
|
@@ -103,7 +105,16 @@ export async function runSetup(options) {
|
|
|
103
105
|
try {
|
|
104
106
|
if (!mode) {
|
|
105
107
|
if (!interactive) {
|
|
106
|
-
console.log(
|
|
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"));
|
|
107
118
|
return;
|
|
108
119
|
}
|
|
109
120
|
reader = createInterface({
|
|
@@ -112,9 +123,11 @@ export async function runSetup(options) {
|
|
|
112
123
|
});
|
|
113
124
|
const answer = (await reader.question([
|
|
114
125
|
"Choose a loadout:",
|
|
115
|
-
" [1] Stable —
|
|
116
|
-
" [2] Power —
|
|
117
|
-
" [3] Maximum — download
|
|
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.",
|
|
118
131
|
" [4] Custom — pick exact package ids",
|
|
119
132
|
"> ",
|
|
120
133
|
].join("\n"))).trim();
|
|
@@ -213,7 +226,25 @@ export async function runWizard() {
|
|
|
213
226
|
console.log("\nPreview first — nothing changes until you approve, and every change is snapshotted for rollback.\n");
|
|
214
227
|
await runSetup({ package: [] });
|
|
215
228
|
}
|
|
216
|
-
|
|
229
|
+
const _require = createRequire(import.meta.url);
|
|
230
|
+
function findPackageJson() {
|
|
231
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
232
|
+
for (let i = 0; i < 5; i++) {
|
|
233
|
+
const candidate = join(dir, "package.json");
|
|
234
|
+
try {
|
|
235
|
+
const pkg = _require(candidate);
|
|
236
|
+
if (pkg.name === "loadout-ai")
|
|
237
|
+
return candidate;
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
// not found, keep walking
|
|
241
|
+
}
|
|
242
|
+
dir = dirname(dir);
|
|
243
|
+
}
|
|
244
|
+
// ponytail: fallback for dist layout — 3 levels up from dist/src/commands/
|
|
245
|
+
return resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", "..", "package.json");
|
|
246
|
+
}
|
|
247
|
+
export const LOADOUT_VERSION = _require(findPackageJson()).version;
|
|
217
248
|
export function durableSchedulerLauncher() {
|
|
218
249
|
return [
|
|
219
250
|
join(dirname(process.execPath), process.platform === "win32" ? "npx.cmd" : "npx"),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { dirname, join } from "node:path";
|
|
2
|
-
import { planSkillInstall } from "
|
|
3
|
-
import { formatTerminalTable } from "
|
|
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
|
-
|
|
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
|
-
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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 "
|
|
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 "
|
|
5
|
-
import { managedFileReadPath } from "
|
|
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 "
|
|
7
|
+
import { loadEffectiveCatalog } from "../catalog/catalog.js";
|
|
8
8
|
import { detectAgents } from "./paths.js";
|
|
9
|
-
import { readLocalOutcomes } from "
|
|
10
|
-
import { readSnapshot } from "
|
|
11
|
-
import { scanInstalledSkills } from "
|
|
12
|
-
import { readInstallState } from "
|
|
13
|
-
import { transactionRoot } from "
|
|
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 "
|
|
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 "
|
|
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 "
|
|
5
|
-
import { readManifest } from "
|
|
6
|
-
import { readInstallState } from "
|
|
7
|
-
import { managedFileReadPath } from "
|
|
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 "
|
|
6
|
-
import { fetchGitHubMetadata } from "
|
|
7
|
-
import { loadoutHome } from "
|
|
8
|
-
import { compareCatalogPackages, explainCatalogScore } from "
|
|
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 "
|
|
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));
|
|
@@ -218,6 +218,19 @@ export async function refreshCatalog(packages, options = {}) {
|
|
|
218
218
|
observationFailures: observations.failures,
|
|
219
219
|
};
|
|
220
220
|
}
|
|
221
|
+
/** Merge a human-approved proposal into the bundled catalog. */
|
|
222
|
+
export async function promoteCatalogCandidate(proposal) {
|
|
223
|
+
const catalogPath = bundledCatalogPath();
|
|
224
|
+
const current = JSON.parse(await readFile(catalogPath, "utf8"));
|
|
225
|
+
if (current.some((pkg) => pkg.id === proposal.id))
|
|
226
|
+
throw new Error(`Catalog already contains id '${proposal.id}'`);
|
|
227
|
+
if (current.some((pkg) => pkg.repository.toLowerCase() === proposal.repository.toLowerCase()))
|
|
228
|
+
throw new Error(`Catalog already contains repository '${proposal.repository}'`);
|
|
229
|
+
const merged = [...current, proposal].sort((a, b) => a.id.localeCompare(b.id));
|
|
230
|
+
validateCatalog(merged, { requireEvidence: true });
|
|
231
|
+
await writeFile(catalogPath, `${JSON.stringify(merged, null, 2)}\n`);
|
|
232
|
+
return { catalogPath, totalRecords: merged.length };
|
|
233
|
+
}
|
|
221
234
|
export function rankCatalog(packages) {
|
|
222
235
|
return [...packages].sort(compareCatalogPackages);
|
|
223
236
|
}
|
|
@@ -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 "
|
|
4
|
-
import { adapterCapabilities, agentComponentDirectory } from "
|
|
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 "
|
|
2
|
-
import { AGENT_DEFINITIONS, agentSkillsDirectory } from "
|
|
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 "
|
|
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
|
|
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 "
|
|
5
|
+
import { ensureDirectory, loadoutHome } from "../agents/paths.js";
|
|
6
6
|
import { discoverSkillDirectories } from "./skills.js";
|
|
7
|
-
import { fetchRepositorySnapshot, } from "
|
|
8
|
-
import { writeFileAtomically } from "
|
|
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
|