mirror of
https://github.com/callstack/agent-device.git
synced 2026-09-14 20:06:34 +08:00
6a8beb653e
* feat(mcp): compact server instructions in both eras + MCP-only help tool (#1833) MCP-only clients got no workflow guidance: server/discover carried two sentences, legacy initialize carried nothing, and the CLI guides (agent-device --help, help <topic>) were unreachable over MCP. - MCP_SERVER_INSTRUCTIONS: one MCP-phrased workflow card (<2 KB, the Claude Code truncation limit) returned by server/discover and legacy initialize alike. - help tool, router-owned (not a command descriptor): no topic -> the CLI decision card; topic -> agent-device help <topic|command> text, prefixed with the one-line CLI->tool-property mapping; unknown topic -> isError listing the topics. listCommandTools() stays descriptor-only for the AI SDK; the router composes descriptors + help. - Move src/cli/parser/cli-help{,-overview}.ts to src/cli-schema/ so src/mcp (rank 3) can import the renderers without a layering back-edge into src/cli (rank 6). * fix(mcp): name terminal-only commands in help guides; colocate cli-help tests with their sources - The MCP guide preamble claimed every `agent-device <command>` line is a tool of that name; `help web` tells the reader to run `web setup` / `web doctor` and no `web` tool exists. The preamble now lists the exact CLI-only set (listCliCommandNames minus listMcpExposedCommandNames) — derived, not scanned out of prose where `device`/`web` are ordinary words. Regression: help web names `web` as terminal-only, and the listed set equals the registry difference. - cli-help-*.test.ts move from src/cli/parser/__tests__ to src/cli-schema/ to mirror the moved sources. * perf(mcp): tighten the guide card, tool description, and preamble Instructions card 1572 -> 1378 bytes (paid every session), tool description and preamble trimmed, HELP_TOOL built once as a const. Bundle delta vs main 3189 -> 2715 bytes; the remainder is the guide text itself, which the bundle carried in no MCP-phrased form before.
69 lines
2.9 KiB
TypeScript
69 lines
2.9 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import { test } from 'vitest';
|
|
import { CASES } from '../help-conformance-cases.mjs';
|
|
import { helpTopicIds } from '../../src/cli-schema/cli-help.ts';
|
|
|
|
// "What enumerates N": benchmark cases are keyed to help topics, and this gate
|
|
// keys the case list to the topic registry itself. A new help topic must gain
|
|
// a benchmark case (docs: [..., '<topic>']) or an explicit waiver here — the
|
|
// waiver names why the topic's guidance is not yet benchmarked, so uncovered
|
|
// topics are a visible decision instead of silent drift.
|
|
const WAIVED_TOPICS: Record<string, string> = {
|
|
cdp: 'JS-heap forensics niche; add cases when heap-guidance regressions show up in practice.',
|
|
commands:
|
|
'Derived command/configuration reference, not a planning loop; catalog completeness is structurally tested.',
|
|
macos: 'macOS surface guidance is thin and stable; no observed planning regressions yet.',
|
|
maestro: 'Compatibility reference, not a planning loop; conformance is oracle-tested instead.',
|
|
'physical-device': 'Needs device-specific setup guidance; no portable planning task defined yet.',
|
|
'react-devtools':
|
|
'Profiling-window guidance; add cases when render-diagnosis planning regresses.',
|
|
};
|
|
|
|
const FIRST_SCREEN_DOC = '--help:first30';
|
|
|
|
test('every case doc id is the first screen or a real help topic', () => {
|
|
const topics = new Set(helpTopicIds());
|
|
for (const testCase of CASES) {
|
|
for (const doc of testCase.docs) {
|
|
assert.ok(
|
|
doc === FIRST_SCREEN_DOC || topics.has(doc),
|
|
`case "${testCase.id}" references unknown help doc "${doc}"`,
|
|
);
|
|
}
|
|
}
|
|
});
|
|
|
|
test('every help topic has a benchmark case or an explicit waiver', () => {
|
|
const covered = new Set(CASES.flatMap((testCase) => testCase.docs));
|
|
const uncovered = helpTopicIds().filter(
|
|
(topic) => !covered.has(topic) && !(topic in WAIVED_TOPICS),
|
|
);
|
|
assert.deepEqual(
|
|
uncovered,
|
|
[],
|
|
'new help topics need a benchmark case in scripts/help-conformance-cases.mjs or a waiver above',
|
|
);
|
|
});
|
|
|
|
test('waivers only name real, uncovered topics', () => {
|
|
const topics = new Set(helpTopicIds());
|
|
const covered = new Set(CASES.flatMap((testCase) => testCase.docs));
|
|
for (const [topic, reason] of Object.entries(WAIVED_TOPICS)) {
|
|
assert.ok(topics.has(topic), `waived topic "${topic}" no longer exists — remove the waiver`);
|
|
assert.ok(
|
|
!covered.has(topic),
|
|
`waived topic "${topic}" is now covered by a case — remove the waiver`,
|
|
);
|
|
assert.ok(reason.trim().length > 0, `waiver for "${topic}" needs a reason`);
|
|
}
|
|
});
|
|
|
|
test('the first help screen is exercised by every case family', () => {
|
|
for (const testCase of CASES) {
|
|
assert.ok(
|
|
testCase.docs.includes(FIRST_SCREEN_DOC),
|
|
`case "${testCase.id}" must include the first-screen doc — it is the only text every runner sees before choosing a topic`,
|
|
);
|
|
}
|
|
});
|