dashclaw 1.8.0 → 1.8.1

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 (3) hide show
  1. package/README.md +642 -1
  2. package/dashclaw.js +316 -8
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Full reference for the DashClaw SDK (Node.js). For Python, see the [Python SDK docs](../sdk-python/README.md).
4
4
 
5
- Install, configure, and instrument your AI agents with 78+ methods across action recording, behavior guard, context management, session handoffs, security scanning, policy testing, compliance, task routing, and more.
5
+ Install, configure, and instrument your AI agents with 95+ methods across 21+ categories including action recording, behavior guard, context management, session handoffs, security scanning, agent messaging, agent pairing, identity binding, organization management, webhooks, policy testing, compliance, task routing, and more.
6
6
 
7
7
  ---
8
8
 
@@ -239,6 +239,54 @@ Stream actions live to the dashboard as they happen.
239
239
 
240
240
  ---
241
241
 
242
+ ## Real-Time Events
243
+
244
+ Subscribe to server-sent events (SSE) for instant push notifications. Eliminates polling for approvals, policy changes, and task assignments.
245
+
246
+ ### claw.events()
247
+
248
+ Open a persistent SSE connection. Returns a chainable handle with `.on(event, callback)` and `.close()`.
249
+
250
+ **Supported events:** `action.created`, `action.updated`, `message.created`, `policy.updated`, `task.assigned`, `task.completed`
251
+
252
+ ```javascript
253
+ const stream = claw.events();
254
+
255
+ stream
256
+ .on('action.created', (data) => console.log('New action:', data.action_id))
257
+ .on('action.updated', (data) => {
258
+ if (data.status === 'running') console.log('Approved:', data.action_id);
259
+ })
260
+ .on('policy.updated', (data) => console.log('Policy changed:', data.change_type))
261
+ .on('task.assigned', (data) => console.log('Task routed:', data.task?.title))
262
+ .on('task.completed', (data) => console.log('Task done:', data.task?.task_id))
263
+ .on('error', (err) => console.error('Stream error:', err));
264
+
265
+ // When done:
266
+ stream.close();
267
+ ```
268
+
269
+ ### claw.waitForApproval(actionId, { useEvents: true })
270
+
271
+ SSE-powered approval waiting — resolves instantly when the operator approves/denies instead of polling every 5 seconds.
272
+
273
+ ```javascript
274
+ // SSE mode (instant, recommended)
275
+ const { action } = await claw.waitForApproval('act_abc', { useEvents: true });
276
+
277
+ // Polling mode (default, backward-compatible)
278
+ const { action } = await claw.waitForApproval('act_abc');
279
+ ```
280
+
281
+ | Parameter | Type | Default | Description |
282
+ |-----------|------|---------|-------------|
283
+ | actionId | string | — | Action ID to watch |
284
+ | options.timeout | number | 300000 | Max wait time (ms) |
285
+ | options.interval | number | 5000 | Poll interval (polling mode only) |
286
+ | options.useEvents | boolean | false | Use SSE instead of polling |
287
+
288
+ ---
289
+
242
290
  ## Token & Cost Analytics
243
291
 
244
292
  Track token usage and estimated costs for every action. DashClaw automatically aggregates these into "Cost per Goal" metrics.
@@ -412,6 +460,20 @@ Retrieve recent guard evaluation decisions for audit and review.
412
460
 
413
461
  Push data from your agent directly to the DashClaw dashboard. All methods auto-attach the agent's agentId.
414
462
 
463
+ ### claw.reportTokenUsage(usage)
464
+ Report a token usage snapshot for this agent.
465
+
466
+ **Parameters:**
467
+ | Parameter | Type | Required | Description |
468
+ |-----------|------|----------|-------------|
469
+ | tokens_in | number | Yes | Input tokens consumed |
470
+ | tokens_out | number | Yes | Output tokens generated |
471
+ | context_used | number | No | Context window tokens used |
472
+ | context_max | number | No | Context window max capacity |
473
+ | model | string | No | Model name |
474
+
475
+ **Returns:** `Promise<{snapshot: Object}>`
476
+
415
477
  ### claw.recordDecision(entry)
416
478
  Record a decision for the learning database. Track what your agent decides and why.
417
479
 
@@ -543,6 +605,47 @@ Report active connections/integrations for this agent.
543
605
 
544
606
  **Returns:** `Promise<{ connections: Object[], created: number }>`
545
607
 
608
+ ### claw.createCalendarEvent(event)
609
+ Create a calendar event.
610
+
611
+ **Parameters:**
612
+ | Parameter | Type | Required | Description |
613
+ |-----------|------|----------|-------------|
614
+ | summary | string | Yes | Event title/summary |
615
+ | start_time | string | Yes | Start time (ISO string) |
616
+ | end_time | string | No | End time (ISO string) |
617
+ | location | string | No | Event location |
618
+ | description | string | No | Event description |
619
+
620
+ **Returns:** `Promise<{event: Object}>`
621
+
622
+ ### claw.recordIdea(idea)
623
+ Record an idea or inspiration for later review.
624
+
625
+ **Parameters:**
626
+ | Parameter | Type | Required | Description |
627
+ |-----------|------|----------|-------------|
628
+ | title | string | Yes | Idea title |
629
+ | description | string | No | Detailed description |
630
+ | category | string | No | Category |
631
+ | score | number | No | Priority/quality score 0-100 |
632
+ | status | string | No | "pending", "in_progress", "shipped", "rejected" |
633
+ | source | string | No | Where this idea came from |
634
+
635
+ **Returns:** `Promise<{idea: Object}>`
636
+
637
+ ### claw.reportMemoryHealth(report)
638
+ Report a memory health snapshot with entities and topics.
639
+
640
+ **Parameters:**
641
+ | Parameter | Type | Required | Description |
642
+ |-----------|------|----------|-------------|
643
+ | health | Object | Yes | Health metrics (must include `score` 0-100) |
644
+ | entities | Object[] | No | Key entities found in memory |
645
+ | topics | Object[] | No | Topics/themes found in memory |
646
+
647
+ **Returns:** `Promise<{snapshot: Object, entities_count: number, topics_count: number}>`
648
+
546
649
  ---
