@parall/parall 1.31.0 → 1.32.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.
Files changed (47) hide show
  1. package/dist/accounts.d.ts +1 -1
  2. package/dist/accounts.js +4 -4
  3. package/dist/channel.d.ts +2 -2
  4. package/dist/channel.d.ts.map +1 -1
  5. package/dist/channel.js +10 -10
  6. package/dist/config-manager.d.ts +1 -1
  7. package/dist/config-manager.d.ts.map +1 -1
  8. package/dist/config-manager.js +70 -30
  9. package/dist/fork.d.ts.map +1 -1
  10. package/dist/fork.js +17 -17
  11. package/dist/gateway.d.ts +3 -3
  12. package/dist/gateway.d.ts.map +1 -1
  13. package/dist/gateway.js +147 -127
  14. package/dist/hooks.d.ts +1 -1
  15. package/dist/hooks.d.ts.map +1 -1
  16. package/dist/hooks.js +52 -26
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.js +7 -7
  19. package/dist/oc-session.d.ts.map +1 -1
  20. package/dist/oc-session.js +35 -27
  21. package/dist/outbound.d.ts +2 -2
  22. package/dist/outbound.d.ts.map +1 -1
  23. package/dist/outbound.js +13 -14
  24. package/dist/routing.d.ts +2 -2
  25. package/dist/routing.js +1 -1
  26. package/dist/runtime.d.ts +5 -5
  27. package/dist/runtime.d.ts.map +1 -1
  28. package/dist/runtime.js +2 -2
  29. package/dist/session.js +4 -4
  30. package/dist/wiki-helper.d.ts.map +1 -1
  31. package/dist/wiki-helper.js +27 -27
  32. package/openclaw.plugin.json +4 -1
  33. package/package.json +3 -3
  34. package/skills/parall-clips/SKILL.md +48 -0
  35. package/src/accounts.ts +5 -5
  36. package/src/channel.ts +15 -14
  37. package/src/config-manager.ts +79 -34
  38. package/src/fork.ts +26 -22
  39. package/src/gateway.ts +177 -134
  40. package/src/hooks.ts +109 -50
  41. package/src/index.ts +8 -8
  42. package/src/oc-session.ts +43 -35
  43. package/src/outbound.ts +18 -17
  44. package/src/routing.ts +2 -2
  45. package/src/runtime.ts +11 -7
  46. package/src/session.ts +4 -4
  47. package/src/wiki-helper.ts +47 -34
@@ -5,9 +5,9 @@
5
5
  // Sync check: when bumping devDependencies.openclaw, diff upstream
6
6
  // pi-coding-agent/dist/core/session-manager.js for new migration steps
7
7
  // or structural changes to createBranchedSession / _buildIndex.
8
- import { randomUUID } from "node:crypto";
9
- import { existsSync, mkdirSync, readFileSync, writeFileSync, } from "node:fs";
10
- import { join, resolve } from "node:path";
8
+ import { randomUUID } from 'node:crypto';
9
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
10
+ import { join, resolve } from 'node:path';
11
11
  export const CURRENT_SESSION_VERSION = 3;
12
12
  // ---------------------------------------------------------------------------
13
13
  // Helpers
