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
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { WEB_ACTION_SIGNATURES } from '../../vendor/actionSignatures.js';
|
|
2
|
+
/**
|
|
3
|
+
* Static per-technology action-type catalogs. Used as the whole `actionsCatalog()`
|
|
4
|
+
* answer for android/api/database/mainframe (there is no live/per-org source for
|
|
5
|
+
* those) and as the `web` fallback when the live per-org `GET /api/actions` catalog
|
|
6
|
+
* is unavailable (see `WalnutAdapter.actionsCatalog` in adapter.ts).
|
|
7
|
+
*
|
|
8
|
+
* Source (copied verbatim -- do not invent action names):
|
|
9
|
+
* - web: walnut-mcp/modules/config/action_types.py, VALID_ACTION_TYPES (lines 12-36)
|
|
10
|
+
* -- the 41 canonical action types mirroring the agent's registered Playwright
|
|
11
|
+
* tool handlers.
|
|
12
|
+
* - android: walnut-mcp/modules/config/platform_action_types.py,
|
|
13
|
+
* ANDROID_ACTION_TYPES (lines 44-91) -- 75 Appium actions.
|
|
14
|
+
* - api: walnut-mcp/modules/config/platform_action_types.py,
|
|
15
|
+
* API_ACTION_TYPES (line 148).
|
|
16
|
+
* - database: walnut-mcp/modules/config/platform_action_types.py,
|
|
17
|
+
* DATABASE_ACTION_TYPES (line 220).
|
|
18
|
+
* - mainframe: no frozenset for this platform exists in either source file --
|
|
19
|
+
* left empty rather than guessed (spec §6A documents a Walnut-only mainframe
|
|
20
|
+
* step_type, but platform_action_types.py has no corresponding action-type set).
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* The walnut-mcp copy of the web catalog (41 types). Kept verbatim as its own const
|
|
24
|
+
* because it is a COPY of an external source; the live web catalog below unions it
|
|
25
|
+
* with the agent's own signature table instead of editing this list by hand.
|
|
26
|
+
*/
|
|
27
|
+
const WALNUT_MCP_WEB_ACTIONS = [
|
|
28
|
+
// Navigation
|
|
29
|
+
'navigate', 'navigate_back', 'go_forward', 'reload', 'close', 'tabs',
|
|
30
|
+
// Input
|
|
31
|
+
'click', 'dblclick', 'type', 'fill_form', 'select_option',
|
|
32
|
+
'press_key', 'tap', 'hover', 'focus', 'blur',
|
|
33
|
+
// Mouse coordinate
|
|
34
|
+
'mouse_click_xy', 'mouse_drag_xy', 'mouse_move_xy',
|
|
35
|
+
// Drag & Drop
|
|
36
|
+
'drag',
|
|
37
|
+
// File
|
|
38
|
+
'file_upload',
|
|
39
|
+
// Verification
|
|
40
|
+
'verify_element_visible', 'verify_text_visible', 'verify_value',
|
|
41
|
+
'verify_url_contains', 'verify_list_visible', 'verify_navigation',
|
|
42
|
+
// Wait
|
|
43
|
+
'wait_for_visible', 'wait_for_hidden', 'wait_for_navigation',
|
|
44
|
+
'wait_for_url', 'wait_for_attached', 'wait_for_detached', 'wait_timeout',
|
|
45
|
+
// Advanced
|
|
46
|
+
'evaluate', 'run_code', 'handle_dialog',
|
|
47
|
+
// Layout
|
|
48
|
+
'scroll', 'resize', 'pdf_save',
|
|
49
|
+
// API
|
|
50
|
+
'api_call',
|
|
51
|
+
];
|
|
52
|
+
/**
|
|
53
|
+
* The web catalog the validator and `actions_catalog` both answer from: the
|
|
54
|
+
* walnut-mcp copy UNIONED with every actionType the agent itself can bake
|
|
55
|
+
* (WEB_ACTION_SIGNATURES -- the same table the recorder fills descriptions from).
|
|
56
|
+
*
|
|
57
|
+
* Why the union rather than a longer hand-kept list: the copy above froze at 41
|
|
58
|
+
* types and the agent has since grown 12 more, so a recording that used any of
|
|
59
|
+
* them was reported as INVALID by our own validator -- `verify_compare` and
|
|
60
|
+
* `store_run_variable` are exposed MCP tools, and every draft containing one came
|
|
61
|
+
* back `validation ✗ -- actionType "verify_compare" not in catalog`. Deriving from
|
|
62
|
+
* the signature table means a future action the agent learns to bake is valid here
|
|
63
|
+
* the moment it has a signature, with no second list to remember.
|
|
64
|
+
*/
|
|
65
|
+
const WEB_ACTIONS = [
|
|
66
|
+
...new Set([...WALNUT_MCP_WEB_ACTIONS, ...Object.keys(WEB_ACTION_SIGNATURES)]),
|
|
67
|
+
];
|
|
68
|
+
export const WALNUT_ACTIONS = {
|
|
69
|
+
web: WEB_ACTIONS,
|
|
70
|
+
android: [
|
|
71
|
+
// App lifecycle
|
|
72
|
+
'android_start_app', 'android_close_app', 'android_reset_app',
|
|
73
|
+
'android_install_app', 'android_uninstall_app', 'android_switch_app',
|
|
74
|
+
'android_is_app_installed',
|
|
75
|
+
// Interaction
|
|
76
|
+
'android_click', 'android_tap', 'android_longpress', 'android_type',
|
|
77
|
+
'android_clear', 'android_click_by_text', 'android_click_by_image',
|
|
78
|
+
'android_click_if_present', 'android_drag_drop',
|
|
79
|
+
'android_hide_keyboard', 'android_press_key',
|
|
80
|
+
'android_pinch_in', 'android_pinch_out',
|
|
81
|
+
// Scroll & Swipe
|
|
82
|
+
'android_scroll_to_element', 'android_scroll_to_text',
|
|
83
|
+
'android_scroll_to_top', 'android_scroll_to_bottom',
|
|
84
|
+
'android_scroll_left', 'android_scroll_right',
|
|
85
|
+
'android_scroll_to_element_and_click',
|
|
86
|
+
'android_scroll_until_element_gone', 'android_scroll_until_text_gone',
|
|
87
|
+
'android_swipe', 'android_swipe_by_direction',
|
|
88
|
+
// Navigation
|
|
89
|
+
'android_back', 'android_home', 'android_recent_apps',
|
|
90
|
+
'android_open_notification', 'android_switch_context',
|
|
91
|
+
'android_get_contexts', 'android_get_current_context',
|
|
92
|
+
// Verification
|
|
93
|
+
'android_validate_text', 'android_validate_partial_text',
|
|
94
|
+
'android_validate_by_text', 'android_validate_by_image',
|
|
95
|
+
'android_wait_for_element', 'android_wait_for_element_gone',
|
|
96
|
+
'android_wait_for_text', 'android_wait_for_text_gone',
|
|
97
|
+
'android_is_element_visible', 'android_is_element_enabled',
|
|
98
|
+
'android_is_element_checked', 'android_is_element_clickable',
|
|
99
|
+
'android_is_element_disabled', 'android_is_element_selected',
|
|
100
|
+
'android_is_element_not_visible', 'android_is_element_not_checked',
|
|
101
|
+
'android_is_element_not_selected',
|
|
102
|
+
// Data retrieval
|
|
103
|
+
'android_get_text', 'android_get_attribute',
|
|
104
|
+
// Device controls
|
|
105
|
+
'android_take_screenshot', 'android_snapshot',
|
|
106
|
+
'android_rotate_screen', 'android_device_info',
|
|
107
|
+
'android_lock', 'android_unlock', 'android_is_locked',
|
|
108
|
+
// Network
|
|
109
|
+
'android_wifi_status', 'android_toggle_wifi',
|
|
110
|
+
'android_data_status', 'android_toggle_data',
|
|
111
|
+
'android_bluetooth_status', 'android_toggle_bluetooth',
|
|
112
|
+
'android_airplane_mode_status',
|
|
113
|
+
// File operations
|
|
114
|
+
'android_push_file', 'android_pull_file',
|
|
115
|
+
// ADB
|
|
116
|
+
'android_adb_command', 'android_type_adb',
|
|
117
|
+
],
|
|
118
|
+
api: ['api_call'],
|
|
119
|
+
database: ['database_query'],
|
|
120
|
+
mainframe: [],
|
|
121
|
+
};
|
|
122
|
+
/** Flattens a per-platform action-type catalog into `ActionDef[]`, tagging every entry. */
|
|
123
|
+
export function actionDefsFrom(catalog) {
|
|
124
|
+
return Object.entries(catalog).flatMap(([platform, actionTypes]) => actionTypes.map((actionType) => ({ actionType, platform })));
|
|
125
|
+
}
|
|
126
|
+
// Precomputed once at module load -- every draft-tool validation call shares
|
|
127
|
+
// these Sets rather than rebuilding them per call.
|
|
128
|
+
const CATALOG_SETS = Object.fromEntries(Object.entries(WALNUT_ACTIONS).map(([platform, list]) => [platform, new Set(list)]));
|
|
129
|
+
/**
|
|
130
|
+
* The single shared `catalogFor` callback every offline draft tool passes to
|
|
131
|
+
* `validateTestCase` -- no network, no adapter, just the static WALNUT_ACTIONS
|
|
132
|
+
* table above. Maps a neutral `Step.stepType` to its WALNUT_ACTIONS bucket;
|
|
133
|
+
* `control_flow` is exempted by `validateTestCase` itself before this is ever
|
|
134
|
+
* consulted, and a stepType with no offline vocabulary (`function`) yields an
|
|
135
|
+
* empty Set, which `validateTestCase` treats as "nothing to check" rather than
|
|
136
|
+
* "nothing is valid".
|
|
137
|
+
*/
|
|
138
|
+
export function offlineCatalogFor(step) {
|
|
139
|
+
return CATALOG_SETS[step.stepType] ?? new Set();
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=actionTypes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actionTypes.js","sourceRoot":"","sources":["../../../src/adapters/walnut/actionTypes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAIzE;;;;;;;;;;;;;;;;;;;GAmBG;AACH;;;;GAIG;AACH,MAAM,sBAAsB,GAAa;IACrC,aAAa;IACb,UAAU,EAAE,eAAe,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM;IACpE,QAAQ;IACR,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,eAAe;IACzD,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM;IAC5C,mBAAmB;IACnB,gBAAgB,EAAE,eAAe,EAAE,eAAe;IAClD,cAAc;IACd,MAAM;IACN,OAAO;IACP,aAAa;IACb,eAAe;IACf,wBAAwB,EAAE,qBAAqB,EAAE,cAAc;IAC/D,qBAAqB,EAAE,qBAAqB,EAAE,mBAAmB;IACjE,OAAO;IACP,kBAAkB,EAAE,iBAAiB,EAAE,qBAAqB;IAC5D,cAAc,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,cAAc;IACxE,WAAW;IACX,UAAU,EAAE,UAAU,EAAE,eAAe;IACvC,SAAS;IACT,QAAQ,EAAE,QAAQ,EAAE,UAAU;IAC9B,MAAM;IACN,UAAU;CACb,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,GAAa;IAC5B,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,sBAAsB,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC;CAC/E,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAqC;IAC9D,GAAG,EAAE,WAAW;IAChB,OAAO,EAAE;QACP,gBAAgB;QAChB,mBAAmB,EAAE,mBAAmB,EAAE,mBAAmB;QAC7D,qBAAqB,EAAE,uBAAuB,EAAE,oBAAoB;QACpE,0BAA0B;QAC1B,cAAc;QACd,eAAe,EAAE,aAAa,EAAE,mBAAmB,EAAE,cAAc;QACnE,eAAe,EAAE,uBAAuB,EAAE,wBAAwB;QAClE,0BAA0B,EAAE,mBAAmB;QAC/C,uBAAuB,EAAE,mBAAmB;QAC5C,kBAAkB,EAAE,mBAAmB;QACvC,iBAAiB;QACjB,2BAA2B,EAAE,wBAAwB;QACrD,uBAAuB,EAAE,0BAA0B;QACnD,qBAAqB,EAAE,sBAAsB;QAC7C,qCAAqC;QACrC,mCAAmC,EAAE,gCAAgC;QACrE,eAAe,EAAE,4BAA4B;QAC7C,aAAa;QACb,cAAc,EAAE,cAAc,EAAE,qBAAqB;QACrD,2BAA2B,EAAE,wBAAwB;QACrD,sBAAsB,EAAE,6BAA6B;QACrD,eAAe;QACf,uBAAuB,EAAE,+BAA+B;QACxD,0BAA0B,EAAE,2BAA2B;QACvD,0BAA0B,EAAE,+BAA+B;QAC3D,uBAAuB,EAAE,4BAA4B;QACrD,4BAA4B,EAAE,4BAA4B;QAC1D,4BAA4B,EAAE,8BAA8B;QAC5D,6BAA6B,EAAE,6BAA6B;QAC5D,gCAAgC,EAAE,gCAAgC;QAClE,iCAAiC;QACjC,iBAAiB;QACjB,kBAAkB,EAAE,uBAAuB;QAC3C,kBAAkB;QAClB,yBAAyB,EAAE,kBAAkB;QAC7C,uBAAuB,EAAE,qBAAqB;QAC9C,cAAc,EAAE,gBAAgB,EAAE,mBAAmB;QACrD,UAAU;QACV,qBAAqB,EAAE,qBAAqB;QAC5C,qBAAqB,EAAE,qBAAqB;QAC5C,0BAA0B,EAAE,0BAA0B;QACtD,8BAA8B;QAC9B,kBAAkB;QAClB,mBAAmB,EAAE,mBAAmB;QACxC,MAAM;QACN,qBAAqB,EAAE,kBAAkB;KAC1C;IACD,GAAG,EAAE,CAAC,UAAU,CAAC;IACjB,QAAQ,EAAE,CAAC,gBAAgB,CAAC;IAC5B,SAAS,EAAE,EAAE;CACd,CAAC;AAEF,2FAA2F;AAC3F,MAAM,UAAU,cAAc,CAAC,OAAyC;IACtE,OAAQ,MAAM,CAAC,OAAO,CAAC,OAAO,CAAuC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,WAAW,CAAC,EAAE,EAAE,CACxG,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC,CAC5D,CAAC;AACJ,CAAC;AAED,6EAA6E;AAC7E,mDAAmD;AACnD,MAAM,YAAY,GAAwC,MAAM,CAAC,WAAW,CACzE,MAAM,CAAC,OAAO,CAAC,cAAc,CAAuC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CACpF,CAAC;AAEzC;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAU;IAC1C,OAAO,YAAY,CAAC,IAAI,CAAC,QAA0B,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC;AACpE,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Step, TcSummary, TestCase } from '../../domain/types.js';
|
|
2
|
+
export type CfKind = NonNullable<Step['controlFlow']>['kind'];
|
|
3
|
+
export declare const WALNUT_TO_CF: Record<string, CfKind>;
|
|
4
|
+
/** Inverse of WALNUT_TO_CF (neutral controlFlow.kind -> walnut action_type),
|
|
5
|
+
* derived once from the same table -- never maintained by hand. */
|
|
6
|
+
export declare const CF_TO_WALNUT: Record<CfKind, string>;
|
|
7
|
+
/**
|
|
8
|
+
* Maps one walnut wire `test_steps[]` entry (models/schemas.ts `step` schema shape)
|
|
9
|
+
* to a neutral `Step`. `toWalnutStep` (the write direction) lands in Task 6.
|
|
10
|
+
*/
|
|
11
|
+
export declare function fromWalnutStep(raw: any): Step;
|
|
12
|
+
/**
|
|
13
|
+
* Maps a walnut `GET /api/test-cases/:id` response document (test-cases.ts:5125,
|
|
14
|
+
* TestCaseSchema-shaped) to the neutral `TestCase`. `toWalnutTc` (the write
|
|
15
|
+
* direction, exact payload shape the backend's zod schema accepts) lands in Task 6.
|
|
16
|
+
*/
|
|
17
|
+
export declare function fromWalnutTc(doc: any): TestCase;
|
|
18
|
+
/** Maps one walnut `GET /api/test-cases` list-row (test-cases.ts:1746 `testCases[]`) to a `TcSummary`. */
|
|
19
|
+
export declare function fromWalnutTcSummary(row: any): TcSummary;
|
|
20
|
+
/**
|
|
21
|
+
* One neutral `Step` -> one walnut-frontend draft `test_steps[]` entry.
|
|
22
|
+
* `fromWalnutStep` above is the reverse (though it targets the backend wire
|
|
23
|
+
* shape, not this draft shape -- see the round-trip test in
|
|
24
|
+
* tests/unit/walnut.mapper.test.ts, which exercises both directions and only
|
|
25
|
+
* asserts on stepType/controlFlow.kind, the fields both shapes agree on).
|
|
26
|
+
*/
|
|
27
|
+
export declare function toWalnutStep(s: Step): Record<string, unknown>;
|
|
28
|
+
/**
|
|
29
|
+
* Whole neutral TestCase -> the walnut-frontend draft payload's TestCase-level
|
|
30
|
+
* fields. `tc_draft_open` layers `draftId`/`mode` on top of this -- those
|
|
31
|
+
* describe the draft's hosting, not the test case itself.
|
|
32
|
+
*/
|
|
33
|
+
export declare function toWalnutTc(tc: TestCase): Record<string, unknown>;
|
|
34
|
+
//# sourceMappingURL=mapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mapper.d.ts","sourceRoot":"","sources":["../../../src/adapters/walnut/mapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAElF,MAAM,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAK9D,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAM/C,CAAC;AAEF;mEACmE;AACnE,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAErB,CAAC;AA0C5B;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAqC7C;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,QAAQ,CAoB/C;AAED,0GAA0G;AAC1G,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,GAAG,GAAG,SAAS,CAQvD;AA+CD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAsC7D;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAOhE"}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
// The single source of truth for control-flow action_type <-> kind. Exported (and
|
|
2
|
+
// inverted into CF_TO_WALNUT below) so the forward direction never hand-writes a
|
|
3
|
+
// second literal that could silently drift out of lockstep with this one.
|
|
4
|
+
export const WALNUT_TO_CF = {
|
|
5
|
+
if_start: 'if',
|
|
6
|
+
else: 'else',
|
|
7
|
+
if_end: 'if_end',
|
|
8
|
+
while_start: 'while',
|
|
9
|
+
while_end: 'while_end',
|
|
10
|
+
};
|
|
11
|
+
/** Inverse of WALNUT_TO_CF (neutral controlFlow.kind -> walnut action_type),
|
|
12
|
+
* derived once from the same table -- never maintained by hand. */
|
|
13
|
+
export const CF_TO_WALNUT = Object.fromEntries(Object.entries(WALNUT_TO_CF).map(([wire, kind]) => [kind, wire]));
|
|
14
|
+
const KNOWN_STEP_TYPES = new Set([
|
|
15
|
+
'web', 'android', 'control_flow', 'function', 'database', 'mainframe',
|
|
16
|
+
]);
|
|
17
|
+
/**
|
|
18
|
+
* Walnut's wire uses upper-case `'API'` for API steps; the neutral model uses
|
|
19
|
+
* lower-case `'api'`. Any other recognized value passes through unchanged; an
|
|
20
|
+
* absent/unrecognized value defaults to `'web'` (mirrors the backend's own
|
|
21
|
+
* `step_type` schema default in models/schemas.ts).
|
|
22
|
+
*/
|
|
23
|
+
function normalizeStepType(raw) {
|
|
24
|
+
if (raw === 'API')
|
|
25
|
+
return 'api';
|
|
26
|
+
if (typeof raw === 'string' && KNOWN_STEP_TYPES.has(raw))
|
|
27
|
+
return raw;
|
|
28
|
+
return 'web';
|
|
29
|
+
}
|
|
30
|
+
function fromWalnutCondition(raw) {
|
|
31
|
+
if (!raw)
|
|
32
|
+
return undefined;
|
|
33
|
+
return {
|
|
34
|
+
type: raw.type,
|
|
35
|
+
selector: raw.selector ?? undefined,
|
|
36
|
+
objectId: raw.object_id ?? undefined,
|
|
37
|
+
text: raw.text ?? undefined,
|
|
38
|
+
variableName: raw.variableName ?? undefined,
|
|
39
|
+
variableValue: raw.variableValue ?? undefined,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function fromWalnutFlags(raw) {
|
|
43
|
+
const sla = raw.stepLevelActions;
|
|
44
|
+
const hasIsOptional = raw.is_optional !== undefined && raw.is_optional !== null;
|
|
45
|
+
if (!sla && !hasIsOptional)
|
|
46
|
+
return undefined;
|
|
47
|
+
return {
|
|
48
|
+
...(sla
|
|
49
|
+
? { skip: !!sla.skip, screenshot: !!sla.captureScreenshot, continueOnFailure: !!sla.continueOnFailure }
|
|
50
|
+
: {}),
|
|
51
|
+
...(hasIsOptional ? { optional: !!raw.is_optional } : {}),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Maps one walnut wire `test_steps[]` entry (models/schemas.ts `step` schema shape)
|
|
56
|
+
* to a neutral `Step`. `toWalnutStep` (the write direction) lands in Task 6.
|
|
57
|
+
*/
|
|
58
|
+
export function fromWalnutStep(raw) {
|
|
59
|
+
const n = raw.step_number;
|
|
60
|
+
const description = raw.step_description ?? '';
|
|
61
|
+
const actionType = raw.action_type;
|
|
62
|
+
const expectedResult = raw.expected_result ?? undefined;
|
|
63
|
+
const flags = fromWalnutFlags(raw);
|
|
64
|
+
const cfKind = WALNUT_TO_CF[actionType];
|
|
65
|
+
if (cfKind) {
|
|
66
|
+
return {
|
|
67
|
+
n,
|
|
68
|
+
description,
|
|
69
|
+
actionType,
|
|
70
|
+
stepType: 'control_flow',
|
|
71
|
+
expectedResult,
|
|
72
|
+
controlFlow: {
|
|
73
|
+
kind: cfKind,
|
|
74
|
+
condition: fromWalnutCondition(raw.condition),
|
|
75
|
+
blockId: raw.block_id ?? undefined,
|
|
76
|
+
maxIterations: raw.max_iterations ?? undefined,
|
|
77
|
+
},
|
|
78
|
+
flags,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
n,
|
|
83
|
+
description,
|
|
84
|
+
actionType,
|
|
85
|
+
stepType: normalizeStepType(raw.step_type),
|
|
86
|
+
objectRef: raw.object_id != null ? { id: String(raw.object_id) } : undefined,
|
|
87
|
+
value: raw.input_value ?? undefined,
|
|
88
|
+
expectedResult,
|
|
89
|
+
api: raw.api_request_data ?? undefined,
|
|
90
|
+
db: raw.db_request_data ?? undefined,
|
|
91
|
+
flags,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Maps a walnut `GET /api/test-cases/:id` response document (test-cases.ts:5125,
|
|
96
|
+
* TestCaseSchema-shaped) to the neutral `TestCase`. `toWalnutTc` (the write
|
|
97
|
+
* direction, exact payload shape the backend's zod schema accepts) lands in Task 6.
|
|
98
|
+
*/
|
|
99
|
+
export function fromWalnutTc(doc) {
|
|
100
|
+
const id = doc.test_case_id ?? (doc._id != null ? String(doc._id) : undefined);
|
|
101
|
+
const category = doc.test_category === 'manual' || doc.test_category === 'playwright' ? doc.test_category : 'automated';
|
|
102
|
+
return {
|
|
103
|
+
id,
|
|
104
|
+
title: doc.title,
|
|
105
|
+
description: doc.description ?? undefined,
|
|
106
|
+
objective: doc.objective ?? undefined,
|
|
107
|
+
priority: doc.priority,
|
|
108
|
+
status: doc.status ?? undefined,
|
|
109
|
+
category,
|
|
110
|
+
preconditions: doc.preconditions ?? undefined,
|
|
111
|
+
expectedOutcome: doc.expected_outcome ?? undefined,
|
|
112
|
+
tags: doc.tags ?? [],
|
|
113
|
+
// Passthrough for Task 6's optimistic-concurrency PUT retry -- dropping this
|
|
114
|
+
// silently overwrites concurrent edits.
|
|
115
|
+
version: doc.version ?? undefined,
|
|
116
|
+
steps: (doc.test_steps ?? []).map(fromWalnutStep),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/** Maps one walnut `GET /api/test-cases` list-row (test-cases.ts:1746 `testCases[]`) to a `TcSummary`. */
|
|
120
|
+
export function fromWalnutTcSummary(row) {
|
|
121
|
+
return {
|
|
122
|
+
id: row.test_case_id ?? String(row._id),
|
|
123
|
+
title: row.title,
|
|
124
|
+
priority: row.priority,
|
|
125
|
+
status: row.status ?? undefined,
|
|
126
|
+
stepCount: row.total_steps ?? undefined,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
// FORWARD direction: neutral -> walnut, for the offline draft hand-off.
|
|
131
|
+
//
|
|
132
|
+
// This is NOT the backend's persistence wire shape (`POST/PUT /api/test-cases`,
|
|
133
|
+
// which uses `input_value`/`object_id` snake_case and lands with the write-side
|
|
134
|
+
// WalnutAdapter in a later task). It is the exact shape walnut-frontend's real
|
|
135
|
+
// TestStepsEditor consumes off the `/embed/test-case-draft#d=<payload>` URL
|
|
136
|
+
// fragment -- reproduced here from scripts/open-in-walnut-editor.ts's hand-built
|
|
137
|
+
// literal so there is one real implementation instead of a throwaway script and
|
|
138
|
+
// a second hand-written literal drifting apart from it.
|
|
139
|
+
// ---------------------------------------------------------------------------
|
|
140
|
+
const PARAM_TOKEN = /\$\{([^}]+)\}/g;
|
|
141
|
+
/** Every distinct `${name}` token in a step description, in first-seen order. */
|
|
142
|
+
function detectParams(description) {
|
|
143
|
+
const found = [];
|
|
144
|
+
for (const m of (description ?? '').matchAll(PARAM_TOKEN)) {
|
|
145
|
+
const name = m[1];
|
|
146
|
+
if (!found.includes(name))
|
|
147
|
+
found.push(name);
|
|
148
|
+
}
|
|
149
|
+
return found;
|
|
150
|
+
}
|
|
151
|
+
/** Forward of fromWalnutCondition: neutral Condition -> walnut condition (object_id snake_case). */
|
|
152
|
+
function toWalnutCondition(c) {
|
|
153
|
+
if (!c)
|
|
154
|
+
return undefined;
|
|
155
|
+
return {
|
|
156
|
+
type: c.type,
|
|
157
|
+
...(c.selector !== undefined ? { selector: c.selector } : {}),
|
|
158
|
+
...(c.objectId !== undefined ? { object_id: c.objectId } : {}),
|
|
159
|
+
...(c.text !== undefined ? { text: c.text } : {}),
|
|
160
|
+
...(c.variableName !== undefined ? { variableName: c.variableName } : {}),
|
|
161
|
+
...(c.variableValue !== undefined ? { variableValue: c.variableValue } : {}),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/** Forward of fromWalnutFlags's stepLevelActions branch. `is_optional` is
|
|
165
|
+
* deliberately NOT emitted -- it never appears in the editor draft payload
|
|
166
|
+
* scripts/open-in-walnut-editor.ts models, only in the backend persistence
|
|
167
|
+
* wire shape (a different contract, out of scope here). */
|
|
168
|
+
function toWalnutFlags(flags) {
|
|
169
|
+
return { skip: !!flags.skip, captureScreenshot: !!flags.screenshot, continueOnFailure: !!flags.continueOnFailure };
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* One neutral `Step` -> one walnut-frontend draft `test_steps[]` entry.
|
|
173
|
+
* `fromWalnutStep` above is the reverse (though it targets the backend wire
|
|
174
|
+
* shape, not this draft shape -- see the round-trip test in
|
|
175
|
+
* tests/unit/walnut.mapper.test.ts, which exercises both directions and only
|
|
176
|
+
* asserts on stepType/controlFlow.kind, the fields both shapes agree on).
|
|
177
|
+
*/
|
|
178
|
+
export function toWalnutStep(s) {
|
|
179
|
+
const cf = s.controlFlow;
|
|
180
|
+
const base = {
|
|
181
|
+
step_number: s.n,
|
|
182
|
+
step_type: s.stepType === 'api' ? 'API' : s.stepType,
|
|
183
|
+
action_type: cf ? CF_TO_WALNUT[cf.kind] : s.actionType,
|
|
184
|
+
step_description: s.description ?? '',
|
|
185
|
+
expected_result: s.expectedResult ?? '',
|
|
186
|
+
};
|
|
187
|
+
if (s.stepType === 'control_flow' && cf) {
|
|
188
|
+
const condition = toWalnutCondition(cf.condition);
|
|
189
|
+
return {
|
|
190
|
+
...base,
|
|
191
|
+
...(condition ? { condition } : {}),
|
|
192
|
+
...(cf.blockId ? { block_id: cf.blockId } : {}),
|
|
193
|
+
...(cf.maxIterations != null ? { max_iterations: cf.maxIterations } : {}),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
const params = detectParams(s.description);
|
|
197
|
+
// Real recorded locator, when this step originated from a LIVE recording
|
|
198
|
+
// session (mcp/qa/tools/recording.tools.ts) rather than LLM-authored text --
|
|
199
|
+
// `objectRef.locators` is only ever populated in that path (see
|
|
200
|
+
// fromRecordedStep below). `element.locator_type`/`locator_value` is exactly
|
|
201
|
+
// the field walnut-frontend's TestStepsEditor `TestStep.element` reads
|
|
202
|
+
// (TestStepsEditor.tsx ~line 2007) -- prefer the locator flagged `unique`
|
|
203
|
+
// (the same selector Walnut's own replay ladder prioritizes), else the first.
|
|
204
|
+
const primaryLocator = s.objectRef?.locators?.find((l) => l.unique) ?? s.objectRef?.locators?.[0];
|
|
205
|
+
return {
|
|
206
|
+
...base,
|
|
207
|
+
...(s.value !== undefined ? { inputValue: s.value } : {}),
|
|
208
|
+
...(params.length ? { parameterName: params[0], detected_parameters: params } : {}),
|
|
209
|
+
...(s.api ? { api_request_data: s.api } : {}),
|
|
210
|
+
...(s.flags ? { stepLevelActions: toWalnutFlags(s.flags) } : {}),
|
|
211
|
+
...(s.objectRef?.id !== undefined ? { object_id: s.objectRef.id } : {}),
|
|
212
|
+
...(primaryLocator ? { element: { locator_type: primaryLocator.name, locator_value: primaryLocator.value } } : {}),
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Whole neutral TestCase -> the walnut-frontend draft payload's TestCase-level
|
|
217
|
+
* fields. `tc_draft_open` layers `draftId`/`mode` on top of this -- those
|
|
218
|
+
* describe the draft's hosting, not the test case itself.
|
|
219
|
+
*/
|
|
220
|
+
export function toWalnutTc(tc) {
|
|
221
|
+
return {
|
|
222
|
+
title: tc.title,
|
|
223
|
+
priority: tc.priority,
|
|
224
|
+
category: tc.category,
|
|
225
|
+
test_steps: tc.steps.map(toWalnutStep),
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=mapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mapper.js","sourceRoot":"","sources":["../../../src/adapters/walnut/mapper.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* `common-qa-mcp` CLI — the published bin. Two jobs, Playwright-style:
|
|
4
|
+
* • (default / `serve`) run the Common QA MCP over stdio (what an AI client launches via npx)
|
|
5
|
+
* • `init-agents --loop=<c>` install the Walnut QA agent into your project for a given AI client
|
|
6
|
+
*
|
|
7
|
+
* stdout is the MCP transport in serve mode, so this file writes ONLY to stderr.
|
|
8
|
+
*/
|
|
9
|
+
import { startStdioServer } from './serve.js';
|
|
10
|
+
import { runInitAgents } from './initAgents.js';
|
|
11
|
+
function printUsage() {
|
|
12
|
+
process.stderr.write('common-qa-mcp — Common QA MCP\n\n' +
|
|
13
|
+
'Usage:\n' +
|
|
14
|
+
' common-qa-mcp [serve] Start the MCP server over stdio (default; AI clients launch this)\n' +
|
|
15
|
+
' common-qa-mcp init-agents --loop=<c> Install the Walnut QA agent into this project\n' +
|
|
16
|
+
' <c> = claude | cursor | windsurf | vscode | codex | all\n');
|
|
17
|
+
}
|
|
18
|
+
async function main() {
|
|
19
|
+
const argv = process.argv.slice(2);
|
|
20
|
+
const cmd = argv[0];
|
|
21
|
+
if (cmd === 'init-agents') {
|
|
22
|
+
await runInitAgents(argv.slice(1));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (cmd === undefined || cmd === 'serve') {
|
|
26
|
+
await startStdioServer();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
printUsage();
|
|
30
|
+
process.exitCode = cmd === 'help' || cmd === '--help' || cmd === '-h' ? 0 : 1;
|
|
31
|
+
}
|
|
32
|
+
main().catch((e) => {
|
|
33
|
+
process.stderr.write(`${e instanceof Error ? (e.stack ?? e.message) : String(e)}\n`);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
});
|
|
36
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;GAMG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,SAAS,UAAU;IACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,mCAAmC;QACjC,UAAU;QACV,8GAA8G;QAC9G,0FAA0F;QAC1F,oGAAoG,CACvG,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,IAAI,GAAG,KAAK,aAAa,EAAE,CAAC;QAC1B,MAAM,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACnC,OAAO;IACT,CAAC;IACD,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;QACzC,MAAM,gBAAgB,EAAE,CAAC;QACzB,OAAO;IACT,CAAC;IACD,UAAU,EAAE,CAAC;IACb,OAAO,CAAC,QAAQ,GAAG,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChF,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;IACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACrF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
type ConfigCommon = {
|
|
2
|
+
provider?: 'walnut' | 'simplifyqa';
|
|
3
|
+
customerId?: string;
|
|
4
|
+
moduleId?: string;
|
|
5
|
+
walnutAuth: 'key' | 'jwt';
|
|
6
|
+
caps: Set<string>;
|
|
7
|
+
port?: number;
|
|
8
|
+
connection?: string;
|
|
9
|
+
/** Origin of a running walnut-frontend, used by tc_draft_open to build the
|
|
10
|
+
* `/embed/test-case-draft` URL. Optional in both modes -- offline mode has no
|
|
11
|
+
* backend to derive one from, so this is the only source; connected mode may
|
|
12
|
+
* still want to point at a different UI host than the API origin.
|
|
13
|
+
*
|
|
14
|
+
* Also read by `recording_start` (mcp/qa/tools/recording.tools.ts) as an
|
|
15
|
+
* OVERRIDE: when set (env `QA_MCP_WALNUT_UI`), the live recording editor URL
|
|
16
|
+
* points at this deployed frontend's `/embed/test-case-draft` instead of the
|
|
17
|
+
* agent's own self-hosted `/editor` (the default when this is absent). */
|
|
18
|
+
walnutUiOrigin?: string;
|
|
19
|
+
/** Loopback base for the local Walnut agent, which can host the editor window.
|
|
20
|
+
* Only consulted by the standalone stdio dev harness (src/mcp/qa/index.ts) --
|
|
21
|
+
* when this tool surface is mounted in-process inside the agent itself (the
|
|
22
|
+
* product path, see src/mcp/qa/mount.ts), `tc_draft_open` calls the window
|
|
23
|
+
* opener directly and never reads this field. */
|
|
24
|
+
agentUrl?: string;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* "No credentials at all" -- the deliberate, error-free mode this server boots
|
|
28
|
+
* into when QA_MCP_URL/TOKEN/PROJECT_ID are all absent (spec: author drafts and
|
|
29
|
+
* hand off to walnut-frontend's editor, no backend, no network). `url`/`token`/
|
|
30
|
+
* `projectId` may still be partially present here in principle, but resolveConfig
|
|
31
|
+
* never returns this shape in that case -- partial credentials are a
|
|
32
|
+
* misconfiguration and throw instead (see resolveConfig).
|
|
33
|
+
*/
|
|
34
|
+
export type OfflineQaConfig = ConfigCommon & {
|
|
35
|
+
mode: 'offline';
|
|
36
|
+
url?: string;
|
|
37
|
+
token?: string;
|
|
38
|
+
projectId?: string;
|
|
39
|
+
};
|
|
40
|
+
/** url + token present -- the shape a live ProviderAdapter is built from. `projectId` is OPTIONAL:
|
|
41
|
+
* a session can be connected with NO project selected yet, and the user picks one at runtime
|
|
42
|
+
* (list_projects -> qa_switch_project). Only list_projects works with no project; every other
|
|
43
|
+
* project-scoped op asks the user to choose one first. */
|
|
44
|
+
export type ConnectedQaConfig = ConfigCommon & {
|
|
45
|
+
mode: 'connected';
|
|
46
|
+
url: string;
|
|
47
|
+
token: string;
|
|
48
|
+
projectId?: string;
|
|
49
|
+
};
|
|
50
|
+
export type QaConfig = OfflineQaConfig | ConnectedQaConfig;
|
|
51
|
+
/**
|
|
52
|
+
* Resolution order (spec §12): defaults -> ~/.common-qa-mcp/config.json
|
|
53
|
+
* (named connections; cliFlags.connection selects) -> QA_MCP_* env -> CLI flags.
|
|
54
|
+
* Each layer only overrides keys it actually sets.
|
|
55
|
+
*
|
|
56
|
+
* Credentials (url/token) are optional overall:
|
|
57
|
+
* - BOTH url+token ABSENT -> OfflineQaConfig, no throw. The normal, supported way
|
|
58
|
+
* to run with no backend at all (author drafts, hand off to the editor).
|
|
59
|
+
* - ONE of url/token present but not the other -> misconfiguration, throws naming
|
|
60
|
+
* the missing var.
|
|
61
|
+
* - url+token present -> ConnectedQaConfig. projectId is OPTIONAL: absent means
|
|
62
|
+
* "connected, no project selected yet" and the user chooses one at runtime.
|
|
63
|
+
* Never logs `token` -- callers must go through `mask()` from log.ts if they log
|
|
64
|
+
* config at all.
|
|
65
|
+
*/
|
|
66
|
+
export declare function resolveConfig(env: NodeJS.ProcessEnv, cliFlags?: Partial<QaConfig>): QaConfig;
|
|
67
|
+
/**
|
|
68
|
+
* Best-effort provider auto-detect (spec §3: explicit config always wins over this).
|
|
69
|
+
* Runs both probes concurrently (never short-circuits) and only returns a provider when
|
|
70
|
+
* exactly one of them gives a confident match. Returns null on any ambiguity -- including
|
|
71
|
+
* ties -- so the caller surfaces `describeAmbiguousProvider` instead of guessing.
|
|
72
|
+
*/
|
|
73
|
+
export declare function detectProvider(url: string, fetchImpl?: typeof fetch): Promise<'walnut' | 'simplifyqa' | null>;
|
|
74
|
+
/**
|
|
75
|
+
* The exact message a caller (the adapter factory, Task 5/6/11/12) should surface when
|
|
76
|
+
* `detectProvider` returns null -- spec §3: "on ambiguity, error asking for QA_MCP_PROVIDER".
|
|
77
|
+
* `detectProvider` itself never throws; this is a pure formatter for whoever does.
|
|
78
|
+
*/
|
|
79
|
+
export declare function describeAmbiguousProvider(url: string): string;
|
|
80
|
+
export {};
|
|
81
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,KAAK,YAAY,GAAG;IAClB,QAAQ,CAAC,EAAE,QAAQ,GAAG,YAAY,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,KAAK,GAAG,KAAK,CAAC;IAC1B,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;;;8EAQ0E;IAC1E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;qDAIiD;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG;IAC3C,IAAI,EAAE,SAAS,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;2DAG2D;AAC3D,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG;IAC7C,IAAI,EAAE,WAAW,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,eAAe,GAAG,iBAAiB,CAAC;AAgH3D;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,EAAE,QAAQ,GAAE,OAAO,CAAC,QAAQ,CAAM,GAAG,QAAQ,CAyBhG;AA4BD;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,SAAS,GAAE,OAAO,KAAa,GAC9B,OAAO,CAAC,QAAQ,GAAG,YAAY,GAAG,IAAI,CAAC,CAoBzC;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK7D"}
|