547
650
 
548
651
  ## Session Handoffs
@@ -573,6 +676,20 @@ Get handoffs for this agent with optional date and limit filters.
573
676
 
574
677
  **Returns:** `Promise<{handoffs: Object[], total: number}>`
575
678
 
679
+ ### claw.getLatestHandoff()
680
+ Get the most recent handoff for this agent. Useful for resuming context at the start of a new session.
681
+
682
+ **Returns:** `Promise<{handoff: Object|null}>`
683
+
684
+ **Example:**
685
+ ```javascript
686
+ const { handoff } = await claw.getLatestHandoff();
687
+ if (handoff) {
688
+ console.log('Last session:', handoff.summary);
689
+ console.log('Next priorities:', handoff.next_priorities);
690
+ }
691
+ ```
692
+
576
693
  ---
577
694
 
578
695
  ## Context Manager
@@ -603,9 +720,63 @@ Create a context thread for tracking a topic across multiple entries.
603
720
 
604
721
  **Returns:** `Promise<{thread: Object, thread_id: string}>`
605
722
 
723
+ ### claw.getKeyPoints(filters?)
724
+ Get key points with optional filters.
725
+
726
+ **Parameters:**
727
+ | Parameter | Type | Required | Description |
728
+ |-----------|------|----------|-------------|
729
+ | category | string | No | Filter by category: decision, task, insight, question, general |
730
+ | session_date | string | No | Filter by date (YYYY-MM-DD) |
731
+ | limit | number | No | Max results |
732
+
733
+ **Returns:** `Promise<{points: Object[], total: number}>`
734
+
606
735
  ### claw.addThreadEntry(threadId, content, entryType?)
607
736
  Add an entry to an existing thread.
608
737
 
738
+ **Parameters:**
739
+ | Parameter | Type | Required | Description |
740
+ |-----------|------|----------|-------------|
741
+ | threadId | string | Yes | The thread ID |
742
+ | content | string | Yes | Entry content |
743
+ | entryType | string | No | Entry type (default: "note") |
744
+
745
+ **Returns:** `Promise<{entry: Object, entry_id: string}>`
746
+
747
+ ### claw.closeThread(threadId, summary?)
748
+ Close a context thread with an optional final summary.
749
+
750
+ **Parameters:**
751
+ | Parameter | Type | Required | Description |
752
+ |-----------|------|----------|-------------|
753
+ | threadId | string | Yes | The thread ID to close |
754
+ | summary | string | No | Final summary for the thread |
755
+
756
+ **Returns:** `Promise<{thread: Object}>`
757
+
758
+ ### claw.getThreads(filters?)
759
+ Get context threads with optional filters.
760
+
761
+ **Parameters:**
762
+ | Parameter | Type | Required | Description |
763
+ |-----------|------|----------|-------------|
764
+ | status | string | No | Filter by status: active, closed |
765
+ | limit | number | No | Max results |
766
+
767
+ **Returns:** `Promise<{threads: Object[], total: number}>`
768
+
769
+ ### claw.getContextSummary()
770
+ Get a combined context summary containing today's key points and all active threads. Convenience method that calls `getKeyPoints()` and `getThreads()` in parallel.
771
+
772
+ **Returns:** `Promise<{points: Object[], threads: Object[]}>`
773
+
774
+ **Example:**
775
+ ```javascript
776
+ const { points, threads } = await claw.getContextSummary();
777
+ console.log(`${points.length} key points today, ${threads.length} active threads`);
778
+ ```
779
+
609
780
  ---
610
781
 
611
782
  ## Automation Snippets
@@ -702,6 +873,144 @@ await claw.deleteSnippet('sn_abc123');
702
873
 
703
874
  ---
704
875
 
