@floomhq/signaldash 0.39.6 → 0.39.7
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/README.md +5 -5
- package/bin/sd.mjs +27 -9
- package/package.json +1 -1
- package/skills/signaldash/SKILL.md +28 -24
package/README.md
CHANGED
|
@@ -120,7 +120,7 @@ setup installs both from the same pinned npm package
|
|
|
120
120
|
the human chose to execute:
|
|
121
121
|
|
|
122
122
|
```bash
|
|
123
|
-
npx -y @floomhq/signaldash@0.39.
|
|
123
|
+
npx -y @floomhq/signaldash@0.39.7 <invite-code>
|
|
124
124
|
```
|
|
125
125
|
|
|
126
126
|
Run that command in a terminal, not in an agent chat. Do not ask an agent to
|
|
@@ -168,7 +168,7 @@ SignalDash exposes:
|
|
|
168
168
|
- `li_create_invitation_batch(source_label, time_zone, targets)`
|
|
169
169
|
- `li_get_invitation_batch(batch_id)`
|
|
170
170
|
- `li_cancel_invitation_batch(batch_id, approval_view_hash, confirm)`
|
|
171
|
-
- `sd_campaign_create(source_label, time_zone, messages
|
|
171
|
+
- `sd_campaign_create(source_label, time_zone, messages?, target_source?, targets?, engagers?, invite_ttl_days?)`
|
|
172
172
|
- `sd_campaign_preview(campaign_id)`
|
|
173
173
|
- `sd_campaign_approve(campaign_id, confirm_token)`
|
|
174
174
|
- `sd_campaign_status(campaign_id)`
|
|
@@ -587,9 +587,9 @@ messaging. Campaign invitations require a valid sender IANA timezone, run only
|
|
|
587
587
|
Monday through Friday from 09:00 to 17:00 sender-local time, and reserve a new
|
|
588
588
|
90–180 second per-sender pacing interval atomically with every attempted
|
|
589
589
|
action. Timing is checked before final provider preflight and again during the
|
|
590
|
-
write reservation. Downtime never creates a catch-up burst.
|
|
591
|
-
|
|
592
|
-
|
|
590
|
+
write reservation. Downtime never creates a catch-up burst. A campaign can be
|
|
591
|
+
connect-only or carry an exact human-approved acceptance-triggered sequence.
|
|
592
|
+
User-selected future start dates and recurring schedules are not exposed.
|
|
593
593
|
|
|
594
594
|
Deleting a WhatsApp message is a write, and an irreversible one, so it is
|
|
595
595
|
treated as such. SignalDash proves the chat belongs to the connected account,
|
package/bin/sd.mjs
CHANGED
|
@@ -133,6 +133,24 @@ export async function api(
|
|
|
133
133
|
) {
|
|
134
134
|
json.approval_url = new URL(json.approval_path, targetBackend).toString();
|
|
135
135
|
}
|
|
136
|
+
// The batch magic link gets the same rebase for the same reason: the backend
|
|
137
|
+
// stamps its own configured public origin, but the human has to open the
|
|
138
|
+
// host THIS client is actually talking to. Rebasing only the path keeps the
|
|
139
|
+
// token intact and never logs it; leaving it alone would hand a self-hosted
|
|
140
|
+
// user a link pointing at somebody else's deployment.
|
|
141
|
+
if (
|
|
142
|
+
json &&
|
|
143
|
+
typeof json === "object" &&
|
|
144
|
+
typeof json.approval_link === "string" &&
|
|
145
|
+
json.approval_link
|
|
146
|
+
) {
|
|
147
|
+
try {
|
|
148
|
+
json.approval_link = new URL(
|
|
149
|
+
new URL(json.approval_link).pathname,
|
|
150
|
+
targetBackend,
|
|
151
|
+
).toString();
|
|
152
|
+
} catch {}
|
|
153
|
+
}
|
|
136
154
|
return { status: r.status, json };
|
|
137
155
|
}
|
|
138
156
|
|
|
@@ -980,7 +998,7 @@ const TOOLS = [
|
|
|
980
998
|
{
|
|
981
999
|
name: "sd_campaign_create",
|
|
982
1000
|
path: "/sd/campaign/create",
|
|
983
|
-
description: "Create one campaign: a paced connection request to each exact person,
|
|
1001
|
+
description: "Create one campaign: a paced connection request to each exact person, optionally followed by exact approved message(s) once that person is PROVEN to have accepted. Omit messages or pass an empty array for a connect-only campaign; no message ever follows. Nothing is sent until a human approves the exact recipient list and actions on the approval page. Targets come from an explicit list you supply (for example one you built with li_search_connections or li_post_reactions) or from your own post engagers, which costs zero profile fetches. If the user already sent someone a connection request by hand and wants an approved follow-up automated, set adopt_existing_invitation on that target instead of leaving them out. When messages are present, draft them in the user's own voice and keep them short: the on-acceptance group is 2-3 separate short sends, never one block.",
|
|
984
1002
|
inputSchema: {
|
|
985
1003
|
type: "object",
|
|
986
1004
|
properties: {
|
|
@@ -1036,9 +1054,9 @@ const TOOLS = [
|
|
|
1036
1054
|
},
|
|
1037
1055
|
messages: {
|
|
1038
1056
|
type: "array",
|
|
1039
|
-
minItems:
|
|
1057
|
+
minItems: 0,
|
|
1040
1058
|
maxItems: 5,
|
|
1041
|
-
description: "
|
|
1059
|
+
description: "Optional exact frozen texts. Empty means connect-only and no message ever follows. after_days 0 means sent once the invitation is accepted (1-3 of these, sent as separate consecutive messages); a later step needs after_days 1-30 and only goes out if there has been no reply.",
|
|
1042
1060
|
items: {
|
|
1043
1061
|
type: "object",
|
|
1044
1062
|
properties: {
|
|
@@ -1057,7 +1075,7 @@ const TOOLS = [
|
|
|
1057
1075
|
description: "An invitation not accepted within this many days is dropped and never messaged.",
|
|
1058
1076
|
},
|
|
1059
1077
|
},
|
|
1060
|
-
required: ["source_label", "time_zone"
|
|
1078
|
+
required: ["source_label", "time_zone"],
|
|
1061
1079
|
additionalProperties: false,
|
|
1062
1080
|
},
|
|
1063
1081
|
},
|
|
@@ -1609,7 +1627,7 @@ const TOOLS = [
|
|
|
1609
1627
|
{
|
|
1610
1628
|
name: "li_draft_post",
|
|
1611
1629
|
path: "/li/create_post",
|
|
1612
|
-
description: "Draft, publish, or schedule a LinkedIn post. Scheduling requires an offset-qualified scheduled_at plus publish:true after exact human approval. When the content pipeline is enabled, use an approved content_pipeline_id or preview one exact reasoned content_pipeline_override and repeat it with confirm:true plus its single-use approval_hash. Optional mentions, base64 image attachments, and an account-owner-authored first_comment are preserved for the scheduled publish.",
|
|
1630
|
+
description: "Draft, publish, or schedule a LinkedIn post. Scheduling requires an offset-qualified scheduled_at plus publish:true after exact human approval. When the content pipeline is enabled, use an approved content_pipeline_id or preview one exact reasoned content_pipeline_override and repeat it with confirm:true plus its single-use approval_hash. Optional mentions, up to 20 base64 image attachments, and an account-owner-authored first_comment are preserved for the scheduled publish.",
|
|
1613
1631
|
inputSchema: {
|
|
1614
1632
|
type: "object",
|
|
1615
1633
|
properties: {
|
|
@@ -1629,7 +1647,7 @@ const TOOLS = [
|
|
|
1629
1647
|
},
|
|
1630
1648
|
first_comment: { type: "string", minLength: 1, maxLength: 1250 },
|
|
1631
1649
|
mentions: {
|
|
1632
|
-
type: "array", maxItems:
|
|
1650
|
+
type: "array", maxItems: 25,
|
|
1633
1651
|
items: {
|
|
1634
1652
|
type: "object",
|
|
1635
1653
|
properties: {
|
|
@@ -1640,7 +1658,7 @@ const TOOLS = [
|
|
|
1640
1658
|
},
|
|
1641
1659
|
},
|
|
1642
1660
|
attachments: {
|
|
1643
|
-
type: "array", maxItems:
|
|
1661
|
+
type: "array", maxItems: 20,
|
|
1644
1662
|
items: {
|
|
1645
1663
|
type: "object",
|
|
1646
1664
|
properties: {
|
|
@@ -1701,7 +1719,7 @@ const TOOLS = [
|
|
|
1701
1719
|
text: { type: "string", minLength: 1, maxLength: 3000 },
|
|
1702
1720
|
scheduled_at: { type: "string", format: "date-time" },
|
|
1703
1721
|
mentions: {
|
|
1704
|
-
type: "array", maxItems:
|
|
1722
|
+
type: "array", maxItems: 25,
|
|
1705
1723
|
items: {
|
|
1706
1724
|
type: "object",
|
|
1707
1725
|
properties: {
|
|
@@ -1713,7 +1731,7 @@ const TOOLS = [
|
|
|
1713
1731
|
},
|
|
1714
1732
|
},
|
|
1715
1733
|
attachments: {
|
|
1716
|
-
type: "array", maxItems:
|
|
1734
|
+
type: "array", maxItems: 20,
|
|
1717
1735
|
items: {
|
|
1718
1736
|
type: "object",
|
|
1719
1737
|
properties: {
|
package/package.json
CHANGED
|
@@ -420,7 +420,7 @@ Use the exact tool names and argument keys below. Limits are optional.
|
|
|
420
420
|
| `li_create_invitation_batch` | `source_label` required exact string, max 120 code points; `time_zone` required IANA timezone; `targets` required array of 1-10 exact `{profile_url,inclusion_reason,note?}` objects; reason max 240 and note max 200 Unicode code points | Create one immutable durable preview from canonical LinkedIn Classic `/in/` URLs. The agent structures an explicit human request; the server never generates targets or text. |
|
|
421
421
|
| `li_get_invitation_batch` | `batch_id` required | Inspect every stored target, exact note, exclusion, hash, timing, capacity, and result. Use the returned browser review path for human approval. This read also authorizes a later exact cancel. |
|
|
422
422
|
| `li_cancel_invitation_batch` | `batch_id` required; `approval_view_hash` required string or null exactly as inspected; `confirm:true` required | Permanently cancel unstarted targets in one freshly inspected batch. It cannot recall an executing invitation, and restarting requires a new preview and approval. |
|
|
423
|
-
| `sd_campaign_create` | `source_label` required, max 120 code points; `time_zone` required IANA timezone; `messages`
|
|
423
|
+
| `sd_campaign_create` | `source_label` required, max 120 code points; `time_zone` required IANA timezone; `messages` optional array of 0-5 exact `{text,after_days?}` objects, text max 1200 code points; omit it or pass `[]` for connect-only; `target_source` optional (`explicit` default or `post_engagers`); `targets` array of up to 150 `{profile_url?,provider_id?,inclusion_reason,note?,display_name?,headline?,adopt_existing_invitation?}` for `explicit` (at most 10 adopted targets per campaign, and an adopted target may not carry a `note`); `engagers` object with `post_limit` 1-10, `max_targets` 1-150, `inclusion_reason`, `note` for `post_engagers`; `invite_ttl_days` optional 1-60, default 21 | Create one campaign: a connection request to each exact person, optionally followed by exact approved messages after proven acceptance. A connect-only campaign completes after its invitations and never watches acceptance or sends a message. The server never generates a target or a word of text. Nothing is sent before human approval. |
|
|
424
424
|
| `sd_campaign_preview` | `campaign_id` required | Inspect every exact recipient, every exclusion and reason, the exact text of every message step, the timing, the invitation and existing-thread message lanes, the aggregate brake, and the `approval_url` to hand the human. This read also authorizes a later exact cancel. |
|
|
425
425
|
| `sd_campaign_approve` | `campaign_id` required; `confirm_token` required in the exact `sd-xxxx-xxxx-xxxx` form the human read off the approval page | Record the human's approval using the single-use code that authenticated page minted for them. An agent cannot mint, guess, or bypass that code. |
|
|
426
426
|
| `sd_campaign_status` | `campaign_id` required | Monitor per person: invited, acceptance proven, messaged, replied and halted, expired, or excluded, plus every message step and any provider response SignalDash could not parse. |
|
|
@@ -448,11 +448,11 @@ Use the exact tool names and argument keys below. Limits are optional.
|
|
|
448
448
|
| `li_like_comment` | `post_id`, `parent_comment_id`, and `comment_id` required; `expected_watermark` optional exact 64-character watermark | Like once one exact inbound comment on this sender's own post after `li_post_comments`. SignalDash re-proves post ownership, the unchanged comment, its author and parent, no own like, sender generation, budget, and provider health immediately before writing. A 2xx is not success until bounded readback finds exactly one own like. |
|
|
449
449
|
| `li_delete_message` | `chat_id`, `message_id`, and `confirm:true` required | Remediate one exact own LinkedIn message within 60 minutes of sending. SignalDash proves account, exact chat, own authorship, timestamp eligibility, a separate remediation budget, and the provider's post-delete state. Success requires `deleted:1` or a genuine 404. A present row or failed readback returns `502 deleted_unconfirmed`, locks the sender, and is never retried automatically. This cannot undo delivery, reading, or notifications and never relaxes a send gate. |
|
|
450
450
|
| `li_delete_comment` | `post_id`, `comment_id`, and `confirm:true` required | Currently unavailable: the fixture-tested Unipile v2 wrapper is held at database capability state `untested` until live compatibility is proved against Federico's own removable comment. When enabled it proves own comment identity and readback. Deletion is remediation, not rollback. |
|
|
451
|
-
| `li_draft_post` | `text` required, max 3000; `publish` optional; `scheduled_at` optional offset-qualified ISO date-time; `content_pipeline_id` normally required for scheduling while that user's pipeline is enabled; `content_pipeline_override` optional exact `{reason,confirm?,approval_hash?}`; `mentions` optional array of up to
|
|
451
|
+
| `li_draft_post` | `text` required, max 3000; `publish` optional; `scheduled_at` optional offset-qualified ISO date-time; `content_pipeline_id` normally required for scheduling while that user's pipeline is enabled; `content_pipeline_override` optional exact `{reason,confirm?,approval_hash?}`; `mentions` optional array of up to 25 exact `{name,profile_id}` objects; `attachments` optional array of up to 20 exact `{filename,content_type,content_base64}` images, max 5 MiB each and 12 MiB total; `first_comment` optional, max 1250 | Create a server-confirmed draft, publish now, or persist an exact future LinkedIn post and its approved first comment. An enabled pipeline normally runs its fact, exact-text, shared-calendar, frequency, and breathing preflight. For one deliberate exception, preview the exact payload with `{reason}`, show it to the human, then repeat it with `confirm:true` and the returned single-use payload-bound `approval_hash`. The audit record preserves the reason, preview ID, and approval time; every non-pipeline provider safety guard remains active. |
|
|
452
452
|
| `li_set_scheduled_post_first_comment` | `id` required UUID; `first_comment` required, max 1250; `confirm:true` required | Attach one exact approved first comment to a scheduled post. SignalDash publishes it through the same connected account after the post and never republishes the post if the comment fails. |
|
|
453
453
|
| `li_scheduled_posts` | no arguments | Read one shared content-calendar view across SignalDash and the configured Buffer LinkedIn channel. Inspect `completeness` and every `sources.*.state` before treating absence as an empty calendar. Native LinkedIn scheduled posts and drafts are invisible because Unipile has no documented read route for them; SignalDash does not use raw Voyager routes or linkedin.com browser access. An empty `items` array proves only that the visible sources returned no entries. |
|
|
454
454
|
| `li_scheduled_post_preview` | `id` required UUID | Create a short-lived, single-use `https://signaldash.dev/p/<token>` browser handoff for one exact active SignalDash post. The isolated page includes its stored image attachments through account- and post-scoped protected media routes. |
|
|
455
|
-
| `li_edit_scheduled_post` | `id`, `text`, and offset-qualified `scheduled_at` required; full replacement `mentions
|
|
455
|
+
| `li_edit_scheduled_post` | `id`, `text`, and offset-qualified `scheduled_at` required; full replacement `mentions` (up to 25), image `attachments` (up to 20, max 5 MiB each and 12 MiB total), and `first_comment` optional; confirmation repeats the identical payload with `confirm:true`, `approval_hash`, `expected_version`, and `expected_updated_at` from preview | Atomically replace one scheduled post in place. The UUID, creation time, provider account, and content-pipeline audit fields remain unchanged. A changed or non-scheduled row is refused, approval is single-use and expires, and no provider call occurs. Omitting an optional replacement field clears it. Duplicate identity covers the complete normalized payload, including exact attachment bytes, and only active scheduled or executing rows participate; cancelled history never blocks a replacement. |
|
|
456
456
|
| `li_cancel_scheduled_post` | `id` required UUID; `confirm:true` required | Cancel one exact post while it is still scheduled. It cannot recall an executing or published post. |
|
|
457
457
|
| `sd_schedule_message` | `channel` required, `whatsapp` or `linkedin`; `chat_id` required, max 500; `text` required, max 5000; `scheduled_at` required offset-qualified ISO date-time from 60 seconds to 365 days ahead; `confirm:true` required | Schedule one exact message into one chat you have already read. Read that exact chat first, at `limit` 10 or more on LinkedIn: SignalDash records what the thread looked like and refuses at send time if the conversation moved. Text only; attachments are refused rather than dropped. One message at one time, never a sequence. |
|
|
458
458
|
| `sd_scheduled_messages` | `state` optional, one of `scheduled`, `executing`, `sent`, `cancelled`, `failed`, `needs_review`; `channel` optional | List only this authenticated user's scheduled messages and their durable states. Returns every matching row, unpaginated, and always reports `needs_review_count` outside your filter. |
|
|
@@ -833,11 +833,12 @@ eligible to run. SignalDash limits are not LinkedIn-safe thresholds, and
|
|
|
833
833
|
native LinkedIn activity can still race the final reads.
|
|
834
834
|
|
|
835
835
|
|
|
836
|
-
###
|
|
836
|
+
### Human-approved campaigns
|
|
837
837
|
|
|
838
|
-
A campaign
|
|
839
|
-
message
|
|
840
|
-
|
|
838
|
+
A campaign sends a connection request and may stop there. When it has an
|
|
839
|
+
approved message sequence, SignalDash continues only after acceptance is
|
|
840
|
+
proven and acts only on the exact text a human read and approved. A connect-only
|
|
841
|
+
campaign never watches acceptance and completes after its invitations are sent.
|
|
841
842
|
|
|
842
843
|
What the server proves, and refuses to assume:
|
|
843
844
|
|
|
@@ -866,16 +867,17 @@ What the server proves, and refuses to assume:
|
|
|
866
867
|
|
|
867
868
|
Use the campaign tools in this order:
|
|
868
869
|
|
|
869
|
-
1. Get the exact people and the
|
|
870
|
-
|
|
871
|
-
|
|
870
|
+
1. Get the exact people and whether the campaign is connect-only. For a message
|
|
871
|
+
campaign, get the exact words from the human. Draft the messages in the
|
|
872
|
+
user's own voice and keep them short: the on-acceptance group is two or
|
|
873
|
+
three separate sends, never one block. Never invent a recipient or a
|
|
872
874
|
sentence. Ask whether they already sent any of these people a connection
|
|
873
|
-
request themselves;
|
|
874
|
-
instead of dropping them.
|
|
875
|
+
request themselves; for a message campaign, mark that target
|
|
876
|
+
`adopt_existing_invitation` instead of dropping them.
|
|
875
877
|
2. Call `sd_campaign_create` once.
|
|
876
878
|
3. Poll `sd_campaign_preview` until the campaign is `previewed` or terminal.
|
|
877
|
-
Show the human every recipient, every exclusion and its reason, and
|
|
878
|
-
text of every message step.
|
|
879
|
+
Show the human every recipient, every exclusion and its reason, and either
|
|
880
|
+
the exact text of every message step or the explicit connect-only statement.
|
|
879
881
|
4. Relay the returned `approval_url`. The human authenticates with the
|
|
880
882
|
SignalDash invite credential, reads the rows, ticks the recipients they
|
|
881
883
|
approve (none are preselected), and acknowledges the consequences. They then
|
|
@@ -884,8 +886,10 @@ Use the campaign tools in this order:
|
|
|
884
886
|
bearer token cannot approve, and you cannot mint that code. Five failed
|
|
885
887
|
credential attempts durably block that campaign's authentication surface for
|
|
886
888
|
15 minutes.
|
|
887
|
-
5. Watch progress with `sd_campaign_status`.
|
|
888
|
-
|
|
889
|
+
5. Watch progress with `sd_campaign_status`. A connect-only campaign completes
|
|
890
|
+
after its invitations are sent. For a message campaign, report acceptances,
|
|
891
|
+
replies, exclusions, and parse failures honestly, including people who never
|
|
892
|
+
accepted.
|
|
889
893
|
6. To stop, inspect first, show the exact state and `approval_view_hash`, obtain
|
|
890
894
|
cancellation approval, then call `sd_campaign_cancel` once with that hash and
|
|
891
895
|
`confirm:true`.
|
|
@@ -918,14 +922,14 @@ them out. It inverts one check and nothing else:
|
|
|
918
922
|
- at most 10 adopted targets per campaign: each one costs one profile read in
|
|
919
923
|
the preview to resolve its provider id.
|
|
920
924
|
|
|
921
|
-
|
|
922
|
-
proven only by a fresh profile read showing a
|
|
923
|
-
messages still need their own approval on the
|
|
924
|
-
read before the first message, and anything in
|
|
925
|
-
send halts the sequence permanently. If the
|
|
926
|
-
note without accepting, that conversation
|
|
927
|
-
dropped with `existing_conversation`: it is a
|
|
928
|
-
not a campaign to resume.
|
|
925
|
+
For a campaign with messages, everything after that is identical to any other
|
|
926
|
+
target. Acceptance is still proven only by a fresh profile read showing a
|
|
927
|
+
connected network distance, the messages still need their own approval on the
|
|
928
|
+
same page, the thread is still read before the first message, and anything in
|
|
929
|
+
that thread the campaign did not send halts the sequence permanently. If the
|
|
930
|
+
recipient answered the invitation note without accepting, that conversation
|
|
931
|
+
already exists and the target is dropped with `existing_conversation`: it is a
|
|
932
|
+
human conversation in progress, not a campaign to resume.
|
|
929
933
|
|
|
930
934
|
The acceptance window (`invite_ttl_days`) for an adopted target is counted from
|
|
931
935
|
the moment SignalDash adopts it, not from the hand-sent invitation, whose age
|