@termwright/probe-ink 0.2.0 → 0.3.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @termwright/probe-ink
2
2
 
3
- Zero-config semantics for an Ink 7 application that imports nothing from
3
+ Zero-config semantics for an exact-certified Ink application that imports nothing from
4
4
  termwright. The application keeps its normal `import {render} from 'ink'` and
5
5
  normal `render(<App />)` call; the launcher adds one preload flag.
6
6
 
@@ -10,12 +10,15 @@ normal `render(<App />)` call; the launcher adds one preload flag.
10
10
  npm install --save-dev @termwright/probe-ink
11
11
  ```
12
12
 
13
- Peers: `ink >= 7.1 < 8`, React >= 19.2. Node >= 22, or Bun.
13
+ Peers: an exact Ink version listed in the compatibility registry, React >= 19.2,
14
+ Node >= 22, or Bun. The Ink version is exact:
15
+ the preload verifies both instrumented upstream modules by SHA-256 before it
16
+ negotiates semantic capabilities.
14
17
 
15
18
  ```ts
16
- import {withProbe} from '@termwright/probe-ink';
19
+ import { withProbe } from '@termwright/probe-ink';
17
20
 
18
- const {command} = withProbe('node', ['node', 'app.mjs']);
21
+ const { command } = withProbe('node', ['node', 'app.mjs']);
19
22
  await launchTerminal({
20
23
  command,
21
24
  env: {
@@ -27,7 +30,9 @@ await launchTerminal({
27
30
 
28
31
  For Bun, pass `withProbe('bun', ['bun', 'app.tsx'])`; the launcher places
29
32
  `--preload` before the application entry, where Bun requires it. Node uses
30
- `--import`. The returned preload path is a `file://` URL, including on Windows.
33
+ `--import`. Node receives a `file://` preload URL, including on Windows; Bun
34
+ receives a native absolute path because its Windows preload resolver does not
35
+ load `file://` entries.
31
36
 
32
37
  Early Node 22 releases do not have `module.registerHooks`; the preload detects
33
38
  that case and uses `module.register`. It does not change Node's warning policy.
@@ -37,10 +42,10 @@ without the probe, and byte parity retains it.
37
42
  ## Dormant and failure behaviour
38
43
 
39
44
  Without both `TERMWRIGHT_ENDPOINT` and `TERMWRIGHT_TOKEN`, the preload installs
40
- no loader hook and `ink.render` is untouched. If the driver is unavailable or
41
- the observed Ink internals move, semantics disable themselves and the
42
- application continues. Process tests assert byte identity for dormant and
43
- faulted runs under both Node and Bun.
45
+ no loader hook and `ink.render` is untouched. If either Ink artifact does not
46
+ match 7.1.1 exactly, the adapter does not attach or advertise a partial
47
+ contract. An unreachable driver remains isolated from the application. Process
48
+ tests assert byte identity for dormant and faulted runs under Node and Bun.
44
49
 
45
50
  ## What is observed
46
51
 
@@ -68,12 +73,25 @@ marker last. A newer render that arrives during drain suppresses the stale
68
73
  marker. Instrumented output is byte-identical to vanilla output after those
69
74
  markers are removed.
70
75
 
71
- Bounds are published only when Ink runs interactively in the alternate screen
72
- buffer and no `<Static>` content shifts the live region. Otherwise coordinates
73
- are omitted rather than reported as terminal-absolute when they are not.
74
- With `TERMWRIGHT_PROTOCOL=termwright/2`, those facts use tagged observations:
75
- display is known, intended bounds are known or explicitly unsupported, and
76
- visible clipping plus pointer ownership are unsupported rather than inferred.
76
+ The checksummed renderer hook records Yoga rectangles and the same nested
77
+ overflow intersections used by `render-node-to-output`. A paired output tracker
78
+ maps those relative rectangles into the committed normal or alternate VT
79
+ viewport. It handles terminal wrapping, wide cells, resize, fullscreen scroll,
80
+ and `<Static>` output retained above the live region. Hidden nodes publish
81
+ authoritative absence instead of fabricated zero-sized boxes. Every marker is
82
+ written only after the corresponding output bytes drain.
83
+
84
+ Ink does not expose pointer ownership. Bounds therefore do not enable click,
85
+ hover, or drag by themselves. Those actions require an application evidence
86
+ provider that publishes revision-bound pointer regions and a native hit test;
87
+ device input still travels through the real PTY.
88
+
89
+ Ink instrumentation also does not automatically certify terminal input modes.
90
+ Its output shadow sees JavaScript `stream.write` calls, but direct descriptor or
91
+ native writes and inherited descendant output bypass that surface. On ConPTY,
92
+ where the transport hides DEC mouse/focus negotiation, an opaque Ink child
93
+ therefore remains fail-closed. Hidden-mode pointer/focus input requires an
94
+ explicit provider backed by the application's production input-mode state.
77
95
 
78
96
  ## Deliberate limits
79
97
 
@@ -2,12 +2,19 @@ import {
2
2
  INK_ENTRY_PATTERN,
3
3
  buildShimSource,
4
4
  shouldShim
5
- } from "./chunk-IUFXTMZ7.js";
5
+ } from "./chunk-CLY2SLYH.js";
6
6
  import {
7
7
  isInstrumented
8
- } from "./chunk-LO7YF74P.js";
8
+ } from "./chunk-67M2GX5S.js";
9
+ import {
10
+ INK_CORE_PATTERN,
11
+ INK_RENDERER_PATTERN,
12
+ instrumentInkCore,
13
+ instrumentInkRenderer
14
+ } from "./chunk-SLKX554P.js";
9
15
 
10
16
  // src/bun-preload.ts
17
+ import { readFile } from "fs/promises";
11
18
  function installBunPreload(env = process.env) {
12
19
  if (!isInstrumented(env)) return false;
13
20
  const bun = globalThis.Bun;
@@ -19,6 +26,16 @@ function installBunPreload(env = process.env) {
19
26
  if (!shouldShim(args.path)) return void 0;
20
27
  return { loader: "js", contents: buildShimSource(args.path) };
21
28
  });
29
+ build.onLoad({ filter: INK_RENDERER_PATTERN }, async (args) => {
30
+ const source = await readFile(args.path, "utf8");
31
+ const contents = instrumentInkRenderer(args.path, source);
32
+ return contents === void 0 ? void 0 : { loader: "js", contents };
33
+ });
34
+ build.onLoad({ filter: INK_CORE_PATTERN }, async (args) => {
35
+ const source = await readFile(args.path, "utf8");
36
+ const contents = instrumentInkCore(args.path, source);
37
+ return contents === void 0 ? void 0 : { loader: "js", contents };
38
+ });
22
39
  }
23
40
  });
