@parall/parall 1.58.2 → 1.60.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parall/parall",
3
- "version": "1.58.2",
3
+ "version": "1.60.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.58.2",
20
- "@parall/sdk": "1.58.2"
19
+ "@parall/agent-core": "1.60.0",
20
+ "@parall/sdk": "1.60.0"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@types/node": "^22.0.0",
@@ -52,43 +52,65 @@ paths stay open for human review. Follow the returned `next_action` either way.
52
52
 
53
53
  ## Stale base (server moved since your sync)
54
54
 
55
- If files changed on the server after your last sync, `changeset create` is
56
- rejected both by a CLI precheck and by the server (409 `STALE_BASE`) — so
57
- you can't silently overwrite someone's concurrent edit. Recovery:
55
+ If files changed on the server after your last sync, `changeset create`
56
+ recovers on its own: it re-syncs (a three-way merge that keeps your edits and
57
+ folds non-overlapping upstream changes into your files), then proposes again
58
+ once. When this happened the result says so (`stale_recovery`, and the
59
+ `next_action` text) — re-read any file it names before editing further, since
60
+ your copy now contains the upstream changes too.
58
61
 
59
- ```bash
60
- parall wiki sync # pull latest; your local edits are preserved
61
- # if a file conflicts, resolve it (see next section)
62
- parall wiki changeset create <wiki> --title "..."
63
- ```
62
+ It stops and tells you when the merge could not settle a file on its own. That
63
+ is not a dead end: see **Sync conflicts** the fix is always "make the file say
64
+ what you want, then propose again".
64
65
 
65
66
  ## Sync conflicts
66
67
 
67
- `sync` three-way merges. When both you and the server changed the same file,
68
- your file is left intact and the upstream copy lands under
69
- `<workspace>/.parall-wiki/conflicts/`:
70
-
71
- | Marker | Meaning |
72
- |--------|---------|
73
- | `conflicts/<path>.remote` | Server has different content for `<path>` |
74
- | `conflicts/<path>.remote-deleted` | Server deleted `<path>`; you still have edits |
68
+ `sync` three-way merges at line level (diff3). When both you and the server
69
+ changed the same file and the changed hunks do not overlap — at least one
70
+ unchanged line separates them — the upstream changes are merged into your copy
71
+ and your edits stay pending. When they DO overlap (both sides touched the same
72
+ or adjacent lines), `sync` writes the conflict into your file the way git does:
75
73
 
