ptywright 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/agent.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { a as formatAgentLaunchPlan, i as runAgentSpecPath, n as replayAgentRecordPath, r as runAgentSpec, t as defaultSpecNameForPath } from "./runner-C1gPRyCM.mjs";
1
+ import { a as formatAgentLaunchPlan, i as runAgentSpecPath, n as replayAgentRecordPath, r as runAgentSpec, t as defaultSpecNameForPath } from "./runner-GIEf0C6d.mjs";
2
2
  export { defaultSpecNameForPath, formatAgentLaunchPlan, replayAgentRecordPath, runAgentSpec, runAgentSpecPath };
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bun
2
- import { t as main } from "../cli-PnG6UR43.mjs";
2
+ import { t as main } from "../cli-IXmvK56U.mjs";
3
3
  //#region src/bin/ptywright.ts
4
4
  await main();
5
5
  //#endregion
@@ -1,16 +1,16 @@
1
1
  import { n as loadPtywrightConfig } from "./config-bGg636EW.mjs";
2
- import { C as writeAgentManifestPath, D as escapeHtml, E as escapeAttribute, O as normalizeAgentFlowSpec, S as validateAgentManifestFiles, T as readAgentCassettePath, _ as formatArgv, b as isAgentManifestLike, c as launchAgentBrowser, d as AGENT_RUN_RECORD_SCHEMA_URL, f as agentRunModeSchema, g as writeAgentRunRecordPath, h as readAgentRunRecordPath, i as runAgentSpecPath, k as sanitizeArtifactName, l as createAgentTemplateSpec, m as isAgentRunRecordLike, n as replayAgentRecordPath, o as resolveAgentLaunchTarget, p as formatAgentArgv, s as normalizeAgentFlowSpecWithConfig, u as loadAgentSpec, v as AGENT_MANIFEST_FILE_NAME, w as isAgentCassetteLike, x as readAgentManifestPath, y as agentManifestPath } from "./runner-C1gPRyCM.mjs";
2
+ import { C as writeAgentManifestPath, D as escapeHtml, E as escapeAttribute, O as normalizeAgentFlowSpec, S as validateAgentManifestFiles, T as readAgentCassettePath, _ as formatArgv, b as isAgentManifestLike, c as launchAgentBrowser, d as AGENT_RUN_RECORD_SCHEMA_URL, f as agentRunModeSchema, g as writeAgentRunRecordPath, h as readAgentRunRecordPath, i as runAgentSpecPath, k as sanitizeArtifactName, l as createAgentTemplateSpec, m as isAgentRunRecordLike, n as replayAgentRecordPath, o as resolveAgentLaunchTarget, p as formatAgentArgv, s as normalizeAgentFlowSpecWithConfig, u as loadAgentSpec, v as AGENT_MANIFEST_FILE_NAME, w as isAgentCassetteLike, x as readAgentManifestPath, y as agentManifestPath } from "./runner-GIEf0C6d.mjs";
3
3
  import { a as sameArgv, i as diffCommandMaps, r as formatZodIssues } from "./manifest_files-DW80c1H7.mjs";
4
4
  import { i as portableCliPath, n as mergeProcessEnv, o as relativeHref, s as samePath } from "./env-DPYHo-zH.mjs";
5
- import { d as resolvePtyBackend, u as createDefaultPtyAdapter } from "./runner-wW_DCBX7.mjs";
6
- import { a as resolveScriptManifestPath, c as relocateScriptManifestCommands, d as resolveScriptRunSummaryPath, f as runScriptPath, i as readScriptManifestPath, l as resolveManifestPrimaryPath$1, n as runAllScripts, o as validateScriptManifest, r as findScriptSummaryManifest, t as createPtywrightServer, u as readScriptRunSummaryPath } from "./server-DMnnXjWv.mjs";
7
- import { c as createPtyCassetteReplay, i as formatPtyCassetteInspectLines, l as readPtyCassettePath, o as inspectPtyCassettePath, r as createPtyCassetteRecorder, t as wrapPtyLike, v as validatePtyCassette } from "./pty_like-BjeBibSL.mjs";
5
+ import { d as resolvePtyBackend, u as createDefaultPtyAdapter } from "./runner-BHXXwxYp.mjs";
6
+ import { a as resolveScriptManifestPath, c as relocateScriptManifestCommands, d as resolveScriptRunSummaryPath, f as runScriptPath, i as readScriptManifestPath, l as resolveManifestPrimaryPath$1, n as runAllScripts, o as validateScriptManifest, r as findScriptSummaryManifest, t as createPtywrightServer, u as readScriptRunSummaryPath } from "./server-ceZ1-s_J.mjs";
7
+ import { c as createPtyCassetteReplay, i as formatPtyCassetteInspectLines, l as readPtyCassettePath, o as inspectPtyCassettePath, r as createPtyCassetteRecorder, t as wrapPtyLike, v as validatePtyCassette } from "./pty_like-DWIlWGgA.mjs";
8
8
  import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
