codeloop-mcp-server 0.1.73 → 0.1.75

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 (37) hide show
  1. package/dist/evidence/backend_verification.d.ts +27 -0
  2. package/dist/evidence/backend_verification.d.ts.map +1 -1
  3. package/dist/evidence/backend_verification.js +22 -0
  4. package/dist/evidence/backend_verification.js.map +1 -1
  5. package/dist/index.js +54 -0
  6. package/dist/index.js.map +1 -1
  7. package/dist/runners/backend_runtime.d.ts +21 -0
  8. package/dist/runners/backend_runtime.d.ts.map +1 -1
  9. package/dist/runners/backend_runtime.js +157 -6
  10. package/dist/runners/backend_runtime.js.map +1 -1
  11. package/dist/runners/device_probe.d.ts +41 -0
  12. package/dist/runners/device_probe.d.ts.map +1 -1
  13. package/dist/runners/device_probe.js +162 -1
  14. package/dist/runners/device_probe.js.map +1 -1
  15. package/dist/runners/flutter.d.ts +17 -0
  16. package/dist/runners/flutter.d.ts.map +1 -1
  17. package/dist/runners/flutter.js +47 -13
  18. package/dist/runners/flutter.js.map +1 -1
  19. package/dist/runners/interaction_engine.d.ts +59 -0
  20. package/dist/runners/interaction_engine.d.ts.map +1 -0
  21. package/dist/runners/interaction_engine.js +272 -0
  22. package/dist/runners/interaction_engine.js.map +1 -0
  23. package/dist/tools/gate_check.d.ts.map +1 -1
  24. package/dist/tools/gate_check.js +15 -1
  25. package/dist/tools/gate_check.js.map +1 -1
  26. package/dist/tools/plan_user_journey.d.ts +8 -0
  27. package/dist/tools/plan_user_journey.d.ts.map +1 -1
  28. package/dist/tools/plan_user_journey.js +20 -7
  29. package/dist/tools/plan_user_journey.js.map +1 -1
  30. package/dist/tools/run_journey.d.ts +69 -0
  31. package/dist/tools/run_journey.d.ts.map +1 -0
  32. package/dist/tools/run_journey.js +309 -0
  33. package/dist/tools/run_journey.js.map +1 -0
  34. package/dist/tools/verify.d.ts.map +1 -1
  35. package/dist/tools/verify.js +5 -1
  36. package/dist/tools/verify.js.map +1 -1
  37. package/package.json +2 -2
@@ -2,4 +2,21 @@ import type { RunnerResult } from "./base.js";
2
2
  export declare function runFlutterAnalyze(cwd: string, logPath: string): Promise<RunnerResult>;
3
3
  export declare function runFlutterTest(cwd: string, logPath: string): Promise<RunnerResult>;
4
4
  export declare function runFlutterIntegrationTest(cwd: string, logPath: string): Promise<RunnerResult>;
5
+ /**
6
+ * Severity-aware classification of `flutter analyze` output.
7
+ *
8
+ * `flutter analyze` lists every diagnostic — info, warning AND error — and
9
+ * prints a trailing "N issues found." total. The OLD parser matched that total
10
+ * and reported it ALL as `failed`, so a project with thousands of harmless
11
+ * `avoid_print`/style INFO lints (and maybe one real error) looked
12
+ * catastrophically broken. We now classify by severity and let the caller fail
13
+ * only on ERRORS (matching the deep-internal static_analysis gate's
14
+ * errors-only policy), while still surfacing the warning/info counts.
15
+ */
16
+ export declare function classifyAnalyzeOutput(output: string): {
17
+ errors: number;
18
+ warnings: number;
19
+ infos: number;
20
+ total: number;
21
+ };
5
22
  //# sourceMappingURL=flutter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"flutter.d.ts","sourceRoot":"","sources":["../../src/runners/flutter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AA2C9C,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,YAAY,CAAC,CA2CvB;AAED,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,YAAY,CAAC,CAuDvB;AAED,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,YAAY,CAAC,CAsGvB"}
