@oka-core/reason 0.2.15 → 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 (158) 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/binary-check.d.ts +16 -0
  17. package/dist/binary-check.d.ts.map +1 -0
  18. package/dist/binary-check.js +43 -0
  19. package/dist/buffered-writer.d.ts +30 -0
  20. package/dist/buffered-writer.d.ts.map +1 -0
  21. package/dist/buffered-writer.js +87 -0
  22. package/dist/circular-buffer.d.ts +28 -0
  23. package/dist/circular-buffer.d.ts.map +1 -0
  24. package/dist/circular-buffer.js +61 -0
  25. package/dist/cleanup-registry.d.ts +23 -0
  26. package/dist/cleanup-registry.d.ts.map +1 -0
  27. package/dist/cleanup-registry.js +34 -0
  28. package/dist/client.d.ts +4 -0
  29. package/dist/client.d.ts.map +1 -1
  30. package/dist/client.js +32 -10
  31. package/dist/combined-abort-signal.d.ts +25 -0
  32. package/dist/combined-abort-signal.d.ts.map +1 -0
  33. package/dist/combined-abort-signal.js +47 -0
  34. package/dist/cron-lock.d.ts +29 -0
  35. package/dist/cron-lock.d.ts.map +1 -0
  36. package/dist/cron-lock.js +127 -0
  37. package/dist/cron-scheduler.d.ts +41 -0
  38. package/dist/cron-scheduler.d.ts.map +1 -0
  39. package/dist/cron-scheduler.js +189 -0
  40. package/dist/cron-tasks.d.ts +86 -0
  41. package/dist/cron-tasks.d.ts.map +1 -0
  42. package/dist/cron-tasks.js +205 -0
  43. package/dist/cron.d.ts +35 -0
  44. package/dist/cron.d.ts.map +1 -0
  45. package/dist/cron.js +215 -0
  46. package/dist/env.d.ts +26 -0
  47. package/dist/env.d.ts.map +1 -0
  48. package/dist/env.js +50 -0
  49. package/dist/errors.d.ts +99 -0
  50. package/dist/errors.d.ts.map +1 -0
  51. package/dist/errors.js +214 -0
  52. package/dist/format.d.ts +21 -0
  53. package/dist/format.d.ts.map +1 -0
  54. package/dist/format.js +48 -0
  55. package/dist/fps-tracker.d.ts +22 -0
  56. package/dist/fps-tracker.d.ts.map +1 -0
  57. package/dist/fps-tracker.js +44 -0
  58. package/dist/graceful-shutdown.d.ts +35 -0
  59. package/dist/graceful-shutdown.d.ts.map +1 -0
  60. package/dist/graceful-shutdown.js +89 -0
  61. package/dist/hash.d.ts +21 -0
  62. package/dist/hash.d.ts.map +1 -0
  63. package/dist/hash.js +31 -0
  64. package/dist/heap-diagnostics.d.ts +68 -0
  65. package/dist/heap-diagnostics.d.ts.map +1 -0
  66. package/dist/heap-diagnostics.js +110 -0
  67. package/dist/idle-timeout.d.ts +21 -0
  68. package/dist/idle-timeout.d.ts.map +1 -0
  69. package/dist/idle-timeout.js +42 -0
  70. package/dist/index.d.ts +2 -1
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +5 -0
  73. package/dist/intl.d.ts +18 -0
  74. package/dist/intl.d.ts.map +1 -0
  75. package/dist/intl.js +75 -0
  76. package/dist/jsonl.d.ts +16 -0
  77. package/dist/jsonl.d.ts.map +1 -0
  78. package/dist/jsonl.js +60 -0
  79. package/dist/lazy-schema.d.ts +6 -0
  80. package/dist/lazy-schema.d.ts.map +1 -0
  81. package/dist/lazy-schema.js +8 -0
  82. package/dist/memo.d.ts +64 -0
  83. package/dist/memo.d.ts.map +1 -0
  84. package/dist/memo.js +162 -0
  85. package/dist/pkce.d.ts +13 -0
  86. package/dist/pkce.d.ts.map +1 -0
  87. package/dist/pkce.js +28 -0
  88. package/dist/priority-queue.d.ts +36 -0
  89. package/dist/priority-queue.d.ts.map +1 -0
  90. package/dist/priority-queue.js +97 -0
  91. package/dist/process-utils.d.ts +20 -0
  92. package/dist/process-utils.d.ts.map +1 -0
  93. package/dist/process-utils.js +54 -0
  94. package/dist/query-guard.d.ts +34 -0
  95. package/dist/query-guard.d.ts.map +1 -0
  96. package/dist/query-guard.js +74 -0
  97. package/dist/retry.d.ts +60 -0
  98. package/dist/retry.d.ts.map +1 -0
  99. package/dist/retry.js +89 -0
  100. package/dist/schemas.d.ts +6 -6
  101. package/dist/secrets.d.ts +44 -0
  102. package/dist/secrets.d.ts.map +1 -0
  103. package/dist/secrets.js +115 -0
  104. package/dist/semantic-types.d.ts +39 -0
  105. package/dist/semantic-types.d.ts.map +1 -0
  106. package/dist/semantic-types.js +49 -0
  107. package/dist/sequential.d.ts +21 -0
  108. package/dist/sequential.d.ts.map +1 -0
  109. package/dist/sequential.js +49 -0
  110. package/dist/signal.d.ts +29 -0
  111. package/dist/signal.d.ts.map +1 -0
  112. package/dist/signal.js +39 -0
  113. package/dist/sleep.d.ts +21 -0
  114. package/dist/sleep.d.ts.map +1 -0
  115. package/dist/sleep.js +58 -0
  116. package/dist/slow-ops.d.ts +41 -0
  117. package/dist/slow-ops.d.ts.map +1 -0
  118. package/dist/slow-ops.js +133 -0
  119. package/dist/store.d.ts +20 -0
  120. package/dist/store.d.ts.map +1 -0
  121. package/dist/store.js +34 -0
  122. package/dist/stream.d.ts +29 -0
  123. package/dist/stream.d.ts.map +1 -0
  124. package/dist/stream.js +92 -0
  125. package/dist/string-utils.d.ts +46 -0
  126. package/dist/string-utils.d.ts.map +1 -0
  127. package/dist/string-utils.js +69 -0
  128. package/dist/strip-bom.d.ts +8 -0
  129. package/dist/strip-bom.d.ts.map +1 -0
  130. package/dist/strip-bom.js +10 -0
  131. package/dist/subprocess-env.d.ts +25 -0
  132. package/dist/subprocess-env.d.ts.map +1 -0
  133. package/dist/subprocess-env.js +55 -0
  134. package/dist/temp-file.d.ts +18 -0
  135. package/dist/temp-file.d.ts.map +1 -0
  136. package/dist/temp-file.js +26 -0
  137. package/dist/tool-contract.d.ts +85 -0
  138. package/dist/tool-contract.d.ts.map +1 -0
  139. package/dist/tool-contract.js +101 -0
  140. package/dist/tools/read.d.ts +2 -10
  141. package/dist/tools/read.d.ts.map +1 -1
  142. package/dist/tools/read.js +662 -537
  143. package/dist/tools/write.d.ts +3 -2
  144. package/dist/tools/write.d.ts.map +1 -1
  145. package/dist/tools/write.js +329 -177
  146. package/dist/uuid.d.ts +20 -0
  147. package/dist/uuid.d.ts.map +1 -0
  148. package/dist/uuid.js +28 -0
  149. package/dist/validation.d.ts +64 -0
  150. package/dist/validation.d.ts.map +1 -0
  151. package/dist/validation.js +236 -0
  152. package/dist/with-resolvers.d.ts +12 -0
  153. package/dist/with-resolvers.d.ts.map +1 -0
  154. package/dist/with-resolvers.js +14 -0
  155. package/dist/xml-escape.d.ts +12 -0
  156. package/dist/xml-escape.d.ts.map +1 -0
  157. package/dist/xml-escape.js +15 -0
  158. package/package.json +1 -1
