@oh-my-pi/pi-wire 18.17.0 → 18.18.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/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [18.18.0] - 2026-11-07
6
+
7
+ ### Changed
8
+
9
+ - `ShellTrace` fields that carry values from the run (argv, assignments, redirect targets, unlocated unit sources, diagnostics) are `ShellTraceBytes`: a string when the bytes are UTF-8, otherwise the raw byte values. `isShellTrace` accepts both forms
10
+
5
11
  ## [18.17.0] - 2026-11-06
6
12
 
7
13
  ### Added
@@ -5,6 +5,12 @@
5
5
  * node's props. Every offset is a BYTE offset; UIs convert bytes to characters
6
6
  * when the script is not ASCII. Fields at their default are omitted.
7
7
  */
8
+ /**
9
+ * Bytes a run produced (expansions, assignments, eval bodies, diagnostics):
10
+ * a string when they are UTF-8, else the raw byte values. Nothing is replaced,
11
+ * so values and byte offsets stay exactly what the engine recorded.
12
+ */
13
+ export type ShellTraceBytes = string | number[];
8
14
  /** NodeKind of the engine's AST, snake_case. `assign` and `word` are not statements. */
9
15
  export type ShellTraceNodeKind = "and_or" | "pipeline" | "simple" | "brace" | "subshell" | "if" | "while" | "until" | "for" | "arith_for" | "select" | "case" | "arith" | "cond" | "func_def" | "coproc" | "assign" | "word";
10
16
  /** How the engine resolved a simple command's name. */
@@ -14,11 +20,11 @@ export type ShellTraceState = "pending" | "running" | "ok" | "fail" | "skipped";
14
20
  export interface ShellTraceRedir {
15
21
  fd: number;
16
22
  op: string;
17
- target: string;
23
+ target: ShellTraceBytes;
18
24
  }
19
25
  export interface ShellTraceDiag {
20
26
  code: string;
21
- message: string;
27
+ message: ShellTraceBytes;
22
28
  }
23
29
  /** One AST node of a unit; the unit's `nodes` index is the AstNodeId. */
