@linxiraos/pi-utils 1.1.7 → 1.1.9

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.
Files changed (188) hide show
  1. package/CHANGELOG.md +2 -8
  2. package/README.md +18 -18
  3. package/package.json +57 -63
  4. package/src/acp/connection.ts +6 -10
  5. package/src/ar/entries.ts +1 -1
  6. package/src/ar/sevenzip.ts +17 -2
  7. package/src/async.ts +25 -4
  8. package/src/browsers.ts +11 -5
  9. package/src/dirs.ts +15 -10
  10. package/src/dom/core.ts +4 -4
  11. package/src/env.ts +12 -0
  12. package/src/fetch-retry.ts +36 -1
  13. package/src/format.ts +1 -1
  14. package/src/frontmatter.ts +1 -0
  15. package/src/incoming-json.ts +856 -0
  16. package/src/index.ts +2 -0
  17. package/src/json-lexer.ts +413 -0
  18. package/src/json-parse.ts +93 -350
  19. package/src/marked/core.ts +8 -1
  20. package/src/materialize-string.ts +10 -0
  21. package/src/path.ts +14 -0
  22. package/src/postmortem.ts +33 -6
  23. package/src/prompt.ts +1 -0
  24. package/src/ring.ts +1 -0
  25. package/src/temp.ts +16 -4
  26. package/src/template.ts +2 -2
  27. package/src/tls-fetch.ts +2 -16
  28. package/src/turndown/html.ts +1 -1
  29. package/src/vterm/query-responder.ts +76 -0
  30. package/src/vterm.ts +1 -0
  31. package/THIRD-PARTY-NOTICES.txt +0 -22909
  32. package/dist/types/abortable.d.ts +0 -32
  33. package/dist/types/acp/connection.d.ts +0 -118
  34. package/dist/types/acp/protocol.d.ts +0 -526
  35. package/dist/types/acp/schema.d.ts +0 -41
  36. package/dist/types/acp/stream.d.ts +0 -8
  37. package/dist/types/acp/transport.d.ts +0 -88
  38. package/dist/types/acp.d.ts +0 -6
  39. package/dist/types/ar/arj.d.ts +0 -5
  40. package/dist/types/ar/asar.d.ts +0 -7
  41. package/dist/types/ar/bytes.d.ts +0 -20
  42. package/dist/types/ar/cab.d.ts +0 -5
  43. package/dist/types/ar/checksums.d.ts +0 -10
  44. package/dist/types/ar/codecs/bzip2.d.ts +0 -4
  45. package/dist/types/ar/codecs/gzip.d.ts +0 -6
  46. package/dist/types/ar/codecs/lzma.d.ts +0 -6
  47. package/dist/types/ar/codecs/lzw.d.ts +0 -4
  48. package/dist/types/ar/codecs/lzx.d.ts +0 -7
  49. package/dist/types/ar/codecs/xz.d.ts +0 -4
  50. package/dist/types/ar/codecs/zstd.d.ts +0 -6
  51. package/dist/types/ar/cpio.d.ts +0 -7
  52. package/dist/types/ar/deb.d.ts +0 -5
  53. package/dist/types/ar/entries.d.ts +0 -22
  54. package/dist/types/ar/error.d.ts +0 -8
  55. package/dist/types/ar/index.d.ts +0 -11
  56. package/dist/types/ar/iso.d.ts +0 -5
  57. package/dist/types/ar/limits.d.ts +0 -33
  58. package/dist/types/ar/lzh.d.ts +0 -7
  59. package/dist/types/ar/open.d.ts +0 -45
  60. package/dist/types/ar/paths.d.ts +0 -18
  61. package/dist/types/ar/rar/rar4-decoder.d.ts +0 -6
  62. package/dist/types/ar/rar/rar5-decoder.d.ts +0 -6
  63. package/dist/types/ar/rar.d.ts +0 -5
  64. package/dist/types/ar/reader.d.ts +0 -28
  65. package/dist/types/ar/registry.d.ts +0 -17
  66. package/dist/types/ar/rpm.d.ts +0 -5
  67. package/dist/types/ar/sevenzip/decode.d.ts +0 -33
  68. package/dist/types/ar/sevenzip.d.ts +0 -5
  69. package/dist/types/ar/source.d.ts +0 -54
  70. package/dist/types/ar/tar.d.ts +0 -9
  71. package/dist/types/ar/types.d.ts +0 -99
  72. package/dist/types/ar/unix-ar.d.ts +0 -7
  73. package/dist/types/ar/write.d.ts +0 -10
  74. package/dist/types/ar/zip.d.ts +0 -10
  75. package/dist/types/async.d.ts +0 -22
  76. package/dist/types/binary.d.ts +0 -23
  77. package/dist/types/browsers.d.ts +0 -68
  78. package/dist/types/chalk.d.ts +0 -125
  79. package/dist/types/cli.d.ts +0 -134
  80. package/dist/types/color.d.ts +0 -136
  81. package/dist/types/dates.d.ts +0 -7
  82. package/dist/types/dirs.d.ts +0 -325
  83. package/dist/types/docx/converter.d.ts +0 -46
  84. package/dist/types/docx/xml.d.ts +0 -26
  85. package/dist/types/docx.d.ts +0 -11
  86. package/dist/types/dom/core.d.ts +0 -431
  87. package/dist/types/dom/parser.d.ts +0 -7
  88. package/dist/types/dom/selector.d.ts +0 -5
  89. package/dist/types/dom.d.ts +0 -5
  90. package/dist/types/env.d.ts +0 -124
  91. package/dist/types/fetch-retry.d.ts +0 -96
  92. package/dist/types/file-lock.d.ts +0 -23
  93. package/dist/types/format.d.ts +0 -37
  94. package/dist/types/frontmatter.d.ts +0 -46
  95. package/dist/types/fs-error.d.ts +0 -31
  96. package/dist/types/glob.d.ts +0 -28
  97. package/dist/types/headers.d.ts +0 -34
  98. package/dist/types/index.d.ts +0 -41
  99. package/dist/types/json-parse.d.ts +0 -83
  100. package/dist/types/json.d.ts +0 -20
  101. package/dist/types/logger/rotating-file.d.ts +0 -18
  102. package/dist/types/logger.d.ts +0 -96
  103. package/dist/types/loop-phase.d.ts +0 -10
  104. package/dist/types/lru.d.ts +0 -46
  105. package/dist/types/marked/core.d.ts +0 -445
  106. package/dist/types/marked.d.ts +0 -2
  107. package/dist/types/math-delimiters.d.ts +0 -45
  108. package/dist/types/mermaid-ascii.d.ts +0 -11
  109. package/dist/types/mime.d.ts +0 -29
  110. package/dist/types/module-timer.d.ts +0 -1
  111. package/dist/types/path-tree.d.ts +0 -76
  112. package/dist/types/path.d.ts +0 -2
  113. package/dist/types/peek-file.d.ts +0 -29
  114. package/dist/types/postmortem.d.ts +0 -174
  115. package/dist/types/process-name.d.ts +0 -7
  116. package/dist/types/procmgr.d.ts +0 -74
  117. package/dist/types/prompt.d.ts +0 -18
  118. package/dist/types/ptree.d.ts +0 -124
  119. package/dist/types/readability/readability.d.ts +0 -9
  120. package/dist/types/readability/readerable.d.ts +0 -10
  121. package/dist/types/readability/types.d.ts +0 -70
  122. package/dist/types/readability.d.ts +0 -4
  123. package/dist/types/ring.d.ts +0 -93
  124. package/dist/types/runtime-install.d.ts +0 -85
  125. package/dist/types/sanitize-text.d.ts +0 -29
  126. package/dist/types/snowflake.d.ts +0 -25
  127. package/dist/types/sqlite.d.ts +0 -26
  128. package/dist/types/stderr-guard.d.ts +0 -22
  129. package/dist/types/stream.d.ts +0 -75
  130. package/dist/types/tab-spacing.d.ts +0 -24
  131. package/dist/types/temp.d.ts +0 -17
  132. package/dist/types/template.d.ts +0 -62
  133. package/dist/types/timing-buffer.d.ts +0 -22
  134. package/dist/types/tls-fetch.d.ts +0 -37
  135. package/dist/types/turndown/gfm.d.ts +0 -11
  136. package/dist/types/turndown/html.d.ts +0 -5
  137. package/dist/types/turndown/service.d.ts +0 -21
  138. package/dist/types/turndown/types.d.ts +0 -70
  139. package/dist/types/turndown.d.ts +0 -4
  140. package/dist/types/type-guards.d.ts +0 -5
  141. package/dist/types/vendor/mermaid-ascii/ascii/ansi.d.ts +0 -41
  142. package/dist/types/vendor/mermaid-ascii/ascii/canvas.d.ts +0 -89
  143. package/dist/types/vendor/mermaid-ascii/ascii/class-diagram.d.ts +0 -7
  144. package/dist/types/vendor/mermaid-ascii/ascii/converter.d.ts +0 -12
  145. package/dist/types/vendor/mermaid-ascii/ascii/draw.d.ts +0 -66
  146. package/dist/types/vendor/mermaid-ascii/ascii/edge-bundling.d.ts +0 -48
  147. package/dist/types/vendor/mermaid-ascii/ascii/edge-routing.d.ts +0 -43
  148. package/dist/types/vendor/mermaid-ascii/ascii/er-diagram.d.ts +0 -7
  149. package/dist/types/vendor/mermaid-ascii/ascii/grid.d.ts +0 -56
  150. package/dist/types/vendor/mermaid-ascii/ascii/index.d.ts +0 -65
  151. package/dist/types/vendor/mermaid-ascii/ascii/multiline-utils.d.ts +0 -27
  152. package/dist/types/vendor/mermaid-ascii/ascii/pathfinder.d.ts +0 -17
  153. package/dist/types/vendor/mermaid-ascii/ascii/sequence.d.ts +0 -7
  154. package/dist/types/vendor/mermaid-ascii/ascii/shapes/circle.d.ts +0 -11
  155. package/dist/types/vendor/mermaid-ascii/ascii/shapes/corners.d.ts +0 -34
  156. package/dist/types/vendor/mermaid-ascii/ascii/shapes/diamond.d.ts +0 -11
  157. package/dist/types/vendor/mermaid-ascii/ascii/shapes/hexagon.d.ts +0 -11
  158. package/dist/types/vendor/mermaid-ascii/ascii/shapes/index.d.ts +0 -26
  159. package/dist/types/vendor/mermaid-ascii/ascii/shapes/rectangle.d.ts +0 -31
  160. package/dist/types/vendor/mermaid-ascii/ascii/shapes/rounded.d.ts +0 -11
  161. package/dist/types/vendor/mermaid-ascii/ascii/shapes/special.d.ts +0 -59
  162. package/dist/types/vendor/mermaid-ascii/ascii/shapes/stadium.d.ts +0 -17
  163. package/dist/types/vendor/mermaid-ascii/ascii/shapes/state.d.ts +0 -30
  164. package/dist/types/vendor/mermaid-ascii/ascii/shapes/types.d.ts +0 -55
  165. package/dist/types/vendor/mermaid-ascii/ascii/types.d.ts +0 -206
  166. package/dist/types/vendor/mermaid-ascii/ascii/validate.d.ts +0 -51
  167. package/dist/types/vendor/mermaid-ascii/ascii/xychart.d.ts +0 -2
  168. package/dist/types/vendor/mermaid-ascii/class/parser.d.ts +0 -6
  169. package/dist/types/vendor/mermaid-ascii/class/types.d.ts +0 -102
  170. package/dist/types/vendor/mermaid-ascii/er/parser.d.ts +0 -6
  171. package/dist/types/vendor/mermaid-ascii/er/types.d.ts +0 -76
  172. package/dist/types/vendor/mermaid-ascii/index.d.ts +0 -1
  173. package/dist/types/vendor/mermaid-ascii/multiline-utils.d.ts +0 -9
  174. package/dist/types/vendor/mermaid-ascii/parser.d.ts +0 -7
  175. package/dist/types/vendor/mermaid-ascii/sequence/parser.d.ts +0 -6
  176. package/dist/types/vendor/mermaid-ascii/sequence/types.d.ts +0 -130
  177. package/dist/types/vendor/mermaid-ascii/text-metrics.d.ts +0 -23
  178. package/dist/types/vendor/mermaid-ascii/types.d.ts +0 -114
  179. package/dist/types/vendor/mermaid-ascii/xychart/colors.d.ts +0 -25
  180. package/dist/types/vendor/mermaid-ascii/xychart/parser.d.ts +0 -6
  181. package/dist/types/vendor/mermaid-ascii/xychart/types.d.ts +0 -145
  182. package/dist/types/version.d.ts +0 -18
  183. package/dist/types/vterm/buffer.d.ts +0 -99
  184. package/dist/types/vterm/terminal.d.ts +0 -44
  185. package/dist/types/vterm.d.ts +0 -8
  186. package/dist/types/which.d.ts +0 -37
  187. package/dist/types/worker-host.d.ts +0 -51
  188. package/dist/types/xml.d.ts +0 -31