@@ -0,0 +1,19 @@
1
+ /**
2
+ * AbortController factory with listener-limit management and
3
+ * memory-safe parent→child propagation via WeakRef.
4
+ *
5
+ * Inspired by Claude Code's `src/utils/abortController.ts`.
6
+ */
7
+ /**
8
+ * Create an AbortController with raised listener limit to prevent
9
+ * MaxListenersExceededWarning when many consumers share one signal.
10
+ */
11
+ export declare function createAbortController(maxListeners?: number): AbortController;
12
+ /**
13
+ * Create a child AbortController that aborts when its parent aborts.
14
+ * Aborting the child does NOT affect the parent.
15
+ *
16
+ * Memory-safe: uses WeakRef so the parent doesn't retain abandoned children.
17
+ */
18
+ export declare function createChildAbortController(parent: AbortController, maxListeners?: number): AbortController;
19
+ //# sourceMappingURL=abort-controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"abort-controller.d.ts","sourceRoot":"","sources":["../src/abort-controller.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,YAAY,GAAE,MAA8B,GAC3C,eAAe,CAQjB;AAuBD;;;;;GAKG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,eAAe,EACvB,YAAY,CAAC,EAAE,MAAM,GACpB,eAAe,CAqBjB"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * AbortController factory with listener-limit management and
3
+ * memory-safe parent→child propagation via WeakRef.
4
+ *
5
+ * Inspired by Claude Code's `src/utils/abortController.ts`.
6
+ */
7
+ import { setMaxListeners } from "events";
8
+ const DEFAULT_MAX_LISTENERS = 50;
9
+ /**
10
+ * Create an AbortController with raised listener limit to prevent
11
+ * MaxListenersExceededWarning when many consumers share one signal.
12
+ */
13
+ export function createAbortController(maxListeners = DEFAULT_MAX_LISTENERS) {
14
+ const controller = new AbortController();
15
+ try {
16
+ setMaxListeners(maxListeners, controller.signal);
17
+ }
18
+ catch {
19
+ /* runtime doesn't support setMaxListeners on EventTarget */
20
+ }
21
+ return controller;
22
+ }
23
+ // ── WeakRef-based parent→child propagation ────────────────────────
24
+ function propagateAbort(weakChild) {
25
+ const parent = this.deref();
26
+ weakChild.deref()?.abort(parent?.signal.reason);
27
+ }
28
+ function removeAbortHandler(weakHandler) {
29
+ const parent = this.deref();
30
+ const handler = weakHandler.deref();
31
+ if (parent && handler) {
32
+ parent.signal.removeEventListener("abort", handler);
33
+ }
34
+ }
35
+ /**
36
+ * Create a child AbortController that aborts when its parent aborts.
37
+ * Aborting the child does NOT affect the parent.
38
+ *
39
+ * Memory-safe: uses WeakRef so the parent doesn't retain abandoned children.
40
+ */
41
+ export function createChildAbortController(parent, maxListeners) {
42
+ const child = createAbortController(maxListeners);
43
+ if (parent.signal.aborted) {
44
+ child.abort(parent.signal.reason);
45
+ return child;
46
+ }
47
+ const weakChild = new WeakRef(child);
48
+ const weakParent = new WeakRef(parent);
49
+ const handler = propagateAbort.bind(weakParent, weakChild);
50
+ parent.signal.addEventListener("abort", handler, { once: true });
51
+ child.signal.addEventListener("abort", removeAbortHandler.bind(weakParent, new WeakRef(handler)), { once: true });
52
+ return child;
53
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Activity tracker for user vs CLI operation time tracking.
3
+ *
4
+ * Tracks overlapping operations with automatic deduplication.
5
+ * Injectable time source and callback for clean architecture.
6
+ *
7
+ * Extracted from Claude Code's ActivityManager — stripped singleton,
8
+ * bootstrap state, and metric counter coupling.
9
+ */
10
+ export type ActivityType = "user" | "cli";
11
+ export type ActivityRecord = {
12
+ type: ActivityType;
13
+ durationSeconds: number;
14
+ };
15
+ export type ActivityTrackerOptions = {
16
+ /** Time source (default: Date.now). */
17
+ getNow?: () => number;
18
+ /** Called when an activity period ends with its type and duration. */
19
+ onRecord?: (record: ActivityRecord) => void;
20
+ /** User inactivity timeout in ms (default: 5000). */
21
+ userTimeoutMs?: number;
22
+ };
23
+ export type ActivityStates = {
24
+ isUserActive: boolean;
25
+ isCliActive: boolean;
26
+ activeOperationCount: number;
27
+ };
28
+ export declare class ActivityTracker {
29
+ private activeOperations;
30
+ private lastUserActivityTime;
31
+ private lastCliRecordedTime;
32
+ private isCliActive;
33
+ private readonly getNow;
34
+ private readonly onRecord;
35
+ private readonly userTimeoutMs;
36
+ constructor(options?: ActivityTrackerOptions);
37
+ /** Record a user interaction (typing, clicking, etc.). */
38
+ recordUserActivity(): void;
39
+ /** Start tracking a CLI operation. Duplicate IDs are force-ended first. */
40
+ startActivity(operationId: string): void;
41
+ /** End tracking a CLI operation. Records CLI time when last op ends. */
42
+ endActivity(operationId: string): void;
43
+ /** Track an async operation automatically. */
44
+ trackOperation<T>(operationId: string, fn: () => Promise<T>): Promise<T>;
45
+ /** Get current activity states. */
46
+ getActivityStates(): ActivityStates;
47
+ }
48
+ //# sourceMappingURL=activity-tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity-tracker.d.ts","sourceRoot":"","sources":["../src/activity-tracker.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,KAAK,CAAC;AAE1C,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,YAAY,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC;IACtB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC;IAC5C,qDAAqD;IACrD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;IACrB,oBAAoB,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF,qBAAa,eAAe;IAC1B,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,oBAAoB,CAAK;IACjC,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,WAAW,CAAS;IAE5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmC;IAC5D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;gBAE3B,OAAO,CAAC,EAAE,sBAAsB;IAO5C,0DAA0D;IAC1D,kBAAkB,IAAI,IAAI;IAW1B,2EAA2E;IAC3E,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAYxC,wEAAwE;IACxE,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAatC,8CAA8C;IACxC,cAAc,CAAC,CAAC,EACpB,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC;IASb,mCAAmC;IACnC,iBAAiB,IAAI,cAAc;CAUpC"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Activity tracker for user vs CLI operation time tracking.
3
+ *
4
+ * Tracks overlapping operations with automatic deduplication.
5
+ * Injectable time source and callback for clean architecture.
6
+ *
7
+ * Extracted from Claude Code's ActivityManager — stripped singleton,
8
+ * bootstrap state, and metric counter coupling.
9
+ */
10
+ export class ActivityTracker {
11
+ activeOperations = new Set();
12
+ lastUserActivityTime = 0;
13
+ lastCliRecordedTime;
14
+ isCliActive = false;
15
+ getNow;
16
+ onRecord;
17
+ userTimeoutMs;
18
+ constructor(options) {
19
+ this.getNow = options?.getNow ?? (() => Date.now());
20
+ this.onRecord = options?.onRecord ?? (() => { });
21
+ this.userTimeoutMs = options?.userTimeoutMs ?? 5000;
22
+ this.lastCliRecordedTime = this.getNow();
23
+ }
24
+ /** Record a user interaction (typing, clicking, etc.). */
25
+ recordUserActivity() {
26
+ if (!this.isCliActive && this.lastUserActivityTime !== 0) {
27
+ const now = this.getNow();
28
+ const elapsed = (now - this.lastUserActivityTime) / 1000;
29
+ if (elapsed > 0 && elapsed < this.userTimeoutMs / 1000) {
30
+ this.onRecord({ type: "user", durationSeconds: elapsed });
31
+ }
32
+ }
33
+ this.lastUserActivityTime = this.getNow();
34
+ }
35
+ /** Start tracking a CLI operation. Duplicate IDs are force-ended first. */
36
+ startActivity(operationId) {
37
+ if (this.activeOperations.has(operationId)) {
38
+ this.endActivity(operationId);
39
+ }
40
+ const wasEmpty = this.activeOperations.size === 0;
41
+ this.activeOperations.add(operationId);
42
+ if (wasEmpty) {
43
+ this.isCliActive = true;
44
+ this.lastCliRecordedTime = this.getNow();
45
+ }
46
+ }
47
+ /** End tracking a CLI operation. Records CLI time when last op ends. */
48
+ endActivity(operationId) {
49
+ this.activeOperations.delete(operationId);
50
+ if (this.activeOperations.size === 0) {
51
+ const now = this.getNow();
52
+ const elapsed = (now - this.lastCliRecordedTime) / 1000;
53
+ if (elapsed > 0) {
54
+ this.onRecord({ type: "cli", durationSeconds: elapsed });
55
+ }
56
+ this.lastCliRecordedTime = now;
57
+ this.isCliActive = false;
58
+ }
59
+ }
60
+ /** Track an async operation automatically. */
61
+ async trackOperation(operationId, fn) {
62
+ this.startActivity(operationId);
63
+ try {
64
+ return await fn();
65
+ }
66
+ finally {
67
+ this.endActivity(operationId);
68
+ }
69
+ }
70
+ /** Get current activity states. */
71
+ getActivityStates() {
72
+ const now = this.getNow();
73
+ const elapsed = (now - this.lastUserActivityTime) / 1000;
74
+ return {
75
+ isUserActive: this.lastUserActivityTime > 0 && elapsed < this.userTimeoutMs / 1000,
76
+ isCliActive: this.isCliActive,
77
+ activeOperationCount: this.activeOperations.size,
78
+ };
79
+ }
80
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Analytics decoupling layer — deferred sink attachment with PII safety.
3
+ *
4
+ * ZERO external dependencies — pure domain layer.
5
+ *
6
+ * Inspired by Claude Code's analytics pattern:
7
+ * - Events queue before any sink is attached (startup race-free)
8
+ * - Drain happens via queueMicrotask (non-blocking)
9
+ * - PII-marked fields are stripped before forwarding to sink
10
+ * - _resetForTesting() ensures test isolation
11
+ */
12
+ /** A single analytics event. */
13
+ export interface AnalyticsEvent {
14
+ /** Machine-readable event name (e.g., "tool.invoked", "search.completed"). */
15
+ name: string;
16
+ /** Event properties. Keys prefixed with `_pii:` are stripped before sink. */
17
+ properties: Record<string, unknown>;
18
+ /** ISO timestamp — defaults to now. */
19
+ timestamp?: string;
20
+ }
21
+ /** Sink port — implement this to send events to your telemetry backend. */
22
+ export interface AnalyticsSink {
23
+ track(event: AnalyticsEvent): void;
24
+ flush?(): Promise<void>;
25
+ }
26
+ /**
27
+ * Analytics tracker with deferred sink attachment.
28
+ *
29
+ * Events are queued until a sink is attached, then drained via microtask.
30
+ * PII-marked properties are stripped before forwarding.
31
+ */
32
+ export declare class AnalyticsTracker {
33
+ private sink;
34
+ private queue;
35
+ private drainScheduled;
36
+ /** Attach a sink and drain any queued events. */
37
+ attach(sink: AnalyticsSink): void;
38
+ /** Track an event. If no sink is attached, queues for later delivery. */
39
+ track(name: string, properties?: Record<string, unknown>): void;
40
+ /** Flush the underlying sink (if it supports flushing). */
41
+ flush(): Promise<void>;
42
+ /** Reset all state — for test isolation only. */
43
+ _resetForTesting(): void;
44
+ private forward;
45
+ private scheduleDrain;
46
+ }
47
+ /** Default global tracker instance. */
48
+ export declare const analytics: AnalyticsTracker;
49
+ //# sourceMappingURL=analytics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,gCAAgC;AAChC,MAAM,WAAW,cAAc;IAC7B,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,2EAA2E;AAC3E,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAAC;IACnC,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AAqBD;;;;;GAKG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,IAAI,CAA8B;IAC1C,OAAO,CAAC,KAAK,CAAwB;IACrC,OAAO,CAAC,cAAc,CAAS;IAE/B,iDAAiD;IACjD,MAAM,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI;IAKjC,yEAAyE;IACzE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,IAAI;IAanE,2DAA2D;IACrD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,iDAAiD;IACjD,gBAAgB,IAAI,IAAI;IAMxB,OAAO,CAAC,OAAO;IASf,OAAO,CAAC,aAAa;CAWtB;AAID,uCAAuC;AACvC,eAAO,MAAM,SAAS,kBAAyB,CAAC"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Analytics decoupling layer — deferred sink attachment with PII safety.
3
+ *
4
+ * ZERO external dependencies — pure domain layer.
5
+ *
6
+ * Inspired by Claude Code's analytics pattern:
7
+ * - Events queue before any sink is attached (startup race-free)
8
+ * - Drain happens via queueMicrotask (non-blocking)
9
+ * - PII-marked fields are stripped before forwarding to sink
10
+ * - _resetForTesting() ensures test isolation
11
+ */
12
+ // ─── PII Stripping ──────────────────────────────────────────────────
13
+ const PII_PREFIX = "_pii:";
14
+ /** Remove any property whose key starts with `_pii:` — returns a clean copy. */
15
+ function stripPii(properties) {
16
+ const clean = {};
17
+ for (const [key, value] of Object.entries(properties)) {
18
+ if (!key.startsWith(PII_PREFIX)) {
19
+ clean[key] = value;
20
+ }
21
+ }
22
+ return clean;
23
+ }
24
+ // ─── Tracker ────────────────────────────────────────────────────────
25
+ /**
26
+ * Analytics tracker with deferred sink attachment.
27
+ *
28
+ * Events are queued until a sink is attached, then drained via microtask.
29
+ * PII-marked properties are stripped before forwarding.
30
+ */
31
+ export class AnalyticsTracker {
32
+ sink = null;
33
+ queue = [];
34
+ drainScheduled = false;
35
+ /** Attach a sink and drain any queued events. */
36
+ attach(sink) {
37
+ this.sink = sink;
38
+ this.scheduleDrain();
39
+ }
40
+ /** Track an event. If no sink is attached, queues for later delivery. */
41
+ track(name, properties = {}) {
42
+ const event = {
43
+ name,
44
+ properties,
45
+ timestamp: new Date().toISOString(),
46
+ };
47
+ if (this.sink) {
48
+ this.forward(event);
49
+ }
50
+ else {
51
+ this.queue.push(event);
52
+ }
53
+ }
54
+ /** Flush the underlying sink (if it supports flushing). */
55
+ async flush() {
56
+ await this.sink?.flush?.();
57
+ }
58
+ /** Reset all state — for test isolation only. */
59
+ _resetForTesting() {
60
+ this.sink = null;
61
+ this.queue = [];
62
+ this.drainScheduled = false;
63
+ }
64
+ forward(event) {
65
+ if (!this.sink)
66
+ return; // Guard against drain after reset
67
+ const clean = {
68
+ ...event,
69
+ properties: stripPii(event.properties),
70
+ };
71
+ this.sink.track(clean);
72
+ }
73
+ scheduleDrain() {
74
+ if (this.drainScheduled || this.queue.length === 0)
75
+ return;
76
+ this.drainScheduled = true;
77
+ queueMicrotask(() => {
78
+ this.drainScheduled = false;
79
+ const events = this.queue.splice(0);
80
+ for (const event of events) {
81
+ this.forward(event);
82
+ }
83
+ });
84
+ }
85
+ }
86
+ // ─── Singleton ──────────────────────────────────────────────────────
87
+ /** Default global tracker instance. */
88
+ export const analytics = new AnalyticsTracker();
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Functional array utilities — zero dependencies.
3
+ *
4
+ * Inspired by Claude Code's `src/utils/array.ts`.
5
+ */
6
+ /** Interleave a separator (computed from index) between array elements. */
7
+ export declare function intersperse<A>(as: A[], separator: (index: number) => A): A[];
8
+ /** Count elements matching a predicate. */
9
+ export declare function count<T>(arr: readonly T[], pred: (x: T) => unknown): number;
10
+ /** Deduplicate via Set, preserving insertion order. */
11
+ export declare function uniq<T>(xs: Iterable<T>): T[];
12
+ //# sourceMappingURL=array.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"array.d.ts","sourceRoot":"","sources":["../src/array.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,2EAA2E;AAC3E,wBAAgB,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,CAAC,GAAG,CAAC,EAAE,CAE5E;AAED,2CAA2C;AAC3C,wBAAgB,KAAK,CAAC,CAAC,EAAE,GAAG,EAAE,SAAS,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,GAAG,MAAM,CAI3E;AAED,uDAAuD;AACvD,wBAAgB,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAE5C"}
package/dist/array.js ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Functional array utilities — zero dependencies.
3
+ *
4
+ * Inspired by Claude Code's `src/utils/array.ts`.
5
+ */
6
+ /** Interleave a separator (computed from index) between array elements. */
7
+ export function intersperse(as, separator) {
8
+ return as.flatMap((a, i) => (i ? [separator(i), a] : [a]));
9
+ }
10
+ /** Count elements matching a predicate. */
11
+ export function count(arr, pred) {
12
+ let n = 0;
13
+ for (const x of arr)
14
+ n += +!!pred(x);
15
+ return n;
16
+ }
17
+ /** Deduplicate via Set, preserving insertion order. */
18
+ export function uniq(xs) {
19
+ return [...new Set(xs)];
20
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * AsyncLocalStorage-based CWD override for concurrent async contexts.
3
+ *
4
+ * Enables multiple agents to each see their own working directory
5
+ * without affecting each other or the global process.cwd().
6
+ *
7
+ * Inspired by Claude Code's `src/utils/cwd.ts`.
8
+ */
9
+ /**
10
+ * Run a function with an overridden working directory for the current
11
+ * async context. All calls to `getContextCwd()` within `fn` (and its
12
+ * async descendants) will return `cwd`.
13
+ */
14
+ export declare function runWithCwdOverride<T>(cwd: string, fn: () => T): T;
15
+ /**
16
+ * Get the current working directory, respecting any active override.
17
+ * Falls back to `process.cwd()` when no override is set.
18
+ */
19
+ export declare function getContextCwd(): string;
20
+ //# sourceMappingURL=async-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"async-context.d.ts","sourceRoot":"","sources":["../src/async-context.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAEjE;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * AsyncLocalStorage-based CWD override for concurrent async contexts.
3
+ *
4
+ * Enables multiple agents to each see their own working directory
5
+ * without affecting each other or the global process.cwd().
6
+ *
7
+ * Inspired by Claude Code's `src/utils/cwd.ts`.
8
+ */
9
+ import { AsyncLocalStorage } from "async_hooks";
10
+ const cwdOverrideStorage = new AsyncLocalStorage();
11
+ /**
12
+ * Run a function with an overridden working directory for the current
13
+ * async context. All calls to `getContextCwd()` within `fn` (and its
14
+ * async descendants) will return `cwd`.
15
+ */
16
+ export function runWithCwdOverride(cwd, fn) {
17
+ return cwdOverrideStorage.run(cwd, fn);
18
+ }
19
+ /**
20
+ * Get the current working directory, respecting any active override.
21
+ * Falls back to `process.cwd()` when no override is set.
22
+ */
23
+ export function getContextCwd() {
24
+ return cwdOverrideStorage.getStore() ?? process.cwd();
25
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Session-cached binary existence probe.
3
+ *
4
+ * Checks whether a command is installed via the platform's `which` / `where`.
5
+ * Results are cached for the process lifetime.
6
+ *
7
+ * Inspired by Claude Code's `src/utils/binaryCheck.ts`.
8
+ */
9
+ /**
10
+ * Check if a binary/command is installed and available on the system.
11
+ * Results are cached for the process lifetime.
12
+ */
13
+ export declare function isBinaryInstalled(command: string): Promise<boolean>;
14
+ /** Clear the binary check cache (useful for testing). */
15
+ export declare function clearBinaryCache(): void;
16
+ //# sourceMappingURL=binary-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binary-check.d.ts","sourceRoot":"","sources":["../src/binary-check.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAoBH;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUzE;AAED,yDAAyD;AACzD,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Session-cached binary existence probe.
3
+ *
4
+ * Checks whether a command is installed via the platform's `which` / `where`.
5
+ * Results are cached for the process lifetime.
6
+ *
7
+ * Inspired by Claude Code's `src/utils/binaryCheck.ts`.
8
+ */
9
+ import { execFile } from "child_process";
10
+ const binaryCache = new Map();
11
+ /** Resolve a command to its path, or null if not found. */
12
+ function which(command) {
13
+ const cmd = process.platform === "win32" ? "where" : "which";
14
+ return new Promise((resolve) => {
15
+ execFile(cmd, [command], (err, stdout) => {
16
+ if (err) {
17
+ resolve(null);
18
+ }
19
+ else {
20
+ resolve(stdout.trim() || null);
21
+ }
22
+ });
23
+ });
24
+ }
25
+ /**
26
+ * Check if a binary/command is installed and available on the system.
27
+ * Results are cached for the process lifetime.
28
+ */
29
+ export async function isBinaryInstalled(command) {
30
+ if (!command || !command.trim())
31
+ return false;
32
+ const trimmed = command.trim();
33
+ const cached = binaryCache.get(trimmed);
34
+ if (cached !== undefined)
35
+ return cached;
36
+ const exists = (await which(trimmed)) !== null;
37
+ binaryCache.set(trimmed, exists);
38
+ return exists;
39
+ }
40
+ /** Clear the binary check cache (useful for testing). */
41
+ export function clearBinaryCache() {
42
+ binaryCache.clear();
43
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Batched I/O writer with backpressure — zero external dependencies.
3
+ *
4
+ * Batches writes by count, byte size, or time interval. Overflow batches
5
+ * are deferred via `setImmediate` to keep the current tick fast.
6
+ *
7
+ * Inspired by Claude Code's `src/utils/bufferedWriter.ts`.
8
+ */
9
+ export type BufferedWriter = {
10
+ /** Append content to the buffer. May trigger an async flush on overflow. */
11
+ write: (content: string) => void;
12
+ /** Flush all buffered content immediately. */
13
+ flush: () => void;
14
+ /** Flush and stop the periodic timer. */
15
+ dispose: () => void;
16
+ };
17
+ export type BufferedWriterOptions = {
18
+ /** The function that actually writes a batch of content. */
19
+ writeFn: (batch: string[]) => void;
20
+ /** Flush interval in ms. Default: 1000. */
21
+ flushIntervalMs?: number;
22
+ /** Max items before overflow flush. Default: 100. */
23
+ maxBufferSize?: number;
24
+ /** Max total bytes before overflow flush. Default: Infinity. */
25
+ maxBufferBytes?: number;
26
+ /** Bypass buffering entirely — write immediately. Default: false. */
27
+ immediateMode?: boolean;
28
+ };
29
+ export declare function createBufferedWriter(opts: BufferedWriterOptions): BufferedWriter;
30
+ //# sourceMappingURL=buffered-writer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buffered-writer.d.ts","sourceRoot":"","sources":["../src/buffered-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,MAAM,cAAc,GAAG;IAC3B,4EAA4E;IAC5E,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,8CAA8C;IAC9C,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,yCAAyC;IACzC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,4DAA4D;IAC5D,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACnC,2CAA2C;IAC3C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qDAAqD;IACrD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gEAAgE;IAChE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AASF,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,qBAAqB,GAC1B,cAAc,CAsFhB"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Batched I/O writer with backpressure — zero external dependencies.
3
+ *
4
+ * Batches writes by count, byte size, or time interval. Overflow batches
5
+ * are deferred via `setImmediate` to keep the current tick fast.
6
+ *
7
+ * Inspired by Claude Code's `src/utils/bufferedWriter.ts`.
8
+ */
9
+ // ─── Factory ────────────────────────────────────────────────────────
10
+ const scheduleImmediate = typeof globalThis.setImmediate === "function"
11
+ ? globalThis.setImmediate
12
+ : (fn) => setTimeout(fn, 0);
13
+ export function createBufferedWriter(opts) {
14
+ const { writeFn, flushIntervalMs = 1000, maxBufferSize = 100, maxBufferBytes = Infinity, immediateMode = false, } = opts;
15
+ let buffer = [];
16
+ let bufferBytes = 0;
17
+ let flushTimer = null;
18
+ let pendingOverflow = null;
19
+ function drainOverflow() {
20
+ if (pendingOverflow) {
21
+ const batch = pendingOverflow;
22
+ pendingOverflow = null;
23
+ writeFn(batch);
24
+ }
25
+ }
26
+ function flushBuffer() {
27
+ if (buffer.length === 0)
28
+ return;
29
+ const batch = buffer;
30
+ buffer = [];
31
+ bufferBytes = 0;
32
+ writeFn(batch);
33
+ }
34
+ function scheduleFlush() {
35
+ if (flushTimer !== null)
36
+ return;
37
+ flushTimer = setTimeout(() => {
38
+ flushTimer = null;
39
+ flushBuffer();
40
+ }, flushIntervalMs);
41
+ if (typeof flushTimer === "object" && "unref" in flushTimer) {
42
+ flushTimer.unref();
43
+ }
44
+ }
45
+ return {
46
+ write(content) {
47
+ if (immediateMode) {
48
+ writeFn([content]);
49
+ return;
50
+ }
51
+ buffer.push(content);
52
+ bufferBytes += content.length;
53
+ if (buffer.length >= maxBufferSize || bufferBytes >= maxBufferBytes) {
54
+ // Overflow: detach buffer and defer the write
55
+ const batch = buffer;
56
+ buffer = [];
57
+ bufferBytes = 0;
58
+ if (pendingOverflow) {
59
+ pendingOverflow.push(...batch);
60
+ }
61
+ else {
62
+ pendingOverflow = batch;
63
+ scheduleImmediate(drainOverflow);
64
+ }
65
+ }
66
+ else {
67
+ scheduleFlush();
68
+ }
69
+ },
70
+ flush() {
71
+ drainOverflow();
72
+ flushBuffer();
73
+ if (flushTimer !== null) {
74
+ clearTimeout(flushTimer);
75
+ flushTimer = null;
76
+ }
77
+ },
78
+ dispose() {
79
+ drainOverflow();
80
+ flushBuffer();
81
+ if (flushTimer !== null) {
82
+ clearTimeout(flushTimer);
83
+ flushTimer = null;
84
+ }
85
+ },
86
+ };
87
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Fixed-size circular buffer — zero external dependencies.
3
+ *
4
+ * O(1) add, automatic eviction of oldest entries when capacity is exceeded.
5
+ * Useful for metrics windows, log tailing, and recent-activity buffers.
6
+ *
7
+ * Inspired by Claude Code's `src/utils/CircularBuffer.ts`.
8
+ */
9
+ export declare class CircularBuffer<T> {
10
+ private readonly capacity;
11
+ private buffer;
12
+ private head;
13
+ private _size;
14
+ constructor(capacity: number);
15
+ /** Add an item, evicting the oldest if at capacity. */
16
+ add(item: T): void;
17
+ /** Add multiple items. */
18
+ addAll(items: T[]): void;
19
+ /** Get the most recent `count` items in insertion order (oldest first). */
20
+ getRecent(count?: number): T[];
21
+ /** Get all items in insertion order (oldest first). */
22
+ toArray(): T[];
23
+ /** Remove all items. */
24
+ clear(): void;
25
+ /** Current number of items (0 to capacity). */
26
+ get length(): number;
27
+ }
28
+ //# sourceMappingURL=circular-buffer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circular-buffer.d.ts","sourceRoot":"","sources":["../src/circular-buffer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,qBAAa,cAAc,CAAC,CAAC;IAKf,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAJrC,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,KAAK,CAAK;gBAEW,QAAQ,EAAE,MAAM;IAO7C,uDAAuD;IACvD,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI;IAQlB,0BAA0B;IAC1B,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI;IAMxB,2EAA2E;IAC3E,SAAS,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE;IAa9B,uDAAuD;IACvD,OAAO,IAAI,CAAC,EAAE;IAId,wBAAwB;IACxB,KAAK,IAAI,IAAI;IAKb,+CAA+C;IAC/C,IAAI,MAAM,IAAI,MAAM,CAEnB;CACF"}