9b395f5cc3
Build Chrome Extension / build (push) Waiting to run
Trigger Website Rebuild (Docs Updated) / dispatch (push) Waiting to run
E2E Headed Chrome / e2e-headed (macos-15) (push) Has been cancelled
E2E Headed Chrome / e2e-headed (ubuntu-latest) (push) Has been cancelled
E2E Headed Chrome / e2e-headed (windows-latest) (push) Has been cancelled
CI / build (macos-latest) (push) Has been cancelled
CI / build (ubuntu-latest) (push) Has been cancelled
CI / build (windows-latest) (push) Has been cancelled
CI / unit-test (push) Has been cancelled
CI / bun-test (push) Has been cancelled
CI / adapter-test (push) Has been cancelled
CI / smoke-test (macos-latest) (push) Has been cancelled
CI / smoke-test (ubuntu-latest) (push) Has been cancelled
Security Audit / audit (push) Has been cancelled
175 lines
6.6 KiB
JavaScript
175 lines
6.6 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
/**
|
|
* postinstall script — install shell completion files and print setup instructions.
|
|
*
|
|
* Detects the user's default shell and writes the completion script to the
|
|
* standard completion directory. For zsh and bash, the script prints manual
|
|
* instructions instead of modifying rc files (~/.zshrc, ~/.bashrc) — this
|
|
* avoids breaking multi-line shell commands and other fragile rc structures.
|
|
* Fish completions work automatically without rc changes.
|
|
*
|
|
* Supported shells: bash, zsh, fish.
|
|
*
|
|
* This script is intentionally plain Node.js (no TypeScript, no imports from
|
|
* the main source tree) so that it can run without a build step.
|
|
*/
|
|
|
|
import { mkdirSync, writeFileSync, existsSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
import { homedir } from 'node:os';
|
|
|
|
|
|
// ── Completion script content ──────────────────────────────────────────────
|
|
|
|
const BASH_COMPLETION = `# Bash completion for opencli (auto-installed)
|
|
_opencli_completions() {
|
|
local cur words cword
|
|
_get_comp_words_by_ref -n : cur words cword
|
|
|
|
local completions
|
|
completions=$(opencli --get-completions --cursor "$cword" "\${words[@]:1}" 2>/dev/null)
|
|
|
|
COMPREPLY=( $(compgen -W "$completions" -- "$cur") )
|
|
__ltrim_colon_completions "$cur"
|
|
}
|
|
complete -F _opencli_completions opencli
|
|
`;
|
|
|
|
const ZSH_COMPLETION = `#compdef opencli
|
|
# Zsh completion for opencli (auto-installed)
|
|
_opencli() {
|
|
local -a completions
|
|
local cword=$((CURRENT - 1))
|
|
completions=(\${(f)"$(opencli --get-completions --cursor "$cword" "\${words[@]:1}" 2>/dev/null)"})
|
|
compadd -a completions
|
|
}
|
|
_opencli
|
|
`;
|
|
|
|
const FISH_COMPLETION = `# Fish completion for opencli (auto-installed)
|
|
complete -c opencli -f -a '(
|
|
set -l tokens (commandline -cop)
|
|
set -l cursor (count (commandline -cop))
|
|
opencli --get-completions --cursor $cursor $tokens[2..] 2>/dev/null
|
|
)'
|
|
`;
|
|
|
|
// ── Helpers ────────────────────────────────────────────────────────────────
|
|
|
|
function detectShell() {
|
|
const shell = process.env.SHELL || '';
|
|
if (shell.includes('zsh')) return 'zsh';
|
|
if (shell.includes('bash')) return 'bash';
|
|
if (shell.includes('fish')) return 'fish';
|
|
return null;
|
|
}
|
|
|
|
function ensureDir(dir) {
|
|
if (!existsSync(dir)) {
|
|
mkdirSync(dir, { recursive: true });
|
|
}
|
|
}
|
|
|
|
// ── Main ───────────────────────────────────────────────────────────────────
|
|
|
|
function main() {
|
|
// Skip in CI environments
|
|
if (process.env.CI || process.env.CONTINUOUS_INTEGRATION) {
|
|
return;
|
|
}
|
|
|
|
// Only install completion for global installs and npm link
|
|
const isGlobal = process.env.npm_config_global === 'true';
|
|
if (!isGlobal) {
|
|
return;
|
|
}
|
|
|
|
const shell = detectShell();
|
|
if (!shell) {
|
|
// Cannot determine shell; silently skip
|
|
return;
|
|
}
|
|
|
|
const home = homedir();
|
|
|
|
try {
|
|
switch (shell) {
|
|
case 'zsh': {
|
|
const completionsDir = join(home, '.zsh', 'completions');
|
|
const completionFile = join(completionsDir, '_opencli');
|
|
ensureDir(completionsDir);
|
|
writeFileSync(completionFile, ZSH_COMPLETION, 'utf8');
|
|
|
|
console.log(`✓ Zsh completion installed to ${completionFile}`);
|
|
console.log('');
|
|
console.log(' \x1b[1mTo enable, add these lines to your ~/.zshrc:\x1b[0m');
|
|
console.log(` fpath=(${completionsDir} $fpath)`);
|
|
console.log(' autoload -Uz compinit && compinit');
|
|
console.log('');
|
|
console.log(' If you already have compinit (oh-my-zsh, zinit, etc.), just add the fpath line \x1b[1mbefore\x1b[0m it.');
|
|
console.log(' Then restart your shell or run: \x1b[36mexec zsh\x1b[0m');
|
|
break;
|
|
}
|
|
case 'bash': {
|
|
const userCompDir = join(home, '.bash_completion.d');
|
|
const completionFile = join(userCompDir, 'opencli');
|
|
ensureDir(userCompDir);
|
|
writeFileSync(completionFile, BASH_COMPLETION, 'utf8');
|
|
|
|
console.log(`✓ Bash completion installed to ${completionFile}`);
|
|
console.log('');
|
|
console.log(' \x1b[1mTo enable, add this line to your ~/.bashrc:\x1b[0m');
|
|
console.log(` [ -f "${completionFile}" ] && source "${completionFile}"`);
|
|
console.log('');
|
|
console.log(' Then restart your shell or run: \x1b[36msource ~/.bashrc\x1b[0m');
|
|
break;
|
|
}
|
|
case 'fish': {
|
|
const completionsDir = join(home, '.config', 'fish', 'completions');
|
|
const completionFile = join(completionsDir, 'opencli.fish');
|
|
ensureDir(completionsDir);
|
|
writeFileSync(completionFile, FISH_COMPLETION, 'utf8');
|
|
|
|
console.log(`✓ Fish completion installed to ${completionFile}`);
|
|
console.log(` Restart your shell to activate.`);
|
|
break;
|
|
}
|
|
}
|
|
} catch (err) {
|
|
// Completion install is best-effort; never fail the package install
|
|
if (process.env.OPENCLI_VERBOSE) {
|
|
console.error(`Warning: Could not install shell completion: ${err.message}`);
|
|
}
|
|
}
|
|
|
|
// ── Spotify credentials template ────────────────────────────────────
|
|
const opencliDir = join(home, '.opencli');
|
|
const spotifyEnvFile = join(opencliDir, 'spotify.env');
|
|
ensureDir(opencliDir);
|
|
if (!existsSync(spotifyEnvFile)) {
|
|
writeFileSync(spotifyEnvFile,
|
|
`# Spotify credentials — get them at https://developer.spotify.com/dashboard\n` +
|
|
`# Add http://127.0.0.1:8888/callback as a Redirect URI in your Spotify app\n` +
|
|
`SPOTIFY_CLIENT_ID=your_spotify_client_id_here\n` +
|
|
`SPOTIFY_CLIENT_SECRET=your_spotify_client_secret_here\n`,
|
|
'utf8'
|
|
);
|
|
console.log(`✓ Spotify credentials template created at ${spotifyEnvFile}`);
|
|
console.log(` Edit the file and add your Client ID and Secret, then run: opencli spotify auth`);
|
|
}
|
|
|
|
// ── Browser Bridge setup hint ───────────────────────────────────────
|
|
console.log('');
|
|
console.log(' \x1b[1mNext step — Browser Bridge setup\x1b[0m');
|
|
console.log(' Browser commands (bilibili, zhihu, twitter...) require the extension:');
|
|
console.log(' 1. Download: https://github.com/jackwener/opencli/releases');
|
|
console.log(' 2. In Chrome or Chromium, open chrome://extensions → enable Developer Mode → Load unpacked');
|
|
console.log('');
|
|
console.log(' Then run \x1b[36mopencli doctor\x1b[0m to verify.');
|
|
console.log('');
|
|
|
|
}
|
|
|
|
main();
|