@zibby/core 0.1.21 → 0.1.22

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 (167) hide show
  1. package/dist/agents/base.js +17 -0
  2. package/dist/backend-client.js +1 -0
  3. package/dist/constants/tool-names.js +1 -0
  4. package/dist/constants/zibby-scratch.js +1 -0
  5. package/dist/constants.js +1 -0
  6. package/dist/enrichment/base.js +1 -0
  7. package/dist/enrichment/enrichers/accessibility-enricher.js +1 -0
  8. package/dist/enrichment/enrichers/dom-enricher.js +1 -0
  9. package/dist/enrichment/enrichers/page-state-enricher.js +1 -0
  10. package/dist/enrichment/enrichers/position-enricher.js +1 -0
  11. package/dist/enrichment/index.js +1 -0
  12. package/dist/enrichment/mcp-integration.js +1 -0
  13. package/dist/enrichment/mcp-ref-enricher.js +1 -0
  14. package/dist/enrichment/pipeline.js +3 -0
  15. package/dist/enrichment/trace-text-enricher.js +1 -0
  16. package/dist/framework/agents/assistant-strategy.js +5 -0
  17. package/dist/framework/agents/base.js +1 -0
  18. package/dist/framework/agents/claude-strategy.js +4 -0
  19. package/dist/framework/agents/codex-strategy.js +4 -0
  20. package/dist/framework/agents/cursor-strategy.js +32 -0
  21. package/dist/framework/agents/gemini-strategy.js +11 -0
  22. package/dist/framework/agents/index.js +13 -0
  23. package/dist/framework/agents/middleware/assistant-round-pipeline.js +3 -0
  24. package/dist/framework/agents/providers/base.js +1 -0
  25. package/dist/framework/agents/providers/index.js +1 -0
  26. package/dist/framework/agents/providers/openai-transport.js +2 -0
  27. package/dist/framework/agents/providers/openai.js +1 -0
  28. package/dist/framework/agents/providers/transport-base.js +1 -0
  29. package/dist/framework/agents/utils/auth-resolver.js +1 -0
  30. package/dist/framework/agents/utils/cursor-output-formatter.js +1 -0
  31. package/dist/framework/agents/utils/openai-proxy-formatter.js +9 -0
  32. package/dist/framework/agents/utils/payload-budget.js +3 -0
  33. package/dist/framework/agents/utils/structured-output-formatter.js +21 -0
  34. package/dist/framework/code-generator.js +10 -0
  35. package/dist/framework/constants.js +1 -0
  36. package/dist/framework/context-loader.js +5 -0
  37. package/dist/framework/function-bridge.js +2 -0
  38. package/dist/framework/function-skill-registry.js +1 -0
  39. package/dist/framework/graph-compiler.js +1 -0
  40. package/dist/framework/graph.js +5 -0
  41. package/dist/framework/index.js +1 -0
  42. package/dist/framework/mcp-client.js +2 -0
  43. package/dist/framework/node-registry.js +9 -0
  44. package/dist/framework/node.js +5 -0
  45. package/dist/framework/output-parser.js +3 -0
  46. package/dist/framework/skill-registry.js +1 -0
  47. package/dist/framework/state-utils.js +1 -0
  48. package/dist/framework/state.js +1 -0
  49. package/dist/framework/tool-resolver.js +1 -0
  50. package/dist/index.js +8 -0
  51. package/dist/runtime/generation/base.js +1 -0
  52. package/dist/runtime/generation/index.js +3 -0
  53. package/dist/runtime/generation/mcp-ref-strategy.js +41 -0
  54. package/dist/runtime/generation/stable-id-strategy.js +16 -0
  55. package/dist/runtime/stable-id-runtime.js +1 -0
  56. package/dist/runtime/verification/base.js +1 -0
  57. package/dist/runtime/verification/index.js +3 -0
  58. package/dist/runtime/verification/playwright-json-strategy.js +1 -0
  59. package/dist/runtime/zibby-runtime.js +1 -0
  60. package/dist/sync/index.js +1 -0
  61. package/dist/sync/uploader.js +1 -0
  62. package/dist/tools/run-playwright-test.js +5 -0
  63. package/dist/utils/adf-converter.js +7 -0
  64. package/dist/utils/ast-utils.js +1 -0
  65. package/dist/utils/ci-setup.js +5 -0
  66. package/dist/utils/cursor-mcp-isolated-home.js +1 -0
  67. package/dist/utils/cursor-utils.js +18 -0
  68. package/dist/utils/live-frame-discovery.js +1 -0
  69. package/dist/utils/logger.js +1 -0
  70. package/dist/utils/mcp-config-writer.js +10 -0
  71. package/dist/utils/mission-control-from-run-states.js +1 -0
  72. package/dist/utils/node-schema-parser.js +1 -0
  73. package/dist/utils/parallel-config.js +1 -0
  74. package/dist/utils/post-process-events.js +1 -0
  75. package/dist/utils/result-handler.js +1 -0
  76. package/{src → dist}/utils/ripple-effect.js +3 -12
  77. package/dist/utils/run-capacity-coordinator.js +1 -0
  78. package/dist/utils/run-capacity-queue.js +2 -0
  79. package/dist/utils/run-index-merge.js +1 -0
  80. package/dist/utils/run-index-post-cli.js +1 -0
  81. package/dist/utils/run-registry.js +3 -0
  82. package/dist/utils/run-state-session.js +2 -0
  83. package/dist/utils/selector-generator.js +4 -0
  84. package/dist/utils/session-state-constants.js +1 -0
  85. package/dist/utils/session-state-live-runs.js +1 -0
  86. package/dist/utils/streaming-parser.js +4 -0
  87. package/dist/utils/test-post-processor.js +18 -0
  88. package/dist/utils/timeline.js +14 -0
  89. package/dist/utils/trace-parser.js +2 -0
  90. package/dist/utils/video-organizer.js +3 -0
  91. package/package.json +49 -35
  92. package/templates/browser-test-automation/README.md +29 -7
  93. package/templates/browser-test-automation/chat.mjs +36 -0
  94. package/templates/browser-test-automation/graph.mjs +5 -9
  95. package/templates/browser-test-automation/nodes/execute-live.mjs +30 -58
  96. package/templates/browser-test-automation/nodes/generate-script.mjs +32 -12
  97. package/templates/browser-test-automation/nodes/utils.mjs +153 -10
  98. package/templates/browser-test-automation/pipeline-ids.js +12 -0
  99. package/templates/browser-test-automation/result-handler.mjs +78 -2
  100. package/templates/browser-test-automation/run-index.mjs +418 -0
  101. package/scripts/export-default-workflows.js +0 -51
  102. package/scripts/patch-cursor-mcp.js +0 -174
  103. package/scripts/setup-ci.sh +0 -115
  104. package/scripts/setup-official-playwright-mcp.sh +0 -226
  105. package/scripts/test-with-video.sh +0 -49
  106. package/src/agents/base.js +0 -361
  107. package/src/constants.js +0 -47
  108. package/src/enrichment/base.js +0 -49
  109. package/src/enrichment/enrichers/accessibility-enricher.js +0 -197
  110. package/src/enrichment/enrichers/dom-enricher.js +0 -171
  111. package/src/enrichment/enrichers/page-state-enricher.js +0 -129
  112. package/src/enrichment/enrichers/position-enricher.js +0 -67
  113. package/src/enrichment/index.js +0 -96
  114. package/src/enrichment/mcp-integration.js +0 -149
  115. package/src/enrichment/mcp-ref-enricher.js +0 -78
  116. package/src/enrichment/pipeline.js +0 -192
  117. package/src/enrichment/trace-text-enricher.js +0 -115
  118. package/src/framework/AGENTS.md +0 -98
  119. package/src/framework/agents/base.js +0 -72
  120. package/src/framework/agents/claude-strategy.js +0 -278
  121. package/src/framework/agents/cursor-strategy.js +0 -544
  122. package/src/framework/agents/index.js +0 -105
  123. package/src/framework/agents/utils/cursor-output-formatter.js +0 -67
  124. package/src/framework/agents/utils/openai-proxy-formatter.js +0 -249
  125. package/src/framework/code-generator.js +0 -301
  126. package/src/framework/constants.js +0 -33
  127. package/src/framework/context-loader.js +0 -101
  128. package/src/framework/function-bridge.js +0 -78
  129. package/src/framework/function-skill-registry.js +0 -20
  130. package/src/framework/graph-compiler.js +0 -342
  131. package/src/framework/graph.js +0 -610
  132. package/src/framework/index.js +0 -28
  133. package/src/framework/node-registry.js +0 -163
  134. package/src/framework/node.js +0 -259
  135. package/src/framework/output-parser.js +0 -71
  136. package/src/framework/skill-registry.js +0 -55
  137. package/src/framework/state-utils.js +0 -52
  138. package/src/framework/state.js +0 -67
  139. package/src/framework/tool-resolver.js +0 -65
  140. package/src/index.js +0 -345
  141. package/src/runtime/generation/base.js +0 -46
  142. package/src/runtime/generation/index.js +0 -70
  143. package/src/runtime/generation/mcp-ref-strategy.js +0 -197
  144. package/src/runtime/generation/stable-id-strategy.js +0 -170
  145. package/src/runtime/stable-id-runtime.js +0 -248
  146. package/src/runtime/verification/base.js +0 -44
  147. package/src/runtime/verification/index.js +0 -67
  148. package/src/runtime/verification/playwright-json-strategy.js +0 -119
  149. package/src/runtime/zibby-runtime.js +0 -299
  150. package/src/sync/index.js +0 -2
  151. package/src/sync/uploader.js +0 -29
  152. package/src/tools/run-playwright-test.js +0 -158
  153. package/src/utils/adf-converter.js +0 -68
  154. package/src/utils/ast-utils.js +0 -37
  155. package/src/utils/ci-setup.js +0 -124
  156. package/src/utils/cursor-utils.js +0 -71
  157. package/src/utils/logger.js +0 -144
  158. package/src/utils/mcp-config-writer.js +0 -115
  159. package/src/utils/node-schema-parser.js +0 -522
  160. package/src/utils/post-process-events.js +0 -55
  161. package/src/utils/result-handler.js +0 -102
  162. package/src/utils/selector-generator.js +0 -239
  163. package/src/utils/streaming-parser.js +0 -387
  164. package/src/utils/test-post-processor.js +0 -211
  165. package/src/utils/timeline.js +0 -217
  166. package/src/utils/trace-parser.js +0 -325
  167. package/src/utils/video-organizer.js +0 -91
