@eidra-umain/greenlight 0.1.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 (142) hide show
  1. package/README.md +391 -0
  2. package/dist/browser/browser.d.ts +24 -0
  3. package/dist/browser/browser.d.ts.map +1 -0
  4. package/dist/browser/browser.js +44 -0
  5. package/dist/browser/browser.js.map +1 -0
  6. package/dist/cli/index.d.ts +3 -0
  7. package/dist/cli/index.d.ts.map +1 -0
  8. package/dist/cli/index.js +140 -0
  9. package/dist/cli/index.js.map +1 -0
  10. package/dist/cli/run.d.ts +9 -0
  11. package/dist/cli/run.d.ts.map +1 -0
  12. package/dist/cli/run.js +277 -0
  13. package/dist/cli/run.js.map +1 -0
  14. package/dist/config.d.ts +48 -0
  15. package/dist/config.d.ts.map +1 -0
  16. package/dist/config.js +107 -0
  17. package/dist/config.js.map +1 -0
  18. package/dist/globals.d.ts +21 -0
  19. package/dist/globals.d.ts.map +1 -0
  20. package/dist/globals.js +24 -0
  21. package/dist/globals.js.map +1 -0
  22. package/dist/parser/loader.d.ts +7 -0
  23. package/dist/parser/loader.d.ts.map +1 -0
  24. package/dist/parser/loader.js +43 -0
  25. package/dist/parser/loader.js.map +1 -0
  26. package/dist/parser/schema.d.ts +42 -0
  27. package/dist/parser/schema.d.ts.map +1 -0
  28. package/dist/parser/schema.js +33 -0
  29. package/dist/parser/schema.js.map +1 -0
  30. package/dist/parser/steps.d.ts +13 -0
  31. package/dist/parser/steps.d.ts.map +1 -0
  32. package/dist/parser/steps.js +44 -0
  33. package/dist/parser/steps.js.map +1 -0
  34. package/dist/parser/variables.d.ts +18 -0
  35. package/dist/parser/variables.d.ts.map +1 -0
  36. package/dist/parser/variables.js +44 -0
  37. package/dist/parser/variables.js.map +1 -0
  38. package/dist/pilot/a11y-parser.d.ts +26 -0
  39. package/dist/pilot/a11y-parser.d.ts.map +1 -0
  40. package/dist/pilot/a11y-parser.js +195 -0
  41. package/dist/pilot/a11y-parser.js.map +1 -0
  42. package/dist/pilot/assertions.d.ts +30 -0
  43. package/dist/pilot/assertions.d.ts.map +1 -0
  44. package/dist/pilot/assertions.js +219 -0
  45. package/dist/pilot/assertions.js.map +1 -0
  46. package/dist/pilot/checkbox.d.ts +12 -0
  47. package/dist/pilot/checkbox.d.ts.map +1 -0
  48. package/dist/pilot/checkbox.js +104 -0
  49. package/dist/pilot/checkbox.js.map +1 -0
  50. package/dist/pilot/executor.d.ts +17 -0
  51. package/dist/pilot/executor.d.ts.map +1 -0
  52. package/dist/pilot/executor.js +462 -0
  53. package/dist/pilot/executor.js.map +1 -0
  54. package/dist/pilot/form-fields.d.ts +34 -0
  55. package/dist/pilot/form-fields.d.ts.map +1 -0
  56. package/dist/pilot/form-fields.js +139 -0
  57. package/dist/pilot/form-fields.js.map +1 -0
  58. package/dist/pilot/llm.d.ts +49 -0
  59. package/dist/pilot/llm.d.ts.map +1 -0
  60. package/dist/pilot/llm.js +188 -0
  61. package/dist/pilot/llm.js.map +1 -0
  62. package/dist/pilot/locator.d.ts +58 -0
  63. package/dist/pilot/locator.d.ts.map +1 -0
  64. package/dist/pilot/locator.js +248 -0
  65. package/dist/pilot/locator.js.map +1 -0
  66. package/dist/pilot/message-builder.d.ts +31 -0
  67. package/dist/pilot/message-builder.d.ts.map +1 -0
  68. package/dist/pilot/message-builder.js +112 -0
  69. package/dist/pilot/message-builder.js.map +1 -0
  70. package/dist/pilot/network.d.ts +23 -0
  71. package/dist/pilot/network.d.ts.map +1 -0
  72. package/dist/pilot/network.js +92 -0
  73. package/dist/pilot/network.js.map +1 -0
  74. package/dist/pilot/pilot.d.ts +27 -0
  75. package/dist/pilot/pilot.d.ts.map +1 -0
  76. package/dist/pilot/pilot.js +249 -0
  77. package/dist/pilot/pilot.js.map +1 -0
  78. package/dist/pilot/prompts.d.ts +8 -0
  79. package/dist/pilot/prompts.d.ts.map +1 -0
  80. package/dist/pilot/prompts.js +163 -0
  81. package/dist/pilot/prompts.js.map +1 -0
  82. package/dist/pilot/providers/anthropic.d.ts +6 -0
  83. package/dist/pilot/providers/anthropic.d.ts.map +1 -0
  84. package/dist/pilot/providers/anthropic.js +45 -0
  85. package/dist/pilot/providers/anthropic.js.map +1 -0
  86. package/dist/pilot/providers/gemini.d.ts +6 -0
  87. package/dist/pilot/providers/gemini.d.ts.map +1 -0
  88. package/dist/pilot/providers/gemini.js +55 -0
  89. package/dist/pilot/providers/gemini.js.map +1 -0
  90. package/dist/pilot/providers/index.d.ts +10 -0
  91. package/dist/pilot/providers/index.d.ts.map +1 -0
  92. package/dist/pilot/providers/index.js +25 -0
  93. package/dist/pilot/providers/index.js.map +1 -0
  94. package/dist/pilot/providers/openai-compatible.d.ts +7 -0
  95. package/dist/pilot/providers/openai-compatible.d.ts.map +1 -0
  96. package/dist/pilot/providers/openai-compatible.js +34 -0
  97. package/dist/pilot/providers/openai-compatible.js.map +1 -0
  98. package/dist/pilot/providers/types.d.ts +12 -0
  99. package/dist/pilot/providers/types.d.ts.map +1 -0
  100. package/dist/pilot/providers/types.js +2 -0
  101. package/dist/pilot/providers/types.js.map +1 -0
  102. package/dist/pilot/response-parser.d.ts +31 -0
  103. package/dist/pilot/response-parser.d.ts.map +1 -0
  104. package/dist/pilot/response-parser.js +188 -0
  105. package/dist/pilot/response-parser.js.map +1 -0
  106. package/dist/pilot/state.d.ts +19 -0
  107. package/dist/pilot/state.d.ts.map +1 -0
  108. package/dist/pilot/state.js +67 -0
  109. package/dist/pilot/state.js.map +1 -0
  110. package/dist/pilot/trace.d.ts +16 -0
  111. package/dist/pilot/trace.d.ts.map +1 -0
  112. package/dist/pilot/trace.js +117 -0
  113. package/dist/pilot/trace.js.map +1 -0
  114. package/dist/planner/hasher.d.ts +14 -0
  115. package/dist/planner/hasher.d.ts.map +1 -0
  116. package/dist/planner/hasher.js +21 -0
  117. package/dist/planner/hasher.js.map +1 -0
  118. package/dist/planner/plan-generator.d.ts +23 -0
  119. package/dist/planner/plan-generator.d.ts.map +1 -0
  120. package/dist/planner/plan-generator.js +56 -0
  121. package/dist/planner/plan-generator.js.map +1 -0
  122. package/dist/planner/plan-runner.d.ts +16 -0
  123. package/dist/planner/plan-runner.d.ts.map +1 -0
  124. package/dist/planner/plan-runner.js +375 -0
  125. package/dist/planner/plan-runner.js.map +1 -0
  126. package/dist/planner/plan-store.d.ts +22 -0
  127. package/dist/planner/plan-store.d.ts.map +1 -0
  128. package/dist/planner/plan-store.js +71 -0
  129. package/dist/planner/plan-store.js.map +1 -0
  130. package/dist/planner/plan-types.d.ts +64 -0
  131. package/dist/planner/plan-types.d.ts.map +1 -0
  132. package/dist/planner/plan-types.js +7 -0
  133. package/dist/planner/plan-types.js.map +1 -0
  134. package/dist/reporter/types.d.ts +130 -0
  135. package/dist/reporter/types.d.ts.map +1 -0
  136. package/dist/reporter/types.js +5 -0
  137. package/dist/reporter/types.js.map +1 -0
  138. package/dist/types.d.ts +51 -0
  139. package/dist/types.d.ts.map +1 -0
  140. package/dist/types.js +23 -0
  141. package/dist/types.js.map +1 -0
  142. package/package.json +64 -0
@@ -0,0 +1,10 @@
1
+ import type { Provider } from "../../types.js";
2
+ import type { LLMProvider } from "./types.js";
3
+ export type { ChatMessage, ProviderConfig, LLMProvider } from "./types.js";
4
+ /**
5
+ * Factory: create an LLMProvider by name.
6
+ * @param name - The provider identifier.
7
+ * @param baseUrlOverride - Optional override for the provider's base URL.
8
+ */
9
+ export declare function createProvider(name: Provider, baseUrlOverride?: string): LLMProvider;
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/pilot/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAK7C,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE1E;;;;GAIG;AACH,wBAAgB,cAAc,CAC7B,IAAI,EAAE,QAAQ,EACd,eAAe,CAAC,EAAE,MAAM,GACtB,WAAW,CAqBb"}
@@ -0,0 +1,25 @@
1
+ import { createOpenAICompatibleProvider } from "./openai-compatible.js";
2
+ import { createAnthropicProvider } from "./anthropic.js";
3
+ import { createGeminiProvider } from "./gemini.js";
4
+ /**
5
+ * Factory: create an LLMProvider by name.
6
+ * @param name - The provider identifier.
7
+ * @param baseUrlOverride - Optional override for the provider's base URL.
8
+ */
9
+ export function createProvider(name, baseUrlOverride) {
10
+ switch (name) {
11
+ case "openrouter":
12
+ return createOpenAICompatibleProvider(baseUrlOverride ?? "https://openrouter.ai/api/v1");
13
+ case "openai":
14
+ return createOpenAICompatibleProvider(baseUrlOverride ?? "https://api.openai.com/v1");
15
+ case "claude":
16
+ return createAnthropicProvider(baseUrlOverride ?? "https://api.anthropic.com");
17
+ case "gemini":
18
+ return createGeminiProvider(baseUrlOverride);
19
+ default: {
20
+ const _exhaustive = name;
21
+ throw new Error(`Unknown provider: ${String(_exhaustive)}`);
22
+ }
23
+ }
24
+ }
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/pilot/providers/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,8BAA8B,EAAE,MAAM,wBAAwB,CAAA;AACvE,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAIlD;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC7B,IAAc,EACd,eAAwB;IAExB,QAAQ,IAAI,EAAE,CAAC;QACd,KAAK,YAAY;YAChB,OAAO,8BAA8B,CACpC,eAAe,IAAI,8BAA8B,CACjD,CAAA;QACF,KAAK,QAAQ;YACZ,OAAO,8BAA8B,CACpC,eAAe,IAAI,2BAA2B,CAC9C,CAAA;QACF,KAAK,QAAQ;YACZ,OAAO,uBAAuB,CAC7B,eAAe,IAAI,2BAA2B,CAC9C,CAAA;QACF,KAAK,QAAQ;YACZ,OAAO,oBAAoB,CAAC,eAAe,CAAC,CAAA;QAC7C,OAAO,CAAC,CAAC,CAAC;YACT,MAAM,WAAW,GAAU,IAAI,CAAA;YAC/B,MAAM,IAAI,KAAK,CAAC,qBAAqB,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAA;QAC5D,CAAC;IACF,CAAC;AACF,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { LLMProvider } from "./types.js";
2
+ /**
3
+ * OpenAI-compatible chat completions provider.
4
+ * Works with OpenRouter, OpenAI, and any API that follows the same format.
5
+ */
6
+ export declare function createOpenAICompatibleProvider(baseUrl: string): LLMProvider;
7
+ //# sourceMappingURL=openai-compatible.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai-compatible.d.ts","sourceRoot":"","sources":["../../../src/pilot/providers/openai-compatible.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,WAAW,EAAkB,MAAM,YAAY,CAAA;AAE1E;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAwC3E"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * OpenAI-compatible chat completions provider.
3
+ * Works with OpenRouter, OpenAI, and any API that follows the same format.
4
+ */
5
+ export function createOpenAICompatibleProvider(baseUrl) {
6
+ const endpoint = `${baseUrl.replace(/\/+$/, "")}/chat/completions`;
7
+ return {
8
+ async chatCompletion(messages, config) {
9
+ const response = await fetch(endpoint, {
10
+ method: "POST",
11
+ headers: {
12
+ "Content-Type": "application/json",
13
+ Authorization: `Bearer ${config.apiKey}`,
14
+ },
15
+ body: JSON.stringify({
16
+ model: config.model,
17
+ messages,
18
+ temperature: 0,
19
+ }),
20
+ });
21
+ if (!response.ok) {
22
+ const body = await response.text();
23
+ throw new Error(`LLM API error ${String(response.status)}: ${body}`);
24
+ }
25
+ const data = (await response.json());
26
+ const content = data.choices[0]?.message?.content;
27
+ if (!content) {
28
+ throw new Error("LLM returned empty response");
29
+ }
30
+ return content;
31
+ },
32
+ };
33
+ }
34
+ //# sourceMappingURL=openai-compatible.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai-compatible.js","sourceRoot":"","sources":["../../../src/pilot/providers/openai-compatible.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,8BAA8B,CAAC,OAAe;IAC7D,MAAM,QAAQ,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,mBAAmB,CAAA;IAElE,OAAO;QACN,KAAK,CAAC,cAAc,CACnB,QAAuB,EACvB,MAAsB;YAEtB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;gBACtC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACR,cAAc,EAAE,kBAAkB;oBAClC,aAAa,EAAE,UAAU,MAAM,CAAC,MAAM,EAAE;iBACxC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACpB,KAAK,EAAE,MAAM,CAAC,KAAK;oBACnB,QAAQ;oBACR,WAAW,EAAE,CAAC;iBACd,CAAC;aACF,CAAC,CAAA;YAEF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBAClB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;gBAClC,MAAM,IAAI,KAAK,CACd,iBAAiB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CACnD,CAAA;YACF,CAAC;YAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAElC,CAAA;YAED,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAA;YACjD,IAAI,CAAC,OAAO,EAAE,CAAC;gBACd,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAA;YAC/C,CAAC;YAED,OAAO,OAAO,CAAA;QACf,CAAC;KACD,CAAA;AACF,CAAC"}
@@ -0,0 +1,12 @@
1
+ export interface ChatMessage {
2
+ role: "system" | "user" | "assistant";
3
+ content: string;
4
+ }
5
+ export interface ProviderConfig {
6
+ apiKey: string;
7
+ model: string;
8
+ }
9
+ export interface LLMProvider {
10
+ chatCompletion(messages: ChatMessage[], config: ProviderConfig): Promise<string>;
11
+ }
12
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/pilot/providers/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAA;IACrC,OAAO,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,cAAc;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,WAAW;IAC3B,cAAc,CACb,QAAQ,EAAE,WAAW,EAAE,EACvB,MAAM,EAAE,cAAc,GACpB,OAAO,CAAC,MAAM,CAAC,CAAA;CAClB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/pilot/providers/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Parsing and validation for LLM responses.
3
+ */
4
+ import type { Action } from "../reporter/types.js";
5
+ /** A single planned step: the display label and either a pre-resolved action or null. */
6
+ export interface PlannedStep {
7
+ step: string;
8
+ action: Action | null;
9
+ /** If true, this step needs runtime expansion into multiple sub-actions (e.g. form filling). */
10
+ needsExpansion?: boolean;
11
+ /** For REMEMBER steps: the variable name to store the captured value under. */
12
+ rememberAs?: string;
13
+ /** For COMPARE steps: the comparison metadata (variable + operator). Resolved at runtime. */
14
+ compare?: {
15
+ variable: string;
16
+ operator: string;
17
+ };
18
+ }
19
+ /** Parse a JSON string from the LLM into a validated Action. */
20
+ export declare function parseActionResponse(raw: string): Action;
21
+ /**
22
+ * Parse the planning LLM response (line-based format) into a flat list of PlannedSteps.
23
+ * One line per action — compound input steps produce multiple lines.
24
+ */
25
+ export declare function parsePlanResponse(raw: string): PlannedStep[];
26
+ /**
27
+ * Validate that every COMPARE in the plan references a REMEMBER that
28
+ * appears earlier. Returns an array of error messages (empty if valid).
29
+ */
30
+ export declare function validatePlanReferences(plan: PlannedStep[]): string[];
31
+ //# sourceMappingURL=response-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-parser.d.ts","sourceRoot":"","sources":["../../src/pilot/response-parser.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAElD,yFAAyF;AACzF,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,gGAAgG;IAChG,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,6FAA6F;IAC7F,OAAO,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;CAChD;AAED,gEAAgE;AAChE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA+EvD;AAyFD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,EAAE,CAgB5D;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,MAAM,EAAE,CAoBpE"}
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Parsing and validation for LLM responses.
3
+ */
4
+ /** Parse a JSON string from the LLM into a validated Action. */
5
+ export function parseActionResponse(raw) {
6
+ // Strip markdown code fences if the LLM wraps in ```json
7
+ let cleaned = raw.trim();
8
+ if (cleaned.startsWith("```")) {
9
+ cleaned = cleaned.replace(/^```(?:json)?\s*/, "").replace(/\s*```$/, "");
10
+ }
11
+ let parsed;
12
+ try {
13
+ parsed = JSON.parse(cleaned);
14
+ }
15
+ catch {
16
+ throw new Error(`LLM returned invalid JSON: ${raw}`);
17
+ }
18
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
19
+ throw new Error(`LLM returned non-object JSON: ${raw}`);
20
+ }
21
+ const obj = parsed;
22
+ if (typeof obj.action !== "string" || obj.action.length === 0) {
23
+ throw new Error(`LLM response missing "action" field: ${raw}`);
24
+ }
25
+ const VALID_ACTIONS = [
26
+ "click",
27
+ "check",
28
+ "uncheck",
29
+ "type",
30
+ "select",
31
+ "autocomplete",
32
+ "scroll",
33
+ "navigate",
34
+ "press",
35
+ "wait",
36
+ "assert",
37
+ "remember",
38
+ ];
39
+ if (!VALID_ACTIONS.includes(obj.action)) {
40
+ throw new Error(`LLM returned unknown action "${obj.action}". Valid: ${VALID_ACTIONS.join(", ")}`);
41
+ }
42
+ const action = { action: obj.action };
43
+ if (typeof obj.ref === "string") {
44
+ action.ref = obj.ref;
45
+ }
46
+ if (typeof obj.text === "string") {
47
+ action.text = obj.text;
48
+ }
49
+ if (typeof obj.value === "string") {
50
+ action.value = obj.value;
51
+ }
52
+ if (typeof obj.option === "string") {
53
+ action.option = obj.option;
54
+ }
55
+ if (typeof obj.rememberAs === "string") {
56
+ action.rememberAs = obj.rememberAs;
57
+ }
58
+ if (typeof obj.compare === "object" && obj.compare !== null) {
59
+ const c = obj.compare;
60
+ if (typeof c.variable === "string" && typeof c.operator === "string") {
61
+ action.compare = {
62
+ variable: c.variable,
63
+ operator: c.operator,
64
+ };
65
+ }
66
+ }
67
+ if (typeof obj.assertion === "object" && obj.assertion !== null) {
68
+ const a = obj.assertion;
69
+ if (typeof a.type === "string" && typeof a.expected === "string") {
70
+ action.assertion = { type: a.type, expected: a.expected };
71
+ }
72
+ }
73
+ return action;
74
+ }
75
+ /**
76
+ * Parse a single action token from the plan response line format.
77
+ * Returns the action (or null for PAGE) and an optional description.
78
+ */
79
+ function parsePlanAction(token) {
80
+ const t = token.trim();
81
+ // REMEMBER "description" as "variable_name"
82
+ const rememberMatch = /^remember\s+"([^"]+)"\s+as\s+"([^"]+)"$/i.exec(t);
83
+ if (rememberMatch) {
84
+ return {
85
+ action: null,
86
+ description: rememberMatch[1],
87
+ rememberAs: rememberMatch[2],
88
+ };
89
+ }
90
+ // COMPARE "description" "operator" remembered "variable_name"
91
+ // Returns action: null so it goes through resolveStep at runtime
92
+ // (needs the live page to find the element containing the current value).
93
+ // The compare metadata is stored on the PlannedStep for the pilot to use.
94
+ const compareMatch = /^compare\s+"([^"]+)"\s+"([^"]+)"\s+remembered\s+"([^"]+)"$/i.exec(t);
95
+ if (compareMatch) {
96
+ return {
97
+ action: null,
98
+ description: compareMatch[1],
99
+ compare: {
100
+ variable: compareMatch[3],
101
+ operator: compareMatch[2],
102
+ },
103
+ };
104
+ }
105
+ // EXPAND "description" — compound step needing runtime expansion
106
+ if (/^expand(?:\s|$)/i.test(t)) {
107
+ const after = t.slice(6).trim();
108
+ const description = after.replace(/^"(.*)"$/, "$1") || undefined;
109
+ return { action: null, description, needsExpansion: true };
110
+ }
111
+ // PAGE "description", PAGE description, or bare PAGE
112
+ if (/^page(?:\s|$)/i.test(t)) {
113
+ const after = t.slice(4).trim();
114
+ // Strip surrounding quotes if present
115
+ const description = after.replace(/^"(.*)"$/, "$1") || undefined;
116
+ return { action: null, description };
117
+ }
118
+ // assert <type> "<expected>"
119
+ const assertMatch = /^assert\s+(\S+)\s+"([^"]*)"$/i.exec(t);
120
+ if (assertMatch) {
121
+ return {
122
+ action: {
123
+ action: "assert",
124
+ assertion: { type: assertMatch[1], expected: assertMatch[2] },
125
+ },
126
+ };
127
+ }
128
+ // navigate "<url>"
129
+ const navMatch = /^navigate\s+"([^"]*)"$/i.exec(t);
130
+ if (navMatch) {
131
+ return { action: { action: "navigate", value: navMatch[1] } };
132
+ }
133
+ // press "<key>"
134
+ const pressMatch = /^press\s+"([^"]*)"$/i.exec(t);
135
+ if (pressMatch) {
136
+ return { action: { action: "press", value: pressMatch[1] } };
137
+ }
138
+ // scroll "<direction>"
139
+ const scrollMatch = /^scroll\s+"([^"]*)"$/i.exec(t);
140
+ if (scrollMatch) {
141
+ return { action: { action: "scroll", value: scrollMatch[1].toLowerCase() } };
142
+ }
143
+ // Unknown token — treat as page-dependent
144
+ return { action: null };
145
+ }
146
+ /**
147
+ * Parse the planning LLM response (line-based format) into a flat list of PlannedSteps.
148
+ * One line per action — compound input steps produce multiple lines.
149
+ */
150
+ export function parsePlanResponse(raw) {
151
+ return raw
152
+ .trim()
153
+ .split("\n")
154
+ .filter((l) => l.trim().length > 0)
155
+ .map((line) => {
156
+ const { action, description, needsExpansion, rememberAs, compare } = parsePlanAction(line);
157
+ const step = description ?? line.trim();
158
+ return {
159
+ step,
160
+ action,
161
+ ...(needsExpansion ? { needsExpansion: true } : {}),
162
+ ...(rememberAs ? { rememberAs } : {}),
163
+ ...(compare ? { compare } : {}),
164
+ };
165
+ });
166
+ }
167
+ /**
168
+ * Validate that every COMPARE in the plan references a REMEMBER that
169
+ * appears earlier. Returns an array of error messages (empty if valid).
170
+ */
171
+ export function validatePlanReferences(plan) {
172
+ const errors = [];
173
+ const remembered = new Set();
174
+ for (const step of plan) {
175
+ if (step.rememberAs) {
176
+ remembered.add(step.rememberAs);
177
+ }
178
+ const compare = step.compare ?? step.action?.compare;
179
+ if (compare) {
180
+ const varName = compare.variable;
181
+ if (!remembered.has(varName)) {
182
+ errors.push(`COMPARE references "${varName}" but no REMEMBER "${varName}" appears before it`);
183
+ }
184
+ }
185
+ }
186
+ return errors;
187
+ }
188
+ //# sourceMappingURL=response-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-parser.js","sourceRoot":"","sources":["../../src/pilot/response-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Page state capture: accessibility tree snapshots, screenshots, and console logs.
3
+ *
4
+ * Sub-modules:
5
+ * - ./network.ts — network idle tracking, console collector
6
+ * - ./a11y-parser.ts — a11y snapshot parsing with stable refs
7
+ * - ./form-fields.ts — form field capture and formatting
8
+ */
9
+ import type { Page } from "playwright";
10
+ import type { ConsoleEntry, PageState } from "../reporter/types.js";
11
+ /**
12
+ * Capture the page state: a11y tree, URL, title, console logs.
13
+ * Screenshots are optional — skip them on pre-action captures to avoid
14
+ * triggering lazy-loaded elements (e.g. IntersectionObserver-based maps).
15
+ */
16
+ export declare function capturePageState(page: Page, consoleDrain: () => ConsoleEntry[], options?: {
17
+ screenshot?: boolean;
18
+ }): Promise<PageState>;
19
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/pilot/state.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAKnE;;;;GAIG;AACH,wBAAsB,gBAAgB,CACrC,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,MAAM,YAAY,EAAE,EAClC,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,GAChC,OAAO,CAAC,SAAS,CAAC,CAoDpB"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Page state capture: accessibility tree snapshots, screenshots, and console logs.
3
+ *
4
+ * Sub-modules:
5
+ * - ./network.ts — network idle tracking, console collector
6
+ * - ./a11y-parser.ts — a11y snapshot parsing with stable refs
7
+ * - ./form-fields.ts — form field capture and formatting
8
+ */
9
+ import { parseA11ySnapshot } from "./a11y-parser.js";
10
+ // ── Orchestrator ──────────────────────────────────────────────────────
11
+ /**
12
+ * Capture the page state: a11y tree, URL, title, console logs.
13
+ * Screenshots are optional — skip them on pre-action captures to avoid
14
+ * triggering lazy-loaded elements (e.g. IntersectionObserver-based maps).
15
+ */
16
+ export async function capturePageState(page, consoleDrain, options) {
17
+ const takeScreenshot = options?.screenshot ?? false;
18
+ const [a11yRaw, screenshotBuffer, url, title] = await Promise.all([
19
+ page.locator("body").ariaSnapshot(),
20
+ takeScreenshot ? page.screenshot({ type: "png" }) : Promise.resolve(null),
21
+ Promise.resolve(page.url()),
22
+ page.title(),
23
+ ]);
24
+ const a11yTree = parseA11ySnapshot(a11yRaw);
25
+ // Capture all text content on the page. This supplements the a11y tree
26
+ // which can miss content rendered with non-semantic markup.
27
+ // We use textContent (not innerText) because innerText skips elements
28
+ // hidden by CSS transitions/animations that are still interactive.
29
+ // Script and style content is excluded.
30
+ let visibleText;
31
+ try {
32
+ const raw = await page.evaluate(() => {
33
+ function walk(node) {
34
+ if (node.nodeType === 3)
35
+ return node.textContent ?? ""; // TEXT_NODE
36
+ if (node.nodeType !== 1)
37
+ return ""; // Only process ELEMENT_NODE
38
+ const el = node;
39
+ const tag = el.tagName;
40
+ if (tag === "SCRIPT" || tag === "STYLE" || tag === "NOSCRIPT")
41
+ return "";
42
+ const parts = [];
43
+ for (const child of el.childNodes) {
44
+ parts.push(walk(child));
45
+ }
46
+ return parts.join("");
47
+ }
48
+ return walk(document.body);
49
+ });
50
+ // Collapse whitespace runs into single spaces, trim blank lines
51
+ visibleText =
52
+ raw
53
+ .split("\n")
54
+ .map((l) => l.replace(/\s+/g, " ").trim())
55
+ .filter((l) => l.length > 0)
56
+ .join("\n") || undefined;
57
+ }
58
+ catch {
59
+ // Skip if page is mid-navigation
60
+ }
61
+ const screenshot = screenshotBuffer
62
+ ? screenshotBuffer.toString("base64")
63
+ : undefined;
64
+ const consoleLogs = consoleDrain();
65
+ return { a11yTree, a11yRaw, visibleText, screenshot, url, title, consoleLogs };
66
+ }
67
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/pilot/state.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAEpD,yEAAyE;AAEzE;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACrC,IAAU,EACV,YAAkC,EAClC,OAAkC;IAElC,MAAM,cAAc,GAAG,OAAO,EAAE,UAAU,IAAI,KAAK,CAAA;IAEnD,MAAM,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACjE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,YAAY,EAAE;QACnC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;QACzE,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QAC3B,IAAI,CAAC,KAAK,EAAE;KACZ,CAAC,CAAA;IAEF,MAAM,QAAQ,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAA;IAE3C,uEAAuE;IACvE,4DAA4D;IAC5D,sEAAsE;IACtE,mEAAmE;IACnE,wCAAwC;IACxC,IAAI,WAA+B,CAAA;IACnC,IAAI,CAAC;QACJ,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE;YACpC,SAAS,IAAI,CAAC,IAAU;gBACvB,IAAI,IAAI,CAAC,QAAQ,KAAK,CAAC;oBAAE,OAAO,IAAI,CAAC,WAAW,IAAI,EAAE,CAAA,CAAC,YAAY;gBACnE,IAAI,IAAI,CAAC,QAAQ,KAAK,CAAC;oBAAE,OAAO,EAAE,CAAA,CAAC,4BAA4B;gBAC/D,MAAM,EAAE,GAAG,IAAe,CAAA;gBAC1B,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAA;gBACtB,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,UAAU;oBAC5D,OAAO,EAAE,CAAA;gBACV,MAAM,KAAK,GAAa,EAAE,CAAA;gBAC1B,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,UAAU,EAAE,CAAC;oBACnC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;gBACxB,CAAC;gBACD,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YACtB,CAAC;YACD,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;QAC3B,CAAC,CAAC,CAAA;QACF,gEAAgE;QAChE,WAAW;YACV,GAAG;iBACD,KAAK,CAAC,IAAI,CAAC;iBACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;iBACzC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;iBAC3B,IAAI,CAAC,IAAI,CAAC,IAAI,SAAS,CAAA;IAC3B,CAAC;IAAC,MAAM,CAAC;QACR,iCAAiC;IAClC,CAAC;IAED,MAAM,UAAU,GAAG,gBAAgB;QAClC,CAAC,CAAC,gBAAgB,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACrC,CAAC,CAAC,SAAS,CAAA;IACZ,MAAM,WAAW,GAAG,YAAY,EAAE,CAAA;IAElC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,CAAA;AAC/E,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Trace logger — logs timestamped browser and pilot events for performance analysis.
3
+ * Enabled with --trace. Attaches to Playwright page events and provides
4
+ * a log() function for manual instrumentation.
5
+ */
6
+ import type { Page } from "playwright";
7
+ export interface TraceLogger {
8
+ log(event: string, detail?: string): void;
9
+ attachToPage(page: Page): void;
10
+ detachFromPage(page: Page): void;
11
+ }
12
+ /**
13
+ * Create a trace logger. If enabled is false, returns a no-op logger.
14
+ */
15
+ export declare function createTraceLogger(enabled: boolean): TraceLogger;
16
+ //# sourceMappingURL=trace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../../src/pilot/trace.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAEtC,MAAM,WAAW,WAAW;IAC3B,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzC,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;IAC9B,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;CAChC;AAKD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,WAAW,CA8H/D"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Trace logger — logs timestamped browser and pilot events for performance analysis.
3
+ * Enabled with --trace. Attaches to Playwright page events and provides
4
+ * a log() function for manual instrumentation.
5
+ */
6
+ const GREY = "\x1b[90m";
7
+ const RESET = "\x1b[0m";
8
+ /**
9
+ * Create a trace logger. If enabled is false, returns a no-op logger.
10
+ */
11
+ export function createTraceLogger(enabled) {
12
+ if (!enabled) {
13
+ return {
14
+ log() {
15
+ // no-op
16
+ },
17
+ attachToPage() {
18
+ // no-op
19
+ },
20
+ detachFromPage() {
21
+ // no-op
22
+ },
23
+ };
24
+ }
25
+ const startTime = performance.now();
26
+ function ts() {
27
+ return String(Math.round(performance.now() - startTime)).padStart(7, " ");
28
+ }
29
+ function log(event, detail) {
30
+ const d = detail ? ` ${detail}` : "";
31
+ console.log(`${GREY}[${ts()}ms] ${event}${d}${RESET}`);
32
+ }
33
+ /** URL patterns for media/third-party resources to exclude from trace. */
34
+ const NOISE_PATTERNS = [
35
+ /\.pmtiles/,
36
+ /\.pbf$/,
37
+ /\.png$/,
38
+ /\.jpg$/,
39
+ /\.jpeg$/,
40
+ /\.gif$/,
41
+ /\.svg$/,
42
+ /\.webp$/,
43
+ /\.woff2?$/,
44
+ /\.ttf$/,
45
+ /\.mp4$/,
46
+ /\.webm$/,
47
+ /googlesyndication\.com/,
48
+ /googletagmanager\.com/,
49
+ /google-analytics\.com/,
50
+ /cookiebot\.com/,
51
+ /protomaps\.github\.io/,
52
+ ];
53
+ function isNoise(url) {
54
+ return NOISE_PATTERNS.some((p) => p.test(url));
55
+ }
56
+ // Store bound handlers so we can remove them
57
+ const handlers = new WeakMap();
58
+ function attachToPage(page) {
59
+ const h = {
60
+ framenavigated: (frame) => {
61
+ const f = frame;
62
+ if (!f.parentFrame()) {
63
+ log("navigation", f.url());
64
+ }
65
+ },
66
+ load: () => {
67
+ log("page:load");
68
+ },
69
+ domcontentloaded: () => {
70
+ log("page:domcontentloaded");
71
+ },
72
+ request: (req) => {
73
+ const r = req;
74
+ const type = r.resourceType();
75
+ if ((type === "document" || type === "xhr" || type === "fetch") &&
76
+ !isNoise(r.url())) {
77
+ log(`request:${type}`, r.url());
78
+ }
79
+ },
80
+ response: (res) => {
81
+ const r = res;
82
+ const type = r.request().resourceType();
83
+ if ((type === "document" || type === "xhr" || type === "fetch") &&
84
+ !isNoise(r.url())) {
85
+ log(`response:${type}`, `${String(r.status())} ${r.url()}`);
86
+ }
87
+ },
88
+ console: (msg) => {
89
+ const m = msg;
90
+ if (m.type() === "error") {
91
+ log("console:error", m.text());
92
+ }
93
+ },
94
+ };
95
+ handlers.set(page, h);
96
+ page.on("framenavigated", h.framenavigated);
97
+ page.on("load", h.load);
98
+ page.on("domcontentloaded", h.domcontentloaded);
99
+ page.on("request", h.request);
100
+ page.on("response", h.response);
101
+ page.on("console", h.console);
102
+ }
103
+ function detachFromPage(page) {
104
+ const h = handlers.get(page);
105
+ if (!h)
106
+ return;
107
+ page.off("framenavigated", h.framenavigated);
108
+ page.off("load", h.load);
109
+ page.off("domcontentloaded", h.domcontentloaded);
110
+ page.off("request", h.request);
111
+ page.off("response", h.response);
112
+ page.off("console", h.console);
113
+ handlers.delete(page);
114
+ }
115
+ return { log, attachToPage, detachFromPage };
116
+ }
117
+ //# sourceMappingURL=trace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace.js","sourceRoot":"","sources":["../../src/pilot/trace.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Hashing and slug utilities for cached test plans.
3
+ */
4
+ /**
5
+ * Compute a SHA-256 hash of a test case's effective definition.
6
+ * The input should be the fully resolved test case (after variable
7
+ * interpolation and reusable step expansion).
8
+ */
9
+ export declare function computeTestHash(testCase: {
10
+ steps: string[];
11
+ }): string;
12
+ /** Convert a name to a URL/filesystem-safe kebab-case slug. */
13
+ export declare function slugify(name: string): string;
14
+ //# sourceMappingURL=hasher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hasher.d.ts","sourceRoot":"","sources":["../../src/planner/hasher.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE;IAAE,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,MAAM,CAGrE;AAED,+DAA+D;AAC/D,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK5C"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Hashing and slug utilities for cached test plans.
3
+ */
4
+ import { createHash } from "node:crypto";
5
+ /**
6
+ * Compute a SHA-256 hash of a test case's effective definition.
7
+ * The input should be the fully resolved test case (after variable
8
+ * interpolation and reusable step expansion).
9
+ */
10
+ export function computeTestHash(testCase) {
11
+ const content = JSON.stringify(testCase.steps);
12
+ return createHash("sha256").update(content).digest("hex");
13
+ }
14
+ /** Convert a name to a URL/filesystem-safe kebab-case slug. */
15
+ export function slugify(name) {
16
+ return name
17
+ .toLowerCase()
18
+ .replace(/[^a-z0-9]+/g, "-")
19
+ .replace(/^-|-$/g, "");
20
+ }
21
+ //# sourceMappingURL=hasher.js.map