@ziggs-ai/ziggs-mcp 0.1.12 → 0.1.14

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/dist/tools.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { randomUUID } from 'node:crypto';
2
2
  import { z } from 'zod';
3
- import { getAgreement, getMyAgreements, listMyChats, openConversation, proposeDirectTo, respondToAgreement, ScopeClient, MessagesClient, sendChatMessage, ContextDiscoveryClient, ContextReadClient, InboxClient, ArtifactsClient, getBackendUrl, } from '@ziggs-ai/api-client';
3
+ import { getAgreement, getMyAgreements, listMyChats, openConversation, proposeDirectTo, respondToAgreement, ScopeClient, MessagesClient, sendChatMessage, ContextDiscoveryClient, ContextReadClient, InboxClient, ArtifactsClient, createTask, updateTaskState, replaceTaskPlan, listTasks, getBackendUrl, } from '@ziggs-ai/api-client';
4
4
  import { decodeOperatorKeyClaims } from './operatorKey.js';
5
5
  import { registerTrustTools } from './trustTools.js';
6
6
  import { formatInboxToolResult } from './inboxToolResult.js';
@@ -236,7 +236,7 @@ export function registerZiggsTools(server, creds, cfg) {
236
236
  return toolError(e.message);
237
237
  }
238
238
  });
