@ankhorage/devtools 1.1.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +165 -138
  2. package/dist/cli/bin/eslint.js +4 -0
  3. package/dist/cli/bin/knip.js +4 -0
  4. package/dist/cli/bin/prettier.js +4 -0
  5. package/dist/cli/commands.d.ts +25 -0
  6. package/dist/cli/commands.js +92 -0
  7. package/dist/cli/index.d.ts +5 -5
  8. package/dist/cli/index.js +3 -4
  9. package/dist/cli/runExternalTool.d.ts +31 -0
  10. package/dist/{internal/runDevtoolsCommand.js → cli/runExternalTool.js} +3 -3
  11. package/dist/cli/runProviderCommand.d.ts +8 -0
  12. package/dist/cli/runProviderCommand.js +11 -0
  13. package/dist/cli/runRepositoryCommand.d.ts +16 -0
  14. package/dist/cli/runRepositoryCommand.js +108 -0
  15. package/dist/cli/runStandaloneTool.d.ts +3 -0
  16. package/dist/cli/runStandaloneTool.js +5 -0
  17. package/dist/internal/readmeDocs.js +7 -7
  18. package/dist/{eslint.d.ts → tools/eslint/index.d.ts} +1 -0
  19. package/dist/tools/eslint/types.d.ts +18 -0
  20. package/dist/tools/knip/index.d.ts +20 -0
  21. package/dist/tools/shared/managedFiles.d.ts +20 -0
  22. package/dist/tools/shared/managedFiles.js +84 -0
  23. package/dist/tools/vscode/files/extensions.json +9 -0
  24. package/dist/tools/vscode/files/settings.json +15 -0
  25. package/dist/tools/vscode/index.d.ts +7 -0
  26. package/dist/tools/vscode/index.js +10 -0
  27. package/dist/tools/workflows/files/ci.yml +88 -0
  28. package/dist/tools/workflows/files/release.yml +65 -0
  29. package/dist/tools/workflows/index.d.ts +7 -0
  30. package/dist/tools/workflows/index.js +10 -0
  31. package/package.json +21 -15
  32. package/dist/eslint-cli.js +0 -4
  33. package/dist/internal/devtoolsCommands.d.ts +0 -11
  34. package/dist/internal/devtoolsCommands.js +0 -39
  35. package/dist/internal/runDevtoolsCommand.d.ts +0 -31
  36. package/dist/internal/runStandaloneDevtoolsCommand.d.ts +0 -3
  37. package/dist/internal/runStandaloneDevtoolsCommand.js +0 -5
  38. package/dist/knip-cli.js +0 -4
  39. package/dist/knip.d.ts +0 -20
  40. package/dist/prettier-cli.js +0 -4
  41. package/dist/types.d.ts +0 -18
  42. /package/dist/{eslint-cli.d.ts → cli/bin/eslint.d.ts} +0 -0
  43. /package/dist/{knip-cli.d.ts → cli/bin/knip.d.ts} +0 -0
  44. /package/dist/{prettier-cli.d.ts → cli/bin/prettier.d.ts} +0 -0
  45. /package/dist/{eslint.js → tools/eslint/index.js} +0 -0
  46. /package/dist/{types.js → tools/eslint/types.js} +0 -0
  47. /package/dist/{knip.js → tools/knip/index.js} +0 -0
  48. /package/dist/{prettier.cjs → tools/prettier/index.cjs} +0 -0
package/README.md CHANGED
@@ -1,26 +1,29 @@
1
1
  # devtools
2
2
 
3
- Shared ESLint, Prettier, and Knip configuration for modern TypeScript projects.
3
+ Shared development tools and repository standards for Ankhorage TypeScript projects.
4
4
 
5
- ## What you get
5
+ ## What it owns
6
6
 
