@parallel-cli/parallel 0.4.3 → 0.4.5
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/CHANGELOG.md +60 -2
- package/README.md +112 -99
- package/dist/agents/agent.js +2 -2
- package/dist/agents/tools.js +105 -7
- package/dist/commands.js +104 -18
- package/dist/config.js +31 -1
- package/dist/controller.js +68 -14
- package/dist/coordination/blackboard.js +75 -0
- package/dist/i18n.js +140 -32
- package/dist/index.js +3 -3
- package/dist/server.js +10 -0
- package/dist/ui/AgentPanel.js +22 -7
- package/dist/ui/App.js +86 -62
- package/dist/ui/AttachApp.js +13 -3
- package/dist/ui/CommandInput.js +60 -9
- package/dist/ui/SettingsPanel.js +86 -18
- package/dist/ui/Timeline.js +11 -9
- package/dist/ui/views.js +39 -15
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,64 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to Parallel are documented here.
|
|
4
4
|
|
|
5
|
+
## 0.4.5 - 2026-06-23
|
|
6
|
+
|
|
7
|
+
### 0.4.5 Added
|
|
8
|
+
|
|
9
|
+
- Added explicit hub, focus, and attach input contexts with context-specific hints and filtered command suggestions.
|
|
10
|
+
- Added agent argument autocomplete for `/focus`, `/send`, `/attach`, `/pause`, `/resume`, `/stop`, `/restore`, and `/commit`.
|
|
11
|
+
- Added attach-terminal routing for `@all`, `@agent`, and `/send`, so dedicated terminals can broadcast or steer another agent through the main session.
|
|
12
|
+
- Added richer hub rows using latest useful agent signals, specialist badges, context percentage, and responsive timeline widths.
|
|
13
|
+
- Added durable session memory for claims, recent diff excerpts, file activity, work-map warnings, agent aliases, provider/model metadata, specialist, and context usage.
|
|
14
|
+
- Added shell mutation tracking: files changed by `run_command` now appear in live diffs, file activity, and agent commit ownership.
|
|
15
|
+
- Added a non-blocking work map that surfaces overlapping claims and repeated co-edit conflicts in `/board` and agent context.
|
|
16
|
+
|
|
17
|
+
### 0.4.5 Changed
|
|
18
|
+
|
|
19
|
+
- Clarified agent naming around `Name: task` syntax in README examples.
|
|
20
|
+
- Made `/raw` visible only when it affects the active focus view.
|
|
21
|
+
- Reset focus scroll follow-tail behavior when switching focused agents.
|
|
22
|
+
- Improved session restore so `/restore` can target saved agents by name, alias, or id when their conversation is available.
|
|
23
|
+
|
|
24
|
+
### 0.4.5 Fixed
|
|
25
|
+
|
|
26
|
+
- Fixed attach-terminal `@all` being treated as plain text to the attached agent.
|
|
27
|
+
- Fixed restored note ids drifting by resynchronizing blackboard note and change sequences after loading session data.
|
|
28
|
+
- Fixed shell-created edits being invisible to `/diff`, `/board`, and `/commit`.
|
|
29
|
+
|
|
30
|
+
## 0.4.4 - 2026-06-23
|
|
31
|
+
|
|
32
|
+
### 0.4.4 Added
|
|
33
|
+
|
|
34
|
+
- Added tool-level safeguards for `/ask` and `/plan`: ask agents cannot mutate project state, and plan agents must get explicit approval before mutating files or running risky shell commands.
|
|
35
|
+
- Added session-only provider setup for `/settings-session`, with an explicit choice between temporary session use and saving globally.
|
|
36
|
+
- Expanded `/doctor` into actionable readiness diagnostics for provider, model, key, local endpoints, attach socket, `git`, and `gh`.
|
|
37
|
+
- Added scrolling/windowing budgets to long TUI views such as board, notes, diffs, cost, skills, specialists, and sessions.
|
|
38
|
+
- Added saved-session restore hints and clearer `/restore` errors.
|
|
39
|
+
|
|
40
|
+
### 0.4.4 Changed
|
|
41
|
+
|
|
42
|
+
- Reworked the README to render consistently on both GitHub and npm.
|
|
43
|
+
- Replaced wide Markdown tables and fixed-width command blocks with npm-friendly lists.
|
|
44
|
+
- Removed provider-specific environment variable guidance from the public README so provider setup remains neutral.
|
|
45
|
+
- Documented DeepSeek only as one provider preset in the Chinese provider group, not as a special standalone setup path.
|
|
46
|
+
- Made `@all` steer active agents directly instead of only posting a passive note.
|
|
47
|
+
- Made `/plan` timeouts safe by requiring manual approval before mutations are unlocked.
|
|
48
|
+
- Increased the saved sessions list window from 8 to 20 and shows `/save [name]` labels in `/sessions`.
|
|
49
|
+
- Bumped the TUI header version to `0.4.4`.
|
|
50
|
+
|
|
51
|
+
### 0.4.4 Fixed
|
|
52
|
+
|
|
53
|
+
- Fixed `/commit message...` with exactly one agent so the first word is treated as part of the message, not as a missing agent name.
|
|
54
|
+
- Fixed `/project` and `/wizard` transitions by warning when active agents are running unless `--force` is passed.
|
|
55
|
+
- Fixed local/custom provider setup so localhost endpoints do not require an API key and placeholder models are not considered ready.
|
|
56
|
+
- Fixed stale focus after agents disappear through clear, stop, project switch, session load, or restore.
|
|
57
|
+
- Fixed `/settings-session` key entry so provider setup reaches the session-only vs global-save choice instead of returning early.
|
|
58
|
+
- Fixed first-run custom provider setup so it reviews/edits endpoints and skips API keys for localhost endpoints.
|
|
59
|
+
- Fixed filesystem boundary checks so agent tools reject sibling paths with a shared project-root prefix.
|
|
60
|
+
- Fixed TUI clipping risks by budgeting the hub by rendered rows and applying body-height windowing to notes/diffs.
|
|
61
|
+
- Fixed Settings Escape handling so typed inputs clear before navigating back.
|
|
62
|
+
|
|
5
63
|
## 0.4.3 - 2026-06-23
|
|
6
64
|
|
|
7
65
|
### 0.4.3 Added
|
|
@@ -32,7 +90,7 @@ All notable changes to Parallel are documented here.
|
|
|
32
90
|
- Fixed session settings accidentally behaving like global provider mutation in several flows.
|
|
33
91
|
- Fixed bare model IDs containing `:` such as `qwen3-coder:480b`.
|
|
34
92
|
- Fixed stale default provider normalization during config load and provider removal.
|
|
35
|
-
- Fixed
|
|
93
|
+
- Fixed provider-specific environment overrides leaking into whichever provider happened to be default.
|
|
36
94
|
- Fixed local endpoints being blocked by missing API keys.
|
|
37
95
|
- Fixed sensitive `/key ...` entries being stored in input history.
|
|
38
96
|
- Fixed tiny pseudo-TTY dimensions causing negative string repeat values in the TUI header.
|
|
@@ -49,7 +107,7 @@ All notable changes to Parallel are documented here.
|
|
|
49
107
|
|
|
50
108
|
### 0.4.2 Changed
|
|
51
109
|
|
|
52
|
-
- Reworked the README provider section to be provider-agnostic
|
|
110
|
+
- Reworked the README provider section to be provider-agnostic.
|
|
53
111
|
- Updated provider tables, endpoint documentation, and model catalog references.
|
|
54
112
|
- Removed internal docs from remote tracking and kept them out of the public package.
|
|
55
113
|
|
package/README.md
CHANGED
|
@@ -16,9 +16,12 @@ Parallel lets you run several AI coding agents on the same repository at the sam
|
|
|
16
16
|
- Run multiple agents in parallel on one project.
|
|
17
17
|
- Choose explicit modes: `/ask`, `/task`, and `/plan`.
|
|
18
18
|
- Type plain text to launch a task agent immediately.
|
|
19
|
+
- Use context-aware input in the hub, focus view, and attached agent terminals.
|
|
19
20
|
- Steer one agent with `@a1 ...` or broadcast with `@all ...`.
|
|
20
21
|
- Open dedicated agent terminals with native scrollback.
|
|
22
|
+
- See a richer live hub with latest agent signals, mode badges, context usage, and responsive timelines.
|
|
21
23
|
- Review agents, notes, file activity, diffs, cost, skills, specialists, and saved sessions from the TUI.
|
|
24
|
+
- Track shell-created file mutations in the same live diff feed as agent edits.
|
|
22
25
|
- Configure OpenAI-compatible providers through a guided wizard and settings panel.
|
|
23
26
|
- Use 29 provider presets across Western, Chinese, Gateway, Inference, and Local categories.
|
|
24
27
|
- Support local no-key endpoints such as Ollama and vLLM/SGLang.
|
|
@@ -79,9 +82,9 @@ Plain text launches a `/task` agent. You can launch another agent while the firs
|
|
|
79
82
|
Use explicit modes when intent matters:
|
|
80
83
|
|
|
81
84
|
```text
|
|
82
|
-
/ask
|
|
83
|
-
/plan
|
|
84
|
-
/task
|
|
85
|
+
/ask Reviewer: should we split the CLI parser?
|
|
86
|
+
/plan Migration: propose the safest rollout for the config change
|
|
87
|
+
/task Builder: implement the approved plan
|
|
85
88
|
```
|
|
86
89
|
|
|
87
90
|
Steer a running agent:
|
|
@@ -96,13 +99,13 @@ Broadcast to every agent:
|
|
|
96
99
|
@all stop changing public interfaces until the test agent finishes
|
|
97
100
|
```
|
|
98
101
|
|
|
102
|
+
`@all` steers active agents in real time. Finished, stopped, or errored agents are not relaunched by a broadcast.
|
|
103
|
+
|
|
99
104
|
## Agent Modes
|
|
100
105
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
| `/task` | Implementation work | Executes, edits, validates, and summarizes. |
|
|
105
|
-
| `/plan` | Risky or unclear work | Inspects first, presents a plan, then edits only after approval. |
|
|
106
|
+
- `/ask`: questions, reviews, audits, and tradeoffs. The agent answers and advises; mutating tools and shell commands are blocked.
|
|
107
|
+
- `/task`: implementation work. The agent can execute, edit, validate, and summarize.
|
|
108
|
+
- `/plan`: risky or unclear work. The agent inspects first, presents a plan, then edits only after explicit approval. A timeout does not approve the plan.
|
|
106
109
|
|
|
107
110
|
Aliases:
|
|
108
111
|
|
|
@@ -122,29 +125,42 @@ The main TUI is the Parallel hub. It is designed to answer:
|
|
|
122
125
|
- what changed in the project
|
|
123
126
|
- what model, provider, shell mode, and cost are active
|
|
124
127
|
|
|
125
|
-
|
|
128
|
+
Input has three explicit contexts:
|
|
129
|
+
|
|
130
|
+
- Hub: plain text launches a new `/task` agent. Slash suggestions show hub commands and agent arguments autocomplete for `/focus`, `/send`, `/attach`, `/pause`, `/resume`, `/stop`, `/restore`, and `/commit`.
|
|
131
|
+
- Focus: after `/focus a1`, plain text talks to the focused agent instead of spawning a new one. `/raw` affects this view only.
|
|
132
|
+
- Attach: in `parallel attach a1`, plain text steers the attached agent. `/task`, `/ask`, and `/plan` spawn new agents from that terminal, while `@all ...`, `@a2 ...`, and `/send ...` route instructions through the main session.
|
|
133
|
+
|
|
134
|
+
Use `Name: task` when naming an agent:
|
|
126
135
|
|
|
127
136
|
```text
|
|
128
|
-
/
|
|
129
|
-
/
|
|
130
|
-
/raw toggle raw detail in focus view
|
|
131
|
-
/board shared blackboard, claims, notes, file activity
|
|
132
|
-
/diff live diff history
|
|
133
|
-
/cost token and cost breakdown
|
|
134
|
-
/sessions saved sessions
|
|
135
|
-
/settings global settings
|
|
136
|
-
/settings-session session-only settings
|
|
137
|
-
/project [folder] change project folder
|
|
138
|
-
/wizard rerun setup wizard
|
|
137
|
+
/task Tests: add regression coverage for the auth middleware
|
|
138
|
+
/plan Migration: outline the safest database rollout
|
|
139
139
|
```
|
|
140
140
|
|
|
141
|
+
Common hub commands:
|
|
142
|
+
|
|
143
|
+
- `/agents`: agent overview.
|
|
144
|
+
- `/focus a1`: inspect and steer one agent.
|
|
145
|
+
- `/raw`: toggle raw detail in focus view.
|
|
146
|
+
- `/board`: shared blackboard, claims, notes, and file activity.
|
|
147
|
+
- `/diff`: live diff history.
|
|
148
|
+
- `/cost`: token and cost breakdown.
|
|
149
|
+
- `/sessions`: saved sessions.
|
|
150
|
+
- `/settings`: global settings.
|
|
151
|
+
- `/settings-session`: session-only settings.
|
|
152
|
+
- `/project [folder]`: change project folder.
|
|
153
|
+
- `/wizard`: rerun setup wizard.
|
|
154
|
+
|
|
155
|
+
Commands are typed in the control room input. When a long view is open, use Escape to return to the agents view/input.
|
|
156
|
+
|
|
141
157
|
Keyboard behavior:
|
|
142
158
|
|
|
143
159
|
- `/` opens slash command suggestions.
|
|
144
160
|
- Up/Down selects suggestions when a suggestion menu is open.
|
|
145
161
|
- Enter accepts the selected suggestion.
|
|
146
162
|
- Tab or Right accepts the best completion.
|
|
147
|
-
- Up/Down scrolls long views
|
|
163
|
+
- PgUp/PgDn scrolls the hub or focus view even while the input is active. Up/Down scrolls long views and navigates suggestions/history.
|
|
148
164
|
- Escape returns to the agents view or clears the input.
|
|
149
165
|
|
|
150
166
|
Best terminal size is around `120x34`. Parallel adapts to smaller terminals, but the hub is most readable with enough width for model, folder, status, and agent summaries.
|
|
@@ -170,9 +186,12 @@ From an attached terminal:
|
|
|
170
186
|
|
|
171
187
|
```text
|
|
172
188
|
plain text sends a message to this agent
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
/
|
|
189
|
+
@all pause public interface changes until tests finish
|
|
190
|
+
@a2 re-read the API client before editing it
|
|
191
|
+
/send a2 check the new parser contract
|
|
192
|
+
/task Tests: write parser regression tests
|
|
193
|
+
/ask Reviewer: is this result safe to merge?
|
|
194
|
+
/plan Migration: prepare a migration plan
|
|
176
195
|
/raw
|
|
177
196
|
/quit
|
|
178
197
|
```
|
|
@@ -202,101 +221,93 @@ Provider setup is guided in both the first-run wizard and `/settings`:
|
|
|
202
221
|
4. Enter the provider API key if the provider requires one.
|
|
203
222
|
5. Save globally or use the provider/model for the current session.
|
|
204
223
|
|
|
205
|
-
Local providers such as Ollama
|
|
224
|
+
Local providers such as Ollama, vLLM/SGLang, and custom localhost OpenAI-compatible endpoints do not require an API key. You can still review and edit their endpoints. Ollama/local OpenAI-compatible endpoints can detect models from `/models`; vLLM/SGLang requires replacing the `your-model-here` placeholder before it is considered ready.
|
|
206
225
|
|
|
207
226
|
Useful settings commands:
|
|
208
227
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
/doctor check provider/model/API key readiness
|
|
215
|
-
```
|
|
228
|
+
- `/settings`: global language, providers, keys, defaults, and approvals.
|
|
229
|
+
- `/settings-session`: temporary model, provider, approvals, and sound. New providers can be used for this session only or saved globally.
|
|
230
|
+
- `/model`: show the current session model.
|
|
231
|
+
- `/model provider:id`: switch model for this session.
|
|
232
|
+
- `/doctor`: check provider, model, API key, local endpoint reachability, attach socket, `git`, and `gh`.
|
|
216
233
|
|
|
217
234
|
Configuration is stored in `~/.parallel/config.json`.
|
|
218
235
|
|
|
219
236
|
Environment variables:
|
|
220
237
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
| `PARALLEL_BASE_URL` | Override the default provider base URL. |
|
|
226
|
-
| `PARALLEL_MODEL` | Override the session model. |
|
|
227
|
-
| `PARALLEL_NO_ALT_SCREEN=1` | Disable the alternate terminal screen. |
|
|
238
|
+
- `PARALLEL_API_KEY`: API key for the current default provider.
|
|
239
|
+
- `PARALLEL_BASE_URL`: override the default provider base URL.
|
|
240
|
+
- `PARALLEL_MODEL`: override the session model.
|
|
241
|
+
- `PARALLEL_NO_ALT_SCREEN=1`: disable the alternate terminal screen.
|
|
228
242
|
|
|
229
243
|
## Commands
|
|
230
244
|
|
|
231
245
|
### Create Agents
|
|
232
246
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
| `/specialist new <name> [global]` | Create a specialist template. |
|
|
241
|
-
| `/skill new <name> [global]` | Create a skill template. |
|
|
247
|
+
- `/ask [Name:] <question> [--model=m]`: launch an ask-only agent.
|
|
248
|
+
- `/task [Name:] <task> [--model=m] [#skill]`: launch a task agent. Plain text does the same.
|
|
249
|
+
- `/plan [Name:] <task> [--model=m]`: launch a plan-first agent. It cannot mutate files or run risky shell commands until you manually approve the plan.
|
|
250
|
+
- `/issue <n>`: spawn a task from a GitHub issue. Requires the `gh` CLI, a GitHub repository, and `gh auth login`.
|
|
251
|
+
- `/specialist <name> <task>`: spawn with a specialist persona.
|
|
252
|
+
- `/specialist new <name> [global]`: create a specialist template.
|
|
253
|
+
- `/skill new <name> [global]`: create a skill template.
|
|
242
254
|
|
|
243
255
|
### Steer Agents
|
|
244
256
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
| `/raw` | Toggle conversation-raw view. |
|
|
257
|
-
| `/copy` | Copy the latest completed result to clipboard. |
|
|
257
|
+
- `@agent <message>`: send a live instruction to one agent.
|
|
258
|
+
- `@all <message>`: broadcast an instruction to all agents.
|
|
259
|
+
- `/send <agent|all> <message>`: command form of live steering.
|
|
260
|
+
- `/attach <agent|on|off>`: open an agent terminal or toggle automatic terminals.
|
|
261
|
+
- `/focus <agent|off>`: route plain input to one agent instead of spawning new agents.
|
|
262
|
+
- `/pause <agent|all>`: pause at the next action boundary.
|
|
263
|
+
- `/resume <agent|all>`: resume paused agents.
|
|
264
|
+
- `/stop <agent|all>`: stop running agents.
|
|
265
|
+
- `/clear`: remove finished agents from the current display.
|
|
266
|
+
- `/raw`: toggle conversation-raw view.
|
|
267
|
+
- `/copy`: copy the latest completed result to clipboard.
|
|
258
268
|
|
|
259
269
|
### Git Safety
|
|
260
270
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
| `/commit [agent\|all] [message]` | Commit files touched by an agent or by all agents. |
|
|
265
|
-
| `/autocommit <on\|off>` | Commit each agent's changes automatically when it finishes. |
|
|
271
|
+
- `/undo [agent]`: revert the last file change made by an agent, with conflict detection.
|
|
272
|
+
- `/commit [agent|all] [message]`: commit only files touched by the selected agent or by all agents. It does not run `git add -A`. With exactly one agent, `/commit message...` uses that agent and treats the rest as the message.
|
|
273
|
+
- `/autocommit <on|off>`: commit each agent's touched files automatically when it finishes. This is session-only.
|
|
266
274
|
|
|
267
275
|
### Views And Sessions
|
|
268
276
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
277
|
+
- `/agents`: agent overview.
|
|
278
|
+
- `/board`: shared blackboard, file activity, claims, and notes.
|
|
279
|
+
- `/notes`: full notes history.
|
|
280
|
+
- `/diff`: live diff history.
|
|
281
|
+
- `/cost`: token and cost breakdown.
|
|
282
|
+
- `/status`: session model, approval mode, agents, and cost snapshot.
|
|
283
|
+
- `/skills`: available skills.
|
|
284
|
+
- `/specialists`: available specialists.
|
|
285
|
+
- `/save [name]`: save the current session.
|
|
286
|
+
- `/sessions`: list saved sessions.
|
|
287
|
+
- `/session <n|latest>`: load a saved session snapshot. If active agents are running, use `/session <n|latest> --force` after saving/stopping what you need.
|
|
288
|
+
- `/restore <agent>`: relaunch a restored agent by name, alias, or saved id when its conversation history is still available.
|
|
289
|
+
|
|
290
|
+
Session memory has two layers:
|
|
291
|
+
|
|
292
|
+
- Live memory: active agents see statuses, notes, claims, work-map warnings, file activity, and recent diffs before every model action.
|
|
293
|
+
- Durable memory: `/save` and autosave persist notes, claims, recent diff excerpts, file activity, work-map warnings, agent aliases, model/provider metadata, context usage, and conversation paths for restore.
|
|
294
|
+
|
|
295
|
+
Restore is best effort and explicit. `/session` reloads coordination memory into the blackboard; `/restore <agent>` relaunches an agent only when the saved conversation file still exists. Restored agents keep their prior task, mode, model, specialist, and conversation when available.
|
|
283
296
|
|
|
284
297
|
### Settings And Exit
|
|
285
298
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
| `/help` | Full command reference. |
|
|
299
|
-
| `/quit` | Save the session and exit. |
|
|
299
|
+
- `/model [[provider:]model]`: show or switch the session model.
|
|
300
|
+
- `/approvals <ask|auto|auto-safe|yolo>`: set shell approvals for this session.
|
|
301
|
+
- `/sound <on|off>`: toggle terminal bell notifications.
|
|
302
|
+
- `/settings`: edit global language, providers, keys, defaults, and approvals.
|
|
303
|
+
- `/settings-session`: edit session-only model, provider, approvals, and sound.
|
|
304
|
+
- `/project [folder]`: change project folder or reopen the folder picker. If agents are active, use `/project [folder] --force` after saving/stopping what you need.
|
|
305
|
+
- `/folder [folder]`: alias for `/project`.
|
|
306
|
+
- `/wizard`: relaunch the setup wizard. If agents are active, use `/wizard --force` after saving/stopping what you need.
|
|
307
|
+
- `/setup`: alias for `/wizard`.
|
|
308
|
+
- `/doctor`: run local readiness diagnostics for provider, key, model, endpoint, attach socket, and Git tooling.
|
|
309
|
+
- `/help`: full command reference.
|
|
310
|
+
- `/quit`: save the session and exit.
|
|
300
311
|
|
|
301
312
|
When there is exactly one agent, commands such as `/undo`, `/focus`, `/pause`, `/resume`, `/stop`, and `/commit` can omit the agent name.
|
|
302
313
|
|
|
@@ -310,11 +321,9 @@ Parallel separates agent modes from shell approval behavior.
|
|
|
310
321
|
/approvals yolo
|
|
311
322
|
```
|
|
312
323
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
| `auto-safe` | Auto-approve safe inspection/build/test commands and ask for risky commands. |
|
|
317
|
-
| `yolo` | Auto-approve every shell command. Intended for trusted/headless usage only. |
|
|
324
|
+
- `ask`: ask before shell commands unless explicitly allowed.
|
|
325
|
+
- `auto-safe`: auto-approve safe inspection/build/test commands and ask for risky commands.
|
|
326
|
+
- `yolo`: auto-approve every shell command. Intended for trusted/headless usage only.
|
|
318
327
|
|
|
319
328
|
`auto` is accepted as a compatibility spelling for `auto-safe`.
|
|
320
329
|
|
|
@@ -353,6 +362,10 @@ When an agent writes a file:
|
|
|
353
362
|
|
|
354
363
|
This keeps agents moving without allowing silent overwrites.
|
|
355
364
|
|
|
365
|
+
Commands run through `run_command` are also snapshotted before and after execution. If a shell command edits, creates, or deletes tracked project files, Parallel records those mutations in `/diff`, `/board`, and `/commit` ownership just like tool-based edits.
|
|
366
|
+
|
|
367
|
+
The work map is advisory, not a lock. Agents can declare claims with `claim_files`; Parallel detects overlapping claims and repeated conflicts, then shows non-blocking warnings in `/board` and injects them into agent context so agents can coordinate before collisions become expensive.
|
|
368
|
+
|
|
356
369
|
## Headless Mode
|
|
357
370
|
|
|
358
371
|
For CI and scripts, run without the TUI:
|
package/dist/agents/agent.js
CHANGED
|
@@ -27,7 +27,7 @@ ${mode === 'ask'
|
|
|
27
27
|
- Explore first with read-only tools.
|
|
28
28
|
- Before modifying any file or running mutating commands, call ask_user with a concrete implementation plan.
|
|
29
29
|
- The plan must include steps, files you expect to touch, risks, and validation.
|
|
30
|
-
- Use options ["Approve", "Revise"], recommended "
|
|
30
|
+
- Use options ["Approve", "Revise"], recommended "Revise" so timeout never approves changes.
|
|
31
31
|
- Start editing only after explicit "Approve".
|
|
32
32
|
- Finish with task_complete using this user-facing structure in ${userLang}: "Plan appliqué", "Ce que j’ai modifié", "Validation", "Risques restants".`
|
|
33
33
|
: `TASK MODE:
|
|
@@ -97,7 +97,7 @@ export class Agent {
|
|
|
97
97
|
this.llm = opts.llm;
|
|
98
98
|
this.board = opts.board;
|
|
99
99
|
this.maxSteps = opts.maxSteps;
|
|
100
|
-
this.executor = new ToolExecutor(opts.board, opts.id, opts.name, opts.projectRoot, opts.requestApproval, opts.requestQuestion, opts.skills);
|
|
100
|
+
this.executor = new ToolExecutor(opts.board, opts.id, opts.name, opts.projectRoot, opts.requestApproval, opts.requestQuestion, opts.skills, opts.mode);
|
|
101
101
|
const info = {
|
|
102
102
|
id: opts.id,
|
|
103
103
|
name: opts.name,
|
package/dist/agents/tools.js
CHANGED
|
@@ -2,8 +2,21 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { exec } from 'node:child_process';
|
|
4
4
|
import * as Diff from 'diff';
|
|
5
|
-
const IGNORED = new Set(['node_modules', '.git', '.parallel', 'dist', '__pycache__', '.venv', 'venv']);
|
|
5
|
+
const IGNORED = new Set(['node_modules', '.git', '.parallel', '.cursor', 'dist', '__pycache__', '.venv', 'venv']);
|
|
6
6
|
const MAX_OUTPUT = 12_000;
|
|
7
|
+
const MUTATING_TOOLS = new Set(['write_file', 'edit_file', 'claim_files', 'remember']);
|
|
8
|
+
function isMutatingShell(command) {
|
|
9
|
+
const c = command.toLowerCase();
|
|
10
|
+
if (/\b(rm|mv|cp|chmod|chown|mkdir|touch|truncate)\b/.test(c))
|
|
11
|
+
return true;
|
|
12
|
+
if (/\b(git\s+(add|commit|push|pull|merge|rebase|checkout|switch|reset|clean|stash|tag))\b/.test(c))
|
|
13
|
+
return true;
|
|
14
|
+
if (/\b(npm|pnpm|yarn)\s+(install|add|remove|update|audit\s+fix)\b/.test(c))
|
|
15
|
+
return true;
|
|
16
|
+
if (/[>|]\s*(sh|bash)\b/.test(c) || /\b(curl|wget)\b.*\|\s*(sh|bash)/.test(c))
|
|
17
|
+
return true;
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
7
20
|
export const TOOL_DEFINITIONS = [
|
|
8
21
|
{
|
|
9
22
|
type: 'function',
|
|
@@ -228,11 +241,13 @@ export class ToolExecutor {
|
|
|
228
241
|
requestApproval;
|
|
229
242
|
requestQuestion;
|
|
230
243
|
skills;
|
|
244
|
+
mode;
|
|
231
245
|
/** Last content this agent has seen for each file — basis of adaptive merging. */
|
|
232
246
|
lastRead = new Map();
|
|
233
247
|
/** Questions already asked — capped at 3 per task. */
|
|
234
248
|
questionsAsked = 0;
|
|
235
|
-
|
|
249
|
+
planApproved = false;
|
|
250
|
+
constructor(board, agentId, agentName, projectRoot, requestApproval, requestQuestion, skills, mode = 'task') {
|
|
236
251
|
this.board = board;
|
|
237
252
|
this.agentId = agentId;
|
|
238
253
|
this.agentName = agentName;
|
|
@@ -240,10 +255,13 @@ export class ToolExecutor {
|
|
|
240
255
|
this.requestApproval = requestApproval;
|
|
241
256
|
this.requestQuestion = requestQuestion;
|
|
242
257
|
this.skills = skills;
|
|
258
|
+
this.mode = mode;
|
|
243
259
|
}
|
|
244
260
|
resolve(rel) {
|
|
245
|
-
const
|
|
246
|
-
|
|
261
|
+
const root = path.resolve(this.projectRoot);
|
|
262
|
+
const abs = path.resolve(root, rel);
|
|
263
|
+
const relative = path.relative(root, abs);
|
|
264
|
+
if (relative.startsWith('..') || path.isAbsolute(relative)) {
|
|
247
265
|
throw new Error(`Path outside the project refused: ${rel}`);
|
|
248
266
|
}
|
|
249
267
|
return abs;
|
|
@@ -251,8 +269,65 @@ export class ToolExecutor {
|
|
|
251
269
|
relOf(p) {
|
|
252
270
|
return path.relative(this.projectRoot, this.resolve(p)) || '.';
|
|
253
271
|
}
|
|
272
|
+
snapshotProject() {
|
|
273
|
+
const snapshot = new Map();
|
|
274
|
+
const walk = (dir, depth) => {
|
|
275
|
+
if (depth > 8)
|
|
276
|
+
return;
|
|
277
|
+
let entries;
|
|
278
|
+
try {
|
|
279
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
280
|
+
}
|
|
281
|
+
catch {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
for (const e of entries) {
|
|
285
|
+
if (IGNORED.has(e.name) || e.name.startsWith('.git'))
|
|
286
|
+
continue;
|
|
287
|
+
const full = path.join(dir, e.name);
|
|
288
|
+
const relPath = path.relative(this.projectRoot, full);
|
|
289
|
+
if (e.isDirectory()) {
|
|
290
|
+
walk(full, depth + 1);
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (!e.isFile())
|
|
294
|
+
continue;
|
|
295
|
+
try {
|
|
296
|
+
const stat = fs.statSync(full);
|
|
297
|
+
if (stat.size > 750_000)
|
|
298
|
+
continue;
|
|
299
|
+
snapshot.set(relPath, fs.readFileSync(full, 'utf8'));
|
|
300
|
+
}
|
|
301
|
+
catch {
|
|
302
|
+
/* binary/unreadable files are ignored for diff tracking */
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
walk(this.projectRoot, 0);
|
|
307
|
+
return snapshot;
|
|
308
|
+
}
|
|
309
|
+
recordShellMutations(before) {
|
|
310
|
+
const after = this.snapshotProject();
|
|
311
|
+
const paths = new Set([...before.keys(), ...after.keys()]);
|
|
312
|
+
let count = 0;
|
|
313
|
+
for (const relPath of [...paths].sort()) {
|
|
314
|
+
const oldContent = before.get(relPath);
|
|
315
|
+
const newContent = after.get(relPath);
|
|
316
|
+
if (oldContent === newContent)
|
|
317
|
+
continue;
|
|
318
|
+
this.board.addChange(this.agentId, relPath, oldContent ?? '', newContent ?? '');
|
|
319
|
+
this.board.recordActivity(relPath, this.agentId, 'shell');
|
|
320
|
+
count++;
|
|
321
|
+
}
|
|
322
|
+
if (count > 0)
|
|
323
|
+
this.board.log(this.agentId, 'tool', `✏ shell changed ${count} file${count === 1 ? '' : 's'}`);
|
|
324
|
+
return count;
|
|
325
|
+
}
|
|
254
326
|
async execute(name, args) {
|
|
255
327
|
try {
|
|
328
|
+
const guard = this.guardTool(name, args);
|
|
329
|
+
if (guard)
|
|
330
|
+
return guard;
|
|
256
331
|
switch (name) {
|
|
257
332
|
case 'list_files':
|
|
258
333
|
return this.listFiles(args?.path ?? '.');
|
|
@@ -293,6 +368,22 @@ export class ToolExecutor {
|
|
|
293
368
|
return `ERROR: ${err?.message ?? String(err)}`;
|
|
294
369
|
}
|
|
295
370
|
}
|
|
371
|
+
guardTool(name, args) {
|
|
372
|
+
if (this.mode === 'ask') {
|
|
373
|
+
if (MUTATING_TOOLS.has(name) || name === 'run_command') {
|
|
374
|
+
return `DENIED: this agent is in /ask mode. It can inspect and advise, but cannot modify files, run shell commands, claim files, or write memory.`;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
if (this.mode === 'plan' && !this.planApproved) {
|
|
378
|
+
if (MUTATING_TOOLS.has(name)) {
|
|
379
|
+
return `DENIED: this agent is in /plan mode and the plan has not been approved yet. Present the plan with ask_user and wait for "Approve" before modifying project state.`;
|
|
380
|
+
}
|
|
381
|
+
if (name === 'run_command' && isMutatingShell(String(args?.command ?? ''))) {
|
|
382
|
+
return `DENIED: this shell command looks mutating. In /plan mode, run only read-only inspection before approval; ask_user for plan approval first.`;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
296
387
|
/**
|
|
297
388
|
* Ask the user a multiple-choice question. NEVER blocks forever: the UI shows
|
|
298
389
|
* a visible 30s countdown and falls back to the recommended option (auto-run).
|
|
@@ -312,9 +403,14 @@ export class ToolExecutor {
|
|
|
312
403
|
this.questionsAsked++;
|
|
313
404
|
this.board.setAgentState(this.agentId, 'waiting', `question: ${question.slice(0, 60)}`);
|
|
314
405
|
this.board.log(this.agentId, 'note', `❓ ${question}`);
|
|
315
|
-
const
|
|
406
|
+
const response = await this.requestQuestion(this.agentId, question, options, recommended);
|
|
407
|
+
const answer = response.answer;
|
|
408
|
+
if (this.mode === 'plan' && !response.auto && answer.trim().toLowerCase().startsWith('approve')) {
|
|
409
|
+
this.planApproved = true;
|
|
410
|
+
}
|
|
316
411
|
this.board.setAgentState(this.agentId, 'working');
|
|
317
|
-
|
|
412
|
+
const source = response.auto ? 'The timeout auto-selected' : 'The user answered';
|
|
413
|
+
return `${source}: "${answer}". Act on this choice now (${3 - this.questionsAsked} question(s) left for this task).`;
|
|
318
414
|
}
|
|
319
415
|
/** Declare (advisory) work areas — visible to the user and the other agents. */
|
|
320
416
|
claimFiles(args) {
|
|
@@ -550,6 +646,7 @@ export class ToolExecutor {
|
|
|
550
646
|
}
|
|
551
647
|
this.board.setAgentState(this.agentId, 'working', `$ ${command.slice(0, 60)}`);
|
|
552
648
|
this.board.log(this.agentId, 'tool', `$ ${command}`);
|
|
649
|
+
const before = this.snapshotProject();
|
|
553
650
|
return new Promise((resolve) => {
|
|
554
651
|
exec(command, { cwd: this.projectRoot, timeout: 120_000, maxBuffer: 4 * 1024 * 1024 }, (err, stdout, stderr) => {
|
|
555
652
|
let out = '';
|
|
@@ -564,8 +661,9 @@ export class ToolExecutor {
|
|
|
564
661
|
if (out.length > MAX_OUTPUT)
|
|
565
662
|
out = out.slice(0, MAX_OUTPUT) + '\n... (output truncated)';
|
|
566
663
|
const result = out || '(no output, success)';
|
|
664
|
+
const changed = this.recordShellMutations(before);
|
|
567
665
|
this.board.log(this.agentId, 'tool_result', result);
|
|
568
|
-
resolve(result);
|
|
666
|
+
resolve(changed > 0 ? `${result}\n\nTracked shell mutations: ${changed} file${changed === 1 ? '' : 's'}.` : result);
|
|
569
667
|
});
|
|
570
668
|
});
|
|
571
669
|
}
|