@hover-dev/core 0.17.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/engine.d.ts +16 -39
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +18 -67
- package/dist/specs/pageObjectManifest.d.ts.map +1 -1
- package/dist/specs/pageObjectManifest.js +11 -10
- package/dist/specs/replayGrounded.d.ts.map +1 -1
- package/dist/specs/writeApiSpec.d.ts +36 -0
- package/dist/specs/writeApiSpec.d.ts.map +1 -0
- package/dist/specs/writeApiSpec.js +94 -0
- package/package.json +5 -22
- package/dist/agents/argv.d.ts +0 -11
- package/dist/agents/argv.d.ts.map +0 -1
- package/dist/agents/argv.js +0 -23
- package/dist/agents/claude.d.ts +0 -3
- package/dist/agents/claude.d.ts.map +0 -1
- package/dist/agents/claude.js +0 -220
- package/dist/agents/codex.d.ts +0 -19
- package/dist/agents/codex.d.ts.map +0 -1
- package/dist/agents/codex.js +0 -231
- package/dist/agents/detect.d.ts +0 -46
- package/dist/agents/detect.d.ts.map +0 -1
- package/dist/agents/detect.js +0 -80
- package/dist/agents/gemini.d.ts +0 -17
- package/dist/agents/gemini.d.ts.map +0 -1
- package/dist/agents/gemini.js +0 -186
- package/dist/agents/index.d.ts +0 -6
- package/dist/agents/index.d.ts.map +0 -1
- package/dist/agents/index.js +0 -5
- package/dist/agents/invoke.d.ts +0 -12
- package/dist/agents/invoke.d.ts.map +0 -1
- package/dist/agents/invoke.js +0 -93
- package/dist/agents/qwen.d.ts +0 -17
- package/dist/agents/qwen.d.ts.map +0 -1
- package/dist/agents/qwen.js +0 -172
- package/dist/agents/registry.d.ts +0 -19
- package/dist/agents/registry.d.ts.map +0 -1
- package/dist/agents/registry.js +0 -30
- package/dist/agents/shared.d.ts +0 -28
- package/dist/agents/shared.d.ts.map +0 -1
- package/dist/agents/shared.js +0 -35
- package/dist/agents/types.d.ts +0 -194
- package/dist/agents/types.d.ts.map +0 -1
- package/dist/agents/types.js +0 -23
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -2
- package/dist/mcp/actuateServer.d.ts +0 -3
- package/dist/mcp/actuateServer.d.ts.map +0 -1
- package/dist/mcp/actuateServer.js +0 -594
- package/dist/mcp/sourceFence.d.ts +0 -23
- package/dist/mcp/sourceFence.d.ts.map +0 -1
- package/dist/mcp/sourceFence.js +0 -79
- package/dist/mcp/sourceServer.d.ts +0 -3
- package/dist/mcp/sourceServer.d.ts.map +0 -1
- package/dist/mcp/sourceServer.js +0 -191
- package/dist/modes.d.ts +0 -39
- package/dist/modes.d.ts.map +0 -1
- package/dist/modes.js +0 -34
- package/dist/playwright/cdpStatus.d.ts +0 -14
- package/dist/playwright/cdpStatus.d.ts.map +0 -1
- package/dist/playwright/cdpStatus.js +0 -52
- package/dist/playwright/preflight.d.ts +0 -31
- package/dist/playwright/preflight.d.ts.map +0 -1
- package/dist/playwright/preflight.js +0 -82
- package/dist/playwright/preflightCache.d.ts +0 -27
- package/dist/playwright/preflightCache.d.ts.map +0 -1
- package/dist/playwright/preflightCache.js +0 -21
- package/dist/playwright/resolveMcpConfig.d.ts +0 -61
- package/dist/playwright/resolveMcpConfig.d.ts.map +0 -1
- package/dist/playwright/resolveMcpConfig.js +0 -84
- package/dist/plugin-api.d.ts +0 -237
- package/dist/plugin-api.d.ts.map +0 -1
- package/dist/plugin-api.js +0 -52
- package/dist/qa/classify.d.ts +0 -38
- package/dist/qa/classify.d.ts.map +0 -1
- package/dist/qa/classify.js +0 -138
- package/dist/runSession.d.ts +0 -53
- package/dist/runSession.d.ts.map +0 -1
- package/dist/runSession.js +0 -96
- package/dist/service/cdpHandlers.d.ts +0 -24
- package/dist/service/cdpHandlers.d.ts.map +0 -1
- package/dist/service/cdpHandlers.js +0 -50
- package/dist/service/cdpHint.d.ts +0 -41
- package/dist/service/cdpHint.d.ts.map +0 -1
- package/dist/service/cdpHint.js +0 -158
- package/dist/service/conventions.d.ts +0 -8
- package/dist/service/conventions.d.ts.map +0 -1
- package/dist/service/conventions.js +0 -42
- package/dist/service/relayHandlers.d.ts +0 -28
- package/dist/service/relayHandlers.d.ts.map +0 -1
- package/dist/service/relayHandlers.js +0 -105
- package/dist/service/saveHandlers.d.ts +0 -50
- package/dist/service/saveHandlers.d.ts.map +0 -1
- package/dist/service/saveHandlers.js +0 -77
- package/dist/service/types.d.ts +0 -158
- package/dist/service/types.d.ts.map +0 -1
- package/dist/service/types.js +0 -26
- package/dist/service.d.ts +0 -54
- package/dist/service.d.ts.map +0 -1
- package/dist/service.js +0 -1772
- package/dist/specs/businessMap.d.ts +0 -29
- package/dist/specs/businessMap.d.ts.map +0 -1
- package/dist/specs/businessMap.js +0 -95
- package/dist/specs/extractPageObjects.d.ts +0 -18
- package/dist/specs/extractPageObjects.d.ts.map +0 -1
- package/dist/specs/extractPageObjects.js +0 -98
- package/dist/specs/optimizeSpecWithAgent.d.ts +0 -9
- package/dist/specs/optimizeSpecWithAgent.d.ts.map +0 -1
- package/dist/specs/optimizeSpecWithAgent.js +0 -39
package/dist/engine.d.ts
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* In-process engine surface for the `@hover-dev/mcp` server (and any other
|
|
3
|
+
* standalone consumer). The MCP server drives the debug Chrome directly via
|
|
4
|
+
* `playwright-core` and buffers grounded steps, then crystallizes them with
|
|
5
|
+
* `writeSpec` — no WebSocket service, no agent spawning. This barrel re-exports
|
|
6
|
+
* exactly those building blocks.
|
|
7
|
+
*
|
|
8
|
+
* (The old staged-engine surface — `runSession`, the WS `service`, the
|
|
9
|
+
* Playwright-MCP config in `resolveMcpConfig` / `buildGroundedMcpConfig`, and
|
|
10
|
+
* the `mcp/actuateServer` + `mcp/sourceServer` relays — has been removed. The
|
|
11
|
+
* MCP-first path doesn't spawn Playwright's MCP; it actuates through
|
|
12
|
+
* `playwright-core` and `groundedLocate` below, which is what keeps
|
|
13
|
+
* record == replay.)
|
|
14
|
+
*/
|
|
3
15
|
export { writeSpec } from './specs/writeSpec.js';
|
|
4
16
|
export type { WriteSpecOptions, WriteSpecResult, Redaction } from './specs/writeSpec.js';
|
|
5
17
|
export type { SkillStep } from './specs/specStep.js';
|
|
18
|
+
export { writeApiSpec } from './specs/writeApiSpec.js';
|
|
19
|
+
export type { ApiCheck, WriteApiSpecOptions, WriteApiSpecResult } from './specs/writeApiSpec.js';
|
|
6
20
|
export { replayGroundedSteps, replayOnPage, applyGroundedStep, groundedLocate } from './specs/replayGrounded.js';
|
|
7
21
|
export type { ReplayResult, ReplayFailure, ReplayStep, GroundedTarget } from './specs/replayGrounded.js';
|
|
8
|
-
export { resolveMcpConfig, mcpToolPrefix } from './playwright/resolveMcpConfig.js';
|
|
9
22
|
export { launchDebugChrome, closeDebugChrome, findChromeBinary } from './playwright/launchChrome.js';
|
|
10
23
|
export type { LaunchOptions, LaunchResult } from './playwright/launchChrome.js';
|
|
11
24
|
export { GROUNDED_ACTUATION_DENY, GROUNDED_ACTUATION_DIRECTIVE } from './agentDirectives.js';
|
|
@@ -14,40 +27,4 @@ export type { BusinessFact } from './memory/businessMemory.js';
|
|
|
14
27
|
export { RECON_DIRECTIVE, QA_EXPLORATION_DIRECTIVE } from './agentDirectives.js';
|
|
15
28
|
export { QA_INTENSITY, DEFAULT_QA_INTENSITY, asQaIntensity, qaBudgetDirective } from './qa/intensity.js';
|
|
16
29
|
export type { QaIntensity, QaIntensitySpec } from './qa/intensity.js';
|
|
17
|
-
/**
|
|
18
|
-
* The always-on control-actuation MCP server id. Alphanumeric on purpose — a
|
|
19
|
-
* hyphen would make the hard-sandbox allow prefix (`mcp__hovercontrol`) fail to
|
|
20
|
-
* match the tool names (`mcp__hovercontrol__click_control`), so every grounded
|
|
21
|
-
* actuation would be denied. (Same constant + reasoning as service.ts.)
|
|
22
|
-
*/
|
|
23
|
-
export declare const CONTROL_MCP_ID = "hovercontrol";
|
|
24
|
-
/** The hard-sandbox allow prefix for the control server — pass in
|
|
25
|
-
* `runSession({ allowedToolsExtra: [CONTROL_MCP_TOOL_PREFIX] })`. */
|
|
26
|
-
export declare const CONTROL_MCP_TOOL_PREFIX: string;
|
|
27
|
-
export interface GroundedMcpOptions {
|
|
28
|
-
/** CDP endpoint of the debug Chrome the agent drives. */
|
|
29
|
-
cdpUrl: string;
|
|
30
|
-
/** Port used only to namespace the generated config filename. */
|
|
31
|
-
port: number;
|
|
32
|
-
/** Project root — where the control server resolves relative paths / writes
|
|
33
|
-
* its placeholder upload fixture, and where `@playwright/mcp` resolves from. */
|
|
34
|
-
devRoot: string;
|
|
35
|
-
/** The dev-server origin the run targets (defaults to `cdpUrl`). */
|
|
36
|
-
devUrl?: string;
|
|
37
|
-
/** WS port the control server's back-channel (`ask_user` / `record_*`)
|
|
38
|
-
* connects to. Omit when there's no listener — actuation still works; the
|
|
39
|
-
* back-channel features silently no-op (actuateServer fails soft). */
|
|
40
|
-
approvalPort?: number;
|
|
41
|
-
/** Directory the Playwright MCP + control screenshots write into. */
|
|
42
|
-
outputDir?: string;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Build an MCP config mirroring the service's grounded/normal mode: the
|
|
46
|
-
* Playwright MCP over CDP PLUS the hover-control actuation server. Pair it in
|
|
47
|
-
* `runSession` with `allowedToolsExtra: [CONTROL_MCP_TOOL_PREFIX]`,
|
|
48
|
-
* `disallowedToolsExtra: GROUNDED_ACTUATION_DENY`, and append
|
|
49
|
-
* `GROUNDED_ACTUATION_DIRECTIVE` to the system prompt — then the selectors the
|
|
50
|
-
* agent actuates with are the ones crystallized (record==replay).
|
|
51
|
-
*/
|
|
52
|
-
export declare function buildGroundedMcpConfig(opts: GroundedMcpOptions): string;
|
|
53
30
|
//# sourceMappingURL=engine.d.ts.map
|
package/dist/engine.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACzF,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,YAAY,EAAE,QAAQ,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAEjG,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AACjH,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAGzG,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACrG,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAGhF,OAAO,EAAE,uBAAuB,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC;AAG7F,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACrG,YAAY,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAG/D,OAAO,EAAE,eAAe,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACzG,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/engine.js
CHANGED
|
@@ -1,78 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* In-process engine surface for
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* record==replay fidelity the extension does), and spec crystallization —
|
|
8
|
-
* without the WebSocket layer.
|
|
2
|
+
* In-process engine surface for the `@hover-dev/mcp` server (and any other
|
|
3
|
+
* standalone consumer). The MCP server drives the debug Chrome directly via
|
|
4
|
+
* `playwright-core` and buffers grounded steps, then crystallizes them with
|
|
5
|
+
* `writeSpec` — no WebSocket service, no agent spawning. This barrel re-exports
|
|
6
|
+
* exactly those building blocks.
|
|
9
7
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
8
|
+
* (The old staged-engine surface — `runSession`, the WS `service`, the
|
|
9
|
+
* Playwright-MCP config in `resolveMcpConfig` / `buildGroundedMcpConfig`, and
|
|
10
|
+
* the `mcp/actuateServer` + `mcp/sourceServer` relays — has been removed. The
|
|
11
|
+
* MCP-first path doesn't spawn Playwright's MCP; it actuates through
|
|
12
|
+
* `playwright-core` and `groundedLocate` below, which is what keeps
|
|
13
|
+
* record == replay.)
|
|
14
14
|
*/
|
|
15
|
-
|
|
16
|
-
import { fileURLToPath } from 'node:url';
|
|
17
|
-
import { resolveMcpConfig, mcpToolPrefix } from './playwright/resolveMcpConfig.js';
|
|
18
|
-
// ── in-process session + crystallization ─────────────────────────────────────
|
|
19
|
-
export { runSession } from './runSession.js';
|
|
15
|
+
// ── crystallization + grounded replay ────────────────────────────────────────
|
|
20
16
|
export { writeSpec } from './specs/writeSpec.js';
|
|
17
|
+
// API-layer crystallizer — observed/replayed requests → *.api-test.spec.ts.
|
|
18
|
+
export { writeApiSpec } from './specs/writeApiSpec.js';
|
|
21
19
|
// Creation-verification: replay a flow's grounded steps over CDP (no playwright test).
|
|
22
20
|
export { replayGroundedSteps, replayOnPage, applyGroundedStep, groundedLocate } from './specs/replayGrounded.js';
|
|
23
|
-
// ──
|
|
24
|
-
export { resolveMcpConfig, mcpToolPrefix } from './playwright/resolveMcpConfig.js';
|
|
21
|
+
// ── debug-Chrome lifecycle ───────────────────────────────────────────────────
|
|
25
22
|
export { launchDebugChrome, closeDebugChrome, findChromeBinary } from './playwright/launchChrome.js';
|
|
26
|
-
// ── grounded-actuation knobs (
|
|
23
|
+
// ── grounded-actuation knobs (the deny-list + directive the agent runs under) ─
|
|
27
24
|
export { GROUNDED_ACTUATION_DENY, GROUNDED_ACTUATION_DIRECTIVE } from './agentDirectives.js';
|
|
28
|
-
// ── business memory (ask → remember loop
|
|
25
|
+
// ── business memory (ask → remember loop) ────────────────────────────────────
|
|
29
26
|
export { loadMemory, formatMemoryForPrompt, writeFact, memoryDir } from './memory/businessMemory.js';
|
|
30
|
-
// ── autonomous-exploration directives (
|
|
31
|
-
// The CLI's "explore → discover business flows → record_candidate" loop is the
|
|
32
|
-
// same mechanism QA mode drives the agent with; reuse the directives verbatim
|
|
33
|
-
// so behaviour stays in lock-step.
|
|
27
|
+
// ── autonomous-exploration directives + intensity (the test_app workflow) ─────
|
|
34
28
|
export { RECON_DIRECTIVE, QA_EXPLORATION_DIRECTIVE } from './agentDirectives.js';
|
|
35
29
|
export { QA_INTENSITY, DEFAULT_QA_INTENSITY, asQaIntensity, qaBudgetDirective } from './qa/intensity.js';
|
|
36
|
-
/**
|
|
37
|
-
* The always-on control-actuation MCP server id. Alphanumeric on purpose — a
|
|
38
|
-
* hyphen would make the hard-sandbox allow prefix (`mcp__hovercontrol`) fail to
|
|
39
|
-
* match the tool names (`mcp__hovercontrol__click_control`), so every grounded
|
|
40
|
-
* actuation would be denied. (Same constant + reasoning as service.ts.)
|
|
41
|
-
*/
|
|
42
|
-
export const CONTROL_MCP_ID = 'hovercontrol';
|
|
43
|
-
/** The hard-sandbox allow prefix for the control server — pass in
|
|
44
|
-
* `runSession({ allowedToolsExtra: [CONTROL_MCP_TOOL_PREFIX] })`. */
|
|
45
|
-
export const CONTROL_MCP_TOOL_PREFIX = mcpToolPrefix(CONTROL_MCP_ID);
|
|
46
|
-
// dist/engine.js sits beside dist/service.js, so mcp/actuateServer.js resolves
|
|
47
|
-
// the same way it does from service.ts.
|
|
48
|
-
const CONTROL_MCP_SCRIPT = resolve(dirname(fileURLToPath(import.meta.url)), 'mcp', 'actuateServer.js');
|
|
49
|
-
/**
|
|
50
|
-
* Build an MCP config mirroring the service's grounded/normal mode: the
|
|
51
|
-
* Playwright MCP over CDP PLUS the hover-control actuation server. Pair it in
|
|
52
|
-
* `runSession` with `allowedToolsExtra: [CONTROL_MCP_TOOL_PREFIX]`,
|
|
53
|
-
* `disallowedToolsExtra: GROUNDED_ACTUATION_DENY`, and append
|
|
54
|
-
* `GROUNDED_ACTUATION_DIRECTIVE` to the system prompt — then the selectors the
|
|
55
|
-
* agent actuates with are the ones crystallized (record==replay).
|
|
56
|
-
*/
|
|
57
|
-
export function buildGroundedMcpConfig(opts) {
|
|
58
|
-
return resolveMcpConfig({
|
|
59
|
-
cdpUrl: opts.cdpUrl,
|
|
60
|
-
port: opts.port,
|
|
61
|
-
cwd: opts.devRoot,
|
|
62
|
-
outputDir: opts.outputDir,
|
|
63
|
-
extra: [
|
|
64
|
-
{
|
|
65
|
-
id: CONTROL_MCP_ID,
|
|
66
|
-
command: process.execPath,
|
|
67
|
-
args: [CONTROL_MCP_SCRIPT],
|
|
68
|
-
env: {
|
|
69
|
-
HOVER_CDP_URL: opts.cdpUrl,
|
|
70
|
-
HOVER_DEV_URL: opts.devUrl ?? opts.cdpUrl,
|
|
71
|
-
HOVER_PROJECT_ROOT: opts.devRoot,
|
|
72
|
-
...(opts.approvalPort ? { HOVER_APPROVAL_PORT: String(opts.approvalPort) } : {}),
|
|
73
|
-
...(opts.outputDir ? { HOVER_SHOT_DIR: opts.outputDir } : {}),
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
],
|
|
77
|
-
});
|
|
78
|
-
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pageObjectManifest.d.ts","sourceRoot":"","sources":["../../src/specs/pageObjectManifest.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pageObjectManifest.d.ts","sourceRoot":"","sources":["../../src/specs/pageObjectManifest.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,0DAA0D;IAC1D,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,eAAe,EAAE,CAAC;CAC1B;AAMD,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,eAAe,EAAE,GACvB,OAAO,CAAC,MAAM,CAAC,CAOjB;AAED;;wDAEwD;AACxD,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAUhG"}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Page Object manifest —
|
|
3
|
-
*
|
|
2
|
+
* Page Object manifest — `.hover/page-objects.json` describing each emitted
|
|
3
|
+
* Page Object (class/method/fixture names + the signature prefix it replays).
|
|
4
|
+
* writeSpec reads it (`readPageObjectManifest`) to decide whether a freshly-saved
|
|
5
|
+
* spec's prefix matches an existing Page Object — if so it consumes
|
|
6
|
+
* `await loginPage.login(…)` and imports from `./fixtures` instead of re-emitting
|
|
7
|
+
* the steps inline.
|
|
4
8
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* Kept separate from extractPageObjects so writeSpec can read the manifest
|
|
12
|
-
* without importing the detection/generation chain.
|
|
9
|
+
* NOTE: cross-spec reuse is currently DORMANT — the manifest writer
|
|
10
|
+
* (`writePageObjectManifest`) has no caller since the standalone extraction stage
|
|
11
|
+
* was removed, so the read path returns null and writeSpec emits Page Objects
|
|
12
|
+
* inline. Kept as the seam for when cross-spec Page Object reuse is wired into
|
|
13
|
+
* the MCP-first flow.
|
|
13
14
|
*/
|
|
14
15
|
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
15
16
|
import { join } from 'node:path';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replayGrounded.d.ts","sourceRoot":"","sources":["../../src/specs/replayGrounded.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"replayGrounded.d.ts","sourceRoot":"","sources":["../../src/specs/replayGrounded.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAiBlF,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3C;AAGD,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AACD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AACD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,OAAO,CAAC;IACZ,8CAA8C;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AA+BD,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,cAAc,GAAG,OAAO,GAAG,IAAI,CAS5E;AAED;yEACyE;AACzE,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CA4B/F;AAED;;qEAEqE;AACrE,wBAAsB,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAqBzG;AAuBD,+EAA+E;AAC/E,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,UAAU,EAAE,CAAA;CAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAoB9H"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** One asserted API call — a contract, shape, or authz check. */
|
|
2
|
+
export interface ApiCheck {
|
|
3
|
+
/** Short imperative title → the `test()` name (e.g. "GET /api/cart returns the cart"). */
|
|
4
|
+
title: string;
|
|
5
|
+
/** HTTP method. */
|
|
6
|
+
method: string;
|
|
7
|
+
/** URL as captured. Same-origin URLs are relativized to a path so the spec
|
|
8
|
+
* rides the config's baseURL; cross-origin URLs are emitted in full. */
|
|
9
|
+
url: string;
|
|
10
|
+
/** Request body to send (objects are emitted as a JSON literal via `data`). */
|
|
11
|
+
requestBody?: unknown;
|
|
12
|
+
/** Headers to send. For an authz check the agent omits/alters the auth header. */
|
|
13
|
+
headers?: Record<string, string>;
|
|
14
|
+
/** Expected status — observed for a contract check, or expected-after-mutation
|
|
15
|
+
* for an authz check (verified with replay_request before crystallizing). */
|
|
16
|
+
expectStatus?: number;
|
|
17
|
+
/** Top-level response keys to assert present (a light shape contract). */
|
|
18
|
+
expectBodyKeys?: string[];
|
|
19
|
+
/** Optional human note → emitted as a leading comment (e.g. "authz: no session → 401"). */
|
|
20
|
+
note?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface WriteApiSpecOptions {
|
|
23
|
+
devRoot: string;
|
|
24
|
+
name: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
checks: ApiCheck[];
|
|
27
|
+
/** Run target origin — same-origin URLs are relativized against it. */
|
|
28
|
+
startUrl?: string;
|
|
29
|
+
overwrite?: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface WriteApiSpecResult {
|
|
32
|
+
path: string;
|
|
33
|
+
slug: string;
|
|
34
|
+
}
|
|
35
|
+
export declare function writeApiSpec(opts: WriteApiSpecOptions): Promise<WriteApiSpecResult>;
|
|
36
|
+
//# sourceMappingURL=writeApiSpec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writeApiSpec.d.ts","sourceRoot":"","sources":["../../src/specs/writeApiSpec.ts"],"names":[],"mappings":"AAgBA,iEAAiE;AACjE,MAAM,WAAW,QAAQ;IACvB,0FAA0F;IAC1F,KAAK,EAAE,MAAM,CAAC;IACd,mBAAmB;IACnB,MAAM,EAAE,MAAM,CAAC;IACf;6EACyE;IACzE,GAAG,EAAE,MAAM,CAAC;IACZ,+EAA+E;IAC/E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC;kFAC8E;IAC9E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0EAA0E;IAC1E,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,2FAA2F;IAC3F,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AA0DD,wBAAsB,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAyBzF"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic API-spec crystallizer — the API-layer sibling of writeSpec.
|
|
3
|
+
*
|
|
4
|
+
* Writes a `<devRoot>/__vibe_tests__/<slug>.api-test.spec.ts` from a list of
|
|
5
|
+
* `ApiCheck`s the agent assembled (observed via CDP capture, optionally with a
|
|
6
|
+
* mutation it verified with replay_request). Pure `@playwright/test`
|
|
7
|
+
* `APIRequestContext` — `request.get/post(...)` + status / shape / authz
|
|
8
|
+
* assertions. No LLM in the codegen path: a 1:1 string-template translation, so
|
|
9
|
+
* record == replay holds for the API layer too (the call that was captured is
|
|
10
|
+
* the call that's asserted).
|
|
11
|
+
*/
|
|
12
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
13
|
+
import { existsSync } from 'node:fs';
|
|
14
|
+
import { join } from 'node:path';
|
|
15
|
+
import { slugify, firstSentence } from './text.js';
|
|
16
|
+
const KNOWN_METHODS = new Set(['get', 'post', 'put', 'delete', 'patch', 'head']);
|
|
17
|
+
function q(s) {
|
|
18
|
+
return `'${String(s).replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`;
|
|
19
|
+
}
|
|
20
|
+
/** Same-origin → path (rides baseURL); cross-origin → full URL. */
|
|
21
|
+
function toRequestUrl(url, startUrl) {
|
|
22
|
+
try {
|
|
23
|
+
const u = new URL(url);
|
|
24
|
+
if (startUrl) {
|
|
25
|
+
const base = new URL(startUrl);
|
|
26
|
+
if (u.origin === base.origin)
|
|
27
|
+
return (u.pathname + u.search) || '/';
|
|
28
|
+
}
|
|
29
|
+
return url;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return url; // already a path, or unparseable — emit as-is
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function renderCheck(check, startUrl) {
|
|
36
|
+
const m = check.method.toLowerCase();
|
|
37
|
+
const useFetch = !KNOWN_METHODS.has(m);
|
|
38
|
+
const fn = useFetch ? 'fetch' : m;
|
|
39
|
+
const url = toRequestUrl(check.url, startUrl);
|
|
40
|
+
// Build the options object (data / headers / method-for-fetch).
|
|
41
|
+
const opts = [];
|
|
42
|
+
if (useFetch)
|
|
43
|
+
opts.push(`method: ${q(check.method.toUpperCase())}`);
|
|
44
|
+
if (check.requestBody !== undefined && m !== 'get' && m !== 'head') {
|
|
45
|
+
opts.push(`data: ${JSON.stringify(check.requestBody)}`);
|
|
46
|
+
}
|
|
47
|
+
if (check.headers && Object.keys(check.headers).length) {
|
|
48
|
+
opts.push(`headers: ${JSON.stringify(check.headers)}`);
|
|
49
|
+
}
|
|
50
|
+
const callArgs = opts.length ? `${q(url)}, { ${opts.join(', ')} }` : q(url);
|
|
51
|
+
const body = [];
|
|
52
|
+
if (check.note)
|
|
53
|
+
body.push(` // ${check.note}`);
|
|
54
|
+
body.push(` const res = await request.${fn}(${callArgs});`);
|
|
55
|
+
if (typeof check.expectStatus === 'number') {
|
|
56
|
+
body.push(` expect(res.status()).toBe(${check.expectStatus});`);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
body.push(` expect(res.ok()).toBeTruthy();`);
|
|
60
|
+
}
|
|
61
|
+
if (check.expectBodyKeys && check.expectBodyKeys.length) {
|
|
62
|
+
body.push(` const body = await res.json();`);
|
|
63
|
+
for (const k of check.expectBodyKeys) {
|
|
64
|
+
body.push(` expect(body).toHaveProperty(${q(k)});`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const title = check.title.replace(/'/g, "\\'");
|
|
68
|
+
return [` test('${title}', async ({ request }) => {`, ...body, ` });`].join('\n');
|
|
69
|
+
}
|
|
70
|
+
export async function writeApiSpec(opts) {
|
|
71
|
+
const slug = slugify(opts.name);
|
|
72
|
+
if (!slug)
|
|
73
|
+
throw new Error('api spec name must contain at least one alphanumeric character');
|
|
74
|
+
if (!opts.checks.length)
|
|
75
|
+
throw new Error('api spec needs at least one check');
|
|
76
|
+
const dir = join(opts.devRoot, '__vibe_tests__');
|
|
77
|
+
const path = join(dir, `${slug}.api-test.spec.ts`);
|
|
78
|
+
if (existsSync(path) && !opts.overwrite) {
|
|
79
|
+
throw new Error(`${path} already exists (pass overwrite to replace)`);
|
|
80
|
+
}
|
|
81
|
+
const header = opts.description ? `// ${firstSentence(opts.description)}` : null;
|
|
82
|
+
const lines = [
|
|
83
|
+
...(header ? [header] : []),
|
|
84
|
+
`import { test, expect } from '@playwright/test';`,
|
|
85
|
+
``,
|
|
86
|
+
`test.describe(${q(opts.name)}, () => {`,
|
|
87
|
+
opts.checks.map(c => renderCheck(c, opts.startUrl)).join('\n\n'),
|
|
88
|
+
`});`,
|
|
89
|
+
``,
|
|
90
|
+
];
|
|
91
|
+
await mkdir(dir, { recursive: true });
|
|
92
|
+
await writeFile(path, lines.join('\n'), 'utf-8');
|
|
93
|
+
return { path, slug };
|
|
94
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hover-dev/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "Hover's local Node service: agent invocation, Playwright CDP preflight, WebSocket bridge.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Hyperyond",
|
|
@@ -20,32 +20,16 @@
|
|
|
20
20
|
"claude"
|
|
21
21
|
],
|
|
22
22
|
"type": "module",
|
|
23
|
-
"main": "dist/
|
|
24
|
-
"types": "dist/
|
|
23
|
+
"main": "dist/engine.js",
|
|
24
|
+
"types": "dist/engine.d.ts",
|
|
25
25
|
"exports": {
|
|
26
26
|
".": {
|
|
27
|
-
"types": "./dist/
|
|
28
|
-
"import": "./dist/
|
|
29
|
-
},
|
|
30
|
-
"./agents": {
|
|
31
|
-
"types": "./dist/agents/index.d.ts",
|
|
32
|
-
"import": "./dist/agents/index.js"
|
|
33
|
-
},
|
|
34
|
-
"./service": {
|
|
35
|
-
"types": "./dist/service.d.ts",
|
|
36
|
-
"import": "./dist/service.js"
|
|
27
|
+
"types": "./dist/engine.d.ts",
|
|
28
|
+
"import": "./dist/engine.js"
|
|
37
29
|
},
|
|
38
30
|
"./engine": {
|
|
39
31
|
"types": "./dist/engine.d.ts",
|
|
40
32
|
"import": "./dist/engine.js"
|
|
41
|
-
},
|
|
42
|
-
"./launch-chrome": {
|
|
43
|
-
"types": "./dist/playwright/launchChrome.d.ts",
|
|
44
|
-
"import": "./dist/playwright/launchChrome.js"
|
|
45
|
-
},
|
|
46
|
-
"./plugin-api": {
|
|
47
|
-
"types": "./dist/plugin-api.d.ts",
|
|
48
|
-
"import": "./dist/plugin-api.js"
|
|
49
33
|
}
|
|
50
34
|
},
|
|
51
35
|
"files": [
|
|
@@ -55,7 +39,6 @@
|
|
|
55
39
|
],
|
|
56
40
|
"dependencies": {
|
|
57
41
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
58
|
-
"@playwright/mcp": "0.0.75",
|
|
59
42
|
"cross-spawn": "^7.0.6",
|
|
60
43
|
"playwright-core": "^1.50.0",
|
|
61
44
|
"ts-morph": "^28.0.0",
|
package/dist/agents/argv.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { AgentDescriptor, InvokeOptions } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Build argv for spawning an agent.
|
|
4
|
-
*
|
|
5
|
-
* Per-agent argument logic lives on the descriptor (e.g. claude.ts owns its
|
|
6
|
-
* own `--mcp-config`, `--permission-mode` etc.). This dispatcher only
|
|
7
|
-
* gates by protocol — `acp` and `pi-rpc` are not yet implemented because
|
|
8
|
-
* they require a long-lived bidirectional channel rather than argv.
|
|
9
|
-
*/
|
|
10
|
-
export declare function buildArgv(descriptor: AgentDescriptor, opts: InvokeOptions): string[];
|
|
11
|
-
//# sourceMappingURL=argv.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"argv.d.ts","sourceRoot":"","sources":["../../src/agents/argv.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGjE;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,eAAe,EAAE,IAAI,EAAE,aAAa,GAAG,MAAM,EAAE,CAepF"}
|
package/dist/agents/argv.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { UnsupportedAgentProtocolError } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Build argv for spawning an agent.
|
|
4
|
-
*
|
|
5
|
-
* Per-agent argument logic lives on the descriptor (e.g. claude.ts owns its
|
|
6
|
-
* own `--mcp-config`, `--permission-mode` etc.). This dispatcher only
|
|
7
|
-
* gates by protocol — `acp` and `pi-rpc` are not yet implemented because
|
|
8
|
-
* they require a long-lived bidirectional channel rather than argv.
|
|
9
|
-
*/
|
|
10
|
-
export function buildArgv(descriptor, opts) {
|
|
11
|
-
switch (descriptor.protocol) {
|
|
12
|
-
case 'argv':
|
|
13
|
-
case 'stdin':
|
|
14
|
-
return descriptor.buildArgs(opts);
|
|
15
|
-
case 'acp':
|
|
16
|
-
case 'pi-rpc':
|
|
17
|
-
throw new UnsupportedAgentProtocolError(`Agent protocol "${descriptor.protocol}" is not yet implemented (agent: ${descriptor.id})`);
|
|
18
|
-
default: {
|
|
19
|
-
const exhaustive = descriptor.protocol;
|
|
20
|
-
throw new UnsupportedAgentProtocolError(`Unknown protocol: ${String(exhaustive)}`);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
package/dist/agents/claude.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/agents/claude.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAA2C,MAAM,YAAY,CAAC;AAiI3F,eAAO,MAAM,WAAW,EAAE,eA8IzB,CAAC"}
|