@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
package/README.md
CHANGED
|
@@ -3,485 +3,70 @@
|
|
|
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
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
## What it owns
|
|
15
|
-
|
|
16
|
-
`@ankhorage/devtools` is the single source of truth for these separate concerns:
|
|
17
|
-
|
|
18
|
-
```text
|
|
19
|
-
src/
|
|
20
|
-
├── cli/
|
|
21
|
-
├── policy/
|
|
22
|
-
└── tools/
|
|
23
|
-
├── agents/
|
|
24
|
-
├── skills/
|
|
25
|
-
├── eslint/
|
|
26
|
-
├── prettier/
|
|
27
|
-
├── knip/
|
|
28
|
-
├── package/
|
|
29
|
-
├── workflows/
|
|
30
|
-
└── vscode/
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
- `policy`: shared repository runtime policy, including the canonical Bun version
|
|
34
|
-
- `changesets`: package-resolved Changesets execution and release command policy
|
|
35
|
-
- `agents`: canonical repository `AGENTS.md` rendered from stable package identity
|
|
36
|
-
- `skills`: immutable Ankhorage-owned repository skills under `.agents/skills/`
|
|
37
|
-
- `eslint`: shared flat ESLint configuration, automatic project profiles, and the bundled ESLint runner
|
|
38
|
-
- `prettier`: shared Prettier configuration and the bundled Prettier runner
|
|
39
|
-
- `knip`: shared Knip configuration helpers and the bundled Knip runner
|
|
40
|
-
- `package`: merge-aware synchronization of the shared `package.json` tooling and Bun runtime contract
|
|
41
|
-
- `workflows`: canonical `.github/workflows/ci.yml` and `release.yml`
|
|
42
|
-
- `vscode`: canonical `.vscode/settings.json` and `extensions.json`
|
|
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. It also owns the Bun runtime version used by Ankhorage repository metadata and managed workflows.
|
|
45
|
-
|
|
46
|
-
## Bootstrap
|
|
47
|
-
|
|
48
|
-
For a repository that does not yet depend on the shared toolchain:
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
bun add -D @ankhorage/devtools
|
|
52
|
-
bunx @ankhorage/ankh devtools sync .
|
|
53
|
-
```
|
|
12
|
+
### CLI
|
|
54
13
|
|
|
55
|
-
|
|
14
|
+
Ankhorage packages expose their command-line interface through `ankh`. Use `ankh --help` to discover available package commands, or run a package command with `--help` for package-specific usage.
|
|
56
15
|
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
The target path is optional and defaults to the current working directory.
|
|
62
|
-
|
|
63
|
-
Synchronization ensures `@ankhorage/devtools` is declared using the version of the provider performing the sync, installs the standard package scripts, applies the managed Bun runtime policy, and removes direct devDependencies for tools/plugins owned by devtools. When package metadata changes, sync runs `bun install` so installed dependencies and `bun.lock` match the synchronized manifest. Unrelated package metadata, dependencies, and scripts are preserved.
|
|
64
|
-
|
|
65
|
-
`devtools sync` does not upgrade the globally installed Bun executable. The managed version applies to repository metadata, Bun types, and GitHub workflows.
|
|
66
|
-
|
|
67
|
-
## Ankh provider
|
|
68
|
-
|
|
69
|
-
The package is discovered under the `devtools` category and exposes these capabilities:
|
|
70
|
-
|
|
71
|
-
- `devtools.apm.sync`
|
|
72
|
-
- `devtools.apm.validate`
|
|
73
|
-
- `devtools.lint`
|
|
74
|
-
- `devtools.changeset`
|
|
75
|
-
- `devtools.format`
|
|
76
|
-
- `devtools.knip`
|
|
77
|
-
- `devtools.sync`
|
|
78
|
-
- `devtools.status`
|
|
79
|
-
- `devtools.agents.sync`
|
|
80
|
-
- `devtools.agents.status`
|
|
81
|
-
- `devtools.skills.sync`
|
|
82
|
-
- `devtools.skills.status`
|
|
83
|
-
- `devtools.eslint.sync`
|
|
84
|
-
- `devtools.eslint.status`
|
|
85
|
-
- `devtools.prettier.sync`
|
|
86
|
-
- `devtools.prettier.status`
|
|
87
|
-
- `devtools.knip.sync`
|
|
88
|
-
- `devtools.knip.status`
|
|
89
|
-
- `devtools.package.sync`
|
|
90
|
-
- `devtools.package.status`
|
|
91
|
-
- `devtools.workflows.sync`
|
|
92
|
-
- `devtools.workflows.status`
|
|
93
|
-
- `devtools.vscode.sync`
|
|
94
|
-
- `devtools.vscode.status`
|
|
95
|
-
|
|
96
|
-
The canonical command prefix is always:
|
|
97
|
-
|
|
98
|
-
```bash
|
|
99
|
-
ankh devtools ...
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
## Tool commands
|
|
16
|
+
```zsh
|
|
17
|
+
# Install the Ankhorage CLI
|
|
18
|
+
bun add --global @ankhorage/ankh
|
|
103
19
|
|
|
104
|
-
|
|
105
|
-
ankh devtools
|
|
106
|
-
ankh devtools lint -- --max-warnings=0 .
|
|
107
|
-
ankh devtools format -- --check .
|
|
108
|
-
ankh devtools knip -- --production
|
|
20
|
+
# Show usage information for devtools
|
|
21
|
+
ankh devtools --help
|
|
109
22
|
```
|
|
110
23
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
- `ankh devtools changeset` → `ankhorage-changeset`
|
|
114
|
-
- `ankh devtools lint` → `ankhorage-eslint`
|
|
115
|
-
- `ankh devtools format` → `ankhorage-prettier`
|
|
116
|
-
- `ankh devtools knip` → `ankhorage-knip`
|
|
117
|
-
|
|
118
|
-
The synchronized package scripts are:
|
|
119
|
-
|
|
120
|
-
```json
|
|
121
|
-
{
|
|
122
|
-
"scripts": {
|
|
123
|
-
"changeset": "ankhorage-changeset",
|
|
124
|
-
"changeset:status": "ankhorage-changeset status --since=origin/main",
|
|
125
|
-
"lint": "ankhorage-eslint . --max-warnings=0",
|
|
126
|
-
"lint:fix": "ankhorage-eslint . --fix --max-warnings=0",
|
|
127
|
-
"format": "ankhorage-prettier --write .",
|
|
128
|
-
"format:check": "ankhorage-prettier --check .",
|
|
129
|
-
"knip:check": "ankhorage-knip",
|
|
130
|
-
"version-packages": "ankhorage-changeset version"
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
## Repository synchronization
|
|
136
|
-
|
|
137
|
-
Synchronize or inspect every managed concern:
|
|
138
|
-
|
|
139
|
-
```bash
|
|
140
|
-
ankh devtools sync .
|
|
141
|
-
ankh devtools status .
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
Synchronize one concern:
|
|
145
|
-
|
|
146
|
-
```bash
|
|
147
|
-
ankh devtools agents sync .
|
|
148
|
-
ankh devtools skills sync .
|
|
149
|
-
ankh devtools eslint sync .
|
|
150
|
-
ankh devtools prettier sync .
|
|
151
|
-
ankh devtools knip sync .
|
|
152
|
-
ankh devtools package sync .
|
|
153
|
-
ankh devtools workflows sync .
|
|
154
|
-
ankh devtools vscode sync .
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
Report one concern:
|
|
158
|
-
|
|
159
|
-
```bash
|
|
160
|
-
ankh devtools agents status .
|
|
161
|
-
ankh devtools skills status .
|
|
162
|
-
ankh devtools eslint status .
|
|
163
|
-
ankh devtools prettier status .
|
|
164
|
-
ankh devtools knip status .
|
|
165
|
-
ankh devtools package status .
|
|
166
|
-
ankh devtools workflows status .
|
|
167
|
-
ankh devtools vscode status .
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
Preview synchronization without writing:
|
|
171
|
-
|
|
172
|
-
```bash
|
|
173
|
-
ankh devtools sync . --dry-run
|
|
174
|
-
ankh devtools agents sync . --dry-run
|
|
175
|
-
ankh devtools skills sync . --dry-run
|
|
176
|
-
ankh devtools eslint sync . --dry-run
|
|
177
|
-
ankh devtools package sync . --dry-run
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
A dry run reports `would create`, `would update`, and `would remove` actions without mutating files. `status` exits with code `1` when managed state has drifted and `0` when it is current.
|
|
181
|
-
|
|
182
|
-
## Synchronization guarantees
|
|
183
|
-
|
|
184
|
-
Synchronization is deterministic and idempotent:
|
|
185
|
-
|
|
186
|
-
- missing managed artifacts are created
|
|
187
|
-
- outdated centrally owned artifacts are updated
|
|
188
|
-
- stale files in Devtools-owned skill trees are removed
|
|
189
|
-
- the managed Bun runtime version is applied consistently to package metadata and workflows
|
|
190
|
-
- Changesets-enabled repositories use the Devtools-owned runner without a direct `@changesets/cli` declaration
|
|
191
|
-
- package changes are followed by `bun install` after all managed files have been written, keeping installed dependencies and `bun.lock` synchronized without invalidating the running sync
|
|
192
|
-
- current artifacts are left untouched
|
|
193
|
-
- unrelated files and package fields are preserved
|
|
194
|
-
- repeated sync produces only `unchanged` results
|
|
195
|
-
- invalid target paths and write failures return a non-zero exit code
|
|
196
|
-
- create-only repository extension files are never overwritten after creation
|
|
24
|
+
### Standalone package ESLint configuration
|
|
197
25
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
## Managed agent instructions
|
|
201
|
-
|
|
202
|
-
`ankh devtools agents sync` owns the repository-root `AGENTS.md` plus `CLAUDE.md` and `GEMINI.md` as symbolic links to that canonical file. The shared instructions are intentionally small and stable. The target repository's package name and description are rendered from `package.json`; the remaining content defines the unconditional current-architecture policy, directs structural work to the managed project-structure skill, and requires the canonical build, type, lint, Knip, Changeset, and formatting commands before pull request creation.
|
|
203
|
-
|
|
204
|
-
Only the current Ankhorage architecture is supported. Managed instructions reject deprecated APIs, compatibility aliases, shims, dual old/new paths, historical-state fallbacks, and migrations whose sole purpose is obsolete state. A canonical cross-package change requires affected repositories to update to the latest released public API.
|
|
205
|
-
|
|
206
|
-
Every Devtools-managed repository is standalone: its own checkout must be sufficient to install, build, test, and use it with declared dependencies and explicit configuration. Published packages are additionally consumer-agnostic and reusable outside Ankhorage. Sibling repositories/source imports, unpublished workspace/file/link coupling, hidden organization-local state, and hard assumptions about a consuming app, infrastructure, hosting provider, web server, container runtime, or deployment topology are architecture debt rather than supported exceptions.
|
|
207
|
-
|
|
208
|
-
## Managed repository skills
|
|
209
|
-
|
|
210
|
-
`ankh devtools skills sync` owns the complete `.agents/skills/ankhorage-coding-rules/`, `.agents/skills/hexagonal-architecture/`, and `.agents/skills/ankhorage-project-structure/` trees from the immutable copies shipped in the Devtools release. It creates `.agents/` when missing, replaces stale files in those managed skills, and preserves every unrelated skill directory. The project-structure skill requires both the coding-rules and hexagonal-architecture skills before structural work can continue.
|
|
211
|
-
|
|
212
|
-
`.agents/.devtools-manifest.json` records the source Devtools version and SHA-256 hashes for every managed skill file. That ownership record allows status and dry-run to report drift and lets later releases remove stale owned files without deleting repository-owned skills.
|
|
213
|
-
|
|
214
|
-
Agent Skill scripts are always TypeScript files with a `.ts` extension and run with Bun. JavaScript skill scripts using `.js`, `.mjs`, or `.cjs` are not supported.
|
|
215
|
-
|
|
216
|
-
## ESLint profiles
|
|
217
|
-
|
|
218
|
-
`createConfig()` defaults to `profile: 'auto'`.
|
|
219
|
-
|
|
220
|
-
Automatic detection reads the consuming repository's `package.json` and delegates project trait detection to `@ankhorage/project-detector`. Dependency signals are considered across `dependencies`, `devDependencies`, and `peerDependencies`.
|
|
221
|
-
|
|
222
|
-
Profile precedence is:
|
|
223
|
-
|
|
224
|
-
```text
|
|
225
|
-
React Native / Expo
|
|
226
|
-
↓
|
|
227
|
-
react-native
|
|
228
|
-
↓ includes
|
|
229
|
-
react
|
|
230
|
-
↓ includes
|
|
231
|
-
base
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
A React or Next.js project selects `react`. A React Native or Expo project selects `react-native`. Everything else selects `base`.
|
|
235
|
-
|
|
236
|
-
An unusual repository can opt out of automatic selection:
|
|
26
|
+
Configure ESLint for a standalone TypeScript package with the Devtools shared policy.
|
|
237
27
|
|
|
238
28
|
```js
|
|
239
|
-
import { createConfig } from '@ankhorage/devtools/eslint';
|
|
240
|
-
|
|
241
29
|
export default createConfig({
|
|
242
|
-
|
|
243
|
-
profile: 'base',
|
|
30
|
+
tsconfigRootDir: __dirname,
|
|
244
31
|
project: ['./tsconfig.json'],
|
|
245
|
-
|
|
32
|
+
files: ['src/**/*.{ts,tsx}'],
|
|
246
33
|
});
|
|
247
34
|
```
|
|
248
35
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
- maximum 50 effective lines per function
|
|
252
|
-
- maximum 300 effective lines per file
|
|
253
|
-
- modified cyclomatic complexity maximum 15
|
|
254
|
-
- security review for dynamic object access
|
|
255
|
-
- rejection of non-literal `require()` calls
|
|
256
|
-
|
|
257
|
-
The React profile adds React and React Hooks correctness rules. The React Native profile composes the React profile and adds the selected React Native style rules.
|
|
258
|
-
|
|
259
|
-
### Managed ESLint setup and local overrides
|
|
260
|
-
|
|
261
|
-
`ankh devtools eslint sync` centrally owns `eslint.config.mjs` and creates `eslint.local.config.mjs` once. When the repository has a root `examples/` directory, synchronization also owns `eslint.examples.config.mjs`; repositories without public examples do not receive that file, and synchronization removes the managed wrapper when the directory is removed.
|
|
262
|
-
|
|
263
|
-
The canonical wrapper uses automatic profile detection and appends repository-owned flat-config entries:
|
|
264
|
-
|
|
265
|
-
```js
|
|
266
|
-
import { createConfig } from '@ankhorage/devtools/eslint';
|
|
267
|
-
import localConfig from './eslint.local.config.mjs';
|
|
268
|
-
|
|
269
|
-
const localEntries = Array.isArray(localConfig) ? localConfig : [localConfig];
|
|
270
|
-
|
|
271
|
-
export default [
|
|
272
|
-
...createConfig({
|
|
273
|
-
files: ['src/**/*.{ts,tsx}'],
|
|
274
|
-
project: ['./tsconfig.json'],
|
|
275
|
-
tsconfigRootDir: import.meta.dirname,
|
|
276
|
-
}),
|
|
277
|
-
...localEntries,
|
|
278
|
-
];
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
Use `eslint.local.config.mjs` for narrow repository-specific flat-config overrides, including temporary file-specific migration overrides. On first synchronization, an existing non-canonical `eslint.config.mjs` is preserved as the initial local config before the canonical wrapper is installed. Synchronization never overwrites that local file afterward.
|
|
36
|
+
This package contains 1 additional example. See the generated documentation for the complete set.
|
|
282
37
|
|
|
283
|
-
|
|
38
|
+
## Configuration
|
|
284
39
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
Repositories can lint their independently runnable examples explicitly:
|
|
288
|
-
|
|
289
|
-
```bash
|
|
290
|
-
ankhorage-eslint examples --config eslint.examples.config.mjs --max-warnings=0
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
## Prettier
|
|
294
|
-
|
|
295
|
-
`ankh devtools prettier sync` owns `.prettierrc.js`, emits the correct ESM or CommonJS wrapper based on the repository's `package.json` module type, and creates `prettier.local.config.js` once for narrow repository-specific options.
|
|
296
|
-
|
|
297
|
-
The consumer delegates formatting policy to:
|
|
298
|
-
|
|
299
|
-
```text
|
|
300
|
-
@ankhorage/devtools/prettier
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
The wrapper merges shared and local `overrides` in that order. On first synchronization, an existing non-canonical `.prettierrc.js` is preserved as `prettier.local.config.js`; former shared-only Devtools delegates become an empty local config. Later synchronization never overwrites the local file.
|
|
304
|
-
|
|
305
|
-
## Knip
|
|
306
|
-
|
|
307
|
-
`ankh devtools knip sync` bootstraps `knip.config.ts` with:
|
|
40
|
+
### Example
|
|
308
41
|
|
|
309
42
|
```ts
|
|
310
|
-
import {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
It owns:
|
|
338
|
-
|
|
339
|
-
- the `@ankhorage/devtools` dependency version range
|
|
340
|
-
- removal of direct consumer `@changesets/cli` dependencies
|
|
341
|
-
- `packageManager` according to the managed Bun runtime policy
|
|
342
|
-
- the `@types/bun` development dependency according to the managed Bun runtime policy
|
|
343
|
-
- `lint`
|
|
344
|
-
- `lint:fix`
|
|
345
|
-
- `format`
|
|
346
|
-
- `format:check`
|
|
347
|
-
- `knip:check`
|
|
348
|
-
- `changeset`, `changeset:status`, and `version-packages` for Changesets-enabled repositories
|
|
349
|
-
|
|
350
|
-
For normal consumers, `@ankhorage/devtools` is a devDependency. `@ankhorage/ankh` keeps devtools as a runtime dependency because it loads the provider. Devtools itself participates in the Bun runtime policy without attempting to install itself as a consumer dependency.
|
|
351
|
-
|
|
352
|
-
When this managed package contract changes, synchronization runs `bun install`. This updates installed dependencies and `bun.lock` before sync completes. It also removes direct dependencies for Changesets and direct devDependencies for tools and ESLint plugins already provided by `@ankhorage/devtools`. Unrelated scripts, dependencies, metadata, and repository-specific configuration remain unchanged.
|
|
353
|
-
|
|
354
|
-
A repository participates in Changesets synchronization when `.changeset/config.json` exists or any of the canonical `changeset`, `changeset:status`, or `version-packages` script keys is present. This explicit rule migrates partially configured repositories while ensuring repositories without Changesets do not acquire release tooling. The repository continues to own `.changeset/config.json`, pending `.changeset/*.md` files, and its package release semantics. Direct `@changesets/cli` declarations, ambient `changeset` scripts, and `bunx changeset` workflow commands are not supported consumer forms.
|
|
355
|
-
|
|
356
|
-
## Managed GitHub Actions workflows
|
|
357
|
-
|
|
358
|
-
`workflows` owns exactly:
|
|
359
|
-
|
|
360
|
-
```text
|
|
361
|
-
.github/workflows/ci.yml
|
|
362
|
-
.github/workflows/renovate.yml
|
|
363
|
-
.github/workflows/release.yml
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
CI and Release render their `bun-version` from the same managed Bun runtime policy used for `package.json`. They also render Changesets status, version, and publish commands from the same policy that owns the synchronized package scripts. 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
|
-
|
|
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
|
-
|
|
370
|
-
The Renovate workflow accepts only same-repository branches created by `renovate[bot]`. It calls the SHA-pinned `ankhorage/renovate` workflow to add a release Changeset for runtime Ankhorage dependency updates or an empty Changeset for dev-only updates. The trusted workflow scopes the Ankhorage Renovate Sync GitHub App token to the current repository and uses it only for the validated commit, allowing every normal pull-request CI workflow to start without manual approval. It never checks out or executes pull-request code in the privileged `pull_request_target` context.
|
|
371
|
-
|
|
372
|
-
## Managed VS Code configuration
|
|
373
|
-
|
|
374
|
-
`vscode` owns exactly:
|
|
375
|
-
|
|
376
|
-
```text
|
|
377
|
-
.vscode/settings.json
|
|
378
|
-
.vscode/extensions.json
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
Unknown workflow and VS Code files are never deleted.
|
|
382
|
-
|
|
383
|
-
## Adding another managed concern
|
|
384
|
-
|
|
385
|
-
A new concern should:
|
|
386
|
-
|
|
387
|
-
1. live in its own sibling directory under `src/tools`
|
|
388
|
-
2. define only the files and behavior it owns
|
|
389
|
-
3. expose deterministic status and synchronization
|
|
390
|
-
4. add provider commands under `ankh devtools`
|
|
391
|
-
5. include dry-run, status, and idempotence coverage
|
|
392
|
-
6. document its central ownership and repository-owned extension points
|
|
393
|
-
|
|
394
|
-
## Package-owned APM release gates
|
|
395
|
-
|
|
396
|
-
A package opts in through `ankh.apm` in its `package.json`:
|
|
397
|
-
|
|
398
|
-
```json
|
|
399
|
-
{
|
|
400
|
-
"ankh": {
|
|
401
|
-
"apm": { "protocolVersion": 1, "descriptor": "./apm/update.json" }
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
```
|
|
405
|
-
|
|
406
|
-
Include the descriptor in `files` and expose any executable extension with an explicit public
|
|
407
|
-
`exports` subpath. Use the released APM descriptor and extension types from `@ankhorage/apm/types`;
|
|
408
|
-
Devtools does not own or duplicate the protocol. Add `test:apm` to run the owner's deterministic
|
|
409
|
-
source-to-target fixtures, including skipped versions, unsupported old states, idempotency and
|
|
410
|
-
interruption recovery. A no-migration release still declares supported history explicitly and
|
|
411
|
-
can pass without an extension. Absence of metadata is reported as inapplicable, not migration-safe.
|
|
412
|
-
|
|
413
|
-
```sh
|
|
414
|
-
ankh devtools apm sync .
|
|
415
|
-
ankh devtools apm validate . --allow-owner-code --artifact /tmp/reviewed-owner.tgz
|
|
416
|
-
```
|
|
417
|
-
|
|
418
|
-
The standalone `ankhorage-apm-release sync|validate` binary runs the same operations. The public
|
|
419
|
-
`@ankhorage/devtools/apm-release` entrypoint exports `synchronizeApmReleaseDescriptorAsync`,
|
|
420
|
-
`validatePackedApmReleaseAsync` and `validateApmReleaseCandidate`; types are available from
|
|
421
|
-
`@ankhorage/devtools/types`. Programmatic callers can supply `previousDescriptors` to enforce
|
|
422
|
-
unchanged migration checksums and `relatedDescriptors` for cross-owner prerequisites. Owners
|
|
423
|
-
must include historical descriptors in their `test:apm` fixtures where their migrations require them.
|
|
424
|
-
|
|
425
|
-
Validation packs with lifecycle scripts disabled, reads only the packed descriptor, checks owner
|
|
426
|
-
identity, protocol/schema, migration/projection IDs, prerequisite graphs and public extension
|
|
427
|
-
capabilities using APM's canonical validators. Invalid metadata is a failure, not an opt-out.
|
|
428
|
-
`--allow-owner-code` is explicit permission to import the packed extension in a bounded child
|
|
429
|
-
process. The child is **not a security sandbox**; run only trusted owner code. Registry metadata
|
|
430
|
-
alone never grants this permission. Installed dependency resolution uses the repository's
|
|
431
|
-
frozen dependency graph; the package's own code is loaded through native public export resolution
|
|
432
|
-
from the extracted archive, never from the source checkout.
|
|
433
|
-
|
|
434
|
-
`--artifact` creates a new file containing exactly the validated bytes and refuses an existing
|
|
435
|
-
output. The JSON result includes SHA-512 integrity; `--expected-integrity` refuses a different
|
|
436
|
-
archive. Keep the retained archive immutable. The managed release workflow versions with
|
|
437
|
-
Changesets, synchronizes descriptor identity, rebuilds, runs `test:apm`, validates a fresh archive,
|
|
438
|
-
and publishes that same archive using `npm publish --ignore-scripts`, without repacking.
|
|
439
|
-
Authentication and network errors are not treated as an unpublished version. Packages without
|
|
440
|
-
APM metadata retain their existing Changesets publication path.
|
|
441
|
-
|
|
442
|
-
Producer order is: released APM protocol, validated owner package release, then consumer rollout.
|
|
443
|
-
Never declare an unpublished owner version. Project migration recovery is owned by APM and the
|
|
444
|
-
package's declared handlers; passing this release gate does not execute migrations against user
|
|
445
|
-
projects, deploy production services, or prove compatibility with shipped native binaries.
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
## CLI
|
|
449
|
-
|
|
450
|
-
Run and synchronize the shared development toolchain through the Ankh CLI.
|
|
451
|
-
|
|
452
|
-
`ankh devtools changeset`, `ankh devtools lint`, `ankh devtools format`, and
|
|
453
|
-
`ankh devtools knip` execute the bundled Changesets, ESLint, Prettier, and Knip versions.
|
|
454
|
-
Repository synchronization is available through
|
|
455
|
-
`ankh devtools sync` and `ankh devtools status`, with focused `agents`, `skills`, `eslint`,
|
|
456
|
-
`prettier`, `knip`, `package`, `workflows`, and `vscode` sync/status subcommands.
|
|
457
|
-
Owner packages can opt into deterministic structural metadata with
|
|
458
|
-
`ankh devtools structure build` and verify committed evidence with `ankh devtools structure check`.
|
|
459
|
-
|
|
460
|
-
Sync commands accept an optional target directory and `--dry-run`. Aggregate sync is
|
|
461
|
-
deterministic and idempotent: canonical managed files and skill trees are created or updated,
|
|
462
|
-
unrelated repository-local skills and create-only local extension files remain repository-owned,
|
|
463
|
-
and package metadata is merge-updated without replacing unrelated fields.
|
|
464
|
-
|
|
465
|
-
Fresh repositories can bootstrap the standard setup with `ankh devtools sync .` after adding
|
|
466
|
-
`@ankhorage/devtools`. Existing ESLint configuration is preserved during first migration as a
|
|
467
|
-
local extension before the canonical auto-detecting wrapper is installed.
|
|
468
|
-
|
|
469
|
-
APM owner releases opt in through `ankh.apm`. `ankh devtools apm sync .` binds a valid
|
|
470
|
-
descriptor to the selected Changesets version. `ankh devtools apm validate .` checks a
|
|
471
|
-
script-free tarball; `--allow-owner-code` explicitly permits the isolated executable probe.
|
|
472
|
-
`--artifact <path>` retains the exact accepted tarball and `--expected-integrity <SRI>`
|
|
473
|
-
rejects changed bytes. Owners provide `test:apm` for source-to-target and recovery fixtures.
|
|
474
|
-
CI runs that owner suite and the packed check. Release rebuilds after versioning, validates,
|
|
475
|
-
then publishes the retained archive with scripts disabled through the existing release job.
|
|
476
|
-
Packages without metadata keep their existing Changesets publish path unchanged.
|
|
477
|
-
|
|
478
|
-
```bash
|
|
479
|
-
bunx @ankhorage/devtools ankhorage-apm-release
|
|
480
|
-
bunx @ankhorage/devtools ankhorage-changeset
|
|
481
|
-
bunx @ankhorage/devtools ankhorage-eslint
|
|
482
|
-
bunx @ankhorage/devtools ankhorage-knip
|
|
483
|
-
bunx @ankhorage/devtools ankhorage-prettier
|
|
484
|
-
bunx @ankhorage/devtools ankhorage-structure
|
|
43
|
+
import { readFileSync } from 'node:fs';
|
|
44
|
+
|
|
45
|
+
import { defineParadoxConfig } from '@ankhorage/paradox';
|
|
46
|
+
|
|
47
|
+
import { renderBunPolicyDocumentation } from './src/policy/renderBunPolicyDocumentation.js';
|
|
48
|
+
|
|
49
|
+
export default defineParadoxConfig({
|
|
50
|
+
mode: 'write',
|
|
51
|
+
docs: {
|
|
52
|
+
usage: {
|
|
53
|
+
description: renderBunPolicyDocumentation(
|
|
54
|
+
readFileSync(new URL('./src/cli/usage.md', import.meta.url), 'utf8'),
|
|
55
|
+
),
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
package: {
|
|
59
|
+
root: '.',
|
|
60
|
+
entrypoints: [
|
|
61
|
+
'src/cli/index.ts',
|
|
62
|
+
'src/tools/eslint/index.ts',
|
|
63
|
+
'src/tools/knip/index.ts',
|
|
64
|
+
'src/apmRelease.ts',
|
|
65
|
+
'src/types/public.ts',
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
output: { dir: './paradox' },
|
|
69
|
+
});
|
|
485
70
|
```
|
|
486
71
|
|
|
487
72
|
## Generated documentation
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { runApmReleaseCommandAsync } from '
|
|
2
|
+
import { runApmReleaseCommandAsync } from '../runApmReleaseCommandAsync.js';
|
|
3
3
|
const [operation, ...argv] = process.argv.slice(2);
|
|
4
4
|
if (operation !== 'sync' && operation !== 'validate') {
|
|
5
5
|
console.error('Usage: ankhorage-apm-release <sync|validate> [directory] [--allow-owner-code] [--artifact path] [--expected-integrity value]');
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { runStructureGenerationCommandAsync } from '
|
|
2
|
+
import { runStructureGenerationCommandAsync } from '../runStructureGenerationCommandAsync.js';
|
|
3
3
|
const [operation, ...argv] = process.argv.slice(2);
|
|
4
4
|
if (operation !== 'build' && operation !== 'check') {
|
|
5
5
|
console.error('Usage: ankhorage-structure <build|check> [directory]');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { runApmReleaseCommandAsync } from '
|
|
1
|
+
import { runApmReleaseCommandAsync } from '../../runApmReleaseCommandAsync.js';
|
|
2
2
|
/*** Adapt the public APM release sync command to the shared release boundary. */
|
|
3
3
|
export async function sync(argv, context) {
|
|
4
4
|
return runApmReleaseCommandAsync('sync', argv, context);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { runApmReleaseCommandAsync } from '
|
|
1
|
+
import { runApmReleaseCommandAsync } from '../../runApmReleaseCommandAsync.js';
|
|
2
2
|
/*** Adapt the public APM release validate command to the shared release boundary. */
|
|
3
3
|
export async function validate(argv, context) {
|
|
4
4
|
return runApmReleaseCommandAsync('validate', argv, context);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { runStructureGenerationCommandAsync } from '
|
|
1
|
+
import { runStructureGenerationCommandAsync } from '../../runStructureGenerationCommandAsync.js';
|
|
2
2
|
/*** Adapt the public structure build command to deterministic owner artifact generation. */
|
|
3
3
|
export async function build(argv, context) {
|
|
4
4
|
return runStructureGenerationCommandAsync('build', argv, context);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { runStructureGenerationCommandAsync } from '
|
|
1
|
+
import { runStructureGenerationCommandAsync } from '../../runStructureGenerationCommandAsync.js';
|
|
2
2
|
/*** Adapt the public structure check command to deterministic owner artifact verification. */
|
|
3
3
|
export async function check(argv, context) {
|
|
4
4
|
return runStructureGenerationCommandAsync('check', argv, context);
|
package/dist/{features/apm-release-validation/adapters/inbound → cli}/runApmReleaseCommandAsync.js
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolve } from 'node:path';
|
|
2
|
-
import { synchronizeApmReleaseDescriptorAsync } from '
|
|
3
|
-
import { validatePackedApmReleaseAsync } from '
|
|
2
|
+
import { synchronizeApmReleaseDescriptorAsync } from '../features/apm-release-validation/composition/synchronizeApmReleaseDescriptorAsync.js';
|
|
3
|
+
import { validatePackedApmReleaseAsync } from '../features/apm-release-validation/composition/validatePackedApmReleaseAsync.js';
|
|
4
4
|
/*** Parse release CLI input and report the same structured validation result on every entrypoint. */
|
|
5
5
|
export async function runApmReleaseCommandAsync(operation, argv, context) {
|
|
6
6
|
try {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { resolve } from 'node:path';
|
|
2
|
-
import { synchronizeStructureArtifactForDirectoryAsync } from '
|
|
2
|
+
import { synchronizeStructureArtifactForDirectoryAsync } from '../features/structure-descriptor-generation/composition/synchronizeStructureArtifactForDirectoryAsync.js';
|
|
3
3
|
/*** Parse structure build/check CLI input and emit one machine-readable result. */
|
|
4
4
|
export async function runStructureGenerationCommandAsync(operation, argv, context) {
|
|
5
5
|
try {
|
|
@@ -1,43 +1,12 @@
|
|
|
1
|
-
import { bunRuntimePolicy } from '../policy/bunRuntimePolicy.js';
|
|
2
1
|
const REQUIRED_README_SNIPPETS = [
|
|
3
|
-
'
|
|
4
|
-
'
|
|
5
|
-
'
|
|
6
|
-
'ankh devtools
|
|
7
|
-
'
|
|
8
|
-
'
|
|
9
|
-
'
|
|
10
|
-
'
|
|
11
|
-
'ankh devtools eslint sync',
|
|
12
|
-
'ankh devtools prettier sync',
|
|
13
|
-
'ankh devtools knip sync',
|
|
14
|
-
'ankh devtools package sync',
|
|
15
|
-
'ankh devtools workflows sync',
|
|
16
|
-
'ankh devtools vscode sync',
|
|
17
|
-
'devtools.eslint.sync',
|
|
18
|
-
'devtools.agents.sync',
|
|
19
|
-
'devtools.skills.sync',
|
|
20
|
-
'ankhorage-coding-rules',
|
|
21
|
-
'hexagonal-architecture',
|
|
22
|
-
'devtools.prettier.sync',
|
|
23
|
-
'devtools.knip.sync',
|
|
24
|
-
'devtools.package.sync',
|
|
25
|
-
'devtools.workflows.sync',
|
|
26
|
-
'devtools.vscode.sync',
|
|
27
|
-
'--dry-run',
|
|
28
|
-
"profile: 'auto'",
|
|
29
|
-
'@ankhorage/project-detector',
|
|
30
|
-
'ankhorage-changeset',
|
|
31
|
-
'without creating a second Version Packages pull request',
|
|
32
|
-
'chore(release)',
|
|
33
|
-
'.changeset/config.json',
|
|
34
|
-
'<!-- devtools-bun-policy:start -->',
|
|
35
|
-
'<!-- devtools-bun-policy:end -->',
|
|
36
|
-
'bun scripts/sync-renovate-owner.ts sync repository',
|
|
37
|
-
'bun scripts/sync-renovate-owner.ts status',
|
|
38
|
-
bunRuntimePolicy.version,
|
|
39
|
-
bunRuntimePolicy.packageManager,
|
|
40
|
-
bunRuntimePolicy.typesRange,
|
|
2
|
+
'<!-- This file is generated by Paradox. Do not edit manually. -->',
|
|
3
|
+
'# @ankhorage/devtools',
|
|
4
|
+
'## Usage',
|
|
5
|
+
'ankh devtools --help',
|
|
6
|
+
'Standalone package ESLint configuration',
|
|
7
|
+
'export default createConfig({',
|
|
8
|
+
'## Generated documentation',
|
|
9
|
+
'paradox/index.html',
|
|
41
10
|
];
|
|
42
11
|
export function getReadmeDocumentationErrors(readmeContents) {
|
|
43
12
|
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 Devtools-owned 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 {
|