24
41
  return true;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/bun-preload.ts"],"sourcesContent":["/** Bun entry: `bun --preload @termwright/probe-ink/bun-preload app.js`. */\n\nimport { buildShimSource, INK_ENTRY_PATTERN, shouldShim } from './shim.js';\nimport { isInstrumented } from './runtime.js';\n\ninterface BunPluginBuild {\n onLoad(\n options: { filter: RegExp },\n callback: (args: { path: string }) => Promise<{ loader: string; contents: string } | undefined>,\n ): void;\n}\n\ninterface BunGlobal {\n plugin(definition: { name: string; setup(build: BunPluginBuild): void }): void;\n}\n\n/** Register the Ink entry replacement before the application's first import. */\nexport function installBunPreload(\n env: Record<string, string | undefined> = process.env,\n): boolean {\n if (!isInstrumented(env)) return false;\n const bun = (globalThis as { Bun?: BunGlobal }).Bun;\n if (bun === undefined) return false;\n\n bun.plugin({\n name: 'termwright-ink',\n setup(build) {\n build.onLoad({ filter: INK_ENTRY_PATTERN }, async (args) => {\n if (!shouldShim(args.path)) return undefined;\n return { loader: 'js', contents: buildShimSource(args.path) };\n });\n },\n });\n return true;\n}\n\ninstallBunPreload();\n"],"mappings":";;;;;;;;;;AAiBO,SAAS,kBACd,MAA0C,QAAQ,KACzC;AACT,MAAI,CAAC,eAAe,GAAG,EAAG,QAAO;AACjC,QAAM,MAAO,WAAmC;AAChD,MAAI,QAAQ,OAAW,QAAO;AAE9B,MAAI,OAAO;AAAA,IACT,MAAM;AAAA,IACN,MAAM,OAAO;AACX,YAAM,OAAO,EAAE,QAAQ,kBAAkB,GAAG,OAAO,SAAS;AAC1D,YAAI,CAAC,WAAW,KAAK,IAAI,EAAG,QAAO;AACnC,eAAO,EAAE,QAAQ,MAAM,UAAU,gBAAgB,KAAK,IAAI,EAAE;AAAA,MAC9D,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACD,SAAO;AACT;AAEA,kBAAkB;","names":[]}