876
+ ## User Preferences
877
+
878
+ Track user observations, learned preferences, mood/energy, and approach effectiveness across sessions.
879
+
880
+ ### claw.logObservation(obs)
881
+ Log a user observation (what you noticed about the user's behavior or preferences).
882
+
883
+ **Parameters:**
884
+ | Parameter | Type | Required | Description |
885
+ |-----------|------|----------|-------------|
886
+ | observation | string | Yes | The observation text |
887
+ | category | string | No | Category tag |
888
+ | importance | number | No | Importance 1-10 |
889
+
890
+ **Returns:** `Promise<{observation: Object, observation_id: string}>`
891
+
892
+ **Example:**
893
+ ```javascript
894
+ await claw.logObservation({
895
+ observation: 'User prefers concise responses over detailed explanations',
896
+ category: 'communication',
897
+ importance: 8,
898
+ });
899
+ ```
900
+
901
+ ### claw.setPreference(pref)
902
+ Set a learned user preference. Use this to record patterns you detect about how the user likes to work.
903
+
904
+ **Parameters:**
905
+ | Parameter | Type | Required | Description |
906
+ |-----------|------|----------|-------------|
907
+ | preference | string | Yes | The preference description |
908
+ | category | string | No | Category tag |
909
+ | confidence | number | No | Confidence 0-100 |
910
+
911
+ **Returns:** `Promise<{preference: Object, preference_id: string}>`
912
+
913
+ ### claw.logMood(entry)
914
+ Log user mood/energy for a session. Helps track patterns in productivity and satisfaction.
915
+
916
+ **Parameters:**
917
+ | Parameter | Type | Required | Description |
918
+ |-----------|------|----------|-------------|
919
+ | mood | string | Yes | Mood description (e.g., "focused", "frustrated") |
920
+ | energy | string | No | Energy level (e.g., "high", "low") |
921
+ | notes | string | No | Additional notes |
922
+
923
+ **Returns:** `Promise<{mood: Object, mood_id: string}>`
924
+
925
+ ### claw.trackApproach(entry)
926
+ Track an approach and whether it succeeded or failed. Builds a knowledge base of what works.
927
+
928
+ **Parameters:**
929
+ | Parameter | Type | Required | Description |
930
+ |-----------|------|----------|-------------|
931
+ | approach | string | Yes | The approach description |
932
+ | context | string | No | Context for when to use this approach |
933
+ | success | boolean | No | true = worked, false = failed, undefined = just recording |
934
+
935
+ **Returns:** `Promise<{approach: Object, approach_id: string}>`
936
+
937
+ ### claw.getPreferenceSummary()
938
+ Get a summary of all user preference data including observations, preferences, moods, and approaches.
939
+
940
+ **Returns:** `Promise<{summary: Object}>`
941
+
942
+ ### claw.getApproaches(filters?)
943
+ Get tracked approaches with success/fail counts.
944
+
945
+ **Parameters:**
946
+ | Parameter | Type | Required | Description |
947
+ |-----------|------|----------|-------------|
948
+ | limit | number | No | Max results |
949
+
950
+ **Returns:** `Promise<{approaches: Object[], total: number}>`
951
+
952
+ ---
953
+
954
+ ## Daily Digest
955
+
956
+ ### claw.getDailyDigest(date?)
957
+ Get a daily activity digest aggregated from all data sources (actions, decisions, handoffs, context, etc.).
958
+
959
+ **Parameters:**
960
+ | Parameter | Type | Required | Description |
961
+ |-----------|------|----------|-------------|
962
+ | date | string | No | Date string YYYY-MM-DD (defaults to today) |
963
+
964
+ **Returns:** `Promise<{date: string, digest: Object, summary: Object}>`
965
+
966
+ **Example:**
967
+ ```javascript
968
+ const { digest, summary } = await claw.getDailyDigest('2025-01-15');
969
+ console.log(`Actions: ${summary.actions_count}, Decisions: ${summary.decisions_count}`);
970
+ ```
971
+
972
+ ---
973
+
974
+ ## Security Scanning
975
+
976
+ Scan text for sensitive data before sending it anywhere. The scanner detects API keys, tokens, PII, and other secrets.
977
+
978
+ ### claw.scanContent(text, destination?)
979
+ Scan text for sensitive data. Returns findings and redacted text. Does NOT store the original content.
980
+
981
+ **Parameters:**
982
+ | Parameter | Type | Required | Description |
983
+ |-----------|------|----------|-------------|
984
+ | text | string | Yes | Text to scan |
985
+ | destination | string | No | Where this text is headed (for context) |
986
+
987
+ **Returns:** `Promise<{clean: boolean, findings_count: number, findings: Object[], redacted_text: string}>`
988
+
989
+ **Example:**
990
+ ```javascript
991
+ const result = await claw.scanContent(
992
+ 'Deploy with key sk-abc123xyz to production',
993
+ 'slack'
994
+ );
995
+ if (!result.clean) {
996
+ console.log(`Found ${result.findings_count} issues`);
997
+ console.log('Safe version:', result.redacted_text);
998
+ }
999
+ ```
1000
+
1001
+ ### claw.reportSecurityFinding(text, destination?)
1002
+ Scan text and store finding metadata for audit trails. The original content is never stored, only the finding metadata.
1003
+
1004
+ **Parameters:**
1005
+ | Parameter | Type | Required | Description |
1006
+ |-----------|------|----------|-------------|
1007
+ | text | string | Yes | Text to scan |
1008
+ | destination | string | No | Where this text is headed |
1009
+
1010
+ **Returns:** `Promise<{clean: boolean, findings_count: number, findings: Object[], redacted_text: string}>`
1011
+
1012
+ ---
1013
+
705
1014
  ## Agent Messaging
706
1015
 
707
1016
  ### claw.sendMessage(params)
@@ -720,9 +1029,298 @@ Send a message to another agent or broadcast.
720
1029
 
721
1030
  **Returns:** `Promise<{message: Object, message_id: string}>`
722
1031
 
1032
+ ### claw.getInbox(params?)
1033
+ Get inbox messages for this agent.
1034
+
1035
+ **Parameters:**
1036
+ | Parameter | Type | Required | Description |
1037
+ |-----------|------|----------|-------------|
1038
+ | type | string | No | Filter by message type |
1039
+ | unread | boolean | No | Only unread messages |
1040
+ | threadId | string | No | Filter by thread |
1041
+ | limit | number | No | Max messages to return (default: 50) |
1042
+
1043
+ **Returns:** `Promise<{messages: Object[], total: number, unread_count: number}>`
1044
+
1045
+ ### claw.markRead(messageIds)
1046
+ Mark messages as read.
1047
+
1048
+ **Parameters:**
1049
+ | Parameter | Type | Required | Description |
1050
+ |-----------|------|----------|-------------|
1051
+ | messageIds | string[] | Yes | Array of message IDs to mark read |
1052
+
1053
+ **Returns:** `Promise<{updated: number}>`
1054
+
1055
+ ### claw.archiveMessages(messageIds)
1056
+ Archive messages.
1057
+
1058
+ **Parameters:**
1059
+ | Parameter | Type | Required | Description |
1060
+ |-----------|------|----------|-------------|
1061
+ | messageIds | string[] | Yes | Array of message IDs to archive |
1062
+
1063
+ **Returns:** `Promise<{updated: number}>`
1064
+
1065
+ ### claw.broadcast(params)
1066
+ Broadcast a message to all agents in the organization.
1067
+
1068
+ **Parameters:**
1069
+ | Parameter | Type | Required | Description |
1070
+ |-----------|------|----------|-------------|
1071
+ | type | string | No | Message type (default: "info") |
1072
+ | subject | string | No | Subject line |
1073
+ | body | string | Yes | Message body |
1074
+ | threadId | string | No | Thread ID |
1075
+
1076
+ **Returns:** `Promise<{message: Object, message_id: string}>`
1077
+
1078
+ ### claw.createMessageThread(params)
1079
+ Create a new message thread for multi-turn conversations between agents.
1080
+
1081
+ **Parameters:**
1082
+ | Parameter | Type | Required | Description |
1083
+ |-----------|------|----------|-------------|
1084
+ | name | string | Yes | Thread name |
1085
+ | participants | string[] | No | Agent IDs (null = open to all) |
1086
+
1087
+ **Returns:** `Promise<{thread: Object, thread_id: string}>`
1088
+
1089
+ ### claw.getMessageThreads(params?)
1090
+ List message threads.
1091
+
1092
+ **Parameters:**
1093
+ | Parameter | Type | Required | Description |
1094
+ |-----------|------|----------|-------------|
1095
+ | status | string | No | Filter by status: open, resolved, archived |
1096
+ | limit | number | No | Max threads to return (default: 20) |
1097
+
1098
+ **Returns:** `Promise<{threads: Object[], total: number}>`
1099
+
1100
+ ### claw.resolveMessageThread(threadId, summary?)
1101
+ Resolve (close) a message thread with an optional summary.
1102
+
1103
+ **Parameters:**
1104
+ | Parameter | Type | Required | Description |
1105
+ |-----------|------|----------|-------------|
1106
+ | threadId | string | Yes | Thread ID to resolve |
1107
+ | summary | string | No | Resolution summary |
1108
+
1109
+ **Returns:** `Promise<{thread: Object}>`
1110
+
723
1111
  ### claw.saveSharedDoc(params)
724
1112
  Create or update a shared workspace document. Upserts by name.
725
1113
 
1114
+ **Parameters:**
1115
+ | Parameter | Type | Required | Description |
1116
+ |-----------|------|----------|-------------|
1117
+ | name | string | Yes | Document name (unique per org) |
1118
+ | content | string | Yes | Document content |
1119
+
1120
+ **Returns:** `Promise<{doc: Object, doc_id: string}>`
1121
+
1122
+ ---
1123
+
1124
+ ## Agent Pairing
1125
+
1126
+ Pair agents with user accounts via public key registration and approval flow.
1127
+
1128
+ ### claw.createPairing(options)
1129
+ Create an agent pairing request. Returns a link the user can click to approve the pairing.
1130
+
1131
+ **Parameters:**
1132
+ | Parameter | Type | Required | Description |
1133
+ |-----------|------|----------|-------------|
1134
+ | publicKeyPem | string | Yes | PEM public key (SPKI format) to register for this agent |
1135
+ | algorithm | string | No | Signing algorithm (default: "RSASSA-PKCS1-v1_5") |
1136
+ | agentName | string | No | Agent name override |
1137
+
1138
+ **Returns:** `Promise<{pairing: Object, pairing_url: string}>`
1139
+
1140
+ ### claw.createPairingFromPrivateJwk(privateJwk, options?)
1141
+ Convenience method that derives the public PEM from a private JWK and creates a pairing request.
1142
+
1143
+ **Parameters:**
1144
+ | Parameter | Type | Required | Description |
1145
+ |-----------|------|----------|-------------|
1146
+ | privateJwk | Object | Yes | Private key in JWK format |
1147
+ | options.agentName | string | No | Agent name override |
1148
+
1149
+ **Returns:** `Promise<{pairing: Object, pairing_url: string}>`
1150
+
1151
+ ### claw.waitForPairing(pairingId, options?)
1152
+ Poll a pairing request until it is approved or expired.
1153
+
1154
+ **Parameters:**
1155
+ | Parameter | Type | Required | Description |
1156
+ |-----------|------|----------|-------------|
1157
+ | pairingId | string | Yes | The pairing ID to poll |
1158
+ | options.timeout | number | No | Max wait time in ms (default: 300000 / 5 min) |
1159
+ | options.interval | number | No | Poll interval in ms (default: 2000) |
1160
+
1161
+ **Returns:** `Promise<Object>` (the approved pairing object)
1162
+
1163
+ **Throws:** `Error` if pairing expires or times out.
1164
+
1165
+ **Example:**
1166
+ ```javascript
1167
+ const { pairing, pairing_url } = await claw.createPairing({
1168
+ publicKeyPem: myPublicKeyPem,
1169
+ });
1170
+ console.log('Approve pairing at:', pairing_url);
1171
+
1172
+ const approved = await claw.waitForPairing(pairing.id);
1173
+ console.log('Pairing approved!', approved.status);
1174
+ ```
1175
+
1176
+ ---
1177
+
1178
+ ## Identity Binding
1179
+
1180
+ Register and manage agent public keys for cryptographic identity verification.
1181
+
1182
+ ### claw.registerIdentity(identity)
1183
+ Register or update an agent's public key for identity verification. Requires admin API key.
1184
+
1185
+ **Parameters:**
1186
+ | Parameter | Type | Required | Description |
1187
+ |-----------|------|----------|-------------|
1188
+ | agent_id | string | Yes | Agent ID to register |
1189
+ | public_key | string | Yes | PEM public key (SPKI format) |
1190
+ | algorithm | string | No | Signing algorithm (default: "RSASSA-PKCS1-v1_5") |
1191
+
1192
+ **Returns:** `Promise<{identity: Object}>`
1193
+
1194
+ ### claw.getIdentities()
1195
+ List all registered agent identities for this organization.
1196
+
1197
+ **Returns:** `Promise<{identities: Object[]}>`
1198
+
1199
+ ---
1200
+
1201
+ ## Organization Management
1202
+
1203
+ Manage organizations and API keys. All methods require admin API key.
1204
+
1205
+ ### claw.getOrg()
1206
+ Get the current organization's details.
1207
+
1208
+ **Returns:** `Promise<{organizations: Object[]}>`
1209
+
1210
+ ### claw.createOrg(org)
1211
+ Create a new organization with an initial admin API key.
1212
+
1213
+ **Parameters:**
1214
+ | Parameter | Type | Required | Description |
1215
+ |-----------|------|----------|-------------|
1216
+ | name | string | Yes | Organization name |
1217
+ | slug | string | Yes | URL-safe slug (lowercase alphanumeric + hyphens) |
1218
+
1219
+ **Returns:** `Promise<{organization: Object, api_key: Object}>`
1220
+
1221
+ ### claw.getOrgById(orgId)
1222
+ Get organization details by ID.
1223
+
1224
+ **Parameters:**
1225
+ | Parameter | Type | Required | Description |
1226
+ |-----------|------|----------|-------------|
1227
+ | orgId | string | Yes | Organization ID |
1228
+
1229
+ **Returns:** `Promise<{organization: Object}>`
1230
+
1231
+ ### claw.updateOrg(orgId, updates)
1232
+ Update organization details.
1233
+
1234
+ **Parameters:**
1235
+ | Parameter | Type | Required | Description |
1236
+ |-----------|------|----------|-------------|
1237
+ | orgId | string | Yes | Organization ID |
1238
+ | updates | Object | Yes | Fields to update (name, slug) |
1239
+
1240
+ **Returns:** `Promise<{organization: Object}>`
1241
+
1242
+ ### claw.getOrgKeys(orgId)
1243
+ List API keys for an organization.
1244
+
1245
+ **Parameters:**
1246
+ | Parameter | Type | Required | Description |
1247
+ |-----------|------|----------|-------------|
1248
+ | orgId | string | Yes | Organization ID |
1249
+
1250
+ **Returns:** `Promise<{keys: Object[]}>`
1251
+
1252
+ ---
1253
+
1254
+ ## Activity Logs
1255
+
1256
+ ### claw.getActivityLogs(filters?)
1257
+ Get activity/audit logs for the organization.
1258
+
1259
+ **Parameters:**
1260
+ | Parameter | Type | Required | Description |
1261
+ |-----------|------|----------|-------------|
1262
+ | action | string | No | Filter by action type |
1263
+ | actor_id | string | No | Filter by actor |
1264
+ | resource_type | string | No | Filter by resource type |
1265
+ | before | string | No | Before timestamp (ISO string) |
1266
+ | after | string | No | After timestamp (ISO string) |
1267
+ | limit | number | No | Max results (default: 50, max: 200) |
1268
+ | offset | number | No | Pagination offset |
1269
+
1270
+ **Returns:** `Promise<{logs: Object[], stats: Object, pagination: Object}>`
1271
+
1272
+ ---
1273
+
1274
+ ## Webhooks
1275
+
1276
+ Subscribe to DashClaw events and receive real-time notifications.
1277
+
1278
+ ### claw.getWebhooks()
1279
+ List all webhooks for this organization.
1280
+
1281
+ **Returns:** `Promise<{webhooks: Object[]}>`
1282
+
1283
+ ### claw.createWebhook(webhook)
1284
+ Create a new webhook subscription.
1285
+
1286
+ **Parameters:**
1287
+ | Parameter | Type | Required | Description |
1288
+ |-----------|------|----------|-------------|
1289
+ | url | string | Yes | Webhook endpoint URL |
1290
+ | events | string[] | No | Event types to subscribe to |
1291
+
1292
+ **Returns:** `Promise<{webhook: Object}>`
1293
+
1294
+ ### claw.deleteWebhook(webhookId)
1295
+ Delete a webhook.
1296
+
1297
+ **Parameters:**
1298
+ | Parameter | Type | Required | Description |
1299
+ |-----------|------|----------|-------------|
1300
+ | webhookId | string | Yes | Webhook ID |
1301
+
1302
+ **Returns:** `Promise<{deleted: boolean}>`
1303
+
1304
+ ### claw.testWebhook(webhookId)
1305
+ Send a test event to a webhook to verify connectivity.
1306
+
1307
+ **Parameters:**
1308
+ | Parameter | Type | Required | Description |
1309
+ |-----------|------|----------|-------------|
1310
+ | webhookId | string | Yes | Webhook ID |
1311
+
1312
+ **Returns:** `Promise<{delivery: Object}>`
1313
+
1314
+ ### claw.getWebhookDeliveries(webhookId)
1315
+ Get delivery history for a webhook.
1316
+
1317
+ **Parameters:**
1318
+ | Parameter | Type | Required | Description |
1319
+ |-----------|------|----------|-------------|
1320
+ | webhookId | string | Yes | Webhook ID |
1321
+
1322
+ **Returns:** `Promise<{deliveries: Object[]}>`
1323
+
726
1324
  ---
727
1325
 
728
1326
  ## Bulk Sync
@@ -959,6 +1557,49 @@ Get routing system health status and diagnostics.
959
1557
 
960
1558
  ---
961
1559
 
1560
+ ## Agent Schedules
1561
+
1562
+ Define recurring tasks and cron-based schedules for agents.
1563
+
1564
+ ### claw.listAgentSchedules(filters?)
1565
+ List agent schedules, optionally filtered by agent.
1566
+
1567
+ ```javascript
1568
+ const { schedules } = await claw.listAgentSchedules({ agent_id: 'forge' });
1569
+ ```
1570
+
1571
+ **Parameters:**
1572
+ | Parameter | Type | Required | Description |
1573
+ |-----------|------|----------|-------------|
1574
+ | filters.agent_id | string | No | Filter by agent ID |
1575
+
1576
+ **Returns:** `Promise<{ schedules: Object[] }>`
1577
+
1578
+ ### claw.createAgentSchedule(schedule)
1579
+ Create a new agent schedule entry.
1580
+
1581
+ ```javascript
1582
+ const { schedule } = await claw.createAgentSchedule({
1583
+ agent_id: 'forge',
1584
+ name: 'Build projects',
1585
+ cron_expression: '0 */6 * * *',
1586
+ description: 'Check for pending builds every 6 hours'
1587
+ });
1588
+ ```
1589
+
1590
+ **Parameters:**
1591
+ | Parameter | Type | Required | Description |
1592
+ |-----------|------|----------|-------------|
1593
+ | schedule.agent_id | string | Yes | Agent this schedule belongs to |
1594
+ | schedule.name | string | Yes | Schedule name |
1595
+ | schedule.cron_expression | string | Yes | Cron expression (e.g. `0 */6 * * *`) |
1596
+ | schedule.description | string | No | Human-readable description |
1597
+ | schedule.enabled | boolean | No | Whether schedule is active (default: true) |
1598
+
1599
+ **Returns:** `Promise<{ schedule: Object }>`
1600
+
1601
+ ---
1602
+
962
1603
  ## Error Handling
963
1604
 
964
1605
  All SDK methods throw on non-2xx responses. Errors include `status` (HTTP code) and `details` (when available).
package/dashclaw.js CHANGED
@@ -3,7 +3,7 @@
3
3
  * Full-featured agent toolkit for the DashClaw platform.
4
4
  * Zero-dependency ESM SDK — requires Node 18+ (native fetch).
5
5
  *
6
- * 78+ methods across 16+ categories:
6
+ * 96+ methods across 22+ categories:
7
7
  * - Action Recording (7)
8
8
  * - Loops & Assumptions (7)
9
9
  * - Signals (1)
@@ -16,10 +16,16 @@
16
16
  * - Security Scanning (2)
17
17
  * - Agent Messaging (9)
18
18
  * - Behavior Guard (2)
19
+ * - Agent Pairing (3)
20
+ * - Identity Binding (2)
21
+ * - Organization Management (5)
22
+ * - Activity Logs (1)
23
+ * - Webhooks (5)
19
24
  * - Bulk Sync (1)
20
25
  * - Policy Testing (3)
21
26
  * - Compliance Engine (5)
22
27
  * - Task Routing (10)
28
+ * - Real-Time Events (1)
23
29
  */
24
30
 
25
31
  class DashClaw {
@@ -65,6 +71,9 @@ class DashClaw {
65
71
  }
66
72
 
67
73
  this.baseUrl = baseUrl.replace(/\/$/, '');
74
+ if (!this.baseUrl.startsWith('https://') && !this.baseUrl.includes('localhost') && !this.baseUrl.includes('127.0.0.1')) {
75
+ console.warn('[DashClaw] WARNING: baseUrl does not use HTTPS. API keys will be sent in plaintext. Use HTTPS in production.');
76
+ }
68
77
  this.apiKey = apiKey;
69
78
  this.agentId = agentId;
70
79
  this.agentName = agentName || null;
@@ -464,32 +473,172 @@ class DashClaw {
464
473
 
465
474
  /**
466
475
  * Poll for human approval of a pending action.
467
- * @param {string} actionId
476
+ * @param {string} actionId
468
477
  * @param {Object} [options]
469
478
  * @param {number} [options.timeout=300000] - Max wait time (5 min)
470
479
  * @param {number} [options.interval=5000] - Poll interval
480
+ * @param {boolean} [options.useEvents=false] - Use SSE stream instead of polling
471
481
  */
472
- async waitForApproval(actionId, { timeout = 300000, interval = 5000 } = {}) {
482
+ async waitForApproval(actionId, { timeout = 300000, interval = 5000, useEvents = false } = {}) {
483
+ if (!useEvents) {
484
+ return this._waitForApprovalPolling(actionId, timeout, interval);
485
+ }
486
+
487
+ return new Promise((resolve, reject) => {
488
+ const stream = this.events();
489
+ const timeoutId = setTimeout(() => {
490
+ stream.close();
491
+ reject(new Error(`Timed out waiting for approval of action ${actionId}`));
492
+ }, timeout);
493
+
494
+ stream.on('action.updated', (data) => {
495
+ if (data.action_id !== actionId) return;
496
+ if (data.status === 'running') {
497
+ clearTimeout(timeoutId);
498
+ stream.close();
499
+ resolve({ action: data, action_id: actionId });
500
+ } else if (data.status === 'failed' || data.status === 'cancelled') {
501
+ clearTimeout(timeoutId);
502
+ stream.close();
503
+ reject(new ApprovalDeniedError(data.error_message || 'Operator denied the action.'));
504
+ }
505
+ });
506
+
507
+ stream.on('error', (err) => {
508
+ clearTimeout(timeoutId);
509
+ stream.close();
510
+ reject(err);
511
+ });
512
+ });
513
+ }
514
+
515
+ /** @private Polling-based waitForApproval implementation. */
516
+ async _waitForApprovalPolling(actionId, timeout, interval) {
473
517
  const startTime = Date.now();
474
-
518
+
475
519
  while (Date.now() - startTime < timeout) {
476
520
  const { action } = await this.getAction(actionId);
477
-
521
+
478
522
  if (action.status === 'running') {
479
523
  console.log(`[DashClaw] Action ${actionId} approved by operator.`);
480
524
  return { action, action_id: actionId };
481
525
  }
482
-
526
+
483
527
  if (action.status === 'failed' || action.status === 'cancelled') {
484
528
  throw new ApprovalDeniedError(action.error_message || 'Operator denied the action.');
485
529
  }
486
-
530
+
487
531
  await new Promise(r => setTimeout(r, interval));
488
532
  }
489
-
533
+
490
534
  throw new Error(`[DashClaw] Timed out waiting for approval of action ${actionId}`);
491
535
  }
492
536
 
537
+ // ══════════════════════════════════════════════
538
+ // Real-Time Events (1 method)
539
+ // ══════════════════════════════════════════════
540
+
541
+ /**
542
+ * Subscribe to real-time SSE events from the DashClaw server.
543
+ * Uses fetch-based SSE parsing for Node 18+ compatibility (no native EventSource required).
544
+ *
545
+ * @returns {{ on(eventType: string, callback: Function): this, close(): void, _promise: Promise<void> }}
546
+ *
547
+ * @example
548
+ * const stream = client.events();
549
+ * stream
550
+ * .on('action.created', (data) => console.log('New action:', data))
551
+ * .on('action.updated', (data) => console.log('Action updated:', data))
552
+ * .on('policy.updated', (data) => console.log('Policy changed:', data))
553
+ * .on('task.assigned', (data) => console.log('Task assigned:', data))
554
+ * .on('task.completed', (data) => console.log('Task done:', data))
555
+ * .on('error', (err) => console.error('Stream error:', err));
556
+ *
557
+ * // Later:
558
+ * stream.close();
559
+ */
560
+ events() {
561
+ const url = `${this.baseUrl}/api/stream`;
562
+ const apiKey = this.apiKey;
563
+
564
+ const handlers = new Map();
565
+ let closed = false;
566
+ let controller = null;
567
+
568
+ const connect = async () => {
569
+ controller = new AbortController();
570
+ const res = await fetch(url, {
571
+ headers: { 'x-api-key': apiKey },
572
+ signal: controller.signal,
573
+ });
574
+
575
+ if (!res.ok) {
576
+ throw new Error(`SSE connection failed: ${res.status} ${res.statusText}`);
577
+ }
578
+
579
+ const reader = res.body.getReader();
580
+ const decoder = new TextDecoder();
581
+ let buffer = '';
582
+
583
+ while (!closed) {
584
+ const { done, value } = await reader.read();
585
+ if (done) break;
586
+ buffer += decoder.decode(value, { stream: true });
587
+
588
+ // Parse SSE frames from buffer
589
+ const lines = buffer.split('\n');
590
+ buffer = lines.pop(); // Keep incomplete line in buffer
591
+
592
+ let currentEvent = null;
593
+ let currentData = '';
594
+
595
+ for (const line of lines) {
596
+ if (line.startsWith('event: ')) {
597
+ currentEvent = line.slice(7).trim();
598
+ } else if (line.startsWith('data: ')) {
599
+ currentData += line.slice(6);
600
+ } else if (line === '' && currentEvent) {
601
+ // End of SSE frame — dispatch
602
+ const eventHandlers = handlers.get(currentEvent) || [];
603
+ if (eventHandlers.length > 0 && currentData) {
604
+ try {
605
+ const parsed = JSON.parse(currentData);
606
+ for (const cb of eventHandlers) {
607
+ try { cb(parsed); } catch { /* ignore handler errors */ }
608
+ }
609
+ } catch { /* ignore parse errors */ }
610
+ }
611
+ currentEvent = null;
612
+ currentData = '';
613
+ }
614
+ }
615
+ }
616
+ };
617
+
618
+ const connectionPromise = connect().catch((err) => {
619
+ if (closed) return; // Abort is expected on close
620
+ const errorHandlers = handlers.get('error') || [];
621
+ for (const cb of errorHandlers) {
622
+ try { cb(err); } catch { /* ignore */ }
623
+ }
624
+ });
625
+
626
+ const handle = {
627
+ on(eventType, callback) {
628
+ if (!handlers.has(eventType)) handlers.set(eventType, []);
629
+ handlers.get(eventType).push(callback);
630
+ return handle;
631
+ },
632
+ close() {
633
+ closed = true;
634
+ if (controller) controller.abort();
635
+ },
636
+ _promise: connectionPromise,
637
+ };
638
+
639
+ return handle;
640
+ }
641
+
493
642
  /**
494
643
  * Update the outcome of an existing action.
495
644
  * @param {string} actionId - The action_id to update
@@ -1747,6 +1896,165 @@ class DashClaw {
1747
1896
  return this._request('/api/routing/health', 'GET');
1748
1897
  }
1749
1898
 
1899
+ // ══════════════════════════════════════════════════════════
1900
+ // Agent Pairing (3 methods)
1901
+ // ══════════════════════════════════════════════════════════
1902
+
1903
+ // createPairing, createPairingFromPrivateJwk, waitForPairing
1904
+ // (defined near the top of the class)
1905
+
1906
+ // ══════════════════════════════════════════════════════════
1907
+ // Identity Binding (2 methods)
1908
+ // ══════════════════════════════════════════════════════════
1909
+
1910
+ /**
1911
+ * Register or update an agent's public key for identity verification.
1912
+ * Requires admin API key.
1913
+ * @param {Object} identity
1914
+ * @param {string} identity.agent_id - Agent ID to register
1915
+ * @param {string} identity.public_key - PEM public key (SPKI format)
1916
+ * @param {string} [identity.algorithm='RSASSA-PKCS1-v1_5'] - Signing algorithm
1917
+ * @returns {Promise<{identity: Object}>}
1918
+ */
1919
+ async registerIdentity(identity) {
1920
+ return this._request('/api/identities', 'POST', identity);
1921
+ }
1922
+
1923
+ /**
1924
+ * List all registered agent identities for this org.
1925
+ * @returns {Promise<{identities: Object[]}>}
1926
+ */
1927
+ async getIdentities() {
1928
+ return this._request('/api/identities', 'GET');
1929
+ }
1930
+
1931
+ // ══════════════════════════════════════════════════════════
1932
+ // Organization Management (5 methods)
1933
+ // ══════════════════════════════════════════════════════════
1934
+
1935
+ /**
1936
+ * Get the current organization's details. Requires admin API key.
1937
+ * @returns {Promise<{organizations: Object[]}>}
1938
+ */
1939
+ async getOrg() {
1940
+ return this._request('/api/orgs', 'GET');
1941
+ }
1942
+
1943
+ /**
1944
+ * Create a new organization with an initial admin API key. Requires admin API key.
1945
+ * @param {Object} org
1946
+ * @param {string} org.name - Organization name
1947
+ * @param {string} org.slug - URL-safe slug (lowercase alphanumeric + hyphens)
1948
+ * @returns {Promise<{organization: Object, api_key: Object}>}
1949
+ */
1950
+ async createOrg(org) {
1951
+ return this._request('/api/orgs', 'POST', org);
1952
+ }
1953
+
1954
+ /**
1955
+ * Get organization details by ID. Requires admin API key.
1956
+ * @param {string} orgId - Organization ID
1957
+ * @returns {Promise<{organization: Object}>}
1958
+ */
1959
+ async getOrgById(orgId) {
1960
+ return this._request(`/api/orgs/${encodeURIComponent(orgId)}`, 'GET');
1961
+ }
1962
+
1963
+ /**
1964
+ * Update organization details. Requires admin API key.
1965
+ * @param {string} orgId - Organization ID
1966
+ * @param {Object} updates - Fields to update (name, slug)
1967
+ * @returns {Promise<{organization: Object}>}
1968
+ */
1969
+ async updateOrg(orgId, updates) {
1970
+ return this._request(`/api/orgs/${encodeURIComponent(orgId)}`, 'PATCH', updates);
1971
+ }
1972
+
1973
+ /**
1974
+ * List API keys for an organization. Requires admin API key.
1975
+ * @param {string} orgId - Organization ID
1976
+ * @returns {Promise<{keys: Object[]}>}
1977
+ */
1978
+ async getOrgKeys(orgId) {
1979
+ return this._request(`/api/orgs/${encodeURIComponent(orgId)}/keys`, 'GET');
1980
+ }
1981
+
1982
+ // ══════════════════════════════════════════════════════════
1983
+ // Activity Logs (1 method)
1984
+ // ══════════════════════════════════════════════════════════
1985
+
1986
+ /**
1987
+ * Get activity/audit logs for the organization.
1988
+ * @param {Object} [filters]
1989
+ * @param {string} [filters.action] - Filter by action type
1990
+ * @param {string} [filters.actor_id] - Filter by actor
1991
+ * @param {string} [filters.resource_type] - Filter by resource type
1992
+ * @param {string} [filters.before] - Before timestamp (ISO string)
1993
+ * @param {string} [filters.after] - After timestamp (ISO string)
1994
+ * @param {number} [filters.limit=50] - Max results (max 200)
1995
+ * @param {number} [filters.offset=0] - Pagination offset
1996
+ * @returns {Promise<{logs: Object[], stats: Object, pagination: Object}>}
1997
+ */
1998
+ async getActivityLogs(filters = {}) {
1999
+ const params = new URLSearchParams();
2000
+ for (const [key, value] of Object.entries(filters)) {
2001
+ if (value !== undefined && value !== null && value !== '') {
2002
+ params.set(key, String(value));
2003
+ }
2004
+ }
2005
+ return this._request(`/api/activity?${params}`, 'GET');
2006
+ }
2007
+
2008
+ // ══════════════════════════════════════════════════════════
2009
+ // Webhooks (5 methods)
2010
+ // ══════════════════════════════════════════════════════════
2011
+
2012
+ /**
2013
+ * List all webhooks for this org.
2014
+ * @returns {Promise<{webhooks: Object[]}>}
2015
+ */
2016
+ async getWebhooks() {
2017
+ return this._request('/api/webhooks', 'GET');
2018
+ }
2019
+
2020
+ /**
2021
+ * Create a new webhook subscription.
2022
+ * @param {Object} webhook
2023
+ * @param {string} webhook.url - Webhook endpoint URL
2024
+ * @param {string[]} [webhook.events] - Event types to subscribe to
2025
+ * @returns {Promise<{webhook: Object}>}
2026
+ */
2027
+ async createWebhook(webhook) {
2028
+ return this._request('/api/webhooks', 'POST', webhook);
2029
+ }
2030
+
2031
+ /**
2032
+ * Delete a webhook.
2033
+ * @param {string} webhookId - Webhook ID
2034
+ * @returns {Promise<{deleted: boolean}>}
2035
+ */
2036
+ async deleteWebhook(webhookId) {
2037
+ return this._request(`/api/webhooks?id=${encodeURIComponent(webhookId)}`, 'DELETE');
2038
+ }
2039
+
2040
+ /**
2041
+ * Send a test event to a webhook.
2042
+ * @param {string} webhookId - Webhook ID
2043
+ * @returns {Promise<{delivery: Object}>}
2044
+ */
2045
+ async testWebhook(webhookId) {
2046
+ return this._request(`/api/webhooks/${encodeURIComponent(webhookId)}/test`, 'POST');
2047
+ }
2048
+
2049
+ /**
2050
+ * Get delivery history for a webhook.
2051
+ * @param {string} webhookId - Webhook ID
2052
+ * @returns {Promise<{deliveries: Object[]}>}
2053
+ */
2054
+ async getWebhookDeliveries(webhookId) {
2055
+ return this._request(`/api/webhooks/${encodeURIComponent(webhookId)}/deliveries`, 'GET');
2056
+ }
2057
+
1750
2058
  // ─── Bulk Sync ────────────────────────────────────────────
1751
2059
 
1752
2060
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dashclaw",
3
- "version": "1.8.0",
4
- "description": "Full-featured agent toolkit for the DashClaw platform. 78+ methods for action recording, context management, session handoffs, security scanning, behavior guard, compliance, task routing, bulk sync, and more.",
3
+ "version": "1.8.1",
4
+ "description": "Full-featured agent toolkit for the DashClaw platform. 95+ methods across 21+ categories for action recording, context management, session handoffs, security scanning, behavior guard, compliance, task routing, identity binding, organization management, webhooks, bulk sync, and more.",
5
5
  "type": "module",
6
6
  "publishConfig": {
7
7
  "access": "public"