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.
Files changed (123) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +96 -0
  3. package/dist/adapters/factory.d.ts +15 -0
  4. package/dist/adapters/factory.d.ts.map +1 -0
  5. package/dist/adapters/factory.js +18 -0
  6. package/dist/adapters/factory.js.map +1 -0
  7. package/dist/adapters/remoteMcp/adapter.d.ts +92 -0
  8. package/dist/adapters/remoteMcp/adapter.d.ts.map +1 -0
  9. package/dist/adapters/remoteMcp/adapter.js +219 -0
  10. package/dist/adapters/remoteMcp/adapter.js.map +1 -0
  11. package/dist/adapters/types.d.ts +77 -0
  12. package/dist/adapters/types.d.ts.map +1 -0
  13. package/dist/adapters/types.js +2 -0
  14. package/dist/adapters/types.js.map +1 -0
  15. package/dist/adapters/walnut/actionTypes.d.ts +16 -0
  16. package/dist/adapters/walnut/actionTypes.d.ts.map +1 -0
  17. package/dist/adapters/walnut/actionTypes.js +141 -0
  18. package/dist/adapters/walnut/actionTypes.js.map +1 -0
  19. package/dist/adapters/walnut/mapper.d.ts +34 -0
  20. package/dist/adapters/walnut/mapper.d.ts.map +1 -0
  21. package/dist/adapters/walnut/mapper.js +228 -0
  22. package/dist/adapters/walnut/mapper.js.map +1 -0
  23. package/dist/cli.d.ts +3 -0
  24. package/dist/cli.d.ts.map +1 -0
  25. package/dist/cli.js +36 -0
  26. package/dist/cli.js.map +1 -0
  27. package/dist/config.d.ts +81 -0
  28. package/dist/config.d.ts.map +1 -0
  29. package/dist/config.js +211 -0
  30. package/dist/config.js.map +1 -0
  31. package/dist/connection.d.ts +101 -0
  32. package/dist/connection.d.ts.map +1 -0
  33. package/dist/connection.js +190 -0
  34. package/dist/connection.js.map +1 -0
  35. package/dist/domain/types.d.ts +279 -0
  36. package/dist/domain/types.d.ts.map +1 -0
  37. package/dist/domain/types.js +2 -0
  38. package/dist/domain/types.js.map +1 -0
  39. package/dist/domain/validate.d.ts +3 -0
  40. package/dist/domain/validate.d.ts.map +1 -0
  41. package/dist/domain/validate.js +29 -0
  42. package/dist/domain/validate.js.map +1 -0
  43. package/dist/drafts/store.d.ts +62 -0
  44. package/dist/drafts/store.d.ts.map +1 -0
  45. package/dist/drafts/store.js +119 -0
  46. package/dist/drafts/store.js.map +1 -0
  47. package/dist/httpMain.d.ts +3 -0
  48. package/dist/httpMain.d.ts.map +1 -0
  49. package/dist/httpMain.js +22 -0
  50. package/dist/httpMain.js.map +1 -0
  51. package/dist/index.d.ts +3 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +46 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/initAgents.d.ts +2 -0
  56. package/dist/initAgents.d.ts.map +1 -0
  57. package/dist/initAgents.js +178 -0
  58. package/dist/initAgents.js.map +1 -0
  59. package/dist/log.d.ts +14 -0
  60. package/dist/log.d.ts.map +1 -0
  61. package/dist/log.js +14 -0
  62. package/dist/log.js.map +1 -0
  63. package/dist/mcpResult.d.ts +20 -0
  64. package/dist/mcpResult.d.ts.map +1 -0
  65. package/dist/mcpResult.js +8 -0
  66. package/dist/mcpResult.js.map +1 -0
  67. package/dist/mount.d.ts +12 -0
  68. package/dist/mount.d.ts.map +1 -0
  69. package/dist/mount.js +126 -0
  70. package/dist/mount.js.map +1 -0
  71. package/dist/projectStore.d.ts +5 -0
  72. package/dist/projectStore.d.ts.map +1 -0
  73. package/dist/projectStore.js +60 -0
  74. package/dist/projectStore.js.map +1 -0
  75. package/dist/requestConnection.d.ts +20 -0
  76. package/dist/requestConnection.d.ts.map +1 -0
  77. package/dist/requestConnection.js +44 -0
  78. package/dist/requestConnection.js.map +1 -0
  79. package/dist/serve.d.ts +10 -0
  80. package/dist/serve.d.ts.map +1 -0
  81. package/dist/serve.js +37 -0
  82. package/dist/serve.js.map +1 -0
  83. package/dist/server.d.ts +29 -0
  84. package/dist/server.d.ts.map +1 -0
  85. package/dist/server.js +76 -0
  86. package/dist/server.js.map +1 -0
  87. package/dist/tools/connection.tools.d.ts +16 -0
  88. package/dist/tools/connection.tools.d.ts.map +1 -0
  89. package/dist/tools/connection.tools.js +106 -0
  90. package/dist/tools/connection.tools.js.map +1 -0
  91. package/dist/tools/discovery.tools.d.ts +16 -0
  92. package/dist/tools/discovery.tools.d.ts.map +1 -0
  93. package/dist/tools/discovery.tools.js +369 -0
  94. package/dist/tools/discovery.tools.js.map +1 -0
  95. package/dist/tools/markdown.d.ts +13 -0
  96. package/dist/tools/markdown.d.ts.map +1 -0
  97. package/dist/tools/markdown.js +65 -0
  98. package/dist/tools/markdown.js.map +1 -0
  99. package/dist/tools/recording.tools.d.ts +16 -0
  100. package/dist/tools/recording.tools.d.ts.map +1 -0
  101. package/dist/tools/recording.tools.js +378 -0
  102. package/dist/tools/recording.tools.js.map +1 -0
  103. package/dist/tools/run.tools.d.ts +13 -0
  104. package/dist/tools/run.tools.d.ts.map +1 -0
  105. package/dist/tools/run.tools.js +230 -0
  106. package/dist/tools/run.tools.js.map +1 -0
  107. package/dist/tools/schemas.d.ts +560 -0
  108. package/dist/tools/schemas.d.ts.map +1 -0
  109. package/dist/tools/schemas.js +112 -0
  110. package/dist/tools/schemas.js.map +1 -0
  111. package/dist/tools/testcase.tools.d.ts +50 -0
  112. package/dist/tools/testcase.tools.d.ts.map +1 -0
  113. package/dist/tools/testcase.tools.js +384 -0
  114. package/dist/tools/testcase.tools.js.map +1 -0
  115. package/dist/vendor/actionSignatures.d.ts +117 -0
  116. package/dist/vendor/actionSignatures.d.ts.map +1 -0
  117. package/dist/vendor/actionSignatures.js +420 -0
  118. package/dist/vendor/actionSignatures.js.map +1 -0
  119. package/dist/vendor/logger.d.ts +38 -0
  120. package/dist/vendor/logger.d.ts.map +1 -0
  121. package/dist/vendor/logger.js +174 -0
  122. package/dist/vendor/logger.js.map +1 -0
  123. package/package.json +57 -0
