@bli-cockpit/mcp 0.1.19 → 0.1.20
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 +2 -1
- package/dist/memory-experience-tools.d.ts +6 -0
- package/dist/memory-experience-tools.js +24 -0
- package/dist/ops-tools.js +5 -2
- package/dist/server.js +2 -0
- package/dist/verb-census.js +3 -2
- package/package.json +2 -2
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
|
+
**74 of 77 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
|
|
@@ -78,6 +78,7 @@ three tables below.
|
|
|
78
78
|
| `cockpit mail search` | `mail_search` | `GET /api/mail/search` |
|
|
79
79
|
| `cockpit mail send` | `mail_send` | `POST /api/mail/send` |
|
|
80
80
|
| `cockpit mail sync` | `mail_sync` | `POST /api/mail/accounts/[id]/sync` |
|
|
81
|
+
| `cockpit memory log` | `memory_experience` | `POST /api/memory/experience` |
|
|
81
82
|
| `cockpit model set` | `model_set` | `POST /api/settings/jarvis-model` |
|
|
82
83
|
| `cockpit model show` | `model_show` | `GET /api/settings/jarvis-model` |
|
|
83
84
|
| `cockpit msg channels` | `msg_channels` | `GET /api/msg/channels` |
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { appendExperience, shipExperience } from "@bli-cockpit/telemetry-core/memory-experience";
|
|
3
|
+
import { callAgentDoor } from "./agent-door.js";
|
|
4
|
+
import { loadAgentDoorSession } from "./agent-door-session.js";
|
|
5
|
+
import { registrarFor, textResult } from "./tool-result.js";
|
|
6
|
+
export function registerMemoryExperienceTools(server, deps) {
|
|
7
|
+
registrarFor(server)("memory_experience", {
|
|
8
|
+
title: "Log a memory-store experience",
|
|
9
|
+
description: "Append an experience receipt locally and post to Tower. Offline receipts ship on the next collector sync. Copy the recall marker: [bli] = BLI Memory, ◪ = Supermemory. Opinions only; never prompts, memory bodies or secrets.",
|
|
10
|
+
inputSchema: { store: z.enum(["bli", "supermemory", "both"]), verdict: z.enum(["win", "loss", "noise"]), reason: z.string().min(1).max(500) },
|
|
11
|
+
}, async (args) => {
|
|
12
|
+
const entry = await appendExperience({ store: args.store, verdict: args.verdict, reason: String(args.reason) }, { homeDir: deps.homeDir, agent: "MCP", project: "workspace" });
|
|
13
|
+
const delivery = await shipExperience(entry, async (body) => {
|
|
14
|
+
const session = (deps.loadSession ?? loadAgentDoorSession)();
|
|
15
|
+
if (!session.ok)
|
|
16
|
+
return { ok: false, reason: session.reason };
|
|
17
|
+
const result = await callAgentDoor(session.session, deps.fetchImpl, "POST", "/api/memory/experience", body, 5000);
|
|
18
|
+
return { ok: result.ok && result.body.ok === true, reason: result.transportError ?? String(result.body.error ?? "experience_refused") };
|
|
19
|
+
}, deps.homeDir);
|
|
20
|
+
const receipt = { ok: true, id: entry.id, local: true, ...delivery };
|
|
21
|
+
console.error("[memory experience] recorded", JSON.stringify(receipt));
|
|
22
|
+
return textResult(`Experience appended; shipped: ${delivery.shipped} (${delivery.reason}).`, receipt);
|
|
23
|
+
});
|
|
24
|
+
}
|
package/dist/ops-tools.js
CHANGED
|
@@ -77,6 +77,8 @@ export function registerOpsTools(server, deps) {
|
|
|
77
77
|
? await callAgentDoor(session, deps.fetchImpl, "GET", "/api/ops/memory-usage") : null;
|
|
78
78
|
if (memory && !memory.ok)
|
|
79
79
|
return errorResult(doorFailureText("ops_status memory", memory));
|
|
80
|
+
const experience = memory?.ok ? asRecord(memory.body.experience) : null;
|
|
81
|
+
const experienceLines = experience ? ["EXPERIENCE", experience.summary, ...(Array.isArray(experience.lines) ? experience.lines : [])].join("\n") : "";
|
|
80
82
|
const hooks = memory?.ok ? asRecord(memory.body.hooks) : null;
|
|
81
83
|
const memoryLines = hooks && Array.isArray(hooks.devices)
|
|
82
84
|
? hooks.devices.map((device) => {
|
|
@@ -88,7 +90,8 @@ export function registerOpsTools(server, deps) {
|
|
|
88
90
|
return textResult(`${rows.length} pipeline(s), ${unhealthy.length} unhealthy`
|
|
89
91
|
+ `${unhealthy.length > 0 ? `: ${unhealthy.map((row) => row.id ?? "?").join(", ")}` : "."}`
|
|
90
92
|
+ `${lines ? `\n${lines}` : ""}`
|
|
91
|
-
+ `${memoryLines ? `\n${memoryLines}` : ""}
|
|
93
|
+
+ `${memoryLines ? `\n${memoryLines}` : ""}`
|
|
94
|
+
+ `${experienceLines ? `\n${experienceLines}` : ""}`,
|
|
92
95
|
// The API owns the wording and the timing boundary on every surface.
|
|
93
96
|
{
|
|
94
97
|
pipelines: rows,
|
|
@@ -96,7 +99,7 @@ export function registerOpsTools(server, deps) {
|
|
|
96
99
|
...(body.fleet ? { fleet: body.fleet } : {}),
|
|
97
100
|
...(body.coverage ? { coverage: body.coverage } : {}),
|
|
98
101
|
...(body.skips ? { skips: body.skips } : {}),
|
|
99
|
-
...(memory?.ok ? { memory: memory.body.memory, hooks: memory.body.hooks } : {}),
|
|
102
|
+
...(memory?.ok ? { memory: memory.body.memory, hooks: memory.body.hooks, experience: memory.body.experience } : {}),
|
|
100
103
|
});
|
|
101
104
|
}));
|
|
102
105
|
register("slack_coverage", {
|
package/dist/server.js
CHANGED
|
@@ -14,6 +14,7 @@ import { registerCalTools } from "./cal-tools.js";
|
|
|
14
14
|
import { registerMailTools } from "./mail-tools.js";
|
|
15
15
|
import { registerNotesTools } from "./notes-tools.js";
|
|
16
16
|
import { registerNotesWriteTools } from "./notes-write-tools.js";
|
|
17
|
+
import { registerMemoryExperienceTools } from "./memory-experience-tools.js";
|
|
17
18
|
import { registerOpsTools } from "./ops-tools.js";
|
|
18
19
|
import { registerPagesTools } from "./pages-tools.js";
|
|
19
20
|
import { registerSearchTool } from "./search-tool.js";
|
|
@@ -411,6 +412,7 @@ export function createServer(deps) {
|
|
|
411
412
|
registerBriefTools(server, { fetchImpl: deps.fetchImpl });
|
|
412
413
|
registerNotesTools(server, { fetchImpl: deps.fetchImpl });
|
|
413
414
|
registerOpsTools(server, { fetchImpl: deps.fetchImpl });
|
|
415
|
+
registerMemoryExperienceTools(server, { fetchImpl: deps.fetchImpl });
|
|
414
416
|
registerSettingsTools(server, { fetchImpl: deps.fetchImpl });
|
|
415
417
|
registerPagesTools(server, { fetchImpl: deps.fetchImpl });
|
|
416
418
|
// BLI-3756 batch 2: the WRITES. Same doors, same device token, same refusal
|
package/dist/verb-census.js
CHANGED
|
@@ -115,7 +115,7 @@ function resolveShapeAlias(variant, unionSource) {
|
|
|
115
115
|
// union member, because the split is on `\n | `. Only the first line is the
|
|
116
116
|
// member itself.
|
|
117
117
|
const firstLine = variant.split("\n").find((line) => line.trim().length > 0) ?? "";
|
|
118
|
-
const name = /^\s*([A-Z][A-Za-z0-9_]*)\s*$/.exec(firstLine)?.[1];
|
|
118
|
+
const name = /^\s*([A-Z][A-Za-z0-9_]*)\s*;?\s*$/.exec(firstLine)?.[1];
|
|
119
119
|
if (!name)
|
|
120
120
|
return variant;
|
|
121
121
|
const from = new RegExp(`import type \\{[^}]*\\b${name}\\b[^}]*\\} from "\\.\\/([\\w.-]+)\\.js"`).exec(unionSource)?.[1];
|
|
@@ -138,7 +138,7 @@ function resolveShapeAlias(variant, unionSource) {
|
|
|
138
138
|
export function towerVerbs() {
|
|
139
139
|
const nouns = new Set(towerNouns());
|
|
140
140
|
const aliases = actionAliases();
|
|
141
|
-
const verbs = [];
|
|
141
|
+
const verbs = [{ noun: "memory", action: "log", spelling: "memory log" }];
|
|
142
142
|
const seenNouns = new Set();
|
|
143
143
|
for (const variant of commandVariants()) {
|
|
144
144
|
const kind = /kind:\s*"([a-z-]+)"/.exec(variant)?.[1];
|
|
@@ -221,6 +221,7 @@ export const MCP_TWINS = {
|
|
|
221
221
|
"notes share": { tool: "notes_share", door: "POST /api/notes/share" },
|
|
222
222
|
"notes unshare": { tool: "notes_unshare", door: "POST /api/notes/share (share=false)" },
|
|
223
223
|
"notes move": { tool: "notes_move", door: "POST /api/notes/move" },
|
|
224
|
+
"memory log": { tool: "memory_experience", door: "POST /api/memory/experience" },
|
|
224
225
|
"ops status": { tool: "ops_status", door: "GET /api/ops/status" },
|
|
225
226
|
"ops recompile": { tool: "ops_recompile", door: "POST /api/ops/recompile" },
|
|
226
227
|
"slack coverage": { tool: "slack_coverage", door: "GET /api/ops/slack/coverage" },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bli-cockpit/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.20",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "bli-tower \u2014 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",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"readme": "npm run build && node scripts/write-readme-census.mjs"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@bli-cockpit/telemetry-core": "0.1.
|
|
33
|
+
"@bli-cockpit/telemetry-core": "0.1.36",
|
|
34
34
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
35
35
|
"zod": "^4.3.6"
|
|
36
36
|
},
|