1
+ {"version":3,"file":"flutter.d.ts","sourceRoot":"","sources":["../../src/runners/flutter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AA4C9C,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,YAAY,CAAC,CAiEvB;AAED,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,YAAY,CAAC,CAuDvB;AAED,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,YAAY,CAAC,CAsGvB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAWA"}
@@ -1,5 +1,6 @@
1
1
  import { runCommand, checkToolAvailable, makeSkippedResult } from "./base.js";
2
2
  import { runFlutterAnalyzeOnce, runFlutterTestCoverageOnce, FLUTTER_TEST_SETTLE, FLUTTER_TEST_STALL, } from "./flutter_cache.js";
3
+ import { parseFlutterAnalyzeOutput, reconcile } from "./static_analysis.js";
3
4
  import { existsSync } from "fs";
4
5
  import { join } from "path";
5
6
  // Wall-clock watchdogs for the Flutter verify commands. Before this, all
@@ -55,18 +56,39 @@ export async function runFlutterAnalyze(cwd, logPath) {
55
56
  stderr: `${note}\n${result.stderr}`,
56
57
  };
57
58
  }
58
- const analyzeResult = parseAnalyzeOutput(result.stdout + result.stderr);
59
+ const combined = result.stdout + result.stderr;
60
+ const { errors, warnings, infos, total } = classifyAnalyzeOutput(combined);
61
+ // ERRORS-ONLY blocker policy (same as the deep-internal static_analysis
62
+ // gate): only error-severity diagnostics count as failures. `reconcile`
63
+ // promotes an UNEXPLAINED non-zero exit (0 errors AND 0 warnings parsed) to
64
+ // a single error so a parser miss / tool crash never silently passes; it
65
+ // does NOT promote when warnings explain the non-zero exit.
66
+ const failed = reconcile({ errors, warnings }, result.exit_code).errors;
67
+ // Surface the warning/info breakdown so the agent SEES the lint debt without
68
+ // it inflating the failure count. Before this fix the runner reported EVERY
69
+ // issue (info + warning + error) as a failure — a Flutter app with 2,517
70
+ // mostly-`avoid_print` info lints in tool/ scripts and ONE real error
71
+ // produced `failed: 2517` (the WedCheese "2524 failed" headline), which
72
+ // tanked confidence to 0 and made the build gate fail on lint noise.
73
+ let stderr = result.stderr;
74
+ if (total > 0 && (warnings > 0 || infos > 0)) {
75
+ stderr =
76
+ `[CodeLoop] flutter analyze: ${failed} error(s) [BLOCKING], ` +
77
+ `${warnings} warning(s), ${infos} info(s) [NON-BLOCKING lint, e.g. avoid_print]. ` +
78
+ `Only errors fail the build gate; the ${warnings + infos} warning/info ` +
79
+ `finding(s) are surfaced for cleanup but do NOT count as failures.\n${stderr}`;
80
+ }
59
81
  return {
60
82
  runner_name: "flutter_analyze",
61
83
  available: true,
62
84
  exit_code: result.exit_code,
63
- passed: analyzeResult.passed,
64
- failed: analyzeResult.failed,
85
+ passed: failed === 0 ? 1 : 0,
86
+ failed,
65
87
  skipped: 0,
66
88
  log_path: logPath,
67
89
  duration_ms: result.duration_ms,
68
90
  stdout: result.stdout,
69
- stderr: result.stderr,
91
+ stderr,
70
92
  };
71
93
  }
72
94
  export async function runFlutterTest(cwd, logPath) {
@@ -196,16 +218,28 @@ export async function runFlutterIntegrationTest(cwd, logPath) {
196
218
  stderr: result.stderr,
197
219
  };
198
220
  }