1
+ {"version":3,"sources":["../src/bun-preload.ts"],"sourcesContent":["/** Bun entry: `bun --preload @termwright/probe-ink/bun-preload app.js`. */\n\nimport { buildShimSource, INK_ENTRY_PATTERN, shouldShim } from './shim.js';\nimport { readFile } from 'node:fs/promises';\nimport {\n instrumentInkCore,\n instrumentInkRenderer,\n INK_CORE_PATTERN,\n INK_RENDERER_PATTERN,\n} from './instrumentation.js';\nimport { isInstrumented } from './runtime.js';\n\ninterface BunPluginBuild {\n onLoad(\n options: { filter: RegExp },\n callback: (args: { path: string }) => Promise<{ loader: string; contents: string } | undefined>,\n ): void;\n}\n\ninterface BunGlobal {\n plugin(definition: { name: string; setup(build: BunPluginBuild): void }): void;\n}\n\n/** Register the Ink entry replacement before the application's first import. */\nexport function installBunPreload(env: Record<string, string | undefined> = process.env): boolean {\n if (!isInstrumented(env)) return false;\n const bun = (globalThis as { Bun?: BunGlobal }).Bun;\n if (bun === undefined) return false;\n\n bun.plugin({\n name: 'termwright-ink',\n setup(build) {\n build.onLoad({ filter: INK_ENTRY_PATTERN }, async (args) => {\n if (!shouldShim(args.path)) return undefined;\n return { loader: 'js', contents: buildShimSource(args.path) };\n });\n build.onLoad({ filter: INK_RENDERER_PATTERN }, async (args) => {\n const source = await readFile(args.path, 'utf8');\n const contents = instrumentInkRenderer(args.path, source);\n return contents === undefined ? undefined : { loader: 'js', contents };\n });\n build.onLoad({ filter: INK_CORE_PATTERN }, async (args) => {\n const source = await readFile(args.path, 'utf8');\n const contents = instrumentInkCore(args.path, source);\n return contents === undefined ? undefined : { loader: 'js', contents };\n });\n },\n });\n return true;\n}\n\ninstallBunPreload();\n"],"mappings":";;;;;;;;;;;;;;;;AAGA,SAAS,gBAAgB;AAqBlB,SAAS,kBAAkB,MAA0C,QAAQ,KAAc;AAChG,MAAI,CAAC,eAAe,GAAG,EAAG,QAAO;AACjC,QAAM,MAAO,WAAmC;AAChD,MAAI,QAAQ,OAAW,QAAO;AAE9B,MAAI,OAAO;AAAA,IACT,MAAM;AAAA,IACN,MAAM,OAAO;AACX,YAAM,OAAO,EAAE,QAAQ,kBAAkB,GAAG,OAAO,SAAS;AAC1D,YAAI,CAAC,WAAW,KAAK,IAAI,EAAG,QAAO;AACnC,eAAO,EAAE,QAAQ,MAAM,UAAU,gBAAgB,KAAK,IAAI,EAAE;AAAA,MAC9D,CAAC;AACD,YAAM,OAAO,EAAE,QAAQ,qBAAqB,GAAG,OAAO,SAAS;AAC7D,cAAM,SAAS,MAAM,SAAS,KAAK,MAAM,MAAM;AAC/C,cAAM,WAAW,sBAAsB,KAAK,MAAM,MAAM;AACxD,eAAO,aAAa,SAAY,SAAY,EAAE,QAAQ,MAAM,SAAS;AAAA,MACvE,CAAC;AACD,YAAM,OAAO,EAAE,QAAQ,iBAAiB,GAAG,OAAO,SAAS;AACzD,cAAM,SAAS,MAAM,SAAS,KAAK,MAAM,MAAM;AAC/C,cAAM,WAAW,kBAAkB,KAAK,MAAM,MAAM;AACpD,eAAO,aAAa,SAAY,SAAY,EAAE,QAAQ,MAAM,SAAS;AAAA,MACvE,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACD,SAAO;AACT;AAEA,kBAAkB;","names":[]}