diff --git a/package.json b/package.json index b8153519..c8248f16 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "default", - "version": "1.6.1", + "version": "1.7.1", "description": "Default plugin for Codify - provides 50+ declarative resources for managing development tools and system configuration across macOS and Linux", "main": "dist/index.js", "scripts": { diff --git a/scripts/deploy.ts b/scripts/deploy.ts index 6df530f0..19d6f879 100644 --- a/scripts/deploy.ts +++ b/scripts/deploy.ts @@ -89,6 +89,24 @@ if (!isBeta) { // Build and deploy completions as well. console.log('Deploying completions...') cp.spawnSync('source ~/.zshrc; npm run deploy:completions' , { shell: 'zsh', stdio: 'inherit' }) + + // Trigger vector reindex so search embeddings reflect the latest resources + console.log('Triggering vector reindex...') + const reindexKey = process.env.REINDEX_API_KEY + if (!reindexKey) { + console.warn('REINDEX_API_KEY not set — skipping reindex') + } else { + const res = await fetch('https://api.codifycli.com/v1/embeddings/reindex', { + method: 'POST', + headers: { Authorization: `Bearer ${reindexKey}` }, + }) + if (!res.ok) { + console.error(`Reindex failed: ${res.status} ${await res.text()}`) + } else { + const body = await res.json() as { resources_processed: number; templates_processed: number } + console.log(`Reindex complete — resources: ${body.resources_processed}, templates: ${body.templates_processed}`) + } + } } async function uploadResources(prerelease: boolean) { diff --git a/src/resources/homebrew/casks-parameter.ts b/src/resources/homebrew/casks-parameter.ts index 5d8d27eb..c437bd7c 100644 --- a/src/resources/homebrew/casks-parameter.ts +++ b/src/resources/homebrew/casks-parameter.ts @@ -28,7 +28,7 @@ export class CasksParameter extends StatefulParameter async refresh(desired: string[], config: Partial | null): Promise { const $ = getPty(); - const caskQuery = await $.spawnSafe('brew list --casks -1 --full-name') + const caskQuery = await $.spawnSafe('brew list --casks -1 --full-name', { env: { NONINTERACTIVE: 1 }}) if (caskQuery.status === SpawnStatus.SUCCESS && caskQuery.data !== null && caskQuery.data !== undefined) { const installedCasks = caskQuery.data @@ -100,7 +100,7 @@ export class CasksParameter extends StatefulParameter for (const cask of casksToInstall) { const result = await $.spawnSafe(`brew install --casks ${cask}`, { interactive: true, - env: { HOMEBREW_NO_AUTO_UPDATE: 1 } + env: { HOMEBREW_NO_AUTO_UPDATE: 1, HOMEBREW_NO_ASK: 1, NONINTERACTIVE: 1 } }) if (result.status === SpawnStatus.SUCCESS) { @@ -111,7 +111,7 @@ export class CasksParameter extends StatefulParameter if (result.data?.includes('It seems there is already an App at')) { const adoptResult = await $.spawnSafe(`brew install --casks --adopt ${cask}`, { interactive: true, - env: { HOMEBREW_NO_AUTO_UPDATE: 1 } + env: { HOMEBREW_NO_AUTO_UPDATE: 1, HOMEBREW_NO_ASK: 1, NONINTERACTIVE: 1 } }) if (adoptResult.status === SpawnStatus.SUCCESS) { @@ -133,7 +133,7 @@ export class CasksParameter extends StatefulParameter const $ = getPty(); const result = await $.spawnSafe(`brew uninstall ${casks.join(' ')}`, { interactive: true, - env: { HOMEBREW_NO_AUTO_UPDATE: 1 } + env: { HOMEBREW_NO_AUTO_UPDATE: 1, HOMEBREW_NO_ASK: 1, NONINTERACTIVE: 1 } }) if (result.status === SpawnStatus.SUCCESS) { @@ -153,7 +153,7 @@ export class CasksParameter extends StatefulParameter const result = (await $.spawn( `brew info -q --json=v2 ${casks.map((c) => `"${c}"`).join(' ')}`, { interactive: true, - env: { HOMEBREW_NO_AUTO_UPDATE: 1 } + env: { HOMEBREW_NO_AUTO_UPDATE: 1, HOMEBREW_NO_ASK: 1, NONINTERACTIVE: 1 } }) ) .data diff --git a/src/resources/homebrew/formulae-parameter.ts b/src/resources/homebrew/formulae-parameter.ts index 46a29c59..c23c344b 100644 --- a/src/resources/homebrew/formulae-parameter.ts +++ b/src/resources/homebrew/formulae-parameter.ts @@ -24,7 +24,9 @@ export class FormulaeParameter extends StatefulParameter): Promise { const $ = getPty(); - const formulaeQuery = await $.spawnSafe(`brew list --formula -1 --full-name ${config.onlyPlanUserInstalled ? '--installed-on-request' : ''}`) + const formulaeQuery = await $.spawnSafe(`brew list --formula -1 --full-name ${config.onlyPlanUserInstalled ? '--installed-on-request' : ''}`, + { env: { NONINTERACTIVE: 1 }} + ) if (formulaeQuery.status === SpawnStatus.SUCCESS && formulaeQuery.data !== null && formulaeQuery.data !== undefined) { return formulaeQuery.data @@ -59,7 +61,7 @@ export class FormulaeParameter extends StatefulParameter { override async refresh(parameters: Partial): Promise | null> { const $ = getPty(); - const homebrewInfo = await $.spawnSafe('brew config'); + const homebrewInfo = await $.spawnSafe('brew config', { env: { HOMEBREW_NO_ASK: 1, NONINTERACTIVE: 1 }}); if (homebrewInfo.status === SpawnStatus.ERROR) { return null; } @@ -126,7 +126,7 @@ export class HomebrewResource extends Resource { return; } - const homebrewInfo = await $.spawn('brew config', { interactive: true }); + const homebrewInfo = await $.spawn('brew config', { interactive: true, env: { NONINTERACTIVE: 1 } }); const homebrewDirectory = this.getCurrentLocation(homebrewInfo.data) if (homebrewDirectory === '/opt/homebrew') { diff --git a/src/resources/homebrew/tap-parameter.ts b/src/resources/homebrew/tap-parameter.ts index acbca448..03b8d70f 100644 --- a/src/resources/homebrew/tap-parameter.ts +++ b/src/resources/homebrew/tap-parameter.ts @@ -13,7 +13,7 @@ export class TapsParameter extends StatefulParameter { override async refresh(): Promise { const $ = getPty(); - const tapsQuery = await $.spawnSafe('brew tap') + const tapsQuery = await $.spawnSafe('brew tap', { env: { NONINTERACTIVE: 1 }}) if (tapsQuery.status === SpawnStatus.SUCCESS && tapsQuery.data !== null && tapsQuery.data !== undefined) { return tapsQuery.data .split('\n') @@ -49,7 +49,7 @@ export class TapsParameter extends StatefulParameter { for (const tap of taps) { await $.spawn(`brew tap ${tap}`, { interactive: true, - env: { HOMEBREW_NO_AUTO_UPDATE: 1 }, + env: { HOMEBREW_NO_AUTO_UPDATE: 1, HOMEBREW_NO_ASK: 1, NONINTERACTIVE: 1 }, }); } } @@ -63,7 +63,7 @@ export class TapsParameter extends StatefulParameter { for (const tap of taps) { await $.spawn(`brew untap ${tap}`, { interactive: true, - env: { HOMEBREW_NO_AUTO_UPDATE: 1 }, + env: { HOMEBREW_NO_AUTO_UPDATE: 1, HOMEBREW_NO_ASK: 1, NONINTERACTIVE: 1 }, }); } } diff --git a/test/homebrew/default.test.ts b/test/homebrew/default.test.ts index 8a5705bb..a7c51720 100644 --- a/test/homebrew/default.test.ts +++ b/test/homebrew/default.test.ts @@ -44,6 +44,21 @@ describe('Homebrew main resource integration tests', { skip: !Utils.isMacOS() }, }); }); + it('Installs formulae with dependencies without prompting (HOMEBREW_NO_ASK)', { timeout: 300000 }, async () => { + // ripgrep depends on pcre2; without HOMEBREW_NO_ASK brew would interactively ask + // whether to install the dependency, hanging the process + await PluginTester.fullTest(pluginPath, [{ + type: 'homebrew', + formulae: ['ripgrep'], + }], { + skipUninstall: true, + validateApply: async () => { + expect(await testSpawn('which rg')).toMatchObject({ status: SpawnStatus.SUCCESS }); + expect(await testSpawn('brew list pcre2')).toMatchObject({ status: SpawnStatus.SUCCESS }); + } + }); + }); + it('Can handle casks that were already installed by skipping in the plan', { timeout: 300000 }, async () => { if (!Utils.isMacOS()) { return;