@williamthorsen/release-kit 10.8.0 → 11.0.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.
Files changed (69) hide show
  1. package/.meta/changelog.json +100 -3
  2. package/.readyup/kits/default.js +3 -3
  3. package/.readyup/kits/npm-auto-publish.js +43 -23
  4. package/.readyup/manifest.json +9 -9
  5. package/CHANGELOG.md +82 -3
  6. package/README.md +46 -11
  7. package/dist/esm/bin/release-kit.js +46 -120
  8. package/dist/esm/buildChangelogEntries.js +1 -0
  9. package/dist/esm/configFlagSchema.d.ts +12 -0
  10. package/dist/esm/configFlagSchema.js +3 -0
  11. package/dist/esm/createGithubReleaseCommand.d.ts +2 -1
  12. package/dist/esm/createGithubReleaseCommand.js +9 -3
  13. package/dist/esm/createTags.d.ts +2 -0
  14. package/dist/esm/createTags.js +5 -4
  15. package/dist/esm/discoverWorkspaces.d.ts +53 -8
  16. package/dist/esm/discoverWorkspaces.js +57 -37
  17. package/dist/esm/format.d.ts +5 -5
  18. package/dist/esm/format.js +5 -4
  19. package/dist/esm/glyphs.d.ts +3 -0
  20. package/dist/esm/glyphs.js +6 -0
  21. package/dist/esm/help/prepareHelp.d.ts +1 -1
  22. package/dist/esm/help/prepareHelp.js +1 -0
  23. package/dist/esm/init/initCommand.d.ts +3 -1
  24. package/dist/esm/init/initCommand.js +15 -15
  25. package/dist/esm/loadConfig.d.ts +7 -4
  26. package/dist/esm/loadConfig.js +6 -3
  27. package/dist/esm/loadValidatedConfig.d.ts +47 -5
  28. package/dist/esm/loadValidatedConfig.js +32 -15
  29. package/dist/esm/prepareCommand.d.ts +7 -1
  30. package/dist/esm/prepareCommand.js +37 -45
  31. package/dist/esm/previewTagPrefixes.d.ts +9 -6
  32. package/dist/esm/previewTagPrefixes.js +12 -24
  33. package/dist/esm/publishCommand.d.ts +4 -3
  34. package/dist/esm/publishCommand.js +9 -3
  35. package/dist/esm/pushCommand.d.ts +1 -1
  36. package/dist/esm/pushCommand.js +2 -2
  37. package/dist/esm/reportPrepare.d.ts +2 -0
  38. package/dist/esm/reportPrepare.js +51 -41
  39. package/dist/esm/resolveCommandTags.d.ts +3 -2
  40. package/dist/esm/resolveCommandTags.js +10 -6
  41. package/dist/esm/resolveReleaseNotesConfig.d.ts +10 -11
  42. package/dist/esm/resolveReleaseNotesConfig.js +10 -29
  43. package/dist/esm/resolveStylesOrExit.d.ts +10 -0
  44. package/dist/esm/resolveStylesOrExit.js +10 -0
  45. package/dist/esm/showTagPrefixesCommand.d.ts +5 -2
  46. package/dist/esm/showTagPrefixesCommand.js +31 -11
  47. package/dist/esm/sync-labels/generateCommand.d.ts +18 -8
  48. package/dist/esm/sync-labels/generateCommand.js +12 -11
  49. package/dist/esm/sync-labels/initCommand.d.ts +11 -4
  50. package/dist/esm/sync-labels/initCommand.js +24 -18
  51. package/dist/esm/sync-labels/retiredConfig.d.ts +4 -2
  52. package/dist/esm/sync-labels/retiredConfig.js +2 -2
  53. package/dist/esm/tagCommand.d.ts +2 -1
  54. package/dist/esm/tagCommand.js +2 -2
  55. package/dist/esm/validateOverridesCommand.d.ts +13 -7
  56. package/dist/esm/validateOverridesCommand.js +28 -36
  57. package/docs/configuration.md +35 -1
  58. package/docs/labels.md +2 -0
  59. package/docs/work-types.md +11 -8
  60. package/package.json +13 -14
  61. package/presets/labels/common.yaml +2 -2
  62. package/dist/esm/checkWorkTypesDrift.d.ts +0 -35
  63. package/dist/esm/checkWorkTypesDrift.js +0 -117
  64. package/dist/esm/syncWorkTypes.d.ts +0 -28
  65. package/dist/esm/syncWorkTypes.js +0 -94
  66. package/dist/esm/work-types.json +0 -149
  67. package/dist/esm/work-types.schema.json +0 -110
  68. package/dist/esm/workTypesUtils.d.ts +0 -22
  69. package/dist/esm/workTypesUtils.js +0 -16