package/CHANGELOG.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
- ## [1.1.7] - 2026-09-01
5
+ ## [1.1.9] - 2026-09-05
6
6
 
7
- - 同步上游 OMP v18.0.11(`b8ce33a58911c26bed1d84f0db9a5e2e727c49a2`)。
7
+ - USER_AGENT constant restored to zeta/<version> (the v18.1.10 merge re-introduced the upstream omp/ UA on every provider request); brand wording in path-resolver docs corrected; profile validation error message Zeta'd.
8
8
 
9
9
  ## [1.1.6] - 2026-08-30
10
10
 
@@ -15,12 +15,6 @@
15
15
 
16
16
  - 同步上游 OMP v18.0.5 / v18.0.6:新增 browsers / json 工具,SHA-2/SHA-3 在 ARM64 上加速。
17
17
 
18
- ## [1.1.3] - 2026-08-25
19
-
20
- ### Fixed
21
-
22
- - Republished as 1.1.3 to reset the latest tag after the broken 1.1.2 (no functional change over 1.1.1).
23
-
24
18
  ## [1.1.2] - 2026-08-25
25
19
 
26
20
  ### Fixed
package/README.md CHANGED
@@ -1,25 +1,25 @@
1
1
  # @linxiraos/pi-utils
2
2
 
