Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9e97efb
Implement managed devtools file synchronization
artiphishle Jul 12, 2026
27c56b1
Add canonical CI workflow
artiphishle Jul 12, 2026
086812a
Add canonical release workflow
artiphishle Jul 12, 2026
97f92e4
Add canonical VS Code settings
artiphishle Jul 12, 2026
2b2ab38
Add canonical VS Code extension recommendations
artiphishle Jul 12, 2026
60e9268
Expose managed workflow definitions
artiphishle Jul 12, 2026
6a58b6a
Expose managed VS Code definitions
artiphishle Jul 12, 2026
4b822ef
Add managed files command runner
artiphishle Jul 12, 2026
e23e8fb
Add devtools sync and status commands
artiphishle Jul 12, 2026
93bcf81
Dispatch managed devtools commands
artiphishle Jul 12, 2026
7381b15
Route managed devtools provider commands
artiphishle Jul 12, 2026
9604483
Restrict binary devtools runner types
artiphishle Jul 12, 2026
5b40372
Publish managed devtools commands and assets
artiphishle Jul 12, 2026
1ab3cff
Move ESLint tooling under src tools
artiphishle Jul 12, 2026
6f83559
Move ESLint types under src tools
artiphishle Jul 12, 2026
035d156
Move ESLint CLI under src tools
artiphishle Jul 12, 2026
1e51091
Move Knip tooling under src tools
artiphishle Jul 12, 2026
bf56e3a
Move Knip CLI under src tools
artiphishle Jul 12, 2026
c106b17
Move Prettier CLI under src tools
artiphishle Jul 12, 2026
0e658f0
Move Prettier config under src tools
artiphishle Jul 12, 2026
e125aae
Use relocated ESLint tooling
artiphishle Jul 12, 2026
2e6ba5a
Use relocated Knip tooling
artiphishle Jul 12, 2026
808fad3
Remove relocated ESLint source
artiphishle Jul 12, 2026
52d53ec
Remove relocated ESLint types
artiphishle Jul 12, 2026
f5f0b1d
Remove relocated Knip source
artiphishle Jul 12, 2026
2769bf7
Remove relocated ESLint CLI
artiphishle Jul 12, 2026
e6779fa
Remove relocated Knip CLI
artiphishle Jul 12, 2026
2ff8dd2
Remove relocated Prettier CLI
artiphishle Jul 12, 2026
cc1a6a2
Remove relocated Prettier config
artiphishle Jul 12, 2026
ca94b6a
Update ESLint tests for tools structure
artiphishle Jul 12, 2026
eec0744
Update Knip tests for tools structure
artiphishle Jul 12, 2026
abb6bab
Cover expanded devtools provider surface
artiphishle Jul 12, 2026
8ad97e1
Cover nested devtools commands
artiphishle Jul 12, 2026
985bc81
Test managed file synchronization
artiphishle Jul 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createConfig } from './dist/eslint.js';
import { createConfig } from './dist/tools/eslint/index.js';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

Expand Down
2 changes: 1 addition & 1 deletion knip.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createKnipConfig } from './src/knip.js';
import { createKnipConfig } from './src/tools/knip/index.js';

