Full Code of sindresorhus/fkill-cli for AI

main 2afe64c91106 cached
12 files
19.4 KB
5.6k tokens
4 symbols
1 requests
Download .txt
Repository: sindresorhus/fkill-cli
Branch: main
Commit: 2afe64c91106
Files: 12
Total size: 19.4 KB

Directory structure:
gitextract_uzc5eiyk/

├── .editorconfig
├── .gitattributes
├── .github/
│   └── workflows/
│       └── main.yml
├── .gitignore
├── .npmrc
├── cli.js
├── fixture.js
├── interactive.js
├── license
├── package.json
├── readme.md
└── test.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
root = true

[*]
indent_style = tab
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.yml]
indent_style = space
indent_size = 2


================================================
FILE: .gitattributes
================================================
* text=auto eol=lf


================================================
FILE: .github/workflows/main.yml
================================================
name: CI
on:
  - push
  - pull_request
jobs:
  test:
    name: Node.js ${{ matrix.node-version }} on ${{ matrix.os }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        node-version:
          - 24
          - 20
        os:
          - ubuntu-latest
          - macos-latest
          - windows-latest
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-node@v6
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm install
      - run: npm test


================================================
FILE: .gitignore
================================================
node_modules
yarn.lock


================================================
FILE: .npmrc
================================================
package-lock=false


================================================
FILE: cli.js
================================================
#!/usr/bin/env node
import process from 'node:process';
import meow from 'meow';
import fkill from 'fkill';

const cli = meow(`
	Usage
	  $ fkill [<pid|name|:port> …]

	Options
	  --force -f                         Force kill
	  --verbose -v                       Show process arguments
	  --silent -s                        Silently kill and always exit with code 0
	  --force-after-timeout <N>, -t <N>  Force kill processes which didn't exit after N seconds
	  --smart-case                       Case-insensitive unless pattern contains uppercase
	  --case-sensitive                   Force case-sensitive matching

	Examples
	  $ fkill 1337
	  $ fkill safari
	  $ fkill :8080
	  $ fkill 1337 safari :8080
	  $ fkill

	To kill a port, prefix it with a colon. For example: :8080.

	Run without arguments to use the interactive mode.
	In interactive mode, 🚦n% indicates high CPU usage and 🐏n% indicates high memory usage.
	Supports fuzzy search in the interactive mode.

	The process name is case-insensitive by default.
`, {
	importMeta: import.meta,
	inferType: true,
	flags: {
		force: {
			type: 'boolean',
			shortFlag: 'f',
		},
		verbose: {
			type: 'boolean',
			shortFlag: 'v',
		},
		silent: {
			type: 'boolean',
			shortFlag: 's',
		},
		forceAfterTimeout: {
			type: 'number',
			shortFlag: 't',
		},
		smartCase: {
			type: 'boolean',
		},
		caseSensitive: {
			type: 'boolean',
		},
	},
});

const shouldIgnoreCase = (inputs, flags) => {
	// Explicit case-sensitive flag takes precedence over smart-case
	if (flags.caseSensitive) {
		return false;
	}

	// Smart-case: ignore case unless ANY input contains uppercase
	// Note: With multiple inputs, if ANY has uppercase, ALL are matched case-sensitively
	if (flags.smartCase) {
		const hasUpperCase = inputs.some(input => /[A-Z]/.test(String(input)));
		return !hasUpperCase;
	}

	// Default: always ignore case (maintains backward compatibility)
	return true;
};

if (cli.input.length === 0) {
	const interactiveInterface = await import('./interactive.js');
	interactiveInterface.init(cli.flags);
} else {
	const forceAfterTimeout = cli.flags.forceAfterTimeout === undefined ? undefined : cli.flags.forceAfterTimeout * 1000;
	const ignoreCase = shouldIgnoreCase(cli.input, cli.flags);
	const promise = fkill(cli.input, {...cli.flags, forceAfterTimeout, ignoreCase});

	if (!cli.flags.force) {
		try {
			await promise;
		} catch (error) {
			if (!cli.flags.silent) {
				if (error.message.includes('Could not find a process with port')) {
					console.error(error.message);
					process.exit(1);
				}

				const interactiveInterface = await import('./interactive.js');
				interactiveInterface.handleFkillError(cli.input, cli.flags);
			}
		}
	}
}


================================================
FILE: fixture.js
================================================
import process from 'node:process';
import http from 'node:http';

const server = http.createServer((request, response) => {
	response.end();
});

server.listen(process.argv.slice(2)[0]);


================================================
FILE: interactive.js
================================================
import process from 'node:process';
import chalk from 'chalk';
import inquirer from 'inquirer';
import search from '@inquirer/search';
import psList from 'ps-list';
import {numberSortDescending} from 'num-sort';
import escExit from 'esc-exit';
import cliTruncate from 'cli-truncate';
import {allPortsWithPid} from 'pid-port';
import fkill from 'fkill';
import {processExists} from 'process-exists';
import FuzzySearch from 'fuzzy-search';

const isWindows = process.platform === 'win32';
const commandLineMargins = 4;

const PROCESS_EXITED_MIN_INTERVAL = 5;
const PROCESS_EXITED_MAX_INTERVAL = 1280;

const delay = ms => new Promise(resolve => {
	setTimeout(resolve, ms);
});

const processExited = async (pid, timeout) => {
	const endTime = Date.now() + timeout;
	let interval = PROCESS_EXITED_MIN_INTERVAL;
	if (interval > timeout) {
		interval = timeout;
	}

	let exists;

	do {
		await delay(interval); // eslint-disable-line no-await-in-loop

		exists = await processExists(pid); // eslint-disable-line no-await-in-loop

		interval *= 2;
		if (interval > PROCESS_EXITED_MAX_INTERVAL) {
			interval = PROCESS_EXITED_MAX_INTERVAL;
		}
	} while (Date.now() < endTime && exists);

	return !exists;
};

const preferNotMatching = matches => (a, b) => {
	const aMatches = matches(a);
	return matches(b) === aMatches ? 0 : (aMatches ? 1 : -1);
};

const deprioritizedProcesses = new Set(['iTerm', 'iTerm2', 'fkill']);
const isDeprioritizedProcess = process_ => deprioritizedProcesses.has(process_.name);
const preferNotDeprioritized = preferNotMatching(isDeprioritizedProcess);
const preferLowAlphanumericNames = (a, b) => a.name.localeCompare(b.name);

const preferHighPerformanceImpact = (a, b) => {
	const hasCpu = typeof a.cpu === 'number' && typeof b.cpu === 'number';
	const hasMemory = typeof a.memory === 'number' && typeof b.memory === 'number';

	if (hasCpu && hasMemory) {
		return numberSortDescending(a.cpu + a.memory, b.cpu + b.memory);
	}

	if (hasCpu) {
		return numberSortDescending(a.cpu, b.cpu);
	}

	if (hasMemory) {
		return numberSortDescending(a.memory, b.memory);
	}

	return 0;
};

const preferHeurisicallyInterestingProcesses = (a, b) => {
	let result;

	result = preferNotDeprioritized(a, b);
	if (result !== 0) {
		return result;
	}

	result = preferHighPerformanceImpact(a, b);
	if (result !== 0) {
		return result;
	}

	return preferLowAlphanumericNames(a, b);
};

const isHelperProcess = process_ => process_.name.endsWith('-helper')
	|| process_.name.endsWith('Helper')
	|| process_.name.endsWith('HelperApp');

const renderPercentage = percents => {
	const digits = Math.floor(percents * 10).toString().padStart(2, '0');
	const whole = digits.slice(0, -1);
	const fraction = digits.slice(-1);
	return fraction === '0' ? `${whole}%` : `${whole}.${fraction}%`;
};

const renderProcessForDisplay = (process_, flags, memoryThreshold, cpuThreshold) => {
	const lineLength = process.stdout.columns || 80;
	const ports = process_.ports.length === 0 ? '' : (' ' + process_.ports.slice(0, 4).map(x => `:${x}`).join(' '));
	const memory = (process_.memory !== undefined && (process_.memory > memoryThreshold)) ? ` 🐏${renderPercentage(process_.memory)}` : '';
	const cpu = (process_.cpu !== undefined && (process_.cpu > cpuThreshold)) ? `🚦${renderPercentage(process_.cpu)}` : '';
	const margins = commandLineMargins + process_.pid.toString().length + ports.length + memory.length + cpu.length;
	const length = lineLength - margins;
	const name = cliTruncate(flags.verbose && !isWindows ? process_.cmd : process_.name, length, {position: 'middle', preferTruncationOnSpace: true});
	const extraMargin = 2;
	const spacer = lineLength === process.stdout.columns ? ''.padEnd(length - name.length - extraMargin) : '';

	return {
		name: `${name} ${chalk.dim(process_.pid)}${spacer}${chalk.dim(ports)}${cpu}${memory}`,
		value: process_.pid,
	};
};

const searchProcessesByPort = (processes, port) => processes.filter(process_ => process_.ports.includes(port));

const searchProcessByPid = (processes, pid) => processes.find(process_ => String(process_.pid) === pid);

const searchProcessesByName = (processes, term, searcher, flags = {}) => {
	// Determine if we should match case-sensitively
	const hasUpperCase = /[A-Z]/.test(term);
	const shouldMatchCase = flags.caseSensitive || (flags.smartCase && hasUpperCase);

	const normalizedTerm = shouldMatchCase ? term : term.toLowerCase();
	const exactMatches = [];
	const startsWithMatches = [];
	const containsMatches = [];

	for (const process_ of processes) {
		const normalizedName = shouldMatchCase ? process_.name : process_.name.toLowerCase();
		if (normalizedName === normalizedTerm) {
			exactMatches.push(process_);
		} else if (normalizedName.startsWith(normalizedTerm)) {
			startsWithMatches.push(process_);
		} else if (normalizedName.includes(normalizedTerm)) {
			containsMatches.push(process_);
		}
	}

	// Fuzzy matches (excluding all exact/starts/contains matches)
	// Keep fuzzy search case-insensitive for better UX
	const matchedPids = new Set([...exactMatches, ...startsWithMatches, ...containsMatches].map(process_ => process_.pid));
	const fuzzyResults = searcher.search(term).filter(process_ => !matchedPids.has(process_.pid));

	// Combine in priority order
	return [...exactMatches, ...startsWithMatches, ...containsMatches, ...fuzzyResults];
};

const filterAndSortProcesses = (processes, term, searcher, flags) => {
	const filtered = processes.filter(process_ => !isHelperProcess(process_));

	// No search term: show all sorted by performance
	if (!term) {
		return filtered.sort(preferHeurisicallyInterestingProcesses);
	}

	// Search by port
	if (term.startsWith(':')) {
		const port = term.slice(1);
		return searchProcessesByPort(filtered, port);
	}

	// Search by PID
	const pidMatch = searchProcessByPid(filtered, term);
	if (pidMatch) {
		return [pidMatch];
	}

	// Search by name
	return searchProcessesByName(filtered, term, searcher, flags);
};

const handleFkillError = async (inputs, flags = {}) => {
	const shouldForceKill = await promptForceKill(inputs, 'Error killing process.');

	if (shouldForceKill) {
		// Determine case sensitivity based on flags and inputs
		// If ANY input has uppercase letter, match case-sensitively with --smart-case
		const hasUpperCase = inputs.some(input => /[A-Z]/.test(String(input)));
		const ignoreCase = flags.caseSensitive ? false : (flags.smartCase ? !hasUpperCase : true);

		await fkill(inputs, {
			force: true,
			ignoreCase,
		});
	}
};

const DEFAULT_EXIT_TIMEOUT = 3000;

const attemptKillProcesses = async processes => {
	try {
		await fkill(processes);
		const exitStatuses = await Promise.all(processes.map(process_ => processExited(process_, DEFAULT_EXIT_TIMEOUT)));
		const survivors = processes.filter((_, index) => !exitStatuses[index]);
		return {survivors, hadError: false};
	} catch {
		return {survivors: processes, hadError: true};
	}
};

const promptForceKill = async (survivingProcesses, message) => {
	if (process.stdout.isTTY === false) {
		console.error(`${message} Try \`fkill --force ${survivingProcesses.join(' ')}\``);
		process.exit(1); // eslint-disable-line unicorn/no-process-exit
	}

	const answer = await inquirer.prompt([{
		type: 'confirm',
		name: 'forceKill',
		message: `${message} Would you like to use the force?`,
	}]);

	return answer.forceKill;
};

const performKillSequence = async processes => {
	const processList = Array.isArray(processes) ? processes : [processes];
	const {survivors, hadError} = await attemptKillProcesses(processList);

	if (survivors.length === 0) {
		return;
	}

	const suffix = survivors.length > 1 ? 'es' : '';
	const message = hadError ? `Error killing process${suffix}.` : `Process${suffix} didn't exit in ${DEFAULT_EXIT_TIMEOUT}ms.`;
	const shouldForceKill = await promptForceKill(survivors, message);

	if (shouldForceKill) {
		await fkill(processList, {
			force: true,
			ignoreCase: true,
		});
	}
};

const findPortsForProcess = (processId, portToPidMap) => {
	const ports = [];

	for (const [port, pid] of portToPidMap.entries()) {
		if (processId === pid) {
			ports.push(String(port));
		}
	}

	return ports;
};

const listProcesses = async (processes, flags) => {
	const memoryThreshold = flags.verbose ? 0 : 1;
	const cpuThreshold = flags.verbose ? 0 : 3;
	const searcher = new FuzzySearch(processes, ['name'], {caseSensitive: false});

	const selectedPid = await search({
		message: 'Running processes:',
		pageSize: 10,
		async source(term = '') {
			const matchingProcesses = filterAndSortProcesses(processes, term, searcher, flags);
			return matchingProcesses.map(process_ => renderProcessForDisplay(process_, flags, memoryThreshold, cpuThreshold));
		},
	});

	performKillSequence(selectedPid);
};

const init = async flags => {
	escExit();

	const [portToPidMap, processes] = await Promise.all([
		allPortsWithPid(),
		psList({all: false}),
	]);

	const processesWithPorts = processes.map(process_ => ({
		...process_,
		ports: findPortsForProcess(process_.pid, portToPidMap),
	}));

	listProcesses(processesWithPorts, flags);
};

export {init, handleFkillError};


================================================
FILE: license
================================================
MIT License

Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: package.json
================================================
{
	"name": "fkill-cli",
	"version": "9.0.0",
	"description": "Fabulously kill processes. Cross-platform.",
	"license": "MIT",
	"repository": "sindresorhus/fkill-cli",
	"funding": "https://github.com/sponsors/sindresorhus",
	"author": {
		"name": "Sindre Sorhus",
		"email": "sindresorhus@gmail.com",
		"url": "https://sindresorhus.com"
	},
	"type": "module",
	"bin": {
		"fkill": "./cli.js"
	},
	"sideEffects": false,
	"engines": {
		"node": ">=20"
	},
	"scripts": {
		"test": "xo && ava"
	},
	"files": [
		"cli.js",
		"interactive.js"
	],
	"keywords": [
		"cli-app",
		"cli",
		"fkill",
		"kill",
		"killing",
		"killall",
		"taskkill",
		"sigkill",
		"sigterm",
		"force",
		"exit",
		"zap",
		"die",
		"ps",
		"proc"
	],
	"dependencies": {
		"@inquirer/search": "^3.2.1",
		"chalk": "^5.6.2",
		"cli-truncate": "^5.1.1",
		"esc-exit": "^3.0.1",
		"fkill": "^10.0.0",
		"fuzzy-search": "^3.2.1",
		"inquirer": "^12.11.0",
		"meow": "^14.0.0",
		"num-sort": "^4.0.0",
		"pid-port": "^2.0.0",
		"ps-list": "^9.0.0"
	},
	"devDependencies": {
		"ava": "^6.4.1",
		"delay": "^7.0.0",
		"execa": "^9.6.0",
		"get-port": "^7.1.0",
		"noop-process": "^5.0.0",
		"process-exists": "^5.0.0",
		"xo": "^1.2.3"
	}
}


================================================
FILE: readme.md
================================================
<h1 align="center">
	<br>
	<img width="360" src="https://cdn.jsdelivr.net/gh/sindresorhus/fkill@913dce9ae670cd12410f6a64eaf94d7e5f50ed69/media/logo.svg" alt="fkill">
	<br>
	<br>
	<br>
</h1>

> Fabulously kill processes. Cross-platform.

Works on macOS, Linux, and Windows.

## Install

```sh
npm install --global fkill-cli
```

## Usage

```
$ fkill --help

	Usage
		$ fkill [<pid|name|:port> …]

	Options
		--force, -f                  Force kill
		--verbose, -v                Show process arguments
		--silent, -s                 Silently kill and always exit with code 0
		--force-timeout <N>, -t <N>  Force kill processes which didn't exit after N seconds
		--smart-case                 Case-insensitive unless pattern contains uppercase
		--case-sensitive             Force case-sensitive matching

	Examples
		$ fkill 1337
		$ fkill safari
		$ fkill :8080
		$ fkill 1337 safari :8080
		$ fkill

	To kill a port, prefix it with a colon. For example: :8080.

	Run without arguments to use the interactive interface.
	In interactive mode, 🚦n% indicates high CPU usage and 🐏n% indicates high memory usage.
	Supports fuzzy search in the interactive mode.

	The process name is case-insensitive by default.
```

## Interactive UI

Run `fkill` without arguments to launch the interactive UI.

![](screenshot.svg)

## Related

- [fkill](https://github.com/sindresorhus/fkill) - API for this package
- [alfred-fkill](https://github.com/SamVerschueren/alfred-fkill) - Alfred workflow for this package


================================================
FILE: test.js
================================================
import process from 'node:process';
import childProcess from 'node:child_process';
import test from 'ava';
import {execa} from 'execa';
import delay from 'delay';
import noopProcess from 'noop-process';
import {processExists} from 'process-exists';
import getPort from 'get-port';

const noopProcessKilled = async (t, pid) => {
	// Ensure the noop process has time to exit
	await delay(100);
	t.false(await processExists(pid));
};

test('main', async t => {
	const {stdout} = await execa('./cli.js', ['--version']);
	t.true(stdout.length > 0);
});

test('pid', async t => {
	const pid = await noopProcess();
	await execa('./cli.js', ['--force', pid]);
	await noopProcessKilled(t, pid);
});

// TODO: Upgrading AVA to latest caused this to not finish. Unclear why.
// test('fuzzy search', async t => {
// 	const pid = await noopProcess({title: '!noo00oop@'});
// 	await execa('./cli.js', ['o00oop@']);
// 	await noopProcessKilled(t, pid);
// });

test('kill from port', async t => {
	const port = await getPort();
	const {pid} = childProcess.spawn('node', ['fixture.js', port]);
	await execa('./cli.js', ['--force', pid]);
	await noopProcessKilled(t, pid);
});

test('error when process is not found', async t => {
	await t.throwsAsync(
		execa('./cli.js', ['--force', 'notFoundProcess']),
		{message: /Killing process notFoundProcess failed: Process doesn't exist/},
	);
});

test('force killing process at unused port throws error', async t => {
	await t.throwsAsync(
		execa('./cli.js', ['--force', ':1337']),
		{message: /Killing process :1337 failed: Process doesn't exist/},
	);
});

test('silently force killing process at unused port exits with code 0', async t => {
	const {exitCode} = await execa('./cli.js', ['--force', '--silent', ':1337']);
	t.is(exitCode, 0);
});

// Case-sensitivity tests only work on Unix-like systems
// Windows process names work differently and don't support custom titles via noopProcess
if (process.platform !== 'win32') {
	test('default case-insensitive behavior', async t => {
		const pid = await noopProcess({title: 'DefaultCase'});
		await execa('./cli.js', ['--force', 'defaultcase']);
		await noopProcessKilled(t, pid);
	});

	test('case-sensitive flag makes matching case-sensitive', async t => {
		const pid = await noopProcess({title: 'CaseSensitive'});
		await t.throwsAsync(
			execa('./cli.js', ['--case-sensitive', '--force', 'casesensitive']),
			{message: /Killing process casesensitive failed/},
		);
		// Clean up the process
		await execa('./cli.js', ['--force', pid]);
	});

	test('smart-case with lowercase is case-insensitive', async t => {
		const pid = await noopProcess({title: 'SmartLower'});
		await execa('./cli.js', ['--smart-case', '--force', 'smartlower']);
		await noopProcessKilled(t, pid);
	});

	test('smart-case with uppercase is case-sensitive', async t => {
		const pid = await noopProcess({title: 'smartupper'});
		await t.throwsAsync(
			execa('./cli.js', ['--smart-case', '--force', 'SmartUpper']),
			{message: /Killing process SmartUpper failed/},
		);
		// Clean up the process
		await execa('./cli.js', ['--force', pid]);
	});
}

test('silent flag with -s shortflag works', async t => {
	const {exitCode} = await execa('./cli.js', ['-s', '--force', ':1337']);
	t.is(exitCode, 0);
});
Download .txt
gitextract_uzc5eiyk/

├── .editorconfig
├── .gitattributes
├── .github/
│   └── workflows/
│       └── main.yml
├── .gitignore
├── .npmrc
├── cli.js
├── fixture.js
├── interactive.js
├── license
├── package.json
├── readme.md
└── test.js
Download .txt
SYMBOL INDEX (4 symbols across 1 files)

FILE: interactive.js
  constant PROCESS_EXITED_MIN_INTERVAL (line 17) | const PROCESS_EXITED_MIN_INTERVAL = 5;
  constant PROCESS_EXITED_MAX_INTERVAL (line 18) | const PROCESS_EXITED_MAX_INTERVAL = 1280;
  constant DEFAULT_EXIT_TIMEOUT (line 194) | const DEFAULT_EXIT_TIMEOUT = 3000;
  method source (line 262) | async source(term = '') {
Condensed preview — 12 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (22K chars).
[
  {
    "path": ".editorconfig",
    "chars": 175,
    "preview": "root = true\n\n[*]\nindent_style = tab\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newlin"
  },
  {
    "path": ".gitattributes",
    "chars": 19,
    "preview": "* text=auto eol=lf\n"
  },
  {
    "path": ".github/workflows/main.yml",
    "chars": 534,
    "preview": "name: CI\non:\n  - push\n  - pull_request\njobs:\n  test:\n    name: Node.js ${{ matrix.node-version }} on ${{ matrix.os }}\n  "
  },
  {
    "path": ".gitignore",
    "chars": 23,
    "preview": "node_modules\nyarn.lock\n"
  },
  {
    "path": ".npmrc",
    "chars": 19,
    "preview": "package-lock=false\n"
  },
  {
    "path": "cli.js",
    "chars": 2714,
    "preview": "#!/usr/bin/env node\nimport process from 'node:process';\nimport meow from 'meow';\nimport fkill from 'fkill';\n\nconst cli ="
  },
  {
    "path": "fixture.js",
    "chars": 188,
    "preview": "import process from 'node:process';\nimport http from 'node:http';\n\nconst server = http.createServer((request, response) "
  },
  {
    "path": "interactive.js",
    "chars": 9101,
    "preview": "import process from 'node:process';\nimport chalk from 'chalk';\nimport inquirer from 'inquirer';\nimport search from '@inq"
  },
  {
    "path": "license",
    "chars": 1117,
    "preview": "MIT License\n\nCopyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)\n\nPermission is hereby grant"
  },
  {
    "path": "package.json",
    "chars": 1206,
    "preview": "{\n\t\"name\": \"fkill-cli\",\n\t\"version\": \"9.0.0\",\n\t\"description\": \"Fabulously kill processes. Cross-platform.\",\n\t\"license\": \""
  },
  {
    "path": "readme.md",
    "chars": 1498,
    "preview": "<h1 align=\"center\">\n\t<br>\n\t<img width=\"360\" src=\"https://cdn.jsdelivr.net/gh/sindresorhus/fkill@913dce9ae670cd12410f6a64"
  },
  {
    "path": "test.js",
    "chars": 3266,
    "preview": "import process from 'node:process';\nimport childProcess from 'node:child_process';\nimport test from 'ava';\nimport {execa"
  }
]

About this extraction

This page contains the full source code of the sindresorhus/fkill-cli GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 12 files (19.4 KB), approximately 5.6k tokens, and a symbol index with 4 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!