@alexgorbatchev/dotfiles 0.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.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +397 -0
  3. package/cli-fj2hdbnx.js +5 -0
  4. package/cli-fj2hdbnx.js.map +9 -0
  5. package/cli-w822cqdk.js +4 -0
  6. package/cli-w822cqdk.js.map +10 -0
  7. package/cli.js +449 -0
  8. package/cli.js.map +283 -0
  9. package/dashboard-0ebz5sqb.js +159 -0
  10. package/dashboard-0ebz5sqb.js.map +102 -0
  11. package/dashboard-3axqywva.css +1 -0
  12. package/dashboard.js +13 -0
  13. package/package.json +63 -0
  14. package/prerender-kpxyx916.js +3 -0
  15. package/prerender-kpxyx916.js.map +11 -0
  16. package/schemas.d.ts +2730 -0
  17. package/skill/SKILL.md +74 -0
  18. package/skill/references/api-reference.md +614 -0
  19. package/skill/references/configuration.md +1154 -0
  20. package/skill/references/installation-methods/brew.md +62 -0
  21. package/skill/references/installation-methods/cargo.md +86 -0
  22. package/skill/references/installation-methods/curl-binary.md +73 -0
  23. package/skill/references/installation-methods/curl-script.md +132 -0
  24. package/skill/references/installation-methods/curl-tar.md +58 -0
  25. package/skill/references/installation-methods/dmg.md +113 -0
  26. package/skill/references/installation-methods/gitea-release.md +106 -0
  27. package/skill/references/installation-methods/github-release.md +97 -0
  28. package/skill/references/installation-methods/manual.md +74 -0
  29. package/skill/references/installation-methods/npm.md +75 -0
  30. package/skill/references/installation-methods/overview.md +293 -0
  31. package/skill/references/installation-methods/zsh-plugin.md +156 -0
  32. package/skill/references/make-tool.md +866 -0
  33. package/skill/references/shell-and-hooks.md +833 -0
  34. package/tool-types.d.ts +14 -0
  35. package/wasm-n3cagcre.js +3 -0
  36. package/wasm-n3cagcre.js.map +10 -0
