@ankhorage/devtools 1.21.3 → 2.0.1
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/README.md +43 -458
- package/dist/cli/bin/apm-release.js +1 -1
- package/dist/cli/bin/structure.js +1 -1
- package/dist/cli/commands/apm/sync.js +1 -1
- package/dist/cli/commands/apm/validate.js +1 -1
- package/dist/cli/commands/structure/build.js +1 -1
- package/dist/cli/commands/structure/check.js +1 -1
- package/dist/{features/apm-release-validation/adapters/inbound → cli}/runApmReleaseCommandAsync.js +2 -2
- package/dist/{features/structure-descriptor-generation/adapters/inbound → cli}/runStructureGenerationCommandAsync.js +1 -1
- package/dist/internal/readmeDocs.js +8 -39
- package/dist/owner/synchronizeRenovateOwnerAsync.d.ts +1 -1
- package/dist/owner/synchronizeRenovateOwnerAsync.js +12 -33
- package/dist/policy/applyBunRuntimePolicy.d.ts +2 -4
- package/dist/policy/applyBunRuntimePolicy.js +5 -3
- package/dist/policy/bunRuntimePolicy.d.ts +2 -14
- package/dist/policy/bunRuntimePolicy.js +4 -24
- package/dist/policy/renderBunPolicyDocumentation.d.ts +1 -2
- package/dist/policy/renderBunPolicyDocumentation.js +7 -6
- package/dist/policy/resolvePkgvizAuditPolicyAsync.d.ts +1 -1
- package/dist/policy/resolvePkgvizAuditPolicyAsync.js +4 -6
- package/dist/tools/agents/index.js +4 -0
- package/dist/tools/package/index.js +16 -15
- package/dist/tools/skills/assets/ankhorage-coding-rules/SKILL.md +13 -7
- package/dist/tools/workflows/files/ci.yml +21 -1
- package/dist/tools/workflows/files/renovate.yml +1 -1
- package/dist/tools/workflows/index.js +6 -5
- package/dist/tools/workflows/renderRenovateConfigAsync.d.ts +1 -1
- package/dist/tools/workflows/renderRenovateConfigAsync.js +2 -19
- package/dist/tools/workflows/renderWorkflowAsync.js +4 -4
- package/examples/package/eslint.config.mjs +8 -1
- package/examples/package/package.json +13 -0
- package/examples/package/src/index.ts +1 -0
- package/examples/package/tsconfig.json +9 -0
- package/package.json +9 -12
- package/dist/policy/changesetsPolicy.d.ts +0 -19
- package/dist/policy/changesetsPolicy.js +0 -19
- package/dist/types/bunPolicy.d.ts +0 -5
- package/dist/types/bunPolicy.js +0 -1
- /package/dist/{features/apm-release-validation/adapters/inbound → cli}/runApmReleaseCommandAsync.d.ts +0 -0
- /package/dist/{features/structure-descriptor-generation/adapters/inbound → cli}/runStructureGenerationCommandAsync.d.ts +0 -0
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { dirname, resolve } from 'node:path';
|
|
4
|
+
import { REPOSITORY_POLICY } from '@ankhorage/policy/repository';
|
|
4
5
|
import { resolveApmReleaseCommandAsync } from '../features/apm-release-validation/adapters/outbound/resolveApmReleaseCommandAsync.js';
|
|
5
6
|
import { resolveStructureReleaseCommandAsync } from '../features/structure-descriptor-generation/adapters/outbound/resolveStructureReleaseCommandAsync.js';
|
|
6
7
|
import { applyBunRuntimePolicy } from '../policy/applyBunRuntimePolicy.js';
|
|
7
|
-
import {
|
|
8
|
+
import { DEVTOOLS_BUN_RUNTIME_POLICY } from '../policy/bunRuntimePolicy.js';
|
|
8
9
|
import { renderBunPolicyDocumentation } from '../policy/renderBunPolicyDocumentation.js';
|
|
9
10
|
import { readCurrentDoctorVersion } from '../tools/workflows/readCurrentDoctorVersion.js';
|
|
10
11
|
import { renderRenovateWorkflowAsync } from '../tools/workflows/renderRenovateWorkflowAsync.js';
|
|
11
12
|
import { renderWorkflowAsync, } from '../tools/workflows/renderWorkflowAsync.js';
|
|
12
|
-
/*** Synchronize or validate Renovate-owned Devtools policy
|
|
13
|
+
/*** Synchronize or validate Renovate-owned Devtools artifacts from Devtools-owned policy. */
|
|
13
14
|
export async function synchronizeRenovateOwnerAsync(operation, targetDirectory, options = {}) {
|
|
14
15
|
const target = resolve(targetDirectory);
|
|
15
|
-
const
|
|
16
|
-
const definitions = await createManagedDefinitionsAsync(target, policy);
|
|
16
|
+
const definitions = await createManagedDefinitionsAsync(target);
|
|
17
17
|
await assertDevtoolsTargetAsync(target);
|
|
18
18
|
if (operation === 'sync') {
|
|
19
19
|
await syncDefinitionsAsync(target, definitions);
|
|
@@ -34,18 +34,18 @@ async function assertDevtoolsTargetAsync(targetDirectory) {
|
|
|
34
34
|
throw new Error('The Renovate owner sync target must be @ankhorage/devtools.');
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
-
/*** Build the
|
|
38
|
-
async function createManagedDefinitionsAsync(targetDirectory
|
|
37
|
+
/*** Build the owner-managed artifact definitions from released central policy. */
|
|
38
|
+
async function createManagedDefinitionsAsync(targetDirectory) {
|
|
39
39
|
const manifest = JSON.parse(await readFile(resolve(targetDirectory, 'package.json'), 'utf8'));
|
|
40
40
|
if (!isRecord(manifest)) {
|
|
41
41
|
throw new Error('Devtools package.json must contain a JSON object.');
|
|
42
42
|
}
|
|
43
43
|
const readme = await readFile(resolve(targetDirectory, 'README.md'), 'utf8');
|
|
44
|
-
const workflowPolicy = await createWorkflowPolicyAsync(targetDirectory
|
|
44
|
+
const workflowPolicy = await createWorkflowPolicyAsync(targetDirectory);
|
|
45
45
|
return [
|
|
46
46
|
{
|
|
47
47
|
relativePath: 'package.json',
|
|
48
|
-
contents: serializePackageManifest(applyBunRuntimePolicy(manifest
|
|
48
|
+
contents: serializePackageManifest(applyBunRuntimePolicy(manifest)),
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
51
|
relativePath: '.github/workflows/ci.yml',
|
|
@@ -61,18 +61,18 @@ async function createManagedDefinitionsAsync(targetDirectory, policy) {
|
|
|
61
61
|
},
|
|
62
62
|
{
|
|
63
63
|
relativePath: 'README.md',
|
|
64
|
-
contents: renderBunPolicyDocumentation(readme
|
|
64
|
+
contents: renderBunPolicyDocumentation(readme),
|
|
65
65
|
},
|
|
66
66
|
];
|
|
67
67
|
}
|
|
68
68
|
/*** Build the self-hosted workflow policy used by Devtools owner synchronization. */
|
|
69
|
-
async function createWorkflowPolicyAsync(targetDirectory
|
|
69
|
+
async function createWorkflowPolicyAsync(targetDirectory) {
|
|
70
70
|
return {
|
|
71
71
|
apmReleaseCommand: await resolveApmReleaseCommandAsync(targetDirectory),
|
|
72
72
|
structureReleaseCommand: await resolveStructureReleaseCommandAsync(targetDirectory),
|
|
73
|
-
bunVersion:
|
|
73
|
+
bunVersion: DEVTOOLS_BUN_RUNTIME_POLICY.version,
|
|
74
74
|
doctorVersion: readCurrentDoctorVersion(),
|
|
75
|
-
nodeVersion:
|
|
75
|
+
nodeVersion: REPOSITORY_POLICY.runtime.node.setupVersion,
|
|
76
76
|
};
|
|
77
77
|
}
|
|
78
78
|
/*** Return owner-managed artifact paths whose current bytes differ from policy output. */
|
|
@@ -95,25 +95,6 @@ function isNodeError(error) {
|
|
|
95
95
|
function isRecord(value) {
|
|
96
96
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
97
97
|
}
|
|
98
|
-
/*** Read the target repository's canonical Bun policy literals. */
|
|
99
|
-
async function readTargetBunPolicyAsync(targetDirectory) {
|
|
100
|
-
const contents = await readFile(resolve(targetDirectory, 'src/policy/bunRuntimePolicy.ts'), 'utf8');
|
|
101
|
-
const matches = [...contents.matchAll(BUN_VERSION_PATTERN)];
|
|
102
|
-
const version = matches.length === 1 ? matches[0]?.[1] : undefined;
|
|
103
|
-
if (version === undefined) {
|
|
104
|
-
throw new Error('Expected exactly one canonical BUN_VERSION literal in the target policy.');
|
|
105
|
-
}
|
|
106
|
-
const typesMatches = [...contents.matchAll(BUN_TYPES_VERSION_PATTERN)];
|
|
107
|
-
const typesVersion = typesMatches.length === 1 ? typesMatches[0]?.[1] : undefined;
|
|
108
|
-
if (typesVersion === undefined) {
|
|
109
|
-
throw new Error('Expected exactly one canonical BUN_TYPES_VERSION literal in the target policy.');
|
|
110
|
-
}
|
|
111
|
-
return {
|
|
112
|
-
packageManager: `bun@${version}`,
|
|
113
|
-
typesRange: `^${typesVersion}`,
|
|
114
|
-
version,
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
98
|
/*** Synchronize or validate the target Bun lockfile through Bun itself. */
|
|
118
99
|
async function runBunLockfileAsync(operation, targetDirectory) {
|
|
119
100
|
const args = [
|
|
@@ -155,5 +136,3 @@ async function syncDefinitionsAsync(targetDirectory, definitions) {
|
|
|
155
136
|
await writeFile(targetPath, contents, 'utf8');
|
|
156
137
|
}
|
|
157
138
|
}
|
|
158
|
-
const BUN_VERSION_PATTERN = /const BUN_VERSION = '(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)';/gu;
|
|
159
|
-
const BUN_TYPES_VERSION_PATTERN = /const BUN_TYPES_VERSION = '(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)';/gu;
|
|
@@ -1,4 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
readonly typesRange: string;
|
|
4
|
-
}): Record<string, unknown>;
|
|
1
|
+
/*** Apply the Devtools-owned Bun runtime policy to one package manifest. */
|
|
2
|
+
export declare function applyBunRuntimePolicy(manifest: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
import { DEVTOOLS_BUN_RUNTIME_POLICY } from './bunRuntimePolicy.js';
|
|
2
|
+
/*** Apply the Devtools-owned Bun runtime policy to one package manifest. */
|
|
3
|
+
export function applyBunRuntimePolicy(manifest) {
|
|
2
4
|
const devDependencies = toRecord(manifest.devDependencies);
|
|
3
|
-
devDependencies['@types/bun'] =
|
|
5
|
+
devDependencies['@types/bun'] = DEVTOOLS_BUN_RUNTIME_POLICY.typesRange;
|
|
4
6
|
return {
|
|
5
7
|
...manifest,
|
|
6
|
-
packageManager:
|
|
8
|
+
packageManager: DEVTOOLS_BUN_RUNTIME_POLICY.packageManager,
|
|
7
9
|
devDependencies,
|
|
8
10
|
};
|
|
9
11
|
}
|
|
@@ -1,17 +1,5 @@
|
|
|
1
|
-
export declare const
|
|
1
|
+
export declare const DEVTOOLS_BUN_RUNTIME_POLICY: {
|
|
2
2
|
readonly packageManager: "bun@1.4.2";
|
|
3
|
-
readonly typesRange: "^1.4.
|
|
3
|
+
readonly typesRange: "^1.4.2";
|
|
4
4
|
readonly version: "1.4.2";
|
|
5
5
|
};
|
|
6
|
-
/**
|
|
7
|
-
* Canonical Node LTS baseline for Node-based Ankhorage tooling and CI execution.
|
|
8
|
-
*
|
|
9
|
-
* Bun remains the repository package manager/primary command runtime where configured;
|
|
10
|
-
* this policy makes Node-based tooling deterministic instead of inheriting the ambient
|
|
11
|
-
* Node version from a CI runner image.
|
|
12
|
-
*/
|
|
13
|
-
export declare const nodeRuntimePolicy: {
|
|
14
|
-
readonly engineRange: "24.x";
|
|
15
|
-
readonly major: 24;
|
|
16
|
-
readonly setupVersion: "24";
|
|
17
|
-
};
|
|
@@ -1,25 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* the managed Bun or Node baseline without defining an independent version authority.
|
|
6
|
-
*/
|
|
7
|
-
const BUN_VERSION = '1.4.2';
|
|
8
|
-
const BUN_TYPES_VERSION = '1.4.1';
|
|
9
|
-
export const bunRuntimePolicy = {
|
|
10
|
-
packageManager: `bun@${BUN_VERSION}`,
|
|
11
|
-
typesRange: `^${BUN_TYPES_VERSION}`,
|
|
12
|
-
version: BUN_VERSION,
|
|
13
|
-
};
|
|
14
|
-
/**
|
|
15
|
-
* Canonical Node LTS baseline for Node-based Ankhorage tooling and CI execution.
|
|
16
|
-
*
|
|
17
|
-
* Bun remains the repository package manager/primary command runtime where configured;
|
|
18
|
-
* this policy makes Node-based tooling deterministic instead of inheriting the ambient
|
|
19
|
-
* Node version from a CI runner image.
|
|
20
|
-
*/
|
|
21
|
-
export const nodeRuntimePolicy = {
|
|
22
|
-
engineRange: '24.x',
|
|
23
|
-
major: 24,
|
|
24
|
-
setupVersion: '24',
|
|
1
|
+
export const DEVTOOLS_BUN_RUNTIME_POLICY = {
|
|
2
|
+
packageManager: 'bun@1.4.2',
|
|
3
|
+
typesRange: '^1.4.2',
|
|
4
|
+
version: '1.4.2',
|
|
25
5
|
};
|
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
import type { BunPolicy } from '../types/bunPolicy.js';
|
|
2
1
|
/*** Render the managed Bun policy section while preserving the surrounding guide. */
|
|
3
|
-
export declare function renderBunPolicyDocumentation(readme: string
|
|
2
|
+
export declare function renderBunPolicyDocumentation(readme: string): string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { DEVTOOLS_BUN_RUNTIME_POLICY } from './bunRuntimePolicy.js';
|
|
1
2
|
/*** Render the managed Bun policy section while preserving the surrounding guide. */
|
|
2
|
-
export function renderBunPolicyDocumentation(readme
|
|
3
|
+
export function renderBunPolicyDocumentation(readme) {
|
|
3
4
|
const startIndex = readme.indexOf(README_POLICY_START);
|
|
4
5
|
const endIndex = readme.indexOf(README_POLICY_END);
|
|
5
6
|
if (startIndex === -1 || endIndex === -1 || endIndex < startIndex) {
|
|
@@ -9,15 +10,15 @@ export function renderBunPolicyDocumentation(readme, policy) {
|
|
|
9
10
|
readme.includes(README_POLICY_END, endIndex + README_POLICY_END.length)) {
|
|
10
11
|
throw new Error('README.md must contain exactly one Devtools Bun policy marker pair.');
|
|
11
12
|
}
|
|
12
|
-
const replacement = `${README_POLICY_START}\n\n${renderReadmePolicy(
|
|
13
|
+
const replacement = `${README_POLICY_START}\n\n${renderReadmePolicy()}\n\n${README_POLICY_END}`;
|
|
13
14
|
return `${readme.slice(0, startIndex)}${replacement}${readme.slice(endIndex + README_POLICY_END.length)}`;
|
|
14
15
|
}
|
|
15
16
|
/*** Format canonical runtime and type-package versions for the guide. */
|
|
16
|
-
function renderReadmePolicy(
|
|
17
|
+
function renderReadmePolicy() {
|
|
17
18
|
return `\`\`\`text
|
|
18
|
-
Bun runtime ${
|
|
19
|
-
packageManager ${
|
|
20
|
-
@types/bun ${
|
|
19
|
+
Bun runtime ${DEVTOOLS_BUN_RUNTIME_POLICY.version}
|
|
20
|
+
packageManager ${DEVTOOLS_BUN_RUNTIME_POLICY.packageManager}
|
|
21
|
+
@types/bun ${DEVTOOLS_BUN_RUNTIME_POLICY.typesRange}
|
|
21
22
|
\`\`\``;
|
|
22
23
|
}
|
|
23
24
|
const README_POLICY_END = '<!-- devtools-bun-policy:end -->';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*** Resolve the
|
|
1
|
+
/*** Resolve the central PKGViz CI audit for repositories with analyzable source. */
|
|
2
2
|
export declare function resolvePkgvizAuditPolicyAsync(targetDirectory: string): Promise<PkgvizAuditPolicy | undefined>;
|
|
3
3
|
interface PkgvizAuditPolicy {
|
|
4
4
|
readonly artifactName: string;
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { stat } from 'node:fs/promises';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
-
|
|
3
|
+
import { REPOSITORY_POLICY } from '@ankhorage/policy/repository';
|
|
4
|
+
/*** Resolve the central PKGViz CI audit for repositories with analyzable source. */
|
|
4
5
|
export async function resolvePkgvizAuditPolicyAsync(targetDirectory) {
|
|
5
6
|
if (!(await hasSourceDirectoryAsync(targetDirectory)))
|
|
6
7
|
return undefined;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
artifactPath: 'pkgviz-audit.json',
|
|
10
|
-
command: 'bunx pkgviz@0.8.1 --out pkgviz-audit.json --rule cyclic-dependencies=block',
|
|
11
|
-
};
|
|
8
|
+
const { artifactName, artifactPath, command } = REPOSITORY_POLICY.pkgvizAudit;
|
|
9
|
+
return { artifactName, artifactPath, command };
|
|
12
10
|
}
|
|
13
11
|
/*** Detect whether the managed repository has a source tree that PKGViz can inspect. */
|
|
14
12
|
async function hasSourceDirectoryAsync(targetDirectory) {
|
|
@@ -127,6 +127,10 @@ bun run changeset
|
|
|
127
127
|
bun run format
|
|
128
128
|
\`\`\`
|
|
129
129
|
|
|
130
|
+
For repositories that use Changesets, run \`bun run changeset\` only for release-impacting work.
|
|
131
|
+
No Changeset means no release is requested. Never add an empty Changeset to satisfy CI; remove it
|
|
132
|
+
for a no-release pull request, or add explicit release intent before validation.
|
|
133
|
+
|
|
130
134
|
`;
|
|
131
135
|
}
|
|
132
136
|
/*** Render the repository rule for executable Agent Skill scripts. */
|
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
* `lint:fix`, `format`, `format:check`, and `knip:check` scripts are written.
|
|
8
8
|
* Unrelated manifest fields, scripts, dependencies, and metadata are preserved.
|
|
9
9
|
*
|
|
10
|
-
* The Bun runtime
|
|
11
|
-
* only its consumer dependency/script normalization so it never
|
|
10
|
+
* The Bun runtime synchronization contract is Devtools-owned for every repository, including
|
|
11
|
+
* Devtools itself. Devtools skips only its consumer dependency/script normalization so it never
|
|
12
|
+
* attempts to install itself.
|
|
12
13
|
*
|
|
13
14
|
* Status compares only the fields owned by this contract, so unrelated repository customization
|
|
14
15
|
* does not count as drift. `--dry-run` reports whether `package.json` would be created or updated
|
|
@@ -19,9 +20,9 @@
|
|
|
19
20
|
import { existsSync, readFileSync } from 'node:fs';
|
|
20
21
|
import { readFile, writeFile } from 'node:fs/promises';
|
|
21
22
|
import { resolve } from 'node:path';
|
|
23
|
+
import { REPOSITORY_POLICY } from '@ankhorage/policy/repository';
|
|
22
24
|
import { applyBunRuntimePolicy } from '../../policy/applyBunRuntimePolicy.js';
|
|
23
|
-
import {
|
|
24
|
-
import { changesetsPolicy } from '../../policy/changesetsPolicy.js';
|
|
25
|
+
import { DEVTOOLS_BUN_RUNTIME_POLICY } from '../../policy/bunRuntimePolicy.js';
|
|
25
26
|
const PACKAGE_PATH = 'package.json';
|
|
26
27
|
const DEVTOOLS_PACKAGE_NAME = '@ankhorage/devtools';
|
|
27
28
|
const BUN_TYPES_PACKAGE_NAME = '@types/bun';
|
|
@@ -85,26 +86,26 @@ export async function syncPackageManifest(targetDirectory, devtoolsVersion, opti
|
|
|
85
86
|
/*** Apply the Devtools-owned package scripts, dependencies, and Bun runtime policy. */
|
|
86
87
|
export function applyManagedPackageContract(manifest, devtoolsVersion, changesetsConfigExists = false) {
|
|
87
88
|
if (manifest.name === DEVTOOLS_PACKAGE_NAME) {
|
|
88
|
-
return applyBunRuntimePolicy(manifest
|
|
89
|
+
return applyBunRuntimePolicy(manifest);
|
|
89
90
|
}
|
|
90
91
|
const scripts = { ...toRecord(manifest.scripts) };
|
|
91
92
|
const changesetsEnabled = isChangesetsEnabled(scripts, changesetsConfigExists);
|
|
92
93
|
delete scripts.knip;
|
|
93
94
|
Object.assign(scripts, STANDARD_SCRIPTS);
|
|
94
95
|
if (changesetsEnabled) {
|
|
95
|
-
Object.assign(scripts,
|
|
96
|
+
Object.assign(scripts, REPOSITORY_POLICY.changesets.packageScripts);
|
|
96
97
|
}
|
|
97
98
|
const devDependencies = removeOwnedDependencies(toRecord(manifest.devDependencies));
|
|
98
99
|
const dependencies = toRecord(manifest.dependencies);
|
|
99
|
-
delete dependencies[
|
|
100
|
-
delete devDependencies[
|
|
100
|
+
delete dependencies[REPOSITORY_POLICY.changesets.packageName];
|
|
101
|
+
delete devDependencies[REPOSITORY_POLICY.changesets.packageName];
|
|
101
102
|
applyDevtoolsDependencyPlacement(dependencies, devDependencies, devtoolsVersion);
|
|
102
103
|
return applyBunRuntimePolicy({
|
|
103
104
|
...manifest,
|
|
104
105
|
...normalizedDependencies(manifest, dependencies),
|
|
105
106
|
scripts,
|
|
106
107
|
devDependencies,
|
|
107
|
-
}
|
|
108
|
+
});
|
|
108
109
|
}
|
|
109
110
|
/*** Check whether the Devtools-owned package manifest fields match current policy. */
|
|
110
111
|
export function isManagedPackageContractCurrent(manifest, devtoolsVersion, changesetsConfigExists = false) {
|
|
@@ -120,8 +121,8 @@ export function isManagedPackageContractCurrent(manifest, devtoolsVersion, chang
|
|
|
120
121
|
const changesetsEnabled = isChangesetsEnabled(scripts, changesetsConfigExists);
|
|
121
122
|
return (hasStandardScripts(scripts) &&
|
|
122
123
|
DEVTOOLS_OWNED_DEV_DEPENDENCIES.every((name) => devDependencies[name] === undefined) &&
|
|
123
|
-
dependencies[
|
|
124
|
-
devDependencies[
|
|
124
|
+
dependencies[REPOSITORY_POLICY.changesets.packageName] === undefined &&
|
|
125
|
+
devDependencies[REPOSITORY_POLICY.changesets.packageName] === undefined &&
|
|
125
126
|
hasCurrentChangesetsScripts(scripts, changesetsEnabled) &&
|
|
126
127
|
hasCurrentDevtoolsDependencyPlacement(dependencies, devDependencies, devtoolsVersion));
|
|
127
128
|
}
|
|
@@ -154,8 +155,8 @@ async function readPackageManifest(targetDirectory) {
|
|
|
154
155
|
/*** Check the Bun package manager and Bun type dependency contract. */
|
|
155
156
|
function hasCurrentBunRuntimePolicy(manifest) {
|
|
156
157
|
const devDependencies = toRecord(manifest.devDependencies);
|
|
157
|
-
return (manifest.packageManager ===
|
|
158
|
-
devDependencies[BUN_TYPES_PACKAGE_NAME] ===
|
|
158
|
+
return (manifest.packageManager === DEVTOOLS_BUN_RUNTIME_POLICY.packageManager &&
|
|
159
|
+
devDependencies[BUN_TYPES_PACKAGE_NAME] === DEVTOOLS_BUN_RUNTIME_POLICY.typesRange);
|
|
159
160
|
}
|
|
160
161
|
/*** Place Devtools in development dependencies for every consuming repository. */
|
|
161
162
|
function applyDevtoolsDependencyPlacement(dependencies, devDependencies, devtoolsVersion) {
|
|
@@ -188,12 +189,12 @@ function hasStandardScripts(scripts) {
|
|
|
188
189
|
/*** Check Changesets scripts when the repository participates in Changesets. */
|
|
189
190
|
function hasCurrentChangesetsScripts(scripts, changesetsEnabled) {
|
|
190
191
|
return (!changesetsEnabled ||
|
|
191
|
-
Object.entries(
|
|
192
|
+
Object.entries(REPOSITORY_POLICY.changesets.packageScripts).every(([name, command]) => scripts[name] === command));
|
|
192
193
|
}
|
|
193
194
|
/*** Determine whether the repository participates in Changesets synchronization. */
|
|
194
195
|
function isChangesetsEnabled(scripts, changesetsConfigExists) {
|
|
195
196
|
return (changesetsConfigExists ||
|
|
196
|
-
Object.keys(
|
|
197
|
+
Object.keys(REPOSITORY_POLICY.changesets.packageScripts).some((scriptName) => scripts[scriptName] !== undefined));
|
|
197
198
|
}
|
|
198
199
|
/*** Serialize a package manifest using the repository formatting contract. */
|
|
199
200
|
function serializePackageManifest(manifest) {
|
|
@@ -52,16 +52,22 @@ exceptions or replaced by generic preferences from this skill.
|
|
|
52
52
|
- Use ordinary inline comments when they explain non-obvious intent, invariants, constraints, or the
|
|
53
53
|
reason behind a decision. Do not narrate self-explanatory code or duplicate what names and types
|
|
54
54
|
already express.
|
|
55
|
-
- Paradox documentation metadata belongs only inside `/*** ... */` comments.
|
|
56
|
-
|
|
57
|
-
`@
|
|
55
|
+
- Paradox documentation metadata belongs only inside `/*** ... */` comments. The canonical tag
|
|
56
|
+
vocabulary is owned by `@ankhorage/policy`: `@readme`, `@usage`, `@config`, `@title`,
|
|
57
|
+
`@see`, and `@security`. Unsupported tag-shaped lines are invalid; `@example` does not exist.
|
|
58
|
+
Do not use JSDoc-only tags such as `@param` or `@returns` as Paradox metadata.
|
|
59
|
+
- Paradox comments contain documentation prose and metadata only. Fenced or indented code blocks are
|
|
60
|
+
invalid; source examples come from real code. Inline code spans remain valid prose.
|
|
58
61
|
- Add a supported Paradox tag only when it changes or usefully enriches generated documentation;
|
|
59
62
|
plain function descriptions do not need tags.
|
|
60
63
|
- README usage documentation must come from a real repository-root `examples/<example>/...` source
|
|
61
|
-
file.
|
|
62
|
-
|
|
63
|
-
`usage-readme`, `readmeUsage`, or equivalent source modules whose
|
|
64
|
-
usage text.
|
|
64
|
+
file. A package that opts into `@usage` must have exactly one example combining `@usage`,
|
|
65
|
+
`@readme`, and `@title`; additional `@usage` examples remain full-doc-only. Do not create
|
|
66
|
+
dedicated `readme-usage`, `usage-readme`, `readmeUsage`, or equivalent source modules whose
|
|
67
|
+
only purpose is feeding README usage text.
|
|
68
|
+
- Configuration documentation is optional until a package opts in. Once it does, the canonical schema
|
|
69
|
+
is `src/types/config.ts` with exactly one root type/interface carrying `@config`, `@readme`,
|
|
70
|
+
and `@title`.
|
|
65
71
|
- Update documentation sources in the pull request, including repository-owned manual documentation
|
|
66
72
|
outside the configured generated output. Never hand-edit generated README or Paradox artifacts.
|
|
67
73
|
- Generated documentation is release-owned. Ordinary feature pull requests must not regenerate or
|
|
@@ -107,10 +107,30 @@ jobs:
|
|
|
107
107
|
- name: Check changesets
|
|
108
108
|
if: github.event_name == 'pull_request'
|
|
109
109
|
run: |
|
|
110
|
+
base_sha='${{ github.event.pull_request.base.sha }}'
|
|
111
|
+
head_sha='${{ github.event.pull_request.head.sha }}'
|
|
112
|
+
export ANKH_PR_CHANGESET_FILES
|
|
113
|
+
ANKH_PR_CHANGESET_FILES="$(git diff --name-only --diff-filter=AMCR "$base_sha" "$head_sha" -- .changeset)"
|
|
114
|
+
if [ -z "$ANKH_PR_CHANGESET_FILES" ]; then
|
|
115
|
+
echo "No pull-request-owned Changeset files; no release requested."
|
|
116
|
+
exit 0
|
|
117
|
+
fi
|
|
118
|
+
node -e '
|
|
119
|
+
const { readFileSync } = require("node:fs");
|
|
120
|
+
const files = process.env.ANKH_PR_CHANGESET_FILES.split("\n").filter(Boolean);
|
|
121
|
+
const empty = files.filter((file) => {
|
|
122
|
+
if (!/^\.changeset\/[^/]+\.md$/u.test(file) || file === ".changeset/README.md") return false;
|
|
123
|
+
const match = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/u.exec(readFileSync(file, "utf8"));
|
|
124
|
+
return match?.[1].trim() === "";
|
|
125
|
+
});
|
|
126
|
+
if (empty.length > 0) {
|
|
127
|
+
throw new Error("Empty Changesets are not supported. Remove " + empty.join(", ") + " for a no-release PR, or add release intent.");
|
|
128
|
+
}
|
|
129
|
+
'
|
|
110
130
|
if node -e "const p=require('./package.json'); process.exit(p.scripts?.['changeset:status'] ? 0 : 1)"; then
|
|
111
131
|
__ANKH_CHANGESETS_STATUS_COMMAND__
|
|
112
132
|
else
|
|
113
|
-
echo "No changeset:status script found; skipping."
|
|
133
|
+
echo "No changeset:status script found; skipping validation."
|
|
114
134
|
fi
|
|
115
135
|
|
|
116
136
|
# __ANKH_PKGVIZ_AUDIT_STEPS__
|
|
@@ -25,7 +25,7 @@ jobs:
|
|
|
25
25
|
(github.event.pull_request.user.login == 'renovate[bot]' || github.event.pull_request.user.login == 'ankhorage-renovate-sync[bot]') &&
|
|
26
26
|
github.event.pull_request.head.repo.full_name == github.repository &&
|
|
27
27
|
startsWith(github.event.pull_request.head.ref, 'renovate/')
|
|
28
|
-
uses: ankhorage/renovate/.github/workflows/changeset.yml@
|
|
28
|
+
uses: ankhorage/renovate/.github/workflows/changeset.yml@60f0b8c853ecc2c3601d947e8c9414c8a89bd481
|
|
29
29
|
with:
|
|
30
30
|
renovate_sync_client_id: ${{ vars.ANKHORAGE_RENOVATE_SYNC_CLIENT_ID }}
|
|
31
31
|
secrets:
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { access } from 'node:fs/promises';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
+
import { REPOSITORY_POLICY } from '@ankhorage/policy/repository';
|
|
3
4
|
import { resolveApmReleaseCommandAsync } from '../../features/apm-release-validation/adapters/outbound/resolveApmReleaseCommandAsync.js';
|
|
4
5
|
import { resolveStructureReleaseCommandAsync } from '../../features/structure-descriptor-generation/adapters/outbound/resolveStructureReleaseCommandAsync.js';
|
|
5
|
-
import {
|
|
6
|
+
import { DEVTOOLS_BUN_RUNTIME_POLICY } from '../../policy/bunRuntimePolicy.js';
|
|
6
7
|
import { resolvePkgvizAuditPolicyAsync } from '../../policy/resolvePkgvizAuditPolicyAsync.js';
|
|
7
8
|
import { readCurrentDoctorVersion } from './readCurrentDoctorVersion.js';
|
|
8
9
|
import { renderRenovateConfigAsync } from './renderRenovateConfigAsync.js';
|
|
@@ -38,9 +39,9 @@ function createWorkflowDefinition(relativePath, sourcePath) {
|
|
|
38
39
|
render: async (targetDirectory) => await renderWorkflowAsync(sourceUrl, {
|
|
39
40
|
apmReleaseCommand: await resolveApmReleaseCommandAsync(targetDirectory),
|
|
40
41
|
structureReleaseCommand: await resolveStructureReleaseCommandAsync(targetDirectory),
|
|
41
|
-
bunVersion:
|
|
42
|
+
bunVersion: DEVTOOLS_BUN_RUNTIME_POLICY.version,
|
|
42
43
|
doctorVersion: readCurrentDoctorVersion(),
|
|
43
|
-
nodeVersion:
|
|
44
|
+
nodeVersion: REPOSITORY_POLICY.runtime.node.setupVersion,
|
|
44
45
|
pkgvizAudit: await resolvePkgvizAuditPolicyAsync(targetDirectory),
|
|
45
46
|
}),
|
|
46
47
|
};
|
|
@@ -53,9 +54,9 @@ function createRenovateWorkflowDefinition() {
|
|
|
53
54
|
render: async (targetDirectory) => await renderRenovateWorkflowAsync(sourceUrl, targetDirectory, {
|
|
54
55
|
apmReleaseCommand: await resolveApmReleaseCommandAsync(targetDirectory),
|
|
55
56
|
structureReleaseCommand: await resolveStructureReleaseCommandAsync(targetDirectory),
|
|
56
|
-
bunVersion:
|
|
57
|
+
bunVersion: DEVTOOLS_BUN_RUNTIME_POLICY.version,
|
|
57
58
|
doctorVersion: readCurrentDoctorVersion(),
|
|
58
|
-
nodeVersion:
|
|
59
|
+
nodeVersion: REPOSITORY_POLICY.runtime.node.setupVersion,
|
|
59
60
|
}),
|
|
60
61
|
};
|
|
61
62
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*** Render Renovate config while preserving repository-owned rules
|
|
1
|
+
/*** Render the current Renovate config while preserving supported repository-owned rules. */
|
|
2
2
|
export declare function renderRenovateConfigAsync(targetDirectory: string): Promise<string>;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
const TEMPLATE_URL = new URL('./files/renovate.json5', import.meta.url);
|
|
4
|
-
|
|
5
|
-
/*** Render Renovate config while preserving repository-owned rules and removing obsolete Paradox metadata. */
|
|
4
|
+
/*** Render the current Renovate config while preserving supported repository-owned rules. */
|
|
6
5
|
export async function renderRenovateConfigAsync(targetDirectory) {
|
|
7
6
|
const targetPath = join(targetDirectory, 'renovate.json5');
|
|
8
7
|
let current;
|
|
@@ -15,21 +14,5 @@ export async function renderRenovateConfigAsync(targetDirectory) {
|
|
|
15
14
|
}
|
|
16
15
|
throw error;
|
|
17
16
|
}
|
|
18
|
-
return
|
|
19
|
-
}
|
|
20
|
-
/*** Convert the historical managed Paradox header to an ordinary comment without changing config data. */
|
|
21
|
-
function migrateLegacyRenovateHeader(contents) {
|
|
22
|
-
const match = LEGACY_HEADER_PATTERN.exec(contents);
|
|
23
|
-
if (match === null)
|
|
24
|
-
return contents;
|
|
25
|
-
const [header, body = ''] = match;
|
|
26
|
-
if (!body.includes('Repository configuration'))
|
|
27
|
-
return contents;
|
|
28
|
-
if (!body.includes('@usage') && !body.includes('@readme'))
|
|
29
|
-
return contents;
|
|
30
|
-
const migratedBody = body
|
|
31
|
-
.split('\n')
|
|
32
|
-
.filter((line) => !/^\s*\*\s+@(usage|readme)\s*$/u.test(line))
|
|
33
|
-
.join('\n');
|
|
34
|
-
return `/**${migratedBody}*/\n${contents.slice(header.length)}`;
|
|
17
|
+
return current;
|
|
35
18
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
|
-
import {
|
|
2
|
+
import { REPOSITORY_POLICY } from '@ankhorage/policy/repository';
|
|
3
3
|
/*** Renders one workflow template with the canonical runtime, Doctor, and Changesets policy. */
|
|
4
4
|
export async function renderWorkflowAsync(sourceUrl, policy) {
|
|
5
5
|
const template = await readFile(sourceUrl, 'utf8');
|
|
6
6
|
const rendered = template
|
|
7
7
|
.replaceAll(BUN_VERSION_TOKEN, policy.bunVersion)
|
|
8
8
|
.replaceAll(PKGVIZ_AUDIT_STEPS_TOKEN, renderPkgvizAuditSteps(policy))
|
|
9
|
-
.replaceAll(CHANGESETS_PUBLISH_COMMAND_TOKEN,
|
|
10
|
-
.replaceAll(CHANGESETS_STATUS_COMMAND_TOKEN,
|
|
11
|
-
.replaceAll(CHANGESETS_VERSION_COMMAND_TOKEN,
|
|
9
|
+
.replaceAll(CHANGESETS_PUBLISH_COMMAND_TOKEN, REPOSITORY_POLICY.changesets.workflowCommands.publish)
|
|
10
|
+
.replaceAll(CHANGESETS_STATUS_COMMAND_TOKEN, REPOSITORY_POLICY.changesets.workflowCommands.status)
|
|
11
|
+
.replaceAll(CHANGESETS_VERSION_COMMAND_TOKEN, REPOSITORY_POLICY.changesets.workflowCommands.version)
|
|
12
12
|
.replaceAll(DOCTOR_VERSION_TOKEN, policy.doctorVersion)
|
|
13
13
|
.replaceAll('__ANKH_APM_RELEASE_COMMAND__', policy.apmReleaseCommand ?? './node_modules/.bin/ankhorage-apm-release')
|
|
14
14
|
.replaceAll('__ANKH_STRUCTURE_RELEASE_COMMAND__', policy.structureReleaseCommand ?? './node_modules/.bin/ankhorage-structure')
|
|
@@ -4,8 +4,15 @@ import { fileURLToPath } from 'node:url';
|
|
|
4
4
|
|
|
5
5
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
6
|
|
|
7
|
+
/***
|
|
8
|
+
* Configure ESLint for a standalone TypeScript package with the Devtools shared policy.
|
|
9
|
+
*
|
|
10
|
+
* @usage
|
|
11
|
+
* @readme
|
|
12
|
+
* @title Standalone package ESLint configuration
|
|
13
|
+
*/
|
|
7
14
|
export default createConfig({
|
|
8
15
|
tsconfigRootDir: __dirname,
|
|
9
|
-
project: ['./tsconfig.
|
|
16
|
+
project: ['./tsconfig.json'],
|
|
10
17
|
files: ['src/**/*.{ts,tsx}'],
|
|
11
18
|
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ankhorage/devtools-eslint-example",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"devDependencies": {
|
|
6
|
+
"@ankhorage/devtools": "^2.0.0",
|
|
7
|
+
"typescript": "~6.0.3"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"lint": "ankhorage-eslint . --max-warnings=0"
|
|
11
|
+
},
|
|
12
|
+
"packageManager": "bun@1.4.2"
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const exampleMessage = 'Standalone Devtools ESLint configuration.';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ankhorage/devtools",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Shared tooling, repository automation,
|
|
3
|
+
"version": "2.0.1",
|
|
4
|
+
"description": "Shared tooling, repository automation, and agent standards for Ankhorage TypeScript projects",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/ankhorage/devtools#readme",
|
|
7
7
|
"bugs": {
|
|
@@ -82,10 +82,6 @@
|
|
|
82
82
|
"types": "./dist/tools/knip/index.d.ts",
|
|
83
83
|
"import": "./dist/tools/knip/index.js"
|
|
84
84
|
},
|
|
85
|
-
"./policy": {
|
|
86
|
-
"types": "./dist/policy/bunRuntimePolicy.d.ts",
|
|
87
|
-
"import": "./dist/policy/bunRuntimePolicy.js"
|
|
88
|
-
},
|
|
89
85
|
"./prettier": {
|
|
90
86
|
"import": "./dist/tools/prettier/index.cjs",
|
|
91
87
|
"require": "./dist/tools/prettier/index.cjs",
|
|
@@ -145,16 +141,17 @@
|
|
|
145
141
|
"knip": "^6.38.0",
|
|
146
142
|
"prettier": "^3.9.9",
|
|
147
143
|
"typescript-eslint": "^8.70.1",
|
|
148
|
-
"@ankhorage/contracts": "^22.8.
|
|
149
|
-
"typescript": "~6.0.3"
|
|
144
|
+
"@ankhorage/contracts": "^22.8.2",
|
|
145
|
+
"typescript": "~6.0.3",
|
|
146
|
+
"@ankhorage/policy": "^0.5.2"
|
|
150
147
|
},
|
|
151
148
|
"devDependencies": {
|
|
152
|
-
"@ankhorage/paradox": "^0.
|
|
149
|
+
"@ankhorage/paradox": "^0.2.6",
|
|
153
150
|
"@ankhorage/ankh": "^0.10.4",
|
|
154
|
-
"@ankhorage/doctor": "0.11.
|
|
151
|
+
"@ankhorage/doctor": "0.11.8",
|
|
155
152
|
"@techstark/opencv-js": "^5.0.0-release.1",
|
|
156
|
-
"@types/bun": "^1.4.
|
|
157
|
-
"@types/node": "^26.6.
|
|
153
|
+
"@types/bun": "^1.4.2",
|
|
154
|
+
"@types/node": "^26.6.3",
|
|
158
155
|
"sharp": "^0.35.4"
|
|
159
156
|
},
|
|
160
157
|
"packageManager": "bun@1.4.2"
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export declare const changesetsPolicy: {
|
|
2
|
-
readonly packageName: "@changesets/cli";
|
|
3
|
-
readonly binaryName: "ankhorage-changeset";
|
|
4
|
-
readonly packageScripts: {
|
|
5
|
-
readonly changeset: "ankhorage-changeset";
|
|
6
|
-
readonly 'changeset:status': "ankhorage-changeset status --since=origin/main";
|
|
7
|
-
readonly 'version-packages': "ankhorage-changeset version";
|
|
8
|
-
};
|
|
9
|
-
readonly ownerPackageScripts: {
|
|
10
|
-
readonly changeset: "bun src/cli/bin/changeset.ts";
|
|
11
|
-
readonly 'changeset:status': "bun src/cli/bin/changeset.ts status --since=origin/main";
|
|
12
|
-
readonly 'version-packages': "bun src/cli/bin/changeset.ts version";
|
|
13
|
-
};
|
|
14
|
-
readonly workflowCommands: {
|
|
15
|
-
readonly status: "bun run changeset:status";
|
|
16
|
-
readonly version: "bun run version-packages";
|
|
17
|
-
readonly publish: "bun run changeset -- publish";
|
|
18
|
-
};
|
|
19
|
-
};
|