@linxiraos/pi-utils 1.0.0 → 1.0.2

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 (132) hide show
  1. package/CHANGELOG.md +41 -6
  2. package/package.json +56 -57
  3. package/src/dirs.ts +99 -91
  4. package/src/fetch-retry.ts +11 -2
  5. package/src/json-parse.ts +18 -7
  6. package/src/logger.ts +55 -20
  7. package/src/ptree.ts +2 -2
  8. package/src/stderr-guard.ts +1 -1
  9. package/src/stream.ts +27 -3
  10. package/src/vendor/mermaid-ascii/ascii/canvas.ts +8 -6
  11. package/src/vendor/mermaid-ascii/ascii/draw.ts +21 -14
  12. package/src/vendor/mermaid-ascii/text-metrics.ts +3 -0
  13. package/dist/types/abortable.d.ts +0 -32
  14. package/dist/types/acp/connection.d.ts +0 -118
  15. package/dist/types/acp/protocol.d.ts +0 -526
  16. package/dist/types/acp/schema.d.ts +0 -41
  17. package/dist/types/acp/stream.d.ts +0 -8
  18. package/dist/types/acp/transport.d.ts +0 -81
  19. package/dist/types/acp.d.ts +0 -6
  20. package/dist/types/async.d.ts +0 -20
  21. package/dist/types/binary.d.ts +0 -17
  22. package/dist/types/browsers.d.ts +0 -68
  23. package/dist/types/chalk.d.ts +0 -125
  24. package/dist/types/cli.d.ts +0 -134
  25. package/dist/types/color.d.ts +0 -102
  26. package/dist/types/dates.d.ts +0 -7
  27. package/dist/types/dirs.d.ts +0 -282
  28. package/dist/types/docx/converter.d.ts +0 -46
  29. package/dist/types/docx/xml.d.ts +0 -26
  30. package/dist/types/docx/zip.d.ts +0 -6
  31. package/dist/types/docx.d.ts +0 -11
  32. package/dist/types/dom/core.d.ts +0 -431
  33. package/dist/types/dom/parser.d.ts +0 -7
  34. package/dist/types/dom/selector.d.ts +0 -5
  35. package/dist/types/dom.d.ts +0 -5
  36. package/dist/types/env.d.ts +0 -124
  37. package/dist/types/fetch-retry.d.ts +0 -96
  38. package/dist/types/file-lock.d.ts +0 -23
  39. package/dist/types/format.d.ts +0 -37
  40. package/dist/types/frontmatter.d.ts +0 -46
  41. package/dist/types/fs-error.d.ts +0 -31
  42. package/dist/types/glob.d.ts +0 -28
  43. package/dist/types/headers.d.ts +0 -34
  44. package/dist/types/index.d.ts +0 -39
  45. package/dist/types/json-parse.d.ts +0 -74
  46. package/dist/types/json.d.ts +0 -14
  47. package/dist/types/logger/rotating-file.d.ts +0 -18
  48. package/dist/types/logger.d.ts +0 -96
  49. package/dist/types/loop-phase.d.ts +0 -10
  50. package/dist/types/lru.d.ts +0 -46
  51. package/dist/types/marked/core.d.ts +0 -445
  52. package/dist/types/marked.d.ts +0 -2
  53. package/dist/types/mermaid-ascii.d.ts +0 -11
  54. package/dist/types/mime.d.ts +0 -29
  55. package/dist/types/module-timer.d.ts +0 -1
  56. package/dist/types/path-tree.d.ts +0 -76
  57. package/dist/types/path.d.ts +0 -2
  58. package/dist/types/peek-file.d.ts +0 -29
  59. package/dist/types/postmortem.d.ts +0 -104
  60. package/dist/types/process-name.d.ts +0 -7
  61. package/dist/types/procmgr.d.ts +0 -74
  62. package/dist/types/prompt.d.ts +0 -18
  63. package/dist/types/ptree.d.ts +0 -110
  64. package/dist/types/readability/readability.d.ts +0 -9
  65. package/dist/types/readability/readerable.d.ts +0 -10
  66. package/dist/types/readability/types.d.ts +0 -70
  67. package/dist/types/readability.d.ts +0 -4
  68. package/dist/types/ring.d.ts +0 -93
  69. package/dist/types/runtime-install.d.ts +0 -78
  70. package/dist/types/sanitize-text.d.ts +0 -29
  71. package/dist/types/snowflake.d.ts +0 -25
  72. package/dist/types/stderr-guard.d.ts +0 -22
  73. package/dist/types/stream.d.ts +0 -67
  74. package/dist/types/tab-spacing.d.ts +0 -24
  75. package/dist/types/temp.d.ts +0 -17
  76. package/dist/types/template.d.ts +0 -62
  77. package/dist/types/timing-buffer.d.ts +0 -22
  78. package/dist/types/tls-fetch.d.ts +0 -37
  79. package/dist/types/turndown/gfm.d.ts +0 -11
  80. package/dist/types/turndown/html.d.ts +0 -5
  81. package/dist/types/turndown/service.d.ts +0 -21
  82. package/dist/types/turndown/types.d.ts +0 -70
  83. package/dist/types/turndown.d.ts +0 -4
  84. package/dist/types/type-guards.d.ts +0 -5
  85. package/dist/types/vendor/mermaid-ascii/ascii/ansi.d.ts +0 -41
  86. package/dist/types/vendor/mermaid-ascii/ascii/canvas.d.ts +0 -89
  87. package/dist/types/vendor/mermaid-ascii/ascii/class-diagram.d.ts +0 -7
  88. package/dist/types/vendor/mermaid-ascii/ascii/converter.d.ts +0 -12
  89. package/dist/types/vendor/mermaid-ascii/ascii/draw.d.ts +0 -66
  90. package/dist/types/vendor/mermaid-ascii/ascii/edge-bundling.d.ts +0 -48
  91. package/dist/types/vendor/mermaid-ascii/ascii/edge-routing.d.ts +0 -43
  92. package/dist/types/vendor/mermaid-ascii/ascii/er-diagram.d.ts +0 -7
  93. package/dist/types/vendor/mermaid-ascii/ascii/grid.d.ts +0 -56
  94. package/dist/types/vendor/mermaid-ascii/ascii/index.d.ts +0 -65
  95. package/dist/types/vendor/mermaid-ascii/ascii/multiline-utils.d.ts +0 -27
  96. package/dist/types/vendor/mermaid-ascii/ascii/pathfinder.d.ts +0 -17
  97. package/dist/types/vendor/mermaid-ascii/ascii/sequence.d.ts +0 -7
  98. package/dist/types/vendor/mermaid-ascii/ascii/shapes/circle.d.ts +0 -11
  99. package/dist/types/vendor/mermaid-ascii/ascii/shapes/corners.d.ts +0 -34
  100. package/dist/types/vendor/mermaid-ascii/ascii/shapes/diamond.d.ts +0 -11
  101. package/dist/types/vendor/mermaid-ascii/ascii/shapes/hexagon.d.ts +0 -11
  102. package/dist/types/vendor/mermaid-ascii/ascii/shapes/index.d.ts +0 -26
  103. package/dist/types/vendor/mermaid-ascii/ascii/shapes/rectangle.d.ts +0 -31
  104. package/dist/types/vendor/mermaid-ascii/ascii/shapes/rounded.d.ts +0 -11
  105. package/dist/types/vendor/mermaid-ascii/ascii/shapes/special.d.ts +0 -59
  106. package/dist/types/vendor/mermaid-ascii/ascii/shapes/stadium.d.ts +0 -17
  107. package/dist/types/vendor/mermaid-ascii/ascii/shapes/state.d.ts +0 -30
  108. package/dist/types/vendor/mermaid-ascii/ascii/shapes/types.d.ts +0 -55
  109. package/dist/types/vendor/mermaid-ascii/ascii/types.d.ts +0 -206
  110. package/dist/types/vendor/mermaid-ascii/ascii/validate.d.ts +0 -51
  111. package/dist/types/vendor/mermaid-ascii/ascii/xychart.d.ts +0 -2
  112. package/dist/types/vendor/mermaid-ascii/class/parser.d.ts +0 -6
  113. package/dist/types/vendor/mermaid-ascii/class/types.d.ts +0 -102
  114. package/dist/types/vendor/mermaid-ascii/er/parser.d.ts +0 -6
  115. package/dist/types/vendor/mermaid-ascii/er/types.d.ts +0 -76
  116. package/dist/types/vendor/mermaid-ascii/index.d.ts +0 -1
  117. package/dist/types/vendor/mermaid-ascii/multiline-utils.d.ts +0 -9
  118. package/dist/types/vendor/mermaid-ascii/parser.d.ts +0 -7
  119. package/dist/types/vendor/mermaid-ascii/sequence/parser.d.ts +0 -6
  120. package/dist/types/vendor/mermaid-ascii/sequence/types.d.ts +0 -130
  121. package/dist/types/vendor/mermaid-ascii/text-metrics.d.ts +0 -21
  122. package/dist/types/vendor/mermaid-ascii/types.d.ts +0 -114
  123. package/dist/types/vendor/mermaid-ascii/xychart/colors.d.ts +0 -25
  124. package/dist/types/vendor/mermaid-ascii/xychart/parser.d.ts +0 -6
  125. package/dist/types/vendor/mermaid-ascii/xychart/types.d.ts +0 -145
  126. package/dist/types/version.d.ts +0 -18
  127. package/dist/types/vterm/buffer.d.ts +0 -99
  128. package/dist/types/vterm/terminal.d.ts +0 -44
  129. package/dist/types/vterm.d.ts +0 -8
  130. package/dist/types/which.d.ts +0 -37
  131. package/dist/types/worker-host.d.ts +0 -51
  132. package/dist/types/xml.d.ts +0 -31
