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.
- package/README.md +122 -19
- package/catalog/discovered.json +25557 -24308
- package/dist/src/cli.js +2 -2
- package/dist/src/commands/agents.js +6 -23
- package/dist/src/commands/catalog.js +130 -33
- package/dist/src/commands/health.js +6 -6
- package/dist/src/commands/inventory.js +19 -120
- 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 +20 -9
- 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} +5 -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} +2 -2
- 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/{cli-guide.js → reporting/cli-guide.js} +29 -45
- package/dist/src/core/{doctor.js → reporting/doctor.js} +3 -6
- 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/{handoff.js → routing/handoff.js} +120 -3
- package/dist/src/core/{model-config.js → routing/model-config.js} +4 -4
- package/dist/src/core/{route.js → routing/route.js} +325 -34
- 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/DISCOVERED.md +247 -246
- 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/{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
package/dist/src/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command, CommanderError } from "commander";
|
|
3
|
-
import { HIDDEN_FROM_FIRST_SCREEN } from "./core/cli-guide.js";
|
|
4
|
-
import { recoverPendingTransactions } from "./core/transaction.js";
|
|
3
|
+
import { HIDDEN_FROM_FIRST_SCREEN } from "./core/reporting/cli-guide.js";
|
|
4
|
+
import { recoverPendingTransactions } from "./core/install/transaction.js";
|
|
5
5
|
import { LOADOUT_VERSION, printBeginnerGuide, runWizard, } from "./commands/support.js";
|
|
6
6
|
import { registerSetup } from "./commands/setup.js";
|
|
7
7
|
import { registerSharing } from "./commands/sharing.js";
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import { detectAgents, parseAgentSelection } from "../core/paths.js";
|
|
2
|
-
import { DEFAULT_ACTIVE_SKILL_LIMIT } from "../core/active-limit.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
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";
|
|
1
|
+
import { detectAgents, parseAgentSelection } from "../core/agents/paths.js";
|
|
2
|
+
import { DEFAULT_ACTIVE_SKILL_LIMIT } from "../core/workspace/active-limit.js";
|
|
3
|
+
import { applyActivationChange, formatActivationPlan, planActivationChange, } from "../core/workspace/active-set.js";
|
|
4
|
+
import { applyProjectActivation, formatProjectActivation, planProjectActivation, } from "../core/workspace/active-policy.js";
|
|
5
|
+
import { applyNativeSchedulerBundle, formatNativeScheduler, planNativeScheduler, } from "../core/runtime/scheduler.js";
|
|
6
|
+
import { REVIEWED_RUNTIME_TOOLS, applyRuntimeToolPlan, formatRuntimeToolPlan, planRuntimeTool, } from "../core/agents/runtime-tools.js";
|
|
11
7
|
import { collectOption, durableSchedulerLauncher } from "./support.js";
|
|
12
8
|
export function registerAgents(program) {
|
|
13
9
|
for (const workflow of ["activate", "optimize"]) {
|
|
@@ -108,19 +104,6 @@ export function registerAgents(program) {
|
|
|
108
104
|
? JSON.stringify({ action, plans, snapshotId }, null, 2)
|
|
109
105
|
: `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
106
|
});
|
|
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
107
|
program
|
|
125
108
|
.command("tool")
|
|
126
109
|
.description("Preview, install, or remove an explicitly reviewed runtime-tool recipe")
|
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
import { explainCatalogScore, loadEffectiveCatalog, loadCatalog, promoteCatalogCandidate, rankCatalog, refreshCatalog, validateCatalog, } from "../core/catalog.js";
|
|
2
|
-
import { parseAgentSelection } from "../core/paths.js";
|
|
1
|
+
import { explainCatalogScore, loadEffectiveCatalog, loadCatalog, promoteCatalogCandidate, rankCatalog, refreshCatalog, validateCatalog, } from "../core/catalog/catalog.js";
|
|
2
|
+
import { detectAgents, parseAgentSelection } from "../core/agents/paths.js";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
import { readFile } from "node:fs/promises";
|
|
5
|
-
import { allPhaseRoutes, formatCostTable, formatModelCatalog, formatRouteRecommendation, formatRoutingTable, routePhase, routeTask, } from "../core/route.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
5
|
+
import { allPhaseRoutes, formatCostTable, formatModelCatalog, formatRouteRecommendation, formatRoutingTable, routePhase, routeTask, } from "../core/routing/route.js";
|
|
6
|
+
import { applyFirstPartySkill, FIRST_PARTY_SKILLS, formatFirstPartySkillList, formatFirstPartySkillPlan, installedFirstPartySkills, planFirstPartySkill, removeFirstPartySkill, } from "../core/routing/first-party-skills.js";
|
|
7
|
+
import { applyPickup, formatHandoffStatus, formatInbox, formatPickupPlan, getHandoffState, initHandoff, isHandoffInitialized, markDone, planPickup, readInbox, sendHandoff, } from "../core/routing/handoff.js";
|
|
8
|
+
import { catalogTrustStage, formatCatalogTrustStage, } from "../core/catalog/profiles.js";
|
|
9
|
+
import { discoverHackerNewsRepositories } from "../core/discovery/community.js";
|
|
10
|
+
import { discoverPrivateRepositories } from "../core/discovery/private-discovery.js";
|
|
11
|
+
import { defaultGitHubDiscoveryQueries, discoverGitHubRepositories, } from "../core/discovery/github-discovery.js";
|
|
12
|
+
import { formatStarHistory, readCatalogObservations, } from "../core/discovery/observations.js";
|
|
13
|
+
import { writeFileAtomically } from "../core/install/atomic-file.js";
|
|
14
|
+
import { formatReviewQueue, markPromoted, mergeReviewQueue, readReviewQueue, } from "../core/discovery/review-queue.js";
|
|
15
|
+
import { applyProviderModelSelection, defaultModelConfigurationPath, formatProviderModelConfiguration, planProviderModelSelection, readProviderModelConfiguration, requestOpenRouter, } from "../core/routing/model-config.js";
|
|
16
|
+
import { parseCompletionShell, renderShellCompletion, } from "../core/reporting/completion.js";
|
|
17
|
+
import { buildCatalogCoverage, formatCatalogCoverage, } from "../core/catalog/catalog-coverage.js";
|
|
18
|
+
import { createCredentialResolver, createOsCredentialStore, } from "../core/routing/credentials.js";
|
|
19
|
+
import { buildCandidateDossier, buildCatalogProposal, formatCandidateDossier, formatCandidateSummaries, listDiscoveryCandidates, readCandidateDossier, verifyCandidateDossierSource, writeCandidateDossier, } from "../core/discovery/candidate-intelligence.js";
|
|
20
|
+
import { discoverSkillsSh } from "../core/discovery/skills-sh-discovery.js";
|
|
21
|
+
import { discoverOfficialMcpRegistry } from "../core/discovery/mcp-registry-discovery.js";
|
|
21
22
|
import { readCredentialFromStdin } from "./support.js";
|
|
22
23
|
export function registerCatalog(program) {
|
|
23
24
|
program
|
|
@@ -444,17 +445,6 @@ export function registerCatalog(program) {
|
|
|
444
445
|
? JSON.stringify(filtered, null, 2)
|
|
445
446
|
: formatReviewQueue(filtered));
|
|
446
447
|
});
|
|
447
|
-
program
|
|
448
|
-
.command("review")
|
|
449
|
-
.description("Record a human queue decision; shortlisting still does not promote or install")
|
|
450
|
-
.argument("<repository>", "owner/repository")
|
|
451
|
-
.requiredOption("--decision <value>", "pending, shortlisted, or ignored")
|
|
452
|
-
.action(async (repository, options) => {
|
|
453
|
-
if (!["pending", "shortlisted", "ignored"].includes(options.decision))
|
|
454
|
-
throw new Error("--decision must be pending, shortlisted, or ignored");
|
|
455
|
-
const item = await setReviewDecision(repository, options.decision);
|
|
456
|
-
console.log(`${item.repository}: ${item.decision}. No catalog or agent files changed.`);
|
|
457
|
-
});
|
|
458
448
|
const credentials = program
|
|
459
449
|
.command("credentials")
|
|
460
450
|
.description("Store, inspect, or remove secrets in the native OS credential store");
|
|
@@ -600,6 +590,70 @@ export function registerCatalog(program) {
|
|
|
600
590
|
});
|
|
601
591
|
console.log(`Verified model selection '${id}'. No credential value was stored or printed.`);
|
|
602
592
|
});
|
|
593
|
+
const skills = program
|
|
594
|
+
.command("skills")
|
|
595
|
+
.description("Install the skills Loadout ships so your agents can use Loadout from inside a conversation");
|
|
596
|
+
skills
|
|
597
|
+
.command("list", { isDefault: true })
|
|
598
|
+
.description("Show the skills Loadout ships and whether they are installed")
|
|
599
|
+
.option("--json", "emit machine-readable JSON")
|
|
600
|
+
.action(async (options) => {
|
|
601
|
+
const installed = await installedFirstPartySkills();
|
|
602
|
+
console.log(options.json
|
|
603
|
+
? JSON.stringify(FIRST_PARTY_SKILLS.map((skill) => ({
|
|
604
|
+
...skill,
|
|
605
|
+
installed: installed.has(skill.id),
|
|
606
|
+
})), null, 2)
|
|
607
|
+
: formatFirstPartySkillList(installed));
|
|
608
|
+
});
|
|
609
|
+
skills
|
|
610
|
+
.command("install")
|
|
611
|
+
.description("Preview or install one Loadout skill into detected agents")
|
|
612
|
+
.argument("<id>", "skill id, for example loadout-router")
|
|
613
|
+
.option("--agents <ids>", "comma-separated agent ids; defaults to all detected")
|
|
614
|
+
.option("--yes", "apply after previewing")
|
|
615
|
+
.action(async (id, options) => {
|
|
616
|
+
const plan = await planFirstPartySkill(id, {
|
|
617
|
+
...(options.agents
|
|
618
|
+
? { agents: parseAgentSelection(options.agents) }
|
|
619
|
+
: {}),
|
|
620
|
+
});
|
|
621
|
+
console.log(formatFirstPartySkillPlan(plan));
|
|
622
|
+
if (!plan.targets.length)
|
|
623
|
+
return;
|
|
624
|
+
if (!options.yes) {
|
|
625
|
+
console.log("\nPreview only. Re-run with --yes to install.");
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
await applyFirstPartySkill(plan);
|
|
629
|
+
console.log(`\nInstalled '${plan.skill.id}' for ${plan.targets.length} agent(s). Start a new agent session to pick it up.`);
|
|
630
|
+
});
|
|
631
|
+
skills
|
|
632
|
+
.command("remove")
|
|
633
|
+
.description("Preview or remove one Loadout skill from detected agents")
|
|
634
|
+
.argument("<id>", "skill id")
|
|
635
|
+
.option("--agents <ids>", "comma-separated agent ids; defaults to all detected")
|
|
636
|
+
.option("--yes", "apply after previewing")
|
|
637
|
+
.action(async (id, options) => {
|
|
638
|
+
const plan = await planFirstPartySkill(id, {
|
|
639
|
+
...(options.agents
|
|
640
|
+
? { agents: parseAgentSelection(options.agents) }
|
|
641
|
+
: {}),
|
|
642
|
+
});
|
|
643
|
+
const present = plan.targets.filter((target) => target.replacing);
|
|
644
|
+
if (!present.length) {
|
|
645
|
+
console.log(`'${id}' is not installed for any detected agent.`);
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
for (const target of present)
|
|
649
|
+
console.log(` remove → ${target.destination} [${target.displayName}]`);
|
|
650
|
+
if (!options.yes) {
|
|
651
|
+
console.log("\nPreview only. Re-run with --yes to remove.");
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
await removeFirstPartySkill(plan);
|
|
655
|
+
console.log(`\nRemoved '${id}' from ${present.length} agent(s).`);
|
|
656
|
+
});
|
|
603
657
|
const handoff = program
|
|
604
658
|
.command("handoff")
|
|
605
659
|
.description("Cross-agent file-based task handoff — send work between Claude Code, Codex, and other agents");
|
|
@@ -646,6 +700,39 @@ export function registerCatalog(program) {
|
|
|
646
700
|
? JSON.stringify(message, null, 2)
|
|
647
701
|
: `Marked ${id} as done`);
|
|
648
702
|
});
|
|
703
|
+
handoff
|
|
704
|
+
.command("inbox")
|
|
705
|
+
.description("Show pending tasks addressed to one agent, as instructions it can act on")
|
|
706
|
+
.argument("<agent>", "agent reading its inbox (e.g. claude-code, codex)")
|
|
707
|
+
.option("--json", "emit machine-readable JSON")
|
|
708
|
+
.action(async (agent, options) => {
|
|
709
|
+
const messages = await readInbox(process.cwd(), agent);
|
|
710
|
+
console.log(options.json
|
|
711
|
+
? JSON.stringify(messages, null, 2)
|
|
712
|
+
: formatInbox(agent, messages));
|
|
713
|
+
});
|
|
714
|
+
handoff
|
|
715
|
+
.command("pickup")
|
|
716
|
+
.description("Teach agents to check their handoff inbox by adding a managed block to CLAUDE.md / AGENTS.md")
|
|
717
|
+
.option("--agents <ids>", "comma-separated agents to instruct", "claude-code,codex")
|
|
718
|
+
.option("--yes", "write the files after previewing")
|
|
719
|
+
.action(async (options) => {
|
|
720
|
+
const agents = options.agents
|
|
721
|
+
.split(",")
|
|
722
|
+
.map((value) => value.trim())
|
|
723
|
+
.filter(Boolean);
|
|
724
|
+
const plans = [];
|
|
725
|
+
for (const agent of agents)
|
|
726
|
+
plans.push(await planPickup(process.cwd(), agent));
|
|
727
|
+
console.log(formatPickupPlan(plans));
|
|
728
|
+
if (!options.yes) {
|
|
729
|
+
console.log("\nPreview only. Re-run with --yes to write these files.");
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
for (const plan of plans)
|
|
733
|
+
await applyPickup(plan);
|
|
734
|
+
console.log(`\nWrote pickup instructions for ${plans.length} agent(s). They will check their inbox on the next session.`);
|
|
735
|
+
});
|
|
649
736
|
handoff
|
|
650
737
|
.command("status")
|
|
651
738
|
.description("Show pending and completed handoff tasks")
|
|
@@ -671,7 +758,7 @@ export function registerCatalog(program) {
|
|
|
671
758
|
.action(async (descriptionWords, options) => {
|
|
672
759
|
if (options.models) {
|
|
673
760
|
console.log(options.json
|
|
674
|
-
? JSON.stringify((await import("../core/route.js")).MODEL_CATALOG, null, 2)
|
|
761
|
+
? JSON.stringify((await import("../core/routing/route.js")).MODEL_CATALOG, null, 2)
|
|
675
762
|
: formatModelCatalog({
|
|
676
763
|
provider: options.provider,
|
|
677
764
|
tier: options.tier,
|
|
@@ -680,7 +767,7 @@ export function registerCatalog(program) {
|
|
|
680
767
|
}
|
|
681
768
|
if (options.cost) {
|
|
682
769
|
console.log(options.json
|
|
683
|
-
? JSON.stringify((await import("../core/route.js")).estimateCostSavings(), null, 2)
|
|
770
|
+
? JSON.stringify((await import("../core/routing/route.js")).estimateCostSavings(), null, 2)
|
|
684
771
|
: formatCostTable());
|
|
685
772
|
return;
|
|
686
773
|
}
|
|
@@ -694,9 +781,19 @@ export function registerCatalog(program) {
|
|
|
694
781
|
const rec = options.phase
|
|
695
782
|
? routePhase(options.phase, options.conserve)
|
|
696
783
|
: routeTask(description, options.conserve);
|
|
784
|
+
// Recommendations are only useful when they name agents this machine
|
|
785
|
+
// actually has, so detection drives both the advice and the handoff line.
|
|
786
|
+
const detected = await detectAgents();
|
|
787
|
+
const installedAgents = detected
|
|
788
|
+
.filter((agent) => agent.installed)
|
|
789
|
+
.map((agent) => agent.id);
|
|
697
790
|
console.log(options.json
|
|
698
|
-
? JSON.stringify(rec, null, 2)
|
|
699
|
-
: formatRouteRecommendation(rec
|
|
791
|
+
? JSON.stringify({ ...rec, installedAgents }, null, 2)
|
|
792
|
+
: formatRouteRecommendation(rec, {
|
|
793
|
+
installedAgents,
|
|
794
|
+
...(description ? { description } : {}),
|
|
795
|
+
handoffReady: await isHandoffInitialized(process.cwd()),
|
|
796
|
+
}));
|
|
700
797
|
});
|
|
701
798
|
program
|
|
702
799
|
.command("completion")
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { parseAgentSelection } from "../core/paths.js";
|
|
2
|
-
import { buildUpdatePlan } from "../core/update.js";
|
|
3
|
-
import { buildHealthReport, formatHealthReport } from "../core/health.js";
|
|
4
|
-
import { buildFreshnessAlerts, formatFreshnessAlerts, ignoreFreshnessAlert, pinReplacement, readReplacementPins, unpinReplacement, } from "../core/freshness-alerts.js";
|
|
5
|
-
import { formatAgentHealthScore } from "../core/agent-health-score.js";
|
|
6
|
-
import { buildLocalAgentHealthScores } from "../core/health-score-evidence.js";
|
|
1
|
+
import { parseAgentSelection } from "../core/agents/paths.js";
|
|
2
|
+
import { buildUpdatePlan } from "../core/install/update.js";
|
|
3
|
+
import { buildHealthReport, formatHealthReport, } from "../core/reporting/health.js";
|
|
4
|
+
import { buildFreshnessAlerts, formatFreshnessAlerts, ignoreFreshnessAlert, pinReplacement, readReplacementPins, unpinReplacement, } from "../core/reporting/freshness-alerts.js";
|
|
5
|
+
import { formatAgentHealthScore } from "../core/agents/agent-health-score.js";
|
|
6
|
+
import { buildLocalAgentHealthScores } from "../core/agents/health-score-evidence.js";
|
|
7
7
|
export function registerHealth(program) {
|
|
8
8
|
program
|
|
9
9
|
.command("health")
|
|
@@ -1,24 +1,21 @@
|
|
|
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 { resolve } from "node:path";
|
|
4
|
-
import { runDoctor, formatDoctorReport } from "../core/doctor.js";
|
|
5
|
-
import { applyProfileToManifest } from "../core/manifest.js";
|
|
6
|
-
import { buildHealthReport, formatStatusScreen, gradeHealth, } from "../core/health.js";
|
|
7
|
-
import { applyRemove, planRemove } from "../core/remove.js";
|
|
8
|
-
import { applyUninstall, buildUninstallPlan, formatUninstallPlan, uninstallGlobalCli, } from "../core/uninstall.js";
|
|
9
|
-
import { formatRecommendations, personalizeRecommendations, profileManifestPackages, recommendPackages, RECOMMENDATION_BOUNDARY, scanProject, TESTED_PROFILES, } from "../core/recommend.js";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import { readLocalOutcomes } from "../core/outcomes.js";
|
|
20
|
-
import { formatAgentVersions, inspectAgentVersions, } from "../core/agent-versions.js";
|
|
21
|
-
import { scanSkillSecurity } from "../core/skill-security.js";
|
|
4
|
+
import { runDoctor, formatDoctorReport } from "../core/reporting/doctor.js";
|
|
5
|
+
import { applyProfileToManifest } from "../core/workspace/manifest.js";
|
|
6
|
+
import { buildHealthReport, formatStatusScreen, gradeHealth, } from "../core/reporting/health.js";
|
|
7
|
+
import { applyRemove, planRemove } from "../core/install/remove.js";
|
|
8
|
+
import { applyUninstall, buildUninstallPlan, formatUninstallPlan, uninstallGlobalCli, } from "../core/install/uninstall.js";
|
|
9
|
+
import { formatRecommendations, personalizeRecommendations, profileManifestPackages, recommendPackages, RECOMMENDATION_BOUNDARY, scanProject, TESTED_PROFILES, } from "../core/workspace/recommend.js";
|
|
10
|
+
import { applySyncPlan, buildSyncPlan } from "../core/install/sync.js";
|
|
11
|
+
import { formatAgentInventory, inspectAgents, } from "../core/agents/agent-inspection.js";
|
|
12
|
+
import { formatInstalledSkillInventory, scanInstalledSkills, } from "../core/catalog/skill-inventory.js";
|
|
13
|
+
import { enrichInventoryWithProvenance, formatProvenanceSummary, resolveCatalogSkillIndex, } from "../core/catalog/provenance.js";
|
|
14
|
+
import { applySkillAdoption, formatAdoptionPlan, planSkillAdoption, } from "../core/install/adopt.js";
|
|
15
|
+
import { applyReconcilePlan, buildReconcilePlan, formatReconcilePlan, } from "../core/install/reconcile.js";
|
|
16
|
+
import { readLocalOutcomes } from "../core/workspace/outcomes.js";
|
|
17
|
+
import { formatAgentVersions, inspectAgentVersions, } from "../core/agents/agent-versions.js";
|
|
18
|
+
import { scanSkillSecurity } from "../core/catalog/skill-security.js";
|
|
22
19
|
import { printProvenanceProgress } from "./support.js";
|
|
23
20
|
export function registerInventory(program) {
|
|
24
21
|
program
|
|
@@ -117,35 +114,6 @@ export function registerInventory(program) {
|
|
|
117
114
|
? JSON.stringify({ name, ...TESTED_PROFILES[name], packages }, null, 2)
|
|
118
115
|
: `${name}: ${TESTED_PROFILES[name].description}\n${packages.map((pkg) => ` ${pkg.id} — ${pkg.repository}`).join("\n")}`);
|
|
119
116
|
});
|
|
120
|
-
program
|
|
121
|
-
.command("improve")
|
|
122
|
-
.description("Propose the next evidence-backed improvement without changing anything")
|
|
123
|
-
.option("--json", "emit machine-readable JSON")
|
|
124
|
-
.option("--write", "persist the cycle record and reusable prompt locally")
|
|
125
|
-
.option("--output <directory>", "output directory; defaults to private Loadout state")
|
|
126
|
-
.action(async (options) => {
|
|
127
|
-
const cycle = await buildImprovementCycle();
|
|
128
|
-
console.log(options.json
|
|
129
|
-
? JSON.stringify(cycle, null, 2)
|
|
130
|
-
: formatImprovementCycle(cycle));
|
|
131
|
-
if (options.write) {
|
|
132
|
-
const paths = await writeImprovementCycle(cycle, options.output);
|
|
133
|
-
console.log(`Cycle record: ${paths.json}\nLoop prompt: ${paths.prompt}`);
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
program
|
|
137
|
-
.command("improve-feedback")
|
|
138
|
-
.description("Record a human-reviewed outcome for a persisted improvement cycle")
|
|
139
|
-
.requiredOption("--id <id>", "cycle id")
|
|
140
|
-
.requiredOption("--outcome <outcome>", "success, failure, or partial")
|
|
141
|
-
.option("--note <text>", "short non-secret lesson")
|
|
142
|
-
.option("--directory <path>", "improvement history directory")
|
|
143
|
-
.action(async (options) => {
|
|
144
|
-
if (!["success", "failure", "partial"].includes(options.outcome))
|
|
145
|
-
throw new Error("--outcome must be success, failure, or partial");
|
|
146
|
-
await recordImprovementOutcome(options.id, options.outcome, options.note, options.directory);
|
|
147
|
-
console.log(`Recorded ${options.outcome} outcome for ${options.id}.`);
|
|
148
|
-
});
|
|
149
117
|
program
|
|
150
118
|
.command("sync")
|
|
151
119
|
.description("Reproduce a loadout.json manifest as one safe transaction")
|
|
@@ -284,53 +252,10 @@ export function registerInventory(program) {
|
|
|
284
252
|
? JSON.stringify({ plan, snapshotId }, null, 2)
|
|
285
253
|
: `${formatAdoptionPlan(plan)}\nAdopted without changing skill bytes. Snapshot: ${snapshotId}`);
|
|
286
254
|
});
|
|
287
|
-
program
|
|
288
|
-
.command("compare")
|
|
289
|
-
.description("Compare an installed or reviewed skill with evidence-related catalog alternatives without changing anything")
|
|
290
|
-
.argument("<skill>", "installed skill name, directory name, or catalog package id")
|
|
291
|
-
.option("--agent <id>", "select one installed agent when names are ambiguous")
|
|
292
|
-
.option("--refresh", "rebuild the inspected catalog skill index")
|
|
293
|
-
.option("--offline", "never fetch; use the existing local index only")
|
|
294
|
-
.option("--limit <count>", "maximum alternatives to show", "10")
|
|
295
|
-
.option("--json", "emit the complete machine-readable comparison")
|
|
296
|
-
.action(async (skill, options) => {
|
|
297
|
-
if (options.refresh && options.offline)
|
|
298
|
-
throw new Error("--refresh and --offline cannot be used together");
|
|
299
|
-
const limit = Number(options.limit);
|
|
300
|
-
if (!Number.isInteger(limit) || limit < 1 || limit > 50)
|
|
301
|
-
throw new Error("--limit must be an integer from 1 to 50");
|
|
302
|
-
const detected = await detectAgents();
|
|
303
|
-
const agent = options.agent;
|
|
304
|
-
if (agent && !detected.some((item) => item.id === agent))
|
|
305
|
-
throw new Error(`Unknown agent id: ${options.agent}`);
|
|
306
|
-
const selected = detected.filter((item) => item.installed);
|
|
307
|
-
if (!selected.length)
|
|
308
|
-
throw new Error("No detected agent profile is available to compare");
|
|
309
|
-
const catalog = await loadEffectiveCatalog();
|
|
310
|
-
const resolved = await resolveCatalogSkillIndex({
|
|
311
|
-
refresh: options.refresh,
|
|
312
|
-
offline: options.offline,
|
|
313
|
-
build: {
|
|
314
|
-
catalog,
|
|
315
|
-
onProgress: options.offline ? undefined : printProvenanceProgress,
|
|
316
|
-
},
|
|
317
|
-
});
|
|
318
|
-
if (!resolved.index)
|
|
319
|
-
throw new Error("No local catalog skill index exists. Re-run without --offline or use --refresh.");
|
|
320
|
-
const inventory = enrichInventoryWithProvenance(await scanInstalledSkills(selected), resolved.index, resolved.source);
|
|
321
|
-
const comparison = compareSkill(skill, inventory, resolved.index.records, catalog, {
|
|
322
|
-
...(agent ? { agent } : {}),
|
|
323
|
-
limit,
|
|
324
|
-
indexGeneratedAt: resolved.index.generatedAt,
|
|
325
|
-
failures: resolved.index.failures,
|
|
326
|
-
});
|
|
327
|
-
console.log(options.json
|
|
328
|
-
? JSON.stringify(comparison, null, 2)
|
|
329
|
-
: formatSkillComparison(comparison));
|
|
330
|
-
});
|
|
331
255
|
program
|
|
332
256
|
.command("status")
|
|
333
257
|
.description("Home screen: a health grade, detected agents, and the next thing to do")
|
|
258
|
+
.option("--details", "show per-component adapter compatibility for each agent")
|
|
334
259
|
.option("--json", "emit machine-readable status")
|
|
335
260
|
.action(async (options) => {
|
|
336
261
|
const agents = await detectAgents();
|
|
@@ -340,7 +265,7 @@ export function registerInventory(program) {
|
|
|
340
265
|
]);
|
|
341
266
|
if (options.json)
|
|
342
267
|
return console.log(JSON.stringify({ grade: gradeHealth(report), report, inventory }, null, 2));
|
|
343
|
-
console.log(formatStatusScreen(report, inventory.map((item) => formatAgentInventory(item))));
|
|
268
|
+
console.log(formatStatusScreen(report, inventory.map((item) => formatAgentInventory(item, { details: options.details }))));
|
|
344
269
|
});
|
|
345
270
|
program
|
|
346
271
|
.command("versions")
|
|
@@ -377,32 +302,6 @@ export function registerInventory(program) {
|
|
|
377
302
|
if (report.verdict === "blocked")
|
|
378
303
|
process.exitCode = 2;
|
|
379
304
|
});
|
|
380
|
-
program
|
|
381
|
-
.command("capabilities")
|
|
382
|
-
.description("Show honest native, adapted, and unsupported adapter capabilities")
|
|
383
|
-
.option("--json", "emit machine-readable JSON")
|
|
384
|
-
.option("--inspect", "also inspect managed component directories on this machine")
|
|
385
|
-
.option("--gaps", "show the evidence-gated backlog for unsupported adapter combinations")
|
|
386
|
-
.action(async (options) => {
|
|
387
|
-
if (options.gaps) {
|
|
388
|
-
if (options.inspect)
|
|
389
|
-
throw new Error("Choose either --inspect or --gaps");
|
|
390
|
-
const gaps = buildAdapterCapabilityGaps();
|
|
391
|
-
return console.log(options.json
|
|
392
|
-
? JSON.stringify(gaps, null, 2)
|
|
393
|
-
: formatAdapterCapabilityGaps());
|
|
394
|
-
}
|
|
395
|
-
if (!options.inspect)
|
|
396
|
-
return console.log(options.json
|
|
397
|
-
? JSON.stringify(ADAPTER_CAPABILITIES, null, 2)
|
|
398
|
-
: formatCapabilityMatrix());
|
|
399
|
-
const inventory = await inspectAgents(await detectAgents());
|
|
400
|
-
if (options.json)
|
|
401
|
-
return console.log(JSON.stringify({ capabilities: ADAPTER_CAPABILITIES, inventory }, null, 2));
|
|
402
|
-
console.log(`${formatCapabilityMatrix()}\n\nLocal managed-component inventory:`);
|
|
403
|
-
for (const item of inventory)
|
|
404
|
-
console.log(formatAgentInventory(item));
|
|
405
|
-
});
|
|
406
305
|
program
|
|
407
306
|
.command("doctor")
|
|
408
307
|
.description("Check agents, skill directories, permissions, and Loadout setup")
|
|
@@ -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
|
}
|