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.
- package/dist/evidence/backend_verification.d.ts +27 -0
- package/dist/evidence/backend_verification.d.ts.map +1 -1
- package/dist/evidence/backend_verification.js +22 -0
- package/dist/evidence/backend_verification.js.map +1 -1
- package/dist/index.js +54 -0
- package/dist/index.js.map +1 -1
- package/dist/runners/backend_runtime.d.ts +21 -0
- package/dist/runners/backend_runtime.d.ts.map +1 -1
- package/dist/runners/backend_runtime.js +157 -6
- package/dist/runners/backend_runtime.js.map +1 -1
- package/dist/runners/device_probe.d.ts +41 -0
- package/dist/runners/device_probe.d.ts.map +1 -1
- package/dist/runners/device_probe.js +162 -1
- package/dist/runners/device_probe.js.map +1 -1
- package/dist/runners/flutter.d.ts +17 -0
- package/dist/runners/flutter.d.ts.map +1 -1
- package/dist/runners/flutter.js +47 -13
- package/dist/runners/flutter.js.map +1 -1
- package/dist/runners/interaction_engine.d.ts +59 -0
- package/dist/runners/interaction_engine.d.ts.map +1 -0
- package/dist/runners/interaction_engine.js +272 -0
- package/dist/runners/interaction_engine.js.map +1 -0
- package/dist/tools/gate_check.d.ts.map +1 -1
- package/dist/tools/gate_check.js +15 -1
- package/dist/tools/gate_check.js.map +1 -1
- package/dist/tools/plan_user_journey.d.ts +8 -0
- package/dist/tools/plan_user_journey.d.ts.map +1 -1
- package/dist/tools/plan_user_journey.js +20 -7
- package/dist/tools/plan_user_journey.js.map +1 -1
- package/dist/tools/run_journey.d.ts +69 -0
- package/dist/tools/run_journey.d.ts.map +1 -0
- package/dist/tools/run_journey.js +309 -0
- package/dist/tools/run_journey.js.map +1 -0
- package/dist/tools/verify.d.ts.map +1 -1
- package/dist/tools/verify.js +5 -1
- package/dist/tools/verify.js.map +1 -1
- 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;
|
|
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"}
|
package/dist/runners/flutter.js
CHANGED
|
@@ -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
|
|
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:
|
|
64
|
-
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
|
|
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
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
-
|
|
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":"AAAA,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAE9E,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,yEAAyE;AACzE,4EAA4E;AAC5E,uEAAuE;AACvE,0EAA0E;AAC1E,4EAA4E;AAC5E,uEAAuE;AACvE,uEAAuE;AACvE,0EAA0E;AAC1E,yEAAyE;AACzE,MAAM,kBAAkB,GAAG,OAAO,CAAC,CAAC,QAAQ;AAC5C,MAAM,sBAAsB,GAAG,OAAO,CAAC,CAAC,QAAQ;AAEhD,8EAA8E;AAC9E,8EAA8E;AAC9E,6BAA6B;AAC7B,MAAM,kBAAkB,GAA2B,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC;AAElE,SAAS,WAAW,CAAC,GAAW,EAAE,SAAiB;IACjD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,MAAM,CAAC,CAAC;IAC5C,OAAO,CACL,gBAAgB,GAAG,uBAAuB,IAAI,8BAA8B;QAC5E,wEAAwE;QACxE,4EAA4E;QAC5E,2EAA2E;QAC3E,yEAAyE;QACzE,wEAAwE;QACxE,0EAA0E;QAC1E,4EAA4E;QAC5E,2EAA2E;QAC3E,YAAY,CACb,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,GAAW,EACX,OAAe;IAEf,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;QAC3C,OAAO,iBAAiB,CAAC,iBAAiB,EAAE,uBAAuB,CAAC,CAAC;IACvE,CAAC;IAED,IAAI,CAAC,CAAC,MAAM,kBAAkB,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;QAC3C,OAAO,iBAAiB,CAAC,iBAAiB,EAAE,2BAA2B,CAAC,CAAC;IAC3E,CAAC;IAED,2EAA2E;IAC3E,uEAAuE;IACvE,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAEzD,IAAI,MAAM,CAAC,SAAS,KAAK,GAAG,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,WAAW,CAAC,kCAAkC,EAAE,kBAAkB,CAAC,CAAC;QACjF,OAAO;YACL,WAAW,EAAE,iBAAiB;YAC9B,SAAS,EAAE,IAAI;YACf,SAAS,EAAE,GAAG;YACd,MAAM,EAAE,CAAC;YACT,MAAM,EAAE,CAAC;YACT,OAAO,EAAE,CAAC;YACV,QAAQ,EAAE,OAAO;YACjB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,MAAM,EAAE,GAAG,IAAI,KAAK,MAAM,CAAC,MAAM,EAAE;SACpC,CAAC;IACJ,CAAC;IAED,MAAM,
|
|
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;
|
|
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"}
|
package/dist/tools/gate_check.js
CHANGED
|
@@ -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 = {
|