forgeos 0.1.0-alpha.48 → 0.1.0-alpha.49
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/AGENTS.md +1 -1
- package/CHANGELOG.md +17 -0
- package/docs/changelog.md +11 -0
- package/package.json +1 -1
- package/src/forge/_generated/releaseManifest.json +1 -1
- package/src/forge/_generated/releaseManifest.ts +3 -3
- package/src/forge/cli/commands.ts +179 -1
- package/src/forge/compiler/diagnostics/codes.ts +6 -0
- package/src/forge/version.ts +1 -1
package/AGENTS.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// @forge-generated generator=0.1.0-alpha.
|
|
1
|
+
// @forge-generated generator=0.1.0-alpha.49 input=a7c20b1d3492dcb4111d826ff8622647abd8f6be499cffb3c27e077c9b3267b1 content=721818a6f9a664aa898092d4aa5cd68cbbd8ad6e150c7d3ad3ef785a2e3fcf53
|
|
2
2
|
# AGENTS.md
|
|
3
3
|
|
|
4
4
|
<!-- forge-generated:start -->
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# forgeos
|
|
2
2
|
|
|
3
|
+
## 0.1.0-alpha.49
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Improve release doctor visibility for npm dist-tag drift.
|
|
8
|
+
|
|
9
|
+
- `forge release doctor --json` now checks the published npm `alpha` and
|
|
10
|
+
`latest` dist-tags for public packages, reports the currently published
|
|
11
|
+
tag versions, and suggests the exact `npm dist-tag add` remediation when
|
|
12
|
+
`latest` still points at an older alpha.
|
|
13
|
+
- The npm dist-tag check is advisory rather than publish-blocking, so a
|
|
14
|
+
prepared alpha release can still ship while clearly reporting that the
|
|
15
|
+
consumer-facing `latest` tag needs promotion.
|
|
16
|
+
- GitHub Actions latest-promotion notices now include the local remediation
|
|
17
|
+
command and the `NPM_TOKEN` configuration hint when latest promotion is
|
|
18
|
+
skipped.
|
|
19
|
+
|
|
3
20
|
## 0.1.0-alpha.48
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
package/docs/changelog.md
CHANGED
|
@@ -6,6 +6,17 @@ The canonical source file in the repository is `CHANGELOG.md`.
|
|
|
6
6
|
|
|
7
7
|
## Unreleased
|
|
8
8
|
|
|
9
|
+
## 0.1.0-alpha.49
|
|
10
|
+
|
|
11
|
+
- `forge release doctor --json` now reports npm `alpha` and `latest` dist-tag
|
|
12
|
+
versions for public packages, including exact remediation when `latest`
|
|
13
|
+
points at an older alpha.
|
|
14
|
+
- The dist-tag check is advisory and non-publish-blocking, keeping alpha
|
|
15
|
+
release validation usable while making stale `latest` state explicit.
|
|
16
|
+
- GitHub Actions latest-promotion notices now include the local
|
|
17
|
+
`npm dist-tag add <package>@<version> latest` fallback and `NPM_TOKEN`
|
|
18
|
+
configuration hint when promotion is skipped.
|
|
19
|
+
|
|
9
20
|
## 0.1.0-alpha.48
|
|
10
21
|
|
|
11
22
|
- Added the production-shaped WorkOS FGA flow:
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"defaultProvider":"local","diagnostics":[],"env":{"deployEnv":"FORGE_DEPLOY_ENV","deployId":"FORGE_DEPLOY_ID","publicReleaseId":"NEXT_PUBLIC_FORGE_RELEASE_ID","releaseId":"FORGE_RELEASE_ID"},"gitSha":"unknown","optionalProviders":["local","sentry-compatible","sentry","glitchtip","bugsink","otel","custom"],"packageName":"forgeos","packageVersion":"0.1.0-alpha.
|
|
1
|
+
{"defaultProvider":"local","diagnostics":[],"env":{"deployEnv":"FORGE_DEPLOY_ENV","deployId":"FORGE_DEPLOY_ID","publicReleaseId":"NEXT_PUBLIC_FORGE_RELEASE_ID","releaseId":"FORGE_RELEASE_ID"},"gitSha":"unknown","optionalProviders":["local","sentry-compatible","sentry","glitchtip","bugsink","otel","custom"],"packageName":"forgeos","packageVersion":"0.1.0-alpha.49","releaseId":"forgeos@0.1.0-alpha.49+unknown","schemaVersion":"0.1.0"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// @forge-generated generator=0.1.0-alpha.
|
|
1
|
+
// @forge-generated generator=0.1.0-alpha.49 input=a7c20b1d3492dcb4111d826ff8622647abd8f6be499cffb3c27e077c9b3267b1 content=bfe9659e5f5a5d2d52e6ac7eb6c13d2bc356c8bf95724fafc6e10fe4641f2104
|
|
2
2
|
export const releaseManifest = {
|
|
3
3
|
"defaultProvider": "local",
|
|
4
4
|
"diagnostics": [],
|
|
@@ -19,7 +19,7 @@ export const releaseManifest = {
|
|
|
19
19
|
"custom"
|
|
20
20
|
],
|
|
21
21
|
"packageName": "forgeos",
|
|
22
|
-
"packageVersion": "0.1.0-alpha.
|
|
23
|
-
"releaseId": "forgeos@0.1.0-alpha.
|
|
22
|
+
"packageVersion": "0.1.0-alpha.49",
|
|
23
|
+
"releaseId": "forgeos@0.1.0-alpha.49+unknown",
|
|
24
24
|
"schemaVersion": "0.1.0"
|
|
25
25
|
} as const;
|
|
@@ -6,6 +6,8 @@ import { classify } from "../compiler/classifier/classify.ts";
|
|
|
6
6
|
import { buildRuntimeMatrix } from "../compiler/classifier/runtime-matrix.ts";
|
|
7
7
|
import {
|
|
8
8
|
FORGE_DB_EMPTY_TIMESTAMP_LITERAL,
|
|
9
|
+
FORGE_RELEASE_NPM_DIST_TAG_CHECK_FAILED,
|
|
10
|
+
FORGE_RELEASE_NPM_DIST_TAG_STALE,
|
|
9
11
|
FORGE_RELEASE_PACKAGE_PACK_FAILED,
|
|
10
12
|
} from "../compiler/diagnostics/codes.ts";
|
|
11
13
|
import { createDiagnostic } from "../compiler/diagnostics/create.ts";
|
|
@@ -1149,7 +1151,7 @@ interface ReleaseDoctorCheck {
|
|
|
1149
1151
|
requiredForPublish: boolean;
|
|
1150
1152
|
requiredForProduction?: boolean;
|
|
1151
1153
|
state?: string;
|
|
1152
|
-
result: ReleaseCommandResult | SelfHostCommandResult | DocsCheckResult | DeployCommandResult | PackagePackCheckResult;
|
|
1154
|
+
result: ReleaseCommandResult | SelfHostCommandResult | DocsCheckResult | DeployCommandResult | PackagePackCheckResult | NpmDistTagCheckResult;
|
|
1153
1155
|
}
|
|
1154
1156
|
|
|
1155
1157
|
interface PackagePackCheckResult {
|
|
@@ -1166,6 +1168,24 @@ interface PackagePackCheckResult {
|
|
|
1166
1168
|
exitCode: 0 | 1;
|
|
1167
1169
|
}
|
|
1168
1170
|
|
|
1171
|
+
interface NpmDistTagCheckResult {
|
|
1172
|
+
ok: boolean;
|
|
1173
|
+
data: {
|
|
1174
|
+
command: string;
|
|
1175
|
+
packageName: string | null;
|
|
1176
|
+
packageVersion: string | null;
|
|
1177
|
+
alphaVersion: string | null;
|
|
1178
|
+
latestVersion: string | null;
|
|
1179
|
+
alphaMatches: boolean;
|
|
1180
|
+
latestMatches: boolean;
|
|
1181
|
+
source: "npm-view" | "env-fixture" | "skipped";
|
|
1182
|
+
};
|
|
1183
|
+
diagnostics: ReturnType<typeof createDiagnostic>[];
|
|
1184
|
+
nextActions?: string[];
|
|
1185
|
+
failureKind?: string;
|
|
1186
|
+
exitCode: 0 | 1;
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1169
1189
|
interface ReleaseDoctorResult {
|
|
1170
1190
|
schemaVersion: "0.1.0";
|
|
1171
1191
|
ok: boolean;
|
|
@@ -1263,6 +1283,156 @@ function runPackagePackDryRun(workspaceRoot: string): PackagePackCheckResult {
|
|
|
1263
1283
|
}
|
|
1264
1284
|
}
|
|
1265
1285
|
|
|
1286
|
+
function parseNpmDistTagsJson(raw: string): Record<string, string> | null {
|
|
1287
|
+
try {
|
|
1288
|
+
const parsed = JSON.parse(raw) as unknown;
|
|
1289
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
1290
|
+
return null;
|
|
1291
|
+
}
|
|
1292
|
+
const tags: Record<string, string> = {};
|
|
1293
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
1294
|
+
if (typeof value === "string") {
|
|
1295
|
+
tags[key] = value;
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
return tags;
|
|
1299
|
+
} catch {
|
|
1300
|
+
return null;
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
function runNpmDistTagCheck(workspaceRoot: string): NpmDistTagCheckResult {
|
|
1305
|
+
const pkg = readPackageJson(workspaceRoot) as {
|
|
1306
|
+
name?: unknown;
|
|
1307
|
+
version?: unknown;
|
|
1308
|
+
private?: unknown;
|
|
1309
|
+
};
|
|
1310
|
+
const packageName = typeof pkg.name === "string" ? pkg.name : null;
|
|
1311
|
+
const packageVersion = typeof pkg.version === "string" ? pkg.version : null;
|
|
1312
|
+
const command = packageName ? `npm view ${packageName} dist-tags --json` : "npm view <package> dist-tags --json";
|
|
1313
|
+
const baseData = {
|
|
1314
|
+
command,
|
|
1315
|
+
packageName,
|
|
1316
|
+
packageVersion,
|
|
1317
|
+
alphaVersion: null,
|
|
1318
|
+
latestVersion: null,
|
|
1319
|
+
alphaMatches: false,
|
|
1320
|
+
latestMatches: false,
|
|
1321
|
+
source: "skipped" as const,
|
|
1322
|
+
};
|
|
1323
|
+
|
|
1324
|
+
if (pkg.private === true) {
|
|
1325
|
+
return {
|
|
1326
|
+
ok: true,
|
|
1327
|
+
data: baseData,
|
|
1328
|
+
diagnostics: [],
|
|
1329
|
+
exitCode: 0,
|
|
1330
|
+
};
|
|
1331
|
+
}
|
|
1332
|
+
if (!packageName || !packageVersion) {
|
|
1333
|
+
return {
|
|
1334
|
+
ok: false,
|
|
1335
|
+
data: baseData,
|
|
1336
|
+
diagnostics: [
|
|
1337
|
+
createDiagnostic({
|
|
1338
|
+
severity: "warning",
|
|
1339
|
+
code: FORGE_RELEASE_NPM_DIST_TAG_CHECK_FAILED,
|
|
1340
|
+
message: "release doctor could not check npm dist-tags because package.json is missing name or version",
|
|
1341
|
+
fixHint: "Set package.json name and version before publishing, then rerun forge release doctor.",
|
|
1342
|
+
suggestedCommands: ["node bin/forge.mjs release doctor --json"],
|
|
1343
|
+
}),
|
|
1344
|
+
],
|
|
1345
|
+
nextActions: ["node bin/forge.mjs release doctor --json"],
|
|
1346
|
+
failureKind: "npm-dist-tags-package-metadata-missing",
|
|
1347
|
+
exitCode: 1,
|
|
1348
|
+
};
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
const fixture = process.env.FORGE_RELEASE_NPM_DIST_TAGS_JSON;
|
|
1352
|
+
const source = fixture ? "env-fixture" as const : "npm-view" as const;
|
|
1353
|
+
const stdout = fixture ?? spawnSync("npm", ["view", packageName, "dist-tags", "--json"], {
|
|
1354
|
+
cwd: workspaceRoot,
|
|
1355
|
+
encoding: "utf8",
|
|
1356
|
+
timeout: 10_000,
|
|
1357
|
+
windowsHide: true,
|
|
1358
|
+
}).stdout;
|
|
1359
|
+
const tags = parseNpmDistTagsJson(stdout || "");
|
|
1360
|
+
if (!tags) {
|
|
1361
|
+
return {
|
|
1362
|
+
ok: false,
|
|
1363
|
+
data: { ...baseData, source },
|
|
1364
|
+
diagnostics: [
|
|
1365
|
+
createDiagnostic({
|
|
1366
|
+
severity: "warning",
|
|
1367
|
+
code: FORGE_RELEASE_NPM_DIST_TAG_CHECK_FAILED,
|
|
1368
|
+
message: `release doctor could not read npm dist-tags for ${packageName}`,
|
|
1369
|
+
fixHint: `Run ${command}. If the package has not been published yet, publish it with the alpha tag first.`,
|
|
1370
|
+
suggestedCommands: [command, "npm run release:publish-alpha"],
|
|
1371
|
+
}),
|
|
1372
|
+
],
|
|
1373
|
+
nextActions: [command, "npm run release:publish-alpha"],
|
|
1374
|
+
failureKind: "npm-dist-tags-unavailable",
|
|
1375
|
+
exitCode: 1,
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
const alphaVersion = tags.alpha ?? null;
|
|
1380
|
+
const latestVersion = tags.latest ?? null;
|
|
1381
|
+
const alphaMatches = alphaVersion === packageVersion;
|
|
1382
|
+
const latestMatches = latestVersion === packageVersion;
|
|
1383
|
+
const data = {
|
|
1384
|
+
command,
|
|
1385
|
+
packageName,
|
|
1386
|
+
packageVersion,
|
|
1387
|
+
alphaVersion,
|
|
1388
|
+
latestVersion,
|
|
1389
|
+
alphaMatches,
|
|
1390
|
+
latestMatches,
|
|
1391
|
+
source,
|
|
1392
|
+
};
|
|
1393
|
+
if (alphaMatches && latestMatches) {
|
|
1394
|
+
return {
|
|
1395
|
+
ok: true,
|
|
1396
|
+
data,
|
|
1397
|
+
diagnostics: [],
|
|
1398
|
+
exitCode: 0,
|
|
1399
|
+
};
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
const nextActions: string[] = [];
|
|
1403
|
+
const diagnostics: ReturnType<typeof createDiagnostic>[] = [];
|
|
1404
|
+
if (!alphaMatches) {
|
|
1405
|
+
nextActions.push("npm run release:publish-alpha");
|
|
1406
|
+
diagnostics.push(createDiagnostic({
|
|
1407
|
+
severity: "warning",
|
|
1408
|
+
code: FORGE_RELEASE_NPM_DIST_TAG_STALE,
|
|
1409
|
+
message: `${packageName}@alpha points to ${alphaVersion ?? "none"}, not local version ${packageVersion}`,
|
|
1410
|
+
fixHint: "Publish the current package with the alpha tag before asking users to install forgeos@alpha.",
|
|
1411
|
+
suggestedCommands: ["npm run release:publish-alpha", command],
|
|
1412
|
+
}));
|
|
1413
|
+
}
|
|
1414
|
+
if (!latestMatches) {
|
|
1415
|
+
const promote = `npm dist-tag add ${packageName}@${packageVersion} latest`;
|
|
1416
|
+
nextActions.push(promote);
|
|
1417
|
+
nextActions.push("configure NPM_TOKEN in GitHub Actions secrets, or run npm login locally before promoting latest");
|
|
1418
|
+
diagnostics.push(createDiagnostic({
|
|
1419
|
+
severity: "warning",
|
|
1420
|
+
code: FORGE_RELEASE_NPM_DIST_TAG_STALE,
|
|
1421
|
+
message: `${packageName}@latest points to ${latestVersion ?? "none"}, not local version ${packageVersion}`,
|
|
1422
|
+
fixHint: `Promote latest after the alpha package is verified: ${promote}`,
|
|
1423
|
+
suggestedCommands: [promote, command],
|
|
1424
|
+
}));
|
|
1425
|
+
}
|
|
1426
|
+
return {
|
|
1427
|
+
ok: false,
|
|
1428
|
+
data,
|
|
1429
|
+
diagnostics,
|
|
1430
|
+
nextActions,
|
|
1431
|
+
failureKind: !alphaMatches ? "npm-alpha-dist-tag-stale" : "npm-latest-dist-tag-stale",
|
|
1432
|
+
exitCode: 1,
|
|
1433
|
+
};
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1266
1436
|
export async function runReleaseDoctorCommand(command: Extract<ForgeCommand, { kind: "release" }>): Promise<ReleaseDoctorResult> {
|
|
1267
1437
|
const release = await runReleaseCommand({
|
|
1268
1438
|
...command,
|
|
@@ -1300,6 +1470,7 @@ export async function runReleaseDoctorCommand(command: Extract<ForgeCommand, { k
|
|
|
1300
1470
|
production: true,
|
|
1301
1471
|
});
|
|
1302
1472
|
const packagePack = runPackagePackDryRun(command.workspaceRoot);
|
|
1473
|
+
const npmDistTags = runNpmDistTagCheck(command.workspaceRoot);
|
|
1303
1474
|
const checks: ReleaseDoctorCheck[] = [
|
|
1304
1475
|
{
|
|
1305
1476
|
name: "release-prepared",
|
|
@@ -1340,6 +1511,13 @@ export async function runReleaseDoctorCommand(command: Extract<ForgeCommand, { k
|
|
|
1340
1511
|
requiredForPublish: true,
|
|
1341
1512
|
result: packagePack,
|
|
1342
1513
|
},
|
|
1514
|
+
{
|
|
1515
|
+
name: "npm-dist-tags",
|
|
1516
|
+
ok: npmDistTags.ok,
|
|
1517
|
+
requiredForPublish: false,
|
|
1518
|
+
state: npmDistTags.failureKind ?? (npmDistTags.data.source === "skipped" ? "skipped" : "current"),
|
|
1519
|
+
result: npmDistTags,
|
|
1520
|
+
},
|
|
1343
1521
|
];
|
|
1344
1522
|
const failed = checks.filter((check) => !check.ok).map((check) => check.name);
|
|
1345
1523
|
const notPrepared = checks
|
|
@@ -111,6 +111,10 @@ export const FORGE_RELEASE_GENERATED_DRIFT =
|
|
|
111
111
|
export const FORGE_RELEASE_ID_MISSING = "FORGE_RELEASE_ID_MISSING" as const;
|
|
112
112
|
export const FORGE_RELEASE_PACKAGE_PACK_FAILED =
|
|
113
113
|
"FORGE_RELEASE_PACKAGE_PACK_FAILED" as const;
|
|
114
|
+
export const FORGE_RELEASE_NPM_DIST_TAG_STALE =
|
|
115
|
+
"FORGE_RELEASE_NPM_DIST_TAG_STALE" as const;
|
|
116
|
+
export const FORGE_RELEASE_NPM_DIST_TAG_CHECK_FAILED =
|
|
117
|
+
"FORGE_RELEASE_NPM_DIST_TAG_CHECK_FAILED" as const;
|
|
114
118
|
export const FORGE_SOURCEMAP_PUBLIC_EXPOSURE =
|
|
115
119
|
"FORGE_SOURCEMAP_PUBLIC_EXPOSURE" as const;
|
|
116
120
|
export const FORGE_SOURCEMAP_UPLOAD_MISSING =
|
|
@@ -475,6 +479,8 @@ export const DIAGNOSTIC_CODES = [
|
|
|
475
479
|
FORGE_RELEASE_GENERATED_DRIFT,
|
|
476
480
|
FORGE_RELEASE_ID_MISSING,
|
|
477
481
|
FORGE_RELEASE_PACKAGE_PACK_FAILED,
|
|
482
|
+
FORGE_RELEASE_NPM_DIST_TAG_STALE,
|
|
483
|
+
FORGE_RELEASE_NPM_DIST_TAG_CHECK_FAILED,
|
|
478
484
|
FORGE_SOURCEMAP_PUBLIC_EXPOSURE,
|
|
479
485
|
FORGE_SOURCEMAP_UPLOAD_MISSING,
|
|
480
486
|
FORGE_SOURCEMAP_UPLOAD_FAILED,
|
package/src/forge/version.ts
CHANGED