7
- - Consistent linting across repos
8
- - Zero-config Prettier setup
9
- - Shared Knip static-analysis defaults
10
- - Bundled tool binaries for ESLint, Prettier, and Knip
11
- - Ankh provider commands for lint, format, and Knip
12
- - Strict TypeScript rules without compromise
13
- - One source of truth for tooling
7
+ `@ankhorage/devtools` is the single source of truth for these equal, separate concerns:
14
8
 
15
- ## Features
9
+ ```text
10
+ src/
11
+ ├── cli/
12
+ └── tools/
13
+ ├── eslint/
14
+ ├── prettier/
15
+ ├── knip/
16
+ ├── workflows/
17
+ └── vscode/
18
+ ```
19
+
20
+ - `eslint`: shared flat ESLint configuration and the bundled ESLint runner
21
+ - `prettier`: shared Prettier configuration and the bundled Prettier runner
22
+ - `knip`: shared Knip configuration and the bundled Knip runner
23
+ - `workflows`: canonical `.github/workflows/ci.yml` and `release.yml`
24
+ - `vscode`: canonical `.vscode/settings.json` and `extensions.json`
16
25
 
17
- - Flat ESLint config (latest standard)
18
- - Preconfigured plugin ecosystem
19
- - Prettier integration
20
- - Shared Knip config factories
21
- - `ankhorage-eslint`, `ankhorage-prettier`, and `ankhorage-knip` binaries
22
- - `ankh devtools lint`, `ankh devtools format`, and `ankh devtools knip`
23
- - Monorepo-friendly
26
+ There is no generic template layer around these concerns. Each tool owns its canonical files and behavior.
24
27
 
25
28
  ## Installation
26
29
 
@@ -28,23 +31,43 @@ Shared ESLint, Prettier, and Knip configuration for modern TypeScript projects.
28
31
  bun add -D @ankhorage/devtools
29
32
  ```
30
33
 
31
- The package owns the ESLint, Prettier, and Knip toolchain. Consuming repos should not install `eslint`, `prettier`, or `knip` directly unless they intentionally need a different version from the shared Ankhorage toolchain.
34
+ The package owns the ESLint, Prettier, and Knip versions used by consuming repositories. Do not install those tools directly unless a repository intentionally opts out of the shared Ankhorage toolchain.
35
+
36
+ ## Ankh provider
32
37
 
33
- It also participates in Ankh package discovery with:
38
+ The package is discovered under the `devtools` category and exposes these capabilities:
34
39
 
35
- - category: `devtools`
36
- - capabilities:
37
- - `devtools.lint`
38
- - `devtools.format`
39
- - `devtools.knip`
40
+ - `devtools.lint`
41
+ - `devtools.format`
42
+ - `devtools.knip`
43
+ - `devtools.sync`
44
+ - `devtools.status`
45
+ - `devtools.workflows.sync`
46
+ - `devtools.workflows.status`
47
+ - `devtools.vscode.sync`
48
+ - `devtools.vscode.status`
40
49
 
41
- `@ankhorage/devtools` owns primitive lint/format/knip tooling. Local emulator, app, and workstation workflows belong in `@ankhorage/dev`.
50
+ The canonical command prefix is always:
51
+
52
+ ```bash
53
+ ankh devtools ...
54
+ ```
55
+
56
+ ## Tool commands
57
+
58
+ ```bash
59
+ ankh devtools lint -- --max-warnings=0 .
60
+ ankh devtools format -- --check .
61
+ ankh devtools knip -- --production
62
+ ```
42
63
 
43
- ## Usage
64
+ These commands delegate to the same bundled tools as the package binaries:
44
65
 
45
- ### Scripts
66
+ - `ankh devtools lint` → `ankhorage-eslint`
67
+ - `ankh devtools format` → `ankhorage-prettier`
68
+ - `ankh devtools knip` → `ankhorage-knip`
46
69
 
47
- Use the devtools-owned binaries in package scripts:
70
+ Recommended package scripts:
48
71
 
49
72
  ```json
50
73
  {
@@ -58,165 +81,169 @@ Use the devtools-owned binaries in package scripts:
58
81
  }
