Skip to content

Commit ec8c26a

Browse files
committed
chore: move all homebrew calls to the utils.installviapackagemgr
1 parent d9b38f7 commit ec8c26a

21 files changed

Lines changed: 95 additions & 100 deletions

File tree

CLAUDE.md

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -300,16 +300,34 @@ Utils.isWindows()
300300

301301
**Package Installation:**
302302

303-
Always use `Utils.installViaPkgMgr(pkg)` from `@codifycli/plugin-core` to install system packages. This is platform-agnostic and automatically dispatches to the correct package manager (Homebrew on macOS, apt on Debian/Ubuntu, etc.). Never hardcode package manager calls like `brew install`, `apt-get install -y`, or `sudo apt install` in resource code.
303+
Always use `Utils.installViaPkgMgr(pkg)` from `@codifycli/plugin-core` to install system packages. This is platform-agnostic and automatically dispatches to the correct package manager (Homebrew on macOS, apt on Debian/Ubuntu, etc.). Never hardcode package manager calls like `brew install`, `apt-get install -y`, or `sudo apt install` in resource code — not even inside macOS-only branches.
304+
305+
The function accepts an optional `PkgMgrOptionsMap` (second arg) for per-PM flags, and an optional `forcePackageManager` (third arg) to skip OS detection:
304306

305307
```typescript
306-
// Correct — works on macOS and Linux
308+
import { Utils, PackageManager } from '@codifycli/plugin-core';
309+
310+
// Auto-detect OS — works on macOS (brew) and Linux (apt/dnf/etc.)
307311
await Utils.installViaPkgMgr('curl');
308312
await Utils.uninstallViaPkgMgr('curl');
309313

310-
// Wrong — hardcoded to a specific platform/package manager
311-
await $.spawn('sudo apt-get install -y curl');
312-
await $.spawn('brew install curl');
314+
// Force brew for a macOS-only formula resource
315+
await Utils.installViaPkgMgr('syncthing', undefined, PackageManager.BREW);
316+
await Utils.uninstallViaPkgMgr('syncthing', undefined, PackageManager.BREW);
317+
318+
// Force brew + cask for a macOS GUI app
319+
await Utils.installViaPkgMgr('cursor', { [PackageManager.BREW]: { cask: true } }, PackageManager.BREW);
320+
await Utils.uninstallViaPkgMgr('cursor', { [PackageManager.BREW]: { cask: true } }, PackageManager.BREW);
321+
322+
// Auto-detect OS but pass custom flags per PM
323+
await Utils.installViaPkgMgr('github-cli', {
324+
[PackageManager.APT]: { flags: ['--allow-unauthenticated'] },
325+
[PackageManager.DNF]: { flags: ['--repo', 'gh-cli'] },
326+
});
327+
328+
// Wrong — direct brew calls are forbidden even in macOS-only code
329+
await $.spawn('brew install syncthing', { ... });
330+
await $.spawn('brew install --cask cursor', { ... });
313331
```
314332

315333
This applies to prerequisite checks too. When a resource needs a system dependency (e.g. `curl`, `git`, `make`), always install via `Utils.installViaPkgMgr` rather than spawning a package manager directly.

package-lock.json

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"license": "ISC",
4242
"type": "module",
4343
"dependencies": {
44-
"@codifycli/plugin-core": "1.2.3",
44+
"@codifycli/plugin-core": "1.2.5-beta.1",
4545
"@codifycli/schemas": "1.2.0",
4646
"ajv": "^8.18.0",
4747
"ajv-formats": "^2.1.1",

src/resources/asdf/asdf.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { CreatePlan, ExampleConfig, FileUtils, Resource, ResourceSettings, SpawnStatus, Utils as CoreUtils, getPty, z, Utils } from '@codifycli/plugin-core';
1+
import { CreatePlan, ExampleConfig, FileUtils, Resource, ResourceSettings, SpawnStatus, Utils as CoreUtils, getPty, z, Utils, PackageManager } from '@codifycli/plugin-core';
22
import { OS } from '@codifycli/schemas';
33
import fs from 'node:fs/promises';
44
import os from 'node:os';
@@ -83,7 +83,7 @@ export class AsdfResource extends Resource<AsdfConfig> {
8383
throw new Error('Homebrew is not installed. Please install Homebrew before installing asdf.');
8484
}
8585

86-
await $.spawn('brew install asdf', { interactive: true, env: { HOMEBREW_NO_AUTO_UPDATE: 1 } });
86+
await Utils.installViaPkgMgr('asdf', undefined, PackageManager.BREW);
8787
}
8888

8989
if (Utils.isLinux()) {
@@ -124,7 +124,7 @@ export class AsdfResource extends Resource<AsdfConfig> {
124124
return;
125125
}
126126

127-
await $.spawn('brew uninstall asdf', { interactive: true, env: { HOMEBREW_NO_AUTO_UPDATE: 1 } });
127+
await Utils.uninstallViaPkgMgr('asdf', undefined, PackageManager.BREW);
128128
} else {
129129
await fs.rm(asdfDir, { recursive: true, force: true });
130130
}

