@rallycry/conveyor-mcp 5.0.0 → 5.0.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 ADDED
@@ -0,0 +1,102 @@
1
+ # @rallycry/conveyor-mcp
2
+
3
+ The Conveyor MCP server. It gives a coding agent — Claude Code, Codex, Cursor,
4
+ Windsurf, VS Code, Claude Desktop — direct access to your Conveyor cards,
5
+ plans, chat, tags, and pull requests.
6
+
7
+ ## Get your values
8
+
9
+ Open **User Settings → Connect your coding agent (MCP)** in the Conveyor web
10
+ app. It generates a token and copies a pre-filled command or config block that
11
+ already carries your API URL, token, and project id. Use that if you can.
12
+
13
+ To register the server by hand, replace the three placeholders below:
14
+
15
+ - `<api-url>` — your Conveyor API host.
16
+ - `<user-token>` — your personal token from User Settings. Treat it as a secret.
17
+ - `<project-id>` — the project to work in. Omit this variable for multi-project
18
+ mode, then pass `projectId` per tool call after calling `list_projects`.
19
+
20
+ ## Install
21
+
22
+ ### Claude Code (CLI)
23
+
24
+ ```bash
25
+ claude mcp remove conveyor -s local 2>/dev/null;
26
+ claude mcp add conveyor -s local \
27
+ -e CONVEYOR_API_URL=<api-url> \
28
+ -e CONVEYOR_USER_TOKEN=<user-token> \
29
+ -e CONVEYOR_PROJECT_ID=<project-id> \
30
+ -- npx -y @rallycry/conveyor-mcp@latest
31
+ ```
32
+
33
+ The `claude mcp remove` prefix makes the command idempotent. A bare
34
+ `claude mcp add` exits 1 with "already exists in local config" when a `conveyor`
35
+ server is already registered, which blocks a re-paste after a token rotation.
36
+
37
+ ### JSON config (Cursor, Windsurf, VS Code, Claude Desktop)
38
+
39
+ Merge this into your `mcpServers` block:
40
+
41
+ ```json
42
+ {
43
+ "mcpServers": {
44
+ "conveyor": {
45
+ "command": "npx",
46
+ "args": ["-y", "@rallycry/conveyor-mcp@latest"],
47
+ "env": {
48
+ "CONVEYOR_API_URL": "<api-url>",
49
+ "CONVEYOR_USER_TOKEN": "<user-token>",
50
+ "CONVEYOR_PROJECT_ID": "<project-id>"
51
+ }
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ ### TOML config (Codex CLI, `~/.codex/config.toml`)
58
+
59
+ ```toml
60
+ [mcp_servers.conveyor]
61
+ command = "npx"
62
+ args = ["-y", "@rallycry/conveyor-mcp@latest"]
63
+
64
+ [mcp_servers.conveyor.env]
65
+ CONVEYOR_API_URL = "<api-url>"
66
+ CONVEYOR_USER_TOKEN = "<user-token>"
67
+ CONVEYOR_PROJECT_ID = "<project-id>"
68
+ ```
69
+
70
+ ## Environment variables
71
+
72
+ | Variable | Required | Purpose |
73
+ | ------------------------ | -------- | ------------------------------------------------------------------------------------ |
74
+ | `CONVEYOR_API_URL` | yes | Conveyor API host. |
75
+ | `CONVEYOR_USER_TOKEN` | yes | Your personal token. `CONVEYOR_PROJECT_TOKEN` is a backwards-compatible alias. |
76
+ | `CONVEYOR_PROJECT_ID` | no | Default project for unqualified tools. Omit it for multi-project mode. |
77
+ | `CONVEYOR_SUBPROJECT_ID` | no | Default board. Unqualified `create_task`/`list_tasks`/`search_tasks` target it. |
78
+
79
+ ## Why `npx -y …@latest`
80
+
81
+ Every form above launches the server through
82
+ `npx -y @rallycry/conveyor-mcp@latest`, so each start re-resolves the `@latest`
83
+ tag from the registry. Restarting the MCP server picks up newly published
84
+ versions, and there is no upgrade step to remember. The trade-off is a slightly
85
+ slower launch, because npx checks the registry each time.
86
+
87
+ The `@latest` tag is load-bearing. npx resolves a bare package name against the
88
+ local workspace first, so a bare `npx @rallycry/conveyor-mcp` inside a repo that
89
+ vendors a package of that name execs the unbuilt local copy and the server fails
90
+ to start. A version or tag spec forces registry resolution regardless of cwd.
91
+ Never shorten the command.
92
+
93
+ ## Verify
94
+
95
+ After you reload MCP servers, call `verify_connection`. It returns a plain
96
+ pass/fail plus, on failure, the failing layer and one next action. Then call
97
+ `get_connection_context` to confirm the account, project, and board are the ones
98
+ you intended.
99
+
100
+ ## License
101
+
102
+ MIT
@@ -208,14 +208,13 @@ var ConveyorConnection = class {
208
208
  const { projectId, subProjectId, tags, ...rest } = params;
209
209
  const resolvedProjectId = this.resolveProjectId(projectId);
210
210
  const resolvedSubProjectId = this.resolveSubProjectId(subProjectId);
211
+ const tagIds = await this.resolveTagIds(resolvedProjectId, tags ?? []);
211
212
  const result = await this.call("createProjectTask", {
212
213
  projectId: resolvedProjectId,
213
214
  subProjectId: resolvedSubProjectId,
214
215
  ...rest
215
216
  });
216
- if (tags && tags.length > 0) {
217
- await this.assignTagsToTask(result.id, resolvedProjectId, tags);
218
- }
217
+ await this.assignResolvedTags(result.id, tagIds);
219
218
  return {
220
219
  ...result,
221
220
  effectiveScope: {
@@ -230,12 +229,10 @@ var ConveyorConnection = class {
230
229
  const hasCoreUpdate = rest.title !== void 0 || rest.description !== void 0 || rest.plan !== void 0 || rest.status !== void 0 || rest.risk !== void 0 || rest.storyPointValue !== void 0 || rest.assignedUserId !== void 0 || rest.subProjectId !== void 0 || rest.githubBranch !== void 0;
231
230
  const removedTags = removeTags ?? [];
232
231
  const addedTags = addTags ?? [];
233
- if (removedTags.length > 0) {
234
- await this.removeTagsFromTask(rest.taskId, resolvedProjectId, removedTags);
235
- }
236
- if (addedTags.length > 0) {
237
- await this.assignTagsToTask(rest.taskId, resolvedProjectId, addedTags);
238
- }
232
+ const removeIds = await this.resolveTagIds(resolvedProjectId, removedTags);
233
+ const addIds = await this.resolveTagIds(resolvedProjectId, addedTags);
234
+ await this.removeResolvedTags(rest.taskId, removeIds);
235
+ await this.assignResolvedTags(rest.taskId, addIds);
239
236
  if (hasCoreUpdate) {
240
237
  const result = await this.call("updateProjectTask", { projectId: resolvedProjectId, ...rest });
241
238
  return { ...result, addedTags, removedTags };
@@ -270,13 +267,11 @@ var ConveyorConnection = class {
270
267
  }
271
268
  return [...new Set(ids)];
272
269
  }
273
- async assignTagsToTask(taskId, projectId, names) {
274
- const tagIds = await this.resolveTagIds(projectId, names);
270
+ async assignResolvedTags(taskId, tagIds) {
275
271
  if (tagIds.length === 0) return;
276
272
  await this.callService("tagService", "assignToTask", { taskId, tagIds });
277
273
  }
278
- async removeTagsFromTask(taskId, projectId, names) {
279
- const tagIds = await this.resolveTagIds(projectId, names);
274
+ async removeResolvedTags(taskId, tagIds) {
280
275
  if (tagIds.length === 0) return;
281
276
  await this.callService("tagService", "removeFromTask", { taskId, tagIds });
282
277
  }
@@ -473,27 +468,45 @@ var ConveyorConnection = class {
473
468
  // credential and cannot reach outside that subtree.
474
469
  listProjectDriveFiles(params) {
475
470
  const { projectId, ...rest } = params;
476
- return this.call("listProjectDriveFiles", { projectId: this.resolveProjectId(projectId), ...rest });
471
+ return this.call("listProjectDriveFiles", {
472
+ projectId: this.resolveProjectId(projectId),
473
+ ...rest
474
+ });
477
475
  }
478
476
  readProjectDriveFile(params) {
479
477
  const { projectId, ...rest } = params;
480
- return this.call("readProjectDriveFile", { projectId: this.resolveProjectId(projectId), ...rest });
478
+ return this.call("readProjectDriveFile", {
479
+ projectId: this.resolveProjectId(projectId),
480
+ ...rest
481
+ });
481
482
  }
482
483
  createProjectDriveFile(params) {
483
484
  const { projectId, ...rest } = params;
484
- return this.call("createProjectDriveFile", { projectId: this.resolveProjectId(projectId), ...rest });
485
+ return this.call("createProjectDriveFile", {
486
+ projectId: this.resolveProjectId(projectId),
487
+ ...rest
488
+ });
485
489
  }
486
490
  updateProjectDriveFile(params) {
487
491
  const { projectId, ...rest } = params;
488
- return this.call("updateProjectDriveFile", { projectId: this.resolveProjectId(projectId), ...rest });
492
+ return this.call("updateProjectDriveFile", {
493
+ projectId: this.resolveProjectId(projectId),
494
+ ...rest
495
+ });
489
496
  }
490
497
  deleteProjectDriveFile(params) {
491
498
  const { projectId, ...rest } = params;
492
- return this.call("deleteProjectDriveFile", { projectId: this.resolveProjectId(projectId), ...rest });
499
+ return this.call("deleteProjectDriveFile", {
500
+ projectId: this.resolveProjectId(projectId),
501
+ ...rest
502
+ });
493
503
  }
494
504
  createProjectDriveFolder(params) {
495
505
  const { projectId, ...rest } = params;
496
- return this.call("createProjectDriveFolder", { projectId: this.resolveProjectId(projectId), ...rest });
506
+ return this.call("createProjectDriveFolder", {
507
+ projectId: this.resolveProjectId(projectId),
508
+ ...rest
509
+ });
497
510
  }
498
511
  /**
499
512
  * What this project is connected to, plus its registered work channels.
@@ -534,7 +547,7 @@ var ConveyorConnection = class {
534
547
  ...rest
535
548
  });
536
549
  }
537
- // ── Meetings (read-only) ────────────────────────────────────────────
550
+ // ── Meetings ────────────────────────────────────────────────────────
538
551
  listMeetings(params) {
539
552
  const { projectId, ...rest } = params;
540
553
  return this.call("listMeetings", { projectId: this.resolveProjectId(projectId), ...rest });
@@ -550,6 +563,48 @@ var ConveyorConnection = class {
550
563
  ...rest
551
564
  });
552
565
  }
566
+ createMeeting(params) {
567
+ const { projectId, ...rest } = params;
568
+ return this.call("createProjectMeeting", {
569
+ projectId: this.resolveProjectId(projectId),
570
+ ...rest
571
+ });
572
+ }
573
+ updateMeeting(params) {
574
+ const { projectId, ...rest } = params;
575
+ return this.call("updateProjectMeeting", {
576
+ projectId: this.resolveProjectId(projectId),
577
+ ...rest
578
+ });
579
+ }
580
+ addMeetingChecklistItems(params) {
581
+ const { projectId, ...rest } = params;
582
+ return this.call("addProjectMeetingChecklistItems", {
583
+ projectId: this.resolveProjectId(projectId),
584
+ ...rest
585
+ });
586
+ }
587
+ checkMeetingChecklistItem(params) {
588
+ const { projectId, ...rest } = params;
589
+ return this.call("checkProjectMeetingChecklistItem", {
590
+ projectId: this.resolveProjectId(projectId),
591
+ ...rest
592
+ });
593
+ }
594
+ editMeetingChecklistItem(params) {
595
+ const { projectId, ...rest } = params;
596
+ return this.call("editProjectMeetingChecklistItem", {
597
+ projectId: this.resolveProjectId(projectId),
598
+ ...rest
599
+ });
600
+ }
601
+ removeMeetingChecklistItem(params) {
602
+ const { projectId, ...rest } = params;
603
+ return this.call("removeProjectMeetingChecklistItem", {
604
+ projectId: this.resolveProjectId(projectId),
605
+ ...rest
606
+ });
607
+ }
553
608
  /** Effective account/project/board identity + capabilities for this token. */
554
609
  getConnectionContext(projectId) {
555
610
  return this.call("getConnectionContext", {
@@ -689,13 +744,12 @@ var ConveyorConnection = class {
689
744
  async createSubtask(params) {
690
745
  const { projectId, tags, ...rest } = params;
691
746
  const resolvedProjectId = this.resolveProjectId(projectId);
747
+ const tagIds = await this.resolveTagIds(resolvedProjectId, tags ?? []);
692
748
  const result = await this.call("createProjectSubtask", {
693
749
  projectId: resolvedProjectId,
694
750
  ...rest
695
751
  });
696
- if (tags && tags.length > 0) {
697
- await this.assignTagsToTask(result.id, resolvedProjectId, tags);
698
- }
752
+ await this.assignResolvedTags(result.id, tagIds);
699
753
  return result;
700
754
  }
701
755
  /**
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ConveyorConnection
4
- } from "./chunk-2TVN7F5E.js";
4
+ } from "./chunk-XLDG5QEX.js";
5
5
 
6
6
  // src/cli.ts
7
7
  import { createRequire } from "module";
@@ -231,14 +231,14 @@ var f = {
231
231
  return { kind: "nullable", inner };
232
232
  }
233
233
  };
234
- function compileString(z10, spec) {
235
- let schema = z10.string();
234
+ function compileString(z11, spec) {
235
+ let schema = z11.string();
236
236
  if (spec.min !== void 0) schema = schema.min(spec.min);
237
237
  if (spec.max !== void 0) schema = schema.max(spec.max);
238
238
  return schema;
239
239
  }
240
- function compileNumber(z10, spec) {
241
- let schema = z10.number();
240
+ function compileNumber(z11, spec) {
241
+ let schema = z11.number();
242
242
  if (spec.int) schema = schema.int();
243
243
  if (spec.positive) schema = schema.positive();
244
244
  if (spec.nonnegative) schema = schema.nonnegative();
@@ -246,49 +246,49 @@ function compileNumber(z10, spec) {
246
246
  if (spec.max !== void 0) schema = schema.max(spec.max);
247
247
  return schema;
248
248
  }
249
- function compileArray(z10, spec) {
250
- let schema = z10.array(compileField(z10, spec.item));
249
+ function compileArray(z11, spec) {
250
+ let schema = z11.array(compileField(z11, spec.item));
251
251
  if (spec.min !== void 0) schema = schema.min(spec.min);
252
252
  return schema;
253
253
  }
254
- function compileBase(z10, spec) {
254
+ function compileBase(z11, spec) {
255
255
  switch (spec.kind) {
256
256
  case "string":
257
- return compileString(z10, spec);
257
+ return compileString(z11, spec);
258
258
  case "number":
259
- return compileNumber(z10, spec);
259
+ return compileNumber(z11, spec);
260
260
  case "boolean":
261
- return z10.boolean();
261
+ return z11.boolean();
262
262
  case "enum":
263
- return z10.enum([...spec.values]);
263
+ return z11.enum([...spec.values]);
264
264
  case "array":
265
- return compileArray(z10, spec);
265
+ return compileArray(z11, spec);
266
266
  case "object":
267
- return z10.object(compileShape(z10, spec.fields));
267
+ return z11.object(compileShape(z11, spec.fields));
268
268
  }
269
269
  }
270
270
  function descriptionOf(spec) {
271
271
  if (spec.kind === "optional" || spec.kind === "nullable") return descriptionOf(spec.inner);
272
272
  return spec.desc;
273
273
  }
274
- function compileUndescribed(z10, spec) {
274
+ function compileUndescribed(z11, spec) {
275
275
  if (spec.kind === "optional") {
276
- return compileUndescribed(z10, spec.inner).optional();
276
+ return compileUndescribed(z11, spec.inner).optional();
277
277
  }
278
278
  if (spec.kind === "nullable") {
279
- return compileUndescribed(z10, spec.inner).nullable();
279
+ return compileUndescribed(z11, spec.inner).nullable();
280
280
  }
281
- return compileBase(z10, spec);
281
+ return compileBase(z11, spec);
282
282
  }
283
- function compileField(z10, spec) {
284
- const schema = compileUndescribed(z10, spec);
283
+ function compileField(z11, spec) {
284
+ const schema = compileUndescribed(z11, spec);
285
285
  const desc = descriptionOf(spec);
286
286
  return desc === void 0 ? schema : schema.describe(desc);
287
287
  }
288
- function compileShape(z10, fields) {
288
+ function compileShape(z11, fields) {
289
289
  const shape = {};
290
290
  for (const [key, spec] of Object.entries(fields)) {
291
- shape[key] = compileField(z10, spec);
291
+ shape[key] = compileField(z11, spec);
292
292
  }
293
293
  return shape;
294
294
  }
@@ -869,7 +869,7 @@ var createSubtaskContract = defineToolContract({
869
869
  ),
870
870
  tags: f.optional(
871
871
  f.array(f.string(), {
872
- desc: 'Tag names to assign to the subtask (e.g. ["refactor"]). Unknown names are rejected \u2014 create the tag first with manage_tags. Use list_tags to see available tags.'
872
+ desc: 'Tag names to assign to the subtask (e.g. ["refactor"]). Unknown names are rejected before the subtask is created, so nothing is written and a corrected retry creates exactly one subtask. Create the tag first with manage_tags. Use list_tags to see available tags.'
873
873
  })
874
874
  )
875
875
  }
@@ -1283,7 +1283,9 @@ var driveListFilesContract = defineToolContract({
1283
1283
  fields: {
1284
1284
  folderId: f.optional(f.string({ desc: `Folder to list. ${ROOT_DEFAULT}` })),
1285
1285
  search: f.optional(f.string({ desc: "Only return names containing this text", max: 200 })),
1286
- limit: f.optional(f.number({ desc: "Max entries (default 100)", int: true, min: 1, max: 200 }))
1286
+ limit: f.optional(
1287
+ f.number({ desc: "Max entries (default 100)", int: true, min: 1, max: 200 })
1288
+ )
1287
1289
  }
1288
1290
  },
1289
1291
  mcp: {
@@ -1292,7 +1294,9 @@ var driveListFilesContract = defineToolContract({
1292
1294
  projectId: mcpProjectId,
1293
1295
  folderId: f.optional(f.string({ desc: `Folder to list. ${ROOT_DEFAULT}` })),
1294
1296
  search: f.optional(f.string({ desc: "Only return names containing this text", max: 200 })),
1295
- limit: f.optional(f.number({ desc: "Max entries (default 100)", int: true, min: 1, max: 200 }))
1297
+ limit: f.optional(
1298
+ f.number({ desc: "Max entries (default 100)", int: true, min: 1, max: 200 })
1299
+ )
1296
1300
  }
1297
1301
  }
1298
1302
  });
@@ -1395,7 +1399,12 @@ var listMeetingsContract = defineToolContract({
1395
1399
  description: `List this project's meetings, newest first \u2014 each with its title, date, source, status, participants, and a short summary preview. Start here when you are asked about "the meeting", "what did we decide", or "what came out of that call". ${SUMMARY_NOTE}`,
1396
1400
  fields: {
1397
1401
  limit: f.optional(
1398
- f.number({ desc: "How many to return (default 20, maximum 50).", int: true, min: 1, max: 50 })
1402
+ f.number({
1403
+ desc: "How many to return (default 20, maximum 50).",
1404
+ int: true,
1405
+ min: 1,
1406
+ max: 50
1407
+ })
1399
1408
  ),
1400
1409
  search: f.optional(
1401
1410
  f.string({ desc: "Case-insensitive match on the meeting title.", max: 200 })
@@ -1407,7 +1416,12 @@ var listMeetingsContract = defineToolContract({
1407
1416
  fields: {
1408
1417
  projectId: mcpProjectId,
1409
1418
  limit: f.optional(
1410
- f.number({ desc: "How many to return (default 20, maximum 50).", int: true, min: 1, max: 50 })
1419
+ f.number({
1420
+ desc: "How many to return (default 20, maximum 50).",
1421
+ int: true,
1422
+ min: 1,
1423
+ max: 50
1424
+ })
1411
1425
  ),
1412
1426
  search: f.optional(
1413
1427
  f.string({ desc: "Case-insensitive match on the meeting title.", max: 200 })
@@ -1448,10 +1462,149 @@ var readMeetingTranscriptContract = defineToolContract({
1448
1462
  }
1449
1463
  }
1450
1464
  });
1465
+ var RAW_TEXT_DESC = "The transcript itself. Plain text with `Speaker: line` labels, or a WebVTT/SRT file's contents \u2014 the format is detected, and the speaker labels become the participant list. Paste the whole thing; it is stored as the meeting's record.";
1466
+ var OCCURRED_AT_DESC = "When the meeting happened, ISO 8601 (e.g. 2026-09-02T15:00:00Z). Defaults to now. Must be a real date \u2014 no earlier than 2000, and no more than 48 hours ahead.";
1467
+ var TITLE_DESC = "Meeting title. Defaults to `Meeting <date>` when you do not name one.";
1468
+ var createMeetingContract = defineToolContract({
1469
+ name: "create_meeting",
1470
+ agent: {
1471
+ description: `File a transcript as a project meeting. Use this when you have the text of a call \u2014 a paste, an export, notes captured elsewhere \u2014 and it belongs in the project's record. The transcript is parsed into speaker segments and an AI summary is written straight after, so the meeting reads "processing" for a few seconds before its overview appears. This creates a MEETING, not cards: turning what was decided into work is still create_task's job.`,
1472
+ fields: {
1473
+ rawText: f.string({ desc: RAW_TEXT_DESC, min: 1 }),
1474
+ title: f.optional(f.string({ desc: TITLE_DESC, max: 200 })),
1475
+ occurredAt: f.optional(f.string({ desc: OCCURRED_AT_DESC }))
1476
+ }
1477
+ },
1478
+ mcp: {
1479
+ description: `File a transcript as a project meeting. The text is parsed into speaker segments and summarized automatically, so the meeting reports status "processing" briefly before its overview lands. Creates a meeting only \u2014 use the card tools to turn decisions into work. ${MCP_TAIL}`,
1480
+ fields: {
1481
+ projectId: mcpProjectId,
1482
+ rawText: f.string({ desc: RAW_TEXT_DESC, min: 1 }),
1483
+ title: f.optional(f.string({ desc: TITLE_DESC, max: 200 })),
1484
+ occurredAt: f.optional(f.string({ desc: OCCURRED_AT_DESC }))
1485
+ }
1486
+ }
1487
+ });
1488
+ var SUMMARY_DESC = "Replace the meeting's overview with this text. Markdown, and it is what every reader sees from then on \u2014 write the whole overview, not a note about it. Writing a summary marks the meeting ready, so a later regenerate is the only thing that overwrites it.";
1489
+ var updateMeetingContract = defineToolContract({
1490
+ name: "update_meeting",
1491
+ agent: {
1492
+ description: `Correct a meeting's title or date, or replace its AI summary with a better one. This is how a rewritten overview actually persists \u2014 read the transcript, write the summary you want, and pass it here. Pass at least one field; the ones you leave out are untouched.`,
1493
+ fields: {
1494
+ meetingId: f.string({ desc: MEETING_ID }),
1495
+ title: f.optional(f.string({ desc: TITLE_DESC, max: 200 })),
1496
+ occurredAt: f.optional(f.string({ desc: OCCURRED_AT_DESC })),
1497
+ summary: f.optional(f.string({ desc: SUMMARY_DESC, min: 1 }))
1498
+ }
1499
+ },
1500
+ mcp: {
1501
+ description: `Correct a meeting's title or date, or replace its AI summary with a rewritten one. Pass at least one field; omitted fields are left alone. ${MCP_TAIL}`,
1502
+ fields: {
1503
+ projectId: mcpProjectId,
1504
+ meetingId: f.string({ desc: MEETING_ID }),
1505
+ title: f.optional(f.string({ desc: TITLE_DESC, max: 200 })),
1506
+ occurredAt: f.optional(f.string({ desc: OCCURRED_AT_DESC })),
1507
+ summary: f.optional(f.string({ desc: SUMMARY_DESC, min: 1 }))
1508
+ }
1509
+ }
1510
+ });
1511
+ var CHECKLIST_ITEM_TITLE = "The item's exact title, as get_meeting lists it. Matched case-insensitively.";
1512
+ var CHECKLIST_INTRO = "A meeting's checklist is its follow-ups: one line each, ticked when done, optionally pointing at the Conveyor card that carries the work. The AI summary's proposed next steps are seeded here automatically.";
1513
+ var addMeetingChecklistItemsContract = defineToolContract({
1514
+ name: "add_meeting_checklist_items",
1515
+ agent: {
1516
+ description: `Add follow-up items to a meeting's checklist. ${CHECKLIST_INTRO} Use this for a step the summary missed, or one that came out of a later conversation. Items whose title already exists are skipped, so re-running this is safe.`,
1517
+ fields: {
1518
+ meetingId: f.string({ desc: MEETING_ID }),
1519
+ items: f.array(
1520
+ f.object({ title: f.string({ desc: "One follow-up, as a single line.", min: 1 }) }),
1521
+ { desc: "The items to add, in the order they should appear." }
1522
+ )
1523
+ }
1524
+ },
1525
+ mcp: {
1526
+ description: `Add follow-up items to a meeting's checklist. ${CHECKLIST_INTRO} Existing titles are skipped, so re-running is safe. ${MCP_TAIL}`,
1527
+ fields: {
1528
+ projectId: mcpProjectId,
1529
+ meetingId: f.string({ desc: MEETING_ID }),
1530
+ items: f.array(
1531
+ f.object({ title: f.string({ desc: "One follow-up, as a single line.", min: 1 }) }),
1532
+ { desc: "The items to add, in the order they should appear." }
1533
+ )
1534
+ }
1535
+ }
1536
+ });
1537
+ var LINKED_TASK_DESC = "Card id or slug to attach to this item \u2014 the card that carries the work. Must be in the same project. Pass it in the same call that ticks the item when you just filed the card.";
1538
+ var checkMeetingChecklistItemContract = defineToolContract({
1539
+ name: "check_meeting_checklist_item",
1540
+ agent: {
1541
+ description: `Tick or untick one of a meeting's checklist items, and optionally attach the card that carries it. This is how a next step becomes tracked work: file the card with create_task, then call this with the item's title and the new card's slug. Ticking records YOU as the person who did it. Unticking clears that, but keeps the linked card.`,
1542
+ fields: {
1543
+ meetingId: f.string({ desc: MEETING_ID }),
1544
+ title: f.string({ desc: CHECKLIST_ITEM_TITLE }),
1545
+ checked: f.boolean({ desc: "true to tick the item, false to untick it." }),
1546
+ linkedTask: f.optional(f.string({ desc: LINKED_TASK_DESC }))
1547
+ }
1548
+ },
1549
+ mcp: {
1550
+ description: `Tick or untick a meeting checklist item, optionally attaching the card that carries it. Ticking records the acting user. Unticking clears that but keeps the link. ${MCP_TAIL}`,
1551
+ fields: {
1552
+ projectId: mcpProjectId,
1553
+ meetingId: f.string({ desc: MEETING_ID }),
1554
+ title: f.string({ desc: CHECKLIST_ITEM_TITLE }),
1555
+ checked: f.boolean({ desc: "true to tick the item, false to untick it." }),
1556
+ linkedTask: f.optional(f.string({ desc: LINKED_TASK_DESC }))
1557
+ }
1558
+ }
1559
+ });
1560
+ var editMeetingChecklistItemContract = defineToolContract({
1561
+ name: "edit_meeting_checklist_item",
1562
+ agent: {
1563
+ description: `Reword one of a meeting's checklist items. Use it to sharpen a vague next step into something someone can act on; to mark it done use check_meeting_checklist_item instead.`,
1564
+ fields: {
1565
+ meetingId: f.string({ desc: MEETING_ID }),
1566
+ title: f.string({ desc: CHECKLIST_ITEM_TITLE }),
1567
+ newTitle: f.string({ desc: "The replacement text, as a single line.", min: 1 })
1568
+ }
1569
+ },
1570
+ mcp: {
1571
+ description: `Reword a meeting checklist item. To mark it done use check_meeting_checklist_item. ${MCP_TAIL}`,
1572
+ fields: {
1573
+ projectId: mcpProjectId,
1574
+ meetingId: f.string({ desc: MEETING_ID }),
1575
+ title: f.string({ desc: CHECKLIST_ITEM_TITLE }),
1576
+ newTitle: f.string({ desc: "The replacement text, as a single line.", min: 1 })
1577
+ }
1578
+ }
1579
+ });
1580
+ var removeMeetingChecklistItemContract = defineToolContract({
1581
+ name: "remove_meeting_checklist_item",
1582
+ agent: {
1583
+ description: `Delete one of a meeting's checklist items. For a step that turned out not to be needed. An item someone already ticked is a record that work happened \u2014 untick it or leave it rather than deleting it.`,
1584
+ fields: {
1585
+ meetingId: f.string({ desc: MEETING_ID }),
1586
+ title: f.string({ desc: CHECKLIST_ITEM_TITLE })
1587
+ }
1588
+ },
1589
+ mcp: {
1590
+ description: `Delete a meeting checklist item. Prefer unticking over deleting an item someone already completed. ${MCP_TAIL}`,
1591
+ fields: {
1592
+ projectId: mcpProjectId,
1593
+ meetingId: f.string({ desc: MEETING_ID }),
1594
+ title: f.string({ desc: CHECKLIST_ITEM_TITLE })
1595
+ }
1596
+ }
1597
+ });
1451
1598
  var meetingsContracts = [
1452
1599
  listMeetingsContract,
1453
1600
  getMeetingContract,
1454
- readMeetingTranscriptContract
1601
+ readMeetingTranscriptContract,
1602
+ createMeetingContract,
1603
+ updateMeetingContract,
1604
+ addMeetingChecklistItemsContract,
1605
+ checkMeetingChecklistItemContract,
1606
+ editMeetingChecklistItemContract,
1607
+ removeMeetingChecklistItemContract
1455
1608
  ];
1456
1609
  var SINCE_MINUTES = f.optional(
1457
1610
  f.number({
@@ -1461,9 +1614,7 @@ var SINCE_MINUTES = f.optional(
1461
1614
  max: 10080
1462
1615
  })
1463
1616
  );
1464
- var START_TIME = f.optional(
1465
- f.string({ desc: "ISO 8601 lower bound (overrides sinceMinutes)" })
1466
- );
1617
+ var START_TIME = f.optional(f.string({ desc: "ISO 8601 lower bound (overrides sinceMinutes)" }));
1467
1618
  var END_TIME = f.optional(f.string({ desc: "ISO 8601 upper bound (default now)" }));
1468
1619
  var LIMIT = f.optional(
1469
1620
  f.number({ desc: "Max entries per page (default 50)", int: true, min: 1, max: 200 })
@@ -1497,7 +1648,10 @@ var gcpFields = {
1497
1648
  })
1498
1649
  ),
1499
1650
  search: f.optional(
1500
- f.string({ desc: "Free-text search across all log fields (exact substring, not regex)", max: 256 })
1651
+ f.string({
1652
+ desc: "Free-text search across all log fields (exact substring, not regex)",
1653
+ max: 256
1654
+ })
1501
1655
  ),
1502
1656
  filter: f.optional(
1503
1657
  f.string({
@@ -1725,7 +1879,9 @@ var contextPathSchema = z4.object({
1725
1879
  locator: z4.string().min(1).max(CONTEXT_LINK_LOCATOR_MAX).regex(/^[^\r\n]*$/, "Locator cannot contain line breaks").optional().describe(
1726
1880
  'Verified-link tether: text that must keep existing in the file for the link to stay live. With locatorType "test" it must appear inside a real it/test/describe TITLE (a renamed test flags the link stale even if its words survive in a comment); with "code" anywhere in the file. Conveyor re-validates links periodically and exposes per-link status in get_tag / manage_tags list. Locators containing <> are documentation placeholders and stay unchecked.'
1727
1881
  ),
1728
- locatorType: z4.enum(["test", "code"]).optional().describe("How the locator must match \u2014 required iff locator is set; not valid on folder links")
1882
+ locatorType: z4.enum(["test", "code"]).optional().describe(
1883
+ "How the locator must match \u2014 required iff locator is set; not valid on folder links"
1884
+ )
1729
1885
  }).refine((link) => link.locator === void 0 === (link.locatorType === void 0), {
1730
1886
  message: "locator and locatorType must be provided together"
1731
1887
  }).refine((link) => link.locator === void 0 || link.type !== "folder", {
@@ -2071,7 +2227,7 @@ function registerCreateTask(server2, conn2) {
2071
2227
  status: z5.enum(["Planning", "Open"]).optional().describe("Initial status (default: Planning)"),
2072
2228
  subProjectId: BOARD_ASSIGN,
2073
2229
  tags: z5.array(z5.string()).optional().describe(
2074
- 'Tag names to assign to the new card (e.g. ["refactor"]). Unknown names are rejected \u2014 create the tag first with manage_tags. Use list_tags to see available tags.'
2230
+ 'Tag names to assign to the new card (e.g. ["refactor"]). Unknown names are rejected before the card is created, so nothing is written and a corrected retry creates exactly one card. Create the tag first with manage_tags. Use list_tags to see available tags.'
2075
2231
  )
2076
2232
  },
2077
2233
  async (params) => {
@@ -3047,10 +3203,11 @@ import { z as z62 } from "zod";
3047
3203
  import { z as z72 } from "zod";
3048
3204
  import { z as z82 } from "zod";
3049
3205
  import { z as z92 } from "zod";
3206
+ import { z as z10 } from "zod";
3050
3207
  var DEFAULT_SONNET_MODEL = "claude-sonnet-5";
3051
3208
  var DEFAULT_OPUS_MODEL = "claude-opus-5";
3052
3209
  var DEFAULT_HAIKU_MODEL = "claude-haiku-4-5-20251001";
3053
- var FABLE_MODEL = "claude-fable-5";
3210
+ var FABLE_MODEL = "claude-fable-5-1";
3054
3211
  var PREVIOUS_SONNET_MODEL = "claude-sonnet-4-6";
3055
3212
  var PREVIOUS_OPUS_MODEL = "claude-opus-4-8";
3056
3213
  var PTY_STREAM_PORT_BASE = 7420;
@@ -3753,10 +3910,6 @@ var ReportReviewSpawnFailureRequestSchema = z42.object({
3753
3910
  var ReportBuilderSpawnFailureRequestSchema = ReportReviewSpawnFailureRequestSchema.omit({
3754
3911
  reviewSessionId: true
3755
3912
  }).extend({ buildSessionId: z42.string() });
3756
- var RequestWorkspaceRecycleRequestSchema = z42.object({
3757
- sessionId: z42.string(),
3758
- reason: z42.string().max(2e3)
3759
- });
3760
3913
  var SpawnTaskSessionRequestSchema = z42.object({
3761
3914
  taskId: z42.string(),
3762
3915
  kind: z42.enum(["tui", "shell"])
@@ -4439,12 +4592,21 @@ var GetProjectAnalyticsSummaryRequestSchema = z62.object({
4439
4592
  rangeDays: z62.number().int().min(1).max(GET_ANALYTICS_SUMMARY_MAX_RANGE_DAYS).optional(),
4440
4593
  campaign: z62.string().max(200).optional()
4441
4594
  });
4595
+ var RequestWorkspaceRecycleRequestSchema = z72.object({
4596
+ sessionId: z72.string(),
4597
+ reason: z72.string().max(2e3)
4598
+ });
4599
+ var ReportApiOutageRequestSchema = z72.object({
4600
+ sessionId: z72.string(),
4601
+ detail: z72.string().max(2e3),
4602
+ attempts: z72.number().int().min(0).max(100)
4603
+ });
4442
4604
  var SHA_PATTERN = /^[0-9a-f]{40}$/i;
4443
- var ReviewGuideFileReferenceSchema = z72.object({
4444
- path: z72.string().min(1).max(500),
4445
- startLine: z72.number().int().positive().max(1e6).optional(),
4446
- endLine: z72.number().int().positive().max(1e6).optional(),
4447
- hunkHeader: z72.string().min(1).max(300).optional()
4605
+ var ReviewGuideFileReferenceSchema = z82.object({
4606
+ path: z82.string().min(1).max(500),
4607
+ startLine: z82.number().int().positive().max(1e6).optional(),
4608
+ endLine: z82.number().int().positive().max(1e6).optional(),
4609
+ hunkHeader: z82.string().min(1).max(300).optional()
4448
4610
  }).strict().superRefine((value, ctx) => {
4449
4611
  if (value.endLine !== void 0 && value.startLine === void 0) {
4450
4612
  ctx.addIssue({
@@ -4461,190 +4623,282 @@ var ReviewGuideFileReferenceSchema = z72.object({
4461
4623
  });
4462
4624
  }
4463
4625
  });
4464
- var ReviewGuideSectionSchema = z72.object({
4465
- title: z72.string().min(1).max(160),
4466
- explanation: z72.string().min(1).max(2e3),
4467
- classification: z72.enum(["core", "supporting"]).optional(),
4468
- files: z72.array(ReviewGuideFileReferenceSchema).min(1).max(20)
4626
+ var ReviewGuideSectionSchema = z82.object({
4627
+ title: z82.string().min(1).max(160),
4628
+ explanation: z82.string().min(1).max(2e3),
4629
+ classification: z82.enum(["core", "supporting"]).optional(),
4630
+ files: z82.array(ReviewGuideFileReferenceSchema).min(1).max(20)
4469
4631
  }).strict();
4470
- var ReviewGuideContentSchema = z72.object({
4471
- overview: z72.string().min(1).max(3e3),
4472
- sections: z72.array(ReviewGuideSectionSchema).min(1).max(12)
4632
+ var ReviewGuideContentSchema = z82.object({
4633
+ overview: z82.string().min(1).max(3e3),
4634
+ sections: z82.array(ReviewGuideSectionSchema).min(1).max(12)
4473
4635
  }).strict();
4474
4636
  var PublishReviewGuideRequestSchema = ReviewGuideContentSchema.extend({
4475
- sessionId: z72.string().min(1),
4476
- reviewedSha: z72.string().regex(SHA_PATTERN, "reviewedSha must be a 40-character commit SHA")
4637
+ sessionId: z82.string().min(1),
4638
+ reviewedSha: z82.string().regex(SHA_PATTERN, "reviewedSha must be a 40-character commit SHA")
4477
4639
  }).strict();
4478
4640
  var CONTEXT_LINK_LOCATOR_MAX2 = 300;
4479
4641
  var TAG_DESCRIPTION_MAX = CARD_DESCRIPTION_MAX;
4480
4642
  var TAG_OVERVIEW_MAX = 32e3;
4481
4643
  var TAG_REASON_MAX = 500;
4482
- var ProjectTagContextPathSchema = z82.object({
4483
- type: z82.enum(["rule", "doc", "file", "folder"]),
4484
- path: z82.string().min(1).max(500),
4485
- label: z82.string().max(100).optional(),
4644
+ var ProjectTagContextPathSchema = z92.object({
4645
+ type: z92.enum(["rule", "doc", "file", "folder"]),
4646
+ path: z92.string().min(1).max(500),
4647
+ label: z92.string().max(100).optional(),
4486
4648
  /** Verified-link tether — text that must keep existing in the file. */
4487
- locator: z82.string().min(1).max(CONTEXT_LINK_LOCATOR_MAX2).regex(/^[^\r\n]*$/, "Locator cannot contain line breaks").optional(),
4649
+ locator: z92.string().min(1).max(CONTEXT_LINK_LOCATOR_MAX2).regex(/^[^\r\n]*$/, "Locator cannot contain line breaks").optional(),
4488
4650
  /** test = must appear in a real test/describe title; code = any substring. */
4489
- locatorType: z82.enum(["test", "code"]).optional()
4651
+ locatorType: z92.enum(["test", "code"]).optional()
4490
4652
  }).refine((link) => link.locator === void 0 === (link.locatorType === void 0), {
4491
4653
  message: "locator and locatorType must be provided together"
4492
4654
  }).refine((link) => link.locator === void 0 || link.type !== "folder", {
4493
4655
  message: "folder links cannot carry a locator"
4494
4656
  });
4495
- var hexColor = z82.string().regex(/^#[0-9a-fA-F]{6}$/, "Expected #RRGGBB hex color");
4496
- var overviewPathSchema = z82.string().min(1).max(500).regex(/^[^\r\n]*$/, "Overview path cannot contain line breaks");
4497
- var CreateProjectTagRequestSchema = z82.object({
4498
- projectId: z82.string(),
4499
- name: z82.string().min(1).max(50),
4657
+ var hexColor = z92.string().regex(/^#[0-9a-fA-F]{6}$/, "Expected #RRGGBB hex color");
4658
+ var overviewPathSchema = z92.string().min(1).max(500).regex(/^[^\r\n]*$/, "Overview path cannot contain line breaks");
4659
+ var CreateProjectTagRequestSchema = z92.object({
4660
+ projectId: z92.string(),
4661
+ name: z92.string().min(1).max(50),
4500
4662
  color: hexColor.optional(),
4501
- description: z82.string().max(TAG_DESCRIPTION_MAX).optional(),
4502
- overview: z82.string().max(TAG_OVERVIEW_MAX).optional(),
4663
+ description: z92.string().max(TAG_DESCRIPTION_MAX).optional(),
4664
+ overview: z92.string().max(TAG_OVERVIEW_MAX).optional(),
4503
4665
  /** Source the overview from this repo file (stored overview stays as the pending fallback). */
4504
4666
  overviewPath: overviewPathSchema.optional(),
4505
- contextPaths: z82.array(ProjectTagContextPathSchema).max(20).optional(),
4667
+ contextPaths: z92.array(ProjectTagContextPathSchema).max(20).optional(),
4506
4668
  /** Parents to link at create time (multi-parent DAG). */
4507
- parentTagIds: z82.array(z82.string()).max(25).optional(),
4508
- requestingUserId: z82.string().optional()
4669
+ parentTagIds: z92.array(z92.string()).max(25).optional(),
4670
+ requestingUserId: z92.string().optional()
4509
4671
  });
4510
- var UpdateProjectTagRequestSchema = z82.object({
4511
- projectId: z82.string(),
4512
- tagId: z82.string(),
4513
- name: z82.string().min(1).max(50).optional(),
4672
+ var UpdateProjectTagRequestSchema = z92.object({
4673
+ projectId: z92.string(),
4674
+ tagId: z92.string(),
4675
+ name: z92.string().min(1).max(50).optional(),
4514
4676
  color: hexColor.optional(),
4515
- description: z82.string().max(TAG_DESCRIPTION_MAX).optional(),
4677
+ description: z92.string().max(TAG_DESCRIPTION_MAX).optional(),
4516
4678
  /** Full markdown glossary body; null clears it. Rejected while overviewPath is set. */
4517
- overview: z82.string().max(TAG_OVERVIEW_MAX).nullable().optional(),
4679
+ overview: z92.string().max(TAG_OVERVIEW_MAX).nullable().optional(),
4518
4680
  /** Repo file to source the overview from; null clears back to the stored overview. */
4519
4681
  overviewPath: overviewPathSchema.nullable().optional(),
4520
4682
  /** Full replacement of the tag's context links when provided. */
4521
- contextPaths: z82.array(ProjectTagContextPathSchema).max(20).optional(),
4683
+ contextPaths: z92.array(ProjectTagContextPathSchema).max(20).optional(),
4522
4684
  /** Full-set replacement of the tag's parent tags (multi-parent DAG). */
4523
- parentTagIds: z82.array(z82.string()).max(25).optional(),
4685
+ parentTagIds: z92.array(z92.string()).max(25).optional(),
4524
4686
  /** One-line revision provenance, recorded in the tag's history. */
4525
- reason: z82.string().max(TAG_REASON_MAX).optional(),
4687
+ reason: z92.string().max(TAG_REASON_MAX).optional(),
4526
4688
  /** Card the caller was working in — stamped into the revision history. */
4527
- taskId: z82.string().optional(),
4528
- requestingUserId: z82.string().optional()
4689
+ taskId: z92.string().optional(),
4690
+ requestingUserId: z92.string().optional()
4529
4691
  });
4530
- var PostToProjectChatRequestSchema = z82.object({
4531
- projectId: z82.string(),
4532
- content: z82.string().min(1).max(2e4),
4533
- requestingUserId: z82.string().optional(),
4692
+ var PostToProjectChatRequestSchema = z92.object({
4693
+ projectId: z92.string(),
4694
+ content: z92.string().min(1).max(2e4),
4695
+ requestingUserId: z92.string().optional(),
4534
4696
  /** Marks the post so the server can persist it beyond chat (tag-audit summaries land in tag history). */
4535
- kind: z82.enum(["tag_audit_summary"]).optional()
4536
- });
4537
- var StartTagAuditRequestSchema = z82.object({
4538
- projectId: z82.string(),
4539
- requestingUserId: z82.string().optional()
4540
- });
4541
- var StartTaskAuditRequestSchema = z82.object({
4542
- projectId: z82.string(),
4543
- taskIds: z82.array(z82.string()).min(1).max(20),
4544
- requestingUserId: z82.string().optional()
4545
- });
4546
- var GetActiveAuditSessionsRequestSchema = z82.object({
4547
- projectId: z82.string()
4548
- });
4549
- var ReportTaskAuditResultRequestSchema = z82.object({
4550
- projectId: z82.string(),
4551
- taskId: z82.string(),
4552
- summary: z82.string(),
4553
- turnGrades: z82.array(
4554
- z82.object({
4555
- turnIndex: z82.number(),
4556
- phase: z82.enum(["planning", "building", "human"]),
4557
- grade: z82.enum(["correct", "neutral", "blunder"]),
4558
- reasoning: z82.string(),
4559
- eventType: z82.string(),
4560
- eventSummary: z82.string()
4697
+ kind: z92.enum(["tag_audit_summary"]).optional()
4698
+ });
4699
+ var StartTagAuditRequestSchema = z92.object({
4700
+ projectId: z92.string(),
4701
+ requestingUserId: z92.string().optional()
4702
+ });
4703
+ var StartTaskAuditRequestSchema = z92.object({
4704
+ projectId: z92.string(),
4705
+ taskIds: z92.array(z92.string()).min(1).max(20),
4706
+ requestingUserId: z92.string().optional()
4707
+ });
4708
+ var GetActiveAuditSessionsRequestSchema = z92.object({
4709
+ projectId: z92.string()
4710
+ });
4711
+ var ReportTaskAuditResultRequestSchema = z92.object({
4712
+ projectId: z92.string(),
4713
+ taskId: z92.string(),
4714
+ summary: z92.string(),
4715
+ turnGrades: z92.array(
4716
+ z92.object({
4717
+ turnIndex: z92.number(),
4718
+ phase: z92.enum(["planning", "building", "human"]),
4719
+ grade: z92.enum(["correct", "neutral", "blunder"]),
4720
+ reasoning: z92.string(),
4721
+ eventType: z92.string(),
4722
+ eventSummary: z92.string()
4561
4723
  })
4562
4724
  ),
4563
- planningAccuracy: z82.number().nullable(),
4564
- buildingAccuracy: z82.number().nullable(),
4565
- humanAccuracy: z82.number().nullable(),
4566
- planningCorrect: z82.number(),
4567
- planningNeutral: z82.number(),
4568
- planningBlunder: z82.number(),
4569
- buildingCorrect: z82.number(),
4570
- buildingNeutral: z82.number(),
4571
- buildingBlunder: z82.number(),
4572
- humanCorrect: z82.number(),
4573
- humanNeutral: z82.number(),
4574
- humanBlunder: z82.number(),
4575
- humanEvaluations: z82.array(
4576
- z82.object({
4577
- messageIndex: z82.number(),
4578
- rating: z82.union([z82.literal(-1), z82.literal(0), z82.literal(1)]),
4579
- reasoning: z82.string()
4725
+ planningAccuracy: z92.number().nullable(),
4726
+ buildingAccuracy: z92.number().nullable(),
4727
+ humanAccuracy: z92.number().nullable(),
4728
+ planningCorrect: z92.number(),
4729
+ planningNeutral: z92.number(),
4730
+ planningBlunder: z92.number(),
4731
+ buildingCorrect: z92.number(),
4732
+ buildingNeutral: z92.number(),
4733
+ buildingBlunder: z92.number(),
4734
+ humanCorrect: z92.number(),
4735
+ humanNeutral: z92.number(),
4736
+ humanBlunder: z92.number(),
4737
+ humanEvaluations: z92.array(
4738
+ z92.object({
4739
+ messageIndex: z92.number(),
4740
+ rating: z92.union([z92.literal(-1), z92.literal(0), z92.literal(1)]),
4741
+ reasoning: z92.string()
4580
4742
  })
4581
4743
  ).optional(),
4582
- suggestionIds: z82.array(z82.string()),
4583
- auditCostUsd: z82.number().nullable(),
4584
- model: z82.string().nullable(),
4744
+ suggestionIds: z92.array(z92.string()),
4745
+ auditCostUsd: z92.number().nullable(),
4746
+ model: z92.string().nullable(),
4585
4747
  /** When set, the audit is marked failed with this message instead. */
4586
- error: z82.string().optional()
4748
+ error: z92.string().optional()
4587
4749
  });
4588
- var GetTaskAuditsRequestSchema = z82.object({
4589
- projectId: z82.string(),
4590
- limit: z82.number().int().positive().max(200).optional().default(50)
4750
+ var GetTaskAuditsRequestSchema = z92.object({
4751
+ projectId: z92.string(),
4752
+ limit: z92.number().int().positive().max(200).optional().default(50)
4591
4753
  });
4592
- var GetTaskAuditRequestSchema = z82.object({
4593
- projectId: z82.string(),
4594
- auditId: z82.string()
4754
+ var GetTaskAuditRequestSchema = z92.object({
4755
+ projectId: z92.string(),
4756
+ auditId: z92.string()
4595
4757
  });
4596
- var GetTaskAuditAggregatesRequestSchema = z82.object({
4597
- projectId: z82.string()
4758
+ var GetTaskAuditAggregatesRequestSchema = z92.object({
4759
+ projectId: z92.string()
4598
4760
  });
4599
- var DeleteTaskAuditRequestSchema = z82.object({
4600
- projectId: z82.string(),
4601
- auditId: z82.string(),
4602
- requestingUserId: z82.string().optional()
4761
+ var DeleteTaskAuditRequestSchema = z92.object({
4762
+ projectId: z92.string(),
4763
+ auditId: z92.string(),
4764
+ requestingUserId: z92.string().optional()
4603
4765
  });
4604
- var MarkInitialPromptSubmittedRequestSchema = z82.object({
4605
- sessionId: z82.string()
4766
+ var MarkInitialPromptSubmittedRequestSchema = z92.object({
4767
+ sessionId: z92.string()
4606
4768
  });
4769
+ var MEETING_CHECKLIST_TITLE_MAX = 300;
4607
4770
  var MEETING_TRANSCRIPT_MAX_CHARS = 2e6;
4608
4771
  var MEETING_TITLE_MAX = 200;
4609
- var CreateMeetingFromTranscriptRequestSchema = z92.object({
4610
- projectId: z92.string().cuid(),
4611
- rawText: z92.string().min(1).max(MEETING_TRANSCRIPT_MAX_CHARS),
4612
- title: z92.string().min(1).max(MEETING_TITLE_MAX).optional(),
4772
+ var MEETING_OCCURRED_AT_MIN_YEAR = 2e3;
4773
+ var MEETING_OCCURRED_AT_MAX_FUTURE_MS = 48 * 60 * 60 * 1e3;
4774
+ var OCCURRED_AT_RANGE_MESSAGE = `occurredAt must be a real date: no earlier than ${MEETING_OCCURRED_AT_MIN_YEAR}, and no more than 48 hours in the future.`;
4775
+ var MeetingOccurredAtSchema = z10.string().datetime().refine((value) => {
4776
+ const ms = Date.parse(value);
4777
+ if (Number.isNaN(ms)) return false;
4778
+ if (ms > Date.now() + MEETING_OCCURRED_AT_MAX_FUTURE_MS) return false;
4779
+ return new Date(ms).getUTCFullYear() >= MEETING_OCCURRED_AT_MIN_YEAR;
4780
+ }, OCCURRED_AT_RANGE_MESSAGE);
4781
+ var CreateMeetingFromTranscriptRequestSchema = z10.object({
4782
+ projectId: z10.string().cuid(),
4783
+ rawText: z10.string().min(1).max(MEETING_TRANSCRIPT_MAX_CHARS),
4784
+ title: z10.string().min(1).max(MEETING_TITLE_MAX).optional(),
4613
4785
  /** ISO 8601. Defaults to now when the source carries no date. */
4614
- occurredAt: z92.string().datetime().optional(),
4786
+ occurredAt: MeetingOccurredAtSchema.optional(),
4615
4787
  /** Override auto-detection. Rarely needed; detection handles the three formats. */
4616
- format: z92.enum(["text", "vtt", "srt"]).optional(),
4617
- source: z92.enum(["manual", "slack"]).optional()
4618
- });
4619
- var GetMeetingRequestSchema = z92.object({
4620
- projectId: z92.string().cuid(),
4621
- meetingId: z92.string().cuid()
4622
- });
4623
- var UpdateMeetingRequestSchema = z92.object({
4624
- projectId: z92.string().cuid(),
4625
- meetingId: z92.string().cuid(),
4626
- title: z92.string().min(1).max(MEETING_TITLE_MAX).optional(),
4627
- occurredAt: z92.string().datetime().optional()
4628
- });
4629
- var RegenerateMeetingSummaryRequestSchema = z92.object({
4630
- projectId: z92.string().cuid(),
4631
- meetingId: z92.string().cuid()
4632
- });
4633
- var DeleteMeetingRequestSchema = z92.object({
4634
- projectId: z92.string().cuid(),
4635
- meetingId: z92.string().cuid()
4636
- });
4637
- var ListMeetingsRequestSchema = z92.object({
4638
- projectId: z92.string().cuid(),
4639
- limit: z92.number().int().min(1).max(50).optional(),
4640
- search: z92.string().max(200).optional()
4641
- });
4642
- var ReadMeetingTranscriptRequestSchema = z92.object({
4643
- projectId: z92.string().cuid(),
4644
- meetingId: z92.string().cuid(),
4645
- offset: z92.number().int().min(0).optional(),
4646
- limit: z92.number().int().min(1).max(500).optional()
4647
- });
4788
+ format: z10.enum(["text", "vtt", "srt"]).optional(),
4789
+ source: z10.enum(["manual", "slack"]).optional()
4790
+ });
4791
+ var GetMeetingRequestSchema = z10.object({
4792
+ projectId: z10.string().cuid(),
4793
+ meetingId: z10.string().cuid()
4794
+ });
4795
+ var UpdateMeetingRequestSchema = z10.object({
4796
+ projectId: z10.string().cuid(),
4797
+ meetingId: z10.string().cuid(),
4798
+ title: z10.string().min(1).max(MEETING_TITLE_MAX).optional(),
4799
+ occurredAt: MeetingOccurredAtSchema.optional()
4800
+ });
4801
+ var RegenerateMeetingSummaryRequestSchema = z10.object({
4802
+ projectId: z10.string().cuid(),
4803
+ meetingId: z10.string().cuid()
4804
+ });
4805
+ var DeleteMeetingRequestSchema = z10.object({
4806
+ projectId: z10.string().cuid(),
4807
+ meetingId: z10.string().cuid()
4808
+ });
4809
+ var checklistTitle = z10.string().min(1).max(MEETING_CHECKLIST_TITLE_MAX);
4810
+ var ListMeetingChecklistRequestSchema = z10.object({
4811
+ projectId: z10.string().cuid(),
4812
+ meetingId: z10.string().cuid()
4813
+ });
4814
+ var AddMeetingChecklistItemsRequestSchema = z10.object({
4815
+ projectId: z10.string().cuid(),
4816
+ meetingId: z10.string().cuid(),
4817
+ items: z10.array(z10.object({ title: checklistTitle })).min(1).max(50)
4818
+ });
4819
+ var UpdateMeetingChecklistItemRequestSchema = z10.object({
4820
+ projectId: z10.string().cuid(),
4821
+ meetingId: z10.string().cuid(),
4822
+ itemId: z10.string().cuid(),
4823
+ title: checklistTitle.optional(),
4824
+ ordinal: z10.number().int().min(0).optional(),
4825
+ /** Explicit null clears the link; undefined leaves it alone. */
4826
+ linkedTaskId: z10.string().cuid().nullable().optional()
4827
+ }).refine(
4828
+ (v) => v.title !== void 0 || v.ordinal !== void 0 || v.linkedTaskId !== void 0,
4829
+ "Pass at least one of title, ordinal, or linkedTaskId."
4830
+ );
4831
+ var DeleteMeetingChecklistItemRequestSchema = z10.object({
4832
+ projectId: z10.string().cuid(),
4833
+ meetingId: z10.string().cuid(),
4834
+ itemId: z10.string().cuid()
4835
+ });
4836
+ var SetMeetingChecklistItemCheckedRequestSchema = z10.object({
4837
+ projectId: z10.string().cuid(),
4838
+ meetingId: z10.string().cuid(),
4839
+ itemId: z10.string().cuid(),
4840
+ checked: z10.boolean(),
4841
+ /** Attach the card in the same call that ticks the item. */
4842
+ linkedTaskId: z10.string().cuid().nullable().optional()
4843
+ });
4844
+ var ListMeetingsRequestSchema = z10.object({
4845
+ projectId: z10.string().cuid(),
4846
+ limit: z10.number().int().min(1).max(50).optional(),
4847
+ search: z10.string().max(200).optional()
4848
+ });
4849
+ var ReadMeetingTranscriptRequestSchema = z10.object({
4850
+ projectId: z10.string().cuid(),
4851
+ meetingId: z10.string().cuid(),
4852
+ offset: z10.number().int().min(0).optional(),
4853
+ limit: z10.number().int().min(1).max(500).optional()
4854
+ });
4855
+ var MEETING_SUMMARY_MAX_CHARS = 5e4;
4856
+ var AddProjectMeetingChecklistItemsRequestSchema = z10.object({
4857
+ projectId: z10.string().cuid(),
4858
+ meetingId: z10.string().cuid(),
4859
+ items: z10.array(z10.object({ title: z10.string().min(1).max(MEETING_CHECKLIST_TITLE_MAX) })).min(1).max(50),
4860
+ requestingUserId: z10.string().optional()
4861
+ });
4862
+ var CheckProjectMeetingChecklistItemRequestSchema = z10.object({
4863
+ projectId: z10.string().cuid(),
4864
+ meetingId: z10.string().cuid(),
4865
+ title: z10.string().min(1).max(MEETING_CHECKLIST_TITLE_MAX),
4866
+ checked: z10.boolean(),
4867
+ /** Card id or slug. Resolved server-side and required to be in the project. */
4868
+ linkedTask: z10.string().min(1).optional(),
4869
+ requestingUserId: z10.string().optional()
4870
+ });
4871
+ var EditProjectMeetingChecklistItemRequestSchema = z10.object({
4872
+ projectId: z10.string().cuid(),
4873
+ meetingId: z10.string().cuid(),
4874
+ title: z10.string().min(1).max(MEETING_CHECKLIST_TITLE_MAX),
4875
+ newTitle: z10.string().min(1).max(MEETING_CHECKLIST_TITLE_MAX),
4876
+ requestingUserId: z10.string().optional()
4877
+ });
4878
+ var RemoveProjectMeetingChecklistItemRequestSchema = z10.object({
4879
+ projectId: z10.string().cuid(),
4880
+ meetingId: z10.string().cuid(),
4881
+ title: z10.string().min(1).max(MEETING_CHECKLIST_TITLE_MAX),
4882
+ requestingUserId: z10.string().optional()
4883
+ });
4884
+ var CreateProjectMeetingRequestSchema = z10.object({
4885
+ projectId: z10.string().cuid(),
4886
+ rawText: z10.string().min(1).max(MEETING_TRANSCRIPT_MAX_CHARS),
4887
+ title: z10.string().min(1).max(MEETING_TITLE_MAX).optional(),
4888
+ occurredAt: MeetingOccurredAtSchema.optional(),
4889
+ requestingUserId: z10.string().optional()
4890
+ });
4891
+ var UpdateProjectMeetingRequestSchema = z10.object({
4892
+ projectId: z10.string().cuid(),
4893
+ meetingId: z10.string().cuid(),
4894
+ title: z10.string().min(1).max(MEETING_TITLE_MAX).optional(),
4895
+ occurredAt: MeetingOccurredAtSchema.optional(),
4896
+ summary: z10.string().min(1).max(MEETING_SUMMARY_MAX_CHARS).optional(),
4897
+ requestingUserId: z10.string().optional()
4898
+ }).refine(
4899
+ (v) => v.title !== void 0 || v.occurredAt !== void 0 || v.summary !== void 0,
4900
+ "Pass at least one of title, occurredAt, or summary."
4901
+ );
4648
4902
  var TASK_CHAT_HISTORY_LIMIT = 20;
4649
4903
  var PM_CHAT_HISTORY_LIMIT = 40;
4650
4904
  var AGENT_CHAT_HISTORY_FETCH_LIMIT = Math.max(TASK_CHAT_HISTORY_LIMIT, PM_CHAT_HISTORY_LIMIT) + 10;
@@ -4672,8 +4926,11 @@ var ANTHROPIC_CATALOG = [
4672
4926
  anthropicEntry(PREVIOUS_SONNET_MODEL, "Sonnet 4.6", 3, 15),
4673
4927
  // The Haiku line (4.5 and older) predates the tuning surface and 400s on it.
4674
4928
  anthropicEntry(DEFAULT_HAIKU_MODEL, "Haiku 4.5", 1, 5, { supportsEffort: false }),
4675
- anthropicEntry(FABLE_MODEL, "Fable 5 (experimental)", 10, 50, { experimental: true })
4929
+ anthropicEntry(FABLE_MODEL, "Fable 5.1", 10, 50)
4676
4930
  ];
4931
+ var CLAUDESPACE_WORKLOAD_LABEL = "rc-workload";
4932
+ var CLAUDESPACE_WORKLOAD_VALUE = "claudespace";
4933
+ var CONVEYOR_POD_SELECTOR = `${CLAUDESPACE_WORKLOAD_LABEL}=${CLAUDESPACE_WORKLOAD_VALUE}`;
4677
4934
  var MS_PER_DAY = 24 * 60 * 60 * 1e3;
4678
4935
  var POSTGRES_ENV = {
4679
4936
  POSTGRES_HOST_AUTH_METHOD: "trust",
@@ -5073,7 +5330,34 @@ ${content}` }] };
5073
5330
  }
5074
5331
 
5075
5332
  // src/tools/meetings.ts
5333
+ function describeItem(item) {
5334
+ const box = item.checked ? "[x]" : "[ ]";
5335
+ const who = item.checked && item.checkedBy ? ` \u2014 ${item.checkedBy}` : "";
5336
+ const card = item.linkedTaskSlug ? ` (${item.linkedTaskSlug})` : "";
5337
+ return `${box} ${item.title}${who}${card}`;
5338
+ }
5339
+ function registerChecklistTools2(server2, conn2) {
5340
+ registerContractTool(server2, addMeetingChecklistItemsContract, async (params) => {
5341
+ const res = await conn2.addMeetingChecklistItems(params);
5342
+ const text = res.length === 0 ? "No items added \u2014 every title is already on this checklist." : `Added ${res.length}:
5343
+ ${res.map(describeItem).join("\n")}`;
5344
+ return { content: [{ type: "text", text }] };
5345
+ });
5346
+ registerContractTool(server2, checkMeetingChecklistItemContract, async (params) => {
5347
+ const res = await conn2.checkMeetingChecklistItem(params);
5348
+ return { content: [{ type: "text", text: describeItem(res) }] };
5349
+ });
5350
+ registerContractTool(server2, editMeetingChecklistItemContract, async (params) => {
5351
+ const res = await conn2.editMeetingChecklistItem(params);
5352
+ return { content: [{ type: "text", text: describeItem(res) }] };
5353
+ });
5354
+ registerContractTool(server2, removeMeetingChecklistItemContract, async (params) => {
5355
+ const res = await conn2.removeMeetingChecklistItem(params);
5356
+ return { content: [{ type: "text", text: `Removed "${res.title}".` }] };
5357
+ });
5358
+ }
5076
5359
  function registerMeetingTools(server2, conn2) {
5360
+ registerChecklistTools2(server2, conn2);
5077
5361
  registerContractTool(server2, listMeetingsContract, async (params) => {
5078
5362
  const res = await conn2.listMeetings(params);
5079
5363
  if (res.meetings.length === 0) {
@@ -5092,6 +5376,24 @@ function registerMeetingTools(server2, conn2) {
5092
5376
  const res = await conn2.getMeeting(params);
5093
5377
  return { content: [{ type: "text", text: JSON.stringify(res, null, 2) }] };
5094
5378
  });
5379
+ registerContractTool(server2, createMeetingContract, async (params) => {
5380
+ const res = await conn2.createMeeting(params);
5381
+ return {
5382
+ content: [
5383
+ {
5384
+ type: "text",
5385
+ text: `Created "${res.title}" (${res.segmentCount} segments, ${res.participants.length} participants).
5386
+ The AI summary is being written now; read it back with get_meeting in a few seconds.
5387
+ ${res.url}`
5388
+ }
5389
+ ]
5390
+ };
5391
+ });
5392
+ registerContractTool(server2, updateMeetingContract, async (params) => {
5393
+ const res = await conn2.updateMeeting(params);
5394
+ return { content: [{ type: "text", text: `Updated "${res.title}".
5395
+ ${res.url}` }] };
5396
+ });
5095
5397
  registerContractTool(server2, readMeetingTranscriptContract, async (params) => {
5096
5398
  const res = await conn2.readMeetingTranscript(params);
5097
5399
  const header = `${res.title} \u2014 segments ${res.offset + 1}-${res.offset + res.lines.length} of ${res.segmentCount}`;
@@ -1,4 +1,4 @@
1
- import { ListDriveFilesResponse, ReadDriveFileResponse, DriveFileDTO, DeleteDriveFileResponse, ProjectIntegrationsSummary, GaAnalyticsSummaryDTO, ProjectChannelDTO, ReadChannelMessagesResponse, PostChannelMessageResponse, ListMeetingsResponse, MeetingForAgent, ReadMeetingTranscriptResponse } from '@project/shared';
1
+ import { ListDriveFilesResponse, ReadDriveFileResponse, DriveFileDTO, DeleteDriveFileResponse, ProjectIntegrationsSummary, GaAnalyticsSummaryDTO, ProjectChannelDTO, ReadChannelMessagesResponse, PostChannelMessageResponse, ListMeetingsResponse, MeetingForAgent, ReadMeetingTranscriptResponse, MeetingChecklistItemForAgent } from '@project/shared';
2
2
 
3
3
  interface ConveyorMcpConfig {
4
4
  apiUrl: string;
@@ -427,8 +427,8 @@ declare class ConveyorConnection {
427
427
  }>;
428
428
  /** Resolve tag names to IDs within a project, throwing on any unknown name. */
429
429
  private resolveTagIds;
430
- private assignTagsToTask;
431
- private removeTagsFromTask;
430
+ private assignResolvedTags;
431
+ private removeResolvedTags;
432
432
  /** Guarded status transition used by the review tools (approve/request). */
433
433
  transitionTaskStatus(params: {
434
434
  projectId?: string;
@@ -685,6 +685,46 @@ declare class ConveyorConnection {
685
685
  offset?: number;
686
686
  limit?: number;
687
687
  }): Promise<ReadMeetingTranscriptResponse>;
688
+ createMeeting(params: {
689
+ projectId?: string;
690
+ rawText: string;
691
+ title?: string;
692
+ occurredAt?: string;
693
+ }): Promise<MeetingForAgent>;
694
+ updateMeeting(params: {
695
+ projectId?: string;
696
+ meetingId: string;
697
+ title?: string;
698
+ occurredAt?: string;
699
+ summary?: string;
700
+ }): Promise<MeetingForAgent>;
701
+ addMeetingChecklistItems(params: {
702
+ projectId?: string;
703
+ meetingId: string;
704
+ items: {
705
+ title: string;
706
+ }[];
707
+ }): Promise<MeetingChecklistItemForAgent[]>;
708
+ checkMeetingChecklistItem(params: {
709
+ projectId?: string;
710
+ meetingId: string;
711
+ title: string;
712
+ checked: boolean;
713
+ linkedTask?: string;
714
+ }): Promise<MeetingChecklistItemForAgent>;
715
+ editMeetingChecklistItem(params: {
716
+ projectId?: string;
717
+ meetingId: string;
718
+ title: string;
719
+ newTitle: string;
720
+ }): Promise<MeetingChecklistItemForAgent>;
721
+ removeMeetingChecklistItem(params: {
722
+ projectId?: string;
723
+ meetingId: string;
724
+ title: string;
725
+ }): Promise<{
726
+ title: string;
727
+ }>;
688
728
  /** Effective account/project/board identity + capabilities for this token. */
689
729
  getConnectionContext(projectId?: string): Promise<ConnectionContext>;
690
730
  /** Layered verify-by-scope probe (auth → account → project → board →
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { A as ActivePtySession, d as ConveyorConnection, e as ConveyorMcpConfig, P as PtyAttachSnapshot, c as PtyDataChunk } from './connection-DtGKRfga.js';
1
+ export { A as ActivePtySession, d as ConveyorConnection, e as ConveyorMcpConfig, P as PtyAttachSnapshot, c as PtyDataChunk } from './connection-B7CwszOV.js';
2
2
  export { AttachTunnelOptions, ResolvedPtySession, RunTunnelOptions, TunnelConnection, TunnelHandle, TunnelSession, TunnelTty, WaitForPtySessionOptions, attachTunnel, runTunnel, waitForPtySession } from './tunnel.js';
3
3
  import '@project/shared';
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  } from "./chunk-HIVOGGE3.js";
6
6
  import {
7
7
  ConveyorConnection
8
- } from "./chunk-2TVN7F5E.js";
8
+ } from "./chunk-XLDG5QEX.js";
9
9
  export {
10
10
  ConveyorConnection,
11
11
  attachTunnel,
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-HIVOGGE3.js";
5
5
  import {
6
6
  ConveyorConnection
7
- } from "./chunk-2TVN7F5E.js";
7
+ } from "./chunk-XLDG5QEX.js";
8
8
 
9
9
  // src/tunnel-cli.ts
10
10
  var HELP = `conveyor-tunnel \u2014 attach your local terminal to a cloud Claude Code session.
package/dist/tunnel.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as ActivePtySession, P as PtyAttachSnapshot, c as PtyDataChunk } from './connection-DtGKRfga.js';
1
+ import { A as ActivePtySession, P as PtyAttachSnapshot, c as PtyDataChunk } from './connection-B7CwszOV.js';
2
2
  import '@project/shared';
3
3
 
4
4
  /**
package/dist/wait-cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ConveyorConnection
4
- } from "./chunk-2TVN7F5E.js";
4
+ } from "./chunk-XLDG5QEX.js";
5
5
  import {
6
6
  runWait
7
7
  } from "./chunk-OPZL4NDT.js";
@@ -1,4 +1,4 @@
1
- import { C as CardCollectionPage, a as CardCollectionDelta } from './connection-DtGKRfga.js';
1
+ import { C as CardCollectionPage, a as CardCollectionDelta } from './connection-B7CwszOV.js';
2
2
  import { WaitFilter, WaitResult } from './wait.js';
3
3
  import '@project/shared';
4
4
 
package/dist/wait.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { b as CardCollectionItem } from './connection-DtGKRfga.js';
1
+ import { b as CardCollectionItem } from './connection-B7CwszOV.js';
2
2
  import '@project/shared';
3
3
 
4
4
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rallycry/conveyor-mcp",
3
- "version": "5.0.0",
3
+ "version": "5.0.2",
4
4
  "description": "Conveyor MCP server for Claude Code PM integration",
5
5
  "keywords": [
6
6
  "claude",