59
82
  ```
60
83
 
61
- ### Ankh commands
84
+ ## Repository synchronization
62
85
 
63
- When discovered by `@ankhorage/ankh`, the package exposes:
86
+ ### Synchronize all managed files
64
87
 
65
88
  ```bash
66
- ankh devtools lint -- --max-warnings=0 .
67
- ankh devtools format -- --check .
68
- ankh devtools knip -- --production
89
+ ankh devtools sync .
69
90
  ```
70
91
 
71
- These provider-backed commands delegate to the same underlying tools as the standalone binaries:
92
+ The target path is optional and defaults to the current working directory:
93
+
94
+ ```bash
95
+ ankh devtools sync
96
+ ```
72
97
 
73
- - `ankh devtools lint` -> `ankhorage-eslint`
74
- - `ankh devtools format` -> `ankhorage-prettier`
75
- - `ankh devtools knip` -> `ankhorage-knip`
98
+ ### Report drift without changing files
76
99
 
77
- ### ESLint
100
+ ```bash
101
+ ankh devtools status .
102
+ ```
78
103
 
79
- Create an `eslint.config.js` file:
104
+ `status` exits with code `1` when any managed file is missing or outdated. It exits with code `0` when all managed files are current.
80
105
 
81
- ```js
82
- import { createConfig } from '@ankhorage/devtools/eslint';
106
+ Example output:
83
107
 
84
- export default createConfig({
85
- files: ['src/**/*.{ts,tsx}'],
86
- project: ['./tsconfig.json'],
87
- tsconfigRootDir: import.meta.dirname,
88
- });
108
+ ```text
109
+ .github/workflows/ci.yml
110
+ .github/workflows/release.yml outdated
111
+ + .vscode/settings.json missing
112
+ ✓ .vscode/extensions.json
89
113
  ```
90
114
 
91
- ### Prettier
115
+ ### Synchronize one concern
92
116
 
93
- Create a Prettier config file:
117
+ ```bash
118
+ ankh devtools workflows sync .
119
+ ankh devtools vscode sync .
120
+ ```
94
121
 
95
- ```js
96
- export { default } from '@ankhorage/devtools/prettier';
122
+ ### Report one concern
123
+
124
+ ```bash
125
+ ankh devtools workflows status .
126
+ ankh devtools vscode status .
97
127
  ```
98
128
 
99
- CommonJS repos can use:
129
+ ### Preview synchronization
100
130
 
101
- ```js
102
- module.exports = require('@ankhorage/devtools/prettier');
131
+ ```bash
132
+ ankh devtools sync . --dry-run
133
+ ankh devtools workflows sync . --dry-run
134
+ ankh devtools vscode sync . --dry-run
103
135
  ```
104
136
 
105
- ### Knip
137
+ A dry run reports `would create` and `would update` actions without writing any files.
106
138
 
107
- Create a repo-local `knip.config.ts` file:
139
+ ## Synchronization guarantees
108
140
 
109
- ```ts
110
- import { createKnipConfig } from '@ankhorage/devtools/knip';
141
+ Synchronization is deterministic and idempotent:
111
142
 
112
- export default createKnipConfig();
113
- ```
143
+ - missing managed files are created
144
+ - outdated managed files are replaced with the canonical package version
145
+ - current managed files are left untouched
146
+ - unrelated files are never modified
147
+ - unknown files in `.github/workflows` and `.vscode` are never deleted
148
+ - repeating `sync` after a successful run produces only `unchanged` results
149
+ - invalid target paths and write failures return a non-zero exit code
114
150
 
115
- Repos can add narrow repo-specific patterns when needed:
151
+ The canonical files are packaged with `@ankhorage/devtools`; synchronization does not fetch mutable files from GitHub at runtime.
116
152
 
