diff --git a/README.md b/README.md index 19c7278..c4d4e13 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,7 @@ Web search queries the `mixedbread/web` store in addition to your local store, m | --- | --- | | `mgrep` / `mgrep search [path]` | Natural-language search with many `grep`-style flags (`-i`, `-r`, `-m`...). | | `mgrep watch` | Index current repo and keep the Mixedbread store in sync via file watchers. | +| `mgrep list` | List active mgrep watch processes with their working directories. | | `mgrep login` & `mgrep logout` | Manage device-based authentication with Mixedbread. | | `mgrep install-claude-code` | Authenticate, add the Mixedbread mgrep plugin to Claude Code. | | `mgrep install-opencode` | Authenticate and add the Mixedbread mgrep to OpenCode. | @@ -208,6 +209,19 @@ mgrep watch --max-file-size 1048576 # limit uploads to files under 1MB mgrep watch --max-file-count 5000 # limit uploads to directories with 5000 files or fewer ``` +### mgrep list + +`mgrep list` shows all running `mgrep watch` processes with their working directories. + +**Example:** +```bash +mgrep list +# /home/user/project-a +# /home/user/project-b +``` + +Output is one directory per line. + ## Mixedbread under the hood - Every file is pushed into a Mixedbread Store using the same SDK your apps get. diff --git a/package.json b/package.json index 9a94855..837c62b 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,8 @@ "istextorbinary": "^9.5.0", "open": "^10.2.0", "ora": "^5.4.1", + "pid-cwd": "^1.2.0", + "ps-list": "^9.0.0", "p-limit": "^3.1.0", "winston": "^3.18.3", "winston-daily-rotate-file": "^5.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 337c240..262dd08 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -47,6 +47,12 @@ importers: p-limit: specifier: ^3.1.0 version: 3.1.0 + pid-cwd: + specifier: ^1.2.0 + version: 1.2.0 + ps-list: + specifier: ^9.0.0 + version: 9.0.0 winston: specifier: ^3.18.3 version: 3.18.3 @@ -796,6 +802,9 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + pid-cwd@1.2.0: + resolution: {integrity: sha512-8QQzIdBmy4bd2l1NKWON1X8flO5TQQRzU2uRDua/XaxSC0iJ+rgbDrlX76t0W3DaJ7OevTYpftyvQ6oMe3hclQ==} + pkce-challenge@5.0.1: resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} engines: {node: '>=16.20.0'} @@ -804,6 +813,10 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} + ps-list@9.0.0: + resolution: {integrity: sha512-lxMEoIL/BQlk2KunFzxwUPwMvjFH7x7cmvzSLsSHpyMXl9FFfLUlfKrYwFc4wx/ZaIxxuXC4n8rjQ1CX/tkXVQ==} + engines: {node: '>=20'} + pvtsutils@1.3.6: resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==} @@ -1782,6 +1795,8 @@ snapshots: picocolors@1.1.1: {} + pid-cwd@1.2.0: {} + pkce-challenge@5.0.1: {} proxy-addr@2.0.7: @@ -1789,6 +1804,8 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 + ps-list@9.0.0: {} + pvtsutils@1.3.6: dependencies: tslib: 2.8.1 diff --git a/src/commands/list.ts b/src/commands/list.ts new file mode 100644 index 0000000..addb7e3 --- /dev/null +++ b/src/commands/list.ts @@ -0,0 +1,51 @@ +import { Command } from "commander"; +import pidCwd from "pid-cwd"; +import psList from "ps-list"; + +interface WatcherInfo { + pid: number; + directory: string; +} + +async function getWatchers(): Promise { + const processes = await psList(); + const watchers: WatcherInfo[] = []; + + for (const proc of processes) { + const cmd = proc.cmd || ""; + if (cmd.includes("mgrep watch")) { + const cwd = await pidCwd(proc.pid).catch(() => null); + if (cwd) { + watchers.push({ pid: proc.pid, directory: cwd }); + } + } + } + + return watchers; +} + +export async function listAction(): Promise { + if (process.platform === "win32") { + console.error("mgrep list is not supported on Windows."); + process.exitCode = 1; + return; + } + + const watchers = await getWatchers(); + + if (watchers.length === 0) { + console.error("No active mgrep watch processes found."); + process.exitCode = 0; + return; + } + + for (const w of watchers) { + console.log(w.directory); + } +} + +export const list = new Command("list") + .description("List active mgrep watch processes") + .action(async () => { + await listAction(); + }); diff --git a/src/index.ts b/src/index.ts index 9eafb04..fc6472c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,6 +3,7 @@ import * as fs from "node:fs"; import * as path from "node:path"; import { fileURLToPath } from "node:url"; import { program } from "commander"; +import { list } from "./commands/list.js"; import { login } from "./commands/login.js"; import { logout } from "./commands/logout.js"; import { search } from "./commands/search.js"; @@ -39,6 +40,7 @@ program program.addCommand(search, { isDefault: true }); program.addCommand(watch); +program.addCommand(list); program.addCommand(installClaudeCode); program.addCommand(uninstallClaudeCode); program.addCommand(installCodex);