package/package.json CHANGED
@@ -1,31 +1,47 @@
1
1
  {
2
2
  "name": "@zibby/core",
3
- "version": "0.1.21",
3
+ "version": "0.1.22",
4
4
  "description": "Core test automation engine with multi-agent and multi-MCP support",
5
5
  "type": "module",
6
- "main": "src/index.js",
6
+ "main": "dist/index.js",
7
7
  "exports": {
8
- ".": "./src/index.js",
9
- "./sync": "./src/sync/index.js",
10
- "./framework/graph.js": "./src/framework/graph.js",
11
- "./framework/state.js": "./src/framework/state.js",
12
- "./framework/node.js": "./src/framework/node.js",
13
- "./framework/graph-compiler.js": "./src/framework/graph-compiler.js",
14
- "./framework/node-registry.js": "./src/framework/node-registry.js",
15
- "./framework/skill-registry.js": "./src/framework/skill-registry.js",
16
- "./framework/tool-resolver.js": "./src/framework/tool-resolver.js",
17
- "./framework/function-bridge.js": "./src/framework/function-bridge.js",
18
- "./framework/function-skill-registry.js": "./src/framework/function-skill-registry.js",
19
- "./framework/code-generator.js": "./src/framework/code-generator.js",
20
- "./utils/ast-utils.js": "./src/utils/ast-utils.js",
21
- "./utils/mcp-config-writer.js": "./src/utils/mcp-config-writer.js",
22
- "./utils/node-schema-parser.js": "./src/utils/node-schema-parser.js",
8
+ ".": "./dist/index.js",
9
+ "./backend-client.js": "./dist/backend-client.js",
10
+ "./sync": "./dist/sync/index.js",
11
+ "./framework/graph.js": "./dist/framework/graph.js",
12
+ "./framework/state.js": "./dist/framework/state.js",
13
+ "./framework/node.js": "./dist/framework/node.js",
14
+ "./framework/graph-compiler.js": "./dist/framework/graph-compiler.js",
15
+ "./framework/node-registry.js": "./dist/framework/node-registry.js",
16
+ "./framework/skill-registry.js": "./dist/framework/skill-registry.js",
17
+ "./framework/tool-resolver.js": "./dist/framework/tool-resolver.js",
18
+ "./framework/function-bridge.js": "./dist/framework/function-bridge.js",
19
+ "./framework/function-skill-registry.js": "./dist/framework/function-skill-registry.js",
20
+ "./framework/code-generator.js": "./dist/framework/code-generator.js",
21
+ "./utils/ast-utils.js": "./dist/utils/ast-utils.js",
22
+ "./utils/mcp-config-writer.js": "./dist/utils/mcp-config-writer.js",
23
+ "./utils/node-schema-parser.js": "./dist/utils/node-schema-parser.js",
24
+ "./utils/parallel-config.js": "./dist/utils/parallel-config.js",
25
+ "./utils/run-registry.js": "./dist/utils/run-registry.js",
26
+ "./utils/run-index-merge.js": "./dist/utils/run-index-merge.js",
27
+ "./utils/run-index-post-cli.js": "./dist/utils/run-index-post-cli.js",
28
+ "./utils/run-state-session.js": "./dist/utils/run-state-session.js",
29
+ "./utils/session-state-live-runs.js": "./dist/utils/session-state-live-runs.js",
30
+ "./utils/mission-control-from-run-states.js": "./dist/utils/mission-control-from-run-states.js",
31
+ "./utils/live-frame-discovery.js": "./dist/utils/live-frame-discovery.js",
32
+ "./utils/run-capacity-coordinator.js": "./dist/utils/run-capacity-coordinator.js",
33
+ "./utils/run-capacity-queue.js": "./dist/utils/run-capacity-queue.js",
34
+ "./utils/cursor-mcp-isolated-home.js": "./dist/utils/cursor-mcp-isolated-home.js",
35
+ "./constants/zibby-scratch.js": "./dist/constants/zibby-scratch.js",
36
+ "./templates/browser-test-automation/pipeline-ids.js": "./templates/browser-test-automation/pipeline-ids.js",
37
+ "./templates/browser-test-automation/run-index.mjs": "./templates/browser-test-automation/run-index.mjs",
23
38
  "./templates/register-nodes.js": "./templates/register-nodes.js",
24
39
  "./templates": "./templates/index.js",
25
40
  "./templates/*": "./templates/*",
26
41
  "./package.json": "./package.json"
27
42
  },
28
43
  "scripts": {
44
+ "build": "node ../scripts/build.mjs",
29
45
  "test": "vitest run --exclude '**/memory/**'",
30
46
  "test:watch": "vitest",
31
47
  "test:state-schema": "vitest run src/framework/__tests__/state-schema.test.js",
@@ -52,15 +68,11 @@
52
68
  "url": "https://github.com/ZibbyHQ/zibby-agent/issues"
53
69
  },
54
70
  "files": [
55
- "src/",
56
- "!src/**/__tests__/",
57
- "!src/**/*.test.js",
58
- "!src/**/*.spec.js",
71
+ "dist/",
59
72
  "templates/",
60
73
  "!templates/**/__tests__/",
61
74
  "!templates/**/*.test.js",
62
75
  "!templates/**/*.spec.js",
63
- "scripts/",
64
76
  "README.md",
65
77
  "LICENSE"
66
78
  ],
@@ -68,26 +80,28 @@
68
80
  "node": ">=18.0.0"
69
81
  },
