@ziggs-ai/ziggs-mcp 0.1.12 → 0.1.13

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';
@@ -38,7 +38,6 @@ async function writeArtifactStrict(creds, input) {
38
38
  visibility: input.visibility,
39
39
  chatId: input.chatId,
40
40
  agreementId: input.agreementId,
41
- taskId: input.taskId,
42
41
  }),
43
42
  });
44
43
  if (!res.ok) {
@@ -236,7 +235,7 @@ export function registerZiggsTools(server, creds, cfg) {
236
235
  return toolError(e.message);
237
236
  }
238
237
  });
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.", {
238
+ 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
239
  ack: z
241
240
  .array(z.object({
242
241
  kind: z.enum(['chat', 'agreement', 'org']),
@@ -312,9 +311,8 @@ export function registerZiggsTools(server, creds, cfg) {
312
311
  .string()
313
312
  .optional()
314
313
  .describe('Target agreement (xor chatId)'),
315
- taskId: z.string().optional().describe('Optional task link'),
316
314
  content_type: z.string().optional().describe('Default text'),
317
- }, async ({ text, visibility, chatId, agreementId, taskId, content_type }) => {
315
+ }, async ({ text, visibility, chatId, agreementId, content_type }) => {
318
316
  try {
319
317
  if ((chatId && agreementId) || (!chatId && !agreementId)) {
320
318
  return toolError('Pass exactly one of chatId or agreementId');
@@ -324,7 +322,6 @@ export function registerZiggsTools(server, creds, cfg) {
324
322
  visibility,
325
323
  chatId,
326
324
  agreementId,
327
- taskId,
328
325
  content_type,
329
326
  });
330
327
  return textResult({ ok: true, visibility, chatId, agreementId });
@@ -351,5 +348,77 @@ export function registerZiggsTools(server, creds, cfg) {
351
348
  return toolError(e.message);
352
349
  }
353
350
  });
351
+ // ---------------------------------------------------------------------------
352
+ // Task mutation tools (ZIG-555)
353
+ // ---------------------------------------------------------------------------
354
+ server.tool('ziggs_create_task', 'Create a task under an agreement. Every task belongs to exactly one agreement (agreementId required).', {
355
+ agreementId: z.string().describe('Agreement this task belongs to'),
356
+ description: z.string().describe('What the task entails'),
357
+ parentTaskId: z.string().optional().describe('Parent task id for sub-tasks'),
358
+ }, async ({ agreementId, description, parentTaskId }) => {
359
+ try {
360
+ const task = await createTask({ agreementId, description, parentTaskId }, creds);
361
+ return textResult({ ok: true, task });
362
+ }
363
+ catch (e) {
364
+ return toolError(e.message);
365
+ }
366
+ });
367
+ 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.', {
368
+ taskId: z.string(),
369
+ state: z.enum(['completed', 'failed', 'cancelled']),
370
+ result: z
371
+ .object({
372
+ summary: z.string().optional(),
373
+ status: z.string().optional(),
374
+ links: z.array(z.string()).optional(),
375
+ })
376
+ .passthrough()
377
+ .optional()
378
+ .describe('Outcome payload (summary, status, links, …)'),
379
+ errorMessage: z.string().optional().describe('Required when state=failed'),
380
+ }, async ({ taskId, state, result, errorMessage }) => {
381
+ try {
382
+ const task = await updateTaskState(taskId, state, { result, errorMessage }, creds);
383
+ return textResult({ ok: true, task });
384
+ }
385
+ catch (e) {
386
+ return toolError(e.message);
387
+ }
388
+ });
389
+ 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.', {
390
+ taskId: z.string(),
391
+ steps: z
392
+ .array(z.object({
393
+ stepId: z.string().describe('Stable id for this step (e.g. uuid)'),
394
+ description: z.string(),
395
+ order: z.number().int(),
396
+ }))
397
+ .describe('Full replacement step list (ordered)'),
398
+ }, async ({ taskId, steps }) => {
399
+ try {
400
+ const task = await replaceTaskPlan(taskId, steps, creds);
401
+ return textResult({ ok: true, task });
402
+ }
403
+ catch (e) {
404
+ return toolError(e.message);
405
+ }
406
+ });
407
+ 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.', {
408
+ state: z
409
+ .string()
410
+ .optional()
411
+ .describe('Filter by state: active, completed, failed, cancelled'),
412
+ cursor: z.string().optional().describe('Opaque cursor from prior nextCursor'),
413
+ limit: z.number().optional().describe('Max rows (default server-side)'),
414
+ }, async ({ state, cursor, limit }) => {
415
+ try {
416
+ const result = await listTasks({ state, cursor, limit }, creds);
417
+ return textResult(result);
418
+ }
419
+ catch (e) {
420
+ return toolError(e.message);
421
+ }
422
+ });
354
423
  registerTrustTools(server, creds, cfg);
355
424
  }
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.13",
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.14",
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: