imprint-mcp 0.2.1 → 0.3.1

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 (130) hide show
  1. package/README.md +193 -189
  2. package/examples/discoverandgo/README.md +1 -1
  3. package/examples/echo/README.md +1 -1
  4. package/examples/google-flights/README.md +28 -0
  5. package/examples/google-flights/_shared/batchexecute.ts +63 -0
  6. package/examples/google-flights/_shared/flights_request.ts +95 -0
  7. package/examples/google-flights/_shared/package.json +9 -0
  8. package/examples/google-flights/get_flight_booking_details/index.ts +159 -0
  9. package/examples/google-flights/get_flight_booking_details/package.json +9 -0
  10. package/examples/google-flights/get_flight_booking_details/parser.ts +182 -0
  11. package/examples/google-flights/get_flight_booking_details/playbook.yaml +138 -0
  12. package/examples/google-flights/get_flight_booking_details/request-transform.ts +86 -0
  13. package/examples/google-flights/get_flight_booking_details/workflow.json +98 -0
  14. package/examples/google-flights/get_flight_calendar_prices/index.ts +131 -0
  15. package/examples/google-flights/get_flight_calendar_prices/package.json +9 -0
  16. package/examples/google-flights/get_flight_calendar_prices/parser.ts +86 -0
  17. package/examples/google-flights/get_flight_calendar_prices/playbook.yaml +97 -0
  18. package/examples/google-flights/get_flight_calendar_prices/request-transform.ts +31 -0
  19. package/examples/google-flights/get_flight_calendar_prices/workflow.json +78 -0
  20. package/examples/google-flights/lookup_airport/index.ts +101 -0
  21. package/examples/google-flights/lookup_airport/package.json +9 -0
  22. package/examples/google-flights/lookup_airport/parser.ts +66 -0
  23. package/examples/google-flights/lookup_airport/playbook.yaml +47 -0
  24. package/examples/google-flights/lookup_airport/request-transform.ts +20 -0
  25. package/examples/google-flights/lookup_airport/workflow.json +57 -0
  26. package/examples/google-flights/search_flights/index.ts +219 -0
  27. package/examples/google-flights/search_flights/package.json +9 -0
  28. package/examples/google-flights/search_flights/parser.ts +169 -0
  29. package/examples/google-flights/search_flights/playbook.yaml +184 -0
  30. package/examples/google-flights/search_flights/request-transform.ts +119 -0
  31. package/examples/google-flights/search_flights/workflow.json +143 -0
  32. package/examples/google-hotels/README.md +29 -0
  33. package/examples/google-hotels/_shared/batchexecute.ts +73 -0
  34. package/examples/google-hotels/_shared/freq.ts +158 -0
  35. package/examples/google-hotels/_shared/package.json +9 -0
  36. package/examples/google-hotels/autocomplete_hotel_location/index.ts +80 -0
  37. package/examples/google-hotels/autocomplete_hotel_location/package.json +9 -0
  38. package/examples/google-hotels/autocomplete_hotel_location/parser.ts +71 -0
  39. package/examples/google-hotels/autocomplete_hotel_location/playbook.yaml +36 -0
  40. package/examples/google-hotels/autocomplete_hotel_location/request-transform.ts +37 -0
  41. package/examples/google-hotels/autocomplete_hotel_location/workflow.json +36 -0
  42. package/examples/google-hotels/get_hotel_booking_options/index.ts +143 -0
  43. package/examples/google-hotels/get_hotel_booking_options/package.json +9 -0
  44. package/examples/google-hotels/get_hotel_booking_options/parser.ts +271 -0
  45. package/examples/google-hotels/get_hotel_booking_options/playbook.yaml +154 -0
  46. package/examples/google-hotels/get_hotel_booking_options/request-transform.ts +154 -0
  47. package/examples/google-hotels/get_hotel_booking_options/workflow.json +84 -0
  48. package/examples/google-hotels/get_hotel_reviews/index.ts +81 -0
  49. package/examples/google-hotels/get_hotel_reviews/package.json +9 -0
  50. package/examples/google-hotels/get_hotel_reviews/parser.ts +128 -0
  51. package/examples/google-hotels/get_hotel_reviews/playbook.yaml +64 -0
  52. package/examples/google-hotels/get_hotel_reviews/request-transform.ts +42 -0
  53. package/examples/google-hotels/get_hotel_reviews/workflow.json +37 -0
  54. package/examples/google-hotels/search_hotels/index.ts +207 -0
  55. package/examples/google-hotels/search_hotels/package.json +9 -0
  56. package/examples/google-hotels/search_hotels/parser.ts +260 -0
  57. package/examples/google-hotels/search_hotels/playbook.yaml +87 -0
  58. package/examples/google-hotels/search_hotels/request-transform.ts +197 -0
  59. package/examples/google-hotels/search_hotels/workflow.json +127 -0
  60. package/examples/southwest/README.md +3 -2
  61. package/examples/southwest/search_southwest_flights/index.ts +18 -1
  62. package/examples/southwest/search_southwest_flights/workflow.json +18 -1
  63. package/package.json +3 -2
  64. package/prompts/audit-agent.md +71 -0
  65. package/prompts/build-planning.md +74 -0
  66. package/prompts/compile-agent.md +131 -27
  67. package/prompts/prereq-builder.md +64 -0
  68. package/prompts/prereq-planner.md +34 -0
  69. package/prompts/tool-planning.md +39 -0
  70. package/src/cli.ts +116 -3
  71. package/src/imprint/agent.ts +5 -0
  72. package/src/imprint/audit.ts +996 -0
  73. package/src/imprint/backend-ladder.ts +1214 -184
  74. package/src/imprint/build-plan.ts +1051 -0
  75. package/src/imprint/cdp-browser-fetch.ts +592 -0
  76. package/src/imprint/cdp-jar-cache.ts +320 -0
  77. package/src/imprint/chromium.ts +414 -8
  78. package/src/imprint/claude-cli-compile.ts +125 -25
  79. package/src/imprint/codex-cli-compile.ts +26 -23
  80. package/src/imprint/compile-agent-types.ts +38 -0
  81. package/src/imprint/compile-agent.ts +63 -25
  82. package/src/imprint/compile-tools.ts +1666 -66
  83. package/src/imprint/compile.ts +13 -1
  84. package/src/imprint/concurrency.ts +87 -0
  85. package/src/imprint/cron.ts +4 -0
  86. package/src/imprint/doctor.ts +48 -3
  87. package/src/imprint/freeform-redact.ts +5 -4
  88. package/src/imprint/install.ts +79 -4
  89. package/src/imprint/integrations.ts +3 -3
  90. package/src/imprint/llm.ts +56 -8
  91. package/src/imprint/mcp-compile-server.ts +43 -10
  92. package/src/imprint/mcp-maintenance.ts +18 -102
  93. package/src/imprint/mcp-server.ts +73 -7
  94. package/src/imprint/multi-progress.ts +7 -2
  95. package/src/imprint/param-grounding.ts +367 -0
  96. package/src/imprint/paths.ts +29 -0
  97. package/src/imprint/playbook-runner.ts +101 -40
  98. package/src/imprint/prereq-builder.ts +651 -0
  99. package/src/imprint/probe-backends.ts +6 -3
  100. package/src/imprint/record.ts +10 -1
  101. package/src/imprint/redact.ts +30 -2
  102. package/src/imprint/replay-capture.ts +19 -18
  103. package/src/imprint/runtime.ts +19 -10
  104. package/src/imprint/session-diff.ts +79 -2
  105. package/src/imprint/session-merge.ts +9 -5
  106. package/src/imprint/stealth-chromium.ts +79 -0
  107. package/src/imprint/stealth-fetch.ts +309 -29
  108. package/src/imprint/stealth-token-cache.ts +88 -0
  109. package/src/imprint/teach-plan.ts +251 -0
  110. package/src/imprint/teach-state.ts +10 -0
  111. package/src/imprint/teach.ts +456 -142
  112. package/src/imprint/tool-candidates.ts +72 -14
  113. package/src/imprint/tool-plan.ts +313 -0
  114. package/src/imprint/tracing.ts +135 -6
  115. package/src/imprint/types.ts +61 -3
  116. package/examples/google-flights/search_google_flights/index.ts +0 -101
  117. package/examples/google-flights/search_google_flights/parser.test.ts +0 -140
  118. package/examples/google-flights/search_google_flights/parser.ts +0 -189
  119. package/examples/google-flights/search_google_flights/playbook.yaml +0 -130
  120. package/examples/google-flights/search_google_flights/workflow.json +0 -48
  121. package/examples/google-hotels/search_google_hotels/index.ts +0 -194
  122. package/examples/google-hotels/search_google_hotels/parser.test.ts +0 -168
  123. package/examples/google-hotels/search_google_hotels/parser.ts +0 -330
  124. package/examples/google-hotels/search_google_hotels/playbook.yaml +0 -125
  125. package/examples/google-hotels/search_google_hotels/workflow.json +0 -111
  126. package/examples/namecheap-domains/search_namecheap_domains/index.ts +0 -144
  127. package/examples/namecheap-domains/search_namecheap_domains/parser.ts +0 -380
  128. package/examples/namecheap-domains/search_namecheap_domains/playbook.yaml +0 -50
  129. package/examples/namecheap-domains/search_namecheap_domains/request-transform.ts +0 -136
  130. package/examples/namecheap-domains/search_namecheap_domains/workflow.json +0 -97
