@oka-core/reason 0.2.14 → 0.2.16

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 (163) hide show
  1. package/dist/abort-controller.d.ts +19 -0
  2. package/dist/abort-controller.d.ts.map +1 -0
  3. package/dist/abort-controller.js +53 -0
  4. package/dist/activity-tracker.d.ts +48 -0
  5. package/dist/activity-tracker.d.ts.map +1 -0
  6. package/dist/activity-tracker.js +80 -0
  7. package/dist/analytics.d.ts +49 -0
  8. package/dist/analytics.d.ts.map +1 -0
  9. package/dist/analytics.js +88 -0
  10. package/dist/array.d.ts +12 -0
  11. package/dist/array.d.ts.map +1 -0
  12. package/dist/array.js +20 -0
  13. package/dist/async-context.d.ts +20 -0
  14. package/dist/async-context.d.ts.map +1 -0
  15. package/dist/async-context.js +25 -0
  16. package/dist/auth.d.ts +15 -0
  17. package/dist/auth.d.ts.map +1 -1
  18. package/dist/auth.js +77 -0
  19. package/dist/binary-check.d.ts +16 -0
  20. package/dist/binary-check.d.ts.map +1 -0
  21. package/dist/binary-check.js +43 -0
  22. package/dist/buffered-writer.d.ts +30 -0
  23. package/dist/buffered-writer.d.ts.map +1 -0
  24. package/dist/buffered-writer.js +87 -0
  25. package/dist/circular-buffer.d.ts +28 -0
  26. package/dist/circular-buffer.d.ts.map +1 -0
  27. package/dist/circular-buffer.js +61 -0
  28. package/dist/cleanup-registry.d.ts +23 -0
  29. package/dist/cleanup-registry.d.ts.map +1 -0
  30. package/dist/cleanup-registry.js +34 -0
  31. package/dist/client.d.ts +6 -5
  32. package/dist/client.d.ts.map +1 -1
  33. package/dist/client.js +51 -64
  34. package/dist/combined-abort-signal.d.ts +25 -0
  35. package/dist/combined-abort-signal.d.ts.map +1 -0
  36. package/dist/combined-abort-signal.js +47 -0
  37. package/dist/cron-lock.d.ts +29 -0
  38. package/dist/cron-lock.d.ts.map +1 -0
  39. package/dist/cron-lock.js +127 -0
  40. package/dist/cron-scheduler.d.ts +41 -0
  41. package/dist/cron-scheduler.d.ts.map +1 -0
  42. package/dist/cron-scheduler.js +189 -0
  43. package/dist/cron-tasks.d.ts +86 -0
  44. package/dist/cron-tasks.d.ts.map +1 -0
  45. package/dist/cron-tasks.js +205 -0
  46. package/dist/cron.d.ts +35 -0
  47. package/dist/cron.d.ts.map +1 -0
  48. package/dist/cron.js +215 -0
  49. package/dist/env.d.ts +26 -0
  50. package/dist/env.d.ts.map +1 -0
  51. package/dist/env.js +50 -0
  52. package/dist/errors.d.ts +99 -0
  53. package/dist/errors.d.ts.map +1 -0
  54. package/dist/errors.js +214 -0
  55. package/dist/format.d.ts +21 -0
  56. package/dist/format.d.ts.map +1 -0
  57. package/dist/format.js +48 -0
  58. package/dist/fps-tracker.d.ts +22 -0
  59. package/dist/fps-tracker.d.ts.map +1 -0
  60. package/dist/fps-tracker.js +44 -0
  61. package/dist/graceful-shutdown.d.ts +35 -0
  62. package/dist/graceful-shutdown.d.ts.map +1 -0
  63. package/dist/graceful-shutdown.js +89 -0
  64. package/dist/hash.d.ts +21 -0
  65. package/dist/hash.d.ts.map +1 -0
  66. package/dist/hash.js +31 -0
  67. package/dist/heap-diagnostics.d.ts +68 -0
  68. package/dist/heap-diagnostics.d.ts.map +1 -0
  69. package/dist/heap-diagnostics.js +110 -0
  70. package/dist/idle-timeout.d.ts +21 -0
  71. package/dist/idle-timeout.d.ts.map +1 -0
  72. package/dist/idle-timeout.js +42 -0
  73. package/dist/index.d.ts +2 -1
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +5 -0
  76. package/dist/intl.d.ts +18 -0
  77. package/dist/intl.d.ts.map +1 -0
  78. package/dist/intl.js +75 -0
  79. package/dist/jsonl.d.ts +16 -0
  80. package/dist/jsonl.d.ts.map +1 -0
  81. package/dist/jsonl.js +60 -0
  82. package/dist/lazy-schema.d.ts +6 -0
  83. package/dist/lazy-schema.d.ts.map +1 -0
  84. package/dist/lazy-schema.js +8 -0
  85. package/dist/memo.d.ts +64 -0
  86. package/dist/memo.d.ts.map +1 -0
  87. package/dist/memo.js +162 -0
  88. package/dist/pkce.d.ts +13 -0
  89. package/dist/pkce.d.ts.map +1 -0
  90. package/dist/pkce.js +28 -0
  91. package/dist/priority-queue.d.ts +36 -0
  92. package/dist/priority-queue.d.ts.map +1 -0
  93. package/dist/priority-queue.js +97 -0
  94. package/dist/process-utils.d.ts +20 -0
  95. package/dist/process-utils.d.ts.map +1 -0
  96. package/dist/process-utils.js +54 -0
  97. package/dist/query-guard.d.ts +34 -0
  98. package/dist/query-guard.d.ts.map +1 -0
  99. package/dist/query-guard.js +74 -0
  100. package/dist/retry.d.ts +60 -0
  101. package/dist/retry.d.ts.map +1 -0
  102. package/dist/retry.js +89 -0
  103. package/dist/schemas.d.ts +6 -6
  104. package/dist/secrets.d.ts +44 -0
  105. package/dist/secrets.d.ts.map +1 -0
  106. package/dist/secrets.js +115 -0
  107. package/dist/semantic-types.d.ts +39 -0
  108. package/dist/semantic-types.d.ts.map +1 -0
  109. package/dist/semantic-types.js +49 -0
  110. package/dist/sequential.d.ts +21 -0
  111. package/dist/sequential.d.ts.map +1 -0
  112. package/dist/sequential.js +49 -0
  113. package/dist/signal.d.ts +29 -0
  114. package/dist/signal.d.ts.map +1 -0
  115. package/dist/signal.js +39 -0
  116. package/dist/sleep.d.ts +21 -0
  117. package/dist/sleep.d.ts.map +1 -0
  118. package/dist/sleep.js +58 -0
  119. package/dist/slow-ops.d.ts +41 -0
  120. package/dist/slow-ops.d.ts.map +1 -0
  121. package/dist/slow-ops.js +133 -0
  122. package/dist/store.d.ts +20 -0
  123. package/dist/store.d.ts.map +1 -0
  124. package/dist/store.js +34 -0
  125. package/dist/stream.d.ts +29 -0
  126. package/dist/stream.d.ts.map +1 -0
  127. package/dist/stream.js +92 -0
  128. package/dist/string-utils.d.ts +46 -0
  129. package/dist/string-utils.d.ts.map +1 -0
  130. package/dist/string-utils.js +69 -0
  131. package/dist/strip-bom.d.ts +8 -0
  132. package/dist/strip-bom.d.ts.map +1 -0
  133. package/dist/strip-bom.js +10 -0
  134. package/dist/subprocess-env.d.ts +25 -0
  135. package/dist/subprocess-env.d.ts.map +1 -0
  136. package/dist/subprocess-env.js +55 -0
  137. package/dist/temp-file.d.ts +18 -0
  138. package/dist/temp-file.d.ts.map +1 -0
  139. package/dist/temp-file.js +26 -0
  140. package/dist/tool-contract.d.ts +85 -0
  141. package/dist/tool-contract.d.ts.map +1 -0
  142. package/dist/tool-contract.js +101 -0
  143. package/dist/tools/auth.d.ts.map +1 -1
  144. package/dist/tools/auth.js +8 -7
  145. package/dist/tools/read.d.ts +2 -10
  146. package/dist/tools/read.d.ts.map +1 -1
  147. package/dist/tools/read.js +662 -537
  148. package/dist/tools/write.d.ts +3 -2
  149. package/dist/tools/write.d.ts.map +1 -1
  150. package/dist/tools/write.js +329 -177
  151. package/dist/uuid.d.ts +20 -0
  152. package/dist/uuid.d.ts.map +1 -0
  153. package/dist/uuid.js +28 -0
  154. package/dist/validation.d.ts +64 -0
  155. package/dist/validation.d.ts.map +1 -0
  156. package/dist/validation.js +236 -0
  157. package/dist/with-resolvers.d.ts +12 -0
  158. package/dist/with-resolvers.d.ts.map +1 -0
  159. package/dist/with-resolvers.js +14 -0
  160. package/dist/xml-escape.d.ts +12 -0
  161. package/dist/xml-escape.d.ts.map +1 -0
  162. package/dist/xml-escape.js +15 -0
  163. package/package.json +1 -1