117
- ```ts
118
- import { createKnipConfig } from '@ankhorage/devtools/knip';
153
+ ## Managed GitHub Actions workflows
119
154
 
120
- export default createKnipConfig({
121
- entry: ['scripts/release.ts'],
122
- project: ['scripts/**/*.ts'],
123
- ignore: ['fixtures/**'],
124
- ignoreBinaries: ['custom-tool'],
125
- ignoreFiles: ['examples/fixture.ts'],
126
- });
155
+ `workflows` owns exactly:
156
+
157
+ ```text
158
+ .github/workflows/ci.yml
159
+ .github/workflows/release.yml
127
160
  ```
128
161
 
129
- For workspaces-based monorepos, use the monorepo preset:
162
+ The CI workflow:
130
163
 
131
- ```ts
132
- import { createKnipMonorepoConfig } from '@ankhorage/devtools/knip';
164
+ - checks out full history
165
+ - installs the pinned Bun version
166
+ - installs dependencies with `bun install --frozen-lockfile`
167
+ - runs `bunx @ankhorage/ankh doctor validate .`
168
+ - conditionally runs build, lint, format check, Knip, tests, and typecheck when scripts exist
169
+ - conditionally runs `changeset:status` for pull requests when the script exists
133
170
 
134
- export default createKnipMonorepoConfig({
135
- root: {
136
- ignoreFiles: ['.prettierrc.js', 'eslint.config.js'],
137
- },
138
- });
139
- ```
171
+ The release workflow:
140
172
 
141
- By default, the monorepo preset configures Knip workspaces for the root package, `packages/*`, and `apps/*`. Repos can override those defaults or add extra workspace globs:
173
+ - checks out full history
174
+ - configures Bun and Node for npm publishing
175
+ - installs dependencies with the frozen lockfile
176
+ - conditionally builds
177
+ - runs the Changesets release PR/publish flow
178
+ - protects release execution with a concurrency group
179
+ - skips cleanly when no Changesets configuration exists
142
180
 
143
- ```ts
144
- import { createKnipMonorepoConfig } from '@ankhorage/devtools/knip';
145
-
146
- export default createKnipMonorepoConfig({
147
- workspaceGlobs: ['packages/*', 'apps/*', 'examples/*'],
148
- workspaceDefaults: {
149
- ignoreFiles: ['fixtures/**'],
150
- },
151
- workspaces: {
152
- '.': {
153
- ignoreFiles: ['.prettierrc.js', 'eslint.config.js'],
154
- },
155
- 'apps/editor': {
156
- ignoreFiles: ['babel.config.js'],
157
- ignoreDependencies: ['babel-preset-expo'],
158
- },
159
- },
160
- });
181
+ ## Managed VS Code configuration
182
+
183
+ `vscode` owns exactly:
184
+
185
+ ```text
186
+ .vscode/settings.json
187
+ .vscode/extensions.json
161
188
  ```
162
189
 
163
- The shared config intentionally keeps defaults narrow so Knip can still report real unused files, exports, dependencies, and binaries. Prefer explicit `entry`, `project`, `ignoreBinaries`, `ignoreDependencies`, or `ignoreFiles` over broad ignores.
190
+ The shared settings use the workspace TypeScript SDK, enable the workspace-SDK prompt, configure intentional ESLint save actions, and enforce basic whitespace/newline consistency.
164
191
 
165
- ### CI
192
+ The extension recommendations are limited to the standard Ankhorage workflow:
166
193
 
167
- Run the scripts in CI after dependencies are installed:
194
+ - Bun
195
+ - ESLint
196
+ - Prettier
197
+ - YAML
198
+ - GitHub Actions
168
199
 
169
- ```yaml
170
- - name: Run lint
171
- run: bun run lint
200
+ `launch.json` is intentionally not managed globally. Libraries, CLIs, Expo packages, services, and integration repositories require different debug configurations.
172
201
 
173
- - name: Run format check
174
- run: bun run format:check
202
+ ## ESLint
175
203
 
176
- - name: Run Knip
177
- run: bun run knip
178
- ```
204
+ Create `eslint.config.mjs`:
179
205
 
180
- For workflows that support optional scripts, use the same guard style as the other devtools checks:
206
+ ```js
207
+ import { createConfig } from '@ankhorage/devtools/eslint';
181
208
 
182
- ```yaml
183
- - name: Run Knip
184
- run: |
185
- if node -e "const p=require('./package.json'); process.exit(p.scripts?.knip ? 0 : 1)"; then
186
- bun run knip
187
- else
188
- echo "No knip script found; skipping."
189
- fi
209
+ export default createConfig({
210
+ files: ['src/**/*.{ts,tsx}'],
211
+ project: ['./tsconfig.json'],
212
+ tsconfigRootDir: import.meta.dirname,
213
+ });
190
214
  ```
191
215
 
192
- ## Use Cases
216
+ ## Prettier
193
217
 
194
- - Monorepos with shared standards
195
- - Teams that want strict, predictable linting
196
- - Projects avoiding duplicated config
197
- - Repos that need consistent unused-file, unused-export, and dependency checks
218
+ ES modules:
198
219
 
199
- ## Why this exists
220
+ ```js
221
+ export { default } from '@ankhorage/devtools/prettier';
222
+ ```
200
223
 
201
- Maintaining ESLint, Prettier, and Knip configs across multiple repositories leads to:
224
+ CommonJS:
202
225
 
203
- - duplication
204
- - inconsistency
205
- - drift over time
226
+ ```js
227
+ module.exports = require('@ankhorage/devtools/prettier');
228
+ ```
229
+
230
+ ## Knip
206
231
 
207
- This package centralizes tooling so all projects stay aligned.
232
+ ```ts
233
+ import { createKnipConfig } from '@ankhorage/devtools/knip';
208
234
 
