bereach-openclaw 0.2.16 → 0.2.17

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "bereach",
3
3
  "name": "BeReach",
4
- "version": "0.2.16",
4
+ "version": "0.2.17",
5
5
  "description": "LinkedIn outreach automation — 33 tools, auto-reply commands",
6
6
  "configSchema": {
7
7
  "type": "object",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bereach-openclaw",
3
- "version": "0.2.16",
3
+ "version": "0.2.17",
4
4
  "description": "BeReach LinkedIn automation plugin for OpenClaw",
5
5
  "license": "AGPL-3.0",
6
6
  "scripts": {
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: bereach
3
3
  description: "Automate LinkedIn outreach via BeReach (berea.ch). Use when: prospecting, engaging posts, scraping engagement, searching LinkedIn, managing inbox, running campaigns, managing invitations. Requires BEREACH_API_KEY."
4
- lastUpdatedAt: 1772673508
4
+ lastUpdatedAt: 1772678140
5
5
  metadata: { "openclaw": { "requires": { "env": ["BEREACH_API_KEY"] }, "primaryEnv": "BEREACH_API_KEY" } }
6
6
  ---
7
7
 
@@ -17,7 +17,7 @@ Automate LinkedIn prospection and engagement via BeReach.
17
17
 
18
18
  | Sub-skill | Keywords | URL | lastUpdatedAt |
19
19
  | --------------------- | ------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ------------- |
20
- | Lead Magnet | lead magnet, comment to DM, resource delivery, post giveaway, auto-accept invitations, scheduled run, recap, campaign stats, pause | sub/lead-magnet.md | 1772673508 |
20
+ | Lead Magnet | lead magnet, comment to DM, resource delivery, post giveaway, auto-accept invitations, scheduled run, recap, campaign stats, pause | sub/lead-magnet.md | 1772678140 |
21
21
  | OpenClaw Optimization | openclaw, model, opus, sonnet, haiku, config, SOUL.md, heartbeat, prompt caching, AI cost reduction, /model | openclaw-optimization.md | 1772619338 |
22
22
  | SDK Reference | sdk, method, parameter, signature, reference, api, script | sdk-reference.md | 1772672714 |
23
23
 
@@ -81,9 +81,13 @@ The SDK auto-reads `BEREACH_API_KEY` from the environment. NEVER hardcode tokens
81
81
 
82
82
  - Lead magnet scripts use the SDK. Tools are for interactive agent use only.
83
83
  - Import from the `bereach` SDK exclusively. If a method doesn't exist, the operation doesn't exist.
84
- - Scripts MUST be TypeScript (`.ts`). Run with `npx tsx script.ts`.
85
- - Run `npx tsc --noEmit` before executing to catch type errors.
86
- - Load the [SDK Reference](sdk-reference.md) sub-skill for method signatures.
84
+ - Scripts MUST be TypeScript (`.ts`). Load the [SDK Reference](sdk-reference.md) sub-skill for method signatures.
85
+
86
+ **Mandatory validation loop** after generating or editing any script:
87
+
88
+ 1. Run `npx tsc --noEmit` in the script directory. If type errors: fix them using the SDK Reference, then repeat.
89
+ 2. Run `npx tsx <script-name>.ts` — fix runtime errors (e.g. "linkedinInbox is not defined", "visitProfile is not a function"). If config missing, run with minimal env to reach first SDK call.
90
+ 3. Only after both pass: consider the script ready.
87
91
 
88
92
  ### Always
89
93
 
@@ -139,7 +143,7 @@ More workflows coming soon. You can build your own using the SDK methods and too
139
143
 
140
144
  Crons are OpenClaw scheduled tasks. Create entries in `~/.openclaw/cron/jobs.json` (via `openclaw cron add`).
141
145
 
142
- **Lead Magnet** — 3 global crons. Config at `~/.openclaw/lead-magnet.json`. Each cron runs one script that loops over all enabled campaigns:
146
+ **Lead Magnet** — 3 global crons. Campaign config at `~/.bereach/lead-magnet.json`. Each cron runs one script that loops over all enabled campaigns:
143
147
 
144
148
  ```json
145
149
  { "id": "lm-comments", "every": "1h", "skill": "bereach", "sessionTarget": "spawn", "prompt": "Run lm-comments.ts and report recap" }
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: bereach-lead-magnet
3
3
  description: "Lead magnet workflow — deliver a resource to everyone who engages with a LinkedIn post."
4
- lastUpdatedAt: 1772673508
4
+ lastUpdatedAt: 1772678140
5
5
  ---
6
6
 
7
7
  # BeReach Lead Magnet Skill
@@ -16,6 +16,14 @@ Requires [BeReach SKILL.md](SKILL.md) (constraints, SDK setup, anti-hallucinatio
16
16
 
17
17
  All lead magnet scripts MUST be TypeScript using the `bereach` SDK (see main skill for SDK setup and rules).
18
18
 
19
+ **Always use full SDK paths** — e.g. `client.linkedinChat.findConversation`, `client.linkedinScrapers.visitProfile`. Never infer the resource from method name alone (e.g. "inbox" ≠ linkedinInbox; "visit" ≠ linkedinActions.visitProfile).
20
+
21
+ **Validation loop (mandatory)** — after writing each script:
22
+
23
+ 1. `npx tsc --noEmit` — fix any type errors using SDK Reference.
24
+ 2. `npx tsx <script-name>.ts` — fix any runtime errors (e.g. undefined method, wrong resource). If config is missing, run with minimal env to at least reach the first SDK call.
25
+ 3. Repeat until both pass. Only then save or paste the script.
26
+
19
27
  ## Tone
20
28
 
21
29
  All script output and chatbot messages are **for the end user**. Write like you're talking to a non-technical person. Never mention internal concepts like "Track A", "Layer 2", "DM guard", "server-side dedup", "retryAfter", "URN", "O(1) lookup", etc. The campaign slug is fine to show — it helps the user know which campaign is running. Just say what happened in plain language: "Sent the resource to 12 people", "Skipped 3 (already received it)", "Outside active hours, will resume at 7:00".
@@ -129,7 +137,7 @@ For each campaign (from config): scrape commenters and engage them.
129
137
  2. **Fetch**: `collectComments` with `campaignSlug` → response: `profiles[]` (NOT "comments"). Paginate: while `hasMore`, increment `start` by `count`.
130
138
  3. Each profile has: `profileUrl`, `commentUrn`, `name`, `profileUrn`, `actionsCompleted: { message, reply, like, visit, connect }`, `knownDistance`, `hasReplyFromPostAuthor`
131
139
  4. For each profile (skip own URN, skip `actionsCompleted.message === true`):
132
- a. If `knownDistance` is set, use it (skip visit, saves 1 credit). Otherwise: `visitProfile` with `campaignSlug` → `memberDistance`, `pendingConnection`
140
+ a. If `knownDistance` is set, use it (skip visit, saves 1 credit). Otherwise: `client.linkedinScrapers.visitProfile` with `{ profile, campaignSlug }` → `memberDistance`, `pendingConnection`
133
141
  b. Distance 1:
134
142
  - **DM dedup** (see "DM dedup" section): check both layers. If either says "already sent", skip. Otherwise: `sendMessage` with `campaignSlug`.
135
143
  - Skip reply if `actionsCompleted.reply === true` or `hasReplyFromPostAuthor === true`. Otherwise: `replyToComment` with `commentUrn` and `campaignSlug`
@@ -147,7 +155,7 @@ Accept pending invitations and deliver the resource to campaign-related invitees
147
155
  - **Campaign attribution**: `listInvitations` returns ALL pending invitations. Cross-reference each inviter against campaign commenter lists to find which campaign (if any) they belong to. Accept all invitations, but only DM if campaign-matched.
148
156
  - For each invitation:
149
157
  1. `acceptInvitation` with `invitationId` and `sharedSecret`
150
- 2. If campaign matched: `visitProfile` with matched `campaignSlug`, then **DM dedup** → DM if not already sent.
158
+ 2. If campaign matched: `client.linkedinScrapers.visitProfile` with `{ profile, campaignSlug }`, then **DM dedup** → DM if not already sent.
151
159
  3. If no campaign match (organic invitation): accept only, no DM.
152
160
 
153
161
  ### Script 3 — New connections
@@ -156,7 +164,7 @@ For each campaign (from config): check if distance 2+ commenters have now connec
156
164
 
157
165
  - Re-fetch commenters: `collectComments` with `campaignSlug` — paginate all
158
166
  - Filter: `actionsCompleted.message === false` and `knownDistance > 1` (skip profiles where `knownDistance` is null — they haven't been visited yet and belong to Script 1)
159
- - For each: `visitProfile` with `campaignSlug` → check `memberDistance` and `pendingConnection`
167
+ - For each: `client.linkedinScrapers.visitProfile` with `{ profile, campaignSlug }` → check `memberDistance` and `pendingConnection`
160
168
  - `memberDistance === 1`: **DM dedup** (see "DM dedup" section) → DM the resource if not already sent.
161
169
  - `pendingConnection === "pending"`: not connected yet, skip
162
170
 
@@ -172,7 +180,7 @@ Check in order. If either says "already sent", skip the DM.
172
180
 
173
181
  **Layer 1 — `actionsCompleted.message`** (free, within campaign). Already checked in the script loop — `true` → skip.
174
182
 
175
- **Layer 2 — `/find` inbox lookup** (0 credits, cross-campaign). Only when `resourceLink` is set. Call `findConversation` with `includeMessages: true` → `{ found, messages }`. `messages` is at the **top level**, not nested. If any message text contains `resourceLink`: skip DM, call `syncActions` to mark done. If found but no link in messages: pass `messages` as context for DM tone adaptation. The function must return both skip decision and messages.
183
+ **Layer 2 — DM guard** (0 credits, cross-campaign). Only when `resourceLink` is set. Call `client.linkedinChat.findConversation` with `{ profile, includeMessages: true }` → `{ found, messages }`. `messages` is at the **top level**, not nested. If any message text contains `resourceLink`: skip DM, call `client.campaigns.syncActions` to mark done. If found but no link in messages: pass `messages` as context for DM tone adaptation. The function must return both skip decision and messages.
176
184
 
177
185
  **Fail-safe**: if `findConversation` errors or all retries fail, **skip this profile** — do NOT send the DM. A failed lookup treated as "not found" causes duplicates. The profile will be retried next run.
178
186
 
@@ -206,7 +214,7 @@ Follow pacing rules from the main skill (Constraints #2). No exceptions — slee
206
214
 
207
215
  ## Cron
208
216
 
209
- Three global crons. Config at `~/.openclaw/lead-magnet.json`. Each cron runs one script that loops over all enabled campaigns.
217
+ Three global crons. Campaign config at `~/.bereach/lead-magnet.json`. Each cron runs one script that loops over all enabled campaigns.
210
218
 
211
219
  All crons MUST use `"sessionTarget": "spawn"` to avoid blocking the main session. Each spawned sub-agent runs the script independently and pushes the recap back to the user when done.
212
220