70
82
  "dependencies": {
71
- "@anthropic-ai/claude-agent-sdk": "^0.2.50",
72
- "@anthropic-ai/sdk": "^0.71.2",
73
- "@modelcontextprotocol/sdk": "^1.27.1",
74
- "@playwright/mcp": "^0.0.54",
83
+ "@anthropic-ai/claude-agent-sdk": "^0.2.104",
84
+ "@anthropic-ai/sdk": "^0.88.0",
85
+ "@modelcontextprotocol/sdk": "^1.29.0",
86
+ "@openai/codex-sdk": "^0.120.0",
87
+ "@playwright/mcp": "^0.0.70",
88
+ "@zibby/mcp-browser": "^0.1.6",
75
89
  "acorn": "^8.15.0",
76
- "acorn-walk": "^8.3.4",
77
- "axios": "^1.13.3",
90
+ "acorn-walk": "^8.3.5",
91
+ "axios": "^1.15.0",
78
92
  "chalk": "^5.3.0",
79
- "dotenv": "^16.4.0",
80
- "handlebars": "^4.7.8",
81
- "zod": "^3.23.0",
82
- "@zibby/mcp-browser": "^0.1.0",
83
- "zod-to-json-schema": "^3.25.1"
93
+ "dotenv": "^17.4.1",
94
+ "handlebars": "^4.7.9",
95
+ "zod": "^4.3.6",
96
+ "zod-to-json-schema": "^3.25.2"
84
97
  },