src/resources/aws-cli/cli/aws-cli.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Resource, ResourceSettings, SpawnStatus, Utils, getPty, FileUtils } from '@codifycli/plugin-core';
1+
import { Resource, ResourceSettings, SpawnStatus, Utils, PackageManager, getPty, FileUtils } from '@codifycli/plugin-core';
22
import { OS, StringIndexedObject } from '@codifycli/schemas';
33
import fs from 'node:fs/promises';
44
import os from 'node:os';
@@ -52,7 +52,7 @@ export class AwsCliResource extends Resource<AwsCliConfig> {
5252

5353
if (isArmArch && isHomebrewInstalled) {
5454
console.log('Resource: \'aws-cli\'. Detected that mac is aarch64. Installing AWS-CLI via homebrew')
55-
await $.spawn('HOMEBREW_NO_AUTO_UPDATE=1 brew install awscli', { interactive: true })
55+
await Utils.installViaPkgMgr('awscli', undefined, PackageManager.BREW)
5656

5757
} else if (!isArmArch || isRosettaInstalled) {
5858
console.log('Resource: \'aws-cli\'. Detected that mac is not ARM or Rosetta is installed. Installing AWS-CLI standalone version')
@@ -105,7 +105,7 @@ softwareupdate --install-rosetta
105105
}
106106

107107
if (installLocation.includes('homebrew')) {
108-
await $.spawn('brew uninstall awscli', { interactive: true, env: { HOMEBREW_NO_AUTO_UPDATE: 1 } });
108+
await Utils.uninstallViaPkgMgr('awscli', undefined, PackageManager.BREW);
109109
return;
110110
}
111111

src/resources/cursor/cursor.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
ResourceSettings,
88
SpawnStatus,
99
Utils,
10+
PackageManager,
1011
getPty,
1112
z,
1213
} from '@codifycli/plugin-core';
@@ -170,7 +171,7 @@ export class CursorResource extends Resource<CursorConfig> {
170171

171172
private async installMacOS(): Promise<void> {
172173
const $ = getPty();
173-
await $.spawn('brew install --cask cursor', { interactive: true });
174+
await Utils.installViaPkgMgr('cursor', { [PackageManager.BREW]: { cask: true } }, PackageManager.BREW);
174175
}
175176

176177
private async installLinux(plan: CreatePlan<CursorConfig>): Promise<void> {

src/resources/github-cli/github-cli-alias.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,9 @@ export class GithubCliAliasResource extends Resource<GithubCliAliasConfig> {
6565
.split('\n')
6666
.filter(Boolean)
6767
.map((line) => {
68-
const tabIdx = line.indexOf('\t');
69-
const alias = (tabIdx !== -1 ? line.slice(0, tabIdx) : line).trim();
68+
// gh alias list outputs "alias: expansion" (colon-space separated)
69+
const colonIdx = line.indexOf(':');
70+
const alias = (colonIdx !== -1 ? line.slice(0, colonIdx) : line).trim();
7071
return { alias };
7172
})
7273
.filter((a) => Boolean(a.alias));
@@ -79,7 +80,7 @@ export class GithubCliAliasResource extends Resource<GithubCliAliasConfig> {
7980
const $ = getPty();
8081

8182
const { data, status } = await $.spawnSafe('gh alias list');
82-
if (status === SpawnStatus.ERROR) return null;
83+
if (status === SpawnStatus.ERROR || !data.trim()) return null;
8384

8485
const found = this.parseAliasList(data).find((a) => a.alias === params.alias);
8586
if (!found) return null;
@@ -119,11 +120,12 @@ export class GithubCliAliasResource extends Resource<GithubCliAliasConfig> {
119120
.split('\n')
120121
.filter(Boolean)
121122
.map((line) => {
122-
const tabIdx = line.indexOf('\t');
123-
if (tabIdx === -1) return null;
123+
// gh alias list outputs "alias: expansion" (colon-space separated)
124+
const colonIdx = line.indexOf(':');
125+
if (colonIdx === -1) return null;
124126

125-
const alias = line.slice(0, tabIdx).trim();
126-
const rawExpansion = line.slice(tabIdx + 1).trim();
127+
const alias = line.slice(0, colonIdx).trim();
128+
const rawExpansion = line.slice(colonIdx + 1).trim();
127129
const isShell = rawExpansion.startsWith('!');
128130

129131
return {

src/resources/go/goenv/goenv.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
ResourceSettings,
77
SpawnStatus,
88
Utils,
9+
PackageManager,
910
z,
1011
} from '@codifycli/plugin-core';
1112
import { OS } from '@codifycli/schemas';
@@ -112,10 +113,7 @@ export class GoenvResource extends Resource<GoenvConfig> {
112113

113114
async function installOnMacOS(): Promise<void> {
114115
const $ = getPty();
115-
await $.spawn('brew install goenv', {
116-
interactive: true,
117-
env: { HOMEBREW_NO_AUTO_UPDATE: '1' },
118-
});
116+
await Utils.installViaPkgMgr('goenv', undefined, PackageManager.BREW);
119117
await FileUtils.addToShellRc(GOENV_INIT);
120118
}
121119

@@ -132,9 +130,7 @@ async function installOnLinux(): Promise<void> {
132130

133131
async function uninstallOnMacOS(): Promise<void> {
134132
const $ = getPty();
135-
await $.spawnSafe('brew uninstall goenv', {
136-
env: { HOMEBREW_NO_AUTO_UPDATE: '1' },
137-
});
133+
await Utils.uninstallViaPkgMgr('goenv', undefined, PackageManager.BREW);
138134
await removeGoenvFromShellRc([GOENV_INIT]);
139135
}
140136

src/resources/homebrew/casks-parameter.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ export class CasksParameter extends StatefulParameter<HomebrewConfig, string[]>
100100
for (const cask of casksToInstall) {
101101
const result = await $.spawnSafe(`brew install --casks ${cask}`, {
102102
interactive: true,
103-
env: { HOMEBREW_NO_AUTO_UPDATE: 1, HOMEBREW_NO_ASK: 1, NONINTERACTIVE: 1 }
103+
env: { HOMEBREW_NO_AUTO_UPDATE: 1, HOMEBREW_NO_ASK: 1, NONINTERACTIVE: 1, HOMEBREW_NO_REQUIRE_TAP_TRUST: 1 }
104104
})
105105

106106
if (result.status === SpawnStatus.SUCCESS) {
@@ -111,7 +111,7 @@ export class CasksParameter extends StatefulParameter<HomebrewConfig, string[]>
111111
if (result.data?.includes('It seems there is already an App at')) {
112112
const adoptResult = await $.spawnSafe(`brew install --casks --adopt ${cask}`, {
113113
interactive: true,
114-
env: { HOMEBREW_NO_AUTO_UPDATE: 1, HOMEBREW_NO_ASK: 1, NONINTERACTIVE: 1 }
114+
env: { HOMEBREW_NO_AUTO_UPDATE: 1, HOMEBREW_NO_ASK: 1, NONINTERACTIVE: 1, HOMEBREW_NO_REQUIRE_TAP_TRUST: 1 }
115115
})
116116

117117
if (adoptResult.status === SpawnStatus.SUCCESS) {
@@ -133,7 +133,7 @@ export class CasksParameter extends StatefulParameter<HomebrewConfig, string[]>
133133
const $ = getPty();
134134
const result = await $.spawnSafe(`brew uninstall ${casks.join(' ')}`, {
135135
interactive: true,
136-
env: { HOMEBREW_NO_AUTO_UPDATE: 1, HOMEBREW_NO_ASK: 1, NONINTERACTIVE: 1 }
136+
env: { HOMEBREW_NO_AUTO_UPDATE: 1, HOMEBREW_NO_ASK: 1, NONINTERACTIVE: 1, HOMEBREW_NO_REQUIRE_TAP_TRUST: 1 }
137137
})
138138

139139
if (result.status === SpawnStatus.SUCCESS) {

src/resources/homebrew/formulae-parameter.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export class FormulaeParameter extends StatefulParameter<HomebrewConfig, string[
6161
const $ = getPty();
6262
const result = await $.spawnSafe(`brew install --formulae ${formulae.join(' ')}`, {
6363
interactive: true,
64-
env: { HOMEBREW_NO_AUTO_UPDATE: 1, HOMEBREW_NO_ASK: 1, NONINTERACTIVE: 1 }
64+
env: { HOMEBREW_NO_AUTO_UPDATE: 1, HOMEBREW_NO_ASK: 1, NONINTERACTIVE: 1, HOMEBREW_NO_REQUIRE_TAP_TRUST: 1 }
6565
})
6666

6767
if (result.status === SpawnStatus.SUCCESS) {
@@ -79,7 +79,7 @@ export class FormulaeParameter extends StatefulParameter<HomebrewConfig, string[
7979
const $ = getPty();
8080
const result = await $.spawnSafe(`brew uninstall ${formulae.join(' ')}`, {
8181
interactive: true,
82-
env: { HOMEBREW_NO_AUTO_UPDATE: 1, HOMEBREW_NO_ASK: 1, NONINTERACTIVE: 1 }
82+
env: { HOMEBREW_NO_AUTO_UPDATE: 1, HOMEBREW_NO_ASK: 1, NONINTERACTIVE: 1, HOMEBREW_NO_REQUIRE_TAP_TRUST: 1 }
8383
})
8484

8585
if (result.status === SpawnStatus.SUCCESS) {

0 commit comments

Comments
 (0)