mirror of
https://github.com/vercel/vercel-plugin.git
synced 2026-09-14 15:39:47 +08:00
266f79d026
The orchestrator now has to treat skill bodies as external, cacheable state so projects stay clean and the plugin can ship without bundled skill content. This keeps runtime behavior aligned with the zero-bundle design, makes first-session installs happen against the hashed home-state cache, and prevents prompts and status banners from sending users back to the retired project-local .skills flow. The test updates also lock cache-dependent behavior to an isolated plugin home so verification exercises the hashed cache contract instead of ambient machine state. That keeps the migration reliable across environments and catches regressions in the new cache resolution model. Ploop-Iter: 3
97 lines
3.5 KiB
JavaScript
97 lines
3.5 KiB
JavaScript
// hooks/src/orchestrator-action-spec.mts
|
|
function planActionMap(plan) {
|
|
return new Map(plan.actions.map((action) => [action.id, action]));
|
|
}
|
|
function blockedReasonForAction(plan, actionId) {
|
|
switch (actionId) {
|
|
case "bootstrap-project":
|
|
case "install-missing":
|
|
case "vercel-link":
|
|
return null;
|
|
case "vercel-env-pull":
|
|
if (!plan.vercelLinked) {
|
|
return "Link the project first; `vercel env pull` requires a linked Vercel project.";
|
|
}
|
|
if (plan.hasEnvLocal) {
|
|
return "`.env.local` already exists; env pull is not needed.";
|
|
}
|
|
return null;
|
|
case "vercel-deploy":
|
|
return plan.vercelLinked ? null : "Link the project first; `vercel deploy` is only runnable after the project is linked.";
|
|
}
|
|
}
|
|
function withRunState(plan, spec) {
|
|
const blockedReason = blockedReasonForAction(plan, spec.id);
|
|
return {
|
|
...spec,
|
|
runnable: blockedReason === null,
|
|
blockedReason
|
|
};
|
|
}
|
|
function getOrchestratorActionSpecs(plan) {
|
|
const actions = planActionMap(plan);
|
|
const installMissing = actions.get("install-missing");
|
|
const vercelLink = actions.get("vercel-link");
|
|
const vercelEnvPull = actions.get("vercel-env-pull");
|
|
const vercelDeploy = actions.get("vercel-deploy");
|
|
return [
|
|
withRunState(plan, {
|
|
id: "bootstrap-project",
|
|
label: "Bootstrap project (link + env + skills)",
|
|
description: "Link the project if needed, pull `.env.local` if missing, then install detected skills.",
|
|
discoverable: !plan.vercelLinked || !plan.hasEnvLocal || plan.missingSkills.length > 0,
|
|
visible: !plan.vercelLinked || !plan.hasEnvLocal || plan.missingSkills.length > 0,
|
|
steps: [
|
|
{ step: "vercel-link", mode: "if-needed" },
|
|
{ step: "vercel-env-pull", mode: "if-needed" },
|
|
{ step: "install-missing", mode: "always" }
|
|
]
|
|
}),
|
|
withRunState(plan, {
|
|
id: "install-missing",
|
|
label: "Install missing skills into cache",
|
|
description: installMissing?.description ?? "Install detected skills into the project skill cache.",
|
|
discoverable: plan.missingSkills.length > 0,
|
|
visible: plan.missingSkills.length > 0,
|
|
steps: [{ step: "install-missing", mode: "always" }]
|
|
}),
|
|
withRunState(plan, {
|
|
id: "vercel-link",
|
|
label: vercelLink?.label ?? "Link Vercel project",
|
|
description: vercelLink?.description ?? "Link this project to a Vercel project.",
|
|
discoverable: !plan.vercelLinked,
|
|
visible: !plan.vercelLinked,
|
|
steps: [{ step: "vercel-link", mode: "always" }]
|
|
}),
|
|
withRunState(plan, {
|
|
id: "vercel-env-pull",
|
|
label: "Pull .env.local from Vercel",
|
|
description: vercelEnvPull?.description ?? "Pull `.env.local` from the linked Vercel project.",
|
|
discoverable: !plan.hasEnvLocal,
|
|
visible: plan.vercelLinked && !plan.hasEnvLocal,
|
|
steps: [{ step: "vercel-env-pull", mode: "always" }]
|
|
}),
|
|
withRunState(plan, {
|
|
id: "vercel-deploy",
|
|
label: vercelDeploy?.label ?? "Deploy to Vercel",
|
|
description: vercelDeploy?.description ?? "Deploy the current project to Vercel.",
|
|
discoverable: plan.vercelLinked,
|
|
visible: plan.vercelLinked,
|
|
steps: [{ step: "vercel-deploy", mode: "always" }]
|
|
})
|
|
];
|
|
}
|
|
function getOrchestratorActionSpec(plan, actionId) {
|
|
const spec = getOrchestratorActionSpecs(plan).find(
|
|
(entry) => entry.id === actionId
|
|
);
|
|
if (!spec) {
|
|
throw new Error(`Invalid --action: ${actionId}`);
|
|
}
|
|
return spec;
|
|
}
|
|
export {
|
|
getOrchestratorActionSpec,
|
|
getOrchestratorActionSpecs
|
|
};
|