@bli-cockpit/mcp 0.1.49 → 0.1.51
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 +4 -1
- package/dist/brief-write-tools.js +70 -0
- package/dist/careers-tools.js +10 -0
- package/dist/verb-census.js +5 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ about what an agent can reach.
|
|
|
34
34
|
|
|
35
35
|
<!-- BEGIN GENERATED verb census — `npm run mcp:readme` -->
|
|
36
36
|
|
|
37
|
-
**
|
|
37
|
+
**103 of 108 Tower verbs have an MCP twin.**
|
|
38
38
|
Each tool goes through the SAME door its CLI verb calls, with the same
|
|
39
39
|
collector device token — never a second route and never a service-role
|
|
40
40
|
reader. `src/verb-census.test.ts` fails when a verb is in none of the
|
|
@@ -42,10 +42,12 @@ three tables below.
|
|
|
42
42
|
|
|
43
43
|
| CLI verb | MCP tool | Door |
|
|
44
44
|
| --- | --- | --- |
|
|
45
|
+
| `cockpit brief done` | `brief_done` | `POST /api/jarvis/ticks` |
|
|
45
46
|
| `cockpit brief history` | `brief_history` | `GET /api/jarvis/brief?history=1` |
|
|
46
47
|
| `cockpit brief read` | `brief_read` | `GET /api/jarvis/brief` |
|
|
47
48
|
| `cockpit brief rewrite` | `brief_rewrite` | `POST /api/jarvis/recompile` |
|
|
48
49
|
| `cockpit brief status` | `brief_status` | `GET /api/ops/brief-status` |
|
|
50
|
+
| `cockpit brief undone` | `brief_undone` | `POST /api/jarvis/ticks` |
|
|
49
51
|
| `cockpit cal calendars` | `cal_calendars` | `GET /api/cal/calendars` |
|
|
50
52
|
| `cockpit cal create` | `cal_create` | `POST /api/cal/events` |
|
|
51
53
|
| `cockpit cal detach` | `cal_detach` | `DELETE /api/cal/calendars` |
|
|
@@ -56,6 +58,7 @@ three tables below.
|
|
|
56
58
|
| `cockpit cal today` | `cal_today` | `GET /api/cal/today` |
|
|
57
59
|
| `cockpit cal week` | `cal_week` | `GET /api/cal/week` |
|
|
58
60
|
| `cockpit careers decide` | `careers_decide` | `POST /api/careers/applications/[id]/decide` |
|
|
61
|
+
| `cockpit careers grade` | `careers_grade` | `POST /api/careers/applications/[id]/grade` |
|
|
59
62
|
| `cockpit careers invite` | `careers_invite` | `POST /api/careers/applications/[id]/invite` |
|
|
60
63
|
| `cockpit careers list` | `careers_list` | `GET /api/careers/applications` |
|
|
61
64
|
| `cockpit careers rescreen` | `careers_rescreen` | `POST /api/careers/applications/[id]/rescreen` |
|
|
@@ -175,4 +175,74 @@ export function registerBriefWriteTools(server, deps) {
|
|
|
175
175
|
link: filed.link ?? null,
|
|
176
176
|
});
|
|
177
177
|
}));
|
|
178
|
+
// BLI-3605: the board's done checkbox. Two tools rather than one with a
|
|
179
|
+
// boolean, for the same reason the CLI has two verbs: "mark it done" and
|
|
180
|
+
// "put it back" are different intentions, and a model picking a flag wrong
|
|
181
|
+
// silently un-finishes somebody's work.
|
|
182
|
+
registerTick(register, deps, "brief_done", true);
|
|
183
|
+
registerTick(register, deps, "brief_undone", false);
|
|
184
|
+
}
|
|
185
|
+
/** The item a tick is about, in the two spellings a board row can have. */
|
|
186
|
+
const TICK_ITEM = z
|
|
187
|
+
.string()
|
|
188
|
+
.min(1)
|
|
189
|
+
.max(200)
|
|
190
|
+
.describe("The board row: a ticket exactly as the board writes it (BLI-3511), or a claim id from brief_read({claims: true}) for a row with no ticket.");
|
|
191
|
+
const TICKET_IDENTIFIER = /^[A-Z][A-Z0-9]{1,9}-\d+$/;
|
|
192
|
+
/**
|
|
193
|
+
* One tick tool. `brief_done` and `brief_undone` differ by one boolean and
|
|
194
|
+
* nothing else, so they are built once here rather than written twice.
|
|
195
|
+
*
|
|
196
|
+
* The page is read first and the item looked for in it, exactly as
|
|
197
|
+
* `brief_correct` refuses an unknown claim id before writing: a key naming
|
|
198
|
+
* nothing would sit in the table forever, ticked against a row nobody can
|
|
199
|
+
* find. There is no `subject` argument on purpose, a tick is the caller's own
|
|
200
|
+
* working state, and the door has no way to accept one for anybody else.
|
|
201
|
+
*/
|
|
202
|
+
function registerTick(register, deps, name, done) {
|
|
203
|
+
register(name, {
|
|
204
|
+
title: done
|
|
205
|
+
? "Tick one Tower DO THIS FIRST item off as done"
|
|
206
|
+
: "Put one Tower DO THIS FIRST item back on the board",
|
|
207
|
+
description: done
|
|
208
|
+
? "Marks ONE row of the daily page's DO THIS FIRST board done, the website's checkbox and `cockpit brief done`, "
|
|
209
|
+
+ "same door. A row with a ticket stays ticked across every recompile. Your own board only; a tick is private "
|
|
210
|
+
+ "working state and cannot be made on anybody else's behalf."
|
|
211
|
+
: "Takes back a tick on ONE row of the DO THIS FIRST board, `cockpit brief undone`, same door. The row goes "
|
|
212
|
+
+ "back to open. Your own board only.",
|
|
213
|
+
inputSchema: { item: TICK_ITEM },
|
|
214
|
+
}, async (args) => withSession(deps, async (session) => {
|
|
215
|
+
const item = String(args.item ?? "").trim();
|
|
216
|
+
const page = await readPage(deps, session, new URLSearchParams({ claims: "1" }));
|
|
217
|
+
if (!page.ok)
|
|
218
|
+
return errorResult(page.text);
|
|
219
|
+
const claims = page.body.claims ?? [];
|
|
220
|
+
const isTicket = TICKET_IDENTIFIER.test(item);
|
|
221
|
+
const line = isTicket
|
|
222
|
+
? claims.find((candidate) => (candidate.text ?? "").includes(item))
|
|
223
|
+
: claims.find((candidate) => candidate.claimId === item);
|
|
224
|
+
if (!line) {
|
|
225
|
+
return errorResult(`Refused (unknown_item): nothing on your page is called “${item}”. `
|
|
226
|
+
+ "Call brief_read with `claims: true` to see the ids, or name the ticket exactly as the board writes "
|
|
227
|
+
+ "it. Nothing was recorded.");
|
|
228
|
+
}
|
|
229
|
+
const response = await callAgentDoor(session, deps.fetchImpl, "POST", "/api/jarvis/ticks", {
|
|
230
|
+
item_key: item,
|
|
231
|
+
ticket_identifier: isTicket ? item : null,
|
|
232
|
+
claim_id: line.claimId ?? null,
|
|
233
|
+
page_id: page.body.page?.pageId ?? null,
|
|
234
|
+
done,
|
|
235
|
+
}, QUEUE_DEADLINE_MS);
|
|
236
|
+
if (!response.ok)
|
|
237
|
+
return errorResult(doorFailureText(name, response));
|
|
238
|
+
const body = response.body;
|
|
239
|
+
if (!body.ok)
|
|
240
|
+
return errorResult(body.reply ?? body.error ?? "Tower did not record that.");
|
|
241
|
+
return textResult(done ? `[x] ${item} is done.` : `[ ] ${item} is back on the board.`, {
|
|
242
|
+
ok: true,
|
|
243
|
+
itemKey: body.item_key ?? item,
|
|
244
|
+
done,
|
|
245
|
+
tickedAt: body.ticked_at ?? null,
|
|
246
|
+
});
|
|
247
|
+
}));
|
|
178
248
|
}
|
package/dist/careers-tools.js
CHANGED
|
@@ -34,6 +34,14 @@ export function registerCareersTools(server, deps) {
|
|
|
34
34
|
const answer = await callAgentDoor(session, deps.fetchImpl, 'POST', `/api/careers/applications/${encodeURIComponent(String(args.id))}/invite`, undefined, 60_000);
|
|
35
35
|
return answer.ok ? textResult('Invitation sent', answer.body) : errorResult(doorFailureText('careers_invite', answer));
|
|
36
36
|
}));
|
|
37
|
+
register('careers_grade', {
|
|
38
|
+
title: 'Re-queue a take-home for grading',
|
|
39
|
+
description: 'Super-admin only. Puts one submitted or graded application back in the take-home grader\'s queue. The grader runs on Railway every 15 minutes because it clones a repository and reads a video; `now` is answered honestly rather than run here.',
|
|
40
|
+
inputSchema: { id: z.string().uuid(), now: z.boolean().optional() },
|
|
41
|
+
}, async (args) => withSession(deps, async (session) => {
|
|
42
|
+
const answer = await callAgentDoor(session, deps.fetchImpl, 'POST', `/api/careers/applications/${encodeURIComponent(String(args.id))}/grade`, { now: args.now === true }, 60_000);
|
|
43
|
+
return answer.ok ? textResult('Queued for grading', answer.body) : errorResult(doorFailureText('careers_grade', answer));
|
|
44
|
+
}));
|
|
37
45
|
register('careers_decide', {
|
|
38
46
|
title: 'Decide on an application',
|
|
39
47
|
description: 'Super-admin only. Records the call on one application: `passed_on`, `archived`, or `reopen` to put it back at `screened`.',
|
|
@@ -82,6 +90,8 @@ export function registerCareersTools(server, deps) {
|
|
|
82
90
|
auto_invite_min_score: z.number().min(0).max(100).optional(),
|
|
83
91
|
attention_min_score: z.number().min(0).max(100).optional(),
|
|
84
92
|
invite_account_id: z.string().uuid().nullable().optional(),
|
|
93
|
+
booking_link: z.string().url().max(2000).nullable().optional(),
|
|
94
|
+
grader_model: z.string().min(3).max(200).optional(),
|
|
85
95
|
},
|
|
86
96
|
}, async (args) => withSession(deps, async (session) => {
|
|
87
97
|
const answer = await callAgentDoor(session, deps.fetchImpl, 'PUT', '/api/careers/settings', args);
|
package/dist/verb-census.js
CHANGED
|
@@ -214,6 +214,7 @@ export const MCP_TWINS = {
|
|
|
214
214
|
"careers rescreen": { tool: "careers_rescreen", door: "POST /api/careers/applications/[id]/rescreen" },
|
|
215
215
|
"careers invite": { tool: "careers_invite", door: "POST /api/careers/applications/[id]/invite" },
|
|
216
216
|
"careers decide": { tool: "careers_decide", door: "POST /api/careers/applications/[id]/decide" },
|
|
217
|
+
"careers grade": { tool: "careers_grade", door: "POST /api/careers/applications/[id]/grade" },
|
|
217
218
|
"careers takehome-show": { tool: "careers_takehome_show", door: "GET /api/careers/takehomes/[role]" },
|
|
218
219
|
"careers takehome-set": { tool: "careers_takehome_set", door: "PUT /api/careers/takehomes/[role]" },
|
|
219
220
|
"careers settings-show": { tool: "careers_settings_show", door: "GET /api/careers/settings" },
|
|
@@ -260,6 +261,10 @@ export const MCP_TWINS = {
|
|
|
260
261
|
"brief history": { tool: "brief_history", door: "GET /api/jarvis/brief?history=1" },
|
|
261
262
|
"brief status": { tool: "brief_status", door: "GET /api/ops/brief-status" },
|
|
262
263
|
"brief rewrite": { tool: "brief_rewrite", door: "POST /api/jarvis/recompile" },
|
|
264
|
+
// BLI-3605: the DO THIS FIRST done checkbox. One door, two verbs, because
|
|
265
|
+
// "mark it done" and "put it back" are different intentions.
|
|
266
|
+
"brief done": { tool: "brief_done", door: "POST /api/jarvis/ticks" },
|
|
267
|
+
"brief undone": { tool: "brief_undone", door: "POST /api/jarvis/ticks" },
|
|
263
268
|
correct: { tool: "brief_correct", door: "POST /api/jarvis/corrections" },
|
|
264
269
|
"notes folders": { tool: "notes_folders", door: "GET /api/notes/folders" },
|
|
265
270
|
"notes mkdir": { tool: "notes_mkdir", door: "POST /api/notes/folders" },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bli-cockpit/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.51",
|
|
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",
|