199
- function parseAnalyzeOutput(output) {
200
- // "No issues found!" or "X issue(s) found"
201
- if (output.includes("No issues found")) {
202
- return { passed: 1, failed: 0 };
203
- }
204
- const issueMatch = output.match(/(\d+)\s+issue/);
205
- if (issueMatch) {
206
- return { passed: 0, failed: parseInt(issueMatch[1], 10) };
221
+ /**
222
+ * Severity-aware classification of `flutter analyze` output.
223
+ *
224
+ * `flutter analyze` lists every diagnostic — info, warning AND error — and
225
+ * prints a trailing "N issues found." total. The OLD parser matched that total
226
+ * and reported it ALL as `failed`, so a project with thousands of harmless
227
+ * `avoid_print`/style INFO lints (and maybe one real error) looked
228
+ * catastrophically broken. We now classify by severity and let the caller fail
229
+ * only on ERRORS (matching the deep-internal static_analysis gate's
230
+ * errors-only policy), while still surfacing the warning/info counts.
231
+ */
232
+ export function classifyAnalyzeOutput(output) {
233
+ if (/No issues found/i.test(output)) {
234
+ return { errors: 0, warnings: 0, infos: 0, total: 0 };
207
235
  }
208
- return { passed: 0, failed: 0 };
236
+ // parseFlutterAnalyzeOutput counts `error •` / `warning •` severity lines.
237
+ const { errors, warnings } = parseFlutterAnalyzeOutput(output);
238
+ const totalMatch = output.match(/(\d+)\s+issue/);
239
+ const total = totalMatch ? parseInt(totalMatch[1], 10) : errors + warnings;
240
+ // Anything in the total that isn't an error or warning is an info lint.
241
+ const infos = Math.max(0, total - errors - warnings);
242
+ return { errors, warnings, infos, total };
209
243
  }
210
244
  function parseFlutterTestOutput(output) {
211
245
  let passed = 0;
@@ -1 +1 @@
1
- {"version":3,"file":"flutter.js","sourceRoot":"","sources":["../../src/runners/flutter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"flutter.js","sourceRoot":"","sources":["../../src/runners/flutter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Interaction engine — the reusable core that DRIVES a single UI step against
3
+ * a running app, across all four target types (browser / desktop / Android /
4
+ * iOS). It dispatches the journey-relevant action set to the same low-level
5
+ * primitives the `codeloop_interact` MCP tool uses (browser_interaction.ts +
6
+ * window_manager.ts), so the new server-side orchestrator (codeloop_run_journey)
7
+ * can drive a planned journey end-to-end WITHOUT a per-step MCP round-trip.
8
+ *
9
+ * Scope: this engine intentionally covers the subset of actions a planned
10
+ * journey needs (navigate, click, type, submit, fill, read-back/assert, scroll,
11
+ * wait, simple mobile taps/keys). The full, exhaustive action surface (UIA
12
+ * automation, Maestro flows, biometric, network shaping, drag, etc.) remains in
13
+ * the `codeloop_interact` tool. When the engine hits an action or a missing
14
+ * field it can't satisfy, it returns `{ success: false, unsupported: true }`
15
+ * with a directive so the orchestrator can fall back to the agent instead of
16
+ * failing the whole run.
17
+ */
18
+ export type JourneyTarget = "browser" | "desktop" | "android_emulator" | "ios_simulator";
19
+ export interface InteractionStep {
20
+ action: string;
21
+ selector?: string;
22
+ text?: string;
23
+ url?: string;
24
+ x?: number;
25
+ y?: number;
26
+ x2?: number;
27
+ y2?: number;
28
+ key?: string;
29
+ keys?: string;
30
+ direction?: "up" | "down" | "left" | "right";
31
+ amount?: number;
32
+ duration_ms?: number;
33
+ /** [get_text] assert the read-back text contains this substring (ci). */
34
+ expect_contains?: string;
35
+ /** Semantic label for CRUD/intent classification (logged by the caller). */
36
+ intent?: string;
37
+ }
38
+ export interface InteractionContext {
39
+ target: JourneyTarget;
40
+ /** App name for desktop front-bring (optional). */
41
+ app_name?: string;
42
+ }
43
+ export interface InteractionResult {
44
+ action: string;
45
+ success: boolean;
46
+ detail: string;
47
+ /** Text read back by a get_text action. */
48
+ extractedText?: string | null;
49
+ assertion?: {
50
+ expected: string;
51
+ matched: boolean;
52
+ actual_excerpt: string;
53
+ };
54
+ /** True when the engine can't satisfy this step (caller should fall back). */
55
+ unsupported?: boolean;
56
+ }
57
+ /** Drive a single journey step. Never throws; returns a structured result. */
58
+ export declare function executeInteraction(step: InteractionStep, ctx: InteractionContext): Promise<InteractionResult>;
59
+ //# sourceMappingURL=interaction_engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interaction_engine.d.ts","sourceRoot":"","sources":["../../src/runners/interaction_engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,MAAM,aAAa,GACrB,SAAS,GACT,SAAS,GACT,kBAAkB,GAClB,eAAe,CAAC;AAEpB,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yEAAyE;IACzE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,4EAA4E;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,aAAa,CAAC;IACtB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3E,8EAA8E;IAC9E,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AA0BD,8EAA8E;AAC9E,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,eAAe,EACrB,GAAG,EAAE,kBAAkB,GACtB,OAAO,CAAC,iBAAiB,CAAC,CAwB5B"}
@@ -0,0 +1,272 @@
1
+ /**
2
+ * Interaction engine — the reusable core that DRIVES a single UI step against
3
+ * a running app, across all four target types (browser / desktop / Android /
4
+ * iOS). It dispatches the journey-relevant action set to the same low-level
5
+ * primitives the `codeloop_interact` MCP tool uses (browser_interaction.ts +
6
+ * window_manager.ts), so the new server-side orchestrator (codeloop_run_journey)
7
+ * can drive a planned journey end-to-end WITHOUT a per-step MCP round-trip.
8
+ *
9
+ * Scope: this engine intentionally covers the subset of actions a planned
10
+ * journey needs (navigate, click, type, submit, fill, read-back/assert, scroll,
11
+ * wait, simple mobile taps/keys). The full, exhaustive action surface (UIA
12
+ * automation, Maestro flows, biometric, network shaping, drag, etc.) remains in
13
+ * the `codeloop_interact` tool. When the engine hits an action or a missing
14
+ * field it can't satisfy, it returns `{ success: false, unsupported: true }`
15
+ * with a directive so the orchestrator can fall back to the agent instead of
16
+ * failing the whole run.
17
+ */
18
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
19
+ function unsupported(action, why) {
20
+ return {
21
+ action,
22
+ success: false,
23
+ unsupported: true,
24
+ detail: `[engine] ${why} — fall back to codeloop_interact for this step.`,
25
+ };
26
+ }
27
+ function buildAssertion(expect, actual) {
28
+ if (!expect)
29
+ return undefined;
30
+ const hay = (actual ?? "").toLowerCase();
31
+ return {
32
+ expected: expect,
33
+ matched: hay.includes(expect.toLowerCase()),
34
+ actual_excerpt: (actual ?? "").slice(0, 280),
35
+ };
36
+ }
37
+ /** Drive a single journey step. Never throws; returns a structured result. */
38
+ export async function executeInteraction(step, ctx) {
39
+ const action = step.action;
40
+ try {
41
+ // wait is target-agnostic.
42
+ if (action === "wait") {
43
+ await sleep(step.duration_ms ?? 1000);
44
+ return { action, success: true, detail: `waited ${step.duration_ms ?? 1000}ms` };
45
+ }
46
+ switch (ctx.target) {
47
+ case "browser":
48
+ return await driveBrowser(step, ctx);
49
+ case "desktop":
50
+ return await driveDesktop(step, ctx);
51
+ case "android_emulator":
52
+ return await driveAndroid(step, ctx);
53
+ case "ios_simulator":
54
+ return await driveIos(step, ctx);
55
+ default:
56
+ return unsupported(action, `unknown target ${String(ctx.target)}`);
57
+ }
58
+ }
59
+ catch (e) {
60
+ return { action, success: false, detail: `[engine] error: ${e.message}` };
61
+ }
62
+ }
63
+ // ── Browser (Playwright) ────────────────────────────────────────────
64
+ async function driveBrowser(step, _ctx) {
65
+ const bi = await import("./browser_interaction.js");
66
+ await bi.ensureBrowserPage();
67
+ const a = step.action;
68
+ const sel = step.selector;
69
+ switch (a) {
70
+ case "navigate_url":
71
+ if (!step.url)
72
+ return unsupported(a, "navigate_url needs a url");
73
+ return { action: a, success: await bi.browserNavigate(step.url), detail: `navigate ${step.url}` };
74
+ case "navigate_back":
75
+ return { action: a, success: await bi.browserGoBack(), detail: "back" };
76
+ case "navigate_forward":
77
+ return { action: a, success: await bi.browserGoForward(), detail: "forward" };
78
+ case "click":
79
+ if (!sel)
80
+ return unsupported(a, "browser click needs a selector");
81
+ return { action: a, success: await bi.browserClick(sel), detail: `click ${sel}` };
82
+ case "double_click":
83
+ if (!sel)
84
+ return unsupported(a, "double_click needs a selector");
85
+ return { action: a, success: await bi.browserDoubleClick(sel), detail: `double_click ${sel}` };
86
+ case "hover":
87
+ if (!sel)
88
+ return unsupported(a, "hover needs a selector");
89
+ return { action: a, success: await bi.browserHover(sel), detail: `hover ${sel}` };
90
+ case "type":
91
+ if (!sel || step.text == null)
92
+ return unsupported(a, "type needs selector+text");
93
+ return { action: a, success: await bi.browserType(sel, step.text), detail: `type into ${sel}` };
94
+ case "type_and_submit":
95
+ if (!sel || step.text == null)
96
+ return unsupported(a, "type_and_submit needs selector+text");
97
+ return { action: a, success: await bi.browserTypeAndSubmit(sel, step.text), detail: `type+submit ${sel}` };
98
+ case "type_and_tab":
99
+ if (!sel || step.text == null)
100
+ return unsupported(a, "type_and_tab needs selector+text");
101
+ return { action: a, success: await bi.browserTypeAndTab(sel, step.text), detail: `type+tab ${sel}` };
102
+ case "select_option":
103
+ if (!sel || step.text == null)
104
+ return unsupported(a, "select_option needs selector+value");
105
+ return { action: a, success: await bi.browserSelectOption(sel, step.text), detail: `select ${sel}` };
106
+ case "toggle":
107
+ if (!sel)
108
+ return unsupported(a, "toggle needs a selector");
109
+ return { action: a, success: await bi.browserToggle(sel), detail: `toggle ${sel}` };
110
+ case "scroll":
111
+ return { action: a, success: await bi.browserScroll(step.direction ?? "down", step.amount ?? 300), detail: `scroll ${step.direction ?? "down"}` };
112
+ case "hotkey":
113
+ if (!step.keys)
114
+ return unsupported(a, "hotkey needs keys");
115
+ return { action: a, success: await bi.browserHotkey(step.keys), detail: `hotkey ${step.keys}` };
116
+ case "keystroke":
117
+ if (!step.key)
118
+ return unsupported(a, "keystroke needs key");
119
+ return { action: a, success: await bi.browserKeystroke(step.key), detail: `key ${step.key}` };
120
+ case "get_text": {
121
+ const text = await bi.browserGetText(sel);
122
+ const assertion = buildAssertion(step.expect_contains, text);
123
+ return {
124
+ action: a,
125
+ success: assertion ? assertion.matched : text != null,
126
+ detail: assertion ? `assert "${step.expect_contains}" -> ${assertion.matched}` : "read text",
127
+ extractedText: text,
128
+ assertion,
129
+ };
130
+ }
131
+ default:
132
+ return unsupported(a, `browser action "${a}" not in the engine subset`);
133
+ }
134
+ }
135
+ // ── Desktop (CGEvent / user32 / xdotool) ────────────────────────────
136
+ async function driveDesktop(step, ctx) {
137
+ const wm = await import("./window_manager.js");
138
+ if (ctx.app_name) {
139
+ try {
140
+ await wm.bringAppToFront(ctx.app_name);
141
+ }
142
+ catch { /* best-effort */ }
143
+ }
144
+ const a = step.action;
145
+ switch (a) {
146
+ case "navigate_url":
147
+ if (!step.url)
148
+ return unsupported(a, "navigate_url needs a url");
149
+ return { action: a, success: await wm.navigateDesktopBrowser(step.url), detail: `open ${step.url}` };
150
+ case "click":
151
+ if (step.x == null || step.y == null)
152
+ return unsupported(a, "desktop click needs x,y (or use codeloop_interact for text/UIA targeting)");
153
+ return { action: a, success: await wm.clickAtPosition(step.x, step.y), detail: `click (${step.x},${step.y})` };
154
+ case "double_click":
155
+ if (step.x == null || step.y == null)
156
+ return unsupported(a, "double_click needs x,y");
157
+ return { action: a, success: await wm.doubleClickAtPosition(step.x, step.y), detail: `double_click (${step.x},${step.y})` };
158
+ case "right_click":
159
+ if (step.x == null || step.y == null)
160
+ return unsupported(a, "right_click needs x,y");
161
+ return { action: a, success: await wm.rightClickAtPosition(step.x, step.y), detail: `right_click (${step.x},${step.y})` };
162
+ case "hover":
163
+ if (step.x == null || step.y == null)
164
+ return unsupported(a, "hover needs x,y");
165
+ return { action: a, success: await wm.hoverAtPosition(step.x, step.y), detail: `hover (${step.x},${step.y})` };
166
+ case "type":
167
+ if (step.text == null)
168
+ return unsupported(a, "type needs text");
169
+ return { action: a, success: await wm.typeText(step.text), detail: "type" };
170
+ case "scroll":
171
+ if (step.x == null || step.y == null)
172
+ return unsupported(a, "desktop scroll needs x,y");
173
+ return { action: a, success: await wm.scrollAtPosition(step.x, step.y, step.direction ?? "down", step.amount ?? 3), detail: `scroll ${step.direction ?? "down"}` };
174
+ case "hotkey":
175
+ if (!step.keys)
176
+ return unsupported(a, "hotkey needs keys");
177
+ return { action: a, success: await wm.sendHotkey(step.keys), detail: `hotkey ${step.keys}` };
178
+ case "keystroke":
179
+ if (!step.key)
180
+ return unsupported(a, "keystroke needs key");
181
+ return { action: a, success: await wm.sendKeyByName(step.key), detail: `key ${step.key}` };
182
+ default:
183
+ return unsupported(a, `desktop action "${a}" not in the engine subset`);
184
+ }
185
+ }
186
+ // ── Android (adb) ───────────────────────────────────────────────────
187
+ async function driveAndroid(step, _ctx) {
188
+ const wm = await import("./window_manager.js");
189
+ const a = step.action;
190
+ switch (a) {
191
+ case "click":
192
+ case "tap":
193
+ if (step.x == null || step.y == null)
194
+ return unsupported(a, "android tap needs x,y");
195
+ return { action: a, success: await wm.adbTap(step.x, step.y), detail: `tap (${step.x},${step.y})` };
196
+ case "type":
197
+ if (step.text == null)
198
+ return unsupported(a, "type needs text");
199
+ return { action: a, success: await wm.adbType(step.text), detail: "type" };
200
+ case "type_and_submit":
201
+ if (step.text == null)
202
+ return unsupported(a, "type_and_submit needs text");
203
+ {
204
+ const typed = await wm.adbType(step.text);
205
+ const entered = await wm.adbKey("66"); /* KEYCODE_ENTER */
206
+ return { action: a, success: typed && entered, detail: "type+enter" };
207
+ }
208
+ case "keystroke":
209
+ if (!step.key)
210
+ return unsupported(a, "keystroke needs key");
211
+ return { action: a, success: await wm.adbKey(step.key), detail: `key ${step.key}` };
212
+ case "back_button":
213
+ case "navigate_back":
214
+ return { action: a, success: await wm.adbBackButton(), detail: "back" };
215
+ case "swipe":
216
+ case "scroll": {
217
+ // Default vertical swipe gesture for scrolling.
218
+ const x1 = step.x ?? 540, y1 = step.y ?? 1200, x2 = step.x2 ?? 540, y2 = step.y2 ?? 400;
219
+ return { action: a, success: await wm.adbSwipe(x1, y1, x2, y2, step.duration_ms ?? 300), detail: "swipe" };
220
+ }
221
+ case "navigate_url":
222
+ case "deep_link":
223
+ if (!step.url)
224
+ return unsupported(a, "deep_link needs a url");
225
+ return { action: a, success: await wm.adbDeepLink(step.url), detail: `deep link ${step.url}` };
226
+ case "get_text": {
227
+ const text = await wm.adbGetText(step.selector);
228
+ const assertion = buildAssertion(step.expect_contains, text);
229
+ return {
230
+ action: a,
231
+ success: assertion ? assertion.matched : text != null,
232
+ detail: assertion ? `assert "${step.expect_contains}" -> ${assertion.matched}` : "read text",
233
+ extractedText: text,
234
+ assertion,
235
+ };
236
+ }
237
+ default:
238
+ return unsupported(a, `android action "${a}" not in the engine subset`);
239
+ }
240
+ }
241
+ // ── iOS (simctl) ────────────────────────────────────────────────────
242
+ async function driveIos(step, _ctx) {
243
+ const wm = await import("./window_manager.js");
244
+ const a = step.action;
245
+ switch (a) {
246
+ case "click":
247
+ case "tap":
248
+ if (step.x == null || step.y == null)
249
+ return unsupported(a, "ios tap needs x,y");
250
+ return { action: a, success: await wm.simctlTap(step.x, step.y), detail: `tap (${step.x},${step.y})` };
251
+ case "type":
252
+ if (step.text == null)
253
+ return unsupported(a, "type needs text");
254
+ return { action: a, success: await wm.simctlType(step.text), detail: "type" };
255
+ case "navigate_url":
256
+ case "deep_link":
257
+ if (!step.url)
258
+ return unsupported(a, "deep_link needs a url");
259
+ return { action: a, success: await wm.simctlOpenUrl(step.url), detail: `open ${step.url}` };
260
+ case "swipe":
261
+ case "scroll": {
262
+ const x1 = step.x ?? 200, y1 = step.y ?? 600, x2 = step.x2 ?? 200, y2 = step.y2 ?? 200;
263
+ return { action: a, success: await wm.simctlSwipe(x1, y1, x2, y2, step.duration_ms ?? 300), detail: "swipe" };
264
+ }
265
+ case "get_text":
266
+ // iOS text read-back isn't available via simctl; vision (screenshot) only.
267
+ return unsupported(a, "iOS get_text needs vision — use codeloop_capture_screenshot");
268
+ default:
269
+ return unsupported(a, `ios action "${a}" not in the engine subset`);
270
+ }
271
+ }
272
+ //# sourceMappingURL=interaction_engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interaction_engine.js","sourceRoot":"","sources":["../../src/runners/interaction_engine.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"gate_check.d.ts","sourceRoot":"","sources":["../../src/tools/gate_check.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EAEf,cAAc,EAEf,MAAM,sBAAsB,CAAC;AA4D9B,wBAAsB,YAAY,CAChC,KAAK,EAAE,cAAc,EACrB,MAAM,EAAE,cAAc,EACtB,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAAC,eAAe,CAAC,CAwG1B;AAyED,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,CAAC"}
1
+ {"version":3,"file":"gate_check.d.ts","sourceRoot":"","sources":["../../src/tools/gate_check.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EAEf,cAAc,EAEf,MAAM,sBAAsB,CAAC;AA6D9B,wBAAsB,YAAY,CAChC,KAAK,EAAE,cAAc,EACrB,MAAM,EAAE,cAAc,EACtB,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAAC,eAAe,CAAC,CAwG1B;AA2ED,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,CAAC"}
@@ -10,7 +10,7 @@ import { evaluateChangeCoverage, resolveChangeCoverageConfig, } from "../evidenc
10
10
  import { formatStalenessSuffix, isEvidenceStale, isRunEvidenceStale, runEvidenceMtime, } from "../evidence/evidence_freshness.js";
11
11
  import { loadCycleIssues, summariseCycleIssue, } from "../evidence/cycle_issues.js";
12
12
  import { loadCodeQualityEvidence, evaluateStaticAnalysisGate, evaluateCoverageGate, resolveCoverageThreshold, } from "../evidence/deep_internal.js";
13
- import { loadBackendVerification, evaluateBackendSmokeGate, evaluateApiContractGate, evaluateDbSchemaGate, } from "../evidence/backend_verification.js";
13
+ import { loadBackendVerification, evaluateBackendSmokeGate, evaluateApiContractGate, evaluateDbSchemaGate, evaluateBackendTestsGate, } from "../evidence/backend_verification.js";
14
14
  import { loadRuntimeLogScan, evaluateRuntimeLogGate, } from "../evidence/runtime_log_scan.js";
15
15
  import { loadObservabilityEvidence, evaluateObservabilityGate, } from "../evidence/observability.js";
16
16
  export async function runGateCheck(input, config, cwd = process.cwd()) {
@@ -154,6 +154,8 @@ function nextStepForGate(name, reason, cwd) {
154
154
  return `API responses violate the declared contract (${reason}). Reconcile the route handlers with the OpenAPI/Swagger schema (or update the schema if the change is intentional), then call codeloop_verify.`;
155
155
  case "db_schema_evidence":
156
156
  return `Database schema drift or a failed migration (${reason}). Generate + apply the pending migration for your ORM (dotnet ef migrations add / Django makemigrations / alembic revision --autogenerate / prisma migrate dev / rails db:migrate), then call codeloop_verify.`;
157
+ case "backend_tests_evidence":
158
+ return `The backend's own test suite is failing (${reason}). Run it directly in the backend dir (npm test / pytest / dotnet test / go test) to see the failures, fix the backend logic or tests, then call codeloop_verify.`;
157
159
  case "logging_observability_evidence":
158
160
  return `The project lacks a logging system (${reason}). Read artifacts/runs/<latest>/observability.json for the per-stack recommendations, then BUILD the missing piece(s): (1) a structured, leveled logger (pino/winston, Python logging/loguru, Serilog/ILogger, slog/zap, tracing) wired through the app instead of bare console/print; (2) request/HTTP logging middleware on servers (method, path, status, latency); (3) a global error handler / React error boundary that logs the full stack trace at the boundary. Persist logs to ./logs when observability.require_log_sink is on. Then call codeloop_verify. Per-project tuning lives in .codeloop/config.json -> observability.`;
159
161
  default:
@@ -712,6 +714,18 @@ function evaluateDeepInternalGates(runId, cwd, config) {
712
714
  };
713
715
  const dbVerdict = evaluateDbSchemaGate(backend);
714
716
  results.push({ gate: dbSchemaGate, passed: dbVerdict.passed, reason: dbVerdict.reason });
717
+ const backendTestsGate = {
718
+ name: "backend_tests_evidence",
719
+ description: "The backend's OWN dedicated test suite (functions/server/api subdir) must pass in detail.",
720
+ rule: "backend_verification.json backend_tests.passed === true (n/a when no backend test suite)",
721
+ input_artifacts: ["backend_verification.json"],
722
+ pass_threshold: true,
723
+ severity_if_failed: "blocker",
724
+ retry_allowance: 5,
725
+ escalation_condition: "Backend test suite still failing after 5 attempts",
726
+ };
727
+ const backendTestsVerdict = evaluateBackendTestsGate(backend);
728
+ results.push({ gate: backendTestsGate, passed: backendTestsVerdict.passed, reason: backendTestsVerdict.reason });
715
729
  // ── runtime_log_clean_evidence (Phase 2) ─────────────────────────
716
730
  const logScan = loadRuntimeLogScan(runDir);
717
731
  const runtimeLogGate = {