loadout-ai 0.6.0 → 0.8.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/CHANGELOG.md +72 -0
- package/README.md +129 -26
- package/catalog/discovered.json +28469 -24524
- package/dist/src/cli.js +7 -2
- package/dist/src/commands/agents.js +6 -23
- package/dist/src/commands/catalog.js +186 -102
- 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} +48 -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} +59 -11
- package/dist/src/core/{safety.js → catalog/safety.js} +36 -7
- 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} +22 -8
- 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/reporting/completion.js +90 -0
- package/dist/src/core/{doctor.js → reporting/doctor.js} +5 -10
- 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 +314 -0
- package/dist/src/core/{model-config.js → routing/model-config.js} +4 -4
- package/dist/src/core/routing/policy.js +147 -0
- package/dist/src/core/{route.js → routing/route.js} +202 -39
- 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/CANDIDATE_INTELLIGENCE.md +9 -2
- package/docs/CATALOG.md +1 -1
- package/docs/CREDENTIAL_AND_UPDATE_POLICY.md +1 -1
- package/docs/DISCOVERED.md +250 -248
- package/docs/FEATURE_TEST_MATRIX.md +7 -260
- package/docs/GITHUB_AUTHORIZATION.md +5 -0
- package/docs/PROVENANCE_AND_COMPARISON.md +1 -1
- package/docs/RELEASE_REVIEW.md +0 -1
- package/docs/evidence/readme-claims.json +22 -19
- package/package.json +7 -4
- package/skills/loadout-curator/SKILL.md +105 -0
- package/skills/loadout-router/SKILL.md +85 -0
- package/MASTER_PLAN.md +0 -2207
- package/dist/src/core/completion.js +0 -143
- package/dist/src/core/handoff.js +0 -161
- package/docs/ACTIVE_SET.md +0 -53
- package/docs/COMPATIBILITY_POLICY.md +0 -22
- package/docs/CONVERSION_AND_SANDBOX.md +0 -27
- package/docs/EVALUATION_PROTOCOL_V1.md +0 -300
- package/docs/HEAD_TO_HEAD_EVALUATION.md +0 -79
- package/docs/PROVIDER_CONFIGURATION.md +0 -45
- package/docs/README_RESEARCH.md +0 -36
- package/docs/REPOSITORY_STABILIZATION.md +0 -190
- package/docs/SAFE_UPDATE_DEMO.md +0 -25
- package/docs/SCHEMA_DECISIONS.md +0 -25
- package/docs/SUBMISSION_COPY.md +0 -90
- package/docs/TEAM_POLICY.md +0 -18
- package/docs/superpowers/plans/2026-07-19-relatable-readme-hero.md +0 -283
- package/docs/superpowers/plans/2026-07-20-loadout-readme-explainer.md +0 -116
- package/docs/superpowers/plans/2026-07-20-project-activation-safety.md +0 -469
- package/docs/superpowers/specs/2026-07-19-relatable-readme-hero-design.md +0 -80
- package/docs/superpowers/specs/2026-07-20-loadout-readme-explainer-design.md +0 -55
- package/docs/superpowers/specs/2026-07-20-project-activation-safety-design.md +0 -228
- /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/{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/{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
|
@@ -4,29 +4,64 @@
|
|
|
4
4
|
// Prices as of August 2026.
|
|
5
5
|
export const MODEL_CATALOG = [
|
|
6
6
|
// --- Anthropic (Claude Code) ---
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
{
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
7
|
+
// Haiku and the 4.x line are deliberately absent: for real coding work the
|
|
8
|
+
// choice is Opus or Sonnet, and offering a weaker tier invites picking it.
|
|
9
|
+
{
|
|
10
|
+
id: "claude-opus-5",
|
|
11
|
+
provider: "anthropic",
|
|
12
|
+
name: "Claude Opus 5",
|
|
13
|
+
tier: "frontier",
|
|
14
|
+
inputCostPer1M: 5,
|
|
15
|
+
outputCostPer1M: 25,
|
|
16
|
+
nativeAgents: ["claude-code"],
|
|
17
|
+
current: true,
|
|
18
|
+
generation: "5",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: "claude-sonnet-5",
|
|
22
|
+
provider: "anthropic",
|
|
23
|
+
name: "Claude Sonnet 5",
|
|
24
|
+
tier: "standard",
|
|
25
|
+
inputCostPer1M: 3,
|
|
26
|
+
outputCostPer1M: 15,
|
|
27
|
+
nativeAgents: ["claude-code"],
|
|
28
|
+
current: true,
|
|
29
|
+
generation: "5",
|
|
30
|
+
},
|
|
31
|
+
// --- OpenAI (Codex) — the current GPT-5.6 tiers only ---
|
|
32
|
+
{
|
|
33
|
+
id: "gpt-5.6-sol",
|
|
34
|
+
provider: "openai",
|
|
35
|
+
name: "GPT-5.6 Sol",
|
|
36
|
+
tier: "frontier",
|
|
37
|
+
inputCostPer1M: 5,
|
|
38
|
+
outputCostPer1M: 30,
|
|
39
|
+
nativeAgents: ["codex"],
|
|
40
|
+
current: true,
|
|
41
|
+
generation: "5.6",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: "gpt-5.6-terra",
|
|
45
|
+
provider: "openai",
|
|
46
|
+
name: "GPT-5.6 Terra",
|
|
47
|
+
tier: "standard",
|
|
48
|
+
inputCostPer1M: 2,
|
|
49
|
+
outputCostPer1M: 12,
|
|
50
|
+
nativeAgents: ["codex"],
|
|
51
|
+
current: true,
|
|
52
|
+
generation: "5.6",
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: "gpt-5.6-luna",
|
|
56
|
+
provider: "openai",
|
|
57
|
+
name: "GPT-5.6 Luna",
|
|
58
|
+
tier: "fast",
|
|
59
|
+
inputCostPer1M: 0.2,
|
|
60
|
+
outputCostPer1M: 1.2,
|
|
61
|
+
nativeAgents: ["codex"],
|
|
62
|
+
current: true,
|
|
63
|
+
generation: "5.6",
|
|
64
|
+
},
|
|
30
65
|
];
|
|
31
66
|
const TIER_LABELS = {
|
|
32
67
|
frontier: "Frontier (deep reasoning)",
|
|
@@ -74,12 +109,70 @@ const PHASE_CONFIG = {
|
|
|
74
109
|
},
|
|
75
110
|
};
|
|
76
111
|
const PHASE_KEYWORDS = {
|
|
77
|
-
plan: [
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
112
|
+
plan: [
|
|
113
|
+
"plan",
|
|
114
|
+
"design",
|
|
115
|
+
"architect",
|
|
116
|
+
"architecture",
|
|
117
|
+
"rfc",
|
|
118
|
+
"spec",
|
|
119
|
+
"decompose",
|
|
120
|
+
"strategy",
|
|
121
|
+
"system design",
|
|
122
|
+
],
|
|
123
|
+
implement: [
|
|
124
|
+
"implement",
|
|
125
|
+
"build",
|
|
126
|
+
"code",
|
|
127
|
+
"create",
|
|
128
|
+
"add",
|
|
129
|
+
"feature",
|
|
130
|
+
"write",
|
|
131
|
+
"develop",
|
|
132
|
+
"make",
|
|
133
|
+
],
|
|
134
|
+
review: [
|
|
135
|
+
"review",
|
|
136
|
+
"audit",
|
|
137
|
+
"check",
|
|
138
|
+
"inspect",
|
|
139
|
+
"critique",
|
|
140
|
+
"pr",
|
|
141
|
+
"pull request",
|
|
142
|
+
"diff",
|
|
143
|
+
],
|
|
144
|
+
test: [
|
|
145
|
+
"test",
|
|
146
|
+
"spec",
|
|
147
|
+
"coverage",
|
|
148
|
+
"unit",
|
|
149
|
+
"integration",
|
|
150
|
+
"e2e",
|
|
151
|
+
"assert",
|
|
152
|
+
"vitest",
|
|
153
|
+
"jest",
|
|
154
|
+
],
|
|
155
|
+
debug: [
|
|
156
|
+
"debug",
|
|
157
|
+
"fix",
|
|
158
|
+
"bug",
|
|
159
|
+
"error",
|
|
160
|
+
"crash",
|
|
161
|
+
"broken",
|
|
162
|
+
"investigate",
|
|
163
|
+
"troubleshoot",
|
|
164
|
+
"failing",
|
|
165
|
+
],
|
|
166
|
+
document: [
|
|
167
|
+
"document",
|
|
168
|
+
"docs",
|
|
169
|
+
"readme",
|
|
170
|
+
"comment",
|
|
171
|
+
"jsdoc",
|
|
172
|
+
"changelog",
|
|
173
|
+
"explain",
|
|
174
|
+
"docstring",
|
|
175
|
+
],
|
|
83
176
|
};
|
|
84
177
|
// ---------------------------------------------------------------------------
|
|
85
178
|
// Classification
|
|
@@ -114,6 +207,25 @@ export function cheapestInTier(tier) {
|
|
|
114
207
|
const models = modelsForTier(tier);
|
|
115
208
|
return models.sort((a, b) => a.inputCostPer1M - b.inputCostPer1M)[0];
|
|
116
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* Narrow a recommendation to the agents actually present on this machine. A
|
|
212
|
+
* recommendation that names an agent the user has not installed is noise, so
|
|
213
|
+
* the resolved list drives both the printed advice and the handoff command.
|
|
214
|
+
*/
|
|
215
|
+
export function resolveAvailableAgents(suggested, installed) {
|
|
216
|
+
const present = new Set(installed);
|
|
217
|
+
return {
|
|
218
|
+
available: suggested.filter((id) => present.has(id)),
|
|
219
|
+
missing: suggested.filter((id) => !present.has(id)),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
/** Models in the recommended tier that the given agents can actually run. */
|
|
223
|
+
export function modelsRunnableBy(models, agents) {
|
|
224
|
+
if (!agents.length)
|
|
225
|
+
return models;
|
|
226
|
+
const wanted = new Set(agents);
|
|
227
|
+
return models.filter((m) => m.nativeAgents.some((id) => wanted.has(id)));
|
|
228
|
+
}
|
|
117
229
|
// ---------------------------------------------------------------------------
|
|
118
230
|
// Routing
|
|
119
231
|
// ---------------------------------------------------------------------------
|
|
@@ -166,23 +278,60 @@ export function estimateCostSavings() {
|
|
|
166
278
|
const conserveTotal = conserveEstimates.reduce((s, c) => s + c, 0);
|
|
167
279
|
return { estimates, normalTotal, conserveTotal };
|
|
168
280
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
281
|
+
/** Shell-quote a task description for the suggested handoff command. */
|
|
282
|
+
function shellQuote(value) {
|
|
283
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
284
|
+
}
|
|
285
|
+
export function formatRouteRecommendation(rec, context = {}) {
|
|
286
|
+
// `undefined` means detection never ran, so every suggested agent stands. An
|
|
287
|
+
// empty array means detection ran and found nothing, which must not be
|
|
288
|
+
// silently upgraded back to the full suggestion list.
|
|
289
|
+
const checked = context.installedAgents !== undefined;
|
|
290
|
+
const { available, missing } = checked
|
|
291
|
+
? resolveAvailableAgents(rec.suggestedAgents, context.installedAgents)
|
|
292
|
+
: { available: rec.suggestedAgents, missing: [] };
|
|
293
|
+
// Only recommend models an available agent can actually run. Not every
|
|
294
|
+
// provider offers every tier — Claude Code has no fast tier — so when the
|
|
295
|
+
// recommended tier holds nothing the user can reach, step up to the nearest
|
|
296
|
+
// tier that does rather than naming a model they cannot run.
|
|
297
|
+
const runnable = checked
|
|
298
|
+
? modelsRunnableBy(rec.models, available)
|
|
299
|
+
: rec.models;
|
|
300
|
+
const stepUp = {
|
|
301
|
+
fast: "standard",
|
|
302
|
+
standard: "frontier",
|
|
303
|
+
};
|
|
304
|
+
let effective = runnable;
|
|
305
|
+
let tier = rec.tier;
|
|
306
|
+
let substituted;
|
|
307
|
+
while (checked && available.length && !effective.length && stepUp[tier]) {
|
|
308
|
+
const next = stepUp[tier];
|
|
309
|
+
effective = modelsRunnableBy(modelsForTier(next), available);
|
|
310
|
+
if (effective.length)
|
|
311
|
+
substituted = { from: rec.tier, to: next };
|
|
312
|
+
tier = next;
|
|
313
|
+
}
|
|
314
|
+
const shown = (effective.length ? effective : rec.models).slice(0, 4);
|
|
315
|
+
const modelNames = shown.map((m) => `${m.name} ($${m.inputCostPer1M}/$${m.outputCostPer1M})`);
|
|
174
316
|
const lines = [
|
|
175
317
|
`Phase: ${rec.phase}`,
|
|
176
318
|
`Tier: ${rec.tierLabel}`,
|
|
177
319
|
`Models: ${modelNames.join("\n ")}`,
|
|
178
|
-
`Agents: ${
|
|
320
|
+
`Agents: ${available.length ? available.join(", ") : "none detected"}${missing.length ? ` (not installed: ${missing.join(", ")})` : ""}`,
|
|
179
321
|
`Why: ${rec.reason}`,
|
|
180
322
|
];
|
|
323
|
+
if (substituted)
|
|
324
|
+
lines.push(`Note: your agents have no ${substituted.from}-tier model, so this shows`, ` the ${substituted.to} tier instead.`);
|
|
181
325
|
if (rec.conserveAlternative) {
|
|
182
326
|
const alt = rec.conserveAlternative;
|
|
183
327
|
const altCheapest = cheapestInTier(alt.tier);
|
|
184
328
|
lines.push(``, `Conserve: drop to ${alt.tier} tier (${altCheapest?.name ?? "—"} at $${altCheapest?.inputCostPer1M ?? "?"}/$${altCheapest?.outputCostPer1M ?? "?"})`, ` ${alt.tradeoff}`);
|
|
185
329
|
}
|
|
330
|
+
// Actionable next step: hand this task to a detected agent.
|
|
331
|
+
if (context.description && available.length) {
|
|
332
|
+
const target = available[0];
|
|
333
|
+
lines.push(``, `Hand off:`, ` loadout handoff ${target} ${shellQuote(context.description)}`);
|
|
334
|
+
}
|
|
186
335
|
return lines.join("\n");
|
|
187
336
|
}
|
|
188
337
|
export function formatRoutingTable(conserve = false) {
|
|
@@ -200,8 +349,13 @@ export function formatRoutingTable(conserve = false) {
|
|
|
200
349
|
return `${phase} ${tier} ${model} ${inCost} ${outCost} ${agents}`;
|
|
201
350
|
});
|
|
202
351
|
return [
|
|
203
|
-
conserve
|
|
204
|
-
|
|
352
|
+
conserve
|
|
353
|
+
? "ROUTING TABLE (conserve mode — usage-saving tier for each phase)"
|
|
354
|
+
: "ROUTING TABLE",
|
|
355
|
+
"",
|
|
356
|
+
header,
|
|
357
|
+
divider,
|
|
358
|
+
...rows,
|
|
205
359
|
].join("\n");
|
|
206
360
|
}
|
|
207
361
|
export function formatCostTable() {
|
|
@@ -216,7 +370,10 @@ export function formatCostTable() {
|
|
|
216
370
|
});
|
|
217
371
|
const savings = Math.round((1 - conserveTotal / normalTotal) * 100);
|
|
218
372
|
return [
|
|
219
|
-
header,
|
|
373
|
+
header,
|
|
374
|
+
divider,
|
|
375
|
+
...rows,
|
|
376
|
+
divider,
|
|
220
377
|
`Normal total: $${normalTotal.toFixed(2)}/M input across 6 phases`,
|
|
221
378
|
`Conserve total: $${conserveTotal.toFixed(2)}/M input (${savings}% cheaper)`,
|
|
222
379
|
"",
|
|
@@ -244,5 +401,11 @@ export function formatModelCatalog(filter) {
|
|
|
244
401
|
const agents = m.nativeAgents.slice(0, 3).join(", ");
|
|
245
402
|
return `${name} ${provider} ${tier} ${inCost} ${outCost} ${gen} ${agents}`;
|
|
246
403
|
});
|
|
247
|
-
return [
|
|
404
|
+
return [
|
|
405
|
+
`${models.length} models${filter?.current === false ? " (including legacy)" : ""}`,
|
|
406
|
+
"",
|
|
407
|
+
header,
|
|
408
|
+
divider,
|
|
409
|
+
...rows,
|
|
410
|
+
].join("\n");
|
|
248
411
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createServer, } from "node:http";
|
|
2
|
-
import { loadEffectiveCatalog, rankCatalog } from "
|
|
3
|
-
import { detectAgents } from "
|
|
4
|
-
import { buildUpdatePlan } from "
|
|
5
|
-
import { buildHealthReport } from "
|
|
2
|
+
import { loadEffectiveCatalog, rankCatalog } from "../catalog/catalog.js";
|
|
3
|
+
import { detectAgents } from "../agents/paths.js";
|
|
4
|
+
import { buildUpdatePlan } from "../install/update.js";
|
|
5
|
+
import { buildHealthReport } from "../reporting/health.js";
|
|
6
6
|
function json(response, statusCode, body) {
|
|
7
7
|
const payload = JSON.stringify(body);
|
|
8
8
|
response.writeHead(statusCode, {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import { loadoutHome } from "
|
|
4
|
+
import { loadoutHome } from "../agents/paths.js";
|
|
5
5
|
function normalizeRepository(input) {
|
|
6
6
|
const value = input
|
|
7
7
|
.trim()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
|
-
import { createCredentialResolver } from "
|
|
4
|
+
import { createCredentialResolver } from "../routing/credentials.js";
|
|
5
5
|
import { planMcpConfig } from "./mcp.js";
|
|
6
6
|
/**
|
|
7
7
|
* Small, source-linked recipes. These configure a connection only; authorizing
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { readFile, readdir, mkdir, rename, writeFile, rm, } from "node:fs/promises";
|
|
2
2
|
import { join, resolve, dirname, basename } from "node:path";
|
|
3
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
4
|
-
import { loadoutHome } from "
|
|
5
|
-
import { runMutationTransaction, withMutationLock } from "
|
|
4
|
+
import { loadoutHome } from "../agents/paths.js";
|
|
5
|
+
import { runMutationTransaction, withMutationLock, } from "../install/transaction.js";
|
|
6
6
|
const missingConfigMarker = "loadout:mcp-config:missing";
|
|
7
7
|
async function configFingerprint(path) {
|
|
8
8
|
let content;
|
|
@@ -2,10 +2,10 @@ import { execFile } from "node:child_process";
|
|
|
2
2
|
import { rm } from "node:fs/promises";
|
|
3
3
|
import { dirname, win32, join } from "node:path";
|
|
4
4
|
import { promisify } from "node:util";
|
|
5
|
-
import { writeFileAtomically } from "
|
|
6
|
-
import { ensureDirectory, loadoutHome, userHome } from "
|
|
7
|
-
import { createSnapshot, recordSnapshotPostMutationState } from "
|
|
8
|
-
import { beginTransaction, completeTransaction, markTransactionCommitting, recoverPendingTransactions, rollbackTransaction, } from "
|
|
5
|
+
import { writeFileAtomically } from "../install/atomic-file.js";
|
|
6
|
+
import { ensureDirectory, loadoutHome, userHome } from "../agents/paths.js";
|
|
7
|
+
import { createSnapshot, recordSnapshotPostMutationState, } from "../install/snapshot.js";
|
|
8
|
+
import { beginTransaction, completeTransaction, markTransactionCommitting, recoverPendingTransactions, rollbackTransaction, } from "../install/transaction.js";
|
|
9
9
|
const execFileAsync = promisify(execFile);
|
|
10
10
|
function parseTime(value) {
|
|
11
11
|
const match = /^(\d{2}):(\d{2})$/.exec(value);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { applyActivationChange, formatActivationPlan, planActivationChange, } from "./active-set.js";
|
|
2
2
|
import { DEFAULT_ACTIVE_SKILL_LIMIT } from "./active-limit.js";
|
|
3
|
-
import { detectAgents } from "
|
|
3
|
+
import { detectAgents } from "../agents/paths.js";
|
|
4
4
|
import { formatDetectedSignals, scanProject } from "./recommend.js";
|
|
5
|
-
import { scanInstalledSkills } from "
|
|
5
|
+
import { scanInstalledSkills } from "../catalog/skill-inventory.js";
|
|
6
6
|
import { readInstallState } from "./state.js";
|
|
7
7
|
import { outcomeAdjustment, projectTaskFamilies, readLocalOutcomes, } from "./outcomes.js";
|
|
8
8
|
const FOUNDATION = new Set([
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { cp, lstat, mkdir, readFile, readdir, rm } from "node:fs/promises";
|
|
3
3
|
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
4
|
-
import { agentSkillsDirectory, ensureDirectory } from "
|
|
4
|
+
import { agentSkillsDirectory, ensureDirectory } from "../agents/paths.js";
|
|
5
5
|
import { activationLibraryPath, installStatePath, readInstallState, writeInstallState, } from "./state.js";
|
|
6
6
|
import { inspectTargetOccupancy } from "./target-occupancy.js";
|
|
7
|
-
import { runMutationTransaction } from "
|
|
7
|
+
import { runMutationTransaction } from "../install/transaction.js";
|
|
8
8
|
/** Resolve a managed file to its active location or disabled library copy. */
|
|
9
9
|
export function managedFileReadPath(packageId, filePath, activations) {
|
|
10
10
|
const disabled = activations.find((activation) => activation.packageId === packageId &&
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { buildHealthReport } from "
|
|
1
|
+
import { buildHealthReport } from "../reporting/health.js";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
|
|
4
4
|
import { join, resolve } from "node:path";
|
|
5
|
-
import { loadoutHome } from "
|
|
6
|
-
import { detectSecretKinds } from "
|
|
5
|
+
import { loadoutHome } from "../agents/paths.js";
|
|
6
|
+
import { detectSecretKinds } from "../catalog/safety.js";
|
|
7
7
|
export function proposeImprovements(report) {
|
|
8
8
|
const proposals = [];
|
|
9
9
|
if (report.driftedFiles)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
|
-
import { formatSchemaError, loadoutManifestSchema } from "
|
|
3
|
+
import { formatSchemaError, loadoutManifestSchema, } from "../../shared/schemas.js";
|
|
4
4
|
import { readInstallState } from "./state.js";
|
|
5
|
-
import { writeFileAtomically } from "
|
|
5
|
+
import { writeFileAtomically } from "../install/atomic-file.js";
|
|
6
6
|
const AGENTS = new Set([
|
|
7
7
|
"claude-code",
|
|
8
8
|
"codex",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
|
-
import { writeFileAtomically } from "
|
|
5
|
-
import { ensureDirectory, loadoutHome } from "
|
|
6
|
-
import { withFileLock } from "
|
|
4
|
+
import { writeFileAtomically } from "../install/atomic-file.js";
|
|
5
|
+
import { ensureDirectory, loadoutHome } from "../agents/paths.js";
|
|
6
|
+
import { withFileLock } from "../install/file-lock.js";
|
|
7
7
|
const outcomePath = () => join(loadoutHome(), "outcomes.json");
|
|
8
8
|
const outcomeLockPath = () => join(loadoutHome(), "outcomes.lock");
|
|
9
9
|
const RESULTS = new Set([
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { lstat, mkdir, readFile, rename, rm, writeFile, } from "node:fs/promises";
|
|
2
2
|
import { dirname, isAbsolute, resolve } from "node:path";
|
|
3
|
-
import { parseLockfile, readLockfile } from "
|
|
3
|
+
import { parseLockfile, readLockfile } from "../catalog/audit.js";
|
|
4
4
|
import { parseManifest, readManifest } from "./manifest.js";
|
|
5
|
-
import { runMutationTransaction } from "
|
|
6
|
-
import { detectSecretKinds } from "
|
|
5
|
+
import { runMutationTransaction } from "../install/transaction.js";
|
|
6
|
+
import { detectSecretKinds } from "../catalog/safety.js";
|
|
7
7
|
export function parsePortableLoadout(value) {
|
|
8
8
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
9
9
|
throw new Error("Portable Loadout must be an object");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFile, readdir } from "node:fs/promises";
|
|
2
2
|
import { basename, resolve } from "node:path";
|
|
3
|
-
import { POWER_SKILL_ALLOWLIST, STABLE_BOOST_PACKAGE_IDS } from "
|
|
3
|
+
import { POWER_SKILL_ALLOWLIST, STABLE_BOOST_PACKAGE_IDS, } from "../catalog/profiles.js";
|
|
4
4
|
import { packageOutcomeAdjustment, projectTaskFamilies, } from "./outcomes.js";
|
|
5
5
|
const SIGNAL_FILES = new Set([
|
|
6
6
|
"package.json",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { readFile, readdir, stat } from "node:fs/promises";
|
|
3
3
|
import { basename, join, relative, sep } from "node:path";
|
|
4
|
-
import { formatSchemaError, installStateSchema } from "
|
|
5
|
-
import { ensureDirectory, loadoutHome } from "
|
|
6
|
-
import { writeFileAtomically } from "
|
|
4
|
+
import { formatSchemaError, installStateSchema } from "../../shared/schemas.js";
|
|
5
|
+
import { ensureDirectory, loadoutHome } from "../agents/paths.js";
|
|
6
|
+
import { writeFileAtomically } from "../install/atomic-file.js";
|
|
7
7
|
const stateFile = () => join(loadoutHome(), "state.json");
|
|
8
8
|
export const installStatePath = () => stateFile();
|
|
9
9
|
export async function writeInstallState(state) {
|
|
@@ -93,10 +93,16 @@ powers, platform behavior, category, and catalog policy.
|
|
|
93
93
|
|
|
94
94
|
## Distribute a trusted catalog release
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
> **Not implemented.** The signing flow below is a design sketch. `loadout keygen`,
|
|
97
|
+
> `loadout catalog-sign`, and `loadout catalog-update` do not exist in the CLI
|
|
98
|
+
> today; the catalog ships in the package and is verified by the evidence gate
|
|
99
|
+
> instead. Kept here as the intended shape, not as instructions.
|
|
100
|
+
|
|
101
|
+
Maintainers would sign a technically screened full catalog array with an Ed25519 key kept outside the
|
|
97
102
|
repository:
|
|
98
103
|
|
|
99
104
|
```bash
|
|
105
|
+
# Design sketch — these commands do not exist yet.
|
|
100
106
|
loadout keygen --private-key /secure/catalog-private.pem \
|
|
101
107
|
--public-key ./catalog-public.pem
|
|
102
108
|
loadout catalog-sign --catalog ./catalog/packages.json \
|
|
@@ -104,9 +110,10 @@ loadout catalog-sign --catalog ./catalog/packages.json \
|
|
|
104
110
|
--output ./catalog.signed.json
|
|
105
111
|
```
|
|
106
112
|
|
|
107
|
-
Users preview the verified release before trusting it:
|
|
113
|
+
Users would preview the verified release before trusting it:
|
|
108
114
|
|
|
109
115
|
```bash
|
|
116
|
+
# Design sketch — these commands do not exist yet.
|
|
110
117
|
loadout catalog-update --source ./catalog.signed.json \
|
|
111
118
|
--public-key ./catalog-public.pem
|
|
112
119
|
loadout catalog-update --source ./catalog.signed.json \
|
package/docs/CATALOG.md
CHANGED
|
@@ -12,7 +12,7 @@ Thank you to every maintainer and contributor whose work appears here. Loadout d
|
|
|
12
12
|
- **License** is the SPDX identifier recorded in `catalog/packages.json` from GitHub metadata. **Review required** corresponds to `NOASSERTION`: no SPDX identifier was reported, so users must inspect the upstream terms instead of assuming permission.
|
|
13
13
|
- **Reviewed revision** links to the immutable commit inspected for catalog admission. It is not necessarily the newest upstream commit.
|
|
14
14
|
|
|
15
|
-
The machine-readable catalog remains the source of truth. Run `loadout catalog --coverage --json` to inspect coverage and `loadout
|
|
15
|
+
The machine-readable catalog remains the source of truth. Run `loadout catalog --coverage --json` to inspect coverage and `loadout doctor --verbose` to inspect what each local agent adapter can actually manage.
|
|
16
16
|
|
|
17
17
|
## All 53 credited repositories
|
|
18
18
|
|
|
@@ -26,6 +26,6 @@ verification restores the snapshot and quarantines the candidate commit. A user
|
|
|
26
26
|
revoke a policy at any time; revocation prevents future mutations but never deletes
|
|
27
27
|
existing snapshots.
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
Update safety runs as a non-mutating static gate during `loadout upgrade` previews. A
|
|
30
30
|
transaction layer must provide verification and promotion callbacks before a
|
|
31
31
|
candidate can be promoted; the command itself never installs a candidate.
|