package/src/dirs.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * Centralized path helpers for omp config directories.
3
3
  *
4
- * Uses PI_CONFIG_DIR (default ".omp") for the config root and
4
+ * Uses PI_CONFIG_DIR (default ".zeta") for the config root and
5
5
  * PI_CODING_AGENT_DIR to override the agent directory.
6
6
  *
7
7
  * On Linux, if XDG_DATA_HOME / XDG_STATE_HOME / XDG_CACHE_HOME environment
8
8
  * variables are set, paths are redirected to XDG-compliant locations under
9
- * $XDG_*_HOME/omp/. This requires running `omp config migrate` first to
9
+ * $XDG_*_HOME/omp/. This requires running `zeta config migrate` first to
10
10
  * move data to the new locations. No filesystem existence checks are performed
11
11
  * — if the env var is set, omp trusts that the migration has been done.
12
12
  */
@@ -28,6 +28,9 @@ export const MAIN_CONFIG_FILENAMES = ["config.yml", "config.yaml"] as const;
28
28
  /** Version (e.g. "1.0.0") */
29
29
  export const VERSION: string = version;
30
30
 
31
+ /** Default User-Agent header string (e.g. "omp/17.2.12") */
32
+ export const USER_AGENT = `omp/${VERSION}`;
33
+
31
34
  /** Minimum Bun version */
32
35
  export const MIN_BUN_VERSION: string = engines.bun.replace(/[^0-9.]/g, "");
33
36
 
@@ -202,21 +205,34 @@ export async function directoryExists(dir: string): Promise<boolean> {
202
205
  }
203
206
  }
204
207
 
