run402 4.81.0 → 4.83.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/cli.mjs +1 -1
- package/gitvault-surface.json +1 -1
- package/lib/buzz-notifications.mjs +98 -5
- package/lib/command-manifest.mjs +2 -0
- package/lib/deploy-v2.mjs +14 -6
- package/lib/up.mjs +35 -11
- package/lib/up.test.mjs +16 -0
- package/package.json +1 -1
- package/sdk/dist/namespaces/buzz-notifications.types.d.ts +13 -3
- package/sdk/dist/namespaces/buzz-notifications.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/buzz.d.ts.map +1 -1
- package/sdk/dist/namespaces/buzz.js +6 -3
- package/sdk/dist/namespaces/buzz.js.map +1 -1
- package/sdk/dist/node/actions-node.d.ts +18 -0
- package/sdk/dist/node/actions-node.d.ts.map +1 -1
- package/sdk/dist/node/actions-node.js +75 -41
- package/sdk/dist/node/actions-node.js.map +1 -1
- package/sdk/dist/node/index.d.ts +1 -1
- package/sdk/dist/node/index.d.ts.map +1 -1
- package/sdk/dist/node/index.js +3 -2
- package/sdk/dist/node/index.js.map +1 -1
|
@@ -191,8 +191,17 @@ export class NodeActions {
|
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
193
|
async #runUpFromWorkspace(input, run, source, startedAt) {
|
|
194
|
-
|
|
194
|
+
let workspaceDir = source.workspaceDir;
|
|
195
195
|
const manifest = await this.#discoverAndValidateManifest(input, workspaceDir, source.metadata, run);
|
|
196
|
+
workspaceDir = dirname(manifest.manifestPath);
|
|
197
|
+
if (!input.verifyOnly) {
|
|
198
|
+
await resolveDeploymentTarget({
|
|
199
|
+
appRoot: workspaceDir, manifestPath: manifest.manifestPath, projectId: input.projectId,
|
|
200
|
+
manifestProjectId: manifest.manifestProjectId ?? manifest.appSpec?.project.id, name: input.name,
|
|
201
|
+
targetKind: this.#targetKind(), apiBase: this.sdk.apiBase,
|
|
202
|
+
allowUnresolved: run.executionMode === "check" || run.executionMode === "printSpec" || run.dryRun,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
196
205
|
if (manifest.manifestKind === "app") {
|
|
197
206
|
if (input.verifyOnly) {
|
|
198
207
|
return this.#verifyAppManifestOnly(input, manifest, workspaceDir, run, startedAt);
|
|
@@ -272,7 +281,7 @@ export class NodeActions {
|
|
|
272
281
|
schema_version: "run402.workspace-project.v1",
|
|
273
282
|
project_id: resolved.projectId,
|
|
274
283
|
...(input.name ? { name: input.name } : {}),
|
|
275
|
-
target: { kind: this.#targetKind() },
|
|
284
|
+
target: { kind: this.#targetKind(), api_base: this.sdk.apiBase },
|
|
276
285
|
created_at: resolved.link?.created_at ?? new Date().toISOString(),
|
|
277
286
|
updated_at: new Date().toISOString(),
|
|
278
287
|
}, resolved.link, run);
|
|
@@ -588,14 +597,26 @@ export class NodeActions {
|
|
|
588
597
|
// level down) usually is one `--dir` away from the manifest it meant.
|
|
589
598
|
// Name what is one directory down so the hop is executable.
|
|
590
599
|
const nearby = await findNearbyManifests(workspaceDir);
|
|
591
|
-
const
|
|
600
|
+
const selectorArgs = [...(input.projectId ? ["--project", input.projectId] : []), ...(input.name ? ["--name", input.name] : [])];
|
|
601
|
+
const candidateActions = await Promise.all(nearby.map(async (entry) => ({
|
|
602
|
+
binding: await nearbyBinding(entry.path),
|
|
603
|
+
cwd: workspaceDir,
|
|
604
|
+
env: { RUN402_API_BASE: this.sdk.apiBase, ...(this.opts.profile ? { RUN402_WALLET: this.opts.profile } : {}) },
|
|
592
605
|
type: "run_in_directory",
|
|
593
|
-
command:
|
|
594
|
-
argv: ["run402", "up", "--check", "--dir", entry.relative_dir],
|
|
606
|
+
command: ["run402", "up", "--check", "--dir", entry.relative_dir, ...selectorArgs].map(shellArg).join(" "),
|
|
607
|
+
argv: ["run402", "up", "--check", "--dir", entry.relative_dir, ...selectorArgs],
|
|
608
|
+
app_root: dirname(entry.path),
|
|
609
|
+
manifest_path: entry.path,
|
|
610
|
+
safe_to_auto_execute: true,
|
|
595
611
|
path: entry.path,
|
|
596
612
|
dir: entry.relative_dir,
|
|
597
613
|
why: "A manifest exists one directory down; up does not walk into subdirectories.",
|
|
598
|
-
}));
|
|
614
|
+
})));
|
|
615
|
+
const nearbyActions = nearby.length > 1 ? [{
|
|
616
|
+
type: "select_application", safe_to_auto_execute: false,
|
|
617
|
+
why: "Choose the intended application; directory order does not indicate a recommendation.",
|
|
618
|
+
candidates: candidateActions.map((entry) => ({ ...entry, recommended: false })),
|
|
619
|
+
}] : candidateActions;
|
|
599
620
|
throw run.error(nearby.length > 0
|
|
600
621
|
? `No deploy manifest found in ${workspaceDir}, but ${nearby.length === 1 ? "one exists" : `${nearby.length} exist`} one directory down (${nearby.map((entry) => entry.relative_dir).join(", ")}). Re-run with --dir <that directory>, or add run402.json, run402.deploy.json or app.json here.`
|
|
601
622
|
: "No deploy manifest found. Add run402.json, run402.deploy.json or app.json, or pass --manifest for executable configs.", "UP_MANIFEST_REQUIRED", {
|
|
@@ -603,7 +624,7 @@ export class NodeActions {
|
|
|
603
624
|
candidates: MANIFEST_CANDIDATES,
|
|
604
625
|
executable_candidates: EXECUTABLE_MANIFEST_CANDIDATES,
|
|
605
626
|
nearby_manifests: nearby,
|
|
606
|
-
next_actions: [
|
|
627
|
+
next_actions: nearby.length > 1 ? nearbyActions : [
|
|
607
628
|
...nearbyActions,
|
|
608
629
|
{
|
|
609
630
|
type: "create_manifest",
|
|
@@ -684,6 +705,7 @@ export class NodeActions {
|
|
|
684
705
|
});
|
|
685
706
|
return {
|
|
686
707
|
manifestKind: "app",
|
|
708
|
+
manifestProjectId: appSpec.project.id,
|
|
687
709
|
manifestPath,
|
|
688
710
|
releaseSpec: null,
|
|
689
711
|
appGraph,
|
|
@@ -693,9 +715,7 @@ export class NodeActions {
|
|
|
693
715
|
}
|
|
694
716
|
}
|
|
695
717
|
const loaded = await loadDeployManifest(manifestPath, {
|
|
696
|
-
|
|
697
|
-
? { project: input.projectId }
|
|
698
|
-
: { defaultProject: "prj_up_preflight_placeholder" }),
|
|
718
|
+
defaultProject: "prj_up_preflight_placeholder",
|
|
699
719
|
});
|
|
700
720
|
if (!hasDeployableContent(loaded.spec)) {
|
|
701
721
|
throw run.error("Deploy manifest contains no deployable sections.", "MANIFEST_EMPTY", { manifest_path: manifestPath });
|
|
@@ -1060,7 +1080,7 @@ export class NodeActions {
|
|
|
1060
1080
|
schema_version: "run402.workspace-project.v1",
|
|
1061
1081
|
project_id: resolved.projectId,
|
|
1062
1082
|
...(input.name ? { name: input.name } : {}),
|
|
1063
|
-
target: { kind: this.#targetKind() },
|
|
1083
|
+
target: { kind: this.#targetKind(), api_base: this.sdk.apiBase },
|
|
1064
1084
|
created_at: resolved.link?.created_at ?? new Date().toISOString(),
|
|
1065
1085
|
updated_at: new Date().toISOString(),
|
|
1066
1086
|
}, resolved.link, run);
|
|
@@ -1793,7 +1813,7 @@ export class NodeActions {
|
|
|
1793
1813
|
});
|
|
1794
1814
|
run.setState(step, "running");
|
|
1795
1815
|
const linkConflict = workspaceLinkConflict(link, input, this.#targetKind(), linkPath);
|
|
1796
|
-
if (linkConflict
|
|
1816
|
+
if (linkConflict) {
|
|
1797
1817
|
throw run.error(linkConflict.message, "RUN402_WORKSPACE_LINK_CONFLICT", linkConflict.details);
|
|
1798
1818
|
}
|
|
1799
1819
|
let projectId = null;
|
|
@@ -1898,34 +1918,7 @@ export class NodeActions {
|
|
|
1898
1918
|
shouldWriteLink: true,
|
|
1899
1919
|
};
|
|
1900
1920
|
}
|
|
1901
|
-
|
|
1902
|
-
if (active) {
|
|
1903
|
-
const activeStep = run.addStep({
|
|
1904
|
-
action: "project.resolve",
|
|
1905
|
-
description: "Use active project for this workspace",
|
|
1906
|
-
mutation: false,
|
|
1907
|
-
auto: true,
|
|
1908
|
-
details: { active_project_id: active },
|
|
1909
|
-
});
|
|
1910
|
-
await run.approve(activeStep, [], `Use active project ${active} and link this workspace to it.`);
|
|
1911
|
-
run.setState(activeStep, run.dryRun ? "planned" : "succeeded", {
|
|
1912
|
-
project_id: active,
|
|
1913
|
-
source: "active",
|
|
1914
|
-
});
|
|
1915
|
-
run.setState(step, run.dryRun ? "planned" : "succeeded", {
|
|
1916
|
-
project_id: active,
|
|
1917
|
-
source: "active",
|
|
1918
|
-
link_path: linkPath,
|
|
1919
|
-
});
|
|
1920
|
-
return {
|
|
1921
|
-
projectId: active,
|
|
1922
|
-
source: "active",
|
|
1923
|
-
link,
|
|
1924
|
-
linkPath,
|
|
1925
|
-
shouldWriteLink: true,
|
|
1926
|
-
};
|
|
1927
|
-
}
|
|
1928
|
-
throw run.error("No project is configured for this workspace. Pass --project, add project_id to the manifest, or pass --name to create one.", "RUN402_PROJECT_REQUIRED", { link_path: linkPath, manifest_path: manifest.manifestPath });
|
|
1921
|
+
throw projectSelectionRequired(workspaceDir, manifest.manifestPath);
|
|
1929
1922
|
}
|
|
1930
1923
|
async #resolveProjectForVerify(input, manifest, workspaceDir, run) {
|
|
1931
1924
|
const linkPath = join(workspaceDir, ".run402", "project.json");
|
|
@@ -2732,7 +2725,9 @@ async function readWorkspaceProjectLink(path) {
|
|
|
2732
2725
|
try {
|
|
2733
2726
|
raw = await readFile(path, "utf-8");
|
|
2734
2727
|
}
|
|
2735
|
-
catch {
|
|
2728
|
+
catch (err) {
|
|
2729
|
+
if (err.code !== "ENOENT")
|
|
2730
|
+
throw err;
|
|
2736
2731
|
return null;
|
|
2737
2732
|
}
|
|
2738
2733
|
let parsed;
|
|
@@ -2913,4 +2908,43 @@ function actionErrorDetails(err) {
|
|
|
2913
2908
|
function assertNever(value) {
|
|
2914
2909
|
throw new LocalError(`Unknown Run402 action ${value.type}`, "running Run402 action", { code: "RUN402_ACTION_UNKNOWN" });
|
|
2915
2910
|
}
|
|
2911
|
+
/** Resolve only local destination intent. Approval and global active state are never selectors. */
|
|
2912
|
+
export async function resolveDeploymentTarget(input) {
|
|
2913
|
+
const linkPath = join(input.appRoot, ".run402", "project.json");
|
|
2914
|
+
const link = await readWorkspaceProjectLink(linkPath);
|
|
2915
|
+
const conflict = workspaceLinkConflict(link, input, input.targetKind ?? "unknown", linkPath);
|
|
2916
|
+
if (conflict)
|
|
2917
|
+
throw new LocalError(conflict.message, "resolving deployment target", { code: "RUN402_WORKSPACE_LINK_CONFLICT", details: conflict.details });
|
|
2918
|
+
if (link?.target?.api_base && input.apiBase && link.target.api_base.replace(/\/$/, "") !== input.apiBase.replace(/\/$/, "")) {
|
|
2919
|
+
throw new LocalError("Workspace link belongs to a different API target.", "resolving deployment target", { code: "RUN402_WORKSPACE_LINK_CONFLICT", details: { reason: "api_base_mismatch", link_path: linkPath } });
|
|
2920
|
+
}
|
|
2921
|
+
const selectors = [input.projectId, input.environmentProjectId, link?.project_id, input.manifestProjectId].filter(Boolean);
|
|
2922
|
+
if (new Set(selectors).size > 1) {
|
|
2923
|
+
throw new LocalError("Deployment project selectors disagree.", "resolving deployment target", { code: "RUN402_PROJECT_CONFLICT", details: { explicit_project_id: input.projectId ?? null, linked_project_id: link?.project_id ?? null, manifest_project_id: input.manifestProjectId ?? null } });
|
|
2924
|
+
}
|
|
2925
|
+
const projectId = input.projectId ?? input.environmentProjectId ?? link?.project_id ?? input.manifestProjectId ?? null;
|
|
2926
|
+
if (projectId && input.name && (!link || link.name !== input.name)) {
|
|
2927
|
+
throw new LocalError("--name is creation intent and cannot select or rename an existing project. Pass --project alone.", "resolving deployment target", { code: "RUN402_PROJECT_CONFLICT", details: { project_id: projectId, name: input.name } });
|
|
2928
|
+
}
|
|
2929
|
+
if (!projectId && !input.name && !input.allowUnresolved)
|
|
2930
|
+
throw projectSelectionRequired(input.appRoot, input.manifestPath);
|
|
2931
|
+
return { project_id: projectId, project_name: input.name ?? link?.name ?? null,
|
|
2932
|
+
source: input.projectId || input.environmentProjectId ? "explicit" : link ? "workspace_link" : input.manifestProjectId ? "manifest" : input.name ? "create" : "unresolved" };
|
|
2933
|
+
}
|
|
2934
|
+
function projectSelectionRequired(appRoot, manifestPath) {
|
|
2935
|
+
return new LocalError("No deployment destination is selected. Pass --project for an existing project or --name to create one; -y never selects the global active project.", "resolving deployment target", {
|
|
2936
|
+
code: "UP_PROJECT_REQUIRED", details: { app_root: appRoot, manifest_path: manifestPath ?? null, mutation_state: "not_started" },
|
|
2937
|
+
next_actions: [{ type: "select_project", safe_to_auto_execute: false, why: "Select the intended project explicitly, or name a new project, then retry in this application directory.", app_root: appRoot }],
|
|
2938
|
+
});
|
|
2939
|
+
}
|
|
2940
|
+
async function nearbyBinding(manifestPath) {
|
|
2941
|
+
try {
|
|
2942
|
+
const manifest = JSON.parse(await readFile(manifestPath, "utf-8"));
|
|
2943
|
+
const link = await readWorkspaceProjectLink(join(dirname(manifestPath), ".run402", "project.json"));
|
|
2944
|
+
return { app_name: manifest.app?.name ?? manifest.app?.id ?? null, manifest_project_id: typeof manifest.project === "string" ? manifest.project : manifest.project_id ?? manifest.project?.id ?? null, linked_project_id: link?.project_id ?? null, target: link?.target ?? null };
|
|
2945
|
+
}
|
|
2946
|
+
catch {
|
|
2947
|
+
return { status: "unknown", reason: "Local binding could not be read; select the application and run its check." };
|
|
2948
|
+
}
|
|
2949
|
+
}
|
|
2916
2950
|
//# sourceMappingURL=actions-node.js.map
|