@@ -1,117 +0,0 @@
1
- import { readFileSync } from 'node:fs';
2
- import { dirname, resolve } from 'node:path';
3
- import { fileURLToPath } from 'node:url';
4
- import { formatErrorLine } from '@williamthorsen/nmr-core';
5
- import { describeError } from '@williamthorsen/toolbelt.errors';
6
- import { buildFetchInit, hasExpectedTopLevelShape } from "./workTypesUtils.js";
7
- export const UPSTREAM_WORK_TYPES_URL = 'https://raw.githubusercontent.com/williamthorsen/codeassembly/main/packages/agents/content/skills/_data/work-types.json';
8
- function resolveDefaultLocalPath() {
9
- const moduleDir = dirname(fileURLToPath(import.meta.url));
10
- return resolve(moduleDir, 'work-types.json');
11
- }
12
- export async function checkWorkTypesDrift(dependencies = {}) {
13
- const localPath = dependencies.localPath ?? resolveDefaultLocalPath();
14
- const fetcher = dependencies.fetch ?? globalThis.fetch;
15
- const url = dependencies.upstreamUrl ?? UPSTREAM_WORK_TYPES_URL;
16
- const localContent = readFileSync(localPath, 'utf8');
17
- let localJson;
18
- try {
19
- localJson = JSON.parse(localContent);
20
- }
21
- catch (error) {
22
- return {
23
- exitCode: 3,
24
- message: `Local work-types.json is not valid JSON: ${describeError(error)}`,
25
- };
26
- }
27
- const fetchInit = buildFetchInit();
28
- let response;
29
- try {
30
- response = fetchInit === undefined ? await fetcher(url) : await fetcher(url, fetchInit);
31
- }
32
- catch (error) {
33
- return {
34
- exitCode: 2,
35
- message: formatErrorLine(`Failed to fetch upstream work-types.json: ${describeError(error)}`),
36
- };
37
- }
38
- if (response.status === 404) {
39
- return {
40
- exitCode: 0,
41
- message: `Upstream work-types.json not found at ${url}; skipping drift check.`,
42
- };
43
- }
44
- if (!response.ok) {
45
- return {
46
- exitCode: 2,
47
- message: formatErrorLine(`Failed to fetch upstream work-types.json: HTTP ${response.status} ${response.statusText}`),
48
- };
49
- }
50
- const upstreamText = await response.text();
51
- let upstreamJson;
52
- try {
53
- upstreamJson = JSON.parse(upstreamText);
54
- }
55
- catch (error) {
56
- return {
57
- exitCode: 3,
58
- message: `Upstream work-types.json is not valid JSON: ${describeError(error)}`,
59
- };
60
- }
61
- if (!hasExpectedTopLevelShape(upstreamJson)) {
62
- return {
63
- exitCode: 3,
64
- message: 'Upstream work-types.json does not match the expected schema shape (missing `tiers` or `types`).',
65
- };
66
- }
67
- const normalisedLocal = stripLocalOnlyFields(localJson);
68
- if (deepEqual(normalisedLocal, upstreamJson)) {
69
- return {
70
- exitCode: 0,
71
- message: 'Local work-types.json matches upstream.',
72
- };
73
- }
74
- return {
75
- exitCode: 1,
76
- message: `Drift detected. Local and upstream work-types.json differ. Run \`nmr work-types:sync\` to update from upstream.\nLocal: ${localPath}\nUpstream: ${url}`,
77
- };
78
- }
79
- function stripLocalOnlyFields(value) {
80
- if (typeof value !== 'object' || value === null || Array.isArray(value)) {
81
- return value;
82
- }
83
- const record = { ...value };
84
- delete record['$schema'];
85
- return record;
86
- }
87
- function deepEqual(a, b) {
88
- if (a === b)
89
- return true;
90
- if (typeof a !== typeof b)
91
- return false;
92
- if (a === null || b === null)
93
- return a === b;
94
- if (Array.isArray(a) && Array.isArray(b)) {
95
- if (a.length !== b.length)
96
- return false;
97
- for (let i = 0; i < a.length; i++) {
98
- if (!deepEqual(a[i], b[i]))
99
- return false;
100
- }
101
- return true;
102
- }
103
- if (typeof a === 'object' && typeof b === 'object' && !Array.isArray(a) && !Array.isArray(b)) {
104
- const aRecord = { ...a };
105
- const bRecord = { ...b };
106
- const aKeys = Object.keys(aRecord);
107
- const bKeys = Object.keys(bRecord);
108
- if (aKeys.length !== bKeys.length)
109
- return false;
110
- for (const key of aKeys) {
111
- if (!deepEqual(aRecord[key], bRecord[key]))
112
- return false;
113
- }
114
- return true;
115
- }
116
- return false;
117
- }
@@ -1,28 +0,0 @@
1
- /** Outcome of a sync operation. */
2
- export interface SyncResult {
3
- /**
4
- * Process exit code semantics:
5
- * - `0` — sync succeeded (file may be unchanged).
6
- * - `2` — network error or local write failure.
7
- * - `3` — schema mismatch (upstream JSON does not parse or fails the shape check).
8
- */
9
- exitCode: 0 | 2 | 3;
10
- message: string;
11
- }
12
- /** Minimal injection seam so unit tests can substitute a deterministic fetcher. */
13
- export interface SyncWorkTypesDependencies {
14
- /** Absolute path of the local `work-types.json`. Defaults to the bundled file. */
15
- localPath?: string;
16
- /** HTTP fetcher. Defaults to global `fetch`. */
17
- fetch?: typeof globalThis.fetch;
18
- /** Override the upstream URL (used by tests). */
19
- upstreamUrl?: string;
20
- }
21
- /**
22
- * Fetch the upstream `work-types.json`, validate its top-level shape, and overwrite the
23
- * locally-bundled copy with the formatted upstream contents.
24
- *
25
- * Output is reformatted to match the local file's conventions (2-space indent, trailing
26
- * newline) so subsequent diffs are content-driven, not whitespace-driven.
27
- */
28
- export declare function syncWorkTypes(dependencies?: SyncWorkTypesDependencies): Promise<SyncResult>;
@@ -1,94 +0,0 @@
1
- import { readFileSync, writeFileSync } from 'node:fs';
2
- import { dirname, resolve } from 'node:path';
3
- import { fileURLToPath } from 'node:url';
4
- import { formatErrorLine } from '@williamthorsen/nmr-core';
5
- import { describeError } from '@williamthorsen/toolbelt.errors';
6
- import { UPSTREAM_WORK_TYPES_URL } from "./checkWorkTypesDrift.js";
7
- import { isRecord } from "./typeGuards.js";
8
- import { buildFetchInit, hasExpectedTopLevelShape } from "./workTypesUtils.js";
9
- function resolveDefaultLocalPath() {
10
- const moduleDir = dirname(fileURLToPath(import.meta.url));
11
- return resolve(moduleDir, 'work-types.json');
12
- }
13
- function extractLocalSchemaUrl(content) {
14
- let parsed;
15
- try {
16
- parsed = JSON.parse(content);
17
- }
18
- catch {
19
- return undefined;
20
- }
21
- if (!isRecord(parsed)) {
22
- return undefined;
23
- }
24
- const schema = parsed['$schema'];
25
- return typeof schema === 'string' ? schema : undefined;
26
- }
27
- export async function syncWorkTypes(dependencies = {}) {
28
- const localPath = dependencies.localPath ?? resolveDefaultLocalPath();
29
- const fetcher = dependencies.fetch ?? globalThis.fetch;
30
- const url = dependencies.upstreamUrl ?? UPSTREAM_WORK_TYPES_URL;
31
- const fetchInit = buildFetchInit();
32
- let response;
33
- try {
34
- response = fetchInit === undefined ? await fetcher(url) : await fetcher(url, fetchInit);
35
- }
36
- catch (error) {
37
- return {
38
- exitCode: 2,
39
- message: formatErrorLine(`Failed to fetch upstream work-types.json: ${describeError(error)}`),
40
- };
41
- }
42
- if (!response.ok) {
43
- return {
44
- exitCode: 2,
45
- message: formatErrorLine(`Failed to fetch upstream work-types.json: HTTP ${response.status} ${response.statusText}`),
46
- };
47
- }
48
- const upstreamText = await response.text();
49
- let upstreamJson;
50
- try {
51
- upstreamJson = JSON.parse(upstreamText);
52
- }
53
- catch (error) {
54
- return {
55
- exitCode: 3,
56
- message: `Upstream work-types.json is not valid JSON: ${describeError(error)}`,
57
- };
58
- }
59
- if (!hasExpectedTopLevelShape(upstreamJson)) {
60
- return {
61
- exitCode: 3,
62
- message: 'Upstream work-types.json does not match the expected schema shape (missing `tiers` or `types`).',
63
- };
64
- }
65
- let priorContent;
66
- try {
67
- priorContent = readFileSync(localPath, 'utf8');
68
- }
69
- catch {
70
- priorContent = undefined;
71
- }
72
- const localSchemaUrl = priorContent !== undefined ? extractLocalSchemaUrl(priorContent) : undefined;
73
- const outputJson = localSchemaUrl !== undefined ? { $schema: localSchemaUrl, ...upstreamJson } : upstreamJson;
74
- const formatted = `${JSON.stringify(outputJson, null, 2)}\n`;
75
- if (priorContent === formatted) {
76
- return {
77
- exitCode: 0,
78
- message: `Local work-types.json already matches upstream (${localPath}).`,
79
- };
80
- }
81
- try {
82
- writeFileSync(localPath, formatted, 'utf8');
83
- }
84
- catch (error) {
85
- return {
86
- exitCode: 2,
87
- message: formatErrorLine(`Failed to write ${localPath}: ${describeError(error)}`),
88
- };
89
- }
90
- return {
91
- exitCode: 0,
92
- message: `Synced work-types.json from ${url} → ${localPath}.`,
93
- };
94
- }
@@ -1,149 +0,0 @@
1
- {
2
- "$schema": "./work-types.schema.json",
3
- "markers": {
4
- "breaking": {
5
- "emoji": "🚨",
6
- "label": "Breaking"
7
- }
8
- },
9
- "tiers": ["public", "internal", "process"],
10
- "types": [
11
- {
12
- "aliases": ["feature"],
13
- "breakingPolicy": "optional",
14
- "description": "A change that gives consumers a new capability or extends an existing one.",
15
- "emoji": "🎉",
16
- "key": "feat",
17
- "label": "Features",
18
- "tier": "public"
19
- },
20
- {
21
- "aliases": [],
22
- "breakingPolicy": "required",
23
- "description": "A change that removes a capability or surface on which consumers depend.",
24
- "emoji": "🪦",
25
- "key": "drop",
26
- "label": "Removed",
27
- "tier": "public"
28
- },
29
- {
30
- "aliases": [],
31
- "breakingPolicy": "forbidden",
32
- "description": "A change that marks a capability or surface for removal while the capability or surface keeps working.",
33
- "emoji": "🗑️",
34
- "key": "deprecate",
35
- "label": "Deprecated",
36
- "tier": "public"
37
- },
38
- {
39
- "aliases": ["bugfix"],
40
- "breakingPolicy": "optional",
41
- "description": "A change that corrects behavior that consumers meet and that differs from what was intended.",
42
- "emoji": "🐛",
43
- "key": "fix",
44
- "label": "Bug fixes",
45
- "tier": "public"
46
- },
47
- {
48
- "aliases": ["security"],
49
- "breakingPolicy": "optional",
50
- "description": "A change that closes a vulnerability or hardens a consumer-facing surface against attack.",
51
- "emoji": "🔒",
52
- "key": "sec",
53
- "label": "Security",
54
- "tier": "public"
55
- },
56
- {
57
- "aliases": ["performance"],
58
- "breakingPolicy": "optional",
59
- "description": "A change that reduces the time, memory, or other resources that consumer-facing work uses, without changing its result.",
60
- "emoji": "⚡",
61
- "key": "perf",
62
- "label": "Performance",
63
- "tier": "public"
64
- },
65
- {
66
- "aliases": ["utility"],
67
- "breakingPolicy": "forbidden",
68
- "description": "A change that adds or extends a capability that consumers do not use directly, such as a helper or an internal module.",
69
- "emoji": "🏗️",
70
- "key": "internal",
71
- "label": "Internal features",
72
- "tier": "internal"
73
- },
74
- {
75
- "aliases": [],
76
- "breakingPolicy": "forbidden",
77
- "description": "A change that restructures existing code without changing its behavior.",
78
- "emoji": "♻️",
79
- "key": "refactor",
80
- "label": "Refactoring",
81
- "tier": "internal"
82
- },
83
- {
84
- "aliases": ["test"],
85
- "breakingPolicy": "forbidden",
86
- "description": "A change confined to tests, test fixtures, or test helpers, including one that unblocks a build or a type check.",
87
- "emoji": "🧪",
88
- "key": "tests",
89
- "label": "Tests",
90
- "tier": "internal"
91
- },
92
- {
93
- "aliases": [],
94
- "breakingPolicy": "forbidden",
95
- "description": "A change to the tools used to develop the project: build, lint, formatting, and release configuration, and development scripts.",
96
- "emoji": "⚙️",
97
- "key": "tooling",
98
- "label": "Tooling",
99
- "tier": "process"
100
- },
101
- {
102
- "aliases": [],
103
- "breakingPolicy": "forbidden",
104
- "description": "A change to continuous-integration workflows and their configuration.",
105
- "emoji": "👷",
106
- "key": "ci",
107
- "label": "CI",
108
- "tier": "process"
109
- },
110
- {
111
- "aliases": ["dep"],
112
- "breakingPolicy": "forbidden",
113
- "description": "A change that adds, removes, or upgrades a dependency, including its lockfile and version-catalog entries.",
114
- "emoji": "📦",
115
- "key": "deps",
116
- "label": "Dependencies",
117
- "tier": "process"
118
- },
119
- {
120
- "aliases": [],
121
- "breakingPolicy": "forbidden",
122
- "description": "A change to guidance on working in the repository itself, such as its `AGENTS.md` or a repo-local skill, or to the repository's agent configuration.",
123
- "emoji": "🤖",
124
- "key": "ai",
125
- "label": "Agentic support",
126
- "tier": "process"
127
- },
128
- {
129
- "aliases": ["doc"],
130
- "breakingPolicy": "forbidden",
131
- "description": "A change to documentation for human readers, such as a README, a guide, or a code comment.",
132
- "emoji": "📚",
133
- "key": "docs",
134
- "label": "Documentation",
135
- "tier": "process"
136
- },
137
- {
138
- "aliases": [],
139
- "breakingPolicy": "forbidden",
140
- "description": "A change to formatting alone, such as whitespace or line wrapping, that leaves the content unchanged.",
141
- "emoji": "🎨",
142
- "excludedFromChangelog": true,
143
- "key": "fmt",
144
- "label": "Formatting",
145
- "tier": "process"
146
- }
147
- ],
148
- "version": "1.1.0"
149
- }
@@ -1,110 +0,0 @@
1
- {
2
- "$schema": "http://json-schema.org/draft-07/schema#",
3
- "$id": "https://github.com/williamthorsen/node-monorepo-tools/raw/main/packages/release-kit/src/work-types.schema.json",
4
- "title": "Work types",
5
- "description": "Canonical taxonomy of commit work types used by release-kit. Drives section ordering, audience classification, and the `!` (breaking) policy. The structured single-source-of-truth for everything that previously lived in `DEFAULT_WORK_TYPES` and `cliff.toml.template` group definitions.",
6
- "type": "object",
7
- "required": ["tiers", "types", "markers", "version"],
8
- "additionalProperties": false,
9
- "properties": {
10
- "$schema": {
11
- "type": "string",
12
- "description": "Optional reference to this schema for IDE validation."
13
- },
14
- "version": {
15
- "type": "string",
16
- "description": "Semantic version of the data shape. Bumped when the structure changes in a way that breaks downstream consumers.",
17
- "pattern": "^\\d+\\.\\d+\\.\\d+$"
18
- },
19
- "tiers": {
20
- "type": "array",
21
- "description": "Render tiers in canonical order. Each entry's `tier` field must reference one of these names.",
22
- "items": { "type": "string", "minLength": 1 },
23
- "minItems": 1,
24
- "uniqueItems": true
25
- },
26
- "types": {
27
- "type": "array",
28
- "description": "Work-type entries in canonical render order (tier order, then row order within tier).",
29
- "items": { "$ref": "#/definitions/workType" },
30
- "minItems": 1
31
- },
32
- "markers": {
33
- "type": "object",
34
- "description": "Orthogonal section markers used by downstream renderers (PR descriptions, changelogs, release notes). Keyed by marker name; values describe the rendering inputs (emoji + label). Markers are cross-cutting — they are not tied to a specific work type.",
35
- "required": ["breaking"],
36
- "properties": {
37
- "breaking": { "$ref": "#/definitions/marker" }
38
- },
39
- "additionalProperties": { "$ref": "#/definitions/marker" }
40
- }
41
- },
42
- "definitions": {
43
- "marker": {
44
- "type": "object",
45
- "description": "Rendering inputs for a single marker. Stored as plain text; consumers apply their own formatting (e.g., bolding, prefix punctuation) at construction time.",
46
- "required": ["emoji", "label"],
47
- "additionalProperties": false,
48
- "properties": {
49
- "emoji": {
50
- "type": "string",
51
- "description": "Decorative emoji rendered as the prefix of the marker.",
52
- "minLength": 1
53
- },
54
- "label": {
55
- "type": "string",
56
- "description": "Human-readable marker label. Plain text; consumers add their own emphasis (e.g., bold) when constructing the rendered form.",
57
- "minLength": 1
58
- }
59
- }
60
- },
61
- "workType": {
62
- "type": "object",
63
- "required": ["tier", "key", "aliases", "emoji", "label", "breakingPolicy", "description"],
64
- "additionalProperties": false,
65
- "properties": {
66
- "tier": {
67
- "type": "string",
68
- "description": "Render tier this entry belongs to. Must match one of the names in the top-level `tiers` array."
69
- },
70
- "key": {
71
- "type": "string",
72
- "description": "Canonical work-type identifier (e.g. `feat`, `fix`). Must be globally unique across all entries.",
73
- "minLength": 1,
74
- "pattern": "^[a-z][a-z0-9]*$"
75
- },
76
- "aliases": {
77
- "type": "array",
78
- "description": "Alternate identifiers that resolve to this work type. Must be globally unique and not collide with any `key`.",
79
- "items": { "type": "string", "minLength": 1, "pattern": "^[a-z][a-z0-9]*$" },
80
- "uniqueItems": true
81
- },
82
- "emoji": {
83
- "type": "string",
84
- "description": "Decorative emoji rendered as the prefix of the section heading.",
85
- "minLength": 1
86
- },
87
- "label": {
88
- "type": "string",
89
- "description": "Human-readable section label (rendered as `${emoji} ${label}` in changelogs and release notes).",
90
- "minLength": 1
91
- },
92
- "description": {
93
- "type": "string",
94
- "description": "The changes that the type covers, read by an agent choosing a type for a change.",
95
- "minLength": 1
96
- },
97
- "breakingPolicy": {
98
- "type": "string",
99
- "description": "Policy governing the `!` (breaking) marker for this type. `forbidden`: `!` is a policy violation. `optional`: `!` is allowed. `required`: bare type is a policy violation; only the `!` form is accepted.",
100
- "enum": ["forbidden", "optional", "required"]
101
- },
102
- "excludedFromChangelog": {
103
- "type": "boolean",
104
- "description": "When `true`, this type's commits never appear in any changelog or release note. Currently only `fmt` sets this. Default: `false`.",
105
- "default": false
106
- }
107
- }
108
- }
109
- }
110
- }
@@ -1,22 +0,0 @@
1
- /**
2
- * Shared helpers for the work-types canonical-source tooling.
3
- *
4
- * Both `checkWorkTypesDrift` and `syncWorkTypes` need to validate the upstream JSON's top-level
5
- * shape and render unknown errors as strings. Keeping a single copy here avoids byte-for-byte
6
- * duplication between the two entry points.
7
- */
8
- /** Sanity-check that the parsed upstream JSON carries the expected top-level shape. */
9
- export declare function hasExpectedTopLevelShape(value: unknown): value is {
10
- tiers: unknown[];
11
- types: unknown[];
12
- };
13
- /**
14
- * Build the `init` argument for `fetch` to reach codeassembly's canonical work-types files.
15
- *
16
- * Returns `{ headers: { Authorization: 'Bearer <token>' } }` when `GITHUB_TOKEN` is set in the
17
- * environment; returns `undefined` otherwise so the call site stays byte-identical to an
18
- * unauthenticated request. Centralised here so `checkWorkTypesDrift` and `syncWorkTypes`
19
- * cannot diverge on auth handling. Tests stub the env via `vi.stubEnv` rather than parameter
20
- * injection, so this reads `process.env` directly.
21
- */
22
- export declare function buildFetchInit(): RequestInit | undefined;
@@ -1,16 +0,0 @@
1
- export function hasExpectedTopLevelShape(value) {
2
- if (typeof value !== 'object' || value === null) {
3
- return false;
4
- }
5
- if (!('tiers' in value) || !('types' in value)) {
6
- return false;
7
- }
8
- return Array.isArray(value.tiers) && Array.isArray(value.types);
9
- }
10
- export function buildFetchInit() {
11
- const token = process.env['GITHUB_TOKEN'];
12
- if (token === undefined || token === '') {
13
- return undefined;
14
- }
15
- return { headers: { Authorization: `Bearer ${token}` } };
16
- }