dashclaw 1.8.0 → 1.8.2
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 +675 -1
- package/dashclaw.js +394 -12
- 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
|
|
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)
|
|
@@ -717,12 +1026,334 @@ Send a message to another agent or broadcast.
|
|
|
717
1026
|
| threadId | string | No | Thread ID to attach to |
|
|
718
1027
|
| urgent | boolean | No | Mark as urgent |
|
|
719
1028
|
| docRef | string | No | Reference to a shared doc ID |
|
|
1029
|
+
| attachments | Array<{filename, mime_type, data}> | No | File attachments (base64, max 3, max 5MB each) |
|
|
720
1030
|
|
|
721
1031
|
**Returns:** `Promise<{message: Object, message_id: string}>`
|
|
722
1032
|
|
|
1033
|
+
### claw.getInbox(params?)
|
|
1034
|
+
Get inbox messages for this agent.
|
|
1035
|
+
|
|
1036
|
+
**Parameters:**
|
|
1037
|
+
| Parameter | Type | Required | Description |
|
|
1038
|
+
|-----------|------|----------|-------------|
|
|
1039
|
+
| type | string | No | Filter by message type |
|
|
1040
|
+
| unread | boolean | No | Only unread messages |
|
|
1041
|
+
| threadId | string | No | Filter by thread |
|
|
1042
|
+
| limit | number | No | Max messages to return (default: 50) |
|
|
1043
|
+
|
|
1044
|
+
**Returns:** `Promise<{messages: Object[], total: number, unread_count: number}>`
|
|
1045
|
+
|
|
1046
|
+
### claw.markRead(messageIds)
|
|
1047
|
+
Mark messages as read.
|
|
1048
|
+
|
|
1049
|
+
**Parameters:**
|
|
1050
|
+
| Parameter | Type | Required | Description |
|
|
1051
|
+
|-----------|------|----------|-------------|
|
|
1052
|
+
| messageIds | string[] | Yes | Array of message IDs to mark read |
|
|
1053
|
+
|
|
1054
|
+
**Returns:** `Promise<{updated: number}>`
|
|
1055
|
+
|
|
1056
|
+
### claw.archiveMessages(messageIds)
|
|
1057
|
+
Archive messages.
|
|
1058
|
+
|
|
1059
|
+
**Parameters:**
|
|
1060
|
+
| Parameter | Type | Required | Description |
|
|
1061
|
+
|-----------|------|----------|-------------|
|
|
1062
|
+
| messageIds | string[] | Yes | Array of message IDs to archive |
|
|
1063
|
+
|
|
1064
|
+
**Returns:** `Promise<{updated: number}>`
|
|
1065
|
+
|
|
1066
|
+
### claw.broadcast(params)
|
|
1067
|
+
Broadcast a message to all agents in the organization.
|
|
1068
|
+
|
|
1069
|
+
**Parameters:**
|
|
1070
|
+
| Parameter | Type | Required | Description |
|
|
1071
|
+
|-----------|------|----------|-------------|
|
|
1072
|
+
| type | string | No | Message type (default: "info") |
|
|
1073
|
+
| subject | string | No | Subject line |
|
|
1074
|
+
| body | string | Yes | Message body |
|
|
1075
|
+
| threadId | string | No | Thread ID |
|
|
1076
|
+
|
|
1077
|
+
**Returns:** `Promise<{message: Object, message_id: string}>`
|
|
1078
|
+
|
|
1079
|
+
### claw.createMessageThread(params)
|
|
1080
|
+
Create a new message thread for multi-turn conversations between agents.
|
|
1081
|
+
|
|
1082
|
+
**Parameters:**
|
|
1083
|
+
| Parameter | Type | Required | Description |
|
|
1084
|
+
|-----------|------|----------|-------------|
|
|
1085
|
+
| name | string | Yes | Thread name |
|
|
1086
|
+
| participants | string[] | No | Agent IDs (null = open to all) |
|
|
1087
|
+
|
|
1088
|
+
**Returns:** `Promise<{thread: Object, thread_id: string}>`
|
|
1089
|
+
|
|
1090
|
+
### claw.getMessageThreads(params?)
|
|
1091
|
+
List message threads.
|
|
1092
|
+
|
|
1093
|
+
**Parameters:**
|
|
1094
|
+
| Parameter | Type | Required | Description |
|
|
1095
|
+
|-----------|------|----------|-------------|
|
|
1096
|
+
| status | string | No | Filter by status: open, resolved, archived |
|
|
1097
|
+
| limit | number | No | Max threads to return (default: 20) |
|
|
1098
|
+
|
|
1099
|
+
**Returns:** `Promise<{threads: Object[], total: number}>`
|
|
1100
|
+
|
|
1101
|
+
### claw.resolveMessageThread(threadId, summary?)
|
|
1102
|
+
Resolve (close) a message thread with an optional summary.
|
|
1103
|
+
|
|
1104
|
+
**Parameters:**
|
|
1105
|
+
| Parameter | Type | Required | Description |
|
|
1106
|
+
|-----------|------|----------|-------------|
|
|
1107
|
+
| threadId | string | Yes | Thread ID to resolve |
|
|
1108
|
+
| summary | string | No | Resolution summary |
|
|
1109
|
+
|
|
1110
|
+
**Returns:** `Promise<{thread: Object}>`
|
|
1111
|
+
|
|
723
1112
|
### claw.saveSharedDoc(params)
|
|
724
1113
|
Create or update a shared workspace document. Upserts by name.
|
|
725
1114
|
|
|
1115
|
+
**Parameters:**
|
|
1116
|
+
| Parameter | Type | Required | Description |
|
|
1117
|
+
|-----------|------|----------|-------------|
|
|
1118
|
+
| name | string | Yes | Document name (unique per org) |
|
|
1119
|
+
| content | string | Yes | Document content |
|
|
1120
|
+
|
|
1121
|
+
**Returns:** `Promise<{doc: Object, doc_id: string}>`
|
|
1122
|
+
|
|
1123
|
+
### claw.getAttachmentUrl(attachmentId)
|
|
1124
|
+
|
|
1125
|
+
Get a URL to download an attachment.
|
|
1126
|
+
|
|
1127
|
+
| Parameter | Type | Description |
|
|
1128
|
+
|---|---|---|
|
|
1129
|
+
| `attachmentId` | `string` | Attachment ID (`att_*`) |
|
|
1130
|
+
|
|
1131
|
+
**Returns:** `string` — URL to fetch the attachment binary
|
|
1132
|
+
|
|
1133
|
+
---
|
|
1134
|
+
|
|
1135
|
+
### claw.getAttachment(attachmentId)
|
|
1136
|
+
|
|
1137
|
+
Download an attachment as a Buffer.
|
|
1138
|
+
|
|
1139
|
+
| Parameter | Type | Description |
|
|
1140
|
+
|---|---|---|
|
|
1141
|
+
| `attachmentId` | `string` | Attachment ID (`att_*`) |
|
|
1142
|
+
|
|
1143
|
+
**Returns:** `Promise<{ data: Buffer, filename: string, mimeType: string }>`
|
|
1144
|
+
|
|
1145
|
+
```js
|
|
1146
|
+
const inbox = await claw.getInbox();
|
|
1147
|
+
for (const msg of inbox.messages) {
|
|
1148
|
+
for (const att of msg.attachments || []) {
|
|
1149
|
+
const { data, filename } = await claw.getAttachment(att.id);
|
|
1150
|
+
fs.writeFileSync(filename, data);
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
```
|
|
1154
|
+
|
|
1155
|
+
---
|
|
1156
|
+
|
|
1157
|
+
## Agent Pairing
|
|
1158
|
+
|
|
1159
|
+
Pair agents with user accounts via public key registration and approval flow.
|
|
1160
|
+
|
|
1161
|
+
### claw.createPairing(options)
|
|
1162
|
+
Create an agent pairing request. Returns a link the user can click to approve the pairing.
|
|
1163
|
+
|
|
1164
|
+
**Parameters:**
|
|
1165
|
+
| Parameter | Type | Required | Description |
|
|
1166
|
+
|-----------|------|----------|-------------|
|
|
1167
|
+
| publicKeyPem | string | Yes | PEM public key (SPKI format) to register for this agent |
|
|
1168
|
+
| algorithm | string | No | Signing algorithm (default: "RSASSA-PKCS1-v1_5") |
|
|
1169
|
+
| agentName | string | No | Agent name override |
|
|
1170
|
+
|
|
1171
|
+
**Returns:** `Promise<{pairing: Object, pairing_url: string}>`
|
|
1172
|
+
|
|
1173
|
+
### claw.createPairingFromPrivateJwk(privateJwk, options?)
|
|
1174
|
+
Convenience method that derives the public PEM from a private JWK and creates a pairing request.
|
|
1175
|
+
|
|
1176
|
+
**Parameters:**
|
|
1177
|
+
| Parameter | Type | Required | Description |
|
|
1178
|
+
|-----------|------|----------|-------------|
|
|
1179
|
+
| privateJwk | Object | Yes | Private key in JWK format |
|
|
1180
|
+
| options.agentName | string | No | Agent name override |
|
|
1181
|
+
|
|
1182
|
+
**Returns:** `Promise<{pairing: Object, pairing_url: string}>`
|
|
1183
|
+
|
|
1184
|
+
### claw.waitForPairing(pairingId, options?)
|
|
1185
|
+
Poll a pairing request until it is approved or expired.
|
|
1186
|
+
|
|
1187
|
+
**Parameters:**
|
|
1188
|
+
| Parameter | Type | Required | Description |
|
|
1189
|
+
|-----------|------|----------|-------------|
|
|
1190
|
+
| pairingId | string | Yes | The pairing ID to poll |
|
|
1191
|
+
| options.timeout | number | No | Max wait time in ms (default: 300000 / 5 min) |
|
|
1192
|
+
| options.interval | number | No | Poll interval in ms (default: 2000) |
|
|
1193
|
+
|
|
1194
|
+
**Returns:** `Promise<Object>` (the approved pairing object)
|
|
1195
|
+
|
|
1196
|
+
**Throws:** `Error` if pairing expires or times out.
|
|
1197
|
+
|
|
1198
|
+
**Example:**
|
|
1199
|
+
```javascript
|
|
1200
|
+
const { pairing, pairing_url } = await claw.createPairing({
|
|
1201
|
+
publicKeyPem: myPublicKeyPem,
|
|
1202
|
+
});
|
|
1203
|
+
console.log('Approve pairing at:', pairing_url);
|
|
1204
|
+
|
|
1205
|
+
const approved = await claw.waitForPairing(pairing.id);
|
|
1206
|
+
console.log('Pairing approved!', approved.status);
|
|
1207
|
+
```
|
|
1208
|
+
|
|
1209
|
+
---
|
|
1210
|
+
|
|
1211
|
+
## Identity Binding
|
|
1212
|
+
|
|
1213
|
+
Register and manage agent public keys for cryptographic identity verification.
|
|
1214
|
+
|
|
1215
|
+
### claw.registerIdentity(identity)
|
|
1216
|
+
Register or update an agent's public key for identity verification. Requires admin API key.
|
|
1217
|
+
|
|
1218
|
+
**Parameters:**
|
|
1219
|
+
| Parameter | Type | Required | Description |
|
|
1220
|
+
|-----------|------|----------|-------------|
|
|
1221
|
+
| agent_id | string | Yes | Agent ID to register |
|
|
1222
|
+
| public_key | string | Yes | PEM public key (SPKI format) |
|
|
1223
|
+
| algorithm | string | No | Signing algorithm (default: "RSASSA-PKCS1-v1_5") |
|
|
1224
|
+
|
|
1225
|
+
**Returns:** `Promise<{identity: Object}>`
|
|
1226
|
+
|
|
1227
|
+
### claw.getIdentities()
|
|
1228
|
+
List all registered agent identities for this organization.
|
|
1229
|
+
|
|
1230
|
+
**Returns:** `Promise<{identities: Object[]}>`
|
|
1231
|
+
|
|
1232
|
+
---
|
|
1233
|
+
|
|
1234
|
+
## Organization Management
|
|
1235
|
+
|
|
1236
|
+
Manage organizations and API keys. All methods require admin API key.
|
|
1237
|
+
|
|
1238
|
+
### claw.getOrg()
|
|
1239
|
+
Get the current organization's details.
|
|
1240
|
+
|
|
1241
|
+
**Returns:** `Promise<{organizations: Object[]}>`
|
|
1242
|
+
|
|
1243
|
+
### claw.createOrg(org)
|
|
1244
|
+
Create a new organization with an initial admin API key.
|
|
1245
|
+
|
|
1246
|
+
**Parameters:**
|
|
1247
|
+
| Parameter | Type | Required | Description |
|
|
1248
|
+
|-----------|------|----------|-------------|
|
|
1249
|
+
| name | string | Yes | Organization name |
|
|
1250
|
+
| slug | string | Yes | URL-safe slug (lowercase alphanumeric + hyphens) |
|
|
1251
|
+
|
|
1252
|
+
**Returns:** `Promise<{organization: Object, api_key: Object}>`
|
|
1253
|
+
|
|
1254
|
+
### claw.getOrgById(orgId)
|
|
1255
|
+
Get organization details by ID.
|
|
1256
|
+
|
|
1257
|
+
**Parameters:**
|
|
1258
|
+
| Parameter | Type | Required | Description |
|
|
1259
|
+
|-----------|------|----------|-------------|
|
|
1260
|
+
| orgId | string | Yes | Organization ID |
|
|
1261
|
+
|
|
1262
|
+
**Returns:** `Promise<{organization: Object}>`
|
|
1263
|
+
|
|
1264
|
+
### claw.updateOrg(orgId, updates)
|
|
1265
|
+
Update organization details.
|
|
1266
|
+
|
|
1267
|
+
**Parameters:**
|
|
1268
|
+
| Parameter | Type | Required | Description |
|
|
1269
|
+
|-----------|------|----------|-------------|
|
|
1270
|
+
| orgId | string | Yes | Organization ID |
|
|
1271
|
+
| updates | Object | Yes | Fields to update (name, slug) |
|
|
1272
|
+
|
|
1273
|
+
**Returns:** `Promise<{organization: Object}>`
|
|
1274
|
+
|
|
1275
|
+
### claw.getOrgKeys(orgId)
|
|
1276
|
+
List API keys for an organization.
|
|
1277
|
+
|
|
1278
|
+
**Parameters:**
|
|
1279
|
+
| Parameter | Type | Required | Description |
|
|
1280
|
+
|-----------|------|----------|-------------|
|
|
1281
|
+
| orgId | string | Yes | Organization ID |
|
|
1282
|
+
|
|
1283
|
+
**Returns:** `Promise<{keys: Object[]}>`
|
|
1284
|
+
|
|
1285
|
+
---
|
|
1286
|
+
|
|
1287
|
+
## Activity Logs
|
|
1288
|
+
|
|
1289
|
+
### claw.getActivityLogs(filters?)
|
|
1290
|
+
Get activity/audit logs for the organization.
|
|
1291
|
+
|
|
1292
|
+
**Parameters:**
|
|
1293
|
+
| Parameter | Type | Required | Description |
|
|
1294
|
+
|-----------|------|----------|-------------|
|
|
1295
|
+
| action | string | No | Filter by action type |
|
|
1296
|
+
| actor_id | string | No | Filter by actor |
|
|
1297
|
+
| resource_type | string | No | Filter by resource type |
|
|
1298
|
+
| before | string | No | Before timestamp (ISO string) |
|
|
1299
|
+
| after | string | No | After timestamp (ISO string) |
|
|
1300
|
+
| limit | number | No | Max results (default: 50, max: 200) |
|
|
1301
|
+
| offset | number | No | Pagination offset |
|
|
1302
|
+
|
|
1303
|
+
**Returns:** `Promise<{logs: Object[], stats: Object, pagination: Object}>`
|
|
1304
|
+
|
|
1305
|
+
---
|
|
1306
|
+
|
|
1307
|
+
## Webhooks
|
|
1308
|
+
|
|
1309
|
+
Subscribe to DashClaw events and receive real-time notifications.
|
|
1310
|
+
|
|
1311
|
+
### claw.getWebhooks()
|
|
1312
|
+
List all webhooks for this organization.
|
|
1313
|
+
|
|
1314
|
+
**Returns:** `Promise<{webhooks: Object[]}>`
|
|
1315
|
+
|
|
1316
|
+
### claw.createWebhook(webhook)
|
|
1317
|
+
Create a new webhook subscription.
|
|
1318
|
+
|
|
1319
|
+
**Parameters:**
|
|
1320
|
+
| Parameter | Type | Required | Description |
|
|
1321
|
+
|-----------|------|----------|-------------|
|
|
1322
|
+
| url | string | Yes | Webhook endpoint URL |
|
|
1323
|
+
| events | string[] | No | Event types to subscribe to |
|
|
1324
|
+
|
|
1325
|
+
**Returns:** `Promise<{webhook: Object}>`
|
|
1326
|
+
|
|
1327
|
+
### claw.deleteWebhook(webhookId)
|
|
1328
|
+
Delete a webhook.
|
|
1329
|
+
|
|
1330
|
+
**Parameters:**
|
|
1331
|
+
| Parameter | Type | Required | Description |
|
|
1332
|
+
|-----------|------|----------|-------------|
|
|
1333
|
+
| webhookId | string | Yes | Webhook ID |
|
|
1334
|
+
|
|
1335
|
+
**Returns:** `Promise<{deleted: boolean}>`
|
|
1336
|
+
|
|
1337
|
+
### claw.testWebhook(webhookId)
|
|
1338
|
+
Send a test event to a webhook to verify connectivity.
|
|
1339
|
+
|
|
1340
|
+
**Parameters:**
|
|
1341
|
+
| Parameter | Type | Required | Description |
|
|
1342
|
+
|-----------|------|----------|-------------|
|
|
1343
|
+
| webhookId | string | Yes | Webhook ID |
|
|
1344
|
+
|
|
1345
|
+
**Returns:** `Promise<{delivery: Object}>`
|
|
1346
|
+
|
|
1347
|
+
### claw.getWebhookDeliveries(webhookId)
|
|
1348
|
+
Get delivery history for a webhook.
|
|
1349
|
+
|
|
1350
|
+
**Parameters:**
|
|
1351
|
+
| Parameter | Type | Required | Description |
|
|
1352
|
+
|-----------|------|----------|-------------|
|
|
1353
|
+
| webhookId | string | Yes | Webhook ID |
|
|
1354
|
+
|
|
1355
|
+
**Returns:** `Promise<{deliveries: Object[]}>`
|
|
1356
|
+
|
|
726
1357
|
---
|
|
727
1358
|
|
|
728
1359
|
## Bulk Sync
|
|
@@ -959,6 +1590,49 @@ Get routing system health status and diagnostics.
|
|
|
959
1590
|
|
|
960
1591
|
---
|
|
961
1592
|
|
|
1593
|
+
## Agent Schedules
|
|
1594
|
+
|
|
1595
|
+
Define recurring tasks and cron-based schedules for agents.
|
|
1596
|
+
|
|
1597
|
+
### claw.listAgentSchedules(filters?)
|
|
1598
|
+
List agent schedules, optionally filtered by agent.
|
|
1599
|
+
|
|
1600
|
+
```javascript
|
|
1601
|
+
const { schedules } = await claw.listAgentSchedules({ agent_id: 'forge' });
|
|
1602
|
+
```
|
|
1603
|
+
|
|
1604
|
+
**Parameters:**
|
|
1605
|
+
| Parameter | Type | Required | Description |
|
|
1606
|
+
|-----------|------|----------|-------------|
|
|
1607
|
+
| filters.agent_id | string | No | Filter by agent ID |
|
|
1608
|
+
|
|
1609
|
+
**Returns:** `Promise<{ schedules: Object[] }>`
|
|
1610
|
+
|
|
1611
|
+
### claw.createAgentSchedule(schedule)
|
|
1612
|
+
Create a new agent schedule entry.
|
|
1613
|
+
|
|
1614
|
+
```javascript
|
|
1615
|
+
const { schedule } = await claw.createAgentSchedule({
|
|
1616
|
+
agent_id: 'forge',
|
|
1617
|
+
name: 'Build projects',
|
|
1618
|
+
cron_expression: '0 */6 * * *',
|
|
1619
|
+
description: 'Check for pending builds every 6 hours'
|
|
1620
|
+
});
|
|
1621
|
+
```
|
|
1622
|
+
|
|
1623
|
+
**Parameters:**
|
|
1624
|
+
| Parameter | Type | Required | Description |
|
|
1625
|
+
|-----------|------|----------|-------------|
|
|
1626
|
+
| schedule.agent_id | string | Yes | Agent this schedule belongs to |
|
|
1627
|
+
| schedule.name | string | Yes | Schedule name |
|
|
1628
|
+
| schedule.cron_expression | string | Yes | Cron expression (e.g. `0 */6 * * *`) |
|
|
1629
|
+
| schedule.description | string | No | Human-readable description |
|
|
1630
|
+
| schedule.enabled | boolean | No | Whether schedule is active (default: true) |
|
|
1631
|
+
|
|
1632
|
+
**Returns:** `Promise<{ schedule: Object }>`
|
|
1633
|
+
|
|
1634
|
+
---
|
|
1635
|
+
|
|
962
1636
|
## Error Handling
|
|
963
1637
|
|
|
964
1638
|
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
|
-
*
|
|
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,210 @@ 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
|
+
* @param {Object} [options]
|
|
546
|
+
* @param {boolean} [options.reconnect=true] - Auto-reconnect on disconnect (resumes from last event ID)
|
|
547
|
+
* @param {number} [options.maxRetries=Infinity] - Max reconnection attempts before giving up
|
|
548
|
+
* @param {number} [options.retryInterval=3000] - Milliseconds between reconnection attempts
|
|
549
|
+
* @returns {{ on(eventType: string, callback: Function): this, close(): void, _promise: Promise<void> }}
|
|
550
|
+
*
|
|
551
|
+
* @example
|
|
552
|
+
* const stream = client.events();
|
|
553
|
+
* stream
|
|
554
|
+
* .on('action.created', (data) => console.log('New action:', data))
|
|
555
|
+
* .on('action.updated', (data) => console.log('Action updated:', data))
|
|
556
|
+
* .on('policy.updated', (data) => console.log('Policy changed:', data))
|
|
557
|
+
* .on('task.assigned', (data) => console.log('Task assigned:', data))
|
|
558
|
+
* .on('task.completed', (data) => console.log('Task done:', data))
|
|
559
|
+
* .on('reconnecting', ({ attempt }) => console.log(`Reconnecting #${attempt}...`))
|
|
560
|
+
* .on('error', (err) => console.error('Stream error:', err));
|
|
561
|
+
*
|
|
562
|
+
* // Later:
|
|
563
|
+
* stream.close();
|
|
564
|
+
*/
|
|
565
|
+
events({ reconnect = true, maxRetries = Infinity, retryInterval = 3000 } = {}) {
|
|
566
|
+
const url = `${this.baseUrl}/api/stream`;
|
|
567
|
+
const apiKey = this.apiKey;
|
|
568
|
+
|
|
569
|
+
const handlers = new Map();
|
|
570
|
+
let closed = false;
|
|
571
|
+
let controller = null;
|
|
572
|
+
let lastEventId = null;
|
|
573
|
+
let retryCount = 0;
|
|
574
|
+
|
|
575
|
+
const emit = (eventType, data) => {
|
|
576
|
+
const cbs = handlers.get(eventType) || [];
|
|
577
|
+
for (const cb of cbs) {
|
|
578
|
+
try { cb(data); } catch { /* ignore handler errors */ }
|
|
579
|
+
}
|
|
580
|
+
};
|
|
581
|
+
|
|
582
|
+
const connect = async () => {
|
|
583
|
+
controller = new AbortController();
|
|
584
|
+
const headers = { 'x-api-key': apiKey };
|
|
585
|
+
if (lastEventId) headers['last-event-id'] = lastEventId;
|
|
586
|
+
|
|
587
|
+
const res = await fetch(url, {
|
|
588
|
+
headers,
|
|
589
|
+
signal: controller.signal,
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
if (!res.ok) {
|
|
593
|
+
throw new Error(`SSE connection failed: ${res.status} ${res.statusText}`);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
retryCount = 0; // Reset on successful connection
|
|
597
|
+
|
|
598
|
+
const reader = res.body.getReader();
|
|
599
|
+
const decoder = new TextDecoder();
|
|
600
|
+
let buffer = '';
|
|
601
|
+
// Persist across reads so frames split across chunks are handled correctly
|
|
602
|
+
let currentEvent = null;
|
|
603
|
+
let currentData = '';
|
|
604
|
+
|
|
605
|
+
while (!closed) {
|
|
606
|
+
const { done, value } = await reader.read();
|
|
607
|
+
if (done) break;
|
|
608
|
+
buffer += decoder.decode(value, { stream: true });
|
|
609
|
+
|
|
610
|
+
// Parse SSE frames from buffer
|
|
611
|
+
const lines = buffer.split('\n');
|
|
612
|
+
buffer = lines.pop(); // Keep incomplete line in buffer
|
|
613
|
+
|
|
614
|
+
for (const line of lines) {
|
|
615
|
+
if (line.startsWith('id: ')) {
|
|
616
|
+
lastEventId = line.slice(4).trim();
|
|
617
|
+
} else if (line.startsWith('event: ')) {
|
|
618
|
+
currentEvent = line.slice(7).trim();
|
|
619
|
+
} else if (line.startsWith('data: ')) {
|
|
620
|
+
currentData += line.slice(6);
|
|
621
|
+
} else if (line.startsWith(':')) {
|
|
622
|
+
// SSE comment (keepalive heartbeat) — ignore
|
|
623
|
+
} else if (line === '' && currentEvent) {
|
|
624
|
+
// End of SSE frame — dispatch
|
|
625
|
+
if (currentData) {
|
|
626
|
+
try {
|
|
627
|
+
const parsed = JSON.parse(currentData);
|
|
628
|
+
emit(currentEvent, parsed);
|
|
629
|
+
} catch { /* ignore parse errors */ }
|
|
630
|
+
}
|
|
631
|
+
currentEvent = null;
|
|
632
|
+
currentData = '';
|
|
633
|
+
} else if (line === '') {
|
|
634
|
+
// Blank line without a pending event — reset partial state
|
|
635
|
+
currentEvent = null;
|
|
636
|
+
currentData = '';
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
};
|
|
641
|
+
|
|
642
|
+
const connectLoop = async () => {
|
|
643
|
+
while (!closed) {
|
|
644
|
+
try {
|
|
645
|
+
await connect();
|
|
646
|
+
} catch (err) {
|
|
647
|
+
if (closed) return;
|
|
648
|
+
emit('error', err);
|
|
649
|
+
}
|
|
650
|
+
// Stream ended (server closed, network drop, etc.)
|
|
651
|
+
if (closed) return;
|
|
652
|
+
if (!reconnect || retryCount >= maxRetries) {
|
|
653
|
+
emit('error', new Error('SSE stream ended'));
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
retryCount++;
|
|
657
|
+
emit('reconnecting', { attempt: retryCount, maxRetries });
|
|
658
|
+
await new Promise((r) => setTimeout(r, retryInterval));
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
const connectionPromise = connectLoop();
|
|
663
|
+
|
|
664
|
+
const handle = {
|
|
665
|
+
on(eventType, callback) {
|
|
666
|
+
if (!handlers.has(eventType)) handlers.set(eventType, []);
|
|
667
|
+
handlers.get(eventType).push(callback);
|
|
668
|
+
return handle;
|
|
669
|
+
},
|
|
670
|
+
close() {
|
|
671
|
+
closed = true;
|
|
672
|
+
if (controller) controller.abort();
|
|
673
|
+
},
|
|
674
|
+
_promise: connectionPromise,
|
|
675
|
+
};
|
|
676
|
+
|
|
677
|
+
return handle;
|
|
678
|
+
}
|
|
679
|
+
|
|
493
680
|
/**
|
|
494
681
|
* Update the outcome of an existing action.
|
|
495
682
|
* @param {string} actionId - The action_id to update
|
|
@@ -1346,7 +1533,7 @@ class DashClaw {
|
|
|
1346
1533
|
}
|
|
1347
1534
|
|
|
1348
1535
|
// ══════════════════════════════════════════════
|
|
1349
|
-
// Category 11: Agent Messaging (
|
|
1536
|
+
// Category 11: Agent Messaging (11 methods)
|
|
1350
1537
|
// ══════════════════════════════════════════════
|
|
1351
1538
|
|
|
1352
1539
|
/**
|
|
@@ -1359,10 +1546,11 @@ class DashClaw {
|
|
|
1359
1546
|
* @param {string} [params.threadId] - Thread ID to attach message to
|
|
1360
1547
|
* @param {boolean} [params.urgent=false] - Mark as urgent
|
|
1361
1548
|
* @param {string} [params.docRef] - Reference to a shared doc ID
|
|
1549
|
+
* @param {Array<{filename: string, mime_type: string, data: string}>} [params.attachments] - File attachments (base64 data, max 3, max 5MB each)
|
|
1362
1550
|
* @returns {Promise<{message: Object, message_id: string}>}
|
|
1363
1551
|
*/
|
|
1364
|
-
async sendMessage({ to, type, subject, body, threadId, urgent, docRef }) {
|
|
1365
|
-
|
|
1552
|
+
async sendMessage({ to, type, subject, body, threadId, urgent, docRef, attachments }) {
|
|
1553
|
+
const payload = {
|
|
1366
1554
|
from_agent_id: this.agentId,
|
|
1367
1555
|
to_agent_id: to || null,
|
|
1368
1556
|
message_type: type || 'info',
|
|
@@ -1371,7 +1559,9 @@ class DashClaw {
|
|
|
1371
1559
|
thread_id: threadId,
|
|
1372
1560
|
urgent,
|
|
1373
1561
|
doc_ref: docRef,
|
|
1374
|
-
}
|
|
1562
|
+
};
|
|
1563
|
+
if (attachments?.length) payload.attachments = attachments;
|
|
1564
|
+
return this._request('/api/messages', 'POST', payload);
|
|
1375
1565
|
}
|
|
1376
1566
|
|
|
1377
1567
|
/**
|
|
@@ -1493,6 +1683,39 @@ class DashClaw {
|
|
|
1493
1683
|
});
|
|
1494
1684
|
}
|
|
1495
1685
|
|
|
1686
|
+
/**
|
|
1687
|
+
* Get an attachment's download URL or fetch its binary data.
|
|
1688
|
+
* @param {string} attachmentId - Attachment ID (att_*)
|
|
1689
|
+
* @returns {string} URL to fetch the attachment
|
|
1690
|
+
*/
|
|
1691
|
+
getAttachmentUrl(attachmentId) {
|
|
1692
|
+
return `${this.baseUrl}/api/messages/attachments?id=${encodeURIComponent(attachmentId)}`;
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
/**
|
|
1696
|
+
* Download an attachment as a Buffer.
|
|
1697
|
+
* @param {string} attachmentId - Attachment ID (att_*)
|
|
1698
|
+
* @returns {Promise<{data: Buffer, filename: string, mimeType: string}>}
|
|
1699
|
+
*/
|
|
1700
|
+
async getAttachment(attachmentId) {
|
|
1701
|
+
const url = this.getAttachmentUrl(attachmentId);
|
|
1702
|
+
const res = await fetch(url, {
|
|
1703
|
+
headers: { 'x-api-key': this.apiKey },
|
|
1704
|
+
});
|
|
1705
|
+
if (!res.ok) {
|
|
1706
|
+
const err = await res.json().catch(() => ({}));
|
|
1707
|
+
throw new Error(err.error || `Attachment fetch failed: ${res.status}`);
|
|
1708
|
+
}
|
|
1709
|
+
const data = Buffer.from(await res.arrayBuffer());
|
|
1710
|
+
const cd = res.headers.get('content-disposition') || '';
|
|
1711
|
+
const match = cd.match(/filename="(.+?)"/);
|
|
1712
|
+
return {
|
|
1713
|
+
data,
|
|
1714
|
+
filename: match ? match[1] : attachmentId,
|
|
1715
|
+
mimeType: res.headers.get('content-type') || 'application/octet-stream',
|
|
1716
|
+
};
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1496
1719
|
// ══════════════════════════════════════════════
|
|
1497
1720
|
// Category 13: Behavior Guard (2 methods)
|
|
1498
1721
|
// ══════════════════════════════════════════════
|
|
@@ -1747,6 +1970,165 @@ class DashClaw {
|
|
|
1747
1970
|
return this._request('/api/routing/health', 'GET');
|
|
1748
1971
|
}
|
|
1749
1972
|
|
|
1973
|
+
// ══════════════════════════════════════════════════════════
|
|
1974
|
+
// Agent Pairing (3 methods)
|
|
1975
|
+
// ══════════════════════════════════════════════════════════
|
|
1976
|
+
|
|
1977
|
+
// createPairing, createPairingFromPrivateJwk, waitForPairing
|
|
1978
|
+
// (defined near the top of the class)
|
|
1979
|
+
|
|
1980
|
+
// ══════════════════════════════════════════════════════════
|
|
1981
|
+
// Identity Binding (2 methods)
|
|
1982
|
+
// ══════════════════════════════════════════════════════════
|
|
1983
|
+
|
|
1984
|
+
/**
|
|
1985
|
+
* Register or update an agent's public key for identity verification.
|
|
1986
|
+
* Requires admin API key.
|
|
1987
|
+
* @param {Object} identity
|
|
1988
|
+
* @param {string} identity.agent_id - Agent ID to register
|
|
1989
|
+
* @param {string} identity.public_key - PEM public key (SPKI format)
|
|
1990
|
+
* @param {string} [identity.algorithm='RSASSA-PKCS1-v1_5'] - Signing algorithm
|
|
1991
|
+
* @returns {Promise<{identity: Object}>}
|
|
1992
|
+
*/
|
|
1993
|
+
async registerIdentity(identity) {
|
|
1994
|
+
return this._request('/api/identities', 'POST', identity);
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
/**
|
|
1998
|
+
* List all registered agent identities for this org.
|
|
1999
|
+
* @returns {Promise<{identities: Object[]}>}
|
|
2000
|
+
*/
|
|
2001
|
+
async getIdentities() {
|
|
2002
|
+
return this._request('/api/identities', 'GET');
|
|
2003
|
+
}
|
|
2004
|
+
|
|
2005
|
+
// ══════════════════════════════════════════════════════════
|
|
2006
|
+
// Organization Management (5 methods)
|
|
2007
|
+
// ══════════════════════════════════════════════════════════
|
|
2008
|
+
|
|
2009
|
+
/**
|
|
2010
|
+
* Get the current organization's details. Requires admin API key.
|
|
2011
|
+
* @returns {Promise<{organizations: Object[]}>}
|
|
2012
|
+
*/
|
|
2013
|
+
async getOrg() {
|
|
2014
|
+
return this._request('/api/orgs', 'GET');
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
/**
|
|
2018
|
+
* Create a new organization with an initial admin API key. Requires admin API key.
|
|
2019
|
+
* @param {Object} org
|
|
2020
|
+
* @param {string} org.name - Organization name
|
|
2021
|
+
* @param {string} org.slug - URL-safe slug (lowercase alphanumeric + hyphens)
|
|
2022
|
+
* @returns {Promise<{organization: Object, api_key: Object}>}
|
|
2023
|
+
*/
|
|
2024
|
+
async createOrg(org) {
|
|
2025
|
+
return this._request('/api/orgs', 'POST', org);
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
/**
|
|
2029
|
+
* Get organization details by ID. Requires admin API key.
|
|
2030
|
+
* @param {string} orgId - Organization ID
|
|
2031
|
+
* @returns {Promise<{organization: Object}>}
|
|
2032
|
+
*/
|
|
2033
|
+
async getOrgById(orgId) {
|
|
2034
|
+
return this._request(`/api/orgs/${encodeURIComponent(orgId)}`, 'GET');
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
/**
|
|
2038
|
+
* Update organization details. Requires admin API key.
|
|
2039
|
+
* @param {string} orgId - Organization ID
|
|
2040
|
+
* @param {Object} updates - Fields to update (name, slug)
|
|
2041
|
+
* @returns {Promise<{organization: Object}>}
|
|
2042
|
+
*/
|
|
2043
|
+
async updateOrg(orgId, updates) {
|
|
2044
|
+
return this._request(`/api/orgs/${encodeURIComponent(orgId)}`, 'PATCH', updates);
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
/**
|
|
2048
|
+
* List API keys for an organization. Requires admin API key.
|
|
2049
|
+
* @param {string} orgId - Organization ID
|
|
2050
|
+
* @returns {Promise<{keys: Object[]}>}
|
|
2051
|
+
*/
|
|
2052
|
+
async getOrgKeys(orgId) {
|
|
2053
|
+
return this._request(`/api/orgs/${encodeURIComponent(orgId)}/keys`, 'GET');
|
|
2054
|
+
}
|
|
2055
|
+
|
|
2056
|
+
// ══════════════════════════════════════════════════════════
|
|
2057
|
+
// Activity Logs (1 method)
|
|
2058
|
+
// ══════════════════════════════════════════════════════════
|
|
2059
|
+
|
|
2060
|
+
/**
|
|
2061
|
+
* Get activity/audit logs for the organization.
|
|
2062
|
+
* @param {Object} [filters]
|
|
2063
|
+
* @param {string} [filters.action] - Filter by action type
|
|
2064
|
+
* @param {string} [filters.actor_id] - Filter by actor
|
|
2065
|
+
* @param {string} [filters.resource_type] - Filter by resource type
|
|
2066
|
+
* @param {string} [filters.before] - Before timestamp (ISO string)
|
|
2067
|
+
* @param {string} [filters.after] - After timestamp (ISO string)
|
|
2068
|
+
* @param {number} [filters.limit=50] - Max results (max 200)
|
|
2069
|
+
* @param {number} [filters.offset=0] - Pagination offset
|
|
2070
|
+
* @returns {Promise<{logs: Object[], stats: Object, pagination: Object}>}
|
|
2071
|
+
*/
|
|
2072
|
+
async getActivityLogs(filters = {}) {
|
|
2073
|
+
const params = new URLSearchParams();
|
|
2074
|
+
for (const [key, value] of Object.entries(filters)) {
|
|
2075
|
+
if (value !== undefined && value !== null && value !== '') {
|
|
2076
|
+
params.set(key, String(value));
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
return this._request(`/api/activity?${params}`, 'GET');
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
// ══════════════════════════════════════════════════════════
|
|
2083
|
+
// Webhooks (5 methods)
|
|
2084
|
+
// ══════════════════════════════════════════════════════════
|
|
2085
|
+
|
|
2086
|
+
/**
|
|
2087
|
+
* List all webhooks for this org.
|
|
2088
|
+
* @returns {Promise<{webhooks: Object[]}>}
|
|
2089
|
+
*/
|
|
2090
|
+
async getWebhooks() {
|
|
2091
|
+
return this._request('/api/webhooks', 'GET');
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
/**
|
|
2095
|
+
* Create a new webhook subscription.
|
|
2096
|
+
* @param {Object} webhook
|
|
2097
|
+
* @param {string} webhook.url - Webhook endpoint URL
|
|
2098
|
+
* @param {string[]} [webhook.events] - Event types to subscribe to
|
|
2099
|
+
* @returns {Promise<{webhook: Object}>}
|
|
2100
|
+
*/
|
|
2101
|
+
async createWebhook(webhook) {
|
|
2102
|
+
return this._request('/api/webhooks', 'POST', webhook);
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
/**
|
|
2106
|
+
* Delete a webhook.
|
|
2107
|
+
* @param {string} webhookId - Webhook ID
|
|
2108
|
+
* @returns {Promise<{deleted: boolean}>}
|
|
2109
|
+
*/
|
|
2110
|
+
async deleteWebhook(webhookId) {
|
|
2111
|
+
return this._request(`/api/webhooks?id=${encodeURIComponent(webhookId)}`, 'DELETE');
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
/**
|
|
2115
|
+
* Send a test event to a webhook.
|
|
2116
|
+
* @param {string} webhookId - Webhook ID
|
|
2117
|
+
* @returns {Promise<{delivery: Object}>}
|
|
2118
|
+
*/
|
|
2119
|
+
async testWebhook(webhookId) {
|
|
2120
|
+
return this._request(`/api/webhooks/${encodeURIComponent(webhookId)}/test`, 'POST');
|
|
2121
|
+
}
|
|
2122
|
+
|
|
2123
|
+
/**
|
|
2124
|
+
* Get delivery history for a webhook.
|
|
2125
|
+
* @param {string} webhookId - Webhook ID
|
|
2126
|
+
* @returns {Promise<{deliveries: Object[]}>}
|
|
2127
|
+
*/
|
|
2128
|
+
async getWebhookDeliveries(webhookId) {
|
|
2129
|
+
return this._request(`/api/webhooks/${encodeURIComponent(webhookId)}/deliveries`, 'GET');
|
|
2130
|
+
}
|
|
2131
|
+
|
|
1750
2132
|
// ─── Bulk Sync ────────────────────────────────────────────
|
|
1751
2133
|
|
|
1752
2134
|
/**
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dashclaw",
|
|
3
|
-
"version": "1.8.
|
|
4
|
-
"description": "Full-featured agent toolkit for the DashClaw platform.
|
|
3
|
+
"version": "1.8.2",
|
|
4
|
+
"description": "Full-featured agent toolkit for the DashClaw platform. 96+ methods across 22+ 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"
|