@@ -0,0 +1,279 @@
1
+ export type Locator = {
2
+ name: string;
3
+ value: string;
4
+ unique?: boolean | undefined;
5
+ };
6
+ export type Condition = {
7
+ type: string;
8
+ selector?: string | undefined;
9
+ objectId?: string | undefined;
10
+ text?: string | undefined;
11
+ variableName?: string | undefined;
12
+ variableValue?: string | undefined;
13
+ };
14
+ export type Step = {
15
+ n: number;
16
+ description: string;
17
+ actionType: string;
18
+ /** Opaque provider step id (Walnut step `_id`), carried READ→WRITE so an edit's PUT matches kept
19
+ * steps by identity (update in place) and correctly deletes the ones dropped — not fragile
20
+ * slot-by-number matching. Absent on freshly-inserted steps (the backend then creates them). */
21
+ sourceId?: string | undefined;
22
+ stepType: 'web' | 'api' | 'control_flow' | 'function' | 'database' | 'android' | 'mainframe';
23
+ objectRef?: {
24
+ id?: string | undefined;
25
+ name?: string | undefined;
26
+ locators?: Locator[] | undefined;
27
+ } | undefined;
28
+ value?: string | undefined;
29
+ expectedResult?: string | undefined;
30
+ controlFlow?: {
31
+ kind: 'if' | 'else' | 'if_end' | 'while' | 'while_end';
32
+ condition?: Condition | undefined;
33
+ blockId?: string | undefined;
34
+ maxIterations?: number | undefined;
35
+ } | undefined;
36
+ api?: Record<string, unknown> | undefined;
37
+ db?: Record<string, unknown> | undefined;
38
+ /** NESTED test-case call (stepType 'function'): the child TC this step executes. Carried through
39
+ * the mapper so a nested step ROUND-TRIPS (read→edit→save) without losing its child binding —
40
+ * without this, editing any TC containing a nested step silently drops the reference on save. */
41
+ functionCall?: {
42
+ testCaseId: string;
43
+ testCaseName?: string | undefined;
44
+ inputParams?: Record<string, unknown> | undefined;
45
+ continueOnFailure?: boolean | undefined;
46
+ } | undefined;
47
+ flags?: {
48
+ skip?: boolean | undefined;
49
+ screenshot?: boolean | undefined;
50
+ continueOnFailure?: boolean | undefined;
51
+ optional?: boolean | undefined;
52
+ } | undefined;
53
+ };
54
+ export type TestCase = {
55
+ id?: string | undefined;
56
+ title: string;
57
+ description?: string | undefined;
58
+ objective?: string | undefined;
59
+ priority: 'critical' | 'high' | 'medium' | 'low';
60
+ status?: string | undefined;
61
+ category: 'automated' | 'manual' | 'playwright';
62
+ preconditions?: string | undefined;
63
+ expectedOutcome?: string | undefined;
64
+ folderOrModule?: string | undefined;
65
+ storyRef?: string | undefined;
66
+ tags?: string[] | undefined;
67
+ steps: Step[];
68
+ version?: number | undefined;
69
+ /** Default-row test data: param name -> value. Forwarded to the product on save to populate the
70
+ * datarow of the dataset it auto-creates from the `${param}` tokens in step descriptions, so the
71
+ * saved test case is executable with data. Optional -- the product also derives it from each
72
+ * step's single `${param}` + its value. */
73
+ data?: Record<string, string> | undefined;
74
+ };
75
+ export type TcSummary = {
76
+ id: string;
77
+ title: string;
78
+ priority: string;
79
+ status?: string;
80
+ stepCount?: number;
81
+ };
82
+ export type ProjectSummary = {
83
+ id: string;
84
+ name: string;
85
+ counts?: Record<string, number> | undefined;
86
+ };
87
+ export type TcQuery = {
88
+ search?: string;
89
+ status?: string;
90
+ limit?: number;
91
+ offset?: number;
92
+ };
93
+ /** A USER STORY (Walnut `user_stories` doc, type 'story'). `key` = the human business key (walnut_key
94
+ * like US_001, or an external Jira/ADO key). `id` = the Mongo _id (what test cases link to via story_id). */
95
+ export type StorySummary = {
96
+ id: string;
97
+ key?: string | undefined;
98
+ title: string;
99
+ status?: string | undefined;
100
+ priority?: string | undefined;
101
+ };
102
+ export type Story = {
103
+ id: string;
104
+ key?: string | undefined;
105
+ title: string;
106
+ description?: string | undefined;
107
+ acceptanceCriteria?: string[] | undefined;
108
+ status?: string | undefined;
109
+ priority?: string | undefined;
110
+ };
111
+ export type StoryQuery = {
112
+ search?: string;
113
+ status?: string;
114
+ limit?: number;
115
+ offset?: number;
116
+ };
117
+ export type QaObject = {
118
+ id?: string;
119
+ name: string;
120
+ pageName?: string;
121
+ objectType?: string;
122
+ locators: Locator[];
123
+ };
124
+ export type ObjectQuery = {
125
+ query: string;
126
+ pageName?: string;
127
+ };
128
+ export type Suite = {
129
+ id?: string;
130
+ name: string;
131
+ description?: string;
132
+ members: {
133
+ tcId: string;
134
+ order: number;
135
+ }[];
136
+ };
137
+ export type SuiteSummary = {
138
+ id: string;
139
+ name: string;
140
+ memberCount?: number;
141
+ };
142
+ export type MemberOp = {
143
+ op: 'add' | 'remove' | 'reorder';
144
+ tcId: string;
145
+ order?: number;
146
+ };
147
+ export type RunTarget = {
148
+ tcId?: string;
149
+ suiteId?: string;
150
+ };
151
+ export type RunOptions = {
152
+ environment?: string;
153
+ browser?: string;
154
+ headless?: boolean;
155
+ /** Where to run: 'local' = the connected agent's own browser; 'cloud' = a cloud runner VM.
156
+ * The client MUST decide this (asking the user when unstated) — there is no safe default. */
157
+ mode?: 'local' | 'cloud';
158
+ /** For mode:'cloud' — the specific online cloud runner to dispatch to (resolved from listCloudRunners). */
159
+ cloudRunnerId?: string;
160
+ /** SUITE runs only. Cloud dispatch order across the suite's test cases: 'serial' one-at-a-time,
161
+ * 'batch'/'dynamic' concurrent (with maxConcurrent). Local is always serial. Default 'serial'. */
162
+ strategy?: 'serial' | 'batch' | 'dynamic';
163
+ /** SUITE cloud batch/dynamic only — max test cases running at once. */
164
+ maxConcurrent?: number;
165
+ /** SUITE runs only — stop dispatching remaining test cases after the first failure. */
166
+ terminateOnFailure?: boolean;
167
+ };
168
+ export type RunRef = {
169
+ runId: string;
170
+ };
171
+ /** A cloud runner VM registered to the project. `online` is the single flag the run flow gates on. */
172
+ export type CloudRunner = {
173
+ id: string;
174
+ name: string;
175
+ online: boolean;
176
+ status?: string;
177
+ os?: string;
178
+ };
179
+ export type RunStatus = {
180
+ runId: string;
181
+ state: 'queued' | 'running' | 'passed' | 'failed' | 'stopped' | 'error';
182
+ progress?: {
183
+ done: number;
184
+ total: number;
185
+ };
186
+ stepResults?: {
187
+ n: number;
188
+ description: string;
189
+ status: string;
190
+ error?: string;
191
+ screenshotUrl?: string;
192
+ }[];
193
+ /** SUITE runs only — per-test-case rollup (one row per member). `progress` then counts TEST CASES,
194
+ * not steps. Absent for a single test-case run. */
195
+ children?: {
196
+ id: string;
197
+ title?: string;
198
+ state: 'queued' | 'running' | 'passed' | 'failed' | 'stopped' | 'error';
199
+ }[];
200
+ reportUrl?: string;
201
+ };
202
+ export type SavedRef = {
203
+ id: string;
204
+ productUrl?: string;
205
+ created: boolean;
206
+ artifacts?: string[];
207
+ };
208
+ export type ActionDef = {
209
+ actionType: string;
210
+ platform: string;
211
+ description?: string;
212
+ };
213
+ export type EnvInfo = {
214
+ id: string;
215
+ name: string;
216
+ };
217
+ export type DatasetInfo = {
218
+ id: string;
219
+ name: string;
220
+ rowCount?: number;
221
+ };
222
+ export type EntityRef = {
223
+ kind: 'testcase' | 'suite' | 'run';
224
+ id: string;
225
+ };
226
+ /** The recording-JOURNAL view of a test case, for journal-first editing. `source:'journal'` = steps
227
+ * derived from the stored journal seed (edits stay healer/re-record consistent); `source:'steps'` =
228
+ * fell back to the persisted test_steps because the TC has no journal seed. */
229
+ export type JournalView = {
230
+ tcId: string;
231
+ source: 'journal' | 'steps';
232
+ steps: Step[];
233
+ savedAt?: string | undefined;
234
+ ageDays?: number | undefined;
235
+ entryCount?: number | undefined;
236
+ };
237
+ /** A granular edit op for journal_modify / edit_journal. `n` / `from` / `to` are the CLIENT-VISIBLE
238
+ * step numbers from journal_grep (1-based). Range ops wrap the inclusive [from,to] span. */
239
+ export type JournalOp = {
240
+ op: 'set_meta';
241
+ patch: Partial<TestCase>;
242
+ } | {
243
+ op: 'add_step';
244
+ at?: number | undefined;
245
+ step: Omit<Step, 'n'>;
246
+ } | {
247
+ op: 'update_step';
248
+ n: number;
249
+ patch: Partial<Step>;
250
+ } | {
251
+ op: 'remove_step';
252
+ n: number;
253
+ } | {
254
+ op: 'move_step';
255
+ n: number;
256
+ to: number;
257
+ } | {
258
+ op: 'wrap_in_loop';
259
+ from: number;
260
+ to: number;
261
+ condition?: Condition | undefined;
262
+ maxIterations?: number | undefined;
263
+ } | {
264
+ op: 'wrap_in_if';
265
+ from: number;
266
+ to: number;
267
+ condition?: Condition | undefined;
268
+ } | {
269
+ op: 'insert_nested';
270
+ at?: number | undefined;
271
+ tcId: string;
272
+ name?: string | undefined;
273
+ };
274
+ export type ValidationIssue = {
275
+ step?: number;
276
+ field?: string;
277
+ msg: string;
278
+ };
279
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/domain/types.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,OAAO,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAAE,CAAC;AACpF,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC,CAAC;AACF,MAAM,MAAM,IAAI,GAAG;IACjB,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IACnD;;qGAEiG;IACjG,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,QAAQ,EAAE,KAAK,GAAG,KAAK,GAAG,cAAc,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,WAAW,CAAC;IAC7F,SAAS,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,GAAG,SAAS,CAAA;KAAE,GAAG,SAAS,CAAC;IACjH,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChE,WAAW,CAAC,EAAE;QACZ,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,WAAW,CAAC;QACvD,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;QAClC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC7B,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;KACpC,GAAG,SAAS,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IACpF;;sGAEkG;IAClG,YAAY,CAAC,EAAE;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAClC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;QAClD,iBAAiB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;KACzC,GAAG,SAAS,CAAC;IACd,KAAK,CAAC,EAAE;QACN,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;QAC3B,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;QACjC,iBAAiB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;QACxC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;KAChC,GAAG,SAAS,CAAC;CACf,CAAC;AACF,MAAM,MAAM,QAAQ,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChI,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,QAAQ,EAAE,WAAW,GAAG,QAAQ,GAAG,YAAY,CAAC;IAC/H,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7I,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzE;;;gDAG4C;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAA;CAAE,CAAC;AAC9C,MAAM,MAAM,SAAS,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAC7G,MAAM,MAAM,cAAc,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAA;CAAE,CAAC;AACvG,MAAM,MAAM,OAAO,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAC5F;8GAC8G;AAC9G,MAAM,MAAM,YAAY,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAC/I,MAAM,MAAM,KAAK,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1G,kBAAkB,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAC1G,MAAM,MAAM,UAAU,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAC/F,MAAM,MAAM,QAAQ,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,EAAE,CAAA;CAAE,CAAC;AAClH,MAAM,MAAM,WAAW,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAC/D,MAAM,MAAM,KAAK,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAAC;AACpH,MAAM,MAAM,YAAY,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAC9E,MAAM,MAAM,QAAQ,GAAG;IAAE,EAAE,EAAE,KAAK,GAAG,QAAQ,GAAG,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAC1F,MAAM,MAAM,SAAS,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAC5D,MAAM,MAAM,UAAU,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACpF;kGAC8F;IAC9F,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IACzB,2GAA2G;IAC3G,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;uGACmG;IACnG,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;IAC1C,uEAAuE;IACvE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uFAAuF;IACvF,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AACjC,MAAM,MAAM,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AACvC,sGAAsG;AACtG,MAAM,MAAM,WAAW,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AACtG,MAAM,MAAM,SAAS,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;IAC/G,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,WAAW,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC3G;wDACoD;IACpD,QAAQ,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAA;KAAE,EAAE,CAAC;IACrH,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AACvB,MAAM,MAAM,QAAQ,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AACnG,MAAM,MAAM,SAAS,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AACvF,MAAM,MAAM,OAAO,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AACnD,MAAM,MAAM,WAAW,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAC1E,MAAM,MAAM,SAAS,GAAG;IAAE,IAAI,EAAE,UAAU,GAAG,OAAO,GAAG,KAAK,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAC3E;;gFAEgF;AAChF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;IAC5B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC,CAAC;AACF;6FAC6F;AAC7F,MAAM,MAAM,SAAS,GACjB;IAAE,EAAE,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;CAAE,GAC5C;IAAE,EAAE,EAAE,UAAU,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;CAAE,GAClE;IAAE,EAAE,EAAE,aAAa,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,GACtD;IAAE,EAAE,EAAE,aAAa,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,EAAE,EAAE,WAAW,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,EAAE,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GACvH;IAAE,EAAE,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;CAAE,GACjF;IAAE,EAAE,EAAE,eAAe,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAC9F,MAAM,MAAM,eAAe,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/domain/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ import type { Step, TestCase, ValidationIssue } from './types.js';
2
+ export declare function validateTestCase(tc: TestCase, catalogFor: (s: Step) => Set<string>): ValidationIssue[];
3
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/domain/validate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElE,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC,EAAE,IAAI,KAAK,GAAG,CAAC,MAAM,CAAC,GAAG,eAAe,EAAE,CAoBtG"}
@@ -0,0 +1,29 @@
1
+ export function validateTestCase(tc, catalogFor) {
2
+ const issues = [];
3
+ if (!tc.title?.trim())
4
+ issues.push({ field: 'title', msg: 'title is required' });
5
+ const stack = [];
6
+ for (const s of tc.steps) {
7
+ const catalog = catalogFor(s);
8
+ if (s.stepType === 'control_flow') {
9
+ const k = s.controlFlow?.kind;
10
+ if (k === 'if' || k === 'while')
11
+ stack.push({ kind: k, n: s.n });
12
+ else if (k === 'else' && stack.at(-1)?.kind !== 'if')
13
+ issues.push({ step: s.n, msg: 'else without open if' });
14
+ else if (k === 'if_end' && stack.pop()?.kind !== 'if')
15
+ issues.push({ step: s.n, msg: 'if_end without open if' });
16
+ else if (k === 'while_end' && stack.pop()?.kind !== 'while')
17
+ issues.push({ step: s.n, msg: 'while_end without open while' });
18
+ }
19
+ else if (tc.category !== 'manual' && catalog.size && !catalog.has(s.actionType)) {
20
+ // Manual test cases are descriptive prose (no automation binding), so their steps are not held
21
+ // to the action-type catalog — only automated/playwright steps must name a real action.
22
+ issues.push({ step: s.n, msg: `actionType "${s.actionType}" not in catalog` });
23
+ }
24
+ }
25
+ for (const open of stack)
26
+ issues.push({ step: open.n, msg: `${open.kind} never closed` });
27
+ return issues;
28
+ }
29
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/domain/validate.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,gBAAgB,CAAC,EAAY,EAAE,UAAoC;IACjF,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE;QAAE,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,mBAAmB,EAAE,CAAC,CAAC;IACjF,MAAM,KAAK,GAA0C,EAAE,CAAC;IACxD,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QAC9B,IAAI,CAAC,CAAC,QAAQ,KAAK,cAAc,EAAE,CAAC;YAClC,MAAM,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC;YAC9B,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,OAAO;gBAAE,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;iBAC5D,IAAI,CAAC,KAAK,MAAM,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,IAAI;gBAAE,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,sBAAsB,EAAE,CAAC,CAAC;iBACzG,IAAI,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,GAAG,EAAE,EAAE,IAAI,KAAK,IAAI;gBAAE,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,wBAAwB,EAAE,CAAC,CAAC;iBAC5G,IAAI,CAAC,KAAK,WAAW,IAAI,KAAK,CAAC,GAAG,EAAE,EAAE,IAAI,KAAK,OAAO;gBAAE,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,8BAA8B,EAAE,CAAC,CAAC;QAC/H,CAAC;aAAM,IAAI,EAAE,CAAC,QAAQ,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC;YAClF,+FAA+F;YAC/F,wFAAwF;YACxF,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,eAAe,CAAC,CAAC,UAAU,kBAAkB,EAAE,CAAC,CAAC;QACjF,CAAC;IACH,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI,eAAe,EAAE,CAAC,CAAC;IAC1F,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,62 @@
1
+ import type { Step, TestCase } from '../domain/types.js';
2
+ export type Draft = {
3
+ draftId: string;
4
+ tc: TestCase;
5
+ updatedAt: number;
6
+ };
7
+ export type DraftOp = {
8
+ op: 'set_meta';
9
+ patch: Partial<TestCase>;
10
+ } | {
11
+ op: 'add_step';
12
+ at?: number;
13
+ step: Omit<Step, 'n'>;
14
+ } | {
15
+ op: 'update_step';
16
+ n: number;
17
+ patch: Partial<Step>;
18
+ } | {
19
+ op: 'remove_step';
20
+ n: number;
21
+ } | {
22
+ op: 'move_step';
23
+ n: number;
24
+ to: number;
25
+ };
26
+ /**
27
+ * Thrown by `get`/`applyOps`/`delete` on an unknown draftId. A distinct class
28
+ * (rather than a bare Error) so the tool layer can catch it specifically if it
29
+ * ever needs to, though today every tool just funnels `e.message` into `err()`.
30
+ */
31
+ export declare class DraftNotFoundError extends Error {
32
+ constructor(draftId: string);
33
+ }
34
+ /**
35
+ * In-memory draft store -- deliberately the ENTIRE persistence layer for this
36
+ * server's authoring mode. The user explicitly does not want test-case drafts
37
+ * written anywhere (no disk spill, no backend write) until a future "save"
38
+ * feature exists; this Map is scoped to this process's lifetime and a restart
39
+ * silently loses every open draft. That data loss is intentional, not a defect --
40
+ * do not "fix" it by adding a spill file or any other persistence.
41
+ */
42
+ export declare class DraftStore {
43
+ private readonly drafts;
44
+ private counter;
45
+ create(tc: TestCase): string;
46
+ get(draftId: string): Draft;
47
+ /**
48
+ * Bind a draft to the product id it was just saved as. After tc_save CREATES a test case, the draft
49
+ * still has no `tc.id`; stamping it here means a later tc_draft_update + tc_save is an UPDATE of that
50
+ * same test case (tc_save keys create-vs-update on `tc.id`) instead of minting a duplicate.
51
+ */
52
+ markSaved(draftId: string, id: string): void;
53
+ delete(draftId: string): void;
54
+ /**
55
+ * Applies ops in order, renumbering steps contiguously from 1 after EVERY op
56
+ * (not just at the end) -- later ops in the same call address steps by the
57
+ * number they'd have *after* the previous op, matching how a caller reasons
58
+ * about the draft one op at a time.
59
+ */
60
+ applyOps(draftId: string, ops: DraftOp[]): Draft;
61
+ }
62
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/drafts/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEzD,MAAM,MAAM,KAAK,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzE,MAAM,MAAM,OAAO,GACf;IAAE,EAAE,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;CAAE,GAC5C;IAAE,EAAE,EAAE,UAAU,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;CAAE,GACtD;IAAE,EAAE,EAAE,aAAa,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,GACtD;IAAE,EAAE,EAAE,aAAa,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,EAAE,EAAE,WAAW,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/C;;;;GAIG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAQ5B;AAUD;;;;;;;GAOG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;IACnD,OAAO,CAAC,OAAO,CAAK;IAEpB,MAAM,CAAC,EAAE,EAAE,QAAQ,GAAG,MAAM;IAM5B,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK;IAM3B;;;;OAIG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAO5C,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI7B;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,KAAK;CAYjD"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Thrown by `get`/`applyOps`/`delete` on an unknown draftId. A distinct class
3
+ * (rather than a bare Error) so the tool layer can catch it specifically if it
4
+ * ever needs to, though today every tool just funnels `e.message` into `err()`.
5
+ */
6
+ export class DraftNotFoundError extends Error {
7
+ constructor(draftId) {
8
+ super(`No draft found for id "${draftId}". Drafts are in-memory only and never ` +
9
+ `persisted -- this id may have been discarded, or the server process may ` +
10
+ `have restarted since it was created.`);
11
+ this.name = 'DraftNotFoundError';
12
+ }
13
+ }
14
+ function renumber(steps) {
15
+ return steps.map((s, i) => ({ ...s, n: i + 1 }));
16
+ }
17
+ function clamp(n, min, max) {
18
+ return Math.min(Math.max(n, min), max);
19
+ }
20
+ /**
21
+ * In-memory draft store -- deliberately the ENTIRE persistence layer for this
22
+ * server's authoring mode. The user explicitly does not want test-case drafts
23
+ * written anywhere (no disk spill, no backend write) until a future "save"
24
+ * feature exists; this Map is scoped to this process's lifetime and a restart
25
+ * silently loses every open draft. That data loss is intentional, not a defect --
26
+ * do not "fix" it by adding a spill file or any other persistence.
27
+ */
28
+ export class DraftStore {
29
+ constructor() {
30
+ this.drafts = new Map();
31
+ this.counter = 0;
32
+ }
33
+ create(tc) {
34
+ const draftId = `draft_${Date.now().toString(36)}_${(++this.counter).toString(36)}`;
35
+ this.drafts.set(draftId, { draftId, tc: { ...tc, steps: renumber(tc.steps) }, updatedAt: Date.now() });
36
+ return draftId;
37
+ }
38
+ get(draftId) {
39
+ const d = this.drafts.get(draftId);
40
+ if (!d)
41
+ throw new DraftNotFoundError(draftId);
42
+ return d;
43
+ }
44
+ /**
45
+ * Bind a draft to the product id it was just saved as. After tc_save CREATES a test case, the draft
46
+ * still has no `tc.id`; stamping it here means a later tc_draft_update + tc_save is an UPDATE of that
47
+ * same test case (tc_save keys create-vs-update on `tc.id`) instead of minting a duplicate.
48
+ */
49
+ markSaved(draftId, id) {
50
+ const d = this.drafts.get(draftId);
51
+ if (!d)
52
+ throw new DraftNotFoundError(draftId);
53
+ d.tc = { ...d.tc, id };
54
+ d.updatedAt = Date.now();
55
+ }
56
+ delete(draftId) {
57
+ if (!this.drafts.delete(draftId))
58
+ throw new DraftNotFoundError(draftId);
59
+ }
60
+ /**
61
+ * Applies ops in order, renumbering steps contiguously from 1 after EVERY op
62
+ * (not just at the end) -- later ops in the same call address steps by the
63
+ * number they'd have *after* the previous op, matching how a caller reasons
64
+ * about the draft one op at a time.
65
+ */
66
+ applyOps(draftId, ops) {
67
+ const current = this.get(draftId);
68
+ let tc = current.tc;
69
+ for (const opItem of ops) {
70
+ tc = applyOne(tc, opItem);
71
+ }
72
+ const updated = { draftId, tc, updatedAt: Date.now() };
73
+ this.drafts.set(draftId, updated);
74
+ return updated;
75
+ }
76
+ }
77
+ function applyOne(tc, opItem) {
78
+ switch (opItem.op) {
79
+ case 'set_meta': {
80
+ // `steps` is deliberately never accepted through set_meta -- steps are
81
+ // exclusively managed by add_step/update_step/remove_step/move_step so
82
+ // renumbering invariants can never be bypassed.
83
+ const { steps: _ignored, ...metaPatch } = opItem.patch;
84
+ return { ...tc, ...metaPatch };
85
+ }
86
+ case 'add_step': {
87
+ const idx = opItem.at != null ? clamp(opItem.at - 1, 0, tc.steps.length) : tc.steps.length;
88
+ const newStep = { ...opItem.step, n: 0 }; // n is overwritten by renumber() below
89
+ const steps = [...tc.steps.slice(0, idx), newStep, ...tc.steps.slice(idx)];
90
+ return { ...tc, steps: renumber(steps) };
91
+ }
92
+ case 'update_step': {
93
+ if (!tc.steps.some((s) => s.n === opItem.n)) {
94
+ throw new Error(`update_step: no step numbered ${opItem.n} (draft has ${tc.steps.length} step(s))`);
95
+ }
96
+ const steps = tc.steps.map((s) => (s.n === opItem.n ? { ...s, ...opItem.patch, n: s.n } : s));
97
+ return { ...tc, steps: renumber(steps) };
98
+ }
99
+ case 'remove_step': {
100
+ if (!tc.steps.some((s) => s.n === opItem.n)) {
101
+ throw new Error(`remove_step: no step numbered ${opItem.n} (draft has ${tc.steps.length} step(s))`);
102
+ }
103
+ const steps = tc.steps.filter((s) => s.n !== opItem.n);
104
+ return { ...tc, steps: renumber(steps) };
105
+ }
106
+ case 'move_step': {
107
+ const fromIdx = tc.steps.findIndex((s) => s.n === opItem.n);
108
+ if (fromIdx === -1) {
109
+ throw new Error(`move_step: no step numbered ${opItem.n} (draft has ${tc.steps.length} step(s))`);
110
+ }
111
+ const moved = tc.steps[fromIdx];
112
+ const without = [...tc.steps.slice(0, fromIdx), ...tc.steps.slice(fromIdx + 1)];
113
+ const toIdx = clamp(opItem.to - 1, 0, without.length);
114
+ const steps = [...without.slice(0, toIdx), moved, ...without.slice(toIdx)];
115
+ return { ...tc, steps: renumber(steps) };
116
+ }
117
+ }
118
+ }
119
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/drafts/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=httpMain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"httpMain.d.ts","sourceRoot":"","sources":["../src/httpMain.ts"],"names":[],"mappings":""}
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Standalone HTTP entrypoint for the Common QA MCP gateway.
4
+ *
5
+ * Starts a loopback Express server and mounts the MCP at /mcp. An AI client connects with just a URL
6
+ * + token (the connection is primed from the request's Authorization / x-qa-* headers -- see
7
+ * requestConnection.ts), and the gateway routes to Walnut (REST) or SimplifyQA (its own MCP) per the
8
+ * `x-qa-product` header. Bound to 127.0.0.1 -- it is a local gateway, not a public server.
9
+ *
10
+ * `mountQaMcp` is registered BEFORE any body parser (it reads the raw body itself), so no
11
+ * express.json() is added here.
12
+ */
13
+ import express from 'express';
14
+ import { mountQaMcp } from './mount.js';
15
+ import { log } from './log.js';
16
+ const PORT = Number(process.env['PORT'] ?? 4060);
17
+ const app = express();
18
+ mountQaMcp(app);
19
+ app.listen(PORT, '127.0.0.1', () => {
20
+ log(`common-qa-mcp gateway ready on http://127.0.0.1:${PORT}/mcp`);
21
+ });
22
+ //# sourceMappingURL=httpMain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"httpMain.js","sourceRoot":"","sources":["../src/httpMain.ts"],"names":[],"mappings":";AACA;;;;;;;;;;GAUG;AACH,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC;AAEjD,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;AACtB,UAAU,CAAC,GAAG,CAAC,CAAC;AAChB,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE;IACjC,GAAG,CAAC,mDAAmD,IAAI,MAAM,CAAC,CAAC;AACrE,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Standalone stdio entry point -- kept ONLY as a local dev harness for exercising
4
+ * this tool surface with a real MCP stdio client (e.g. the MCP Inspector) without
5
+ * going through the agent's HTTP mount. This is explicitly NOT part of the
6
+ * product path:
7
+ * - not referenced by package.json's `bin` or `main`
8
+ * - not one of esbuild.config.js's entryPoints (only src/server.ts is bundled)
9
+ * - not imported from src/server.ts or src/routes/index.ts
10
+ * The product path is src/mcp/qa/mount.ts, mounted at POST/GET/DELETE /mcp on the
11
+ * agent's own Express app (see src/server.ts). Run this file directly only for
12
+ * local debugging: `npx tsx src/mcp/qa/index.ts`.
13
+ *
14
+ * Simplified from the original common-qa-mcp CLI: drops the `commander`-based
15
+ * --port/--connection/--caps flags (commander is not a declared dependency of
16
+ * this repo, and adding one for a dev-only harness would violate the "costs
17
+ * nothing" bar this file is held to). Configure via QA_MCP_* env vars instead
18
+ * (see config.ts) -- functionally equivalent for local debugging.
19
+ */
20
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
21
+ import { buildServer } from './server.js';
22
+ import { resolveConfig } from './config.js';
23
+ import { createAdapter } from './adapters/factory.js';
24
+ import { log, mask } from './log.js';
25
+ function loadConfig() {
26
+ try {
27
+ return resolveConfig(process.env);
28
+ }
29
+ catch (e) {
30
+ log(e instanceof Error ? e.message : String(e));
31
+ process.exit(1);
32
+ }
33
+ }
34
+ const config = loadConfig();
35
+ if (config.mode === 'offline') {
36
+ log('config resolved: mode=offline (no QA_MCP_URL/TOKEN/PROJECT_ID) -- draft authoring only, zero network');
37
+ }
38
+ else {
39
+ log(`config resolved: mode=connected provider=${config.provider ?? '(auto)'} url=${config.url} ` +
40
+ `projectId=${config.projectId} token=${mask(config.token)}`);
41
+ }
42
+ const adapter = createAdapter(config);
43
+ const server = buildServer({ adapter, mode: config.mode, walnutUiOrigin: config.walnutUiOrigin, agentUrl: config.agentUrl });
44
+ await server.connect(new StdioServerTransport());
45
+ log('stdio server ready');
46
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAiB,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAErC,SAAS,UAAU;IACjB,IAAI,CAAC;QACH,OAAO,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,GAAG,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;AAC5B,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;IAC9B,GAAG,CAAC,sGAAsG,CAAC,CAAC;AAC9G,CAAC;KAAM,CAAC;IACN,GAAG,CACD,4CAA4C,MAAM,CAAC,QAAQ,IAAI,QAAQ,QAAQ,MAAM,CAAC,GAAG,GAAG;QAC1F,aAAa,MAAM,CAAC,SAAS,UAAU,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAC9D,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;AACtC,MAAM,MAAM,GAAG,WAAW,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,CAAC,cAAc,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC7H,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC;AACjD,GAAG,CAAC,oBAAoB,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function runInitAgents(args: string[]): Promise<void>;
2
+ //# sourceMappingURL=initAgents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"initAgents.d.ts","sourceRoot":"","sources":["../src/initAgents.ts"],"names":[],"mappings":"AAyKA,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA0CjE"}