@modootoday/pmcp 0.11.0 → 0.13.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 +92 -494
- package/dist/cli.js +9307 -3930
- package/dist/{embed-BBhv3y5x.d.ts → embed-BW6AWD1e.d.ts} +1 -1
- package/dist/harness-egress-bridge.d.ts +2 -0
- package/dist/harness-egress-bridge.js +74 -0
- package/dist/harness-launch-gate.d.ts +2 -0
- package/dist/harness-launch-gate.js +1187 -0
- package/dist/harness-pane-runner.d.ts +2 -0
- package/dist/harness-pane-runner.js +118 -0
- package/dist/harness-worker.d.ts +2 -0
- package/dist/harness-worker.js +2737 -0
- package/dist/http.d.ts +3 -3
- package/dist/http.js +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +1 -1
- package/dist/stdio.d.ts +1 -1
- package/dist/stdio.js +1 -1
- package/dist/tui-worker.d.ts +2 -0
- package/dist/tui-worker.js +5973 -0
- package/docs/embeddings.md +125 -0
- package/docs/hosting.md +46 -0
- package/docs/mailbox.md +59 -0
- package/docs/project-configuration.md +203 -0
- package/docs/skills.md +74 -0
- package/docs/terminal-harness.md +393 -0
- package/docs/terminal-workspace.md +116 -0
- package/package.json +3 -2
- package/dist/{server-CwWcRjqz.d.ts → server-9w4R1caM.d.ts} +4 -4
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
# Native terminal control
|
|
2
|
+
|
|
3
|
+
Use `pmcp harness` to manage a main runtime and its workers through a local CLI.
|
|
4
|
+
Each runtime keeps its own conversation interface, OAuth login, folder trust and
|
|
5
|
+
tool permissions. PMCP manages owned terminal processes, observations and
|
|
6
|
+
explicit input delivery. These controls are available from version 0.12.0;
|
|
7
|
+
check your installed release's `pmcp harness --help` before using them.
|
|
8
|
+
|
|
9
|
+
The host currently needs Linux, tmux, util-linux flock and a working user systemd
|
|
10
|
+
manager. Native executables must be on PATH. The terminal transport was tested
|
|
11
|
+
with tmux 3.2a and controlled executable fixtures. That does not qualify every
|
|
12
|
+
vendor's prompt state, automatic wake, authentication refresh or native children.
|
|
13
|
+
|
|
14
|
+
## Check the host
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
pmcp harness capabilities inspect
|
|
18
|
+
pmcp harness doctor inspect
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
These commands report executable paths and required tools without starting a
|
|
22
|
+
provider or reading its credentials. An installed executable is not a qualified
|
|
23
|
+
provider feature. Use `pmcp doctor` separately for project configuration checks.
|
|
24
|
+
|
|
25
|
+
Group creation checks required tools and contacts the user manager before it
|
|
26
|
+
writes group state. Missing tools return native_host_tool_unavailable followed
|
|
27
|
+
by the tool name; an unreachable manager returns native_user_manager_unavailable.
|
|
28
|
+
The doctor report lists prerequisites and does not certify cgroup delegation.
|
|
29
|
+
An ordinary isolated Docker container usually lacks this user manager and a
|
|
30
|
+
writable delegated cgroup subtree. Container resource limits alone do not
|
|
31
|
+
qualify the native session controls; the current profile requires its Linux host.
|
|
32
|
+
|
|
33
|
+
## Choose native or Docker execution
|
|
34
|
+
|
|
35
|
+
The default native profile starts executables on the Linux host. The optional
|
|
36
|
+
Docker profile keeps the same host-side tmux and user-systemd controller, while
|
|
37
|
+
each native executable runs in its own bounded container. Docker does not
|
|
38
|
+
replace the host prerequisites above. Only a local Docker Engine is supported.
|
|
39
|
+
|
|
40
|
+
Prepare an image locally with your runtime installed. PMCP requires its exact
|
|
41
|
+
image ID, refuses a missing image and never builds or pulls one. The image must
|
|
42
|
+
support the host UID/GID and the absolute command paths in your policy.
|
|
43
|
+
Create `docker-policy.json` with this structure, replacing the image ID:
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"schemaVersion": 1,
|
|
48
|
+
"image": "sha256:YOUR_64_CHARACTER_IMAGE_ID",
|
|
49
|
+
"network": "none",
|
|
50
|
+
"workspaceAccess": "read-only",
|
|
51
|
+
"commands": {
|
|
52
|
+
"codex-cli": ["/usr/local/bin/codex"]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Set `profile` to `docker` and `dockerPolicyFile` to the policy's absolute path in
|
|
58
|
+
your group specification. The policy is validated and frozen into group state;
|
|
59
|
+
editing its file does not expand a running group's authority. Group creation and
|
|
60
|
+
session start use the same commands as native execution.
|
|
61
|
+
|
|
62
|
+
Each container gets a read-only root, no network, all capabilities dropped,
|
|
63
|
+
no-new-privileges, 64 PIDs and a memory/swap ceiling. Its only bind mounts are
|
|
64
|
+
the project at `/workspace` and a private writable profile at `/state`.
|
|
65
|
+
The workspace is read-only unless the policy explicitly selects read-write.
|
|
66
|
+
Native arguments belong in the session specification; PMCP adds no native
|
|
67
|
+
permission bypass. Docker access itself is a privileged host capability.
|
|
68
|
+
|
|
69
|
+
The session `memoryMb` reserves both runtime memory and 64 MiB for its host
|
|
70
|
+
connection. Its Docker memory limit is therefore 64 MiB smaller. Leave additional
|
|
71
|
+
headroom in the group budget for its controller and tmux server.
|
|
72
|
+
Session receipts include the owned container identity only for Docker execution.
|
|
73
|
+
Unknown or changed container identity blocks cleanup and admission.
|
|
74
|
+
|
|
75
|
+
### Allow provider connections explicitly
|
|
76
|
+
|
|
77
|
+
Network-none containers are offline by default. To allow provider HTTPS, add an
|
|
78
|
+
`egress` entry to the policy:
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"hosts": ["chatgpt.com", "auth.openai.com"],
|
|
83
|
+
"bridgeExecutable": "/usr/local/bin/node"
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
These are exact hostnames on port 443, not domain suffixes or wildcards. The
|
|
88
|
+
host proxy rejects private addresses and undeclared destinations. The declared
|
|
89
|
+
Node executable must exist inside the image. PMCP stages a digest-checked opaque
|
|
90
|
+
bridge and provides proxy environment variables to the native process. It does
|
|
91
|
+
not intercept TLS or interpret OAuth. A runtime that ignores proxy variables
|
|
92
|
+
cannot reach the provider through this profile. Actual Codex 0.161.0 login and
|
|
93
|
+
main/worker responses have been qualified; other vendors and token refresh need
|
|
94
|
+
their own validation. These two hosts are an observed test scope, not a promise
|
|
95
|
+
that all future Codex features use only them.
|
|
96
|
+
|
|
97
|
+
### Keep authenticated roles independent
|
|
98
|
+
|
|
99
|
+
Omitting `privateProfiles` creates a new empty profile for each launch. For
|
|
100
|
+
explicit reuse, prepare distinct local directories owned by your UID with mode
|
|
101
|
+
0700, outside the project and credential home. Add named grants to the policy:
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"main": {
|
|
106
|
+
"runtime": "codex-cli",
|
|
107
|
+
"directory": "/absolute/private/main-profile",
|
|
108
|
+
"lockExecutable": "/usr/bin/flock"
|
|
109
|
+
},
|
|
110
|
+
"worker": {
|
|
111
|
+
"runtime": "codex-cli",
|
|
112
|
+
"directory": "/absolute/private/worker-profile",
|
|
113
|
+
"lockExecutable": "/usr/bin/flock"
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Place this object under `privateProfiles`. Select `privateProfile: "main"` or
|
|
119
|
+
`privateProfile: "worker"` in the corresponding session specification. PMCP
|
|
120
|
+
checks and freezes directory/lock identity; the selected runtime must match its
|
|
121
|
+
grant. The image must provide the declared flock executable.
|
|
122
|
+
|
|
123
|
+
Authenticate each role with its vendor's native login in that role's isolated
|
|
124
|
+
profile. PMCP supplies no credential import or account-switching command.
|
|
125
|
+
Do not copy your host credentials or clone one role's profile into another.
|
|
126
|
+
Never place profiles or mailbox actor files below the mounted project. An
|
|
127
|
+
exclusive kernel lock stays held by the container while its runtime lives,
|
|
128
|
+
even if the host terminal connection exits. Stop the exact owned session before
|
|
129
|
+
reusing its profile. This lock is cooperative same-UID fencing, not protection
|
|
130
|
+
against a hostile host administrator.
|
|
131
|
+
|
|
132
|
+
Keep private profiles when you stop a group if you intend to reuse their native
|
|
133
|
+
login. Session termination does not log out the account or delete credentials.
|
|
134
|
+
Do not publish these directories or add them to source control.
|
|
135
|
+
|
|
136
|
+
## Create a group and its sessions
|
|
137
|
+
|
|
138
|
+
Save this as `group-spec.json`, replacing the project path:
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
{
|
|
142
|
+
"projectRoot": "/absolute/project/path",
|
|
143
|
+
"allowedRuntimes": ["codex-cli", "claude-code"],
|
|
144
|
+
"memoryMb": 2048,
|
|
145
|
+
"maxActive": 2
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
```sh
|
|
150
|
+
pmcp harness group create --input group-spec.json
|
|
151
|
+
pmcp harness group list
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
The JSON receipt provides the private groupFile and generation. Set GROUP_FILE
|
|
155
|
+
and GENERATION to those values for the examples below. Group state lives below
|
|
156
|
+
XDG_STATE_HOME/pmcp/harness, or ~/.local/state/pmcp/harness. The tmux socket path
|
|
157
|
+
must fit within 100 bytes; an unusually long state root is refused.
|
|
158
|
+
|
|
159
|
+
Save `main-spec.json`:
|
|
160
|
+
|
|
161
|
+
```json
|
|
162
|
+
{
|
|
163
|
+
"runtime": "codex-cli",
|
|
164
|
+
"role": "main",
|
|
165
|
+
"memoryMb": 768
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
```sh
|
|
170
|
+
pmcp harness session start --group-file "$GROUP_FILE" --generation "$GENERATION" --input main-spec.json
|
|
171
|
+
pmcp harness session list --group-file "$GROUP_FILE"
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Start a worker with another specification whose role is worker. Supported
|
|
175
|
+
runtime IDs are codex-cli, claude-code, gemini-cli, grok-cli and antigravity;
|
|
176
|
+
their executable names are codex, claude, gemini, grok and agy. Optional args
|
|
177
|
+
contains native CLI arguments. PMCP adds no permission bypass flags.
|
|
178
|
+
Start resolves the executable against the native working directory before
|
|
179
|
+
creating a launch record. A missing or non-executable program is refused as
|
|
180
|
+
runtime_executable_unavailable; directories are not accepted as executables.
|
|
181
|
+
|
|
182
|
+
A group has one main. Workers require an available main, a runtime grant and
|
|
183
|
+
room in both the session-count and memory budgets. cwd defaults to projectRoot
|
|
184
|
+
and must resolve inside it. This working-directory check and cooperative writer
|
|
185
|
+
leases do not isolate filesystem access from another process of the same UID.
|
|
186
|
+
|
|
187
|
+
Native execution waits behind a start gate until its owned terminal record and
|
|
188
|
+
group registration are saved. The gate checks the group generation, runtime
|
|
189
|
+
grant and role before starting the executable. A failed or interrupted start
|
|
190
|
+
blocks further admission until you explicitly resolve it.
|
|
191
|
+
|
|
192
|
+
## Observe or take control
|
|
193
|
+
|
|
194
|
+
Set SESSION to a session ID from the receipt:
|
|
195
|
+
|
|
196
|
+
```sh
|
|
197
|
+
pmcp harness session inspect --group-file "$GROUP_FILE" --session "$SESSION"
|
|
198
|
+
pmcp harness session read --group-file "$GROUP_FILE" --session "$SESSION"
|
|
199
|
+
pmcp harness attach open --group-file "$GROUP_FILE" --session "$SESSION"
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Attachment is read-only by default. Detach with tmux's Ctrl-b then d, or use
|
|
203
|
+
attach detach with the target session and current generation. Detach preserves
|
|
204
|
+
the runtime. Reading returns terminal text and does not infer model readiness.
|
|
205
|
+
|
|
206
|
+
For longer history, save read-options.json:
|
|
207
|
+
|
|
208
|
+
```json
|
|
209
|
+
{ "lines": 2000, "maxBytes": 16384 }
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
```sh
|
|
213
|
+
pmcp harness session read --group-file "$GROUP_FILE" --session "$SESSION" --input read-options.json
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
lines accepts 1–2000 and maxBytes accepts 1–65536. Defaults remain 100 lines and
|
|
217
|
+
16384 bytes. A bounded result reports truncated when it omits earlier content.
|
|
218
|
+
During an alternate-screen application, alternate: true reads the saved normal
|
|
219
|
+
screen; omitted or false reads the current screen. This returns the owned native
|
|
220
|
+
pane's content, separate from a surrounding terminal's older shell output.
|
|
221
|
+
|
|
222
|
+
On the tested tmux 3.2a, read-only native clients ignore typing, wheel reports
|
|
223
|
+
and copy-mode keys; use session read for history without acquiring control.
|
|
224
|
+
Inside another tmux with the same Ctrl-b prefix, Ctrl-b then Ctrl-b forwards
|
|
225
|
+
one prefix to the inner layer. Ctrl-b then [ opens the outer copy mode, while
|
|
226
|
+
Ctrl-b, Ctrl-b, d detaches the inner connection. Outer history is the rendered
|
|
227
|
+
wrapper screen; session read retrieves the owned runtime's history.
|
|
228
|
+
PMCP does not change the outer tmux configuration. Other terminal mouse and
|
|
229
|
+
trackpad settings require their own qualification.
|
|
230
|
+
|
|
231
|
+
For bounded polling, session watch also takes an input file containing count
|
|
232
|
+
(1–10) and intervalMs (100–2000). It returns snapshots rather than an endless
|
|
233
|
+
stream.
|
|
234
|
+
|
|
235
|
+
Acquire native control before opening a writable attachment:
|
|
236
|
+
|
|
237
|
+
```sh
|
|
238
|
+
pmcp harness control acquire --group-file "$GROUP_FILE" --generation "$GENERATION" --session "$SESSION" --controller operator --mode native
|
|
239
|
+
pmcp harness attach open --group-file "$GROUP_FILE" --generation "$GENERATION" --session "$SESSION" --mode write --lease-file "$LEASE_FILE"
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Set LEASE_FILE to the acquire receipt's private credential path. A writable
|
|
243
|
+
attachment renews its 60-second lease and releases it after detach. Failed
|
|
244
|
+
renewal disconnects the client. It does not stop the runtime. Another writable
|
|
245
|
+
tmux client blocks CLI delivery even if it bypassed PMCP's lease.
|
|
246
|
+
|
|
247
|
+
## Deliver input explicitly
|
|
248
|
+
|
|
249
|
+
Use mode cli when acquiring a lease for explicit command-line input.
|
|
250
|
+
Save literal single-line UTF-8 text in prompt.txt:
|
|
251
|
+
|
|
252
|
+
```sh
|
|
253
|
+
pmcp harness input write --group-file "$GROUP_FILE" --generation "$GENERATION" --lease-file "$LEASE_FILE" --request-id task1-attempt1-draft --text-file prompt.txt
|
|
254
|
+
pmcp harness input submit --group-file "$GROUP_FILE" --generation "$GENERATION" --lease-file "$LEASE_FILE" --request-id task1-attempt1-submit
|
|
255
|
+
pmcp harness control release --group-file "$GROUP_FILE" --generation "$GENERATION" --lease-file "$LEASE_FILE"
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Write and Enter submission are separate operations. Newlines, tabs, terminal
|
|
259
|
+
control characters and input above 16 KiB are refused. A tmux paste flag alone
|
|
260
|
+
cannot guarantee safe multiline delivery in a native approval menu.
|
|
261
|
+
|
|
262
|
+
Inspect the native screen before writing or submitting. A control lease identifies
|
|
263
|
+
the writer; it does not identify the active native widget. PMCP does not infer
|
|
264
|
+
that a composer is ready or that a native approval has been granted.
|
|
265
|
+
|
|
266
|
+
Reuse an input request ID only for an exact retry. Matching retries return the
|
|
267
|
+
previous receipt; they do not send again. Conflicting content is refused.
|
|
268
|
+
input_written means terminal delivery, not model processing or task completion.
|
|
269
|
+
Intent or uncertain delivery requires recovery and is never automatically
|
|
270
|
+
replayed. delivery list and delivery inspect expose this journal.
|
|
271
|
+
|
|
272
|
+
An uncertain receipt has ok: false and CLI exit code 1, including an exact
|
|
273
|
+
retry that returns the stored receipt. Inspect its state instead of assuming
|
|
274
|
+
that a nonzero exit means no record exists. An exited worker remains observable;
|
|
275
|
+
stop it by ID and explicitly start a replacement. Old request IDs are not
|
|
276
|
+
transferred to the replacement, and sibling sessions retain their input.
|
|
277
|
+
|
|
278
|
+
Input interrupt sends an explicit terminal Ctrl-c under the same lease.
|
|
279
|
+
Cancellation, process termination and provider-side completion are distinct.
|
|
280
|
+
|
|
281
|
+
## Coordinate through the existing mailbox
|
|
282
|
+
|
|
283
|
+
Use the existing `pmcp mailbox` commands for send, inbox, read and ack.
|
|
284
|
+
Keep task and attempt IDs in your message body; send a result with replyToId
|
|
285
|
+
pointing to its request. Main review reads the reply. Acknowledgment records
|
|
286
|
+
receipt handling and does not declare task completion or user acceptance.
|
|
287
|
+
|
|
288
|
+
PMCP does not create another message engine or automatically type a wake prompt
|
|
289
|
+
into a native menu. Follow the [mailbox guide](mailbox.md) for actor credentials
|
|
290
|
+
and launcher-bound runtime attachments.
|
|
291
|
+
There is no automatic delivery loop. Native readiness and approval stay with
|
|
292
|
+
the operator and runtime; an input receipt does not establish prompt readiness.
|
|
293
|
+
|
|
294
|
+
### A manual request and review workflow
|
|
295
|
+
|
|
296
|
+
Mailbox actor names and harness session roles are separate. Creating a main or
|
|
297
|
+
worker terminal does not register a mailbox actor or give it credentials. Use
|
|
298
|
+
the mailbox guide to initialize the project and register main, worker and
|
|
299
|
+
operator actors. Keep their credential files private. The following workflow
|
|
300
|
+
uses CLI actor files for manual coordination; it does not attach a vendor child
|
|
301
|
+
or automatically configure a runtime's MCP server.
|
|
302
|
+
|
|
303
|
+
Save request.json with your actor name and a unique task/attempt pair:
|
|
304
|
+
|
|
305
|
+
```json
|
|
306
|
+
{
|
|
307
|
+
"recipients": [{ "actorId": "worker" }],
|
|
308
|
+
"body": "{\"taskId\":\"review-1\",\"attemptId\":\"attempt-1\",\"kind\":\"request\",\"text\":\"Review the proposed change\"}",
|
|
309
|
+
"idempotencyKey": "review-1-attempt-1"
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
```sh
|
|
314
|
+
pmcp mailbox send --config ./pmcp.toml --actor-file "$MAIN_ACTOR_FILE" --input request.json
|
|
315
|
+
pmcp mailbox inbox --config ./pmcp.toml --actor-file "$WORKER_ACTOR_FILE"
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
The send receipt returns messageId and threadId. Save the returned messageId
|
|
319
|
+
in message.json as {"messageId":"the-returned-UUID"}, then read and acknowledge:
|
|
320
|
+
|
|
321
|
+
```sh
|
|
322
|
+
pmcp mailbox read --config ./pmcp.toml --actor-file "$WORKER_ACTOR_FILE" --input message.json
|
|
323
|
+
pmcp mailbox ack --config ./pmcp.toml --actor-file "$WORKER_ACTOR_FILE" --input message.json
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
Receiving and acknowledging a request sends no terminal input. When its native
|
|
327
|
+
prompt is ready, deliver a single-line prompt through the worker's CLI lease
|
|
328
|
+
and submit separately. Include the task/attempt and request message ID so the
|
|
329
|
+
worker can associate its response. Preserve uncertain delivery for inspection.
|
|
330
|
+
|
|
331
|
+
To report a result, use mailbox send with the same taskId and attemptId in body,
|
|
332
|
+
a new idempotencyKey, recipients containing main, and replyToId containing the
|
|
333
|
+
original request messageId. The worker must first read that request. The result
|
|
334
|
+
keeps its threadId; the main can filter inbox with an input file containing
|
|
335
|
+
{"threadId":"the-returned-thread-UUID"} and read the selected reply.
|
|
336
|
+
|
|
337
|
+
Read the body and verify its task, attempt and sender before accepting the
|
|
338
|
+
result. These body fields are a coordination convention, not a mailbox-enforced
|
|
339
|
+
task state machine. A new attempt uses a new request and idempotency key; keep
|
|
340
|
+
the previous result in its original thread. Exact send retries reuse their key
|
|
341
|
+
and return the existing message; changed payloads are refused.
|
|
342
|
+
|
|
343
|
+
The main can send its synthesis to operator as a reply to the reviewed result.
|
|
344
|
+
After reading it, the operator may send a separate acceptance reply. ACK records
|
|
345
|
+
receipt handling only. Neither result text, ACK nor acceptance automatically
|
|
346
|
+
submits a terminal draft, transfers control or executes a command.
|
|
347
|
+
|
|
348
|
+
## Pause, stop and recover
|
|
349
|
+
|
|
350
|
+
group pause prevents new sessions without interrupting running providers.
|
|
351
|
+
group resume permits admission again. group configure takes a JSON input to
|
|
352
|
+
adjust budgets or narrow runtime grants; it refuses reductions below active
|
|
353
|
+
reservations. Expanding grants requires a new group.
|
|
354
|
+
|
|
355
|
+
session stop names one owned session. group stop explicitly stops its entire
|
|
356
|
+
owned group and removes runtime budget properties. Both require the current
|
|
357
|
+
generation. They do not target an existing external tmux session.
|
|
358
|
+
|
|
359
|
+
recovery inspect reports observations, leases, uncertain deliveries and
|
|
360
|
+
unregistered owned sessions. recovery reconcile removes a writer lock only
|
|
361
|
+
after its controller has exited and never resends input. Use recovery
|
|
362
|
+
stop-orphan for a named unregistered session, or recovery replace-main with a
|
|
363
|
+
new main specification after the previous main has stopped. Replacement changes
|
|
364
|
+
the generation and invalidates old control credentials. Unknown server or pane
|
|
365
|
+
identity fails closed; no session is silently adopted.
|
|
366
|
+
|
|
367
|
+
Include pending starts explicitly when inspecting a failed launch:
|
|
368
|
+
|
|
369
|
+
```sh
|
|
370
|
+
pmcp harness recovery inspect --group-file "$GROUP_FILE" --include-starts
|
|
371
|
+
pmcp harness recovery abort-start --group-file "$GROUP_FILE" --generation "$GENERATION" --session "$SESSION"
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
abort-start stops a named incomplete launch and marks any saved group reference
|
|
375
|
+
as stopped. It neither adopts the session nor restarts it. A committed session
|
|
376
|
+
uses session stop instead. If the start gate died before recording ownership,
|
|
377
|
+
automatic cleanup is refused and admission remains blocked for administrative
|
|
378
|
+
repair. Keep the private state directory as evidence; do not guess a pane target
|
|
379
|
+
or resend an uncertain request.
|
|
380
|
+
|
|
381
|
+
## Layout planning
|
|
382
|
+
|
|
383
|
+
```sh
|
|
384
|
+
pmcp harness layout --columns 120 --rows 40
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
This pure command needs no tmux, provider, project or network. It returns layout
|
|
388
|
+
A at 120 columns and 32 rows or larger: a main pane, worker dock and bottom
|
|
389
|
+
coordination pane. Smaller terminals retain a full-width main. The minimum is
|
|
390
|
+
40 columns by 12 rows; the maximum is 1000 in either dimension.
|
|
391
|
+
|
|
392
|
+
Use the [terminal workspace](terminal-workspace.md) to render this layout over
|
|
393
|
+
an existing owned group. All control operations remain available through the CLI.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Terminal workspace
|
|
2
|
+
|
|
3
|
+
Use pmcp tui to view an existing main runtime and its workers in one terminal.
|
|
4
|
+
The main conversation stays in its native interface. PMCP adds a worker dock,
|
|
5
|
+
coordination panel and explicit control switching. Provider login, folder trust
|
|
6
|
+
and tool approvals stay in their native screens.
|
|
7
|
+
|
|
8
|
+
The host requires Linux, tmux, util-linux flock, Node.js 22 or later and a working
|
|
9
|
+
user systemd manager. The PMCP CLI supports Node or Bun; pane helpers use Node.
|
|
10
|
+
The presentation gets its own 512 MiB, 128-task, one-CPU scope. Native sessions
|
|
11
|
+
retain their existing group budgets and execution profile.
|
|
12
|
+
|
|
13
|
+
## Open a workspace
|
|
14
|
+
|
|
15
|
+
First [create a harness group and its sessions](terminal-harness.md). Set GROUP_FILE
|
|
16
|
+
to that group's private state path, then check prerequisites and create a view:
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
pmcp tui doctor
|
|
20
|
+
pmcp tui create --group-file "$GROUP_FILE" --columns 160 --rows 48
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Set VIEW_FILE to viewFile from the JSON receipt:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
pmcp tui inspect --view "$VIEW_FILE"
|
|
27
|
+
pmcp tui open --view "$VIEW_FILE"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Only open requires an interactive terminal. Create can take its dimensions from
|
|
31
|
+
the current terminal; give both dimensions explicitly when calling from a script.
|
|
32
|
+
At 120 columns by 32 rows or larger, main fills the left, workers appear on the
|
|
33
|
+
right, and coordination occupies four bottom rows. Smaller terminals keep a
|
|
34
|
+
full-width main and a separate management window. The minimum is 40 by 12.
|
|
35
|
+
Views refer to an existing owned group and do not start a provider.
|
|
36
|
+
|
|
37
|
+
## Observe and control
|
|
38
|
+
|
|
39
|
+
Press Ctrl-g, release it, then press a key:
|
|
40
|
+
|
|
41
|
+
| Key | Action | CLI operation |
|
|
42
|
+
| --- | --- | --- |
|
|
43
|
+
| m | Return to main and release worker control | main |
|
|
44
|
+
| w or 1–4 | Observe a worker | observe --index 1 |
|
|
45
|
+
| c | Request control of the current native target | control |
|
|
46
|
+
| r | Release control | release |
|
|
47
|
+
| h | Read owned native history | history |
|
|
48
|
+
| b | Show configured inbox metadata | mailbox |
|
|
49
|
+
| g | Open compact management window | management |
|
|
50
|
+
| d | Detach the view, preserving runtimes | detach |
|
|
51
|
+
| ! | Dismiss the last visible error | dismiss |
|
|
52
|
+
| ? | Show key help | Help in the status line |
|
|
53
|
+
|
|
54
|
+
CLI operations use pmcp tui OPERATION --view "$VIEW_FILE". Worker indices follow
|
|
55
|
+
the dock; CLI observe supports all available indices. Press Ctrl-g twice to
|
|
56
|
+
forward Ctrl-g to the native interface. Native Ctrl-b remains available when
|
|
57
|
+
you hold control. A surrounding tmux may consume its own prefix first.
|
|
58
|
+
|
|
59
|
+
The default is read only. Control progresses through REQUESTING CONTROL and
|
|
60
|
+
CONNECTING WRITER to CONTROL READY. A lease alone does not enable typing: PMCP
|
|
61
|
+
checks that the writable native client is attached to the selected pane's TTY.
|
|
62
|
+
Input stays blocked during acquisition and release. A control lease identifies
|
|
63
|
+
the writer, not which native prompt or approval menu is active.
|
|
64
|
+
|
|
65
|
+
Another writer causes a visible error with a next step. Failures remain in the
|
|
66
|
+
status line, coordination panel and inspect receipt until explicitly dismissed.
|
|
67
|
+
Resize does not clear them. CONTROL UNKNOWN blocks input and requires inspection.
|
|
68
|
+
PMCP never replays uncertain input. An input receipt or mailbox ACK does not
|
|
69
|
+
establish model completion. Provider state remains unknown.
|
|
70
|
+
|
|
71
|
+
## History and mailbox
|
|
72
|
+
|
|
73
|
+
History reads only the owned runtime pane, bounded to 2000 lines and 64 KiB.
|
|
74
|
+
It does not include shell history from before the runtime. The history panel
|
|
75
|
+
supports tmux copy mode; returning to main preserves its native draft. Closing
|
|
76
|
+
the view removes its private history cache.
|
|
77
|
+
|
|
78
|
+
To observe inbox metadata, supply an explicitly chosen mailbox observer actor:
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
pmcp tui create --group-file "$GROUP_FILE" --columns 160 --rows 48 --config ./pmcp.toml --actor-file "$OBSERVER_ACTOR_FILE"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The actor must have no live attachment. PMCP uses the existing mailbox service
|
|
85
|
+
and refuses a conflicting attachment. The panel shows message, thread and reply
|
|
86
|
+
IDs. It never reads bodies, marks messages read, acknowledges them, submits input
|
|
87
|
+
or wakes a runtime. Use the [mailbox CLI](mailbox.md) for those explicit actions.
|
|
88
|
+
The view stores the private credential file reference, not its contents.
|
|
89
|
+
|
|
90
|
+
## Detach, close and stop
|
|
91
|
+
|
|
92
|
+
Detach preserves processes and drafts. Reopening returns to read-only main
|
|
93
|
+
observation after releasing this view's control. A lost outer terminal also
|
|
94
|
+
requests release; a crash or unreachable manager may prevent confirmation.
|
|
95
|
+
Inspect before retrying, without replaying input:
|
|
96
|
+
|
|
97
|
+
```sh
|
|
98
|
+
pmcp harness recovery inspect --group-file "$GROUP_FILE"
|
|
99
|
+
pmcp harness attach inspect --group-file "$GROUP_FILE" --session "$SESSION"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Close ends the presentation and preserves all native runtimes:
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
pmcp tui close --view "$VIEW_FILE"
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Stop names the exact current native target and requires confirmation:
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
pmcp tui stop --view "$VIEW_FILE" --confirm-session "$SESSION"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
There is no stop keyboard shortcut. Group replacement invalidates a view's
|
|
115
|
+
generation: create a fresh view instead of transferring old authority. These
|
|
116
|
+
controls are CLI-only and cannot be invoked through the MCP server.
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modootoday/pmcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"license": "Elastic-2.0",
|
|
5
5
|
"author": "modootoday",
|
|
6
|
-
"description": "
|
|
6
|
+
"description": "Use the skills your packages already ship, and keep your AI tools' project configuration in one place.",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"mcp",
|
|
9
9
|
"model-context-protocol",
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
"!dist/**/*.map",
|
|
59
59
|
"!dist/.tsbuildinfo",
|
|
60
60
|
"skills",
|
|
61
|
+
"docs/*.md",
|
|
61
62
|
"README.md",
|
|
62
63
|
"SECURITY.md",
|
|
63
64
|
"LICENSE",
|
|
@@ -346,11 +346,11 @@ declare const catalogItemSchema: z.ZodObject<{
|
|
|
346
346
|
mcp: "mcp";
|
|
347
347
|
}>>;
|
|
348
348
|
verifiedRuntimes: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
349
|
+
antigravity: "antigravity";
|
|
349
350
|
"claude-code": "claude-code";
|
|
350
351
|
"codex-cli": "codex-cli";
|
|
351
352
|
"gemini-cli": "gemini-cli";
|
|
352
353
|
"grok-cli": "grok-cli";
|
|
353
|
-
antigravity: "antigravity";
|
|
354
354
|
}>>>;
|
|
355
355
|
verified: z.ZodOptional<z.ZodBoolean>;
|
|
356
356
|
}, z.core.$loose>;
|
|
@@ -372,11 +372,11 @@ declare const catalogResponseSchema: z.ZodObject<{
|
|
|
372
372
|
mcp: "mcp";
|
|
373
373
|
}>>;
|
|
374
374
|
verifiedRuntimes: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
375
|
+
antigravity: "antigravity";
|
|
375
376
|
"claude-code": "claude-code";
|
|
376
377
|
"codex-cli": "codex-cli";
|
|
377
378
|
"gemini-cli": "gemini-cli";
|
|
378
379
|
"grok-cli": "grok-cli";
|
|
379
|
-
antigravity: "antigravity";
|
|
380
380
|
}>>>;
|
|
381
381
|
verified: z.ZodOptional<z.ZodBoolean>;
|
|
382
382
|
}, z.core.$loose>>;
|
|
@@ -388,11 +388,11 @@ declare const findResultSchema: z.ZodObject<{
|
|
|
388
388
|
lexical: "lexical";
|
|
389
389
|
}>;
|
|
390
390
|
runtime: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
391
|
+
antigravity: "antigravity";
|
|
391
392
|
"claude-code": "claude-code";
|
|
392
393
|
"codex-cli": "codex-cli";
|
|
393
394
|
"gemini-cli": "gemini-cli";
|
|
394
395
|
"grok-cli": "grok-cli";
|
|
395
|
-
antigravity: "antigravity";
|
|
396
396
|
}>>>;
|
|
397
397
|
matches: z.ZodArray<z.ZodObject<{
|
|
398
398
|
name: z.ZodString;
|
|
@@ -400,11 +400,11 @@ declare const findResultSchema: z.ZodObject<{
|
|
|
400
400
|
description: z.ZodString;
|
|
401
401
|
score: z.ZodNumber;
|
|
402
402
|
verifiedRuntimes: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
403
|
+
antigravity: "antigravity";
|
|
403
404
|
"claude-code": "claude-code";
|
|
404
405
|
"codex-cli": "codex-cli";
|
|
405
406
|
"gemini-cli": "gemini-cli";
|
|
406
407
|
"grok-cli": "grok-cli";
|
|
407
|
-
antigravity: "antigravity";
|
|
408
408
|
}>>>;
|
|
409
409
|
verified: z.ZodOptional<z.ZodBoolean>;
|
|
410
410
|
}, z.core.$loose>>;
|