@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.
Files changed (109) hide show
  1. package/dist/engine.d.ts +16 -39
  2. package/dist/engine.d.ts.map +1 -1
  3. package/dist/engine.js +18 -67
  4. package/dist/specs/pageObjectManifest.d.ts.map +1 -1
  5. package/dist/specs/pageObjectManifest.js +11 -10
  6. package/dist/specs/replayGrounded.d.ts.map +1 -1
  7. package/dist/specs/writeApiSpec.d.ts +36 -0
  8. package/dist/specs/writeApiSpec.d.ts.map +1 -0
  9. package/dist/specs/writeApiSpec.js +94 -0
  10. package/package.json +5 -22
  11. package/dist/agents/argv.d.ts +0 -11
  12. package/dist/agents/argv.d.ts.map +0 -1
  13. package/dist/agents/argv.js +0 -23
  14. package/dist/agents/claude.d.ts +0 -3
  15. package/dist/agents/claude.d.ts.map +0 -1
  16. package/dist/agents/claude.js +0 -220
  17. package/dist/agents/codex.d.ts +0 -19
  18. package/dist/agents/codex.d.ts.map +0 -1
  19. package/dist/agents/codex.js +0 -231
  20. package/dist/agents/detect.d.ts +0 -46
  21. package/dist/agents/detect.d.ts.map +0 -1
  22. package/dist/agents/detect.js +0 -80
  23. package/dist/agents/gemini.d.ts +0 -17
  24. package/dist/agents/gemini.d.ts.map +0 -1
  25. package/dist/agents/gemini.js +0 -186
  26. package/dist/agents/index.d.ts +0 -6
  27. package/dist/agents/index.d.ts.map +0 -1
  28. package/dist/agents/index.js +0 -5
  29. package/dist/agents/invoke.d.ts +0 -12
  30. package/dist/agents/invoke.d.ts.map +0 -1
  31. package/dist/agents/invoke.js +0 -93
  32. package/dist/agents/qwen.d.ts +0 -17
  33. package/dist/agents/qwen.d.ts.map +0 -1
  34. package/dist/agents/qwen.js +0 -172
  35. package/dist/agents/registry.d.ts +0 -19
  36. package/dist/agents/registry.d.ts.map +0 -1
  37. package/dist/agents/registry.js +0 -30
  38. package/dist/agents/shared.d.ts +0 -28
  39. package/dist/agents/shared.d.ts.map +0 -1
  40. package/dist/agents/shared.js +0 -35
  41. package/dist/agents/types.d.ts +0 -194
  42. package/dist/agents/types.d.ts.map +0 -1
  43. package/dist/agents/types.js +0 -23
  44. package/dist/index.d.ts +0 -3
  45. package/dist/index.d.ts.map +0 -1
  46. package/dist/index.js +0 -2
  47. package/dist/mcp/actuateServer.d.ts +0 -3
  48. package/dist/mcp/actuateServer.d.ts.map +0 -1
  49. package/dist/mcp/actuateServer.js +0 -594
  50. package/dist/mcp/sourceFence.d.ts +0 -23
  51. package/dist/mcp/sourceFence.d.ts.map +0 -1
  52. package/dist/mcp/sourceFence.js +0 -79
  53. package/dist/mcp/sourceServer.d.ts +0 -3
  54. package/dist/mcp/sourceServer.d.ts.map +0 -1
  55. package/dist/mcp/sourceServer.js +0 -191
  56. package/dist/modes.d.ts +0 -39
  57. package/dist/modes.d.ts.map +0 -1
  58. package/dist/modes.js +0 -34
  59. package/dist/playwright/cdpStatus.d.ts +0 -14
  60. package/dist/playwright/cdpStatus.d.ts.map +0 -1
  61. package/dist/playwright/cdpStatus.js +0 -52
  62. package/dist/playwright/preflight.d.ts +0 -31
  63. package/dist/playwright/preflight.d.ts.map +0 -1
  64. package/dist/playwright/preflight.js +0 -82
  65. package/dist/playwright/preflightCache.d.ts +0 -27
  66. package/dist/playwright/preflightCache.d.ts.map +0 -1
  67. package/dist/playwright/preflightCache.js +0 -21
  68. package/dist/playwright/resolveMcpConfig.d.ts +0 -61
  69. package/dist/playwright/resolveMcpConfig.d.ts.map +0 -1
  70. package/dist/playwright/resolveMcpConfig.js +0 -84
  71. package/dist/plugin-api.d.ts +0 -237
  72. package/dist/plugin-api.d.ts.map +0 -1
  73. package/dist/plugin-api.js +0 -52
  74. package/dist/qa/classify.d.ts +0 -38
  75. package/dist/qa/classify.d.ts.map +0 -1
  76. package/dist/qa/classify.js +0 -138
  77. package/dist/runSession.d.ts +0 -53
  78. package/dist/runSession.d.ts.map +0 -1
  79. package/dist/runSession.js +0 -96
  80. package/dist/service/cdpHandlers.d.ts +0 -24
  81. package/dist/service/cdpHandlers.d.ts.map +0 -1
  82. package/dist/service/cdpHandlers.js +0 -50
  83. package/dist/service/cdpHint.d.ts +0 -41
  84. package/dist/service/cdpHint.d.ts.map +0 -1
  85. package/dist/service/cdpHint.js +0 -158
  86. package/dist/service/conventions.d.ts +0 -8
  87. package/dist/service/conventions.d.ts.map +0 -1
  88. package/dist/service/conventions.js +0 -42
  89. package/dist/service/relayHandlers.d.ts +0 -28
  90. package/dist/service/relayHandlers.d.ts.map +0 -1
  91. package/dist/service/relayHandlers.js +0 -105
  92. package/dist/service/saveHandlers.d.ts +0 -50
  93. package/dist/service/saveHandlers.d.ts.map +0 -1
  94. package/dist/service/saveHandlers.js +0 -77
  95. package/dist/service/types.d.ts +0 -158
  96. package/dist/service/types.d.ts.map +0 -1
  97. package/dist/service/types.js +0 -26
  98. package/dist/service.d.ts +0 -54
  99. package/dist/service.d.ts.map +0 -1
  100. package/dist/service.js +0 -1772
  101. package/dist/specs/businessMap.d.ts +0 -29
  102. package/dist/specs/businessMap.d.ts.map +0 -1
  103. package/dist/specs/businessMap.js +0 -95
  104. package/dist/specs/extractPageObjects.d.ts +0 -18
  105. package/dist/specs/extractPageObjects.d.ts.map +0 -1
  106. package/dist/specs/extractPageObjects.js +0 -98
  107. package/dist/specs/optimizeSpecWithAgent.d.ts +0 -9
  108. package/dist/specs/optimizeSpecWithAgent.d.ts.map +0 -1
  109. package/dist/specs/optimizeSpecWithAgent.js +0 -39