209
- ## Scope
235
+ export default createKnipConfig();
236
+ ```
210
237
 
211
- Includes:
238
+ Monorepos can use `createKnipMonorepoConfig` and add narrow repository-specific entries, projects, ignores, binaries, dependencies, or workspace overrides.
212
239
 
213
- - ESLint configuration and binary wrapper
214
- - Prettier configuration and binary wrapper
215
- - Knip configuration and binary wrapper
216
- - Ankh provider descriptors and handlers for lint, format, and Knip
240
+ ## Adding another managed concern
217
241
 
218
- Excludes:
242
+ A new concern should:
219
243
 
220
- - runtime code
221
- - build tooling
222
- - local dev workflows
244
+ 1. live in its own sibling directory under `src/tools`
245
+ 2. define only the files and behavior it owns
246
+ 3. expose deterministic status and synchronization through the shared managed-file engine
247
+ 4. add provider commands under `ankh devtools`
248
+ 5. include source-tree, built-package, dry-run, status, and idempotence coverage
249
+ 6. document overwrite and exit-code behavior
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { runStandaloneTool } from '../runStandaloneTool.js';
3
+ const result = await runStandaloneTool('lint', process.argv.slice(2));
4
+ process.exit(result.exitCode);
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { runStandaloneTool } from '../runStandaloneTool.js';
3
+ const result = await runStandaloneTool('knip', process.argv.slice(2));
4
+ process.exit(result.exitCode);
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { runStandaloneTool } from '../runStandaloneTool.js';
3
+ const result = await runStandaloneTool('format', process.argv.slice(2));
4
+ process.exit(result.exitCode);
@@ -0,0 +1,25 @@
1
+ export type DevtoolsToolName = 'format' | 'knip' | 'lint';
2
+ type DevtoolsManagedScope = 'all' | 'vscode' | 'workflows';
3
+ type DevtoolsManagedOperation = 'status' | 'sync';
4
+ type DevtoolsCapability = 'devtools.format' | 'devtools.knip' | 'devtools.lint' | 'devtools.status' | 'devtools.sync' | 'devtools.vscode.status' | 'devtools.vscode.sync' | 'devtools.workflows.status' | 'devtools.workflows.sync';
5
+ interface DevtoolsCommandBase {
6
+ readonly path: readonly [string, ...string[]];
7
+ readonly capability: DevtoolsCapability;
8
+ readonly summary: string;
9
+ }
10
+ export interface DevtoolsExternalCommandDefinition extends DevtoolsCommandBase {
11
+ readonly kind: 'external';
12
+ readonly toolName: DevtoolsToolName;
13
+ readonly packageName: 'eslint' | 'knip' | 'prettier';
14
+ readonly binName: 'eslint' | 'knip' | 'prettier';
15
+ }
16
+ export interface DevtoolsRepositoryCommandDefinition extends DevtoolsCommandBase {
17
+ readonly kind: 'repository';
18
+ readonly scope: DevtoolsManagedScope;
19
+ readonly operation: DevtoolsManagedOperation;
20
+ }
21
+ export type DevtoolsCommandDefinition = DevtoolsExternalCommandDefinition | DevtoolsRepositoryCommandDefinition;
22
+ export declare function getDevtoolsCommands(): readonly DevtoolsCommandDefinition[];
23
+ export declare function findDevtoolsCommandByPath(path: readonly string[]): DevtoolsCommandDefinition | null;
24
+ export declare function getDevtoolsToolCommand(toolName: DevtoolsToolName): DevtoolsExternalCommandDefinition;
25
+ export {};
@@ -0,0 +1,92 @@
1
+ const DEVTOOLS_COMMANDS = [
2
+ {
3
+ kind: 'external',
4
+ toolName: 'lint',
5
+ path: ['lint'],
6
+ capability: 'devtools.lint',
7
+ summary: 'Run the shared ESLint toolchain.',
8
+ packageName: 'eslint',
9
+ binName: 'eslint',
10
+ },
11
+ {
12
+ kind: 'external',
13
+ toolName: 'format',
14
+ path: ['format'],
15
+ capability: 'devtools.format',
16
+ summary: 'Run the shared Prettier toolchain.',
17
+ packageName: 'prettier',
18
+ binName: 'prettier',
19
+ },
20
+ {
21
+ kind: 'external',
22
+ toolName: 'knip',
23
+ path: ['knip'],
24
+ capability: 'devtools.knip',
25
+ summary: 'Run the shared Knip toolchain.',
26
+ packageName: 'knip',
27
+ binName: 'knip',
28
+ },
29
+ {
30
+ kind: 'repository',
31
+ path: ['sync'],
32
+ capability: 'devtools.sync',
33
+ summary: 'Synchronize all centrally managed repository files.',
34
+ scope: 'all',
35
+ operation: 'sync',
36
+ },
37
+ {
38
+ kind: 'repository',
39
+ path: ['status'],
40
+ capability: 'devtools.status',
41
+ summary: 'Report drift for all centrally managed repository files.',
42
+ scope: 'all',
43
+ operation: 'status',
44
+ },
45
+ {
46
+ kind: 'repository',
47
+ path: ['workflows', 'sync'],
48
+ capability: 'devtools.workflows.sync',
49
+ summary: 'Synchronize the canonical GitHub Actions workflows.',
50
+ scope: 'workflows',
51
+ operation: 'sync',
52
+ },
53
+ {
54
+ kind: 'repository',
55
+ path: ['workflows', 'status'],
56
+ capability: 'devtools.workflows.status',
57
+ summary: 'Report drift for the canonical GitHub Actions workflows.',
58
+ scope: 'workflows',
59
+ operation: 'status',
60
+ },
61
+ {
62
+ kind: 'repository',
63
+ path: ['vscode', 'sync'],
64
+ capability: 'devtools.vscode.sync',
65
+ summary: 'Synchronize the canonical VS Code workspace configuration.',
66
+ scope: 'vscode',
67
+ operation: 'sync',
68
+ },
69
+ {
70
+ kind: 'repository',
71
+ path: ['vscode', 'status'],
72
+ capability: 'devtools.vscode.status',
73
+ summary: 'Report drift for the canonical VS Code workspace configuration.',
74
+ scope: 'vscode',
75
+ operation: 'status',
76
+ },
77
+ ];
78
+ export function getDevtoolsCommands() {
79
+ return DEVTOOLS_COMMANDS;
80
+ }
81
+ export function findDevtoolsCommandByPath(path) {
82
+ return (DEVTOOLS_COMMANDS.find((command) => command.path.length === path.length &&
83
+ command.path.every((segment, index) => segment === path[index])) ?? null);
84
+ }
85
+ export function getDevtoolsToolCommand(toolName) {
86
+ for (const command of DEVTOOLS_COMMANDS) {
87
+ if (command.kind === 'external' && command.toolName === toolName) {
88
+ return command;
89
+ }
90
+ }
91
+ throw new Error(`Unknown devtools tool command: ${toolName}`);
92
+ }
@@ -2,16 +2,16 @@ declare const provider: {
2
2
  id: string;
3
3
  category: string;
4
4
  version: string;
5
- capabilities: ("devtools.format" | "devtools.knip" | "devtools.lint")[];
5
+ capabilities: ("devtools.format" | "devtools.knip" | "devtools.lint" | "devtools.status" | "devtools.sync" | "devtools.vscode.status" | "devtools.vscode.sync" | "devtools.workflows.status" | "devtools.workflows.sync")[];
6
6
  commands: {
7
- path: [import("../internal/devtoolsCommands.js").DevtoolsToolName];
8
- capability: "devtools.format" | "devtools.knip" | "devtools.lint";
7
+ path: [string, ...string[]];
8
+ capability: "devtools.format" | "devtools.knip" | "devtools.lint" | "devtools.status" | "devtools.sync" | "devtools.vscode.status" | "devtools.vscode.sync" | "devtools.workflows.status" | "devtools.workflows.sync";
9
9
  summary: string;
10
10
  }[];
11
11
  handlers: {
12
- path: [import("../internal/devtoolsCommands.js").DevtoolsToolName];
12
+ path: [string, ...string[]];
13
13
  handler: (request: import("@ankhorage/ankh").AnkhCommandExecutionRequest) => Promise<{
14
- exitCode: number;
14
+ readonly exitCode: number;
15
15
  }>;
16
16
  }[];
17
17
  };
package/dist/cli/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { readFileSync } from 'node:fs';
2
- import { getDevtoolsCommands } from '../internal/devtoolsCommands.js';
3
- import { runDevtoolsCommand } from '../internal/runDevtoolsCommand.js';
2
+ import { getDevtoolsCommands } from './commands.js';
3
+ import { runProviderCommand } from './runProviderCommand.js';
4
4
  const packageVersion = readPackageVersion();
5
5
  const commands = getDevtoolsCommands();
6
6
  const provider = {
@@ -16,8 +16,7 @@ const provider = {
16
16
  handlers: commands.map((command) => ({
17
17
  path: [...command.path],
18
18
  handler: async (request) => {
19
- const result = await runDevtoolsCommand(command, request.argv);
20
- return { exitCode: result.exitCode };
19
+ return await runProviderCommand(command, request.argv, request.context);
21
20
  },
22
21
  })),
23
22
  };
@@ -0,0 +1,31 @@
1
+ import type { DevtoolsExternalCommandDefinition } from './commands.js';
2
+ export interface DevtoolsRunResult {
3
+ readonly exitCode: number;
4
+ }
5
+ interface DevtoolsRunnerOptions {
6
+ readonly cwd?: string;
7
+ readonly env?: NodeJS.ProcessEnv;
8
+ }
9
+ interface ResolvedExecutionTarget {
10
+ readonly command: string;
11
+ readonly args: readonly string[];
12
+ readonly shell: boolean;
13
+ }
14
+ interface SpawnedProcess {
15
+ on(event: 'error', listener: (error: Error) => void): SpawnedProcess;
16
+ on(event: 'exit', listener: (code: number | null, signal: NodeJS.Signals | null) => void): SpawnedProcess;
17
+ }
18
+ type SpawnProcess = (command: string, args: readonly string[], options: {
19
+ readonly cwd: string;
20
+ readonly env: NodeJS.ProcessEnv;
21
+ readonly shell: boolean;
22
+ readonly stdio: 'inherit';
23
+ }) => SpawnedProcess;
24
+ interface DevtoolsRunnerDependencies {
25
+ readonly logError: (message: string) => void;
26
+ readonly resolveExecutionTarget: (command: DevtoolsExternalCommandDefinition) => Promise<ResolvedExecutionTarget>;
27
+ readonly spawnProcess: SpawnProcess;
28
+ }
29
+ export declare function runExternalTool(command: DevtoolsExternalCommandDefinition, argv: readonly string[], options?: DevtoolsRunnerOptions): Promise<DevtoolsRunResult>;
30
+ export declare function runExternalToolWithDependencies(command: DevtoolsExternalCommandDefinition, argv: readonly string[], options: DevtoolsRunnerOptions | undefined, dependencies: DevtoolsRunnerDependencies): Promise<DevtoolsRunResult>;
31
+ export {};
@@ -11,10 +11,10 @@ const defaultRunnerDependencies = {
11
11
  resolveExecutionTarget,
12
12
  spawnProcess: (command, args, options) => spawn(command, args, options),
13
13
  };
14
- export async function runDevtoolsCommand(command, argv, options) {
15
- return runDevtoolsCommandWithDependencies(command, argv, options, defaultRunnerDependencies);
14
+ export async function runExternalTool(command, argv, options) {
15
+ return await runExternalToolWithDependencies(command, argv, options, defaultRunnerDependencies);
16
16
  }
17
- export async function runDevtoolsCommandWithDependencies(command, argv, options, dependencies) {
17
+ export async function runExternalToolWithDependencies(command, argv, options, dependencies) {
18
18
  let executionTarget;
19
19
  try {
20
20
  executionTarget = await dependencies.resolveExecutionTarget(command);
@@ -0,0 +1,8 @@
1
+ import type { DevtoolsCommandDefinition } from './commands.js';
2
+ import { type DevtoolsRepositoryCommandContext } from './runRepositoryCommand.js';
3
+ export interface DevtoolsProviderCommandContext extends DevtoolsRepositoryCommandContext {
4
+ readonly env: Readonly<Record<string, string | undefined>>;
5
+ }
6
+ export declare function runProviderCommand(command: DevtoolsCommandDefinition, argv: readonly string[], context: DevtoolsProviderCommandContext): Promise<{
7
+ readonly exitCode: number;
8
+ }>;
@@ -0,0 +1,11 @@
1
+ import { runExternalTool } from './runExternalTool.js';
2
+ import { runRepositoryCommand, } from './runRepositoryCommand.js';
3
+ export async function runProviderCommand(command, argv, context) {
4
+ if (command.kind === 'external') {
5
+ return await runExternalTool(command, argv, {
6
+ cwd: context.cwd,
7
+ env: { ...context.env },
8
+ });
9
+ }
10
+ return await runRepositoryCommand(command, argv, context);
11
+ }
@@ -0,0 +1,16 @@
1
+ import type { DevtoolsRepositoryCommandDefinition } from './commands.js';
2
+ export interface DevtoolsRepositoryCommandContext {
3
+ readonly cwd: string;
4
+ writeStdout(text: string): void;
5
+ writeStderr(text: string): void;
6
+ }
7
+ export interface DevtoolsRepositoryCommandResult {
8
+ readonly exitCode: number;
9
+ }
10
+ interface ParsedRepositoryArguments {
11
+ readonly dryRun: boolean;
12
+ readonly targetPath: string | undefined;
13
+ }
14
+ export declare function runRepositoryCommand(command: DevtoolsRepositoryCommandDefinition, argv: readonly string[], context: DevtoolsRepositoryCommandContext): Promise<DevtoolsRepositoryCommandResult>;
15
+ export declare function parseRepositoryArguments(argv: readonly string[], allowDryRun: boolean): ParsedRepositoryArguments;
16
+ export {};