@ankhorage/devtools 1.21.3 → 2.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.
- package/README.md +9 -9
- package/dist/internal/readmeDocs.js +5 -4
- package/dist/owner/synchronizeRenovateOwnerAsync.d.ts +1 -1
- package/dist/owner/synchronizeRenovateOwnerAsync.js +11 -33
- package/dist/policy/applyBunRuntimePolicy.d.ts +2 -4
- package/dist/policy/applyBunRuntimePolicy.js +5 -3
- package/dist/policy/renderBunPolicyDocumentation.d.ts +1 -2
- package/dist/policy/renderBunPolicyDocumentation.js +5 -3
- package/dist/policy/resolvePkgvizAuditPolicyAsync.d.ts +1 -1
- package/dist/policy/resolvePkgvizAuditPolicyAsync.js +4 -6
- package/dist/tools/package/index.js +13 -14
- package/dist/tools/skills/assets/ankhorage-coding-rules/SKILL.md +13 -7
- package/dist/tools/workflows/index.js +5 -5
- package/dist/tools/workflows/renderWorkflowAsync.js +4 -4
- package/package.json +5 -8
- package/dist/policy/bunRuntimePolicy.d.ts +0 -17
- package/dist/policy/bunRuntimePolicy.js +0 -25
- 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/README.md
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
|
|
4
4
|
# @ankhorage/devtools
|
|
5
5
|
|
|
6
|
-
         
