Files
SuperCharged-Claude-Code-Up…/dexto/scripts/install-global-cli.ts
admin b52318eeae feat: Add intelligent auto-router and enhanced integrations
- Add intelligent-router.sh hook for automatic agent routing
- Add AUTO-TRIGGER-SUMMARY.md documentation
- Add FINAL-INTEGRATION-SUMMARY.md documentation
- Complete Prometheus integration (6 commands + 4 tools)
- Complete Dexto integration (12 commands + 5 tools)
- Enhanced Ralph with access to all agents
- Fix /clawd command (removed disable-model-invocation)
- Update hooks.json to v5 with intelligent routing
- 291 total skills now available
- All 21 commands with automatic routing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-28 00:27:56 +04:00

245 lines
7.6 KiB
TypeScript

#!/usr/bin/env tsx
/**
* Installs the dexto CLI globally using a local npm registry (verdaccio).
* This mimics exactly what `npm install -g dexto` does when published to npm.
*
* Process:
* 1. Start verdaccio (local npm registry) in background
* 2. Publish all @dexto/* packages and dexto CLI to it
* 3. Install dexto globally from local registry (npm resolves deps like production)
* 4. Stop verdaccio and clean up
*
* This ensures peer dependencies resolve correctly through the dependency tree,
* exactly as they would when users install from npm.
*/
import { execSync, spawn, ChildProcess } from 'child_process';
import { existsSync, rmSync, mkdirSync, writeFileSync } from 'fs';
import { join } from 'path';
const REGISTRY_URL = 'http://localhost:4873';
const VERDACCIO_CONFIG_DIR = join(process.cwd(), '.verdaccio');
// Packages in dependency order (dependencies first)
const PACKAGES = [
{ name: '@dexto/analytics', path: 'packages/analytics' },
{ name: '@dexto/core', path: 'packages/core' },
{ name: '@dexto/registry', path: 'packages/registry' },
{ name: '@dexto/tools-filesystem', path: 'packages/tools-filesystem' },
{ name: '@dexto/tools-process', path: 'packages/tools-process' },
{ name: '@dexto/tools-todo', path: 'packages/tools-todo' },
{ name: '@dexto/image-local', path: 'packages/image-local' },
{ name: '@dexto/agent-management', path: 'packages/agent-management' },
{ name: '@dexto/server', path: 'packages/server' },
{ name: 'dexto', path: 'packages/cli' },
];
let verdaccioProcess: ChildProcess | null = null;
function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function waitForRegistry(maxAttempts = 30): Promise<boolean> {
for (let i = 0; i < maxAttempts; i++) {
try {
execSync(`curl -s ${REGISTRY_URL} > /dev/null 2>&1`, { stdio: 'ignore' });
return true;
} catch {
await sleep(500);
}
}
return false;
}
function startVerdaccio(): ChildProcess {
console.log('🚀 Starting local npm registry (verdaccio)...');
// Create minimal config for verdaccio
mkdirSync(VERDACCIO_CONFIG_DIR, { recursive: true });
const configPath = join(VERDACCIO_CONFIG_DIR, 'config.yaml');
const config = `
storage: ${join(VERDACCIO_CONFIG_DIR, 'storage')}
auth:
htpasswd:
file: ${join(VERDACCIO_CONFIG_DIR, 'htpasswd')}
max_users: -1
uplinks:
npmjs:
url: https://registry.npmjs.org/
packages:
'@dexto/*':
access: $all
publish: $anonymous
unpublish: $anonymous
'dexto':
access: $all
publish: $anonymous
unpublish: $anonymous
'**':
access: $all
proxy: npmjs
server:
keepAliveTimeout: 60
log: { type: stdout, format: pretty, level: warn }
`;
writeFileSync(configPath, config);
const proc = spawn('npx', ['verdaccio', '--config', configPath], {
stdio: ['ignore', 'pipe', 'pipe'],
detached: false,
});
proc.stdout?.on('data', (data) => {
const str = data.toString();
if (str.includes('warn') || str.includes('error')) {
process.stdout.write(` [verdaccio] ${str}`);
}
});
proc.stderr?.on('data', (data) => {
const str = data.toString();
if (!str.includes('npm warn')) {
process.stderr.write(` [verdaccio] ${str}`);
}
});
return proc;
}
function stopVerdaccio() {
if (verdaccioProcess) {
console.log('🛑 Stopping local registry...');
verdaccioProcess.kill('SIGTERM');
verdaccioProcess = null;
}
}
function cleanup() {
stopVerdaccio();
if (existsSync(VERDACCIO_CONFIG_DIR)) {
console.log('🧹 Cleaning up verdaccio data...');
rmSync(VERDACCIO_CONFIG_DIR, { recursive: true, force: true });
}
}
function publishPackage(pkg: { name: string; path: string }) {
console.log(` 📤 Publishing ${pkg.name}...`);
try {
// Create a temporary .npmrc in the package directory with fake auth for local registry
const pkgDir = join(process.cwd(), pkg.path);
const npmrcPath = join(pkgDir, '.npmrc');
const npmrcContent = `//localhost:4873/:_authToken="fake-token-for-local-testing"\n`;
writeFileSync(npmrcPath, npmrcContent);
try {
// Use pnpm publish to correctly resolve workspace:* dependencies to actual versions
execSync(`pnpm publish --registry ${REGISTRY_URL} --no-git-checks`, {
cwd: pkgDir,
stdio: ['ignore', 'ignore', 'pipe'],
});
} finally {
// Clean up the temporary .npmrc
if (existsSync(npmrcPath)) {
rmSync(npmrcPath);
}
}
} catch (error: any) {
// Ignore "already published" errors
const stderr = error.stderr?.toString() || '';
if (!stderr.includes('cannot publish over')) {
throw error;
}
console.log(` (already published, skipping)`);
}
}
async function main() {
const rootDir = process.cwd();
// Ensure we're in the right directory
if (!existsSync(join(rootDir, 'packages/cli/package.json'))) {
console.error('❌ Must run from repository root');
process.exit(1);
}
// Clean up any previous state
cleanup();
// Register cleanup handlers
process.on('SIGINT', () => {
cleanup();
process.exit(1);
});
process.on('SIGTERM', () => {
cleanup();
process.exit(1);
});
process.on('exit', cleanup);
try {
// Start verdaccio
verdaccioProcess = startVerdaccio();
// Wait for registry to be ready
console.log(' ⏳ Waiting for registry to start...');
const ready = await waitForRegistry();
if (!ready) {
throw new Error('Verdaccio failed to start');
}
console.log(' ✓ Registry ready');
// Publish all packages
console.log('📦 Publishing packages to local registry...');
for (const pkg of PACKAGES) {
publishPackage(pkg);
}
console.log(' ✓ All packages published');
// Uninstall existing global dexto (both npm and pnpm)
console.log('🗑️ Removing existing global dexto...');
let removedAny = false;
try {
execSync('npm uninstall -g dexto', { stdio: 'ignore' });
console.log(' ✓ Removed npm global installation');
removedAny = true;
} catch {
// npm global not installed
}
try {
// Remove pnpm global link if it exists
const pnpmBinDir = execSync('pnpm bin -g', { encoding: 'utf-8' }).trim();
const pnpmDextoPath = join(pnpmBinDir, 'dexto');
if (existsSync(pnpmDextoPath)) {
rmSync(pnpmDextoPath, { force: true });
console.log(' ✓ Removed pnpm global link');
removedAny = true;
}
} catch {
// pnpm not available or no global link
}
if (!removedAny) {
console.log(' (no existing installation)');
}
// Install from local registry
console.log('📥 Installing dexto globally from local registry...');
execSync(`npm install -g dexto --registry ${REGISTRY_URL}`, {
stdio: 'inherit',
});
console.log('');
console.log('✅ Successfully installed dexto globally!');
console.log(' Run "dexto --help" to get started');
} catch (error) {
console.error('❌ Installation failed:', error);
process.exit(1);
} finally {
cleanup();
}
}
main();