@@ -0,0 +1,98 @@
1
+ {
2
+ "toolName": "get_flight_booking_details",
3
+ "site": "google-flights",
4
+ "intent": {
5
+ "description": "Get booking/fare details and bookable options for a specific selected flight itinerary on Google Flights.",
6
+ "userSaid": "clicked one of the one-way fares to find more details and booking details; saw the options for another flight; chose round trip fares; kept exploring round trip fare details"
7
+ },
8
+ "parameters": [
9
+ {
10
+ "name": "origin",
11
+ "type": "string",
12
+ "description": "Origin airport IATA code for the outbound leg, e.g. SJC",
13
+ "verified": false,
14
+ "verifyNote": "annotated"
15
+ },
16
+ {
17
+ "name": "destination",
18
+ "type": "string",
19
+ "description": "Destination airport IATA code for the outbound leg, e.g. SAN",
20
+ "verified": false,
21
+ "verifyNote": "annotated"
22
+ },
23
+ {
24
+ "name": "departure_date",
25
+ "type": "string",
26
+ "description": "Outbound date in YYYY-MM-DD",
27
+ "verified": false,
28
+ "verifyNote": "annotated"
29
+ },
30
+ {
31
+ "name": "return_date",
32
+ "type": "string",
33
+ "description": "Return date in YYYY-MM-DD. Empty/omit for a one-way booking.",
34
+ "default": "",
35
+ "verified": true
36
+ },
37
+ {
38
+ "name": "outbound_flight",
39
+ "type": "string",
40
+ "description": "Selected outbound flight as 'carrier number', e.g. 'WN 3489'",
41
+ "verified": false,
42
+ "verifyNote": "annotated"
43
+ },
44
+ {
45
+ "name": "return_flight",
46
+ "type": "string",
47
+ "description": "Selected return flight as 'carrier number' (round trip only), e.g. 'WN 3540'. Empty for one-way.",
48
+ "default": "",
49
+ "verified": false,
50
+ "verifyNote": "annotated"
51
+ },
52
+ {
53
+ "name": "flight_token",
54
+ "type": "string",
55
+ "description": "Opaque per-itinerary booking token minted by the search_flights tool's flight_token output for the selected itinerary."
56
+ }
57
+ ],
58
+ "bootstrap": {
59
+ "url": "https://www.google.com/travel/flights",
60
+ "waitUntil": "domcontentloaded",
61
+ "timeoutMs": 30000,
62
+ "captures": [
63
+ {
64
+ "source": "html_regex",
65
+ "name": "f_sid",
66
+ "pattern": "\"FdrFJe\":\"([^\"]+)\"",
67
+ "group": 1,
68
+ "required": false,
69
+ "capability": "browser_bootstrap"
70
+ },
71
+ {
72
+ "source": "html_regex",
73
+ "name": "bl",
74
+ "pattern": "\"cfb2h\":\"([^\"]+)\"",
75
+ "group": 1,
76
+ "required": false,
77
+ "capability": "browser_bootstrap"
78
+ }
79
+ ]
80
+ },
81
+ "requests": [
82
+ {
83
+ "method": "POST",
84
+ "url": "https://www.google.com/_/FlightsFrontendUi/data/travel.frontend.flights.FlightsFrontendService/GetBookingResults?f.sid=${state.f_sid}&bl=${state.bl}&hl=en-US&soc-app=162&soc-platform=1&soc-device=1&_reqid=1659189&rt=c",
85
+ "headers": {
86
+ "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
87
+ "X-Same-Domain": "1",
88
+ "Referer": "https://www.google.com/travel/flights",
89
+ "x-goog-ext-259736195-jspb": "[\"en-US\",\"US\",\"USD\",2,null,[420],null,null,7,[]]"
90
+ },
91
+ "body": "f.req=${param.origin}|${param.destination}|${param.departure_date}|${param.return_date}|${param.outbound_flight}|${param.return_flight}|${param.flight_token}&",
92
+ "effect": "safe"
93
+ }
94
+ ],
95
+ "requestTransformModule": "./request-transform.ts",
96
+ "parserModule": "./parser.ts",
97
+ "liveVerified": true
98
+ }
@@ -0,0 +1,131 @@
1
+ /**
2
+ * GENERATED by `imprint emit` — DO NOT EDIT BY HAND.
3
+ *
4
+ * Tool: get_flight_calendar_prices
5
+ * Site: google-flights
6
+ * Intent: Get a calendar grid of lowest round-trip prices by departure date for a route over a date window.
7
+ *
8
+ * To regenerate: imprint emit ~/.imprint/google-flights/get_flight_calendar_prices/workflow.json --force
9
+ */
10
+
11
+ import { fileURLToPath } from 'node:url';
12
+ import { dirname, join } from 'node:path';
13
+ import {
14
+ executeWorkflow,
15
+ type CredentialStore,
16
+ } from 'imprint/runtime';
17
+ import type { ToolResult, Workflow } from 'imprint/types';
18
+
19
+ const WORKFLOW: Workflow = {
20
+ "toolName": "get_flight_calendar_prices",
21
+ "intent": {
22
+ "description": "Get a calendar grid of lowest round-trip prices by departure date for a route over a date window.",
23
+ "userSaid": "searched for a round trip flight; SJC to SAN"
24
+ },
25
+ "parameters": [
26
+ {
27
+ "name": "origin",
28
+ "type": "string",
29
+ "description": "Origin airport IATA code, e.g. SJC",
30
+ "verified": false,
31
+ "verifyNote": "annotated"
32
+ },
33
+ {
34
+ "name": "destination",
35
+ "type": "string",
36
+ "description": "Destination airport IATA code, e.g. SAN",
37
+ "verified": false,
38
+ "verifyNote": "annotated"
39
+ },
40
+ {
41
+ "name": "start_date",
42
+ "type": "string",
43
+ "description": "Start of departure-date window, YYYY-MM-DD",
44
+ "verified": false,
45
+ "verifyNote": "annotated"
46
+ },
47
+ {
48
+ "name": "end_date",
49
+ "type": "string",
50
+ "description": "End of departure-date window, YYYY-MM-DD",
51
+ "verified": false,
52
+ "verifyNote": "annotated"
53
+ }
54
+ ],
55
+ "requests": [
56
+ {
57
+ "method": "POST",
58
+ "url": "https://www.google.com/_/FlightsFrontendUi/data/travel.frontend.flights.FlightsFrontendService/GetCalendarPicker?f.sid=${state.f_sid}&bl=${state.bl}&hl=en-US&soc-app=162&soc-platform=1&soc-device=1&_reqid=1508023&rt=c",
59
+ "headers": {
60
+ "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
61
+ "X-Same-Domain": "1",
62
+ "x-goog-ext-259736195-jspb": "[\"en-US\",\"US\",\"USD\",2,null,[420],null,null,7,[]]",
63
+ "Referer": "https://www.google.com/travel/flights",
64
+ "Accept-Language": "en-US,en;q=0.9"
65
+ },
66
+ "body": "f.req=%5Bnull%2C%22%5Bnull%2C%5Bnull%2Cnull%2C1%2Cnull%2C%5B%5D%2C1%2C%5B1%2C0%2C0%2C0%5D%2Cnull%2Cnull%2Cnull%2Cnull%2Cnull%2Cnull%2C%5B%5B%5B%5B%5B%5C%22${param.origin}%5C%22%2C0%5D%5D%5D%2C%5B%5B%5B%5C%22${param.destination}%5C%22%2C0%5D%5D%5D%2Cnull%2C0%5D%2C%5B%5B%5B%5B%5C%22${param.destination}%5C%22%2C0%5D%5D%5D%2C%5B%5B%5B%5C%22${param.origin}%5C%22%2C0%5D%5D%5D%2Cnull%2C0%5D%5D%2Cnull%2Cnull%2Cnull%2C1%5D%2C%5B%5C%22${param.start_date}%5C%22%2C%5C%22${param.end_date}%5C%22%5D%2Cnull%2C%5B7%2C7%5D%5D%22%5D&",
67
+ "effect": "safe"
68
+ }
69
+ ],
70
+ "site": "google-flights",
71
+ "bootstrap": {
72
+ "url": "https://www.google.com/travel/flights?hl=en-US&curr=USD",
73
+ "waitUntil": "domcontentloaded",
74
+ "captures": [
75
+ {
76
+ "name": "f_sid",
77
+ "required": false,
78
+ "capability": "browser_bootstrap",
79
+ "source": "html_regex",
80
+ "pattern": "\"FdrFJe\":\"([^\"]+)\"",
81
+ "group": 1
82
+ },
83
+ {
84
+ "name": "bl",
85
+ "required": false,
86
+ "capability": "browser_bootstrap",
87
+ "source": "html_regex",
88
+ "pattern": "\"cfb2h\":\"([^\"]+)\"",
89
+ "group": 1
90
+ }
91
+ ]
92
+ },
93
+ "parserModule": "./parser.ts",
94
+ "requestTransformModule": "./request-transform.ts",
95
+ "liveVerified": true
96
+ };
97
+
98
+ export interface GetFlightCalendarPricesInput {
99
+ /** Origin airport IATA code, e.g. SJC */
100
+ origin: string;
101
+ /** Destination airport IATA code, e.g. SAN */
102
+ destination: string;
103
+ /** Start of departure-date window, YYYY-MM-DD */
104
+ start_date: string;
105
+ /** End of departure-date window, YYYY-MM-DD */
106
+ end_date: string;
107
+ }
108
+
109
+ export async function getFlightCalendarPrices(
110
+ input: GetFlightCalendarPricesInput,
111
+ opts: { credentials?: CredentialStore; fetchImpl?: typeof fetch; initialState?: Record<string, unknown> } = {},
112
+ ): Promise<ToolResult> {
113
+ const __dirname = dirname(fileURLToPath(import.meta.url));
114
+ const params: Record<string, string | number | boolean> = {
115
+ origin: input.origin,
116
+ destination: input.destination,
117
+ start_date: input.start_date,
118
+ end_date: input.end_date,
119
+
120
+ };
121
+ return executeWorkflow({
122
+ workflow: WORKFLOW,
123
+ params,
124
+ credentials: opts.credentials,
125
+ fetchImpl: opts.fetchImpl,
126
+ initialState: opts.initialState,
127
+ workflowPath: join(__dirname, 'workflow.json'),
128
+ });
129
+ }
130
+
131
+ export { WORKFLOW };
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "imprint-tool-google-flights",
3
+ "private": true,
4
+ "devDependencies": {
5
+ "@types/bun": "latest",
6
+ "@types/node": "latest",
7
+ "bun-types": "latest"
8
+ }
9
+ }
@@ -0,0 +1,86 @@
1
+ // Parse a Google Flights GetCalendarPicker batchexecute response into a
2
+ // date->price calendar for the route. Decoding of the )]}' envelope is delegated
3
+ // to the shared batchexecute helper (imported per the build plan).
4
+ import { decodeBatchExecute } from '../_shared/batchexecute.ts';
5
+
6
+ type CalendarEntry = {
7
+ departureDate: string;
8
+ returnDate: string | null;
9
+ lowestPriceUSD: number;
10
+ };
11
+
12
+ const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
13
+
14
+ // The GetCalendarPicker wrb.fr payload is shaped:
15
+ // [ <metadata>, [ [depDate, retDate, [[null, price], token], 1], ... ] ]
16
+ // The metadata entry is skipped naturally because we only keep array items whose
17
+ // [0] is an ISO date string. We scan every nested array so we are robust to the
18
+ // list living at payload[1] (the recorded shape) or being flattened.
19
+ function collectEntries(payload: unknown): CalendarEntry[] {
20
+ const entries: CalendarEntry[] = [];
21
+ const seen = new Set<string>();
22
+ if (!Array.isArray(payload)) return entries;
23
+
24
+ const consider = (item: unknown) => {
25
+ if (!Array.isArray(item)) return;
26
+ const dep = item[0];
27
+ if (typeof dep !== 'string' || !ISO_DATE.test(dep)) return;
28
+ const ret = typeof item[1] === 'string' && ISO_DATE.test(item[1]) ? (item[1] as string) : null;
29
+ // price lives at item[2][0][1]
30
+ const priceContainer = item[2];
31
+ let price: unknown = null;
32
+ if (Array.isArray(priceContainer) && Array.isArray(priceContainer[0])) {
33
+ price = (priceContainer[0] as unknown[])[1];
34
+ }
35
+ if (typeof price !== 'number') return; // no fare found for that date -> omit
36
+ if (seen.has(dep)) return;
37
+ seen.add(dep);
38
+ entries.push({ departureDate: dep, returnDate: ret, lowestPriceUSD: price });
39
+ };
40
+
41
+ for (const top of payload) {
42
+ if (Array.isArray(top)) {
43
+ // top may itself be the list of date entries, or a single entry.
44
+ consider(top);
45
+ for (const inner of top) consider(inner);
46
+ }
47
+ }
48
+ return entries;
49
+ }
50
+
51
+ export function extract(
52
+ rawResponse: unknown,
53
+ context?: { params?: Record<string, string | number | boolean>; responses?: unknown[] },
54
+ ): unknown {
55
+ const raw = typeof rawResponse === 'string' ? rawResponse : JSON.stringify(rawResponse ?? '');
56
+ const frames = decodeBatchExecute(raw);
57
+
58
+ let payload: unknown = null;
59
+ for (const f of frames) {
60
+ const candidate = collectEntries(f.payload);
61
+ if (candidate.length > 0) {
62
+ payload = f.payload;
63
+ break;
64
+ }
65
+ }
66
+ // If no frame produced entries, still attempt the first frame's payload so an
67
+ // empty (zero-result) response yields an empty calendar rather than throwing.
68
+ if (payload == null && frames.length > 0) payload = frames[0]?.payload ?? null;
69
+
70
+ const entries = collectEntries(payload).sort((a, b) =>
71
+ a.departureDate < b.departureDate ? -1 : a.departureDate > b.departureDate ? 1 : 0,
72
+ );
73
+
74
+ const prices: Record<string, number> = {};
75
+ for (const e of entries) prices[e.departureDate] = e.lowestPriceUSD;
76
+
77
+ const params = context?.params ?? {};
78
+ return {
79
+ origin: params.origin != null ? String(params.origin).toUpperCase() : null,
80
+ destination: params.destination != null ? String(params.destination).toUpperCase() : null,
81
+ currency: 'USD',
82
+ count: entries.length,
83
+ prices,
84
+ calendar: entries,
85
+ };
86
+ }
@@ -0,0 +1,97 @@
1
+ toolName: get_flight_calendar_prices
2
+ summary: Open the Google Flights date picker for a route to capture the calendar grid of lowest prices by departure/return date.
3
+ parameters:
4
+ - name: origin
5
+ type: string
6
+ description: Origin airport code, e.g. SJC
7
+ - name: destination
8
+ type: string
9
+ description: Destination airport code, e.g. SAN
10
+ - name: start_date
11
+ type: string
12
+ description: Start of date window YYYY-MM-DD (used to filter the returned calendar range; the picker returns a fixed window starting near today)
13
+ - name: end_date
14
+ type: string
15
+ description: End of date window YYYY-MM-DD (used to filter the returned calendar range)
16
+ steps:
17
+ - action: navigate
18
+ url: https://www.google.com/travel/flights
19
+ wait_for: networkidle
20
+ - action: click
21
+ locators:
22
+ - by: role
23
+ value: combobox
24
+ name: "Where from?"
25
+ - by: aria_label
26
+ value: "Where from?"
27
+ wait_for:
28
+ sleep_ms: 300
29
+ - action: type
30
+ locators:
31
+ - by: aria_label
32
+ value: "Where from?"
33
+ - by: aria_label
34
+ value: "Where else?"
35
+ value: ${origin}
36
+ wait_for:
37
+ sleep_ms: 500
38
+ - action: click
39
+ locators:
40
+ - by: aria_label
41
+ value_pattern: ${origin}
42
+ - by: role
43
+ value: option
44
+ - by: css
45
+ value: "ul.DFGgtd > li.n4HaVc"
46
+ wait_for: visible
47
+ - action: click
48
+ locators:
49
+ - by: role
50
+ value: combobox
51
+ name: "Where to?"
52
+ - by: aria_label
53
+ value: "Where to? "
54
+ wait_for:
55
+ sleep_ms: 300
56
+ - action: type
57
+ locators:
58
+ - by: aria_label
59
+ value: "Where to? "
60
+ - by: aria_label
61
+ value: "Where else?"
62
+ value: ${destination}
63
+ wait_for:
64
+ sleep_ms: 500
65
+ - action: click
66
+ locators:
67
+ - by: aria_label
68
+ value_pattern: ${destination}
69
+ - by: role
70
+ value: option
71
+ - by: css
72
+ value: "ul.DFGgtd > li.n4HaVc"
73
+ wait_for: visible
74
+ - action: click
75
+ locators:
76
+ - by: aria_label
77
+ value: Departure
78
+ - by: css
79
+ value: "div.GYgkab.YICvqf > div.NA5Egc.ESCxub > input.TP4Lpb.eoY5cb"
80
+ wait_for:
81
+ xhr: /GetCalendarPicker
82
+ result:
83
+ source: xhr
84
+ url_pattern: /GetCalendarPicker
85
+ extract: "[1][]"
86
+ return_as: calendar_prices
87
+ notes: >-
88
+ The GetCalendarPicker response is a Google batchexecute payload: strip the )]}' prefix, split on
89
+ numeric length-prefix lines, and JSON.parse the "wrb.fr" envelope's third element (a JSON-encoded
90
+ string). Inside that decoded array, index [1] is the list of date entries; each entry is
91
+ [departureDate (YYYY-MM-DD), returnDate (YYYY-MM-DD), [[null, lowestPriceUSD], opaqueFlightToken], 1].
92
+ Build a departureDate->lowestPriceUSD map and filter to [start_date, end_date]. The extract path
93
+ "[1][]" is relative to the decoded wrb.fr payload, not the raw HTTP body. start_date/end_date are
94
+ client-side filters: the picker returns a fixed forward window (~from today) and is opened simply by
95
+ clicking the Departure field — no date is typed to drive the request. The request is authorized by a
96
+ per-page f.sid plus X-Goog-BatchExecute-Bgr header that must be captured fresh from the page bootstrap
97
+ (navigate step), not parameterized.
@@ -0,0 +1,31 @@
1
+ // Local adapter: maps this tool's user-facing params (origin/destination/
2
+ // start_date/end_date) into the shape the shared FlightsFrontendService body
3
+ // builder consumes (legs[]/startDate/endDate/tripType), then delegates the
4
+ // byte-for-byte f.req encoding to the assigned shared request-transform.
5
+ import { transform as sharedTransform } from '../_shared/flights_request.ts';
6
+
7
+ export function transform(
8
+ method: string,
9
+ url: string,
10
+ responses: Record<string, any>,
11
+ params?: Record<string, any>,
12
+ ): { url: string; body: string } {
13
+ const p: Record<string, any> = params ?? {};
14
+ const origin = String(p.origin ?? '').toUpperCase();
15
+ const destination = String(p.destination ?? '').toUpperCase();
16
+
17
+ // GetCalendarPicker for this tool is a round-trip (tripType 1), 1 adult,
18
+ // with a mirrored outbound/return leg pair — exactly as recorded in seq 97.
19
+ const adapted = {
20
+ tripType: 1,
21
+ adults: 1,
22
+ legs: [
23
+ { origin, dest: destination },
24
+ { origin: destination, dest: origin },
25
+ ],
26
+ startDate: p.start_date ?? null,
27
+ endDate: p.end_date ?? null,
28
+ };
29
+
30
+ return sharedTransform(method, url, responses, adapted);
31
+ }
@@ -0,0 +1,78 @@
1
+ {
2
+ "toolName": "get_flight_calendar_prices",
3
+ "intent": {
4
+ "description": "Get a calendar grid of lowest round-trip prices by departure date for a route over a date window.",
5
+ "userSaid": "searched for a round trip flight; SJC to SAN"
6
+ },
7
+ "site": "google-flights",
8
+ "parameters": [
9
+ {
10
+ "name": "origin",
11
+ "type": "string",
12
+ "description": "Origin airport IATA code, e.g. SJC",
13
+ "verified": false,
14
+ "verifyNote": "annotated"
15
+ },
16
+ {
17
+ "name": "destination",
18
+ "type": "string",
19
+ "description": "Destination airport IATA code, e.g. SAN",
20
+ "verified": false,
21
+ "verifyNote": "annotated"
22
+ },
23
+ {
24
+ "name": "start_date",
25
+ "type": "string",
26
+ "description": "Start of departure-date window, YYYY-MM-DD",
27
+ "verified": false,
28
+ "verifyNote": "annotated"
29
+ },
30
+ {
31
+ "name": "end_date",
32
+ "type": "string",
33
+ "description": "End of departure-date window, YYYY-MM-DD",
34
+ "verified": false,
35
+ "verifyNote": "annotated"
36
+ }
37
+ ],
38
+ "bootstrap": {
39
+ "url": "https://www.google.com/travel/flights?hl=en-US&curr=USD",
40
+ "waitUntil": "domcontentloaded",
41
+ "captures": [
42
+ {
43
+ "source": "html_regex",
44
+ "name": "f_sid",
45
+ "pattern": "\"FdrFJe\":\"([^\"]+)\"",
46
+ "group": 1,
47
+ "required": false,
48
+ "capability": "browser_bootstrap"
49
+ },
50
+ {
51
+ "source": "html_regex",
52
+ "name": "bl",
53
+ "pattern": "\"cfb2h\":\"([^\"]+)\"",
54
+ "group": 1,
55
+ "required": false,
56
+ "capability": "browser_bootstrap"
57
+ }
58
+ ]
59
+ },
60
+ "requests": [
61
+ {
62
+ "method": "POST",
63
+ "url": "https://www.google.com/_/FlightsFrontendUi/data/travel.frontend.flights.FlightsFrontendService/GetCalendarPicker?f.sid=${state.f_sid}&bl=${state.bl}&hl=en-US&soc-app=162&soc-platform=1&soc-device=1&_reqid=1508023&rt=c",
64
+ "headers": {
65
+ "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
66
+ "X-Same-Domain": "1",
67
+ "x-goog-ext-259736195-jspb": "[\"en-US\",\"US\",\"USD\",2,null,[420],null,null,7,[]]",
68
+ "Referer": "https://www.google.com/travel/flights",
69
+ "Accept-Language": "en-US,en;q=0.9"
70
+ },
71
+ "body": "f.req=%5Bnull%2C%22%5Bnull%2C%5Bnull%2Cnull%2C1%2Cnull%2C%5B%5D%2C1%2C%5B1%2C0%2C0%2C0%5D%2Cnull%2Cnull%2Cnull%2Cnull%2Cnull%2Cnull%2C%5B%5B%5B%5B%5B%5C%22${param.origin}%5C%22%2C0%5D%5D%5D%2C%5B%5B%5B%5C%22${param.destination}%5C%22%2C0%5D%5D%5D%2Cnull%2C0%5D%2C%5B%5B%5B%5B%5C%22${param.destination}%5C%22%2C0%5D%5D%5D%2C%5B%5B%5B%5C%22${param.origin}%5C%22%2C0%5D%5D%5D%2Cnull%2C0%5D%5D%2Cnull%2Cnull%2Cnull%2C1%5D%2C%5B%5C%22${param.start_date}%5C%22%2C%5C%22${param.end_date}%5C%22%5D%2Cnull%2C%5B7%2C7%5D%5D%22%5D&",
72
+ "effect": "safe"
73
+ }
74
+ ],
75
+ "requestTransformModule": "./request-transform.ts",
76
+ "parserModule": "./parser.ts",
77
+ "liveVerified": true
78
+ }
@@ -0,0 +1,101 @@
1
+ /**
2
+ * GENERATED by `imprint emit` — DO NOT EDIT BY HAND.
3
+ *
4
+ * Tool: lookup_airport
5
+ * Site: google-flights
6
+ * Intent: Resolve a city or airport query into airport codes and structured airport details.
7
+ *
8
+ * To regenerate: imprint emit ~/.imprint/google-flights/lookup_airport/workflow.json --force
9
+ */
10
+
11
+ import { fileURLToPath } from 'node:url';
12
+ import { dirname, join } from 'node:path';
13
+ import {
14
+ executeWorkflow,
15
+ type CredentialStore,
16
+ } from 'imprint/runtime';
17
+ import type { ToolResult, Workflow } from 'imprint/types';
18
+
19
+ const WORKFLOW: Workflow = {
20
+ "toolName": "lookup_airport",
21
+ "intent": {
22
+ "description": "Resolve a city or airport query into airport codes and structured airport details.",
23
+ "userSaid": "multi city from SJC to SAN to LAX to SFO"
24
+ },
25
+ "parameters": [
26
+ {
27
+ "name": "query",
28
+ "type": "string",
29
+ "description": "City or airport search text, e.g. 'san jose' or 'SJC'",
30
+ "verified": true
31
+ }
32
+ ],
33
+ "requests": [
34
+ {
35
+ "method": "POST",
36
+ "url": "https://www.google.com/_/FlightsFrontendUi/data/batchexecute?rpcids=tDoGIe&source-path=%2Ftravel%2Fflights&f.sid=${state.f_sid}&bl=${state.bl}&hl=en-US&soc-app=162&soc-platform=1&soc-device=1&_reqid=608023&rt=c",
37
+ "headers": {
38
+ "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
39
+ "X-Same-Domain": "1",
40
+ "Referer": "https://www.google.com/travel/flights",
41
+ "Accept-Language": "en-US,en;q=0.9",
42
+ "x-goog-ext-259736195-jspb": "[\"en-US\",\"US\",\"USD\",2,null,[420],null,null,7,[]]"
43
+ },
44
+ "body": "f.req=%5B%5B%5B%22tDoGIe%22%2C%22%5Bnull%2C%5B%5B%5C%22${param.query}%5C%22%2C0%5D%5D%5D%22%2Cnull%2C%22generic%22%5D%5D%5D&",
45
+ "effect": "safe"
46
+ }
47
+ ],
48
+ "site": "google-flights",
49
+ "bootstrap": {
50
+ "url": "https://www.google.com/travel/flights",
51
+ "waitUntil": "domcontentloaded",
52
+ "timeoutMs": 30000,
53
+ "captures": [
54
+ {
55
+ "name": "f_sid",
56
+ "required": true,
57
+ "capability": "browser_bootstrap",
58
+ "source": "html_regex",
59
+ "pattern": "\"FdrFJe\":\"([^\"]+)\"",
60
+ "group": 1
61
+ },
62
+ {
63
+ "name": "bl",
64
+ "required": true,
65
+ "capability": "browser_bootstrap",
66
+ "source": "html_regex",
67
+ "pattern": "\"cfb2h\":\"([^\"]+)\"",
68
+ "group": 1
69
+ }
70
+ ]
71
+ },
72
+ "parserModule": "./parser.ts",
73
+ "requestTransformModule": "./request-transform.ts",
74
+ "liveVerified": true
75
+ };
76
+
77
+ export interface LookupAirportInput {
78
+ /** City or airport search text, e.g. 'san jose' or 'SJC' */
79
+ query: string;
80
+ }
81
+
82
+ export async function lookupAirport(
83
+ input: LookupAirportInput,
84
+ opts: { credentials?: CredentialStore; fetchImpl?: typeof fetch; initialState?: Record<string, unknown> } = {},
85
+ ): Promise<ToolResult> {
86
+ const __dirname = dirname(fileURLToPath(import.meta.url));
87
+ const params: Record<string, string | number | boolean> = {
88
+ query: input.query,
89
+
90
+ };
91
+ return executeWorkflow({
92
+ workflow: WORKFLOW,
93
+ params,
94
+ credentials: opts.credentials,
95
+ fetchImpl: opts.fetchImpl,
96
+ initialState: opts.initialState,
97
+ workflowPath: join(__dirname, 'workflow.json'),
98
+ });
99
+ }
100
+
101
+ export { WORKFLOW };
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "imprint-tool-google-flights",
3
+ "private": true,
4
+ "devDependencies": {
5
+ "@types/bun": "latest",
6
+ "@types/node": "latest",
7
+ "bun-types": "latest"
8
+ }
9
+ }