package/dist/format.js ADDED
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Format utilities — human-readable sizes and durations.
3
+ *
4
+ * ZERO external dependencies — pure domain layer.
5
+ */
6
+ const SIZE_UNITS = ["B", "KB", "MB", "GB", "TB"];
7
+ /**
8
+ * Format a byte count as a human-readable string.
9
+ *
10
+ * @example humanReadableSize(1536) // "1.5 KB"
11
+ * @example humanReadableSize(0) // "0 B"
12
+ */
13
+ export function humanReadableSize(bytes) {
14
+ if (bytes < 0)
15
+ return `-${humanReadableSize(-bytes)}`;
16
+ if (bytes === 0)
17
+ return "0 B";
18
+ let value = bytes;
19
+ let unitIndex = 0;
20
+ while (value >= 1024 && unitIndex < SIZE_UNITS.length - 1) {
21
+ value /= 1024;
22
+ unitIndex++;
23
+ }
24
+ const formatted = unitIndex === 0 ? String(value) : value.toFixed(1).replace(/\.0$/, "");
25
+ return `${formatted} ${SIZE_UNITS[unitIndex]}`;
26
+ }
27
+ /**
28
+ * Format a duration in milliseconds as a human-readable string.
29
+ *
30
+ * @example humanReadableDuration(350) // "350ms"
31
+ * @example humanReadableDuration(1200) // "1.2s"
32
+ * @example humanReadableDuration(135000) // "2m 15s"
33
+ */
34
+ export function humanReadableDuration(ms) {
35
+ if (ms < 0)
36
+ return `-${humanReadableDuration(-ms)}`;
37
+ if (ms < 1000)
38
+ return `${Math.round(ms)}ms`;
39
+ const seconds = ms / 1000;
40
+ if (seconds < 60) {
41
+ return `${seconds.toFixed(1).replace(/\.0$/, "")}s`;
42
+ }
43
+ const minutes = Math.floor(seconds / 60);
44
+ const remainingSeconds = Math.round(seconds % 60);
45
+ if (remainingSeconds === 0)
46
+ return `${minutes}m`;
47
+ return `${minutes}m ${remainingSeconds}s`;
48
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Frame-rate tracker with percentile-based metrics.
3
+ *
4
+ * Records individual frame durations and computes:
5
+ * - averageFps: total frames / elapsed wall-clock time
6
+ * - low1PctFps: 1/p99-frame-duration (worst 1% frames)
7
+ *
8
+ * Useful for render loops, streaming pipelines, or any periodic work
9
+ * where throughput and tail latency matter.
10
+ */
11
+ export type FpsMetrics = {
12
+ averageFps: number;
13
+ low1PctFps: number;
14
+ };
15
+ export declare class FpsTracker {
16
+ private frameDurations;
17
+ private firstRenderTime;
18
+ private lastRenderTime;
19
+ record(durationMs: number): void;
20
+ getMetrics(): FpsMetrics | undefined;
21
+ }
22
+ //# sourceMappingURL=fps-tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fps-tracker.d.ts","sourceRoot":"","sources":["../src/fps-tracker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,MAAM,UAAU,GAAG;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,qBAAa,UAAU;IACrB,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,cAAc,CAAqB;IAE3C,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAShC,UAAU,IAAI,UAAU,GAAG,SAAS;CA2BrC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Frame-rate tracker with percentile-based metrics.
3
+ *
4
+ * Records individual frame durations and computes:
5
+ * - averageFps: total frames / elapsed wall-clock time
6
+ * - low1PctFps: 1/p99-frame-duration (worst 1% frames)
7
+ *
8
+ * Useful for render loops, streaming pipelines, or any periodic work
9
+ * where throughput and tail latency matter.
10
+ */
11
+ export class FpsTracker {
12
+ frameDurations = [];
13
+ firstRenderTime;
14
+ lastRenderTime;
15
+ record(durationMs) {
16
+ const now = performance.now();
17
+ if (this.firstRenderTime === undefined) {
18
+ this.firstRenderTime = now;
19
+ }
20
+ this.lastRenderTime = now;
21
+ this.frameDurations.push(durationMs);
22
+ }
23
+ getMetrics() {
24
+ if (this.frameDurations.length === 0 ||
25
+ this.firstRenderTime === undefined ||
26
+ this.lastRenderTime === undefined) {
27
+ return undefined;
28
+ }
29
+ const totalTimeMs = this.lastRenderTime - this.firstRenderTime;
30
+ if (totalTimeMs <= 0) {
31
+ return undefined;
32
+ }
33
+ const totalFrames = this.frameDurations.length;
34
+ const averageFps = totalFrames / (totalTimeMs / 1000);
35
+ const sorted = this.frameDurations.slice().sort((a, b) => b - a);
36
+ const p99Index = Math.max(0, Math.ceil(sorted.length * 0.01) - 1);
37
+ const p99FrameTimeMs = sorted[p99Index];
38
+ const low1PctFps = p99FrameTimeMs > 0 ? 1000 / p99FrameTimeMs : 0;
39
+ return {
40
+ averageFps: Math.round(averageFps * 100) / 100,
41
+ low1PctFps: Math.round(low1PctFps * 100) / 100,
42
+ };
43
+ }
44
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Graceful shutdown orchestrator — depends on cleanup-registry.ts, sleep.ts.
3
+ *
4
+ * Registers signal handlers, runs cleanup phases in order, and guarantees
5
+ * process exit via a failsafe timer.
6
+ *
7
+ * Inspired by Claude Code's `src/utils/gracefulShutdown.ts` (simplified).
8
+ */
9
+ export type ShutdownOptions = {
10
+ /** Time budget in ms for cleanup before force-exit. Default: 5000. */
11
+ budget?: number;
12
+ /** Called when shutdown starts. */
13
+ onShutdown?: (reason: string) => void;
14
+ /** Called after cleanup, before exit. Use for analytics flush. */
15
+ onBeforeExit?: () => Promise<void>;
16
+ };
17
+ /** Whether the process is currently shutting down. */
18
+ export declare function isShuttingDown(): boolean;
19
+ /**
20
+ * Register SIGINT, SIGTERM, SIGHUP handlers for graceful shutdown.
21
+ * Idempotent — safe to call multiple times.
22
+ */
23
+ export declare function setupGracefulShutdown(opts?: ShutdownOptions): void;
24
+ /**
25
+ * Execute a graceful shutdown sequence:
26
+ * 1. Run cleanup registry functions (parallel, with timeout)
27
+ * 2. Call onBeforeExit hook (e.g., analytics flush)
28
+ * 3. Exit process
29
+ */
30
+ export declare function gracefulShutdown(exitCode?: number, reason?: string, opts?: ShutdownOptions): Promise<never>;
31
+ /**
32
+ * Reset shutdown state (for testing only).
33
+ */
34
+ export declare function _resetShutdownForTesting(): void;
35
+ //# sourceMappingURL=graceful-shutdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graceful-shutdown.d.ts","sourceRoot":"","sources":["../src/graceful-shutdown.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAWH,MAAM,MAAM,eAAe,GAAG;IAC5B,sEAAsE;IACtE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mCAAmC;IACnC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC,CAAC;AAEF,sDAAsD;AACtD,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,CAAC,EAAE,eAAe,GAAG,IAAI,CAiBlE;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,SAAI,EACZ,MAAM,SAAa,EACnB,IAAI,CAAC,EAAE,eAAe,GACrB,OAAO,CAAC,KAAK,CAAC,CA8ChB;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAG/C"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Graceful shutdown orchestrator — depends on cleanup-registry.ts, sleep.ts.
3
+ *
4
+ * Registers signal handlers, runs cleanup phases in order, and guarantees
5
+ * process exit via a failsafe timer.
6
+ *
7
+ * Inspired by Claude Code's `src/utils/gracefulShutdown.ts` (simplified).
8
+ */
9
+ import { runCleanupFunctions } from "./cleanup-registry.js";
10
+ // ─── State ──────────────────────────────────────────────────────────
11
+ let shuttingDown = false;
12
+ let setupDone = false;
13
+ /** Whether the process is currently shutting down. */
14
+ export function isShuttingDown() {
15
+ return shuttingDown;
16
+ }
17
+ /**
18
+ * Register SIGINT, SIGTERM, SIGHUP handlers for graceful shutdown.
19
+ * Idempotent — safe to call multiple times.
20
+ */
21
+ export function setupGracefulShutdown(opts) {
22
+ if (setupDone)
23
+ return;
24
+ setupDone = true;
25
+ const handler = (signal) => {
26
+ if (shuttingDown) {
27
+ // Double-signal: force immediate exit
28
+ process.exit(1);
29
+ }
30
+ void gracefulShutdown(0, signal, opts);
31
+ };
32
+ process.on("SIGINT", () => handler("SIGINT"));
33
+ process.on("SIGTERM", () => handler("SIGTERM"));
34
+ if (process.platform !== "win32") {
35
+ process.on("SIGHUP", () => handler("SIGHUP"));
36
+ }
37
+ }
38
+ /**
39
+ * Execute a graceful shutdown sequence:
40
+ * 1. Run cleanup registry functions (parallel, with timeout)
41
+ * 2. Call onBeforeExit hook (e.g., analytics flush)
42
+ * 3. Exit process
43
+ */
44
+ export async function gracefulShutdown(exitCode = 0, reason = "shutdown", opts) {
45
+ if (shuttingDown) {
46
+ process.exit(exitCode);
47
+ }
48
+ shuttingDown = true;
49
+ const budget = opts?.budget ?? 5000;
50
+ // Failsafe: guarantee exit even if cleanup hangs
51
+ const failsafe = setTimeout(() => {
52
+ process.exit(exitCode || 1);
53
+ }, budget);
54
+ if (typeof failsafe === "object" && "unref" in failsafe) {
55
+ failsafe.unref();
56
+ }
57
+ opts?.onShutdown?.(reason);
58
+ // Phase 1: Run registered cleanup functions
59
+ try {
60
+ await Promise.race([
61
+ runCleanupFunctions(),
62
+ new Promise((resolve) => setTimeout(resolve, Math.floor(budget * 0.6))),
63
+ ]);
64
+ }
65
+ catch {
66
+ // Continue shutdown even if cleanup fails
67
+ }
68
+ // Phase 2: Before-exit hook (analytics flush, etc.)
69
+ if (opts?.onBeforeExit) {
70
+ try {
71
+ await Promise.race([
72
+ opts.onBeforeExit(),
73
+ new Promise((resolve) => setTimeout(resolve, Math.floor(budget * 0.3))),
74
+ ]);
75
+ }
76
+ catch {
77
+ // Continue shutdown
78
+ }
79
+ }
80
+ clearTimeout(failsafe);
81
+ process.exit(exitCode);
82
+ }
83
+ /**
84
+ * Reset shutdown state (for testing only).
85
+ */
86
+ export function _resetShutdownForTesting() {
87
+ shuttingDown = false;
88
+ setupDone = false;
89
+ }
package/dist/hash.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Content hashing utilities — uses Node built-in `crypto`.
3
+ *
4
+ * Inspired by Claude Code's `src/utils/hash.ts`.
5
+ */
6
+ /**
7
+ * Fast non-cryptographic DJB2 hash.
8
+ * Returns a signed 32-bit integer. Deterministic across runtimes.
9
+ */
10
+ export declare function djb2Hash(str: string): number;
11
+ /**
12
+ * SHA-256 content hash. Returns a hex string.
13
+ * Suitable for change detection and content-addressable caching (not crypto-signing).
14
+ */
15
+ export declare function hashContent(content: string): string;
16
+ /**
17
+ * Hash two strings together without concatenation allocation.
18
+ * Uses a null separator to disambiguate ("ab","c") from ("a","bc").
19
+ */
20
+ export declare function hashPair(a: string, b: string): string;
21
+ //# sourceMappingURL=hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../src/hash.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAM5C;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAErD"}
package/dist/hash.js ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Content hashing utilities — uses Node built-in `crypto`.
3
+ *
4
+ * Inspired by Claude Code's `src/utils/hash.ts`.
5
+ */
6
+ import { createHash } from "node:crypto";
7
+ /**
8
+ * Fast non-cryptographic DJB2 hash.
9
+ * Returns a signed 32-bit integer. Deterministic across runtimes.
10
+ */
11
+ export function djb2Hash(str) {
12
+ let hash = 5381;
13
+ for (let i = 0; i < str.length; i++) {
14
+ hash = ((hash << 5) + hash + str.charCodeAt(i)) | 0;
15
+ }
16
+ return hash;
17
+ }
18
+ /**
19
+ * SHA-256 content hash. Returns a hex string.
20
+ * Suitable for change detection and content-addressable caching (not crypto-signing).
21
+ */
22
+ export function hashContent(content) {
23
+ return createHash("sha256").update(content).digest("hex");
24
+ }
25
+ /**
26
+ * Hash two strings together without concatenation allocation.
27
+ * Uses a null separator to disambiguate ("ab","c") from ("a","bc").
28
+ */
29
+ export function hashPair(a, b) {
30
+ return createHash("sha256").update(a).update("\0").update(b).digest("hex");
31
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * V8 heap diagnostics and leak detection.
3
+ *
4
+ * Pure diagnostic capture — no snapshot writing, no CC-specific deps.
5
+ * Extracted from Claude Code's heapDumpService.
6
+ */
7
+ export type MemoryDiagnostics = {
8
+ timestamp: string;
9
+ uptimeSeconds: number;
10
+ memoryUsage: {
11
+ heapUsed: number;
12
+ heapTotal: number;
13
+ external: number;
14
+ arrayBuffers: number;
15
+ rss: number;
16
+ };
17
+ memoryGrowthRate: {
18
+ bytesPerSecond: number;
19
+ mbPerHour: number;
20
+ };
21
+ v8HeapStats: {
22
+ heapSizeLimit: number;
23
+ mallocedMemory: number;
24
+ peakMallocedMemory: number;
25
+ detachedContexts: number;
26
+ nativeContexts: number;
27
+ };
28
+ v8HeapSpaces?: Array<{
29
+ name: string;
30
+ size: number;
31
+ used: number;
32
+ available: number;
33
+ }>;
34
+ resourceUsage: {
35
+ maxRSS: number;
36
+ userCPUTime: number;
37
+ systemCPUTime: number;
38
+ };
39
+ activeHandles: number;
40
+ activeRequests: number;
41
+ openFileDescriptors?: number;
42
+ analysis: LeakAnalysis;
43
+ smapsRollup?: string;
44
+ platform: string;
45
+ nodeVersion: string;
46
+ };
47
+ export type LeakAnalysis = {
48
+ potentialLeaks: string[];
49
+ recommendation: string;
50
+ };
51
+ export type DiagnosticsOptions = {
52
+ /** Override timestamp (for testing). */
53
+ timestamp?: string;
54
+ };
55
+ /** Capture a full memory diagnostics snapshot. */
56
+ export declare function captureMemoryDiagnostics(options?: DiagnosticsOptions): Promise<MemoryDiagnostics>;
57
+ type LeakInputs = {
58
+ detachedContexts: number;
59
+ activeHandles: number;
60
+ nativeMemory: number;
61
+ heapUsed: number;
62
+ mbPerHour: number;
63
+ openFileDescriptors?: number;
64
+ };
65
+ /** Analyze memory metrics for potential leak indicators. */
66
+ export declare function analyzeLeaks(inputs: LeakInputs): LeakAnalysis;
67
+ export {};
68
+ //# sourceMappingURL=heap-diagnostics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heap-diagnostics.d.ts","sourceRoot":"","sources":["../src/heap-diagnostics.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,gBAAgB,EAAE;QAChB,cAAc,EAAE,MAAM,CAAC;QACvB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,WAAW,EAAE;QACX,aAAa,EAAE,MAAM,CAAC;QACtB,cAAc,EAAE,MAAM,CAAC;QACvB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,gBAAgB,EAAE,MAAM,CAAC;QACzB,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,YAAY,CAAC,EAAE,KAAK,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC,CAAC;IACH,aAAa,EAAE;QACb,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,EAAE,YAAY,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,kDAAkD;AAClD,wBAAsB,wBAAwB,CAC5C,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,iBAAiB,CAAC,CAmF5B;AAED,KAAK,UAAU,GAAG;IAChB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF,4DAA4D;AAC5D,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,YAAY,CAkC7D"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * V8 heap diagnostics and leak detection.
3
+ *
4
+ * Pure diagnostic capture — no snapshot writing, no CC-specific deps.
5
+ * Extracted from Claude Code's heapDumpService.
6
+ */
7
+ import { readdir, readFile } from "node:fs/promises";
8
+ import { getHeapSpaceStatistics, getHeapStatistics, } from "node:v8";
9
+ /** Capture a full memory diagnostics snapshot. */
10
+ export async function captureMemoryDiagnostics(options) {
11
+ const usage = process.memoryUsage();
12
+ const heapStats = getHeapStatistics();
13
+ const resourceUsage = process.resourceUsage();
14
+ const uptimeSeconds = process.uptime();
15
+ let heapSpaceStats;
16
+ try {
17
+ heapSpaceStats = getHeapSpaceStatistics();
18
+ }
19
+ catch {
20
+ // Not available in Bun runtime
21
+ }
22
+ const activeHandles = process._getActiveHandles().length;
23
+ const activeRequests = process._getActiveRequests().length;
24
+ let openFileDescriptors;
25
+ try {
26
+ openFileDescriptors = (await readdir("/proc/self/fd")).length;
27
+ }
28
+ catch {
29
+ // Not on Linux
30
+ }
31
+ let smapsRollup;
32
+ try {
33
+ smapsRollup = await readFile("/proc/self/smaps_rollup", "utf8");
34
+ }
35
+ catch {
36
+ // Not on Linux or no access
37
+ }
38
+ const bytesPerSecond = uptimeSeconds > 0 ? usage.rss / uptimeSeconds : 0;
39
+ const mbPerHour = (bytesPerSecond * 3600) / (1024 * 1024);
40
+ const analysis = analyzeLeaks({
41
+ detachedContexts: heapStats.number_of_detached_contexts,
42
+ activeHandles,
43
+ nativeMemory: usage.rss - usage.heapUsed,
44
+ heapUsed: usage.heapUsed,
45
+ mbPerHour,
46
+ openFileDescriptors,
47
+ });
48
+ return {
49
+ timestamp: options?.timestamp ?? new Date().toISOString(),
50
+ uptimeSeconds,
51
+ memoryUsage: {
52
+ heapUsed: usage.heapUsed,
53
+ heapTotal: usage.heapTotal,
54
+ external: usage.external,
55
+ arrayBuffers: usage.arrayBuffers,
56
+ rss: usage.rss,
57
+ },
58
+ memoryGrowthRate: { bytesPerSecond, mbPerHour },
59
+ v8HeapStats: {
60
+ heapSizeLimit: heapStats.heap_size_limit,
61
+ mallocedMemory: heapStats.malloced_memory,
62
+ peakMallocedMemory: heapStats.peak_malloced_memory,
63
+ detachedContexts: heapStats.number_of_detached_contexts,
64
+ nativeContexts: heapStats.number_of_native_contexts,
65
+ },
66
+ v8HeapSpaces: heapSpaceStats?.map((space) => ({
67
+ name: space.space_name,
68
+ size: space.space_size,
69
+ used: space.space_used_size,
70
+ available: space.space_available_size,
71
+ })),
72
+ resourceUsage: {
73
+ maxRSS: resourceUsage.maxRSS * 1024,
74
+ userCPUTime: resourceUsage.userCPUTime,
75
+ systemCPUTime: resourceUsage.systemCPUTime,
76
+ },
77
+ activeHandles,
78
+ activeRequests,
79
+ openFileDescriptors,
80
+ analysis,
81
+ smapsRollup,
82
+ platform: process.platform,
83
+ nodeVersion: process.version,
84
+ };
85
+ }
86
+ /** Analyze memory metrics for potential leak indicators. */
87
+ export function analyzeLeaks(inputs) {
88
+ const potentialLeaks = [];
89
+ if (inputs.detachedContexts > 0) {
90
+ potentialLeaks.push(`${inputs.detachedContexts} detached context(s) - possible iframe/context leak`);
91
+ }
92
+ if (inputs.activeHandles > 100) {
93
+ potentialLeaks.push(`${inputs.activeHandles} active handles - possible timer/socket leak`);
94
+ }
95
+ if (inputs.nativeMemory > inputs.heapUsed) {
96
+ potentialLeaks.push("Native memory > heap - leak may be in native addons");
97
+ }
98
+ if (inputs.mbPerHour > 100) {
99
+ potentialLeaks.push(`High memory growth rate: ${inputs.mbPerHour.toFixed(1)} MB/hour`);
100
+ }
101
+ if (inputs.openFileDescriptors && inputs.openFileDescriptors > 500) {
102
+ potentialLeaks.push(`${inputs.openFileDescriptors} open file descriptors - possible file/socket leak`);
103
+ }
104
+ return {
105
+ potentialLeaks,
106
+ recommendation: potentialLeaks.length > 0
107
+ ? `WARNING: ${potentialLeaks.length} potential leak indicator(s) found. See potentialLeaks array.`
108
+ : "No obvious leak indicators. Check heap snapshot for retained objects.",
109
+ };
110
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Idle timeout manager for long-running services.
3
+ *
4
+ * Configurable via options or environment variable. Calls a shutdown
5
+ * callback after continuous idle duration exceeds threshold.
6
+ *
7
+ * Inspired by Claude Code's `src/utils/idleTimeout.ts`.
8
+ */
9
+ export type IdleTimeoutOptions = {
10
+ /** Returns true when the system is idle. */
11
+ isIdle: () => boolean;
12
+ /** Idle duration in ms before triggering shutdown. Default: from OKA_EXIT_AFTER_IDLE_MS env. */
13
+ delayMs?: number;
14
+ /** Called when idle timeout fires. Default: process.exit(0). */
15
+ onTimeout?: () => void;
16
+ };
17
+ export declare function createIdleTimeoutManager(opts: IdleTimeoutOptions): {
18
+ start: () => void;
19
+ stop: () => void;
20
+ };
21
+ //# sourceMappingURL=idle-timeout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idle-timeout.d.ts","sourceRoot":"","sources":["../src/idle-timeout.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,4CAA4C;IAC5C,MAAM,EAAE,MAAM,OAAO,CAAC;IACtB,gGAAgG;IAChG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB,CAAC;AAEF,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,kBAAkB,GAAG;IAClE,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB,CAsCA"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Idle timeout manager for long-running services.
3
+ *
4
+ * Configurable via options or environment variable. Calls a shutdown
5
+ * callback after continuous idle duration exceeds threshold.
6
+ *
7
+ * Inspired by Claude Code's `src/utils/idleTimeout.ts`.
8
+ */
9
+ export function createIdleTimeoutManager(opts) {
10
+ const envDelay = process.env["OKA_EXIT_AFTER_IDLE_MS"];
11
+ const delayMs = opts.delayMs ?? (envDelay ? parseInt(envDelay, 10) : undefined);
12
+ const isValidDelay = delayMs !== undefined && !isNaN(delayMs) && delayMs > 0;
13
+ const onTimeout = opts.onTimeout ?? (() => process.exit(0));
14
+ let timer = null;
15
+ let lastIdleTime = 0;
16
+ return {
17
+ start() {
18
+ if (timer) {
19
+ clearTimeout(timer);
20
+ timer = null;
21
+ }
22
+ if (isValidDelay && delayMs) {
23
+ lastIdleTime = Date.now();
24
+ timer = setTimeout(() => {
25
+ const idleDuration = Date.now() - lastIdleTime;
26
+ if (opts.isIdle() && idleDuration >= delayMs) {
27
+ onTimeout();
28
+ }
29
+ }, delayMs);
30
+ if (typeof timer === "object" && "unref" in timer) {
31
+ timer.unref();
32
+ }
33
+ }
34
+ },
35
+ stop() {
36
+ if (timer) {
37
+ clearTimeout(timer);
38
+ timer = null;
39
+ }
40
+ },
41
+ };
42
+ }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  #!/usr/bin/env node
2
- export {};
2
+ export { analytics } from "./analytics.js";
3
+ export type { AnalyticsSink } from "./analytics.js";
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAUA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -7,8 +7,13 @@ import { registerWriteTools } from "./tools/write.js";
7
7
  import { registerReadTools } from "./tools/read.js";
8
8
  import { registerAuthTools } from "./tools/auth.js";
9
9
  import { loadEnvFile } from "./auth.js";
10
+ import { analytics } from "./analytics.js";
11
+ export { analytics } from "./analytics.js";
10
12
  // Load .env from the project root (cwd), env vars take precedence
11
13
  loadEnvFile(process.cwd());
14
+ // Attach a no-op sink so analytics events don't queue indefinitely.
15
+ // Downstream consumers can replace this by calling analytics.attach() with a real sink.
16
+ analytics.attach({ track: () => { } });
12
17
  const require = createRequire(import.meta.url);
13
18
  const { version } = require("../package.json");
14
19
  const server = new McpServer({
package/dist/intl.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Lazy-cached Intl object instances.
3
+ *
4
+ * Intl constructors are expensive (~0.05-0.1ms each). Caching avoids
5
+ * re-instantiation across hot paths.
6
+ *
7
+ * Inspired by Claude Code's `src/utils/intl.ts`.
8
+ */
9
+ export declare function getGraphemeSegmenter(): Intl.Segmenter;
10
+ /** Extract the first grapheme cluster from a string. */
11
+ export declare function firstGrapheme(text: string): string;
12
+ /** Extract the last grapheme cluster from a string. */
13
+ export declare function lastGrapheme(text: string): string;
14
+ export declare function getWordSegmenter(): Intl.Segmenter;
15
+ export declare function getRelativeTimeFormat(style: "long" | "short" | "narrow", numeric: "always" | "auto"): Intl.RelativeTimeFormat;
16
+ export declare function getTimeZone(): string;
17
+ export declare function getSystemLocaleLanguage(): string | undefined;
18
+ //# sourceMappingURL=intl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intl.d.ts","sourceRoot":"","sources":["../src/intl.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,wBAAgB,oBAAoB,IAAI,IAAI,CAAC,SAAS,CAOrD;AAED,wDAAwD;AACxD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED,uDAAuD;AACvD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOjD;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAAC,SAAS,CAKjD;AAMD,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,EAClC,OAAO,EAAE,QAAQ,GAAG,MAAM,GACzB,IAAI,CAAC,kBAAkB,CAQzB;AAMD,wBAAgB,WAAW,IAAI,MAAM,CAKpC;AAID,wBAAgB,uBAAuB,IAAI,MAAM,GAAG,SAAS,CAU5D"}