common-qa-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/LICENSE +21 -0
- package/README.md +96 -0
- package/dist/adapters/factory.d.ts +15 -0
- package/dist/adapters/factory.d.ts.map +1 -0
- package/dist/adapters/factory.js +18 -0
- package/dist/adapters/factory.js.map +1 -0
- package/dist/adapters/remoteMcp/adapter.d.ts +92 -0
- package/dist/adapters/remoteMcp/adapter.d.ts.map +1 -0
- package/dist/adapters/remoteMcp/adapter.js +219 -0
- package/dist/adapters/remoteMcp/adapter.js.map +1 -0
- package/dist/adapters/types.d.ts +77 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +2 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/adapters/walnut/actionTypes.d.ts +16 -0
- package/dist/adapters/walnut/actionTypes.d.ts.map +1 -0
- package/dist/adapters/walnut/actionTypes.js +141 -0
- package/dist/adapters/walnut/actionTypes.js.map +1 -0
- package/dist/adapters/walnut/mapper.d.ts +34 -0
- package/dist/adapters/walnut/mapper.d.ts.map +1 -0
- package/dist/adapters/walnut/mapper.js +228 -0
- package/dist/adapters/walnut/mapper.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +36 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +81 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +211 -0
- package/dist/config.js.map +1 -0
- package/dist/connection.d.ts +101 -0
- package/dist/connection.d.ts.map +1 -0
- package/dist/connection.js +190 -0
- package/dist/connection.js.map +1 -0
- package/dist/domain/types.d.ts +279 -0
- package/dist/domain/types.d.ts.map +1 -0
- package/dist/domain/types.js +2 -0
- package/dist/domain/types.js.map +1 -0
- package/dist/domain/validate.d.ts +3 -0
- package/dist/domain/validate.d.ts.map +1 -0
- package/dist/domain/validate.js +29 -0
- package/dist/domain/validate.js.map +1 -0
- package/dist/drafts/store.d.ts +62 -0
- package/dist/drafts/store.d.ts.map +1 -0
- package/dist/drafts/store.js +119 -0
- package/dist/drafts/store.js.map +1 -0
- package/dist/httpMain.d.ts +3 -0
- package/dist/httpMain.d.ts.map +1 -0
- package/dist/httpMain.js +22 -0
- package/dist/httpMain.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/initAgents.d.ts +2 -0
- package/dist/initAgents.d.ts.map +1 -0
- package/dist/initAgents.js +178 -0
- package/dist/initAgents.js.map +1 -0
- package/dist/log.d.ts +14 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +14 -0
- package/dist/log.js.map +1 -0
- package/dist/mcpResult.d.ts +20 -0
- package/dist/mcpResult.d.ts.map +1 -0
- package/dist/mcpResult.js +8 -0
- package/dist/mcpResult.js.map +1 -0
- package/dist/mount.d.ts +12 -0
- package/dist/mount.d.ts.map +1 -0
- package/dist/mount.js +126 -0
- package/dist/mount.js.map +1 -0
- package/dist/projectStore.d.ts +5 -0
- package/dist/projectStore.d.ts.map +1 -0
- package/dist/projectStore.js +60 -0
- package/dist/projectStore.js.map +1 -0
- package/dist/requestConnection.d.ts +20 -0
- package/dist/requestConnection.d.ts.map +1 -0
- package/dist/requestConnection.js +44 -0
- package/dist/requestConnection.js.map +1 -0
- package/dist/serve.d.ts +10 -0
- package/dist/serve.d.ts.map +1 -0
- package/dist/serve.js +37 -0
- package/dist/serve.js.map +1 -0
- package/dist/server.d.ts +29 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +76 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/connection.tools.d.ts +16 -0
- package/dist/tools/connection.tools.d.ts.map +1 -0
- package/dist/tools/connection.tools.js +106 -0
- package/dist/tools/connection.tools.js.map +1 -0
- package/dist/tools/discovery.tools.d.ts +16 -0
- package/dist/tools/discovery.tools.d.ts.map +1 -0
- package/dist/tools/discovery.tools.js +369 -0
- package/dist/tools/discovery.tools.js.map +1 -0
- package/dist/tools/markdown.d.ts +13 -0
- package/dist/tools/markdown.d.ts.map +1 -0
- package/dist/tools/markdown.js +65 -0
- package/dist/tools/markdown.js.map +1 -0
- package/dist/tools/recording.tools.d.ts +16 -0
- package/dist/tools/recording.tools.d.ts.map +1 -0
- package/dist/tools/recording.tools.js +378 -0
- package/dist/tools/recording.tools.js.map +1 -0
- package/dist/tools/run.tools.d.ts +13 -0
- package/dist/tools/run.tools.d.ts.map +1 -0
- package/dist/tools/run.tools.js +230 -0
- package/dist/tools/run.tools.js.map +1 -0
- package/dist/tools/schemas.d.ts +560 -0
- package/dist/tools/schemas.d.ts.map +1 -0
- package/dist/tools/schemas.js +112 -0
- package/dist/tools/schemas.js.map +1 -0
- package/dist/tools/testcase.tools.d.ts +50 -0
- package/dist/tools/testcase.tools.d.ts.map +1 -0
- package/dist/tools/testcase.tools.js +384 -0
- package/dist/tools/testcase.tools.js.map +1 -0
- package/dist/vendor/actionSignatures.d.ts +117 -0
- package/dist/vendor/actionSignatures.d.ts.map +1 -0
- package/dist/vendor/actionSignatures.js +420 -0
- package/dist/vendor/actionSignatures.js.map +1 -0
- package/dist/vendor/logger.d.ts +38 -0
- package/dist/vendor/logger.d.ts.map +1 -0
- package/dist/vendor/logger.js +174 -0
- package/dist/vendor/logger.js.map +1 -0
- package/package.json +57 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Simplify3x
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Common QA MCP
|
|
2
|
+
|
|
3
|
+
One **product-neutral MCP** that AI clients (Claude Code, Cursor, Windsurf, …) connect to with a
|
|
4
|
+
single URL + token, and which **routes** test-case-lifecycle requests to the right product:
|
|
5
|
+
|
|
6
|
+
- **Walnut** — directly over its REST API (`WalnutAdapter`).
|
|
7
|
+
- **SimplifyQA** — over the SimplifyQA agent's own MCP (`SimplifyQaAdapter`, an MCP client).
|
|
8
|
+
|
|
9
|
+
The client sees **one tool vocabulary** and **one neutral data model** regardless of product.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
AI client ──MCP (url + token)──▶ COMMON QA MCP ──▶ Walnut backend (REST)
|
|
13
|
+
└────────▶ SimplifyQA agent MCP ──▶ SQA backend
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## What's here
|
|
17
|
+
This repo is the **standalone gateway** build of the neutral core: the API lifecycle surface —
|
|
18
|
+
connection, projects, discovery, drafts, validation and save-orchestration. Files under `src/`:
|
|
19
|
+
|
|
20
|
+
- `adapters/` — the `ProviderAdapter` contract + `walnut/` (REST) and `simplifyqa/` (remote MCP) drivers, and the adapter factory.
|
|
21
|
+
- `connection.ts` / `requestConnection.ts` — the runtime connection (URL + token, in-memory, validate-before-adopt) and the header/URL-based config connection.
|
|
22
|
+
- `domain/` — the neutral data model + validation.
|
|
23
|
+
- `drafts/` — the edit-before-save draft store.
|
|
24
|
+
- `tools/` — the client-facing tools: `connection.tools` (qa_connect / qa_switch_project / …), `discovery.tools` (list_projects / tc_list / tc_get), `testcase.tools` (tc_draft_*), plus `markdown` / `schemas`.
|
|
25
|
+
- `server.ts` — assembles the MCP (`buildServer`).
|
|
26
|
+
- `mount.ts` / `httpMain.ts` — the standalone Streamable-HTTP `/mcp` gateway + its entrypoint.
|
|
27
|
+
- `vendor/` — three self-contained files vendored from the Walnut agent (`logger`, `actionSignatures`, `bridge`).
|
|
28
|
+
|
|
29
|
+
> **Not here:** browser recording + the live editor. Those need a real browser/Electron window, so
|
|
30
|
+
> they stay in the **Walnut agent**, which mounts this same core with those extra deps injected.
|
|
31
|
+
|
|
32
|
+
## Install
|
|
33
|
+
Nothing to install — AI clients launch it over stdio with `npx`. Requires Node >= 20.
|
|
34
|
+
|
|
35
|
+
`.mcp.json` (Claude Code, Cursor, Windsurf, …):
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"mcpServers": {
|
|
39
|
+
"common-qa": {
|
|
40
|
+
"command": "npx",
|
|
41
|
+
"args": ["-y", "common-qa-mcp"],
|
|
42
|
+
"env": {
|
|
43
|
+
"QA_MCP_URL": "http://localhost:8080",
|
|
44
|
+
"QA_MCP_TOKEN": "<token>",
|
|
45
|
+
"QA_MCP_PROJECT_ID": "<projectId>"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
With no `QA_MCP_*` set it starts in **offline** mode — draft authoring only, zero network — and you
|
|
52
|
+
can connect from chat with `qa_connect`.
|
|
53
|
+
|
|
54
|
+
Install the Walnut QA agent (persona + tool guidance) into your project:
|
|
55
|
+
```bash
|
|
56
|
+
npx common-qa-mcp init-agents --loop=claude # claude | cursor | windsurf | vscode | codex | all
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Develop
|
|
60
|
+
```bash
|
|
61
|
+
npm install
|
|
62
|
+
npm run build # tsc -> dist/
|
|
63
|
+
npm start # stdio server from dist/ (what npx runs)
|
|
64
|
+
npm run dev # same, via tsx, no build step
|
|
65
|
+
npm run start:http # HTTP gateway on http://127.0.0.1:4060/mcp (override with PORT=)
|
|
66
|
+
npm run dev:http # HTTP gateway via tsx watch
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Connect an AI client over HTTP (config-based, no chat)
|
|
70
|
+
`.mcp.json`:
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"mcpServers": {
|
|
74
|
+
"common-qa": {
|
|
75
|
+
"type": "http",
|
|
76
|
+
"url": "http://127.0.0.1:4060/mcp",
|
|
77
|
+
"headers": {
|
|
78
|
+
"Authorization": "Bearer <token>",
|
|
79
|
+
"x-qa-product": "walnut",
|
|
80
|
+
"x-qa-url": "http://localhost:8080",
|
|
81
|
+
"x-project-id": "<projectId>"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
Switch `x-qa-product` to `simplifyqa` and point `x-qa-url` at the SimplifyQA agent's `/mcp` to route
|
|
88
|
+
there instead. Everything after `Authorization` may also be passed as `?query` params, and falls
|
|
89
|
+
back to the `QA_MCP_*` environment. At runtime, `qa_connect` / `qa_switch_project` override the
|
|
90
|
+
connection without re-entering credentials.
|
|
91
|
+
|
|
92
|
+
## SimplifyQA integration
|
|
93
|
+
The SimplifyQA agent implements its own MCP exposing the provider-operation tools this gateway calls
|
|
94
|
+
(`info`, `list_projects`, `list_testcases`, `get_testcase`, `create_testcase`, `update_testcase`,
|
|
95
|
+
`start_run`, `get_run`, `stop_run`, …) returning the neutral shapes. See the integration guide for
|
|
96
|
+
the full contract.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ProviderAdapter } from './types.js';
|
|
2
|
+
import type { QaConfig } from '../config.js';
|
|
3
|
+
/**
|
|
4
|
+
* Builds the adapter for the current connection.
|
|
5
|
+
*
|
|
6
|
+
* In the Common QA MCP, BOTH products are reached the SAME way: a remote MCP hop to that product's
|
|
7
|
+
* agent MCP (`config.url` = its `/mcp` endpoint), forwarding the neutral provider-op calls. So there
|
|
8
|
+
* is a single driver -- `RemoteMcpAdapter` -- regardless of `provider`; the product is just a label
|
|
9
|
+
* for routing/logging. The Common MCP no longer talks any product's REST directly (the Walnut REST
|
|
10
|
+
* logic now lives in the Walnut MCP / walnut-agent, exactly like SQA's lives in the SQA MCP).
|
|
11
|
+
*
|
|
12
|
+
* Offline mode (no credentials) builds nothing -- draft authoring needs no backend.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createAdapter(config: QaConfig): ProviderAdapter | null;
|
|
15
|
+
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/adapters/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAG7C;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,GAAG,eAAe,GAAG,IAAI,CAGtE"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { RemoteMcpAdapter } from './remoteMcp/adapter.js';
|
|
2
|
+
/**
|
|
3
|
+
* Builds the adapter for the current connection.
|
|
4
|
+
*
|
|
5
|
+
* In the Common QA MCP, BOTH products are reached the SAME way: a remote MCP hop to that product's
|
|
6
|
+
* agent MCP (`config.url` = its `/mcp` endpoint), forwarding the neutral provider-op calls. So there
|
|
7
|
+
* is a single driver -- `RemoteMcpAdapter` -- regardless of `provider`; the product is just a label
|
|
8
|
+
* for routing/logging. The Common MCP no longer talks any product's REST directly (the Walnut REST
|
|
9
|
+
* logic now lives in the Walnut MCP / walnut-agent, exactly like SQA's lives in the SQA MCP).
|
|
10
|
+
*
|
|
11
|
+
* Offline mode (no credentials) builds nothing -- draft authoring needs no backend.
|
|
12
|
+
*/
|
|
13
|
+
export function createAdapter(config) {
|
|
14
|
+
if (config.mode !== 'connected')
|
|
15
|
+
return null;
|
|
16
|
+
return new RemoteMcpAdapter(config);
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/adapters/factory.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAAC,MAAgB;IAC5C,IAAI,MAAM,CAAC,IAAI,KAAK,WAAW;QAAE,OAAO,IAAI,CAAC;IAC7C,OAAO,IAAI,gBAAgB,CAAC,MAAM,CAAC,CAAC;AACtC,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
|
|
2
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import type { ConnectedQaConfig } from '../../config.js';
|
|
4
|
+
import type { ProjectInfo, ProviderAdapter } from '../types.js';
|
|
5
|
+
import type { ActionDef, CloudRunner, DatasetInfo, EntityRef, EnvInfo, JournalOp, JournalView, MemberOp, ObjectQuery, ProjectSummary, QaObject, RunOptions, RunRef, RunStatus, RunTarget, SavedRef, Story, StoryQuery, StorySummary, Suite, SuiteSummary, TcQuery, TcSummary, TestCase } from '../../domain/types.js';
|
|
6
|
+
/**
|
|
7
|
+
* RemoteMcpAdapter -- the generic "forward to a product MCP" driver of the Common QA MCP.
|
|
8
|
+
*
|
|
9
|
+
* BOTH products are reached the same way: a thin MCP CLIENT holds a connection to the product's
|
|
10
|
+
* agent MCP (`cfg.url` = that product's `/mcp` endpoint) and fulfils each neutral ProviderAdapter
|
|
11
|
+
* method by calling the correspondingly-named PROVIDER-OP tool on it (info -> `info`, listTestCases
|
|
12
|
+
* -> `list_testcases`, ...), reading the neutral payload out of `structuredContent[<key>]`. This is
|
|
13
|
+
* the provider-op contract in docs/sqa-agent-mcp-integration-guide.md -- the SAME for the Walnut MCP
|
|
14
|
+
* and the product MCP, so the Common MCP forwards to both identically.
|
|
15
|
+
*
|
|
16
|
+
* The bearer token (+ x-project-id) is forwarded to the product MCP on every request. The client
|
|
17
|
+
* connects lazily on first use (and re-arms on failure), so constructing the adapter is cheap.
|
|
18
|
+
*/
|
|
19
|
+
export type RemoteTransportFactory = () => Transport;
|
|
20
|
+
export declare class RemoteMcpAdapter implements ProviderAdapter {
|
|
21
|
+
private readonly cfg;
|
|
22
|
+
/** Test seam: inject a pre-linked in-memory transport instead of a real HTTP one. */
|
|
23
|
+
private readonly transportFactory?;
|
|
24
|
+
private clientPromise;
|
|
25
|
+
constructor(cfg: ConnectedQaConfig,
|
|
26
|
+
/** Test seam: inject a pre-linked in-memory transport instead of a real HTTP one. */
|
|
27
|
+
transportFactory?: RemoteTransportFactory | undefined);
|
|
28
|
+
private headers;
|
|
29
|
+
private client;
|
|
30
|
+
/**
|
|
31
|
+
* callTool with transparent ONE-shot reconnect on a stale session. If the product MCP was
|
|
32
|
+
* restarted, our cached client holds a dead session id and the first call throws "Session not
|
|
33
|
+
* found"; we drop the client so `client()` re-connects fresh, then retry exactly once. Any other
|
|
34
|
+
* error (or a second failure) propagates. Without this, every call after a product restart failed
|
|
35
|
+
* until THIS process was restarted too.
|
|
36
|
+
*/
|
|
37
|
+
private callTool;
|
|
38
|
+
/** Project-scoped provider-ops need a selected project. `list_projects` is the ONE exception (it
|
|
39
|
+
* lists ACROSS projects, so it must work with none selected). Guarding here turns an opaque backend
|
|
40
|
+
* 400 ("Project ID and User ID are required") into a clear instruction so the AI client asks the
|
|
41
|
+
* user to pick a project first. */
|
|
42
|
+
private assertProject;
|
|
43
|
+
/** Call a remote provider-op tool and pull the neutral payload from structuredContent[key]. */
|
|
44
|
+
private call;
|
|
45
|
+
/** For void ops (delete/stop): only surface an error, ignore any payload. */
|
|
46
|
+
private callVoid;
|
|
47
|
+
info(): Promise<ProjectInfo>;
|
|
48
|
+
listProjects(): Promise<ProjectSummary[]>;
|
|
49
|
+
listTestCases(q: TcQuery): Promise<TcSummary[]>;
|
|
50
|
+
getTestCase(id: string): Promise<TestCase>;
|
|
51
|
+
createTestCase(tc: TestCase): Promise<SavedRef>;
|
|
52
|
+
updateTestCase(id: string, tc: TestCase): Promise<SavedRef>;
|
|
53
|
+
deleteTestCase(id: string): Promise<void>;
|
|
54
|
+
cloneTestCase(id: string, title?: string): Promise<SavedRef>;
|
|
55
|
+
searchObjects(q: ObjectQuery): Promise<QaObject[]>;
|
|
56
|
+
createObject(o: QaObject): Promise<QaObject>;
|
|
57
|
+
actionsCatalog(platform?: string): Promise<ActionDef[]>;
|
|
58
|
+
listSuites(): Promise<SuiteSummary[]>;
|
|
59
|
+
getSuite(id: string): Promise<Suite>;
|
|
60
|
+
listStories(q: StoryQuery): Promise<StorySummary[]>;
|
|
61
|
+
getStory(id: string): Promise<Story>;
|
|
62
|
+
readJournal(tcId: string): Promise<JournalView>;
|
|
63
|
+
editJournal(tcId: string, ops: JournalOp[]): Promise<JournalView>;
|
|
64
|
+
createSuite(s: Suite): Promise<SavedRef>;
|
|
65
|
+
updateSuiteMembers(id: string, ops: MemberOp[]): Promise<Suite>;
|
|
66
|
+
deleteSuite(id: string): Promise<void>;
|
|
67
|
+
startRun(target: RunTarget, opts: RunOptions): Promise<RunRef>;
|
|
68
|
+
getRun(runId: string): Promise<RunStatus>;
|
|
69
|
+
stopRun(runId: string): Promise<void>;
|
|
70
|
+
listCloudRunners(): Promise<CloudRunner[]>;
|
|
71
|
+
/**
|
|
72
|
+
* Raw passthrough: forward a tool call to the product MCP verbatim and return its CallToolResult.
|
|
73
|
+
* For AGENT-BOUND tools (recording/browser) the Common MCP proxies rather than wraps -- it cannot
|
|
74
|
+
* implement them (they need the product's real browser), so it relays the call and the result.
|
|
75
|
+
* Stale-session resilient via `callTool`.
|
|
76
|
+
*/
|
|
77
|
+
callRaw(name: string, args: Record<string, unknown>): Promise<CallToolResult>;
|
|
78
|
+
/** The product MCP's advertised tools (name + description + inputSchema), for building passthrough
|
|
79
|
+
* proxies of its agent-bound surface. The inputSchema is mirrored so the client's model knows each
|
|
80
|
+
* tool's real parameters (ref/object_name/expected/value/…) instead of guessing against a
|
|
81
|
+
* permissive schema. */
|
|
82
|
+
listAgentTools(): Promise<Array<{
|
|
83
|
+
name: string;
|
|
84
|
+
description?: string;
|
|
85
|
+
inputSchema?: Record<string, unknown>;
|
|
86
|
+
}>>;
|
|
87
|
+
listEnvironments(): Promise<EnvInfo[]>;
|
|
88
|
+
listDatasets(tcId?: string): Promise<DatasetInfo[]>;
|
|
89
|
+
getObject(id: string): Promise<QaObject>;
|
|
90
|
+
productUrlFor(entity: EntityRef): string;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/remoteMcp/adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
3
|
+
function firstText(res) {
|
|
4
|
+
const content = res.content;
|
|
5
|
+
return content?.find((c) => c?.type === 'text')?.text ?? '';
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* True when a call failed because the product MCP's SESSION is gone -- almost always because that
|
|
9
|
+
* process was restarted (e.g. an agent rebuild), which invalidates the session id our cached client
|
|
10
|
+
* holds. The Streamable-HTTP transport surfaces this as a -32001 "Session not found" while POSTing.
|
|
11
|
+
* We treat it as "reconnect and retry once", NOT a real failure.
|
|
12
|
+
*/
|
|
13
|
+
function isStaleSession(e) {
|
|
14
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
15
|
+
return /session not found|-32001/i.test(msg);
|
|
16
|
+
}
|
|
17
|
+
export class RemoteMcpAdapter {
|
|
18
|
+
constructor(cfg,
|
|
19
|
+
/** Test seam: inject a pre-linked in-memory transport instead of a real HTTP one. */
|
|
20
|
+
transportFactory) {
|
|
21
|
+
this.cfg = cfg;
|
|
22
|
+
this.transportFactory = transportFactory;
|
|
23
|
+
this.clientPromise = null;
|
|
24
|
+
}
|
|
25
|
+
// Bearer token forwarded unchanged to the product MCP; x-project-id only when we have one (a key is
|
|
26
|
+
// project-scoped server-side, so it may be absent). Mirrors the guide's auth section.
|
|
27
|
+
headers() {
|
|
28
|
+
const h = { Authorization: `Bearer ${this.cfg.token}` };
|
|
29
|
+
if (this.cfg.projectId)
|
|
30
|
+
h['x-project-id'] = this.cfg.projectId;
|
|
31
|
+
return h;
|
|
32
|
+
}
|
|
33
|
+
async client() {
|
|
34
|
+
if (!this.clientPromise) {
|
|
35
|
+
this.clientPromise = (async () => {
|
|
36
|
+
const client = new Client({ name: 'common-qa-mcp', version: '0.1.0' });
|
|
37
|
+
// The `as Transport` cast bridges exactOptionalPropertyTypes: StreamableHTTPClientTransport
|
|
38
|
+
// implements Transport, but the SDK's own .d.ts (built without EOPT) leaves its optional
|
|
39
|
+
// callbacks (onclose?/onerror?/onmessage?) without `| undefined`, which this project's EOPT
|
|
40
|
+
// rejects on assignment. The class genuinely satisfies the interface at runtime.
|
|
41
|
+
const transport = this.transportFactory
|
|
42
|
+
? this.transportFactory()
|
|
43
|
+
: new StreamableHTTPClientTransport(new URL(this.cfg.url), { requestInit: { headers: this.headers() } });
|
|
44
|
+
await client.connect(transport);
|
|
45
|
+
return client;
|
|
46
|
+
})().catch((e) => {
|
|
47
|
+
// Re-arm so the next call retries instead of reusing a rejected promise forever.
|
|
48
|
+
this.clientPromise = null;
|
|
49
|
+
throw e instanceof Error
|
|
50
|
+
? new Error(`Could not reach the product MCP at ${this.cfg.url}: ${e.message}`)
|
|
51
|
+
: e;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
return this.clientPromise;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* callTool with transparent ONE-shot reconnect on a stale session. If the product MCP was
|
|
58
|
+
* restarted, our cached client holds a dead session id and the first call throws "Session not
|
|
59
|
+
* found"; we drop the client so `client()` re-connects fresh, then retry exactly once. Any other
|
|
60
|
+
* error (or a second failure) propagates. Without this, every call after a product restart failed
|
|
61
|
+
* until THIS process was restarted too.
|
|
62
|
+
*/
|
|
63
|
+
async callTool(name, args) {
|
|
64
|
+
try {
|
|
65
|
+
return await (await this.client()).callTool({ name, arguments: args });
|
|
66
|
+
}
|
|
67
|
+
catch (e) {
|
|
68
|
+
if (!isStaleSession(e))
|
|
69
|
+
throw e;
|
|
70
|
+
this.clientPromise = null; // discard the dead session; client() mints a new one
|
|
71
|
+
return await (await this.client()).callTool({ name, arguments: args });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** Project-scoped provider-ops need a selected project. `list_projects` is the ONE exception (it
|
|
75
|
+
* lists ACROSS projects, so it must work with none selected). Guarding here turns an opaque backend
|
|
76
|
+
* 400 ("Project ID and User ID are required") into a clear instruction so the AI client asks the
|
|
77
|
+
* user to pick a project first. */
|
|
78
|
+
assertProject(op) {
|
|
79
|
+
if (!this.cfg.projectId && op !== 'list_projects') {
|
|
80
|
+
throw new Error('No project selected. Call list_projects to see the available projects, then ' +
|
|
81
|
+
'qa_switch_project({ projectId }) to choose one — test cases, runs and objects are all ' +
|
|
82
|
+
'scoped to a project.');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/** Call a remote provider-op tool and pull the neutral payload from structuredContent[key]. */
|
|
86
|
+
async call(name, args, key) {
|
|
87
|
+
this.assertProject(name);
|
|
88
|
+
const res = await this.callTool(name, args);
|
|
89
|
+
if (res.isError) {
|
|
90
|
+
throw new Error(firstText(res) || `product MCP tool "${name}" returned an error.`);
|
|
91
|
+
}
|
|
92
|
+
const sc = res.structuredContent;
|
|
93
|
+
if (!sc || !(key in sc)) {
|
|
94
|
+
throw new Error(`product MCP tool "${name}" did not return structuredContent.${key}.`);
|
|
95
|
+
}
|
|
96
|
+
return sc[key];
|
|
97
|
+
}
|
|
98
|
+
/** For void ops (delete/stop): only surface an error, ignore any payload. */
|
|
99
|
+
async callVoid(name, args) {
|
|
100
|
+
this.assertProject(name);
|
|
101
|
+
const res = await this.callTool(name, args);
|
|
102
|
+
if (res.isError) {
|
|
103
|
+
throw new Error(firstText(res) || `product MCP tool "${name}" returned an error.`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async info() {
|
|
107
|
+
return this.call('info', {}, 'info');
|
|
108
|
+
}
|
|
109
|
+
async listProjects() {
|
|
110
|
+
return this.call('list_projects', {}, 'projects');
|
|
111
|
+
}
|
|
112
|
+
async listTestCases(q) {
|
|
113
|
+
return this.call('list_testcases', q, 'testCases');
|
|
114
|
+
}
|
|
115
|
+
async getTestCase(id) {
|
|
116
|
+
return this.call('get_testcase', { id }, 'tc');
|
|
117
|
+
}
|
|
118
|
+
async createTestCase(tc) {
|
|
119
|
+
return this.call('create_testcase', { tc }, 'saved');
|
|
120
|
+
}
|
|
121
|
+
async updateTestCase(id, tc) {
|
|
122
|
+
return this.call('update_testcase', { id, tc }, 'saved');
|
|
123
|
+
}
|
|
124
|
+
async deleteTestCase(id) {
|
|
125
|
+
await this.callVoid('delete_testcase', { id });
|
|
126
|
+
}
|
|
127
|
+
async cloneTestCase(id, title) {
|
|
128
|
+
return this.call('clone_testcase', { id, ...(title !== undefined ? { title } : {}) }, 'saved');
|
|
129
|
+
}
|
|
130
|
+
async searchObjects(q) {
|
|
131
|
+
return this.call('search_objects', q, 'objects');
|
|
132
|
+
}
|
|
133
|
+
async createObject(o) {
|
|
134
|
+
return this.call('create_object', { object: o }, 'object');
|
|
135
|
+
}
|
|
136
|
+
async actionsCatalog(platform) {
|
|
137
|
+
return this.call('actions_catalog', platform !== undefined ? { platform } : {}, 'actions');
|
|
138
|
+
}
|
|
139
|
+
async listSuites() {
|
|
140
|
+
return this.call('list_suites', {}, 'suites');
|
|
141
|
+
}
|
|
142
|
+
async getSuite(id) {
|
|
143
|
+
return this.call('get_suite', { id }, 'suite');
|
|
144
|
+
}
|
|
145
|
+
async listStories(q) {
|
|
146
|
+
return this.call('list_stories', q, 'stories');
|
|
147
|
+
}
|
|
148
|
+
async getStory(id) {
|
|
149
|
+
return this.call('get_story', { id }, 'story');
|
|
150
|
+
}
|
|
151
|
+
async readJournal(tcId) {
|
|
152
|
+
return this.call('read_journal', { id: tcId }, 'view');
|
|
153
|
+
}
|
|
154
|
+
async editJournal(tcId, ops) {
|
|
155
|
+
return this.call('edit_journal', { id: tcId, ops }, 'view');
|
|
156
|
+
}
|
|
157
|
+
async createSuite(s) {
|
|
158
|
+
return this.call('create_suite', { suite: s }, 'saved');
|
|
159
|
+
}
|
|
160
|
+
async updateSuiteMembers(id, ops) {
|
|
161
|
+
return this.call('update_suite_members', { id, ops }, 'suite');
|
|
162
|
+
}
|
|
163
|
+
async deleteSuite(id) {
|
|
164
|
+
await this.callVoid('delete_suite', { id });
|
|
165
|
+
}
|
|
166
|
+
// Execution forwards to the product MCP's own run ops (start_run / get_run / stop_run). For
|
|
167
|
+
// SimplifyQA those are agent MCP tools; the gateway stays product-neutral and just relays.
|
|
168
|
+
async startRun(target, opts) {
|
|
169
|
+
return this.call('start_run', { target, options: opts }, 'run');
|
|
170
|
+
}
|
|
171
|
+
async getRun(runId) {
|
|
172
|
+
return this.call('get_run', { runId }, 'run');
|
|
173
|
+
}
|
|
174
|
+
async stopRun(runId) {
|
|
175
|
+
await this.callVoid('stop_run', { runId });
|
|
176
|
+
}
|
|
177
|
+
async listCloudRunners() {
|
|
178
|
+
return this.call('list_cloud_runners', {}, 'runners');
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Raw passthrough: forward a tool call to the product MCP verbatim and return its CallToolResult.
|
|
182
|
+
* For AGENT-BOUND tools (recording/browser) the Common MCP proxies rather than wraps -- it cannot
|
|
183
|
+
* implement them (they need the product's real browser), so it relays the call and the result.
|
|
184
|
+
* Stale-session resilient via `callTool`.
|
|
185
|
+
*/
|
|
186
|
+
async callRaw(name, args) {
|
|
187
|
+
return (await this.callTool(name, args));
|
|
188
|
+
}
|
|
189
|
+
/** The product MCP's advertised tools (name + description + inputSchema), for building passthrough
|
|
190
|
+
* proxies of its agent-bound surface. The inputSchema is mirrored so the client's model knows each
|
|
191
|
+
* tool's real parameters (ref/object_name/expected/value/…) instead of guessing against a
|
|
192
|
+
* permissive schema. */
|
|
193
|
+
async listAgentTools() {
|
|
194
|
+
const client = await this.client();
|
|
195
|
+
const res = await client.listTools();
|
|
196
|
+
return res.tools.map((t) => ({
|
|
197
|
+
name: t.name,
|
|
198
|
+
...(t.description ? { description: t.description } : {}),
|
|
199
|
+
...(t.inputSchema ? { inputSchema: t.inputSchema } : {}),
|
|
200
|
+
}));
|
|
201
|
+
}
|
|
202
|
+
async listEnvironments() {
|
|
203
|
+
return this.call('list_environments', {}, 'environments');
|
|
204
|
+
}
|
|
205
|
+
async listDatasets(tcId) {
|
|
206
|
+
return this.call('list_datasets', tcId !== undefined ? { tcId } : {}, 'datasets');
|
|
207
|
+
}
|
|
208
|
+
async getObject(id) {
|
|
209
|
+
return this.call('get_object', { id }, 'object');
|
|
210
|
+
}
|
|
211
|
+
// Deep link into the SimplifyQA UI. The AUTHORITATIVE link comes from SavedRef.productUrl (returned
|
|
212
|
+
// by create/update); this synchronous fallback is best-effort off the MCP endpoint origin -- it
|
|
213
|
+
// cannot round-trip to the remote, so callers should prefer SavedRef.productUrl when they have it.
|
|
214
|
+
productUrlFor(entity) {
|
|
215
|
+
const base = this.cfg.url.replace(/\/+$/, '').replace(/\/mcp$/i, '');
|
|
216
|
+
return `${base}/${entity.kind}/${entity.id}`;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/adapters/remoteMcp/adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { ActionDef, CloudRunner, DatasetInfo, EntityRef, EnvInfo, JournalOp, JournalView, MemberOp, ObjectQuery, ProjectSummary, QaObject, RunOptions, RunRef, RunStatus, RunTarget, SavedRef, Story, StoryQuery, StorySummary, Suite, SuiteSummary, TcQuery, TcSummary, TestCase } from '../domain/types.js';
|
|
2
|
+
export type ProjectInfo = {
|
|
3
|
+
provider: 'walnut' | 'simplifyqa';
|
|
4
|
+
projectId: string;
|
|
5
|
+
projectName: string;
|
|
6
|
+
counts?: Record<string, number> | undefined;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Full adapter contract (design spec §5, ~20 methods). Tools and the UI see only this
|
|
10
|
+
* neutral surface -- WalnutAdapter (Tasks 5-6) and SimplifyQaAdapter (Tasks 11-12) each
|
|
11
|
+
* implement it against their own REST API via a QaHttp client (src/adapters/http.ts).
|
|
12
|
+
* Optional methods (`?`) are genuinely optional per product (e.g. `cloneTestCase` is
|
|
13
|
+
* native on Walnut but a get+create composite on SQA; `listDatasets`/`getObject` are
|
|
14
|
+
* walnut-first / migration-only) -- callers must treat their absence as "not supported
|
|
15
|
+
* by this provider", not as a bug.
|
|
16
|
+
*/
|
|
17
|
+
export interface ProviderAdapter {
|
|
18
|
+
/** Validates url+token+project. */
|
|
19
|
+
info(): Promise<ProjectInfo>;
|
|
20
|
+
/** Projects visible to the connected token -- for name→id resolution and browsing. */
|
|
21
|
+
listProjects(): Promise<ProjectSummary[]>;
|
|
22
|
+
listTestCases(q: TcQuery): Promise<TcSummary[]>;
|
|
23
|
+
/** Neutral, steps included. */
|
|
24
|
+
getTestCase(id: string): Promise<TestCase>;
|
|
25
|
+
createTestCase(tc: TestCase): Promise<SavedRef>;
|
|
26
|
+
/** Full-doc semantics. */
|
|
27
|
+
updateTestCase(id: string, tc: TestCase): Promise<SavedRef>;
|
|
28
|
+
deleteTestCase(id: string): Promise<void>;
|
|
29
|
+
/** Walnut native; SQA = get+create. */
|
|
30
|
+
cloneTestCase?(id: string, title?: string): Promise<SavedRef>;
|
|
31
|
+
searchObjects(q: ObjectQuery): Promise<QaObject[]>;
|
|
32
|
+
createObject(o: QaObject): Promise<QaObject>;
|
|
33
|
+
/** Valid action vocabulary per technology (cached by the caller). */
|
|
34
|
+
actionsCatalog(platform?: string): Promise<ActionDef[]>;
|
|
35
|
+
/** Walnut-only: the recording-JOURNAL view of a test case (steps derived from its journal seed,
|
|
36
|
+
* or the persisted steps when no seed exists) — the read side of journal-first editing. Absent on
|
|
37
|
+
* providers with no recording journal. */
|
|
38
|
+
readJournal?(tcId: string): Promise<JournalView>;
|
|
39
|
+
/** Walnut-only: apply granular modify ops (add/remove/update/move step, wrap in loop/if, insert
|
|
40
|
+
* nested) to a test case and persist — the write side of journal-first editing. */
|
|
41
|
+
editJournal?(tcId: string, ops: JournalOp[]): Promise<JournalView>;
|
|
42
|
+
listSuites(): Promise<SuiteSummary[]>;
|
|
43
|
+
getSuite(id: string): Promise<Suite>;
|
|
44
|
+
createSuite(s: Suite): Promise<SavedRef>;
|
|
45
|
+
updateSuiteMembers(id: string, ops: MemberOp[]): Promise<Suite>;
|
|
46
|
+
deleteSuite(id: string): Promise<void>;
|
|
47
|
+
/** USER STORIES — read side of story-driven authoring (list + read-with-AC). `getStory` accepts a
|
|
48
|
+
* Mongo _id or a US_/Jira business key. Optional: only products with a story backlog implement them. */
|
|
49
|
+
listStories?(q: StoryQuery): Promise<StorySummary[]>;
|
|
50
|
+
getStory?(id: string): Promise<Story>;
|
|
51
|
+
startRun(target: RunTarget, opts: RunOptions): Promise<RunRef>;
|
|
52
|
+
/** Per-step results when terminal. */
|
|
53
|
+
getRun(runId: string): Promise<RunStatus>;
|
|
54
|
+
stopRun(runId: string): Promise<void>;
|
|
55
|
+
/** Cloud runner VMs registered to the project, with online status. Optional: only products with a
|
|
56
|
+
* cloud-execution fabric implement it; absence = "this provider has no cloud runners". */
|
|
57
|
+
listCloudRunners?(): Promise<CloudRunner[]>;
|
|
58
|
+
/** Passthrough for AGENT-BOUND tools (recording/browser) the Common MCP proxies rather than wraps.
|
|
59
|
+
* Only the remote-MCP forwarder implements these; `unknown` is a CallToolResult (kept SDK-free
|
|
60
|
+
* here). */
|
|
61
|
+
callRaw?(name: string, args: Record<string, unknown>): Promise<unknown>;
|
|
62
|
+
/** The product MCP's advertised tools (name + description + inputSchema), for building those proxies
|
|
63
|
+
* with the real per-tool parameter schema mirrored to the client. */
|
|
64
|
+
listAgentTools?(): Promise<Array<{
|
|
65
|
+
name: string;
|
|
66
|
+
description?: string;
|
|
67
|
+
inputSchema?: Record<string, unknown>;
|
|
68
|
+
}>>;
|
|
69
|
+
listEnvironments(): Promise<EnvInfo[]>;
|
|
70
|
+
/** Walnut-first. */
|
|
71
|
+
listDatasets?(tcId?: string): Promise<DatasetInfo[]>;
|
|
72
|
+
/** Full locator bag; needed by migration (§7A). */
|
|
73
|
+
getObject?(id: string): Promise<QaObject>;
|
|
74
|
+
/** Deep link into product UI. */
|
|
75
|
+
productUrlFor(entity: EntityRef): string;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/adapters/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,WAAW,EACX,WAAW,EACX,SAAS,EACT,OAAO,EACP,SAAS,EACT,WAAW,EACX,QAAQ,EACR,WAAW,EACX,cAAc,EACd,QAAQ,EACR,UAAU,EACV,MAAM,EACN,SAAS,EACT,SAAS,EACT,QAAQ,EACR,KAAK,EACL,UAAU,EACV,YAAY,EACZ,KAAK,EACL,YAAY,EACZ,OAAO,EACP,SAAS,EACT,QAAQ,EACT,MAAM,oBAAoB,CAAC;AAE5B,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,QAAQ,GAAG,YAAY,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IAGpB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;CAC7C,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,WAAW,eAAe;IAC9B,mCAAmC;IACnC,IAAI,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;IAE7B,sFAAsF;IACtF,YAAY,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAE1C,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAChD,+BAA+B;IAC/B,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC3C,cAAc,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChD,0BAA0B;IAC1B,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5D,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,uCAAuC;IACvC,aAAa,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE9D,aAAa,CAAC,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IACnD,YAAY,CAAC,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC7C,qEAAqE;IACrE,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAExD;;+CAE2C;IAC3C,WAAW,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACjD;wFACoF;IACpF,WAAW,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAEnE,UAAU,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IACtC,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IACrC,WAAW,CAAC,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACzC,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAChE,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvC;6GACyG;IACzG,WAAW,CAAC,CAAC,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IACrD,QAAQ,CAAC,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAEtC,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/D,sCAAsC;IACtC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAC1C,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC;+FAC2F;IAC3F,gBAAgB,CAAC,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAE5C;;iBAEa;IACb,OAAO,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACxE;0EACsE;IACtE,cAAc,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC,CAAC;IAEjH,gBAAgB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACvC,oBAAoB;IACpB,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IACrD,mDAAmD;IACnD,SAAS,CAAC,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE1C,iCAAiC;IACjC,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAAC;CAC1C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/adapters/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ActionDef, Step } from '../../domain/types.js';
|
|
2
|
+
export type WalnutPlatform = 'web' | 'android' | 'api' | 'database' | 'mainframe';
|
|
3
|
+
export declare const WALNUT_ACTIONS: Record<WalnutPlatform, string[]>;
|
|
4
|
+
/** Flattens a per-platform action-type catalog into `ActionDef[]`, tagging every entry. */
|
|
5
|
+
export declare function actionDefsFrom(catalog: Record<WalnutPlatform, string[]>): ActionDef[];
|
|
6
|
+
/**
|
|
7
|
+
* The single shared `catalogFor` callback every offline draft tool passes to
|
|
8
|
+
* `validateTestCase` -- no network, no adapter, just the static WALNUT_ACTIONS
|
|
9
|
+
* table above. Maps a neutral `Step.stepType` to its WALNUT_ACTIONS bucket;
|
|
10
|
+
* `control_flow` is exempted by `validateTestCase` itself before this is ever
|
|
11
|
+
* consulted, and a stepType with no offline vocabulary (`function`) yields an
|
|
12
|
+
* empty Set, which `validateTestCase` treats as "nothing to check" rather than
|
|
13
|
+
* "nothing is valid".
|
|
14
|
+
*/
|
|
15
|
+
export declare function offlineCatalogFor(step: Step): Set<string>;
|
|
16
|
+
//# sourceMappingURL=actionTypes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actionTypes.d.ts","sourceRoot":"","sources":["../../../src/adapters/walnut/actionTypes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAG7D,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,SAAS,GAAG,KAAK,GAAG,UAAU,GAAG,WAAW,CAAC;AAsElF,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,EAAE,CAqD3D,CAAC;AAEF,2FAA2F;AAC3F,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,EAAE,CAAC,GAAG,SAAS,EAAE,CAIrF;AAQD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAEzD"}
|