premanmcp 1.1.18 → 1.1.20
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 +336 -3
- package/bin/agent.js +1 -1
- package/bin/cli.js +42 -4
- package/bin/connect/checkin.js +38 -18
- package/bin/connect/guide.js +2 -1
- package/bin/connect/instructions.js +254 -0
- package/bin/connect/pairing.js +6 -1
- package/bin/connect.js +22 -204
- package/bin/credentials.d.ts +2 -0
- package/bin/credentials.js +109 -0
- package/bin/desktop_client.js +54 -0
- package/bin/eval.js +71 -12
- package/bin/eval_harness.py +20 -0
- package/bin/harness.js +48 -0
- package/bin/hook.js +13 -6
- package/bin/installed_registration.js +135 -0
- package/bin/integrations.js +11 -1
- package/bin/link.js +1 -1
- package/bin/runner.js +3 -2
- package/bin/shared.js +18 -17
- package/bin/swarm-progress.js +127 -0
- package/bin/swarm.js +164 -30
- package/bin/task_callable_runtime.js +116 -0
- package/bin/task_client.js +96 -0
- package/bin/task_local.js +126 -0
- package/bin/task_repair.js +273 -0
- package/bin/task_repair_container.js +190 -0
- package/bin/task_repair_runtime.js +189 -0
- package/bin/task_sandbox_runtime.js +78 -0
- package/bin/task_snapshot.js +208 -0
- package/bin/tasks.js +543 -0
- package/bin/verify.js +15 -3
- package/dist/server.js +2 -5
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# PreMan CLI and MCP bridge
|
|
2
2
|
|
|
3
3
|
`premanmcp` is the compatibility client for agents that can start only a local
|
|
4
4
|
stdio MCP process. It forwards MCP initialization, discovery, notifications,
|
|
@@ -18,6 +18,284 @@ four-tool PreMan conversation protocol:
|
|
|
18
18
|
|
|
19
19
|
PreMan can add private agent capabilities without publishing a new npm package.
|
|
20
20
|
|
|
21
|
+
## Installed desktop and delegated QA
|
|
22
|
+
|
|
23
|
+
This source tree adds durable delegated tasks to the modern CLI. The npm package
|
|
24
|
+
version alone is not evidence that this feature has been published. Desktop
|
|
25
|
+
packages record the exact CLI Git revision, dirty state and content hashes in
|
|
26
|
+
`resources/cli/bundle-manifest.json`; `preman doctor --json` reports that provenance
|
|
27
|
+
when present. Release builds require clean, pinned backend and dashboard sources.
|
|
28
|
+
|
|
29
|
+
On a desktop build containing these resources, sign-in provisions a revocable
|
|
30
|
+
machine API key and an executable at `~/.local/bin/preman` (Windows uses
|
|
31
|
+
`preman.cmd`). The launcher uses the signed app's embedded Electron Node runtime,
|
|
32
|
+
so a separate Node or npm installation is unnecessary. It retains the app's
|
|
33
|
+
absolute path; moving the app requires opening it again to refresh the launcher.
|
|
34
|
+
Add `~/.local/bin` to PATH if it is not already there. Detected Codex, Claude Code
|
|
35
|
+
and Cursor installations get MCP configuration and marked instructions pointing
|
|
36
|
+
to that exact executable. Existing unrelated configuration is preserved and
|
|
37
|
+
conflicts are reported. Start a new harness session after registration.
|
|
38
|
+
|
|
39
|
+
To register an agent explicitly, run the installed executable with
|
|
40
|
+
`preman connect --agent codex --no-guide` (or `claude-code` / `cursor`).
|
|
41
|
+
Connect writes the config and redeems the account pairing through its existing
|
|
42
|
+
heartbeat. Interactive connection verification initializes the configured MCP
|
|
43
|
+
bridge and discovers the four public tools; it does not invoke a tool, start a
|
|
44
|
+
coding agent, or run QA. `--no-self-test` skips that transport check, and
|
|
45
|
+
`--no-wait` writes the config and redeems pairing without waiting or self-testing.
|
|
46
|
+
After restarting the coding agent, use `preman doctor --json` and
|
|
47
|
+
`preman capabilities --json` to inspect readiness and available QA modes.
|
|
48
|
+
|
|
49
|
+
Other coding harnesses can invoke the executable as a normal CLI, or configure
|
|
50
|
+
standard MCP stdio with the absolute launcher path and `args: ["start"]`. The
|
|
51
|
+
generic MCP descriptor is available from `preman local status` in
|
|
52
|
+
`integrations.generic_mcp`. The machine credential is read from the shared,
|
|
53
|
+
backend/account-bound private credential store; it is not copied into harness
|
|
54
|
+
configuration. The bridge passes through server tools/resources and MCP Apps
|
|
55
|
+
metadata rather than maintaining a separate QA tool catalogue. A harness with
|
|
56
|
+
MCP Apps support can render the shared interactive task card; a CLI caller can
|
|
57
|
+
attach the PNG preview described below.
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
preman capabilities --json
|
|
61
|
+
preman doctor --json --workspace WORKSPACE_ID
|
|
62
|
+
preman doctor --json --workspace WORKSPACE_ID --mode endpoint \
|
|
63
|
+
--target http://127.0.0.1:8000 --repo /absolute/repository --executor-kind local
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`connection_ready` means authentication, backend and runtime are connected.
|
|
67
|
+
`target_ready` is null until a target/source is supplied; it never implies a QA
|
|
68
|
+
pass. Capabilities use the server's existing modes, resources and action policies.
|
|
69
|
+
Selection retains workspace → collection → folder → request scope. Supply saved
|
|
70
|
+
IDs in a `--context-json` file, for example:
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"mode": "endpoint",
|
|
75
|
+
"intent": "test",
|
|
76
|
+
"resources": {"collection_id": "COLLECTION_ID", "folder_id": "FOLDER_ID", "request_ids": ["REQUEST_ID"]},
|
|
77
|
+
"caller": {"name": "codex", "session_id": "CALLER_SESSION_ID"}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The durable task interface defaults to one JSON object per response. `watch`
|
|
82
|
+
emits JSONL snapshots, ordered events and a resume checkpoint. Errors are JSON on
|
|
83
|
+
stdout, with a stable code and retryability; no machine command logs in, opens a
|
|
84
|
+
browser or silently answers an approval. Human `chat -p` remains available.
|
|
85
|
+
Nested commands such as `preman task start --help` and `preman patch apply --help` show scoped help without authentication, network calls, or execution.
|
|
86
|
+
|
|
87
|
+
Prepare a complete source handoff before starting a task:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
preman task prepare -p "Run the saved checks; repair the implementation if they fail." \
|
|
91
|
+
--workspace WORKSPACE_ID --context-json scope.json --repo /absolute/repository \
|
|
92
|
+
--target http://127.0.0.1:8000 --executor-kind local --repair patch \
|
|
93
|
+
--output /tmp/preman-prepared.json --json
|
|
94
|
+
preman task start --prepared /tmp/preman-prepared.json --json
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Preparation captures/uploads the requested source and validates its workspace and
|
|
98
|
+
context without starting a task or calling a model. `status: "ready"` validates
|
|
99
|
+
the handoff, not runtime qualification or a passing test. `needs_input` lists
|
|
100
|
+
missing fields and corrective actions. For MCP, call `preman_chat` with the exact
|
|
101
|
+
`mcp.arguments` from that JSON, including the snapshot, workspace, repair policy
|
|
102
|
+
and idempotency key. Plain MCP chat remains conversational. CLI `--prepared`
|
|
103
|
+
rejects context overrides; prepare again when the intended scope changes.
|
|
104
|
+
`PREMAN_WORKSPACE_ID` supplies the workspace when `--workspace` is absent.
|
|
105
|
+
On macOS, source operations fall back to the selected Xcode Git executable when
|
|
106
|
+
the system launcher cannot write its cache inside an agent sandbox. An explicit
|
|
107
|
+
`PREMAN_GIT_BIN` remains authoritative.
|
|
108
|
+
Direct task starts also reject missing source context before creating any work;
|
|
109
|
+
CLI errors preserve `error.issues` and `error.workspace_choices`. Correct the
|
|
110
|
+
input and retry. Existing tasks retain immutable source context; use a linked
|
|
111
|
+
retest for the applied tree.
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
preman task start -p "Check the saved requests against this source; report failures." \
|
|
115
|
+
--workspace WORKSPACE_ID --context-json scope.json --repo /absolute/repository \
|
|
116
|
+
--target http://127.0.0.1:8000 --executor-kind local --repair patch \
|
|
117
|
+
--idempotency-key caller-operation-001
|
|
118
|
+
preman task get TASK_ID
|
|
119
|
+
preman task wait TASK_ID --execute-local --timeout 600 --check
|
|
120
|
+
preman task watch TASK_ID --execute-local --after 0 --timeout 600
|
|
121
|
+
preman task reply TASK_ID --request REQUEST_ID --answers-json answers.json
|
|
122
|
+
preman task message TASK_ID -p "Use the failure evidence to repair the implementation and return a patch."
|
|
123
|
+
preman task cancel TASK_ID
|
|
124
|
+
preman task result TASK_ID --check
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Retain the task ID and event cursor. Retry a mutation with the same idempotency
|
|
128
|
+
key and payload. Required input and exact action proposals return attention
|
|
129
|
+
states; only use `preman action confirm PROPOSAL_ID` after the human explicitly
|
|
130
|
+
approved that proposal's displayed impact. Cancellation is acknowledged only
|
|
131
|
+
after the owned work stops. Ctrl-C stops the CLI's wait, stops its local active
|
|
132
|
+
operation, and preserves the durable task; it does not silently cancel the task.
|
|
133
|
+
An interrupted claimed local operation is reported as incomplete, not replayed.
|
|
134
|
+
|
|
135
|
+
Exit codes: normal successful requests are 0. With `--check`, 0 requires a
|
|
136
|
+
verified pass bound to the task's exact source snapshot or explicit target build;
|
|
137
|
+
1 means failed QA; 2 means unverified, inconclusive or attention required; 3 means
|
|
138
|
+
still running. Client/API errors are 4 and interrupted waits are 130. A completed
|
|
139
|
+
chat turn, submitted job, successful patch application or missing source identity
|
|
140
|
+
cannot produce a verified `--check` pass.
|
|
141
|
+
|
|
142
|
+
### Missing QA capabilities
|
|
143
|
+
|
|
144
|
+
Delegated tasks report genuine unsupported capabilities in `feature_requests`.
|
|
145
|
+
Each persisted receipt has `capture_status: "saved"`, a stable request ID,
|
|
146
|
+
summary, review status and exact web/native links. The Feature requests page in
|
|
147
|
+
Workbench shows the workspace's reports. Developers use the separately
|
|
148
|
+
authenticated review surface to triage them. Repeated reads do not create
|
|
149
|
+
reports, and repeated reports of the same task/capability reuse the receipt.
|
|
150
|
+
|
|
151
|
+
Setup, authentication, permission, budget and transient failures remain task
|
|
152
|
+
blockers. They do not automatically become product feature requests. Saving
|
|
153
|
+
feedback does not resolve missing coverage or establish a verified QA pass.
|
|
154
|
+
An `unavailable` capture has no saved request ID or link; callers must report
|
|
155
|
+
that failure rather than claim the feedback reached developers.
|
|
156
|
+
|
|
157
|
+
The Preman agent can report a missing capability through its private
|
|
158
|
+
`report_capability_gap` action. CLI and MCP callers continue the existing task
|
|
159
|
+
with the missing capability if more context is needed; the four public MCP
|
|
160
|
+
tool names remain unchanged. Display the returned receipt and link alongside
|
|
161
|
+
the coverage gap. See [the feedback contract](../docs/DELEGATION_FEATURE_FEEDBACK.md)
|
|
162
|
+
for storage, access and recovery behavior.
|
|
163
|
+
|
|
164
|
+
### Local execution and repair
|
|
165
|
+
|
|
166
|
+
`--repo` captures dirty and untracked eligible source into an immutable local
|
|
167
|
+
snapshot and uploads the bounded snapshot to the owned workspace: at most 500
|
|
168
|
+
files, 2 MiB each, 8 MiB total. Symlinks, generated paths, credential paths and
|
|
169
|
+
detected private keys are excluded. The returned manifest names exclusions.
|
|
170
|
+
Review it with `preman snapshot create --repo /absolute/repository` before upload
|
|
171
|
+
when needed. Source is not placed in ordinary chat context.
|
|
172
|
+
|
|
173
|
+
An explicitly selected local executor needs `task wait/watch --execute-local`.
|
|
174
|
+
Without a source snapshot, localhost requests use bounded, same-origin HTTP on
|
|
175
|
+
that device and cannot claim a source-specific pass. With a source snapshot,
|
|
176
|
+
the CLI boots the immutable source in a distinct Docker container and replays
|
|
177
|
+
the frozen saved checks against that container, not the caller's original server.
|
|
178
|
+
The source manifest and execution-plan digest are bound to the run lease.
|
|
179
|
+
|
|
180
|
+
Local repairs use the same native PreMan agent loop. Its bounded file operations
|
|
181
|
+
edit a private candidate snapshot; the coding harness is not redispatched as a
|
|
182
|
+
second repair agent. Original test/config files are frozen. Dependencies, suite
|
|
183
|
+
commands and service replay run only in a local Docker engine with a preinstalled
|
|
184
|
+
qualified image. Test/boot containers have no network, dropped capabilities,
|
|
185
|
+
resource limits and no host credentials; dependency installation has network
|
|
186
|
+
access inside its restricted container. No host-shell fallback or implicit image
|
|
187
|
+
pull is used. Missing Docker, images, checks or target permissions remain explicit
|
|
188
|
+
readiness/verification gaps. `--repair patch` permits returning a patch, never
|
|
189
|
+
applying it to the caller's checkout.
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
preman artifacts get TASK_ID PATCH_ARTIFACT_ID --output /absolute/repair.json
|
|
193
|
+
preman patch apply --file /absolute/repair.json --repo /absolute/repository --check-only
|
|
194
|
+
preman patch apply --file /absolute/repair.json --repo /absolute/repository
|
|
195
|
+
preman task retest TASK_ID --repo /absolute/repository --idempotency-key caller-retest-001
|
|
196
|
+
preman task wait NEW_TASK_ID --execute-local --timeout 600 --check
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Patch application validates the original snapshot, exact changed-file preimages
|
|
200
|
+
and modes, paths, digest and postimages before editing. Unrelated caller edits
|
|
201
|
+
are preserved; changed preimages are rejected. Binary patches are unsupported.
|
|
202
|
+
Retest creates a new task/run against the newly captured source and the original
|
|
203
|
+
saved checks. It does not inherit the old verdict or verify merely by applying.
|
|
204
|
+
`artifact fetch` remains an alias for `artifacts get`.
|
|
205
|
+
|
|
206
|
+
For local AppQA, select `mode: "app_qa"`, `executor: {"kind":"local"}` and an
|
|
207
|
+
explicit supported target in context. Task creation checks target readiness and
|
|
208
|
+
registers the existing desktop controller before the server creates its run.
|
|
209
|
+
`wait/watch --execute-local` starts that assigned worker. Web targets without an
|
|
210
|
+
explicit existing-browser selection use the bundled isolated browser. Native app,
|
|
211
|
+
existing-browser and simulator targets require their platform qualification and
|
|
212
|
+
OS permissions; no permissions are requested silently. Closing the app window preserves supported
|
|
213
|
+
background execution; quitting the app stops it. A fully restarted app must prepare
|
|
214
|
+
a new worker/task rather than reusing a revoked worker lease. `preman local status`
|
|
215
|
+
and `preman local app-qa capabilities` distinguish those states.
|
|
216
|
+
|
|
217
|
+
Local web UI Flows use the installed desktop's bundled Electron browser and the
|
|
218
|
+
same Flow step engine as the backend worker. `task wait --execute-local` starts
|
|
219
|
+
only the owned run assigned to this device; no source checkout, separate worker,
|
|
220
|
+
browser download or Node installation is required. The browser uses a disposable
|
|
221
|
+
profile, blocks requests outside the selected origin, and captures each step.
|
|
222
|
+
The CLI also starts child Flow/AppQA runs created by repair verification.
|
|
223
|
+
|
|
224
|
+
Web AppQA uses that isolated browser beneath the existing AppQA observation,
|
|
225
|
+
action, lease and evidence controller. Native macOS apps, explicitly selected
|
|
226
|
+
existing browser sessions and iOS simulators retain their permission and platform
|
|
227
|
+
qualification gates. `doctor --mode flow --executor-kind local --target-kind web
|
|
228
|
+
--target http://127.0.0.1:3000` reports installed runtime readiness.
|
|
229
|
+
|
|
230
|
+
A source-bound repair can keep a private candidate service alive while the real
|
|
231
|
+
saved Flow, AppQA, endpoint and agent checks replay. All source commands run in a
|
|
232
|
+
bounded local container; the runtime verifies the immutable source, execution
|
|
233
|
+
plan and actual image ID. Private headers protect its loopback proxy and never
|
|
234
|
+
appear in public task evidence. Requests are bounded HTTP; WebSockets and streaming
|
|
235
|
+
are not supported by this local candidate proxy. No replay is assigned the
|
|
236
|
+
original caller's localhost service as candidate evidence.
|
|
237
|
+
For ASSERT source callables, the native message/history contract runs only inside
|
|
238
|
+
the selected source container. Provider-dependent code needs explicitly configured
|
|
239
|
+
isolated prerequisites; no caller provider secret is copied into the container.
|
|
240
|
+
Sandbox agent evaluations build the fixed root Dockerfile from the immutable
|
|
241
|
+
snapshot, using cached base images and no build network, mounts, secrets or remote
|
|
242
|
+
ADD. They require an existing paired evaluation runner connected on the same
|
|
243
|
+
device and Docker daemon; that runner consumes the normal agent_eval_v1 case jobs.
|
|
244
|
+
The CLI watch loop does not impersonate that evaluation runner. Missing Dockerfile,
|
|
245
|
+
base image or paired runner is an explicit prerequisite.
|
|
246
|
+
|
|
247
|
+
Closing the desktop window leaves its local executor available. A full process
|
|
248
|
+
restart preserves task history, but an interrupted AppQA worker is not rebound to
|
|
249
|
+
an uncertain browser session. `local_worker_session_lost` requires confirmed
|
|
250
|
+
cleanup followed by `preman task retest <task-id>`; it never replays browser input
|
|
251
|
+
from an expired worker lease.
|
|
252
|
+
|
|
253
|
+
### Evidence, exact links and previews
|
|
254
|
+
|
|
255
|
+
Every task includes `links.native_url` and `links.web_url` for its exact page.
|
|
256
|
+
The native format is `preman://open?source=agent&route=<encoded-workbench-route>`;
|
|
257
|
+
use the web URL when the desktop cannot open. Do not replace a task/run link with
|
|
258
|
+
the app home page. Protected artifacts require the caller's normal authentication:
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
preman artifacts get TASK_ID ARTIFACT_ID --output /absolute/evidence.png
|
|
262
|
+
preman task preview TASK_ID --output /absolute/task-card.png
|
|
263
|
+
preman task result TASK_ID --preview --output /absolute/task-card.png
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
The installed desktop renders previews from the same bundled MCP task card using
|
|
267
|
+
its sandboxed offscreen Chromium. It works with the main window closed while the
|
|
268
|
+
desktop process remains alive. The returned absolute `local_path`, media type and
|
|
269
|
+
SHA256 let a coding harness attach the preview inline. It requires no Chromium
|
|
270
|
+
download. Explicit local execution or preview commands can wake the installed
|
|
271
|
+
app in the background; readiness inspection never launches it or opens login.
|
|
272
|
+
Remote artifacts retain their normal authentication requirements.
|
|
273
|
+
|
|
274
|
+
### Upgrade and removal
|
|
275
|
+
|
|
276
|
+
Upgrade the desktop normally, then open it once to refresh its launcher and
|
|
277
|
+
managed harness registrations. A release bundles a pinned CLI plus the pinned
|
|
278
|
+
dashboard task renderer, and packaging fails if those resources or hashes are
|
|
279
|
+
missing. Release smoke tests execute the packaged Electron binary with Node
|
|
280
|
+
removed from PATH, then initialize MCP and discover tools/resources. The Electron
|
|
281
|
+
RunAsNode fuse must stay enabled for this launcher.
|
|
282
|
+
|
|
283
|
+
`preman harness status` reports managed registrations. Run `preman harness install`
|
|
284
|
+
after installing another coding harness; it preserves unrelated configuration and
|
|
285
|
+
enables the PreMan server for Cursor CLI. Start a fresh harness session afterward.
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
preman harness remove --disconnect --remove-launcher
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
This stops local desktop executors, revokes the connected machine key, removes
|
|
292
|
+
unchanged managed MCP entries and instruction blocks, and removes the marked
|
|
293
|
+
launcher. User-modified entries remain intact and are reported. If backend
|
|
294
|
+
revocation cannot be confirmed, removal stops with an actionable error. Then
|
|
295
|
+
remove the PreMan app normally. Private snapshots/repair evidence under `~/.preman`
|
|
296
|
+
remain available until explicitly removed. Desktop sign-out also stops local
|
|
297
|
+
work, revokes its machine key and removes only that account's credential profile.
|
|
298
|
+
|
|
21
299
|
## Installing
|
|
22
300
|
|
|
23
301
|
```bash
|
|
@@ -32,6 +310,11 @@ stuck in. `--no-desktop` (or `PREMAN_NO_DESKTOP=1`) skips it, and it is skipped
|
|
|
32
310
|
automatically off macOS, where there is no build. The git pre-push hook is the
|
|
33
311
|
one thing still asked about, since it changes what happens on every push.
|
|
34
312
|
|
|
313
|
+
Hook repair preserves an existing `--read-only` verification policy. Background
|
|
314
|
+
repairs and command probes suppress further automatic repairs; help, version,
|
|
315
|
+
and MCP startup do not schedule repairs. `PREMAN_NO_HOOK_REPAIR=1` disables
|
|
316
|
+
background repair while leaving an explicit `preman hook repair` available.
|
|
317
|
+
|
|
35
318
|
`preman install --cursor` writes Cursor's MCP config and nothing else, which is
|
|
36
319
|
what plain `install` used to mean; `install --api-key …` and
|
|
37
320
|
`install --project --backend …` are unchanged.
|
|
@@ -39,6 +322,44 @@ what plain `install` used to mean; `install --api-key …` and
|
|
|
39
322
|
Nothing needs installing to try it: `npm exec -y premanmcp@latest -- <command>`
|
|
40
323
|
runs any of these once, fetching the newest version each time.
|
|
41
324
|
|
|
325
|
+
### Personal QA instructions
|
|
326
|
+
|
|
327
|
+
`npm exec -y premanmcp@latest -- onboard` also installs persistent instructions
|
|
328
|
+
telling detected coding agents to use the PreMan CLI agent for every QA task:
|
|
329
|
+
agent evaluations, compatibility across agents, useful user simulations,
|
|
330
|
+
full-stack API-to-frontend testing, backend testing, and frontend QA. The same
|
|
331
|
+
step runs through `setup` and the onboarding form of `install`.
|
|
332
|
+
|
|
333
|
+
| Coding agent | User instruction file |
|
|
334
|
+
| --- | --- |
|
|
335
|
+
| Codex | `~/.codex/AGENTS.md` (or under `CODEX_HOME`); also updates a nonempty `AGENTS.override.md` because it takes precedence |
|
|
336
|
+
| Claude Code | `~/.claude/CLAUDE.md` (or under `CLAUDE_CONFIG_DIR`) |
|
|
337
|
+
| Cursor | `~/.cursor/rules/preman-qa.mdc`, with `alwaysApply: true` |
|
|
338
|
+
|
|
339
|
+
These are user-level files, not repository instructions. Codex uses the global
|
|
340
|
+
`AGENTS.md` for its [personal instructions](https://learn.chatgpt.com/docs/personalize#add-custom-instructions).
|
|
341
|
+
Claude Code loads [user memory](https://code.claude.com/docs/en/memory) across
|
|
342
|
+
projects. Cursor's [local user rule files](https://prod.cursor.com/help/customization/rules#where-are-rules-stored)
|
|
343
|
+
apply on this machine; they do not change its account-synced User Rules setting.
|
|
344
|
+
|
|
345
|
+
Existing instructions are preserved outside a marked PreMan section. Rerunning
|
|
346
|
+
onboarding updates that section without duplicates. An existing Cursor file
|
|
347
|
+
that is not a PreMan-managed, always-on rule is preserved and reported as a
|
|
348
|
+
conflict. Errors for one file do not prevent setup for the other agents.
|
|
349
|
+
Onboarding prints each installed path and any manual follow-up needed. Start
|
|
350
|
+
a new coding-agent session afterward to load the instructions.
|
|
351
|
+
|
|
352
|
+
Use `--agent codex`, `--agent claude-code`, or `--agent cursor` to target just
|
|
353
|
+
one agent, even before it is installed. Use `--no-agent-instructions` to skip
|
|
354
|
+
this step. If no supported agents are detected, onboarding reports the skip.
|
|
355
|
+
|
|
356
|
+
The installed guidance supplies
|
|
357
|
+
`npm exec -y premanmcp@latest -- chat -p "<QA objective, target, and acceptance criteria>"`
|
|
358
|
+
and tells the coding agent to follow the actual run to completion, report
|
|
359
|
+
results and coverage gaps, explain unavailable targets, and respect the user's
|
|
360
|
+
scope and approvals. Installing instructions does not itself run QA or prove
|
|
361
|
+
that an agent followed them.
|
|
362
|
+
|
|
42
363
|
## The `preman` terminal session
|
|
43
364
|
|
|
44
365
|
Installed globally, a bare `preman` opens an interactive session with the PreMan
|
|
@@ -83,12 +404,24 @@ account, backend, and workspace:
|
|
|
83
404
|
/swarm stop <run-id>
|
|
84
405
|
```
|
|
85
406
|
|
|
86
|
-
|
|
87
|
-
|
|
407
|
+
Launch follows automatically, showing queue and running counts, live tool
|
|
408
|
+
actions, and the final result. `/swarm help` lists every option. Add `--dry-run`
|
|
409
|
+
to preview a launch without starting attempts, or `--no-watch` to return
|
|
410
|
+
immediately. `--json` returns one JSON response. Ctrl+C while watching returns to the conversation and leaves
|
|
88
411
|
the swarm running; `/swarm stop <run-id>` cancels it explicitly. The same commands
|
|
89
412
|
work outside a session as `preman swarm list|launch|watch|stop|bank`. These run
|
|
90
413
|
real agents against hosted MCPs; the app's sample swarms remain a separate demo.
|
|
91
414
|
|
|
415
|
+
Headless callers can choose the existing matrix settings with `--visibility
|
|
416
|
+
resident` (or `deferred`, or both comma-separated), repeat `--model <name>` to
|
|
417
|
+
compare explicit models, and set `--budget <USD>`. The matrix budget stops new
|
|
418
|
+
cells when priced spend plus in-flight reservations reaches the limit; it cannot
|
|
419
|
+
cap provider usage whose cost is unknown. Use a provider-enforced allowance for
|
|
420
|
+
a strict spending ceiling. `launch --json --no-watch`, `watch <id> --json`, and
|
|
421
|
+
`list --json` return result links. Watch JSON also includes the individual cells
|
|
422
|
+
and their evidence; process completion and tool-selection scores do not establish
|
|
423
|
+
a verified QA pass.
|
|
424
|
+
|
|
92
425
|
A session takes a screen of its own, the way `vim` does: nothing above it is
|
|
93
426
|
scrollable, and leaving hands your shell back exactly as it was with one line
|
|
94
427
|
saying how to resume. Ctrl+C stops the current turn (PreMan keeps working on it)
|
package/bin/agent.js
CHANGED
|
@@ -2086,7 +2086,7 @@ export async function runSwarm(rest, { args, token, workspaceId, say, paint, reg
|
|
|
2086
2086
|
}
|
|
2087
2087
|
await swarmCommand(argv, {
|
|
2088
2088
|
sessionArgs: args, token, workspaceId, signal: controller.signal,
|
|
2089
|
-
write: say,
|
|
2089
|
+
write: say,
|
|
2090
2090
|
});
|
|
2091
2091
|
say("\n");
|
|
2092
2092
|
} catch (error) {
|
package/bin/cli.js
CHANGED
|
@@ -51,6 +51,9 @@ import {
|
|
|
51
51
|
} from "./desktop.js";
|
|
52
52
|
import { ACCOUNT_HELP, doctorCommand, loginBrowser, logoutCommand, watchCommand } from "./account.js";
|
|
53
53
|
import { AGENT_HELP, agentCommand } from "./agent.js";
|
|
54
|
+
import { TASK_HELP, taskHelpRequested, taskCommand, artifactCommand, capabilitiesCommand, machineDoctorCommand, snapshotCommand, patchCommand, actionCommand, localCommand } from "./tasks.js";
|
|
55
|
+
import { publicError } from "./task_client.js";
|
|
56
|
+
import { HARNESS_HELP, harnessCommand } from "./harness.js";
|
|
54
57
|
import {
|
|
55
58
|
CREDENTIALS_FILE,
|
|
56
59
|
cliInvocation,
|
|
@@ -105,6 +108,8 @@ const leadingFlag = Boolean(args[0]) && args[0].startsWith("-");
|
|
|
105
108
|
// Only the first two positions, because `run` and `dispatch` forward arguments
|
|
106
109
|
// to a tool and one of those may legitimately be asking that tool for help.
|
|
107
110
|
const wantsHelp = args.slice(0, 2).some((arg) => arg === "--help" || arg === "-h");
|
|
111
|
+
const wantsTaskHelp = ["task", "artifact", "artifacts", "snapshot", "patch", "action", "local", "capabilities", "doctor"].includes(args[0])
|
|
112
|
+
&& taskHelpRequested(args.slice(1));
|
|
108
113
|
// Leading position only, unlike help: `update --version 1.1.9` is how somebody
|
|
109
114
|
// pins a version to install, so reading `--version` anywhere would answer that
|
|
110
115
|
// with a number and never run the update. Asking a CLI its version is also the
|
|
@@ -142,6 +147,10 @@ function printHelp() {
|
|
|
142
147
|
const usage = [
|
|
143
148
|
["", "Chat with the PreMan agent in this terminal"],
|
|
144
149
|
["chat [message] [--continue]", "The same session, named explicitly"],
|
|
150
|
+
["task prepare|start|get|wait|watch|reply|cancel|retest|result", "Delegate durable QA with JSON results"],
|
|
151
|
+
["capabilities --json | doctor --json", "Discover modes and machine readiness"],
|
|
152
|
+
["artifacts get | snapshot create | patch apply", "Fetch evidence and exchange source/patches"],
|
|
153
|
+
["harness status|install|remove", "Manage installed coding-agent integrations"],
|
|
145
154
|
["status", "Healthy / failing / recently fixed endpoints"],
|
|
146
155
|
["swarm list|launch|watch|stop|bank", "Send real coding agents to see if they pick your MCP tools"],
|
|
147
156
|
["verify [options]", "Test endpoints against your local app"],
|
|
@@ -180,7 +189,7 @@ function printHelp() {
|
|
|
180
189
|
|
|
181
190
|
Usage:
|
|
182
191
|
${usageLines}
|
|
183
|
-
${AGENT_HELP}${INTEGRATIONS_HELP}${CONNECT_HELP}${DISPATCH_HELP}${STATUS_HELP}${SWARM_HELP}${VERIFY_HELP}${PROBE_HELP}${HOOK_HELP}${RUNNER_HELP}${EVAL_HELP}${TARGET_HELP}${ACCOUNT_HELP}${DESKTOP_HELP}${PREDICT_HELP}${ENDPOINTS_HELP}${TEST_HELP}${TESTS_HELP}
|
|
192
|
+
${TASK_HELP}${HARNESS_HELP}${AGENT_HELP}${INTEGRATIONS_HELP}${CONNECT_HELP}${DISPATCH_HELP}${STATUS_HELP}${SWARM_HELP}${VERIFY_HELP}${PROBE_HELP}${HOOK_HELP}${RUNNER_HELP}${EVAL_HELP}${TARGET_HELP}${ACCOUNT_HELP}${DESKTOP_HELP}${PREDICT_HELP}${ENDPOINTS_HELP}${TEST_HELP}${TESTS_HELP}
|
|
184
193
|
Login options:
|
|
185
194
|
--email <email> Pre-fill the email prompt
|
|
186
195
|
--backend <url> PreMan backend URL. Defaults to ${DEFAULT_BACKEND}
|
|
@@ -362,13 +371,36 @@ function startServer() {
|
|
|
362
371
|
}
|
|
363
372
|
|
|
364
373
|
async function main() {
|
|
374
|
+
// Scoped help must precede hook repair, credentials, source capture and any
|
|
375
|
+
// executor or network activity, including help on nested operations.
|
|
376
|
+
if (wantsTaskHelp) {
|
|
377
|
+
process.stdout.write(TASK_HELP);
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
365
380
|
// Running at all is the signal. `hook` and `verify` own the hook themselves,
|
|
366
381
|
// and connect reinstalls it in the foreground, so a background rewrite there
|
|
367
|
-
// would only race with the one the user is watching.
|
|
368
|
-
|
|
382
|
+
// would only race with the one the user is watching. Informational commands
|
|
383
|
+
// and MCP startup must remain free of background hook changes.
|
|
384
|
+
if (!["help", "version", "start", "hook", "verify", "connect", "task", "artifact", "artifacts", "snapshot", "patch", "action", "local", "capabilities", "harness"].includes(command) && !(command === "doctor" && commandArgs.includes("--json"))) scheduleHookRepair();
|
|
369
385
|
|
|
370
386
|
if (command === "version") {
|
|
371
387
|
process.stdout.write(`${packageVersion() || "unknown"}\n`);
|
|
388
|
+
} else if (command === "task") {
|
|
389
|
+
process.exitCode = await taskCommand(commandArgs);
|
|
390
|
+
} else if (command === "harness") {
|
|
391
|
+
process.exitCode = await harnessCommand(commandArgs);
|
|
392
|
+
} else if (["artifact", "artifacts"].includes(command)) {
|
|
393
|
+
process.exitCode = await artifactCommand(commandArgs);
|
|
394
|
+
} else if (command === "snapshot") {
|
|
395
|
+
process.exitCode = await snapshotCommand(commandArgs);
|
|
396
|
+
} else if (command === "patch") {
|
|
397
|
+
process.exitCode = await patchCommand(commandArgs);
|
|
398
|
+
} else if (command === "action") {
|
|
399
|
+
process.exitCode = await actionCommand(commandArgs);
|
|
400
|
+
} else if (command === "local") {
|
|
401
|
+
process.exitCode = await localCommand(commandArgs);
|
|
402
|
+
} else if (command === "capabilities") {
|
|
403
|
+
process.exitCode = await capabilitiesCommand(commandArgs);
|
|
372
404
|
} else if (command === "agent" || command === "chat") {
|
|
373
405
|
await agentCommand(commandArgs);
|
|
374
406
|
} else if (command === "target") {
|
|
@@ -414,7 +446,8 @@ async function main() {
|
|
|
414
446
|
} else if (command === "logout") {
|
|
415
447
|
await logoutCommand();
|
|
416
448
|
} else if (command === "doctor") {
|
|
417
|
-
await
|
|
449
|
+
if (commandArgs.includes("--json")) process.exitCode = await machineDoctorCommand(commandArgs);
|
|
450
|
+
else await doctorCommand(commandArgs);
|
|
418
451
|
} else if (command === "watch") {
|
|
419
452
|
await watchCommand(commandArgs);
|
|
420
453
|
} else if (command === "install-desktop") {
|
|
@@ -530,6 +563,11 @@ async function main() {
|
|
|
530
563
|
}
|
|
531
564
|
|
|
532
565
|
main().catch((error) => {
|
|
566
|
+
if (["task", "artifact", "artifacts", "snapshot", "patch", "action", "local", "capabilities", "harness"].includes(command) || (command === "doctor" && commandArgs.includes("--json"))) {
|
|
567
|
+
process.stdout.write(`${JSON.stringify(publicError(error))}\n`);
|
|
568
|
+
process.exitCode = error?.exitCode || 4;
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
533
571
|
const message = error instanceof Error ? error.message : String(error);
|
|
534
572
|
process.stderr.write(`[preman] ${message}\n`);
|
|
535
573
|
process.exit(error?.exitCode || 1);
|
package/bin/connect/checkin.js
CHANGED
|
@@ -9,13 +9,14 @@
|
|
|
9
9
|
|
|
10
10
|
import { spawn, spawnSync } from "node:child_process";
|
|
11
11
|
import { existsSync } from "node:fs";
|
|
12
|
-
import { callBackendJson, onPath } from "../shared.js";
|
|
12
|
+
import { callBackendJson, cliInvocation, onPath } from "../shared.js";
|
|
13
13
|
|
|
14
14
|
import { findAgent } from "./agents.js";
|
|
15
15
|
import { shellQuote } from "./configs.js";
|
|
16
16
|
|
|
17
17
|
const MCP_CONNECT_SOURCES = new Set([
|
|
18
18
|
"mcp",
|
|
19
|
+
// Historical pairing receipts remain valid; this is never invoked as a tool.
|
|
19
20
|
"preman_status",
|
|
20
21
|
"premanmcp",
|
|
21
22
|
"agent",
|
|
@@ -102,10 +103,9 @@ export function pollTicker() {
|
|
|
102
103
|
/**
|
|
103
104
|
* How to ask each agent to make one PreMan call without opening its UI.
|
|
104
105
|
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
* prompting.
|
|
106
|
+
* Retained for callers that explicitly open an agent session. Connection
|
|
107
|
+
* verification itself uses MCP discovery and the terminal's pairing heartbeat,
|
|
108
|
+
* without starting an agent or a QA conversation.
|
|
109
109
|
*/
|
|
110
110
|
export function headlessCheckIn(agent, serverName) {
|
|
111
111
|
const prompt = checkInPrompt(serverName);
|
|
@@ -123,7 +123,8 @@ export function headlessCheckIn(agent, serverName) {
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
function checkInPrompt(serverName) {
|
|
126
|
-
|
|
126
|
+
const cli = cliInvocation();
|
|
127
|
+
return `Run ${cli} doctor --json and ${cli} capabilities --json, then report PreMan readiness and any blockers. The configured MCP server is ${serverName}. Do not start QA or a chat merely to verify the connection.`;
|
|
127
128
|
}
|
|
128
129
|
|
|
129
130
|
/**
|
|
@@ -365,7 +366,7 @@ export function selfTestBudgetMs() {
|
|
|
365
366
|
}
|
|
366
367
|
|
|
367
368
|
/**
|
|
368
|
-
* Run the config we just wrote, exactly as the agent will, and
|
|
369
|
+
* Run the config we just wrote, exactly as the agent will, and discover tools.
|
|
369
370
|
*
|
|
370
371
|
* This is both the fastest way to finish the link and the only check that proves
|
|
371
372
|
* the whole chain — launcher, package, key, backend — rather than proving the
|
|
@@ -374,7 +375,9 @@ export function selfTestBudgetMs() {
|
|
|
374
375
|
* redirect the server to a backend the key was never issued for, and every
|
|
375
376
|
* symptom of that points at the key.
|
|
376
377
|
*
|
|
377
|
-
* Speaks the two JSON-RPC
|
|
378
|
+
* Speaks the two JSON-RPC requests an MCP client makes on startup. No tool is
|
|
379
|
+
* called: discovery verifies the authenticated transport without model usage.
|
|
380
|
+
* Pairing is separately established by the terminal heartbeat. Never throws.
|
|
378
381
|
*/
|
|
379
382
|
export async function mcpSelfTest(
|
|
380
383
|
serverConfig,
|
|
@@ -468,24 +471,41 @@ export async function mcpSelfTest(
|
|
|
468
471
|
continue;
|
|
469
472
|
}
|
|
470
473
|
if (message.id === 1) {
|
|
474
|
+
if (message.error || !message.result?.protocolVersion) {
|
|
475
|
+
finish({ ok: false, reason: message.error?.message || "the MCP server returned an invalid initialization response" });
|
|
476
|
+
continue;
|
|
477
|
+
}
|
|
471
478
|
send({ jsonrpc: "2.0", method: "notifications/initialized" });
|
|
472
479
|
send({
|
|
473
480
|
jsonrpc: "2.0",
|
|
474
481
|
id: 2,
|
|
475
|
-
method: "tools/
|
|
476
|
-
params: {
|
|
482
|
+
method: "tools/list",
|
|
483
|
+
params: {},
|
|
477
484
|
});
|
|
478
485
|
continue;
|
|
479
486
|
}
|
|
480
487
|
if (message.id !== 2) continue;
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
status = text ? JSON.parse(text) : {};
|
|
485
|
-
} catch {
|
|
486
|
-
status = { raw: text };
|
|
488
|
+
if (message.error) {
|
|
489
|
+
finish({ ok: false, reason: message.error.message || "MCP tool discovery failed" });
|
|
490
|
+
continue;
|
|
487
491
|
}
|
|
488
|
-
|
|
492
|
+
const expected = ["preman_chat", "preman_confirm_action", "preman_get_turn", "preman_cancel_turn"].sort();
|
|
493
|
+
const names = Array.isArray(message.result?.tools)
|
|
494
|
+
? message.result.tools.map((tool) => tool?.name).sort()
|
|
495
|
+
: [];
|
|
496
|
+
if (JSON.stringify(names) !== JSON.stringify(expected) || message.result?.nextCursor) {
|
|
497
|
+
finish({ ok: false, reason: "the MCP server did not expose the four supported PreMan tools; update PreMan and check the configured backend" });
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
finish({
|
|
501
|
+
ok: true,
|
|
502
|
+
status: {
|
|
503
|
+
authenticated: true,
|
|
504
|
+
backend_url: serverConfig.env?.PREMAN_BACKEND || "",
|
|
505
|
+
tools: names,
|
|
506
|
+
},
|
|
507
|
+
reason: "",
|
|
508
|
+
});
|
|
489
509
|
}
|
|
490
510
|
});
|
|
491
511
|
|
|
@@ -494,7 +514,7 @@ export async function mcpSelfTest(
|
|
|
494
514
|
id: 1,
|
|
495
515
|
method: "initialize",
|
|
496
516
|
params: {
|
|
497
|
-
protocolVersion: "
|
|
517
|
+
protocolVersion: "2025-06-18",
|
|
498
518
|
capabilities: {},
|
|
499
519
|
clientInfo: { name: "preman-connect-selftest", version: "1" },
|
|
500
520
|
},
|
package/bin/connect/guide.js
CHANGED
|
@@ -40,9 +40,10 @@ function manualSteps() {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export function nextStepsBlock(agent) {
|
|
43
|
+
const cli = cliInvocation();
|
|
43
44
|
return (
|
|
44
45
|
"\nNext steps:\n" +
|
|
45
|
-
` 1. Restart ${agent.label}, then ask it
|
|
46
|
+
` 1. Restart ${agent.label}, then ask it to run "${cli} doctor --json" and "${cli} capabilities --json" to check readiness.\n` +
|
|
46
47
|
` 2. ${cliInvocation()} runner start --background # let PreMan run work here\n` +
|
|
47
48
|
` 3. ${cliInvocation()} endpoints discover # map this repo's endpoints\n` +
|
|
48
49
|
` 4. ${cliInvocation()} hook install # test affected endpoints on git push\n`
|