3
- Shared utilities for [Zeta](https://github.com/Linxira-OS/linxira-zeta) packages. Zero ceremony, Bun-first.
3
+ Shared utilities for [oh-my-pi](https://github.com/can1357/oh-my-pi) packages. Zero ceremony, Bun-first.
4
4
 
5
5
  ## Notable modules
6
6
 
7
- | Module | Purpose |
8
- | --- | --- |
9
- | `logger` | Centralized logger writing to `~/.zeta/logs/` with rotation (TUI-safe — never stdout) |
10
- | `prompt` | Handlebars-based prompt templating and formatting helpers |
11
- | `dirs` | Path helpers for Zeta config directories (`~/.zeta`, XDG-aware on Linux) |
12
- | `stream` | `readStream` / `readLines` helpers over `ReadableStream` |
13
- | `ptree` / `procmgr` | Process trees, `ChildProcess` wrapper, process lifecycle management |
14
- | `postmortem` | Cleanup callbacks on exit, signals, and fatal exceptions |
15
- | `which` | `$which()` binary lookup with caching |
16
- | `fetch-retry` | `fetch` with retry/backoff policies |
17
- | `fs-error` | Errno guards (`isEnoent` and friends) |
18
- | `env` / `worker-host` | Environment plumbing and side-effect-free worker-host entry contract (`workerHostEntry`) |
19
- | `abortable` / `async` | AbortSignal-aware stream/promise helpers |
20
- | `math-delimiters` | LaTeX span/block delimiter grammar (offsets only) shared by the TUI and collab-web renderers |
21
- | `peek-file` | Read the first N bytes of a file with pooled buffers |
22
- | `frontmatter`, `glob`, `mime`, `temp`, `format`, `color`, `snowflake`, `tab-spacing`, `path-tree`, `sanitize-text` | Smaller single-purpose helpers |
7
+ | Module | Purpose |
8
+ | ------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------- |
9
+ | `logger` | Centralized logger writing to `~/.zeta/logs/` with rotation (TUI-safe — never stdout) |
10
+ | `prompt` | Handlebars-based prompt templating and formatting helpers |
11
+ | `dirs` | Path helpers for omp config directories (`~/.zeta`, XDG-aware on Linux) |
12
+ | `stream` | `readStream` / `readLines` helpers over `ReadableStream` |
13
+ | `ptree` / `procmgr` | Process trees, `ChildProcess` wrapper, process lifecycle management |
14
+ | `postmortem` | Cleanup callbacks on exit, signals, and fatal exceptions |
15
+ | `which` | `$which()` binary lookup with caching |
16
+ | `fetch-retry` | `fetch` with retry/backoff policies |
17
+ | `fs-error` | Errno guards (`isEnoent` and friends) |
18
+ | `env` / `worker-host` | Environment plumbing and side-effect-free worker-host entry contract (`workerHostEntry`) |
19
+ | `abortable` / `async` | AbortSignal-aware stream/promise helpers |
20
+ | `math-delimiters` | LaTeX span/block delimiter grammar (offsets only) shared by the TUI and collab-web renderers |
21
+ | `peek-file` | Read the first N bytes of a file with pooled buffers |
22
+ | `frontmatter`, `glob`, `mime`, `temp`, `format`, `color`, `snowflake`, `tab-spacing`, `path-tree`, `sanitize-text` | Smaller single-purpose helpers |
23
23
 
24
24
  Import from the root barrel or per-module subpaths (`@linxiraos/pi-utils/<module>`).
25
25
 
@@ -33,5 +33,5 @@ Ships TypeScript source directly (no build step); requires Bun ≥ 1.3.14.
33
33
 
34
34
  ## References
35
35
 
36
- - [Monorepo README](https://github.com/Linxira-OS/linxira-zeta#readme)
36
+ - [Monorepo README](https://github.com/can1357/oh-my-pi#readme)
37
37
  - [CHANGELOG](./CHANGELOG.md)
package/package.json CHANGED
@@ -1,65 +1,59 @@
1
1
  {
2
- "type": "module",
3
- "name": "@linxiraos/pi-utils",
4
- "version": "1.1.7",
5
- "description": "Shared utilities for pi packages",
6
- "homepage": "https://linxira-os.github.io/zeta/",
7
- "author": "Can Boluk",
8
- "license": "MIT",
9
- "repository": {
10
- "type": "git",
11
- "url": "git+https://github.com/Linxira-OS/linxira-zeta.git",
12
- "directory": "packages/utils"
13
- },
14
- "bugs": {
15
- "url": "https://github.com/Linxira-OS/linxira-zeta/issues"
16
- },
17
- "keywords": [
18
- "utilities",
19
- "cli",
20
- "logging",
21
- "streams"
22
- ],
23
- "main": "./src/index.ts",
24
- "types": "./dist/types/index.d.ts",
25
- "scripts": {
26
- "check": "biome check . && bun run check:types",
27
- "check:types": "tsgo -p tsconfig.json --noEmit",
28
- "lint": "biome lint .",
29
- "test": "bun test --parallel",
30
- "fix": "biome check --write --unsafe .",
31
- "fmt": "biome format --write ."
32
- },
33
- "dependencies": {
34
- "@linxiraos/pi-natives": "1.1.7"
35
- },
36
- "devDependencies": {
37
- "@types/bun": "^1.3.14"
38
- },
39
- "engines": {
40
- "bun": ">=1.3.14"
41
- },
42
- "files": [
43
- "src",
44
- "README.md",
45
- "CHANGELOG.md",
46
- "LICENSE",
47
- "THIRD-PARTY-NOTICES.txt",
48
- "dist/types"
49
- ],
50
- "exports": {
51
- ".": {
52
- "types": "./dist/types/index.d.ts",
53
- "import": "./src/index.ts"
54
- },
55
- "./ar": {
56
- "types": "./dist/types/ar/index.d.ts",
57
- "import": "./src/ar/index.ts"
58
- },
59
- "./*": {
60
- "types": "./dist/types/*.d.ts",
61
- "import": "./src/*.ts"
62
- },
63
- "./*.js": "./src/*.ts"
64
- }
2
+ "engines": {
3
+ "bun": ">=1.3.14"
4
+ },
5
+ "devDependencies": {
6
+ "@types/bun": "^1.3.14"
7
+ },
8
+ "dependencies": {
9
+ "@linxiraos/pi-natives": "1.1.9"
10
+ },
11
+ "scripts": {
12
+ "test": "bun test --parallel",
13
+ "check:types": "tsgo -p tsconfig.json --noEmit",
14
+ "check": "tsgo -p tsconfig.json --noEmit"
15
+ },
16
+ "exports": {
17
+ "./*.js": "./src/*.ts",
18
+ "./*": {
19
+ "import": "./src/*.ts",
20
+ "types": "./src/*.ts"
21
+ },
22
+ "./ar": {
23
+ "import": "./src/ar/index.ts",
24
+ "types": "./src/ar/index.ts"
25
+ },
26
+ ".": {
27
+ "import": "./src/index.ts",
28
+ "types": "./src/index.ts"
29
+ }
30
+ },
31
+ "types": "./src/index.ts",
32
+ "main": "./src/index.ts",
33
+ "type": "module",
34
+ "files": [
35
+ "src",
36
+ "README.md",
37
+ "CHANGELOG.md"
38
+ ],
39
+ "repository": {
40
+ "directory": "packages/utils",
41
+ "url": "git+https://github.com/Linxira-OS/linxira-zeta.git",
42
+ "type": "git"
43
+ },
44
+ "author": "Can Boluk",
45
+ "license": "MIT",
46
+ "bugs": {
47
+ "url": "https://github.com/Linxira-OS/linxira-zeta/issues"
48
+ },
49
+ "homepage": "https://linxira-os.github.io/zeta/",
50
+ "keywords": [
51
+ "utilities",
52
+ "cli",
53
+ "logging",
54
+ "streams"
55
+ ],
56
+ "description": "Shared utilities for pi packages",
57
+ "version": "1.1.9",
58
+ "name": "@linxiraos/pi-utils"
65
59
  }
@@ -67,13 +67,11 @@ export class AgentSideConnection {
67
67
  #connection: RpcConnection;
68
68
 
69
69
  constructor(toAgent: (connection: AgentSideConnection) => Agent, stream: Stream) {
70
- let agent: Agent | undefined;
71
70
  this.#connection = new RpcConnection(stream, async (method, params, notification) => {
72
- const target = agent;
73
- if (!target) throw RequestError.internalError(undefined, "Agent is not initialized");
74
- return dispatchAgent(target, method, params, notification);
71
+ if (!agent) throw RequestError.internalError(undefined, "Agent is not initialized");
72
+ return dispatchAgent(agent, method, params, notification);
75
73
  });
76
- agent = toAgent(this);
74
+ const agent = toAgent(this);
77
75
  }
78
76
 
79
77
  /** Signal aborted when the transport closes. */
@@ -170,13 +168,11 @@ export class ClientSideConnection {
170
168
  #connection: RpcConnection;
171
169
 
172
170
  constructor(toClient: (connection: ClientSideConnection) => Client, stream: Stream) {
173
- let client: Client | undefined;
174
171
  this.#connection = new RpcConnection(stream, async (method, params, notification) => {
175
- const target = client;
176
- if (!target) throw RequestError.internalError(undefined, "Client is not initialized");
177
- return dispatchClient(target, method, params, notification);
172
+ if (!client) throw RequestError.internalError(undefined, "Client is not initialized");
173
+ return dispatchClient(client, method, params, notification);
178
174
  });
179
- client = toClient(this);
175
+ const client = toClient(this);
180
176
  }
181
177
  /** Signal aborted when the transport closes. */
182
178
  get signal(): AbortSignal {
package/src/ar/entries.ts CHANGED
@@ -45,7 +45,7 @@ export function upsertArchiveEntry(
45
45
  */
46
46
  export function ensureParentDirectories(map: Map<string, ArchiveIndexEntry>, limits: ArchiveLimits): void {
47
47
  assertEntryCount(map.size, limits);
48
- for (const entry of [...map.values()]) {
48
+ for (const entry of Array.from(map.values())) {
49
49
  const parts = entry.path.split("/");
50
50
  const stop = parts.length - 1;
51
51
  for (let index = 1; index <= stop; index++) {
@@ -107,6 +107,7 @@ interface FileMetadata {
107
107
  }
108
108
 
109
109
  function readBoolVector(reader: HeaderReader, count: number): boolean[] {
110
+ // [suppressed] length preallocation
110
111
  const result = new Array<boolean>(count);
111
112
  let byte = 0;
112
113
  let mask = 0;
@@ -122,12 +123,16 @@ function readBoolVector(reader: HeaderReader, count: number): boolean[] {
122
123
  }
123
124
 
124
125
  function readDefinedVector(reader: HeaderReader, count: number): boolean[] {
125
- if (reader.readByte() !== 0) return new Array<boolean>(count).fill(true);
126
+ if (reader.readByte() !== 0) {
127
+ // [suppressed] length preallocation
128
+ return new Array<boolean>(count).fill(true);
129
+ }
126
130
  return readBoolVector(reader, count);
127
131
  }
128
132
 
129
133
  function readDigests(reader: HeaderReader, count: number): Digests {
130
134
  const defined = readDefinedVector(reader, count);
135
+ // [suppressed] length preallocation
131
136
  const values = new Array<number | undefined>(count);
132
137
  for (let index = 0; index < count; index++) if (defined[index]) values[index] = reader.readUInt32();
133
138
  return { defined, values };
@@ -229,7 +234,10 @@ function parsePackInfo(reader: HeaderReader, streams: SevenZipStreams, options:
229
234
  } else reader.skipSizedProperty();
230
235
  }
231
236
  if (streams.packSizes.length !== count) throw new ArchiveError("Invalid 7z PackInfo without complete sizes");
232
- if (streams.packCrcs.length === 0) streams.packCrcs = new Array(count).fill(undefined);
237
+ if (streams.packCrcs.length === 0) {
238
+ // [suppressed] length preallocation
239
+ streams.packCrcs = new Array(count).fill(undefined);
240
+ }
233
241
  }
234
242
 
235
243
  function parseUnpackInfo(reader: HeaderReader, streams: SevenZipStreams, options: FormatReadOptions): void {
@@ -254,6 +262,7 @@ function parseUnpackInfo(reader: HeaderReader, streams: SevenZipStreams, options
254
262
  }
255
263
 
256
264
  function parseSubStreamsInfo(reader: HeaderReader, streams: SevenZipStreams): void {
265
+ // [suppressed] length preallocation
257
266
  const counts = new Array<number>(streams.folders.length).fill(1);
258
267
  let sizes: number[] | undefined;
259
268
  let rawDigests: Digests | undefined;
@@ -398,6 +407,7 @@ function parseNames(reader: HeaderReader, count: number, external: Uint8Array[],
398
407
  function parseTimes(reader: HeaderReader, count: number, external: Uint8Array[]): Array<number | undefined> {
399
408
  const defined = readDefinedVector(reader, count);
400
409
  const values = selectPropertyStream(reader, external);
410
+ // [suppressed] length preallocation
401
411
  const result = new Array<number | undefined>(count);
402
412
  for (let index = 0; index < count; index++)
403
413
  if (defined[index]) {
@@ -411,6 +421,7 @@ function parseTimes(reader: HeaderReader, count: number, external: Uint8Array[])
411
421
  function parseAttributes(reader: HeaderReader, count: number, external: Uint8Array[]): Array<number | undefined> {
412
422
  const defined = readDefinedVector(reader, count);
413
423
  const values = selectPropertyStream(reader, external);
424
+ // [suppressed] length preallocation
414
425
  const result = new Array<number | undefined>(count);
415
426
  for (let index = 0; index < count; index++) if (defined[index]) result[index] = values.readUInt32();
416
427
  return result;
@@ -420,11 +431,15 @@ function parseFilesInfo(reader: HeaderReader, external: Uint8Array[], options: F
420
431
  const count = reader.readNumber("file count");
421
432
  assertEntryCount(count, options.limits);
422
433
  const metadata: FileMetadata = {
434
+ // [suppressed] length preallocation
423
435
  names: new Array<string>(count).fill(""),
436
+ // [suppressed] length preallocation
424
437
  emptyStreams: new Array<boolean>(count).fill(false),
425
438
  emptyFiles: [],
426
439
  antiFiles: [],
440
+ // [suppressed] length preallocation
427
441
  mtimes: new Array<number | undefined>(count),
442
+ // [suppressed] length preallocation
428
443
  attributes: new Array<number | undefined>(count),
429
444
  };
430
445
  for (;;) {
package/src/async.ts CHANGED
@@ -1,9 +1,14 @@
1
1
  /**
2
2
  * Wrap a promise with a timeout and optional abort signal.
3
- * Rejects with the given message if the timeout fires first.
4
- * Cleans up all listeners on settlement.
3
+ * Rejects with the given error or a new error containing the given message if
4
+ * the timeout fires first. Cleans up all listeners on settlement.
5
5
  */
6
- export function withTimeout<T>(promise: Promise<T>, ms: number, message: string, signal?: AbortSignal): Promise<T> {
6
+ export function withTimeout<T>(
7
+ promise: Promise<T>,
8
+ ms: number,
9
+ timeout: string | Error,
10
+ signal?: AbortSignal,
11
+ ): Promise<T> {
7
12
  if (signal?.aborted) {
8
13
  const reason = signal.reason instanceof Error ? signal.reason : new Error("Aborted");
9
14
  return Promise.reject(reason);
@@ -15,7 +20,7 @@ export function withTimeout<T>(promise: Promise<T>, ms: number, message: string,
15
20
  if (settled) return;
16
21
  settled = true;
17
22
  if (signal) signal.removeEventListener("abort", onAbort);
18
- reject(new Error(message));
23
+ reject(typeof timeout === "string" ? new Error(timeout) : timeout);
19
24
  }, ms);
20
25
 
21
26
  const onAbort = () => {
@@ -103,3 +108,19 @@ export class AsyncDrain<T> {
103
108
  return this.#promise;
104
109
  }
105
110
  }
111
+
112
+ /**
113
+ * Runs async operations one at a time in call order. Each `run` starts after
114
+ * the previous operation settles (success or failure) and returns that
115
+ * operation's own promise, so a rejected step never poisons the queue. Used by
116
+ * stateful cursors whose concurrent pulls must not interleave.
117
+ */
118
+ export class Serial {
119
+ #tail: Promise<unknown> = Promise.resolve();
120
+
121
+ run<T>(op: () => Promise<T>): Promise<T> {
122
+ const result = this.#tail.then(op, op);
123
+ this.#tail = result.catch(() => {});
124
+ return result;
125
+ }
126
+ }
package/src/browsers.ts CHANGED
@@ -39,6 +39,13 @@ export enum BrowserPlatform {
39
39
  WIN32 = "win32",
40
40
  WIN64 = "win64",
41
41
  }
42
+ type ChromeForTestingPlatform = Exclude<BrowserPlatform, BrowserPlatform.LINUX_ARM>;
43
+
44
+ function requireChromeForTestingPlatform(platform: BrowserPlatform): ChromeForTestingPlatform {
45
+ if (platform === BrowserPlatform.LINUX_ARM)
46
+ throw new Error("Chrome for Testing does not provide linux/arm64 builds");
47
+ return platform;
48
+ }
42
49
 
43
50
  const BROWSERS = [
44
51
  Browser.CHROME,
@@ -163,13 +170,13 @@ export function getDownloadUrl(
163
170
 
164
171
  /** Compute the executable path in Puppeteer's cache layout. */
165
172
  export function computeExecutablePath(options: ComputeExecutablePathOptions): string {
166
- const platform = options.platform ?? detectBrowserPlatform();
167
- if (!platform) throw new Error("Cannot determine a browser platform for this host");
173
+ const detectedPlatform = options.platform ?? detectBrowserPlatform();
174
+ if (!detectedPlatform) throw new Error("Cannot determine a browser platform for this host");
168
175
  if (options.browser !== Browser.CHROME) throw new Error(`Unsupported browser executable: ${options.browser}`);
176
+ const platform = requireChromeForTestingPlatform(detectedPlatform);
169
177
  const installDir = installationDir(options.cacheDir, options.browser, platform, options.buildId);
170
178
  switch (platform) {
171
179
  case BrowserPlatform.LINUX:
172
- case BrowserPlatform.LINUX_ARM:
173
180
  return path.join(installDir, "chrome-linux64", "chrome");
174
181
  case BrowserPlatform.MAC:
175
182
  return path.join(
@@ -292,9 +299,8 @@ async function fetchMetadata<T>(filename: string): Promise<T> {
292
299
  }
293
300
 
294
301
  function chromeArchivePlatform(platform: BrowserPlatform): string {
295
- switch (platform) {
302
+ switch (requireChromeForTestingPlatform(platform)) {
296
303
  case BrowserPlatform.LINUX:
297
- case BrowserPlatform.LINUX_ARM:
298
304
  return "linux64";
299
305
  case BrowserPlatform.MAC:
300
306
  return "mac-x64";
package/src/dirs.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  * variables are set, paths are redirected to XDG-compliant locations under
9
9
  * $XDG_*_HOME/zeta/. This requires running `zeta config migrate` first to
10
10
  * move data to the new locations. No filesystem existence checks are performed
11
- * — if the env var is set, omp trusts that the migration has been done.
11
+ * — if the env var is set, zeta trusts that the migration has been done.
12
12
  */
13
13
 
14
14
  import * as fs from "node:fs";
@@ -17,7 +17,7 @@ import * as path from "node:path";
17
17
  import { engines, version } from "../package.json" with { type: "json" };
18
18
  import { isEnoent, isEnotdir } from "./fs-error";
19
19
 
20
- /** App name (e.g. "omp") */
20
+ /** App name (e.g. "zeta") */
21
21
  export const APP_NAME: string = "zeta";
22
22
 
23
23
  /** Config directory name (e.g. ".zeta") */
@@ -67,7 +67,7 @@ export function normalizeProfileName(profile: string | undefined): string | unde
67
67
  WINDOWS_RESERVED_BASENAME_RE.test(normalized)
68
68
  ) {
69
69
  throw new Error(
70
- `Invalid OMP profile "${profile}". Profile names must match ${PROFILE_NAME_RE.source}, ` +
70
+ `Invalid Zeta profile "${profile}". Profile names must match ${PROFILE_NAME_RE.source}, ` +
71
71
  `cannot be "." or "..", cannot end with ".", and cannot be a Windows reserved device name ` +
72
72
  `(CON, PRN, AUX, NUL, COM0-9, LPT0-9, or any of those with an extension).`,
73
73
  );
@@ -97,7 +97,7 @@ function getProfileFromEnv(): string | undefined {
97
97
  * crash a bare `import` of this module with an uncaught stack trace before the
98
98
  * CLI's error handling is in scope. The default profile is used instead; the
99
99
  * CLI re-validates the env (see `runCli` in coding-agent/src/cli.ts) so the
100
- * user still gets a clean "Invalid OMP profile" message.
100
+ * user still gets a clean "Invalid Zeta profile" message.
101
101
  */
102
102
  function readProfileFromEnvSafe(): string | undefined {
103
103
  try {
@@ -295,7 +295,7 @@ export function getConfigAgentDirName(): string {
295
295
  type XdgCategory = "data" | "state" | "cache";
296
296
 
297
297
  /**
298
- * Resolves and caches all omp directory paths. On Linux, when XDG environment
298
+ * Resolves and caches all zeta directory paths. On Linux, when XDG environment
299
299
  * variables are set, paths are redirected under $XDG_*_HOME/zeta/. A new
300
300
  * instance is created whenever the agent directory changes, which naturally
301
301
  * invalidates all cached paths.
@@ -949,6 +949,11 @@ export function getSecretPlaceholderKeyPath(): string {
949
949
  return keyPath;
950
950
  }
951
951
 
952
+ /** Directory holding the per-model tiny-worker sockets and logs (~/.zeta/run/tiny; XDG default: $XDG_STATE_HOME/zeta/run/tiny). */
953
+ export function getTinyWorkerRuntimeDir(): string {
954
+ return dirs.rootSubdir(path.join("run", "tiny"), "state");
955
+ }
956
+
952
957
  /** Root directory containing every per-project daemon runtime scope (~/.zeta/run/daemons; XDG default: $XDG_STATE_HOME/zeta/run/daemons). */
953
958
  export function getDaemonRuntimeRoot(): string {
954
959
  return dirs.rootSubdir(path.join("run", "daemons"), "state");
@@ -1108,11 +1113,6 @@ export function getInstallId(): string {
1108
1113
  return next;
1109
1114
  }
1110
1115
 
1111
- /** Test-only: clear cached install id. Never call from production code. */
1112
- export function __resetInstallIdCacheForTests(): void {
1113
- cachedInstallId = null;
1114
- }
1115
-
1116
1116
  /** Get the project-level tracking directory (<project>/.zeta/tracking). */
1117
1117
  export function getProjectTrackingDir(cwd: string = getProjectDir()): string {
1118
1118
  return path.join(getProjectAgentDir(cwd), "tracking");
@@ -1122,3 +1122,8 @@ export function getProjectTrackingDir(cwd: string = getProjectDir()): string {
1122
1122
  export function getTrackingIndexPath(agentDir?: string): string {
1123
1123
  return path.join(agentDir ?? getAgentDir(), "tracking-index.json");
1124
1124
  }
1125
+
1126
+ /** Test-only: clear cached install id. Never call from production code. */
1127
+ export function __resetInstallIdCacheForTests(): void {
1128
+ cachedInstallId = null;
1129
+ }
package/src/dom/core.ts CHANGED
@@ -105,7 +105,7 @@ export class EventTarget {
105
105
  dispatchEvent(event: Event): boolean {
106
106
  if (!event.target) event.target = this;
107
107
  event.currentTarget = this;
108
- for (const listener of [...(this.#listeners.get(event.type) ?? [])]) {
108
+ for (const listener of Array.from(this.#listeners.get(event.type) ?? [])) {
109
109
  if (typeof listener === "function") listener.call(this, event);
110
110
  else listener.handleEvent(event);
111
111
  if (event.propagationStopped) break;
@@ -196,7 +196,7 @@ export class Node extends EventTarget {
196
196
  const node: Node = child;
197
197
  if (node === this || node.contains(this)) throw new Error("The new child is an ancestor of this node");
198
198
  if (child instanceof DocumentFragment) {
199
- for (const nested of [...child.childNodes]) this.appendChild(nested);
199
+ for (const nested of Array.from(child.childNodes)) this.appendChild(nested);
200
200
  return child;
201
201
  }
202
202
  child.parentNode?.removeChild(child);
@@ -212,7 +212,7 @@ export class Node extends EventTarget {
212
212
  const index = this.childNodes.indexOf(reference);
213
213
  if (index < 0) throw new Error("The reference node is not a child of this node");
214
214
  if (child instanceof DocumentFragment) {
215
- for (const nested of [...child.childNodes]) this.insertBefore(nested, reference);
215
+ for (const nested of Array.from(child.childNodes)) this.insertBefore(nested, reference);
216
216
  return child;
217
217
  }
218
218
  child.parentNode?.removeChild(child);
@@ -681,7 +681,7 @@ export class Element extends Node {
681
681
  const parent = this.parentNode;
682
682
  if (!parent) return;
683
683
  const fragment = parseFragment(value, this.documentForCreation(), this.parentElement?.localName);
684
- for (const child of [...fragment.childNodes]) parent.insertBefore(child, this);
684
+ for (const child of Array.from(fragment.childNodes)) parent.insertBefore(child, this);
685
685
  parent.removeChild(this);
686
686
  }
687
687
 
package/src/env.ts CHANGED
@@ -36,6 +36,18 @@ export function isMacosMallocStackLoggingEnvName(name: string): boolean {
36
36
  return name === "MallocStackLogging" || name === "MallocStackLoggingNoCompact";
37
37
  }
38
38
 
39
+ /**
40
+ * True when running inside a WSL (Windows Subsystem for Linux) distribution.
41
+ *
42
+ * WSL reports `linux` for `process.platform`, so the only reliable signal is
43
+ * the `WSL_DISTRO_NAME`/`WSL_INTEROP` variables the interop layer injects.
44
+ * Callers use this to translate Windows drive paths to their `/mnt/<drive>`
45
+ * mounts and to route clipboard access through `powershell.exe`.
46
+ */
47
+ export function isWsl(platform: NodeJS.Platform = process.platform, env: NodeJS.ProcessEnv = process.env): boolean {
48
+ return platform === "linux" && Boolean(env.WSL_DISTRO_NAME || env.WSL_INTEROP);
49
+ }
50
+
39
51
  export function filterProcessEnv(env: Record<string, string | undefined>): Record<string, string> {
40
52
  const result: Record<string, string> = {};
41
53
  for (const key in env) {
@@ -12,6 +12,12 @@ const RETRY_DELAY_FIELD_PATTERN = /"retryDelay":\s*"([0-9.]+)(ms|s)"/i;
12
12
  const TRY_AGAIN_PATTERN = /try again in\s+~?\s*([0-9.]+)\s*(ms|sec|s|minutes?|mins?|m|hours?|hrs?|h)\b/i;
13
13
  // "Your limit will reset in 13 minutes" / "reset in 13 minutes" / "will reset in 2h"
14
14
  const WILL_RESET_IN_PATTERN = /(?:will\s+)?reset in\s+~?\s*([0-9.]+)\s*(ms|sec|s|minutes?|mins?|m|hours?|hrs?|h)\b/i;
15
+ // "Your limit will reset at 2026-09-01 09:44:51" / "reset at 2026-09-01T09:44:51Z"
16
+ const WILL_RESET_AT_PATTERN =
17
+ /(?:will\s+)?reset at\s+([0-9]{4}-[0-9]{2}-[0-9]{2}[ T][0-9]{2}:[0-9]{2}:[0-9]{2}(?:\.[0-9]+)?(?:Z|[+-][0-9]{2}:?[0-9]{2})?)/i;
18
+ const CN_RESET_AT_PATTERN = /将在\s*([0-9]{4}-[0-9]{2}-[0-9]{2}\s+[0-9]{2}:[0-9]{2}:[0-9]{2})\s*重置/;
19
+ // "retry-after-ms=98497000"
20
+ const RETRY_AFTER_MS_BODY_PATTERN = /\bretry-after-ms=([0-9]+)\b/i;
15
21
 
16
22
  /**
17
23
  * Server-suggested retry delay extraction. Merges the patterns historically used
@@ -29,6 +35,8 @@ const WILL_RESET_IN_PATTERN = /(?:will\s+)?reset in\s+~?\s*([0-9.]+)\s*(ms|sec|s
29
35
  * - `Please retry in 250ms` / `Please retry in 12s`
30
36
  * - `"retryDelay": "34.074824224s"` (JSON error detail field)
31
37
  * - `try again in 250ms` / `try again in 12s` / `try again in 5 min` / `try again in ~158 min`
38
+ * - `retry-after-ms=98497000`
39
+ * - `Your limit will reset at 2026-09-01 09:44:51` / `将在 2026-09-01 09:44:51 重置`
32
40
  *
33
41
  * Returns `undefined` if no signal is found.
34
42
  */
@@ -85,11 +93,38 @@ export function extractRetryHint(source: Response | Headers | null | undefined,
85
93
  if (totalMs > 0) return totalMs;
86
94
  }
87
95
  }
96
+ for (const pattern of [WILL_RESET_AT_PATTERN, CN_RESET_AT_PATTERN]) {
97
+ const match = pattern.exec(body);
98
+ if (match?.[1]) {
99
+ // Provider timestamps without an explicit offset are interpreted as UTC.
100
+ const normalized = match[1].replace(" ", "T");
101
+ const hasOffset = /(?:Z|[+-][0-9]{2}:?[0-9]{2})$/i.test(normalized);
102
+ const parsed = Date.parse(hasOffset ? normalized : `${normalized}Z`);
103
+ if (!Number.isNaN(parsed) && parsed > Date.now()) {
104
+ return parsed - Date.now();
105
+ }
106
+ }
107
+ }
88
108
  // Account-reset hints ("will reset in …") take precedence over short
89
109
  // retry hints ("please retry in 5s"): a body carrying both must honour the
90
110
  // longer account window, not the shorter generic one. QUOTA_RESET_PATTERN
91
111
  // ("reset after …") above already runs first and stays first.
92
- for (const pattern of [WILL_RESET_IN_PATTERN, PLEASE_RETRY_PATTERN, RETRY_DELAY_FIELD_PATTERN, TRY_AGAIN_PATTERN]) {
112
+ const accountResetMatch = WILL_RESET_IN_PATTERN.exec(body);
113
+ if (accountResetMatch?.[1]) {
114
+ const value = Number.parseFloat(accountResetMatch[1]);
115
+ if (Number.isFinite(value) && value > 0) {
116
+ const unitMs = unitToMs(accountResetMatch[2]!);
117
+ if (unitMs !== undefined) return value * unitMs;
118
+ }
119
+ }
120
+
121
+ const retryAfterMsMatch = RETRY_AFTER_MS_BODY_PATTERN.exec(body);
122
+ if (retryAfterMsMatch?.[1]) {
123
+ const ms = Number(retryAfterMsMatch[1]);
124
+ if (Number.isFinite(ms) && ms > 0) return ms;
125
+ }
126
+
127
+ for (const pattern of [PLEASE_RETRY_PATTERN, RETRY_DELAY_FIELD_PATTERN, TRY_AGAIN_PATTERN]) {
93
128
  const match = pattern.exec(body);
94
129
  if (match?.[1]) {
95
130
  const value = Number.parseFloat(match[1]);
package/src/format.ts CHANGED
@@ -9,7 +9,7 @@ const DAY = 24 * HOUR;
9
9
  */
10
10
  export function formatDuration(ms: number): string {
11
11
  if (!Number.isFinite(ms) || ms <= 0) return "0ms";
12
- if (ms < SEC) return `${ms}ms`;
12
+ if (ms < SEC) return `${Math.floor(ms)}ms`;
13
13
  if (ms < MIN) return `${(ms / SEC).toFixed(1)}s`;
14
14
  if (ms < HOUR) {
15
15
  const mins = Math.floor(ms / MIN);
@@ -22,6 +22,7 @@ export function normalizeFrontmatterKeys<T>(obj: T): T {
22
22
  if (obj === null || typeof obj !== "object") return obj;
23
23
  if (Array.isArray(obj)) {
24
24
  let changed = false;
25
+ // [suppressed] length preallocation
25
26
  const out: unknown[] = new Array(obj.length);
26
27
  for (let i = 0; i < obj.length; i++) {
27
28
  const v = obj[i];