@nextcommerce/campaigns-os 1.54.0 → 1.57.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 +148 -0
- package/CONTEXT.md +19 -5
- package/README.md +26 -12
- package/campaign-spec/README.md +15 -1
- package/campaign-spec/dist/checkout-flow.d.ts +90 -0
- package/campaign-spec/dist/checkout-flow.js +229 -0
- package/campaign-spec/dist/index.d.ts +1 -0
- package/campaign-spec/dist/index.js +6 -1
- package/campaign-spec/dist/normalize.d.ts +3 -2
- package/campaign-spec/dist/normalize.js +7 -5
- package/campaign-spec/dist/routing.d.ts +6 -3
- package/campaign-spec/dist/routing.js +6 -3
- package/campaign-spec/dist/rules/checkout-forward-target.d.ts +17 -0
- package/campaign-spec/dist/rules/checkout-forward-target.js +48 -0
- package/campaign-spec/dist/rules/checkout-step-reaches-checkout.d.ts +12 -0
- package/campaign-spec/dist/rules/checkout-step-reaches-checkout.js +37 -0
- package/campaign-spec/dist/rules/exit-intent-validation.js +2 -1
- package/campaign-spec/dist/rules/index.d.ts +4 -0
- package/campaign-spec/dist/rules/index.js +12 -0
- package/campaign-spec/dist/rules/one-checkout-per-path.d.ts +25 -0
- package/campaign-spec/dist/rules/one-checkout-per-path.js +84 -0
- package/campaign-spec/dist/rules/pre-payment-forward-target.d.ts +12 -0
- package/campaign-spec/dist/rules/pre-payment-forward-target.js +42 -0
- package/campaign-spec/dist/rules/promo-code-input-validation.js +2 -1
- package/campaign-spec/dist/rules/schema-version.d.ts +9 -4
- package/campaign-spec/dist/rules/schema-version.js +10 -5
- package/campaign-spec/dist/types.d.ts +20 -3
- package/campaign-spec/dist/types.js +3 -2
- package/compatibility.json +2 -2
- package/contracts/fixtures/runtime-recipe/accept/current.json +6 -1
- package/contracts/fixtures/runtime-recipe/accept/minimal.json +6 -1
- package/contracts/fixtures/runtime-recipe/dist-states.json +1 -1
- package/contracts/fixtures/runtime-recipe/reject/advisory-enforcement.json +6 -1
- package/contracts/fixtures/runtime-recipe/reject/allowlist-without-hosts.json +6 -1
- package/contracts/fixtures/runtime-recipe/reject/committed-output-claim.json +6 -1
- package/contracts/fixtures/runtime-recipe/reject/engines-disagreement-warns.json +6 -1
- package/contracts/fixtures/runtime-recipe/reject/lifecycle-scripts-enabled.json +6 -1
- package/contracts/fixtures/runtime-recipe/reject/missing-required-field.json +1 -1
- package/contracts/fixtures/runtime-recipe/reject/unknown-kind.json +6 -1
- package/contracts/fixtures/runtime-recipe/reject/unknown-network-policy.json +6 -1
- package/contracts/fixtures/runtime-recipe/reject/unknown-output-check.json +6 -1
- package/contracts/fixtures/runtime-recipe/reject/unknown-revision.json +5 -0
- package/contracts/fixtures/runtime-recipe/reject/unknown-step-id.json +6 -1
- package/contracts/fixtures/runtime-recipe/reject/unperformable-check-skipped.json +6 -1
- package/contracts/fixtures/runtime-recipe/reject/unpinned-lockfile.json +6 -1
- package/contracts/release-ledger.json +1146 -0
- package/contracts/runtime-recipe.campaigns-os-node-v1.json +6 -1
- package/contracts/supported-surface.json +9 -5
- package/docs/brand-theme-bridge.md +10 -0
- package/docs/build-packet.md +86 -26
- package/docs/campaigns-os-build-flow.md +1 -1
- package/docs/effects.md +2 -5
- package/docs/local-setup.md +1 -1
- package/docs/orientation-contract-reference.md +1 -1
- package/docs/qa-and-test-orders.md +133 -29
- package/docs/runtime-readiness.md +8 -3
- package/docs/skills-revision.md +10 -10
- package/docs/supported-surface.md +1 -1
- package/docs/versioning.md +4 -1
- package/docs/workflow-findings-sidecar.md +57 -2
- package/package.json +4 -1
- package/schemas/campaign-runtime-build-context.v0.schema.json +3 -1
- package/schemas/campaign-runtime-build-packet.v0.schema.json +3 -1
- package/schemas/campaign-spec.v5.schema.json +586 -0
- package/schemas/campaigns-os-run-record.v0.schema.json +20 -15
- package/skills/campaign-lifecycle-orientation/SKILL.md +10 -8
- package/skills/campaign-readback-classification/SKILL.md +3 -3
- package/skills/campaign-run-evidence/SKILL.md +3 -3
- package/skills/contribution-intake/SKILL.md +3 -3
- package/skills/next-campaigns-build/SKILL.md +6 -4
- package/skills/next-campaigns-os/SKILL.md +3 -3
- package/skills/next-campaigns-os-setup/SKILL.md +3 -3
- package/skills/next-campaigns-polish/SKILL.md +21 -6
- package/skills/next-campaigns-qa/SKILL.md +5 -4
- package/skills.json +10 -10
- package/src/adapter-decision-contract.mjs +27 -13
- package/src/brand-theme.mjs +44 -8
- package/src/build-brief.mjs +14 -5
- package/src/campaign-identity.mjs +33 -4
- package/src/cli-helpers.mjs +129 -0
- package/src/cli.mjs +156 -111
- package/src/commercial-journey.mjs +25 -2
- package/src/consent.mjs +3 -2
- package/src/design-source-package.mjs +1 -1
- package/src/design-source-publication.mjs +8 -8
- package/src/deviation.mjs +2 -1
- package/src/doctor/checks.mjs +212 -19
- package/src/doctor/inspect.mjs +4 -2
- package/src/doctor/next-step.mjs +46 -16
- package/src/doctor-sidecar.mjs +5 -3
- package/src/gate-actions.mjs +21 -1
- package/src/input-refresh.mjs +6 -6
- package/src/invocation.mjs +4 -3
- package/src/lifecycle.mjs +88 -6
- package/src/local-preview-policy.mjs +116 -12
- package/src/login.mjs +2 -1
- package/src/polish-browser.mjs +8 -2
- package/src/polish-node.mjs +9 -4
- package/src/polish-readability.mjs +2 -2
- package/src/qa-browser.mjs +741 -120
- package/src/qa-cart-entry.mjs +107 -20
- package/src/qa-node.mjs +179 -72
- package/src/qa-test-order-topology.mjs +118 -1
- package/src/qa-verdict-discovery.mjs +21 -4
- package/src/qa-verdict-publish.mjs +2 -1
- package/src/run-record.mjs +46 -34
- package/src/runtime-state-ignore.mjs +7 -5
- package/src/sdk-markup.mjs +41 -1
- package/src/source-html-intake.mjs +46 -4
- package/src/stage-ledger.mjs +18 -4
- package/src/stage-record.mjs +53 -16
package/src/stage-record.mjs
CHANGED
|
@@ -26,11 +26,12 @@ import { fileURLToPath } from "node:url";
|
|
|
26
26
|
import Ajv2020 from "ajv/dist/2020.js";
|
|
27
27
|
|
|
28
28
|
import { BRAND_LAYER_FILENAMES } from "./brand-theme.mjs";
|
|
29
|
+
import { ADAPTER_DECISION_SCALAR_VALUES } from "./adapter-decision-contract.mjs";
|
|
29
30
|
import { computeBuildFingerprint, resolveBuiltSiteScope } from "./built-site-scope.mjs";
|
|
30
31
|
import { resolveCampaignWorkspace, targetRepoFor } from "./campaign-workspace.mjs";
|
|
31
|
-
import { isObject, optionalString, readJsonIfExists, requireArg } from "./cli-helpers.mjs";
|
|
32
|
+
import { isObject, optionalString, portableArtifactPaths, readJsonIfExists, requireArg } from "./cli-helpers.mjs";
|
|
32
33
|
import { LOCAL_PROOF_BUILD_ENVIRONMENT, LOCAL_PROOF_PRODUCTION_ENVIRONMENT, isLocalServePacket } from "./local-proof.mjs";
|
|
33
|
-
import {
|
|
34
|
+
import { polishCarriedForwardForLadder } from "./local-preview-policy.mjs";
|
|
34
35
|
import { isLoopbackHostname } from "./remit.mjs";
|
|
35
36
|
import { campaignRouteRoot } from "./route-identity.mjs";
|
|
36
37
|
import { writeJsonAtomic } from "./doctor-sidecar.mjs";
|
|
@@ -60,7 +61,7 @@ export const RECORD_STAGES = Object.freeze(["setup", "build", "polish", "theme",
|
|
|
60
61
|
const RECORD_FLAGS = Object.freeze(["packet", "context", "report", "dry-run", "json", "run-id", "lifecycle-journal", "deviation-reason"]);
|
|
61
62
|
const POLISH_RECORD_FLAGS = Object.freeze(["evidence"]);
|
|
62
63
|
const DEPLOY_RECORD_FLAGS = Object.freeze(["base-url"]);
|
|
63
|
-
const BUILD_RECORD_FLAGS = Object.freeze(["build-environment"]);
|
|
64
|
+
const BUILD_RECORD_FLAGS = Object.freeze(["build-environment", "adapter-decision"]);
|
|
64
65
|
// `record brief` saves a brief file: --brief names it (otherwise intake's
|
|
65
66
|
// discovery finds it).
|
|
66
67
|
const BRIEF_RECORD_FLAGS = Object.freeze(["brief"]);
|
|
@@ -130,10 +131,43 @@ export function refuseRecord(stage, problems) {
|
|
|
130
131
|
return new Error(`record ${stage} refused; nothing was written:\n${problems.map((problem) => `- ${problem}`).join("\n")}`);
|
|
131
132
|
}
|
|
132
133
|
|
|
134
|
+
function parseAdapterDecisions(value) {
|
|
135
|
+
const allowedKeys = Object.keys(ADAPTER_DECISION_SCALAR_VALUES).join(", ");
|
|
136
|
+
const reject = (reason, key = null) => {
|
|
137
|
+
const allowedValues = key && Object.hasOwn(ADAPTER_DECISION_SCALAR_VALUES, key)
|
|
138
|
+
? ` Allowed values for ${key}: ${ADAPTER_DECISION_SCALAR_VALUES[key].join(", ")}.`
|
|
139
|
+
: "";
|
|
140
|
+
throw refused(`${reason} Allowed keys: ${allowedKeys}.${allowedValues}`);
|
|
141
|
+
};
|
|
142
|
+
if (typeof value !== "string" || !value) reject("--adapter-decision requires a comma-separated list of key=value pairs.");
|
|
143
|
+
const decisions = {};
|
|
144
|
+
for (const pair of value.split(",")) {
|
|
145
|
+
if (!pair) reject("--adapter-decision has an empty pair; use key=value pairs separated by commas.");
|
|
146
|
+
const equal = pair.indexOf("=");
|
|
147
|
+
if (equal < 0) reject(`--adapter-decision pair ${JSON.stringify(pair)} must be key=value.`);
|
|
148
|
+
const key = pair.slice(0, equal);
|
|
149
|
+
const choice = pair.slice(equal + 1);
|
|
150
|
+
if (!key || /\s/.test(key)) reject(`--adapter-decision key ${JSON.stringify(key)} must be a nonempty key without whitespace.`);
|
|
151
|
+
if (key === "wrapper_policy") reject("wrapper_policy is selected at intake with prepare-build --wrapper-policy or the source-html manifest's wrapper_policy option; record build cannot change it.");
|
|
152
|
+
if (!Object.hasOwn(ADAPTER_DECISION_SCALAR_VALUES, key)) reject(`Unknown --adapter-decision key ${JSON.stringify(key)}.`);
|
|
153
|
+
if (Object.hasOwn(decisions, key)) reject(`Duplicate --adapter-decision key ${JSON.stringify(key)} in one list.`);
|
|
154
|
+
const allowed = ADAPTER_DECISION_SCALAR_VALUES[key];
|
|
155
|
+
if (!choice || /\s/.test(choice) || choice.includes("=") || !allowed.includes(choice)) {
|
|
156
|
+
reject(`--adapter-decision ${key} must be one of: ${allowed.join(", ")} (got ${JSON.stringify(choice)}).`, key);
|
|
157
|
+
}
|
|
158
|
+
decisions[key] = choice;
|
|
159
|
+
}
|
|
160
|
+
return decisions;
|
|
161
|
+
}
|
|
162
|
+
|
|
133
163
|
export function parseRecordArgs(args) {
|
|
134
164
|
const stage = args._[1];
|
|
165
|
+
// The shared argv parser leaves an explicit empty value in positional args.
|
|
166
|
+
if (stage === "build" && args["adapter-decision"] === true && args._.length === 3 && args._[2] === "") {
|
|
167
|
+
parseAdapterDecisions("");
|
|
168
|
+
}
|
|
135
169
|
if (!RECORD_SUBCOMMANDS.includes(stage) || args._.length !== 2) {
|
|
136
|
-
throw refused(`Use: ${cmd("record")} <${RECORD_SUBCOMMANDS.join("|")}> --packet <campaign-runtime.build.json> [--context <json>] [--report <json>] [--dry-run] [--json]; record polish also takes --evidence <polish-evidence.json>, record deploy --base-url <served url>, record build [--build-environment <${BUILD_ENVIRONMENTS.join("|")}>], and record brief [--brief <yaml|json>].`);
|
|
170
|
+
throw refused(`Use: ${cmd("record")} <${RECORD_SUBCOMMANDS.join("|")}> --packet <campaign-runtime.build.json> [--context <json>] [--report <json>] [--dry-run] [--json]; record polish also takes --evidence <polish-evidence.json>, record deploy --base-url <served url>, record build [--build-environment <${BUILD_ENVIRONMENTS.join("|")}>] [--adapter-decision <key=value[,key=value...]>], and record brief [--brief <yaml|json>].`);
|
|
137
171
|
}
|
|
138
172
|
const known = new Set([...RECORD_FLAGS, ...(stage === "polish" ? POLISH_RECORD_FLAGS : []), ...(stage === "deploy" ? DEPLOY_RECORD_FLAGS : []), ...(stage === "build" ? BUILD_RECORD_FLAGS : []), ...(stage === "brief" ? BRIEF_RECORD_FLAGS : [])]);
|
|
139
173
|
const unknown = Object.keys(args).filter((key) => key !== "_" && !known.has(key));
|
|
@@ -151,6 +185,7 @@ export function parseRecordArgs(args) {
|
|
|
151
185
|
if (buildEnvironment !== null && !BUILD_ENVIRONMENTS.includes(buildEnvironment)) {
|
|
152
186
|
throw refused(`--build-environment must be one of: ${BUILD_ENVIRONMENTS.join(", ")} (got ${JSON.stringify(buildEnvironment)}).`);
|
|
153
187
|
}
|
|
188
|
+
const adapterDecisions = Object.hasOwn(args, "adapter-decision") ? parseAdapterDecisions(args["adapter-decision"]) : null;
|
|
154
189
|
return {
|
|
155
190
|
stage,
|
|
156
191
|
packetPath: resolve(requireArg(args, "packet")),
|
|
@@ -158,6 +193,7 @@ export function parseRecordArgs(args) {
|
|
|
158
193
|
baseUrl: stage === "deploy" ? requireArg(args, "base-url") : null,
|
|
159
194
|
dryRun: args["dry-run"] === true,
|
|
160
195
|
buildEnvironment,
|
|
196
|
+
adapterDecisions,
|
|
161
197
|
briefPath: stage === "brief" && Object.hasOwn(args, "brief") ? resolve(args.brief) : null,
|
|
162
198
|
deviationReason: optionalString(args["deviation-reason"]),
|
|
163
199
|
};
|
|
@@ -291,7 +327,8 @@ function currentStamps(inputs) {
|
|
|
291
327
|
return Object.fromEntries(Object.entries(stamps).filter(([, value]) => value !== null));
|
|
292
328
|
}
|
|
293
329
|
|
|
294
|
-
function composeBuild(report, { now, recordedBy, fingerprint, buildEnvironment = null, inputs = {}, deviationReason = null }) {
|
|
330
|
+
function composeBuild(report, { now, recordedBy, fingerprint, buildEnvironment = null, adapterDecisions = null, fallbackAdapterDecisions = null, inputs = {}, deviationReason = null }) {
|
|
331
|
+
const nextReport = adapterDecisions ? { ...report, adapter_decisions: { ...(report.adapter_decisions || fallbackAdapterDecisions || {}), ...adapterDecisions } } : report;
|
|
295
332
|
const sourcePackageFingerprint = currentSourcePackageMaterialFingerprint(report);
|
|
296
333
|
const previousAssembly = stageObject(report, "assembly");
|
|
297
334
|
const stamps = currentStamps(inputs);
|
|
@@ -337,7 +374,7 @@ function composeBuild(report, { now, recordedBy, fingerprint, buildEnvironment =
|
|
|
337
374
|
const deploy = deployOwed ? { deploy: deployOwed } : {};
|
|
338
375
|
if (detected) {
|
|
339
376
|
const cause = detected === "spec_material_changed" ? "spec" : "presentation";
|
|
340
|
-
const demoted = demoteStages({ ...
|
|
377
|
+
const demoted = demoteStages({ ...nextReport, stages: { ...nextReport.stages, assembly, ...deploy } }, { causes: [cause], now, by: "record build", only: ["polish", "qa"] });
|
|
341
378
|
return { report: demoted.report, context: null };
|
|
342
379
|
}
|
|
343
380
|
const previousPolish = stageObject(report, "polish");
|
|
@@ -352,7 +389,7 @@ function composeBuild(report, { now, recordedBy, fingerprint, buildEnvironment =
|
|
|
352
389
|
required_by: "build",
|
|
353
390
|
required_for: ["qa"],
|
|
354
391
|
};
|
|
355
|
-
return { report: { ...
|
|
392
|
+
return { report: { ...nextReport, stages: { ...nextReport.stages, assembly, polish, ...deploy } }, context: null };
|
|
356
393
|
}
|
|
357
394
|
|
|
358
395
|
// stages.deploy after a build of `fingerprint`, or null when it is kept: a
|
|
@@ -711,9 +748,8 @@ function ladderProblems(stage, doctor, report) {
|
|
|
711
748
|
if (gate) return [`next answers prepare-build: ${gate.reason}`];
|
|
712
749
|
const problems = [];
|
|
713
750
|
for (const earlier of NEXT_STAGE_ORDER.slice(0, NEXT_STAGE_ORDER.indexOf(stage))) {
|
|
714
|
-
// The rule next's stage picker reads
|
|
715
|
-
|
|
716
|
-
if (earlier === "polish" && doctor.derived?.polish_gate?.status === CARRIED_FORWARD) continue;
|
|
751
|
+
// The same carried-forward rule next's stage picker reads.
|
|
752
|
+
if (earlier === "polish" && polishCarriedForwardForLadder(report, doctor.derived?.polish_gate)) continue;
|
|
717
753
|
// The effective status: a stage owed again by an input change reads
|
|
718
754
|
// required, and one whose inputs cannot be confirmed reads unknown.
|
|
719
755
|
const key = reportKeyForCliStage(earlier);
|
|
@@ -852,7 +888,7 @@ function readPacketFile(stage, packetPath) {
|
|
|
852
888
|
* composed or written.
|
|
853
889
|
*/
|
|
854
890
|
export function recordStageCommand(args, { now = () => new Date(), beforeLock = null, afterDoctorRead = null, probe = null } = {}) {
|
|
855
|
-
const { stage, packetPath, evidencePath, dryRun, buildEnvironment, deviationReason } = parseRecordArgs(args);
|
|
891
|
+
const { stage, packetPath, evidencePath, dryRun, buildEnvironment, adapterDecisions, deviationReason } = parseRecordArgs(args);
|
|
856
892
|
if (!existsSync(packetPath)) throw new Error(`record ${stage}: Build Packet not found at ${packetPath}; run ${cmd("start")} or ${cmd("prepare-build")} first.`);
|
|
857
893
|
if (stage === "deploy" && !probe) throw new Error("record deploy needs the served-route probe; run it through recordCommand.");
|
|
858
894
|
// Operator input, not target state: no campaigns-os writer produces it.
|
|
@@ -873,7 +909,7 @@ export function recordStageCommand(args, { now = () => new Date(), beforeLock =
|
|
|
873
909
|
// A dry run writes nothing, so it takes no lock and creates no lock files
|
|
874
910
|
// (the commitAssemblyReport preview convention); it reads in the same order.
|
|
875
911
|
const run = () => recordUnderLock({
|
|
876
|
-
stage, packetPath, sidecars, lockedTarget, input, dryRun, timestamp, recordedBy, afterDoctorRead, buildEnvironment, deviationReason,
|
|
912
|
+
stage, packetPath, sidecars, lockedTarget, input, dryRun, timestamp, recordedBy, afterDoctorRead, buildEnvironment, adapterDecisions, deviationReason,
|
|
877
913
|
});
|
|
878
914
|
const recorded = dryRun ? run() : withTargetLockSync(lockedTarget, run, { command: `record ${stage}` });
|
|
879
915
|
const { composed, facts, layer, reportPath, contextPath, after } = recorded;
|
|
@@ -891,6 +927,7 @@ export function recordStageCommand(args, { now = () => new Date(), beforeLock =
|
|
|
891
927
|
`stages.${stageKey}.status = ${composed.report.stages[stageKey].status}`,
|
|
892
928
|
...(facts.fingerprint ? [`build output fingerprint ${facts.fingerprint} (doctor derived.build_output_fingerprint.value)`] : []),
|
|
893
929
|
...(stage === "build" && buildEnvironment ? [`stages.assembly.evidence.build_environment = ${buildEnvironment}`] : []),
|
|
930
|
+
...(stage === "build" && adapterDecisions ? Object.entries(adapterDecisions).map(([key, value]) => `report.adapter_decisions.${key} = ${value}`) : []),
|
|
894
931
|
...(stage === "build" ? [`stages.polish.status = ${composed.report.stages.polish.status}`] : []),
|
|
895
932
|
...(stage === "build" && composed.report.stages.deploy?.required_by === "build" ? [`stages.deploy.status = ${composed.report.stages.deploy.status} (the recorded deploy probed other output; run ${cmd("record")} deploy again)`] : []),
|
|
896
933
|
...(composed.context ? ["Build Context scaffold.required = false"] : []),
|
|
@@ -930,7 +967,7 @@ function recordInputs(doctor) {
|
|
|
930
967
|
return { briefMaterial: currency?.brief?.current ?? null, specMaterial: currency?.spec?.current ?? null };
|
|
931
968
|
}
|
|
932
969
|
|
|
933
|
-
function recordUnderLock({ stage, packetPath, sidecars, lockedTarget, input, dryRun, timestamp, recordedBy, afterDoctorRead, buildEnvironment = null, deviationReason = null }) {
|
|
970
|
+
function recordUnderLock({ stage, packetPath, sidecars, lockedTarget, input, dryRun, timestamp, recordedBy, afterDoctorRead, buildEnvironment = null, adapterDecisions = null, deviationReason = null }) {
|
|
934
971
|
// The same workspace `next` resolves, so the record lands in the report
|
|
935
972
|
// `next` reads now, not the one it read before the lock was free.
|
|
936
973
|
const workspace = resolveCampaignWorkspace(packetPath, { ...sidecars, followContextPointer: true });
|
|
@@ -965,7 +1002,7 @@ function recordUnderLock({ stage, packetPath, sidecars, lockedTarget, input, dry
|
|
|
965
1002
|
const next = stage === "setup"
|
|
966
1003
|
? composeSetup(report, context, { now: timestamp, recordedBy })
|
|
967
1004
|
: stage === "build"
|
|
968
|
-
? composeBuild(report, { now: timestamp, recordedBy, fingerprint: facts.fingerprint, buildEnvironment, inputs: recordInputs(doctor), deviationReason })
|
|
1005
|
+
? composeBuild(report, { now: timestamp, recordedBy, fingerprint: facts.fingerprint, buildEnvironment, adapterDecisions, fallbackAdapterDecisions: adapterDecisions && !report.adapter_decisions ? readJsonIfExists(contextPath)?.adapter_decisions || packet.source_html?.adapter_contract : null, inputs: recordInputs(doctor), deviationReason })
|
|
969
1006
|
: stage === "theme"
|
|
970
1007
|
? composeTheme(report, { now: timestamp, recordedBy, layer })
|
|
971
1008
|
: stage === "deploy"
|
|
@@ -980,8 +1017,8 @@ function recordUnderLock({ stage, packetPath, sidecars, lockedTarget, input, dry
|
|
|
980
1017
|
if (dryRun) return null;
|
|
981
1018
|
// Written inside the report's critical section, after every check and
|
|
982
1019
|
// before the report itself, so the files move together.
|
|
983
|
-
if (next.context) writeJsonAtomic(contextPath, next.context);
|
|
984
|
-
if (next.packet) writeJsonAtomic(packetPath, next.packet);
|
|
1020
|
+
if (next.context) writeJsonAtomic(contextPath, portableArtifactPaths(next.context, workspace.targetRepo, { artifactPath: contextPath }));
|
|
1021
|
+
if (next.packet) writeJsonAtomic(packetPath, portableArtifactPaths(next.packet, workspace.targetRepo, { artifactPath: packetPath }));
|
|
985
1022
|
return next.report;
|
|
986
1023
|
};
|
|
987
1024
|
// Already inside the target lock, which commitAssemblyReport re-enters.
|