85
98
  "peerDependencies": {
86
99
  "@playwright/test": ">=1.49.0",
87
100
  "playwright": ">=1.49.0"
88
101
  },
89
102
  "devDependencies": {
90
- "@playwright/test": "^1.49.0",
91
- "vitest": "^4.0.18"
103
+ "@playwright/test": "^1.59.1",
104
+ "esbuild": "^0.28.0",
105
+ "vitest": "^4.1.4"
92
106
  }
93
107
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  This is YOUR workflow graph. You can customize it however you want!
4
4
 
5
- Works with **Claude** or **Cursor** agents (configured in `.zibby.config.js`).
5
+ Works with **Claude** or **Cursor** agents (configured in `.zibby.config.mjs`).
6
6
 
7
7
  ## Default Flow
8
8
 
@@ -86,18 +86,40 @@ graph.addParallelEdges('verify_script', [
86
86
 
87
87
  ## Configuration
88
88
 
89
- Edit `.zibby/config.js` to set default agents per node:
89
+ Edit `.zibby.config.mjs` to set your default agent and optional per-node model overrides:
90
90
 
91
91
  ```javascript
92
92
  export default {
93
- agents: {
94
- execute_live: { type: 'cursor' },
95
- verify_script: { type: 'deepseek', model: 'deepseek-coder' },
96
- update_jira: { type: 'ollama', model: 'llama3' }
97
- }
93
+ agent: {
94
+ cursor: { model: 'auto' }, // or claude: { model: 'auto' }
95
+ strictMode: false,
96
+ },
97
+ models: {
98
+ default: 'auto',
99
+ execute_live: 'auto',
100
+ generate_script: 'auto',
101
+ },
98
102
  };
99
103
  ```
100
104
 
105
+ ## Studio / Scripts tab (code discovery)
106
+
107
+ Runs write `generate_script/result.json` with a `scriptPath` (often under your repo `tests/`). After the graph finishes, **`BrowserTestResultHandler.ensureStudioCodegenMirror`** copies that file into the session folder under stable names so tools don’t need Studio running at generation time:
108
+
109
+ | File (under `.zibby/output/sessions/<sessionId>/generate_script/`) | Role |
110
+ |---------------------------------------------------------------------|------|
111
+ | `generated-test.spec.js` | Playwright (`.js`) |
112
+ | `playwright.spec.ts` | Playwright (`.ts` / `.tsx` source) |
113
+ | `test.selenium.py` | Selenium |
114
+
115
+ **Electron Studio** resolves these via `discoverCodegenArtifactsElectron` (after `session/codegen/`).
116
+
117
+ **Web Studio** (`VITE_STUDIO_API_ORIGIN`, e.g. `:3847`) should implement `GET /api/sessions/:id/codegen/playwright` (and `/selenium`) by reading, in order:
118
+
119
+ 1. `sessions/<id>/codegen/` legacy JIT names (`test.spec.ts`, `generated-test.spec.js`, …)
120
+ 2. **`sessions/<id>/generate_script/`** canonical names above
121
+ 3. `scriptPath` from `generate_script/result.json` (resolve relative to session / `cwd` from session meta)
122
+
101
123
  ## Documentation
102
124
 
103
125
  - [Full Graph Framework Design](../../docs/GRAPH_FRAMEWORK_DESIGN.md)
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Zibby Chat Agent
3
+ *
4
+ * Interactive conversational node that acts as the default entry point
5
+ * when users type `zibby` with no subcommand.
6
+ *
7
+ * This is a plain chat bot — no MCP servers, no middleware, no structured output.
8
+ * Just streamed text conversation with the AI agent.
9
+ *
10
+ * The skill-installer skill injects its promptFragment so the LLM knows which
11
+ * skills are available and can install/uninstall them via natural conversation.
12
+ * Users can customize this file after `zibby init` copies it to .zibby/chat.mjs
13
+ */
14
+
15
+ import { SKILLS } from '@zibby/core';
16
+
17
+ export const CHAT_CONFIG = {
18
+ name: 'zibby_chat',
19
+ skills: [SKILLS.CORE_TOOLS, SKILLS.SKILL_INSTALLER, SKILLS.CHAT_MEMORY],
20
+ timeout: 0,
21
+
22
+ systemPrompt: `You are Zibby, a helpful AI assistant. Capabilities come from installed skills.
23
+
24
+ ## How you work
25
+ 1. When you need data, call tools. You can chain up to 5 calls per turn.
26
+ 2. After each tool result, decide: "Would I be embarrassed to give this answer to a coworker?" If yes, call another tool.
27
+ 3. Only respond once you have something genuinely useful.
28
+ 4. Never claim you did something without actually calling the tool.
29
+ 5. After EVERY response, self-evaluate: is the user's goal fully achieved? Is anything still pending or running? If yes, DO NOT ASK — autonomously poll: call wait (you decide how long), then check status, then respond with an update. Repeat until done or the user interrupts.
30
+
31
+ ## How you talk
32
+ - Talk like a teammate in Slack, not a report generator.
33
+ - Summarize and paraphrase. Never copy-paste field values or list raw steps verbatim.
34
+ - Short paragraphs, not numbered lists (unless the user specifically asks for steps).
35
+ - Match the user's tone and energy. Be concise.`,
36
+ };
@@ -13,17 +13,9 @@ import {
13
13
  } from './nodes/index.mjs';
14
14
  import { BrowserTestResultHandler } from './result-handler.mjs';
15
15
 
16
- let memoryMiddleware = null;
17
- try {
18
- const mem = await import('@zibby/memory');
19
- memoryMiddleware = mem.memoryMiddleware;
20
- } catch { /* @zibby/memory not installed */ }
21
-
22
16
  export class BrowserTestAutomationAgent extends WorkflowAgent {
23
17
  buildGraph() {
24
- const graph = new WorkflowGraph({
25
- middleware: [memoryMiddleware?.()].filter(Boolean),
26
- });
18
+ const graph = new WorkflowGraph();
27
19
 
28
20
  graph.addNode('preflight', preflightNode);
29
21
  graph.addNode('execute_live', executeLiveNode);
@@ -46,6 +38,10 @@ export class BrowserTestAutomationAgent extends WorkflowAgent {
46
38
  const cwd = result.state.cwd || process.cwd();
47
39
  BrowserTestResultHandler.saveTitle(result, cwd);
48
40
  await BrowserTestResultHandler.saveExecutionData(result);
41
+ BrowserTestResultHandler.ensureStudioCodegenMirror(
42
+ result.state?.sessionPath,
43
+ result.state?.cwd || cwd,
44
+ );
49
45
 
50
46
  // Memory end-run hook (if @zibby/memory is installed)
51
47
  try {
@@ -6,7 +6,7 @@
6
6
  * Configuration:
7
7
  * - capabilities: Declares ['browser'] — framework injects the appropriate MCP server
8
8
  * - outputSchema: Structured JSON with execution results, actions, assertions
9
- * - Model: Configured in .zibby.config.js → agent.claude.model or agent.cursor.model
9
+ * - Model: Configured in .zibby.config.mjs → agent.claude.model or agent.cursor.model
10
10
  */
11
11
 
12
12
  import { z, SKILLS } from '@zibby/core';
@@ -31,14 +31,6 @@ ${ctx.env ? `Environment Config:\n${JSON.stringify(ctx.env, null, 2)}\n` : ''}
31
31
 
32
32
  return `⚠️ CRITICAL: At the END, output ONLY the JSON object. NO explanations after the JSON.
33
33
 
34
- Execute this test using ONLY mcp_playwright-official_browser_* tools.
35
-
36
- 🚨 HONESTY REQUIREMENT (STRICT):
37
- - If you DO NOT have access to browser tools → return {"success": false, "steps": [], "browserClosed": false, "notes": "No browser tools available"}
38
- - DO NOT hallucinate or pretend you executed the test
39
- - DO NOT return success: true unless you ACTUALLY called browser tools
40
- - BE HONEST - it's better to admit you can't do it than to lie
41
-
42
34
  🎯 YOUR GOAL: Execute the test steps and collect evidence for script generation.
43
35
  You don't need perfect verification - just capture the key actions and results.
44
36
  The next node will generate the actual test script from your execution.
@@ -151,46 +143,6 @@ IMPORTANT for 'evidenceScreenshots' (array) - OPTIONAL:
151
143
  - If you take screenshots, use descriptive filenames
152
144
  - Filename pattern: "{step-number}-{action-or-state}.png"
153
145
  - Keep it minimal - test execution is more important than documentation
154
-
155
- ════════════════════════════════════════════════════════════
156
- 🚨 CRITICAL JSON OUTPUT RULES 🚨
157
-
158
- YOU MUST OUTPUT JSON USING ONE OF THESE TWO FORMATS:
159
-
160
- ✅ FORMAT 1 (BEST - Use This!):
161
- Think/plan/explain first, THEN output ONLY JSON:
162
-
163
- I'll navigate to the login page and fill the form...
164
- [... use browser tools ...]
165
- [... complete test execution ...]
166
-
167
- {"success": true, "steps": [...], "browserClosed": true}
168
-
169
- NO TEXT AFTER THE JSON! Stop immediately after }.
170
-
171
- ✅ FORMAT 2 (If you need to explain after):
172
- Use delimiters to separate JSON from explanations:
173
-
174
- I'm executing the test now...
175
- [... use browser tools ...]
176
-
177
- ===JSON_START===
178
- {"success": true, "steps": [...], "browserClosed": true}
179
- ===JSON_END===
180
-
181
- Now let me explain what happened...
182
-
183
- ❌ WRONG - DO NOT DO THIS:
184
- {"success": true, "steps": [...]} followed by more explanations
185
-
186
- ❌ WRONG - DO NOT STREAM JSON LETTER BY LETTER:
187
- The test completed successfully, here's the result: { "success": t
188
-
189
- ✅ CORRECT - Output complete JSON in one block:
190
- {"success": true, "steps": ["step 1", "step 2"], "browserClosed": true}
191
-
192
- REMEMBER: After the final }, you MUST STOP or use ===JSON_END===
193
- ════════════════════════════════════════════════════════════
194
146
  `;
195
147
  },
196
148
 
@@ -202,11 +154,27 @@ REMEMBER: After the final }, you MUST STOP or use ===JSON_END===
202
154
  .describe('Array of test steps executed'),
203
155
 
204
156
  finalUrl: z.string()
205
- .optional()
157
+ .nullish()
206
158
  .describe('Final URL after test execution'),
207
159
 
208
- actions: z.array(z.any())
209
- .optional()
160
+ actions: z.array(z.object({
161
+ type: z.string()
162
+ .describe('Action type: navigate, click, fill, type, select, keypress, hover, drag'),
163
+ description: z.string()
164
+ .describe('Human-readable description of the action'),
165
+ reasoning: z.string().nullish()
166
+ .describe('Why this action was performed'),
167
+ selectors: z.object({
168
+ role: z.object({
169
+ role: z.string().describe('ARIA role (e.g. button, link, textbox, generic)'),
170
+ name: z.string().nullish().describe('Accessible name of the element')
171
+ }).nullish().describe('Role-based selector for fallback matching')
172
+ }).nullish()
173
+ .describe('Element selectors captured during the action'),
174
+ value: z.string().nullish()
175
+ .describe('Value entered for fill/type actions')
176
+ }))
177
+ .nullish()
210
178
  .describe('Detailed array of actions performed with descriptions and reasoning'),
211
179
 
212
180
  assertions: z.array(z.object({
@@ -217,14 +185,18 @@ REMEMBER: After the final }, you MUST STOP or use ===JSON_END===
217
185
  verifiedAfterAction: z.number()
218
186
  .describe('Index of the action after which this was verified (0-based, matches actions array index) - REQUIRED'),
219
187
  evidence: z.string()
220
- .optional()
188
+ .nullish()
221
189
  .describe('Brief evidence of what was observed')
222
190
  }))
223
- .optional()
191
+ .nullish()
224
192
  .describe('Array of assertions made during test'),
225
193
 
226
- waits: z.array(z.any())
227
- .optional()
194
+ waits: z.array(z.object({
195
+ description: z.string().describe('What the wait is for'),
196
+ duration: z.number().nullish().describe('Wait duration in milliseconds'),
197
+ condition: z.string().nullish().describe('Wait condition expression')
198
+ }))
199
+ .nullish()
228
200
  .describe('Array of waits needed for proper test execution'),
229
201
 
230
202
  evidenceScreenshots: z.array(z.object({
@@ -237,14 +209,14 @@ REMEMBER: After the final }, you MUST STOP or use ===JSON_END===
237
209
  verdict: z.enum(['pass', 'fail', 'info'])
238
210
  .describe('Test verdict: pass/fail for validation points, info for checkpoints')
239
211
  }))
240
- .optional()
212
+ .nullish()
241
213
  .describe('Array of screenshots taken at key validation points throughout the test'),
242
214
 
243
215
  browserClosed: z.boolean()
244
216
  .describe('Whether the browser was properly closed (should always be true)'),
245
217
 
246
218
  notes: z.string()
247
- .optional()
219
+ .nullish()
248
220
  .describe('Additional notes or observations. REQUIRED when success=false to explain why test failed or could not execute')
249
221
  })