export default createKnipConfig({
ignoreFiles: [
Expand Down
33 changes: 19 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@ankhorage/devtools",
"version": "1.1.2",
"description": "Shared Lint and Format Configuration for Ankhorage",
"description": "Shared development tooling and repository standards for Ankhorage",
"license": "MIT",
"homepage": "https://github.com/ankhorage/devtools#readme",
"bugs": {
Expand All @@ -21,39 +21,44 @@
"capabilities": [
"devtools.lint",
"devtools.format",
"devtools.knip"
"devtools.knip",
"devtools.sync",
"devtools.status",
"devtools.workflows.sync",
"devtools.workflows.status",
"devtools.vscode.sync",
"devtools.vscode.status"
]
},
"keywords": [
"typescript",
"eslint",
"prettier",
"knip",
"linting",
"formatting",
"static-analysis",
"github-actions",
"vscode",
"developer-tools"
],
"bin": {
"ankhorage-eslint": "./dist/eslint-cli.js",
"ankhorage-knip": "./dist/knip-cli.js",
"ankhorage-prettier": "./dist/prettier-cli.js"
"ankhorage-eslint": "./dist/tools/eslint/cli.js",
"ankhorage-knip": "./dist/tools/knip/cli.js",
"ankhorage-prettier": "./dist/tools/prettier/cli.js"
},
"exports": {
"./cli": {
"types": "./dist/cli/index.d.ts",
"import": "./dist/cli/index.js"
},
"./eslint": {
"types": "./dist/eslint.d.ts",
"import": "./dist/eslint.js"
"types": "./dist/tools/eslint/index.d.ts",
"import": "./dist/tools/eslint/index.js"
},
"./knip": {
"types": "./dist/knip.d.ts",
"import": "./dist/knip.js"
"types": "./dist/tools/knip/index.d.ts",
"import": "./dist/tools/knip/index.js"
},
"./prettier": {
"require": "./dist/prettier.cjs"
"require": "./dist/tools/prettier/index.cjs"
}
},
"files": [
Expand All @@ -63,7 +68,7 @@
"examples"
],
"scripts": {
"build": "rm -rf dist tsconfig.tsbuildinfo && tsc && cp src/prettier.cjs dist/prettier.cjs",
"build": "rm -rf dist tsconfig.tsbuildinfo && tsc && mkdir -p dist/tools/workflows dist/tools/vscode dist/tools/prettier && cp -R src/tools/workflows/files dist/tools/workflows/files && cp -R src/tools/vscode/files dist/tools/vscode/files && cp src/tools/prettier/index.cjs dist/tools/prettier/index.cjs",
"typecheck": "bun x tsc --noEmit -p tsconfig.test.json",
"doctor": "ankhorage-doctor validate .",
"knip": "knip",
Expand Down
8 changes: 7 additions & 1 deletion src/ankh.provider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import provider from './cli/index.js';
import { getDevtoolsCommands } from './internal/devtoolsCommands.js';

describe('devtools package provider', () => {
it('exposes only the shipped devtools commands and capabilities', () => {
it('exposes the canonical devtools command surface', () => {
const commands = getDevtoolsCommands();

expect(provider.id).toBe('@ankhorage/devtools');
Expand All @@ -21,6 +21,12 @@ describe('devtools package provider', () => {
'lint',
'format',
'knip',
'sync',
'status',
'workflows sync',
'workflows status',
'vscode sync',
'vscode status',
]);
});

Expand Down
6 changes: 5 additions & 1 deletion src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { AnkhRuntimeCommandProvider } from '@ankhorage/ankh';

import { getDevtoolsCommands } from '../internal/devtoolsCommands.js';
import { runDevtoolsCommand } from '../internal/runDevtoolsCommand.js';
import { runManagedDevtoolsCommand } from '../internal/runManagedDevtoolsCommand.js';

const packageVersion = readPackageVersion();
const commands = getDevtoolsCommands();
Expand All @@ -21,7 +22,10 @@ const provider = {
handlers: commands.map((command) => ({
path: [...command.path],
handler: async (request) => {
const result = await runDevtoolsCommand(command, request.argv);
const result =
command.kind === 'binary'
? await runDevtoolsCommand(command, request.argv, { cwd: request.context.cwd })
: await runManagedDevtoolsCommand(command, request.argv, request.context);
return { exitCode: result.exitCode };
},
})),
Expand Down
2 changes: 1 addition & 1 deletion src/eslint.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, expect, it } from 'bun:test';

import { createConfig, defaultRestrictedImports } from './eslint.js';
import { createConfig, defaultRestrictedImports } from './tools/eslint/index.js';

describe('createConfig sanity check', () => {
const baseOptions = {
Expand Down
50 changes: 23 additions & 27 deletions src/internal/devtoolsCommands.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,33 @@ import {
} from './devtoolsCommands.js';

describe('devtools command table', () => {
it('defines the exact provider-backed command surface', () => {
const commands = getDevtoolsCommands();

expect(commands).toEqual([
{
path: ['lint'],
capability: 'devtools.lint',
summary: 'Run the shared ESLint toolchain.',
packageName: 'eslint',
binName: 'eslint',
},
{
path: ['format'],
capability: 'devtools.format',
summary: 'Run the shared Prettier toolchain.',
packageName: 'prettier',
binName: 'prettier',
},
{
path: ['knip'],
capability: 'devtools.knip',
summary: 'Run the shared Knip toolchain.',
packageName: 'knip',
binName: 'knip',
},
it('defines the canonical provider-backed command paths', () => {
expect(getDevtoolsCommands().map((command) => command.path.join(' '))).toEqual([
'lint',
'format',
'knip',
'sync',
'status',
'workflows sync',
'workflows status',
'vscode sync',
'vscode status',
]);
});

it('returns commands by path and rejects unknown commands', () => {
it('returns binary commands by tool name', () => {
expect(getDevtoolsCommand('lint').path).toEqual(['lint']);
expect(findDevtoolsCommandByPath(['format'])?.capability).toBe('devtools.format');
expect(getDevtoolsCommand('format').binName).toBe('prettier');
expect(getDevtoolsCommand('knip').packageName).toBe('knip');
});

it('resolves nested managed commands and rejects unknown paths', () => {
expect(findDevtoolsCommandByPath(['workflows', 'sync'])?.capability).toBe(
'devtools.workflows.sync',
);
expect(findDevtoolsCommandByPath(['vscode', 'status'])?.capability).toBe(
'devtools.vscode.status',
);
expect(findDevtoolsCommandByPath(['unknown'])).toBeNull();
expect(findDevtoolsCommandByPath(['lint', 'extra'])).toBeNull();
});
Expand Down
103 changes: 90 additions & 13 deletions src/internal/devtoolsCommands.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,107 @@
export type DevtoolsToolName = 'format' | 'knip' | 'lint';
export type ManagedConcern = 'all' | 'vscode' | 'workflows';

export interface DevtoolsCommandDefinition {
path: readonly [DevtoolsToolName];
capability: 'devtools.format' | 'devtools.knip' | 'devtools.lint';
summary: string;
packageName: 'eslint' | 'knip' | 'prettier';
binName: 'eslint' | 'knip' | 'prettier';
export interface BinaryDevtoolsCommandDefinition {
readonly kind: 'binary';
readonly path: readonly [DevtoolsToolName];
readonly capability: 'devtools.format' | 'devtools.knip' | 'devtools.lint';
readonly summary: string;
readonly packageName: 'eslint' | 'knip' | 'prettier';
readonly binName: 'eslint' | 'knip' | 'prettier';
}

export interface ManagedDevtoolsCommandDefinition {
readonly kind: 'managed-files';
readonly path: readonly ['sync' | 'status'] | readonly ['workflows' | 'vscode', 'sync' | 'status'];
readonly capability:
| 'devtools.sync'
| 'devtools.status'
| 'devtools.workflows.sync'
| 'devtools.workflows.status'
| 'devtools.vscode.sync'
| 'devtools.vscode.status';
readonly summary: string;
readonly concern: ManagedConcern;
readonly mode: 'sync' | 'status';
}

export type DevtoolsCommandDefinition =
| BinaryDevtoolsCommandDefinition
| ManagedDevtoolsCommandDefinition;

const DEVTOOLS_COMMANDS = [
{
kind: 'binary',
path: ['lint'],
capability: 'devtools.lint',
summary: 'Run the shared ESLint toolchain.',
packageName: 'eslint',
binName: 'eslint',
},
{
kind: 'binary',
path: ['format'],
capability: 'devtools.format',
summary: 'Run the shared Prettier toolchain.',
packageName: 'prettier',
binName: 'prettier',
},
{
kind: 'binary',
path: ['knip'],
capability: 'devtools.knip',
summary: 'Run the shared Knip toolchain.',
packageName: 'knip',
binName: 'knip',
},
{
kind: 'managed-files',
path: ['sync'],
capability: 'devtools.sync',
summary: 'Synchronize all managed repository development files.',
concern: 'all',
mode: 'sync',
},
{
kind: 'managed-files',
path: ['status'],
capability: 'devtools.status',
summary: 'Report drift in all managed repository development files.',
concern: 'all',
mode: 'status',
},
{
kind: 'managed-files',
path: ['workflows', 'sync'],
capability: 'devtools.workflows.sync',
summary: 'Synchronize managed GitHub Actions workflows.',
concern: 'workflows',
mode: 'sync',
},
{
kind: 'managed-files',
path: ['workflows', 'status'],
capability: 'devtools.workflows.status',
summary: 'Report drift in managed GitHub Actions workflows.',
concern: 'workflows',
mode: 'status',
},
{
kind: 'managed-files',
path: ['vscode', 'sync'],
capability: 'devtools.vscode.sync',
summary: 'Synchronize managed VS Code workspace files.',
concern: 'vscode',
mode: 'sync',
},
{
kind: 'managed-files',
path: ['vscode', 'status'],
capability: 'devtools.vscode.status',
summary: 'Report drift in managed VS Code workspace files.',
concern: 'vscode',
mode: 'status',
},
] as const satisfies readonly DevtoolsCommandDefinition[];

export function getDevtoolsCommands(): readonly DevtoolsCommandDefinition[] {
Expand All @@ -39,15 +111,20 @@ export function getDevtoolsCommands(): readonly DevtoolsCommandDefinition[] {
export function findDevtoolsCommandByPath(
path: readonly string[],
): DevtoolsCommandDefinition | null {
if (path.length !== 1) {
return null;
}

return DEVTOOLS_COMMANDS.find((command) => command.path[0] === path[0]) ?? null;
return (
DEVTOOLS_COMMANDS.find(
(command) =>
command.path.length === path.length &&
command.path.every((segment, index) => segment === path[index]),
) ?? null
);
}

export function getDevtoolsCommand(toolName: DevtoolsToolName): DevtoolsCommandDefinition {
const command = DEVTOOLS_COMMANDS.find((candidate) => candidate.path[0] === toolName);
export function getDevtoolsCommand(toolName: DevtoolsToolName): BinaryDevtoolsCommandDefinition {
const command = DEVTOOLS_COMMANDS.find(
(candidate): candidate is BinaryDevtoolsCommandDefinition =>
candidate.kind === 'binary' && candidate.path[0] === toolName,
);

if (command === undefined) {
throw new Error(`Unknown devtools command: ${toolName}`);
Expand Down
Loading
Loading