@@ -23,7 +23,7 @@ function generateId(existing) {
23
23
  function loadEntries(filePath) {
24
24
  if (!existsSync(filePath))
25
25
  return [];
26
- const lines = readFileSync(filePath, "utf-8").trim().split("\n");
26
+ const lines = readFileSync(filePath, 'utf-8').trim().split('\n');
27
27
  const entries = [];
28
28
  for (const line of lines) {
29
29
  if (!line.trim())
@@ -38,7 +38,7 @@ function loadEntries(filePath) {
38
38
  if (entries.length === 0)
39
39
  return entries;
40
40
  const h = entries[0];
41
- if (h.type !== "session" || typeof h.id !== "string")
41
+ if (h.type !== 'session' || typeof h.id !== 'string')
42
42
  return [];
43
43
  return entries;
44
44
  }
@@ -47,7 +47,7 @@ function migrateV1ToV2(entries) {
47
47
  const ids = new Set();
48
48
  let prevId = null;
49
49
  for (const entry of entries) {
50
- if (entry.type === "session") {
50
+ if (entry.type === 'session') {
51
51
  entry.version = 2;
52
52
  continue;
53
53
  }
@@ -56,11 +56,11 @@ function migrateV1ToV2(entries) {
56
56
  ids.add(e.id);
57
57
  e.parentId = prevId;
58
58
  prevId = e.id;
59
- if (e.type === "compaction") {
59
+ if (e.type === 'compaction') {
60
60
  const comp = e;
61
- if (typeof comp.firstKeptEntryIndex === "number") {
61
+ if (typeof comp.firstKeptEntryIndex === 'number') {
62
62
  const target = entries[comp.firstKeptEntryIndex];
63
- if (target && target.type !== "session") {
63
+ if (target && target.type !== 'session') {
64
64
  comp.firstKeptEntryId = target.id;
65
65
  }
66
66
  delete comp.firstKeptEntryIndex;
@@ -70,18 +70,20 @@ function migrateV1ToV2(entries) {
70
70
  }
71
71
  function migrateV2ToV3(entries) {
72
72
  for (const entry of entries) {
73
- if (entry.type === "session") {
73
+ if (entry.type === 'session') {
74
74
  entry.version = 3;
75
75
  continue;
76
76
  }
77
77
  const e = entry;
78
- if (e.type === "message" && e.message && e.message.role === "hookMessage") {
79
- e.message.role = "custom";
78
+ if (e.type === 'message' &&
79
+ e.message &&
80
+ e.message.role === 'hookMessage') {
81
+ e.message.role = 'custom';
80
82
  }
81
83
  }
82
84
  }
83
85
  function migrate(entries) {
84
- const header = entries.find((e) => e.type === "session");
86
+ const header = entries.find((e) => e.type === 'session');
85
87
  const version = header?.version ?? 1;
86
88
  if (version >= CURRENT_SESSION_VERSION)
87
89
  return false;
@@ -95,7 +97,7 @@ function migrate(entries) {
95
97
  // SessionManager (read-only subset + createBranchedSession)
96
98
  // ---------------------------------------------------------------------------
97
99
  export class SessionManager {
98
- sessionId = "";
100
+ sessionId = '';
99
101
  sessionFile;
100
102
  sessionDir;
101
103
  cwd;
@@ -136,7 +138,7 @@ export class SessionManager {
136
138
  this.flushed = true;
137
139
  return;
138
140
  }
139
- const header = this.fileEntries.find((e) => e.type === "session");
141
+ const header = this.fileEntries.find((e) => e.type === 'session');
140
142
  if (header && header.version > CURRENT_SESSION_VERSION) {
141
143
  throw new Error(`Session file ${this.sessionFile} uses version ${header.version}, ` +
142
144
  `but oc-session.ts only supports up to ${CURRENT_SESSION_VERSION}. ` +
@@ -152,13 +154,19 @@ export class SessionManager {
152
154
  this.sessionId = randomUUID();
153
155
  const timestamp = new Date().toISOString();
154
156
  this.fileEntries = [
155
- { type: "session", version: CURRENT_SESSION_VERSION, id: this.sessionId, timestamp, cwd: this.cwd },
157
+ {
158
+ type: 'session',
159
+ version: CURRENT_SESSION_VERSION,
160
+ id: this.sessionId,
161
+ timestamp,
162
+ cwd: this.cwd,
163
+ },
156
164
  ];
157
165
  this.byId.clear();
158
166
  this.labelsById.clear();
159
167
  this.leafId = null;
160
168
  this.flushed = false;
161
- const ts = timestamp.replace(/[:.]/g, "-");
169
+ const ts = timestamp.replace(/[:.]/g, '-');
162
170
  this.sessionFile = join(this.sessionDir, `${ts}_${this.sessionId}.jsonl`);
163
171
  }
164
172
  buildIndex() {
@@ -167,12 +175,12 @@ export class SessionManager {
167
175
  this.labelTimestampsById.clear();
168
176
  this.leafId = null;
169
177
  for (const entry of this.fileEntries) {
170
- if (entry.type === "session")
178
+ if (entry.type === 'session')
171
179
  continue;
172
180
  const e = entry;
173
181
  this.byId.set(e.id, e);
174
182
  this.leafId = e.id;
175
- if (e.type === "label") {
183
+ if (e.type === 'label') {
176
184
  if (e.label) {
177
185
  this.labelsById.set(e.targetId, e.label);
178
186
  this.labelTimestampsById.set(e.targetId, e.timestamp);
@@ -187,7 +195,7 @@ export class SessionManager {
187
195
  rewrite() {
188
196
  if (!this.sessionFile)
189
197
  return;
190
- writeFileSync(this.sessionFile, this.fileEntries.map((e) => JSON.stringify(e)).join("\n") + "\n");
198
+ writeFileSync(this.sessionFile, this.fileEntries.map((e) => JSON.stringify(e)).join('\n') + '\n');
191
199
  }
192
200
  // -- Public accessors ------------------------------------------------------
193
201
  getLeafId() {
@@ -220,13 +228,13 @@ export class SessionManager {
220
228
  const branch = this.getBranch(leafId);
221
229
  if (branch.length === 0)
222
230
  throw new Error(`Entry ${leafId} not found`);
223
- const pathWithoutLabels = branch.filter((e) => e.type !== "label");
231
+ const pathWithoutLabels = branch.filter((e) => e.type !== 'label');
224
232
  const newId = randomUUID();
225
233
  const timestamp = new Date().toISOString();
226
- const ts = timestamp.replace(/[:.]/g, "-");
234
+ const ts = timestamp.replace(/[:.]/g, '-');
227
235
  const newFile = join(this.sessionDir, `${ts}_${newId}.jsonl`);
228
236
  const header = {
229
- type: "session",
237
+ type: 'session',
230
238
  version: CURRENT_SESSION_VERSION,
231
239
  id: newId,
232
240
  timestamp,
@@ -245,7 +253,7 @@ export class SessionManager {
245
253
  const labelEntries = [];
246
254
  for (const { targetId, label, timestamp: labelTs } of labelsToWrite) {
247
255
  const le = {
248
- type: "label",
256
+ type: 'label',
249
257
  id: generateId(pathEntryIds),
250
258
  parentId,
251
259
  timestamp: labelTs ?? timestamp,
@@ -260,7 +268,7 @@ export class SessionManager {
260
268
  this.sessionId = newId;
261
269
  this.sessionFile = newFile;
262
270
  this.buildIndex();
263
- const hasAssistant = this.fileEntries.some((e) => e.type === "message" && e.message?.role === "assistant");
271
+ const hasAssistant = this.fileEntries.some((e) => e.type === 'message' && e.message?.role === 'assistant');
264
272
  if (hasAssistant) {
265
273
  this.rewrite();
266
274
  this.flushed = true;
@@ -273,9 +281,9 @@ export class SessionManager {
273
281
  // -- Factory ---------------------------------------------------------------
274
282
  static open(path) {
275
283
  const entries = loadEntries(path);
276
- const header = entries.find((e) => e.type === "session");
284
+ const header = entries.find((e) => e.type === 'session');
277
285
  const cwd = header?.cwd ?? process.cwd();
278
- const dir = resolve(path, "..");
286
+ const dir = resolve(path, '..');
279
287
  return new SessionManager(cwd, dir, path);
280
288
  }
281
289
  }
@@ -1,6 +1,6 @@
1
- import type { ChannelPlugin } from "openclaw/plugin-sdk/core";
1
+ import type { ChannelPlugin } from 'openclaw/plugin-sdk/core';
2
2
  /** Extract ChannelOutboundAdapter from ChannelPlugin (removed from public SDK exports in 2026.3.24). */
3
- type ChannelOutboundAdapter = NonNullable<ChannelPlugin["outbound"]>;
3
+ type ChannelOutboundAdapter = NonNullable<ChannelPlugin['outbound']>;
4
4
  export declare const parallOutbound: ChannelOutboundAdapter;
5
5
  export {};
6
6
  //# sourceMappingURL=outbound.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"outbound.d.ts","sourceRoot":"","sources":["../src/outbound.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D,wGAAwG;AACxG,KAAK,sBAAsB,GAAG,WAAW,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC;AAMrE,eAAO,MAAM,cAAc,EAAE,sBA2B5B,CAAC"}
1
+ {"version":3,"file":"outbound.d.ts","sourceRoot":"","sources":["../src/outbound.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D,wGAAwG;AACxG,KAAK,sBAAsB,GAAG,WAAW,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC;AAMrE,eAAO,MAAM,cAAc,EAAE,sBA4B5B,CAAC"}
package/dist/outbound.js CHANGED
@@ -1,30 +1,29 @@
1
- import { resolveParallAccount } from "./accounts.js";
2
- import { getParallAccountState } from "./runtime.js";
3
- import { ParallClient } from "@parall/sdk";
1
+ import { resolveParallAccount } from './accounts.js';
2
+ import { getParallAccountState } from './runtime.js';
3
+ import { ParallClient } from '@parall/sdk';
4
4
  export const parallOutbound = {
5
- deliveryMode: "direct",
5
+ deliveryMode: 'direct',
6
6
  textChunkLimit: 10000,
7
7
  chunker: null,
8
8
  sendText: async ({ cfg, to, text, accountId }) => {
9
9
  const account = resolveParallAccount({ cfg, accountId: accountId ?? undefined });
10
10
  if (!account.enabled)
11
- throw new Error("Parall account is disabled");
11
+ throw new Error('Parall account is disabled');
12
12
  if (!account.configured)
13
- throw new Error("Parall account is not configured: parall_url/api_key/org_id required");
13
+ throw new Error('Parall account is not configured: parall_url/api_key/org_id required');
14
14
  const state = getParallAccountState(account.accountId);
15
- const client = state?.client ?? new ParallClient({
16
- baseUrl: account.config.parall_url,
17
- token: account.config.api_key,
18
- });
15
+ const client = state?.client ??
16
+ new ParallClient({
17
+ baseUrl: account.config.parall_url,
18
+ token: account.config.api_key,
19
+ });
19
20
  const orgId = state?.orgId ?? account.config.org_id;
20
21
  const chatId = to;
21
- // Outbound path has no step context — send without agent_step_id.
22
- // Step linkage happens via the CLI's ENV-injected PRLL_STEP_ID in the normal dispatch path.
23
22
  const req = {
24
- message_type: "text",
23
+ message_type: 'text',
25
24
  content: { text },
26
25
  };
27
26
  const msg = await client.sendMessage(orgId, chatId, req);
28
- return { channel: "parall", messageId: msg.id, channelId: chatId };
27
+ return { channel: 'parall', messageId: msg.id, channelId: chatId };
29
28
  },
30
29
  };
package/dist/routing.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { defaultRoutingStrategy, routeTrigger, } from "@parall/agent-core";
2
- export type { RoutingStrategy, TriggerDisposition, } from "@parall/agent-core";
1
+ export { defaultRoutingStrategy, routeTrigger, } from '@parall/agent-core';
2
+ export type { RoutingStrategy, TriggerDisposition, } from '@parall/agent-core';
3
3
  //# sourceMappingURL=routing.d.ts.map
package/dist/routing.js CHANGED
@@ -1 +1 @@
1
- export { defaultRoutingStrategy, routeTrigger, } from "@parall/agent-core";
1
+ export { defaultRoutingStrategy, routeTrigger, } from '@parall/agent-core';
package/dist/runtime.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import type { PluginRuntime } from "openclaw/plugin-sdk";
2
- import type { ParallClient, ParallWs } from "@parall/sdk";
3
- import type { AgentIdentity } from "@parall/agent-core";
4
- export type { ForkResult, DispatchState, ParallEvent } from "@parall/agent-core";
5
- export { setSessionChatId, getSessionChatId, setSessionMessageId, getSessionMessageId, clearSessionMessageId, setDispatchMessageId, getDispatchMessageId, clearDispatchMessageId, setDispatchGroupKey, getDispatchGroupKey, clearDispatchGroupKey, setDispatchNoReply, getDispatchNoReply, clearDispatchNoReply, } from "@parall/agent-core";
1
+ import type { PluginRuntime } from 'openclaw/plugin-sdk';
2
+ import type { ParallClient, ParallWs } from '@parall/sdk';
3
+ import type { AgentIdentity } from '@parall/agent-core';
4
+ export type { ForkResult, DispatchState, ParallEvent } from '@parall/agent-core';
5
+ export { setSessionChatId, getSessionChatId, setSessionMessageId, getSessionMessageId, clearSessionMessageId, setDispatchMessageId, getDispatchMessageId, clearDispatchMessageId, setDispatchGroupKey, getDispatchGroupKey, clearDispatchGroupKey, setDispatchNoReply, getDispatchNoReply, clearDispatchNoReply, } from '@parall/agent-core';
6
6
  export type ParallAccountState = {
7
7
  client: ParallClient;
8
8
  apiUrl: string;
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,EACtB,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,EAAE,CAAC,EAAE,QAAQ,CAAC;IACd,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAIF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,QAEnD;AAED,wBAAgB,gBAAgB,IAAI,aAAa,CAKhD;AAKD,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,QAEjF;AAED,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,QAEzD;AAED,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAEvF;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,QAMnG;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEhG;AAED,wBAAgB,yBAAyB,IAAI,WAAW,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAEnF;AAID,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,aAAa,QAEvD;AAED,wBAAgB,gBAAgB,IAAI,aAAa,GAAG,SAAS,CAE5D"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,EACtB,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,EAAE,CAAC,EAAE,QAAQ,CAAC;IACd,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAIF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,QAEnD;AAED,wBAAgB,gBAAgB,IAAI,aAAa,CAKhD;AAKD,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,QAEjF;AAED,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,QAEzD;AAED,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAEvF;AAED,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,QAOvB;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEhG;AAED,wBAAgB,yBAAyB,IAAI,WAAW,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAEnF;AAID,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,aAAa,QAEvD;AAED,wBAAgB,gBAAgB,IAAI,aAAa,GAAG,SAAS,CAE5D"}
package/dist/runtime.js CHANGED
@@ -1,11 +1,11 @@
1
- export { setSessionChatId, getSessionChatId, setSessionMessageId, getSessionMessageId, clearSessionMessageId, setDispatchMessageId, getDispatchMessageId, clearDispatchMessageId, setDispatchGroupKey, getDispatchGroupKey, clearDispatchGroupKey, setDispatchNoReply, getDispatchNoReply, clearDispatchNoReply, } from "@parall/agent-core";
1
+ export { setSessionChatId, getSessionChatId, setSessionMessageId, getSessionMessageId, clearSessionMessageId, setDispatchMessageId, getDispatchMessageId, clearDispatchMessageId, setDispatchGroupKey, getDispatchGroupKey, clearDispatchGroupKey, setDispatchNoReply, getDispatchNoReply, clearDispatchNoReply, } from '@parall/agent-core';
2
2
  let runtime = null;
3
3
  export function setParallRuntime(next) {
4
4
  runtime = next;
5
5
  }
6
6
  export function getParallRuntime() {
7
7
  if (!runtime) {
8
- throw new Error("Parall runtime not initialized");
8
+ throw new Error('Parall runtime not initialized');
9
9
  }
10
10
  return runtime;
11
11
  }
package/dist/session.js CHANGED
@@ -1,4 +1,4 @@
1
- const PRLL_SESSION_PREFIX = "agent:main:parall:";
1
+ const PRLL_SESSION_PREFIX = 'agent:main:parall:';
2
2
  /** Build OpenClaw session key from Parall account, chat type, and chat ID. */
3
3
  export function buildSessionKey(accountId, chatType, chatId) {
4
4
  return `${PRLL_SESSION_PREFIX}${accountId}:${chatType}:${chatId}`;
@@ -11,7 +11,7 @@ export function extractAccountIdFromSessionKey(sessionKey) {
11
11
  if (!sessionKey?.startsWith(PRLL_SESSION_PREFIX))
12
12
  return undefined;
13
13
  const rest = sessionKey.slice(PRLL_SESSION_PREFIX.length);
14
- const firstColon = rest.indexOf(":");
14
+ const firstColon = rest.indexOf(':');
15
15
  if (firstColon < 0)
16
16
  return undefined;
17
17
  return rest.slice(0, firstColon) || undefined;
@@ -25,10 +25,10 @@ export function extractChatIdFromSessionKey(sessionKey) {
25
25
  return undefined;
26
26
  const rest = sessionKey.slice(PRLL_SESSION_PREFIX.length);
27
27
  // Skip accountId and chatType segments
28
- const parts = rest.split(":");
28
+ const parts = rest.split(':');
29
29
  if (parts.length < 3)
30
30
  return undefined;
31
- return parts.slice(2).join(":") || undefined;
31
+ return parts.slice(2).join(':') || undefined;
32
32
  }
33
33
  /** Build the single orchestrator session key for all Parall events. */
34
34
  export function buildOrchestratorSessionKey(accountId) {
@@ -1 +1 @@
1
- {"version":3,"file":"wiki-helper.d.ts","sourceRoot":"","sources":["../src/wiki-helper.ts"],"names":[],"mappings":"AAGA,KAAK,MAAM,GAAG;IACZ,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC,CAAC;AAEF,KAAK,qBAAqB,GAAG;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,KAAK,iBAAiB,GAAG;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC;AAqGF,wBAAsB,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAgD/F"}
1
+ {"version":3,"file":"wiki-helper.d.ts","sourceRoot":"","sources":["../src/wiki-helper.ts"],"names":[],"mappings":"AAGA,KAAK,MAAM,GAAG;IACZ,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC,CAAC;AAEF,KAAK,qBAAqB,GAAG;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,KAAK,iBAAiB,GAAG;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC;AA8GF,wBAAsB,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAoD/F"}
@@ -1,24 +1,24 @@
1
- import { spawn, spawnSync } from "node:child_process";
2
- import path from "node:path";
1
+ import { spawn, spawnSync } from 'node:child_process';
2
+ import path from 'node:path';
3
3
  const DEFAULT_SYNC_TIMEOUT_MS = 90_000; // includes npx cold-start download time
4
4
  const DEFAULT_WATCH_INTERVAL_SEC = 30;
5
5
  function isCommandMissing(error) {
6
- return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
6
+ return typeof error === 'object' && error !== null && 'code' in error && error.code === 'ENOENT';
7
7
  }
8
8
  // Prefer bare `parall` (globally installed in hosted images). Fall back to
9
9
  // npx for self-hosted environments that haven't installed @parall/cli yet.
10
10
  let _cli;
11
11
  function resolveParallCli() {
12
12
  if (!_cli) {
13
- const r = spawnSync("parall", ["--version"], { stdio: "ignore", timeout: 5_000 });
13
+ const r = spawnSync('parall', ['--version'], { stdio: 'ignore', timeout: 5_000 });
14
14
  _cli = r.error
15
- ? { cmd: "npx", prefix: ["--yes", "@parall/cli@latest"] }
16
- : { cmd: "parall", prefix: [] };
15
+ ? { cmd: 'npx', prefix: ['--yes', '@parall/cli@latest'] }
16
+ : { cmd: 'parall', prefix: [] };
17
17
  }
18
18
  return _cli;
19
19
  }
20
20
  function resolveMountRoot(stateDir) {
21
- return process.env.PRLL_WIKI_MOUNT_ROOT?.trim() || path.join(stateDir, "workspace");
21
+ return process.env.PRLL_WIKI_MOUNT_ROOT?.trim() || path.join(stateDir, 'workspace');
22
22
  }
23
23
  function resolveWatchIntervalSec() {
24
24
  const raw = process.env.PRLL_WIKI_REFRESH_INTERVAL_SEC?.trim();
@@ -43,9 +43,9 @@ async function runWikiSync(params, env) {
43
43
  let timedOut = false;
44
44
  let settled = false;
45
45
  const { cmd, prefix } = resolveParallCli();
46
- const child = spawn(cmd, [...prefix, "wiki", "sync"], {
46
+ const child = spawn(cmd, [...prefix, 'wiki', 'sync'], {
47
47
  env,
48
- stdio: "ignore",
48
+ stdio: 'ignore',
49
49
  });
50
50
  const settle = (value) => {
51
51
  if (settled)
@@ -56,33 +56,33 @@ async function runWikiSync(params, env) {
56
56
  const timer = setTimeout(() => {
57
57
  timedOut = true;
58
58
  params.log?.warn?.(`parall[${params.accountId}]: parall sync timed out after ${DEFAULT_SYNC_TIMEOUT_MS}ms`);
59
- child.kill("SIGTERM");
60
- setTimeout(() => child.kill("SIGKILL"), 5_000).unref();
59
+ child.kill('SIGTERM');
60
+ setTimeout(() => child.kill('SIGKILL'), 5_000).unref();
61
61
  }, DEFAULT_SYNC_TIMEOUT_MS);
62
62
  timer.unref();
63
- child.on("error", (error) => {
63
+ child.on('error', (error) => {
64
64
  clearTimeout(timer);
65
65
  if (isCommandMissing(error)) {
66
66
  params.log?.warn?.(`parall[${params.accountId}]: parall not installed, skipping wiki auto-sync/watch`);
67
- settle("missing");
67
+ settle('missing');
68
68
  return;
69
69
  }
70
70
  params.log?.warn?.(`parall[${params.accountId}]: parall sync failed to start: ${String(error)}`);
71
- settle("failed");
71
+ settle('failed');
72
72
  });
73
- child.on("exit", (code, signal) => {
73
+ child.on('exit', (code, signal) => {
74
74
  clearTimeout(timer);
75
75
  if (timedOut) {
76
- settle("failed");
76
+ settle('failed');
77
77
  return;
78
78
  }
79
79
  if (code === 0) {
80
80
  params.log?.info?.(`parall[${params.accountId}]: parall sync completed`);
81
- settle("ok");
81
+ settle('ok');
82
82
  return;
83
83
  }
84
- params.log?.warn?.(`parall[${params.accountId}]: parall sync exited with code=${code ?? "null"} signal=${signal ?? "null"}`);
85
- settle("failed");
84
+ params.log?.warn?.(`parall[${params.accountId}]: parall sync exited with code=${code ?? 'null'} signal=${signal ?? 'null'}`);
85
+ settle('failed');
86
86
  });
87
87
  });
88
88
  }
@@ -90,7 +90,7 @@ export async function startWikiHelper(params) {
90
90
  const mountRoot = resolveMountRoot(params.stateDir);
91
91
  const env = buildWikiHelperEnv(params, mountRoot);
92
92
  const syncResult = await runWikiSync(params, env);
93
- if (syncResult === "missing") {
93
+ if (syncResult === 'missing') {
94
94
  return {
95
95
  mountRoot,
96
96
  stop() { },
@@ -99,11 +99,11 @@ export async function startWikiHelper(params) {
99
99
  const intervalSec = resolveWatchIntervalSec();
100
100
  let stopped = false;
101
101
  const { cmd, prefix } = resolveParallCli();
102
- const watch = spawn(cmd, [...prefix, "wiki", "watch", "--interval-sec", String(intervalSec)], {
102
+ const watch = spawn(cmd, [...prefix, 'wiki', 'watch', '--interval-sec', String(intervalSec)], {
103
103
  env,
104
- stdio: "ignore",
104
+ stdio: 'ignore',
105
105
  });
106
- watch.on("error", (error) => {
106
+ watch.on('error', (error) => {
107
107
  if (stopped)
108
108
  return;
109
109
  if (isCommandMissing(error)) {
@@ -112,10 +112,10 @@ export async function startWikiHelper(params) {
112
112
  }
113
113
  params.log?.warn?.(`parall[${params.accountId}]: parall watch failed: ${String(error)}`);
114
114
  });
115
- watch.on("exit", (code, signal) => {
115
+ watch.on('exit', (code, signal) => {
116
116
  if (stopped)
117
117
  return;
118
- params.log?.warn?.(`parall[${params.accountId}]: parall watch exited with code=${code ?? "null"} signal=${signal ?? "null"}`);
118
+ params.log?.warn?.(`parall[${params.accountId}]: parall watch exited with code=${code ?? 'null'} signal=${signal ?? 'null'}`);
119
119
  });
120
120
  params.log?.info?.(`parall[${params.accountId}]: parall watch started (interval=${intervalSec}s)`);
121
121
  return {
@@ -123,8 +123,8 @@ export async function startWikiHelper(params) {
123
123
  stop() {
124
124
  stopped = true;
125
125
  if (watch.exitCode === null && watch.signalCode === null) {
126
- watch.kill("SIGTERM");
127
- setTimeout(() => watch.kill("SIGKILL"), 5_000).unref();
126
+ watch.kill('SIGTERM');
127
+ setTimeout(() => watch.kill('SIGKILL'), 5_000).unref();
128
128
  }
129
129
  },
130
130
  };
@@ -12,7 +12,10 @@
12
12
  "parall_url": { "type": "string", "description": "Parall API base URL" },
13
13
  "api_key": { "type": "string", "description": "Agent API key (agk_xxx)" },
14
14
  "org_id": { "type": "string", "description": "Organisation ID" },
15
- "ws_url": { "type": "string", "description": "WebSocket URL (optional, derived from parall_url)" }
15
+ "ws_url": {
16
+ "type": "string",
17
+ "description": "WebSocket URL (optional, derived from parall_url)"
18
+ }
16
19
  },
17
20
  "required": ["parall_url", "api_key", "org_id"]
18
21
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parall/parall",
3
- "version": "1.31.0",
3
+ "version": "1.32.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/sdk": "1.31.0",
20
- "@parall/agent-core": "1.31.0"
19
+ "@parall/sdk": "1.32.0",
20
+ "@parall/agent-core": "1.32.0"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@types/node": "^22.0.0",
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: parall-clips
3
+ description: "Parall clip operations: list installed clips, invoke clip commands, inspect clip details. Use when: the task requires external capabilities (GitHub, web search, etc.), user asks about available tools/clips, or you need to call a clip command."
4
+ ---
5
+
6
+ # Parall Clips
7
+
8
+ Clips are capability extensions — packaged toolkits that give you extra commands (e.g. GitHub operations, web search, code analysis). Clips installed in the org are available for any agent to invoke via the CLI.
9
+
10
+ ## Discovering available clips
11
+
12
+ ```bash
13
+ # List all clips installed in the org
14
+ parall clip list
15
+
16
+ # Show detailed info about a clip (manifest, commands, version)
17
+ parall clip info <alias>
18
+ ```
19
+
20
+ ## Invoking a clip command
21
+
22
+ ```bash
23
+ # Invoke a command on a clip by alias
24
+ parall clip invoke <alias> <command> [input]
25
+
26
+ # input is optional — when provided, it can be a JSON string or plain text
27
+ parall clip invoke github-tools list-repos '{"org": "acme"}'
28
+ parall clip invoke web-search search "latest Node.js LTS version"
29
+
30
+ # Custom timeout (default 30s)
31
+ parall clip invoke github-tools create-issue '{"title": "Bug report"}' --timeout 60000
32
+ ```
33
+
34
+ ## How clips work
35
+
36
+ 1. An org admin installs a clip from the Pinix registry or creates a custom one
37
+ 2. `parall clip list` shows every clip installed in the org
38
+ 3. You can only **invoke** clips that an admin has **bound to you** — invoking an unbound clip returns a "not bound" error. Ask an admin to bind the clip if you need it.
39
+ 4. Each clip exposes one or more named commands with typed input/output
40
+
41
+ ## When to use clips
42
+
43
+ - Check `parall clip list` when a task requires capabilities beyond your built-in tools (e.g. GitHub API, external services, specialized analysis)
44
+ - Use `parall clip info <alias>` to discover available commands and their expected input format
45
+ - If `parall clip invoke` reports the clip isn't bound to you, that clip exists in the org but hasn't been granted to you — ask an admin to bind it
46
+ - Clip invocations return JSON output on success or an error message on failure
47
+
48
+ CLI command results are JSON on stdout.
package/src/accounts.ts CHANGED
@@ -1,6 +1,6 @@
1
- import type { ResolvedParallAccount, ParallChannelConfig } from "./types.js";
1
+ import type { ResolvedParallAccount, ParallChannelConfig } from './types.js';
2
2
 
3
- const DEFAULT_ACCOUNT_ID = "default";
3
+ const DEFAULT_ACCOUNT_ID = 'default';
4
4
 
5
5
  type OpenClawConfig = Record<string, unknown>;
6
6
 
@@ -22,9 +22,9 @@ export function resolveParallAccount(params: {
22
22
  const { cfg, accountId = DEFAULT_ACCOUNT_ID } = params;
23
23
  const parallCfg = readParallConfig(cfg);
24
24
  const config: ParallChannelConfig = {
25
- parall_url: parallCfg?.parall_url ?? "",
26
- api_key: parallCfg?.api_key ?? "",
27
- org_id: parallCfg?.org_id ?? "",
25
+ parall_url: parallCfg?.parall_url ?? '',
26
+ api_key: parallCfg?.api_key ?? '',
27
+ org_id: parallCfg?.org_id ?? '',
28
28
  ws_url: parallCfg?.ws_url,
29
29
  enabled: parallCfg?.enabled,
30
30
  };
package/src/channel.ts CHANGED
@@ -1,23 +1,23 @@
1
- import type { ChannelPlugin } from "openclaw/plugin-sdk/core";
2
- import { listParallAccountIds, resolveParallAccount } from "./accounts.js";
3
- import { parallGateway } from "./gateway.js";
4
- import { parallOutbound } from "./outbound.js";
5
- import type { ResolvedParallAccount } from "./types.js";
1
+ import type { ChannelPlugin } from 'openclaw/plugin-sdk/core';
2
+ import { listParallAccountIds, resolveParallAccount } from './accounts.js';
3
+ import { parallGateway } from './gateway.js';
4
+ import { parallOutbound } from './outbound.js';
5
+ import type { ResolvedParallAccount } from './types.js';
6
6
 
7
- const meta: ChannelPlugin["meta"] = {
8
- id: "parall",
9
- label: "Parall",
10
- selectionLabel: "Parall IM",
11
- docsPath: "/channels/parall",
12
- blurb: "Agent-Native IM platform.",
7
+ const meta: ChannelPlugin['meta'] = {
8
+ id: 'parall',
9
+ label: 'Parall',
10
+ selectionLabel: 'Parall IM',
11
+ docsPath: '/channels/parall',
12
+ blurb: 'Agent-Native IM platform.',
13
13
  order: 80,
14
14
  };
15
15
 
16
16
  export const parallPlugin: ChannelPlugin<ResolvedParallAccount> = {
17
- id: "parall",
17
+ id: 'parall',
18
18
  meta,
19
19
  capabilities: {
20
- chatTypes: ["direct", "group"],
20
+ chatTypes: ['direct', 'group'],
21
21
  polls: false,
22
22
  threads: false,
23
23
  media: true,
@@ -27,7 +27,8 @@ export const parallPlugin: ChannelPlugin<ResolvedParallAccount> = {
27
27
  },
28
28
  config: {
29
29
  listAccountIds: (cfg) => listParallAccountIds(cfg),
30
- resolveAccount: (cfg, accountId) => resolveParallAccount({ cfg, accountId: accountId ?? undefined }),
30
+ resolveAccount: (cfg, accountId) =>
31
+ resolveParallAccount({ cfg, accountId: accountId ?? undefined }),
31
32
  isConfigured: (account) => account.configured,
32
33
  describeAccount: (account) => ({
33
34
  accountId: account.accountId,