205
- /** Get the config directory name relative to home (e.g. ".zeta" or PI_CONFIG_DIR override). Falls back to ".omp" for backward compatibility. */
208
+ /** Get the config directory name relative to home (e.g. ".zeta" or PI_CONFIG_DIR override). */
206
209
  export function getConfigDirName(): string {
207
210
  if (process.env.PI_CONFIG_DIR) return process.env.PI_CONFIG_DIR;
208
- // Prefer .zeta; fall back to .omp for existing installs
211
+ return ".zeta";
212
+ }
213
+
214
+ /**
215
+ * One-time migration of a legacy `~/.omp` config root to `~/.zeta`. Called
216
+ * from the CLI entrypoint before any user data is written; it only moves the
217
+ * directory when `.zeta` does not exist yet. Zeta keeps no `.omp`
218
+ * compatibility surface afterwards (see AGENTS.md), so this is the single
219
+ * exception that honors pre-existing installs.
220
+ */
221
+ export function migrateLegacyOmpConfigDir(): void {
222
+ if (process.env.PI_CONFIG_DIR) return;
209
223
  const home = os.homedir();
210
224
  try {
211
- if (fs.existsSync(path.join(home, ".zeta"))) return ".zeta";
212
- } catch {}
213
- try {
214
- if (fs.existsSync(path.join(home, ".omp"))) return ".omp";
215
- } catch {}
216
- return ".zeta"; // default for new installs with no existing .omp dir
225
+ const zetaDir = path.join(home, ".zeta");
226
+ if (fs.existsSync(zetaDir)) return;
227
+ const ompDir = path.join(home, ".omp");
228
+ if (!fs.existsSync(ompDir)) return;
229
+ fs.renameSync(ompDir, zetaDir);
230
+ } catch {
231
+ // Migration is best-effort; a failed rename must not break startup.
232
+ }
217
233
  }
218
234
 
