@parall/parall 1.34.0 → 1.35.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.
@@ -27010,6 +27010,7 @@ var ENDPOINTS = {
27010
27010
  // Org-scoped
27011
27011
  ORG: (orgId) => `${API_BASE}/orgs/${orgId}`,
27012
27012
  ORG_MEMBERS: (orgId) => `${API_BASE}/orgs/${orgId}/members`,
27013
+ TEAMS: (orgId) => `${API_BASE}/orgs/${orgId}/teams`,
27013
27014
  ORG_MEMBERS_ONLINE: (orgId) => `${API_BASE}/orgs/${orgId}/members/online`,
27014
27015
  ORG_MEMBER: (orgId, userId) => `${API_BASE}/orgs/${orgId}/members/${userId}`,
27015
27016
  ORG_MEMBER_CHATS: (orgId, memberId) => `${API_BASE}/orgs/${orgId}/members/${memberId}/chats`,
@@ -27054,6 +27055,7 @@ var ENDPOINTS = {
27054
27055
  AGENT: (orgId, agentId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}`,
27055
27056
  AGENT_API_KEYS: (orgId, agentId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/api-keys`,
27056
27057
  AGENT_API_KEY: (orgId, agentId, key) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/api-keys/${key}`,
27058
+ AGENT_API_KEY_REGENERATE: (orgId, agentId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/api-keys/regenerate`,
27057
27059
  AGENT_AVATAR: (orgId, agentId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/avatar`,
27058
27060
  AGENT_ACTIVITY: (orgId, agentId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/activity`,
27059
27061
  AGENT_MONITOR: (orgId, agentId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/monitor`,
@@ -27093,6 +27095,7 @@ var ENDPOINTS = {
27093
27095
  MACHINE_AGENT_WORKSPACE_SETUP: (orgId, machineId, agentId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/agents/${agentId}/workspace/setup`,
27094
27096
  MACHINE_LLM_SOURCE: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/llm-source`,
27095
27097
  MACHINE_PROVIDER_ENABLED: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/provider-enabled`,
27098
+ MACHINE_CAPABILITIES: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/capabilities`,
27096
27099
  MACHINE_RUNTIME_AUTH: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/runtime-auth`,
27097
27100
  MACHINE_KEYS: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/keys`,
27098
27101
  MACHINE_KEY: (orgId, machineId, keyId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/keys/${keyId}`,
@@ -27113,6 +27116,12 @@ var ENDPOINTS = {
27113
27116
  MACHINES_ME_AGENT_WORKSPACE_STATE: (agentId) => `${API_BASE}/machines/me/agents/${agentId}/workspace-state`,
27114
27117
  MACHINES_ME_WS_TICKET: `${API_BASE}/machines/me/ws/ticket`,
27115
27118
  MACHINES_ME_BROWSE_RESPONSE: (requestId) => `${API_BASE}/machines/me/browse-response/${requestId}`,
27119
+ // Hosted browser live-viewer control plane (api-server, NOT clip-service):
27120
+ // the web client drives WebRTC signaling + tab nav through VIEWER_COMMAND;
27121
+ // api-server brokers each command to the host daemon via the machine:{id}
27122
+ // request/reply bridge (mirrors filesystem browse), and the daemon replies on
27123
+ // VIEWER_RESPONSE. See docs/engineering-design/hosted-browser-provider-design.md.
27124
+ MACHINES_ME_BROWSER_PROFILE_VIEWER_RESPONSE: (requestId) => `${API_BASE}/machines/me/browser-profiles/viewer-response/${requestId}`,
27116
27125
  // Tasks (org-scoped)
27117
27126
  TASKS: (orgId) => `${API_BASE}/orgs/${orgId}/tasks`,
27118
27127
  TASK: (orgId, taskId) => `${API_BASE}/orgs/${orgId}/tasks/${taskId}`,
@@ -27178,6 +27187,9 @@ var ENDPOINTS = {
27178
27187
  // Wiki Path Scopes (AFCS ACL)
27179
27188
  WIKI_PATH_SCOPES: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/path-scopes`,
27180
27189
  WIKI_PATH_SCOPE: (orgId, wikiId, scopeId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/path-scopes/${scopeId}`,
27190
+ // Wiki Path Restrictions (AFCS narrowing ACL — private subtrees)
27191
+ WIKI_RESTRICTIONS: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/restrictions`,
27192
+ WIKI_RESTRICTION: (orgId, wikiId, restrictionId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/restrictions/${restrictionId}`,
27181
27193
  WIKI_ACCESS_STATUS: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/access-status`,
27182
27194
  WIKI_ACCESS_REQUESTS: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/access-requests`,
27183
27195
  // Wiki History (commits, file commits, blame)
@@ -27243,6 +27255,7 @@ var ENDPOINTS = {
27243
27255
  // Clips (org-scoped, served by clip-service)
27244
27256
  CLIPS: (orgId) => `${CLIP_BASE}/orgs/${orgId}/clips`,
27245
27257
  CLIP: (orgId, clipId) => `${CLIP_BASE}/orgs/${orgId}/clips/${clipId}`,
27258
+ CLIPS_BULK_METADATA: (orgId) => `${CLIP_BASE}/orgs/${orgId}/clips/bulk-metadata`,
27246
27259
  CLIP_AGENTS: (orgId, clipId) => `${CLIP_BASE}/orgs/${orgId}/clips/${clipId}/agents`,
27247
27260
  AGENT_CLIPS: (orgId, agentId) => `${CLIP_BASE}/orgs/${orgId}/agents/${agentId}/clips`,
27248
27261
  AGENT_CLIP: (orgId, agentId, clipId) => `${CLIP_BASE}/orgs/${orgId}/agents/${agentId}/clips/${clipId}`,
@@ -27255,6 +27268,9 @@ var ENDPOINTS = {
27255
27268
  BROWSER_PROFILE_RESET: (orgId, profileId) => `${CLIP_BASE}/orgs/${orgId}/browser-profiles/${profileId}/reset`,
27256
27269
  BROWSER_PROFILE_CONSENTS: (orgId, profileId) => `${CLIP_BASE}/orgs/${orgId}/browser-profiles/${profileId}/consents`,
27257
27270
  BROWSER_PROFILE_CONSENT: (orgId, profileId, clipId) => `${CLIP_BASE}/orgs/${orgId}/browser-profiles/${profileId}/consents/${clipId}`,
27271
+ // Live viewer command — on api-server (API_BASE), not clip-service: it rides
27272
+ // the machine control-plane request/reply bridge that lives in api-server.
27273
+ BROWSER_PROFILE_VIEWER_COMMAND: (orgId, profileId) => `${API_BASE}/orgs/${orgId}/browser-profiles/${profileId}/viewer/command`,
27258
27274
  // Clip registry (global, served by clip-service → Pinix Hub proxy)
27259
27275
  CLIP_REGISTRY: () => `${CLIP_BASE}/registry/clips`
27260
27276
  };
@@ -27331,6 +27347,7 @@ var WS_EVENTS = {
27331
27347
  MACHINE_CONFIG_UPDATED: "machine.config.updated",
27332
27348
  MACHINE_CLIP_SYNC: "machine.clip.sync",
27333
27349
  MACHINE_BROWSER_PROFILE_LIFECYCLE: "machine.browser_profile.lifecycle",
27350
+ MACHINE_BROWSER_PROFILE_VIEWER: "machine.browser_profile.viewer",
27334
27351
  AGENT_NEW_SESSION: "agent.new_session",
27335
27352
  CLIP_CREATED: "clip.created",
27336
27353
  CLIP_REMOVED: "clip.removed",
@@ -27482,7 +27499,10 @@ var ParallClient = class _ParallClient {
27482
27499
  method,
27483
27500
  headers,
27484
27501
  body: body ? JSON.stringify(body) : void 0,
27485
- signal
27502
+ signal,
27503
+ // keepalive lets a request fired during page unload (e.g. the browser
27504
+ // viewer's stream.close on pagehide) outlive the document.
27505
+ keepalive: opts?.keepalive
27486
27506
  });
27487
27507
  } catch (err) {
27488
27508
  throw _ParallClient.normalizeFetchError(err);
@@ -27653,6 +27673,10 @@ var ParallClient = class _ParallClient {
27653
27673
  const res = await this.request("GET", ENDPOINTS.ORG_MEMBERS(orgId));
27654
27674
  return res.data;
27655
27675
  }
27676
+ async getTeams(orgId) {
27677
+ const res = await this.request("GET", ENDPOINTS.TEAMS(orgId));
27678
+ return res.data;
27679
+ }
27656
27680
  async getOnlineMembers(orgId) {
27657
27681
  const res = await this.request("GET", ENDPOINTS.ORG_MEMBERS_ONLINE(orgId));
27658
27682
  return res.user_ids ?? [];
@@ -27891,6 +27915,10 @@ var ParallClient = class _ParallClient {
27891
27915
  async createAgentApiKey(orgId, agentId) {
27892
27916
  return this.request("POST", ENDPOINTS.AGENT_API_KEYS(orgId, agentId));
27893
27917
  }
27918
+ /** Revokes all of the agent's active API keys and mints a replacement. */
27919
+ async regenerateAgentApiKey(orgId, agentId) {
27920
+ return this.request("POST", ENDPOINTS.AGENT_API_KEY_REGENERATE(orgId, agentId));
27921
+ }
27894
27922
  async revokeAgentApiKey(orgId, agentId, key) {
27895
27923
  return this.request("DELETE", ENDPOINTS.AGENT_API_KEY(orgId, agentId, key));
27896
27924
  }
@@ -28062,6 +28090,17 @@ var ParallClient = class _ParallClient {
28062
28090
  provider_enabled: providerEnabled
28063
28091
  });
28064
28092
  }
28093
+ /**
28094
+ * Replace the machine's capability set (admin). Primary use: healing a
28095
+ * machine that registered without `browser_provider` during the capability
28096
+ * migration's rolling-deploy window. Removing `agent_host` is rejected by the
28097
+ * server while agents are attached (409 AGENTS_STILL_ATTACHED).
28098
+ */
28099
+ async patchMachineCapabilities(orgId, machineId, capabilities) {
28100
+ return this.request("PATCH", ENDPOINTS.MACHINE_CAPABILITIES(orgId, machineId), {
28101
+ capabilities
28102
+ });
28103
+ }
28065
28104
  /** Get machine-level runtime auth state. */
28066
28105
  async getMachineRuntimeAuth(orgId, machineId) {
28067
28106
  return this.request("GET", ENDPOINTS.MACHINE_RUNTIME_AUTH(orgId, machineId));
@@ -28152,6 +28191,22 @@ var ParallClient = class _ParallClient {
28152
28191
  async postBrowseResponse(requestId, response) {
28153
28192
  return this.request("POST", ENDPOINTS.MACHINES_ME_BROWSE_RESPONSE(requestId), response);
28154
28193
  }
28194
+ /**
28195
+ * `POST /machines/me/browser-profiles/viewer-response/{requestId}` — daemon
28196
+ * reply to a `machine.browser_profile.viewer` control command. Wakes the
28197
+ * api-server request/reply bridge (mirrors {@link postBrowseResponse}).
28198
+ */
28199
+ async postBrowserProfileViewerResponse(requestId, response) {
28200
+ return this.request("POST", ENDPOINTS.MACHINES_ME_BROWSER_PROFILE_VIEWER_RESPONSE(requestId), response);
28201
+ }
28202
+ /**
28203
+ * `POST /orgs/{orgId}/browser-profiles/{profileId}/viewer/command` — drive the
28204
+ * hosted browser live viewer (WebRTC signaling + tab nav). Authz: profile
28205
+ * owner or org admin. api-server brokers the command to the host daemon.
28206
+ */
28207
+ async browserViewerCommand(orgId, profileId, req, opts) {
28208
+ return this.request("POST", ENDPOINTS.BROWSER_PROFILE_VIEWER_COMMAND(orgId, profileId), req, void 0, false, opts);
28209
+ }
28155
28210
  async resizeMachine(orgId, machineId, spec) {
28156
28211
  return this.request("PATCH", ENDPOINTS.MACHINE_SPEC(orgId, machineId), spec);
28157
28212
  }
@@ -28528,6 +28583,17 @@ var ParallClient = class _ParallClient {
28528
28583
  async deleteWikiPathScope(orgId, wikiId, scopeId) {
28529
28584
  await this.request("DELETE", ENDPOINTS.WIKI_PATH_SCOPE(orgId, wikiId, scopeId));
28530
28585
  }
28586
+ // ---- Wiki Path Restrictions (narrowing ACL — private subtrees) ----
28587
+ async getWikiRestrictions(orgId, wikiId) {
28588
+ const res = await this.request("GET", ENDPOINTS.WIKI_RESTRICTIONS(orgId, wikiId));
28589
+ return res.data;
28590
+ }
28591
+ async createWikiRestriction(orgId, wikiId, data) {
28592
+ return this.request("POST", ENDPOINTS.WIKI_RESTRICTIONS(orgId, wikiId), data);
28593
+ }
28594
+ async deleteWikiRestriction(orgId, wikiId, restrictionId) {
28595
+ await this.request("DELETE", ENDPOINTS.WIKI_RESTRICTION(orgId, wikiId, restrictionId));
28596
+ }
28531
28597
  async getWikiAccessStatus(orgId, wikiId, path7) {
28532
28598
  return this.request("GET", ENDPOINTS.WIKI_ACCESS_STATUS(orgId, wikiId), void 0, path7 ? { path: path7 } : void 0);
28533
28599
  }
@@ -28690,6 +28756,10 @@ var ParallClient = class _ParallClient {
28690
28756
  async updateClip(orgId, clipId, req) {
28691
28757
  return this.request("PATCH", ENDPOINTS.CLIP(orgId, clipId), req);
28692
28758
  }
28759
+ /** Atomically set display_name and/or description on multiple clip instances (application metadata). */
28760
+ async bulkUpdateClipMetadata(orgId, req) {
28761
+ return this.request("POST", ENDPOINTS.CLIPS_BULK_METADATA(orgId), req);
28762
+ }
28693
28763
  async deleteClip(orgId, clipId) {
28694
28764
  await this.request("DELETE", ENDPOINTS.CLIP(orgId, clipId));
28695
28765
  }
@@ -30221,7 +30291,7 @@ var ParallAgentGateway = class {
30221
30291
  this.dispatchState.mainDispatching = true;
30222
30292
  void this.drainMainBuffer();
30223
30293
  }
30224
- }, 5e3);
30294
+ }, 5e3).unref();
30225
30295
  }
30226
30296
  }
30227
30297
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parall/parall",
3
- "version": "1.34.0",
3
+ "version": "1.35.0",
4
4
  "description": "OpenClaw channel plugin for Parall IM",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -16,8 +16,8 @@
16
16
  "openclaw.plugin.json"
17
17
  ],
18
18
  "dependencies": {
19
- "@parall/agent-core": "1.34.0",
20
- "@parall/sdk": "1.34.0"
19
+ "@parall/agent-core": "1.35.0",
20
+ "@parall/sdk": "1.35.0"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@types/node": "^22.0.0",
@@ -7,129 +7,128 @@ description: "Parall wiki operations: read, search, edit, and propose changes to
7
7
 
8
8
  Manage organization wikis via the Parall CLI. Auth is pre-configured.
9
9
 
10
- ## Browsing (no local state needed)
10
+ ## Mental model
11
+
12
+ Wiki editing works on a **local workspace**: `parall wiki sync` downloads the
13
+ wiki into a directory on disk, you edit those files with your normal file
14
+ tools, then `parall wiki changeset create` uploads the result as a proposal.
15
+ There is no git in the workspace — your edits are detected by diffing against
16
+ the synced baseline.
17
+
18
+ Key facts the commands won't tell you:
19
+
20
+ - **Workspace location is fixed.** Sync output and `parall wiki status` print
21
+ the absolute workspace path (`synced → /path/to/<slug>` / `Mount: ...`).
22
+ Always address wiki files by that absolute path — your shell cwd is usually
23
+ NOT inside the workspace.
24
+ - **Text files only.** Changesets reject binary content. Don't put images or
25
+ archives in the workspace; binary uploads go through the web UI.
26
+ - **`cat`, `search`, `query`, `outline`, and `section` read your local
27
+ workspace copy when it exists** — including your own unproposed edits. Add
28
+ `--remote` to `cat` to read the server version instead.
29
+ - **`search`/`query` are keyword (lexical) matching**, not semantic search.
30
+ `query` additionally ranks whole documents — better for multi-word
31
+ questions; `search` for a single identifier.
32
+ - The `<wiki>` argument is the slug or ID from `parall wiki list`; with a
33
+ single wiki in the org it can be omitted.
34
+
35
+ ## Core workflow
11
36
 
12
37
  ```bash
13
- parall wiki list # List all wikis
14
- parall wiki tree <slug> # List files and directories
15
- parall wiki tree <slug> --path docs/ # List a subdirectory
38
+ parall wiki sync # 1. get/update files (prints workspace path)
39
+ # 2. read + edit files under the workspace path with standard file tools
40
+ parall wiki diff <wiki> # 3. review exactly what you'll propose
41
+ parall wiki changeset create <wiki> --title "..." # 4. submit
16
42
  ```
17
43
 
18
- ## Editing
44
+ Always sync before starting and always check `diff` before proposing — the
45
+ changeset uploads the full content of every changed file.
19
46
 
20
- Wiki editing works on a **local workspace** — a directory on disk where wiki
21
- files are synced. You sync from the server, edit files locally, then propose
22
- a changeset.
47
+ Unprotected paths auto-merge immediately (`auto_merged: true`); protected
48
+ paths stay open for human review. Follow the returned `next_action` either way.
23
49
 
24
- ### Step 1: Sync
50
+ ## Stale base (server moved since your sync)
25
51
 
26
- ```bash
27
- parall wiki sync <slug>
28
- ```
29
-
30
- This downloads wiki files to a local directory. The output includes the
31
- **absolute mount path** for each wiki (e.g. `synced → /path/to/workspace/kb`).
32
-
33
- ### Step 2: Find the mount path
34
-
35
- The sync output JSON contains `synced[].path` — the absolute path where files
36
- live. You can also check it anytime with:
52
+ If files changed on the server after your last sync, `changeset create` is
53
+ rejected both by a CLI precheck and by the server (409 `STALE_BASE`) — so
54
+ you can't silently overwrite someone's concurrent edit. Recovery:
37
55
 
38
56
  ```bash
39
- parall wiki status <slug>
57
+ parall wiki sync # pull latest; your local edits are preserved
58
+ # if a file conflicts, resolve it (see next section)
59
+ parall wiki changeset create <wiki> --title "..."
40
60
  ```
41
61
 
42
- The output includes `Mount: /absolute/path/to/<slug>`.
43
-
44
- Use this path with `read`, `write`, and `edit` tools. For example, if the mount
45
- is `/data/.openclaw/workspace/kb`, then `README.md` is at
46
- `/data/.openclaw/workspace/kb/README.md`.
62
+ ## Sync conflicts
47
63
 
48
- ### Step 3: Edit files
64
+ `sync` three-way merges. When both you and the server changed the same file,
65
+ your file is left intact and the upstream copy lands under
66
+ `<workspace>/.parall-wiki/conflicts/`:
49
67
 
50
- Use standard file tools (`read`, `write`, `edit`) on files under the mount path.
68
+ | Marker | Meaning |
69
+ |--------|---------|
70
+ | `conflicts/<path>.remote` | Server has different content for `<path>` |
71
+ | `conflicts/<path>.remote-deleted` | Server deleted `<path>`; you still have edits |
51
72
 
52
- ### Step 4: Review changes
73
+ All paths below are relative to the workspace root. Pick one:
53
74
 
54
75
  ```bash
55
- parall wiki diff <slug> # Shows unified diff of all local changes
56
- parall wiki status <slug> # Shows which files changed with +/- line counts
57
- ```
76
+ # Accept upstream (drop your edit):
77
+ cp <workspace>/.parall-wiki/conflicts/<path>.remote <workspace>/<path>
58
78
 
59
- Always review before proposing.
79
+ # Keep yours / hand-merge: edit <workspace>/<path> to final content, then
80
+ parall wiki changeset create <wiki> --title "Reconcile <path>"
60
81
 
61
- ### Step 5: Propose changeset
62
-
63
- ```bash
64
- parall wiki changeset create <slug> --title "Description of changes"
82
+ # Accept server delete (.remote-deleted only):
83
+ rm <workspace>/<path>
65
84
  ```
66
85
 
67
- This uploads your local changes. Unprotected paths auto-merge immediately; the
68
- CLI prints `auto_merged: true` and refreshes the local manifest. Protected
69
- paths remain as a changeset for review; follow the returned `next_action`.
70
-
71
- ## Changeset Management
72
-
73
- ```bash
74
- parall wiki changeset list <slug> # List all changesets
75
- parall wiki changeset show <changesetId> <slug> # Show detail + feedback
76
- parall wiki changeset diff <changesetId> <slug> # Show changeset diff
77
- ```
86
+ Then re-run `parall wiki sync` and delete the used marker file. Conflicts
87
+ exit 0 (they need your decision); `failed[]` entries (download error,
88
+ shape-conflict) exit 1 and retry on the next sync.
78
89
 
79
- If a changeset is rejected, fix the files locally and re-propose:
90
+ ## Changesets
80
91
 
81
92
  ```bash
82
- parall wiki changeset create <slug> --update <changesetId>
93
+ parall wiki changeset list <wiki>
94
+ parall wiki changeset show <changesetId> <wiki> # status + feedback
95
+ parall wiki changeset diff <changesetId> <wiki>
96
+ parall wiki changeset create <wiki> --update <id> # re-propose after rejection (title inherited)
83
97
  ```
84
98
 
85
- The title is inherited from the original changeset no need to repeat it.
86
-
87
- ## Handling sync conflicts
88
-
89
- `wiki sync` runs a three-way merge. When both you and the server changed the
90
- same file, sync **does not overwrite your work**. It leaves your file intact
91
- and drops the upstream version under `.parall-wiki/conflicts/`:
92
-
93
- | Marker | Meaning |
94
- |--------|---------|
95
- | `.parall-wiki/conflicts/<path>.remote` | Server has different content (concurrent edit, new file collision, or server changed a file you deleted) |
96
- | `.parall-wiki/conflicts/<path>.remote-deleted` | Server deleted the file; you still have edits |
97
-
98
- stderr prints one line per conflict. Recovery:
99
+ Rejected: read the feedback (`show` / `status`), fix the files, re-propose
100
+ with `--update <id>`. Conflict status: `sync`, resolve, then `--update <id>`.
99
101
 
100
- **Accept upstream** (drop your edit):
101
- ```bash
102
- cp .parall-wiki/conflicts/<path>.remote <path>
103
- parall wiki sync
104
- ```
102
+ Re-propose REPLACES the changeset's previous contents with your current
103
+ workspace diff — to withdraw a file from the proposal, revert it locally
104
+ (restore the synced content) and re-propose; it drops out of the changeset.
105
105
 
106
- **Keep yours** (or hand-merge, then propose):
107
- ```bash
108
- # edit <path> to final content
109
- parall wiki diff <slug>
110
- parall wiki changeset create <slug> --title "Reconcile <path>"
111
- parall wiki sync # fast-forwards after server merges
112
- ```
106
+ ## Discovery & history
113
107
 
114
- **Accept server delete** (`.remote-deleted` only):
115
108
  ```bash
116
- rm <path>
117
- parall wiki sync
109
+ parall wiki query "how is auth configured" <wiki> # multi-word lookup (query FIRST, wiki second)
110
+ parall wiki search "JWT" <wiki> # single keyword (query FIRST, wiki second)
111
+ parall wiki outline <wiki> --path docs/ # heading structure
112
+ parall wiki cat docs/auth.md <wiki> # print a file (--remote for server version)
113
+ parall wiki tree <wiki> # list files
114
+ parall wiki log <wiki> # recent operations
115
+ parall wiki log <wiki> docs/auth.md # per-file commit history
118
116
  ```
119
117
 
120
- Sync failures (`download`, `shape-conflict`) set exit code 1 and retry on
121
- next sync. Conflicts exit 0 — they need your decision, not a retry.
118
+ ## Permissions
122
119
 
123
- ## Discarding local changes
124
-
125
- ```bash
126
- parall wiki reset <slug> # Restore all files to last synced state
127
- ```
120
+ Reads and writes are ACL-checked server-side per path. `parall wiki access
121
+ <path>` shows your level for a path. On a `PERMISSION_DENIED`, errors include
122
+ a `Request approval:` hint — use `parall wiki request-access <path> --reason
123
+ "..."` to file an approval card for a maintainer, then re-sync after approval.
128
124
 
129
- ## History
125
+ ## Recovery
130
126
 
131
127
  ```bash
132
- parall wiki log <slug> # Recent wiki operations
128
+ parall wiki reset <wiki> # discard ALL local edits, restore last-synced state
129
+ parall wiki status <wiki> # local changes + your changesets, anytime
133
130
  ```
134
131
 
135
- CLI success output is JSON; errors may add a plain-text `Request approval:` line on a `PERMISSION_DENIED` — read both. Run `parall wiki --help` for full options.
132
+ CLI success output is JSON on stdout (human summary on stderr); errors state
133
+ the reason and the next step — follow them. `parall wiki --help` for the
134
+ full command list.