package/skill/SKILL.md ADDED
@@ -0,0 +1,74 @@
1
+ ---
2
+ name: dotfiles
3
+ description: >-
4
+ .tool.ts configuration files, defineTool, install(), config.ts, defineConfig,
5
+ installation methods (github-release, gitea-release, brew, cargo, npm, curl-script, curl-tar, curl-binary, dmg, manual, zsh-plugin),
6
+ shell integration (aliases, functions, completions, env, symlinks, sourceFile),
7
+ hooks (before-install, after-download, after-extract, after-install),
8
+ platform overrides, virtual environments, shim generation, dotfiles management.
9
+ ---
10
+
11
+ # Dotfiles Tool Installer
12
+
13
+ Declarative, versioned dotfiles management. Define CLI tools in TypeScript `.tool.ts` files — the system handles installation, shim generation, shell integration, and cross-platform support.
14
+
15
+ ## Quick Reference
16
+
17
+ ```typescript
18
+ import { defineTool } from '@alexgorbatchev/dotfiles';
19
+
20
+ export default defineTool((install, ctx) =>
21
+ install('github-release', { repo: 'BurntSushi/ripgrep' })
22
+ .bin('rg')
23
+ .zsh((shell) => shell.aliases({ rgi: 'rg -i' }).completions('complete/_rg'))
24
+ );
25
+ ```
26
+
27
+ Every tool that provides executables **must** have `.bin()` — it generates a shim that makes the tool available system-wide and triggers installation on first use.
28
+
29
+ ## Syncing Changes
30
+
31
+ After any `.tool.ts` file change (create, delete, or modify), run `dotfiles generate` to sync generated artifacts.
32
+
33
+ ## Reference Files
34
+
35
+ Read these based on the task at hand:
36
+
37
+ - **[make-tool.md](references/make-tool.md)** — Complete guide for creating `.tool.ts` configurations. Read when creating a new tool config or modifying an existing one. Includes tool investigation steps, method selection, examples, and quality checklist.
38
+
39
+ - **[api-reference.md](references/api-reference.md)** — Public API reference: `defineTool`, `defineConfig`, builder methods, shell configurator methods, `Platform`/`Architecture` enums, utilities (`replaceInFile`, `resolve`, `log`).
40
+
41
+ - **Installation Methods** — Parameters and examples for each installation method:
42
+ - [overview.md](references/installation-methods/overview.md) — Available methods, choosing the right method, manual installation guide, common parameters
43
+ - [github-release.md](references/installation-methods/github-release.md) — GitHub release asset selection and platform detection
44
+ - [gitea-release.md](references/installation-methods/gitea-release.md) — Gitea/Forgejo/Codeberg release installation
45
+ - [brew.md](references/installation-methods/brew.md) — Homebrew formula and cask installation
46
+ - [cargo.md](references/installation-methods/cargo.md) — Rust crate installation via cargo-quickinstall or GitHub releases
47
+ - [npm.md](references/installation-methods/npm.md) — npm/bun package installation
48
+ - [curl-script.md](references/installation-methods/curl-script.md) — Shell script installation with stagingDir
49
+ - [curl-tar.md](references/installation-methods/curl-tar.md) — Tarball download and extraction
50
+ - [curl-binary.md](references/installation-methods/curl-binary.md) — Direct binary file download
51
+ - [dmg.md](references/installation-methods/dmg.md) — macOS DMG disk image installation
52
+ - [manual.md](references/installation-methods/manual.md) — Custom scripts, pre-built binaries, config-only tools
53
+ - [zsh-plugin.md](references/installation-methods/zsh-plugin.md) — Zsh plugin Git repository cloning
54
+
55
+ - **[shell-and-hooks.md](references/shell-and-hooks.md)** — Shell integration (aliases, functions, env, path, completions, sourceFile, sourceFunction, source, symlinks), hook events and context, completions configuration.
56
+
57
+ - **[configuration.md](references/configuration.md)** — Project config (`defineConfig`), getting started, platform support, virtual environments, advanced topics, troubleshooting.
58
+
59
+ ## Method Selection Quick Reference
60
+
61
+ | Use Case | Method | Example Tools |
62
+ | ---------------------- | ---------------- | ------------------ |
63
+ | GitHub releases | `github-release` | fzf, ripgrep, bat |
64
+ | Gitea/Forgejo/Codeberg | `gitea-release` | Codeberg tools |
65
+ | Homebrew | `brew` | git, jq |
66
+ | Rust crates | `cargo` | eza, fd |
67
+ | npm packages | `npm` | prettier, eslint |
68
+ | Install scripts | `curl-script` | rustup, nvm |
69
+ | Tarball URLs | `curl-tar` | direct archives |
70
+ | Direct binaries | `curl-binary` | single-file tools |
71
+ | macOS DMG | `dmg` | GUI apps |
72
+ | Custom/scripts | `manual` | deployment scripts |
73
+ | Zsh plugins | `zsh-plugin` | zsh-vi-mode |
74
+ | Config only | `install()` | aliases, env vars |
@@ -0,0 +1,614 @@
1
+ # API Reference
2
+
3
+ ## Table of Contents
4
+
5
+ - [Exports](#exports)
6
+ - [defineTool](#definetool)
7
+ - [Parameters](#parameters)
8
+ - [Builder Methods](#builder-methods)
9
+ - [Base Install Parameters](#base-install-parameters)
10
+ - [Shell Configuration](#shell-configuration)
11
+ - [defineConfig](#defineconfig)
12
+ - [Platform](#platform)
13
+ - [Architecture](#architecture)
14
+ - [Utilities](#utilities)
15
+ - [ctx.replaceInFile](#ctxreplaceinfile)
16
+ - [ctx.resolve](#ctxresolve)
17
+ - [ctx.log](#ctxlog)
18
+ - [dedentTemplate](#dedenttemplate)
19
+ - [Installation Method Parameters](#installation-method-parameters)
20
+ - [Context API](#context-api)
21
+ - [Properties](#properties)
22
+ - [Path Properties via projectConfig](#path-properties-via-projectconfig)
23
+ - [Examples](#examples)
24
+ - [Directory Structure](#directory-structure)
25
+ - [Path Resolution by Method](#path-resolution-by-method)
26
+ - [Common Mistakes](#common-mistakes)
27
+ - [Cross-Platform](#cross-platform)
28
+
29
+ ---
30
+
31
+ # API Reference
32
+
33
+ Reference for the public API available in `@alexgorbatchev/dotfiles`.
34
+
35
+ ## Exports
36
+
37
+ ```typescript
38
+ import {
39
+ Architecture, // Architecture enum
40
+ dedentString, // Utility for template strings
41
+ dedentTemplate, // Tagged template for dedenting
42
+ defineConfig, // Create project configuration
43
+ defineTool, // Create tool configurations
44
+ Platform, // Platform enum for cross-platform configs
45
+ } from '@alexgorbatchev/dotfiles';
46
+ ```
47
+
48
+ ## defineTool
49
+
50
+ Creates a tool configuration.
51
+
52
+ ```typescript
53
+ export default defineTool((install, ctx) => install('github-release', { repo: 'owner/tool' }).bin('tool'));
54
+ ```
55
+
56
+ ### Parameters
57
+
58
+ - `install(method, params)` - Function to select installation method
59
+ - `install(method)` - Some methods (e.g. `manual`) can be called without params
60
+ - `install()` - Configuration-only tool (no installation method)
61
+ - `ctx` - Context object with `projectConfig`, `toolName`, `systemInfo`
62
+
63
+ ### Builder Methods
64
+
65
+ | Method | Description |
66
+ | --------------------- | ------------------------------------------------------- |
67
+ | `.bin(name)` | Define binary name(s) to expose |
68
+ | `.version(v)` | Set version (`'latest'` or specific) |
69
+ | `.dependsOn(...bins)` | Declare binary dependencies |
70
+ | `.symlink(src, dest)` | Create config file symlink |
71
+ | `.hook(event, fn)` | Lifecycle hooks (details in Hooks section) |
72
+ | `.zsh(fn)` | Zsh shell configuration |
73
+ | `.bash(fn)` | Bash shell configuration |
74
+ | `.powershell(fn)` | PowerShell configuration |
75
+ | `.platform(p, fn)` | Platform-specific overrides |
76
+ | `.disable()` | Skip tool during generation (logs warning) |
77
+ | `.hostname(pattern)` | Restrict tool to specific hostname(s) (string or regex) |
78
+
79
+ #### `.bin(name)` runtime behavior
80
+
81
+ Declaring `.bin(name)` generates a shim for `name` in `paths.targetDir`.
82
+
83
+ - Running the shim auto-installs the tool on first use (if needed)
84
+ - Running `{binary} @update` triggers a shim-driven update flow
85
+ - Shim executions are recorded for usage analytics via a private internal command
86
+
87
+ Usage tracking is non-blocking and enabled by default. Set `DOTFILES_USAGE_TRACKING=0` to disable tracking.
88
+
89
+ ### Base Install Parameters
90
+
91
+ All installation methods support these parameters:
92
+
93
+ | Parameter | Type | Description |
94
+ | --------- | ----------------------------------------------------------- | --------------------------------------------------------- |
95
+ | `env` | `Record<string, string> \| (ctx) => Record<string, string>` | Environment variables for installation |
96
+ | `hooks` | `object` | Lifecycle hooks configuration |
97
+ | `auto` | `boolean` | Auto-install during `generate` (default: method-specific) |
98
+
99
+ > **Note**: The `auto` parameter defaults to `true` for `zsh-plugin` and `false` for all other installation methods. When `auto: true`, the tool is automatically installed during `dotfiles generate` without requiring a separate `dotfiles install` step.
100
+
101
+ The `env` parameter can be static or dynamic:
102
+
103
+ ```typescript
104
+ // Static environment variables
105
+ install('github-release', {
106
+ repo: 'owner/tool',
107
+ env: { CUSTOM_FLAG: 'true' },
108
+ }).bin('tool');
109
+
110
+ // Dynamic environment variables (receives context with projectConfig, stagingDir)
111
+ install('github-release', {
112
+ repo: 'owner/tool',
113
+ env: (ctx) => ({ INSTALL_DIR: ctx.stagingDir }),
114
+ }).bin('tool');
115
+ ```
116
+
117
+ ### Shell Configuration
118
+
119
+ The shell methods (`.zsh`, `.bash`, `.powershell`) receive a configurator:
120
+
121
+ ```typescript
122
+ .zsh((shell) =>
123
+ shell
124
+ .completions('completions/_tool')
125
+ .env({ VAR: 'value' })
126
+ .aliases({ t: 'tool' })
127
+ .always(/* zsh */`
128
+ function my-func() { tool "$@"; }
129
+ `)
130
+ )
131
+ ```
132
+
133
+ | Shell Method | Description |
134
+ | ------------------------------------------ | --------------------------------------------------------------------------------------------- |
135
+ | `.completions(path \| config \| callback)` | Completion file, config object, or callback with `ctx.version` (generated after install only) |
136
+ | `.env(obj)` | Environment variables (PATH prohibited - use `.path()`) |
137
+ | `.path(dir)` | Add directory to PATH (deduplicated) |
138
+ | `.aliases(obj)` | Shell aliases |
139
+ | `.functions(obj)` | Shell functions |
140
+ | `.sourceFile(path)` | Source a file (skips if missing) |
141
+ | `.sourceFunction(name)` | Source output of a function defined via `.functions()` |
142
+ | `.always(script)` | Script run on every shell init |
143
+ | `.once(script)` | Script run once after install |
144
+
145
+ **Completions examples:**
146
+
147
+ ```typescript
148
+ .completions('completions/_tool') // Static path (relative to toolDir)
149
+ .completions(`${ctx.currentDir}/completions/_tool`) // Absolute path (from extracted archive)
150
+ .completions({ cmd: 'tool completion zsh' }) // Dynamic via command
151
+ .completions({ url: 'https://.../completions.tar.gz', source: `${ctx.currentDir}/_tool` }) // Archive URL
152
+ ```
153
+
154
+ ## defineConfig
155
+
156
+ Creates project configuration. See Project Configuration section.
157
+
158
+ ```typescript
159
+ export default defineConfig(() => ({
160
+ paths: { dotfilesDir: '~/.dotfiles' },
161
+ }));
162
+ ```
163
+
164
+ ## Platform
165
+
166
+ Enum for platform-specific configurations.
167
+
168
+ ```typescript
169
+ import { defineTool, Platform } from '@alexgorbatchev/dotfiles';
170
+
171
+ export default defineTool((install) =>
172
+ install('github-release', { repo: 'owner/tool' })
173
+ .bin('tool')
174
+ .platform(Platform.MacOS, (install) => install('brew', { formula: 'tool' }))
175
+ );
176
+ ```
177
+
178
+ | Value | Description |
179
+ | ------------------ | -------------------------------- |
180
+ | `Platform.Linux` | Linux systems |
181
+ | `Platform.MacOS` | macOS (alias: `Platform.Darwin`) |
182
+ | `Platform.Windows` | Windows systems |
183
+
184
+ ## Architecture
185
+
186
+ Enum for architecture-specific configurations.
187
+
188
+ | Value | Description |
189
+ | --------------------- | -------------------------------- |
190
+ | `Architecture.X86_64` | Intel/AMD 64-bit |
191
+ | `Architecture.Arm64` | ARM 64-bit (Apple Silicon, etc.) |
192
+
193
+ ## Utilities
194
+
195
+ ### ctx.replaceInFile
196
+
197
+ Performs a regex-based replacement within a file. Pre-bound with the context's file system.
198
+
199
+ **Key behaviors:**
200
+
201
+ - Always replaces _all_ matches (global replacement), even if `from` does not include the `g` flag
202
+ - Supports `to` as either a string or a (a)sync callback
203
+ - Supports `mode: 'file'` (default) and `mode: 'line'` (process each line separately)
204
+ - No-op write: if output equals input, the file is not written
205
+ - Returns `true` if replacements were made, `false` otherwise
206
+
207
+ ```typescript
208
+ .hook('after-install', async (ctx) => {
209
+ // Simple replacement (replaces all matches)
210
+ const wasReplaced = await ctx.replaceInFile(
211
+ `${ctx.installedDir}/config.toml`,
212
+ /placeholder/,
213
+ 'actual_value'
214
+ );
215
+
216
+ // Line-by-line with callback
217
+ await ctx.replaceInFile(
218
+ `${ctx.installedDir}/settings.ini`,
219
+ /version=(\d+)/,
220
+ (match) => `version=${Number(match.captures[0]) + 1}`,
221
+ { mode: 'line' }
222
+ );
223
+
224
+ // With error message for debugging missing patterns
225
+ await ctx.replaceInFile(
226
+ `${ctx.installedDir}/config.toml`,
227
+ /theme = ".*"/,
228
+ 'theme = "dark"',
229
+ { errorMessage: 'Could not find theme setting in config.toml' }
230
+ );
231
+ })
232
+ ```
233
+
234
+ **Parameters:**
235
+
236
+ - `filePath` - Path to the file (supports `~` expansion)
237
+ - `from` - Pattern to match (string or RegExp, always global)
238
+ - `to` - Replacement string or callback receiving `IReplaceInFileMatch`
239
+ - `options` - Optional settings:
240
+ - `mode` - `'file'` (default) or `'line'` (process each line separately)
241
+ - `errorMessage` - If provided and no matches found, logs error: `Could not find '<pattern>' in <filePath>`
242
+
243
+ **Returns:** `Promise<boolean>` - `true` if replacements were made, `false` if no matches found
244
+
245
+ **Callback argument (`IReplaceInFileMatch`):**
246
+
247
+ - `substring` - The matched substring
248
+ - `captures` - Array of capture groups (may contain `undefined`)
249
+ - `offset` - Match offset in the input
250
+ - `input` - Original input string
251
+ - `groups` - Named capture groups (if present)
252
+
253
+ ### ctx.resolve
254
+
255
+ Resolves a glob pattern to a single file or directory path. Useful for referencing files with variable names (versioned directories, platform-specific assets).
256
+
257
+ ```typescript
258
+ .zsh((shell) =>
259
+ shell.always(/* zsh */ `
260
+ source "${ctx.resolve('completions/*.zsh')}"
261
+ `)
262
+ )
263
+
264
+ // In hooks
265
+ .hook('after-install', async (ctx) => {
266
+ const versionDir = ctx.resolve('tool-*-x86_64-linux');
267
+ await ctx.$`${versionDir}/bin/tool init`;
268
+ })
269
+ ```
270
+
271
+ **Parameters:**
272
+
273
+ - `pattern` - Glob pattern to match (relative to `toolDir` or absolute)
274
+
275
+ **Returns:** `string` - The resolved absolute path
276
+
277
+ **Throws:** `ResolveError` if:
278
+
279
+ - No matches are found (logs ERROR: `No matches found for pattern: <pattern>`)
280
+ - Multiple matches are found (logs ERROR: `Pattern '<pattern>' matched N paths (expected exactly 1): ...`)
281
+
282
+ ### ctx.log
283
+
284
+ User-facing logger for tool operations. Messages are automatically prefixed with the tool name.
285
+
286
+ ```typescript
287
+ .hook('after-install', async () => {
288
+ ctx.log.info('Configuring tool settings...');
289
+
290
+ const result = await configureSettings();
291
+
292
+ if (result.warnings.length > 0) {
293
+ ctx.log.warn('Some settings could not be applied');
294
+ }
295
+
296
+ ctx.log.debug('Configuration complete');
297
+ })
298
+ ```
299
+
300
+ **Methods:**
301
+
302
+ - `ctx.log.trace(message)` - Detailed debugging (hidden by default)
303
+ - `ctx.log.debug(message)` - Debug information (hidden by default)
304
+ - `ctx.log.info(message)` - Informational messages
305
+ - `ctx.log.warn(message)` - Warning messages
306
+ - `ctx.log.error(message, error?)` - Error messages (optionally with error object)
307
+
308
+ **Output:** Messages include the tool name as context:
309
+
310
+ ```
311
+ INFO [my-tool] Configuring tool settings...
312
+ ```
313
+
314
+ ### dedentTemplate
315
+
316
+ Tagged template for removing indentation from multi-line strings.
317
+
318
+ ```typescript
319
+ import { dedentTemplate } from '@alexgorbatchev/dotfiles';
320
+
321
+ const script = dedentTemplate`
322
+ if [[ -n "$VAR" ]]; then
323
+ echo "Hello"
324
+ fi
325
+ `;
326
+ ```
327
+
328
+ ## Installation Method Parameters
329
+
330
+ See the Installation Methods reference for detailed parameters for each method:
331
+
332
+ - `github-release` - GitHub Releases
333
+ - `gitea-release` - Gitea/Forgejo Releases
334
+ - `brew` - Homebrew
335
+ - `cargo` - Cargo
336
+ - `npm` - npm
337
+ - `curl-script` - Curl Scripts
338
+ - `curl-tar` - Curl Tar
339
+ - `curl-binary` - Curl Binary
340
+ - `manual` - Manual
341
+ - `zsh-plugin` - Zsh Plugin
342
+
343
+ ---
344
+
345
+ # Context API
346
+
347
+ The `ctx` parameter in `defineTool` provides access to tool and project information.
348
+
349
+ ## Properties
350
+
351
+ | Property | Description |
352
+ | ------------------- | ------------------------------------------------- |
353
+ | `ctx.toolName` | Name of the tool being configured |
354
+ | `ctx.toolDir` | Directory containing the `.tool.ts` file |
355
+ | `ctx.currentDir` | Tool's stable `current` directory (after install) |
356
+ | `ctx.projectConfig` | Full project configuration |
357
+ | `ctx.systemInfo` | Platform, architecture, and home directory |
358
+ | `ctx.replaceInFile` | Replace text in files using regex patterns |
359
+ | `ctx.resolve` | Resolve glob pattern to a single path |
360
+ | `ctx.log` | Logger for user-facing output |
361
+
362
+ ### Path Properties via projectConfig
363
+
364
+ | Path | Description |
365
+ | ----------------------------------------- | ------------------------- |
366
+ | `ctx.projectConfig.paths.dotfilesDir` | Root dotfiles directory |
367
+ | `ctx.projectConfig.paths.binariesDir` | Tool binaries directory |
368
+ | `ctx.projectConfig.paths.generatedDir` | Generated files directory |
369
+ | `ctx.projectConfig.paths.targetDir` | Shim directory |
370
+ | `ctx.projectConfig.paths.shellScriptsDir` | Shell scripts directory |
371
+
372
+ > **Note:** For home directory paths, use `~/` instead of `ctx.projectConfig.paths.homeDir`. Tilde expansion is automatic.
373
+
374
+ ## Examples
375
+
376
+ ### Referencing Files Next to Tool Config
377
+
378
+ ```typescript
379
+ export default defineTool((install, ctx) =>
380
+ install('github-release', { repo: 'owner/tool' })
381
+ .bin('tool')
382
+ .zsh((shell) =>
383
+ shell.always(/* zsh */ `
384
+ source "${ctx.toolDir}/shell/key-bindings.zsh"
385
+ `)
386
+ )
387
+ );
388
+ ```
389
+
390
+ ### Setting Environment Variables
391
+
392
+ ```typescript
393
+ export default defineTool((install, ctx) =>
394
+ install('github-release', { repo: 'owner/tool' })
395
+ .bin('tool')
396
+ .zsh((shell) =>
397
+ shell.env({
398
+ TOOL_HOME: `${ctx.projectConfig.paths.binariesDir}/${ctx.toolName}`,
399
+ })
400
+ )
401
+ );
402
+ ```
403
+
404
+ ### Using currentDir for Installed Assets
405
+
406
+ ```typescript
407
+ export default defineTool((install, ctx) =>
408
+ install('github-release', { repo: 'owner/tool' })
409
+ .bin('tool')
410
+ .zsh((shell) =>
411
+ shell.always(/* zsh */ `
412
+ export TOOL_THEME="${ctx.currentDir}/share/themes/default.toml"
413
+ `)
414
+ )
415
+ );
416
+ ```
417
+
418
+ ### Using replaceInFile for File Modifications
419
+
420
+ The `ctx.replaceInFile` method performs regex-based replacements within files.
421
+
422
+ **Key behaviors:**
423
+
424
+ - Always replaces _all_ matches (global replacement), even if `from` does not include the `g` flag
425
+ - Supports `to` as either a string or a (a)sync callback
426
+ - Supports `mode: 'file'` (default) and `mode: 'line'` (process each line separately)
427
+ - No-op write: if output equals input, the file is not written
428
+ - Returns `true` if replacements were made, `false` otherwise
429
+
430
+ ```typescript
431
+ export default defineTool((install, ctx) =>
432
+ install('github-release', { repo: 'owner/tool' })
433
+ .bin('tool')
434
+ .hook('after-install', async () => {
435
+ // Simple replacement (replaces all matches)
436
+ const wasReplaced = await ctx.replaceInFile(`${ctx.currentDir}/config.toml`, /placeholder_value/, 'actual_value');
437
+
438
+ // Line-by-line replacement with callback
439
+ await ctx.replaceInFile(
440
+ `${ctx.currentDir}/settings.ini`,
441
+ /version=(\d+)/,
442
+ (match) => `version=${Number(match.captures[0]) + 1}`,
443
+ { mode: 'line' },
444
+ );
445
+
446
+ // Async replacer function
447
+ await ctx.replaceInFile(`${ctx.currentDir}/config.yaml`, /api_key: .*/, async () => {
448
+ const key = await fetchApiKey();
449
+ return `api_key: ${key}`;
450
+ });
451
+
452
+ // With error message for debugging missing patterns
453
+ await ctx.replaceInFile(`${ctx.currentDir}/config.toml`, /theme = ".*"/, 'theme = "dark"', {
454
+ errorMessage: 'Could not find theme setting in config.toml',
455
+ });
456
+ })
457
+ );
458
+ ```
459
+
460
+ **Parameters:**
461
+
462
+ - `filePath` - Path to the file (supports `~` expansion)
463
+ - `from` - Pattern to match (string or RegExp, always global)
464
+ - `to` - Replacement string or callback receiving `IReplaceInFileMatch`
465
+ - `options` - Optional settings:
466
+ - `mode` - `'file'` (default) or `'line'` (process each line separately)
467
+ - `errorMessage` - If provided and no matches found, logs error: `Could not find '<pattern>' in <filePath>`
468
+
469
+ **Returns:** `Promise<boolean>` - `true` if replacements were made, `false` if no matches found
470
+
471
+ **Callback argument (`IReplaceInFileMatch`):**
472
+
473
+ - `substring` - The matched substring
474
+ - `captures` - Array of capture groups (may contain `undefined`)
475
+ - `offset` - Match offset in the input
476
+ - `input` - Original input string
477
+ - `groups` - Named capture groups (if present)
478
+
479
+ ### Using log for User Output
480
+
481
+ The `ctx.log` provides a simple logging interface for user-facing messages:
482
+
483
+ ```typescript
484
+ export default defineTool((install, ctx) =>
485
+ install('github-release', { repo: 'owner/tool' })
486
+ .bin('tool')
487
+ .hook('after-install', async () => {
488
+ ctx.log.info('Configuring tool settings...');
489
+
490
+ // Perform configuration
491
+ const result = await configureSettings();
492
+
493
+ if (result.warnings.length > 0) {
494
+ ctx.log.warn('Some settings could not be applied');
495
+ }
496
+
497
+ ctx.log.debug('Configuration complete');
498
+ })
499
+ );
500
+ ```
501
+
502
+ **Log Levels:**
503
+
504
+ - `ctx.log.trace(message)` - Detailed debugging (hidden by default)
505
+ - `ctx.log.debug(message)` - Debug information (hidden by default)
506
+ - `ctx.log.info(message)` - Informational messages
507
+ - `ctx.log.warn(message)` - Warning messages
508
+ - `ctx.log.error(message, error?)` - Error messages (optionally with error object)
509
+
510
+ **Output:** Log messages are automatically prefixed with the tool name:
511
+
512
+ ```
513
+ [my-tool] Configuring tool settings...
514
+ ```
515
+
516
+ ### Using resolve for Glob Pattern Matching
517
+
518
+ The `ctx.resolve` method resolves a glob pattern to a single file or directory path. Use this when you need to reference files or directories with flexible naming (e.g., versioned directories, platform-specific binaries).
519
+
520
+ **Key behaviors:**
521
+
522
+ - Returns the absolute path if exactly one match is found
523
+ - Throws `ResolveError` and logs ERROR if no matches are found
524
+ - Throws `ResolveError` and logs ERROR if multiple matches are found
525
+ - Patterns are resolved relative to `toolDir` unless absolute
526
+
527
+ ```typescript
528
+ export default defineTool((install, ctx) =>
529
+ install('github-release', { repo: 'BurntSushi/ripgrep' })
530
+ .bin('rg')
531
+ .zsh((shell) =>
532
+ shell.always(/* zsh */ `
533
+ source "${ctx.resolve('completions/_rg.zsh')}"
534
+ `)
535
+ )
536
+ );
537
+ ```
538
+
539
+ **Common use cases:**
540
+
541
+ ```typescript
542
+ // Versioned directory with wildcard
543
+ const versionDir = ctx.resolve('ripgrep-*-x86_64-*');
544
+ // -> "/path/to/tools/rg/ripgrep-14.1.0-x86_64-linux"
545
+
546
+ // Single completion file
547
+ const completion = ctx.resolve('completions/*.zsh');
548
+ // -> "/path/to/tools/rg/completions/_rg.zsh"
549
+
550
+ // Absolute path pattern
551
+ const binary = ctx.resolve('/opt/myapp/bin/myapp-*');
552
+ // -> "/opt/myapp/bin/myapp-1.2.3"
553
+ ```
554
+
555
+ **Error handling:**
556
+
557
+ Since `resolve` throws on no matches or multiple matches, failed resolutions stop tool processing. This is intentional - a missing or ambiguous path usually indicates a configuration problem.
558
+
559
+ ```typescript
560
+ // No matches - throws ResolveError, logs:
561
+ // ERROR No matches found for pattern: non-existent-*
562
+
563
+ // Multiple matches - throws ResolveError, logs:
564
+ // ERROR Pattern 'config-*.yaml' matched 2 paths (expected exactly 1): /path/config-a.yaml, /path/config-b.yaml
565
+ ```
566
+
567
+ ## Directory Structure
568
+
569
+ ```
570
+ ${ctx.projectConfig.paths.binariesDir}/${ctx.toolName}/
571
+ ├── 1.2.3/ # Versioned install directory
572
+ │ ├── tool # Binary
573
+ │ └── share/ # Assets
574
+ └── current -> 1.2.3 # Stable symlink (ctx.currentDir)
575
+ ```
576
+
577
+ - Archives extracted to `binaries/tool-name/version/`
578
+ - `current` symlink updated after install
579
+ - Shims in `targetDir` execute `${ctx.currentDir}/binary`
580
+
581
+ ## Path Resolution by Method
582
+
583
+ | Method | Path | Resolution |
584
+ | --------------------- | --------------- | --------------------------------- |
585
+ | `.symlink(src, dest)` | `src` with `./` | Relative to tool config directory |
586
+ | `.symlink(src, dest)` | `dest` | Absolute path (`~` expanded) |
587
+ | `.completions(path)` | `path` | Relative to extracted archive |
588
+ | `binaryPath` | github/cargo | Relative to extracted archive |
589
+ | `binaryPath` | manual | Absolute path |
590
+
591
+ ## Common Mistakes
592
+
593
+ ```typescript
594
+ // ❌ Hardcoded paths
595
+ .symlink('./config', '/home/user/.config/tool')
596
+
597
+ // ✅ Use tilde expansion
598
+ .symlink('./config', '~/.config/tool')
599
+
600
+ // ❌ Shell variable references
601
+ .always(`source $DOTFILES/init.zsh`)
602
+
603
+ // ✅ Use context
604
+ .always(`source "${ctx.currentDir}/init.zsh"`)
605
+ ```
606
+
607
+ ## Cross-Platform
608
+
609
+ Always use forward slashes - context variables handle platform differences:
610
+
611
+ ```typescript
612
+ // Works on all platforms
613
+ .symlink('./config.toml', '~/.config/tool/config.toml')
614
+ ```