@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
@@ -0,0 +1,866 @@
1
+ # Create `.tool.ts` Configuration
2
+
3
+ ## Mission
4
+
5
+ Create a complete, working `.tool.ts` configuration file for a CLI tool.
6
+
7
+ Your job is to analyze the tool and its distribution method, then generate a configuration that follows the repository's best practices and aligns with the current API.
8
+
9
+ ## Input
10
+
11
+ You will receive:
12
+
13
+ - **Tool Source**: a URL (GitHub repo, homepage) or a tool name.
14
+ - **Tool Name** (optional): if not provided, derive it from the source.
15
+
16
+ ## Required Analysis Steps
17
+
18
+ ### 1) Tool Investigation
19
+
20
+ Make best effort to find current README and installation instructions online for the tool to understand:
21
+
22
+ - **Tool purpose**: what it does.
23
+ - **Primary distribution method**: how the authors expect users to install it.
24
+ - **Package managers**: whether it’s available via Homebrew, Cargo, etc.
25
+ - **Release assets**: if it uses GitHub or Gitea/Forgejo releases, what assets exist.
26
+ - **Binary names**: which executables it provides.
27
+ - **Platform support**: macOS/Linux/Windows and supported CPU architectures.
28
+ - **Dependencies**: runtime requirements (shared libs, language runtimes, etc.).
29
+
30
+ ### 2) Release Asset Analysis (if applicable)
31
+
32
+ If the tool uses GitHub or Gitea/Forgejo releases, examine the latest release to determine:
33
+
34
+ - **Asset naming patterns** (OS/arch/target naming).
35
+ - **Archive structure** (`.tar.gz`, `.zip`).
36
+ - **Binary locations** within the archive.
37
+ - **Platform variants** (different archives/assets per OS/arch).
38
+
39
+ ### 3) Tool Behavior Analysis
40
+
41
+ Research the tool’s runtime behavior:
42
+
43
+ - **CLI surface**: common commands/options.
44
+ - **Configuration files**: expected locations and formats.
45
+ - **Shell integration**: completions, aliases, functions.
46
+ - **Environment variables**: supported env vars.
47
+
48
+ ## Configuration Generation Process
49
+
50
+ ### Step 1: Choose the Best Installation Method
51
+
52
+ Select the most appropriate method based on your investigation. Prefer official, precompiled, and well-supported methods.
53
+
54
+ - **`github-release`**: best for tools with prebuilt binaries on GitHub.
55
+ - Guide: [GitHub Release Installation Guide](installation-methods.md#github-release.md)
56
+ - Use `ghCli: true` to fetch releases via `gh` CLI instead of direct API access (useful for GitHub Enterprise or when `GITHUB_TOKEN` isn't configured)
57
+ - Use `prerelease: true` to include prereleases when fetching latest (needed for repos that only publish prerelease versions)
58
+
59
+ - **`gitea-release`**: best for tools with prebuilt binaries on Gitea, Forgejo, or Codeberg.
60
+ - Guide: [Gitea/Forgejo Release Installation Guide](installation-methods.md#gitea-release.md)
61
+ - Requires `instanceUrl` (e.g., `https://codeberg.org`) and `repo` (e.g., `Codeberg/pages-server`)
62
+ - Supports optional `token` for private repos or rate-limited instances
63
+ - Use `prerelease: true` to include prereleases when fetching latest
64
+
65
+ - **`brew`**: use if the tool is officially available on Homebrew.
66
+ - Guide: [Homebrew Installation Guide](installation-methods.md#homebrew.md)
67
+
68
+ - **`cargo`**: prefer for Rust tools available on crates.io.
69
+ - Guide: [Cargo Installation Guide](installation-methods.md#cargo.md)
70
+
71
+ - **`npm`**: for tools published as npm packages.
72
+ - Guide: [npm Installation Guide](installation-methods.md#npm.md)
73
+
74
+ - **`curl-script`**: for tools with an official install script.
75
+ - Guide: [Curl Script Installation Guide](installation-methods.md#curl-script.md)
76
+
77
+ - **`curl-tar`**: for direct archive downloads from a stable URL.
78
+ - Guide: [Curl Tar Installation Guide](installation-methods.md#curl-tar.md)
79
+
80
+ - **`curl-binary`**: for direct binary file downloads (no archive extraction).
81
+ - Guide: [Curl Binary Installation Guide](installation-methods.md#curl-binary.md)
82
+
83
+ - **`manual`**: for custom install logic or dotfiles-provided binaries/scripts. Can be called without params: `install('manual')`.
84
+ - Guide: [Manual Installation Guide](installation-methods.md#manual.md)
85
+
86
+ - **`zsh-plugin`**: for zsh plugins that are cloned from Git repositories.
87
+ - Guide: [Zsh Plugin Installation Guide](installation-methods.md#zsh-plugin.md)
88
+
89
+ ### Step 2: Configure Binary Specification
90
+
91
+ **Important**: `.bin(name, pattern?)` declares which executables the tool provides. It generates a shim for each binary name. The shim acts as a launcher — when a user runs the shim, it triggers installation if the tool isn't installed yet, making the tool available system-wide without manual setup. Shims also record usage asynchronously for dashboard analytics. Users can resolve the real path to a binary (bypassing shims) with `dotfiles bin <name>`.
92
+
93
+ To disable usage tracking globally, set `DOTFILES_USAGE_TRACKING=0` in your environment.
94
+
95
+ > **Every tool that provides a binary MUST have at least one `.bin()` declaration.** Without it, no shim is generated and the tool won't be accessible from the command line. Even if a tool is installed via brew or npm and is already on PATH, always declare `.bin()` so the dotfiles system manages it consistently.
96
+
97
+ ```ts
98
+ // Single binary with default pattern
99
+ install('github-release', { repo: 'owner/tool' }).bin('tool');
100
+
101
+ // Multiple binaries - chain .bin() calls
102
+ install('github-release', { repo: 'owner/tool' }).bin('tool').bin('tool-helper');
103
+
104
+ // Custom pattern for binary location in archive
105
+ install('github-release', { repo: 'owner/tool' }).bin('tool', '*/bin/tool'); // Pattern: {,*/}tool by default
106
+ ```
107
+
108
+ **Binary Pattern Matching (for archive-based installation methods only)**:
109
+
110
+ - **Default Pattern**: `{,*/}name` - matches binary at root or one level deep
111
+ - **Custom Patterns**: Use [minimatch](https://github.com/isaacs/minimatch) glob patterns with brace expansion
112
+ - `'*/bin/tool'` - Binary in bin subdirectory
113
+ - `'tool-*/bin/tool'` - Versioned directory structure
114
+ - `'tool'` - Exact binary at archive root
115
+
116
+ **Key Context Variables** (used throughout configuration):
117
+
118
+ - `ctx.toolDir` → Directory containing the `.tool.ts` file (for files next to tool config)
119
+ - `ctx.currentDir` → Tool's stable `current` symlink directory (for installed assets after install)
120
+ - `ctx.toolName` → Name of the tool being configured
121
+ - `ctx.projectConfig.paths.binariesDir` → Tool binaries directory
122
+ - `ctx.projectConfig.paths.generatedDir` → Generated files directory
123
+ - `ctx.replaceInFile()` → Perform regex-based file modifications (see Step 6)
124
+ - `ctx.resolve()` → Resolve a glob pattern to a single path (throws if 0 or multiple matches)
125
+ - `ctx.log` → Logger for user-facing messages (trace/debug/info/warn/error)
126
+ - Use `~/` for paths relative to user's home directory (tilde expansion is automatic)
127
+
128
+ Reference: [API Reference](api-reference.md) and [Context API](api-reference.md#context-api)
129
+
130
+ ### Step 2.5: Configure Installation Environment (if needed)
131
+
132
+ All installation methods support an `env` parameter for setting environment variables during installation. This can be static or dynamic:
133
+
134
+ ```ts
135
+ // Static environment variables
136
+ install('github-release', {
137
+ repo: 'owner/tool',
138
+ env: { CUSTOM_FLAG: 'true' },
139
+ }).bin('tool');
140
+
141
+ // Dynamic environment variables (receives context with projectConfig, stagingDir)
142
+ install('curl-script', {
143
+ url: 'https://example.com/install.sh',
144
+ shell: 'bash',
145
+ env: (ctx) => ({ INSTALL_DIR: ctx.stagingDir }),
146
+ }).bin('tool');
147
+ ```
148
+
149
+ **Environment Context** (available in dynamic `env` functions):
150
+
151
+ - `ctx.projectConfig` → Full project configuration
152
+ - `ctx.stagingDir` → Temporary installation directory (becomes versioned path after success)
153
+
154
+ > **Note:** For `curl-script`, the env context also includes `scriptPath` (path to downloaded script).
155
+
156
+ ### Step 3: Add Shell Integration
157
+
158
+ Use the fluent shell configurator with `.zsh()`, `.bash()`, or `.powershell()` methods.
159
+
160
+ ```ts
161
+ install('github-release', { repo: 'owner/tool' })
162
+ .bin('tool')
163
+ .zsh((shell) =>
164
+ shell
165
+ .env({
166
+ TOOL_HOME: ctx.currentDir,
167
+ TOOL_CONFIG_DIR: ctx.toolDir,
168
+ })
169
+ .aliases({
170
+ t: 'tool',
171
+ ts: 'tool status',
172
+ })
173
+ .completions('_tool') // Relative path resolves to toolDir/_tool
174
+ .sourceFile('init.zsh') // Relative path resolves to toolDir/init.zsh (skips if missing)
175
+ .always(/* zsh */ `
176
+ # Fast runtime setup (runs every shell startup)
177
+ ...
178
+ `)
179
+ );
180
+ ```
181
+
182
+ > **⚠️ CRITICAL: Shell Startup Performance**
183
+ >
184
+ > All tool configurations MUST be optimized for shell boot time. Every millisecond counts when the shell starts.
185
+ >
186
+ > **The golden rule**: Generate static files once (in `after-install` hook), then source them at shell startup.
187
+ >
188
+ > - ❌ **BAD**: Running `eval "$(tool init)"` in `.always()` - executes on every shell start
189
+ > - ✅ **GOOD**: Using `.completions({ cmd: '...' })` - generates static file once, sources it at startup
190
+ > - ✅ **GOOD**: Using `after-install` hook to generate static files, then `.sourceFile()` to load them
191
+ > - ✅ **GOOD**: Using `.functions()` with `.sourceFunction()` - defines function once, sources its output at startup
192
+ >
193
+ > If a tool requires dynamic initialization (e.g., `eval "$(tool init)"`), generate the output to a static file in the `after-install` hook and source that file instead.
194
+
195
+ **Script Timing**:
196
+
197
+ - `.always(script)` - Runs every time shell starts (fast operations only)
198
+ - `.once(script)` - Runs only once after install/update (expensive operations)
199
+ - `.functions(record)` - Define shell functions
200
+
201
+ **Shell Configurator Methods**:
202
+
203
+ - `.env(record)` - Set environment variables (PATH prohibited - use `.path()`)
204
+ - `.path(dir)` - Add directory to PATH (deduplicated)
205
+ - `.aliases(record)` - Set command aliases
206
+ - `.completions(path | config)` - Set command completions
207
+ - `.sourceFile(path)` - Source a file (skips if missing)
208
+ - `.sourceFunction(fnName)` - Source output of a function defined via `.functions()`
209
+ - `.source(content)` - Source output of inline shell code (see below)
210
+ - `.always(script)` - Fast runtime setup scripts
211
+ - `.once(script)` - Expensive one-time setup scripts
212
+ - `.functions(record)` - Define shell functions
213
+
214
+ **Completions Syntax**:
215
+
216
+ > **Lifecycle**: All completions are generated only after `dotfiles install` succeeds,
217
+ > not during `dotfiles generate`. This ensures cmd-based completions can execute the installed
218
+ > binary and callbacks receive the actual installed version in `ctx.version`.
219
+
220
+ ```ts
221
+ // From static file next to .tool.ts
222
+ .completions('_tool')
223
+
224
+ // From installed archive (use ctx.currentDir for absolute path)
225
+ .completions(`${ctx.currentDir}/completions/zsh/_tool`)
226
+
227
+ // From command output
228
+ .completions({ cmd: 'tool completion zsh' })
229
+
230
+ // From direct URL (filename derived from URL)
231
+ .completions({
232
+ url: 'https://raw.githubusercontent.com/owner/repo/main/completions/_tool'
233
+ })
234
+
235
+ // From archive URL (requires source path within extracted archive)
236
+ .completions({
237
+ url: 'https://github.com/owner/repo/releases/download/v1.0/completions.tar.gz',
238
+ source: `${ctx.currentDir}/completions/_tool`
239
+ })
240
+
241
+ // With version in URL (callback receives ctx.version after install)
242
+ .completions((ctx) => ({
243
+ url: `https://github.com/owner/repo/releases/download/${ctx.version}/completions.tar.gz`,
244
+ source: `${ctx.currentDir}/completions/_tool`,
245
+ }))
246
+
247
+ // With bin override (when binary name differs from tool name)
248
+ .completions({
249
+ cmd: 'fnm completions --shell zsh',
250
+ bin: 'fnm', // Results in '_fnm' instead of default
251
+ })
252
+ ```
253
+
254
+ **Completion Path Resolution**:
255
+
256
+ - **Relative paths** → resolve to `toolDir` (directory containing `.tool.ts`)
257
+ - **Absolute paths** → used as-is
258
+ - **For archive files** → use `ctx.currentDir` to build absolute paths
259
+
260
+ **Functions and sourceFunction Syntax**:
261
+
262
+ ```ts
263
+ // Define shell functions
264
+ .functions({
265
+ 'my-wrapper': /* zsh */`
266
+ original-command --my-defaults "$@"
267
+ `,
268
+ 'tool-safe': /* zsh */`
269
+ TOOL_CONFIG="${ctx.toolDir}/config.yaml" tool "$@"
270
+ `,
271
+ })
272
+
273
+ // Source output of a function defined via .functions()
274
+ // Useful for tools that require `eval "$(tool init)"` style initialization
275
+ .functions({
276
+ initTool: 'tool env --use-on-cd',
277
+ })
278
+ .sourceFunction('initTool')
279
+ // Generates: source <(initTool) in bash/zsh, . (initTool) in PowerShell
280
+ ```
281
+
282
+ **sourceFunction** is type-safe: you can only pass function names that were defined via `.functions()` earlier in the chain. This pattern is ideal for tools requiring dynamic initialization like `fnm`, `zoxide`, or `pyenv`.
283
+
284
+ **source Syntax** (inline sourcing):
285
+
286
+ ```ts
287
+ // Source the output of inline shell code
288
+ // Content must PRINT shell code to stdout - that output gets sourced
289
+ .source('fnm env --use-on-cd')
290
+ // Generates:
291
+ // __dotfiles_source_toolname_0() {
292
+ // fnm env --use-on-cd
293
+ // }
294
+ // source <(__dotfiles_source_toolname_0)
295
+ // unset -f __dotfiles_source_toolname_0
296
+
297
+ // Useful when you don't need a named function
298
+ .source('echo "export MY_VAR=value"')
299
+ ```
300
+
301
+ Use `.source()` when you need to source command output inline without defining a named function via `.functions()`. The content must **print shell code to stdout** - this output is then sourced (executed) in the current shell.
302
+
303
+ Reference: [Shell Integration Guide](shell-and-hooks.md) and [Completions Guide](shell-and-hooks.md#completions)
304
+
305
+ ### Step 4: Configure File Management (Symlinks)
306
+
307
+ Relative symlink source paths resolve to `ctx.toolDir` (the directory containing the `.tool.ts` file). Leading `./` is optional.
308
+
309
+ ```ts
310
+ install('github-release', { repo: 'owner/tool' })
311
+ .bin('tool')
312
+ .symlink('config.toml', '~/.config/tool/config.toml') // Resolves to ctx.toolDir/config.toml
313
+ .symlink('./themes/', '~/.config/tool/themes'); // Leading ./ is optional
314
+ ```
315
+
316
+ Reference: [Shell Integration Guide](shell-and-hooks.md#symbolic-links)
317
+
318
+ ### Step 5: Add Platform Support (only when needed)
319
+
320
+ > **Important**: Only use `.platform()` when a single installer unable to provide necessary binaries. The `github-release` installer automatically selects the correct asset based on standard naming conventions (`darwin`/`linux`, `amd64`/`arm64`/`x86_64`). Do not use `.platform()` just to specify different asset patterns for the same installation method.
321
+
322
+ Use `.platform()` for platform- and architecture-specific overrides. The callback receives an `install` function for that specific platform.
323
+
324
+ ```ts
325
+ import { Architecture, defineTool, Platform } from '@alexgorbatchev/dotfiles';
326
+
327
+ export default defineTool((install) =>
328
+ install()
329
+ .bin('tool')
330
+ // macOS-specific installation (different method: brew)
331
+ .platform(Platform.MacOS, (install) => install('brew', { formula: 'tool' }))
332
+ // Linux-specific installation (different method: github-release)
333
+ .platform(Platform.Linux, (install) =>
334
+ install('github-release', {
335
+ repo: 'owner/tool',
336
+ }))
337
+ // Windows with Arm64
338
+ .platform(Platform.Windows, Architecture.Arm64, (install) =>
339
+ install('github-release', {
340
+ repo: 'owner/tool',
341
+ }))
342
+ );
343
+ ```
344
+
345
+ Reference: [Platform Support Guide](configuration.md#platform-support)
346
+
347
+ ### Step 6: Add Installation Hooks (if needed)
348
+
349
+ Use hooks for custom installation logic when fluent configuration is insufficient.
350
+
351
+ ```ts
352
+ install('github-release', { repo: 'owner/tool' })
353
+ .bin('tool')
354
+ .hook('after-install', async ({ log, $, installedDir }) => {
355
+ await $`${installedDir}/tool init`;
356
+ log.info('Tool initialized');
357
+ });
358
+ ```
359
+
360
+ **Hook Events**: `'before-install'`, `'after-download'`, `'after-extract'`, `'after-install'`
361
+
362
+ **Executing Installed Binaries**: In `after-install` hooks, the shell's PATH is automatically enhanced to include directories containing installed binaries. You can execute freshly installed tools by name:
363
+
364
+ ```ts
365
+ install('github-release', { repo: 'owner/tool' })
366
+ .bin('tool')
367
+ .hook('after-install', async ({ $, log }) => {
368
+ // Binary is automatically available by name - no full path needed
369
+ await $`tool --version`;
370
+ await $`tool init`;
371
+ log.info('Tool initialized');
372
+ });
373
+ ```
374
+
375
+ **File Modifications in Hooks**: Use `ctx.replaceInFile()` for regex-based file modifications:
376
+
377
+ ```ts
378
+ install('github-release', { repo: 'owner/tool' })
379
+ .bin('tool')
380
+ .hook('after-install', async (ctx) => {
381
+ // Replace a value in a config file (returns true if replaced)
382
+ const wasReplaced = await ctx.replaceInFile(
383
+ `${ctx.installedDir}/config.toml`,
384
+ /default_theme = ".*"/,
385
+ 'default_theme = "dark"',
386
+ );
387
+
388
+ // Line-by-line replacement with callback
389
+ await ctx.replaceInFile(
390
+ `${ctx.installedDir}/settings.ini`,
391
+ /version=(\d+)/,
392
+ (match) => `version=${Number(match.captures[0]) + 1}`,
393
+ { mode: 'line' },
394
+ );
395
+
396
+ // With error message - logs "message: filePath: pattern" if pattern not found
397
+ await ctx.replaceInFile(`${ctx.installedDir}/config.toml`, /api_key = ".*"/, 'api_key = "secret"', {
398
+ errorMessage: 'Could not find api_key setting in config.toml',
399
+ });
400
+ });
401
+ ```
402
+
403
+ **`replaceInFile` options:**
404
+
405
+ - `mode` - `'file'` (default) or `'line'` (process each line separately)
406
+ - `errorMessage` - If provided and no matches found, logs error: `Could not find '<pattern>' in <filePath>`
407
+
408
+ **Returns:** `Promise<boolean>` - `true` if replacements were made, `false` if no matches found
409
+
410
+ **Resolving Glob Patterns**: Use `ctx.resolve()` to match a glob pattern to a single path:
411
+
412
+ ```ts
413
+ install('github-release', { repo: 'owner/tool' })
414
+ .bin('tool')
415
+ .zsh((shell) =>
416
+ shell.always(/* zsh */ `
417
+ # Resolve versioned directory (e.g., tool-14.1.0-x86_64-linux)
418
+ source "${ctx.resolve('completions/*.zsh')}"
419
+ `)
420
+ );
421
+ ```
422
+
423
+ `ctx.resolve(pattern)` returns the absolute path if exactly one match is found. It throws `ResolveError` and logs ERROR if:
424
+
425
+ - No matches are found
426
+ - Multiple matches are found (ambiguous)
427
+
428
+ This is useful for referencing files with variable names (versioned directories, platform-specific assets).
429
+
430
+ Reference: [Hooks Guide](shell-and-hooks.md#hooks) and [API Reference](api-reference.md#hook-event-string-handler-hookhandler)
431
+
432
+ ### Step 7: Disable a Tool (if needed)
433
+
434
+ Use `.disable()` to temporarily skip a tool during generation without removing its configuration. A warning will be logged when the tool is skipped.
435
+
436
+ ```ts
437
+ install('github-release', { repo: 'owner/tool' }).bin('tool').disable(); // Tool will be skipped with a warning
438
+ ```
439
+
440
+ This is useful for:
441
+
442
+ - Temporarily disabling a broken or unavailable tool
443
+ - Testing configurations without installing certain tools
444
+ - Keeping tool configurations for future use
445
+
446
+ ### Step 8: Restrict to Specific Hosts (if needed)
447
+
448
+ Use `.hostname(pattern)` to restrict a tool to specific machines. When a hostname is specified, the tool is only installed on machines where the hostname matches the pattern.
449
+
450
+ ```ts
451
+ // Exact hostname match
452
+ install('github-release', { repo: 'owner/work-tools' })
453
+ .bin('work-tool')
454
+ .hostname('my-work-laptop');
455
+
456
+ // Regex pattern match (any hostname starting with "work-")
457
+ install('github-release', { repo: 'owner/work-tools' })
458
+ .bin('work-tool')
459
+ .hostname(/^work-.*$/);
460
+ ```
461
+
462
+ This is useful for:
463
+
464
+ - Work-specific tools that should only be installed on work machines
465
+ - Personal tools that should only be installed on personal machines
466
+ - Machine-specific configurations (different tools for laptops vs desktops)
467
+
468
+ When the hostname doesn't match:
469
+
470
+ - A warning is logged indicating the tool is being skipped
471
+ - Any previously generated artifacts are cleaned up
472
+
473
+ ## Output Requirements
474
+
475
+ ### File Structure
476
+
477
+ Create a file named `{tool-name}.tool.ts`:
478
+
479
+ ```ts
480
+ import { defineTool } from '@alexgorbatchev/dotfiles';
481
+
482
+ export default defineTool((install, ctx) =>
483
+ // Your configuration here
484
+ );
485
+ ```
486
+
487
+ ### Required Elements
488
+
489
+ Your configuration MUST include:
490
+
491
+ 1. An installation method via `install(...)`.
492
+ 2. Binary declaration(s) via `.bin(...)` if the tool provides binaries.
493
+
494
+ ### Documentation Comments
495
+
496
+ Include a brief JSDoc comment explaining:
497
+
498
+ - What the tool does.
499
+ - Platform notes (if applicable).
500
+ - The tool’s home URL as the very last line.
501
+
502
+ Do NOT include archive-structure narration in the comment (the code already shows the method).
503
+
504
+ ## Example Output
505
+
506
+ ### Example 1: Simple GitHub Release Tool
507
+
508
+ ```ts
509
+ import { defineTool } from '@alexgorbatchev/dotfiles';
510
+
511
+ /**
512
+ * ripgrep - A line-oriented search tool that recursively searches your current
513
+ * directory for a regex pattern.
514
+ *
515
+ * https://github.com/BurntSushi/ripgrep
516
+ */
517
+ export default defineTool((install) =>
518
+ install('github-release', {
519
+ repo: 'BurntSushi/ripgrep',
520
+ }).bin('rg')
521
+ );
522
+ ```
523
+
524
+ ### Example 1b: GitHub Release with gh CLI
525
+
526
+ ```ts
527
+ import { defineTool } from '@alexgorbatchev/dotfiles';
528
+
529
+ /**
530
+ * ripgrep - Using gh CLI for API access (GitHub Enterprise or auth via gh).
531
+ *
532
+ * https://github.com/BurntSushi/ripgrep
533
+ */
534
+ export default defineTool((install) =>
535
+ install('github-release', {
536
+ repo: 'BurntSushi/ripgrep',
537
+ ghCli: true, // Use `gh api` instead of direct fetch
538
+ }).bin('rg')
539
+ );
540
+ ```
541
+
542
+ ### Example 2: Tool with Shell Integration
543
+
544
+ ```ts
545
+ import { defineTool } from '@alexgorbatchev/dotfiles';
546
+
547
+ /**
548
+ * fzf - Command-line fuzzy finder.
549
+ *
550
+ * https://github.com/junegunn/fzf
551
+ */
552
+ export default defineTool((install) =>
553
+ install('github-release', {
554
+ repo: 'junegunn/fzf',
555
+ })
556
+ .bin('fzf')
557
+ .zsh((shell) =>
558
+ shell
559
+ .env({
560
+ FZF_DEFAULT_OPTS: '--color=fg+:cyan,bg+:black,hl+:yellow',
561
+ })
562
+ .aliases({ f: 'fzf' })
563
+ .completions('completion.zsh') // Resolves to ctx.toolDir/completion.zsh
564
+ .sourceFile('key-bindings.zsh') // Resolves to ctx.toolDir/key-bindings.zsh
565
+ )
566
+ );
567
+ ```
568
+
569
+ ### Example 3: Manual Installation (Dotfiles Script)
570
+
571
+ ```ts
572
+ import { defineTool } from '@alexgorbatchev/dotfiles';
573
+
574
+ /**
575
+ * deploy - Custom deployment script included with dotfiles.
576
+ *
577
+ * https://example.com/deploy
578
+ */
579
+ export default defineTool((install) =>
580
+ install('manual', {
581
+ binaryPath: './scripts/deploy.sh',
582
+ })
583
+ .bin('deploy')
584
+ .symlink('./deploy.config.yaml', '~/.config/deploy/config.yaml')
585
+ );
586
+ ```
587
+
588
+ ### Example 3b: Manual Without Params
589
+
590
+ ```ts
591
+ import { defineTool } from '@alexgorbatchev/dotfiles';
592
+
593
+ /**
594
+ * tokscale - Token scaling utility via bun.
595
+ *
596
+ * https://example.com/tokscale
597
+ */
598
+ export default defineTool((install) =>
599
+ install('manual')
600
+ .bin('tokscale')
601
+ .dependsOn('bun')
602
+ .zsh((shell) =>
603
+ shell.functions({
604
+ tokscale: `bun x tokscale@latest`,
605
+ })
606
+ )
607
+ );
608
+ ```
609
+
610
+ ### Example 4: Configuration-Only Tool
611
+
612
+ ```ts
613
+ import { defineTool } from '@alexgorbatchev/dotfiles';
614
+
615
+ /**
616
+ * git - Git configuration and aliases.
617
+ *
618
+ * https://git-scm.com
619
+ */
620
+ export default defineTool((install) =>
621
+ install() // Configuration-only: no install params, no .bin()
622
+ .symlink('./gitconfig', '~/.gitconfig')
623
+ .zsh((shell) =>
624
+ shell.aliases({
625
+ g: 'git',
626
+ gs: 'git status',
627
+ ga: 'git add',
628
+ gc: 'git commit',
629
+ })
630
+ )
631
+ );
632
+ ```
633
+
634
+ ### Example 5: Rust Tool with Cargo
635
+
636
+ ```ts
637
+ import { defineTool } from '@alexgorbatchev/dotfiles';
638
+
639
+ /**
640
+ * eza - A modern replacement for ls.
641
+ *
642
+ * https://github.com/eza-community/eza
643
+ */
644
+ export default defineTool((install) =>
645
+ install('cargo', {
646
+ crateName: 'eza',
647
+ githubRepo: 'eza-community/eza',
648
+ })
649
+ .bin('eza')
650
+ .zsh((shell) =>
651
+ shell
652
+ .aliases({
653
+ ls: 'eza',
654
+ ll: 'eza -l',
655
+ la: 'eza -la',
656
+ tree: 'eza --tree',
657
+ })
658
+ .completions('_eza') // Resolves to ctx.toolDir/_eza
659
+ )
660
+ );
661
+ ```
662
+
663
+ ### Example 6: npm Tool
664
+
665
+ ```ts
666
+ import { defineTool } from '@alexgorbatchev/dotfiles';
667
+
668
+ /**
669
+ * prettier - An opinionated code formatter.
670
+ *
671
+ * https://prettier.io
672
+ */
673
+ export default defineTool((install) =>
674
+ install('npm', {
675
+ package: 'prettier',
676
+ }).bin('prettier')
677
+ );
678
+ ```
679
+
680
+ ### Example 6b: Tool with Shell Functions
681
+
682
+ ```ts
683
+ import { defineTool } from '@alexgorbatchev/dotfiles';
684
+
685
+ /**
686
+ * kubectl - Kubernetes command-line tool with custom wrappers.
687
+ *
688
+ * https://kubernetes.io/docs/reference/kubectl/
689
+ */
690
+ export default defineTool((install) =>
691
+ install('github-release', {
692
+ repo: 'kubernetes/kubectl',
693
+ })
694
+ .bin('kubectl')
695
+ .zsh((shell) =>
696
+ shell
697
+ .env({
698
+ KUBECONFIG: '~/.kube/config',
699
+ })
700
+ .aliases({
701
+ k: 'kubectl',
702
+ kgp: 'kubectl get pods',
703
+ })
704
+ .completions({ cmd: 'kubectl completion zsh' })
705
+ .functions({
706
+ kns: /* zsh */ `
707
+ kubectl config set-context --current --namespace="$1"
708
+ `,
709
+ kctx: /* zsh */ `
710
+ kubectl config use-context "$1"
711
+ `,
712
+ })
713
+ )
714
+ );
715
+ ```
716
+
717
+ ### Example 7: Tool with Dynamic Initialization
718
+
719
+ ```ts
720
+ import { defineTool } from '@alexgorbatchev/dotfiles';
721
+
722
+ /**
723
+ * zoxide - A smarter cd command with frecency tracking.
724
+ *
725
+ * https://github.com/ajeetdsouza/zoxide
726
+ */
727
+ export default defineTool((install) =>
728
+ install('github-release', {
729
+ repo: 'ajeetdsouza/zoxide',
730
+ })
731
+ .bin('zoxide')
732
+ .zsh((shell) =>
733
+ shell
734
+ .env({
735
+ _ZO_DATA_DIR: '~/.local/share/zoxide',
736
+ })
737
+ .completions({ cmd: 'zoxide completions zsh' }).always(/* zsh */ `
738
+ # Initialize zoxide with cd replacement
739
+ eval "$(zoxide init zsh --cmd cd)"
740
+ `)
741
+ )
742
+ );
743
+ ```
744
+
745
+ ### Example 8: Zsh Plugin (Git Repository)
746
+
747
+ ```ts
748
+ import { defineTool } from '@alexgorbatchev/dotfiles';
749
+
750
+ /**
751
+ * zsh-vi-mode - A better and friendly vi(vim) mode plugin for ZSH.
752
+ *
753
+ * https://github.com/jeffreytse/zsh-vi-mode
754
+ */
755
+ export default defineTool((install) =>
756
+ install('zsh-plugin', {
757
+ repo: 'jeffreytse/zsh-vi-mode',
758
+ })
759
+ .zsh((shell) =>
760
+ shell.env({
761
+ ZVM_VI_INSERT_ESCAPE_BINDKEY: 'jj',
762
+ ZVM_CURSOR_STYLE_ENABLED: 'false',
763
+ })
764
+ )
765
+ );
766
+ ```
767
+
768
+ ### Example 9: Gitea/Forgejo Release Tool
769
+
770
+ ```ts
771
+ import { defineTool } from '@alexgorbatchev/dotfiles';
772
+
773
+ /**
774
+ * pages-server - Codeberg Pages static site server.
775
+ *
776
+ * https://codeberg.org/Codeberg/pages-server
777
+ */
778
+ export default defineTool((install) =>
779
+ install('gitea-release', {
780
+ instanceUrl: 'https://codeberg.org',
781
+ repo: 'Codeberg/pages-server',
782
+ }).bin('pages-server')
783
+ );
784
+ ```
785
+
786
+ ## Syncing Changes
787
+
788
+ After any `.tool.ts` file change, you **must** run `dotfiles generate` to sync the generated artifacts (shims, shell scripts, completions). This applies whenever:
789
+
790
+ - A new `.tool.ts` file is created
791
+ - An existing `.tool.ts` file is deleted
792
+ - An existing `.tool.ts` file is modified
793
+
794
+ ```bash
795
+ bun cli --config=<path-to-config.ts> generate
796
+ ```
797
+
798
+ Without this step, the generated shims and shell configuration will be out of sync with the tool definitions.
799
+
800
+ ## Quality Checklist
801
+
802
+ **Installation & binaries**
803
+
804
+ - ✅ Installation method matches the tool's official distribution
805
+ - ✅ Every tool that provides executables has at least one `.bin()` declaration
806
+ - ✅ `.bin(name, pattern?)` declarations match actual executables
807
+ - ✅ Binary patterns are correct for archive structures
808
+ - ✅ `.dependsOn()` uses binary names (not tool names) from other tools' `.bin()` declarations
809
+
810
+ **Paths**
811
+
812
+ - ✅ Use `ctx.toolDir` for files next to `.tool.ts` (tool configuration directory)
813
+ - ✅ Use `ctx.currentDir` for installed assets (stable symlink to versioned directory)
814
+ - ✅ For symlink targets and environment variables: use `~/` (tilde expansion is automatic)
815
+ - ✅ All relative paths (`.completions()`, `.sourceFile()`, `.symlink()`) resolve to `toolDir`
816
+ - ✅ For archive files, use `ctx.currentDir` to build absolute paths
817
+ - ✅ Never use hardcoded absolute paths like `/home/user/...`
818
+
819
+ **Shell integration**
820
+
821
+ - ✅ Use `.completions({ cmd: '...' })` for dynamic completions (not `.once()`)
822
+ - ✅ Use `.once()` only for expensive one-time setup (cache building, initialization)
823
+ - ✅ Use `.always()` for fast runtime setup (environment, eval statements)
824
+ - ✅ Use `.functions()` for shell function wrappers
825
+ - ✅ Shell scripts are fast and use context variables
826
+ - ✅ Completions configured within shell blocks (`.zsh()`, `.bash()`, `.powershell()`)
827
+
828
+ **Function signature**
829
+
830
+ - ✅ Import `defineTool` from `'@alexgorbatchev/dotfiles'`
831
+ - ✅ Use `export default defineTool((install, ctx) => ...)` - omit `ctx` if not used
832
+ - ✅ Call `install(method, params)` first to specify installation
833
+ - ✅ Chain additional configuration methods
834
+
835
+ ## References
836
+
837
+ **Core Documentation**
838
+
839
+ - [API Reference](api-reference.md) - Complete API with all parameters
840
+ - [Getting Started](configuration.md#getting-started) - Basic structure and anatomy
841
+ - [Context API](api-reference.md#context-api) - Path resolution and context variables
842
+
843
+ **Configuration Guides**
844
+
845
+ - [Common Patterns](configuration.md#common-patterns) - Real-world examples
846
+ - [Shell Integration](shell-and-hooks.md) - Shell configuration, symlinks
847
+ - [Completions](shell-and-hooks.md#completions) - Command completion setup
848
+
849
+ **Installation Methods**
850
+
851
+ - [GitHub Release Installation](installation-methods.md#github-release.md)
852
+ - [Gitea/Forgejo Release Installation](installation-methods.md#gitea-release.md)
853
+ - [Homebrew Installation](installation-methods.md#homebrew.md)
854
+ - [Cargo Installation](installation-methods.md#cargo.md)
855
+ - [npm Installation](installation-methods.md#npm.md)
856
+ - [Curl Script Installation](installation-methods.md#curl-script.md)
857
+ - [Curl Tar Installation](installation-methods.md#curl-tar.md)
858
+ - [Curl Binary Installation](installation-methods.md#curl-binary.md)
859
+ - [Manual Installation](installation-methods.md#manual.md)
860
+ - [Zsh Plugin Installation](installation-methods.md#zsh-plugin.md)
861
+
862
+ **Other Resources**
863
+
864
+ - [Platform Support](configuration.md#platform-support) - Platform-specific configurations
865
+ - [Hooks](shell-and-hooks.md#hooks) - Installation lifecycle hooks
866
+ - [Troubleshooting](configuration.md#troubleshooting) - Common issues and solutions