@tracelane/cli 0.1.0-alpha.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.
@@ -0,0 +1,508 @@
1
+ // String-based editor for wdio.conf.* (Strategy A from the v0.1 spec).
2
+ //
3
+ // We chose regex over an AST parser (ts-morph) for two reasons:
4
+ // 1. ts-morph adds ~10 MB to the published @tracelane/cli — bad tradeoff
5
+ // for a CLI whose only purpose is one transformation on first install.
6
+ // 2. The space of "real" WDIO conf shapes is small and well-defined; if
7
+ // a user has something exotic the regex doesn't match, the editor backs
8
+ // out cleanly and prints a manual-step snippet (the rest of `init` —
9
+ // install, mkdir, .gitignore — still runs).
10
+ //
11
+ // The contract every edit MUST satisfy after `applyWdioEdit` returns
12
+ // `{ ok: true, ... }`:
13
+ //
14
+ // - The source still contains `import TraceLaneService from '@tracelane/wdio';`
15
+ // (or the existing import was already there — idempotent re-run case).
16
+ // - The source still contains `[TraceLaneService, { mode: 'failed' }]`.
17
+ // - File length grew by 80–200 bytes (sanity bound; 0 = nothing happened,
18
+ // 10kb+ = the regex went off the rails). Idempotent re-runs are allowed
19
+ // to grow by 0 and return `alreadyConfigured: true`.
20
+ //
21
+ // On any sanity-check failure the caller restores the original file from the
22
+ // backup written next to the conf (`{path}.tracelane-init.backup`).
23
+ //
24
+ // SHADOW SAFETY (2026-05-29 code-review fix): every source-scanning regex
25
+ // runs against a `stripStringsAndComments` buffer, NOT the raw source. The
26
+ // strip replaces all string-literal + comment content with same-length
27
+ // space padding so offsets translate 1:1 between stripped and raw buffers
28
+ // — a match in the stripped buffer can be sliced out of the raw source by
29
+ // its index. This prevents:
30
+ // - `/* services: ['x'] */ export const config = { services: ['real'] }`
31
+ // from having the EXAMPLE in the comment edited and the real array
32
+ // left untouched.
33
+ // - `// services: ['x'] (example)` line-comment shadows.
34
+ // - `"services: [stuff]"` string-literal shadows.
35
+ // Plus: `findServicesArray` requires the matched `services:` key to live
36
+ // at brace-depth 1 from the top-level config object literal (not inside
37
+ // `capabilities: [{ services: [...] }]`, which is a per-capability driver
38
+ // hint with different semantics).
39
+ /** The import line we add at the top of the user's wdio.conf. */
40
+ export const TRACELANE_IMPORT = `import TraceLaneService from '@tracelane/wdio';`;
41
+ /** The services-array entry we add. Tuple form: [Service, options]. */
42
+ export const TRACELANE_SERVICE_TUPLE = `[TraceLaneService, { mode: 'failed' }]`;
43
+ /**
44
+ * Sanity bounds for the post-edit byte-count delta. The lower bound is
45
+ * different for the "added both import + entry" path vs the "entry only
46
+ * (idempotent import already present)" path — the import line alone is
47
+ * already ~50 bytes, so an entry-only edit can legitimately grow by less.
48
+ */
49
+ export const EDIT_DELTA_MIN = 80; // both import + entry added
50
+ export const EDIT_DELTA_MIN_ENTRY_ONLY = 30; // entry only — tuple is ~40 bytes
51
+ export const EDIT_DELTA_MAX = 400;
52
+ // ---------------------------------------------------------------------------
53
+ // Shared scanner: walk the source once, tracking string-literal state +
54
+ // line/block comments. Two consumers:
55
+ // 1. `stripStringsAndComments`: produces a same-length buffer where every
56
+ // string-literal content and every comment body is replaced with a
57
+ // space, so a regex run against the stripped buffer can never match
58
+ // inside a string or comment. Offsets translate 1:1 — the index of a
59
+ // match in the stripped buffer points at the equivalent character in
60
+ // the raw source.
61
+ // 2. `findMatchingDelimiter`: bracket/brace counter used to find the
62
+ // closing `]` of a `services: [` or the closing `}` of a config object.
63
+ // Both share the same string/comment skipping so the strip and the matcher
64
+ // agree on what counts as "in code" vs "in a literal".
65
+ // ---------------------------------------------------------------------------
66
+ /**
67
+ * Produce a same-length copy of `src` where every string literal and every
68
+ * comment is replaced with a same-length space-padded run. Newlines inside
69
+ * line comments and block comments are preserved (so regex anchors like
70
+ * `^...$` with the `m` flag still see the same line structure).
71
+ *
72
+ * Inside template literals (backtick), `${...}` interpolation BODIES are
73
+ * treated as code — we re-enter normal mode for the interpolated expression
74
+ * so a `services:` mention there isn't shadowed. This is rare in practice
75
+ * (configs don't usually compute the services array via template literals)
76
+ * but it's cheap to do right.
77
+ */
78
+ export function stripStringsAndComments(src) {
79
+ const out = new Array(src.length);
80
+ let i = 0;
81
+ const n = src.length;
82
+ while (i < n) {
83
+ const ch = src[i];
84
+ const next = src[i + 1];
85
+ // Line comment: `// ...` to end-of-line. Replace the body with spaces
86
+ // but keep newlines.
87
+ if (ch === '/' && next === '/') {
88
+ out[i] = ' ';
89
+ out[i + 1] = ' ';
90
+ i += 2;
91
+ while (i < n && src[i] !== '\n') {
92
+ out[i] = ' ';
93
+ i += 1;
94
+ }
95
+ // The newline itself is left intact when we fall through.
96
+ continue;
97
+ }
98
+ // Block comment: `/* ... */`. Replace bodies with spaces; preserve
99
+ // newlines.
100
+ if (ch === '/' && next === '*') {
101
+ out[i] = ' ';
102
+ out[i + 1] = ' ';
103
+ i += 2;
104
+ while (i < n && !(src[i] === '*' && src[i + 1] === '/')) {
105
+ out[i] = src[i] === '\n' ? '\n' : ' ';
106
+ i += 1;
107
+ }
108
+ // Pad the closing `*/` as well.
109
+ if (i < n) {
110
+ out[i] = ' ';
111
+ out[i + 1] = ' ';
112
+ i += 2;
113
+ }
114
+ continue;
115
+ }
116
+ // String literals: single, double, template.
117
+ if (ch === '"' || ch === "'" || ch === '`') {
118
+ const quote = ch;
119
+ // Keep the opening quote so a `findServicesArray` regex anchored to
120
+ // `^|[\s,{]` can never mistake a quote for the prelude. The CONTENT
121
+ // is what we strip.
122
+ out[i] = ch;
123
+ i += 1;
124
+ while (i < n) {
125
+ const c = src[i];
126
+ if (c === '\\') {
127
+ // Pad the escape pair as two spaces. Preserve the size.
128
+ out[i] = ' ';
129
+ if (i + 1 < n)
130
+ out[i + 1] = src[i + 1] === '\n' ? '\n' : ' ';
131
+ i += 2;
132
+ continue;
133
+ }
134
+ if (quote === '`' && c === '$' && src[i + 1] === '{') {
135
+ // Template-literal `${...}` interpolation. The dollar-brace itself
136
+ // is part of the literal syntax — pad it; INSIDE the braces we
137
+ // re-enter normal "code" mode by copying the chars through. The
138
+ // matching `}` closes the interpolation; pad it on the way out.
139
+ out[i] = ' ';
140
+ out[i + 1] = ' ';
141
+ let braceDepth = 1;
142
+ i += 2;
143
+ while (i < n && braceDepth > 0) {
144
+ const cc = src[i] ?? '';
145
+ if (cc === '{')
146
+ braceDepth += 1;
147
+ else if (cc === '}')
148
+ braceDepth -= 1;
149
+ if (braceDepth === 0) {
150
+ // Pad the closing brace.
151
+ out[i] = ' ';
152
+ i += 1;
153
+ break;
154
+ }
155
+ // Inside the interpolation — recurse-ish: copy chars through.
156
+ out[i] = cc;
157
+ i += 1;
158
+ }
159
+ continue;
160
+ }
161
+ if (c === quote) {
162
+ // Keep the closing quote for symmetry with the opener.
163
+ out[i] = c;
164
+ i += 1;
165
+ break;
166
+ }
167
+ // Plain literal content: replace with space (or newline).
168
+ out[i] = c === '\n' ? '\n' : ' ';
169
+ i += 1;
170
+ }
171
+ continue;
172
+ }
173
+ // Plain code character — copy through.
174
+ out[i] = ch ?? '';
175
+ i += 1;
176
+ }
177
+ return out.join('');
178
+ }
179
+ /**
180
+ * Generic bracket/brace counter. Walks `src` from `openIndex` (which must
181
+ * point at an opening delimiter of the requested kind) and returns the
182
+ * index of the matching closer, or -1 if EOF arrives first.
183
+ *
184
+ * We accept a pre-stripped buffer as `scan`: the bracket/brace counting
185
+ * happens against the stripped buffer (so brackets inside strings/comments
186
+ * are spaces and don't count) but the result is still a valid offset into
187
+ * the original source (the strip is length-preserving).
188
+ */
189
+ function findMatchingDelimiter(scan, openIndex, open, close) {
190
+ let depth = 0;
191
+ let i = openIndex;
192
+ const n = scan.length;
193
+ while (i < n) {
194
+ const ch = scan[i];
195
+ if (ch === open)
196
+ depth += 1;
197
+ else if (ch === close) {
198
+ depth -= 1;
199
+ if (depth === 0)
200
+ return i;
201
+ }
202
+ i += 1;
203
+ }
204
+ return -1;
205
+ }
206
+ function depthAt(scan) {
207
+ const out = new Array(scan.length);
208
+ let braces = 0;
209
+ let brackets = 0;
210
+ for (let i = 0; i < scan.length; i += 1) {
211
+ const ch = scan[i];
212
+ if (ch === '{')
213
+ braces += 1;
214
+ else if (ch === '}')
215
+ braces = Math.max(0, braces - 1);
216
+ else if (ch === '[')
217
+ brackets += 1;
218
+ else if (ch === ']')
219
+ brackets = Math.max(0, brackets - 1);
220
+ out[i] = { depth: braces + brackets };
221
+ }
222
+ return out;
223
+ }
224
+ // ---------------------------------------------------------------------------
225
+ // Public scanning helpers
226
+ // ---------------------------------------------------------------------------
227
+ /**
228
+ * Locate the `services:` array literal in a wdio.conf source string. Returns
229
+ * the bracket indices + the substring inside.
230
+ *
231
+ * The match runs against `stripStringsAndComments(source)` so a `services:`
232
+ * inside a comment or a string can never be selected. Among the remaining
233
+ * candidates, we prefer the SHALLOWEST brace+bracket depth — this rejects
234
+ * `capabilities: [{ services: ['safari'] }]` (depth 3) in favour of the
235
+ * outer testrunner `services:` (depth 1). The depth-1 preference matches
236
+ * the WDIO config schema (services live directly on the config object).
237
+ *
238
+ * Returns `undefined` if no `services:` key with an array literal is present
239
+ * outside strings/comments.
240
+ */
241
+ export function findServicesArray(source) {
242
+ const scan = stripStringsAndComments(source);
243
+ const depths = depthAt(scan);
244
+ const re = /(?:^|[\s,{])(?:services|"services"|'services')\s*:\s*\[/g;
245
+ let m;
246
+ let best;
247
+ // biome-ignore lint/suspicious/noAssignInExpressions: idiomatic for global-flag regex iteration
248
+ while ((m = re.exec(scan)) !== null) {
249
+ const openIndex = m.index + m[0].length - 1; // points at `[`
250
+ const closeIndex = findMatchingDelimiter(scan, openIndex, '[', ']');
251
+ if (closeIndex === -1)
252
+ continue;
253
+ // Depth at the character JUST BEFORE the `[` — that's the depth at
254
+ // which the `services:` key was declared. (After we pass the `[` itself
255
+ // we're one bracket deeper, but the key's scope is the surrounding
256
+ // object.)
257
+ const keyDepth = depths[openIndex - 1]?.depth ?? 0;
258
+ if (best === undefined || keyDepth < best.depth) {
259
+ best = { openIndex, closeIndex, depth: keyDepth };
260
+ }
261
+ }
262
+ if (!best)
263
+ return undefined;
264
+ return {
265
+ openIndex: best.openIndex,
266
+ closeIndex: best.closeIndex,
267
+ // Slice the inner content out of the ORIGINAL source (strip is length-
268
+ // preserving so indices match), so the user's actual array contents
269
+ // are what gets edited.
270
+ inner: source.slice(best.openIndex + 1, best.closeIndex),
271
+ };
272
+ }
273
+ /**
274
+ * Insert the tracelane import after the LAST `import ... from '...';` line in
275
+ * the source. If no imports exist (which should never happen for a real WDIO
276
+ * conf) we insert at the top.
277
+ *
278
+ * We don't attempt to deduplicate or sort — the user's editor + Biome will
279
+ * fold our line in on the next save. Idempotency is enforced by the caller
280
+ * (it checks `hasTracelaneImport(source)` before invoking this).
281
+ *
282
+ * Match runs against the stripped buffer so a top-of-file block comment
283
+ * mentioning `import` cannot shadow the real import section.
284
+ */
285
+ export function insertTracelaneImport(source) {
286
+ const scan = stripStringsAndComments(source);
287
+ const importLineRe = /^\s*import\s.+?\s+from\s+['"][^'"]+['"];?\s*$/gm;
288
+ let lastEnd = -1;
289
+ let m;
290
+ // biome-ignore lint/suspicious/noAssignInExpressions: idiomatic for global-flag regex iteration
291
+ while ((m = importLineRe.exec(scan)) !== null) {
292
+ lastEnd = m.index + m[0].length;
293
+ }
294
+ if (lastEnd === -1) {
295
+ // No imports — insert at the very top, before any code.
296
+ return `${TRACELANE_IMPORT}\n\n${source}`;
297
+ }
298
+ // Insert immediately after the last import line. Index is into the raw
299
+ // source because the strip is length-preserving.
300
+ return `${source.slice(0, lastEnd)}\n${TRACELANE_IMPORT}${source.slice(lastEnd)}`;
301
+ }
302
+ /**
303
+ * True if the source already has an `@tracelane/wdio` import. Matches both
304
+ * default and named import forms (`import TraceLaneService from ...` /
305
+ * `import { TraceLaneService } from ...`) and either quote style. Runs
306
+ * against the stripped buffer so a commented-out example
307
+ * // import TraceLaneService from '@tracelane/wdio';
308
+ * doesn't false-positive — but the stripped buffer preserves the import
309
+ * keyword itself, so a real import is still detected.
310
+ *
311
+ * Wait — we DO want to match the literal '@tracelane/wdio' inside the
312
+ * `from '...'` clause. The strip replaces string CONTENT with spaces, so
313
+ * `from '@tracelane/wdio'` becomes `from ' '` in the stripped
314
+ * buffer. We need to recognise the real import by structure: the keyword
315
+ * `import`, the binding, `from`, a string literal of any contents. We test
316
+ * the structural shape on the stripped buffer, then verify the string
317
+ * literal's contents against the RAW source at the matched offsets.
318
+ */
319
+ export function hasTracelaneImport(source) {
320
+ const scan = stripStringsAndComments(source);
321
+ // Structural match against the stripped buffer (the string contents are
322
+ // padded out to spaces but the surrounding `from '...'` syntax stays).
323
+ const re = /import\s+[^;]*?from\s+(['"])([^'"]*)\1;?/g;
324
+ let m;
325
+ // biome-ignore lint/suspicious/noAssignInExpressions: idiomatic for global-flag regex iteration
326
+ while ((m = re.exec(scan)) !== null) {
327
+ // The group at index 2 is the STRING CONTENT in the stripped buffer (so
328
+ // spaces), but the same offsets in the RAW source carry the real chars.
329
+ const fullMatchStart = m.index;
330
+ const fullMatchEnd = m.index + m[0].length;
331
+ const raw = source.slice(fullMatchStart, fullMatchEnd);
332
+ if (/from\s+['"]@tracelane\/wdio['"]/.test(raw))
333
+ return true;
334
+ }
335
+ return false;
336
+ }
337
+ /**
338
+ * True if the source already mentions the TraceLaneService in a services
339
+ * array entry — either bare (`TraceLaneService`) or tuple
340
+ * (`[TraceLaneService, ...]`). Runs against the stripped buffer to ignore
341
+ * comment + string mentions.
342
+ */
343
+ export function hasTracelaneServiceEntry(source) {
344
+ const scan = stripStringsAndComments(source);
345
+ return /\[\s*TraceLaneService\b|\bTraceLaneService\b\s*[,\]]/.test(scan);
346
+ }
347
+ /**
348
+ * Insert `[TraceLaneService, { mode: 'failed' }]` as the LAST element of an
349
+ * existing services array. Three input shapes covered:
350
+ *
351
+ * services: [] → services: [[Service, opts]]
352
+ * services: ['devtools'] → services: ['devtools', [Service, opts]]
353
+ * services: [['devtools', {}]] → services: [['devtools', {}], [Service, opts]]
354
+ *
355
+ * Returns the new full source. Caller has already located `block` via
356
+ * `findServicesArray`.
357
+ */
358
+ export function appendToServicesArray(source, block) {
359
+ const inner = block.inner;
360
+ const trimmedInner = inner.replace(/\s+$/, '');
361
+ const isEmpty = trimmedInner.trim().length === 0;
362
+ // Detect trailing comma so we don't double-comma.
363
+ const hasTrailingComma = trimmedInner.endsWith(',');
364
+ // Replacement strategy: rebuild the inner content with our entry appended.
365
+ //
366
+ // - Empty array → `[<tuple>]`
367
+ // - Trailing , → `[existing, <tuple>]` (we add tuple after the comma)
368
+ // - No trailing → `[existing, <tuple>]` (we add `, <tuple>`)
369
+ let newInner;
370
+ if (isEmpty) {
371
+ newInner = TRACELANE_SERVICE_TUPLE;
372
+ }
373
+ else if (hasTrailingComma) {
374
+ newInner = `${trimmedInner} ${TRACELANE_SERVICE_TUPLE}`;
375
+ }
376
+ else {
377
+ newInner = `${trimmedInner}, ${TRACELANE_SERVICE_TUPLE}`;
378
+ }
379
+ return `${source.slice(0, block.openIndex + 1)}${newInner}${source.slice(block.closeIndex)}`;
380
+ }
381
+ /**
382
+ * Insert a `services: [[TraceLaneService, ...]]` line into a config object
383
+ * that has no `services:` key at all.
384
+ *
385
+ * Strategy: find the FIRST top-level `export const config` / `export default`
386
+ * config object literal, locate its outermost `{`/`}`, and insert
387
+ * services: [[TraceLaneService, { mode: 'failed' }]],
388
+ * just before the closing `}`. If we can't find the object literal, return
389
+ * undefined and let the caller back out to the manual-snippet path.
390
+ *
391
+ * Runs against the stripped buffer so an `export default { ... }` string in
392
+ * a doc-comment header can't be matched.
393
+ */
394
+ export function insertServicesKey(source) {
395
+ const scan = stripStringsAndComments(source);
396
+ const re = /(?:export\s+(?:default|const\s+config[^=]*=)|module\.exports\s*=)\s*(\{)/;
397
+ const m = re.exec(scan);
398
+ if (!m)
399
+ return undefined;
400
+ const braceIndex = m.index + m[0].length - 1; // points at `{`
401
+ const closeIndex = findMatchingDelimiter(scan, braceIndex, '{', '}');
402
+ if (closeIndex === -1)
403
+ return undefined;
404
+ const insertion = ` services: [${TRACELANE_SERVICE_TUPLE}],\n`;
405
+ return `${source.slice(0, closeIndex)}${insertion}${source.slice(closeIndex)}`;
406
+ }
407
+ /**
408
+ * Manual-paste snippet shown when the editor backs out. The user pastes this
409
+ * at the top of their conf and adds the tuple to `services:` themselves.
410
+ *
411
+ * This is the single source of truth — `init.ts`'s "restored from backup"
412
+ * path also references this constant so the snippet copy doesn't drift.
413
+ */
414
+ export const MANUAL_SNIPPET = `${TRACELANE_IMPORT}
415
+
416
+ // Inside your config object's \`services\` array:
417
+ // services: [${TRACELANE_SERVICE_TUPLE}],
418
+ `;
419
+ /**
420
+ * The single high-level entrypoint. Given the current source of a
421
+ * wdio.conf.*, produce the new source (with the import + service tuple
422
+ * added) — or fail cleanly with a manual snippet for the user to paste.
423
+ *
424
+ * Steps:
425
+ * 1. If both the import + the service entry are already present, no-op.
426
+ * 2. Add the import if it's missing.
427
+ * 3. Append to the existing `services: [...]` array, OR insert a new
428
+ * `services:` key if none exists.
429
+ * 4. Sanity-check the byte-count delta + presence of the marker strings.
430
+ *
431
+ * The sanity check at the END is the safety net: if our regex went off the
432
+ * rails (e.g. landed on an unusual shape) the delta is wildly wrong and we
433
+ * back out instead of writing a corrupt file.
434
+ */
435
+ export function applyWdioEdit(originalSource) {
436
+ const hadImport = hasTracelaneImport(originalSource);
437
+ const hadEntry = hasTracelaneServiceEntry(originalSource);
438
+ // Idempotent re-run: both pieces present, nothing to do.
439
+ if (hadImport && hadEntry) {
440
+ return {
441
+ ok: true,
442
+ source: originalSource,
443
+ alreadyConfigured: true,
444
+ addedImport: false,
445
+ addedServiceEntry: false,
446
+ };
447
+ }
448
+ let next = originalSource;
449
+ if (!hadImport) {
450
+ next = insertTracelaneImport(next);
451
+ }
452
+ let addedEntry = false;
453
+ if (!hadEntry) {
454
+ const block = findServicesArray(next);
455
+ if (block !== undefined) {
456
+ next = appendToServicesArray(next, block);
457
+ addedEntry = true;
458
+ }
459
+ else {
460
+ // No `services:` key at all — try to insert one inside the config object.
461
+ const withKey = insertServicesKey(next);
462
+ if (withKey === undefined) {
463
+ return {
464
+ ok: false,
465
+ reason: "Couldn't find the WDIO config object's `services:` array or a config object literal in the conf file. The auto-edit was aborted — apply the snippet below manually.",
466
+ manualSnippet: MANUAL_SNIPPET,
467
+ };
468
+ }
469
+ next = withKey;
470
+ addedEntry = true;
471
+ }
472
+ }
473
+ // Sanity check: did our edit do something plausible?
474
+ if (!hasTracelaneImport(next)) {
475
+ return {
476
+ ok: false,
477
+ reason: 'Post-edit sanity check failed: import line missing.',
478
+ manualSnippet: MANUAL_SNIPPET,
479
+ };
480
+ }
481
+ if (!hasTracelaneServiceEntry(next)) {
482
+ return {
483
+ ok: false,
484
+ reason: 'Post-edit sanity check failed: TraceLaneService entry missing.',
485
+ manualSnippet: MANUAL_SNIPPET,
486
+ };
487
+ }
488
+ const delta = next.length - originalSource.length;
489
+ // If both import + entry were ADDED we expect ~80-200 bytes of growth.
490
+ // If ONLY the entry was added (import was already there) the floor is
491
+ // smaller — the tuple itself is ~40 bytes.
492
+ const expectedFloor = hadImport ? EDIT_DELTA_MIN_ENTRY_ONLY : EDIT_DELTA_MIN;
493
+ if (delta < expectedFloor || delta > EDIT_DELTA_MAX) {
494
+ return {
495
+ ok: false,
496
+ reason: `Post-edit sanity check failed: byte delta ${delta} outside [${expectedFloor}, ${EDIT_DELTA_MAX}] bounds.`,
497
+ manualSnippet: MANUAL_SNIPPET,
498
+ };
499
+ }
500
+ return {
501
+ ok: true,
502
+ source: next,
503
+ alreadyConfigured: false,
504
+ addedImport: !hadImport,
505
+ addedServiceEntry: addedEntry,
506
+ };
507
+ }
508
+ //# sourceMappingURL=wdio-editor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wdio-editor.js","sourceRoot":"","sources":["../../src/lib/wdio-editor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const CLI_VERSION: string;
2
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,WAAW,QAAe,CAAC"}
@@ -0,0 +1,14 @@
1
+ // CLI version surfaced by `tracelane --version` / `tracelane --help`.
2
+ //
3
+ // Read at runtime from this package's package.json (via `createRequire` to
4
+ // keep an awkward JSON ESM import out of the source) so the printed version
5
+ // always matches what npm shipped — same pattern peek-cli/src/version.ts
6
+ // uses to dodge the P-8 drift bug (a hardcoded literal getting out of sync
7
+ // with Changesets-driven version bumps).
8
+ //
9
+ // The relative path is from the compiled dist/version.js → ../package.json.
10
+ import { createRequire } from 'node:module';
11
+ const _require = createRequire(import.meta.url);
12
+ const _pkg = _require('../package.json');
13
+ export const CLI_VERSION = _pkg.version;
14
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,EAAE;AACF,2EAA2E;AAC3E,4EAA4E;AAC5E,yEAAyE;AACzE,2EAA2E;AAC3E,yCAAyC;AACzC,EAAE;AACF,4EAA4E;AAE5E,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAChD,MAAM,IAAI,GAAG,QAAQ,CAAC,iBAAiB,CAAwB,CAAC;AAEhE,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@tracelane/cli",
3
+ "version": "0.1.0-alpha.1",
4
+ "description": "tracelane scaffolding CLI. `npx tracelane init` detects your test runner (WDIO / Playwright / Cypress) and wires @tracelane/wdio into wdio.conf.* in one command — the published path from `npm install` + manual conf edit to a single npx invocation.",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "bin": {
8
+ "tracelane": "./dist/index.js"
9
+ },
10
+ "main": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "NOTICE",
21
+ "README.md"
22
+ ],
23
+ "scripts": {
24
+ "build": "tsc -p tsconfig.json && node ./scripts/postbuild.mjs",
25
+ "typecheck": "tsc -p tsconfig.json --noEmit",
26
+ "test": "vitest run --passWithNoTests"
27
+ },
28
+ "dependencies": {},
29
+ "devDependencies": {
30
+ "@types/node": "^22.10.0"
31
+ },
32
+ "publishConfig": {
33
+ "access": "public",
34
+ "provenance": true
35
+ },
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/Cubenest/rrweb-stack",
39
+ "directory": "packages/tracelane-cli"
40
+ },
41
+ "homepage": "https://github.com/Cubenest/rrweb-stack/tree/main/packages/tracelane-cli#readme"
42
+ }