239
- server.tool('ziggs_inbox', "What's new since your last ack — references only, never content: scopes with new-message/artifact counts, plus agreement proposals awaiting your response. When humanAttention is present, tell the human immediately (pull-only MCP has no push). Flow: inbox → read (ziggs_read_context) → act → ack. Reading never advances the watermark; pass ack with what you handled (use each scope's latestAt as upTo) to clear it.", {
239
+ server.tool('ziggs_inbox', "What's new since your last ack — references only, never content: scopes with new-message/artifact counts, plus agreement proposals awaiting your response. For org/agreement scopes each entry includes a `chats` breakdown (chatId + per-chat counts) so you can open the conversations behind the count — read them with ziggs_list_messages / ziggs_read_context (via=chat:<chatId>). When humanAttention is present, tell the human immediately (pull-only MCP has no push). Flow: inbox → read → act → ack. Reading never advances the watermark; pass ack with what you handled (use each scope's latestAt as upTo) to clear it.", {
240
240
  ack: z
241
241
  .array(z.object({
242
242
  kind: z.enum(['chat', 'agreement', 'org']),
@@ -312,7 +312,10 @@ export function registerZiggsTools(server, creds, cfg) {
312
312
  .string()
313
313
  .optional()
314
314
  .describe('Target agreement (xor chatId)'),
315
- taskId: z.string().optional().describe('Optional task link'),
315
+ taskId: z
316
+ .string()
317
+ .optional()
318
+ .describe('Optional task — creates a TaskArtifactLink alongside the primary scope link'),
316
319
  content_type: z.string().optional().describe('Default text'),
317
320
  }, async ({ text, visibility, chatId, agreementId, taskId, content_type }) => {
318
321
  try {
@@ -327,7 +330,7 @@ export function registerZiggsTools(server, creds, cfg) {
327
330
  taskId,
328
331
  content_type,
329
332
  });
330
- return textResult({ ok: true, visibility, chatId, agreementId });
333
+ return textResult({ ok: true, visibility, chatId, agreementId, taskId });
331
334
  }
332
335
  catch (e) {
333
336
  return toolError(e.message);
@@ -351,5 +354,77 @@ export function registerZiggsTools(server, creds, cfg) {
351
354
  return toolError(e.message);
352
355
  }
353
356
  });
357
+ // ---------------------------------------------------------------------------
358
+ // Task mutation tools (ZIG-555)
359
+ // ---------------------------------------------------------------------------
360
+ server.tool('ziggs_create_task', 'Create a task under an agreement. Every task belongs to exactly one agreement (agreementId required).', {
361
+ agreementId: z.string().describe('Agreement this task belongs to'),
362
+ description: z.string().describe('What the task entails'),
363
+ parentTaskId: z.string().optional().describe('Parent task id for sub-tasks'),
364
+ }, async ({ agreementId, description, parentTaskId }) => {
365
+ try {
366
+ const task = await createTask({ agreementId, description, parentTaskId }, creds);
367
+ return textResult({ ok: true, task });
368
+ }
369
+ catch (e) {
370
+ return toolError(e.message);
371
+ }
372
+ });
373
+ server.tool('ziggs_set_task_result', 'Transition a task to a terminal state (completed / failed / cancelled) and record the result. Enforces the state machine — only active tasks can be transitioned.', {
374
+ taskId: z.string(),
375
+ state: z.enum(['completed', 'failed', 'cancelled']),
376
+ result: z
377
+ .object({
378
+ summary: z.string().optional(),
379
+ status: z.string().optional(),
380
+ links: z.array(z.string()).optional(),
381
+ })
382
+ .passthrough()
383
+ .optional()
384
+ .describe('Outcome payload (summary, status, links, …)'),
385
+ errorMessage: z.string().optional().describe('Required when state=failed'),
386
+ }, async ({ taskId, state, result, errorMessage }) => {
387
+ try {
388
+ const task = await updateTaskState(taskId, state, { result, errorMessage }, creds);
389
+ return textResult({ ok: true, task });
390
+ }
391
+ catch (e) {
392
+ return toolError(e.message);
393
+ }
394
+ });
395
+ server.tool('ziggs_post_task_plan_step', 'Replace / advance the plan for a task. Provide the full ordered step list — existing steps are replaced. Use this to post progress as plan steps.', {
396
+ taskId: z.string(),
397
+ steps: z
398
+ .array(z.object({
399
+ stepId: z.string().describe('Stable id for this step (e.g. uuid)'),
400
+ description: z.string(),
401
+ order: z.number().int(),
402
+ }))
403
+ .describe('Full replacement step list (ordered)'),
404
+ }, async ({ taskId, steps }) => {
405
+ try {
406
+ const task = await replaceTaskPlan(taskId, steps, creds);
407
+ return textResult({ ok: true, task });
408
+ }
409
+ catch (e) {
410
+ return toolError(e.message);
411
+ }
412
+ });
413
+ server.tool('ziggs_list_tasks', 'List tasks reachable by this delegate agent (GET /tasks). Scope is determined by the operator key — same reach as chats and agreements. Supports optional state filter and cursor pagination.', {
414
+ state: z
415
+ .string()
416
+ .optional()
417
+ .describe('Filter by state: active, completed, failed, cancelled'),
418
+ cursor: z.string().optional().describe('Opaque cursor from prior nextCursor'),
419
+ limit: z.number().optional().describe('Max rows (default server-side)'),
420
+ }, async ({ state, cursor, limit }) => {
421
+ try {
422
+ const result = await listTasks({ state, cursor, limit }, creds);
423
+ return textResult(result);
424
+ }
425
+ catch (e) {
426
+ return toolError(e.message);
427
+ }
428
+ });
354
429
  registerTrustTools(server, creds, cfg);
355
430
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ziggs-ai/ziggs-mcp",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "description": "MCP server for Claude Code, Cursor, and other MCP hosts — act as your Ziggs delegate agent",
5
5
  "type": "module",
6
6
  "bin": {
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@modelcontextprotocol/sdk": "^1.29.0",
37
- "@ziggs-ai/api-client": "^0.1.11",
37
+ "@ziggs-ai/api-client": "^0.1.15",
38
38
  "dotenv": "^16.6.1",
39
39
  "zod": "^3.24.2"
40
40
  },
@@ -25,6 +25,21 @@ Counterparty sent 3 chat messages and 1 agreement proposal while you were offlin
25
25
 
26
26
  5. **`ziggs_inbox`** again — scoped news for handled chat should be empty. Proposals clear when responded, not on ack alone.
27
27
 
28
+ ## Org / agreement scopes — which chats? (ZIG-543)
29
+
30
+ A `chat` scope's id *is* the chatId. For an **org** or **agreement** scope the
31
+ count spans many chats, so the entry includes a **`chats`** breakdown:
32
+
33
+ ```
34
+ { scope: { kind: "org", id: "<orgId>" }, newMessages: 12, chats: [
35
+ { chatId: "<id>", newMessages: 5, newArtifacts: 0, latestAt: "…" }, … ] }
36
+ ```
37
+
38
+ Open each conversation by its `chatId` — `ziggs_list_messages` or
39
+ `ziggs_read_context` (`via: chat:<chatId>`). Your org/scope grant covers those
40
+ chats without explicit membership. If **`truncatedChats`** is set, more chats
41
+ have news than are listed — handle and ack the listed ones, then re-run inbox.
42
+
28
43
  ## Deduping push + inbox
29
44
 
30
45
  If the host delivers a push notification and you also poll inbox: