@bli-cockpit/mcp 0.1.67 → 0.1.69

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 CHANGED
@@ -103,7 +103,7 @@ about what an agent can reach.
103
103
 
104
104
  <!-- BEGIN GENERATED verb census — `npm run mcp:readme` -->
105
105
 
106
- **110 of 115 Tower verbs have an MCP twin.**
106
+ **111 of 116 Tower verbs have an MCP twin.**
107
107
  Each tool goes through the SAME door its CLI verb calls, with the same
108
108
  collector device token — never a second route and never a service-role
109
109
  reader. `src/verb-census.test.ts` fails when a verb is in none of the
@@ -119,6 +119,7 @@ three tables below.
119
119
  | `cockpit brief undone` | `brief_undone` | `POST /api/jarvis/ticks` |
120
120
  | `cockpit cal calendars` | `cal_calendars` | `GET /api/cal/calendars` |
121
121
  | `cockpit cal create` | `cal_create` | `POST /api/cal/events` |
122
+ | `cockpit cal delete` | `cal_delete` | `DELETE /api/cal/events/[eventId]` |
122
123
  | `cockpit cal detach` | `cal_detach` | `DELETE /api/cal/calendars` |
123
124
  | `cockpit cal find` | `cal_find` | `GET /api/cal/find` |
124
125
  | `cockpit cal next` | `cal_next` | `GET /api/cal/next` |
@@ -0,0 +1,9 @@
1
+ /**
2
+ * `cal_delete` (BLI-10564) — split out of `cal-tools.ts` when adding it there
3
+ * would have pushed that file over the 500-line readability band. Same door
4
+ * as `cockpit cal delete`, same confirm gate as `cal_create`/`cal_share`/
5
+ * `cal_detach`: a delete can email everybody on the event, so it is never
6
+ * something to do because a sentence sounded like it.
7
+ */
8
+ import { type RegisterTool, type ToolDeps } from "./tool-result.js";
9
+ export declare function registerCalDeleteTool(register: RegisterTool, deps: ToolDeps): void;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * `cal_delete` (BLI-10564) — split out of `cal-tools.ts` when adding it there
3
+ * would have pushed that file over the 500-line readability band. Same door
4
+ * as `cockpit cal delete`, same confirm gate as `cal_create`/`cal_share`/
5
+ * `cal_detach`: a delete can email everybody on the event, so it is never
6
+ * something to do because a sentence sounded like it.
7
+ */
8
+ import { z } from "zod";
9
+ import { callAgentDoor } from "./agent-door.js";
10
+ import { CONFIRM_INPUT, doorFailureText, errorResult, textResult, unconfirmed, withSession, } from "./tool-result.js";
11
+ export function registerCalDeleteTool(register, deps) {
12
+ register("cal_delete", {
13
+ title: "Delete an event",
14
+ description: "Removes ONE event, AT GOOGLE first and then here — the same order every calendar write in this server "
15
+ + "uses. Only a google_oauth calendar can be written to; an iCal calendar is read-only and says so by name. "
16
+ + "Attendees are notified (sendUpdates=all) only when the event has any. Google already having it gone "
17
+ + "(404/410) is answered as success, not a refusal. Requires confirm: true.",
18
+ inputSchema: {
19
+ event_id: z.string().uuid().describe("Tower's event id (cal_today/cal_week/cal_next/cal_find return it as event_id)."),
20
+ confirm: CONFIRM_INPUT,
21
+ },
22
+ }, async (args) => withSession(deps, async (session) => {
23
+ const refusal = unconfirmed(args, "This would remove that event at Google (emailing any attendees) and then here.");
24
+ if (refusal)
25
+ return refusal;
26
+ const response = await callAgentDoor(session, deps.fetchImpl, "DELETE", `/api/cal/events/${encodeURIComponent(String(args.event_id))}`);
27
+ if (!response.ok)
28
+ return errorResult(doorFailureText("cal_delete", response));
29
+ const deleted = response.body.deleted;
30
+ if (!deleted)
31
+ return textResult("Tower answered without a result. Nothing to report.", response.body);
32
+ const alreadyGone = deleted.google === "already_gone_at_google";
33
+ const stored = deleted.local_store === "removed"
34
+ ? "Tower's copy is removed."
35
+ : "Tower's copy is still there for now — the next sync will pick up that it is gone.";
36
+ return textResult(alreadyGone
37
+ ? `Google already had that event gone. ${stored}`
38
+ : `Deleted at Google${deleted.notified === "all" ? " — attendees were notified." : "."} ${stored}`, { deleted });
39
+ }));
40
+ }
@@ -18,7 +18,9 @@
18
18
  * Attaching a calendar stays a thing a person does at a terminal.
19
19
  * - **`cal_share` requires `confirm: true`.** Making a calendar readable by
20
20
  * everyone at BLI is not a read, and it is not something to do because a
21
- * sentence sounded like it.
21
+ * sentence sounded like it. `cal_create`, `cal_detach` and `cal_delete`
22
+ * (`cal-tools-delete.ts`, BLI-10564) require it too, for the same reason —
23
+ * a delete can email everybody on the event.
22
24
  *
23
25
  * EVERY READ SENDS A ZONE. `time_zone` is a required-in-practice argument on
24
26
  * the window tools, because a window computed without one is computed in UTC —
package/dist/cal-tools.js CHANGED
@@ -18,7 +18,9 @@
18
18
  * Attaching a calendar stays a thing a person does at a terminal.
19
19
  * - **`cal_share` requires `confirm: true`.** Making a calendar readable by
20
20
  * everyone at BLI is not a read, and it is not something to do because a
21
- * sentence sounded like it.
21
+ * sentence sounded like it. `cal_create`, `cal_detach` and `cal_delete`
22
+ * (`cal-tools-delete.ts`, BLI-10564) require it too, for the same reason —
23
+ * a delete can email everybody on the event.
22
24
  *
23
25
  * EVERY READ SENDS A ZONE. `time_zone` is a required-in-practice argument on
24
26
  * the window tools, because a window computed without one is computed in UTC —
@@ -31,6 +33,7 @@
31
33
  */
32
34
  import { z } from "zod";
33
35
  import { callAgentDoor } from "./agent-door.js";
36
+ import { registerCalDeleteTool } from "./cal-tools-delete.js";
34
37
  import { CONFIRM_INPUT, EMAIL_INPUT, doorFailureText, errorResult, queryString, registrarFor, textResult, unconfirmed, withSession, } from "./tool-result.js";
35
38
  /** This machine's zone: what a person means by "today" unless they say otherwise. */
