#!/usr/bin/env node import { basename } from 'node:path'; import { execute, UsageError } from './lib/command.ts'; import { root, version } from './commands/root.ts'; import { expandAlias } from './commands/shell.ts'; import { respond } from './lib/completion.ts'; import { refreshQuietly } from './lib/cache.ts'; import { gitCredential } from './commands/credential.ts'; import { NotSignedIn } from './lib/session.ts'; import { XrpcError } from './lib/xrpc.ts'; import { GitError } from './lib/git.ts'; import { errRed } from './lib/output.ts'; // One program, two names, busybox-style: run as `git-credential-tangled` it is // git's credential helper (git runs `git-credential-` for a helper // configured as ``); under any other name it is the tangled CLI. // A reader that stops early (`| head`) is not an error. for (const stream of [process.stdout, process.stderr]) { stream.on('error', (error: NodeJS.ErrnoException) => { if (error.code === 'EPIPE') process.exit(0); throw error; }); } const invoked = basename(process.argv[1] ?? '').replace(/\.(nzip|js|ts|cmd|exe)$/i, ''); const argv = process.argv.slice(2); async function main(): Promise { if (invoked === 'git-credential-tangled') return await gitCredential(argv[0]); // What a shell runs on Tab: never fails loudly — an error is just nothing to offer. if (argv[0] === '__complete') { try { const lines = respond(root, argv.slice(1)); if (lines.length) process.stdout.write(`${lines.join('\n')}\n`); } catch { // Nothing to offer. } return 0; } // What completion starts in the background when its cache is stale. if (argv[0] === '__refresh') { await refreshQuietly(); return 0; } if (argv[0] === '--version' || argv[0] === '-v') { process.stdout.write(`tangled ${version()}\n`); return 0; } return await execute(root, expandAlias(root, argv)); } try { process.exitCode = await main(); } catch (error) { if (process.env['TANGLED_DEBUG'] && error instanceof Error) process.stderr.write(`${error.stack}\n`); if (error instanceof UsageError) { process.stderr.write(`${error.message}\n`); process.exitCode = 2; } else if (error instanceof NotSignedIn || error instanceof XrpcError || error instanceof GitError) { process.stderr.write(`${errRed('error:')} ${error.message}\n`); process.exitCode = 1; } else { process.stderr.write(`${errRed('error:')} ${(error as Error)?.message ?? String(error)}\n`); process.exitCode = 1; } }