@floomhq/signaldash 0.38.0 → 0.39.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/README.md CHANGED
@@ -102,7 +102,7 @@ setup installs both from the same pinned npm package
102
102
  the human chose to execute:
103
103
 
104
104
  ```bash
105
- npx -y @floomhq/signaldash@0.38.0 <invite-code>
105
+ npx -y @floomhq/signaldash@0.39.0 <invite-code>
106
106
  ```
107
107
 
108
108
  Run that command in a terminal, not in an agent chat. Do not ask an agent to
package/bin/sd.mjs CHANGED
@@ -351,6 +351,56 @@ const TOOLS = [
351
351
  additionalProperties: false,
352
352
  },
353
353
  },
354
+ {
355
+ name: "sd_content_pipeline_set", path: "/sd/content/set",
356
+ description: "Enable or disable the database-gated content pipeline. Enabling captures only new free text from the verified Secretary group. It never publishes or schedules a post.",
357
+ inputSchema: { type:"object",properties:{enabled:{type:"boolean"},confirm:{type:"boolean",const:true}},required:["enabled","confirm"],additionalProperties:false },
358
+ },
359
+ {
360
+ name: "sd_content_pipeline_list", path: "/sd/content/list",
361
+ description: "Read the durable idea to measured state machine with zero provider calls.",
362
+ inputSchema: { type:"object",properties:{state:{type:"string",enum:["all","idee","gepaart","entwurf","freigegeben","geplant","veroeffentlicht","gemessen"]},limit:{type:"integer",minimum:1,maximum:500}},additionalProperties:false },
363
+ },
364
+ {
365
+ name: "sd_content_pipeline_pair", path: "/sd/content/pair",
366
+ description: "Pair one Federico raw content input with one exact unused library post. Refuses arcs without stored source text, author, reactions, and comments.",
367
+ inputSchema: { type:"object",properties:{id:{type:"string"},arc_inspiration_id:{type:"string"},confirm:{type:"boolean",const:true}},required:["id","arc_inspiration_id","confirm"],additionalProperties:false },
368
+ },
369
+ {
370
+ name: "sd_content_pipeline_draft", path: "/sd/content/draft",
371
+ description: "Store one model-authored human-review draft with exactly one tested lever. Runs the executable fact gate and refuses silent weak-category drafts and unsupported agent numbers.",
372
+ inputSchema: { type:"object",properties:{id:{type:"string"},category:{type:"string",enum:["ereignis_mit_einsatz","innenschau"]},weak_category_decision:{type:"string",enum:["ereignis_vorangestellt","bewusst_reichweitenschwach"]},category_evidence:{type:"string",minLength:1,maxLength:500,description:"Required with ereignis_vorangestellt and must exactly start the draft."},tested_lever:{type:"string",minLength:1,maxLength:120},draft_text:{type:"string",minLength:1,maxLength:65536},numeric_claims:{type:"array",maxItems:100,items:{type:"object",properties:{value:{type:"string"},origin:{type:"string",enum:["federico_raw","agent"]},source:{type:"string"},confirmed_at:{type:"string"}},required:["value","origin"],additionalProperties:false}}},required:["id","category","tested_lever","draft_text"],additionalProperties:false },
373
+ },
374
+ {
375
+ name: "sd_content_pipeline_preview", path: "/sd/content/preview",
376
+ description: "Re-run the fact gate and render the exact reference metrics, Federico input, and finished draft as a PNG payload for the existing guarded WhatsApp attachment tool.",
377
+ inputSchema: { type:"object",properties:{id:{type:"string"}},required:["id"],additionalProperties:false },
378
+ },
379
+ {
380
+ name: "sd_content_pipeline_decide", path: "/sd/content/decide",
381
+ description: "Record Federico's exact yes, no, or correction response. Yes advances to approved but never schedules or publishes.",
382
+ inputSchema: { type:"object",properties:{id:{type:"string"},decision:{type:"string",enum:["yes","no","correction"]},correction:{type:"string"},decision_message_id:{type:"string",description:"Exact WhatsApp reply message id, when the decision came from the Secretary group."},confirm:{type:"boolean",const:true}},required:["id","decision","confirm"],additionalProperties:false },
383
+ },
384
+ {
385
+ name: "sd_content_pipeline_bind_schedule", path: "/sd/content/bind_schedule",
386
+ description: "Bind an already human-approved SignalDash scheduled post after a fresh complete SignalDash plus Buffer calendar read, fact gate, same-day, three-per-week, and active-post breathing checks.",
387
+ inputSchema: { type:"object",properties:{id:{type:"string"},scheduled_post_id:{type:"string"},scheduled_at:{type:"string",format:"date-time"},confirm:{type:"boolean",const:true}},required:["id","scheduled_post_id","scheduled_at","confirm"],additionalProperties:false },
388
+ },
389
+ {
390
+ name: "sd_content_pipeline_published", path: "/sd/content/published",
391
+ description: "Bind one planned item to exact provider publication evidence. This records evidence and publishes nothing.",
392
+ inputSchema: { type:"object",properties:{id:{type:"string"},post_urn:{type:"string",pattern:"^urn:li:(activity|ugcPost|share):[0-9]+$"},published_at:{type:"string",format:"date-time"},confirm:{type:"boolean",const:true}},required:["id","post_urn","published_at","confirm"],additionalProperties:false },
393
+ },
394
+ {
395
+ name: "sd_content_pipeline_measure", path: "/sd/content/measure",
396
+ description: "Store one due 24-hour or 72-hour provider measurement against Federico's own category baseline and emit a lever learning report at each five-post boundary.",
397
+ inputSchema: { type:"object",properties:{id:{type:"string"},window_hours:{type:"integer",enum:[24,72]},reactions:{type:"integer",minimum:0},comments:{type:"integer",minimum:0},impressions:{type:"integer",minimum:0},provider_evidence:{type:"object",properties:{source:{type:"string",const:"li_my_posts"},post_urn:{type:"string",pattern:"^urn:li:(activity|ugcPost|share):[0-9]+$"},captured_at:{type:"string",format:"date-time"},reactions:{type:"integer",minimum:0},comments:{type:"integer",minimum:0},impressions:{type:"integer",minimum:0}},required:["source","post_urn","captured_at","reactions","comments"],additionalProperties:true}},required:["id","window_hours","reactions","comments","provider_evidence"],additionalProperties:false },
398
+ },
399
+ {
400
+ name: "sd_content_board", path: "/sd/content/board",
401
+ description: "Generate the static board HTML from the same pipeline and stored shared-calendar rows. Makes zero provider calls.",
402
+ inputSchema: { type:"object",properties:{},additionalProperties:false },
403
+ },
354
404
  {
355
405
  name: "sd_inspiration_list",
356
406
  path: "/sd/inspiration/list",
@@ -1516,6 +1566,7 @@ const TOOLS = [
1516
1566
  text: { type: "string", minLength: 1, maxLength: 3000 },
1517
1567
  publish: { type: "boolean" },
1518
1568
  scheduled_at: { type: "string", format: "date-time" },
1569
+ content_pipeline_id: { type: "string", minLength: 1, maxLength: 200 },
1519
1570
  first_comment: { type: "string", minLength: 1, maxLength: 1250 },
1520
1571
  mentions: {
1521
1572
  type: "array", maxItems: 20,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floomhq/signaldash",
3
- "version": "0.38.0",
3
+ "version": "0.39.0",
4
4
  "description": "Secure LinkedIn, WhatsApp, and email access for AI agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,7 +18,7 @@
18
18
  },
19
19
  "scripts": {
20
20
  "test": "node --test",
21
- "check": "node --check bin/sd.mjs && node --check server/server.cjs && node --check server/buffer-calendar.cjs && node --check server/composio-email.cjs && node --check server/attachments.cjs && node --check server/write-control.cjs && node --check server/secretary-store.cjs && node --check server/secretary-collector.cjs && node --check server/secretary-latest.cjs && node --check server/secretary-approvals.cjs && node --check server/secretary-push.cjs && node --check server/secretary-rules.cjs && node --check server/secretary-shadow-gate.cjs && node --check server/secretary-vault-importer.cjs && node --check server/secretary-inspiration.cjs && node --check server/linkedin-archive-importer.cjs && node --check server/voice-profile.cjs && node --check server/campaign-store.cjs && node --check server/campaign-runner.cjs && node --check server/withdrawal-store.cjs && node --check server/post-scheduler.cjs && node --check server/message-scheduler.cjs && node --check scripts/import-linkedin-archive.mjs && node --check scripts/import-secretary-vault-snapshot.mjs && node --check scripts/rebuild-secretary-actors.mjs && node --check scripts/extract-conversation-inspiration.mjs && node --check bin/signaldash.js && node --check lib/cli.js && node --check lib/config-file.js && node --check lib/mcp.js && node --check lib/rate-guard.js && node --check lib/secrets.js && node --check lib/unipile.js"
21
+ "check": "node --check bin/sd.mjs && node --check server/server.cjs && node --check server/content-pipeline.cjs && node --check server/buffer-calendar.cjs && node --check server/composio-email.cjs && node --check server/attachments.cjs && node --check server/write-control.cjs && node --check server/secretary-store.cjs && node --check server/secretary-collector.cjs && node --check server/secretary-latest.cjs && node --check server/secretary-approvals.cjs && node --check server/secretary-push.cjs && node --check server/secretary-rules.cjs && node --check server/secretary-shadow-gate.cjs && node --check server/secretary-vault-importer.cjs && node --check server/secretary-inspiration.cjs && node --check server/linkedin-archive-importer.cjs && node --check server/voice-profile.cjs && node --check server/campaign-store.cjs && node --check server/campaign-runner.cjs && node --check server/withdrawal-store.cjs && node --check server/post-scheduler.cjs && node --check server/message-scheduler.cjs && node --check scripts/import-linkedin-archive.mjs && node --check scripts/import-secretary-vault-snapshot.mjs && node --check scripts/rebuild-secretary-actors.mjs && node --check scripts/extract-conversation-inspiration.mjs && node --check scripts/render-content-board.mjs && node --check bin/signaldash.js && node --check lib/cli.js && node --check lib/config-file.js && node --check lib/mcp.js && node --check lib/rate-guard.js && node --check lib/secrets.js && node --check lib/unipile.js"
22
22
  },
23
23
  "keywords": [
24
24
  "mcp",
@@ -0,0 +1,58 @@
1
+ ---
2
+ name: content
3
+ description: Turn Federico's raw content ideas into measured LinkedIn experiments through the SignalDash content pipeline. Load before writing any post for Federico.
4
+ ---
5
+
6
+ # Federico content pipeline
7
+
8
+ Use SignalDash states in order: `idee`, `gepaart`, `entwurf`, `freigegeben`,
9
+ `geplant`, `veroeffentlicht`, `gemessen`. Never skip a state. Never publish or
10
+ schedule without Federico approving the exact final text and time.
11
+
12
+ ## Rules that decide the draft
13
+
14
+ - Category beats form. Lead with an event carrying real stakes. Introspection
15
+ either gets an event first or is labelled `bewusst_reichweitenschwach`.
16
+ - Word count is noise. Federico's top and bottom groups both average 10.2
17
+ words. Do not optimize length as a reach lever.
18
+ - Every post has exactly two inputs: Federico's own provable material and one
19
+ foreign library post with stored author, exact text, reactions, and comments.
20
+ An unproved arc is refused.
21
+ - Change exactly one tested lever per post. Store it with the draft.
22
+ - Measure at 24 and 72 hours against Federico's category baseline, never a
23
+ foreign benchmark: events with stakes 139 to 435 reactions, introspection 7
24
+ to 39.
25
+ - Treat question versus opinion endings and reply timing as hypotheses, not
26
+ rules. A test changes one of them while the rest stays stable.
27
+
28
+ ## Operating flow
29
+
30
+ 1. Read `sd_content_pipeline_list` and `sd_inspiration_list`.
31
+ 2. Pair the idea with one evidenced unused arc using
32
+ `sd_content_pipeline_pair`.
33
+ 3. Draft in Federico's raw voice. Call `sd_content_pipeline_draft` with one
34
+ category and one lever. For `innenschau`, pass the exact opening event as
35
+ `category_evidence` or mark it `bewusst_reichweitenschwach`. SignalDash
36
+ verifies the opening and renders either choice. The server then runs
37
+ `/root/secretary-build/fact_gate.py`. A refusal stops the flow.
38
+ 4. Call `sd_content_pipeline_preview`. Send its exact PNG to the returned
39
+ Secretary `chat_id` through the existing WhatsApp read and attachment path.
40
+ Do not send a link or file reference. Federico replies yes, no, or with one
41
+ correction.
42
+ 5. Record the response with `sd_content_pipeline_decide`, including the exact
43
+ WhatsApp `decision_message_id`. A correction returns the item to `gepaart`,
44
+ stays visible on the item, and requires a new fact-gated draft and image.
45
+ 6. Before planning, call `li_scheduled_posts` and inspect SignalDash, Buffer,
46
+ and native LinkedIn completeness. Create the exact approved schedule only
47
+ through `li_draft_post` with the exact `content_pipeline_id`. SignalDash
48
+ binds it in the same request only after the preflight passes. Same-day
49
+ conflicts, three posts in one week, and a post above baseline inside its
50
+ two-day breathing window refuse before a schedule row exists.
51
+ 7. Record exact publication evidence, then read the live own post at 24 and 72
52
+ hours and pass its reactions, comments, impressions, and provider evidence
53
+ to `sd_content_pipeline_measure`. The evidence must name `li_my_posts`, the
54
+ exact post URN and capture time, and repeat the exact submitted metrics.
55
+
56
+ Federico-origin numbers that the fact gate does not know need one simple
57
+ confirmation and a dated source row in `/root/secretary-build/FAKTEN.md`.
58
+ Agent-added numbers without a source are removed, never rationalized.
@@ -370,6 +370,16 @@ Use the exact tool names and argument keys below. Limits are optional.
370
370
  | `sd_inspiration_import` | `source` exact LinkedIn post URL or URN; optional source author, Federico note, purpose, content kind, credit fields, and format description | Migration/manual capture through Unipile's documented post retrieval endpoint. The primary capture path remains pasting a URL into the verified Secretary WhatsApp group. |
371
371
  | `sd_inspiration_channel_configure` | exact `chat_id`, `provider_id`, `chat_name`, and `confirm:true` | Re-prove the connected WhatsApp account and exact group in the live chat list, then enable automatic URL capture and same-group acknowledgements. Never substitute a self-chat. |
372
372
  | `sd_inspiration_channel_set` | `capture_enabled` and `confirm:true` | Disable or re-enable capture and acknowledgements through the database kill switch without a deploy. |
373
+ | `sd_content_pipeline_set` | `enabled` and `confirm:true` | Enable capture from this instant or disable the complete content pipeline through its database flag. It never publishes. |
374
+ | `sd_content_pipeline_list` | optional `state` and `limit` | Read every durable stage from idea through measured with zero provider calls. |
375
+ | `sd_content_pipeline_pair` | `id`, exact `arc_inspiration_id`, `confirm:true` | Bind Federico raw material to one complete unused foreign post carrying real author, text, reaction, and comment evidence. |
376
+ | `sd_content_pipeline_draft` | `id`, category, one `tested_lever`, exact `draft_text`; weak-category decision, exact opening `category_evidence`, and numeric claims when applicable | Verify an asserted event is the actual draft opening, then run the executable fact and authorship gates before a draft is stored. |
377
+ | `sd_content_pipeline_preview` | `id` | Re-run the fact gate and render the exact arc metrics, content input, and draft as a PNG for the guarded WhatsApp attachment path. |
378
+ | `sd_content_pipeline_decide` | `id`, `decision`, optional correction, exact WhatsApp `decision_message_id`, `confirm:true` | Record Federico's yes, no, or correction. A correction returns to paired state for a new fact-gated image. Yes approves but does not schedule or publish. |
379
+ | `sd_content_pipeline_bind_schedule` | `id`, `scheduled_post_id`, `scheduled_at`, `confirm:true` | Bind an existing approved SignalDash schedule after fresh SignalDash plus Buffer calendar, frequency, same-day, fact, and breathing gates. |
380
+ | `sd_content_pipeline_published` | `id`, exact post URN and publish time, `confirm:true` | Record publication evidence without publishing anything. |
381
+ | `sd_content_pipeline_measure` | `id`, 24 or 72 hours, live metrics, provider evidence | Compare the live result with Federico's category baseline and emit lever learning every five posts. |
382
+ | `sd_content_board` | no arguments | Render board HTML from the same pipeline and stored shared-calendar rows with zero provider calls. |
373
383
  | `sd_secretary_approve` | `disposition_id` required; `payload_hash` required exact 64-character hash from latest; `confirm:true` required | Create one single-use, 15-minute receipt for the exact current stored draft. It derives the sender and executable payload from storage. |
374
384
  | `sd_secretary_reject` | `disposition_id` required; `confirm:true` required | Reject one exact current stored draft. It sends nothing. |
375
385
  | `li_list_chats` | `limit` integer 1-100, default 20; `cursor` optional; `search` optional string, max 200 characters; `max_scan` optional integer 1-500; `unread` optional boolean | Find recent LinkedIn chats, unread counts, and exact `chat_id` values. `unread:true` is forwarded to the provider as `unread=true`; SignalDash does not fetch a full chat page and filter it locally. Search accepts a unique stored display name, exact `public_id`, member id, or ordinary chat field. A stored name/public id is resolved to its verified member id before matching, so a provider row with `name:null` remains findable. Without an explicit `max_scan`, a zero-match search extends from 200 up to a hard 500-chat/five-page bound; explicit bounds remain exact. Read `scanned_chats`, `pages_fetched`, `scan_limit`, and `exhaustive` before concluding absence. The response also reports any resolved public/member ids. Any other key, including `text` and `member_id`, is refused with `unsupported_parameter` rather than accepted and ignored. |
@@ -421,7 +431,7 @@ Use the exact tool names and argument keys below. Limits are optional.
421
431
  | `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. |
422
432
  | `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 post-delete absence. This cannot undo delivery, reading, or notifications and never relaxes a send gate. |
423
433
  | `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. |
424
- | `li_draft_post` | `text` required, max 3000; `publish` optional; `scheduled_at` optional offset-qualified ISO date-time; `mentions` optional array of up to 20 exact `{name,profile_id}` objects; `attachments` optional array of up to 4 exact `{filename,content_type,content_base64}` images; `first_comment` optional, max 1250 | Create a server-confirmed draft, publish now, or persist an exact future LinkedIn post and its approved first comment. A schedule is stored only with `publish:true` after approval of the exact text, time, mentions, images, and comment. |
434
+ | `li_draft_post` | `text` required, max 3000; `publish` optional; `scheduled_at` optional offset-qualified ISO date-time; `content_pipeline_id` required for scheduling while that user's pipeline is enabled; `mentions` optional array of up to 20 exact `{name,profile_id}` objects; `attachments` optional array of up to 4 exact `{filename,content_type,content_base64}` images; `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 runs its fact, exact-text, shared-calendar, frequency, and breathing preflight before the schedule row is created. |
425
435
  | `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. |
426
436
  | `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. |
427
437
  | `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. |