|
|
7
7
|
|
|
8
|
-
Shared tooling, repository automation,
|
|
8
|
+
Shared tooling, repository automation, and agent standards for Ankhorage TypeScript projects
|
|
9
9
|
|
|
10
10
|
## Usage
|
|
11
11
|
|
|
@@ -13,7 +13,7 @@ Shared development tools and repository standards for Ankhorage TypeScript proje
|
|
|
13
13
|
|
|
14
14
|
## What it owns
|
|
15
15
|
|
|
16
|
-
`@ankhorage/
|
|
16
|
+
`@ankhorage/policy` is the source of truth for canonical Ankhorage policy. `@ankhorage/devtools` is the execution and synchronization layer for these repository concerns:
|
|
17
17
|
|
|
18
18
|
```text
|
|
19
19
|
src/
|
|
@@ -30,8 +30,8 @@ src/
|
|
|
30
30
|
└── vscode/
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
- `policy`:
|
|
34
|
-
- `changesets`: package-resolved Changesets execution
|
|
33
|
+
- `policy`: policy application/rendering adapters that consume `@ankhorage/policy`
|
|
34
|
+
- `changesets`: package-resolved Changesets execution using centrally defined commands
|
|
35
35
|
- `agents`: canonical repository `AGENTS.md` rendered from stable package identity
|
|
36
36
|
- `skills`: immutable Ankhorage-owned repository skills under `.agents/skills/`
|
|
37
37
|
- `eslint`: shared flat ESLint configuration, automatic project profiles, and the bundled ESLint runner
|
|
@@ -41,7 +41,7 @@ src/
|
|
|
41
41
|
- `workflows`: canonical `.github/workflows/ci.yml` and `release.yml`
|
|
42
42
|
- `vscode`: canonical `.vscode/settings.json` and `extensions.json`
|
|
43
43
|
|
|
44
|
-
The package owns the supported Changesets CLI, ESLint, TypeScript ESLint, Prettier, Knip, security, React, React Hooks, React Native, import/sort, unused-import, and formatting-plugin versions used by consuming repositories.
|
|
44
|
+
The package owns the supported Changesets CLI, ESLint, TypeScript ESLint, Prettier, Knip, security, React, React Hooks, React Native, import/sort, unused-import, and formatting-plugin versions used by consuming repositories. The Bun/Node runtime baseline and canonical Changesets/PKGViz policy values are owned by `@ankhorage/policy` and rendered by Devtools.
|
|
45
45
|
|
|
46
46
|
## Bootstrap
|
|
47
47
|
|
|
@@ -316,7 +316,7 @@ export default createKnipConfig();
|
|
|
316
316
|
|
|
317
317
|
## Managed Bun runtime policy
|
|
318
318
|
|
|
319
|
-
The canonical Bun policy is defined
|
|
319
|
+
The canonical Bun policy is defined by `@ankhorage/policy` and consumed by Devtools package and workflow synchronization. The current released policy is:
|
|
320
320
|
|
|
321
321
|
<!-- devtools-bun-policy:start -->
|
|
322
322
|
|
|
@@ -328,7 +328,7 @@ packageManager bun@1.4.2
|
|
|
328
328
|
|
|
329
329
|
<!-- devtools-bun-policy:end -->
|
|
330
330
|
|
|
331
|
-
|
|
331
|
+
`ankhorage/policy` owns and updates the canonical Bun and `@types/bun` literals through Renovate. A released Policy update reaches Devtools as a normal dependency update; Devtools then renders that policy into `packageManager`, `@types/bun`, workflow setup versions, this documentation block, and `bun.lock`. The trusted owner workflow uses `bun scripts/sync-renovate-owner.ts sync repository` to regenerate those artifacts and `bun scripts/sync-renovate-owner.ts status repository` to reject stale rendered state. Do not duplicate runtime policy literals in Devtools.
|
|
332
332
|
|
|
333
333
|
## Managed package contract
|
|
334
334
|
|
|
@@ -363,7 +363,7 @@ A repository participates in Changesets synchronization when `.changeset/config.
|
|
|
363
363
|
.github/workflows/release.yml
|
|
364
364
|
```
|
|
365
365
|
|
|
366
|
-
CI and Release render their `bun-version` from the same
|
|
366
|
+
CI and Release render their `bun-version` from `@ankhorage/policy/repository`, the same policy used for `package.json`. They also render Changesets status, version, and publish commands from that central policy. The CI workflow installs that Bun version with the frozen lockfile, builds before repository-provider validation, runs `bunx @ankhorage/ankh doctor validate .`, and conditionally runs lint, formatting, Knip, tests, typecheck, and the strict `changeset:status --since=origin/main` guard for pull requests. After a green change reaches `main`, Release uses the scoped Ankhorage Renovate Sync App token to apply Changesets versioning directly to `main` in a `chore(release)` `[skip ci]` commit and publishes without creating a second Version Packages pull request. Release publishing calls the Devtools-owned runner through the synchronized package script; it never resolves an ambient or mutable Changesets executable. Changesets v3 creates the local release tags; the managed workflow pushes those exact tags and creates any missing GitHub Releases directly, without parsing Changesets’ human-readable publish output.
|
|
367
367
|
|
|
368
368
|
For the **first npm publication** of a new `@ankhorage/*` package, the organization publishing credential must be able to create/publish packages in the `@ankhorage` scope. With a granular npm token, grant package permission **Read and write (publish and stage)** to the `@ankhorage` scope or **All Packages**. If initial publication fails after Changesets has already pushed the release commit, correct the npm credential and rerun Release; the current unpublished version is reused and must not be bumped again. The managed workflow diagnoses this first-publish state separately from registry/network failures.
|
|
369
369
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { REPOSITORY_POLICY } from '@ankhorage/policy/repository';
|
|
2
2
|
const REQUIRED_README_SNIPPETS = [
|
|
3
3
|
'ankh devtools lint',
|
|
4
4
|
'ankh devtools changeset',
|
|
@@ -35,9 +35,10 @@ const REQUIRED_README_SNIPPETS = [
|
|
|
35
35
|
'<!-- devtools-bun-policy:end -->',
|
|
36
36
|
'bun scripts/sync-renovate-owner.ts sync repository',
|
|
37
37
|
'bun scripts/sync-renovate-owner.ts status',
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
'@ankhorage/policy',
|
|
39
|
+
REPOSITORY_POLICY.runtime.bun.version,
|
|
40
|
+
REPOSITORY_POLICY.runtime.bun.packageManager,
|
|
41
|
+
REPOSITORY_POLICY.runtime.bun.typesRange,
|
|
41
42
|
];
|
|
42
43
|
export function getReadmeDocumentationErrors(readmeContents) {
|
|
43
44
|
return REQUIRED_README_SNIPPETS.flatMap((snippet) => readmeContents.includes(snippet)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*** Synchronize or validate Renovate-owned Devtools policy
|
|
1
|
+
/*** Synchronize or validate Renovate-owned Devtools artifacts from central repository policy. */
|
|
2
2
|
export declare function synchronizeRenovateOwnerAsync(operation: OwnerSyncOperation, targetDirectory: string, options?: OwnerSyncOptions): Promise<void>;
|
|
3
3
|
type OwnerSyncOperation = 'status' | 'sync';
|
|
4
4
|
interface OwnerSyncOptions {
|
|
@@ -1,19 +1,18 @@
|
|
|
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 { nodeRuntimePolicy } from '../policy/bunRuntimePolicy.js';
|
|
8
8
|
import { renderBunPolicyDocumentation } from '../policy/renderBunPolicyDocumentation.js';
|
|
9
9
|
import { readCurrentDoctorVersion } from '../tools/workflows/readCurrentDoctorVersion.js';
|
|
10
10
|
import { renderRenovateWorkflowAsync } from '../tools/workflows/renderRenovateWorkflowAsync.js';
|
|
11
11
|
import { renderWorkflowAsync, } from '../tools/workflows/renderWorkflowAsync.js';
|
|
12
|
-
/*** Synchronize or validate Renovate-owned Devtools policy
|
|
12
|
+
/*** Synchronize or validate Renovate-owned Devtools artifacts from central repository policy. */
|
|
13
13
|
export async function synchronizeRenovateOwnerAsync(operation, targetDirectory, options = {}) {
|
|
14
14
|
const target = resolve(targetDirectory);
|
|
15
|
-
const
|
|
16
|
-
const definitions = await createManagedDefinitionsAsync(target, policy);
|
|
15
|
+
const definitions = await createManagedDefinitionsAsync(target);
|
|
17
16
|
await assertDevtoolsTargetAsync(target);
|
|
18
17
|
if (operation === 'sync') {
|
|
19
18
|
await syncDefinitionsAsync(target, definitions);
|
|
@@ -34,18 +33,18 @@ async function assertDevtoolsTargetAsync(targetDirectory) {
|
|
|
34
33
|
throw new Error('The Renovate owner sync target must be @ankhorage/devtools.');
|
|
35
34
|
}
|
|
36
35
|
}
|
|
37
|
-
/*** Build the
|
|
38
|
-
async function createManagedDefinitionsAsync(targetDirectory
|
|
36
|
+
/*** Build the owner-managed artifact definitions from released central policy. */
|
|
37
|
+
async function createManagedDefinitionsAsync(targetDirectory) {
|
|
39
38
|
const manifest = JSON.parse(await readFile(resolve(targetDirectory, 'package.json'), 'utf8'));
|
|
40
39
|
if (!isRecord(manifest)) {
|
|
41
40
|
throw new Error('Devtools package.json must contain a JSON object.');
|
|
42
41
|
}
|
|
43
42
|
const readme = await readFile(resolve(targetDirectory, 'README.md'), 'utf8');
|
|
44
|
-
const workflowPolicy = await createWorkflowPolicyAsync(targetDirectory
|
|
43
|
+
const workflowPolicy = await createWorkflowPolicyAsync(targetDirectory);
|
|
45
44
|
return [
|
|
46
45
|
{
|
|
47
46
|
relativePath: 'package.json',
|
|
48
|
-
contents: serializePackageManifest(applyBunRuntimePolicy(manifest
|
|
47
|
+
contents: serializePackageManifest(applyBunRuntimePolicy(manifest)),
|
|
49
48
|
},
|
|
50
49
|
{
|
|
51
50
|
relativePath: '.github/workflows/ci.yml',
|
|
@@ -61,18 +60,18 @@ async function createManagedDefinitionsAsync(targetDirectory, policy) {
|
|
|
61
60
|
},
|
|
62
61
|
{
|
|
63
62
|
relativePath: 'README.md',
|
|
64
|
-
contents: renderBunPolicyDocumentation(readme
|
|
63
|
+
contents: renderBunPolicyDocumentation(readme),
|
|
65
64
|
},
|
|
66
65
|
];
|
|
67
66
|
}
|
|
68
67
|
/*** Build the self-hosted workflow policy used by Devtools owner synchronization. */
|
|
69
|
-
async function createWorkflowPolicyAsync(targetDirectory
|
|
68
|
+
async function createWorkflowPolicyAsync(targetDirectory) {
|
|
70
69
|
return {
|
|
71
70
|
apmReleaseCommand: await resolveApmReleaseCommandAsync(targetDirectory),
|
|
72
71
|
structureReleaseCommand: await resolveStructureReleaseCommandAsync(targetDirectory),
|
|
73
|
-
bunVersion:
|
|
72
|
+
bunVersion: REPOSITORY_POLICY.runtime.bun.version,
|
|
74
73
|
doctorVersion: readCurrentDoctorVersion(),
|
|
75
|
-
nodeVersion:
|
|
74
|
+
nodeVersion: REPOSITORY_POLICY.runtime.node.setupVersion,
|
|
76
75
|
};
|
|
77
76
|
}
|
|
78
77
|
/*** Return owner-managed artifact paths whose current bytes differ from policy output. */
|
|
@@ -95,25 +94,6 @@ function isNodeError(error) {
|
|
|
95
94
|
function isRecord(value) {
|
|
96
95
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
97
96
|
}
|
|
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
97
|
/*** Synchronize or validate the target Bun lockfile through Bun itself. */
|
|
118
98
|
async function runBunLockfileAsync(operation, targetDirectory) {
|
|
119
99
|
const args = [
|
|
@@ -155,5 +135,3 @@ async function syncDefinitionsAsync(targetDirectory, definitions) {
|
|
|
155
135
|
await writeFile(targetPath, contents, 'utf8');
|
|
156
136
|
}
|
|
157
137
|
}
|
|
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 canonical 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 { REPOSITORY_POLICY } from '@ankhorage/policy/repository';
|
|
2
|
+
/*** Apply the canonical 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'] = REPOSITORY_POLICY.runtime.bun.typesRange;
|
|
4
6
|
return {
|
|
5
7
|
...manifest,
|
|
6
|
-
packageManager:
|
|
8
|
+
packageManager: REPOSITORY_POLICY.runtime.bun.packageManager,
|
|
7
9
|
devDependencies,
|
|
8
10
|
};
|
|
9
11
|
}
|
|
@@ -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 { REPOSITORY_POLICY } from '@ankhorage/policy/repository';
|
|
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,11 +10,12 @@ 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() {
|
|
18
|
+
const policy = REPOSITORY_POLICY.runtime.bun;
|
|
17
19
|
return `\`\`\`text
|
|
18
20
|
Bun runtime ${policy.version}
|
|
19
21
|
packageManager ${policy.packageManager}
|
|
@@ -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) {
|
|
@@ -7,7 +7,7 @@
|
|
|
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 policy
|
|
10
|
+
* The Bun runtime policy comes from @ankhorage/policy for every repository, including devtools itself. Devtools skips
|
|
11
11
|
* only its consumer dependency/script normalization so it never attempts to install itself.
|
|
12
12
|
*
|
|
13
13
|
* Status compares only the fields owned by this contract, so unrelated repository customization
|
|
@@ -19,9 +19,8 @@
|
|
|
19
19
|
import { existsSync, readFileSync } from 'node:fs';
|
|
20
20
|
import { readFile, writeFile } from 'node:fs/promises';
|
|
21
21
|
import { resolve } from 'node:path';
|
|
22
|
+
import { REPOSITORY_POLICY } from '@ankhorage/policy/repository';
|
|
22
23
|
import { applyBunRuntimePolicy } from '../../policy/applyBunRuntimePolicy.js';
|
|
23
|
-
import { bunRuntimePolicy } from '../../policy/bunRuntimePolicy.js';
|
|
24
|
-
import { changesetsPolicy } from '../../policy/changesetsPolicy.js';
|
|
25
24
|
const PACKAGE_PATH = 'package.json';
|
|
26
25
|
const DEVTOOLS_PACKAGE_NAME = '@ankhorage/devtools';
|
|
27
26
|
const BUN_TYPES_PACKAGE_NAME = '@types/bun';
|
|
@@ -85,26 +84,26 @@ export async function syncPackageManifest(targetDirectory, devtoolsVersion, opti
|
|
|
85
84
|
/*** Apply the Devtools-owned package scripts, dependencies, and Bun runtime policy. */
|
|
86
85
|
export function applyManagedPackageContract(manifest, devtoolsVersion, changesetsConfigExists = false) {
|
|
87
86
|
if (manifest.name === DEVTOOLS_PACKAGE_NAME) {
|
|
88
|
-
return applyBunRuntimePolicy(manifest
|
|
87
|
+
return applyBunRuntimePolicy(manifest);
|
|
89
88
|
}
|
|
90
89
|
const scripts = { ...toRecord(manifest.scripts) };
|
|
91
90
|
const changesetsEnabled = isChangesetsEnabled(scripts, changesetsConfigExists);
|
|
92
91
|
delete scripts.knip;
|
|
93
92
|
Object.assign(scripts, STANDARD_SCRIPTS);
|
|
94
93
|
if (changesetsEnabled) {
|
|
95
|
-
Object.assign(scripts,
|
|
94
|
+
Object.assign(scripts, REPOSITORY_POLICY.changesets.packageScripts);
|
|
96
95
|
}
|
|
97
96
|
const devDependencies = removeOwnedDependencies(toRecord(manifest.devDependencies));
|
|
98
97
|
const dependencies = toRecord(manifest.dependencies);
|
|
99
|
-
delete dependencies[
|
|
100
|
-
delete devDependencies[
|
|
98
|
+
delete dependencies[REPOSITORY_POLICY.changesets.packageName];
|
|
99
|
+
delete devDependencies[REPOSITORY_POLICY.changesets.packageName];
|
|
101
100
|
applyDevtoolsDependencyPlacement(dependencies, devDependencies, devtoolsVersion);
|
|
102
101
|
return applyBunRuntimePolicy({
|
|
103
102
|
...manifest,
|
|
104
103
|
...normalizedDependencies(manifest, dependencies),
|
|
105
104
|
scripts,
|
|
106
105
|
devDependencies,
|
|
107
|
-
}
|
|
106
|
+
});
|
|
108
107
|
}
|
|
109
108
|
/*** Check whether the Devtools-owned package manifest fields match current policy. */
|
|
110
109
|
export function isManagedPackageContractCurrent(manifest, devtoolsVersion, changesetsConfigExists = false) {
|
|
@@ -120,8 +119,8 @@ export function isManagedPackageContractCurrent(manifest, devtoolsVersion, chang
|
|
|
120
119
|
const changesetsEnabled = isChangesetsEnabled(scripts, changesetsConfigExists);
|
|
121
120
|
return (hasStandardScripts(scripts) &&
|
|
122
121
|
DEVTOOLS_OWNED_DEV_DEPENDENCIES.every((name) => devDependencies[name] === undefined) &&
|
|
123
|
-
dependencies[
|
|
124
|
-
devDependencies[
|
|
122
|
+
dependencies[REPOSITORY_POLICY.changesets.packageName] === undefined &&
|
|
123
|
+
devDependencies[REPOSITORY_POLICY.changesets.packageName] === undefined &&
|
|
125
124
|
hasCurrentChangesetsScripts(scripts, changesetsEnabled) &&
|
|
126
125
|
hasCurrentDevtoolsDependencyPlacement(dependencies, devDependencies, devtoolsVersion));
|
|
127
126
|
}
|
|
@@ -154,8 +153,8 @@ async function readPackageManifest(targetDirectory) {
|
|
|
154
153
|
/*** Check the Bun package manager and Bun type dependency contract. */
|
|
155
154
|
function hasCurrentBunRuntimePolicy(manifest) {
|
|
156
155
|
const devDependencies = toRecord(manifest.devDependencies);
|
|
157
|
-
return (manifest.packageManager ===
|
|
158
|
-
devDependencies[BUN_TYPES_PACKAGE_NAME] ===
|
|
156
|
+
return (manifest.packageManager === REPOSITORY_POLICY.runtime.bun.packageManager &&
|
|
157
|
+
devDependencies[BUN_TYPES_PACKAGE_NAME] === REPOSITORY_POLICY.runtime.bun.typesRange);
|
|
159
158
|
}
|
|
160
159
|
/*** Place Devtools in development dependencies for every consuming repository. */
|
|
161
160
|
function applyDevtoolsDependencyPlacement(dependencies, devDependencies, devtoolsVersion) {
|
|
@@ -188,12 +187,12 @@ function hasStandardScripts(scripts) {
|
|
|
188
187
|
/*** Check Changesets scripts when the repository participates in Changesets. */
|
|
189
188
|
function hasCurrentChangesetsScripts(scripts, changesetsEnabled) {
|
|
190
189
|
return (!changesetsEnabled ||
|
|
191
|
-
Object.entries(
|
|
190
|
+
Object.entries(REPOSITORY_POLICY.changesets.packageScripts).every(([name, command]) => scripts[name] === command));
|
|
192
191
|
}
|
|
193
192
|
/*** Determine whether the repository participates in Changesets synchronization. */
|
|
194
193
|
function isChangesetsEnabled(scripts, changesetsConfigExists) {
|
|
195
194
|
return (changesetsConfigExists ||
|
|
196
|
-
Object.keys(
|
|
195
|
+
Object.keys(REPOSITORY_POLICY.changesets.packageScripts).some((scriptName) => scripts[scriptName] !== undefined));
|
|
197
196
|
}
|
|
198
197
|
/*** Serialize a package manifest using the repository formatting contract. */
|
|
199
198
|
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
|
|
@@ -1,8 +1,8 @@
|
|
|
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 { bunRuntimePolicy, nodeRuntimePolicy } from '../../policy/bunRuntimePolicy.js';
|
|
6
6
|
import { resolvePkgvizAuditPolicyAsync } from '../../policy/resolvePkgvizAuditPolicyAsync.js';
|
|
7
7
|
import { readCurrentDoctorVersion } from './readCurrentDoctorVersion.js';
|
|
8
8
|
import { renderRenovateConfigAsync } from './renderRenovateConfigAsync.js';
|
|
@@ -38,9 +38,9 @@ function createWorkflowDefinition(relativePath, sourcePath) {
|
|
|
38
38
|
render: async (targetDirectory) => await renderWorkflowAsync(sourceUrl, {
|
|
39
39
|
apmReleaseCommand: await resolveApmReleaseCommandAsync(targetDirectory),
|
|
40
40
|
structureReleaseCommand: await resolveStructureReleaseCommandAsync(targetDirectory),
|
|
41
|
-
bunVersion:
|
|
41
|
+
bunVersion: REPOSITORY_POLICY.runtime.bun.version,
|
|
42
42
|
doctorVersion: readCurrentDoctorVersion(),
|
|
43
|
-
nodeVersion:
|
|
43
|
+
nodeVersion: REPOSITORY_POLICY.runtime.node.setupVersion,
|
|
44
44
|
pkgvizAudit: await resolvePkgvizAuditPolicyAsync(targetDirectory),
|
|
45
45
|
}),
|
|
46
46
|
};
|
|
@@ -53,9 +53,9 @@ function createRenovateWorkflowDefinition() {
|
|
|
53
53
|
render: async (targetDirectory) => await renderRenovateWorkflowAsync(sourceUrl, targetDirectory, {
|
|
54
54
|
apmReleaseCommand: await resolveApmReleaseCommandAsync(targetDirectory),
|
|
55
55
|
structureReleaseCommand: await resolveStructureReleaseCommandAsync(targetDirectory),
|
|
56
|
-
bunVersion:
|
|
56
|
+
bunVersion: REPOSITORY_POLICY.runtime.bun.version,
|
|
57
57
|
doctorVersion: readCurrentDoctorVersion(),
|
|
58
|
-
nodeVersion:
|
|
58
|
+
nodeVersion: REPOSITORY_POLICY.runtime.node.setupVersion,
|
|
59
59
|
}),
|
|
60
60
|
};
|
|
61
61
|
}
|
|
@@ -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')
|
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.0",
|
|
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",
|
|
@@ -146,12 +142,13 @@
|
|
|
146
142
|
"prettier": "^3.9.9",
|
|
147
143
|
"typescript-eslint": "^8.70.1",
|
|
148
144
|
"@ankhorage/contracts": "^22.8.1",
|
|
149
|
-
"typescript": "~6.0.3"
|
|
145
|
+
"typescript": "~6.0.3",
|
|
146
|
+
"@ankhorage/policy": "^0.3.1"
|
|
150
147
|
},
|
|
151
148
|
"devDependencies": {
|
|
152
149
|
"@ankhorage/paradox": "^0.1.26",
|
|
153
150
|
"@ankhorage/ankh": "^0.10.4",
|
|
154
|
-
"@ankhorage/doctor": "0.11.
|
|
151
|
+
"@ankhorage/doctor": "0.11.3",
|
|
155
152
|
"@techstark/opencv-js": "^5.0.0-release.1",
|
|
156
153
|
"@types/bun": "^1.4.1",
|
|
157
154
|
"@types/node": "^26.6.2",
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export declare const bunRuntimePolicy: {
|
|
2
|
-
readonly packageManager: "bun@1.4.2";
|
|
3
|
-
readonly typesRange: "^1.4.1";
|
|
4
|
-
readonly version: "1.4.2";
|
|
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 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Canonical runtime/tooling policies for Ankhorage repositories.
|
|
3
|
-
*
|
|
4
|
-
* Import these from `@ankhorage/devtools/policy` when another package needs to inspect
|
|
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',
|
|
25
|
-
};
|
|
@@ -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
|
-
};
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export const changesetsPolicy = {
|
|
2
|
-
packageName: '@changesets/cli',
|
|
3
|
-
binaryName: 'ankhorage-changeset',
|
|
4
|
-
packageScripts: {
|
|
5
|
-
changeset: 'ankhorage-changeset',
|
|
6
|
-
'changeset:status': 'ankhorage-changeset status --since=origin/main',
|
|
7
|
-
'version-packages': 'ankhorage-changeset version',
|
|
8
|
-
},
|
|
9
|
-
ownerPackageScripts: {
|
|
10
|
-
changeset: 'bun src/cli/bin/changeset.ts',
|
|
11
|
-
'changeset:status': 'bun src/cli/bin/changeset.ts status --since=origin/main',
|
|
12
|
-
'version-packages': 'bun src/cli/bin/changeset.ts version',
|
|
13
|
-
},
|
|
14
|
-
workflowCommands: {
|
|
15
|
-
status: 'bun run changeset:status',
|
|
16
|
-
version: 'bun run version-packages',
|
|
17
|
-
publish: 'bun run changeset -- publish',
|
|
18
|
-
},
|
|
19
|
-
};
|
package/dist/types/bunPolicy.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|