dashclaw 2.13.0 → 2.13.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 +15 -8
  2. package/dashclaw.js +95 -7
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # DashClaw SDK (v2.12.0)
1
+ # DashClaw SDK
2
2
 
3
3
  **Minimal governance runtime for AI agents.**
4
4
 
@@ -141,14 +141,16 @@ Telegram button.
141
141
  ### The rule every agent author needs to know
142
142
 
143
143
  **`waitForApproval()` must be called with the `action_id` returned by
144
- `createAction()`, NOT with the `action_id` returned by `guard()`.**
144
+ `createAction()`, NOT with the guard decision's id.**
145
145
 
146
146
  These are two different records in two different tables:
147
147
 
148
- | Call | Returns `action_id` that refers to… | Prefix |
149
- |---|---|---|
150
- | `guard()` | A row in `guard_decisions` (the decision log) | `act_gd_…` |
151
- | `createAction()` | A row in `action_records` (the thing you're actually doing) | `act_…` |
148
+ | Call | Returns an id that refers to… | Prefix | Field on the result |
149
+ |---|---|---|---|
150
+ | `guard()` | A row in `guard_decisions` (the decision log) | `act_gd_…` | `decision_id` (canonical); `action_id` is a **deprecated alias** of the same value |
151
+ | `createAction()` | A row in `action_records` (the thing you're actually doing) | `act_…` | `action_id` |
152
+
153
+ > The guard result's `action_id` field is a legacy alias of `decision_id` and will be removed in a future major — read `decision_id` from `guard()`, and `action_id` from `createAction()`.
152
154
 
153
155
  `waitForApproval()` polls `GET /api/actions/:id`, which is the
154
156
  `action_records` table. Passing it a `guard_decisions` ID (`act_gd_…`) will
@@ -251,7 +253,7 @@ See:
251
253
 
252
254
  ---
253
255
 
254
- ## SDK Surface Area (v2.12.0)
256
+ ## SDK Surface Area
255
257
 
256
258
  The v2 SDK exposes the stable governance runtime plus promoted execution domains in the canonical Node client:
257
259
 
@@ -336,6 +338,11 @@ lessons.forEach(l => console.log(l.guidance));
336
338
  ### Messaging
337
339
  - `sendMessage({ to, type, subject, body, threadId, urgent })` -- Send a message to another agent or broadcast.
338
340
  - `getInbox({ type, unread, limit })` -- Retrieve inbox messages with optional filters.
341
+ - `getSentMessages({ type, threadId, limit })` -- Retrieve messages this agent has sent.
342
+ - `getMessages({ direction, type, unread, threadId, limit })` -- Retrieve messages with flexible filters.
343
+ - `getMessage(messageId)` -- Fetch a single message by id.
344
+ - `markRead(messageIds)` -- Mark messages as read for this agent (`PATCH /api/messages`, `action: 'read'`).
345
+ - `archiveMessages(messageIds)` -- Archive messages for this agent (`PATCH /api/messages`, `action: 'archive'`).
339
346
 
340
347
  ```javascript
341
348
  // Send a message to another agent
@@ -604,7 +611,7 @@ If your agent supports Model Context Protocol (Claude Code, Claude Desktop, Mana
604
611
  - **Open loops (3):** `dashclaw_loop_add`, `dashclaw_loop_list`, `dashclaw_loop_close` — action-scoped commitments (the "I will X later" tracker).
605
612
  - **Learning + retrospection (3):** `dashclaw_learning_log`, `dashclaw_learning_query`, `dashclaw_decisions_recent` — log + query non-obvious decisions; recent governed-action ledger.
606
613
 
607
- **4 resources:** `dashclaw://policies`, `dashclaw://capabilities`, `dashclaw://agent/{agent_id}/history`, `dashclaw://status`.
614
+ **6 resources:** `dashclaw://policies`, `dashclaw://capabilities`, `dashclaw://agent/{agent_id}/history`, `dashclaw://status`, `dashclaw://code-sessions/projects`, `dashclaw://code-sessions/sessions/{session_id}`.
608
615
 
609
616
  ### Agent runtime endpoints (server-side, no SDK wrapper)
610
617
 
package/dashclaw.js CHANGED
@@ -1,6 +1,10 @@
1
1
  /**
2
- * DashClaw SDK v2.12.0 (Stable Runtime API)
2
+ * DashClaw SDK (Stable Runtime API)
3
3
  * Focused governance runtime client for AI agents.
4
+ *
5
+ * Version is the single source of truth in sdk/package.json — never
6
+ * hardcoded here, in the README header, or in app/ pages. Consumers
7
+ * read it at runtime via `import pkg from 'dashclaw/package.json'`.
4
8
  */
5
9
 
6
10
  import { createHash } from 'crypto';
@@ -62,8 +66,16 @@ class DashClaw {
62
66
  async _request(path, method = 'GET', body = null, params = null) {
63
67
  let url = `${this.baseUrl}${path}`;
64
68
  if (params) {
65
- const qs = new URLSearchParams(params).toString();
66
- if (qs) url += `?${qs}`;
69
+ // Skip undefined/null values. Passing them straight into URLSearchParams
70
+ // serializes the literal strings "undefined"/"null", which the receiving
71
+ // routes treat as real filter values and match zero rows. Falsy-but-valid
72
+ // values (0, false, '') are preserved. Mirrors the v1 SDK behavior.
73
+ const qs = new URLSearchParams();
74
+ for (const [key, value] of Object.entries(params)) {
75
+ if (value !== undefined && value !== null) qs.append(key, String(value));
76
+ }
77
+ const s = qs.toString();
78
+ if (s) url += `?${s}`;
67
79
  }
68
80
 
69
81
  const headers = {
@@ -78,7 +90,16 @@ class DashClaw {
78
90
  body: body ? JSON.stringify(body) : undefined
79
91
  });
80
92
 
81
- const data = await res.json();
93
+ // Parse the body defensively. A non-JSON error body (a Vercel 502/504/413
94
+ // gateway page, a 429 rate-limit page) makes res.json() reject with a
95
+ // SyntaxError, which would propagate instead of the status-bearing error
96
+ // below and lose res.status. Fall back to {} so the real status is thrown.
97
+ let data = {};
98
+ try {
99
+ data = await res.json();
100
+ } catch {
101
+ data = {};
102
+ }
82
103
 
83
104
  if (!res.ok) {
84
105
  if (res.status === 403 && data.decision && data.decision.decision === 'block') {
@@ -289,7 +310,12 @@ class DashClaw {
289
310
  let printedBlock = false;
290
311
 
291
312
  while (Date.now() - startTime < timeout) {
292
- const { action } = await this._request(`/api/actions/${actionId}`, 'GET');
313
+ // Return the full GET response (action + open_loops + assumptions +
314
+ // message_summary) so the polling fallback resolves to the same shape as
315
+ // the SSE fast-path above and the Python SDK. Returning only { action }
316
+ // dropped the related collections whenever SSE was unavailable.
317
+ const result = await this._request(`/api/actions/${actionId}`, 'GET');
318
+ const action = result.action;
293
319
 
294
320
  if (!printedBlock) {
295
321
  printedBlock = true;
@@ -319,14 +345,14 @@ class DashClaw {
319
345
  }
320
346
 
321
347
  if (action.status === 'pending_approval') wasPending = true;
322
- if (action.approved_by) return { action };
348
+ if (action.approved_by) return result;
323
349
  if (action.status === 'failed' || action.status === 'cancelled') {
324
350
  throw new ApprovalDeniedError(action.error_message || 'Operator denied the action.', action.status);
325
351
  }
326
352
  if (wasPending && action.status !== 'pending_approval') {
327
353
  throw new Error(`Action ${actionId} left pending_approval state without explicit approval metadata (Status: ${action.status})`);
328
354
  }
329
- if (!wasPending && action.status === 'running') return { action };
355
+ if (!wasPending && action.status === 'running') return result;
330
356
 
331
357
  await new Promise(r => setTimeout(r, interval));
332
358
  }
@@ -611,6 +637,68 @@ class DashClaw {
611
637
  });
612
638
  }
613
639
 
640
+ /**
641
+ * GET /api/messages — Fetch messages this agent has sent.
642
+ */
643
+ async getSentMessages({ type, threadId, limit } = {}) {
644
+ return this._request('/api/messages', 'GET', null, {
645
+ agent_id: this.agentId,
646
+ direction: 'sent',
647
+ ...(type && { type }),
648
+ ...(threadId && { thread_id: threadId }),
649
+ ...(limit && { limit }),
650
+ });
651
+ }
652
+
653
+ /**
654
+ * GET /api/messages — Fetch this agent's messages with flexible filters.
655
+ */
656
+ async getMessages({ direction, type, unread, threadId, limit } = {}) {
657
+ return this._request('/api/messages', 'GET', null, {
658
+ agent_id: this.agentId,
659
+ ...(direction && { direction }),
660
+ ...(type && { type }),
661
+ ...(unread != null && { unread }),
662
+ ...(threadId && { thread_id: threadId }),
663
+ ...(limit && { limit }),
664
+ });
665
+ }
666
+
667
+ /**
668
+ * GET /api/messages/:messageId — Fetch a single message by id.
669
+ */
670
+ async getMessage(messageId) {
671
+ return this._request(`/api/messages/${encodeURIComponent(messageId)}`, 'GET');
672
+ }
673
+
674
+ /**
675
+ * PATCH /api/messages — Mark messages as read for this agent. Direct messages
676
+ * are marked read only for the target agent (or dashboard); broadcasts update
677
+ * read_by for this agent.
678
+ * @param {string[]} messageIds - Message IDs (msg_*) to mark read.
679
+ * @returns {Promise<{ updated: number }>}
680
+ */
681
+ async markRead(messageIds) {
682
+ return this._request('/api/messages', 'PATCH', {
683
+ message_ids: messageIds,
684
+ action: 'read',
685
+ agent_id: this.agentId,
686
+ });
687
+ }
688
+
689
+ /**
690
+ * PATCH /api/messages — Archive messages for this agent.
691
+ * @param {string[]} messageIds - Message IDs (msg_*) to archive.
692
+ * @returns {Promise<{ updated: number }>}
693
+ */
694
+ async archiveMessages(messageIds) {
695
+ return this._request('/api/messages', 'PATCH', {
696
+ message_ids: messageIds,
697
+ action: 'archive',
698
+ agent_id: this.agentId,
699
+ });
700
+ }
701
+
614
702
  // ---------------------------------------------------------------------------
615
703
  // Session Handoffs
616
704
  // ---------------------------------------------------------------------------
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dashclaw",
3
- "version": "2.13.0",
3
+ "version": "2.13.1",
4
4
  "description": "Minimal governance runtime for AI agents. Intercept, govern, and verify agent actions.",
5
5
  "type": "module",
6
6
  "publishConfig": {