2g 0.4.0 → 0.4.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.
- package/CHANGELOG.md +7 -0
- package/dist/chunks/cli-chunk.js +24 -10
- package/dist/chunks/cli-chunk.js.map +1 -1
- package/dist/chunks/cli-chunk.mjs +33 -19
- package/dist/chunks/cli-chunk.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/dist/chunks/cli-chunk.js
CHANGED
|
@@ -733,6 +733,15 @@ async function runRecordCli(e) {
|
|
|
733
733
|
stdio: [ "inherit", c.output ? "inherit" : 2, "inherit" ]
|
|
734
734
|
}));
|
|
735
735
|
p.attach(u);
|
|
736
|
+
const onSignal = e => {
|
|
737
|
+
if ("SIGINT" !== e) {
|
|
738
|
+
try {
|
|
739
|
+
u.kill(e);
|
|
740
|
+
} catch {}
|
|
741
|
+
}
|
|
742
|
+
};
|
|
743
|
+
process.on("SIGINT", onSignal);
|
|
744
|
+
process.on("SIGTERM", onSignal);
|
|
736
745
|
const d = new Promise((e, t) => {
|
|
737
746
|
u.on("exit", t => e(t ?? 0));
|
|
738
747
|
u.on("error", e => t(new Error(`Failed to run ${a[0]}: ${e.message}`)));
|
|
@@ -742,16 +751,21 @@ async function runRecordCli(e) {
|
|
|
742
751
|
processName: a.join(" ")
|
|
743
752
|
};
|
|
744
753
|
const m = filterEvents(p, c);
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
754
|
+
try {
|
|
755
|
+
const e = "opentelemetry" === c.format ? await convertToOpenTelemetry(m, f) : await convertToChromeTrace(m, f);
|
|
756
|
+
const t = await d;
|
|
757
|
+
const n = JSON.stringify(e, null, 2);
|
|
758
|
+
if (c.output) {
|
|
759
|
+
o.writeFileSync(c.output, `${n}\n`);
|
|
760
|
+
} else {
|
|
761
|
+
process.stdout.write(`${n}\n`);
|
|
762
|
+
}
|
|
763
|
+
if (t) {
|
|
764
|
+
process.exitCode = t;
|
|
765
|
+
}
|
|
766
|
+
} finally {
|
|
767
|
+
process.off("SIGINT", onSignal);
|
|
768
|
+
process.off("SIGTERM", onSignal);
|
|
755
769
|
}
|
|
756
770
|
}
|
|
757
771
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-chunk.js","sources":["../../src/commands/clean/index.ts","../../src/commands/shared.ts","../../src/commands/export/chromeTrace.ts","../../src/commands/export/opentelemetry.ts","../../src/commands/export/index.ts","../../src/commands/ps/index.ts","../../src/commands/record/index.ts","../../src/commands/tap/index.ts","../../src/cli.ts"],"sourcesContent":["import { parseArgs } from 'node:util';\n\nimport { cleanExitedSessionsSync, cleanStaleSessionsSync } from '../../clean';\nimport { redirectConsoleToStderr } from '../../utils/redirectConsole';\n\nexport function runCleanCli(args: string[] = []) {\n const options = parseCleanOptions(args);\n if (options.json) redirectConsoleToStderr();\n const removed = options.all\n ? cleanExitedSessionsSync()\n : cleanStaleSessionsSync();\n process.stdout.write(\n options.json\n ? `${JSON.stringify({ removed })}\\n`\n : `Removed ${removed} ${options.all ? 'exited' : 'stale'} sessions.\\n`\n );\n}\n\nfunction parseCleanOptions(args: string[]) {\n const parsed = parseArgs({\n args,\n options: {\n all: { type: 'boolean', short: 'a' },\n json: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n return {\n all: parsed.values.all === true,\n json: parsed.values.json === true,\n };\n}\n\nexport function printCleanHelp() {\n process.stdout.write(\n [\n 'Usage: 2g clean',\n '',\n 'Removes stale exited sessions past the retention window.',\n '',\n 'Options:',\n ' --all, -a Remove all exited sessions',\n ' --json',\n '',\n ].join('\\n')\n );\n}\n","import fs from 'node:fs';\nimport { createInterface } from 'node:readline';\nimport type { Readable } from 'node:stream';\nimport { parseArgs } from 'node:util';\n\nimport { detectRotationLoss, type ListedSession } from '../tap';\nimport {\n compileEventFilter,\n matchesTapOptions,\n parseEventLine,\n parseSince,\n parseDuration as parseDurationValue,\n} from '../utils/eventFilter';\nimport type { ParsedEvent } from '../types';\n\nexport const tapArgOptions = {\n since: { type: 'string' },\n filter: { type: 'string', multiple: true },\n spans: { type: 'boolean' },\n debug: { type: 'boolean' },\n tail: { type: 'boolean' },\n} as const;\n\nexport interface SharedTapOptions {\n since?: string;\n filter?: string[];\n spans?: boolean;\n debug?: boolean;\n follow: boolean;\n}\n\n// Warns (via console.warn → stderr, so it never pollutes the JSON/JSONL on\n// stdout, and stays mockable in tests) when segment rotation has already\n// dropped the start of the run from the retained window.\nexport async function warnOnRotationLoss(sessionDir: string, remedy: string) {\n if (!(await detectRotationLoss(sessionDir))) return;\n console.warn(\n `⚠ Earlier events were rotated out of the retained window.\\n` +\n ` For a complete trace, start \\`${remedy}\\` before the workload.`\n );\n}\n\nexport function formatSessionProcessName(session: ListedSession) {\n return session.version\n ? `${session.command} (v${session.version}, PID ${session.pid})`\n : `${session.command} (PID ${session.pid})`;\n}\n\nexport async function* readJsonlFile(file: string) {\n yield* readJsonlStream(fs.createReadStream(file, { encoding: 'utf8' }));\n}\n\nexport async function* readJsonlStdin() {\n yield* readJsonlStream(process.stdin);\n}\n\nexport async function* readJsonlStream(stream: Readable) {\n const rl = createInterface({ input: stream });\n for await (const line of rl) {\n if (!line) continue;\n // Lossless parse; the debug decision belongs to filterEvents\n const event = parseEventLine(line, { debug: true });\n if (event) yield event;\n }\n}\n\nexport async function* filterEvents(\n events: AsyncIterable<ParsedEvent> | Iterable<ParsedEvent>,\n options: Pick<SharedTapOptions, 'since' | 'filter' | 'spans' | 'debug'>\n) {\n const eventFilter = compileEventFilter(options.filter);\n const since = parseSince(options.since);\n for await (const event of events) {\n if (\n matchesTapOptions(\n event,\n {\n filter: options.filter,\n since,\n spans: options.spans,\n debug: options.debug,\n },\n eventFilter\n )\n )\n yield event;\n }\n}\n\nexport function parseSharedTapOptions(values: {\n since?: string;\n filter?: string[];\n spans?: boolean;\n debug?: boolean;\n tail?: boolean;\n}): SharedTapOptions {\n return {\n since: values.since,\n filter: values.filter\n ?.flatMap(value => value.split(','))\n .map(item => item.trim())\n .filter(Boolean),\n spans: values.spans === true,\n debug: values.debug === true,\n follow: values.tail === true,\n };\n}\n\nexport function parseHelp(args: string[]) {\n return (\n parseArgs({\n args,\n allowPositionals: true,\n strict: false,\n options: {\n help: { type: 'boolean', short: 'h' },\n },\n }).values.help === true\n );\n}\n\nexport function parseJsonFlag(args: string[]) {\n return parseArgs({\n args,\n allowPositionals: true,\n options: {\n json: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n },\n }).values;\n}\n\nexport function parseDuration(value?: string) {\n if (value == null || value === '') return undefined;\n const duration = parseDurationValue(value);\n if (duration == null) throw new Error(`Invalid duration: ${value}`);\n return duration;\n}\n","import type { ParsedEvent } from '../../types';\n\nexport interface ConvertToChromeTraceOptions {\n processName?: string;\n pid?: number;\n}\n\nexport interface TraceFile {\n traceEvents: TraceEvent[];\n metadata: {\n source: '2g';\n version: string;\n convertedAt: string;\n startTime: string;\n startTimestampMs: number;\n };\n}\n\nexport type TraceEvent = TraceComplete | TraceInstant | TraceMetadata;\n\nexport interface TraceComplete {\n ph: 'X';\n name: string;\n cat: string;\n pid: number;\n tid: number;\n ts: number;\n dur: number;\n args?: Record<string, unknown>;\n}\n\nexport interface TraceInstant {\n ph: 'i';\n name: string;\n cat: string;\n pid: number;\n tid: number;\n ts: number;\n s: 'g' | 'p' | 't';\n args?: Record<string, unknown>;\n}\n\nexport interface TraceMetadata {\n ph: 'M';\n name: 'process_name' | 'thread_name' | 'thread_sort_index';\n pid: number;\n tid?: number;\n args: Record<string, unknown>;\n}\n\nconst STRIP_SUFFIXES = [':started', ':done', ':failed'];\n\nexport async function convertToChromeTrace(\n events: Iterable<ParsedEvent> | AsyncIterable<ParsedEvent>,\n options: ConvertToChromeTraceOptions = {}\n): Promise<TraceFile> {\n const converter = new TraceConverter(options);\n for await (const event of events) {\n converter.add(event);\n }\n return converter.toTraceFile();\n}\n\ninterface PendingSpan {\n track: string;\n name: string;\n cat: string;\n ts: number;\n dur: number;\n args?: Record<string, unknown>;\n lane: number;\n}\n\ninterface PendingInstant {\n track: string;\n name: string;\n cat: string;\n ts: number;\n args?: Record<string, unknown>;\n}\n\ntype PendingEvent =\n | ({ kind: 'span' } & PendingSpan)\n | ({ kind: 'instant' } & PendingInstant);\n\nexport class TraceConverter {\n #pending: PendingEvent[] = [];\n #tracks = new Map<string, string>();\n #pid: number;\n #processName: string;\n #version = '0.1.0';\n\n constructor(options: ConvertToChromeTraceOptions = {}) {\n this.#pid = options.pid ?? 1;\n this.#processName = options.processName ?? '2g';\n }\n\n add(event: ParsedEvent) {\n if (event._e === 'root:init') {\n if (typeof event.version === 'string') {\n this.#version = event.version;\n if (this.#processName === '2g') {\n this.#processName = `2g (v${event.version})`;\n }\n }\n return;\n }\n\n const parsed = splitEventName(event._e);\n const track = this.#getTrack(\n parsed.category,\n typeof event._w === 'string' ? event._w : undefined\n );\n const args = extractArgs(event);\n\n if (typeof event._d === 'number') {\n this.#pending.push({\n kind: 'span',\n track,\n name: stripSuffix(parsed.name),\n cat: parsed.category,\n ts: Math.round((event._t - event._d) * 1000),\n dur: Math.round(event._d * 1000),\n args,\n lane: 0,\n });\n } else {\n this.#pending.push({\n kind: 'instant',\n track,\n name: stripSuffix(parsed.name),\n cat: parsed.category,\n ts: Math.round(event._t * 1000),\n args,\n });\n }\n }\n\n toTraceFile(): TraceFile {\n let base = this.#pending.length ? Infinity : 0;\n for (const event of this.#pending) {\n if (event.ts < base) base = event.ts;\n }\n const traceEvents: TraceEvent[] = [\n {\n ph: 'M',\n name: 'process_name',\n pid: this.#pid,\n args: { name: this.#processName },\n },\n ];\n\n const tids = new Map<string, number>();\n let nextTid = 1;\n for (const [track, displayName] of this.#tracks) {\n const spans: PendingSpan[] = [];\n for (const event of this.#pending) {\n if (event.kind === 'span' && event.track === track) spans.push(event);\n }\n const laneCount = Math.max(assignLanes(spans), 1);\n for (let lane = 0; lane < laneCount; lane++) {\n const tid = nextTid++;\n tids.set(`${track}\\0${lane}`, tid);\n traceEvents.push(\n {\n ph: 'M',\n name: 'thread_name',\n pid: this.#pid,\n tid,\n args: {\n name: lane === 0 ? displayName : `${displayName} #${lane + 1}`,\n },\n },\n {\n ph: 'M',\n name: 'thread_sort_index',\n pid: this.#pid,\n tid,\n args: { sort_index: tid },\n }\n );\n }\n }\n\n for (const event of this.#pending) {\n const lane = event.kind === 'span' ? event.lane : 0;\n const tid = tids.get(`${event.track}\\0${lane}`)!;\n if (event.kind === 'span') {\n traceEvents.push({\n ph: 'X',\n name: event.name,\n cat: event.cat,\n pid: this.#pid,\n tid,\n ts: event.ts - base,\n dur: event.dur,\n args: event.args,\n });\n } else {\n traceEvents.push({\n ph: 'i',\n name: event.name,\n cat: event.cat,\n pid: this.#pid,\n tid,\n ts: event.ts - base,\n s: 't',\n args: event.args,\n });\n }\n }\n\n return {\n traceEvents,\n metadata: {\n source: '2g',\n version: this.#version,\n convertedAt: new Date().toISOString(),\n startTime: new Date(base / 1000).toISOString(),\n startTimestampMs: base / 1000,\n },\n };\n }\n\n #getTrack(category: string, worker?: string) {\n const key = worker ? `${category}:${worker}` : category;\n if (!this.#tracks.has(key)) {\n this.#tracks.set(key, worker ? `${category} ${worker}` : category);\n }\n return key;\n }\n}\n\n// 'X' events on one tid nest by containment; partial overlap is invalid.\nfunction assignLanes(spans: PendingSpan[]) {\n const order = [...spans].sort(\n (a, b) => a.ts - b.ts || b.ts + b.dur - (a.ts + a.dur)\n );\n const lanes: PendingSpan[][] = [];\n for (const span of order) {\n const end = span.ts + span.dur;\n let lane = -1;\n for (let index = 0; index < lanes.length; index++) {\n const stack = lanes[index];\n while (\n stack.length &&\n stack[stack.length - 1].ts + stack[stack.length - 1].dur <= span.ts\n ) {\n stack.pop();\n }\n const top = stack[stack.length - 1];\n if (!top || top.ts + top.dur >= end) {\n stack.push(span);\n lane = index;\n break;\n }\n }\n if (lane < 0) {\n lanes.push([span]);\n lane = lanes.length - 1;\n }\n span.lane = lane;\n }\n return lanes.length;\n}\n\nfunction splitEventName(value: string) {\n const index = value.indexOf(':');\n if (index < 1) return { category: 'uncategorized', name: value };\n return {\n category: value.slice(0, index),\n name: value.slice(index + 1),\n };\n}\n\nfunction stripSuffix(name: string) {\n for (const suffix of STRIP_SUFFIXES) {\n if (name.endsWith(suffix)) return name.slice(0, -suffix.length);\n }\n return name;\n}\n\nfunction extractArgs(event: ParsedEvent) {\n const args: Record<string, unknown> = {};\n for (const key of Object.keys(event)) {\n if (key.startsWith('_')) continue;\n args[key] = event[key];\n }\n return Object.keys(args).length ? args : undefined;\n}\n","import crypto from 'node:crypto';\n\nimport type { ParsedEvent } from '../../types';\n\nexport interface ConvertToOpenTelemetryOptions {\n processName?: string;\n pid?: number;\n}\n\nexport interface OpenTelemetryFile {\n resourceSpans: OpenTelemetryResourceSpan[];\n}\n\ninterface OpenTelemetryResourceSpan {\n resource: {\n attributes: OpenTelemetryAttribute[];\n };\n scopeSpans: Array<{\n scope: {\n name: string;\n };\n spans: OpenTelemetrySpan[];\n }>;\n}\n\ninterface OpenTelemetrySpan {\n traceId: string;\n spanId: string;\n parentSpanId?: string;\n name: string;\n startTimeUnixNano: string;\n endTimeUnixNano: string;\n attributes?: OpenTelemetryAttribute[];\n events?: OpenTelemetrySpanEvent[];\n}\n\ninterface OpenTelemetrySpanEvent {\n timeUnixNano: string;\n name: string;\n attributes?: OpenTelemetryAttribute[];\n}\n\ninterface OpenTelemetryAttribute {\n key: string;\n value: OpenTelemetryAnyValue;\n}\n\ntype OpenTelemetryAnyValue =\n | { stringValue: string }\n | { intValue: string }\n | { doubleValue: number }\n | { boolValue: boolean }\n | { arrayValue: { values: OpenTelemetryAnyValue[] } }\n | { kvlistValue: { values: OpenTelemetryAttribute[] } };\n\nconst STRIP_SUFFIXES = [':started', ':done', ':failed'];\n\nexport async function convertToOpenTelemetry(\n events: Iterable<ParsedEvent> | AsyncIterable<ParsedEvent>,\n options: ConvertToOpenTelemetryOptions = {}\n): Promise<OpenTelemetryFile> {\n const converter = new OpenTelemetryConverter(options);\n for await (const event of events) {\n converter.add(event);\n }\n return converter.toFile();\n}\n\nclass OpenTelemetryConverter {\n readonly #traceId = crypto.randomBytes(16).toString('hex');\n readonly #sessionSpanId = createSpanId();\n readonly #spans: OpenTelemetrySpan[] = [];\n readonly #events: OpenTelemetrySpanEvent[] = [];\n #processName: string;\n #version = '0.1.0';\n #startTimeUnixNano: string | undefined;\n #endTimeUnixNano: string | undefined;\n\n constructor(private readonly options: ConvertToOpenTelemetryOptions) {\n this.#processName = options.processName ?? '2g';\n }\n\n add(event: ParsedEvent) {\n const eventTime = unixNano(event._t);\n this.#startTimeUnixNano =\n this.#startTimeUnixNano == null ||\n BigInt(eventTime) < BigInt(this.#startTimeUnixNano)\n ? eventTime\n : this.#startTimeUnixNano;\n this.#endTimeUnixNano =\n this.#endTimeUnixNano == null ||\n BigInt(eventTime) > BigInt(this.#endTimeUnixNano)\n ? eventTime\n : this.#endTimeUnixNano;\n\n if (event._e === 'root:init') {\n if (typeof event.version === 'string') this.#version = event.version;\n if (this.#processName === '2g' && typeof event.version === 'string') {\n this.#processName = `2g (v${event.version})`;\n }\n return;\n }\n\n if (typeof event._d === 'number') {\n this.#spans.push(this.#createSpan(event));\n } else {\n this.#events.push(this.#createEvent(event));\n }\n }\n\n toFile(): OpenTelemetryFile {\n const startTimeUnixNano = this.#startTimeUnixNano ?? unixNano(Date.now());\n const endTimeUnixNano = this.#endTimeUnixNano ?? startTimeUnixNano;\n return {\n resourceSpans: [\n {\n resource: {\n attributes: attributes({\n 'service.name': this.#processName,\n 'service.version': this.#version,\n 'process.pid': this.options.pid,\n 'telemetry.sdk.name': '2g',\n 'telemetry.sdk.language': 'nodejs',\n }),\n },\n scopeSpans: [\n {\n scope: { name: '2g' },\n spans: [\n {\n traceId: this.#traceId,\n spanId: this.#sessionSpanId,\n name: this.#processName,\n startTimeUnixNano,\n endTimeUnixNano,\n attributes: attributes({\n 'event_log.kind': 'session',\n }),\n events: this.#events.length ? this.#events : undefined,\n },\n ...this.#spans,\n ],\n },\n ],\n },\n ],\n };\n }\n\n #createSpan(event: ParsedEvent): OpenTelemetrySpan {\n const parsed = splitEventName(event._e);\n const startTimeUnixNano = unixNano(event._t - event._d!);\n const endTimeUnixNano = unixNano(event._t);\n return {\n traceId: this.#traceId,\n spanId: createSpanId(),\n parentSpanId: this.#sessionSpanId,\n name: parsed ? stripSuffix(parsed.name) : event._e,\n startTimeUnixNano,\n endTimeUnixNano,\n attributes: eventAttributes(event, parsed),\n };\n }\n\n #createEvent(event: ParsedEvent): OpenTelemetrySpanEvent {\n const parsed = splitEventName(event._e);\n return {\n timeUnixNano: unixNano(event._t),\n name: parsed ? stripSuffix(parsed.name) : event._e,\n attributes: eventAttributes(event, parsed),\n };\n }\n}\n\nfunction eventAttributes(\n event: ParsedEvent,\n parsed: ReturnType<typeof splitEventName>\n) {\n const values: Record<string, unknown> = {\n 'event.name': event._e,\n };\n if (parsed) {\n values['event.category'] = parsed.category;\n values['event.action'] = parsed.name;\n }\n if (typeof event._w === 'string') values['event.worker.id'] = event._w;\n\n for (const key of Object.keys(event)) {\n if (\n key === '_e' ||\n key === '_t' ||\n key === '_d' ||\n key === '_l' ||\n key === '_w'\n )\n continue;\n values[`event_log.${key}`] = event[key];\n }\n\n return attributes(values);\n}\n\nfunction attributes(values: Record<string, unknown>): OpenTelemetryAttribute[] {\n const result: OpenTelemetryAttribute[] = [];\n for (const [key, value] of Object.entries(values)) {\n const converted = anyValue(value);\n if (converted) result.push({ key, value: converted });\n }\n return result;\n}\n\nfunction anyValue(value: unknown): OpenTelemetryAnyValue | null {\n if (typeof value === 'string') return { stringValue: value };\n if (typeof value === 'boolean') return { boolValue: value };\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) return null;\n return Number.isInteger(value)\n ? { intValue: String(value) }\n : { doubleValue: value };\n }\n if (Array.isArray(value)) {\n return {\n arrayValue: {\n values: value.flatMap(item => {\n const converted = anyValue(item);\n return converted ? [converted] : [];\n }),\n },\n };\n }\n if (value && typeof value === 'object') {\n return {\n kvlistValue: {\n values: attributes(value as Record<string, unknown>),\n },\n };\n }\n return null;\n}\n\nfunction createSpanId() {\n return crypto.randomBytes(8).toString('hex');\n}\n\nfunction unixNano(timeMs: number) {\n return String(BigInt(Math.round(timeMs * 1_000_000)));\n}\n\nfunction splitEventName(value: string) {\n const index = value.indexOf(':');\n if (index < 1) return null;\n return {\n category: value.slice(0, index),\n name: value.slice(index + 1),\n };\n}\n\nfunction stripSuffix(name: string) {\n for (const suffix of STRIP_SUFFIXES) {\n if (name.endsWith(suffix)) return name.slice(0, -suffix.length);\n }\n return name;\n}\n","import fs from 'node:fs';\nimport { parseArgs } from 'node:util';\n\nimport { resolveSession, tap } from '../../tap';\nimport type { ParsedEvent } from '../../types';\nimport { redirectConsoleToStderr } from '../../utils/redirectConsole';\nimport {\n filterEvents,\n formatSessionProcessName,\n parseHelp,\n parseDuration,\n parseSharedTapOptions,\n readJsonlFile,\n readJsonlStdin,\n tapArgOptions,\n warnOnRotationLoss,\n} from '../shared';\nimport { convertToChromeTrace } from './chromeTrace';\nimport { convertToOpenTelemetry } from './opentelemetry';\n\ntype ExportFormat = 'chrome-trace' | 'opentelemetry';\nconst DEFAULT_IDLE_TIMEOUT = 30_000;\n\nexport async function runExportCli(args: string[]) {\n if (parseHelp(args)) {\n printExportHelp();\n return;\n }\n const options = parseExportOptions(args);\n if (options.json) redirectConsoleToStderr();\n let events: AsyncIterable<ParsedEvent> | ParsedEvent[];\n let processName: string | undefined;\n let exportPid: number | undefined;\n\n if (options.selector) {\n const session = await resolveSession(options.selector);\n processName = formatSessionProcessName(session);\n exportPid = session.pid;\n await warnOnRotationLoss(session.sessionDir, '2g export --tail');\n events = tap(session.sessionDir, {\n follow: options.follow,\n debug: options.debug,\n timeout: options.timeout,\n idleTimeout: options.follow ? options.idleTimeout : undefined,\n });\n } else if (options.inputFile) {\n events = readJsonlFile(options.inputFile);\n } else {\n events = readJsonlStdin();\n }\n\n const filteredEvents = filterEvents(events, options);\n const file =\n options.format === 'opentelemetry'\n ? await convertToOpenTelemetry(filteredEvents, {\n pid: exportPid,\n processName,\n })\n : await convertToChromeTrace(filteredEvents, {\n pid: exportPid,\n processName,\n });\n const output = JSON.stringify(file, null, 2);\n if (options.output) fs.writeFileSync(options.output, `${output}\\n`);\n else process.stdout.write(`${output}\\n`);\n}\n\nfunction parseExportOptions(args: string[]) {\n const parsed = parseArgs({\n args,\n allowPositionals: true,\n options: {\n ...tapArgOptions,\n input: { type: 'string' },\n output: { type: 'string', short: 'o' },\n format: { type: 'string' },\n json: { type: 'boolean' },\n timeout: { type: 'string' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n const tapOptions = parseSharedTapOptions(parsed.values);\n const timeout = parseDuration(parsed.values.timeout);\n\n const format = parsed.values.format ?? 'chrome-trace';\n if (!isExportFormat(format)) throw new Error(`Unsupported format: ${format}`);\n if (parsed.positionals[0] && parsed.values.input)\n throw new Error('Use either a session selector or --input, not both');\n if (timeout != null && !tapOptions.follow)\n throw new Error('Use --timeout only with --tail');\n\n return {\n selector: parsed.positionals[0],\n inputFile: parsed.values.input,\n output: parsed.values.output,\n format,\n since: tapOptions.since,\n filter: tapOptions.filter,\n spans: tapOptions.spans,\n debug: tapOptions.debug,\n follow: tapOptions.follow,\n timeout,\n idleTimeout: DEFAULT_IDLE_TIMEOUT,\n json: parsed.values.json ?? false,\n };\n}\n\nfunction isExportFormat(value: string): value is ExportFormat {\n return value === 'chrome-trace' || value === 'opentelemetry';\n}\n\nfunction printExportHelp() {\n process.stdout.write(\n [\n 'Usage: 2g export [selector]',\n '',\n 'Exports session events to Chrome Trace or OTLP JSON.',\n '(Without --tail it reads only the retained window. Rotated out logs may be lost)',\n '',\n '--tail attaches to an already-running session and follows live from that point.',\n ' Run it after the session is up and leave it attached while the workload runs.',\n ' It will automatically stop on 30s idle.',\n 'To trace a full command instead, use `2g record`.',\n '',\n 'Options:',\n ' selector Substring of PID, CWD, or command; a running',\n ' session wins ties',\n ' --input <file> Read JSONL events from a file',\n ' -o, --output <file> Write output to a file',\n ' --format <format> chrome-trace or opentelemetry',\n ' --json Print JSON output',\n ' --since <time> Duration ago (5m, 90s), Unix time, or ISO date',\n ' --filter <pattern> Event name prefix (whole segments), e.g. category,',\n ' category:kind; * wildcards; comma-separated',\n ' --spans Keep only span events (log.span() pairs with a _d',\n ' duration); omit to include point events too. A',\n ' plain \"ms\" payload field is not a span',\n ' --debug Include debug events (only recorded when the',\n ' command ran with LOG_DEBUG set)',\n ' --tail Follow live events after replaying history; stops',\n ' automatically on 30s idle',\n ' --timeout <duration> Also stop tailing after this absolute duration',\n '',\n ].join('\\n')\n );\n}\n","import { parseArgs } from 'node:util';\n\nimport { listSessions } from '../../tap';\nimport { redirectConsoleToStderr } from '../../utils/redirectConsole';\n\nexport async function runPsCli(args: string[] = []) {\n const parsed = parseArgs({\n args,\n allowPositionals: true,\n options: {\n active: { type: 'boolean', short: 'a' },\n json: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n if (parsed.values.json) redirectConsoleToStderr();\n const sessions = (\n await listSessions({ selector: parsed.positionals[0] })\n ).filter(session => !parsed.values.active || session.alive);\n if (parsed.values.json) {\n process.stdout.write(`${JSON.stringify(sessions, null, 2)}\\n`);\n return;\n }\n\n process.stdout.write('PID\\tSTATUS\\tSTARTED\\tCOMMAND\\tCWD\\n');\n for (const session of sessions) {\n process.stdout.write(\n `${escapeTsv(session.pid)}\\t${escapeTsv(\n session.alive ? 'alive' : 'exited'\n )}\\t${escapeTsv(\n new Date(session.startedAt).toISOString()\n )}\\t${escapeTsv(session.command)}\\t${escapeTsv(session.cwd)}\\n`\n );\n }\n}\n\nfunction escapeTsv(value: unknown) {\n return String(value)\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\\t/g, '\\\\t')\n .replace(/\\r/g, '\\\\r')\n .replace(/\\n/g, '\\\\n');\n}\n\nexport function printPsHelp() {\n process.stdout.write(\n [\n 'Usage: 2g ps [selector]',\n '',\n 'Lists recorded sessions, newest first; alive means still running.',\n '',\n 'Options:',\n ' selector Substring of PID, CWD, or command',\n ' --active, -a Show only active sessions',\n ' --json Print sessions as JSON',\n '',\n ].join('\\n')\n );\n}\n","import { spawn } from 'node:child_process';\nimport fs from 'node:fs';\nimport { parseArgs } from 'node:util';\n\nimport { captureEvents } from '../../capture';\nimport { redirectConsoleToStderr } from '../../utils/redirectConsole';\nimport { filterEvents, parseHelp } from '../shared';\nimport { convertToChromeTrace } from '../export/chromeTrace';\nimport { convertToOpenTelemetry } from '../export/opentelemetry';\n\ntype ExportFormat = 'chrome-trace' | 'opentelemetry';\n\n// `record` owns the process it traces: it spawns <command> with event capture\n// wired in, follows its events end-to-end, and writes the trace when it exits.\n// This is the reliable path for a one-off run — there is no window to attach\n// within and nothing to rotate out, so it never returns a partial trace.\nexport async function runRecordCli(args: string[]) {\n if (parseHelp(args)) {\n printRecordHelp();\n return;\n }\n\n // Everything after `--` is the command and its own arguments, verbatim\n const separator = args.indexOf('--');\n const ownArgs = separator === -1 ? args : args.slice(0, separator);\n const command = separator === -1 ? [] : args.slice(separator + 1);\n const options = parseRecordOptions(ownArgs);\n if (!command.length)\n throw new Error(\n 'record needs a command to run: 2g record [options] -- <command> [args...]'\n );\n\n if (options.json) redirectConsoleToStderr();\n\n const capture = captureEvents({\n debug: options.debug,\n filter: options.filter,\n });\n // The trace lands on stdout when there is no -o, so route the child's stdout\n // to stderr to keep it clean; with -o the child can use stdout normally.\n const child = spawn(\n command[0],\n command.slice(1),\n capture.spawnOptions({\n env: process.env,\n stdio: ['inherit', options.output ? 'inherit' : 2, 'inherit'],\n })\n );\n capture.attach(child);\n\n const exited = new Promise<number>((resolve, reject) => {\n child.on('exit', code => resolve(code ?? 0));\n child.on('error', error =>\n reject(new Error(`Failed to run ${command[0]}: ${error.message}`))\n );\n });\n\n const meta = { pid: child.pid, processName: command.join(' ') };\n const filtered = filterEvents(capture, options);\n // Draining the events resolves once the child closes its event pipe (on exit)\n const file =\n options.format === 'opentelemetry'\n ? await convertToOpenTelemetry(filtered, meta)\n : await convertToChromeTrace(filtered, meta);\n const exitCode = await exited;\n\n const output = JSON.stringify(file, null, 2);\n if (options.output) fs.writeFileSync(options.output, `${output}\\n`);\n else process.stdout.write(`${output}\\n`);\n\n if (exitCode) process.exitCode = exitCode;\n}\n\nfunction parseRecordOptions(args: string[]) {\n const parsed = parseArgs({\n args,\n allowPositionals: true,\n options: {\n filter: { type: 'string', multiple: true },\n spans: { type: 'boolean' },\n debug: { type: 'boolean' },\n output: { type: 'string', short: 'o' },\n format: { type: 'string' },\n json: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n\n const format = parsed.values.format ?? 'chrome-trace';\n if (!isExportFormat(format)) throw new Error(`Unsupported format: ${format}`);\n\n return {\n output: parsed.values.output,\n format,\n filter: parsed.values.filter\n ?.flatMap(value => value.split(','))\n .map(item => item.trim())\n .filter(Boolean),\n spans: parsed.values.spans === true,\n debug: parsed.values.debug === true,\n json: parsed.values.json ?? false,\n };\n}\n\nfunction isExportFormat(value: string): value is ExportFormat {\n return value === 'chrome-trace' || value === 'opentelemetry';\n}\n\nfunction printRecordHelp() {\n process.stdout.write(\n [\n 'Usage: 2g record [options] -- <command> [args...]',\n '',\n 'Runs <command>, traces the events it emits, and writes the trace on exit.',\n '',\n 'This is the reliable way to capture a one-off run (a build, a script): 2g',\n 'owns the process, so the trace is complete end-to-end with no window to',\n 'attach within and nothing to rotate out. To trace an already-running server',\n 'instead, use `2g export <selector> --tail`.',\n '',\n 'Options:',\n ' -o, --output <file> Write the trace to a file (default: stdout)',\n ' --format <format> chrome-trace or opentelemetry',\n ' --json Print JSON output',\n ' --filter <pattern> Event name prefix (whole segments), e.g. category,',\n ' category:kind; * wildcards; comma-separated',\n ' --spans Keep only span events (log.span() pairs with a _d',\n ' duration); omit to include point events too',\n ' --debug Enable and export debug events; no LOG_DEBUG needed',\n '',\n 'Example:',\n ' 2g record -o trace.json -- expo export # run & trace a build end-to-end',\n '',\n ].join('\\n')\n );\n}\n","import { parseArgs } from 'node:util';\n\nimport { resolveSession, tap } from '../../tap';\nimport { redirectConsoleToStderr } from '../../utils/redirectConsole';\nimport { formatPrettyEvent, shouldColorizeStream } from '../../utils/pretty';\nimport {\n parseHelp,\n parseSharedTapOptions,\n tapArgOptions,\n warnOnRotationLoss,\n} from '../shared';\n\nexport async function runTapCli(args: string[]) {\n if (parseHelp(args)) {\n printTapHelp();\n return;\n }\n const options = parseTapOptions(args);\n if (options.json) redirectConsoleToStderr();\n const session = await resolveSession(options.selector);\n await warnOnRotationLoss(session.sessionDir, '2g tap --tail');\n const colorizePretty = shouldColorizeStream(process.stdout);\n for await (const event of tap(session.sessionDir, options)) {\n if (options.pretty) {\n process.stdout.write(\n `${formatPrettyEvent(event, {\n colorize: colorizePretty,\n stream: process.stdout,\n })}\\n`\n );\n } else {\n process.stdout.write(`${JSON.stringify(event)}\\n`);\n }\n }\n}\n\nfunction parseTapOptions(args: string[]) {\n const parsed = parseArgs({\n args,\n allowPositionals: true,\n options: {\n ...tapArgOptions,\n format: { type: 'string' },\n json: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n const tapOptions = parseSharedTapOptions(parsed.values);\n if (parsed.values.json && parsed.values.format === 'pretty')\n throw new Error('Use either --json or --format pretty, not both');\n\n return {\n selector: parsed.positionals[0],\n since: tapOptions.since,\n follow: tapOptions.follow,\n filter: tapOptions.filter,\n spans: tapOptions.spans,\n debug: tapOptions.debug,\n json: parsed.values.json ?? false,\n pretty: parsed.values.json ? false : parsed.values.format === 'pretty',\n };\n}\n\nfunction printTapHelp() {\n process.stdout.write(\n [\n 'Usage: 2g tap [selector]',\n '',\n 'Replays retained session history as JSONL, oldest first.',\n '',\n 'Options:',\n ' selector Substring of PID, CWD, or command; a running',\n ' session wins ties',\n ' --since <time> Duration ago (5m, 90s), Unix time, or ISO date',\n ' --filter <pattern> Event name prefix (whole segments), e.g. category,',\n ' category:kind; * wildcards; comma-separated',\n ' --spans Keep only span events (log.span() pairs with a _d',\n ' duration); omit to include point events too. A',\n ' plain \"ms\" payload field is not a span',\n ' --debug Include debug events (only recorded when the',\n ' command ran with LOG_DEBUG set)',\n ' --format pretty Print a readable line per event',\n ' --tail Follow live events after replaying history; runs',\n ' until killed (use export with a timeout for a',\n ' bounded follow)',\n '',\n ].join('\\n')\n );\n}\n","#!/usr/bin/env node\nimport { fileURLToPath } from 'node:url';\n\nimport { printCleanHelp, runCleanCli } from './commands/clean';\nimport { runExportCli } from './commands/export';\nimport { printPsHelp, runPsCli } from './commands/ps';\nimport { runRecordCli } from './commands/record';\nimport { runTapCli } from './commands/tap';\nimport { parseHelp } from './commands/shared';\n\nexport async function main(argv = process.argv.slice(2)) {\n const [command, ...args] = argv;\n\n if (\n !command ||\n command === '--help' ||\n command === '-h' ||\n command === 'help'\n ) {\n printHelp();\n return 0;\n }\n\n switch (command) {\n case 'typegen': {\n const { runTypegenCli } = await import('./commands/typegen');\n runTypegenCli(args);\n return 0;\n }\n case 'ps':\n if (parseHelp(args)) {\n printPsHelp();\n return 0;\n }\n await runPsCli(args);\n return 0;\n case 'tap':\n await runTapCli(args);\n return 0;\n case 'clean':\n if (parseHelp(args)) {\n printCleanHelp();\n return 0;\n }\n runCleanCli(args);\n return 0;\n case 'record':\n await runRecordCli(args);\n return 0;\n case 'export':\n await runExportCli(args);\n return 0;\n default:\n throw new Error(`Unknown command: ${command}`);\n }\n}\n\nfunction printHelp() {\n process.stdout.write(\n [\n 'Usage: 2g <command>',\n '',\n 'Reads structured JSONL event logs that instrumented CLIs record during runs',\n 'into the system temp dir, with no setup: run a command, then tap it here.',\n '',\n 'Commands:',\n ' ps [selector] List recorded sessions',\n ' --active, -a (running only) --json',\n '',\n ' tap [selector] Replay session events as JSONL, oldest first',\n ' --since <time> --filter <pattern> --spans --debug --format pretty',\n ' --tail (follow live events after replay; runs until killed)',\n '',\n ' record -- <command> Run a command, trace it end-to-end, write on exit',\n ' -o, --output <file> --format chrome-trace|opentelemetry --json',\n ' --filter <pattern> --spans --debug',\n '',\n ' export [selector] Export a past or live (--tail) session',\n ' --input <jsonl-file> -o, --output <file> --json',\n ' --format chrome-trace|opentelemetry',\n ' --since <time> --filter <pattern> --spans --debug',\n ' --tail --timeout <duration> (absolute; tail also stops after 30s idle)',\n '',\n ' typegen List every event name/payload a project can emit',\n ' -p, --project <tsconfig> -o, --output <file> --format dts|json --json',\n '',\n ' clean Remove stale sessions',\n ' --all, -a (remove all exited sessions) --json',\n '',\n 'Typical use:',\n ' 2g ps -a # what is running now?',\n ' 2g tap \"expo start\" --tail # follow live events',\n ' 2g tap \"expo start\" --since 5m --format pretty # recent history, readable',\n ' 2g tap \"expo start\" --filter metro:bundling # narrow to one area',\n '',\n 'Trace a run to a flame chart:',\n ' 2g record -o trace.json -- expo export # run & trace a build',\n ' 2g export \"expo start\" --tail -o trace.json # attach to a running server',\n ' 2g export \"expo start\" -o trace.json # after the fact (partial)',\n '',\n 'Selectors match sessions by substring of PID, CWD, or command. If several',\n 'match, and exactly one of them is running, it is chosen; otherwise 2g errors',\n 'and lists the candidates.',\n '',\n '--filter takes comma-separated event-name prefixes matched on whole',\n 'segments: \"category\" and \"category:kind\" both match \"category:kind:test\";',\n '* matches anything. Discover names by tapping unfiltered or via typegen.',\n '',\n '--since accepts a duration ago (5m, 90s, 1h30m), Unix time, or ISO date.',\n '--spans keeps only span events (log.span() pairs with a \"_d\" duration in',\n 'ms); without it, point events are included alongside spans.',\n '',\n 'Events are single JSON lines: {\"_e\":\"category:kind\",\"_t\":<epoch ms>,...}.',\n '\"_d\" is a span duration, \"_w\" a worker id; debug events need --debug.',\n '',\n 'Set LOG_EVENTS=<file|fd> on an instrumented command to redirect its events.',\n 'Debug events are only recorded when the command runs with LOG_DEBUG set.',\n '',\n 'Pass LOG_DEBUG=<filter> when debugging; it also mirrors matching events to',\n 'stderr. Reading them back needs --debug.',\n '',\n 'Run 2g <command> --help for per-command help.',\n '',\n ].join('\\n')\n );\n}\n\nif (isCliEntrypoint()) {\n main()\n .then(code => {\n process.exitCode = code;\n })\n .catch(error => {\n process.stderr.write(\n `${error instanceof Error ? error.message : String(error)}\\n`\n );\n process.exitCode = 1;\n });\n}\n\nfunction isCliEntrypoint() {\n try {\n return process.argv[1] === fileURLToPath(import.meta.url);\n } catch {\n return false;\n }\n}\n"],"names":["runCleanCli","args","options","parseCleanOptions","parsed","parseArgs","all","type","short","json","help","values","redirectConsoleToStderr","removed","cleanExitedSessionsSync","cleanStaleSessionsSync","process","stdout","write","JSON","stringify","tapArgOptions","since","filter","multiple","spans","debug","tail","async","warnOnRotationLoss","sessionDir","remedy","detectRotationLoss","console","warn","readJsonlStream","stream","rl","createInterface","input","line","event","parseEventLine","filterEvents","events","eventFilter","compileEventFilter","parseSince","matchesTapOptions","parseSharedTapOptions","flatMap","value","split","map","item","trim","Boolean","follow","parseHelp","allowPositionals","strict","STRIP_SUFFIXES","convertToChromeTrace","converter","TraceConverter","add","toTraceFile","pending","tracks","Map","pid","processName","version","constructor","this","_e","splitEventName","index","indexOf","category","name","slice","track","getTrack","_w","undefined","extractArgs","key","Object","keys","startsWith","length","_d","push","kind","stripSuffix","cat","ts","Math","round","_t","dur","lane","base","Infinity","traceEvents","ph","tids","nextTid","displayName","laneCount","max","assignLanes","tid","set","sort_index","get","s","metadata","source","convertedAt","Date","toISOString","startTime","startTimestampMs","worker","has","order","sort","a","b","lanes","span","end","stack","pop","top","suffix","endsWith","convertToOpenTelemetry","OpenTelemetryConverter","toFile","traceId","crypto","randomBytes","toString","sessionSpanId","createSpanId","startTimeUnixNano","endTimeUnixNano","eventTime","unixNano","BigInt","createSpan","createEvent","now","resourceSpans","resource","attributes","scopeSpans","scope","spanId","parentSpanId","eventAttributes","timeUnixNano","result","entries","converted","anyValue","stringValue","boolValue","Number","isFinite","isInteger","intValue","String","doubleValue","Array","isArray","arrayValue","kvlistValue","timeMs","runExportCli","printExportHelp","join","parseExportOptions","output","format","timeout","tapOptions","parseDuration","duration","parseDurationValue","Error","isExportFormat","positionals","selector","inputFile","idleTimeout","exportPid","session","resolveSession","formatSessionProcessName","command","tap","readJsonlFile","file","fs","createReadStream","encoding","readJsonlStdin","stdin","filteredEvents","writeFileSync","escapeTsv","replace","runRecordCli","printRecordHelp","separator","ownArgs","parseRecordOptions","capture","captureEvents","child","spawn","spawnOptions","env","stdio","attach","exited","Promise","resolve","reject","on","code","error","message","meta","filtered","exitCode","runTapCli","printTapHelp","parseTapOptions","pretty","colorizePretty","shouldColorizeStream","formatPrettyEvent","colorize","main","argv","printHelp","runTypegenCli","then","require","printPsHelp","runPsCli","active","sessions","listSessions","alive","startedAt","cwd","printCleanHelp","isCliEntrypoint","fileURLToPath","import","catch","stderr"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli-chunk.js","sources":["../../src/commands/clean/index.ts","../../src/commands/shared.ts","../../src/commands/export/chromeTrace.ts","../../src/commands/export/opentelemetry.ts","../../src/commands/export/index.ts","../../src/commands/ps/index.ts","../../src/commands/record/index.ts","../../src/commands/tap/index.ts","../../src/cli.ts"],"sourcesContent":["import { parseArgs } from 'node:util';\n\nimport { cleanExitedSessionsSync, cleanStaleSessionsSync } from '../../clean';\nimport { redirectConsoleToStderr } from '../../utils/redirectConsole';\n\nexport function runCleanCli(args: string[] = []) {\n const options = parseCleanOptions(args);\n if (options.json) redirectConsoleToStderr();\n const removed = options.all\n ? cleanExitedSessionsSync()\n : cleanStaleSessionsSync();\n process.stdout.write(\n options.json\n ? `${JSON.stringify({ removed })}\\n`\n : `Removed ${removed} ${options.all ? 'exited' : 'stale'} sessions.\\n`\n );\n}\n\nfunction parseCleanOptions(args: string[]) {\n const parsed = parseArgs({\n args,\n options: {\n all: { type: 'boolean', short: 'a' },\n json: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n return {\n all: parsed.values.all === true,\n json: parsed.values.json === true,\n };\n}\n\nexport function printCleanHelp() {\n process.stdout.write(\n [\n 'Usage: 2g clean',\n '',\n 'Removes stale exited sessions past the retention window.',\n '',\n 'Options:',\n ' --all, -a Remove all exited sessions',\n ' --json',\n '',\n ].join('\\n')\n );\n}\n","import fs from 'node:fs';\nimport { createInterface } from 'node:readline';\nimport type { Readable } from 'node:stream';\nimport { parseArgs } from 'node:util';\n\nimport { detectRotationLoss, type ListedSession } from '../tap';\nimport {\n compileEventFilter,\n matchesTapOptions,\n parseEventLine,\n parseSince,\n parseDuration as parseDurationValue,\n} from '../utils/eventFilter';\nimport type { ParsedEvent } from '../types';\n\nexport const tapArgOptions = {\n since: { type: 'string' },\n filter: { type: 'string', multiple: true },\n spans: { type: 'boolean' },\n debug: { type: 'boolean' },\n tail: { type: 'boolean' },\n} as const;\n\nexport interface SharedTapOptions {\n since?: string;\n filter?: string[];\n spans?: boolean;\n debug?: boolean;\n follow: boolean;\n}\n\n// Warns (via console.warn → stderr, so it never pollutes the JSON/JSONL on\n// stdout, and stays mockable in tests) when segment rotation has already\n// dropped the start of the run from the retained window.\nexport async function warnOnRotationLoss(sessionDir: string, remedy: string) {\n if (!(await detectRotationLoss(sessionDir))) return;\n console.warn(\n `⚠ Earlier events were rotated out of the retained window.\\n` +\n ` For a complete trace, start \\`${remedy}\\` before the workload.`\n );\n}\n\nexport function formatSessionProcessName(session: ListedSession) {\n return session.version\n ? `${session.command} (v${session.version}, PID ${session.pid})`\n : `${session.command} (PID ${session.pid})`;\n}\n\nexport async function* readJsonlFile(file: string) {\n yield* readJsonlStream(fs.createReadStream(file, { encoding: 'utf8' }));\n}\n\nexport async function* readJsonlStdin() {\n yield* readJsonlStream(process.stdin);\n}\n\nexport async function* readJsonlStream(stream: Readable) {\n const rl = createInterface({ input: stream });\n for await (const line of rl) {\n if (!line) continue;\n // Lossless parse; the debug decision belongs to filterEvents\n const event = parseEventLine(line, { debug: true });\n if (event) yield event;\n }\n}\n\nexport async function* filterEvents(\n events: AsyncIterable<ParsedEvent> | Iterable<ParsedEvent>,\n options: Pick<SharedTapOptions, 'since' | 'filter' | 'spans' | 'debug'>\n) {\n const eventFilter = compileEventFilter(options.filter);\n const since = parseSince(options.since);\n for await (const event of events) {\n if (\n matchesTapOptions(\n event,\n {\n filter: options.filter,\n since,\n spans: options.spans,\n debug: options.debug,\n },\n eventFilter\n )\n )\n yield event;\n }\n}\n\nexport function parseSharedTapOptions(values: {\n since?: string;\n filter?: string[];\n spans?: boolean;\n debug?: boolean;\n tail?: boolean;\n}): SharedTapOptions {\n return {\n since: values.since,\n filter: values.filter\n ?.flatMap(value => value.split(','))\n .map(item => item.trim())\n .filter(Boolean),\n spans: values.spans === true,\n debug: values.debug === true,\n follow: values.tail === true,\n };\n}\n\nexport function parseHelp(args: string[]) {\n return (\n parseArgs({\n args,\n allowPositionals: true,\n strict: false,\n options: {\n help: { type: 'boolean', short: 'h' },\n },\n }).values.help === true\n );\n}\n\nexport function parseJsonFlag(args: string[]) {\n return parseArgs({\n args,\n allowPositionals: true,\n options: {\n json: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n },\n }).values;\n}\n\nexport function parseDuration(value?: string) {\n if (value == null || value === '') return undefined;\n const duration = parseDurationValue(value);\n if (duration == null) throw new Error(`Invalid duration: ${value}`);\n return duration;\n}\n","import type { ParsedEvent } from '../../types';\n\nexport interface ConvertToChromeTraceOptions {\n processName?: string;\n pid?: number;\n}\n\nexport interface TraceFile {\n traceEvents: TraceEvent[];\n metadata: {\n source: '2g';\n version: string;\n convertedAt: string;\n startTime: string;\n startTimestampMs: number;\n };\n}\n\nexport type TraceEvent = TraceComplete | TraceInstant | TraceMetadata;\n\nexport interface TraceComplete {\n ph: 'X';\n name: string;\n cat: string;\n pid: number;\n tid: number;\n ts: number;\n dur: number;\n args?: Record<string, unknown>;\n}\n\nexport interface TraceInstant {\n ph: 'i';\n name: string;\n cat: string;\n pid: number;\n tid: number;\n ts: number;\n s: 'g' | 'p' | 't';\n args?: Record<string, unknown>;\n}\n\nexport interface TraceMetadata {\n ph: 'M';\n name: 'process_name' | 'thread_name' | 'thread_sort_index';\n pid: number;\n tid?: number;\n args: Record<string, unknown>;\n}\n\nconst STRIP_SUFFIXES = [':started', ':done', ':failed'];\n\nexport async function convertToChromeTrace(\n events: Iterable<ParsedEvent> | AsyncIterable<ParsedEvent>,\n options: ConvertToChromeTraceOptions = {}\n): Promise<TraceFile> {\n const converter = new TraceConverter(options);\n for await (const event of events) {\n converter.add(event);\n }\n return converter.toTraceFile();\n}\n\ninterface PendingSpan {\n track: string;\n name: string;\n cat: string;\n ts: number;\n dur: number;\n args?: Record<string, unknown>;\n lane: number;\n}\n\ninterface PendingInstant {\n track: string;\n name: string;\n cat: string;\n ts: number;\n args?: Record<string, unknown>;\n}\n\ntype PendingEvent =\n | ({ kind: 'span' } & PendingSpan)\n | ({ kind: 'instant' } & PendingInstant);\n\nexport class TraceConverter {\n #pending: PendingEvent[] = [];\n #tracks = new Map<string, string>();\n #pid: number;\n #processName: string;\n #version = '0.1.0';\n\n constructor(options: ConvertToChromeTraceOptions = {}) {\n this.#pid = options.pid ?? 1;\n this.#processName = options.processName ?? '2g';\n }\n\n add(event: ParsedEvent) {\n if (event._e === 'root:init') {\n if (typeof event.version === 'string') {\n this.#version = event.version;\n if (this.#processName === '2g') {\n this.#processName = `2g (v${event.version})`;\n }\n }\n return;\n }\n\n const parsed = splitEventName(event._e);\n const track = this.#getTrack(\n parsed.category,\n typeof event._w === 'string' ? event._w : undefined\n );\n const args = extractArgs(event);\n\n if (typeof event._d === 'number') {\n this.#pending.push({\n kind: 'span',\n track,\n name: stripSuffix(parsed.name),\n cat: parsed.category,\n ts: Math.round((event._t - event._d) * 1000),\n dur: Math.round(event._d * 1000),\n args,\n lane: 0,\n });\n } else {\n this.#pending.push({\n kind: 'instant',\n track,\n name: stripSuffix(parsed.name),\n cat: parsed.category,\n ts: Math.round(event._t * 1000),\n args,\n });\n }\n }\n\n toTraceFile(): TraceFile {\n let base = this.#pending.length ? Infinity : 0;\n for (const event of this.#pending) {\n if (event.ts < base) base = event.ts;\n }\n const traceEvents: TraceEvent[] = [\n {\n ph: 'M',\n name: 'process_name',\n pid: this.#pid,\n args: { name: this.#processName },\n },\n ];\n\n const tids = new Map<string, number>();\n let nextTid = 1;\n for (const [track, displayName] of this.#tracks) {\n const spans: PendingSpan[] = [];\n for (const event of this.#pending) {\n if (event.kind === 'span' && event.track === track) spans.push(event);\n }\n const laneCount = Math.max(assignLanes(spans), 1);\n for (let lane = 0; lane < laneCount; lane++) {\n const tid = nextTid++;\n tids.set(`${track}\\0${lane}`, tid);\n traceEvents.push(\n {\n ph: 'M',\n name: 'thread_name',\n pid: this.#pid,\n tid,\n args: {\n name: lane === 0 ? displayName : `${displayName} #${lane + 1}`,\n },\n },\n {\n ph: 'M',\n name: 'thread_sort_index',\n pid: this.#pid,\n tid,\n args: { sort_index: tid },\n }\n );\n }\n }\n\n for (const event of this.#pending) {\n const lane = event.kind === 'span' ? event.lane : 0;\n const tid = tids.get(`${event.track}\\0${lane}`)!;\n if (event.kind === 'span') {\n traceEvents.push({\n ph: 'X',\n name: event.name,\n cat: event.cat,\n pid: this.#pid,\n tid,\n ts: event.ts - base,\n dur: event.dur,\n args: event.args,\n });\n } else {\n traceEvents.push({\n ph: 'i',\n name: event.name,\n cat: event.cat,\n pid: this.#pid,\n tid,\n ts: event.ts - base,\n s: 't',\n args: event.args,\n });\n }\n }\n\n return {\n traceEvents,\n metadata: {\n source: '2g',\n version: this.#version,\n convertedAt: new Date().toISOString(),\n startTime: new Date(base / 1000).toISOString(),\n startTimestampMs: base / 1000,\n },\n };\n }\n\n #getTrack(category: string, worker?: string) {\n const key = worker ? `${category}:${worker}` : category;\n if (!this.#tracks.has(key)) {\n this.#tracks.set(key, worker ? `${category} ${worker}` : category);\n }\n return key;\n }\n}\n\n// 'X' events on one tid nest by containment; partial overlap is invalid.\nfunction assignLanes(spans: PendingSpan[]) {\n const order = [...spans].sort(\n (a, b) => a.ts - b.ts || b.ts + b.dur - (a.ts + a.dur)\n );\n const lanes: PendingSpan[][] = [];\n for (const span of order) {\n const end = span.ts + span.dur;\n let lane = -1;\n for (let index = 0; index < lanes.length; index++) {\n const stack = lanes[index];\n while (\n stack.length &&\n stack[stack.length - 1].ts + stack[stack.length - 1].dur <= span.ts\n ) {\n stack.pop();\n }\n const top = stack[stack.length - 1];\n if (!top || top.ts + top.dur >= end) {\n stack.push(span);\n lane = index;\n break;\n }\n }\n if (lane < 0) {\n lanes.push([span]);\n lane = lanes.length - 1;\n }\n span.lane = lane;\n }\n return lanes.length;\n}\n\nfunction splitEventName(value: string) {\n const index = value.indexOf(':');\n if (index < 1) return { category: 'uncategorized', name: value };\n return {\n category: value.slice(0, index),\n name: value.slice(index + 1),\n };\n}\n\nfunction stripSuffix(name: string) {\n for (const suffix of STRIP_SUFFIXES) {\n if (name.endsWith(suffix)) return name.slice(0, -suffix.length);\n }\n return name;\n}\n\nfunction extractArgs(event: ParsedEvent) {\n const args: Record<string, unknown> = {};\n for (const key of Object.keys(event)) {\n if (key.startsWith('_')) continue;\n args[key] = event[key];\n }\n return Object.keys(args).length ? args : undefined;\n}\n","import crypto from 'node:crypto';\n\nimport type { ParsedEvent } from '../../types';\n\nexport interface ConvertToOpenTelemetryOptions {\n processName?: string;\n pid?: number;\n}\n\nexport interface OpenTelemetryFile {\n resourceSpans: OpenTelemetryResourceSpan[];\n}\n\ninterface OpenTelemetryResourceSpan {\n resource: {\n attributes: OpenTelemetryAttribute[];\n };\n scopeSpans: Array<{\n scope: {\n name: string;\n };\n spans: OpenTelemetrySpan[];\n }>;\n}\n\ninterface OpenTelemetrySpan {\n traceId: string;\n spanId: string;\n parentSpanId?: string;\n name: string;\n startTimeUnixNano: string;\n endTimeUnixNano: string;\n attributes?: OpenTelemetryAttribute[];\n events?: OpenTelemetrySpanEvent[];\n}\n\ninterface OpenTelemetrySpanEvent {\n timeUnixNano: string;\n name: string;\n attributes?: OpenTelemetryAttribute[];\n}\n\ninterface OpenTelemetryAttribute {\n key: string;\n value: OpenTelemetryAnyValue;\n}\n\ntype OpenTelemetryAnyValue =\n | { stringValue: string }\n | { intValue: string }\n | { doubleValue: number }\n | { boolValue: boolean }\n | { arrayValue: { values: OpenTelemetryAnyValue[] } }\n | { kvlistValue: { values: OpenTelemetryAttribute[] } };\n\nconst STRIP_SUFFIXES = [':started', ':done', ':failed'];\n\nexport async function convertToOpenTelemetry(\n events: Iterable<ParsedEvent> | AsyncIterable<ParsedEvent>,\n options: ConvertToOpenTelemetryOptions = {}\n): Promise<OpenTelemetryFile> {\n const converter = new OpenTelemetryConverter(options);\n for await (const event of events) {\n converter.add(event);\n }\n return converter.toFile();\n}\n\nclass OpenTelemetryConverter {\n readonly #traceId = crypto.randomBytes(16).toString('hex');\n readonly #sessionSpanId = createSpanId();\n readonly #spans: OpenTelemetrySpan[] = [];\n readonly #events: OpenTelemetrySpanEvent[] = [];\n #processName: string;\n #version = '0.1.0';\n #startTimeUnixNano: string | undefined;\n #endTimeUnixNano: string | undefined;\n\n constructor(private readonly options: ConvertToOpenTelemetryOptions) {\n this.#processName = options.processName ?? '2g';\n }\n\n add(event: ParsedEvent) {\n const eventTime = unixNano(event._t);\n this.#startTimeUnixNano =\n this.#startTimeUnixNano == null ||\n BigInt(eventTime) < BigInt(this.#startTimeUnixNano)\n ? eventTime\n : this.#startTimeUnixNano;\n this.#endTimeUnixNano =\n this.#endTimeUnixNano == null ||\n BigInt(eventTime) > BigInt(this.#endTimeUnixNano)\n ? eventTime\n : this.#endTimeUnixNano;\n\n if (event._e === 'root:init') {\n if (typeof event.version === 'string') this.#version = event.version;\n if (this.#processName === '2g' && typeof event.version === 'string') {\n this.#processName = `2g (v${event.version})`;\n }\n return;\n }\n\n if (typeof event._d === 'number') {\n this.#spans.push(this.#createSpan(event));\n } else {\n this.#events.push(this.#createEvent(event));\n }\n }\n\n toFile(): OpenTelemetryFile {\n const startTimeUnixNano = this.#startTimeUnixNano ?? unixNano(Date.now());\n const endTimeUnixNano = this.#endTimeUnixNano ?? startTimeUnixNano;\n return {\n resourceSpans: [\n {\n resource: {\n attributes: attributes({\n 'service.name': this.#processName,\n 'service.version': this.#version,\n 'process.pid': this.options.pid,\n 'telemetry.sdk.name': '2g',\n 'telemetry.sdk.language': 'nodejs',\n }),\n },\n scopeSpans: [\n {\n scope: { name: '2g' },\n spans: [\n {\n traceId: this.#traceId,\n spanId: this.#sessionSpanId,\n name: this.#processName,\n startTimeUnixNano,\n endTimeUnixNano,\n attributes: attributes({\n 'event_log.kind': 'session',\n }),\n events: this.#events.length ? this.#events : undefined,\n },\n ...this.#spans,\n ],\n },\n ],\n },\n ],\n };\n }\n\n #createSpan(event: ParsedEvent): OpenTelemetrySpan {\n const parsed = splitEventName(event._e);\n const startTimeUnixNano = unixNano(event._t - event._d!);\n const endTimeUnixNano = unixNano(event._t);\n return {\n traceId: this.#traceId,\n spanId: createSpanId(),\n parentSpanId: this.#sessionSpanId,\n name: parsed ? stripSuffix(parsed.name) : event._e,\n startTimeUnixNano,\n endTimeUnixNano,\n attributes: eventAttributes(event, parsed),\n };\n }\n\n #createEvent(event: ParsedEvent): OpenTelemetrySpanEvent {\n const parsed = splitEventName(event._e);\n return {\n timeUnixNano: unixNano(event._t),\n name: parsed ? stripSuffix(parsed.name) : event._e,\n attributes: eventAttributes(event, parsed),\n };\n }\n}\n\nfunction eventAttributes(\n event: ParsedEvent,\n parsed: ReturnType<typeof splitEventName>\n) {\n const values: Record<string, unknown> = {\n 'event.name': event._e,\n };\n if (parsed) {\n values['event.category'] = parsed.category;\n values['event.action'] = parsed.name;\n }\n if (typeof event._w === 'string') values['event.worker.id'] = event._w;\n\n for (const key of Object.keys(event)) {\n if (\n key === '_e' ||\n key === '_t' ||\n key === '_d' ||\n key === '_l' ||\n key === '_w'\n )\n continue;\n values[`event_log.${key}`] = event[key];\n }\n\n return attributes(values);\n}\n\nfunction attributes(values: Record<string, unknown>): OpenTelemetryAttribute[] {\n const result: OpenTelemetryAttribute[] = [];\n for (const [key, value] of Object.entries(values)) {\n const converted = anyValue(value);\n if (converted) result.push({ key, value: converted });\n }\n return result;\n}\n\nfunction anyValue(value: unknown): OpenTelemetryAnyValue | null {\n if (typeof value === 'string') return { stringValue: value };\n if (typeof value === 'boolean') return { boolValue: value };\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) return null;\n return Number.isInteger(value)\n ? { intValue: String(value) }\n : { doubleValue: value };\n }\n if (Array.isArray(value)) {\n return {\n arrayValue: {\n values: value.flatMap(item => {\n const converted = anyValue(item);\n return converted ? [converted] : [];\n }),\n },\n };\n }\n if (value && typeof value === 'object') {\n return {\n kvlistValue: {\n values: attributes(value as Record<string, unknown>),\n },\n };\n }\n return null;\n}\n\nfunction createSpanId() {\n return crypto.randomBytes(8).toString('hex');\n}\n\nfunction unixNano(timeMs: number) {\n return String(BigInt(Math.round(timeMs * 1_000_000)));\n}\n\nfunction splitEventName(value: string) {\n const index = value.indexOf(':');\n if (index < 1) return null;\n return {\n category: value.slice(0, index),\n name: value.slice(index + 1),\n };\n}\n\nfunction stripSuffix(name: string) {\n for (const suffix of STRIP_SUFFIXES) {\n if (name.endsWith(suffix)) return name.slice(0, -suffix.length);\n }\n return name;\n}\n","import fs from 'node:fs';\nimport { parseArgs } from 'node:util';\n\nimport { resolveSession, tap } from '../../tap';\nimport type { ParsedEvent } from '../../types';\nimport { redirectConsoleToStderr } from '../../utils/redirectConsole';\nimport {\n filterEvents,\n formatSessionProcessName,\n parseHelp,\n parseDuration,\n parseSharedTapOptions,\n readJsonlFile,\n readJsonlStdin,\n tapArgOptions,\n warnOnRotationLoss,\n} from '../shared';\nimport { convertToChromeTrace } from './chromeTrace';\nimport { convertToOpenTelemetry } from './opentelemetry';\n\ntype ExportFormat = 'chrome-trace' | 'opentelemetry';\nconst DEFAULT_IDLE_TIMEOUT = 30_000;\n\nexport async function runExportCli(args: string[]) {\n if (parseHelp(args)) {\n printExportHelp();\n return;\n }\n const options = parseExportOptions(args);\n if (options.json) redirectConsoleToStderr();\n let events: AsyncIterable<ParsedEvent> | ParsedEvent[];\n let processName: string | undefined;\n let exportPid: number | undefined;\n\n if (options.selector) {\n const session = await resolveSession(options.selector);\n processName = formatSessionProcessName(session);\n exportPid = session.pid;\n await warnOnRotationLoss(session.sessionDir, '2g export --tail');\n events = tap(session.sessionDir, {\n follow: options.follow,\n debug: options.debug,\n timeout: options.timeout,\n idleTimeout: options.follow ? options.idleTimeout : undefined,\n });\n } else if (options.inputFile) {\n events = readJsonlFile(options.inputFile);\n } else {\n events = readJsonlStdin();\n }\n\n const filteredEvents = filterEvents(events, options);\n const file =\n options.format === 'opentelemetry'\n ? await convertToOpenTelemetry(filteredEvents, {\n pid: exportPid,\n processName,\n })\n : await convertToChromeTrace(filteredEvents, {\n pid: exportPid,\n processName,\n });\n const output = JSON.stringify(file, null, 2);\n if (options.output) fs.writeFileSync(options.output, `${output}\\n`);\n else process.stdout.write(`${output}\\n`);\n}\n\nfunction parseExportOptions(args: string[]) {\n const parsed = parseArgs({\n args,\n allowPositionals: true,\n options: {\n ...tapArgOptions,\n input: { type: 'string' },\n output: { type: 'string', short: 'o' },\n format: { type: 'string' },\n json: { type: 'boolean' },\n timeout: { type: 'string' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n const tapOptions = parseSharedTapOptions(parsed.values);\n const timeout = parseDuration(parsed.values.timeout);\n\n const format = parsed.values.format ?? 'chrome-trace';\n if (!isExportFormat(format)) throw new Error(`Unsupported format: ${format}`);\n if (parsed.positionals[0] && parsed.values.input)\n throw new Error('Use either a session selector or --input, not both');\n if (timeout != null && !tapOptions.follow)\n throw new Error('Use --timeout only with --tail');\n\n return {\n selector: parsed.positionals[0],\n inputFile: parsed.values.input,\n output: parsed.values.output,\n format,\n since: tapOptions.since,\n filter: tapOptions.filter,\n spans: tapOptions.spans,\n debug: tapOptions.debug,\n follow: tapOptions.follow,\n timeout,\n idleTimeout: DEFAULT_IDLE_TIMEOUT,\n json: parsed.values.json ?? false,\n };\n}\n\nfunction isExportFormat(value: string): value is ExportFormat {\n return value === 'chrome-trace' || value === 'opentelemetry';\n}\n\nfunction printExportHelp() {\n process.stdout.write(\n [\n 'Usage: 2g export [selector]',\n '',\n 'Exports session events to Chrome Trace or OTLP JSON.',\n '(Without --tail it reads only the retained window. Rotated out logs may be lost)',\n '',\n '--tail attaches to an already-running session and follows live from that point.',\n ' Run it after the session is up and leave it attached while the workload runs.',\n ' It will automatically stop on 30s idle.',\n 'To trace a full command instead, use `2g record`.',\n '',\n 'Options:',\n ' selector Substring of PID, CWD, or command; a running',\n ' session wins ties',\n ' --input <file> Read JSONL events from a file',\n ' -o, --output <file> Write output to a file',\n ' --format <format> chrome-trace or opentelemetry',\n ' --json Print JSON output',\n ' --since <time> Duration ago (5m, 90s), Unix time, or ISO date',\n ' --filter <pattern> Event name prefix (whole segments), e.g. category,',\n ' category:kind; * wildcards; comma-separated',\n ' --spans Keep only span events (log.span() pairs with a _d',\n ' duration); omit to include point events too. A',\n ' plain \"ms\" payload field is not a span',\n ' --debug Include debug events (only recorded when the',\n ' command ran with LOG_DEBUG set)',\n ' --tail Follow live events after replaying history; stops',\n ' automatically on 30s idle',\n ' --timeout <duration> Also stop tailing after this absolute duration',\n '',\n ].join('\\n')\n );\n}\n","import { parseArgs } from 'node:util';\n\nimport { listSessions } from '../../tap';\nimport { redirectConsoleToStderr } from '../../utils/redirectConsole';\n\nexport async function runPsCli(args: string[] = []) {\n const parsed = parseArgs({\n args,\n allowPositionals: true,\n options: {\n active: { type: 'boolean', short: 'a' },\n json: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n if (parsed.values.json) redirectConsoleToStderr();\n const sessions = (\n await listSessions({ selector: parsed.positionals[0] })\n ).filter(session => !parsed.values.active || session.alive);\n if (parsed.values.json) {\n process.stdout.write(`${JSON.stringify(sessions, null, 2)}\\n`);\n return;\n }\n\n process.stdout.write('PID\\tSTATUS\\tSTARTED\\tCOMMAND\\tCWD\\n');\n for (const session of sessions) {\n process.stdout.write(\n `${escapeTsv(session.pid)}\\t${escapeTsv(\n session.alive ? 'alive' : 'exited'\n )}\\t${escapeTsv(\n new Date(session.startedAt).toISOString()\n )}\\t${escapeTsv(session.command)}\\t${escapeTsv(session.cwd)}\\n`\n );\n }\n}\n\nfunction escapeTsv(value: unknown) {\n return String(value)\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\\t/g, '\\\\t')\n .replace(/\\r/g, '\\\\r')\n .replace(/\\n/g, '\\\\n');\n}\n\nexport function printPsHelp() {\n process.stdout.write(\n [\n 'Usage: 2g ps [selector]',\n '',\n 'Lists recorded sessions, newest first; alive means still running.',\n '',\n 'Options:',\n ' selector Substring of PID, CWD, or command',\n ' --active, -a Show only active sessions',\n ' --json Print sessions as JSON',\n '',\n ].join('\\n')\n );\n}\n","import { spawn } from 'node:child_process';\nimport fs from 'node:fs';\nimport { parseArgs } from 'node:util';\n\nimport { captureEvents } from '../../capture';\nimport { redirectConsoleToStderr } from '../../utils/redirectConsole';\nimport { filterEvents, parseHelp } from '../shared';\nimport { convertToChromeTrace } from '../export/chromeTrace';\nimport { convertToOpenTelemetry } from '../export/opentelemetry';\n\ntype ExportFormat = 'chrome-trace' | 'opentelemetry';\n\n// `record` owns the process it traces: it spawns <command> with event capture\n// wired in, follows its events end-to-end, and writes the trace when it exits.\n// This is the reliable path for a one-off run — there is no window to attach\n// within and nothing to rotate out, so it never returns a partial trace.\nexport async function runRecordCli(args: string[]) {\n if (parseHelp(args)) {\n printRecordHelp();\n return;\n }\n\n // Everything after `--` is the command and its own arguments, verbatim\n const separator = args.indexOf('--');\n const ownArgs = separator === -1 ? args : args.slice(0, separator);\n const command = separator === -1 ? [] : args.slice(separator + 1);\n const options = parseRecordOptions(ownArgs);\n if (!command.length)\n throw new Error(\n 'record needs a command to run: 2g record [options] -- <command> [args...]'\n );\n\n if (options.json) redirectConsoleToStderr();\n\n const capture = captureEvents({\n debug: options.debug,\n filter: options.filter,\n });\n // The trace lands on stdout when there is no -o, so route the child's stdout\n // to stderr to keep it clean; with -o the child can use stdout normally.\n const child = spawn(\n command[0],\n command.slice(1),\n capture.spawnOptions({\n env: process.env,\n stdio: ['inherit', options.output ? 'inherit' : 2, 'inherit'],\n })\n );\n capture.attach(child);\n\n const onSignal = (signal: NodeJS.Signals) => {\n if (signal !== 'SIGINT') {\n try {\n child.kill(signal);\n } catch {}\n }\n };\n process.on('SIGINT', onSignal);\n process.on('SIGTERM', onSignal);\n\n const exited = new Promise<number>((resolve, reject) => {\n child.on('exit', code => resolve(code ?? 0));\n child.on('error', error =>\n reject(new Error(`Failed to run ${command[0]}: ${error.message}`))\n );\n });\n\n const meta = { pid: child.pid, processName: command.join(' ') };\n const filtered = filterEvents(capture, options);\n\n try {\n // Draining the events resolves once the child closes its event pipe (on exit)\n const file =\n options.format === 'opentelemetry'\n ? await convertToOpenTelemetry(filtered, meta)\n : await convertToChromeTrace(filtered, meta);\n const exitCode = await exited;\n\n const output = JSON.stringify(file, null, 2);\n if (options.output) fs.writeFileSync(options.output, `${output}\\n`);\n else process.stdout.write(`${output}\\n`);\n\n if (exitCode) process.exitCode = exitCode;\n } finally {\n process.off('SIGINT', onSignal);\n process.off('SIGTERM', onSignal);\n }\n}\n\nfunction parseRecordOptions(args: string[]) {\n const parsed = parseArgs({\n args,\n allowPositionals: true,\n options: {\n filter: { type: 'string', multiple: true },\n spans: { type: 'boolean' },\n debug: { type: 'boolean' },\n output: { type: 'string', short: 'o' },\n format: { type: 'string' },\n json: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n\n const format = parsed.values.format ?? 'chrome-trace';\n if (!isExportFormat(format)) throw new Error(`Unsupported format: ${format}`);\n\n return {\n output: parsed.values.output,\n format,\n filter: parsed.values.filter\n ?.flatMap(value => value.split(','))\n .map(item => item.trim())\n .filter(Boolean),\n spans: parsed.values.spans === true,\n debug: parsed.values.debug === true,\n json: parsed.values.json ?? false,\n };\n}\n\nfunction isExportFormat(value: string): value is ExportFormat {\n return value === 'chrome-trace' || value === 'opentelemetry';\n}\n\nfunction printRecordHelp() {\n process.stdout.write(\n [\n 'Usage: 2g record [options] -- <command> [args...]',\n '',\n 'Runs <command>, traces the events it emits, and writes the trace on exit.',\n '',\n 'This is the reliable way to capture a one-off run (a build, a script): 2g',\n 'owns the process, so the trace is complete end-to-end with no window to',\n 'attach within and nothing to rotate out. To trace an already-running server',\n 'instead, use `2g export <selector> --tail`.',\n '',\n 'Options:',\n ' -o, --output <file> Write the trace to a file (default: stdout)',\n ' --format <format> chrome-trace or opentelemetry',\n ' --json Print JSON output',\n ' --filter <pattern> Event name prefix (whole segments), e.g. category,',\n ' category:kind; * wildcards; comma-separated',\n ' --spans Keep only span events (log.span() pairs with a _d',\n ' duration); omit to include point events too',\n ' --debug Enable and export debug events; no LOG_DEBUG needed',\n '',\n 'Example:',\n ' 2g record -o trace.json -- expo export # run & trace a build end-to-end',\n '',\n ].join('\\n')\n );\n}\n","import { parseArgs } from 'node:util';\n\nimport { resolveSession, tap } from '../../tap';\nimport { redirectConsoleToStderr } from '../../utils/redirectConsole';\nimport { formatPrettyEvent, shouldColorizeStream } from '../../utils/pretty';\nimport {\n parseHelp,\n parseSharedTapOptions,\n tapArgOptions,\n warnOnRotationLoss,\n} from '../shared';\n\nexport async function runTapCli(args: string[]) {\n if (parseHelp(args)) {\n printTapHelp();\n return;\n }\n const options = parseTapOptions(args);\n if (options.json) redirectConsoleToStderr();\n const session = await resolveSession(options.selector);\n await warnOnRotationLoss(session.sessionDir, '2g tap --tail');\n const colorizePretty = shouldColorizeStream(process.stdout);\n for await (const event of tap(session.sessionDir, options)) {\n if (options.pretty) {\n process.stdout.write(\n `${formatPrettyEvent(event, {\n colorize: colorizePretty,\n stream: process.stdout,\n })}\\n`\n );\n } else {\n process.stdout.write(`${JSON.stringify(event)}\\n`);\n }\n }\n}\n\nfunction parseTapOptions(args: string[]) {\n const parsed = parseArgs({\n args,\n allowPositionals: true,\n options: {\n ...tapArgOptions,\n format: { type: 'string' },\n json: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n const tapOptions = parseSharedTapOptions(parsed.values);\n if (parsed.values.json && parsed.values.format === 'pretty')\n throw new Error('Use either --json or --format pretty, not both');\n\n return {\n selector: parsed.positionals[0],\n since: tapOptions.since,\n follow: tapOptions.follow,\n filter: tapOptions.filter,\n spans: tapOptions.spans,\n debug: tapOptions.debug,\n json: parsed.values.json ?? false,\n pretty: parsed.values.json ? false : parsed.values.format === 'pretty',\n };\n}\n\nfunction printTapHelp() {\n process.stdout.write(\n [\n 'Usage: 2g tap [selector]',\n '',\n 'Replays retained session history as JSONL, oldest first.',\n '',\n 'Options:',\n ' selector Substring of PID, CWD, or command; a running',\n ' session wins ties',\n ' --since <time> Duration ago (5m, 90s), Unix time, or ISO date',\n ' --filter <pattern> Event name prefix (whole segments), e.g. category,',\n ' category:kind; * wildcards; comma-separated',\n ' --spans Keep only span events (log.span() pairs with a _d',\n ' duration); omit to include point events too. A',\n ' plain \"ms\" payload field is not a span',\n ' --debug Include debug events (only recorded when the',\n ' command ran with LOG_DEBUG set)',\n ' --format pretty Print a readable line per event',\n ' --tail Follow live events after replaying history; runs',\n ' until killed (use export with a timeout for a',\n ' bounded follow)',\n '',\n ].join('\\n')\n );\n}\n","#!/usr/bin/env node\nimport { fileURLToPath } from 'node:url';\n\nimport { printCleanHelp, runCleanCli } from './commands/clean';\nimport { runExportCli } from './commands/export';\nimport { printPsHelp, runPsCli } from './commands/ps';\nimport { runRecordCli } from './commands/record';\nimport { runTapCli } from './commands/tap';\nimport { parseHelp } from './commands/shared';\n\nexport async function main(argv = process.argv.slice(2)) {\n const [command, ...args] = argv;\n\n if (\n !command ||\n command === '--help' ||\n command === '-h' ||\n command === 'help'\n ) {\n printHelp();\n return 0;\n }\n\n switch (command) {\n case 'typegen': {\n const { runTypegenCli } = await import('./commands/typegen');\n runTypegenCli(args);\n return 0;\n }\n case 'ps':\n if (parseHelp(args)) {\n printPsHelp();\n return 0;\n }\n await runPsCli(args);\n return 0;\n case 'tap':\n await runTapCli(args);\n return 0;\n case 'clean':\n if (parseHelp(args)) {\n printCleanHelp();\n return 0;\n }\n runCleanCli(args);\n return 0;\n case 'record':\n await runRecordCli(args);\n return 0;\n case 'export':\n await runExportCli(args);\n return 0;\n default:\n throw new Error(`Unknown command: ${command}`);\n }\n}\n\nfunction printHelp() {\n process.stdout.write(\n [\n 'Usage: 2g <command>',\n '',\n 'Reads structured JSONL event logs that instrumented CLIs record during runs',\n 'into the system temp dir, with no setup: run a command, then tap it here.',\n '',\n 'Commands:',\n ' ps [selector] List recorded sessions',\n ' --active, -a (running only) --json',\n '',\n ' tap [selector] Replay session events as JSONL, oldest first',\n ' --since <time> --filter <pattern> --spans --debug --format pretty',\n ' --tail (follow live events after replay; runs until killed)',\n '',\n ' record -- <command> Run a command, trace it end-to-end, write on exit',\n ' -o, --output <file> --format chrome-trace|opentelemetry --json',\n ' --filter <pattern> --spans --debug',\n '',\n ' export [selector] Export a past or live (--tail) session',\n ' --input <jsonl-file> -o, --output <file> --json',\n ' --format chrome-trace|opentelemetry',\n ' --since <time> --filter <pattern> --spans --debug',\n ' --tail --timeout <duration> (absolute; tail also stops after 30s idle)',\n '',\n ' typegen List every event name/payload a project can emit',\n ' -p, --project <tsconfig> -o, --output <file> --format dts|json --json',\n '',\n ' clean Remove stale sessions',\n ' --all, -a (remove all exited sessions) --json',\n '',\n 'Typical use:',\n ' 2g ps -a # what is running now?',\n ' 2g tap \"expo start\" --tail # follow live events',\n ' 2g tap \"expo start\" --since 5m --format pretty # recent history, readable',\n ' 2g tap \"expo start\" --filter metro:bundling # narrow to one area',\n '',\n 'Trace a run to a flame chart:',\n ' 2g record -o trace.json -- expo export # run & trace a build',\n ' 2g export \"expo start\" --tail -o trace.json # attach to a running server',\n ' 2g export \"expo start\" -o trace.json # after the fact (partial)',\n '',\n 'Selectors match sessions by substring of PID, CWD, or command. If several',\n 'match, and exactly one of them is running, it is chosen; otherwise 2g errors',\n 'and lists the candidates.',\n '',\n '--filter takes comma-separated event-name prefixes matched on whole',\n 'segments: \"category\" and \"category:kind\" both match \"category:kind:test\";',\n '* matches anything. Discover names by tapping unfiltered or via typegen.',\n '',\n '--since accepts a duration ago (5m, 90s, 1h30m), Unix time, or ISO date.',\n '--spans keeps only span events (log.span() pairs with a \"_d\" duration in',\n 'ms); without it, point events are included alongside spans.',\n '',\n 'Events are single JSON lines: {\"_e\":\"category:kind\",\"_t\":<epoch ms>,...}.',\n '\"_d\" is a span duration, \"_w\" a worker id; debug events need --debug.',\n '',\n 'Set LOG_EVENTS=<file|fd> on an instrumented command to redirect its events.',\n 'Debug events are only recorded when the command runs with LOG_DEBUG set.',\n '',\n 'Pass LOG_DEBUG=<filter> when debugging; it also mirrors matching events to',\n 'stderr. Reading them back needs --debug.',\n '',\n 'Run 2g <command> --help for per-command help.',\n '',\n ].join('\\n')\n );\n}\n\nif (isCliEntrypoint()) {\n main()\n .then(code => {\n process.exitCode = code;\n })\n .catch(error => {\n process.stderr.write(\n `${error instanceof Error ? error.message : String(error)}\\n`\n );\n process.exitCode = 1;\n });\n}\n\nfunction isCliEntrypoint() {\n try {\n return process.argv[1] === fileURLToPath(import.meta.url);\n } catch {\n return false;\n }\n}\n"],"names":["runCleanCli","args","options","parseCleanOptions","parsed","parseArgs","all","type","short","json","help","values","redirectConsoleToStderr","removed","cleanExitedSessionsSync","cleanStaleSessionsSync","process","stdout","write","JSON","stringify","tapArgOptions","since","filter","multiple","spans","debug","tail","async","warnOnRotationLoss","sessionDir","remedy","detectRotationLoss","console","warn","readJsonlStream","stream","rl","createInterface","input","line","event","parseEventLine","filterEvents","events","eventFilter","compileEventFilter","parseSince","matchesTapOptions","parseSharedTapOptions","flatMap","value","split","map","item","trim","Boolean","follow","parseHelp","allowPositionals","strict","STRIP_SUFFIXES","convertToChromeTrace","converter","TraceConverter","add","toTraceFile","pending","tracks","Map","pid","processName","version","constructor","this","_e","splitEventName","index","indexOf","category","name","slice","track","getTrack","_w","undefined","extractArgs","key","Object","keys","startsWith","length","_d","push","kind","stripSuffix","cat","ts","Math","round","_t","dur","lane","base","Infinity","traceEvents","ph","tids","nextTid","displayName","laneCount","max","assignLanes","tid","set","sort_index","get","s","metadata","source","convertedAt","Date","toISOString","startTime","startTimestampMs","worker","has","order","sort","a","b","lanes","span","end","stack","pop","top","suffix","endsWith","convertToOpenTelemetry","OpenTelemetryConverter","toFile","traceId","crypto","randomBytes","toString","sessionSpanId","createSpanId","startTimeUnixNano","endTimeUnixNano","eventTime","unixNano","BigInt","createSpan","createEvent","now","resourceSpans","resource","attributes","scopeSpans","scope","spanId","parentSpanId","eventAttributes","timeUnixNano","result","entries","converted","anyValue","stringValue","boolValue","Number","isFinite","isInteger","intValue","String","doubleValue","Array","isArray","arrayValue","kvlistValue","timeMs","runExportCli","printExportHelp","join","parseExportOptions","output","format","timeout","tapOptions","parseDuration","duration","parseDurationValue","Error","isExportFormat","positionals","selector","inputFile","idleTimeout","exportPid","session","resolveSession","formatSessionProcessName","command","tap","readJsonlFile","file","fs","createReadStream","encoding","readJsonlStdin","stdin","filteredEvents","writeFileSync","escapeTsv","replace","runRecordCli","printRecordHelp","separator","ownArgs","parseRecordOptions","capture","captureEvents","child","spawn","spawnOptions","env","stdio","attach","onSignal","signal","kill","on","exited","Promise","resolve","reject","code","error","message","meta","filtered","exitCode","off","runTapCli","printTapHelp","parseTapOptions","pretty","colorizePretty","shouldColorizeStream","formatPrettyEvent","colorize","main","argv","printHelp","runTypegenCli","then","require","printPsHelp","runPsCli","active","sessions","listSessions","alive","startedAt","cwd","printCleanHelp","isCliEntrypoint","fileURLToPath","import","catch","stderr"],"mappings":"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"}
|
|
@@ -8,9 +8,9 @@ import { r as c, s as p, f as u } from "./pretty-chunk.mjs";
|
|
|
8
8
|
|
|
9
9
|
import d from "node:fs";
|
|
10
10
|
|
|
11
|
-
import { d as
|
|
11
|
+
import { d as f, r as m, t as h, l as g, c as y } from "./api-chunk.mjs";
|
|
12
12
|
|
|
13
|
-
import { createInterface as
|
|
13
|
+
import { createInterface as v } from "node:readline";
|
|
14
14
|
|
|
15
15
|
import w from "node:crypto";
|
|
16
16
|
|
|
@@ -68,14 +68,14 @@ const x = {
|
|
|
68
68
|
};
|
|
69
69
|
|
|
70
70
|
async function warnOnRotationLoss(e, t) {
|
|
71
|
-
if (!await
|
|
71
|
+
if (!await f(e)) {
|
|
72
72
|
return;
|
|
73
73
|
}
|
|
74
74
|
console.warn(`⚠ Earlier events were rotated out of the retained window.\n For a complete trace, start \`${t}\` before the workload.`);
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
async function* readJsonlStream(e) {
|
|
78
|
-
const t =
|
|
78
|
+
const t = v({
|
|
79
79
|
input: e
|
|
80
80
|
});
|
|
81
81
|
for await (const e of t) {
|
|
@@ -374,7 +374,7 @@ class OpenTelemetryConverter {
|
|
|
374
374
|
if ("number" == typeof e._d) {
|
|
375
375
|
this.#l.push(this.#d(e));
|
|
376
376
|
} else {
|
|
377
|
-
this.#c.push(this.#
|
|
377
|
+
this.#c.push(this.#f(e));
|
|
378
378
|
}
|
|
379
379
|
}
|
|
380
380
|
toFile() {
|
|
@@ -424,7 +424,7 @@ class OpenTelemetryConverter {
|
|
|
424
424
|
attributes: eventAttributes(e, t)
|
|
425
425
|
};
|
|
426
426
|
}
|
|
427
|
-
#
|
|
427
|
+
#f(e) {
|
|
428
428
|
const t = splitEventName(e._e);
|
|
429
429
|
return {
|
|
430
430
|
timeUnixNano: unixNano(e._t),
|
|
@@ -617,7 +617,7 @@ async function runExportCli(e) {
|
|
|
617
617
|
let o;
|
|
618
618
|
let r;
|
|
619
619
|
if (n.selector) {
|
|
620
|
-
const e = await
|
|
620
|
+
const e = await m(n.selector);
|
|
621
621
|
o = function formatSessionProcessName(e) {
|
|
622
622
|
return e.version ? `${e.command} (v${e.version}, PID ${e.pid})` : `${e.command} (PID ${e.pid})`;
|
|
623
623
|
}(e);
|
|
@@ -722,7 +722,7 @@ async function runRecordCli(e) {
|
|
|
722
722
|
if (r.json) {
|
|
723
723
|
c();
|
|
724
724
|
}
|
|
725
|
-
const i =
|
|
725
|
+
const i = y({
|
|
726
726
|
debug: r.debug,
|
|
727
727
|
filter: r.filter
|
|
728
728
|
});
|
|
@@ -731,6 +731,15 @@ async function runRecordCli(e) {
|
|
|
731
731
|
stdio: [ "inherit", r.output ? "inherit" : 2, "inherit" ]
|
|
732
732
|
}));
|
|
733
733
|
i.attach(a);
|
|
734
|
+
const onSignal = e => {
|
|
735
|
+
if ("SIGINT" !== e) {
|
|
736
|
+
try {
|
|
737
|
+
a.kill(e);
|
|
738
|
+
} catch {}
|
|
739
|
+
}
|
|
740
|
+
};
|
|
741
|
+
process.on("SIGINT", onSignal);
|
|
742
|
+
process.on("SIGTERM", onSignal);
|
|
734
743
|
const l = new Promise((e, t) => {
|
|
735
744
|
a.on("exit", t => e(t ?? 0));
|
|
736
745
|
a.on("error", e => t(new Error(`Failed to run ${o[0]}: ${e.message}`)));
|
|
@@ -740,16 +749,21 @@ async function runRecordCli(e) {
|
|
|
740
749
|
processName: o.join(" ")
|
|
741
750
|
};
|
|
742
751
|
const u = filterEvents(i, r);
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
752
|
+
try {
|
|
753
|
+
const e = "opentelemetry" === r.format ? await convertToOpenTelemetry(u, p) : await convertToChromeTrace(u, p);
|
|
754
|
+
const t = await l;
|
|
755
|
+
const n = JSON.stringify(e, null, 2);
|
|
756
|
+
if (r.output) {
|
|
757
|
+
d.writeFileSync(r.output, `${n}\n`);
|
|
758
|
+
} else {
|
|
759
|
+
process.stdout.write(`${n}\n`);
|
|
760
|
+
}
|
|
761
|
+
if (t) {
|
|
762
|
+
process.exitCode = t;
|
|
763
|
+
}
|
|
764
|
+
} finally {
|
|
765
|
+
process.off("SIGINT", onSignal);
|
|
766
|
+
process.off("SIGTERM", onSignal);
|
|
753
767
|
}
|
|
754
768
|
}
|
|
755
769
|
|
|
@@ -796,7 +810,7 @@ async function runTapCli(e) {
|
|
|
796
810
|
if (n.json) {
|
|
797
811
|
c();
|
|
798
812
|
}
|
|
799
|
-
const s = await
|
|
813
|
+
const s = await m(n.selector);
|
|
800
814
|
await warnOnRotationLoss(s.sessionDir, "2g tap --tail");
|
|
801
815
|
const o = p(process.stdout);
|
|
802
816
|
for await (const e of h(s.sessionDir, n)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-chunk.mjs","sources":["../../src/commands/clean/index.ts","../../src/commands/shared.ts","../../src/commands/export/chromeTrace.ts","../../src/commands/export/opentelemetry.ts","../../src/commands/export/index.ts","../../src/commands/ps/index.ts","../../src/commands/record/index.ts","../../src/commands/tap/index.ts","../../src/cli.ts"],"sourcesContent":["import { parseArgs } from 'node:util';\n\nimport { cleanExitedSessionsSync, cleanStaleSessionsSync } from '../../clean';\nimport { redirectConsoleToStderr } from '../../utils/redirectConsole';\n\nexport function runCleanCli(args: string[] = []) {\n const options = parseCleanOptions(args);\n if (options.json) redirectConsoleToStderr();\n const removed = options.all\n ? cleanExitedSessionsSync()\n : cleanStaleSessionsSync();\n process.stdout.write(\n options.json\n ? `${JSON.stringify({ removed })}\\n`\n : `Removed ${removed} ${options.all ? 'exited' : 'stale'} sessions.\\n`\n );\n}\n\nfunction parseCleanOptions(args: string[]) {\n const parsed = parseArgs({\n args,\n options: {\n all: { type: 'boolean', short: 'a' },\n json: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n return {\n all: parsed.values.all === true,\n json: parsed.values.json === true,\n };\n}\n\nexport function printCleanHelp() {\n process.stdout.write(\n [\n 'Usage: 2g clean',\n '',\n 'Removes stale exited sessions past the retention window.',\n '',\n 'Options:',\n ' --all, -a Remove all exited sessions',\n ' --json',\n '',\n ].join('\\n')\n );\n}\n","import fs from 'node:fs';\nimport { createInterface } from 'node:readline';\nimport type { Readable } from 'node:stream';\nimport { parseArgs } from 'node:util';\n\nimport { detectRotationLoss, type ListedSession } from '../tap';\nimport {\n compileEventFilter,\n matchesTapOptions,\n parseEventLine,\n parseSince,\n parseDuration as parseDurationValue,\n} from '../utils/eventFilter';\nimport type { ParsedEvent } from '../types';\n\nexport const tapArgOptions = {\n since: { type: 'string' },\n filter: { type: 'string', multiple: true },\n spans: { type: 'boolean' },\n debug: { type: 'boolean' },\n tail: { type: 'boolean' },\n} as const;\n\nexport interface SharedTapOptions {\n since?: string;\n filter?: string[];\n spans?: boolean;\n debug?: boolean;\n follow: boolean;\n}\n\n// Warns (via console.warn → stderr, so it never pollutes the JSON/JSONL on\n// stdout, and stays mockable in tests) when segment rotation has already\n// dropped the start of the run from the retained window.\nexport async function warnOnRotationLoss(sessionDir: string, remedy: string) {\n if (!(await detectRotationLoss(sessionDir))) return;\n console.warn(\n `⚠ Earlier events were rotated out of the retained window.\\n` +\n ` For a complete trace, start \\`${remedy}\\` before the workload.`\n );\n}\n\nexport function formatSessionProcessName(session: ListedSession) {\n return session.version\n ? `${session.command} (v${session.version}, PID ${session.pid})`\n : `${session.command} (PID ${session.pid})`;\n}\n\nexport async function* readJsonlFile(file: string) {\n yield* readJsonlStream(fs.createReadStream(file, { encoding: 'utf8' }));\n}\n\nexport async function* readJsonlStdin() {\n yield* readJsonlStream(process.stdin);\n}\n\nexport async function* readJsonlStream(stream: Readable) {\n const rl = createInterface({ input: stream });\n for await (const line of rl) {\n if (!line) continue;\n // Lossless parse; the debug decision belongs to filterEvents\n const event = parseEventLine(line, { debug: true });\n if (event) yield event;\n }\n}\n\nexport async function* filterEvents(\n events: AsyncIterable<ParsedEvent> | Iterable<ParsedEvent>,\n options: Pick<SharedTapOptions, 'since' | 'filter' | 'spans' | 'debug'>\n) {\n const eventFilter = compileEventFilter(options.filter);\n const since = parseSince(options.since);\n for await (const event of events) {\n if (\n matchesTapOptions(\n event,\n {\n filter: options.filter,\n since,\n spans: options.spans,\n debug: options.debug,\n },\n eventFilter\n )\n )\n yield event;\n }\n}\n\nexport function parseSharedTapOptions(values: {\n since?: string;\n filter?: string[];\n spans?: boolean;\n debug?: boolean;\n tail?: boolean;\n}): SharedTapOptions {\n return {\n since: values.since,\n filter: values.filter\n ?.flatMap(value => value.split(','))\n .map(item => item.trim())\n .filter(Boolean),\n spans: values.spans === true,\n debug: values.debug === true,\n follow: values.tail === true,\n };\n}\n\nexport function parseHelp(args: string[]) {\n return (\n parseArgs({\n args,\n allowPositionals: true,\n strict: false,\n options: {\n help: { type: 'boolean', short: 'h' },\n },\n }).values.help === true\n );\n}\n\nexport function parseJsonFlag(args: string[]) {\n return parseArgs({\n args,\n allowPositionals: true,\n options: {\n json: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n },\n }).values;\n}\n\nexport function parseDuration(value?: string) {\n if (value == null || value === '') return undefined;\n const duration = parseDurationValue(value);\n if (duration == null) throw new Error(`Invalid duration: ${value}`);\n return duration;\n}\n","import type { ParsedEvent } from '../../types';\n\nexport interface ConvertToChromeTraceOptions {\n processName?: string;\n pid?: number;\n}\n\nexport interface TraceFile {\n traceEvents: TraceEvent[];\n metadata: {\n source: '2g';\n version: string;\n convertedAt: string;\n startTime: string;\n startTimestampMs: number;\n };\n}\n\nexport type TraceEvent = TraceComplete | TraceInstant | TraceMetadata;\n\nexport interface TraceComplete {\n ph: 'X';\n name: string;\n cat: string;\n pid: number;\n tid: number;\n ts: number;\n dur: number;\n args?: Record<string, unknown>;\n}\n\nexport interface TraceInstant {\n ph: 'i';\n name: string;\n cat: string;\n pid: number;\n tid: number;\n ts: number;\n s: 'g' | 'p' | 't';\n args?: Record<string, unknown>;\n}\n\nexport interface TraceMetadata {\n ph: 'M';\n name: 'process_name' | 'thread_name' | 'thread_sort_index';\n pid: number;\n tid?: number;\n args: Record<string, unknown>;\n}\n\nconst STRIP_SUFFIXES = [':started', ':done', ':failed'];\n\nexport async function convertToChromeTrace(\n events: Iterable<ParsedEvent> | AsyncIterable<ParsedEvent>,\n options: ConvertToChromeTraceOptions = {}\n): Promise<TraceFile> {\n const converter = new TraceConverter(options);\n for await (const event of events) {\n converter.add(event);\n }\n return converter.toTraceFile();\n}\n\ninterface PendingSpan {\n track: string;\n name: string;\n cat: string;\n ts: number;\n dur: number;\n args?: Record<string, unknown>;\n lane: number;\n}\n\ninterface PendingInstant {\n track: string;\n name: string;\n cat: string;\n ts: number;\n args?: Record<string, unknown>;\n}\n\ntype PendingEvent =\n | ({ kind: 'span' } & PendingSpan)\n | ({ kind: 'instant' } & PendingInstant);\n\nexport class TraceConverter {\n #pending: PendingEvent[] = [];\n #tracks = new Map<string, string>();\n #pid: number;\n #processName: string;\n #version = '0.1.0';\n\n constructor(options: ConvertToChromeTraceOptions = {}) {\n this.#pid = options.pid ?? 1;\n this.#processName = options.processName ?? '2g';\n }\n\n add(event: ParsedEvent) {\n if (event._e === 'root:init') {\n if (typeof event.version === 'string') {\n this.#version = event.version;\n if (this.#processName === '2g') {\n this.#processName = `2g (v${event.version})`;\n }\n }\n return;\n }\n\n const parsed = splitEventName(event._e);\n const track = this.#getTrack(\n parsed.category,\n typeof event._w === 'string' ? event._w : undefined\n );\n const args = extractArgs(event);\n\n if (typeof event._d === 'number') {\n this.#pending.push({\n kind: 'span',\n track,\n name: stripSuffix(parsed.name),\n cat: parsed.category,\n ts: Math.round((event._t - event._d) * 1000),\n dur: Math.round(event._d * 1000),\n args,\n lane: 0,\n });\n } else {\n this.#pending.push({\n kind: 'instant',\n track,\n name: stripSuffix(parsed.name),\n cat: parsed.category,\n ts: Math.round(event._t * 1000),\n args,\n });\n }\n }\n\n toTraceFile(): TraceFile {\n let base = this.#pending.length ? Infinity : 0;\n for (const event of this.#pending) {\n if (event.ts < base) base = event.ts;\n }\n const traceEvents: TraceEvent[] = [\n {\n ph: 'M',\n name: 'process_name',\n pid: this.#pid,\n args: { name: this.#processName },\n },\n ];\n\n const tids = new Map<string, number>();\n let nextTid = 1;\n for (const [track, displayName] of this.#tracks) {\n const spans: PendingSpan[] = [];\n for (const event of this.#pending) {\n if (event.kind === 'span' && event.track === track) spans.push(event);\n }\n const laneCount = Math.max(assignLanes(spans), 1);\n for (let lane = 0; lane < laneCount; lane++) {\n const tid = nextTid++;\n tids.set(`${track}\\0${lane}`, tid);\n traceEvents.push(\n {\n ph: 'M',\n name: 'thread_name',\n pid: this.#pid,\n tid,\n args: {\n name: lane === 0 ? displayName : `${displayName} #${lane + 1}`,\n },\n },\n {\n ph: 'M',\n name: 'thread_sort_index',\n pid: this.#pid,\n tid,\n args: { sort_index: tid },\n }\n );\n }\n }\n\n for (const event of this.#pending) {\n const lane = event.kind === 'span' ? event.lane : 0;\n const tid = tids.get(`${event.track}\\0${lane}`)!;\n if (event.kind === 'span') {\n traceEvents.push({\n ph: 'X',\n name: event.name,\n cat: event.cat,\n pid: this.#pid,\n tid,\n ts: event.ts - base,\n dur: event.dur,\n args: event.args,\n });\n } else {\n traceEvents.push({\n ph: 'i',\n name: event.name,\n cat: event.cat,\n pid: this.#pid,\n tid,\n ts: event.ts - base,\n s: 't',\n args: event.args,\n });\n }\n }\n\n return {\n traceEvents,\n metadata: {\n source: '2g',\n version: this.#version,\n convertedAt: new Date().toISOString(),\n startTime: new Date(base / 1000).toISOString(),\n startTimestampMs: base / 1000,\n },\n };\n }\n\n #getTrack(category: string, worker?: string) {\n const key = worker ? `${category}:${worker}` : category;\n if (!this.#tracks.has(key)) {\n this.#tracks.set(key, worker ? `${category} ${worker}` : category);\n }\n return key;\n }\n}\n\n// 'X' events on one tid nest by containment; partial overlap is invalid.\nfunction assignLanes(spans: PendingSpan[]) {\n const order = [...spans].sort(\n (a, b) => a.ts - b.ts || b.ts + b.dur - (a.ts + a.dur)\n );\n const lanes: PendingSpan[][] = [];\n for (const span of order) {\n const end = span.ts + span.dur;\n let lane = -1;\n for (let index = 0; index < lanes.length; index++) {\n const stack = lanes[index];\n while (\n stack.length &&\n stack[stack.length - 1].ts + stack[stack.length - 1].dur <= span.ts\n ) {\n stack.pop();\n }\n const top = stack[stack.length - 1];\n if (!top || top.ts + top.dur >= end) {\n stack.push(span);\n lane = index;\n break;\n }\n }\n if (lane < 0) {\n lanes.push([span]);\n lane = lanes.length - 1;\n }\n span.lane = lane;\n }\n return lanes.length;\n}\n\nfunction splitEventName(value: string) {\n const index = value.indexOf(':');\n if (index < 1) return { category: 'uncategorized', name: value };\n return {\n category: value.slice(0, index),\n name: value.slice(index + 1),\n };\n}\n\nfunction stripSuffix(name: string) {\n for (const suffix of STRIP_SUFFIXES) {\n if (name.endsWith(suffix)) return name.slice(0, -suffix.length);\n }\n return name;\n}\n\nfunction extractArgs(event: ParsedEvent) {\n const args: Record<string, unknown> = {};\n for (const key of Object.keys(event)) {\n if (key.startsWith('_')) continue;\n args[key] = event[key];\n }\n return Object.keys(args).length ? args : undefined;\n}\n","import crypto from 'node:crypto';\n\nimport type { ParsedEvent } from '../../types';\n\nexport interface ConvertToOpenTelemetryOptions {\n processName?: string;\n pid?: number;\n}\n\nexport interface OpenTelemetryFile {\n resourceSpans: OpenTelemetryResourceSpan[];\n}\n\ninterface OpenTelemetryResourceSpan {\n resource: {\n attributes: OpenTelemetryAttribute[];\n };\n scopeSpans: Array<{\n scope: {\n name: string;\n };\n spans: OpenTelemetrySpan[];\n }>;\n}\n\ninterface OpenTelemetrySpan {\n traceId: string;\n spanId: string;\n parentSpanId?: string;\n name: string;\n startTimeUnixNano: string;\n endTimeUnixNano: string;\n attributes?: OpenTelemetryAttribute[];\n events?: OpenTelemetrySpanEvent[];\n}\n\ninterface OpenTelemetrySpanEvent {\n timeUnixNano: string;\n name: string;\n attributes?: OpenTelemetryAttribute[];\n}\n\ninterface OpenTelemetryAttribute {\n key: string;\n value: OpenTelemetryAnyValue;\n}\n\ntype OpenTelemetryAnyValue =\n | { stringValue: string }\n | { intValue: string }\n | { doubleValue: number }\n | { boolValue: boolean }\n | { arrayValue: { values: OpenTelemetryAnyValue[] } }\n | { kvlistValue: { values: OpenTelemetryAttribute[] } };\n\nconst STRIP_SUFFIXES = [':started', ':done', ':failed'];\n\nexport async function convertToOpenTelemetry(\n events: Iterable<ParsedEvent> | AsyncIterable<ParsedEvent>,\n options: ConvertToOpenTelemetryOptions = {}\n): Promise<OpenTelemetryFile> {\n const converter = new OpenTelemetryConverter(options);\n for await (const event of events) {\n converter.add(event);\n }\n return converter.toFile();\n}\n\nclass OpenTelemetryConverter {\n readonly #traceId = crypto.randomBytes(16).toString('hex');\n readonly #sessionSpanId = createSpanId();\n readonly #spans: OpenTelemetrySpan[] = [];\n readonly #events: OpenTelemetrySpanEvent[] = [];\n #processName: string;\n #version = '0.1.0';\n #startTimeUnixNano: string | undefined;\n #endTimeUnixNano: string | undefined;\n\n constructor(private readonly options: ConvertToOpenTelemetryOptions) {\n this.#processName = options.processName ?? '2g';\n }\n\n add(event: ParsedEvent) {\n const eventTime = unixNano(event._t);\n this.#startTimeUnixNano =\n this.#startTimeUnixNano == null ||\n BigInt(eventTime) < BigInt(this.#startTimeUnixNano)\n ? eventTime\n : this.#startTimeUnixNano;\n this.#endTimeUnixNano =\n this.#endTimeUnixNano == null ||\n BigInt(eventTime) > BigInt(this.#endTimeUnixNano)\n ? eventTime\n : this.#endTimeUnixNano;\n\n if (event._e === 'root:init') {\n if (typeof event.version === 'string') this.#version = event.version;\n if (this.#processName === '2g' && typeof event.version === 'string') {\n this.#processName = `2g (v${event.version})`;\n }\n return;\n }\n\n if (typeof event._d === 'number') {\n this.#spans.push(this.#createSpan(event));\n } else {\n this.#events.push(this.#createEvent(event));\n }\n }\n\n toFile(): OpenTelemetryFile {\n const startTimeUnixNano = this.#startTimeUnixNano ?? unixNano(Date.now());\n const endTimeUnixNano = this.#endTimeUnixNano ?? startTimeUnixNano;\n return {\n resourceSpans: [\n {\n resource: {\n attributes: attributes({\n 'service.name': this.#processName,\n 'service.version': this.#version,\n 'process.pid': this.options.pid,\n 'telemetry.sdk.name': '2g',\n 'telemetry.sdk.language': 'nodejs',\n }),\n },\n scopeSpans: [\n {\n scope: { name: '2g' },\n spans: [\n {\n traceId: this.#traceId,\n spanId: this.#sessionSpanId,\n name: this.#processName,\n startTimeUnixNano,\n endTimeUnixNano,\n attributes: attributes({\n 'event_log.kind': 'session',\n }),\n events: this.#events.length ? this.#events : undefined,\n },\n ...this.#spans,\n ],\n },\n ],\n },\n ],\n };\n }\n\n #createSpan(event: ParsedEvent): OpenTelemetrySpan {\n const parsed = splitEventName(event._e);\n const startTimeUnixNano = unixNano(event._t - event._d!);\n const endTimeUnixNano = unixNano(event._t);\n return {\n traceId: this.#traceId,\n spanId: createSpanId(),\n parentSpanId: this.#sessionSpanId,\n name: parsed ? stripSuffix(parsed.name) : event._e,\n startTimeUnixNano,\n endTimeUnixNano,\n attributes: eventAttributes(event, parsed),\n };\n }\n\n #createEvent(event: ParsedEvent): OpenTelemetrySpanEvent {\n const parsed = splitEventName(event._e);\n return {\n timeUnixNano: unixNano(event._t),\n name: parsed ? stripSuffix(parsed.name) : event._e,\n attributes: eventAttributes(event, parsed),\n };\n }\n}\n\nfunction eventAttributes(\n event: ParsedEvent,\n parsed: ReturnType<typeof splitEventName>\n) {\n const values: Record<string, unknown> = {\n 'event.name': event._e,\n };\n if (parsed) {\n values['event.category'] = parsed.category;\n values['event.action'] = parsed.name;\n }\n if (typeof event._w === 'string') values['event.worker.id'] = event._w;\n\n for (const key of Object.keys(event)) {\n if (\n key === '_e' ||\n key === '_t' ||\n key === '_d' ||\n key === '_l' ||\n key === '_w'\n )\n continue;\n values[`event_log.${key}`] = event[key];\n }\n\n return attributes(values);\n}\n\nfunction attributes(values: Record<string, unknown>): OpenTelemetryAttribute[] {\n const result: OpenTelemetryAttribute[] = [];\n for (const [key, value] of Object.entries(values)) {\n const converted = anyValue(value);\n if (converted) result.push({ key, value: converted });\n }\n return result;\n}\n\nfunction anyValue(value: unknown): OpenTelemetryAnyValue | null {\n if (typeof value === 'string') return { stringValue: value };\n if (typeof value === 'boolean') return { boolValue: value };\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) return null;\n return Number.isInteger(value)\n ? { intValue: String(value) }\n : { doubleValue: value };\n }\n if (Array.isArray(value)) {\n return {\n arrayValue: {\n values: value.flatMap(item => {\n const converted = anyValue(item);\n return converted ? [converted] : [];\n }),\n },\n };\n }\n if (value && typeof value === 'object') {\n return {\n kvlistValue: {\n values: attributes(value as Record<string, unknown>),\n },\n };\n }\n return null;\n}\n\nfunction createSpanId() {\n return crypto.randomBytes(8).toString('hex');\n}\n\nfunction unixNano(timeMs: number) {\n return String(BigInt(Math.round(timeMs * 1_000_000)));\n}\n\nfunction splitEventName(value: string) {\n const index = value.indexOf(':');\n if (index < 1) return null;\n return {\n category: value.slice(0, index),\n name: value.slice(index + 1),\n };\n}\n\nfunction stripSuffix(name: string) {\n for (const suffix of STRIP_SUFFIXES) {\n if (name.endsWith(suffix)) return name.slice(0, -suffix.length);\n }\n return name;\n}\n","import fs from 'node:fs';\nimport { parseArgs } from 'node:util';\n\nimport { resolveSession, tap } from '../../tap';\nimport type { ParsedEvent } from '../../types';\nimport { redirectConsoleToStderr } from '../../utils/redirectConsole';\nimport {\n filterEvents,\n formatSessionProcessName,\n parseHelp,\n parseDuration,\n parseSharedTapOptions,\n readJsonlFile,\n readJsonlStdin,\n tapArgOptions,\n warnOnRotationLoss,\n} from '../shared';\nimport { convertToChromeTrace } from './chromeTrace';\nimport { convertToOpenTelemetry } from './opentelemetry';\n\ntype ExportFormat = 'chrome-trace' | 'opentelemetry';\nconst DEFAULT_IDLE_TIMEOUT = 30_000;\n\nexport async function runExportCli(args: string[]) {\n if (parseHelp(args)) {\n printExportHelp();\n return;\n }\n const options = parseExportOptions(args);\n if (options.json) redirectConsoleToStderr();\n let events: AsyncIterable<ParsedEvent> | ParsedEvent[];\n let processName: string | undefined;\n let exportPid: number | undefined;\n\n if (options.selector) {\n const session = await resolveSession(options.selector);\n processName = formatSessionProcessName(session);\n exportPid = session.pid;\n await warnOnRotationLoss(session.sessionDir, '2g export --tail');\n events = tap(session.sessionDir, {\n follow: options.follow,\n debug: options.debug,\n timeout: options.timeout,\n idleTimeout: options.follow ? options.idleTimeout : undefined,\n });\n } else if (options.inputFile) {\n events = readJsonlFile(options.inputFile);\n } else {\n events = readJsonlStdin();\n }\n\n const filteredEvents = filterEvents(events, options);\n const file =\n options.format === 'opentelemetry'\n ? await convertToOpenTelemetry(filteredEvents, {\n pid: exportPid,\n processName,\n })\n : await convertToChromeTrace(filteredEvents, {\n pid: exportPid,\n processName,\n });\n const output = JSON.stringify(file, null, 2);\n if (options.output) fs.writeFileSync(options.output, `${output}\\n`);\n else process.stdout.write(`${output}\\n`);\n}\n\nfunction parseExportOptions(args: string[]) {\n const parsed = parseArgs({\n args,\n allowPositionals: true,\n options: {\n ...tapArgOptions,\n input: { type: 'string' },\n output: { type: 'string', short: 'o' },\n format: { type: 'string' },\n json: { type: 'boolean' },\n timeout: { type: 'string' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n const tapOptions = parseSharedTapOptions(parsed.values);\n const timeout = parseDuration(parsed.values.timeout);\n\n const format = parsed.values.format ?? 'chrome-trace';\n if (!isExportFormat(format)) throw new Error(`Unsupported format: ${format}`);\n if (parsed.positionals[0] && parsed.values.input)\n throw new Error('Use either a session selector or --input, not both');\n if (timeout != null && !tapOptions.follow)\n throw new Error('Use --timeout only with --tail');\n\n return {\n selector: parsed.positionals[0],\n inputFile: parsed.values.input,\n output: parsed.values.output,\n format,\n since: tapOptions.since,\n filter: tapOptions.filter,\n spans: tapOptions.spans,\n debug: tapOptions.debug,\n follow: tapOptions.follow,\n timeout,\n idleTimeout: DEFAULT_IDLE_TIMEOUT,\n json: parsed.values.json ?? false,\n };\n}\n\nfunction isExportFormat(value: string): value is ExportFormat {\n return value === 'chrome-trace' || value === 'opentelemetry';\n}\n\nfunction printExportHelp() {\n process.stdout.write(\n [\n 'Usage: 2g export [selector]',\n '',\n 'Exports session events to Chrome Trace or OTLP JSON.',\n '(Without --tail it reads only the retained window. Rotated out logs may be lost)',\n '',\n '--tail attaches to an already-running session and follows live from that point.',\n ' Run it after the session is up and leave it attached while the workload runs.',\n ' It will automatically stop on 30s idle.',\n 'To trace a full command instead, use `2g record`.',\n '',\n 'Options:',\n ' selector Substring of PID, CWD, or command; a running',\n ' session wins ties',\n ' --input <file> Read JSONL events from a file',\n ' -o, --output <file> Write output to a file',\n ' --format <format> chrome-trace or opentelemetry',\n ' --json Print JSON output',\n ' --since <time> Duration ago (5m, 90s), Unix time, or ISO date',\n ' --filter <pattern> Event name prefix (whole segments), e.g. category,',\n ' category:kind; * wildcards; comma-separated',\n ' --spans Keep only span events (log.span() pairs with a _d',\n ' duration); omit to include point events too. A',\n ' plain \"ms\" payload field is not a span',\n ' --debug Include debug events (only recorded when the',\n ' command ran with LOG_DEBUG set)',\n ' --tail Follow live events after replaying history; stops',\n ' automatically on 30s idle',\n ' --timeout <duration> Also stop tailing after this absolute duration',\n '',\n ].join('\\n')\n );\n}\n","import { parseArgs } from 'node:util';\n\nimport { listSessions } from '../../tap';\nimport { redirectConsoleToStderr } from '../../utils/redirectConsole';\n\nexport async function runPsCli(args: string[] = []) {\n const parsed = parseArgs({\n args,\n allowPositionals: true,\n options: {\n active: { type: 'boolean', short: 'a' },\n json: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n if (parsed.values.json) redirectConsoleToStderr();\n const sessions = (\n await listSessions({ selector: parsed.positionals[0] })\n ).filter(session => !parsed.values.active || session.alive);\n if (parsed.values.json) {\n process.stdout.write(`${JSON.stringify(sessions, null, 2)}\\n`);\n return;\n }\n\n process.stdout.write('PID\\tSTATUS\\tSTARTED\\tCOMMAND\\tCWD\\n');\n for (const session of sessions) {\n process.stdout.write(\n `${escapeTsv(session.pid)}\\t${escapeTsv(\n session.alive ? 'alive' : 'exited'\n )}\\t${escapeTsv(\n new Date(session.startedAt).toISOString()\n )}\\t${escapeTsv(session.command)}\\t${escapeTsv(session.cwd)}\\n`\n );\n }\n}\n\nfunction escapeTsv(value: unknown) {\n return String(value)\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\\t/g, '\\\\t')\n .replace(/\\r/g, '\\\\r')\n .replace(/\\n/g, '\\\\n');\n}\n\nexport function printPsHelp() {\n process.stdout.write(\n [\n 'Usage: 2g ps [selector]',\n '',\n 'Lists recorded sessions, newest first; alive means still running.',\n '',\n 'Options:',\n ' selector Substring of PID, CWD, or command',\n ' --active, -a Show only active sessions',\n ' --json Print sessions as JSON',\n '',\n ].join('\\n')\n );\n}\n","import { spawn } from 'node:child_process';\nimport fs from 'node:fs';\nimport { parseArgs } from 'node:util';\n\nimport { captureEvents } from '../../capture';\nimport { redirectConsoleToStderr } from '../../utils/redirectConsole';\nimport { filterEvents, parseHelp } from '../shared';\nimport { convertToChromeTrace } from '../export/chromeTrace';\nimport { convertToOpenTelemetry } from '../export/opentelemetry';\n\ntype ExportFormat = 'chrome-trace' | 'opentelemetry';\n\n// `record` owns the process it traces: it spawns <command> with event capture\n// wired in, follows its events end-to-end, and writes the trace when it exits.\n// This is the reliable path for a one-off run — there is no window to attach\n// within and nothing to rotate out, so it never returns a partial trace.\nexport async function runRecordCli(args: string[]) {\n if (parseHelp(args)) {\n printRecordHelp();\n return;\n }\n\n // Everything after `--` is the command and its own arguments, verbatim\n const separator = args.indexOf('--');\n const ownArgs = separator === -1 ? args : args.slice(0, separator);\n const command = separator === -1 ? [] : args.slice(separator + 1);\n const options = parseRecordOptions(ownArgs);\n if (!command.length)\n throw new Error(\n 'record needs a command to run: 2g record [options] -- <command> [args...]'\n );\n\n if (options.json) redirectConsoleToStderr();\n\n const capture = captureEvents({\n debug: options.debug,\n filter: options.filter,\n });\n // The trace lands on stdout when there is no -o, so route the child's stdout\n // to stderr to keep it clean; with -o the child can use stdout normally.\n const child = spawn(\n command[0],\n command.slice(1),\n capture.spawnOptions({\n env: process.env,\n stdio: ['inherit', options.output ? 'inherit' : 2, 'inherit'],\n })\n );\n capture.attach(child);\n\n const exited = new Promise<number>((resolve, reject) => {\n child.on('exit', code => resolve(code ?? 0));\n child.on('error', error =>\n reject(new Error(`Failed to run ${command[0]}: ${error.message}`))\n );\n });\n\n const meta = { pid: child.pid, processName: command.join(' ') };\n const filtered = filterEvents(capture, options);\n // Draining the events resolves once the child closes its event pipe (on exit)\n const file =\n options.format === 'opentelemetry'\n ? await convertToOpenTelemetry(filtered, meta)\n : await convertToChromeTrace(filtered, meta);\n const exitCode = await exited;\n\n const output = JSON.stringify(file, null, 2);\n if (options.output) fs.writeFileSync(options.output, `${output}\\n`);\n else process.stdout.write(`${output}\\n`);\n\n if (exitCode) process.exitCode = exitCode;\n}\n\nfunction parseRecordOptions(args: string[]) {\n const parsed = parseArgs({\n args,\n allowPositionals: true,\n options: {\n filter: { type: 'string', multiple: true },\n spans: { type: 'boolean' },\n debug: { type: 'boolean' },\n output: { type: 'string', short: 'o' },\n format: { type: 'string' },\n json: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n\n const format = parsed.values.format ?? 'chrome-trace';\n if (!isExportFormat(format)) throw new Error(`Unsupported format: ${format}`);\n\n return {\n output: parsed.values.output,\n format,\n filter: parsed.values.filter\n ?.flatMap(value => value.split(','))\n .map(item => item.trim())\n .filter(Boolean),\n spans: parsed.values.spans === true,\n debug: parsed.values.debug === true,\n json: parsed.values.json ?? false,\n };\n}\n\nfunction isExportFormat(value: string): value is ExportFormat {\n return value === 'chrome-trace' || value === 'opentelemetry';\n}\n\nfunction printRecordHelp() {\n process.stdout.write(\n [\n 'Usage: 2g record [options] -- <command> [args...]',\n '',\n 'Runs <command>, traces the events it emits, and writes the trace on exit.',\n '',\n 'This is the reliable way to capture a one-off run (a build, a script): 2g',\n 'owns the process, so the trace is complete end-to-end with no window to',\n 'attach within and nothing to rotate out. To trace an already-running server',\n 'instead, use `2g export <selector> --tail`.',\n '',\n 'Options:',\n ' -o, --output <file> Write the trace to a file (default: stdout)',\n ' --format <format> chrome-trace or opentelemetry',\n ' --json Print JSON output',\n ' --filter <pattern> Event name prefix (whole segments), e.g. category,',\n ' category:kind; * wildcards; comma-separated',\n ' --spans Keep only span events (log.span() pairs with a _d',\n ' duration); omit to include point events too',\n ' --debug Enable and export debug events; no LOG_DEBUG needed',\n '',\n 'Example:',\n ' 2g record -o trace.json -- expo export # run & trace a build end-to-end',\n '',\n ].join('\\n')\n );\n}\n","import { parseArgs } from 'node:util';\n\nimport { resolveSession, tap } from '../../tap';\nimport { redirectConsoleToStderr } from '../../utils/redirectConsole';\nimport { formatPrettyEvent, shouldColorizeStream } from '../../utils/pretty';\nimport {\n parseHelp,\n parseSharedTapOptions,\n tapArgOptions,\n warnOnRotationLoss,\n} from '../shared';\n\nexport async function runTapCli(args: string[]) {\n if (parseHelp(args)) {\n printTapHelp();\n return;\n }\n const options = parseTapOptions(args);\n if (options.json) redirectConsoleToStderr();\n const session = await resolveSession(options.selector);\n await warnOnRotationLoss(session.sessionDir, '2g tap --tail');\n const colorizePretty = shouldColorizeStream(process.stdout);\n for await (const event of tap(session.sessionDir, options)) {\n if (options.pretty) {\n process.stdout.write(\n `${formatPrettyEvent(event, {\n colorize: colorizePretty,\n stream: process.stdout,\n })}\\n`\n );\n } else {\n process.stdout.write(`${JSON.stringify(event)}\\n`);\n }\n }\n}\n\nfunction parseTapOptions(args: string[]) {\n const parsed = parseArgs({\n args,\n allowPositionals: true,\n options: {\n ...tapArgOptions,\n format: { type: 'string' },\n json: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n const tapOptions = parseSharedTapOptions(parsed.values);\n if (parsed.values.json && parsed.values.format === 'pretty')\n throw new Error('Use either --json or --format pretty, not both');\n\n return {\n selector: parsed.positionals[0],\n since: tapOptions.since,\n follow: tapOptions.follow,\n filter: tapOptions.filter,\n spans: tapOptions.spans,\n debug: tapOptions.debug,\n json: parsed.values.json ?? false,\n pretty: parsed.values.json ? false : parsed.values.format === 'pretty',\n };\n}\n\nfunction printTapHelp() {\n process.stdout.write(\n [\n 'Usage: 2g tap [selector]',\n '',\n 'Replays retained session history as JSONL, oldest first.',\n '',\n 'Options:',\n ' selector Substring of PID, CWD, or command; a running',\n ' session wins ties',\n ' --since <time> Duration ago (5m, 90s), Unix time, or ISO date',\n ' --filter <pattern> Event name prefix (whole segments), e.g. category,',\n ' category:kind; * wildcards; comma-separated',\n ' --spans Keep only span events (log.span() pairs with a _d',\n ' duration); omit to include point events too. A',\n ' plain \"ms\" payload field is not a span',\n ' --debug Include debug events (only recorded when the',\n ' command ran with LOG_DEBUG set)',\n ' --format pretty Print a readable line per event',\n ' --tail Follow live events after replaying history; runs',\n ' until killed (use export with a timeout for a',\n ' bounded follow)',\n '',\n ].join('\\n')\n );\n}\n","#!/usr/bin/env node\nimport { fileURLToPath } from 'node:url';\n\nimport { printCleanHelp, runCleanCli } from './commands/clean';\nimport { runExportCli } from './commands/export';\nimport { printPsHelp, runPsCli } from './commands/ps';\nimport { runRecordCli } from './commands/record';\nimport { runTapCli } from './commands/tap';\nimport { parseHelp } from './commands/shared';\n\nexport async function main(argv = process.argv.slice(2)) {\n const [command, ...args] = argv;\n\n if (\n !command ||\n command === '--help' ||\n command === '-h' ||\n command === 'help'\n ) {\n printHelp();\n return 0;\n }\n\n switch (command) {\n case 'typegen': {\n const { runTypegenCli } = await import('./commands/typegen');\n runTypegenCli(args);\n return 0;\n }\n case 'ps':\n if (parseHelp(args)) {\n printPsHelp();\n return 0;\n }\n await runPsCli(args);\n return 0;\n case 'tap':\n await runTapCli(args);\n return 0;\n case 'clean':\n if (parseHelp(args)) {\n printCleanHelp();\n return 0;\n }\n runCleanCli(args);\n return 0;\n case 'record':\n await runRecordCli(args);\n return 0;\n case 'export':\n await runExportCli(args);\n return 0;\n default:\n throw new Error(`Unknown command: ${command}`);\n }\n}\n\nfunction printHelp() {\n process.stdout.write(\n [\n 'Usage: 2g <command>',\n '',\n 'Reads structured JSONL event logs that instrumented CLIs record during runs',\n 'into the system temp dir, with no setup: run a command, then tap it here.',\n '',\n 'Commands:',\n ' ps [selector] List recorded sessions',\n ' --active, -a (running only) --json',\n '',\n ' tap [selector] Replay session events as JSONL, oldest first',\n ' --since <time> --filter <pattern> --spans --debug --format pretty',\n ' --tail (follow live events after replay; runs until killed)',\n '',\n ' record -- <command> Run a command, trace it end-to-end, write on exit',\n ' -o, --output <file> --format chrome-trace|opentelemetry --json',\n ' --filter <pattern> --spans --debug',\n '',\n ' export [selector] Export a past or live (--tail) session',\n ' --input <jsonl-file> -o, --output <file> --json',\n ' --format chrome-trace|opentelemetry',\n ' --since <time> --filter <pattern> --spans --debug',\n ' --tail --timeout <duration> (absolute; tail also stops after 30s idle)',\n '',\n ' typegen List every event name/payload a project can emit',\n ' -p, --project <tsconfig> -o, --output <file> --format dts|json --json',\n '',\n ' clean Remove stale sessions',\n ' --all, -a (remove all exited sessions) --json',\n '',\n 'Typical use:',\n ' 2g ps -a # what is running now?',\n ' 2g tap \"expo start\" --tail # follow live events',\n ' 2g tap \"expo start\" --since 5m --format pretty # recent history, readable',\n ' 2g tap \"expo start\" --filter metro:bundling # narrow to one area',\n '',\n 'Trace a run to a flame chart:',\n ' 2g record -o trace.json -- expo export # run & trace a build',\n ' 2g export \"expo start\" --tail -o trace.json # attach to a running server',\n ' 2g export \"expo start\" -o trace.json # after the fact (partial)',\n '',\n 'Selectors match sessions by substring of PID, CWD, or command. If several',\n 'match, and exactly one of them is running, it is chosen; otherwise 2g errors',\n 'and lists the candidates.',\n '',\n '--filter takes comma-separated event-name prefixes matched on whole',\n 'segments: \"category\" and \"category:kind\" both match \"category:kind:test\";',\n '* matches anything. Discover names by tapping unfiltered or via typegen.',\n '',\n '--since accepts a duration ago (5m, 90s, 1h30m), Unix time, or ISO date.',\n '--spans keeps only span events (log.span() pairs with a \"_d\" duration in',\n 'ms); without it, point events are included alongside spans.',\n '',\n 'Events are single JSON lines: {\"_e\":\"category:kind\",\"_t\":<epoch ms>,...}.',\n '\"_d\" is a span duration, \"_w\" a worker id; debug events need --debug.',\n '',\n 'Set LOG_EVENTS=<file|fd> on an instrumented command to redirect its events.',\n 'Debug events are only recorded when the command runs with LOG_DEBUG set.',\n '',\n 'Pass LOG_DEBUG=<filter> when debugging; it also mirrors matching events to',\n 'stderr. Reading them back needs --debug.',\n '',\n 'Run 2g <command> --help for per-command help.',\n '',\n ].join('\\n')\n );\n}\n\nif (isCliEntrypoint()) {\n main()\n .then(code => {\n process.exitCode = code;\n })\n .catch(error => {\n process.stderr.write(\n `${error instanceof Error ? error.message : String(error)}\\n`\n );\n process.exitCode = 1;\n });\n}\n\nfunction isCliEntrypoint() {\n try {\n return process.argv[1] === fileURLToPath(import.meta.url);\n } catch {\n return false;\n }\n}\n"],"names":["runCleanCli","args","options","parseCleanOptions","parsed","parseArgs","all","type","short","json","help","values","redirectConsoleToStderr","removed","cleanExitedSessionsSync","cleanStaleSessionsSync","process","stdout","write","JSON","stringify","tapArgOptions","since","filter","multiple","spans","debug","tail","async","warnOnRotationLoss","sessionDir","remedy","detectRotationLoss","console","warn","readJsonlStream","stream","rl","createInterface","input","line","event","parseEventLine","filterEvents","events","eventFilter","compileEventFilter","parseSince","matchesTapOptions","parseSharedTapOptions","flatMap","value","split","map","item","trim","Boolean","follow","parseHelp","allowPositionals","strict","STRIP_SUFFIXES","convertToChromeTrace","converter","TraceConverter","add","toTraceFile","pending","tracks","Map","pid","processName","version","constructor","this","_e","splitEventName","index","indexOf","category","name","slice","track","getTrack","_w","undefined","extractArgs","key","Object","keys","startsWith","length","_d","push","kind","stripSuffix","cat","ts","Math","round","_t","dur","lane","base","Infinity","traceEvents","ph","tids","nextTid","displayName","laneCount","max","assignLanes","tid","set","sort_index","get","s","metadata","source","convertedAt","Date","toISOString","startTime","startTimestampMs","worker","has","order","sort","a","b","lanes","span","end","stack","pop","top","suffix","endsWith","convertToOpenTelemetry","OpenTelemetryConverter","toFile","traceId","crypto","randomBytes","toString","sessionSpanId","createSpanId","startTimeUnixNano","endTimeUnixNano","eventTime","unixNano","BigInt","createSpan","createEvent","now","resourceSpans","resource","attributes","scopeSpans","scope","spanId","parentSpanId","eventAttributes","timeUnixNano","result","entries","converted","anyValue","stringValue","boolValue","Number","isFinite","isInteger","intValue","String","doubleValue","Array","isArray","arrayValue","kvlistValue","timeMs","runExportCli","printExportHelp","join","parseExportOptions","output","format","timeout","tapOptions","parseDuration","duration","parseDurationValue","Error","isExportFormat","positionals","selector","inputFile","idleTimeout","exportPid","session","resolveSession","formatSessionProcessName","command","tap","readJsonlFile","file","fs","createReadStream","encoding","readJsonlStdin","stdin","filteredEvents","writeFileSync","escapeTsv","replace","runRecordCli","printRecordHelp","separator","ownArgs","parseRecordOptions","capture","captureEvents","child","spawn","spawnOptions","env","stdio","attach","exited","Promise","resolve","reject","on","code","error","message","meta","filtered","exitCode","runTapCli","printTapHelp","parseTapOptions","pretty","colorizePretty","shouldColorizeStream","formatPrettyEvent","colorize","main","argv","printHelp","runTypegenCli","import","printPsHelp","runPsCli","active","sessions","listSessions","alive","startedAt","cwd","printCleanHelp","isCliEntrypoint","fileURLToPath","url","then","catch","stderr"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli-chunk.mjs","sources":["../../src/commands/clean/index.ts","../../src/commands/shared.ts","../../src/commands/export/chromeTrace.ts","../../src/commands/export/opentelemetry.ts","../../src/commands/export/index.ts","../../src/commands/ps/index.ts","../../src/commands/record/index.ts","../../src/commands/tap/index.ts","../../src/cli.ts"],"sourcesContent":["import { parseArgs } from 'node:util';\n\nimport { cleanExitedSessionsSync, cleanStaleSessionsSync } from '../../clean';\nimport { redirectConsoleToStderr } from '../../utils/redirectConsole';\n\nexport function runCleanCli(args: string[] = []) {\n const options = parseCleanOptions(args);\n if (options.json) redirectConsoleToStderr();\n const removed = options.all\n ? cleanExitedSessionsSync()\n : cleanStaleSessionsSync();\n process.stdout.write(\n options.json\n ? `${JSON.stringify({ removed })}\\n`\n : `Removed ${removed} ${options.all ? 'exited' : 'stale'} sessions.\\n`\n );\n}\n\nfunction parseCleanOptions(args: string[]) {\n const parsed = parseArgs({\n args,\n options: {\n all: { type: 'boolean', short: 'a' },\n json: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n return {\n all: parsed.values.all === true,\n json: parsed.values.json === true,\n };\n}\n\nexport function printCleanHelp() {\n process.stdout.write(\n [\n 'Usage: 2g clean',\n '',\n 'Removes stale exited sessions past the retention window.',\n '',\n 'Options:',\n ' --all, -a Remove all exited sessions',\n ' --json',\n '',\n ].join('\\n')\n );\n}\n","import fs from 'node:fs';\nimport { createInterface } from 'node:readline';\nimport type { Readable } from 'node:stream';\nimport { parseArgs } from 'node:util';\n\nimport { detectRotationLoss, type ListedSession } from '../tap';\nimport {\n compileEventFilter,\n matchesTapOptions,\n parseEventLine,\n parseSince,\n parseDuration as parseDurationValue,\n} from '../utils/eventFilter';\nimport type { ParsedEvent } from '../types';\n\nexport const tapArgOptions = {\n since: { type: 'string' },\n filter: { type: 'string', multiple: true },\n spans: { type: 'boolean' },\n debug: { type: 'boolean' },\n tail: { type: 'boolean' },\n} as const;\n\nexport interface SharedTapOptions {\n since?: string;\n filter?: string[];\n spans?: boolean;\n debug?: boolean;\n follow: boolean;\n}\n\n// Warns (via console.warn → stderr, so it never pollutes the JSON/JSONL on\n// stdout, and stays mockable in tests) when segment rotation has already\n// dropped the start of the run from the retained window.\nexport async function warnOnRotationLoss(sessionDir: string, remedy: string) {\n if (!(await detectRotationLoss(sessionDir))) return;\n console.warn(\n `⚠ Earlier events were rotated out of the retained window.\\n` +\n ` For a complete trace, start \\`${remedy}\\` before the workload.`\n );\n}\n\nexport function formatSessionProcessName(session: ListedSession) {\n return session.version\n ? `${session.command} (v${session.version}, PID ${session.pid})`\n : `${session.command} (PID ${session.pid})`;\n}\n\nexport async function* readJsonlFile(file: string) {\n yield* readJsonlStream(fs.createReadStream(file, { encoding: 'utf8' }));\n}\n\nexport async function* readJsonlStdin() {\n yield* readJsonlStream(process.stdin);\n}\n\nexport async function* readJsonlStream(stream: Readable) {\n const rl = createInterface({ input: stream });\n for await (const line of rl) {\n if (!line) continue;\n // Lossless parse; the debug decision belongs to filterEvents\n const event = parseEventLine(line, { debug: true });\n if (event) yield event;\n }\n}\n\nexport async function* filterEvents(\n events: AsyncIterable<ParsedEvent> | Iterable<ParsedEvent>,\n options: Pick<SharedTapOptions, 'since' | 'filter' | 'spans' | 'debug'>\n) {\n const eventFilter = compileEventFilter(options.filter);\n const since = parseSince(options.since);\n for await (const event of events) {\n if (\n matchesTapOptions(\n event,\n {\n filter: options.filter,\n since,\n spans: options.spans,\n debug: options.debug,\n },\n eventFilter\n )\n )\n yield event;\n }\n}\n\nexport function parseSharedTapOptions(values: {\n since?: string;\n filter?: string[];\n spans?: boolean;\n debug?: boolean;\n tail?: boolean;\n}): SharedTapOptions {\n return {\n since: values.since,\n filter: values.filter\n ?.flatMap(value => value.split(','))\n .map(item => item.trim())\n .filter(Boolean),\n spans: values.spans === true,\n debug: values.debug === true,\n follow: values.tail === true,\n };\n}\n\nexport function parseHelp(args: string[]) {\n return (\n parseArgs({\n args,\n allowPositionals: true,\n strict: false,\n options: {\n help: { type: 'boolean', short: 'h' },\n },\n }).values.help === true\n );\n}\n\nexport function parseJsonFlag(args: string[]) {\n return parseArgs({\n args,\n allowPositionals: true,\n options: {\n json: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n },\n }).values;\n}\n\nexport function parseDuration(value?: string) {\n if (value == null || value === '') return undefined;\n const duration = parseDurationValue(value);\n if (duration == null) throw new Error(`Invalid duration: ${value}`);\n return duration;\n}\n","import type { ParsedEvent } from '../../types';\n\nexport interface ConvertToChromeTraceOptions {\n processName?: string;\n pid?: number;\n}\n\nexport interface TraceFile {\n traceEvents: TraceEvent[];\n metadata: {\n source: '2g';\n version: string;\n convertedAt: string;\n startTime: string;\n startTimestampMs: number;\n };\n}\n\nexport type TraceEvent = TraceComplete | TraceInstant | TraceMetadata;\n\nexport interface TraceComplete {\n ph: 'X';\n name: string;\n cat: string;\n pid: number;\n tid: number;\n ts: number;\n dur: number;\n args?: Record<string, unknown>;\n}\n\nexport interface TraceInstant {\n ph: 'i';\n name: string;\n cat: string;\n pid: number;\n tid: number;\n ts: number;\n s: 'g' | 'p' | 't';\n args?: Record<string, unknown>;\n}\n\nexport interface TraceMetadata {\n ph: 'M';\n name: 'process_name' | 'thread_name' | 'thread_sort_index';\n pid: number;\n tid?: number;\n args: Record<string, unknown>;\n}\n\nconst STRIP_SUFFIXES = [':started', ':done', ':failed'];\n\nexport async function convertToChromeTrace(\n events: Iterable<ParsedEvent> | AsyncIterable<ParsedEvent>,\n options: ConvertToChromeTraceOptions = {}\n): Promise<TraceFile> {\n const converter = new TraceConverter(options);\n for await (const event of events) {\n converter.add(event);\n }\n return converter.toTraceFile();\n}\n\ninterface PendingSpan {\n track: string;\n name: string;\n cat: string;\n ts: number;\n dur: number;\n args?: Record<string, unknown>;\n lane: number;\n}\n\ninterface PendingInstant {\n track: string;\n name: string;\n cat: string;\n ts: number;\n args?: Record<string, unknown>;\n}\n\ntype PendingEvent =\n | ({ kind: 'span' } & PendingSpan)\n | ({ kind: 'instant' } & PendingInstant);\n\nexport class TraceConverter {\n #pending: PendingEvent[] = [];\n #tracks = new Map<string, string>();\n #pid: number;\n #processName: string;\n #version = '0.1.0';\n\n constructor(options: ConvertToChromeTraceOptions = {}) {\n this.#pid = options.pid ?? 1;\n this.#processName = options.processName ?? '2g';\n }\n\n add(event: ParsedEvent) {\n if (event._e === 'root:init') {\n if (typeof event.version === 'string') {\n this.#version = event.version;\n if (this.#processName === '2g') {\n this.#processName = `2g (v${event.version})`;\n }\n }\n return;\n }\n\n const parsed = splitEventName(event._e);\n const track = this.#getTrack(\n parsed.category,\n typeof event._w === 'string' ? event._w : undefined\n );\n const args = extractArgs(event);\n\n if (typeof event._d === 'number') {\n this.#pending.push({\n kind: 'span',\n track,\n name: stripSuffix(parsed.name),\n cat: parsed.category,\n ts: Math.round((event._t - event._d) * 1000),\n dur: Math.round(event._d * 1000),\n args,\n lane: 0,\n });\n } else {\n this.#pending.push({\n kind: 'instant',\n track,\n name: stripSuffix(parsed.name),\n cat: parsed.category,\n ts: Math.round(event._t * 1000),\n args,\n });\n }\n }\n\n toTraceFile(): TraceFile {\n let base = this.#pending.length ? Infinity : 0;\n for (const event of this.#pending) {\n if (event.ts < base) base = event.ts;\n }\n const traceEvents: TraceEvent[] = [\n {\n ph: 'M',\n name: 'process_name',\n pid: this.#pid,\n args: { name: this.#processName },\n },\n ];\n\n const tids = new Map<string, number>();\n let nextTid = 1;\n for (const [track, displayName] of this.#tracks) {\n const spans: PendingSpan[] = [];\n for (const event of this.#pending) {\n if (event.kind === 'span' && event.track === track) spans.push(event);\n }\n const laneCount = Math.max(assignLanes(spans), 1);\n for (let lane = 0; lane < laneCount; lane++) {\n const tid = nextTid++;\n tids.set(`${track}\\0${lane}`, tid);\n traceEvents.push(\n {\n ph: 'M',\n name: 'thread_name',\n pid: this.#pid,\n tid,\n args: {\n name: lane === 0 ? displayName : `${displayName} #${lane + 1}`,\n },\n },\n {\n ph: 'M',\n name: 'thread_sort_index',\n pid: this.#pid,\n tid,\n args: { sort_index: tid },\n }\n );\n }\n }\n\n for (const event of this.#pending) {\n const lane = event.kind === 'span' ? event.lane : 0;\n const tid = tids.get(`${event.track}\\0${lane}`)!;\n if (event.kind === 'span') {\n traceEvents.push({\n ph: 'X',\n name: event.name,\n cat: event.cat,\n pid: this.#pid,\n tid,\n ts: event.ts - base,\n dur: event.dur,\n args: event.args,\n });\n } else {\n traceEvents.push({\n ph: 'i',\n name: event.name,\n cat: event.cat,\n pid: this.#pid,\n tid,\n ts: event.ts - base,\n s: 't',\n args: event.args,\n });\n }\n }\n\n return {\n traceEvents,\n metadata: {\n source: '2g',\n version: this.#version,\n convertedAt: new Date().toISOString(),\n startTime: new Date(base / 1000).toISOString(),\n startTimestampMs: base / 1000,\n },\n };\n }\n\n #getTrack(category: string, worker?: string) {\n const key = worker ? `${category}:${worker}` : category;\n if (!this.#tracks.has(key)) {\n this.#tracks.set(key, worker ? `${category} ${worker}` : category);\n }\n return key;\n }\n}\n\n// 'X' events on one tid nest by containment; partial overlap is invalid.\nfunction assignLanes(spans: PendingSpan[]) {\n const order = [...spans].sort(\n (a, b) => a.ts - b.ts || b.ts + b.dur - (a.ts + a.dur)\n );\n const lanes: PendingSpan[][] = [];\n for (const span of order) {\n const end = span.ts + span.dur;\n let lane = -1;\n for (let index = 0; index < lanes.length; index++) {\n const stack = lanes[index];\n while (\n stack.length &&\n stack[stack.length - 1].ts + stack[stack.length - 1].dur <= span.ts\n ) {\n stack.pop();\n }\n const top = stack[stack.length - 1];\n if (!top || top.ts + top.dur >= end) {\n stack.push(span);\n lane = index;\n break;\n }\n }\n if (lane < 0) {\n lanes.push([span]);\n lane = lanes.length - 1;\n }\n span.lane = lane;\n }\n return lanes.length;\n}\n\nfunction splitEventName(value: string) {\n const index = value.indexOf(':');\n if (index < 1) return { category: 'uncategorized', name: value };\n return {\n category: value.slice(0, index),\n name: value.slice(index + 1),\n };\n}\n\nfunction stripSuffix(name: string) {\n for (const suffix of STRIP_SUFFIXES) {\n if (name.endsWith(suffix)) return name.slice(0, -suffix.length);\n }\n return name;\n}\n\nfunction extractArgs(event: ParsedEvent) {\n const args: Record<string, unknown> = {};\n for (const key of Object.keys(event)) {\n if (key.startsWith('_')) continue;\n args[key] = event[key];\n }\n return Object.keys(args).length ? args : undefined;\n}\n","import crypto from 'node:crypto';\n\nimport type { ParsedEvent } from '../../types';\n\nexport interface ConvertToOpenTelemetryOptions {\n processName?: string;\n pid?: number;\n}\n\nexport interface OpenTelemetryFile {\n resourceSpans: OpenTelemetryResourceSpan[];\n}\n\ninterface OpenTelemetryResourceSpan {\n resource: {\n attributes: OpenTelemetryAttribute[];\n };\n scopeSpans: Array<{\n scope: {\n name: string;\n };\n spans: OpenTelemetrySpan[];\n }>;\n}\n\ninterface OpenTelemetrySpan {\n traceId: string;\n spanId: string;\n parentSpanId?: string;\n name: string;\n startTimeUnixNano: string;\n endTimeUnixNano: string;\n attributes?: OpenTelemetryAttribute[];\n events?: OpenTelemetrySpanEvent[];\n}\n\ninterface OpenTelemetrySpanEvent {\n timeUnixNano: string;\n name: string;\n attributes?: OpenTelemetryAttribute[];\n}\n\ninterface OpenTelemetryAttribute {\n key: string;\n value: OpenTelemetryAnyValue;\n}\n\ntype OpenTelemetryAnyValue =\n | { stringValue: string }\n | { intValue: string }\n | { doubleValue: number }\n | { boolValue: boolean }\n | { arrayValue: { values: OpenTelemetryAnyValue[] } }\n | { kvlistValue: { values: OpenTelemetryAttribute[] } };\n\nconst STRIP_SUFFIXES = [':started', ':done', ':failed'];\n\nexport async function convertToOpenTelemetry(\n events: Iterable<ParsedEvent> | AsyncIterable<ParsedEvent>,\n options: ConvertToOpenTelemetryOptions = {}\n): Promise<OpenTelemetryFile> {\n const converter = new OpenTelemetryConverter(options);\n for await (const event of events) {\n converter.add(event);\n }\n return converter.toFile();\n}\n\nclass OpenTelemetryConverter {\n readonly #traceId = crypto.randomBytes(16).toString('hex');\n readonly #sessionSpanId = createSpanId();\n readonly #spans: OpenTelemetrySpan[] = [];\n readonly #events: OpenTelemetrySpanEvent[] = [];\n #processName: string;\n #version = '0.1.0';\n #startTimeUnixNano: string | undefined;\n #endTimeUnixNano: string | undefined;\n\n constructor(private readonly options: ConvertToOpenTelemetryOptions) {\n this.#processName = options.processName ?? '2g';\n }\n\n add(event: ParsedEvent) {\n const eventTime = unixNano(event._t);\n this.#startTimeUnixNano =\n this.#startTimeUnixNano == null ||\n BigInt(eventTime) < BigInt(this.#startTimeUnixNano)\n ? eventTime\n : this.#startTimeUnixNano;\n this.#endTimeUnixNano =\n this.#endTimeUnixNano == null ||\n BigInt(eventTime) > BigInt(this.#endTimeUnixNano)\n ? eventTime\n : this.#endTimeUnixNano;\n\n if (event._e === 'root:init') {\n if (typeof event.version === 'string') this.#version = event.version;\n if (this.#processName === '2g' && typeof event.version === 'string') {\n this.#processName = `2g (v${event.version})`;\n }\n return;\n }\n\n if (typeof event._d === 'number') {\n this.#spans.push(this.#createSpan(event));\n } else {\n this.#events.push(this.#createEvent(event));\n }\n }\n\n toFile(): OpenTelemetryFile {\n const startTimeUnixNano = this.#startTimeUnixNano ?? unixNano(Date.now());\n const endTimeUnixNano = this.#endTimeUnixNano ?? startTimeUnixNano;\n return {\n resourceSpans: [\n {\n resource: {\n attributes: attributes({\n 'service.name': this.#processName,\n 'service.version': this.#version,\n 'process.pid': this.options.pid,\n 'telemetry.sdk.name': '2g',\n 'telemetry.sdk.language': 'nodejs',\n }),\n },\n scopeSpans: [\n {\n scope: { name: '2g' },\n spans: [\n {\n traceId: this.#traceId,\n spanId: this.#sessionSpanId,\n name: this.#processName,\n startTimeUnixNano,\n endTimeUnixNano,\n attributes: attributes({\n 'event_log.kind': 'session',\n }),\n events: this.#events.length ? this.#events : undefined,\n },\n ...this.#spans,\n ],\n },\n ],\n },\n ],\n };\n }\n\n #createSpan(event: ParsedEvent): OpenTelemetrySpan {\n const parsed = splitEventName(event._e);\n const startTimeUnixNano = unixNano(event._t - event._d!);\n const endTimeUnixNano = unixNano(event._t);\n return {\n traceId: this.#traceId,\n spanId: createSpanId(),\n parentSpanId: this.#sessionSpanId,\n name: parsed ? stripSuffix(parsed.name) : event._e,\n startTimeUnixNano,\n endTimeUnixNano,\n attributes: eventAttributes(event, parsed),\n };\n }\n\n #createEvent(event: ParsedEvent): OpenTelemetrySpanEvent {\n const parsed = splitEventName(event._e);\n return {\n timeUnixNano: unixNano(event._t),\n name: parsed ? stripSuffix(parsed.name) : event._e,\n attributes: eventAttributes(event, parsed),\n };\n }\n}\n\nfunction eventAttributes(\n event: ParsedEvent,\n parsed: ReturnType<typeof splitEventName>\n) {\n const values: Record<string, unknown> = {\n 'event.name': event._e,\n };\n if (parsed) {\n values['event.category'] = parsed.category;\n values['event.action'] = parsed.name;\n }\n if (typeof event._w === 'string') values['event.worker.id'] = event._w;\n\n for (const key of Object.keys(event)) {\n if (\n key === '_e' ||\n key === '_t' ||\n key === '_d' ||\n key === '_l' ||\n key === '_w'\n )\n continue;\n values[`event_log.${key}`] = event[key];\n }\n\n return attributes(values);\n}\n\nfunction attributes(values: Record<string, unknown>): OpenTelemetryAttribute[] {\n const result: OpenTelemetryAttribute[] = [];\n for (const [key, value] of Object.entries(values)) {\n const converted = anyValue(value);\n if (converted) result.push({ key, value: converted });\n }\n return result;\n}\n\nfunction anyValue(value: unknown): OpenTelemetryAnyValue | null {\n if (typeof value === 'string') return { stringValue: value };\n if (typeof value === 'boolean') return { boolValue: value };\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) return null;\n return Number.isInteger(value)\n ? { intValue: String(value) }\n : { doubleValue: value };\n }\n if (Array.isArray(value)) {\n return {\n arrayValue: {\n values: value.flatMap(item => {\n const converted = anyValue(item);\n return converted ? [converted] : [];\n }),\n },\n };\n }\n if (value && typeof value === 'object') {\n return {\n kvlistValue: {\n values: attributes(value as Record<string, unknown>),\n },\n };\n }\n return null;\n}\n\nfunction createSpanId() {\n return crypto.randomBytes(8).toString('hex');\n}\n\nfunction unixNano(timeMs: number) {\n return String(BigInt(Math.round(timeMs * 1_000_000)));\n}\n\nfunction splitEventName(value: string) {\n const index = value.indexOf(':');\n if (index < 1) return null;\n return {\n category: value.slice(0, index),\n name: value.slice(index + 1),\n };\n}\n\nfunction stripSuffix(name: string) {\n for (const suffix of STRIP_SUFFIXES) {\n if (name.endsWith(suffix)) return name.slice(0, -suffix.length);\n }\n return name;\n}\n","import fs from 'node:fs';\nimport { parseArgs } from 'node:util';\n\nimport { resolveSession, tap } from '../../tap';\nimport type { ParsedEvent } from '../../types';\nimport { redirectConsoleToStderr } from '../../utils/redirectConsole';\nimport {\n filterEvents,\n formatSessionProcessName,\n parseHelp,\n parseDuration,\n parseSharedTapOptions,\n readJsonlFile,\n readJsonlStdin,\n tapArgOptions,\n warnOnRotationLoss,\n} from '../shared';\nimport { convertToChromeTrace } from './chromeTrace';\nimport { convertToOpenTelemetry } from './opentelemetry';\n\ntype ExportFormat = 'chrome-trace' | 'opentelemetry';\nconst DEFAULT_IDLE_TIMEOUT = 30_000;\n\nexport async function runExportCli(args: string[]) {\n if (parseHelp(args)) {\n printExportHelp();\n return;\n }\n const options = parseExportOptions(args);\n if (options.json) redirectConsoleToStderr();\n let events: AsyncIterable<ParsedEvent> | ParsedEvent[];\n let processName: string | undefined;\n let exportPid: number | undefined;\n\n if (options.selector) {\n const session = await resolveSession(options.selector);\n processName = formatSessionProcessName(session);\n exportPid = session.pid;\n await warnOnRotationLoss(session.sessionDir, '2g export --tail');\n events = tap(session.sessionDir, {\n follow: options.follow,\n debug: options.debug,\n timeout: options.timeout,\n idleTimeout: options.follow ? options.idleTimeout : undefined,\n });\n } else if (options.inputFile) {\n events = readJsonlFile(options.inputFile);\n } else {\n events = readJsonlStdin();\n }\n\n const filteredEvents = filterEvents(events, options);\n const file =\n options.format === 'opentelemetry'\n ? await convertToOpenTelemetry(filteredEvents, {\n pid: exportPid,\n processName,\n })\n : await convertToChromeTrace(filteredEvents, {\n pid: exportPid,\n processName,\n });\n const output = JSON.stringify(file, null, 2);\n if (options.output) fs.writeFileSync(options.output, `${output}\\n`);\n else process.stdout.write(`${output}\\n`);\n}\n\nfunction parseExportOptions(args: string[]) {\n const parsed = parseArgs({\n args,\n allowPositionals: true,\n options: {\n ...tapArgOptions,\n input: { type: 'string' },\n output: { type: 'string', short: 'o' },\n format: { type: 'string' },\n json: { type: 'boolean' },\n timeout: { type: 'string' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n const tapOptions = parseSharedTapOptions(parsed.values);\n const timeout = parseDuration(parsed.values.timeout);\n\n const format = parsed.values.format ?? 'chrome-trace';\n if (!isExportFormat(format)) throw new Error(`Unsupported format: ${format}`);\n if (parsed.positionals[0] && parsed.values.input)\n throw new Error('Use either a session selector or --input, not both');\n if (timeout != null && !tapOptions.follow)\n throw new Error('Use --timeout only with --tail');\n\n return {\n selector: parsed.positionals[0],\n inputFile: parsed.values.input,\n output: parsed.values.output,\n format,\n since: tapOptions.since,\n filter: tapOptions.filter,\n spans: tapOptions.spans,\n debug: tapOptions.debug,\n follow: tapOptions.follow,\n timeout,\n idleTimeout: DEFAULT_IDLE_TIMEOUT,\n json: parsed.values.json ?? false,\n };\n}\n\nfunction isExportFormat(value: string): value is ExportFormat {\n return value === 'chrome-trace' || value === 'opentelemetry';\n}\n\nfunction printExportHelp() {\n process.stdout.write(\n [\n 'Usage: 2g export [selector]',\n '',\n 'Exports session events to Chrome Trace or OTLP JSON.',\n '(Without --tail it reads only the retained window. Rotated out logs may be lost)',\n '',\n '--tail attaches to an already-running session and follows live from that point.',\n ' Run it after the session is up and leave it attached while the workload runs.',\n ' It will automatically stop on 30s idle.',\n 'To trace a full command instead, use `2g record`.',\n '',\n 'Options:',\n ' selector Substring of PID, CWD, or command; a running',\n ' session wins ties',\n ' --input <file> Read JSONL events from a file',\n ' -o, --output <file> Write output to a file',\n ' --format <format> chrome-trace or opentelemetry',\n ' --json Print JSON output',\n ' --since <time> Duration ago (5m, 90s), Unix time, or ISO date',\n ' --filter <pattern> Event name prefix (whole segments), e.g. category,',\n ' category:kind; * wildcards; comma-separated',\n ' --spans Keep only span events (log.span() pairs with a _d',\n ' duration); omit to include point events too. A',\n ' plain \"ms\" payload field is not a span',\n ' --debug Include debug events (only recorded when the',\n ' command ran with LOG_DEBUG set)',\n ' --tail Follow live events after replaying history; stops',\n ' automatically on 30s idle',\n ' --timeout <duration> Also stop tailing after this absolute duration',\n '',\n ].join('\\n')\n );\n}\n","import { parseArgs } from 'node:util';\n\nimport { listSessions } from '../../tap';\nimport { redirectConsoleToStderr } from '../../utils/redirectConsole';\n\nexport async function runPsCli(args: string[] = []) {\n const parsed = parseArgs({\n args,\n allowPositionals: true,\n options: {\n active: { type: 'boolean', short: 'a' },\n json: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n if (parsed.values.json) redirectConsoleToStderr();\n const sessions = (\n await listSessions({ selector: parsed.positionals[0] })\n ).filter(session => !parsed.values.active || session.alive);\n if (parsed.values.json) {\n process.stdout.write(`${JSON.stringify(sessions, null, 2)}\\n`);\n return;\n }\n\n process.stdout.write('PID\\tSTATUS\\tSTARTED\\tCOMMAND\\tCWD\\n');\n for (const session of sessions) {\n process.stdout.write(\n `${escapeTsv(session.pid)}\\t${escapeTsv(\n session.alive ? 'alive' : 'exited'\n )}\\t${escapeTsv(\n new Date(session.startedAt).toISOString()\n )}\\t${escapeTsv(session.command)}\\t${escapeTsv(session.cwd)}\\n`\n );\n }\n}\n\nfunction escapeTsv(value: unknown) {\n return String(value)\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\\t/g, '\\\\t')\n .replace(/\\r/g, '\\\\r')\n .replace(/\\n/g, '\\\\n');\n}\n\nexport function printPsHelp() {\n process.stdout.write(\n [\n 'Usage: 2g ps [selector]',\n '',\n 'Lists recorded sessions, newest first; alive means still running.',\n '',\n 'Options:',\n ' selector Substring of PID, CWD, or command',\n ' --active, -a Show only active sessions',\n ' --json Print sessions as JSON',\n '',\n ].join('\\n')\n );\n}\n","import { spawn } from 'node:child_process';\nimport fs from 'node:fs';\nimport { parseArgs } from 'node:util';\n\nimport { captureEvents } from '../../capture';\nimport { redirectConsoleToStderr } from '../../utils/redirectConsole';\nimport { filterEvents, parseHelp } from '../shared';\nimport { convertToChromeTrace } from '../export/chromeTrace';\nimport { convertToOpenTelemetry } from '../export/opentelemetry';\n\ntype ExportFormat = 'chrome-trace' | 'opentelemetry';\n\n// `record` owns the process it traces: it spawns <command> with event capture\n// wired in, follows its events end-to-end, and writes the trace when it exits.\n// This is the reliable path for a one-off run — there is no window to attach\n// within and nothing to rotate out, so it never returns a partial trace.\nexport async function runRecordCli(args: string[]) {\n if (parseHelp(args)) {\n printRecordHelp();\n return;\n }\n\n // Everything after `--` is the command and its own arguments, verbatim\n const separator = args.indexOf('--');\n const ownArgs = separator === -1 ? args : args.slice(0, separator);\n const command = separator === -1 ? [] : args.slice(separator + 1);\n const options = parseRecordOptions(ownArgs);\n if (!command.length)\n throw new Error(\n 'record needs a command to run: 2g record [options] -- <command> [args...]'\n );\n\n if (options.json) redirectConsoleToStderr();\n\n const capture = captureEvents({\n debug: options.debug,\n filter: options.filter,\n });\n // The trace lands on stdout when there is no -o, so route the child's stdout\n // to stderr to keep it clean; with -o the child can use stdout normally.\n const child = spawn(\n command[0],\n command.slice(1),\n capture.spawnOptions({\n env: process.env,\n stdio: ['inherit', options.output ? 'inherit' : 2, 'inherit'],\n })\n );\n capture.attach(child);\n\n const onSignal = (signal: NodeJS.Signals) => {\n if (signal !== 'SIGINT') {\n try {\n child.kill(signal);\n } catch {}\n }\n };\n process.on('SIGINT', onSignal);\n process.on('SIGTERM', onSignal);\n\n const exited = new Promise<number>((resolve, reject) => {\n child.on('exit', code => resolve(code ?? 0));\n child.on('error', error =>\n reject(new Error(`Failed to run ${command[0]}: ${error.message}`))\n );\n });\n\n const meta = { pid: child.pid, processName: command.join(' ') };\n const filtered = filterEvents(capture, options);\n\n try {\n // Draining the events resolves once the child closes its event pipe (on exit)\n const file =\n options.format === 'opentelemetry'\n ? await convertToOpenTelemetry(filtered, meta)\n : await convertToChromeTrace(filtered, meta);\n const exitCode = await exited;\n\n const output = JSON.stringify(file, null, 2);\n if (options.output) fs.writeFileSync(options.output, `${output}\\n`);\n else process.stdout.write(`${output}\\n`);\n\n if (exitCode) process.exitCode = exitCode;\n } finally {\n process.off('SIGINT', onSignal);\n process.off('SIGTERM', onSignal);\n }\n}\n\nfunction parseRecordOptions(args: string[]) {\n const parsed = parseArgs({\n args,\n allowPositionals: true,\n options: {\n filter: { type: 'string', multiple: true },\n spans: { type: 'boolean' },\n debug: { type: 'boolean' },\n output: { type: 'string', short: 'o' },\n format: { type: 'string' },\n json: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n\n const format = parsed.values.format ?? 'chrome-trace';\n if (!isExportFormat(format)) throw new Error(`Unsupported format: ${format}`);\n\n return {\n output: parsed.values.output,\n format,\n filter: parsed.values.filter\n ?.flatMap(value => value.split(','))\n .map(item => item.trim())\n .filter(Boolean),\n spans: parsed.values.spans === true,\n debug: parsed.values.debug === true,\n json: parsed.values.json ?? false,\n };\n}\n\nfunction isExportFormat(value: string): value is ExportFormat {\n return value === 'chrome-trace' || value === 'opentelemetry';\n}\n\nfunction printRecordHelp() {\n process.stdout.write(\n [\n 'Usage: 2g record [options] -- <command> [args...]',\n '',\n 'Runs <command>, traces the events it emits, and writes the trace on exit.',\n '',\n 'This is the reliable way to capture a one-off run (a build, a script): 2g',\n 'owns the process, so the trace is complete end-to-end with no window to',\n 'attach within and nothing to rotate out. To trace an already-running server',\n 'instead, use `2g export <selector> --tail`.',\n '',\n 'Options:',\n ' -o, --output <file> Write the trace to a file (default: stdout)',\n ' --format <format> chrome-trace or opentelemetry',\n ' --json Print JSON output',\n ' --filter <pattern> Event name prefix (whole segments), e.g. category,',\n ' category:kind; * wildcards; comma-separated',\n ' --spans Keep only span events (log.span() pairs with a _d',\n ' duration); omit to include point events too',\n ' --debug Enable and export debug events; no LOG_DEBUG needed',\n '',\n 'Example:',\n ' 2g record -o trace.json -- expo export # run & trace a build end-to-end',\n '',\n ].join('\\n')\n );\n}\n","import { parseArgs } from 'node:util';\n\nimport { resolveSession, tap } from '../../tap';\nimport { redirectConsoleToStderr } from '../../utils/redirectConsole';\nimport { formatPrettyEvent, shouldColorizeStream } from '../../utils/pretty';\nimport {\n parseHelp,\n parseSharedTapOptions,\n tapArgOptions,\n warnOnRotationLoss,\n} from '../shared';\n\nexport async function runTapCli(args: string[]) {\n if (parseHelp(args)) {\n printTapHelp();\n return;\n }\n const options = parseTapOptions(args);\n if (options.json) redirectConsoleToStderr();\n const session = await resolveSession(options.selector);\n await warnOnRotationLoss(session.sessionDir, '2g tap --tail');\n const colorizePretty = shouldColorizeStream(process.stdout);\n for await (const event of tap(session.sessionDir, options)) {\n if (options.pretty) {\n process.stdout.write(\n `${formatPrettyEvent(event, {\n colorize: colorizePretty,\n stream: process.stdout,\n })}\\n`\n );\n } else {\n process.stdout.write(`${JSON.stringify(event)}\\n`);\n }\n }\n}\n\nfunction parseTapOptions(args: string[]) {\n const parsed = parseArgs({\n args,\n allowPositionals: true,\n options: {\n ...tapArgOptions,\n format: { type: 'string' },\n json: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n const tapOptions = parseSharedTapOptions(parsed.values);\n if (parsed.values.json && parsed.values.format === 'pretty')\n throw new Error('Use either --json or --format pretty, not both');\n\n return {\n selector: parsed.positionals[0],\n since: tapOptions.since,\n follow: tapOptions.follow,\n filter: tapOptions.filter,\n spans: tapOptions.spans,\n debug: tapOptions.debug,\n json: parsed.values.json ?? false,\n pretty: parsed.values.json ? false : parsed.values.format === 'pretty',\n };\n}\n\nfunction printTapHelp() {\n process.stdout.write(\n [\n 'Usage: 2g tap [selector]',\n '',\n 'Replays retained session history as JSONL, oldest first.',\n '',\n 'Options:',\n ' selector Substring of PID, CWD, or command; a running',\n ' session wins ties',\n ' --since <time> Duration ago (5m, 90s), Unix time, or ISO date',\n ' --filter <pattern> Event name prefix (whole segments), e.g. category,',\n ' category:kind; * wildcards; comma-separated',\n ' --spans Keep only span events (log.span() pairs with a _d',\n ' duration); omit to include point events too. A',\n ' plain \"ms\" payload field is not a span',\n ' --debug Include debug events (only recorded when the',\n ' command ran with LOG_DEBUG set)',\n ' --format pretty Print a readable line per event',\n ' --tail Follow live events after replaying history; runs',\n ' until killed (use export with a timeout for a',\n ' bounded follow)',\n '',\n ].join('\\n')\n );\n}\n","#!/usr/bin/env node\nimport { fileURLToPath } from 'node:url';\n\nimport { printCleanHelp, runCleanCli } from './commands/clean';\nimport { runExportCli } from './commands/export';\nimport { printPsHelp, runPsCli } from './commands/ps';\nimport { runRecordCli } from './commands/record';\nimport { runTapCli } from './commands/tap';\nimport { parseHelp } from './commands/shared';\n\nexport async function main(argv = process.argv.slice(2)) {\n const [command, ...args] = argv;\n\n if (\n !command ||\n command === '--help' ||\n command === '-h' ||\n command === 'help'\n ) {\n printHelp();\n return 0;\n }\n\n switch (command) {\n case 'typegen': {\n const { runTypegenCli } = await import('./commands/typegen');\n runTypegenCli(args);\n return 0;\n }\n case 'ps':\n if (parseHelp(args)) {\n printPsHelp();\n return 0;\n }\n await runPsCli(args);\n return 0;\n case 'tap':\n await runTapCli(args);\n return 0;\n case 'clean':\n if (parseHelp(args)) {\n printCleanHelp();\n return 0;\n }\n runCleanCli(args);\n return 0;\n case 'record':\n await runRecordCli(args);\n return 0;\n case 'export':\n await runExportCli(args);\n return 0;\n default:\n throw new Error(`Unknown command: ${command}`);\n }\n}\n\nfunction printHelp() {\n process.stdout.write(\n [\n 'Usage: 2g <command>',\n '',\n 'Reads structured JSONL event logs that instrumented CLIs record during runs',\n 'into the system temp dir, with no setup: run a command, then tap it here.',\n '',\n 'Commands:',\n ' ps [selector] List recorded sessions',\n ' --active, -a (running only) --json',\n '',\n ' tap [selector] Replay session events as JSONL, oldest first',\n ' --since <time> --filter <pattern> --spans --debug --format pretty',\n ' --tail (follow live events after replay; runs until killed)',\n '',\n ' record -- <command> Run a command, trace it end-to-end, write on exit',\n ' -o, --output <file> --format chrome-trace|opentelemetry --json',\n ' --filter <pattern> --spans --debug',\n '',\n ' export [selector] Export a past or live (--tail) session',\n ' --input <jsonl-file> -o, --output <file> --json',\n ' --format chrome-trace|opentelemetry',\n ' --since <time> --filter <pattern> --spans --debug',\n ' --tail --timeout <duration> (absolute; tail also stops after 30s idle)',\n '',\n ' typegen List every event name/payload a project can emit',\n ' -p, --project <tsconfig> -o, --output <file> --format dts|json --json',\n '',\n ' clean Remove stale sessions',\n ' --all, -a (remove all exited sessions) --json',\n '',\n 'Typical use:',\n ' 2g ps -a # what is running now?',\n ' 2g tap \"expo start\" --tail # follow live events',\n ' 2g tap \"expo start\" --since 5m --format pretty # recent history, readable',\n ' 2g tap \"expo start\" --filter metro:bundling # narrow to one area',\n '',\n 'Trace a run to a flame chart:',\n ' 2g record -o trace.json -- expo export # run & trace a build',\n ' 2g export \"expo start\" --tail -o trace.json # attach to a running server',\n ' 2g export \"expo start\" -o trace.json # after the fact (partial)',\n '',\n 'Selectors match sessions by substring of PID, CWD, or command. If several',\n 'match, and exactly one of them is running, it is chosen; otherwise 2g errors',\n 'and lists the candidates.',\n '',\n '--filter takes comma-separated event-name prefixes matched on whole',\n 'segments: \"category\" and \"category:kind\" both match \"category:kind:test\";',\n '* matches anything. Discover names by tapping unfiltered or via typegen.',\n '',\n '--since accepts a duration ago (5m, 90s, 1h30m), Unix time, or ISO date.',\n '--spans keeps only span events (log.span() pairs with a \"_d\" duration in',\n 'ms); without it, point events are included alongside spans.',\n '',\n 'Events are single JSON lines: {\"_e\":\"category:kind\",\"_t\":<epoch ms>,...}.',\n '\"_d\" is a span duration, \"_w\" a worker id; debug events need --debug.',\n '',\n 'Set LOG_EVENTS=<file|fd> on an instrumented command to redirect its events.',\n 'Debug events are only recorded when the command runs with LOG_DEBUG set.',\n '',\n 'Pass LOG_DEBUG=<filter> when debugging; it also mirrors matching events to',\n 'stderr. Reading them back needs --debug.',\n '',\n 'Run 2g <command> --help for per-command help.',\n '',\n ].join('\\n')\n );\n}\n\nif (isCliEntrypoint()) {\n main()\n .then(code => {\n process.exitCode = code;\n })\n .catch(error => {\n process.stderr.write(\n `${error instanceof Error ? error.message : String(error)}\\n`\n );\n process.exitCode = 1;\n });\n}\n\nfunction isCliEntrypoint() {\n try {\n return process.argv[1] === fileURLToPath(import.meta.url);\n } catch {\n return false;\n }\n}\n"],"names":["runCleanCli","args","options","parseCleanOptions","parsed","parseArgs","all","type","short","json","help","values","redirectConsoleToStderr","removed","cleanExitedSessionsSync","cleanStaleSessionsSync","process","stdout","write","JSON","stringify","tapArgOptions","since","filter","multiple","spans","debug","tail","async","warnOnRotationLoss","sessionDir","remedy","detectRotationLoss","console","warn","readJsonlStream","stream","rl","createInterface","input","line","event","parseEventLine","filterEvents","events","eventFilter","compileEventFilter","parseSince","matchesTapOptions","parseSharedTapOptions","flatMap","value","split","map","item","trim","Boolean","follow","parseHelp","allowPositionals","strict","STRIP_SUFFIXES","convertToChromeTrace","converter","TraceConverter","add","toTraceFile","pending","tracks","Map","pid","processName","version","constructor","this","_e","splitEventName","index","indexOf","category","name","slice","track","getTrack","_w","undefined","extractArgs","key","Object","keys","startsWith","length","_d","push","kind","stripSuffix","cat","ts","Math","round","_t","dur","lane","base","Infinity","traceEvents","ph","tids","nextTid","displayName","laneCount","max","assignLanes","tid","set","sort_index","get","s","metadata","source","convertedAt","Date","toISOString","startTime","startTimestampMs","worker","has","order","sort","a","b","lanes","span","end","stack","pop","top","suffix","endsWith","convertToOpenTelemetry","OpenTelemetryConverter","toFile","traceId","crypto","randomBytes","toString","sessionSpanId","createSpanId","startTimeUnixNano","endTimeUnixNano","eventTime","unixNano","BigInt","createSpan","createEvent","now","resourceSpans","resource","attributes","scopeSpans","scope","spanId","parentSpanId","eventAttributes","timeUnixNano","result","entries","converted","anyValue","stringValue","boolValue","Number","isFinite","isInteger","intValue","String","doubleValue","Array","isArray","arrayValue","kvlistValue","timeMs","runExportCli","printExportHelp","join","parseExportOptions","output","format","timeout","tapOptions","parseDuration","duration","parseDurationValue","Error","isExportFormat","positionals","selector","inputFile","idleTimeout","exportPid","session","resolveSession","formatSessionProcessName","command","tap","readJsonlFile","file","fs","createReadStream","encoding","readJsonlStdin","stdin","filteredEvents","writeFileSync","escapeTsv","replace","runRecordCli","printRecordHelp","separator","ownArgs","parseRecordOptions","capture","captureEvents","child","spawn","spawnOptions","env","stdio","attach","onSignal","signal","kill","on","exited","Promise","resolve","reject","code","error","message","meta","filtered","exitCode","off","runTapCli","printTapHelp","parseTapOptions","pretty","colorizePretty","shouldColorizeStream","formatPrettyEvent","colorize","main","argv","printHelp","runTypegenCli","import","printPsHelp","runPsCli","active","sessions","listSessions","alive","startedAt","cwd","printCleanHelp","isCliEntrypoint","fileURLToPath","url","then","catch","stderr"],"mappings":"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"}
|