itamatrix 1.0.2 → 1.0.3

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.
@@ -24,7 +24,7 @@ export async function driveSearchForm(page, spec) {
24
24
  * `solutionList` shape as a normal search (N slices instead of 1–2).
25
25
  */
26
26
  export async function driveMultiCityForm(page, spec) {
27
- await page.getByRole("tab", { name: "Multi-City", exact: true }).click();
27
+ await page.getByRole("tab", { name: /multi[\s-]?city/i }).click();
28
28
  await ensureLegRows(page, spec.slices.length);
29
29
  for (const [i, leg] of spec.slices.entries()) {
30
30
  await fillAirport(page, 2 * i, leg.origin);
@@ -87,13 +87,16 @@ async function setAdvancedControls(page, spec, roundTrip) {
87
87
  }
88
88
  }
89
89
  /**
90
- * Adds "Add another flight" rows until the form has `count` legs. Matrix shows
91
- * two legs by default, so we only click for the extras.
90
+ * Adds "Add Flight" rows until the form has `count` legs. The default number of
91
+ * rows Matrix renders has drifted (currently one), so derive it from the live
92
+ * combobox count (two per leg) rather than assuming a fixed starting point.
92
93
  */
93
94
  async function ensureLegRows(page, count) {
94
95
  const addLeg = page.getByRole("button", { name: /add (another )?flight/i });
95
- for (let existing = 2; existing < count; existing++) {
96
+ const comboboxes = page.getByRole("combobox", { name: "Add airport" });
97
+ for (let existing = (await comboboxes.count()) / 2; existing < count; existing++) {
96
98
  await addLeg.click();
99
+ await comboboxes.nth(2 * existing + 1).waitFor({ state: "visible", timeout: 15_000 });
97
100
  }
98
101
  }
99
102
  /** Multi-city: shared cabin/stops globally, routing/ext per leg by row index. */
@@ -41,6 +41,8 @@ Define which carriers / airports / operators a slice may use, and in what order.
41
41
  | `C:XX` | force **marketing** carrier | `C:BA` |
42
42
  | `O:XX` | force **operating** carrier | `O:AA` |
43
43
  | `X:AAA` | **require** connection at airport | `X:DFW` |
44
+ | `X` | any single connection point | `UA X UA` |
45
+ | `X?` | nonstop **or** one connection | `X?` |
44
46
  | `N:` | nonstop only (no connections) | `N:` |
45
47
  | `F:` | direct (single flight number, stops allowed) | `F:` |
46
48
 
@@ -96,6 +98,9 @@ pipe-(`|`)-separated.
96
98
  | No red-eyes | `-REDEYES` | `-REDEYES` | exclude red-eye flights |
97
99
  | No overnights | `-OVERNIGHTS` | `-OVERNIGHTS` | exclude overnight layovers |
98
100
  | No props | `-PROPS` | `-PROPS` | exclude propeller aircraft |
101
+ | No airport change | `-CHANGE` | `-CHANGE` | exclude connections that change airports in a city |
102
+ | No trains | `-TRAIN` | `-TRAIN` | exclude rail segments |
103
+ | No helicopters | `-HELICOPTER` | `-HELICOPTER` | exclude helicopter segments |
99
104
 
100
105
  ### Faring codes (`f` / booking class / fare basis)
101
106
 
@@ -123,7 +128,27 @@ pipe-(`|`)-separated.
123
128
 
124
129
  ---
125
130
 
126
- ## 3. Notes for the skill
131
+ ## 3. Power-user strategies (FlyerTalk / community)
132
+
133
+ Higher-leverage patterns that combine the primitives above:
134
+
135
+ - **Force a stopover / overnight.** Matrix has no "stopover" command — fake it with a large
136
+ minimum connection. `MINCONNECT 12:00` forces an overnight layover; values above `24:00`
137
+ (e.g. `MINCONNECT 30:00`) force a 24 h+ stopover. Pin *where* with `X:CITY` in Routing.
138
+ Pair with `MAXCONNECT` to bound it: `X:NRT` + `MINCONNECT 20:00; MAXCONNECT 30:00`.
139
+ - **Split marketing vs operating for mileage credit.** Force the metal you want with `O:` in
140
+ Routing and the program you want to credit with marketing carrier / `ALLIANCE`. E.g. fly
141
+ Lufthansa metal but ticket via a partner: Routing `O:LH+`, Extension `ALLIANCE star-alliance`.
142
+ - **Target a booking class for upgrades / earning.** `f bc=...` pins the prime booking code
143
+ (fare buckets differ in price, upgrade eligibility, and miles earned). `f bc=w|bc=v` allows
144
+ either. Combine with `+CABIN` to keep the displayed cabin honest.
145
+ - **Mileage-run / distance tuning.** `MINMILES`/`MAXMILES` shape itinerary distance; useful for
146
+ hitting an elite-qualifying threshold or avoiding wasteful backtracking.
147
+ - **Consider nearby airports.** Matrix's UI accepts comma-separated origins/destinations
148
+ (e.g. `BOS,PVD,MHT`) and secondary airports are often materially cheaper; if a single-field
149
+ comma string is rejected, fall back to one search per airport and compare.
150
+
151
+ ## 4. Notes for the skill
127
152
 
128
153
  - **Validate field placement**: path-shaped intent → Routing; filter/fare intent → Extension.
129
154
  - **Cabin two ways**: the top-level `--cabin` (search option) sets the *displayed* cabin;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "itamatrix",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "CLI for ITA Matrix flight search",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,7 +18,9 @@ request into the right command + flags, encoding advanced intent as ITA
18
18
 
19
19
  The CLI ships as `itamatrix` (`npx itamatrix ...` if not installed globally).
20
20
  On first use it may ask for the browser: `npx playwright install chromium`.
21
- Queries take 30–60 s (Matrix is slow server-side); repeated queries hit the cache.
21
+ Queries can take a while (Matrix is slow server-side); repeated queries hit the
22
+ cache. **Set the command timeout to at least 180 s** — a search may run that long
23
+ before returning. Don't kill it early and conclude it failed.
22
24
 
23
25
  Always run with `--json` so you get structured output to parse and summarize.
24
26
 
@@ -62,6 +64,17 @@ grammar before constructing codes. Rules of thumb:
62
64
  - The `f` faring grammar is community-documented, not official — let Matrix
63
65
  validate. Don't over-restrict locally.
64
66
 
67
+ ### High-leverage patterns (see the reference doc's "Power-user strategies")
68
+
69
+ - **Force a stopover/overnight** — Matrix has no stopover command; fake it with a
70
+ big minimum connection. "Overnight in Tokyo" → `--routing X:NRT --ext "MINCONNECT 12:00"`;
71
+ 24 h+ stopover → `MINCONNECT 30:00`.
72
+ - **Mileage credit / specific metal** — force operating carrier in `--routing` (`O:LH+`)
73
+ and the crediting program via `--ext "ALLIANCE star-alliance"`.
74
+ - **Upgrade/earning fare buckets** — pin booking class with `--ext "f bc=w|bc=v"`.
75
+ - **Time format gotcha**: `--ext` uses `h:mm` (`MINCONNECT 12:00`); the inline
76
+ `--routing / minconnect 720` form uses raw minutes. Prefer `--ext`.
77
+
65
78
  ## Workflow
66
79
 
67
80
  1. Parse the request: route(s), dates, travelers, and any constraints.
@@ -165,6 +178,13 @@ itamatrix --json multicity \
165
178
  --ext "-OVERNIGHTS"
166
179
  ```
167
180
 
181
+ > "Boston to Singapore in October, but I want a long overnight stopover in Tokyo."
182
+
183
+ ```bash
184
+ itamatrix --json search BOS SIN --depart 2026-10-10 \
185
+ --routing "X:NRT" --ext "MINCONNECT 12:00; MAXCONNECT 30:00"
186
+ ```
187
+
168
188
  > "What's the cheapest week in August to do a 7-night trip BOS→LAX on United?"
169
189
 
170
190
  ```bash