24
30
  export interface ShellTraceNode {
@@ -42,11 +48,11 @@ export interface ShellTraceNode {
42
48
  /** `t_ns` of the last CmdStart, relative to RunStart. */
43
49
  at?: number;
44
50
  /** Last CmdExpanded argv (each arg ≤ 256 bytes, ≤ 64 args). */
45
- argv?: string[];
51
+ argv?: ShellTraceBytes[];
46
52
  /** The full argv length when `argv` was cut. */
47
53
  argc?: number;
48
54
  /** Last CmdExpanded assigns. */
49
- env?: [string, string][];
55
+ env?: [ShellTraceBytes, ShellTraceBytes][];
50
56
  res?: ShellTraceResolved;
51
57
  redirs?: ShellTraceRedir[];
52
58
  /** Pipestatus of the last CmdEnd. */
@@ -73,8 +79,8 @@ export interface ShellTraceUnit {
73
79
  line: number;
74
80
  /** Exact UTF-8 source byte length, including heredocs; absent in older traces. */
75
81
  bytes?: number;
76
- /** The unit's source; present only for unlocated units. */
77
- source?: string;
82
+ /** The unit's source; present only for unlocated units (an eval or function body). */
83
+ source?: ShellTraceBytes;
78
84
  /** Opaque canonical native syntax archive. Only pi-shell may interpret it. */
79
85
  syntax?: unknown;
80
86
  /** Compiler-known wrapper bytes removed from this unit's displayed source. */
@@ -126,19 +132,20 @@ export interface ShellTraceHistoryEvent {
126
132
  status?: number;
127
133
  dur_ns?: number;
128
134
  pipestatus?: number[];
129
- argv?: string[];
130
- assigns?: [string, string][];
135
+ argv?: ShellTraceBytes[];
136
+ assigns?: [ShellTraceBytes, ShellTraceBytes][];
131
137
  resolved?: ShellTraceResolved;
132
138
  redirs?: ShellTraceRedir[];
133
- name?: string;
134
- value?: string;
139
+ name?: ShellTraceBytes;
140
+ value?: ShellTraceBytes;
135
141
  full_len?: number;
136
142
  scope?: string;
137
143
  iteration?: number;
138
144
  iterations?: number;
139
145
  taken?: boolean;
140
146
  construct?: string;
141
- text?: string;
147
+ /** `Output` text is always a string (undecodable bytes arrive as U+FFFD); `Diag` text is run bytes. */
148
+ text?: ShellTraceBytes;
142
149
  contributors?: ShellTraceOutputContributor[];
143
150
  /** Final visible capture descriptor; merged stderr uses stdout's descriptor. */
144
151
  fd?: number;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-wire",
4
- "version": "18.17.0",
4
+ "version": "18.18.0",
5
5
  "description": "Shared wire protocol types for omp packages",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": {
@@ -6,6 +6,13 @@
6
6
  * when the script is not ASCII. Fields at their default are omitted.
7
7
  */
8
8
 
9
+ /**
10
+ * Bytes a run produced (expansions, assignments, eval bodies, diagnostics):
11
+ * a string when they are UTF-8, else the raw byte values. Nothing is replaced,
12
+ * so values and byte offsets stay exactly what the engine recorded.
13
+ */
14
+ export type ShellTraceBytes = string | number[];
15
+
9
16
  /** NodeKind of the engine's AST, snake_case. `assign` and `word` are not statements. */
10
17
  export type ShellTraceNodeKind =
11
18
  | "and_or"
@@ -45,12 +52,12 @@ export type ShellTraceState = "pending" | "running" | "ok" | "fail" | "skipped";
45
52
  export interface ShellTraceRedir {
46
53
  fd: number;
47
54
  op: string;
48
- target: string;
55
+ target: ShellTraceBytes;
49
56
  }
50
57
 
51
58
  export interface ShellTraceDiag {
52
59
  code: string;
53
- message: string;
60
+ message: ShellTraceBytes;
54
61
  }
55
62
 
56
63
  /** One AST node of a unit; the unit's `nodes` index is the AstNodeId. */
@@ -75,11 +82,11 @@ export interface ShellTraceNode {
75
82
  /** `t_ns` of the last CmdStart, relative to RunStart. */
76
83
  at?: number;
77
84
  /** Last CmdExpanded argv (each arg ≤ 256 bytes, ≤ 64 args). */
78
- argv?: string[];
85
+ argv?: ShellTraceBytes[];
79
86
  /** The full argv length when `argv` was cut. */
80
87
  argc?: number;
81
88
  /** Last CmdExpanded assigns. */
82
- env?: [string, string][];
89
+ env?: [ShellTraceBytes, ShellTraceBytes][];
83
90
  res?: ShellTraceResolved;
84
91
  redirs?: ShellTraceRedir[];
85
92
  /** Pipestatus of the last CmdEnd. */
@@ -107,8 +114,8 @@ export interface ShellTraceUnit {
107
114
  line: number;
108
115
  /** Exact UTF-8 source byte length, including heredocs; absent in older traces. */
109
116
  bytes?: number;
110
- /** The unit's source; present only for unlocated units. */
111
- source?: string;
117
+ /** The unit's source; present only for unlocated units (an eval or function body). */
118
+ source?: ShellTraceBytes;
112
119
  /** Opaque canonical native syntax archive. Only pi-shell may interpret it. */
113
120
  syntax?: unknown;
114
121
  /** Compiler-known wrapper bytes removed from this unit's displayed source. */
@@ -181,19 +188,20 @@ export interface ShellTraceHistoryEvent {
181
188
  status?: number;
182
189
  dur_ns?: number;
183
190
  pipestatus?: number[];
184
- argv?: string[];
185
- assigns?: [string, string][];
191
+ argv?: ShellTraceBytes[];
192
+ assigns?: [ShellTraceBytes, ShellTraceBytes][];
186
193
  resolved?: ShellTraceResolved;
187
194
  redirs?: ShellTraceRedir[];
188
- name?: string;
189
- value?: string;
195
+ name?: ShellTraceBytes;
196
+ value?: ShellTraceBytes;
190
197
  full_len?: number;
191
198
  scope?: string;
192
199
  iteration?: number;
193
200
  iterations?: number;
194
201
  taken?: boolean;
195
202
  construct?: string;
196
- text?: string;
203
+ /** `Output` text is always a string (undecodable bytes arrive as U+FFFD); `Diag` text is run bytes. */
204
+ text?: ShellTraceBytes;
197
205
  contributors?: ShellTraceOutputContributor[];
198
206
  /** Final visible capture descriptor; merged stderr uses stdout's descriptor. */
199
207
  fd?: number;
@@ -232,21 +240,29 @@ function finite(value: unknown): value is number {
232
240
  return typeof value === "number" && Number.isFinite(value);
233
241
  }
234
242
 
235
- function strings(value: unknown): value is string[] {
236
- return Array.isArray(value) && value.every((item: unknown) => typeof item === "string");
243
+ function byteValues(value: unknown): value is number[] {
244
+ return (
245
+ Array.isArray(value) &&
246
+ value.every((byte: unknown) => finite(byte) && Number.isInteger(byte) && byte >= 0 && byte <= 255)
247
+ );
248
+ }
249
+
250
+ function bytes(value: unknown): value is ShellTraceBytes {
251
+ return typeof value === "string" || byteValues(value);
252
+ }
253
+
254
+ function byteList(value: unknown): value is ShellTraceBytes[] {
255
+ return Array.isArray(value) && value.every(bytes);
237
256
  }
238
257
 
239
258
  function numbers(value: unknown): value is number[] {
240
259
  return Array.isArray(value) && value.every(finite);
241
260
  }
242
261
 
243
- function pairs(value: unknown): value is [string, string][] {
262
+ function bytePairs(value: unknown): value is [ShellTraceBytes, ShellTraceBytes][] {
244
263
  return (
245
264
  Array.isArray(value) &&
246
- value.every(
247
- (item: unknown) =>
248
- Array.isArray(item) && item.length === 2 && typeof item[0] === "string" && typeof item[1] === "string",
249
- )
265
+ value.every((item: unknown) => Array.isArray(item) && item.length === 2 && bytes(item[0]) && bytes(item[1]))
250
266
  );
251
267
  }
252
268
 
@@ -277,7 +293,7 @@ function resolved(value: unknown): value is ShellTraceResolved {
277
293
  }
278
294
 
279
295
  function redirection(value: unknown): value is ShellTraceRedir {
280
- return record(value) && finite(value.fd) && string(value.op) && string(value.target);
296
+ return record(value) && finite(value.fd) && string(value.op) && bytes(value.target);
281
297
  }
282
298
 
283
299
  function redirections(value: unknown): value is ShellTraceRedir[] {
@@ -322,8 +338,8 @@ function traceNode(value: unknown): value is ShellTraceNode {
322
338
  if (!optional(value, key, finite)) return false;
323
339
  }
324
340
  return (
325
- optional(value, "argv", strings) &&
326
- optional(value, "env", pairs) &&
341
+ optional(value, "argv", byteList) &&
342
+ optional(value, "env", bytePairs) &&
327
343
  optional(value, "res", resolved) &&
328
344
  optional(value, "redirs", redirections) &&
329
345
  optional(value, "pipe", numbers) &&
@@ -338,7 +354,7 @@ function traceUnit(value: unknown): value is ShellTraceUnit {
338
354
  finite(value.line) &&
339
355
  optional(value, "at", finite) &&
340
356
  optional(value, "bytes", finite) &&
341
- optional(value, "source", string) &&
357
+ optional(value, "source", bytes) &&
342
358
  optional(value, "callout", boolean) &&
343
359
  Array.isArray(value.nodes) &&
344
360
  value.nodes.every(traceNode)
@@ -353,8 +369,7 @@ function outputContributor(value: unknown): value is ShellTraceOutputContributor
353
369
  return (
354
370
  record(value) &&
355
371
  finite(value.t_ns) &&
356
- Array.isArray(value.bytes) &&
357
- value.bytes.every((byte: unknown) => finite(byte) && Number.isInteger(byte) && byte >= 0 && byte <= 255) &&
372
+ byteValues(value.bytes) &&
358
373
  optional(value, "u", finite) &&
359
374
  optional(value, "n", finite) &&
360
375
  optional(value, "vpid", finite) &&
@@ -405,12 +420,15 @@ function historyEntry(value: unknown): value is ShellTraceHistoryEvent {
405
420
  ]) {
406
421
  if (!optional(value, key, finite)) return false;
407
422
  }
408
- for (const key of ["name", "value", "scope", "construct", "text"]) {
423
+ for (const key of ["name", "value", "text"]) {
424
+ if (!optional(value, key, bytes)) return false;
425
+ }
426
+ for (const key of ["scope", "construct"]) {
409
427
  if (!optional(value, key, string)) return false;
410
428
  }
411
429
  return (
412
- optional(value, "argv", strings) &&
413
- optional(value, "assigns", pairs) &&
430
+ optional(value, "argv", byteList) &&
431
+ optional(value, "assigns", bytePairs) &&
414
432
  optional(value, "redirs", redirections) &&
415
433
  optional(value, "resolved", resolved) &&
416
434
  optional(value, "pipestatus", numbers) &&
@@ -420,7 +438,7 @@ function historyEntry(value: unknown): value is ShellTraceHistoryEvent {
420
438
  optional(value, "contributors", items => Array.isArray(items) && items.every(outputContributor)) &&
421
439
  (value.kind !== "Output" || (string(value.text) && finite(value.fd))) &&
422
440
  (value.kind !== "Assign" ||
423
- (string(value.name) && string(value.value) && finite(value.full_len) && string(value.scope)))
441
+ (bytes(value.name) && bytes(value.value) && finite(value.full_len) && string(value.scope)))
424
442
  );
425
443
  }
426
444
 
@@ -440,7 +458,7 @@ export function isShellTrace(value: unknown): value is ShellTrace {
440
458
  "diags",
441
459
  items =>
442
460
  Array.isArray(items) &&
443
- items.every((item: unknown) => record(item) && string(item.code) && string(item.message)),
461
+ items.every((item: unknown) => record(item) && string(item.code) && bytes(item.message)),
444
462
  ) &&
445
463
  optional(value, "history", items => Array.isArray(items) && items.every(historyEntry)) &&
446
464
  optional(value, "historyTruncated", boolean)