dashclaw 1.8.1 → 1.8.3
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 +125 -8
- package/dashclaw.js +109 -36
- package/index.cjs +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
# DashClaw SDK
|
|
1
|
+
# DashClaw SDK: Agent Decision Infrastructure
|
|
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
|
-
|
|
5
|
+
DashClaw treats every agent action as a governed decision. The SDK provides decision recording, policy enforcement, assumption tracking, and compliance mapping. It proves what your agents decided and why.
|
|
6
|
+
|
|
7
|
+
Install, configure, and govern 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
8
|
|
|
7
9
|
---
|
|
8
10
|
|
|
@@ -111,11 +113,93 @@ try {
|
|
|
111
113
|
}
|
|
112
114
|
```
|
|
113
115
|
|
|
116
|
+
### Compliance & Governance Patterns
|
|
117
|
+
|
|
118
|
+
DashClaw's guard + action recording pipeline maps directly to compliance controls.
|
|
119
|
+
|
|
120
|
+
**SOC 2 CC6.1: Logical Access Controls**
|
|
121
|
+
```javascript
|
|
122
|
+
// Before any high-risk operation, enforce policy
|
|
123
|
+
const guardResult = await claw.guard({
|
|
124
|
+
action_type: 'database_write',
|
|
125
|
+
risk_score: 85,
|
|
126
|
+
systems_touched: ['production_db'],
|
|
127
|
+
reversible: false,
|
|
128
|
+
declared_goal: 'Drop legacy user table'
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
if (guardResult.decision === 'block') {
|
|
132
|
+
// SOC 2 control satisfied: unauthorized action prevented
|
|
133
|
+
console.log('Policy blocked:', guardResult.reasons);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Decision is governed. Record with full lineage
|
|
138
|
+
const { action_id } = await claw.createAction({
|
|
139
|
+
action_type: 'database_write',
|
|
140
|
+
declared_goal: 'Drop legacy user table',
|
|
141
|
+
risk_score: 85,
|
|
142
|
+
reversible: false,
|
|
143
|
+
authorization_scope: 'admin-approved'
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Register the assumption this decision relies on
|
|
147
|
+
await claw.registerAssumption({
|
|
148
|
+
action_id,
|
|
149
|
+
assumption: 'Legacy table has zero active references',
|
|
150
|
+
basis: 'Schema dependency scan completed 2h ago'
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**EU AI Act Article 14: Human Oversight**
|
|
155
|
+
```javascript
|
|
156
|
+
// require_approval forces human-in-the-loop
|
|
157
|
+
const result = await claw.guard({
|
|
158
|
+
action_type: 'customer_communication',
|
|
159
|
+
risk_score: 60,
|
|
160
|
+
declared_goal: 'Send pricing update to 500 customers'
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
if (result.decision === 'require_approval') {
|
|
164
|
+
// Create action in pending state, wait for human approval
|
|
165
|
+
const { action_id } = await claw.createAction({
|
|
166
|
+
action_type: 'customer_communication',
|
|
167
|
+
declared_goal: 'Send pricing update to 500 customers',
|
|
168
|
+
status: 'pending'
|
|
169
|
+
});
|
|
170
|
+
// Approval queue at /approvals shows this to operators
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**ISO 42001: AI Decision Accountability**
|
|
175
|
+
```javascript
|
|
176
|
+
// Full decision lineage: guard → action → assumptions → outcome
|
|
177
|
+
const { action_id } = await claw.createAction({
|
|
178
|
+
action_type: 'data_processing',
|
|
179
|
+
declared_goal: 'Rebuild customer segmentation model',
|
|
180
|
+
risk_score: 45,
|
|
181
|
+
systems_touched: ['ml-pipeline', 'customer-db']
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
await claw.registerAssumption({
|
|
185
|
+
action_id,
|
|
186
|
+
assumption: 'Customer data is current as of today',
|
|
187
|
+
basis: 'CRM sync completed at 09:00 UTC'
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// Later: validate or invalidate assumptions
|
|
191
|
+
await claw.validateAssumption(assumptionId, true);
|
|
192
|
+
|
|
193
|
+
// Decision integrity signals auto-detect when assumptions drift
|
|
194
|
+
const signals = await claw.getSignals();
|
|
195
|
+
// → Returns 'assumption_drift' if too many invalidated
|
|
196
|
+
```
|
|
197
|
+
|
|
114
198
|
---
|
|
115
199
|
|
|
116
200
|
## Action Recording
|
|
117
201
|
|
|
118
|
-
Create, update, and query action records. Every agent action
|
|
202
|
+
Create, update, and query action records. Every agent action is a governed decision with a full audit trail capturing intent, reasoning, and outcome for compliance and review.
|
|
119
203
|
|
|
120
204
|
### claw.createAction(action)
|
|
121
205
|
Create a new action record. The agent's agentId, agentName, and swarmId are automatically attached.
|
|
@@ -268,7 +352,7 @@ stream.close();
|
|
|
268
352
|
|
|
269
353
|
### claw.waitForApproval(actionId, { useEvents: true })
|
|
270
354
|
|
|
271
|
-
SSE-powered approval waiting
|
|
355
|
+
SSE-powered approval waiting. Resolves instantly when the operator approves/denies instead of polling every 5 seconds.
|
|
272
356
|
|
|
273
357
|
```javascript
|
|
274
358
|
// SSE mode (instant, recommended)
|
|
@@ -280,7 +364,7 @@ const { action } = await claw.waitForApproval('act_abc');
|
|
|
280
364
|
|
|
281
365
|
| Parameter | Type | Default | Description |
|
|
282
366
|
|-----------|------|---------|-------------|
|
|
283
|
-
| actionId | string |
|
|
367
|
+
| actionId | string | Yes | Action ID to watch |
|
|
284
368
|
| options.timeout | number | 300000 | Max wait time (ms) |
|
|
285
369
|
| options.interval | number | 5000 | Poll interval (polling mode only) |
|
|
286
370
|
| options.useEvents | boolean | false | Use SSE instead of polling |
|
|
@@ -425,7 +509,7 @@ Get current risk signals across all agents. Returns 7 signal types: autonomy_spi
|
|
|
425
509
|
|
|
426
510
|
## Behavior Guard
|
|
427
511
|
|
|
428
|
-
|
|
512
|
+
Guard is the heart of DashClaw. Every action can be checked against policies before execution. Returns allow, warn, block, or require_approval based on configured guard policies.
|
|
429
513
|
|
|
430
514
|
### claw.guard(context, options?)
|
|
431
515
|
Evaluate guard policies for a proposed action. Call this before risky operations to get a go/no-go decision. The agent_id is auto-attached from the SDK constructor.
|
|
@@ -1026,6 +1110,7 @@ Send a message to another agent or broadcast.
|
|
|
1026
1110
|
| threadId | string | No | Thread ID to attach to |
|
|
1027
1111
|
| urgent | boolean | No | Mark as urgent |
|
|
1028
1112
|
| docRef | string | No | Reference to a shared doc ID |
|
|
1113
|
+
| attachments | Array<{filename, mime_type, data}> | No | File attachments (base64, max 3, max 5MB each) |
|
|
1029
1114
|
|
|
1030
1115
|
**Returns:** `Promise<{message: Object, message_id: string}>`
|
|
1031
1116
|
|
|
@@ -1119,6 +1204,38 @@ Create or update a shared workspace document. Upserts by name.
|
|
|
1119
1204
|
|
|
1120
1205
|
**Returns:** `Promise<{doc: Object, doc_id: string}>`
|
|
1121
1206
|
|
|
1207
|
+
### claw.getAttachmentUrl(attachmentId)
|
|
1208
|
+
|
|
1209
|
+
Get a URL to download an attachment.
|
|
1210
|
+
|
|
1211
|
+
| Parameter | Type | Description |
|
|
1212
|
+
|---|---|---|
|
|
1213
|
+
| `attachmentId` | `string` | Attachment ID (`att_*`) |
|
|
1214
|
+
|
|
1215
|
+
**Returns:** `string`: URL to fetch the attachment binary
|
|
1216
|
+
|
|
1217
|
+
---
|
|
1218
|
+
|
|
1219
|
+
### claw.getAttachment(attachmentId)
|
|
1220
|
+
|
|
1221
|
+
Download an attachment as a Buffer.
|
|
1222
|
+
|
|
1223
|
+
| Parameter | Type | Description |
|
|
1224
|
+
|---|---|---|
|
|
1225
|
+
| `attachmentId` | `string` | Attachment ID (`att_*`) |
|
|
1226
|
+
|
|
1227
|
+
**Returns:** `Promise<{ data: Buffer, filename: string, mimeType: string }>`
|
|
1228
|
+
|
|
1229
|
+
```js
|
|
1230
|
+
const inbox = await claw.getInbox();
|
|
1231
|
+
for (const msg of inbox.messages) {
|
|
1232
|
+
for (const att of msg.attachments || []) {
|
|
1233
|
+
const { data, filename } = await claw.getAttachment(att.id);
|
|
1234
|
+
fs.writeFileSync(filename, data);
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
```
|
|
1238
|
+
|
|
1122
1239
|
---
|
|
1123
1240
|
|
|
1124
1241
|
## Agent Pairing
|
|
@@ -1346,7 +1463,7 @@ Run guardrails tests against all active policies. Returns pass/fail results per
|
|
|
1346
1463
|
const report = await claw.testPolicies();
|
|
1347
1464
|
console.log(`${report.passed}/${report.total} policies passed`);
|
|
1348
1465
|
for (const r of report.results.filter(r => !r.passed)) {
|
|
1349
|
-
console.log(`FAIL: ${r.policy}
|
|
1466
|
+
console.log(`FAIL: ${r.policy}: ${r.reason}`);
|
|
1350
1467
|
}
|
|
1351
1468
|
```
|
|
1352
1469
|
|
|
@@ -1392,7 +1509,7 @@ Map active policies to framework controls. Returns a control-by-control coverage
|
|
|
1392
1509
|
const { controls, coverage_pct } = await claw.mapCompliance('soc2');
|
|
1393
1510
|
console.log(`SOC 2 coverage: ${coverage_pct}%`);
|
|
1394
1511
|
for (const ctrl of controls.filter(c => !c.covered)) {
|
|
1395
|
-
console.log(`Gap: ${ctrl.id}
|
|
1512
|
+
console.log(`Gap: ${ctrl.id}: ${ctrl.name}`);
|
|
1396
1513
|
}
|
|
1397
1514
|
```
|
|
1398
1515
|
|
package/dashclaw.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* DashClaw SDK
|
|
3
3
|
* Full-featured agent toolkit for the DashClaw platform.
|
|
4
|
-
* Zero-dependency ESM SDK
|
|
4
|
+
* Zero-dependency ESM SDK. Requires Node 18+ (native fetch).
|
|
5
5
|
*
|
|
6
6
|
* 96+ methods across 22+ categories:
|
|
7
7
|
* - Action Recording (7)
|
|
@@ -217,7 +217,7 @@ class DashClaw {
|
|
|
217
217
|
try {
|
|
218
218
|
decision = await this.guard(context);
|
|
219
219
|
} catch (err) {
|
|
220
|
-
// Guard API failure is fail-open
|
|
220
|
+
// Guard API failure is fail-open: log and proceed
|
|
221
221
|
console.warn(`[DashClaw] Guard check failed (proceeding): ${err.message}`);
|
|
222
222
|
return;
|
|
223
223
|
}
|
|
@@ -403,11 +403,11 @@ class DashClaw {
|
|
|
403
403
|
}
|
|
404
404
|
|
|
405
405
|
// ══════════════════════════════════════════════
|
|
406
|
-
// Category 1:
|
|
406
|
+
// Category 1: Decision Recording (6 methods)
|
|
407
407
|
// ══════════════════════════════════════════════
|
|
408
408
|
|
|
409
409
|
/**
|
|
410
|
-
*
|
|
410
|
+
* Record a governed decision. Every action is a decision with a full audit trail: goal, reasoning, assumptions, and policy compliance.
|
|
411
411
|
* @param {Object} action
|
|
412
412
|
* @param {string} action.action_type - One of: build, deploy, post, apply, security, message, api, calendar, research, review, fix, refactor, test, config, monitor, alert, cleanup, sync, migrate, other
|
|
413
413
|
* @param {string} action.declared_goal - What this action aims to accomplish
|
|
@@ -542,6 +542,10 @@ class DashClaw {
|
|
|
542
542
|
* Subscribe to real-time SSE events from the DashClaw server.
|
|
543
543
|
* Uses fetch-based SSE parsing for Node 18+ compatibility (no native EventSource required).
|
|
544
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
|
|
545
549
|
* @returns {{ on(eventType: string, callback: Function): this, close(): void, _promise: Promise<void> }}
|
|
546
550
|
*
|
|
547
551
|
* @example
|
|
@@ -552,23 +556,36 @@ class DashClaw {
|
|
|
552
556
|
* .on('policy.updated', (data) => console.log('Policy changed:', data))
|
|
553
557
|
* .on('task.assigned', (data) => console.log('Task assigned:', data))
|
|
554
558
|
* .on('task.completed', (data) => console.log('Task done:', data))
|
|
559
|
+
* .on('reconnecting', ({ attempt }) => console.log(`Reconnecting #${attempt}...`))
|
|
555
560
|
* .on('error', (err) => console.error('Stream error:', err));
|
|
556
561
|
*
|
|
557
562
|
* // Later:
|
|
558
563
|
* stream.close();
|
|
559
564
|
*/
|
|
560
|
-
events() {
|
|
565
|
+
events({ reconnect = true, maxRetries = Infinity, retryInterval = 3000 } = {}) {
|
|
561
566
|
const url = `${this.baseUrl}/api/stream`;
|
|
562
567
|
const apiKey = this.apiKey;
|
|
563
568
|
|
|
564
569
|
const handlers = new Map();
|
|
565
570
|
let closed = false;
|
|
566
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
|
+
};
|
|
567
581
|
|
|
568
582
|
const connect = async () => {
|
|
569
583
|
controller = new AbortController();
|
|
584
|
+
const headers = { 'x-api-key': apiKey };
|
|
585
|
+
if (lastEventId) headers['last-event-id'] = lastEventId;
|
|
586
|
+
|
|
570
587
|
const res = await fetch(url, {
|
|
571
|
-
headers
|
|
588
|
+
headers,
|
|
572
589
|
signal: controller.signal,
|
|
573
590
|
});
|
|
574
591
|
|
|
@@ -576,9 +593,14 @@ class DashClaw {
|
|
|
576
593
|
throw new Error(`SSE connection failed: ${res.status} ${res.statusText}`);
|
|
577
594
|
}
|
|
578
595
|
|
|
596
|
+
retryCount = 0; // Reset on successful connection
|
|
597
|
+
|
|
579
598
|
const reader = res.body.getReader();
|
|
580
599
|
const decoder = new TextDecoder();
|
|
581
600
|
let buffer = '';
|
|
601
|
+
// Persist across reads so frames split across chunks are handled correctly
|
|
602
|
+
let currentEvent = null;
|
|
603
|
+
let currentData = '';
|
|
582
604
|
|
|
583
605
|
while (!closed) {
|
|
584
606
|
const { done, value } = await reader.read();
|
|
@@ -589,39 +611,55 @@ class DashClaw {
|
|
|
589
611
|
const lines = buffer.split('\n');
|
|
590
612
|
buffer = lines.pop(); // Keep incomplete line in buffer
|
|
591
613
|
|
|
592
|
-
let currentEvent = null;
|
|
593
|
-
let currentData = '';
|
|
594
|
-
|
|
595
614
|
for (const line of lines) {
|
|
596
|
-
if (line.startsWith('
|
|
615
|
+
if (line.startsWith('id: ')) {
|
|
616
|
+
lastEventId = line.slice(4).trim();
|
|
617
|
+
} else if (line.startsWith('event: ')) {
|
|
597
618
|
currentEvent = line.slice(7).trim();
|
|
598
619
|
} else if (line.startsWith('data: ')) {
|
|
599
620
|
currentData += line.slice(6);
|
|
621
|
+
} else if (line.startsWith(':')) {
|
|
622
|
+
// SSE comment (keepalive heartbeat). Ignore.
|
|
600
623
|
} else if (line === '' && currentEvent) {
|
|
601
|
-
// End of SSE frame
|
|
602
|
-
|
|
603
|
-
if (eventHandlers.length > 0 && currentData) {
|
|
624
|
+
// End of SSE frame. Dispatch.
|
|
625
|
+
if (currentData) {
|
|
604
626
|
try {
|
|
605
627
|
const parsed = JSON.parse(currentData);
|
|
606
|
-
|
|
607
|
-
try { cb(parsed); } catch { /* ignore handler errors */ }
|
|
608
|
-
}
|
|
628
|
+
emit(currentEvent, parsed);
|
|
609
629
|
} catch { /* ignore parse errors */ }
|
|
610
630
|
}
|
|
611
631
|
currentEvent = null;
|
|
612
632
|
currentData = '';
|
|
633
|
+
} else if (line === '') {
|
|
634
|
+
// Blank line without a pending event. Reset partial state.
|
|
635
|
+
currentEvent = null;
|
|
636
|
+
currentData = '';
|
|
613
637
|
}
|
|
614
638
|
}
|
|
615
639
|
}
|
|
616
640
|
};
|
|
617
641
|
|
|
618
|
-
const
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
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));
|
|
623
659
|
}
|
|
624
|
-
}
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
const connectionPromise = connectLoop();
|
|
625
663
|
|
|
626
664
|
const handle = {
|
|
627
665
|
on(eventType, callback) {
|
|
@@ -728,11 +766,11 @@ class DashClaw {
|
|
|
728
766
|
}
|
|
729
767
|
|
|
730
768
|
// ══════════════════════════════════════════════
|
|
731
|
-
// Category 2: Loops & Assumptions (7 methods)
|
|
769
|
+
// Category 2: Decision Integrity (Loops & Assumptions) (7 methods)
|
|
732
770
|
// ══════════════════════════════════════════════
|
|
733
771
|
|
|
734
772
|
/**
|
|
735
|
-
* Register an
|
|
773
|
+
* Register an unresolved dependency for a decision. Open loops track work that must be completed before the decision can be considered fully resolved.
|
|
736
774
|
* @param {Object} loop
|
|
737
775
|
* @param {string} loop.action_id - Parent action ID
|
|
738
776
|
* @param {string} loop.loop_type - One of: followup, question, dependency, approval, review, handoff, other
|
|
@@ -779,7 +817,7 @@ class DashClaw {
|
|
|
779
817
|
}
|
|
780
818
|
|
|
781
819
|
/**
|
|
782
|
-
* Register assumptions
|
|
820
|
+
* Register assumptions underlying a decision. Assumptions are the decision basis. They must be validated or invalidated to maintain decision integrity.
|
|
783
821
|
* @param {Object} assumption
|
|
784
822
|
* @param {string} assumption.action_id - Parent action ID
|
|
785
823
|
* @param {string} assumption.assumption - The assumption being made
|
|
@@ -835,11 +873,11 @@ class DashClaw {
|
|
|
835
873
|
}
|
|
836
874
|
|
|
837
875
|
// ══════════════════════════════════════════════
|
|
838
|
-
// Category 3: Signals (1 method)
|
|
876
|
+
// Category 3: Decision Integrity Signals (1 method)
|
|
839
877
|
// ══════════════════════════════════════════════
|
|
840
878
|
|
|
841
879
|
/**
|
|
842
|
-
* Get current
|
|
880
|
+
* Get current decision integrity signals. Returns autonomy breaches, logic drift, and governance violations.
|
|
843
881
|
* @returns {Promise<{signals: Object[], counts: {red: number, amber: number, total: number}}>}
|
|
844
882
|
*/
|
|
845
883
|
async getSignals() {
|
|
@@ -1495,7 +1533,7 @@ class DashClaw {
|
|
|
1495
1533
|
}
|
|
1496
1534
|
|
|
1497
1535
|
// ══════════════════════════════════════════════
|
|
1498
|
-
// Category 11: Agent Messaging (
|
|
1536
|
+
// Category 11: Agent Messaging (11 methods)
|
|
1499
1537
|
// ══════════════════════════════════════════════
|
|
1500
1538
|
|
|
1501
1539
|
/**
|
|
@@ -1508,10 +1546,11 @@ class DashClaw {
|
|
|
1508
1546
|
* @param {string} [params.threadId] - Thread ID to attach message to
|
|
1509
1547
|
* @param {boolean} [params.urgent=false] - Mark as urgent
|
|
1510
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)
|
|
1511
1550
|
* @returns {Promise<{message: Object, message_id: string}>}
|
|
1512
1551
|
*/
|
|
1513
|
-
async sendMessage({ to, type, subject, body, threadId, urgent, docRef }) {
|
|
1514
|
-
|
|
1552
|
+
async sendMessage({ to, type, subject, body, threadId, urgent, docRef, attachments }) {
|
|
1553
|
+
const payload = {
|
|
1515
1554
|
from_agent_id: this.agentId,
|
|
1516
1555
|
to_agent_id: to || null,
|
|
1517
1556
|
message_type: type || 'info',
|
|
@@ -1520,7 +1559,9 @@ class DashClaw {
|
|
|
1520
1559
|
thread_id: threadId,
|
|
1521
1560
|
urgent,
|
|
1522
1561
|
doc_ref: docRef,
|
|
1523
|
-
}
|
|
1562
|
+
};
|
|
1563
|
+
if (attachments?.length) payload.attachments = attachments;
|
|
1564
|
+
return this._request('/api/messages', 'POST', payload);
|
|
1524
1565
|
}
|
|
1525
1566
|
|
|
1526
1567
|
/**
|
|
@@ -1628,7 +1669,7 @@ class DashClaw {
|
|
|
1628
1669
|
|
|
1629
1670
|
/**
|
|
1630
1671
|
* Create or update a shared workspace document.
|
|
1631
|
-
* Upserts by (org_id, name)
|
|
1672
|
+
* Upserts by (org_id, name). Updates increment the version.
|
|
1632
1673
|
* @param {Object} params
|
|
1633
1674
|
* @param {string} params.name - Document name (unique per org)
|
|
1634
1675
|
* @param {string} params.content - Document content
|
|
@@ -1642,13 +1683,45 @@ class DashClaw {
|
|
|
1642
1683
|
});
|
|
1643
1684
|
}
|
|
1644
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
|
+
|
|
1645
1719
|
// ══════════════════════════════════════════════
|
|
1646
|
-
// Category 13:
|
|
1720
|
+
// Category 13: Policy Enforcement (Guard) (2 methods)
|
|
1647
1721
|
// ══════════════════════════════════════════════
|
|
1648
1722
|
|
|
1649
1723
|
/**
|
|
1650
|
-
*
|
|
1651
|
-
* Returns allow/warn/block/require_approval.
|
|
1724
|
+
* Enforce policies before a decision executes. Guard is the heart of DashClaw. It intercepts intent and returns allow/warn/block/require_approval.
|
|
1652
1725
|
* @param {Object} context
|
|
1653
1726
|
* @param {string} context.action_type - Action type (required)
|
|
1654
1727
|
* @param {number} [context.risk_score] - Risk score 0-100
|
|
@@ -2059,7 +2132,7 @@ class DashClaw {
|
|
|
2059
2132
|
|
|
2060
2133
|
/**
|
|
2061
2134
|
* Sync multiple data categories in a single request.
|
|
2062
|
-
* Every key is optional
|
|
2135
|
+
* Every key is optional. Only provided categories are processed.
|
|
2063
2136
|
* @param {Object} state - Data to sync (connections, memory, goals, learning, content, inspiration, context_points, context_threads, handoffs, preferences, snippets)
|
|
2064
2137
|
* @returns {Promise<{results: Object, total_synced: number, total_errors: number, duration_ms: number}>}
|
|
2065
2138
|
*/
|
package/index.cjs
CHANGED
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.3",
|
|
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"
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
],
|
|
23
23
|
"keywords": [
|
|
24
24
|
"ai-agent",
|
|
25
|
-
"
|
|
25
|
+
"decision-infrastructure",
|
|
26
26
|
"agent-toolkit",
|
|
27
27
|
"dashclaw",
|
|
28
28
|
"dashclaw",
|