76
- All paths below are relative to the workspace root. Pick one:
77
-
78
- ```bash
79
- # Accept upstream (drop your edit):
80
- cp <workspace>/.parall-wiki/conflicts/<path>.remote <workspace>/<path>
81
-
82
- # Keep yours / hand-merge: edit <workspace>/<path> to final content, then
83
- parall wiki changeset create <wiki> --title "Reconcile <path>"
84
-
85
- # Accept server delete (.remote-deleted only):
86
- rm <workspace>/<path>
74
+ ```
75
+ <<<<<<< mine (parall-merge)
76
+ your version of the lines
77
+ ======= (parall-merge)
78
+ the server's version of the lines
79
+ >>>>>>> latest (parall-merge)
87
80
  ```
88
81
 
89
- Then re-run `parall wiki sync` and delete the used marker file. Conflicts
90
- exit 0 (they need your decision); `failed[]` entries (download error,
91
- shape-conflict) exit 1 and retry on the next sync.
82
+ The `(parall-merge)` tag is what tells a real delimiter from a quoted example:
83
+ if the page itself contains that block verbatim (say, a page documenting this
84
+ feature), the delimiters of a new conflict read `(parall-merge-2)`, then
85
+ `-3`, and so on. `sync` remembers which set it wrote for the file, and only
86
+ that set is live: propose refuses the file while **any** line of that set is
87
+ still in it — a lone opener or closer left from a half-finished hand merge
88
+ counts — and treats every other set (quoted examples) as content. Everything
89
+ outside the blocks is already merged. Your pre-merge copy is kept at
90
+ `<workspace>/.parall-wiki/conflicts/<path>.mine`.
91
+
92
+ **Your baseline has already moved to the server's version.** There is nothing
93
+ to sync, restore or re-apply: edit each block so the file says what you want
94
+ (keep one side, or combine them), delete the three marker lines, and run
95
+ `parall wiki changeset create` again. A file that still contains any
96
+ `<<<<<<< mine (parall-merge…)` / `======= (parall-merge…)` /
97
+ `>>>>>>> latest (parall-merge…)` line of the set written for it is
98
+ refused at propose, so you cannot ship one by accident.
99
+
100
+ The other shapes follow the same rule — the working tree already holds what you
101
+ meant, propose sends it:
102
+
103
+ | The error says | Working tree now | To finish |
104
+ |---|---|---|
105
+ | overlapping block(s) marked in the file | your file with `<<<<<<< mine (parall-merge)` blocks; `.mine` copy aside | edit the blocks away, propose |
106
+ | not merged in place (binary, LFS, too long/repetitive, or markers from an earlier sync still unresolved) | your file untouched; the server's bytes at `conflicts/<path>.remote` | fold what you want from `.remote` into your file, propose |
107
+ | the server changed it and you deleted it | no file (your delete stands); server's bytes at `conflicts/<path>.remote` | propose to delete the server's newer version too, or copy `.remote` back to `<workspace>/<path>` to keep it |
108
+ | the server deleted it and you still have edits | your file, now a new file (it stays on its old baseline while it still carries an unresolved block — edit that away first) | propose to recreate it, or `rm` it to accept the removal |
109
+
110
+ Conflict artifacts under `.parall-wiki/conflicts/` are removed on their own
111
+ once the path is proposed or back in step with the server. Conflicts exit 0
112
+ (they need your decision); `failed[]` entries (download error, shape-conflict)
113
+ exit 1 and retry on the next sync.
92
114
 
93
115
  ## Changesets
94
116
 
@@ -172,10 +194,16 @@ a `Request approval:` hint — use `parall wiki request-access <path> --reason
172
194
  ## Recovery
173
195
 
174
196
  ```bash
175
- parall wiki reset <wiki> # discard ALL local edits, restore last-synced state
197
+ parall wiki reset <wiki> # discard ALL local edits, restore the synced baseline
176
198
  parall wiki status <wiki> # local changes + your changesets, anytime
177
199
  ```
178
200
 
201
+ After a conflict the synced baseline IS the server's version, so `reset` gives
202
+ you the server's file; your pre-merge edits are still under
203
+ `.parall-wiki/conflicts/<path>.mine` until that path is proposed, or until a
204
+ later `sync` finds it back in step with the server (clean or fast-forwarded)
205
+ and removes the copy.
206
+
179
207
  ## Changeset Discipline
180
208
 
181
209
  - Creation is fail-closed — without explicit CLI confirmation of success,
package/src/gateway.ts CHANGED
@@ -12,6 +12,7 @@ import {
12
12
  parseDispatchDeadlineMs,
13
13
  identityFromMe,
14
14
  initAgentTelemetry,
15
+ resolveServiceVersion,
15
16
  createOtelLogger,
16
17
  type DispatchAdapter,
17
18
  type ParallEvent,
@@ -442,7 +443,11 @@ export const parallGateway: ChannelGatewayAdapter<ResolvedParallAccount> = {
442
443
  setAgentIdentity(identityFromMe(me));
443
444
  log?.info(`parall[${ctx.accountId}]: authenticated as ${me.display_name} (${agentUserId})`);
444
445
 
445
- const telemetry = await initAgentTelemetry('parall-openclaw-agent', 'openclaw');
446
+ const telemetry = await initAgentTelemetry('parall-openclaw-agent', 'openclaw', {
447
+ apiUrl: process.env.PRLL_API_URL,
448
+ apiKey: process.env.PRLL_API_KEY,
449
+ serviceVersion: resolveServiceVersion(import.meta.url),
450
+ });
446
451
  const otelLog = createOtelLogger('agent', 'openclaw-agent');
447
452
  try {
448
453
  const stateDir =