250
222
  };
@@ -1,5 +1,5 @@
1
- import { z } from '@zibby/core';
2
- import { formatRecordedActions, formatAssertionsWithResults } from './utils.mjs';
1
+ import { z, SKILLS } from '@zibby/core';
2
+ import { formatRecordedActions, formatAssertionsWithResults, loadRecordedActions, detectLoginPattern, formatSetupHint } from './utils.mjs';
3
3
 
4
4
  const GenerateScriptOutputSchema = z.object({
5
5
  success: z.boolean(),
@@ -9,8 +9,9 @@ const GenerateScriptOutputSchema = z.object({
9
9
 
10
10
  export const generateScriptNode = {
11
11
  name: 'generate_script',
12
+ skills: [SKILLS.MEMORY],
12
13
  outputSchema: GenerateScriptOutputSchema,
13
- timeout: 360000,
14
+ timeout: 1200000,
14
15
 
15
16
  prompt: (state) => {
16
17
  const exec = state.execute_live || {};
@@ -24,6 +25,9 @@ export const generateScriptNode = {
24
25
  exec.finalUrl
25
26
  );
26
27
 
28
+ const recorded = loadRecordedActions(state.sessionPath);
29
+ const setupHint = formatSetupHint(detectLoginPattern(recorded));
30
+
27
31
  return `Generate and verify Playwright test at ${state.outputPath}
28
32
 
29
33
  Test Spec:
@@ -35,18 +39,23 @@ Live Execution Summary:
35
39
  - Final URL: ${exec.finalUrl || 'unknown'}
36
40
  ${actionsBlock}
37
41
  ${assertionsBlock}
38
-
42
+ ${setupHint}
39
43
  IMPORTS AND PATTERN:
40
44
  \`\`\`javascript
41
45
  import { test, expect } from '@playwright/test';
42
46
  import { StableIdRuntime } from '@zibby/core';
43
47
 
48
+ async function clickSafe(page, stableId, fallback) {
49
+ try { await StableIdRuntime.clickWithRetry(page, stableId); }
50
+ catch { await fallback.click(); }
51
+ }
52
+
44
53
  test('Test Name', async ({ page }) => {
45
54
  await page.goto('https://...');
46
55
  await StableIdRuntime.injectStableIds(page);
47
- // Elements WITH stable IDs — use StableIdRuntime:
56
+ // Elements WITH stable IDs + fallback — use clickSafe:
57
+ await clickSafe(page, 'zibby-xxxxx', page.getByRole('button', { name: '...' }));
48
58
  await StableIdRuntime.fillWithRetry(page, 'zibby-xxxxx', 'value');
49
- await StableIdRuntime.clickWithRetry(page, 'zibby-xxxxx');
50
59
  // Elements WITHOUT stable IDs (NO_STABLE_ID) — use native Playwright selectors:
51
60
  await page.getByText('visible text').click();
52
61
  await page.getByRole('button', { name: 'Submit' }).click();
@@ -58,18 +67,29 @@ test('Test Name', async ({ page }) => {
58
67
  RULES:
59
68
  1. First navigate → page.goto(), skip subsequent navigates
60
69
  2. After goto, call StableIdRuntime.injectStableIds(page)
61
- 3. Use EXACT stable IDs from recorded actions when available
62
- 4. For [NO_STABLE_ID] actions, use the fallback selector (getByText, getByRole, getByPlaceholder). These are typically non-semantic elements like spans acting as buttons use the visible text to target them.
70
+ 3. Selector priority:
71
+ a. If memory/insights flag a stableId as unreliable use the fallback selector instead
72
+ b. If action is marked [DUPLICATE_STABLE_ID] → always use the provided fallback
73
+ c. Cross-reference stableIds against memory "Reliable Selectors" and "Flaky Selectors" — prefer proven selectors, avoid flaky ones
74
+ d. Otherwise use EXACT stable IDs from recorded actions
75
+ 4. For [NO_STABLE_ID] actions, use the fallback selector (getByText, getByRole, getByPlaceholder)
63
76
  5. Skip duplicate consecutive clicks on same stableId
64
77
  6. No comments in generated code
65
78
  7. Implement ALL assertions from the list above
66
79
  8. If an assertion fails after retries, comment it out with a TODO (don't delete it)
80
+ 9. Selector failure handling:
81
+ - When a stableId fails and you switch to a fallback, IMMEDIATELY call memory_save_insight (category: selector_tip) with which stableId failed, which fallback worked, and the page URL
82
+ - Note the specific Playwright locator strategy that succeeded
83
+ 10. Navigation order: always complete setup/login FIRST from the base URL, then navigate to the target page. Never go to a deep URL before setup is done.
84
+ 11. The generated test runs in a FRESH browser with no prior state. Even if the live execution skipped setup steps, the test must include them. Check memory insights for any required setup.
67
85
 
68
86
  WORKFLOW:
69
- 1. Write test to ${state.outputPath}
70
- 2. Run: PLAYWRIGHT_HEADLESS=1 npx playwright test ${state.outputPath} --reporter=line --timeout=30000
71
- 3. If fails: make ONE targeted fix (longer timeout, different selector, short wait)
72
- 4. MAX 2 ATTEMPTS then STOP
87
+ 1. Study the codebase FIRST — search tests/ for existing helpers, fixtures, and shared setup files. Read them. Reuse what exists. Do NOT create files that duplicate existing ones.
88
+ 2. Write test to ${state.outputPath} (after the run, a copy is mirrored under ${state.sessionPath}/generate_script/ for Studio — you may also write directly there if you prefer)
89
+ 3. Verify syntax: run node --check on the file. If it fails, fix and re-check before proceeding.
90
+ 4. Run: PLAYWRIGHT_HEADLESS=1 npx playwright test ${state.outputPath} --reporter=line --timeout=60000
91
+ 5. If fails: try selectors in order — (a) getByRole (b) getByText (c) getByTestId (d) add waitForSelector. Never retry the same selector twice.
92
+ 6. MAX 2 ATTEMPTS then STOP
73
93
 
74
94
  The test runs in: ${state.cwd || 'project root'}
75
95
  `;