package/dist/engine.d.ts CHANGED
@@ -1,11 +1,24 @@
1
- export { runSession } from './runSession.js';
2
- export type { RunSessionOptions, RunSessionResult } from './runSession.js';
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
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAC3E,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,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,gBAAgB,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACnF,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;AAM/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;AAEtE;;;;;GAKG;AACH,eAAO,MAAM,cAAc,iBAAiB,CAAC;AAE7C;sEACsE;AACtE,eAAO,MAAM,uBAAuB,QAAgC,CAAC;AAMrE,MAAM,WAAW,kBAAkB;IACjC,yDAAyD;IACzD,MAAM,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb;qFACiF;IACjF,OAAO,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;2EAEuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,CAqBvE"}
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 non-service consumers — the `hover` CLI and the
3
- * `@hover-dev/mcp` server. The VS Code extension drives core through the WS
4
- * service (`./service`); a standalone process instead calls `runSession`
5
- * directly. This barrel exposes the same building blocks the service composes —
6
- * the session run, the GROUNDED MCP config (so a CLI-authored spec gets the
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
- * Keep this a thin re-export + the one `buildGroundedMcpConfig` helper. The
11
- * grounded path here MUST stay in lock-step with `service.ts`'s normal-mode
12
- * assembly (the control-actuation server + `GROUNDED_ACTUATION_DENY` /
13
- * `GROUNDED_ACTUATION_DIRECTIVE`), or CLI specs would drift from extension specs.
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
- import { resolve, dirname } from 'node:path';
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
- // ── browser / MCP plumbing ───────────────────────────────────────────────────
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 (must match service.ts) ─────────────────────────
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; shared with the extension's QA mode)
25
+ // ── business memory (ask → remember loop) ────────────────────────────────────
29
26
  export { loadMemory, formatMemoryForPrompt, writeFact, memoryDir } from './memory/businessMemory.js';
30
- // ── autonomous-exploration directives (QA mode reuse) ────────────────────────
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":"AAiBA,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
+ {"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 — the link between extraction (Stage 3b) and
3
- * consumption (Stage 3c).
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
- * extractPageObjects writes `.hover/page-objects.json` describing each emitted
6
- * Page Object: its class/method/fixture names and the signature prefix it
7
- * replays. writeSpec reads it to decide whether a freshly-saved spec's prefix
8
- * matches a Page Object if so it consumes `await loginPage.login(…)` and
9
- * imports from `./fixtures` instead of re-emitting the steps inline.
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;AAkBlF,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"}
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.17.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/index.js",
24
- "types": "dist/index.d.ts",
23
+ "main": "dist/engine.js",
24
+ "types": "dist/engine.d.ts",
25
25
  "exports": {
26
26
  ".": {
27
- "types": "./dist/index.d.ts",
28
- "import": "./dist/index.js"
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",
@@ -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"}
@@ -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
- }
@@ -1,3 +0,0 @@
1
- import type { AgentDescriptor } from './types.js';
2
- export declare const claudeAgent: AgentDescriptor;
3
- //# sourceMappingURL=claude.d.ts.map
@@ -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"}