@bli-cockpit/mcp 0.1.7 → 0.1.9
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/dist/jarvis-answer-envelope.d.ts +93 -5
- package/dist/jarvis-answer-envelope.js +124 -3
- package/dist/jarvis-door.js +11 -0
- package/dist/jarvis-tools.js +10 -4
- package/package.json +1 -1
|
@@ -29,12 +29,55 @@
|
|
|
29
29
|
* `latency` / `model` keys `cockpit jarvis --json` also prints: those describe
|
|
30
30
|
* a terminal process's own stopwatch, and this server has no such stopwatch to
|
|
31
31
|
* report honestly.
|
|
32
|
+
*
|
|
33
|
+
* ## Where `sources` comes from (BLI-3770)
|
|
34
|
+
*
|
|
35
|
+
* From the DOOR, as objects, when the door sends them: `POST /api/jarvis/cli`
|
|
36
|
+
* carries `sources` built from the citations the grounding layer minted, and
|
|
37
|
+
* the `Source:` lines inside `answer` are rendered from that same array. The
|
|
38
|
+
* older derivation — a line-anchored regex over the finished prose — could
|
|
39
|
+
* only find a citation the renderer happened to put on its own line, so QA
|
|
40
|
+
* tick 16's c9, c9b and n9 (all off `searchEverything`) ended *"…Source:
|
|
41
|
+
* issue, at /work/BLI-3706, by …"* INSIDE the final sentence and returned
|
|
42
|
+
* `"sources": []`: the person saw a citation, the machine did not.
|
|
43
|
+
*
|
|
44
|
+
* The prose derivation survives as the FALLBACK, for a dashboard deployed
|
|
45
|
+
* before that door field existed, and it is wider than it was: a whole
|
|
46
|
+
* `Sources:` line (plural, any case, bulleted) counts — that is what the
|
|
47
|
+
* server itself treats as provenance — and so does a citation that begins a
|
|
48
|
+
* sentence inside a paragraph. A `Source:` in the MIDDLE of a sentence ("the
|
|
49
|
+
* Source: field on that row was blank") is prose about a source, not a
|
|
50
|
+
* source, and is deliberately not matched.
|
|
32
51
|
*/
|
|
33
52
|
/**
|
|
34
53
|
* Every key of the envelope, in the order it is written. The literal list IS
|
|
35
54
|
* the contract: both copies assert against it, so a drift is a red suite.
|
|
36
55
|
*/
|
|
37
|
-
export declare const JARVIS_ANSWER_ENVELOPE_KEYS: readonly ["ok", "answer", "sources", "turn_id", "thread_id", "trace_thread_id", "proposal_id", "degraded", "degraded_reasons"];
|
|
56
|
+
export declare const JARVIS_ANSWER_ENVELOPE_KEYS: readonly ["ok", "answer", "sources", "turn_id", "thread_id", "trace_thread_id", "proposal_id", "next_action", "degraded", "degraded_reasons"];
|
|
57
|
+
/**
|
|
58
|
+
* One thing that backed the answer (BLI-3770).
|
|
59
|
+
*
|
|
60
|
+
* Minted by the grounding layer with its `kind` already decided, so a caller
|
|
61
|
+
* can tell an issue from a document from a live tool read without parsing the
|
|
62
|
+
* words back apart. `kind: "prose"` means this envelope recovered the line
|
|
63
|
+
* from the answer itself because the door sent no structured sources — an
|
|
64
|
+
* older dashboard, or a citation the model wrote that nothing minted.
|
|
65
|
+
*
|
|
66
|
+
* The same shape is declared by `apps/dashboard/src/lib/jarvis/chat-v2/
|
|
67
|
+
* answer-sources.ts`, which is where the array is built.
|
|
68
|
+
*/
|
|
69
|
+
export interface JarvisAnswerSource {
|
|
70
|
+
/** `issue`, `doc`, `channel`, `memory`, `session`, `note`, `linear`, `web`, `live_read`, `conversation`, `brief`, `correction`, or `prose`. */
|
|
71
|
+
kind: string;
|
|
72
|
+
/** The words the citation carries, without its link. */
|
|
73
|
+
label: string;
|
|
74
|
+
/** The durable link, when the receipt has one. */
|
|
75
|
+
href: string | null;
|
|
76
|
+
/** The thing cited, when it has an identifier a caller could fetch again. */
|
|
77
|
+
id: string | null;
|
|
78
|
+
/** The belt tool the evidence came off, when one did. */
|
|
79
|
+
tool: string | null;
|
|
80
|
+
}
|
|
38
81
|
/**
|
|
39
82
|
* The closed set of ways an answer can be second-rate without being a failure.
|
|
40
83
|
* A degraded answer is still an answer — it is printed, returned and counted —
|
|
@@ -54,12 +97,18 @@ export interface JarvisAnswerEnvelope {
|
|
|
54
97
|
ok: true;
|
|
55
98
|
/**
|
|
56
99
|
* The answer verbatim, exactly as the terminal prints it — `Source:` lines
|
|
57
|
-
* included. Nothing is stripped
|
|
58
|
-
*
|
|
100
|
+
* included. Nothing is stripped, and nothing is derived from it either:
|
|
101
|
+
* since BLI-3770 `sources` below is the array those lines were RENDERED
|
|
102
|
+
* FROM, not a reading taken back out of this string.
|
|
59
103
|
*/
|
|
60
104
|
answer: string;
|
|
61
|
-
/**
|
|
62
|
-
|
|
105
|
+
/**
|
|
106
|
+
* What backed the answer, in the order the grounding layer minted it.
|
|
107
|
+
*
|
|
108
|
+
* BLI-3770: these are objects, not lines. Empty means this turn cited
|
|
109
|
+
* nothing — never "the citation was on a line this side could not parse".
|
|
110
|
+
*/
|
|
111
|
+
sources: JarvisAnswerSource[];
|
|
63
112
|
/**
|
|
64
113
|
* This turn's trace id — what `cockpit jarvis --trace <id>` and the
|
|
65
114
|
* `jarvis_trace` MCP tool open. `null` against a dashboard that predates
|
|
@@ -85,8 +134,25 @@ export interface JarvisAnswerEnvelope {
|
|
|
85
134
|
* could approve with, and that is not approval. The person fetches the code
|
|
86
135
|
* on a surface a person reads and hands it back. Null on every turn that
|
|
87
136
|
* proposed no coding task, which is nearly all of them.
|
|
137
|
+
*
|
|
138
|
+
* BLI-3787: a null here is never on its own. When the arm ran at all,
|
|
139
|
+
* `next_action` below says what happened and what a person has to do — the
|
|
140
|
+
* field was `null` on every proposing turn for two QA ticks while the answer
|
|
141
|
+
* told the caller to spend an id nothing had issued.
|
|
88
142
|
*/
|
|
89
143
|
proposal_id: string | null;
|
|
144
|
+
/**
|
|
145
|
+
* BLI-3787: what has to happen next, in a sentence naming an action a
|
|
146
|
+
* PERSON takes.
|
|
147
|
+
*
|
|
148
|
+
* Today only the coding arm produces one, and it is what makes
|
|
149
|
+
* `proposal_id`'s absence readable: "ask them to fetch the code for proposal
|
|
150
|
+
* X", "nothing was dispatched and no proposal was recorded, a person has to
|
|
151
|
+
* approve this where a person reads", "that approval code has already been
|
|
152
|
+
* used". Null on every turn that never reached the arm, which is nearly all
|
|
153
|
+
* of them — and never a substitute for the answer itself.
|
|
154
|
+
*/
|
|
155
|
+
next_action: string | null;
|
|
90
156
|
degraded: boolean;
|
|
91
157
|
degraded_reasons: JarvisDegradedReason[];
|
|
92
158
|
}
|
|
@@ -96,6 +162,15 @@ export interface JarvisAnswerEnvelope {
|
|
|
96
162
|
* lines the server wrote, so a new citation kind needs no change here.
|
|
97
163
|
*/
|
|
98
164
|
export declare function extractSourceLines(answer: string): string[];
|
|
165
|
+
/**
|
|
166
|
+
* The fallback derivation: what this side can tell from the answer alone.
|
|
167
|
+
*
|
|
168
|
+
* Only reached when the door sent no structured `sources` — a dashboard
|
|
169
|
+
* deployed before BLI-3770, or a turn whose citation nothing minted. Every
|
|
170
|
+
* row it produces is labelled `kind: "prose"` so a consumer can tell a
|
|
171
|
+
* recovered line from a minted receipt.
|
|
172
|
+
*/
|
|
173
|
+
export declare function sourcesFromAnswer(answer: string): JarvisAnswerSource[];
|
|
99
174
|
export interface JarvisAnswerEnvelopeInput {
|
|
100
175
|
/** The reply text the door returned. */
|
|
101
176
|
reply: string;
|
|
@@ -115,5 +190,18 @@ export interface JarvisAnswerEnvelopeInput {
|
|
|
115
190
|
}> | null;
|
|
116
191
|
/** `body.proposalId` — BLI-3755's coding-arm proposal id, when the turn made one. */
|
|
117
192
|
proposalId?: string | null;
|
|
193
|
+
/**
|
|
194
|
+
* `body.nextAction` — BLI-3787's sentence for what a person must do next
|
|
195
|
+
* about the coding arm. Absent from a dashboard that predates it, which is
|
|
196
|
+
* why an older deployment reads as `next_action: null` rather than as a
|
|
197
|
+
* turn that said nothing.
|
|
198
|
+
*/
|
|
199
|
+
nextAction?: string | null;
|
|
200
|
+
/**
|
|
201
|
+
* `body.sources` — BLI-3770's structured citations, straight from the door.
|
|
202
|
+
* Typed as `unknown` on purpose: this is another process's JSON, and the
|
|
203
|
+
* one place it is shaped is `doorSources` above.
|
|
204
|
+
*/
|
|
205
|
+
sources?: unknown;
|
|
118
206
|
}
|
|
119
207
|
export declare function buildJarvisAnswerEnvelope(input: JarvisAnswerEnvelopeInput): JarvisAnswerEnvelope;
|
|
@@ -29,6 +29,25 @@
|
|
|
29
29
|
* `latency` / `model` keys `cockpit jarvis --json` also prints: those describe
|
|
30
30
|
* a terminal process's own stopwatch, and this server has no such stopwatch to
|
|
31
31
|
* report honestly.
|
|
32
|
+
*
|
|
33
|
+
* ## Where `sources` comes from (BLI-3770)
|
|
34
|
+
*
|
|
35
|
+
* From the DOOR, as objects, when the door sends them: `POST /api/jarvis/cli`
|
|
36
|
+
* carries `sources` built from the citations the grounding layer minted, and
|
|
37
|
+
* the `Source:` lines inside `answer` are rendered from that same array. The
|
|
38
|
+
* older derivation — a line-anchored regex over the finished prose — could
|
|
39
|
+
* only find a citation the renderer happened to put on its own line, so QA
|
|
40
|
+
* tick 16's c9, c9b and n9 (all off `searchEverything`) ended *"…Source:
|
|
41
|
+
* issue, at /work/BLI-3706, by …"* INSIDE the final sentence and returned
|
|
42
|
+
* `"sources": []`: the person saw a citation, the machine did not.
|
|
43
|
+
*
|
|
44
|
+
* The prose derivation survives as the FALLBACK, for a dashboard deployed
|
|
45
|
+
* before that door field existed, and it is wider than it was: a whole
|
|
46
|
+
* `Sources:` line (plural, any case, bulleted) counts — that is what the
|
|
47
|
+
* server itself treats as provenance — and so does a citation that begins a
|
|
48
|
+
* sentence inside a paragraph. A `Source:` in the MIDDLE of a sentence ("the
|
|
49
|
+
* Source: field on that row was blank") is prose about a source, not a
|
|
50
|
+
* source, and is deliberately not matched.
|
|
32
51
|
*/
|
|
33
52
|
/**
|
|
34
53
|
* Every key of the envelope, in the order it is written. The literal list IS
|
|
@@ -42,11 +61,24 @@ export const JARVIS_ANSWER_ENVELOPE_KEYS = [
|
|
|
42
61
|
"thread_id",
|
|
43
62
|
"trace_thread_id",
|
|
44
63
|
"proposal_id",
|
|
64
|
+
"next_action",
|
|
45
65
|
"degraded",
|
|
46
66
|
"degraded_reasons",
|
|
47
67
|
];
|
|
48
|
-
/**
|
|
49
|
-
|
|
68
|
+
/**
|
|
69
|
+
* A citation line, in every shape the server itself treats as one.
|
|
70
|
+
*
|
|
71
|
+
* BLI-3770 widened this from `/^\s*Source:\s*\S/` to mirror
|
|
72
|
+
* `apps/dashboard/src/lib/jarvis/chat-v2/provenance-lines.ts`, which matches
|
|
73
|
+
* `sources?` case-insensitively with an optional bullet. The narrow version
|
|
74
|
+
* meant a `Sources: …` line the server had already lifted out of the body as
|
|
75
|
+
* provenance, and put straight back under the answer, was not a source to
|
|
76
|
+
* this side: one thing, two definitions, in two packages.
|
|
77
|
+
*/
|
|
78
|
+
const SOURCE_LINE = /^\s*(?:[-*\u2022]\s+)?sources?\s*:\s*\S/i;
|
|
79
|
+
/** The receipt's link, as `appendCitations` lays it out: `<url>` after the words. */
|
|
80
|
+
const BRACKETED_LINK = /\s*<(https?:\/\/[^>\s]+)>\s*$/;
|
|
81
|
+
const TRAILING_LINK = /\s+(https?:\/\/\S+)\s*$/;
|
|
50
82
|
/**
|
|
51
83
|
* The `Source:` lines inside an answer. Pure string work on what the server
|
|
52
84
|
* already sent — this side never decides what a source IS, it only finds the
|
|
@@ -58,6 +90,90 @@ export function extractSourceLines(answer) {
|
|
|
58
90
|
.map((line) => line.trim())
|
|
59
91
|
.filter((line) => SOURCE_LINE.test(line));
|
|
60
92
|
}
|
|
93
|
+
/** The words and the link, kept apart, the way every surface renders them. */
|
|
94
|
+
function splitLink(line) {
|
|
95
|
+
const trimmed = line.trim().replace(/^[-*\u2022]\s+/, "");
|
|
96
|
+
const bracketed = trimmed.match(BRACKETED_LINK);
|
|
97
|
+
if (bracketed)
|
|
98
|
+
return { label: trimmed.slice(0, bracketed.index).trim(), href: bracketed[1] ?? null };
|
|
99
|
+
const trailing = trimmed.match(TRAILING_LINK);
|
|
100
|
+
if (trailing)
|
|
101
|
+
return { label: trimmed.slice(0, trailing.index).trim(), href: trailing[1] ?? null };
|
|
102
|
+
return { label: trimmed, href: null };
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* A citation the model wrote INSIDE a paragraph (BLI-3770).
|
|
106
|
+
*
|
|
107
|
+
* It counts when it begins a sentence, which is the shape QA tick 16 caught
|
|
108
|
+
* three times. It deliberately does not count in the middle of one — "the
|
|
109
|
+
* Source: field on that row was blank" is a sentence about a field, and
|
|
110
|
+
* treating it as a receipt would put prose in a contract that is supposed to
|
|
111
|
+
* carry evidence.
|
|
112
|
+
*/
|
|
113
|
+
function inlineSourceFragments(line) {
|
|
114
|
+
return line
|
|
115
|
+
.split(/(?<=[.!?])\s+/)
|
|
116
|
+
.map((part) => part.trim())
|
|
117
|
+
.filter((part) => SOURCE_LINE.test(part));
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* The fallback derivation: what this side can tell from the answer alone.
|
|
121
|
+
*
|
|
122
|
+
* Only reached when the door sent no structured `sources` — a dashboard
|
|
123
|
+
* deployed before BLI-3770, or a turn whose citation nothing minted. Every
|
|
124
|
+
* row it produces is labelled `kind: "prose"` so a consumer can tell a
|
|
125
|
+
* recovered line from a minted receipt.
|
|
126
|
+
*/
|
|
127
|
+
export function sourcesFromAnswer(answer) {
|
|
128
|
+
const found = [];
|
|
129
|
+
const seen = new Set();
|
|
130
|
+
const add = (text) => {
|
|
131
|
+
const { label, href } = splitLink(text);
|
|
132
|
+
if (!label || seen.has(label))
|
|
133
|
+
return;
|
|
134
|
+
seen.add(label);
|
|
135
|
+
found.push({ kind: "prose", label, href, id: null, tool: null });
|
|
136
|
+
};
|
|
137
|
+
for (const raw of answer.split("\n")) {
|
|
138
|
+
const line = raw.trim();
|
|
139
|
+
if (!line)
|
|
140
|
+
continue;
|
|
141
|
+
if (SOURCE_LINE.test(line)) {
|
|
142
|
+
add(line);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
for (const fragment of inlineSourceFragments(line))
|
|
146
|
+
add(fragment);
|
|
147
|
+
}
|
|
148
|
+
return found;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* The door's own `sources`, checked rather than trusted. A field that arrives
|
|
152
|
+
* as something other than a list of labelled objects is treated as absent, so
|
|
153
|
+
* a malformed body degrades to the prose fallback instead of putting
|
|
154
|
+
* `[object Object]` in front of an agent.
|
|
155
|
+
*/
|
|
156
|
+
function doorSources(sent) {
|
|
157
|
+
if (!Array.isArray(sent))
|
|
158
|
+
return [];
|
|
159
|
+
const rows = [];
|
|
160
|
+
for (const entry of sent) {
|
|
161
|
+
if (!entry || typeof entry !== "object")
|
|
162
|
+
continue;
|
|
163
|
+
const row = entry;
|
|
164
|
+
const label = typeof row.label === "string" ? row.label.trim() : "";
|
|
165
|
+
if (!label)
|
|
166
|
+
continue;
|
|
167
|
+
rows.push({
|
|
168
|
+
kind: typeof row.kind === "string" && row.kind ? row.kind : "unknown",
|
|
169
|
+
label,
|
|
170
|
+
href: typeof row.href === "string" ? row.href : null,
|
|
171
|
+
id: typeof row.id === "string" ? row.id : null,
|
|
172
|
+
tool: typeof row.tool === "string" ? row.tool : null,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
return rows;
|
|
176
|
+
}
|
|
61
177
|
export function buildJarvisAnswerEnvelope(input) {
|
|
62
178
|
const reasons = [];
|
|
63
179
|
if (input.modelFallback === true)
|
|
@@ -70,14 +186,19 @@ export function buildJarvisAnswerEnvelope(input) {
|
|
|
70
186
|
const turnId = input.traceId ?? null;
|
|
71
187
|
if (!turnId)
|
|
72
188
|
reasons.push("no_turn_id");
|
|
189
|
+
const sent = doorSources(input.sources);
|
|
73
190
|
return {
|
|
74
191
|
ok: true,
|
|
75
192
|
answer: input.reply,
|
|
76
|
-
|
|
193
|
+
// BLI-3770: the door's own citations when it sent them, and only then the
|
|
194
|
+
// prose fallback. Never both — a turn's receipts have one origin, and
|
|
195
|
+
// merging the two would double-count the lines the door already described.
|
|
196
|
+
sources: sent.length > 0 ? sent : sourcesFromAnswer(input.reply),
|
|
77
197
|
turn_id: turnId,
|
|
78
198
|
thread_id: input.thread ?? null,
|
|
79
199
|
trace_thread_id: input.traceThread ?? null,
|
|
80
200
|
proposal_id: input.proposalId ?? null,
|
|
201
|
+
next_action: input.nextAction ?? null,
|
|
81
202
|
degraded: reasons.length > 0,
|
|
82
203
|
degraded_reasons: reasons,
|
|
83
204
|
};
|
package/dist/jarvis-door.js
CHANGED
|
@@ -110,6 +110,11 @@ export async function takeTurn(deps, session, door, body, remember) {
|
|
|
110
110
|
revised: reply.revised,
|
|
111
111
|
trace: reply.trace,
|
|
112
112
|
proposalId: reply.proposalId,
|
|
113
|
+
// BLI-3787: the sentence beside it, so a refusal names what a person must
|
|
114
|
+
// do rather than arriving as a bare `proposal_id: null`.
|
|
115
|
+
nextAction: reply.nextAction,
|
|
116
|
+
// BLI-3770: the door's own structured citations, when it sent them.
|
|
117
|
+
sources: reply.sources,
|
|
113
118
|
});
|
|
114
119
|
remember({ turnId: envelope.turn_id, traceThreadId: envelope.trace_thread_id });
|
|
115
120
|
log(`${TAG} answered ${JSON.stringify({
|
|
@@ -120,6 +125,9 @@ export async function takeTurn(deps, session, door, body, remember) {
|
|
|
120
125
|
// BLI-3755: whether this turn left a coding-arm proposal behind. The id
|
|
121
126
|
// itself is in the envelope; this line says one was made.
|
|
122
127
|
proposal_recorded: envelope.proposal_id !== null,
|
|
128
|
+
// BLI-3787: whether this turn said what to do next. A turn that reached
|
|
129
|
+
// the coding arm and said nothing is the defect, and it is visible here.
|
|
130
|
+
next_action_present: envelope.next_action !== null,
|
|
123
131
|
degraded: envelope.degraded,
|
|
124
132
|
degraded_reasons: envelope.degraded_reasons,
|
|
125
133
|
has_turn_id: envelope.turn_id !== null,
|
|
@@ -132,6 +140,9 @@ export async function takeTurn(deps, session, door, body, remember) {
|
|
|
132
140
|
? `proposal_id: ${envelope.proposal_id} — the person fetches the approval code for it themself, `
|
|
133
141
|
+ `in a Tower tab, their Slack DM, or their own \`cockpit jarvis\` terminal. You were not sent one.`
|
|
134
142
|
: null,
|
|
143
|
+
// BLI-3787: printed whether or not there is a proposal id, because the
|
|
144
|
+
// turns that made none are exactly the ones a caller could not read.
|
|
145
|
+
envelope.next_action ? `next_action: ${envelope.next_action}` : null,
|
|
135
146
|
envelope.degraded ? `degraded: ${envelope.degraded_reasons.join(", ")}` : null,
|
|
136
147
|
]
|
|
137
148
|
.filter((line) => line !== null)
|
package/dist/jarvis-tools.js
CHANGED
|
@@ -78,13 +78,16 @@ export function registerJarvisTools(server, deps) {
|
|
|
78
78
|
register("jarvis_ask", {
|
|
79
79
|
title: "Ask JARVIS",
|
|
80
80
|
description: "Asks JARVIS one question and returns its answer, the Source: lines behind it, this turn's "
|
|
81
|
-
+ "turn_id
|
|
81
|
+
+ "turn_id, the conversation's thread_id, and — when the turn reached the coding arm — a "
|
|
82
|
+
+ "proposal_id and a next_action sentence. Same JARVIS, same tool belt and same evidence "
|
|
82
83
|
+ "rules as Tower web chat, the Slack DM and `cockpit jarvis`. A thread is SINGLE-WRITER: "
|
|
83
84
|
+ "omit thread and this turn gets a FRESH conversation of its own, so two questions asked at "
|
|
84
85
|
+ "the same time can never read each other's; pass the thread_id the answer returned to "
|
|
85
86
|
+ "continue that conversation deliberately. Pass the returned turn_id to jarvis_trace to see "
|
|
86
87
|
+ "how the answer was reached. JARVIS speaks as the person this machine is paired to and "
|
|
87
|
-
+ "cannot be made to speak as anyone else."
|
|
88
|
+
+ "cannot be made to speak as anyone else. proposal_id is null on every turn that proposed no "
|
|
89
|
+
+ "coding task, including one the arm refused; next_action is the sentence saying which it "
|
|
90
|
+
+ "was and what a PERSON has to do about it, so a null proposal_id is never on its own.",
|
|
88
91
|
inputSchema: {
|
|
89
92
|
question: z.string().min(1).max(50_000).describe("What to ask, in plain words."),
|
|
90
93
|
thread: z
|
|
@@ -194,10 +197,13 @@ export function registerJarvisTools(server, deps) {
|
|
|
194
197
|
+ "approval_code: you get the plan and a proposal_id back, and DELIBERATELY no code — a code "
|
|
195
198
|
+ "you can read is a code you could approve with. Show the person the plan and the "
|
|
196
199
|
+ "proposal_id and ask them to fetch the code themself, in a Tower browser tab, their Slack "
|
|
197
|
-
+ "DM with JARVIS, or their own `cockpit jarvis
|
|
200
|
+
+ "DM with JARVIS, or their own interactive `cockpit jarvis`. Then call this again with the code "
|
|
198
201
|
+ "THEY give you and the same instruction. A code approves exactly ONE run: a reused one is "
|
|
199
202
|
+ "refused (approval_code_spent) and the answer is a fresh approval, never a retry. Never "
|
|
200
|
-
+ "derive, guess, or reuse a code the person has not just handed you."
|
|
203
|
+
+ "derive, guess, or reuse a code the person has not just handed you. If the answer comes "
|
|
204
|
+
+ "back with no proposal_id, read next_action: the arm refused rather than proposed, and it "
|
|
205
|
+
+ "names what a person has to do — never send a proposal_id back to JARVIS yourself, this is "
|
|
206
|
+
+ "the surface it was withheld from and the read-back is refused here.",
|
|
201
207
|
inputSchema: {
|
|
202
208
|
instruction: z
|
|
203
209
|
.string()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bli-cockpit/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
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",
|