@variance-authority/mcp 0.1.0
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/CHANGELOG.md +89 -0
- package/LICENSE +21 -0
- package/README.md +407 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.js +32 -0
- package/dist/bin.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/observability-subject.d.ts +22 -0
- package/dist/observability-subject.js +2 -0
- package/dist/observability-subject.js.map +1 -0
- package/dist/presentation.d.ts +6 -0
- package/dist/presentation.js +64 -0
- package/dist/presentation.js.map +1 -0
- package/dist/protocol.d.ts +82 -0
- package/dist/protocol.js +186 -0
- package/dist/protocol.js.map +1 -0
- package/dist/server.d.ts +71 -0
- package/dist/server.js +103 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/adjudicate.d.ts +25 -0
- package/dist/tools/adjudicate.js +122 -0
- package/dist/tools/adjudicate.js.map +1 -0
- package/dist/tools/attention.d.ts +13 -0
- package/dist/tools/attention.js +151 -0
- package/dist/tools/attention.js.map +1 -0
- package/dist/tools/changelog.d.ts +38 -0
- package/dist/tools/changelog.js +201 -0
- package/dist/tools/changelog.js.map +1 -0
- package/dist/tools/changes.d.ts +31 -0
- package/dist/tools/changes.js +120 -0
- package/dist/tools/changes.js.map +1 -0
- package/dist/tools/composition.d.ts +13 -0
- package/dist/tools/composition.js +366 -0
- package/dist/tools/composition.js.map +1 -0
- package/dist/tools/describe.d.ts +20 -0
- package/dist/tools/describe.js +279 -0
- package/dist/tools/describe.js.map +1 -0
- package/dist/tools/diff.d.ts +20 -0
- package/dist/tools/diff.js +85 -0
- package/dist/tools/diff.js.map +1 -0
- package/dist/tools/explain-verdict.d.ts +25 -0
- package/dist/tools/explain-verdict.js +92 -0
- package/dist/tools/explain-verdict.js.map +1 -0
- package/dist/tools/findings.d.ts +40 -0
- package/dist/tools/findings.js +130 -0
- package/dist/tools/findings.js.map +1 -0
- package/dist/tools/narrowing.d.ts +26 -0
- package/dist/tools/narrowing.js +38 -0
- package/dist/tools/narrowing.js.map +1 -0
- package/dist/tools/observability.d.ts +7 -0
- package/dist/tools/observability.js +199 -0
- package/dist/tools/observability.js.map +1 -0
- package/dist/tools/presentations.d.ts +6 -0
- package/dist/tools/presentations.js +74 -0
- package/dist/tools/presentations.js.map +1 -0
- package/dist/tools/run-signals.d.ts +12 -0
- package/dist/tools/run-signals.js +115 -0
- package/dist/tools/run-signals.js.map +1 -0
- package/dist/tools/scenarios.d.ts +6 -0
- package/dist/tools/scenarios.js +62 -0
- package/dist/tools/scenarios.js.map +1 -0
- package/dist/tools/source-tests.d.ts +5 -0
- package/dist/tools/source-tests.js +95 -0
- package/dist/tools/source-tests.js.map +1 -0
- package/dist/tools/subject.d.ts +45 -0
- package/dist/tools/subject.js +57 -0
- package/dist/tools/subject.js.map +1 -0
- package/dist/tools/summary.d.ts +31 -0
- package/dist/tools/summary.js +436 -0
- package/dist/tools/summary.js.map +1 -0
- package/dist/tools/test-signals.d.ts +16 -0
- package/dist/tools/test-signals.js +106 -0
- package/dist/tools/test-signals.js.map +1 -0
- package/dist/tools/tool.d.ts +64 -0
- package/dist/tools/tool.js +9 -0
- package/dist/tools/tool.js.map +1 -0
- package/dist/tools/trace-component.d.ts +17 -0
- package/dist/tools/trace-component.js +50 -0
- package/dist/tools/trace-component.js.map +1 -0
- package/dist/tools/vantage-lines.d.ts +44 -0
- package/dist/tools/vantage-lines.js +66 -0
- package/dist/tools/vantage-lines.js.map +1 -0
- package/dist/tools/variations.d.ts +27 -0
- package/dist/tools/variations.js +125 -0
- package/dist/tools/variations.js.map +1 -0
- package/dist/tools.d.ts +120 -0
- package/dist/tools.js +127 -0
- package/dist/tools.js.map +1 -0
- package/mark.svg +30 -0
- package/package.json +64 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-signals.js","sourceRoot":"","sources":["../../src/tools/test-signals.ts"],"names":[],"mappings":"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","sourcesContent":["import type { VantageState, WatchedTest } from '@variance-authority/vantage';\nimport { stringArg, type Tool } from './tool.js';\nimport { announcement, heading, unattached } from './vantage-lines.js';\n\n/**\n * Everything one test has announced, in order, whatever realm said it.\n *\n * This is the answer a timeout cannot give from outside the worker. A test that\n * is hanging has usually heard *something*, and which realm stopped talking is\n * the whole of the diagnosis: nothing at all means no listener or no `vae` call,\n * and a page that spoke while a service did not means the request never reached\n * the service or never came back.\n *\n * Asked while the test is still running, which is the point. The answer is a\n * snapshot and says so.\n */\nexport const testSignals: Tool<VantageState> = {\n name: 'variance_test_signals',\n description:\n 'Everything one test has announced, in order, with the realm that said each — plus work that started and never ended. Answers while the test is still running.',\n inputSchema: {\n type: 'object',\n properties: {\n test: {\n type: 'string',\n description: 'A test id from variance_run_signals, or part of its title.',\n },\n },\n required: ['test'],\n additionalProperties: false,\n },\n run(state, input) {\n if (state.tests.length === 0) return unattached(state);\n const asked = stringArg(input, 'test');\n const found = locate(state, asked);\n return typeof found === 'string' ? found : described(found);\n },\n};\n\n/** The one test meant, or the sentence explaining why it is not one test. */\nfunction locate(state: VantageState, asked: string): WatchedTest | string {\n const byId = state.tests.find((test) => test.id === asked);\n if (byId !== undefined) return byId;\n\n const byTitle = state.tests.filter((test) => test.title === asked);\n if (byTitle.length === 1 && byTitle[0] !== undefined) return byTitle[0];\n\n const lowered = asked.toLowerCase();\n const partial = state.tests.filter((test) => test.title.toLowerCase().includes(lowered));\n if (partial.length === 1 && partial[0] !== undefined) return partial[0];\n if (partial.length === 0) {\n return [\n `No test here matches ${asked}. ${state.tests.length} test(s) have reported:`,\n ...state.tests.map((test) => ` ${test.title} [${test.id}]`),\n ].join('\\n');\n }\n return [\n `${partial.length} tests match ${asked}; ask for one by id:`,\n ...partial.map((test) => ` ${test.title} [${test.id}]`),\n ].join('\\n');\n}\n\nfunction described(test: WatchedTest): string {\n return [\n `${heading(test)} — ${test.state}`,\n '',\n ...heard(test),\n ...pending(test),\n ...remarks(test),\n ...ended(test),\n ].join('\\n');\n}\n\nfunction heard(test: WatchedTest): string[] {\n if (test.heard.length === 0) {\n return [\n 'Nothing has been announced in this execution, by any realm. Either no ' +\n 'listener is installed for it — the test destructures no `events` ' +\n 'fixture — or the code it drives does not call `vae` yet.',\n ];\n }\n return [\n test.forgotten === 0\n ? 'Heard, in order:'\n : `Heard, in order (the first ${test.forgotten} were dropped to stay bounded):`,\n ...test.heard.map((event) => ` ${announcement(event)}`),\n ];\n}\n\nfunction pending(test: WatchedTest): string[] {\n if (test.pending.length === 0) return [];\n return [\n '',\n 'Started and never ended:',\n ...test.pending.map(\n (event) => ` ${event.realm} ${event.location} / ${event.subject} / ${event.action}`,\n ),\n ];\n}\n\nfunction remarks(test: WatchedTest): string[] {\n if (test.remarks.length === 0) return [];\n return ['', 'The listener also knows:', ...test.remarks.map((line) => ` ${line}`)];\n}\n\nfunction ended(test: WatchedTest): string[] {\n if (test.state === 'running') return ['', 'Still running; this is where it had got to.'];\n if (test.error === undefined) return ['', `Ended: ${test.state}.`];\n return ['', `Ended: ${test.state}.`, ...test.error.split('\\n').map((line) => ` ${line}`)];\n}\n"]}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { RunReport } from '@variance-authority/report';
|
|
2
|
+
/**
|
|
3
|
+
* The contract every tool implements, and the untyped boundary it sits behind.
|
|
4
|
+
*
|
|
5
|
+
* Its own module because every tool imports it and it imports no tool: an
|
|
6
|
+
* interface that lives in the registry beside the list of tools makes each tool
|
|
7
|
+
* depend on all the others, and nothing about that dependency is visible until
|
|
8
|
+
* something loads in the wrong order.
|
|
9
|
+
*
|
|
10
|
+
* The subject is a type parameter rather than `RunReport`, because a tool is a
|
|
11
|
+
* pure function from *something already read* to text, and nothing in that
|
|
12
|
+
* sentence is about a report. It defaults to `RunReport` so the report tools
|
|
13
|
+
* this package ships say nothing about it.
|
|
14
|
+
*
|
|
15
|
+
* `stringArg` is here for the same reason it exists at all. A tool is called with
|
|
16
|
+
* whatever JSON a model produced, so `input` is `unknown` all the way down, and
|
|
17
|
+
* the first thing any tool does with an argument is refuse it or narrow it. That
|
|
18
|
+
* refusal is part of the contract, not a detail of whichever tool refuses first.
|
|
19
|
+
*/
|
|
20
|
+
export interface Tool<Subject = RunReport> {
|
|
21
|
+
readonly name: string;
|
|
22
|
+
readonly description: string;
|
|
23
|
+
readonly inputSchema: Readonly<Record<string, unknown>>;
|
|
24
|
+
run(subject: Subject, input: Readonly<Record<string, unknown>>, invocation?: ToolInvocation<Subject>): string;
|
|
25
|
+
}
|
|
26
|
+
/** State held for exactly one previous MCP tool invocation. */
|
|
27
|
+
export interface ToolInvocation<Subject> {
|
|
28
|
+
readonly previous?: Subject;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* A set of tools, and what the server answering with them calls itself.
|
|
32
|
+
*
|
|
33
|
+
* The subject is a parameter because the protocol has no opinion about it. A run
|
|
34
|
+
* report is one subject; a workspace's published API is another, and the framing
|
|
35
|
+
* between a JSON-RPC line and a tool's text is identical for both. What differs
|
|
36
|
+
* is the list and the name, and that is exactly what this holds.
|
|
37
|
+
*/
|
|
38
|
+
export interface Served<Subject = RunReport> {
|
|
39
|
+
readonly name: string;
|
|
40
|
+
readonly version: string;
|
|
41
|
+
readonly tools: readonly Tool<Subject>[];
|
|
42
|
+
/**
|
|
43
|
+
* What a client puts in front of the model before it has called anything.
|
|
44
|
+
*
|
|
45
|
+
* A tool list says what each tool answers and cannot say when to reach for
|
|
46
|
+
* one, and there is a class of server where that gap is the whole product: a
|
|
47
|
+
* watcher nobody attached a run to lists tools about a run that does not
|
|
48
|
+
* exist, reads as broken, and is never called again. So this takes the
|
|
49
|
+
* subject — the one thing a set of tools cannot see at handshake time — and
|
|
50
|
+
* anything it needs to say about **setup** goes here rather than into a tool
|
|
51
|
+
* nobody has a reason to call yet.
|
|
52
|
+
*
|
|
53
|
+
* Omitted where a tool list is self-explanatory, which is the ordinary case:
|
|
54
|
+
* a report on disk is already there, and nothing has to be arranged.
|
|
55
|
+
*/
|
|
56
|
+
readonly instructions?: (subject: Subject) => string;
|
|
57
|
+
}
|
|
58
|
+
export declare const NO_ARGS: {
|
|
59
|
+
readonly type: 'object';
|
|
60
|
+
readonly properties: {};
|
|
61
|
+
readonly additionalProperties: false;
|
|
62
|
+
};
|
|
63
|
+
export declare function stringArg(input: Readonly<Record<string, unknown>>, name: string): string;
|
|
64
|
+
//# sourceMappingURL=tool.d.ts.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const NO_ARGS = { type: 'object', properties: {}, additionalProperties: false };
|
|
2
|
+
export function stringArg(input, name) {
|
|
3
|
+
const value = input[name];
|
|
4
|
+
if (typeof value !== 'string' || value === '') {
|
|
5
|
+
throw new Error(`\`${name}\` is required and must be a non-empty string`);
|
|
6
|
+
}
|
|
7
|
+
return value;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool.js","sourceRoot":"","sources":["../../src/tools/tool.ts"],"names":[],"mappings":"AAkEA,MAAM,CAAC,MAAM,OAAO,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,oBAAoB,EAAE,KAAK,EAAW,CAAC;AAEhG,MAAM,UAAU,SAAS,CAAC,KAAwC,EAAE,IAAY;IAC9E,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,KAAK,IAAI,+CAA+C,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import type { RunReport } from '@variance-authority/report';\n\n/**\n * The contract every tool implements, and the untyped boundary it sits behind.\n *\n * Its own module because every tool imports it and it imports no tool: an\n * interface that lives in the registry beside the list of tools makes each tool\n * depend on all the others, and nothing about that dependency is visible until\n * something loads in the wrong order.\n *\n * The subject is a type parameter rather than `RunReport`, because a tool is a\n * pure function from *something already read* to text, and nothing in that\n * sentence is about a report. It defaults to `RunReport` so the report tools\n * this package ships say nothing about it.\n *\n * `stringArg` is here for the same reason it exists at all. A tool is called with\n * whatever JSON a model produced, so `input` is `unknown` all the way down, and\n * the first thing any tool does with an argument is refuse it or narrow it. That\n * refusal is part of the contract, not a detail of whichever tool refuses first.\n */\n\nexport interface Tool<Subject = RunReport> {\n readonly name: string;\n readonly description: string;\n readonly inputSchema: Readonly<Record<string, unknown>>;\n run(\n subject: Subject,\n input: Readonly<Record<string, unknown>>,\n invocation?: ToolInvocation<Subject>,\n ): string;\n}\n\n/** State held for exactly one previous MCP tool invocation. */\nexport interface ToolInvocation<Subject> {\n readonly previous?: Subject;\n}\n\n/**\n * A set of tools, and what the server answering with them calls itself.\n *\n * The subject is a parameter because the protocol has no opinion about it. A run\n * report is one subject; a workspace's published API is another, and the framing\n * between a JSON-RPC line and a tool's text is identical for both. What differs\n * is the list and the name, and that is exactly what this holds.\n */\nexport interface Served<Subject = RunReport> {\n readonly name: string;\n readonly version: string;\n readonly tools: readonly Tool<Subject>[];\n /**\n * What a client puts in front of the model before it has called anything.\n *\n * A tool list says what each tool answers and cannot say when to reach for\n * one, and there is a class of server where that gap is the whole product: a\n * watcher nobody attached a run to lists tools about a run that does not\n * exist, reads as broken, and is never called again. So this takes the\n * subject — the one thing a set of tools cannot see at handshake time — and\n * anything it needs to say about **setup** goes here rather than into a tool\n * nobody has a reason to call yet.\n *\n * Omitted where a tool list is self-explanatory, which is the ordinary case:\n * a report on disk is already there, and nothing has to be arranged.\n */\n readonly instructions?: (subject: Subject) => string;\n}\n\nexport const NO_ARGS = { type: 'object', properties: {}, additionalProperties: false } as const;\n\nexport function stringArg(input: Readonly<Record<string, unknown>>, name: string): string {\n const value = input[name];\n if (typeof value !== 'string' || value === '') {\n throw new Error(`\\`${name}\\` is required and must be a non-empty string`);\n }\n return value;\n}\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type Tool } from './tool.js';
|
|
2
|
+
/**
|
|
3
|
+
* `variance_trace_component` — the only answer here that reads across subjects.
|
|
4
|
+
*
|
|
5
|
+
* Its own module because everything else in this package narrows to one subject
|
|
6
|
+
* and then goes deeper. This goes the other way: it holds a component still and
|
|
7
|
+
* sweeps the run past it, and what it returns is a size rather than a diagnosis.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* A component, across the whole run.
|
|
11
|
+
*
|
|
12
|
+
* The question a design-system change actually raises. "Did `Button` change" is
|
|
13
|
+
* answerable from one subject; "what did changing `Button` reach" is not, and it
|
|
14
|
+
* is the one that decides whether a branch is safe.
|
|
15
|
+
*/
|
|
16
|
+
export declare const trace: Tool;
|
|
17
|
+
//# sourceMappingURL=trace-component.d.ts.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { stringArg } from './tool.js';
|
|
2
|
+
/**
|
|
3
|
+
* `variance_trace_component` — the only answer here that reads across subjects.
|
|
4
|
+
*
|
|
5
|
+
* Its own module because everything else in this package narrows to one subject
|
|
6
|
+
* and then goes deeper. This goes the other way: it holds a component still and
|
|
7
|
+
* sweeps the run past it, and what it returns is a size rather than a diagnosis.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* A component, across the whole run.
|
|
11
|
+
*
|
|
12
|
+
* The question a design-system change actually raises. "Did `Button` change" is
|
|
13
|
+
* answerable from one subject; "what did changing `Button` reach" is not, and it
|
|
14
|
+
* is the one that decides whether a branch is safe.
|
|
15
|
+
*/
|
|
16
|
+
export const trace = {
|
|
17
|
+
name: 'variance_trace_component',
|
|
18
|
+
description: 'Every subject a component appears in across the run, with pixels and whether it was ' +
|
|
19
|
+
'the cause of the change or was displaced by it. Use to size the blast radius of a ' +
|
|
20
|
+
'design-system or token edit.',
|
|
21
|
+
inputSchema: {
|
|
22
|
+
type: 'object',
|
|
23
|
+
properties: { component: { type: 'string' } },
|
|
24
|
+
required: ['component'],
|
|
25
|
+
additionalProperties: false,
|
|
26
|
+
},
|
|
27
|
+
run(report, input) {
|
|
28
|
+
const component = stringArg(input, 'component');
|
|
29
|
+
const hits = report.observations.flatMap((observation) => {
|
|
30
|
+
const regions = observation.regions.filter((region) => region.component === component);
|
|
31
|
+
return regions.length === 0 ? [] : [{ observation, regions }];
|
|
32
|
+
});
|
|
33
|
+
if (hits.length === 0)
|
|
34
|
+
return `\`${component}\` does not appear in any region in this run`;
|
|
35
|
+
const causeIn = hits.filter(({ regions }) => regions.some((region) => region.cause));
|
|
36
|
+
const file = hits.flatMap(({ regions }) => regions.map((r) => r.file)).find(Boolean);
|
|
37
|
+
return [
|
|
38
|
+
`\`${component}\` appears in ${hits.length} subject(s); ` +
|
|
39
|
+
`it is the cause in ${causeIn.length} of them` +
|
|
40
|
+
(file !== undefined ? ` — ${file}` : ''),
|
|
41
|
+
'',
|
|
42
|
+
...hits.map(({ observation, regions }) => {
|
|
43
|
+
const pixels = regions.reduce((sum, region) => sum + region.pixels, 0);
|
|
44
|
+
const role = regions.some((region) => region.cause) ? 'cause' : 'collateral';
|
|
45
|
+
return ` ${observation.subject}: ${pixels}px in ${regions.length} region(s) [${role}]`;
|
|
46
|
+
}),
|
|
47
|
+
].join('\n');
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=trace-component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace-component.js","sourceRoot":"","sources":["../../src/tools/trace-component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAa,MAAM,WAAW,CAAC;AAEjD;;;;;;GAMG;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,KAAK,GAAS;IACzB,IAAI,EAAE,0BAA0B;IAChC,WAAW,EACT,sFAAsF;QACtF,oFAAoF;QACpF,8BAA8B;IAChC,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QAC7C,QAAQ,EAAE,CAAC,WAAW,CAAC;QACvB,oBAAoB,EAAE,KAAK;KAC5B;IAED,GAAG,CAAC,MAAM,EAAE,KAAK;QACf,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;QAEhD,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE;YACvD,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC;YACvF,OAAO,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;QAEH,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,KAAK,SAAS,8CAA8C,CAAC;QAE3F,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACrF,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAErF,OAAO;YACL,KAAK,SAAS,iBAAiB,IAAI,CAAC,MAAM,eAAe;gBACvD,sBAAsB,OAAO,CAAC,MAAM,UAAU;gBAC9C,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1C,EAAE;YACF,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,EAAE;gBACvC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;gBACvE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC;gBAC7E,OAAO,KAAK,WAAW,CAAC,OAAO,KAAK,MAAM,SAAS,OAAO,CAAC,MAAM,eAAe,IAAI,GAAG,CAAC;YAC1F,CAAC,CAAC;SACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC;CACF,CAAC","sourcesContent":["import { stringArg, type Tool } from './tool.js';\n\n/**\n * `variance_trace_component` — the only answer here that reads across subjects.\n *\n * Its own module because everything else in this package narrows to one subject\n * and then goes deeper. This goes the other way: it holds a component still and\n * sweeps the run past it, and what it returns is a size rather than a diagnosis.\n */\n\n/**\n * A component, across the whole run.\n *\n * The question a design-system change actually raises. \"Did `Button` change\" is\n * answerable from one subject; \"what did changing `Button` reach\" is not, and it\n * is the one that decides whether a branch is safe.\n */\nexport const trace: Tool = {\n name: 'variance_trace_component',\n description:\n 'Every subject a component appears in across the run, with pixels and whether it was ' +\n 'the cause of the change or was displaced by it. Use to size the blast radius of a ' +\n 'design-system or token edit.',\n inputSchema: {\n type: 'object',\n properties: { component: { type: 'string' } },\n required: ['component'],\n additionalProperties: false,\n },\n\n run(report, input) {\n const component = stringArg(input, 'component');\n\n const hits = report.observations.flatMap((observation) => {\n const regions = observation.regions.filter((region) => region.component === component);\n return regions.length === 0 ? [] : [{ observation, regions }];\n });\n\n if (hits.length === 0) return `\\`${component}\\` does not appear in any region in this run`;\n\n const causeIn = hits.filter(({ regions }) => regions.some((region) => region.cause));\n const file = hits.flatMap(({ regions }) => regions.map((r) => r.file)).find(Boolean);\n\n return [\n `\\`${component}\\` appears in ${hits.length} subject(s); ` +\n `it is the cause in ${causeIn.length} of them` +\n (file !== undefined ? ` — ${file}` : ''),\n '',\n ...hits.map(({ observation, regions }) => {\n const pixels = regions.reduce((sum, region) => sum + region.pixels, 0);\n const role = regions.some((region) => region.cause) ? 'cause' : 'collateral';\n return ` ${observation.subject}: ${pixels}px in ${regions.length} region(s) [${role}]`;\n }),\n ].join('\\n');\n },\n};\n"]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sentences both live tools share.
|
|
3
|
+
*
|
|
4
|
+
* Its own module for the reason every extracted module here has: the two tools
|
|
5
|
+
* disagreeing about how an announcement is written would make one of them the
|
|
6
|
+
* odd one out in a transcript an agent reads end to end, and the way to stop
|
|
7
|
+
* that is for there to be one spelling rather than a convention.
|
|
8
|
+
*/
|
|
9
|
+
import type { VantageState, WatchedTest } from '@variance-authority/vantage';
|
|
10
|
+
/** One announcement, as a line in a listing. */
|
|
11
|
+
export declare function announcement(event: {
|
|
12
|
+
readonly realm: string;
|
|
13
|
+
readonly location: string;
|
|
14
|
+
readonly subject: string;
|
|
15
|
+
readonly action: string;
|
|
16
|
+
readonly phase: string;
|
|
17
|
+
readonly ordinal: number;
|
|
18
|
+
}): string;
|
|
19
|
+
/** A test in one line, without what it heard. */
|
|
20
|
+
export declare function heading(test: WatchedTest): string;
|
|
21
|
+
/** How much this test has to say, as a phrase. */
|
|
22
|
+
export declare function tally(test: WatchedTest): string;
|
|
23
|
+
/**
|
|
24
|
+
* How a run is pointed at this vantage, in the form it goes in.
|
|
25
|
+
*
|
|
26
|
+
* One spelling, said in two places, because the two places are the two moments
|
|
27
|
+
* a reader can act on it: the handshake, before anything has been started, and
|
|
28
|
+
* the empty answer, once something has been started the wrong way. Saying it
|
|
29
|
+
* differently in each would leave a reader comparing two lines to work out
|
|
30
|
+
* whether they are the same instruction.
|
|
31
|
+
*
|
|
32
|
+
* The address is printed verbatim every time. A reader who has to assemble it
|
|
33
|
+
* from a variable name and a port they were told elsewhere is a reader who
|
|
34
|
+
* starts the suite without it.
|
|
35
|
+
*/
|
|
36
|
+
export declare function attaching(state: VantageState): string;
|
|
37
|
+
/**
|
|
38
|
+
* What to do when a vantage has heard nothing.
|
|
39
|
+
*
|
|
40
|
+
* A reader told only "no tests" concludes the run has none, or that the tool is
|
|
41
|
+
* broken, and does not discover that attaching is one environment variable.
|
|
42
|
+
*/
|
|
43
|
+
export declare function unattached(state: VantageState): string;
|
|
44
|
+
//# sourceMappingURL=vantage-lines.d.ts.map
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sentences both live tools share.
|
|
3
|
+
*
|
|
4
|
+
* Its own module for the reason every extracted module here has: the two tools
|
|
5
|
+
* disagreeing about how an announcement is written would make one of them the
|
|
6
|
+
* odd one out in a transcript an agent reads end to end, and the way to stop
|
|
7
|
+
* that is for there to be one spelling rather than a convention.
|
|
8
|
+
*/
|
|
9
|
+
/** One announcement, as a line in a listing. */
|
|
10
|
+
export function announcement(event) {
|
|
11
|
+
const phase = event.phase === 'once' ? '' : ` (${event.phase})`;
|
|
12
|
+
return `${String(event.ordinal).padStart(4)} ${event.realm} ${event.location} / ${event.subject} / ${event.action}${phase}`;
|
|
13
|
+
}
|
|
14
|
+
/** A test in one line, without what it heard. */
|
|
15
|
+
export function heading(test) {
|
|
16
|
+
const parts = [test.title, test.file];
|
|
17
|
+
if (test.project !== undefined)
|
|
18
|
+
parts.push(`project ${test.project}`);
|
|
19
|
+
if (test.worker >= 0)
|
|
20
|
+
parts.push(`worker ${test.worker}`);
|
|
21
|
+
return parts.join(' — ');
|
|
22
|
+
}
|
|
23
|
+
/** How much this test has to say, as a phrase. */
|
|
24
|
+
export function tally(test) {
|
|
25
|
+
const heard = test.forgotten === 0
|
|
26
|
+
? `heard ${test.heard.length}`
|
|
27
|
+
: `heard ${test.heard.length} (+${test.forgotten} forgotten)`;
|
|
28
|
+
return test.pending.length === 0 ? heard : `${heard}, pending ${test.pending.length}`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* How a run is pointed at this vantage, in the form it goes in.
|
|
32
|
+
*
|
|
33
|
+
* One spelling, said in two places, because the two places are the two moments
|
|
34
|
+
* a reader can act on it: the handshake, before anything has been started, and
|
|
35
|
+
* the empty answer, once something has been started the wrong way. Saying it
|
|
36
|
+
* differently in each would leave a reader comparing two lines to work out
|
|
37
|
+
* whether they are the same instruction.
|
|
38
|
+
*
|
|
39
|
+
* The address is printed verbatim every time. A reader who has to assemble it
|
|
40
|
+
* from a variable name and a port they were told elsewhere is a reader who
|
|
41
|
+
* starts the suite without it.
|
|
42
|
+
*/
|
|
43
|
+
export function attaching(state) {
|
|
44
|
+
const address = state.address ?? 'http://127.0.0.1:<port>';
|
|
45
|
+
return [
|
|
46
|
+
'A run reports here when it is started with this in its environment:',
|
|
47
|
+
'',
|
|
48
|
+
` ${VARIABLE}=${address}`,
|
|
49
|
+
'',
|
|
50
|
+
'That is the same env block `VARIANCE_AUTHORITY_EVENTS` goes in. The suite ' +
|
|
51
|
+
'needs `varianceFixtures` from `@variance-authority/playwright-test` and ' +
|
|
52
|
+
'nothing else — a test that takes no screenshot reports exactly what one ' +
|
|
53
|
+
'that does reports, and a run started without the variable pays nothing.',
|
|
54
|
+
].join('\n');
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* What to do when a vantage has heard nothing.
|
|
58
|
+
*
|
|
59
|
+
* A reader told only "no tests" concludes the run has none, or that the tool is
|
|
60
|
+
* broken, and does not discover that attaching is one environment variable.
|
|
61
|
+
*/
|
|
62
|
+
export function unattached(state) {
|
|
63
|
+
return ['Nothing has reported to this vantage yet.', '', attaching(state)].join('\n');
|
|
64
|
+
}
|
|
65
|
+
const VARIABLE = 'VARIANCE_AUTHORITY_VANTAGE';
|
|
66
|
+
//# sourceMappingURL=vantage-lines.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vantage-lines.js","sourceRoot":"","sources":["../../src/tools/vantage-lines.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,gDAAgD;AAChD,MAAM,UAAU,YAAY,CAAC,KAO5B;IACC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,KAAK,GAAG,CAAC;IAChE,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,QAAQ,MAAM,KAAK,CAAC,OAAO,MAAM,KAAK,CAAC,MAAM,GAAG,KAAK,EAAE,CAAC;AAChI,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,OAAO,CAAC,IAAiB;IACvC,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IACtE,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1D,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,KAAK,CAAC,IAAiB;IACrC,MAAM,KAAK,GACT,IAAI,CAAC,SAAS,KAAK,CAAC;QAClB,CAAC,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;QAC9B,CAAC,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,MAAM,MAAM,IAAI,CAAC,SAAS,aAAa,CAAC;IAClE,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,aAAa,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;AACxF,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,SAAS,CAAC,KAAmB;IAC3C,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,IAAI,yBAAyB,CAAC;IAC3D,OAAO;QACL,qEAAqE;QACrE,EAAE;QACF,KAAK,QAAQ,IAAI,OAAO,EAAE;QAC1B,EAAE;QACF,4EAA4E;YAC1E,0EAA0E;YAC1E,0EAA0E;YAC1E,yEAAyE;KAC5E,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,KAAmB;IAC5C,OAAO,CAAC,2CAA2C,EAAE,EAAE,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACxF,CAAC;AAED,MAAM,QAAQ,GAAG,4BAA4B,CAAC","sourcesContent":["/**\n * The sentences both live tools share.\n *\n * Its own module for the reason every extracted module here has: the two tools\n * disagreeing about how an announcement is written would make one of them the\n * odd one out in a transcript an agent reads end to end, and the way to stop\n * that is for there to be one spelling rather than a convention.\n */\n\nimport type { VantageState, WatchedTest } from '@variance-authority/vantage';\n\n/** One announcement, as a line in a listing. */\nexport function announcement(event: {\n readonly realm: string;\n readonly location: string;\n readonly subject: string;\n readonly action: string;\n readonly phase: string;\n readonly ordinal: number;\n}): string {\n const phase = event.phase === 'once' ? '' : ` (${event.phase})`;\n return `${String(event.ordinal).padStart(4)} ${event.realm} ${event.location} / ${event.subject} / ${event.action}${phase}`;\n}\n\n/** A test in one line, without what it heard. */\nexport function heading(test: WatchedTest): string {\n const parts = [test.title, test.file];\n if (test.project !== undefined) parts.push(`project ${test.project}`);\n if (test.worker >= 0) parts.push(`worker ${test.worker}`);\n return parts.join(' — ');\n}\n\n/** How much this test has to say, as a phrase. */\nexport function tally(test: WatchedTest): string {\n const heard =\n test.forgotten === 0\n ? `heard ${test.heard.length}`\n : `heard ${test.heard.length} (+${test.forgotten} forgotten)`;\n return test.pending.length === 0 ? heard : `${heard}, pending ${test.pending.length}`;\n}\n\n/**\n * How a run is pointed at this vantage, in the form it goes in.\n *\n * One spelling, said in two places, because the two places are the two moments\n * a reader can act on it: the handshake, before anything has been started, and\n * the empty answer, once something has been started the wrong way. Saying it\n * differently in each would leave a reader comparing two lines to work out\n * whether they are the same instruction.\n *\n * The address is printed verbatim every time. A reader who has to assemble it\n * from a variable name and a port they were told elsewhere is a reader who\n * starts the suite without it.\n */\nexport function attaching(state: VantageState): string {\n const address = state.address ?? 'http://127.0.0.1:<port>';\n return [\n 'A run reports here when it is started with this in its environment:',\n '',\n ` ${VARIABLE}=${address}`,\n '',\n 'That is the same env block `VARIANCE_AUTHORITY_EVENTS` goes in. The suite ' +\n 'needs `varianceFixtures` from `@variance-authority/playwright-test` and ' +\n 'nothing else — a test that takes no screenshot reports exactly what one ' +\n 'that does reports, and a run started without the variable pays nothing.',\n ].join('\\n');\n}\n\n/**\n * What to do when a vantage has heard nothing.\n *\n * A reader told only \"no tests\" concludes the run has none, or that the tool is\n * broken, and does not discover that attaching is one environment variable.\n */\nexport function unattached(state: VantageState): string {\n return ['Nothing has reported to this vantage yet.', '', attaching(state)].join('\\n');\n}\n\nconst VARIABLE = 'VARIANCE_AUTHORITY_VANTAGE';\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Tool } from './tool.js';
|
|
2
|
+
/**
|
|
3
|
+
* `variance_variations` — subjects that are other subjects on purpose.
|
|
4
|
+
*
|
|
5
|
+
* The third axis, and the smallest. `variance_summary` and everything under it
|
|
6
|
+
* answer *this subject against its baseline*: two revisions, one thing.
|
|
7
|
+
* `variance_composition` answers *these subjects against each other*, at one
|
|
8
|
+
* commit, over what they are built from. This answers a question neither can
|
|
9
|
+
* reach, because it is not a question about a diff at all:
|
|
10
|
+
*
|
|
11
|
+
* > What does the flag actually do?
|
|
12
|
+
*
|
|
13
|
+
* A new arm behind a feature flag, a second viewport, the dark scheme, a backend
|
|
14
|
+
* fixture returning the empty state — each arrives as a new subject, and a new
|
|
15
|
+
* subject is `new`: one baseline written, an empty diff, nothing said. Every run
|
|
16
|
+
* afterwards compares it only to itself, so the difference the arm exists *for*
|
|
17
|
+
* is the one difference nothing in the suite has ever measured.
|
|
18
|
+
*
|
|
19
|
+
* A subject that declares a parent gets it measured. What is reported is the
|
|
20
|
+
* difference between the two, in this run, with no verdict attached — a dark
|
|
21
|
+
* story is darker than its light parent and that is not a regression. What it
|
|
22
|
+
* is, is reviewable: the difference carries a digest that holds still while the
|
|
23
|
+
* two subjects move together, so *the flag changed what it does* becomes a thing
|
|
24
|
+
* a person can see rather than infer.
|
|
25
|
+
*/
|
|
26
|
+
export declare const variations: Tool;
|
|
27
|
+
//# sourceMappingURL=variations.d.ts.map
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `variance_variations` — subjects that are other subjects on purpose.
|
|
3
|
+
*
|
|
4
|
+
* The third axis, and the smallest. `variance_summary` and everything under it
|
|
5
|
+
* answer *this subject against its baseline*: two revisions, one thing.
|
|
6
|
+
* `variance_composition` answers *these subjects against each other*, at one
|
|
7
|
+
* commit, over what they are built from. This answers a question neither can
|
|
8
|
+
* reach, because it is not a question about a diff at all:
|
|
9
|
+
*
|
|
10
|
+
* > What does the flag actually do?
|
|
11
|
+
*
|
|
12
|
+
* A new arm behind a feature flag, a second viewport, the dark scheme, a backend
|
|
13
|
+
* fixture returning the empty state — each arrives as a new subject, and a new
|
|
14
|
+
* subject is `new`: one baseline written, an empty diff, nothing said. Every run
|
|
15
|
+
* afterwards compares it only to itself, so the difference the arm exists *for*
|
|
16
|
+
* is the one difference nothing in the suite has ever measured.
|
|
17
|
+
*
|
|
18
|
+
* A subject that declares a parent gets it measured. What is reported is the
|
|
19
|
+
* difference between the two, in this run, with no verdict attached — a dark
|
|
20
|
+
* story is darker than its light parent and that is not a regression. What it
|
|
21
|
+
* is, is reviewable: the difference carries a digest that holds still while the
|
|
22
|
+
* two subjects move together, so *the flag changed what it does* becomes a thing
|
|
23
|
+
* a person can see rather than infer.
|
|
24
|
+
*/
|
|
25
|
+
export const variations = {
|
|
26
|
+
name: 'variance_variations',
|
|
27
|
+
description: 'Subjects this run measured against another subject rather than against a baseline — a ' +
|
|
28
|
+
'feature flag’s other arm, a second viewport, a dark scheme, a backend fixture — where the ' +
|
|
29
|
+
'subject declared which one it is a variation of. Says what the variation actually changes ' +
|
|
30
|
+
'(which bands, which components) and carries a digest of that difference which stays the ' +
|
|
31
|
+
'same for as long as parent and variation move together. Nothing here is a verdict: a ' +
|
|
32
|
+
'variation is a difference somebody built. Ask this to find out what a flag or a theme does, ' +
|
|
33
|
+
'or when reviewing a change to a subject that has arms.',
|
|
34
|
+
inputSchema: {
|
|
35
|
+
type: 'object',
|
|
36
|
+
properties: {
|
|
37
|
+
subject: {
|
|
38
|
+
type: 'string',
|
|
39
|
+
description: 'Optional. One variation’s entry, instead of every variation in the run.',
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
additionalProperties: false,
|
|
43
|
+
},
|
|
44
|
+
run(report, input) {
|
|
45
|
+
const declared = report.variations;
|
|
46
|
+
if (declared === undefined || declared.length === 0)
|
|
47
|
+
return ABSENT;
|
|
48
|
+
const wanted = typeof input['subject'] === 'string' ? input['subject'] : undefined;
|
|
49
|
+
if (wanted === undefined)
|
|
50
|
+
return whole(declared);
|
|
51
|
+
const entry = declared.find((record) => record.subject === wanted);
|
|
52
|
+
if (entry === undefined)
|
|
53
|
+
return missing(declared, wanted);
|
|
54
|
+
return render(entry);
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* The absence, said as an absence.
|
|
59
|
+
*
|
|
60
|
+
* A run with no variations is the normal run, and it is not evidence that the
|
|
61
|
+
* suite has no arms — it is evidence that no subject said which subject it
|
|
62
|
+
* varies. That distinction is the whole finding here, so the answer names the
|
|
63
|
+
* declaration rather than reporting an empty list.
|
|
64
|
+
*/
|
|
65
|
+
const ABSENT = 'No subject in this run declared itself a variation of another, so nothing was measured on ' +
|
|
66
|
+
'this axis. That is not a claim that the suite has no variants: a feature flag’s second arm, ' +
|
|
67
|
+
'a dark story or a narrow-viewport route are ordinary subjects here, each compared only to its ' +
|
|
68
|
+
'own baseline, and the difference between an arm and what it varies is measured only where a ' +
|
|
69
|
+
'subject carries a `variance-parent:<id>` tag naming the subject it varies.';
|
|
70
|
+
/**
|
|
71
|
+
* Everything, with the ones somebody wrote down first.
|
|
72
|
+
*
|
|
73
|
+
* The split is not cosmetic. A tag is a statement about two subjects; a name is
|
|
74
|
+
* a convention being read back, and a suite that names its variants gets many of
|
|
75
|
+
* those at once. Printing them interleaved would make the weakest entries the
|
|
76
|
+
* bulk of the answer and put them alongside the strongest with nothing marking
|
|
77
|
+
* the difference.
|
|
78
|
+
*/
|
|
79
|
+
function whole(records) {
|
|
80
|
+
const measured = records.filter((record) => record.digest !== undefined);
|
|
81
|
+
const unmeasured = records.filter((record) => record.digest === undefined);
|
|
82
|
+
const identical = measured.filter((record) => record.identical === true);
|
|
83
|
+
const stated = records.filter((record) => record.how !== 'named');
|
|
84
|
+
const named = records.filter((record) => record.how === 'named');
|
|
85
|
+
return [
|
|
86
|
+
`${records.length} variation(s) — ${measured.length} measured` +
|
|
87
|
+
(identical.length === 0 ? '' : `, ${identical.length} of them identical to their parent`) +
|
|
88
|
+
(unmeasured.length === 0 ? '' : `, ${unmeasured.length} not compared`) +
|
|
89
|
+
`; ${stated.length} declared with a tag, ${named.length} read off the names`,
|
|
90
|
+
...(stated.length === 0 ? [] : ['', 'declared', '', ...stated.map(render)]),
|
|
91
|
+
...(named.length === 0
|
|
92
|
+
? []
|
|
93
|
+
: [
|
|
94
|
+
'',
|
|
95
|
+
'named — nobody declared these pairs; each subject’s id extends its parent’s id, so ' +
|
|
96
|
+
'the link is only as good as the naming convention',
|
|
97
|
+
'',
|
|
98
|
+
...named.map(render),
|
|
99
|
+
]),
|
|
100
|
+
].join('\n');
|
|
101
|
+
}
|
|
102
|
+
function render(record) {
|
|
103
|
+
const head = record.parent === undefined
|
|
104
|
+
? record.subject
|
|
105
|
+
: `${record.subject} ← ${record.parent}${bands(record.bands)}`;
|
|
106
|
+
return [
|
|
107
|
+
head,
|
|
108
|
+
` ${record.because}`,
|
|
109
|
+
...(record.components === undefined
|
|
110
|
+
? []
|
|
111
|
+
: [` components: ${record.components.join(', ')}`]),
|
|
112
|
+
...(record.unobserved === undefined
|
|
113
|
+
? []
|
|
114
|
+
: [` unobserved here: ${record.unobserved.join(', ')}`]),
|
|
115
|
+
].join('\n');
|
|
116
|
+
}
|
|
117
|
+
function missing(declared, wanted) {
|
|
118
|
+
return (`\`${wanted}\` declared no parent in this run, so there is no variation to describe. Every ` +
|
|
119
|
+
`subject that did: ${declared.map((record) => record.subject).join(', ')}`);
|
|
120
|
+
}
|
|
121
|
+
/** Empty means the two are alike everywhere observed, never *no band*. */
|
|
122
|
+
function bands(bands) {
|
|
123
|
+
return bands === undefined || bands.length === 0 ? '' : ` (${bands.join(', ')})`;
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=variations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"variations.js","sourceRoot":"","sources":["../../src/tools/variations.ts"],"names":[],"mappings":"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","sourcesContent":["import type { VariationRecord } from '@variance-authority/report';\nimport type { Tool } from './tool.js';\n\n/**\n * `variance_variations` — subjects that are other subjects on purpose.\n *\n * The third axis, and the smallest. `variance_summary` and everything under it\n * answer *this subject against its baseline*: two revisions, one thing.\n * `variance_composition` answers *these subjects against each other*, at one\n * commit, over what they are built from. This answers a question neither can\n * reach, because it is not a question about a diff at all:\n *\n * > What does the flag actually do?\n *\n * A new arm behind a feature flag, a second viewport, the dark scheme, a backend\n * fixture returning the empty state — each arrives as a new subject, and a new\n * subject is `new`: one baseline written, an empty diff, nothing said. Every run\n * afterwards compares it only to itself, so the difference the arm exists *for*\n * is the one difference nothing in the suite has ever measured.\n *\n * A subject that declares a parent gets it measured. What is reported is the\n * difference between the two, in this run, with no verdict attached — a dark\n * story is darker than its light parent and that is not a regression. What it\n * is, is reviewable: the difference carries a digest that holds still while the\n * two subjects move together, so *the flag changed what it does* becomes a thing\n * a person can see rather than infer.\n */\n\nexport const variations: Tool = {\n name: 'variance_variations',\n description:\n 'Subjects this run measured against another subject rather than against a baseline — a ' +\n 'feature flag’s other arm, a second viewport, a dark scheme, a backend fixture — where the ' +\n 'subject declared which one it is a variation of. Says what the variation actually changes ' +\n '(which bands, which components) and carries a digest of that difference which stays the ' +\n 'same for as long as parent and variation move together. Nothing here is a verdict: a ' +\n 'variation is a difference somebody built. Ask this to find out what a flag or a theme does, ' +\n 'or when reviewing a change to a subject that has arms.',\n inputSchema: {\n type: 'object',\n properties: {\n subject: {\n type: 'string',\n description: 'Optional. One variation’s entry, instead of every variation in the run.',\n },\n },\n additionalProperties: false,\n },\n\n run(report, input) {\n const declared = report.variations;\n if (declared === undefined || declared.length === 0) return ABSENT;\n\n const wanted = typeof input['subject'] === 'string' ? input['subject'] : undefined;\n if (wanted === undefined) return whole(declared);\n\n const entry = declared.find((record) => record.subject === wanted);\n if (entry === undefined) return missing(declared, wanted);\n return render(entry);\n },\n};\n\n/**\n * The absence, said as an absence.\n *\n * A run with no variations is the normal run, and it is not evidence that the\n * suite has no arms — it is evidence that no subject said which subject it\n * varies. That distinction is the whole finding here, so the answer names the\n * declaration rather than reporting an empty list.\n */\nconst ABSENT =\n 'No subject in this run declared itself a variation of another, so nothing was measured on ' +\n 'this axis. That is not a claim that the suite has no variants: a feature flag’s second arm, ' +\n 'a dark story or a narrow-viewport route are ordinary subjects here, each compared only to its ' +\n 'own baseline, and the difference between an arm and what it varies is measured only where a ' +\n 'subject carries a `variance-parent:<id>` tag naming the subject it varies.';\n\n/**\n * Everything, with the ones somebody wrote down first.\n *\n * The split is not cosmetic. A tag is a statement about two subjects; a name is\n * a convention being read back, and a suite that names its variants gets many of\n * those at once. Printing them interleaved would make the weakest entries the\n * bulk of the answer and put them alongside the strongest with nothing marking\n * the difference.\n */\nfunction whole(records: readonly VariationRecord[]): string {\n const measured = records.filter((record) => record.digest !== undefined);\n const unmeasured = records.filter((record) => record.digest === undefined);\n const identical = measured.filter((record) => record.identical === true);\n const stated = records.filter((record) => record.how !== 'named');\n const named = records.filter((record) => record.how === 'named');\n\n return [\n `${records.length} variation(s) — ${measured.length} measured` +\n (identical.length === 0 ? '' : `, ${identical.length} of them identical to their parent`) +\n (unmeasured.length === 0 ? '' : `, ${unmeasured.length} not compared`) +\n `; ${stated.length} declared with a tag, ${named.length} read off the names`,\n ...(stated.length === 0 ? [] : ['', 'declared', '', ...stated.map(render)]),\n ...(named.length === 0\n ? []\n : [\n '',\n 'named — nobody declared these pairs; each subject’s id extends its parent’s id, so ' +\n 'the link is only as good as the naming convention',\n '',\n ...named.map(render),\n ]),\n ].join('\\n');\n}\n\nfunction render(record: VariationRecord): string {\n const head =\n record.parent === undefined\n ? record.subject\n : `${record.subject} ← ${record.parent}${bands(record.bands)}`;\n\n return [\n head,\n ` ${record.because}`,\n ...(record.components === undefined\n ? []\n : [` components: ${record.components.join(', ')}`]),\n ...(record.unobserved === undefined\n ? []\n : [` unobserved here: ${record.unobserved.join(', ')}`]),\n ].join('\\n');\n}\n\nfunction missing(declared: readonly VariationRecord[], wanted: string): string {\n return (\n `\\`${wanted}\\` declared no parent in this run, so there is no variation to describe. Every ` +\n `subject that did: ${declared.map((record) => record.subject).join(', ')}`\n );\n}\n\n/** Empty means the two are alike everywhere observed, never *no band*. */\nfunction bands(bands: readonly string[] | undefined): string {\n return bands === undefined || bands.length === 0 ? '' : ` (${bands.join(', ')})`;\n}\n"]}
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { EyesArchive } from '@variance-authority/eyes';
|
|
2
|
+
import type { PresentationReport } from '@variance-authority/presentation';
|
|
3
|
+
import type { ExecutionIndex } from '@variance-authority/sense/test-selection';
|
|
4
|
+
import type { VantageState } from '@variance-authority/vantage';
|
|
5
|
+
import type { ObservabilitySubject } from './observability-subject.js';
|
|
6
|
+
import { diffState, type StateDifference } from './tools/diff.js';
|
|
7
|
+
import { type PresentationEvidence } from './tools/presentations.js';
|
|
8
|
+
import { type ScenarioEvidence } from './tools/scenarios.js';
|
|
9
|
+
import { NO_ARGS, stringArg, type Tool } from './tools/tool.js';
|
|
10
|
+
/**
|
|
11
|
+
* The tools, as pure functions over a run report.
|
|
12
|
+
*
|
|
13
|
+
* Separated from the transport deliberately. A tool implementation tangled into
|
|
14
|
+
* a JSON-RPC handler can only be exercised by speaking JSON-RPC at it, and the
|
|
15
|
+
* interesting question — *does this answer help an agent fix the thing?* — then
|
|
16
|
+
* becomes the hardest thing in the package to ask.
|
|
17
|
+
*
|
|
18
|
+
* Every answer is text, and the shape of that text is the product. An agent does
|
|
19
|
+
* not benefit from a JSON blob it has to interpret; it benefits from the same
|
|
20
|
+
* sentence a person would want, with a file path on the end. So these read like
|
|
21
|
+
* the report does: cause first, collateral counted, and a path an editor opens.
|
|
22
|
+
*
|
|
23
|
+
* `variance_adjudicate` is the one tool that takes evidence *in*. It follows
|
|
24
|
+
* `summary` and `changes` because it needs nothing they printed and everything
|
|
25
|
+
* they cannot supply: an agent's own account of what it was doing. The other report tools
|
|
26
|
+
* answer *what changed*; this one answers *what changed against what you claimed*, and
|
|
27
|
+
* its third arm — declared, and did not happen — is the only thing here that can
|
|
28
|
+
* catch an edit which never landed. An agent that has just edited something
|
|
29
|
+
* should call it before `describe`, and an agent reviewing somebody else's run
|
|
30
|
+
* has nothing to declare and should skip it.
|
|
31
|
+
*
|
|
32
|
+
* One tool per module under `./tools/`, and this file is the list. Each answer is
|
|
33
|
+
* a paragraph somebody argued about, and the arguments do not compose — the
|
|
34
|
+
* reason the summary refuses to say "nothing to review" has nothing to do with
|
|
35
|
+
* the reason findings are grouped by rule — so they are read, and edited, one at
|
|
36
|
+
* a time. What stays here is the only thing that is genuinely about the set:
|
|
37
|
+
* the order, which is the order `tools/list` announces them in and therefore the
|
|
38
|
+
* order an agent meets them in. `variance_summary` is first because every report
|
|
39
|
+
* tool takes an argument it printed. `variance_diff` sits beside it as the session
|
|
40
|
+
* question, and `variance_changes` follows because it
|
|
41
|
+
* is the one that decides how many of the rest get called: an agent that walks
|
|
42
|
+
* forty changed subjects one at a time spends forty calls learning what one call
|
|
43
|
+
* says, which is *three things happened and one of them explains thirty-one*.
|
|
44
|
+
*
|
|
45
|
+
* `variance_composition` follows `adjudicate`, and the boundary it sits on is
|
|
46
|
+
* the one worth seeing: the first seven answer about the *suite* and the last four narrow to a
|
|
47
|
+
* subject. It goes after `changes` rather than before because the two reshape
|
|
48
|
+
* the same run along different axes and only one of them is about this run's
|
|
49
|
+
* diff — `changes` says which decisions there are, and this says which component
|
|
50
|
+
* and which caller is behind one, including when the answer is *nothing in this
|
|
51
|
+
* run*.
|
|
52
|
+
*
|
|
53
|
+
* `variance_variations` follows it, on the same axis and one step further out. Both
|
|
54
|
+
* compare this run to itself; `composition` compares subjects that were never
|
|
55
|
+
* meant to differ, and this compares the ones that were. It is the only tool here
|
|
56
|
+
* whose answer is not, in any reading, a finding — which is why it is neither
|
|
57
|
+
* earlier (an agent triaging a visual diff would spend a call learning that a dark story
|
|
58
|
+
* is dark) nor omitted (when a change *is* to a flagged component, what the flag
|
|
59
|
+
* does is the first thing the reviewer does not know).
|
|
60
|
+
*
|
|
61
|
+
* `variance_changelog` closes the suite-level group because it is the only tool
|
|
62
|
+
* here that is not about the run. The other report tools describe what a run observed;
|
|
63
|
+
* this one describes what *accepting* it would write down, and that answer is
|
|
64
|
+
* the last thing an agent needs before it proposes a command. Its position is
|
|
65
|
+
* also a claim about when it stops being useful: after acceptance there is
|
|
66
|
+
* nothing to preview, because the record exists and `git log` has it.
|
|
67
|
+
*
|
|
68
|
+
* It is the second tool whose answer changes with the agent's own input, and
|
|
69
|
+
* unlike `adjudicate` the input is not evidence — it is the selection, the same
|
|
70
|
+
* one `accept` takes. That is why it must not be earlier: an agent that has not
|
|
71
|
+
* yet read `changes` has no shape to ask about, and would be told what `--all`
|
|
72
|
+
* records before knowing whether `--all` is what it wants.
|
|
73
|
+
*/
|
|
74
|
+
export type { Served, Tool, ToolInvocation } from './tools/tool.js';
|
|
75
|
+
export type { StateDifference };
|
|
76
|
+
export { NO_ARGS, stringArg };
|
|
77
|
+
export { notObservedSentence } from './tools/subject.js';
|
|
78
|
+
export { diffState };
|
|
79
|
+
/** The source-to-named-test tool set for an MCP server over an execution index. */
|
|
80
|
+
export declare const SOURCE_TEST_TOOLS: readonly [Tool<ExecutionIndex>, Tool<ExecutionIndex>];
|
|
81
|
+
/** Look up one source-test tool without widening it to the visual-report subject. */
|
|
82
|
+
export declare function sourceTestToolByName(name: string): Tool<ExecutionIndex> | undefined;
|
|
83
|
+
/**
|
|
84
|
+
* The tool set for a watcher attached to a suite that is still running.
|
|
85
|
+
*
|
|
86
|
+
* A third subject, and the first one that is not a thing somebody produced. The
|
|
87
|
+
* report tools answer about a run that finished and the source-test tools answer
|
|
88
|
+
* about an index that was written; these answer about a run *in flight*, held in
|
|
89
|
+
* the memory of the process answering, and gone when it exits.
|
|
90
|
+
*
|
|
91
|
+
* The listing comes first for the same reason `variance_summary` does: the other
|
|
92
|
+
* two take an argument it printed. `variance_diff` is last here rather than
|
|
93
|
+
* second, because on a live subject it is not the session question but the
|
|
94
|
+
* *progress* question — what the suite did between two asks — and that is only
|
|
95
|
+
* worth asking once a reader knows what they are watching.
|
|
96
|
+
*/
|
|
97
|
+
export declare const VANTAGE_TOOLS: readonly [Tool<VantageState>, Tool<VantageState>, Tool<VantageState>];
|
|
98
|
+
/** Look up one live-run tool without widening it to the visual-report subject. */
|
|
99
|
+
export declare function vantageToolByName(name: string): Tool<VantageState> | undefined;
|
|
100
|
+
export declare const TOOLS: readonly Tool[];
|
|
101
|
+
export declare function toolByName(name: string): Tool | undefined;
|
|
102
|
+
/** Full presentation graphs supplied by the caller, independent of report projections. */
|
|
103
|
+
export declare const PRESENTATION_TOOLS: readonly [Tool<PresentationEvidence>, Tool<PresentationEvidence>];
|
|
104
|
+
export declare function presentationToolByName(name: string): Tool<readonly PresentationReport[]> | undefined;
|
|
105
|
+
/** Test attention captured synchronously while DOM nodes still have attribution. */
|
|
106
|
+
export declare const EYES_TOOLS: readonly [Tool<EyesArchive>, Tool<EyesArchive>];
|
|
107
|
+
export declare function eyesToolByName(name: string): Tool<EyesArchive> | undefined;
|
|
108
|
+
/** Retained scenario executions, including witnessed Arrange state and Act outcomes. */
|
|
109
|
+
export declare const SCENARIO_TOOLS: readonly [Tool<ScenarioEvidence>, Tool<ScenarioEvidence>];
|
|
110
|
+
export declare function scenarioToolByName(name: string): Tool<ScenarioEvidence> | undefined;
|
|
111
|
+
/**
|
|
112
|
+
* Every independently supplied observability domain behind one MCP connection.
|
|
113
|
+
*
|
|
114
|
+
* Native tools are lifted without changing their answers. A missing field is a
|
|
115
|
+
* tool error, not an empty subject, and previous invocation state is projected
|
|
116
|
+
* through the same field before a native diff sees it.
|
|
117
|
+
*/
|
|
118
|
+
export declare const OBSERVABILITY_TOOLS: readonly Tool<ObservabilitySubject>[];
|
|
119
|
+
export declare function observabilityToolByName(name: string): Tool<ObservabilitySubject> | undefined;
|
|
120
|
+
//# sourceMappingURL=tools.d.ts.map
|