36
39
  function localZone() {
@@ -204,6 +207,7 @@ export function registerCalTools(server, deps) {
204
207
  return errorResult(doorFailureText("cal_create", response));
205
208
  const event = response.body.event;
206
209
  return textResult(`Created "${event?.title ?? String(args.title)}" at ${event?.starts_at ?? String(args.starts_at)}.`
210
+ + towerIdLine(event)
207
211
  + (event?.html_link ? `\n${event.html_link}` : "")
208
212
  + (args.meet === true
209
213
  ? event?.meet_link
@@ -273,4 +277,14 @@ export function registerCalTools(server, deps) {
273
277
  return errorResult(doorFailureText("cal_detach", response));
274
278
  return textResult(`Detached ${String(args.calendar_id)}. Its stored events went with it; the calendar itself is untouched at Google.`, response.body);
275
279
  }));
280
+ registerCalDeleteTool(register, deps);
281
+ }
282
+ /** BLI-10560: the new event's Tower id, or why there is none yet. */
283
+ function towerIdLine(event) {
284
+ if (event?.event_id)
285
+ return `\nTower event: ${event.event_id}`;
286
+ if (event?.local_store === "failed" || event?.local_store === "unreadable") {
287
+ return "\nGoogle has the event; Tower has not stored it yet (the next calendar sync will), so there is no Tower id to open yet.";
288
+ }
289
+ return "";
276
290
  }
@@ -21,7 +21,7 @@ export declare const DRY_RUN_TOOLS: readonly ["ops_recompile", "memory_requeue"]
21
21
  * candidates, share calendars. Never called by the smoke; covered by the unit
22
22
  * suites (`write-tools.test.ts` and each family's own).
23
23
  */
24
- export declare const WRITE_TOOLS: readonly ["emit_event", "docs_create", "docs_update", "docs_delete", "docs_link", "msg_create_channel", "msg_dm", "msg_send", "work_create_issue", "work_update_issue", "work_move_issue", "work_comment_issue", "careers_rescreen", "careers_send_takehome", "careers_invite", "careers_grade", "careers_decide", "careers_takehome_set", "careers_settings_set", "mail_send", "mail_sync", "mail_detach", "cal_create", "cal_share", "cal_sync", "cal_detach", "jarvis_dispatch", "notes_mkdir", "notes_rmdir", "notes_rename", "notes_upload", "notes_paste", "notes_share", "notes_unshare", "notes_move", "notes_sync", "notes_detach", "memory_experience", "scout_start", "scout_dismiss", "scout_undo", "brief_rewrite", "brief_correct", "brief_done", "brief_undone", "settings_set", "settings_delete", "model_set", "team_invite", "team_role", "team_device_revoke"];
24
+ export declare const WRITE_TOOLS: readonly ["emit_event", "docs_create", "docs_update", "docs_delete", "docs_link", "msg_create_channel", "msg_dm", "msg_send", "work_create_issue", "work_update_issue", "work_move_issue", "work_comment_issue", "careers_rescreen", "careers_send_takehome", "careers_invite", "careers_grade", "careers_decide", "careers_takehome_set", "careers_settings_set", "mail_send", "mail_sync", "mail_detach", "cal_create", "cal_share", "cal_sync", "cal_detach", "cal_delete", "jarvis_dispatch", "notes_mkdir", "notes_rmdir", "notes_rename", "notes_upload", "notes_paste", "notes_share", "notes_unshare", "notes_move", "notes_sync", "notes_detach", "memory_experience", "scout_start", "scout_dismiss", "scout_undo", "brief_rewrite", "brief_correct", "brief_done", "brief_undone", "settings_set", "settings_delete", "model_set", "team_invite", "team_role", "team_device_revoke"];
25
25
  /** Reads that spend a model turn. The smoke's `--no-model` leaves these out. */
26
26
  export declare const MODEL_SPENDING_TOOLS: readonly ["jarvis_ask", "jarvis_check"];
27
27
  /**
@@ -108,6 +108,7 @@ export const WRITE_TOOLS = [
108
108
  "cal_share",
109
109
  "cal_sync",
110
110
  "cal_detach",
111
+ "cal_delete",
111
112
  "jarvis_dispatch",
112
113
  "notes_mkdir",
113
114
  "notes_rmdir",
@@ -268,6 +268,7 @@ export const MCP_TWINS = {
268
268
  "cal share": { tool: "cal_share", door: "PATCH /api/cal/calendars" },
269
269
  "cal sync": { tool: "cal_sync", door: "POST /api/cal/calendars/[id]/sync" },
270
270
  "cal detach": { tool: "cal_detach", door: "DELETE /api/cal/calendars" },
271
+ "cal delete": { tool: "cal_delete", door: "DELETE /api/cal/events/[eventId]" },
271
272
  "brief read": { tool: "brief_read", door: "GET /api/jarvis/brief" },
272
273
  "brief history": { tool: "brief_history", door: "GET /api/jarvis/brief?history=1" },
273
274
  "brief status": { tool: "brief_status", door: "GET /api/ops/brief-status" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bli-cockpit/mcp",
3
- "version": "0.1.67",
3
+ "version": "0.1.69",
4
4
  "private": false,
5
5
  "description": "bli-tower: an MCP server over BLI Cockpit's agent doors: JARVIS (jarvis_*), documents (docs_*), channels (msg_*), issues (work_*), the daily page (brief_*), meeting notes (notes_*), the ops board (ops_status/slack_*), settings/team/model, Scout and the workbook, plus the legacy event-stream tools (emit_event, get_ticket_timeline, get_active_tickets).",
6
6
  "type": "module",