pum-agent 0.2.8-beta.1 → 0.2.10-beta.1
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 +36 -4
- package/package.json +1 -1
- package/src/agent-selector.tsx +6 -1
- package/src/app.tsx +180 -122
- package/src/apply-patch.ts +92 -34
- package/src/check-approvals.ts +9 -203
- package/src/check-mode-prompt.ts +18 -24
- package/src/check-mode.ts +36 -232
- package/src/cli.ts +39 -9
- package/src/clipboard.ts +17 -1
- package/src/commands.ts +4 -0
- package/src/explanation-strength.ts +1 -0
- package/src/filesystem-sandbox.ts +190 -0
- package/src/headless.ts +186 -0
- package/src/help-popup.tsx +2 -1
- package/src/identity.ts +62 -0
- package/src/index.tsx +6 -0
- package/src/main.tsx +22 -19
- package/src/message-cache.ts +7 -1
- package/src/news-popup.tsx +57 -38
- package/src/news.ts +18 -1
- package/src/sandbox/index.ts +56 -8
- package/src/sandbox/linux.ts +13 -0
- package/src/sandbox/windows.ts +21 -7
- package/src/sandbox-policy.ts +35 -8
- package/src/settings-popup.tsx +2 -4
- package/src/settings.ts +24 -11
- package/src/status-bar.tsx +11 -2
- package/src/subagents/manager.ts +349 -43
- package/src/subagents/readonly.ts +57 -0
- package/src/subagents/spawn-preview-popup.tsx +6 -1
- package/src/subagents/spawn-preview.ts +8 -2
- package/src/subagents/types.ts +4 -1
- package/src/tool-groups.ts +38 -8
- package/src/tool-line.ts +7 -1
- package/src/triggers/manager.ts +72 -4
- package/src/triggers/process.ts +25 -1
- package/src/web-search.ts +103 -20
- package/src/worktree.ts +43 -5
- package/src/check-approval-popup.tsx +0 -224
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ pum
|
|
|
23
23
|
PUM opens the login panel automatically on the first start.
|
|
24
24
|
|
|
25
25
|
> [!WARNING]
|
|
26
|
-
> PUM can read, write, and delete files. Check mode adds deterministic policy checks and can enforce native Bash isolation
|
|
26
|
+
> PUM can read, write, and delete files. Check mode adds deterministic policy checks, and supported hosts can enforce native Bash isolation. The file-tool sandbox is a process-local path guard, not complete operating-system isolation. Review the safeguards before using untrusted workspaces.
|
|
27
27
|
|
|
28
28
|
## See PUM in action
|
|
29
29
|
|
|
@@ -46,7 +46,8 @@ The following screens are real OpenTUI renders captured through `tmux`. A local
|
|
|
46
46
|
- **Prompt control:** Steer active work, answer model questionnaires, use an ownership-aware message cache, attach clipboard images, and resume sessions with metadata-rich history.
|
|
47
47
|
- **External triggers:** Supervise background commands such as `gh run watch` and automatically wake the exact target agent when they exit.
|
|
48
48
|
- **Provider choice:** Search the providers exposed by pi, or add an OpenAI-compatible custom endpoint.
|
|
49
|
-
- **
|
|
49
|
+
- **Filesystem boundary:** `read`, `write`, and `edit` stay inside the project and configured allowed roots. `apply_patch` stays project-local.
|
|
50
|
+
- **Optional safeguards:** Use strict, balanced, or ask Check mode for `bash`, `edit`, `apply_patch`, and external-trigger process proposals. Supported hosts can also use native Bash sandboxing through Bubblewrap or Windows CreateProcessInSandbox.
|
|
50
51
|
- **Terminal-first appearance:** Nine themes, semantic color overrides, Unicode glyphs, and optional animation.
|
|
51
52
|
|
|
52
53
|
PUM uses [pi](https://github.com/earendil-works/pi) for the agent loop and [OpenTUI](https://github.com/anomalyco/opentui) for rendering.
|
|
@@ -140,6 +141,8 @@ Set `PUM_DIR` to override PUM's complete configuration and data directory. Run `
|
|
|
140
141
|
| `Ctrl+L` | Open the agent transcript selector |
|
|
141
142
|
| `Shift+Tab` / `Ctrl+Shift+Tab` | Cycle through agent transcripts |
|
|
142
143
|
| `Ctrl+H` | Open session history when the terminal reports the key distinctly |
|
|
144
|
+
| `Ctrl+N` | Open recent answers (News) |
|
|
145
|
+
| `n` / `p` in News | Jump to the answer / user prompt |
|
|
143
146
|
| `Ctrl+End` | Scroll to the end of the selected transcript |
|
|
144
147
|
| `Ctrl+P` | Open settings |
|
|
145
148
|
| `Ctrl+T` | Open supervised external triggers |
|
|
@@ -147,7 +150,7 @@ Set `PUM_DIR` to override PUM's complete configuration and data directory. Run `
|
|
|
147
150
|
| `Ctrl+C` | Clear the selected non-empty draft; on an empty draft, press twice to quit |
|
|
148
151
|
| `?` | Show all controls when the prompt is empty |
|
|
149
152
|
|
|
150
|
-
Useful commands include `/login`, `/history`, `/triggers`, `/check-path`, `/clear`, `/compress`, and `/worktree`.
|
|
153
|
+
Useful commands include `/login`, `/history`, `/news`, `/triggers`, `/check-path`, `/clear`, `/compress`, and `/worktree`.
|
|
151
154
|
|
|
152
155
|
### Copy transcript text
|
|
153
156
|
|
|
@@ -171,6 +174,20 @@ Reload the `tmux` configuration after this change. Use the terminal's Shift-drag
|
|
|
171
174
|
|
|
172
175
|
PUM limits remote OSC 52 payloads to 100,000 Base64 characters. This limit prevents large selections from corrupting terminal output.
|
|
173
176
|
|
|
177
|
+
### Recent answers (News)
|
|
178
|
+
|
|
179
|
+
Open the News popup with `Ctrl+N` or `/news`. It lists the final answers of user-initiated turns, newest first. Each entry shows the user prompt and any follow-up steers that produced the answer, above the answer itself.
|
|
180
|
+
|
|
181
|
+
- `←` / `→` — move between answers
|
|
182
|
+
- `n` — jump to the answer
|
|
183
|
+
- `p` — jump to the user prompt
|
|
184
|
+
- `Space` — toggle an answer between read and unread
|
|
185
|
+
- `c` — copy the current answer to the clipboard
|
|
186
|
+
- `Enter` — reply to the current answer with a quoted draft
|
|
187
|
+
- `Esc` — close the popup
|
|
188
|
+
|
|
189
|
+
PUM marks an answer read automatically only when a new user prompt follows it directly in the transcript. If anything else appears between the answer and the next prompt — a subagent message, a trigger event, a queued message, or an in-progress stream — the answer stays unread.
|
|
190
|
+
|
|
174
191
|
## Parallel subagents
|
|
175
192
|
|
|
176
193
|
PUM runs up to 10 active subagents by default. Configure a limit from 1 through 25 in Settings. Only starting and running agents count toward the limit. Each subagent has these resources:
|
|
@@ -186,6 +203,8 @@ Use `Ctrl+L` to select an agent transcript. Input then goes to that agent. Finis
|
|
|
186
203
|
|
|
187
204
|
The public `spawn_subagent` tool accepts `preview: true`. PUM then shows the exact child task before it creates any worktree or session. Press `Enter` to approve. An optional note becomes a separate visible user instruction to the new child. Press `Esc` to cancel without creating a child. Cancellation discards the preview note because no child exists. PUM preserves the existing parent transcript draft.
|
|
188
205
|
|
|
206
|
+
When the Sandbox setting is `Auto` or `Require`, `spawn_subagent` also accepts `readonly: true`. A readonly child can inspect files and run sandboxed inspection commands. PUM omits `write`, `edit`, `apply_patch`, child spawning, inter-agent delegation, process-starting trigger tools, and message-cache mutation tools from that child. The remaining tool guard blocks unknown or mutation-capable child paths. Worktree access is limited to `list` and `status`. Bash requires an enforced native sandbox, receives read-only project, `/check-path`, and managed Git metadata roots, and receives no network access. If native enforcement is unavailable, readonly Bash blocks instead of using the `Auto` direct fallback. PUM persists readonly state across resume. Sandbox `Off` removes the argument from live spawn tool schemas and rejects any explicit readonly spawn request.
|
|
207
|
+
|
|
189
208
|
Press `↑` on an empty single-line prompt to recall the newest queued user-authored message for the selected transcript. PUM removes the message from the authoritative queue before restoring its text. PUM does not recall inter-agent, trigger, lifecycle, cache, delivered, or image-bearing messages.
|
|
190
209
|
|
|
191
210
|
Idle notices report settled work cycles to the direct spawner. They are not completion notices. PUM acknowledges completion delivery only after the notice enters the parent session. Persisted completion intent and stable message identifiers let interrupted delivery resume without duplicate completion messages.
|
|
@@ -218,6 +237,17 @@ Trigger events target one exact main or retained child session. A missing sessio
|
|
|
218
237
|
|
|
219
238
|
`apply_patch` supports add, update, delete, move, multiple files, and multiple hunks. PUM validates the full patch before changing files. It rejects traversal, absolute paths, escaping symlinks, path conflicts, and ambiguous context. A failed commit restores all touched files.
|
|
220
239
|
|
|
240
|
+
### Filesystem sandbox
|
|
241
|
+
|
|
242
|
+
The process-local filesystem sandbox validates `read`, `write`, `edit`, and `apply_patch` before execution.
|
|
243
|
+
|
|
244
|
+
- Project paths and `/check-path` roots are allowed.
|
|
245
|
+
- Credential-sensitive paths are blocked.
|
|
246
|
+
- Symbolic links and junctions in tool paths are blocked.
|
|
247
|
+
- `apply_patch` remains project-local and keeps its atomic validation.
|
|
248
|
+
|
|
249
|
+
This boundary does not isolate `bash`, package scripts, extensions, or trigger processes from the operating system. Use a container, VM, or policy-controlled sandbox for stronger isolation.
|
|
250
|
+
|
|
221
251
|
### Check mode
|
|
222
252
|
|
|
223
253
|
Select a Check mode profile in `Ctrl+P`. It applies to `bash`, `edit`, `apply_patch`, and external-trigger process execution:
|
|
@@ -228,7 +258,7 @@ Select a Check mode profile in `Ctrl+P`. It applies to `bash`, `edit`, `apply_pa
|
|
|
228
258
|
|
|
229
259
|
Every active profile hard-blocks external writes, location changes, execution operands, ambiguous path access, escaping links, credential access, privilege escalation, persistence, remote-script execution, destructive Git operations, and broad deletion. Balanced permits explicit, deterministically classified, non-sensitive external reads. It accepts one direct `npm pack` only when lifecycle scripts are disabled, an explicit cache stays in an approved root, output stays in an approved root, and any package operand is one exact registry version. Balanced also accepts one direct `npm install` of one exact registry version only when `--ignore-scripts`, an approved `--prefix`, and an approved `--cache` are explicit. File, Git, URL, tag, range, composed, general install, and global-install forms remain blocked. These hard blocks cannot be overridden and do not open the popup. An explicit verifier `UNSAFE` verdict also blocks without a popup. The only publication exception is a deterministic match for direct main-agent `npm publish` or `npm dist-tag add`. The verifier category does not control this exception. The exception still requires explicit popup approval. Managed subagents cannot use it.
|
|
230
260
|
|
|
231
|
-
Use `/check-path list`, `/check-path add <directory>`, `/check-path remove <directory>`, or `/check-path clear` to manage up to 16 additional directory roots for the current launch project. Bash, edit, and external-trigger checks
|
|
261
|
+
Use `/check-path list`, `/check-path add <directory>`, `/check-path remove <directory>`, or `/check-path clear` to manage up to 16 additional directory roots for the current launch project. The filesystem sandbox applies these roots to `read`, `write`, and `edit`. Bash, edit, and external-trigger checks also use these roots; `apply_patch` remains project-local. Added roots are canonicalized and remain subject to credential, traversal, symlink or junction, broad-deletion, and other hard blocks.
|
|
232
262
|
|
|
233
263
|
For `edit` and `apply_patch`, PUM validates the complete proposed change before any mutation. Review data includes the unified diff, changed paths, line counts, sensitivity flags, project containment, and full-content SHA-256. Invalid, stale, malformed, escaping, or incompletely analyzed input blocks the call. Patch length alone does not block a valid Balanced call.
|
|
234
264
|
|
|
@@ -254,6 +284,8 @@ The override uses pi's `createBashTool` implementation and custom Bash operation
|
|
|
254
284
|
|
|
255
285
|
External triggers preserve direct executable/argument boundaries and continue to use deterministic Check mode, but they are not routed through the native sandbox in this release. The trigger manager's synchronous spawn boundary does not carry the exact approved policy object into execution; silently recomputing a second process policy there would weaken approval identity. Trigger output, environment, limits, and process supervision remain unchanged.
|
|
256
286
|
|
|
287
|
+
The filesystem sandbox is a process-local path guard for `read`, `write`, `edit`, and `apply_patch`. It does not replace native Bash isolation and does not cover scripts, extensions, or trigger processes.
|
|
288
|
+
|
|
257
289
|
Verifier prompts stay bounded. For an oversized Balanced review, PUM sends complete validation metadata, counts, findings, and SHA-256 digests. PUM does not send a raw prefix or suffix as if it were complete. Strict and Ask keep their fail-closed oversized-input behavior.
|
|
258
290
|
|
|
259
291
|
### Hosted web search
|
package/package.json
CHANGED
package/src/agent-selector.tsx
CHANGED
|
@@ -17,6 +17,7 @@ export type AgentTreeRow = {
|
|
|
17
17
|
id: string | null;
|
|
18
18
|
name: string;
|
|
19
19
|
status?: SubagentSnapshot["status"];
|
|
20
|
+
readonly?: boolean;
|
|
20
21
|
depth: number;
|
|
21
22
|
metadata?: StatusMetadataValues;
|
|
22
23
|
};
|
|
@@ -36,7 +37,9 @@ export function agentSelectorRowLayout(
|
|
|
36
37
|
const indent = Math.min(2 + row.depth * 2, Math.max(2, popupColumns - 12));
|
|
37
38
|
// One column remains clear for the pinned scrollbar.
|
|
38
39
|
const contentColumns = Math.max(1, popupColumns - indent - 1);
|
|
39
|
-
const label = row.status
|
|
40
|
+
const label = row.status
|
|
41
|
+
? `${row.name}${row.readonly ? " · readonly" : ""} · ${row.status}`
|
|
42
|
+
: row.name;
|
|
40
43
|
const minimumLabelWidth = Math.min(
|
|
41
44
|
label.length,
|
|
42
45
|
Math.max(8, Math.ceil(contentColumns * 0.45)),
|
|
@@ -73,6 +76,7 @@ export function buildAgentTree(agents: readonly SubagentSnapshot[]): AgentTreeRo
|
|
|
73
76
|
id: agent.id,
|
|
74
77
|
name: agent.name,
|
|
75
78
|
status: agent.status,
|
|
79
|
+
readonly: agent.readonly === true,
|
|
76
80
|
depth,
|
|
77
81
|
metadata: {
|
|
78
82
|
branch: agent.worktree.branch ?? null,
|
|
@@ -95,6 +99,7 @@ export function buildAgentTree(agents: readonly SubagentSnapshot[]): AgentTreeRo
|
|
|
95
99
|
id: agent.id,
|
|
96
100
|
name: agent.name,
|
|
97
101
|
status: agent.status,
|
|
102
|
+
readonly: agent.readonly === true,
|
|
98
103
|
depth: 1,
|
|
99
104
|
metadata: {
|
|
100
105
|
branch: agent.worktree.branch ?? null,
|