219
- /** Get the config agent directory name relative to home (e.g. ".omp/agent" or PI_CONFIG_DIR + "/agent"). */
235
+ /** Get the config agent directory name relative to home (e.g. ".zeta/agent" or PI_CONFIG_DIR + "/agent"). */
220
236
  export function getConfigAgentDirName(): string {
221
237
  const profile = getActiveProfile();
222
238
  return profile ? path.join(getConfigDirName(), "profiles", profile, "agent") : `${getConfigDirName()}/agent`;
@@ -256,12 +272,12 @@ class DirResolver {
256
272
  const isDefault = this.agentDir === defaultAgent;
257
273
 
258
274
  // XDG is a Linux convention. On supported platforms, default profile state
259
- // resolves under $XDG_*_HOME/omp once `omp config init-xdg` has migrated
275
+ // resolves under $XDG_*_HOME/omp once `zeta config init-xdg` has migrated
260
276
  // the user's data. Named profiles follow a stricter rule: the XDG choice
261
277
  // is keyed on the profile-specific XDG path, never the base app root.
262
278
  //
263
279
  // Why: if we consulted the base app root for named profiles too, the same
264
- // profile could resolve to `~/.omp/profiles/<name>` on first activation
280
+ // profile could resolve to `~/.zeta/profiles/<name>` on first activation
265
281
  // (when no $XDG_*_HOME/omp exists yet) and then silently move to
266
282
  // `$XDG_*_HOME/omp/profiles/<name>` the moment the base appeared, orphaning
267
283
  // the earlier state. Pinning on the profile path means a profile's location
@@ -299,7 +315,7 @@ class DirResolver {
299
315
  state: xdgState ?? this.configRoot,
300
316
  cache: xdgCache ?? this.configRoot,
301
317
  };
302
- // XDG flattens the agent/ prefix: ~/.omp/agent/sessions → $XDG_DATA_HOME/omp/sessions
318
+ // XDG flattens the agent/ prefix: ~/.zeta/agent/sessions → $XDG_DATA_HOME/zeta/sessions
303
319
  this.#agentDirs = {
304
320
  data: xdgData ?? this.agentDir,
305
321
  state: xdgState ?? this.agentDir,
@@ -339,7 +355,7 @@ class DirResolver {
339
355
  * agent dir. The profile source can be the active profile or a lower-priority
340
356
  * `PI_PROFILE` that was bypassed because `OMP_PROFILE` explicitly selected the
341
357
  * default profile. Returns `undefined` in those cases so reset falls back to the
342
- * standard `~/.omp/agent`.
358
+ * standard `~/.zeta/agent`.
343
359
  */
344
360
  function resolvePreProfileAgentDir(
345
361
  profile: string | undefined,
@@ -374,7 +390,7 @@ let dirs = new DirResolver({
374
390
  * unconditionally deleting the env var. Without the snapshot, a process started
375
391
  * with `PI_CODING_AGENT_DIR=/custom` then `setProfile("work")` then
376
392
  * `setProfile(undefined)` would silently lose `/custom` and fall back to
377
- * `~/.omp/agent`. Captured at module load — ignoring a profile-derived value
393
+ * `~/.zeta/agent`. Captured at module load — ignoring a profile-derived value
378
394
  * inherited from a parent's `setProfile` (see {@link resolvePreProfileAgentDir})
379
395
  * — and refreshed on `setAgentDir`, since that call is the user explicitly
380
396
  * redefining the baseline.
@@ -411,7 +427,7 @@ export function refreshDirsFromEnv(): void {
411
427
  // Root directories
412
428
  // =============================================================================
413
429
 
414
- /** Get the config root directory (~/.omp). */
430
+ /** Get the config root directory (~/.zeta). */
415
431
  export function getConfigRootDir(): string {
416
432
  return dirs.configRoot;
417
433
  }
@@ -498,45 +514,37 @@ export function getActiveProfile(): string | undefined {
498
514
  export function getProfileRootDir(profile: string | undefined): string {
499
515
  return getProfileConfigRoot(normalizeProfileName(profile));
500
516
  }
501
- /** Get the agent config directory (~/.omp/agent). */
517
+ /** Get the agent config directory (~/.zeta/agent). */
502
518
  export function getAgentDir(): string {
503
519
  return dirs.agentDir;
504
520
  }
505
521
 
506
- /** Get the project-local config directory (.zeta). Falls back to .omp for backward compatibility. */
522
+ /** Get the project-local config directory (.zeta). */
507
523
  export function getProjectAgentDir(cwd: string = getProjectDir()): string {
508
- const zetaDir = path.join(cwd, ".zeta");
509
- try {
510
- if (fs.existsSync(zetaDir)) return zetaDir;
511
- } catch {}
512
- const ompDir = path.join(cwd, ".omp");
513
- try {
514
- if (fs.existsSync(ompDir)) return ompDir;
515
- } catch {}
516
- return zetaDir; // default for new projects
524
+ return path.join(cwd, ".zeta");
517
525
  }
518
526
 
519
527
  // =============================================================================
520
- // Config-root subdirectories (~/.omp/*)
528
+ // Config-root subdirectories (~/.zeta/*)
521
529
  // =============================================================================
522
530
 
523
- /** Get the reports directory (~/.omp/reports). */
531
+ /** Get the reports directory (~/.zeta/reports). */
524
532
  export function getReportsDir(): string {
525
533
  return dirs.rootSubdir("reports", "state");
526
534
  }
527
535
 
528
- /** Get the logs directory (~/.omp/logs). */
536
+ /** Get the logs directory (~/.zeta/logs). */
529
537
  export function getLogsDir(): string {
530
538
  return dirs.rootSubdir("logs", "state");
531
539
  }
532
540
 
533
- /** Get this process's dated log path (~/.omp/logs/omp.YYYY-MM-DD.PID.log). */
541
+ /** Get this process's dated log path (~/.zeta/logs/zeta.YYYY-MM-DD.PID.log). */
534
542
  export function getLogPath(date = new Date(), pid = process.pid): string {
535
543
  return path.join(getLogsDir(), `${APP_NAME}.${date.toISOString().slice(0, 10)}.${pid}.log`);
536
544
  }
537
545
 
538
546
  /**
539
- * Get the plugins directory (~/.omp/plugins or its XDG equivalent).
547
+ * Get the plugins directory (~/.zeta/plugins or its XDG equivalent).
540
548
  *
541
549
  * No-arg form (production callers) goes through the XDG-aware DirResolver so
542
550
  * reads and writes always agree. The optional `home` parameter is for test
@@ -552,22 +560,22 @@ export function getPluginsDir(home?: string): string {
552
560
  return dirs.rootSubdir("plugins", "data");
553
561
  }
554
562
 
555
- /** Where npm installs packages (~/.omp/plugins/node_modules). */
563
+ /** Where npm installs packages (~/.zeta/plugins/node_modules). */
556
564
  export function getPluginsNodeModules(home?: string): string {
557
565
  return path.join(getPluginsDir(home), "node_modules");
558
566
  }
559
567
 
560
- /** Plugin manifest (~/.omp/plugins/package.json). */
568
+ /** Plugin manifest (~/.zeta/plugins/package.json). */
561
569
  export function getPluginsPackageJson(home?: string): string {
562
570
  return path.join(getPluginsDir(home), "package.json");
563
571
  }
564
572
 
565
- /** Plugin lock file (~/.omp/plugins/omp-plugins.lock.json). */
573
+ /** Plugin lock file (~/.zeta/plugins/zeta-plugins.lock.json). */
566
574
  export function getPluginsLockfile(home?: string): string {
567
- return path.join(getPluginsDir(home), "omp-plugins.lock.json");
575
+ return path.join(getPluginsDir(home), "zeta-plugins.lock.json");
568
576
  }
569
577
 
570
- /** Get the remote mount directory (~/.omp/remote). */
578
+ /** Get the remote mount directory (~/.zeta/remote). */
571
579
  export function getRemoteDir(): string {
572
580
  return dirs.rootSubdir("remote", "data");
573
581
  }
@@ -577,7 +585,7 @@ export function getRemoteDir(): string {
577
585
  * empty/whitespace input or a path that is still relative after expansion.
578
586
  *
579
587
  * A worktree base is process-global and consumed by both creation
580
- * (PR checkout, task isolation) and cleanup (`omp worktree`). A relative value
588
+ * (PR checkout, task isolation) and cleanup (`zeta worktree`). A relative value
581
589
  * would resolve against whatever cwd happened to launch `omp`, so checkout and
582
590
  * cleanup could disagree — we refuse it rather than silently bind it to cwd.
583
591
  */
@@ -594,9 +602,9 @@ let worktreesDirOverride: string | undefined;
594
602
 
595
603
  /**
596
604
  * Relocate the base directory for agent-managed worktrees (PR checkouts, task
597
- * isolation, and `omp worktree` cleanup all read the same base). Driven by the
605
+ * isolation, and `zeta worktree` cleanup all read the same base). Driven by the
598
606
  * `worktree.base` setting in coding-agent; pass `undefined`/empty to clear and
599
- * fall back to `OMP_WORKTREE_DIR` or the `~/.omp/wt` default.
607
+ * fall back to `OMP_WORKTREE_DIR` or the `~/.zeta/wt` default.
600
608
  *
601
609
  * `~` is expanded and a relative path is rejected (see {@link resolveWorktreeBase}).
602
610
  * Returns the absolute path that took effect, or `undefined` if the input was
@@ -611,7 +619,7 @@ export function setWorktreesDir(dir: string | undefined): string | undefined {
611
619
  /**
612
620
  * Get the agent-managed worktrees directory. Resolution order: the
613
621
  * `OMP_WORKTREE_DIR` env var, then the {@link setWorktreesDir} override (the
614
- * `worktree.base` setting), then the `~/.omp/wt` default. The env var and the
622
+ * `worktree.base` setting), then the `~/.zeta/wt` default. The env var and the
615
623
  * override are both `~`-expanded and must be absolute; a relative value is
616
624
  * ignored and resolution falls through.
617
625
  */
@@ -619,32 +627,32 @@ export function getWorktreesDir(): string {
619
627
  return resolveWorktreeBase(process.env.OMP_WORKTREE_DIR) ?? worktreesDirOverride ?? dirs.rootSubdir("wt", "data");
620
628
  }
621
629
 
622
- /** Get the SSH control socket directory (~/.omp/ssh-control). */
630
+ /** Get the SSH control socket directory (~/.zeta/ssh-control). */
623
631
  export function getSshControlDir(): string {
624
632
  return dirs.rootSubdir("ssh-control", "state");
625
633
  }
626
634
 
627
- /** Get the remote host info directory (~/.omp/remote-host). */
635
+ /** Get the remote host info directory (~/.zeta/remote-host). */
628
636
  export function getRemoteHostDir(): string {
629
637
  return dirs.rootSubdir("remote-host", "data");
630
638
  }
631
639
 
632
- /** Get the managed Python venv directory (~/.omp/python-env). */
640
+ /** Get the managed Python venv directory (~/.zeta/python-env). */
633
641
  export function getPythonEnvDir(): string {
634
642
  return dirs.rootSubdir("python-env", "data");
635
643
  }
636
644
 
637
- /** Get the shared Python gateway state directory (~/.omp/agent/python-gateway; XDG default: $XDG_STATE_HOME/omp/python-gateway). */
645
+ /** Get the shared Python gateway state directory (~/.zeta/agent/python-gateway; XDG default: $XDG_STATE_HOME/zeta/python-gateway). */
638
646
  export function getPythonGatewayDir(): string {
639
647
  return dirs.agentSubdir(undefined, "python-gateway", "state");
640
648
  }
641
649
 
642
- /** Get the puppeteer sandbox directory (~/.omp/puppeteer). */
650
+ /** Get the puppeteer sandbox directory (~/.zeta/puppeteer). */
643
651
  export function getPuppeteerDir(): string {
644
652
  return dirs.rootSubdir("puppeteer", "cache");
645
653
  }
646
654
 
647
- /** Get the browser relay extension install directory (~/.omp/browser-relay). */
655
+ /** Get the browser relay extension install directory (~/.zeta/browser-relay). */
648
656
  export function getBrowserRelayDir(): string {
649
657
  return dirs.rootSubdir("browser-relay", "data");
650
658
  }
@@ -654,7 +662,7 @@ export function getDocsRsCacheDir(): string {
654
662
  return dirs.rootSubdir("webcache", "cache");
655
663
  }
656
664
 
657
- /** Get the auto-QA grievances SQLite database path (~/.omp/autoqa.db; XDG: $XDG_DATA_HOME/omp/autoqa.db). */
665
+ /** Get the auto-QA grievances SQLite database path (~/.zeta/autoqa.db; XDG: $XDG_DATA_HOME/zeta/autoqa.db). */
658
666
  export function getAutoQaDbPath(): string {
659
667
  return dirs.rootSubdir("autoqa.db", "data");
660
668
  }
@@ -662,7 +670,7 @@ export function getAutoQaDbPath(): string {
662
670
  * Stable 7-character hex digest of an absolute filesystem path.
663
671
  *
664
672
  * Used to pack the project identity into a single short fs-safe segment
665
- * (e.g. PR-checkout and task-isolation worktree dirs under `~/.omp/wt/`).
673
+ * (e.g. PR-checkout and task-isolation worktree dirs under `~/.zeta/wt/`).
666
674
  * Bun.hash is non-cryptographic — collision space is ~2^28, which is fine
667
675
  * for naming a handful of repos on a single machine. Same input on the
668
676
  * same Bun runtime yields the same output.
@@ -671,18 +679,18 @@ export function hashPath(absPath: string): string {
671
679
  return Bun.hash(path.resolve(absPath)).toString(16).padStart(16, "0").slice(-7);
672
680
  }
673
681
 
674
- /** Get the path to a single worktree directory (~/.omp/wt/<segment>). */
682
+ /** Get the path to a single worktree directory (~/.zeta/wt/<segment>). */
675
683
  export function getWorktreeDir(segment: string): string {
676
684
  return path.join(getWorktreesDir(), segment);
677
685
  }
678
686
 
679
- /** Get the GPU cache path (~/.omp/gpu_cache.json). */
687
+ /** Get the GPU cache path (~/.zeta/gpu_cache.json). */
680
688
  export function getGpuCachePath(): string {
681
689
  return dirs.rootSubdir("gpu_cache.json", "cache");
682
690
  }
683
691
 
684
692
  /**
685
- * Get the GitHub view cache database path (~/.omp/cache/github-cache.db).
693
+ * Get the GitHub view cache database path (~/.zeta/cache/github-cache.db).
686
694
  * Honors the `OMP_GITHUB_CACHE_DB` env var when set so tests can isolate the
687
695
  * cache file without touching the rest of the config root.
688
696
  */
@@ -693,7 +701,7 @@ export function getGithubCacheDbPath(): string {
693
701
  }
694
702
 
695
703
  /**
696
- * Get the encrypted auth-broker snapshot cache path (~/.omp/cache/auth-broker-snapshot.enc).
704
+ * Get the encrypted auth-broker snapshot cache path (~/.zeta/cache/auth-broker-snapshot.enc).
697
705
  * Honors the `OMP_AUTH_BROKER_SNAPSHOT_CACHE` env var when set so tests and
698
706
  * operators can isolate or relocate the cache file.
699
707
  */
@@ -703,58 +711,58 @@ export function getAuthBrokerSnapshotCachePath(): string {
703
711
  return dirs.rootSubdir(path.join("cache", "auth-broker-snapshot.enc"), "cache");
704
712
  }
705
713
 
706
- /** Get the local FastEmbed model cache directory (~/.omp/cache/fastembed). */
714
+ /** Get the local FastEmbed model cache directory (~/.zeta/cache/fastembed). */
707
715
  export function getFastembedCacheDir(): string {
708
716
  return dirs.rootSubdir(path.join("cache", "fastembed"), "cache");
709
717
  }
710
718
 
711
- /** Get the on-demand fastembed runtime install root (~/.omp/cache/fastembed-runtime). */
719
+ /** Get the on-demand fastembed runtime install root (~/.zeta/cache/fastembed-runtime). */
712
720
  export function getFastembedRuntimeDir(): string {
713
721
  return dirs.rootSubdir(path.join("cache", "fastembed-runtime"), "cache");
714
722
  }
715
723
 
716
- /** Get the natives directory (~/.omp/natives). */
724
+ /** Get the natives directory (~/.zeta/natives). */
717
725
  export function getNativesDir(): string {
718
726
  return dirs.rootSubdir("natives", "cache");
719
727
  }
720
728
 
721
- /** Get the stats database path (~/.omp/stats.db). */
729
+ /** Get the stats database path (~/.zeta/stats.db). */
722
730
  export function getStatsDbPath(): string {
723
731
  return dirs.rootSubdir("stats.db", "data");
724
732
  }
725
733
 
726
- /** Get the autoresearch state directory (~/.omp/autoresearch). */
734
+ /** Get the autoresearch state directory (~/.zeta/autoresearch). */
727
735
  export function getAutoresearchDir(): string {
728
736
  return dirs.rootSubdir("autoresearch", "state");
729
737
  }
730
738
 
731
- /** Get the per-project autoresearch state directory (~/.omp/autoresearch/<encoded-project>). */
739
+ /** Get the per-project autoresearch state directory (~/.zeta/autoresearch/<encoded-project>). */
732
740
  export function getAutoresearchProjectDir(encodedProject: string): string {
733
741
  return path.join(getAutoresearchDir(), encodedProject);
734
742
  }
735
743
 
736
- /** Get the per-project autoresearch SQLite database path (~/.omp/autoresearch/<encoded-project>.db). */
744
+ /** Get the per-project autoresearch SQLite database path (~/.zeta/autoresearch/<encoded-project>.db). */
737
745
  export function getAutoresearchDbPath(encodedProject: string): string {
738
746
  return path.join(getAutoresearchDir(), `${encodedProject}.db`);
739
747
  }
740
748
 
741
- /** Get the per-run artifact directory (~/.omp/autoresearch/<encoded-project>/runs/<runId>). */
749
+ /** Get the per-run artifact directory (~/.zeta/autoresearch/<encoded-project>/runs/<runId>). */
742
750
  export function getAutoresearchRunDir(encodedProject: string, runId: number): string {
743
751
  return path.join(getAutoresearchProjectDir(encodedProject), "runs", String(runId).padStart(4, "0"));
744
752
  }
745
753
 
746
- /** Get the security-analysis state directory (~/.omp/security). */
754
+ /** Get the security-analysis state directory (~/.zeta/security). */
747
755
  export function getSecurityDir(): string {
748
756
  return dirs.rootSubdir("security", "state");
749
757
  }
750
758
 
751
- /** Get one project's security-analysis state directory (~/.omp/security/<project-key>). */
759
+ /** Get one project's security-analysis state directory (~/.zeta/security/<project-key>). */
752
760
  export function getSecurityProjectDir(projectKey: string): string {
753
761
  return path.join(getSecurityDir(), projectKey);
754
762
  }
755
763
 
756
764
  // =============================================================================
757
- // Agent subdirectories (~/.omp/agent/*)
765
+ // Agent subdirectories (~/.zeta/agent/*)
758
766
  // =============================================================================
759
767
 
760
768
  /** Get the path to agent.db (SQLite database for settings and auth storage). */
@@ -762,7 +770,7 @@ export function getAgentDbPath(agentDir?: string): string {
762
770
  return dirs.agentSubdir(agentDir, "agent.db", "data");
763
771
  }
764
772
 
765
- /** Get the last-seen-changelog-version marker file (~/.omp/agent/last-changelog-version). */
773
+ /** Get the last-seen-changelog-version marker file (~/.zeta/agent/last-changelog-version). */
766
774
  export function getLastChangelogVersionPath(agentDir?: string): string {
767
775
  return dirs.agentSubdir(agentDir, "last-changelog-version", "state");
768
776
  }
@@ -777,67 +785,67 @@ export function getModelDbPath(agentDir?: string): string {
777
785
  return dirs.agentSubdir(agentDir, "models.db", "data");
778
786
  }
779
787
 
780
- /** Get the tiny title model cache directory (~/.omp/agent/cache/tiny-models). */
788
+ /** Get the tiny title model cache directory (~/.zeta/agent/cache/tiny-models). */
781
789
  export function getTinyModelsCacheDir(agentDir?: string): string {
782
790
  return dirs.agentSubdir(agentDir, path.join("cache", "tiny-models"), "cache");
783
791
  }
784
792
 
785
- /** Get the document conversion cache directory (~/.omp/agent/cache/document-conversions; XDG default: $XDG_CACHE_HOME/omp/cache/document-conversions). */
793
+ /** Get the document conversion cache directory (~/.zeta/agent/cache/document-conversions; XDG default: $XDG_CACHE_HOME/zeta/cache/document-conversions). */
786
794
  export function getDocumentConversionCacheDir(agentDir?: string): string {
787
795
  return dirs.agentSubdir(agentDir, path.join("cache", "document-conversions"), "cache");
788
796
  }
789
797
 
790
- /** Get the sessions directory (~/.omp/agent/sessions). */
798
+ /** Get the sessions directory (~/.zeta/agent/sessions). */
791
799
  export function getSessionsDir(agentDir?: string): string {
792
800
  return dirs.agentSubdir(agentDir, "sessions", "data");
793
801
  }
794
802
 
795
- /** Get the content-addressed blob store directory (~/.omp/agent/blobs). */
803
+ /** Get the content-addressed blob store directory (~/.zeta/agent/blobs). */
796
804
  export function getBlobsDir(agentDir?: string): string {
797
805
  return dirs.agentSubdir(agentDir, "blobs", "data");
798
806
  }
799
807
 
800
- /** Get the custom themes directory (~/.omp/agent/themes). */
808
+ /** Get the custom themes directory (~/.zeta/agent/themes). */
801
809
  export function getCustomThemesDir(agentDir?: string): string {
802
810
  return dirs.agentSubdir(agentDir, "themes");
803
811
  }
804
812
 
805
- /** Get the tools directory (~/.omp/agent/tools). */
813
+ /** Get the tools directory (~/.zeta/agent/tools). */
806
814
  export function getToolsDir(agentDir?: string): string {
807
815
  return dirs.agentSubdir(agentDir, "tools");
808
816
  }
809
817
 
810
- /** Get the slash commands directory (~/.omp/agent/commands). */
818
+ /** Get the slash commands directory (~/.zeta/agent/commands). */
811
819
  export function getCommandsDir(agentDir?: string): string {
812
820
  return dirs.agentSubdir(agentDir, "commands");
813
821
  }
814
822
 
815
- /** Get the prompts directory (~/.omp/agent/prompts). */
823
+ /** Get the prompts directory (~/.zeta/agent/prompts). */
816
824
  export function getPromptsDir(agentDir?: string): string {
817
825
  return dirs.agentSubdir(agentDir, "prompts");
818
826
  }
819
827
 
820
- /** Get the user-level Python modules directory (~/.omp/agent/modules). */
828
+ /** Get the user-level Python modules directory (~/.zeta/agent/modules). */
821
829
  export function getAgentModulesDir(agentDir?: string): string {
822
830
  return dirs.agentSubdir(agentDir, "modules");
823
831
  }
824
832
 
825
- /** Get the memories directory (~/.omp/agent/memories). */
833
+ /** Get the memories directory (~/.zeta/agent/memories). */
826
834
  export function getMemoriesDir(agentDir?: string): string {
827
835
  return dirs.agentSubdir(agentDir, "memories", "state");
828
836
  }
829
837
 
830
- /** Get the terminal sessions directory (~/.omp/agent/terminal-sessions). */
838
+ /** Get the terminal sessions directory (~/.zeta/agent/terminal-sessions). */
831
839
  export function getTerminalSessionsDir(agentDir?: string): string {
832
840
  return dirs.agentSubdir(agentDir, "terminal-sessions", "state");
833
841
  }
834
842
 
835
- /** Get the crash log path (~/.omp/agent/omp-crash.log). */
843
+ /** Get the crash log path (~/.zeta/agent/zeta-crash.log). */
836
844
  export function getCrashLogPath(agentDir?: string): string {
837
- return dirs.agentSubdir(agentDir, "omp-crash.log", "state");
845
+ return dirs.agentSubdir(agentDir, "zeta-crash.log", "state");
838
846
  }
839
847
 
840
- /** Get the debug log path (~/.omp/agent/omp-debug.log). */
848
+ /** Get the debug log path (~/.zeta/agent/zeta-debug.log). */
841
849
  export function getDebugLogPath(agentDir?: string): string {
842
850
  return dirs.agentSubdir(agentDir, `${APP_NAME}-debug.log`, "state");
843
851
  }
@@ -861,14 +869,14 @@ function adoptLegacyFile(legacyPath: string, targetPath: string): void {
861
869
  }
862
870
  }
863
871
 
864
- /** Get the secret placeholder key path (~/.omp/agent/secret-placeholder.key; XDG default: $XDG_STATE_HOME/omp/secret-placeholder.key). Adopts a legacy key on first XDG resolution. */
872
+ /** Get the secret placeholder key path (~/.zeta/agent/secret-placeholder.key; XDG default: $XDG_STATE_HOME/zeta/secret-placeholder.key). Adopts a legacy key on first XDG resolution. */
865
873
  export function getSecretPlaceholderKeyPath(): string {
866
874
  const keyPath = dirs.agentSubdir(undefined, "secret-placeholder.key", "state");
867
875
  adoptLegacyFile(path.join(dirs.agentDir, "secret-placeholder.key"), keyPath);
868
876
  return keyPath;
869
877
  }
870
878
 
871
- /** Get the daemon runtime directory for a project (~/.omp/run/daemons/<hash>; XDG default: $XDG_STATE_HOME/omp/run/daemons/<hash>). */
879
+ /** Get the daemon runtime directory for a project (~/.zeta/run/daemons/<hash>; XDG default: $XDG_STATE_HOME/zeta/run/daemons/<hash>). */
872
880
  export function getDaemonRuntimeDir(projectDir: string): string {
873
881
  const key = Bun.hash.wyhash(path.resolve(projectDir)).toString(16).padStart(16, "0");
874
882
  return dirs.rootSubdir(path.join("run", "daemons", key), "state");
@@ -882,12 +890,12 @@ export function getGlobalDaemonRuntimeDir(service: string): string {
882
890
  return path.join(getBaseConfigRoot(), "run", "daemons", "global", service);
883
891
  }
884
892
 
885
- /** Get the provider in-flight root directory (~/.omp/run/provider-inflight; XDG default: $XDG_STATE_HOME/omp/run/provider-inflight). */
893
+ /** Get the provider in-flight root directory (~/.zeta/run/provider-inflight; XDG default: $XDG_STATE_HOME/zeta/run/provider-inflight). */
886
894
  export function getProviderInFlightRoot(): string {
887
895
  return dirs.rootSubdir(path.join("run", "provider-inflight"), "state");
888
896
  }
889
897
 
890
- /** Get the marketplaces registry path (~/.omp/marketplaces.json; XDG default: $XDG_DATA_HOME/omp/marketplaces.json). Adopts a legacy registry on first XDG resolution. */
898
+ /** Get the marketplaces registry path (~/.zeta/marketplaces.json; XDG default: $XDG_DATA_HOME/zeta/marketplaces.json). Adopts a legacy registry on first XDG resolution. */
891
899
  export function getMarketplacesRegistryPath(): string {
892
900
  const registryPath = dirs.rootSubdir("marketplaces.json", "data");
893
901
  adoptLegacyFile(path.join(dirs.configRoot, "marketplaces.json"), registryPath);
@@ -895,20 +903,20 @@ export function getMarketplacesRegistryPath(): string {
895
903
  }
896
904
 
897
905
  // =============================================================================
898
- // Project subdirectories (.omp/*)
906
+ // Project subdirectories (.zeta/*)
899
907
  // =============================================================================
900
908
 
901
- /** Get the project-level Python modules directory (.omp/modules). */
909
+ /** Get the project-level Python modules directory (.zeta/modules). */
902
910
  export function getProjectModulesDir(cwd: string = getProjectDir()): string {
903
911
  return path.join(getProjectAgentDir(cwd), "modules");
904
912
  }
905
913
 
906
- /** Get the project-level prompts directory (.omp/prompts). */
914
+ /** Get the project-level prompts directory (.zeta/prompts). */
907
915
  export function getProjectPromptsDir(cwd: string = getProjectDir()): string {
908
916
  return path.join(getProjectAgentDir(cwd), "prompts");
909
917
  }
910
918
 
911
- /** Get the project-level plugin overrides path (.omp/plugin-overrides.json). */
919
+ /** Get the project-level plugin overrides path (.zeta/plugin-overrides.json). */
912
920
  export function getProjectPluginOverridesPath(cwd: string = getProjectDir()): string {
913
921
  return path.join(getProjectAgentDir(cwd), "plugin-overrides.json");
914
922
  }
@@ -957,15 +965,15 @@ const INSTALL_ID_FILE = "install-id";
957
965
  const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
958
966
 
959
967
  /**
960
- * Persistent per-install UUID stored at `~/.omp/install-id`.
968
+ * Persistent per-install UUID stored at `~/.zeta/install-id`.
961
969
  *
962
970
  * Generated lazily on first call and persisted with `O_CREAT|O_EXCL` so
963
971
  * concurrent first-call races don't clobber each other (loser re-reads the
964
972
  * winner's id). Survives independently of agent state: deleting
965
- * `~/.omp/agent/` does not regenerate it. Server-side dedup for grievance
973
+ * `~/.zeta/agent/` does not regenerate it. Server-side dedup for grievance
966
974
  * pushes (and similar telemetry) keys on this id.
967
975
  *
968
- * Anchored to the base config root (`~/.omp/install-id`) regardless of the
976
+ * Anchored to the base config root (`~/.zeta/install-id`) regardless of the
969
977
  * active profile: install identity is per-install, not per-profile, so every
970
978
  * profile shares one id and the global cache stays correct no matter the
971
979
  * profile / `getInstallId` call order.
@@ -220,7 +220,7 @@ export async function fetchWithRetry(
220
220
  if (signal?.aborted) throw new Error("Request was aborted");
221
221
  const wrapped = wrapNetworkError(error);
222
222
  if (attempt + 1 >= maxAttempts) throw wrapped;
223
- await scheduler.wait(resolveDefaultDelay(defaultDelayMs, attempt, maxDelayMs), { signal });
223
+ await waitForRetry(resolveDefaultDelay(defaultDelayMs, attempt, maxDelayMs), signal);
224
224
  continue;
225
225
  }
226
226
 
@@ -234,7 +234,7 @@ export async function fetchWithRetry(
234
234
  if (hint !== undefined && hint > maxDelayMs) return response;
235
235
 
236
236
  const delayMs = Math.min(hint ?? resolveDefaultDelay(defaultDelayMs, attempt, maxDelayMs), maxDelayMs);
237
- await scheduler.wait(delayMs, { signal });
237
+ await waitForRetry(delayMs, signal);
238
238
  }
239
239
  }
240
240
 
@@ -251,6 +251,15 @@ function mergeInit(base: RequestInit, overlay: RequestInit, timeout: number | fa
251
251
  return merged;
252
252
  }
253
253
 
254
+ async function waitForRetry(delayMs: number, signal: AbortSignal | undefined): Promise<void> {
255
+ try {
256
+ await scheduler.wait(delayMs, { signal });
257
+ } catch (error) {
258
+ if (signal?.aborted) throw new Error("Request was aborted");
259
+ throw error;
260
+ }
261
+ }
262
+
254
263
  function wrapNetworkError(error: unknown): Error {
255
264
  if (error instanceof Error) {
256
265
  if (error.name === "AbortError" || error.message === "Request was aborted") {
package/src/json-parse.ts CHANGED
@@ -579,8 +579,8 @@ export function parseStreamingJson<T = Record<string, unknown>>(partialJson: str
579
579
 
580
580
  /**
581
581
  * Default minimum byte growth before `parseStreamingJsonThrottled` will
582
- * re-parse a streaming tool-call argument buffer. Bounds the mid-stream
583
- * partial-parse cost from quadratic to linear in N.
582
+ * re-parse a streaming tool-call argument buffer. Acts as the floor of the
583
+ * geometric gate see {@link parseStreamingJsonThrottled}.
584
584
  */
585
585
  export const STREAMING_JSON_PARSE_MIN_GROWTH = 256;
586
586
 
@@ -589,14 +589,23 @@ export const STREAMING_JSON_PARSE_MIN_GROWTH = 256;
589
589
  *
590
590
  * Tool calls arrive as a long sequence of small deltas — calling
591
591
  * `parseStreamingJson(buffer)` on every delta re-parses the entire buffer
592
- * each time, giving O(N²) work in the total buffer length. Throttling skips
593
- * the re-parse until at least `minGrowthBytes` of new content has arrived
594
- * since the last successful parse, bounding mid-stream cost to O(N).
592
+ * each time, giving O(N²) work in the total buffer length. A fixed re-parse
593
+ * floor alone does NOT fix this: with `minGrowthBytes` constant, a buffer of
594
+ * length N is parsed N/minGrowthBytes times at an average cost of N/2, which
595
+ * is still O(N²) (the constant just shrinks). Long `write` payloads — where
596
+ * the buffer is the whole file — made this the dominant main-thread stall
597
+ * during streaming.
598
+ *
599
+ * Instead the gate scales geometrically: once the buffer is large, a re-parse
600
+ * requires growth proportional to the current length (`len / 32`, floored at
601
+ * `minGrowthBytes`). Parse points then form a geometric progression, so a
602
+ * buffer of length N is parsed O(log N) times for O(N log N) total work,
603
+ * while small buffers keep the snappy fixed-cadence updates.
595
604
  *
596
605
  * Each provider tracks the last parsed length on its tool-call block, so the
597
606
  * final `toolcall_end` parse (which providers already perform unconditionally)
598
607
  * is the authoritative full parse — the throttle only delays mid-stream UI
599
- * updates by at most `minGrowthBytes` of accumulated partial content.
608
+ * updates, by at most ~3% of the accumulated content for large buffers.
600
609
  *
601
610
  * @returns the parsed object plus the new `parsedLen` to persist; or `null`
602
611
  * when the buffer has not grown enough to warrant a re-parse.
@@ -607,7 +616,9 @@ export function parseStreamingJsonThrottled<T = Record<string, unknown>>(
607
616
  minGrowthBytes: number = STREAMING_JSON_PARSE_MIN_GROWTH,
608
617
  ): { value: T; parsedLen: number } | null {
609
618
  const len = partialJson?.length ?? 0;
610
- if (len === 0 || (lastParsedLen > 0 && len - lastParsedLen < minGrowthBytes)) return null;
619
+ if (len === 0) return null;
620
+ const growth = Math.max(minGrowthBytes, len >> 5);
621
+ if (lastParsedLen > 0 && len - lastParsedLen < growth) return null;
611
622
  return { value: parseStreamingJson<T>(partialJson), parsedLen: len };
612
623
  }
613
624