@bli-cockpit/mcp 0.1.51 → 0.1.53
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 +3 -2
- package/dist/careers-tools.d.ts +4 -0
- package/dist/careers-tools.js +42 -8
- package/dist/verb-census.js +12 -1
- 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
|
+
**104 of 109 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
|
|
@@ -59,9 +59,10 @@ three tables below.
|
|
|
59
59
|
| `cockpit cal week` | `cal_week` | `GET /api/cal/week` |
|
|
60
60
|
| `cockpit careers decide` | `careers_decide` | `POST /api/careers/applications/[id]/decide` |
|
|
61
61
|
| `cockpit careers grade` | `careers_grade` | `POST /api/careers/applications/[id]/grade` |
|
|
62
|
-
| `cockpit careers
|
|
62
|
+
| `cockpit careers send-takehome` | `careers_send_takehome` | `POST /api/careers/applications/[id]/invite` |
|
|
63
63
|
| `cockpit careers list` | `careers_list` | `GET /api/careers/applications` |
|
|
64
64
|
| `cockpit careers rescreen` | `careers_rescreen` | `POST /api/careers/applications/[id]/rescreen` |
|
|
65
|
+
| `cockpit careers resume` | `careers_resume_url` | `GET /api/careers/applications/[id]/resume-url` |
|
|
65
66
|
| `cockpit careers settings set` | `careers_settings_set` | `PUT /api/careers/settings` |
|
|
66
67
|
| `cockpit careers settings show` | `careers_settings_show` | `GET /api/careers/settings` |
|
|
67
68
|
| `cockpit careers show` | `careers_show` | `GET /api/careers/applications/[id]` |
|
package/dist/careers-tools.d.ts
CHANGED
|
@@ -8,6 +8,10 @@ import { type ToolDeps } from './tool-result.js';
|
|
|
8
8
|
* something the browser refuses. `careers_takehome_show` returns the RUBRIC,
|
|
9
9
|
* which is reviewer material: it is readable by a super_admin's agent and is
|
|
10
10
|
* never part of what a candidate receives.
|
|
11
|
+
*
|
|
12
|
+
* BLI-4462 added `careers_resume_url`, the twin of the drawer's Open resume
|
|
13
|
+
* button and of `cockpit careers resume`. It hands back a link that lives 60
|
|
14
|
+
* seconds, which is the whole reason the description says so out loud.
|
|
11
15
|
*/
|
|
12
16
|
export declare function registerCareersTools(server: {
|
|
13
17
|
registerTool: (...args: never[]) => unknown;
|
package/dist/careers-tools.js
CHANGED
|
@@ -10,6 +10,10 @@ import { doorFailureText, errorResult, registrarFor, textResult, withSession } f
|
|
|
10
10
|
* something the browser refuses. `careers_takehome_show` returns the RUBRIC,
|
|
11
11
|
* which is reviewer material: it is readable by a super_admin's agent and is
|
|
12
12
|
* never part of what a candidate receives.
|
|
13
|
+
*
|
|
14
|
+
* BLI-4462 added `careers_resume_url`, the twin of the drawer's Open resume
|
|
15
|
+
* button and of `cockpit careers resume`. It hands back a link that lives 60
|
|
16
|
+
* seconds, which is the whole reason the description says so out loud.
|
|
13
17
|
*/
|
|
14
18
|
export function registerCareersTools(server, deps) {
|
|
15
19
|
const register = registrarFor(server);
|
|
@@ -26,14 +30,24 @@ export function registerCareersTools(server, deps) {
|
|
|
26
30
|
const answer = await callAgentDoor(session, deps.fetchImpl, action === 'show' ? 'GET' : 'POST', `/api/careers/applications/${encodeURIComponent(String(args.id))}${action === 'rescreen' ? '/rescreen' : ''}`, undefined, 60_000);
|
|
27
31
|
return answer.ok ? textResult('Application', answer.body) : errorResult(doorFailureText(`careers_${action}`, answer));
|
|
28
32
|
}));
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
// Two names, ONE door (BLI-4460 follow-up). Tower's button says "Send
|
|
34
|
+
// take-home" and this tool said `invite`, so an agent reading the screen and
|
|
35
|
+
// an agent reading the tool list were looking for different words for the
|
|
36
|
+
// same act. `careers_send_takehome` is the spelling the button uses and the
|
|
37
|
+
// one the census and the README teach; `careers_invite` stays registered
|
|
38
|
+
// because anything that already learned it keeps working.
|
|
39
|
+
for (const [tool, description] of [
|
|
40
|
+
['careers_send_takehome', 'Send the take-home invitation to one applicant (the button labelled Send take-home). Same door as careers_invite. Super-admin only. Sends that role\'s take-home from the configured mailbox, whatever the screening scored. Only a row still at the `screened` stage; a row already invited is refused.'],
|
|
41
|
+
['careers_invite', 'Super-admin only. Sends that role\'s take-home invitation from the configured mailbox, whatever the screening scored. Only a row still at the `screened` stage; a row already invited is refused. The same door as careers_send_takehome, which is the name the button uses.'],
|
|
42
|
+
])
|
|
43
|
+
register(tool, {
|
|
44
|
+
title: 'Send the take-home',
|
|
45
|
+
description,
|
|
46
|
+
inputSchema: { id: z.string().uuid() },
|
|
47
|
+
}, async (args) => withSession(deps, async (session) => {
|
|
48
|
+
const answer = await callAgentDoor(session, deps.fetchImpl, 'POST', `/api/careers/applications/${encodeURIComponent(String(args.id))}/invite`, undefined, 60_000);
|
|
49
|
+
return answer.ok ? textResult('Invitation sent', answer.body) : errorResult(doorFailureText(tool, answer));
|
|
50
|
+
}));
|
|
37
51
|
register('careers_grade', {
|
|
38
52
|
title: 'Re-queue a take-home for grading',
|
|
39
53
|
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.',
|
|
@@ -42,6 +56,26 @@ export function registerCareersTools(server, deps) {
|
|
|
42
56
|
const answer = await callAgentDoor(session, deps.fetchImpl, 'POST', `/api/careers/applications/${encodeURIComponent(String(args.id))}/grade`, { now: args.now === true }, 60_000);
|
|
43
57
|
return answer.ok ? textResult('Queued for grading', answer.body) : errorResult(doorFailureText('careers_grade', answer));
|
|
44
58
|
}));
|
|
59
|
+
// BLI-4462. The drawer has an "Open resume" button and this surface had no
|
|
60
|
+
// word for it, so an agent could read every screening line about a candidate
|
|
61
|
+
// and not reach the document they wrote about themselves. Same door, same
|
|
62
|
+
// super_admin gate, same 60 seconds: the link is a bearer credential for one
|
|
63
|
+
// private object and it dies quickly on purpose, so the description says so
|
|
64
|
+
// rather than letting a caller park it in a note for later.
|
|
65
|
+
register('careers_resume_url', {
|
|
66
|
+
title: 'Link to a resume',
|
|
67
|
+
description: 'Super-admin only. A signed link to one applicant\'s resume file, the same one the Open resume button uses. THE LINK DIES IN 60 SECONDS: fetch it and read it in the same turn, never store it. An application with no resume on file is refused rather than answered with an empty link.',
|
|
68
|
+
inputSchema: { id: z.string().uuid() },
|
|
69
|
+
}, async (args) => withSession(deps, async (session) => {
|
|
70
|
+
const answer = await callAgentDoor(session, deps.fetchImpl, 'GET', `/api/careers/applications/${encodeURIComponent(String(args.id))}/resume-url`);
|
|
71
|
+
if (!answer.ok)
|
|
72
|
+
return errorResult(doorFailureText('careers_resume_url', answer));
|
|
73
|
+
// The door says `expires_in`; every surface a person reads says
|
|
74
|
+
// `expires_in_seconds`, because 60 with no unit reads as minutes.
|
|
75
|
+
const body = (answer.body ?? {});
|
|
76
|
+
const expires = typeof body.expires_in === 'number' && body.expires_in > 0 ? body.expires_in : 60;
|
|
77
|
+
return textResult('Resume link', { url: body.url, expires_in_seconds: expires });
|
|
78
|
+
}));
|
|
45
79
|
register('careers_decide', {
|
|
46
80
|
title: 'Decide on an application',
|
|
47
81
|
description: 'Super-admin only. Records the call on one application: `passed_on`, `archived`, or `reopen` to put it back at `screened`.',
|
package/dist/verb-census.js
CHANGED
|
@@ -212,9 +212,17 @@ export const MCP_TWINS = {
|
|
|
212
212
|
"careers list": { tool: "careers_list", door: "GET /api/careers/applications" },
|
|
213
213
|
"careers show": { tool: "careers_show", door: "GET /api/careers/applications/[id]" },
|
|
214
214
|
"careers rescreen": { tool: "careers_rescreen", door: "POST /api/careers/applications/[id]/rescreen" },
|
|
215
|
-
|
|
215
|
+
// The parser's action is `invite`; what a person types is `careers
|
|
216
|
+
// send-takehome`, the words on Tower's own button, and the tool is named to
|
|
217
|
+
// match (TYPED_SPELLING below carries that spelling into this row of the
|
|
218
|
+
// README). `cockpit careers invite` and `careers_invite` are the older words
|
|
219
|
+
// for the identical door, and both still work.
|
|
220
|
+
"careers invite": { tool: "careers_send_takehome", door: "POST /api/careers/applications/[id]/invite" },
|
|
216
221
|
"careers decide": { tool: "careers_decide", door: "POST /api/careers/applications/[id]/decide" },
|
|
217
222
|
"careers grade": { tool: "careers_grade", door: "POST /api/careers/applications/[id]/grade" },
|
|
223
|
+
// BLI-4462: the drawer's Open resume button, typed. Both twins call the door
|
|
224
|
+
// that signs a 60-second link to the private resume object.
|
|
225
|
+
"careers resume": { tool: "careers_resume_url", door: "GET /api/careers/applications/[id]/resume-url" },
|
|
218
226
|
"careers takehome-show": { tool: "careers_takehome_show", door: "GET /api/careers/takehomes/[role]" },
|
|
219
227
|
"careers takehome-set": { tool: "careers_takehome_set", door: "PUT /api/careers/takehomes/[role]" },
|
|
220
228
|
"careers settings-show": { tool: "careers_settings_show", door: "GET /api/careers/settings" },
|
|
@@ -350,6 +358,9 @@ export const MCP_TWINS = {
|
|
|
350
358
|
* shorter this map is, the closer the census keys are to the product.
|
|
351
359
|
*/
|
|
352
360
|
export const TYPED_SPELLING = {
|
|
361
|
+
// The action is `invite`; the button, the help wall and the docs all say
|
|
362
|
+
// send-takehome, so that is what a stranger is told to type.
|
|
363
|
+
"careers invite": "careers send-takehome",
|
|
353
364
|
"careers takehome-show": "careers takehome show",
|
|
354
365
|
"careers takehome-set": "careers takehome set",
|
|
355
366
|
"careers settings-show": "careers settings show",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bli-cockpit/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.53",
|
|
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",
|