9
9
  import { basename, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
10
10
  import { z } from "zod";
11
+ import { Buffer } from "node:buffer";
11
12
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
12
13
  import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
13
- import { Buffer } from "node:buffer";
14
14
  //#region src/agent/check_summary_schema.ts
15
15
  const AGENT_CHECK_SCHEMA_URL = "https://ptywright.local/schemas/ptywright-agent-check.schema.json";
16
16
  const countSummarySchema$1 = z.object({
package/dist/cli.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { t as main } from "./cli-PnG6UR43.mjs";
1
+ import { t as main } from "./cli-IXmvK56U.mjs";
2
2
  export { main };
@@ -0,0 +1,18 @@
1
+ import { Buffer } from "node:buffer";
2
+ //#region src/pty-cassette/data.ts
3
+ function dataToBytes(data) {
4
+ if (typeof data === "string") return Buffer.from(data, "utf8");
5
+ if (data instanceof ArrayBuffer) return new Uint8Array(data);
6
+ return data;
7
+ }
8
+ function dataToBase64(data) {
9
+ return Buffer.from(dataToBytes(data)).toString("base64");
10
+ }
11
+ function base64ToBytes(dataBase64) {
12
+ return Buffer.from(dataBase64, "base64");
13
+ }
14
+ function byteLength(data) {
15
+ return dataToBytes(data).byteLength;
16
+ }
17
+ //#endregion
18
+ export { dataToBytes as i, byteLength as n, dataToBase64 as r, base64ToBytes as t };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as createPtywrightServer } from "./server-DMnnXjWv.mjs";
1
+ import { t as createPtywrightServer } from "./server-ceZ1-s_J.mjs";
2
2
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
3
  //#region src/index.ts
4
4
  const { server, sessions } = createPtywrightServer();
package/dist/mcp.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { t as createPtywrightServer } from "./server-DMnnXjWv.mjs";
1
+ import { t as createPtywrightServer } from "./server-ceZ1-s_J.mjs";
2
2
  export { createPtywrightServer };
@@ -1,4 +1,5 @@
1
- import { S as dataToBytes, _ as ptyCassetteSchema, a as inspectPtyCassette, b as byteLength, c as createPtyCassetteReplay, d as PTY_CASSETTE_SCHEMA_URL, f as normalizePtyCassette, g as ptyCassetteResizeEventSchema, h as ptyCassetteExitEventSchema, i as formatPtyCassetteInspectLines, l as readPtyCassettePath, m as ptyCassetteEventSchema, n as PtyCassetteRecorder, o as inspectPtyCassettePath, p as ptyCassetteDataEventSchema, r as createPtyCassetteRecorder, s as PtyCassetteReplay, t as wrapPtyLike, u as writePtyCassettePath, v as validatePtyCassette, x as dataToBase64, y as base64ToBytes } from "./pty_like-BjeBibSL.mjs";
1
+ import { i as dataToBytes, n as byteLength, r as dataToBase64, t as base64ToBytes } from "./data-sdbf3IDh.mjs";
2
+ import { _ as ptyCassetteSchema, a as inspectPtyCassette, c as createPtyCassetteReplay, d as PTY_CASSETTE_SCHEMA_URL, f as normalizePtyCassette, g as ptyCassetteResizeEventSchema, h as ptyCassetteExitEventSchema, i as formatPtyCassetteInspectLines, l as readPtyCassettePath, m as ptyCassetteEventSchema, n as PtyCassetteRecorder, o as inspectPtyCassettePath, p as ptyCassetteDataEventSchema, r as createPtyCassetteRecorder, s as PtyCassetteReplay, t as wrapPtyLike, u as writePtyCassettePath, v as validatePtyCassette } from "./pty_like-DWIlWGgA.mjs";
2
3
  //#region src/pty-cassette/bun_terminal.ts
3
4
  function wrapBunTerminalOptions(options, recorder) {
4
5
  const onData = options.data;
@@ -1,23 +1,7 @@
1
+ import { n as byteLength, r as dataToBase64, t as base64ToBytes } from "./data-sdbf3IDh.mjs";
1
2
  import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
3
  import { dirname } from "node:path";
3
4
  import { z } from "zod";
4
- import { Buffer } from "node:buffer";
5
- //#region src/pty-cassette/data.ts
6
- function dataToBytes(data) {
7
- if (typeof data === "string") return Buffer.from(data, "utf8");
8
- if (data instanceof ArrayBuffer) return new Uint8Array(data);
9
- return data;
10
- }
11
- function dataToBase64(data) {
12
- return Buffer.from(dataToBytes(data)).toString("base64");
13
- }
14
- function base64ToBytes(dataBase64) {
15
- return Buffer.from(dataBase64, "base64");
16
- }
17
- function byteLength(data) {
18
- return dataToBytes(data).byteLength;
19
- }
20
- //#endregion
21
5
  //#region src/pty-cassette/schema.ts
22
6
  const PTY_CASSETTE_SCHEMA_URL = "https://ptywright.local/schemas/ptywright-pty-cassette.schema.json";
23
7
  const base64Schema = z.string().refine((value) => value.length % 4 === 0 && /^[A-Za-z0-9+/]*={0,2}$/.test(value), { message: "expected base64-encoded data" });
@@ -401,4 +385,4 @@ function dispose(disposable) {
401
385
  disposable.dispose();
402
386
  }
403
387
  //#endregion
404
- export { dataToBytes as S, ptyCassetteSchema as _, inspectPtyCassette as a, byteLength as b, createPtyCassetteReplay as c, PTY_CASSETTE_SCHEMA_URL as d, normalizePtyCassette as f, ptyCassetteResizeEventSchema as g, ptyCassetteExitEventSchema as h, formatPtyCassetteInspectLines as i, readPtyCassettePath as l, ptyCassetteEventSchema as m, PtyCassetteRecorder as n, inspectPtyCassettePath as o, ptyCassetteDataEventSchema as p, createPtyCassetteRecorder as r, PtyCassetteReplay as s, wrapPtyLike as t, writePtyCassettePath as u, validatePtyCassette as v, dataToBase64 as x, base64ToBytes as y };
388
+ export { ptyCassetteSchema as _, inspectPtyCassette as a, createPtyCassetteReplay as c, PTY_CASSETTE_SCHEMA_URL as d, normalizePtyCassette as f, ptyCassetteResizeEventSchema as g, ptyCassetteExitEventSchema as h, formatPtyCassetteInspectLines as i, readPtyCassettePath as l, ptyCassetteEventSchema as m, PtyCassetteRecorder as n, inspectPtyCassettePath as o, ptyCassetteDataEventSchema as p, createPtyCassetteRecorder as r, PtyCassetteReplay as s, wrapPtyLike as t, writePtyCassettePath as u, validatePtyCassette as v };
@@ -1,12 +1,13 @@
1
1
  import { n as mergeProcessEnv, o as relativeHref, t as envTruthy } from "./env-DPYHo-zH.mjs";
2
- import { a as fnv1a32, c as extractStyle, d as styleKey, f as encodeSgrMouse, i as TraceRecorder, l as findMeaningfulEndCol, n as sleep, o as snapshotGrid, p as encodeKey, r as applyTextMaskRules, s as snapshotLines, t as TerminalSession, u as isDefaultStyle } from "./terminal_session-DJKr-O3X.mjs";
2
+ import { a as styleKey, i as isDefaultStyle, n as extractStyle, r as findMeaningfulEndCol } from "./style-BtIUv5H0.mjs";
3
+ import { a as fnv1a32, c as encodeSgrMouse, i as TraceRecorder, l as encodeKey, n as sleep, o as snapshotGrid, r as applyTextMaskRules, s as snapshotLines, t as TerminalSession } from "./terminal_session-MX_vWpRG.mjs";
3
4
  import { createRequire } from "node:module";
4
5
  import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
5
6
  import { basename, dirname, extname, isAbsolute, join, resolve } from "node:path";
6
7
  import { pathToFileURL } from "node:url";
7
8
  import { z } from "zod";
8
- import { spawn } from "bun-pty";
9
9
  import { Terminal } from "@xterm/headless";
10
+ import { spawn } from "bun-pty";
10
11
  //#region src/pty/bun_pty_adapter.ts
11
12
  function toForkOptions(options) {
12
13
  return {
@@ -1,5 +1,7 @@
1
1
  import { a as sameArgv, n as validateManifestFiles, r as formatZodIssues, t as collectManifestFiles } from "./manifest_files-DW80c1H7.mjs";
2
2
  import { t as envTruthy } from "./env-DPYHo-zH.mjs";
3
+ import { t as base64ToBytes } from "./data-sdbf3IDh.mjs";
4
+ import { a as styleKey, i as isDefaultStyle, n as extractStyle, r as findMeaningfulEndCol, t as DEFAULT_STYLE } from "./style-BtIUv5H0.mjs";
3
5
  import { createRequire } from "node:module";
4
6
  import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
5
7
  import { basename, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
@@ -7,6 +9,7 @@ import { pathToFileURL } from "node:url";
7
9
  import { z } from "zod";
8
10
  import { createServer } from "node:http";
9
11
  import { chromium } from "playwright";
12
+ import { Terminal } from "@xterm/headless";
10
13
  import { spawn } from "node:child_process";
11
14
  //#region src/agent/normalize.ts
12
15
  function applyAgentMasks(input, rules = [], options = {}) {
@@ -1390,23 +1393,23 @@ function renderArtifactViewerShellCss() {
1390
1393
  }
1391
1394
  .viewer-stage {
1392
1395
  display: grid;
1393
- grid-template-columns: max-content;
1394
- grid-template-rows: max-content;
1396
+ grid-template-columns: minmax(0, 1fr);
1397
+ grid-template-rows: minmax(0, 1fr);
1395
1398
  min-width: 0;
1396
1399
  min-height: 0;
1397
- justify-content: start;
1400
+ justify-items: center;
1398
1401
  align-content: start;
1399
- overflow: auto;
1402
+ overflow: hidden;
1400
1403
  background:
1401
1404
  radial-gradient(circle at top left, rgba(121, 192, 255, 0.1), transparent 32%),
1402
1405
  #060a13;
1403
1406
  padding: 14px;
1404
1407
  }
1405
1408
  .viewer-viewport {
1406
- width: var(--config-viewport-width);
1407
- height: var(--config-viewport-height);
1408
- max-width: none;
1409
- max-height: none;
1409
+ width: min(var(--config-viewport-width), 100%);
1410
+ height: min(var(--config-viewport-height), 100%);
1411
+ max-width: 100%;
1412
+ max-height: 100%;
1410
1413
  overflow: auto;
1411
1414
  overscroll-behavior: contain;
1412
1415
  border: 0;
@@ -1416,7 +1419,7 @@ function renderArtifactViewerShellCss() {
1416
1419
  box-shadow: 0 18px 52px rgba(0, 0, 0, 0.34);
1417
1420
  }
1418
1421
  .viewer-viewport[data-mobile="true"] {
1419
- width: var(--config-viewport-width);
1422
+ width: min(var(--config-viewport-width), 100%);
1420
1423
  }
1421
1424
  .dom-viewport {
1422
1425
  overflow: hidden;
@@ -1455,8 +1458,8 @@ function renderArtifactViewerShellCss() {
1455
1458
  padding: 0;
1456
1459
  }
1457
1460
  .viewer-viewport {
1458
- width: var(--config-viewport-width);
1459
- height: var(--config-viewport-height);
1461
+ width: min(var(--config-viewport-width), 100%);
1462
+ height: min(var(--config-viewport-height), 100%);
1460
1463
  border-radius: 0;
1461
1464
  }
1462
1465
  }`;
@@ -1511,22 +1514,19 @@ function renderConfiguredViewportStyle(viewport) {
1511
1514
  return `--config-viewport-width: ${viewport.width}px; --config-viewport-height: ${viewport.height}px;`;
1512
1515
  }
1513
1516
  //#endregion
1514
- //#region src/agent/report_view_options.ts
1515
- function isMobileViewport(viewport) {
1516
- return Boolean(viewport?.isMobile || viewport?.hasTouch || (viewport?.width ?? 9999) <= 720);
1517
+ //#region src/agent/report_launch_args.ts
1518
+ function readReportLaunchArgSets(result) {
1519
+ return [readFlowLaunchArgs(result.flowPath), readCassetteLaunchArgs(result.replaySourceCassettePath ?? result.cassettePath)];
1517
1520
  }
1518
- function resolveReportViewOptions(result) {
1519
- const launchArgSets = [readFlowLaunchArgs(result.flowPath), readCassetteLaunchArgs(result.replaySourceCassettePath ?? result.cassettePath)];
1520
- const screenModeArg = readFlagValueFromArgSets(launchArgSets, "--experimental-screen-mode");
1521
- const themeArg = readFlagValueFromArgSets(launchArgSets, "--theme");
1522
- const fontSizeArg = readFlagValueFromArgSets(launchArgSets, "--font-size");
1523
- const lineHeightArg = readFlagValueFromArgSets(launchArgSets, "--line-height");
1524
- return {
1525
- fontSize: parsePositiveNumber(fontSizeArg) ?? 15,
1526
- lineHeight: parsePositiveNumber(lineHeightArg) ?? 1.6,
1527
- screenMode: screenModeArg && screenModeArg !== "termvision" ? "plain" : "termvision",
1528
- theme: themeArg === "light" ? "light" : "dark"
1529
- };
1521
+ function readFlagValueFromArgSets(argSets, flag) {
1522
+ for (const args of argSets) {
1523
+ const value = readFlagValue(args, flag);
1524
+ if (value !== void 0) return value;
1525
+ }
1526
+ }
1527
+ function readFlagValue(args, flag) {
1528
+ const index = args.indexOf(flag);
1529
+ return index >= 0 ? args[index + 1] : void 0;
1530
1530
  }
1531
1531
  function readCassetteLaunchArgs(cassettePath) {
1532
1532
  try {
@@ -1545,21 +1545,41 @@ function readFlowLaunchArgs(flowPath) {
1545
1545
  function normalizeStringArray(value) {
1546
1546
  return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
1547
1547
  }
1548
- function readFlagValueFromArgSets(argSets, flag) {
1549
- for (const args of argSets) {
1550
- const value = readFlagValue(args, flag);
1551
- if (value !== void 0) return value;
1552
- }
1548
+ //#endregion
1549
+ //#region src/agent/report_view_options.ts
1550
+ function isMobileViewport(viewport) {
1551
+ return Boolean(viewport?.isMobile || viewport?.hasTouch || (viewport?.width ?? 9999) <= 720);
1553
1552
  }
1554
- function readFlagValue(args, flag) {
1555
- const index = args.indexOf(flag);
1556
- return index >= 0 ? args[index + 1] : void 0;
1553
+ function resolveReportViewOptions(result, config) {
1554
+ const launchArgSets = readReportLaunchArgSets(result);
1555
+ const ptyReplayArg = readFlagValueFromArgSets(launchArgSets, "--pty-replay");
1556
+ const screenModeArg = readFlagValueFromArgSets(launchArgSets, "--experimental-screen-mode");
1557
+ const themeArg = readFlagValueFromArgSets(launchArgSets, "--theme");
1558
+ const fontSizeArg = readFlagValueFromArgSets(launchArgSets, "--font-size");
1559
+ const lineHeightArg = readFlagValueFromArgSets(launchArgSets, "--line-height");
1560
+ const stableFrameConfig = resolveStableFrameConfig$1(config, result.name);
1561
+ const themeOverride = ptyReplayArg && stableFrameConfig.enabled !== false && !stableFrameConfig.skip ? stableFrameConfig.theme : void 0;
1562
+ return {
1563
+ fontSize: parsePositiveNumber(fontSizeArg) ?? 15,
1564
+ lineHeight: parsePositiveNumber(lineHeightArg) ?? 1.6,
1565
+ screenMode: screenModeArg && screenModeArg !== "termvision" ? "plain" : "termvision",
1566
+ theme: themeOverride ?? (themeArg === "light" ? "light" : "dark")
1567
+ };
1557
1568
  }
1558
1569
  function parsePositiveNumber(value) {
1559
1570
  if (value === void 0) return void 0;
1560
1571
  const parsed = Number(value);
1561
1572
  return Number.isFinite(parsed) && parsed > 0 ? parsed : void 0;
1562
1573
  }
1574
+ function resolveStableFrameConfig$1(config, flowName) {
1575
+ const stableFrames = config?.agent?.report?.stableFrames;
1576
+ const flowConfig = stableFrames?.flows?.[flowName];
1577
+ return {
1578
+ enabled: flowConfig?.enabled ?? stableFrames?.enabled,
1579
+ skip: flowConfig?.skip ?? stableFrames?.skip,
1580
+ theme: flowConfig?.theme ?? stableFrames?.theme ?? "dark"
1581
+ };
1582
+ }
1563
1583
  //#endregion
1564
1584
  //#region src/agent/report_artifact_viewer.ts
1565
1585
  function renderArtifactViewerHtml(args) {
@@ -1584,6 +1604,358 @@ function renderArtifactViewerHtml(args) {
1584
1604
  });
1585
1605
  }
1586
1606
  //#endregion
1607
+ //#region src/agent/report_pty_stable_frame.ts
1608
+ async function extractPtyReplayStableFrameForReport(args) {
1609
+ const replayPathArg = readFlagValueFromArgSets(readReportLaunchArgSets(args.result), "--pty-replay");
1610
+ if (!replayPathArg) return null;
1611
+ const config = resolveStableFrameConfig(args.config, args.result.name);
1612
+ if (config.enabled === false || config.skip) return null;
1613
+ const replayPath = resolvePtyReplayPath(replayPathArg, args.config);
1614
+ if (!existsSync(replayPath)) return null;
1615
+ const recording = JSON.parse(readFileSync(replayPath, "utf8"));
1616
+ const events = Array.isArray(recording.events) ? recording.events : [];
1617
+ const firstResize = events.find((event) => event.type === "resize");
1618
+ const terminal = new Terminal({
1619
+ allowProposedApi: true,
1620
+ cols: config.cols ?? recording.terminal?.cols ?? recording.command?.cols ?? recording.cols ?? firstResize?.cols ?? 80,
1621
+ convertEol: true,
1622
+ rows: config.rows ?? recording.terminal?.rows ?? recording.command?.rows ?? recording.rows ?? firstResize?.rows ?? 24,
1623
+ scrollback: 2e4
1624
+ });
1625
+ try {
1626
+ return await extractStableFrame({
1627
+ config,
1628
+ events,
1629
+ terminal
1630
+ });
1631
+ } finally {
1632
+ terminal.dispose();
1633
+ }
1634
+ }
1635
+ function renderPtyReplayStableFramePreviewDocument(args) {
1636
+ const targetCols = resolveTargetCols({
1637
+ config: resolveStableFrameConfig(args.config, args.flowName),
1638
+ fontSize: args.viewOptions.fontSize,
1639
+ frameCols: args.frame.cols,
1640
+ viewport: args.viewport
1641
+ });
1642
+ const body = renderAittyPreviewBody({
1643
+ snapshot: renderStableFrameDom(args.frame, targetCols),
1644
+ snapshotLayout: {
1645
+ cols: targetCols,
1646
+ fontSize: args.viewOptions.fontSize,
1647
+ lineHeight: args.viewOptions.lineHeight,
1648
+ paddingInline: isMobileViewport(args.viewport) ? 16 : 32,
1649
+ rows: args.frame.rows
1650
+ },
1651
+ viewOptions: args.viewOptions
1652
+ });
1653
+ const style = renderAittyPreviewCss(args.viewOptions);
1654
+ const assetTags = renderAittyPreviewAssetTags(args.aittyAssets);
1655
+ return `<!doctype html>
1656
+ <html lang="en" data-theme="${escapeAttribute(args.viewOptions.theme)}">
1657
+ <head>
1658
+ <meta charset="utf-8" />
1659
+ <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
1660
+ <title>stable-frame preview (atMs=${args.frame.atMs})</title>
1661
+ ${assetTags} <style>
1662
+ ${style}
1663
+ </style>
1664
+ </head>
1665
+ <body>
1666
+ ${body}
1667
+ </body>
1668
+ </html>`;
1669
+ }
1670
+ function resolveStableFrameConfig(config, flowName) {
1671
+ const stableFrames = config?.agent?.report?.stableFrames;
1672
+ const flowConfig = stableFrames?.flows?.[flowName];
1673
+ return {
1674
+ ...stableFrames,
1675
+ ...flowConfig,
1676
+ stableMs: flowConfig?.stableMs ?? stableFrames?.stableMs ?? 200,
1677
+ theme: flowConfig?.theme ?? stableFrames?.theme ?? "dark",
1678
+ viewportOnly: flowConfig?.viewportOnly ?? stableFrames?.viewportOnly ?? false,
1679
+ viewportTargets: {
1680
+ ...stableFrames?.viewportTargets,
1681
+ ...flowConfig?.viewportTargets
1682
+ }
1683
+ };
1684
+ }
1685
+ function resolvePtyReplayPath(replayPathArg, config) {
1686
+ if (isAbsolute(replayPathArg)) return replayPathArg;
1687
+ return resolve(config?.rootDir ?? process.cwd(), replayPathArg);
1688
+ }
1689
+ async function extractStableFrame(args) {
1690
+ const { config, events, terminal } = args;
1691
+ const targetFrameIndex = config.frameIndex;
1692
+ const matcher = createStableFrameMatcher(config);
1693
+ let matchedFrame = null;
1694
+ const retainedFrames = [];
1695
+ const retainCount = targetFrameIndex === void 0 ? 24 : targetFrameIndex < 0 ? -targetFrameIndex : 1;
1696
+ let totalFrames = 0;
1697
+ let pendingDirtySinceMs = null;
1698
+ let lastEventAtMs = 0;
1699
+ const captureFrame = (atMs, reason) => {
1700
+ const shouldRetain = targetFrameIndex === void 0 || targetFrameIndex >= 0 && totalFrames === targetFrameIndex || targetFrameIndex < 0;
1701
+ if (shouldRetain || matcher) {
1702
+ const frame = {
1703
+ ...snapshotTerminalFrame(terminal, {
1704
+ atMs,
1705
+ index: totalFrames,
1706
+ reason,
1707
+ viewportOnly: config.viewportOnly
1708
+ }),
1709
+ score: scoreTerminalFrame(terminal)
1710
+ };
1711
+ if (matcher?.matches(stableFrameText(frame))) {
1712
+ if (matcher.mode === "last" || !matchedFrame) matchedFrame = frame;
1713
+ }
1714
+ if (shouldRetain) retainedFrames.push(frame);
1715
+ if (retainedFrames.length > retainCount) retainedFrames.splice(0, retainedFrames.length - retainCount);
1716
+ }
1717
+ totalFrames += 1;
1718
+ pendingDirtySinceMs = null;
1719
+ };
1720
+ const flushIfStable = (nowMs) => {
1721
+ if (pendingDirtySinceMs === null) return;
1722
+ if (nowMs - pendingDirtySinceMs >= config.stableMs) captureFrame(pendingDirtySinceMs, "stable");
1723
+ };
1724
+ for (const event of events) {
1725
+ const atMs = event.atMs ?? lastEventAtMs;
1726
+ flushIfStable(atMs);
1727
+ lastEventAtMs = atMs;
1728
+ if (event.type === "output" && event.dataBase64) {
1729
+ await writeTerminal(terminal, base64ToBytes(event.dataBase64));
1730
+ pendingDirtySinceMs = pendingDirtySinceMs ?? atMs;
1731
+ continue;
1732
+ }
1733
+ if (event.type === "resize" && event.cols && event.rows) {
1734
+ terminal.resize(event.cols, event.rows);
1735
+ pendingDirtySinceMs = pendingDirtySinceMs ?? atMs;
1736
+ continue;
1737
+ }
1738
+ if (event.type === "exit") flushIfStable(atMs);
1739
+ }
1740
+ flushIfStable(lastEventAtMs + config.stableMs);
1741
+ if (totalFrames === 0) captureFrame(lastEventAtMs, "final");
1742
+ if (targetFrameIndex !== void 0 && targetFrameIndex >= 0) {
1743
+ const exact = retainedFrames.find((frame) => frame.index === targetFrameIndex);
1744
+ if (exact) return exact;
1745
+ return null;
1746
+ }
1747
+ if (targetFrameIndex !== void 0 && targetFrameIndex < 0) {
1748
+ const resolved = totalFrames + targetFrameIndex;
1749
+ const exact = retainedFrames.find((frame) => frame.index === resolved);
1750
+ if (exact) return exact;
1751
+ }
1752
+ if (matchedFrame) return matchedFrame;
1753
+ return chooseBestStableFrame(retainedFrames);
1754
+ }
1755
+ function writeTerminal(terminal, data) {
1756
+ return new Promise((resolveWrite) => {
1757
+ terminal.write(data, resolveWrite);
1758
+ });
1759
+ }
1760
+ function snapshotTerminalFrame(terminal, options) {
1761
+ const buffer = terminal.buffer.active;
1762
+ const startY = options.viewportOnly ? buffer.viewportY : 0;
1763
+ const count = options.viewportOnly ? terminal.rows : buffer.length;
1764
+ const logicalLines = [];
1765
+ for (let offset = 0; offset < count; offset += 1) {
1766
+ const y = startY + offset;
1767
+ const line = buffer.getLine(y);
1768
+ const cells = readStableLineCells(terminal, y);
1769
+ const live = options.viewportOnly || y >= buffer.viewportY;
1770
+ const previous = logicalLines.at(-1);
1771
+ if (line?.isWrapped && previous) {
1772
+ previous.cells.push(...cells);
1773
+ previous.live = previous.live || live;
1774
+ previous.physicalRows += 1;
1775
+ continue;
1776
+ }
1777
+ logicalLines.push({
1778
+ cells,
1779
+ live,
1780
+ physicalRows: 1
1781
+ });
1782
+ }
1783
+ return {
1784
+ atMs: options.atMs,
1785
+ cols: terminal.cols,
1786
+ index: options.index,
1787
+ lines: logicalLines,
1788
+ reason: options.reason,
1789
+ rows: terminal.rows
1790
+ };
1791
+ }
1792
+ function readStableLineCells(terminal, y) {
1793
+ const buffer = terminal.buffer.active;
1794
+ const nullCell = buffer.getNullCell();
1795
+ const line = buffer.getLine(y);
1796
+ const endCol = findMeaningfulEndCol(line, terminal.cols, nullCell);
1797
+ const cells = [];
1798
+ for (let x = 0; x < endCol; x += 1) {
1799
+ const cell = line?.getCell(x, nullCell);
1800
+ if (!cell) {
1801
+ cells.push({
1802
+ style: DEFAULT_STYLE,
1803
+ text: " ",
1804
+ width: 1
1805
+ });
1806
+ continue;
1807
+ }
1808
+ const width = cell.getWidth();
1809
+ if (width === 0) continue;
1810
+ cells.push({
1811
+ style: extractStyle(cell),
1812
+ text: cell.getChars() || " ",
1813
+ width
1814
+ });
1815
+ }
1816
+ return cells;
1817
+ }
1818
+ function scoreTerminalFrame(terminal) {
1819
+ const buffer = terminal.buffer.active;
1820
+ const nullCell = buffer.getNullCell();
1821
+ let score = 0;
1822
+ for (let y = 0; y < buffer.length; y += 1) {
1823
+ const endCol = findMeaningfulEndCol(buffer.getLine(y), terminal.cols, nullCell);
1824
+ score += endCol;
1825
+ }
1826
+ return score;
1827
+ }
1828
+ function chooseBestStableFrame(frames) {
1829
+ return frames.filter((frame) => frame.score > 0).at(-1) ?? frames.at(-1) ?? null;
1830
+ }
1831
+ function createStableFrameMatcher(config) {
1832
+ const matchText = toStringArray(config.matchText);
1833
+ const matchRegex = toStringArray(config.matchRegex).map((pattern) => {
1834
+ try {
1835
+ return new RegExp(pattern);
1836
+ } catch (error) {
1837
+ throw new Error(`invalid agent.report.stableFrames.matchRegex pattern ${JSON.stringify(pattern)}: ${String(error)}`);
1838
+ }
1839
+ });
1840
+ if (matchText.length === 0 && matchRegex.length === 0) return null;
1841
+ return {
1842
+ mode: config.matchMode ?? "last",
1843
+ matches: (text) => matchText.some((needle) => text.includes(needle)) || matchRegex.some((regex) => regex.test(text))
1844
+ };
1845
+ }
1846
+ function stableFrameText(frame) {
1847
+ return frame.lines.map((line) => line.cells.map((cell) => cell.text).join("").trimEnd()).join("\n");
1848
+ }
1849
+ function toStringArray(value) {
1850
+ if (value === void 0) return [];
1851
+ return Array.isArray(value) ? value : [value];
1852
+ }
1853
+ function resolveTargetCols(args) {
1854
+ const explicit = args.viewport ? args.config.viewportTargets?.[args.viewport.name] : void 0;
1855
+ if (typeof explicit === "number" && Number.isFinite(explicit) && explicit > 0) return Math.trunc(explicit);
1856
+ if (explicit === null) return args.frameCols;
1857
+ if (isMobileViewport(args.viewport)) {
1858
+ const width = args.viewport?.width ?? 390;
1859
+ const cellWidth = Math.max(1, args.fontSize * .6);
1860
+ return Math.max(20, Math.floor(width / cellWidth));
1861
+ }
1862
+ return args.frameCols;
1863
+ }
1864
+ function renderStableFrameDom(frame, targetCols) {
1865
+ let html = "";
1866
+ let totalRows = 0;
1867
+ let wideBlockId = 0;
1868
+ for (const line of frame.lines) {
1869
+ const lineCols = Math.max(targetCols, cellsDisplayWidth(line.cells));
1870
+ if (lineCols > targetCols || line.physicalRows > 1) {
1871
+ wideBlockId += 1;
1872
+ html += `<div class="term-wide-row-block" data-aitty-wide-block="true" data-aitty-wide-block-id="${wideBlockId}" data-aitty-wide-block-kind="viewport-pan" style="--aitty-wide-block-cols: ${lineCols}">`;
1873
+ html += renderStableFrameRow(line, lineCols, totalRows);
1874
+ html += "</div>";
1875
+ } else html += renderStableFrameRow(line, targetCols, totalRows);
1876
+ totalRows += 1;
1877
+ }
1878
+ return `<div class="term-grid" data-cols="${targetCols}" data-rows="${totalRows}" style="--term-cols: ${targetCols}; --term-rows: ${totalRows};">${html}</div>`;
1879
+ }
1880
+ function renderStableFrameRow(line, lineCols, lineIndex) {
1881
+ return `<div class="${line.live ? "term-row" : "term-row term-scrollback-row"}"${line.live ? ` data-aitty-live-grid-row="${lineIndex + 1}"` : ""} data-aitty-line-cols="${lineCols}">${renderStableFrameCells(line.cells, lineCols)}</div>`;
1882
+ }
1883
+ function renderStableFrameCells(cells, lineCols) {
1884
+ const out = [];
1885
+ let usedCols = 0;
1886
+ let runText = "";
1887
+ let runWidth = 0;
1888
+ let runStyle = null;
1889
+ let runKey = null;
1890
+ const flush = () => {
1891
+ if (runText === "" && runWidth === 0) return;
1892
+ out.push(renderSpan(runText, runWidth, runStyle ?? DEFAULT_STYLE));
1893
+ runText = "";
1894
+ runWidth = 0;
1895
+ runStyle = null;
1896
+ runKey = null;
1897
+ };
1898
+ for (const cell of cells) {
1899
+ const key = styleKey(cell.style);
1900
+ const wide = cell.width !== 1;
1901
+ if (!wide && runKey === key) {
1902
+ runText += cell.text;
1903
+ runWidth += cell.width;
1904
+ usedCols += cell.width;
1905
+ continue;
1906
+ }
1907
+ flush();
1908
+ if (wide) {
1909
+ out.push(renderSpan(cell.text, cell.width, cell.style, "term-wide"));
1910
+ usedCols += cell.width;
1911
+ continue;
1912
+ }
1913
+ runText = cell.text;
1914
+ runWidth = cell.width;
1915
+ runStyle = cell.style;
1916
+ runKey = key;
1917
+ usedCols += cell.width;
1918
+ }
1919
+ flush();
1920
+ const remaining = lineCols - usedCols;
1921
+ if (remaining > 0) out.push(renderSpan("", remaining, DEFAULT_STYLE));
1922
+ return out.join("");
1923
+ }
1924
+ function renderSpan(text, width, style, className) {
1925
+ const declarations = styleDeclarations(style);
1926
+ declarations.push(widthDeclaration(width));
1927
+ if (className === "term-wide") declarations.push("overflow: hidden");
1928
+ return `<span${className ? ` class="${escapeAttribute(className)}"` : ""} style="${escapeAttribute(declarations.join("; "))}">${escapeHtml(text)}</span>`;
1929
+ }
1930
+ function styleDeclarations(style) {
1931
+ if (isDefaultStyle(style)) return [];
1932
+ const declarations = [];
1933
+ const fg = colorToCss(style.fg);
1934
+ const bg = colorToCss(style.bg);
1935
+ if (fg) declarations.push(`color: ${fg}`);
1936
+ if (bg) declarations.push(`background-color: ${bg}`);
1937
+ if (style.bold) declarations.push("font-weight: 700");
1938
+ if (style.dim) declarations.push("opacity: 0.72");
1939
+ if (style.italic) declarations.push("font-style: italic");
1940
+ const decorations = [style.underline ? "underline" : "", style.strikethrough ? "line-through" : ""].filter(Boolean);
1941
+ if (decorations.length > 0) declarations.push(`text-decoration: ${decorations.join(" ")}`);
1942
+ if (style.inverse) declarations.push("filter: invert(1)");
1943
+ return declarations;
1944
+ }
1945
+ function colorToCss(color) {
1946
+ if (color.mode === "default") return null;
1947
+ if (color.mode === "palette") return `var(--term-color-${color.value})`;
1948
+ const value = color.value;
1949
+ return `rgb(${value >> 16 & 255},${value >> 8 & 255},${value & 255})`;
1950
+ }
1951
+ function widthDeclaration(width) {
1952
+ if (width <= 1) return "width: var(--term-cell-width, 1ch)";
1953
+ return `width: calc(var(--term-cell-width, 1ch) * ${width})`;
1954
+ }
1955
+ function cellsDisplayWidth(cells) {
1956
+ return cells.reduce((sum, cell) => sum + cell.width, 0);
1957
+ }
1958
+ //#endregion
1587
1959
  //#region src/agent/report_terminal_layout.ts
1588
1960
  function resolveTerminalSnapshotLayout(snapshot, viewport, viewOptions) {
1589
1961
  const cols = inferTerminalCols(snapshot);
@@ -1635,9 +2007,9 @@ ${body}
1635
2007
  }
1636
2008
  //#endregion
1637
2009
  //#region src/agent/report_artifact_writer.ts
1638
- function writeArtifactViewerPages(result) {
2010
+ async function writeArtifactViewerPages(result, options = {}) {
1639
2011
  const viewportsByName = new Map(result.viewports.map((viewport) => [viewport.name, viewport]));
1640
- const viewOptions = resolveReportViewOptions(result);
2012
+ const viewOptions = resolveReportViewOptions(result, options.config);
1641
2013
  const readableArtifacts = [];
1642
2014
  for (const artifact of result.artifacts) {
1643
2015
  const viewerPath = artifactViewerPath(artifact);
@@ -1657,12 +2029,25 @@ function writeArtifactViewerPages(result) {
1657
2029
  reportPath: result.reportPath
1658
2030
  }) : null;
1659
2031
  const writtenDomPreviewPaths = /* @__PURE__ */ new Set();
2032
+ const ptyReplayStableFrame = aittyAssets ? await extractPtyReplayStableFrameForReport({
2033
+ config: options.config,
2034
+ result
2035
+ }) : null;
1660
2036
  if (aittyAssets) for (const { artifact, content } of readableArtifacts) {
1661
2037
  if (artifact.kind !== "dom") continue;
1662
2038
  const viewport = viewportsByName.get(artifact.viewport);
1663
2039
  const domPreviewPath = artifactDomPreviewPath(artifact);
2040
+ const aittyPreviewAssets = resolveAittyPreviewAssets(domPreviewPath, aittyAssets, result.artifactsDir);
2041
+ const previewDocument = ptyReplayStableFrame ? renderPtyReplayStableFramePreviewDocument({
2042
+ aittyAssets: aittyPreviewAssets,
2043
+ config: options.config,
2044
+ flowName: result.name,
2045
+ frame: ptyReplayStableFrame,
2046
+ viewOptions,
2047
+ viewport
2048
+ }) : renderDomPreviewDocument(content, viewport, viewOptions, aittyPreviewAssets);
1664
2049
  mkdirSync(dirname(domPreviewPath), { recursive: true });
1665
- writeFileSync(domPreviewPath, renderDomPreviewDocument(content, viewport, viewOptions, resolveAittyPreviewAssets(domPreviewPath, aittyAssets, result.artifactsDir)), "utf8");
2050
+ writeFileSync(domPreviewPath, previewDocument, "utf8");
1666
2051
  writtenDomPreviewPaths.add(domPreviewPath);
1667
2052
  }
1668
2053
  for (const { artifact, content, viewerPath } of readableArtifacts) {
@@ -2045,9 +2430,9 @@ ${renderAgentReportCss()}
2045
2430
  }
2046
2431
  //#endregion
2047
2432
  //#region src/agent/report.ts
2048
- function writeAgentReport(path, result) {
2433
+ async function writeAgentReport(path, result, options = {}) {
2049
2434
  mkdirSync(dirname(path), { recursive: true });
2050
- writeArtifactViewerPages(result);
2435
+ await writeArtifactViewerPages(result, options);
2051
2436
  writeFileSync(path, renderAgentReportHtml(result), "utf8");
2052
2437
  }
2053
2438
  //#endregion
@@ -2797,7 +3182,7 @@ async function runAgentSpec(input, options = {}) {
2797
3182
  else writeFileSync(cassettePath, JSON.stringify(cassette, null, 2) + "\n", "utf8");
2798
3183
  result.cassetteFrameCount = cassette.frames.length;
2799
3184
  writeRunRecord(result, spec);
2800
- writeAgentReport(reportPath, result);
3185
+ await writeAgentReport(reportPath, result, { config: options.config });
2801
3186
  writeRunManifest(result);
2802
3187
  }
2803
3188
  return result;
package/dist/script.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { n as runScriptFile, t as runScript } from "./runner-wW_DCBX7.mjs";
1
+ import { n as runScriptFile, t as runScript } from "./runner-BHXXwxYp.mjs";
2
2
  export { runScript, runScriptFile };
@@ -1,6 +1,6 @@
1
1
  import { a as sameArgv, i as diffCommandMaps, n as validateManifestFiles, r as formatZodIssues, t as collectManifestFiles } from "./manifest_files-DW80c1H7.mjs";
2
2
  import { i as portableCliPath, o as relativeHref, r as normalizePath, s as samePath } from "./env-DPYHo-zH.mjs";
3
- import { a as jsonForHtml, c as scriptSchema, i as escapeHtml, l as SessionManager, o as ensureAsciinemaPlayerAssets, r as generateTraceReportHtml, s as formatSnapshotView, t as runScript } from "./runner-wW_DCBX7.mjs";
3
+ import { a as jsonForHtml, c as scriptSchema, i as escapeHtml, l as SessionManager, o as ensureAsciinemaPlayerAssets, r as generateTraceReportHtml, s as formatSnapshotView, t as runScript } from "./runner-BHXXwxYp.mjs";
4
4
  import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
5
5
  import { basename, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
6
6
  import { pathToFileURL } from "node:url";
@@ -144,7 +144,7 @@ var ScriptRecordingManager = class {
144
144
  };
145
145
  //#endregion
146
146
  //#region package.json
147
- var version = "0.5.0";
147
+ var version = "0.6.0";
148
148
  //#endregion
149
149
  //#region src/mcp/tool_result.ts
150
150
  function toolError(message, extra = {}) {
package/dist/session.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { t as TerminalSession } from "./terminal_session-DJKr-O3X.mjs";
1
+ import { t as TerminalSession } from "./terminal_session-MX_vWpRG.mjs";
2
2
  export { TerminalSession };
@@ -0,0 +1,65 @@
1
+ //#region src/terminal/style.ts
2
+ const DEFAULT_STYLE = {
3
+ fg: { mode: "default" },
4
+ bg: { mode: "default" },
5
+ bold: false,
6
+ dim: false,
7
+ italic: false,
8
+ underline: false,
9
+ inverse: false,
10
+ strikethrough: false
11
+ };
12
+ function extractStyle(cell) {
13
+ const style = {
14
+ fg: extractColor(cell.isFgDefault(), cell.isFgPalette(), cell.isFgRGB(), cell.getFgColor()),
15
+ bg: extractColor(cell.isBgDefault(), cell.isBgPalette(), cell.isBgRGB(), cell.getBgColor()),
16
+ bold: cell.isBold() !== 0,
17
+ dim: cell.isDim() !== 0,
18
+ italic: cell.isItalic() !== 0,
19
+ underline: cell.isUnderline() !== 0,
20
+ inverse: cell.isInverse() !== 0,
21
+ strikethrough: cell.isStrikethrough() !== 0
22
+ };
23
+ return isDefaultStyle(style) ? DEFAULT_STYLE : style;
24
+ }
25
+ function isDefaultStyle(style) {
26
+ return style.fg.mode === "default" && style.bg.mode === "default" && !style.bold && !style.dim && !style.italic && !style.underline && !style.inverse && !style.strikethrough;
27
+ }
28
+ function styleKey(style) {
29
+ return [
30
+ style.fg.mode === "default" ? "d" : `${style.fg.mode}:${style.fg.value}`,
31
+ style.bg.mode === "default" ? "d" : `${style.bg.mode}:${style.bg.value}`,
32
+ style.bold ? "b" : "",
33
+ style.dim ? "d" : "",
34
+ style.italic ? "i" : "",
35
+ style.underline ? "u" : "",
36
+ style.inverse ? "r" : "",
37
+ style.strikethrough ? "s" : ""
38
+ ].join("|");
39
+ }
40
+ function findMeaningfulEndCol(line, cols, nullCell) {
41
+ if (!line) return 0;
42
+ for (let x = cols - 1; x >= 0; x -= 1) {
43
+ const cell = line.getCell(x, nullCell);
44
+ if (!cell) continue;
45
+ if (cell.getWidth() === 0) continue;
46
+ const chars = cell.getChars();
47
+ const style = extractStyle(cell);
48
+ if (chars !== "" && chars !== " " || !isDefaultStyle(style)) return x + 1;
49
+ }
50
+ return 0;
51
+ }
52
+ function extractColor(isDefault, isPalette, isRgb, value) {
53
+ if (isDefault) return { mode: "default" };
54
+ if (isRgb) return {
55
+ mode: "rgb",
56
+ value
57
+ };
58
+ if (isPalette) return {
59
+ mode: "palette",
60
+ value
61
+ };
62
+ return { mode: "default" };
63
+ }
64
+ //#endregion
65
+ export { styleKey as a, isDefaultStyle as i, extractStyle as n, findMeaningfulEndCol as r, DEFAULT_STYLE as t };
@@ -1,3 +1,4 @@
1
+ import { a as styleKey, i as isDefaultStyle, n as extractStyle, r as findMeaningfulEndCol, t as DEFAULT_STYLE } from "./style-BtIUv5H0.mjs";
1
2
  import { Terminal } from "@xterm/headless";
2
3
  //#region src/terminal/keys.ts
3
4
  const CSI = "\x1B[";
@@ -180,70 +181,6 @@ function clampInt(value, min, max) {
180
181
  return int;
181
182
  }
182
183
  //#endregion
183
- //#region src/terminal/style.ts
184
- const DEFAULT_STYLE = {
185
- fg: { mode: "default" },
186
- bg: { mode: "default" },
187
- bold: false,
188
- dim: false,
189
- italic: false,
190
- underline: false,
191
- inverse: false,
192
- strikethrough: false
193
- };
194
- function extractStyle(cell) {
195
- const style = {
196
- fg: extractColor(cell.isFgDefault(), cell.isFgPalette(), cell.isFgRGB(), cell.getFgColor()),
197
- bg: extractColor(cell.isBgDefault(), cell.isBgPalette(), cell.isBgRGB(), cell.getBgColor()),
198
- bold: cell.isBold() !== 0,
199
- dim: cell.isDim() !== 0,
200
- italic: cell.isItalic() !== 0,
201
- underline: cell.isUnderline() !== 0,
202
- inverse: cell.isInverse() !== 0,
203
- strikethrough: cell.isStrikethrough() !== 0
204
- };
205
- return isDefaultStyle(style) ? DEFAULT_STYLE : style;
206
- }
207
- function isDefaultStyle(style) {
208
- return style.fg.mode === "default" && style.bg.mode === "default" && !style.bold && !style.dim && !style.italic && !style.underline && !style.inverse && !style.strikethrough;
209
- }
210
- function styleKey(style) {
211
- return [
212
- style.fg.mode === "default" ? "d" : `${style.fg.mode}:${style.fg.value}`,
213
- style.bg.mode === "default" ? "d" : `${style.bg.mode}:${style.bg.value}`,
214
- style.bold ? "b" : "",
215
- style.dim ? "d" : "",
216
- style.italic ? "i" : "",
217
- style.underline ? "u" : "",
218
- style.inverse ? "r" : "",
219
- style.strikethrough ? "s" : ""
220
- ].join("|");
221
- }
222
- function findMeaningfulEndCol(line, cols, nullCell) {
223
- if (!line) return 0;
224
- for (let x = cols - 1; x >= 0; x -= 1) {
225
- const cell = line.getCell(x, nullCell);
226
- if (!cell) continue;
227
- if (cell.getWidth() === 0) continue;
228
- const chars = cell.getChars();
229
- const style = extractStyle(cell);
230
- if (chars !== "" && chars !== " " || !isDefaultStyle(style)) return x + 1;
231
- }
232
- return 0;
233
- }
234
- function extractColor(isDefault, isPalette, isRgb, value) {
235
- if (isDefault) return { mode: "default" };
236
- if (isRgb) return {
237
- mode: "rgb",
238
- value
239
- };
240
- if (isPalette) return {
241
- mode: "palette",
242
- value
243
- };
244
- return { mode: "default" };
245
- }
246
- //#endregion
247
184
  //#region src/terminal/snapshot_rows.ts
248
185
  function snapshotPlainLine(line, cols, nullCell, trimRight) {
249
186
  let endCol = cols;
@@ -911,4 +848,4 @@ var TerminalSession = class {
911
848
  }
912
849
  };
913
850
  //#endregion
914
- export { fnv1a32 as a, extractStyle as c, styleKey as d, encodeSgrMouse as f, TraceRecorder as i, findMeaningfulEndCol as l, sleep as n, snapshotGrid as o, encodeKey as p, applyTextMaskRules as r, snapshotLines as s, TerminalSession as t, isDefaultStyle as u };
851
+ export { fnv1a32 as a, encodeSgrMouse as c, TraceRecorder as i, encodeKey as l, sleep as n, snapshotGrid as o, applyTextMaskRules as r, snapshotLines as s, TerminalSession as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ptywright",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Terminal/TUI automation driver over PTY + xterm, exposed as MCP tools",
5
5
  "keywords": [
6
6
  "agent",