premanmcp 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,11 +19,12 @@ Local development form:
19
19
  node bin/cli.js connect
20
20
  ```
21
21
 
22
- First-time users are prompted for email, OTP, and password directly in the terminal.
23
- PreMan creates or connects the account, generates an API key, saves it to
24
- `~/.preman/credentials.json`, then writes a `preman` MCP server into the config your
25
- agent actually reads (`~/.cursor/mcp.json`, Claude Code's MCP config, or
26
- `~/.codex/config.toml`):
22
+ First-time users are asked for an email and the code sent to it — no password: the
23
+ terminal's credential is the `pm_live_` key. Pass `--password` to also set one for
24
+ dashboard sign-in, or set it later from the dashboard. PreMan creates or connects the
25
+ account, generates an API key, saves it to `~/.preman/credentials.json`, then writes a
26
+ `preman` MCP server into the config your agent actually reads (`~/.cursor/mcp.json`,
27
+ Claude Code's MCP config, or `~/.codex/config.toml`):
27
28
 
28
29
  ```json
29
30
  {
@@ -40,19 +41,36 @@ agent actually reads (`~/.cursor/mcp.json`, Claude Code's MCP config, or
40
41
  }
41
42
  ```
42
43
 
43
- Restart your agent afterwards, then ask it to `run preman_status` to finish linking.
44
-
45
44
  `connect` reads the config back after writing it, and prints a copy-paste snippet if it
46
- cannot confirm the entry landed. It then waits for your agent to check in — that
47
- check-in is the only real proof the agent loaded the server.
48
-
49
- Once the agent has checked in, `connect` walks you into your first test: it runs one
50
- against an endpoint you already have, or prints the discovery brief to hand your agent,
51
- followed by `preman endpoints setup` and `preman test`. Pass `--no-guide` to skip it.
45
+ cannot confirm the entry landed. Then it finishes the link itself rather than asking you
46
+ to go restart anything, in cheapest-first order:
47
+
48
+ 1. **Self-test.** It starts the MCP server exactly as your agent will and calls
49
+ `preman_status` over stdio. That both completes the link and proves the whole chain
50
+ launcher, package, key, backend. `--no-self-test` turns it off.
51
+ 2. **Headless agent run** (`claude -p`, `cursor-agent -p`, `codex exec`), which also
52
+ proves your agent can load what was written. `--no-auto-checkin` turns it off.
53
+ 3. **Wait**, if neither is possible: restart your agent and it links on its first call.
54
+
55
+ A self-test that answers from an unexpected backend is reported with the file that
56
+ redirected it — a repo-local `preman-mcp.config.json` with `"PREMAN_CONFIG_OVERRIDE": true`
57
+ wins over the MCP config env, and otherwise only fills in what the env leaves unset.
58
+
59
+ Once linked, `connect` finishes onboarding without handing you homework:
60
+
61
+ | Step | What happens |
62
+ |------|--------------|
63
+ | Endpoints | Runs your agent on the discovery brief, then reports `N endpoints · M runnable` |
64
+ | First test | Generates and runs scenarios against the first runnable request |
65
+ | Runner | Pairs this machine and starts `preman runner` in the background, so PreMan can apply fixes here instead of only describing them |
66
+ | Desktop app | Offers the macOS app for watching runs and endpoints |
67
+ | Integrations | Shows GitHub / AWS / Slack, opens what is missing, and picks the connection up when you finish in the browser or the desktop app |
68
+ | Testing on push | Installs the git pre-push hook, so `git push` checks the endpoints you touched |
52
69
 
53
70
  Useful flags: `--agent cursor|claude-code|codex` skips the picker, `--project` writes
54
- project-local config, `--print` shows the config without writing it, `--no-guide` skips
55
- the guided first run.
71
+ project-local config, `--print` shows the config without writing it, `--yes` accepts every
72
+ optional step, `--no-guide` skips all of them, and `--no-runner` / `--no-desktop` /
73
+ `--no-integrations` / `--no-hook` skip one each.
56
74
 
57
75
  In CI or any non-interactive shell, run `connect --agent <name> --api-key pm_live_…`.
58
76
  Without `--agent` there is nothing to prompt on, so `connect` prints ready-to-paste
@@ -62,10 +80,18 @@ setup blocks for all three agents and exits 2.
62
80
 
63
81
  ### Cloud dispatch (optional)
64
82
 
65
- `connect` offers to store a coding-agent credential — a Cursor API key, or a Claude
66
- Code routine token and id. With one saved, PreMan can start an agent run for you when
67
- it finds a failing endpoint instead of handing back a prompt to paste. Press Enter to
68
- skip; everything else still works.
83
+ With a coding-agent credential saved — a Cursor API key from
84
+ `cursor.com/dashboard Integrations API Keys`, or a Claude Code routine token and id
85
+ from `claude.ai/code/routines your routine Add API trigger` PreMan can start an
86
+ agent run for you when it finds a failing endpoint, instead of handing back a prompt to
87
+ paste.
88
+
89
+ `connect` asks for it once you are already set up, so skipping costs nothing. Come back
90
+ to it any time:
91
+
92
+ ```bash
93
+ npm exec -y premanmcp@latest -- dispatch
94
+ ```
69
95
 
70
96
  You can also create or connect your account first:
71
97
 
@@ -180,6 +206,24 @@ npm exec -y premanmcp@latest -- login # Create/login and generate a PreMan API
180
206
  npm exec -y premanmcp@latest -- install # Cursor-only installer (legacy)
181
207
  ```
182
208
 
209
+ ### Runner
210
+
211
+ `connect` sets this up for you; these are for managing it afterwards.
212
+
213
+ ```bash
214
+ preman runner status # Paired? Running?
215
+ preman runner start --background # Hold the job stream, log to ~/.preman/runner.log
216
+ preman runner stop # Stop it and report offline
217
+ preman runner register --agent claude-code # Re-pair (e.g. a different project)
218
+ ```
219
+
220
+ The runner holds one outbound connection to PreMan and runs the work PreMan queues for
221
+ this machine — a failing endpoint becomes an agent run in your own repo instead of a
222
+ prompt you have to paste. It is bound to the agent and directory it was registered with
223
+ and refuses any job that names a different one. The agent may edit files; running commands
224
+ needs `--full-access` (or `PREMAN_RUNNER_FULL_ACCESS=1`). Nothing runs until PreMan has
225
+ something to fix, and `preman runner stop` ends it.
226
+
183
227
  Options:
184
228
 
185
229
  - `--api-key <key>`: PreMan API key.
package/bin/account.js CHANGED
@@ -8,7 +8,6 @@
8
8
  */
9
9
 
10
10
  import { existsSync, rmSync } from "node:fs";
11
- import { spawn } from "node:child_process";
12
11
  import os from "node:os";
13
12
 
14
13
  import { detectCandidates } from "./detect.js";
@@ -19,6 +18,7 @@ import {
19
18
  cliInvocation,
20
19
  frontendUrl,
21
20
  makeArgs,
21
+ openUrl,
22
22
  readStoredCredentials,
23
23
  resolveApiKey,
24
24
  saveStoredCredentials,
@@ -35,17 +35,6 @@ Account options:
35
35
  const POLL_INTERVAL_MS = 3000;
36
36
  const LOGIN_TIMEOUT_MS = 5 * 60 * 1000;
37
37
 
38
- function openBrowser(url) {
39
- const opener =
40
- process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
41
- try {
42
- spawn(opener, [url], { stdio: "ignore", detached: true, shell: process.platform === "win32" }).unref();
43
- return true;
44
- } catch {
45
- return false;
46
- }
47
- }
48
-
49
38
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
50
39
 
51
40
  export async function loginBrowser(args) {
@@ -61,7 +50,7 @@ export async function loginBrowser(args) {
61
50
  `\nApprove this device in your browser:\n ${verificationUrl}\n\n` +
62
51
  `Confirmation code: ${start.user_code}\n\n`
63
52
  );
64
- if (!openBrowser(verificationUrl)) {
53
+ if (!openUrl(verificationUrl)) {
65
54
  process.stdout.write("Could not open a browser automatically — open the link above.\n");
66
55
  }
67
56
  process.stdout.write("Waiting for approval…\n");
package/bin/cli.js CHANGED
@@ -17,7 +17,13 @@ import path from "node:path";
17
17
  import { fileURLToPath } from "node:url";
18
18
 
19
19
  import { ENDPOINTS_HELP, TEST_HELP, endpointsCommand, testCommand } from "./api_tools.js";
20
- import { CONNECT_HELP, connectCommand, writeCursorConfig } from "./connect.js";
20
+ import {
21
+ CONNECT_HELP,
22
+ DISPATCH_HELP,
23
+ connectCommand,
24
+ dispatchCommand,
25
+ writeCursorConfig,
26
+ } from "./connect.js";
21
27
  import {
22
28
  INTEGRATIONS_HELP,
23
29
  awsCommand,
@@ -28,6 +34,7 @@ import {
28
34
  import { HOSTED_HELP, linkCommand, runCommand, toolsCommand } from "./hosted.js";
29
35
  import { STATUS_HELP, statusCommand } from "./status.js";
30
36
  import { HOOK_HELP, hookCommand } from "./hook.js";
37
+ import { RUNNER_HELP, runnerCommand } from "./runner.js";
31
38
  import { VERIFY_HELP, verifyCommand } from "./verify.js";
32
39
  import { DESKTOP_HELP, installDesktopCommand } from "./desktop.js";
33
40
  import { ACCOUNT_HELP, doctorCommand, loginBrowser, logoutCommand, watchCommand } from "./account.js";
@@ -74,10 +81,12 @@ function printHelp() {
74
81
  ["status", "Healthy / failing / recently fixed endpoints"],
75
82
  ["verify [options]", "Test endpoints against your local app"],
76
83
  ["hook install|uninstall|status", "Manage the git pre-push hook"],
84
+ ["runner start|status|stop", "Run PreMan's queued agent work on this machine"],
77
85
  ["doctor", "Diagnose credentials, backend, target, integrations"],
78
86
  ["install-desktop", "Download and install the PreMan desktop app"],
79
87
  ["onboard", "Sign in, then connect agent, GitHub, AWS, Slack"],
80
88
  ["connect [options]", "Pick a coding agent and connect it"],
89
+ ["dispatch [options]", "Let PreMan start agent runs for you"],
81
90
  ["aws | github | slack", "Connect one integration on its own"],
82
91
  ["login [--browser]", "Create/login to PreMan from the terminal"],
83
92
  ["logout", "Delete stored CLI credentials"],
@@ -97,7 +106,7 @@ function printHelp() {
97
106
 
98
107
  Usage:
99
108
  ${usageLines}
100
- ${INTEGRATIONS_HELP}${CONNECT_HELP}${STATUS_HELP}${VERIFY_HELP}${HOOK_HELP}${ACCOUNT_HELP}${DESKTOP_HELP}${ENDPOINTS_HELP}${TEST_HELP}
109
+ ${INTEGRATIONS_HELP}${CONNECT_HELP}${DISPATCH_HELP}${STATUS_HELP}${VERIFY_HELP}${HOOK_HELP}${RUNNER_HELP}${ACCOUNT_HELP}${DESKTOP_HELP}${ENDPOINTS_HELP}${TEST_HELP}
101
110
  Login options:
102
111
  --email <email> Pre-fill the email prompt
103
112
  --backend <url> PreMan backend URL. Defaults to ${DEFAULT_BACKEND}
@@ -214,6 +223,8 @@ async function main() {
214
223
  await verifyCommand(commandArgs);
215
224
  } else if (command === "hook") {
216
225
  await hookCommand(commandArgs);
226
+ } else if (command === "runner") {
227
+ await runnerCommand(commandArgs);
217
228
  } else if (command === "logout") {
218
229
  await logoutCommand();
219
230
  } else if (command === "doctor") {
@@ -224,6 +235,8 @@ async function main() {
224
235
  await installDesktopCommand(commandArgs);
225
236
  } else if (command === "connect") {
226
237
  await connectCommand(commandArgs);
238
+ } else if (command === "dispatch") {
239
+ await dispatchCommand(commandArgs);
227
240
  } else if (command === "onboard" || command === "setup") {
228
241
  // makeArgs/authenticateTerminal/connectCommand are injected rather than
229
242
  // imported there, so integrations.js stays free of a cycle back into the CLI.