@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
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Concurrency state machine — prevents re-entrant async operations.
3
+ *
4
+ * Tracks a 3-state lifecycle: idle → dispatching → running → idle.
5
+ * A generation counter ensures stale finally-blocks from cancelled
6
+ * queries don't corrupt cleanup.
7
+ *
8
+ * Inspired by Claude Code's `src/utils/QueryGuard.ts`.
9
+ */
10
+ export declare class QueryGuard {
11
+ private state;
12
+ private _generation;
13
+ private _changed;
14
+ /** Try to reserve the guard for a new operation. Returns false if busy. */
15
+ reserve(): boolean;
16
+ /** Cancel a reservation (go back to idle). */
17
+ cancelReservation(): void;
18
+ /** Transition from dispatching to running. Returns generation or null if not dispatching. */
19
+ tryStart(): number | null;
20
+ /**
21
+ * End a running operation. Only succeeds if the generation matches
22
+ * (prevents stale cleanups). Returns true if the guard was released.
23
+ */
24
+ end(generation: number): boolean;
25
+ /** Force the guard back to idle regardless of state. */
26
+ forceEnd(): void;
27
+ /** Whether the guard is in dispatching or running state. */
28
+ get isActive(): boolean;
29
+ /** Current generation counter. */
30
+ get generation(): number;
31
+ subscribe: (listener: () => void) => (() => void);
32
+ getSnapshot: () => boolean;
33
+ }
34
+ //# sourceMappingURL=query-guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-guard.d.ts","sourceRoot":"","sources":["../src/query-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAUH,qBAAa,UAAU;IACrB,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,QAAQ,CAAkB;IAElC,2EAA2E;IAC3E,OAAO,IAAI,OAAO;IAOlB,8CAA8C;IAC9C,iBAAiB,IAAI,IAAI;IAMzB,6FAA6F;IAC7F,QAAQ,IAAI,MAAM,GAAG,IAAI;IAQzB;;;OAGG;IACH,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAQhC,wDAAwD;IACxD,QAAQ,IAAI,IAAI;IAMhB,4DAA4D;IAC5D,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,kCAAkC;IAClC,IAAI,UAAU,IAAI,MAAM,CAEvB;IAID,SAAS,GAAI,UAAU,MAAM,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC,CAE9C;IAEF,WAAW,QAAO,OAAO,CAEvB;CACH"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Concurrency state machine — prevents re-entrant async operations.
3
+ *
4
+ * Tracks a 3-state lifecycle: idle → dispatching → running → idle.
5
+ * A generation counter ensures stale finally-blocks from cancelled
6
+ * queries don't corrupt cleanup.
7
+ *
8
+ * Inspired by Claude Code's `src/utils/QueryGuard.ts`.
9
+ */
10
+ import { createSignal } from "./signal.js";
11
+ // ─── Class ──────────────────────────────────────────────────────────
12
+ export class QueryGuard {
13
+ state = "idle";
14
+ _generation = 0;
15
+ _changed = createSignal();
16
+ /** Try to reserve the guard for a new operation. Returns false if busy. */
17
+ reserve() {
18
+ if (this.state !== "idle")
19
+ return false;
20
+ this.state = "dispatching";
21
+ this._changed.emit();
22
+ return true;
23
+ }
24
+ /** Cancel a reservation (go back to idle). */
25
+ cancelReservation() {
26
+ if (this.state !== "dispatching")
27
+ return;
28
+ this.state = "idle";
29
+ this._changed.emit();
30
+ }
31
+ /** Transition from dispatching to running. Returns generation or null if not dispatching. */
32
+ tryStart() {
33
+ if (this.state !== "dispatching")
34
+ return null;
35
+ this.state = "running";
36
+ this._generation++;
37
+ this._changed.emit();
38
+ return this._generation;
39
+ }
40
+ /**
41
+ * End a running operation. Only succeeds if the generation matches
42
+ * (prevents stale cleanups). Returns true if the guard was released.
43
+ */
44
+ end(generation) {
45
+ if (this.state !== "running")
46
+ return false;
47
+ if (generation !== this._generation)
48
+ return false;
49
+ this.state = "idle";
50
+ this._changed.emit();
51
+ return true;
52
+ }
53
+ /** Force the guard back to idle regardless of state. */
54
+ forceEnd() {
55
+ this.state = "idle";
56
+ this._generation++;
57
+ this._changed.emit();
58
+ }
59
+ /** Whether the guard is in dispatching or running state. */
60
+ get isActive() {
61
+ return this.state !== "idle";
62
+ }
63
+ /** Current generation counter. */
64
+ get generation() {
65
+ return this._generation;
66
+ }
67
+ // ─── useSyncExternalStore compatibility ───────────────────────
68
+ subscribe = (listener) => {
69
+ return this._changed.subscribe(listener);
70
+ };
71
+ getSnapshot = () => {
72
+ return this.isActive;
73
+ };
74
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Retry utility with exponential backoff and jitter.
3
+ *
4
+ * ZERO external dependencies — pure domain layer.
5
+ *
6
+ * Inspired by Claude Code's `withRetry.ts` pattern:
7
+ * - Exponential backoff with ±25% jitter
8
+ * - Foreground vs background retry profiles
9
+ * - AbortSignal-aware — bails immediately on abort
10
+ * - Delegates retryability decisions to `isRetryableError()`
11
+ */
12
+ /** Retry profile: foreground has fewer retries, background is more patient. */
13
+ export type RetrySource = "foreground" | "background";
14
+ /** Configuration for retry behavior. */
15
+ export interface RetryOptions {
16
+ /** Retry profile — controls default maxRetries. Default: 'foreground'. */
17
+ source?: RetrySource;
18
+ /** Maximum number of retry attempts. Foreground default: 3, background default: 10. */
19
+ maxRetries?: number;
20
+ /** Base delay in ms before first retry. Default: 500. */
21
+ baseDelayMs?: number;
22
+ /** Maximum delay cap in ms. Default: 8000. */
23
+ maxDelayMs?: number;
24
+ /** Abort signal — if aborted, throws immediately without retry. */
25
+ signal?: AbortSignal;
26
+ /** Custom predicate for retryable errors. Default: `isRetryableError` from ./errors.js. */
27
+ shouldRetry?: (error: unknown) => boolean;
28
+ }
29
+ /**
30
+ * Calculate delay for a given retry attempt with exponential backoff and jitter.
31
+ *
32
+ * Formula: `min(baseMs * 2^attempt, maxMs)` with ±25% random jitter.
33
+ *
34
+ * @param attempt - Zero-based attempt index (0 = first retry)
35
+ * @param baseMs - Base delay in milliseconds
36
+ * @param maxMs - Maximum delay cap in milliseconds
37
+ * @returns Delay in milliseconds with jitter applied
38
+ */
39
+ export declare function calculateDelay(attempt: number, baseMs: number, maxMs: number): number;
40
+ /**
41
+ * Execute an async function with automatic retries on transient failures.
42
+ *
43
+ * Uses exponential backoff with jitter, respects AbortSignal, and delegates
44
+ * retryability checks to `isRetryableError()` by default.
45
+ *
46
+ * @param fn - Async function to execute
47
+ * @param options - Retry configuration
48
+ * @returns The resolved value from `fn`
49
+ * @throws The last error if all retries are exhausted, or immediately on non-retryable/abort errors
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * const result = await withRetry(() => client.search(query), {
54
+ * source: 'foreground',
55
+ * signal: controller.signal,
56
+ * });
57
+ * ```
58
+ */
59
+ export declare function withRetry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
60
+ //# sourceMappingURL=retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,+EAA+E;AAC/E,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,YAAY,CAAC;AAEtD,wCAAwC;AACxC,MAAM,WAAW,YAAY;IAC3B,0EAA0E;IAC1E,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,uFAAuF;IACvF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,2FAA2F;IAC3F,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;CAC3C;AAID;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,MAAM,CAMR;AAID;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,CAAC,CAAC,CA2CZ"}
package/dist/retry.js ADDED
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Retry utility with exponential backoff and jitter.
3
+ *
4
+ * ZERO external dependencies — pure domain layer.
5
+ *
6
+ * Inspired by Claude Code's `withRetry.ts` pattern:
7
+ * - Exponential backoff with ±25% jitter
8
+ * - Foreground vs background retry profiles
9
+ * - AbortSignal-aware — bails immediately on abort
10
+ * - Delegates retryability decisions to `isRetryableError()`
11
+ */
12
+ import { isAbortError, isRetryableError } from "./errors.js";
13
+ import { sleep } from "./sleep.js";
14
+ // ─── Delay Calculation ──────────────────────────────────────────────
15
+ /**
16
+ * Calculate delay for a given retry attempt with exponential backoff and jitter.
17
+ *
18
+ * Formula: `min(baseMs * 2^attempt, maxMs)` with ±25% random jitter.
19
+ *
20
+ * @param attempt - Zero-based attempt index (0 = first retry)
21
+ * @param baseMs - Base delay in milliseconds
22
+ * @param maxMs - Maximum delay cap in milliseconds
23
+ * @returns Delay in milliseconds with jitter applied
24
+ */
25
+ export function calculateDelay(attempt, baseMs, maxMs) {
26
+ const exponential = baseMs * Math.pow(2, attempt);
27
+ const capped = Math.min(exponential, maxMs);
28
+ // ±25% jitter: multiply by random value in [0.75, 1.25]
29
+ const jitter = 0.75 + Math.random() * 0.5;
30
+ return Math.round(capped * jitter);
31
+ }
32
+ // ─── Core Retry Function ────────────────────────────────────────────
33
+ /**
34
+ * Execute an async function with automatic retries on transient failures.
35
+ *
36
+ * Uses exponential backoff with jitter, respects AbortSignal, and delegates
37
+ * retryability checks to `isRetryableError()` by default.
38
+ *
39
+ * @param fn - Async function to execute
40
+ * @param options - Retry configuration
41
+ * @returns The resolved value from `fn`
42
+ * @throws The last error if all retries are exhausted, or immediately on non-retryable/abort errors
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * const result = await withRetry(() => client.search(query), {
47
+ * source: 'foreground',
48
+ * signal: controller.signal,
49
+ * });
50
+ * ```
51
+ */
52
+ export async function withRetry(fn, options) {
53
+ const source = options?.source ?? "foreground";
54
+ const maxRetries = options?.maxRetries ?? (source === "background" ? 10 : 3);
55
+ const baseDelayMs = options?.baseDelayMs ?? 500;
56
+ const maxDelayMs = options?.maxDelayMs ?? 8000;
57
+ const signal = options?.signal;
58
+ const shouldRetry = options?.shouldRetry ?? isRetryableError;
59
+ let lastError;
60
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
61
+ // Check abort before each attempt
62
+ if (signal?.aborted) {
63
+ throw signal.reason ?? new Error("Operation aborted");
64
+ }
65
+ try {
66
+ return await fn();
67
+ }
68
+ catch (error) {
69
+ lastError = error;
70
+ // Never retry aborts
71
+ if (isAbortError(error)) {
72
+ throw error;
73
+ }
74
+ // Final attempt — no more retries
75
+ if (attempt >= maxRetries) {
76
+ break;
77
+ }
78
+ // Non-retryable error — throw immediately
79
+ if (!shouldRetry(error)) {
80
+ throw error;
81
+ }
82
+ // Wait with exponential backoff + jitter
83
+ const delay = calculateDelay(attempt, baseDelayMs, maxDelayMs);
84
+ await sleep(delay, signal);
85
+ }
86
+ }
87
+ throw lastError;
88
+ }
89
+ // sleep is imported from ./sleep.js
package/dist/schemas.d.ts CHANGED
@@ -71,12 +71,12 @@ export declare const RecordObservationInput: z.ZodObject<{
71
71
  }, "strip", z.ZodTypeAny, {
72
72
  file_patterns: string[];
73
73
  confidence: number;
74
- category: "architecture" | "bug_pattern" | "convention" | "performance" | "security" | "workflow" | "dependency" | "code_quality" | "other";
74
+ category: "security" | "architecture" | "bug_pattern" | "convention" | "performance" | "workflow" | "dependency" | "code_quality" | "other";
75
75
  tags: string[];
76
76
  summary: string;
77
77
  details?: string | undefined;
78
78
  }, {
79
- category: "architecture" | "bug_pattern" | "convention" | "performance" | "security" | "workflow" | "dependency" | "code_quality" | "other";
79
+ category: "security" | "architecture" | "bug_pattern" | "convention" | "performance" | "workflow" | "dependency" | "code_quality" | "other";
80
80
  summary: string;
81
81
  file_patterns?: string[] | undefined;
82
82
  confidence?: number | undefined;
@@ -114,13 +114,13 @@ export declare const ListLearningsInput: z.ZodObject<{
114
114
  limit: number;
115
115
  repo?: string | undefined;
116
116
  min_confidence?: number | undefined;
117
- category?: "decision" | "architecture" | "bug_pattern" | "convention" | "performance" | "security" | "workflow" | "domain_knowledge" | undefined;
117
+ category?: "security" | "decision" | "architecture" | "bug_pattern" | "convention" | "performance" | "workflow" | "domain_knowledge" | undefined;
118
118
  status?: "active" | "reinforced" | "contradicted" | "obsolete" | undefined;
119
119
  }, {
120
120
  repo?: string | undefined;
121
121
  limit?: number | undefined;
122
122
  min_confidence?: number | undefined;
123
- category?: "decision" | "architecture" | "bug_pattern" | "convention" | "performance" | "security" | "workflow" | "domain_knowledge" | undefined;
123
+ category?: "security" | "decision" | "architecture" | "bug_pattern" | "convention" | "performance" | "workflow" | "domain_knowledge" | undefined;
124
124
  status?: "active" | "reinforced" | "contradicted" | "obsolete" | undefined;
125
125
  }>;
126
126
  export type ListLearningsInput = z.infer<typeof ListLearningsInput>;
@@ -167,20 +167,20 @@ export declare const ReasoningEvent: z.ZodObject<{
167
167
  timestamp: z.ZodString;
168
168
  }, "strip", z.ZodTypeAny, {
169
169
  repo: string;
170
+ timestamp: string;
170
171
  id: string;
171
172
  agent_id: string;
172
173
  event_type: string;
173
174
  payload: Record<string, unknown>;
174
175
  session_id: string;
175
- timestamp: string;
176
176
  }, {
177
177
  repo: string;
178
+ timestamp: string;
178
179
  id: string;
179
180
  agent_id: string;
180
181
  event_type: string;
181
182
  payload: Record<string, unknown>;
182
183
  session_id: string;
183
- timestamp: string;
184
184
  }>;
185
185
  export type ReasoningEvent = z.infer<typeof ReasoningEvent>;
186
186
  export declare const Learning: z.ZodObject<{
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Secret detection scanner for content passing through the Oka Reason platform.
3
+ *
4
+ * ZERO external dependencies — pure domain layer.
5
+ *
6
+ * Inspired by Claude Code's `secretScanner.ts`. All patterns are high-confidence
7
+ * to minimise false positives. Regex compilation is lazy — patterns are compiled
8
+ * on first invocation and cached for the lifetime of the process.
9
+ *
10
+ * This module is pure detection. Callers decide whether to throw
11
+ * {@link SecretDetectedError}, redact, or log.
12
+ */
13
+ import type { SecretDetectedError } from "./errors.js";
14
+ export type { SecretDetectedError };
15
+ /** A single secret match found in content. */
16
+ export interface SecretMatch {
17
+ /** Human-readable name of the pattern that matched (e.g. "AWS Access Key"). */
18
+ patternName: string;
19
+ /** Start index of the match within the scanned string. */
20
+ startIndex: number;
21
+ /** End index (exclusive) of the match within the scanned string. */
22
+ endIndex: number;
23
+ }
24
+ /**
25
+ * Scan content for known secret patterns.
26
+ *
27
+ * Returns all matches found across every pattern. The same region of text
28
+ * may appear in multiple matches if it satisfies more than one pattern.
29
+ *
30
+ * @param content - The string to scan.
31
+ * @returns An array of {@link SecretMatch} objects (empty if clean).
32
+ */
33
+ export declare function scanForSecrets(content: string): SecretMatch[];
34
+ /**
35
+ * Fast-path check: does the content contain any secrets?
36
+ *
37
+ * Returns `true` on the first match without scanning the entire content
38
+ * against all patterns. Use this when you only need a boolean gate.
39
+ *
40
+ * @param content - The string to scan.
41
+ * @returns `true` if at least one secret pattern matches.
42
+ */
43
+ export declare function containsSecrets(content: string): boolean;
44
+ //# sourceMappingURL=secrets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secrets.d.ts","sourceRoot":"","sources":["../src/secrets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGvD,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAIpC,8CAA8C;AAC9C,MAAM,WAAW,WAAW;IAC1B,+EAA+E;IAC/E,WAAW,EAAE,MAAM,CAAC;IACpB,0DAA0D;IAC1D,UAAU,EAAE,MAAM,CAAC;IACnB,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAiFD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,CAmB7D;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAWxD"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Secret detection scanner for content passing through the Oka Reason platform.
3
+ *
4
+ * ZERO external dependencies — pure domain layer.
5
+ *
6
+ * Inspired by Claude Code's `secretScanner.ts`. All patterns are high-confidence
7
+ * to minimise false positives. Regex compilation is lazy — patterns are compiled
8
+ * on first invocation and cached for the lifetime of the process.
9
+ *
10
+ * This module is pure detection. Callers decide whether to throw
11
+ * {@link SecretDetectedError}, redact, or log.
12
+ */
13
+ /**
14
+ * Curated set of HIGH-CONFIDENCE secret patterns.
15
+ *
16
+ * Each entry uses a raw source string so that compilation can be deferred.
17
+ * Only patterns with very low false-positive rates are included.
18
+ */
19
+ const PATTERN_DEFS = [
20
+ {
21
+ name: "AWS Access Key",
22
+ source: "AKIA[0-9A-Z]{16}",
23
+ },
24
+ {
25
+ name: "GCP API Key",
26
+ source: "AIza[\\w-]{35}",
27
+ },
28
+ {
29
+ name: "GitHub Token",
30
+ source: "gh[ps]_[A-Za-z0-9_]{36,}",
31
+ },
32
+ {
33
+ name: "Anthropic API Key",
34
+ source: "sk-ant-api03-[\\w-]{90,}",
35
+ },
36
+ {
37
+ name: "OpenAI API Key",
38
+ source: "sk-proj-[\\w-]{40,}",
39
+ },
40
+ {
41
+ name: "Slack Token",
42
+ source: "xox[bpors]-[\\w-]{10,}",
43
+ },
44
+ {
45
+ name: "npm Token",
46
+ source: "npm_[a-zA-Z0-9]{36}",
47
+ },
48
+ {
49
+ name: "Generic Long Hex Secret",
50
+ source: "(?:secret|key|token|password)\\s*[:=]\\s*[\"']?[0-9a-fA-F]{64,}",
51
+ flags: "i",
52
+ },
53
+ {
54
+ name: "Private Key Block",
55
+ source: "-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----",
56
+ },
57
+ ];
58
+ let compiledPatterns = null;
59
+ /** Compile patterns on first use and cache them. */
60
+ function getPatterns() {
61
+ if (compiledPatterns !== null) {
62
+ return compiledPatterns;
63
+ }
64
+ compiledPatterns = PATTERN_DEFS.map((def) => ({
65
+ name: def.name,
66
+ regex: new RegExp(def.source, def.flags ? `g${def.flags}` : "g"),
67
+ }));
68
+ return compiledPatterns;
69
+ }
70
+ // ─── Public API ──────────────────────────────────────────────────────
71
+ /**
72
+ * Scan content for known secret patterns.
73
+ *
74
+ * Returns all matches found across every pattern. The same region of text
75
+ * may appear in multiple matches if it satisfies more than one pattern.
76
+ *
77
+ * @param content - The string to scan.
78
+ * @returns An array of {@link SecretMatch} objects (empty if clean).
79
+ */
80
+ export function scanForSecrets(content) {
81
+ const matches = [];
82
+ const patterns = getPatterns();
83
+ for (const { name, regex } of patterns) {
84
+ // Reset lastIndex for each scan (RegExp with `g` flag is stateful)
85
+ regex.lastIndex = 0;
86
+ let match;
87
+ while ((match = regex.exec(content)) !== null) {
88
+ matches.push({
89
+ patternName: name,
90
+ startIndex: match.index,
91
+ endIndex: match.index + match[0].length,
92
+ });
93
+ }
94
+ }
95
+ return matches;
96
+ }
97
+ /**
98
+ * Fast-path check: does the content contain any secrets?
99
+ *
100
+ * Returns `true` on the first match without scanning the entire content
101
+ * against all patterns. Use this when you only need a boolean gate.
102
+ *
103
+ * @param content - The string to scan.
104
+ * @returns `true` if at least one secret pattern matches.
105
+ */
106
+ export function containsSecrets(content) {
107
+ const patterns = getPatterns();
108
+ for (const { regex } of patterns) {
109
+ regex.lastIndex = 0;
110
+ if (regex.test(content)) {
111
+ return true;
112
+ }
113
+ }
114
+ return false;
115
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Zod preprocessors for model-generated tool inputs that quote
3
+ * booleans and numbers as strings.
4
+ *
5
+ * LLMs occasionally produce `"replace_all":"false"` instead of
6
+ * `"replace_all":false`. Standard z.coerce is too permissive
7
+ * (JS truthiness makes "false" → true). These preprocessors
8
+ * only coerce the exact string literals, rejecting everything else.
9
+ *
10
+ * Inspired by Claude Code's `src/utils/semanticBoolean.ts` and
11
+ * `src/utils/semanticNumber.ts`.
12
+ */
13
+ import { z } from "zod";
14
+ /**
15
+ * Boolean that also accepts the string literals "true" / "false".
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * semanticBoolean() // → boolean
20
+ * semanticBoolean(z.boolean().optional()) // → boolean | undefined
21
+ * semanticBoolean(z.boolean().default(false)) // → boolean
22
+ * ```
23
+ */
24
+ export declare function semanticBoolean<T extends z.ZodType>(inner?: T): z.ZodEffects<T, T["_output"], unknown>;
25
+ /**
26
+ * Number that also accepts numeric string literals like "30", "-5", "3.14".
27
+ *
28
+ * Only strings matching `/^-?\d+(\.\d+)?$/` are coerced. Anything else
29
+ * passes through and is rejected by the inner schema.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * semanticNumber() // → number
34
+ * semanticNumber(z.number().optional()) // → number | undefined
35
+ * semanticNumber(z.number().default(0)) // → number
36
+ * ```
37
+ */
38
+ export declare function semanticNumber<T extends z.ZodType>(inner?: T): z.ZodEffects<T, T["_output"], unknown>;
39
+ //# sourceMappingURL=semantic-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semantic-types.d.ts","sourceRoot":"","sources":["../src/semantic-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EACjD,KAAK,GAAE,CAA+B,0CAMvC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAChD,KAAK,GAAE,CAA8B,0CAStC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Zod preprocessors for model-generated tool inputs that quote
3
+ * booleans and numbers as strings.
4
+ *
5
+ * LLMs occasionally produce `"replace_all":"false"` instead of
6
+ * `"replace_all":false`. Standard z.coerce is too permissive
7
+ * (JS truthiness makes "false" → true). These preprocessors
8
+ * only coerce the exact string literals, rejecting everything else.
9
+ *
10
+ * Inspired by Claude Code's `src/utils/semanticBoolean.ts` and
11
+ * `src/utils/semanticNumber.ts`.
12
+ */
13
+ import { z } from "zod";
14
+ /**
15
+ * Boolean that also accepts the string literals "true" / "false".
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * semanticBoolean() // → boolean
20
+ * semanticBoolean(z.boolean().optional()) // → boolean | undefined
21
+ * semanticBoolean(z.boolean().default(false)) // → boolean
22
+ * ```
23
+ */
24
+ export function semanticBoolean(inner = z.boolean()) {
25
+ return z.preprocess((v) => (v === "true" ? true : v === "false" ? false : v), inner);
26
+ }
27
+ /**
28
+ * Number that also accepts numeric string literals like "30", "-5", "3.14".
29
+ *
30
+ * Only strings matching `/^-?\d+(\.\d+)?$/` are coerced. Anything else
31
+ * passes through and is rejected by the inner schema.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * semanticNumber() // → number
36
+ * semanticNumber(z.number().optional()) // → number | undefined
37
+ * semanticNumber(z.number().default(0)) // → number
38
+ * ```
39
+ */
40
+ export function semanticNumber(inner = z.number()) {
41
+ return z.preprocess((v) => {
42
+ if (typeof v === "string" && /^-?\d+(\.\d+)?$/.test(v)) {
43
+ const n = Number(v);
44
+ if (Number.isFinite(n))
45
+ return n;
46
+ }
47
+ return v;
48
+ }, inner);
49
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Serialize concurrent async calls into FIFO sequential execution.
3
+ *
4
+ * Wraps an async function so concurrent callers queue behind the
5
+ * in-flight invocation instead of racing.
6
+ *
7
+ * Inspired by Claude Code's `src/utils/sequential.ts`.
8
+ */
9
+ /**
10
+ * Create a sequential execution wrapper for an async function.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * const writeFile = sequential(fs.writeFile);
15
+ * // These execute one at a time, in order:
16
+ * writeFile("a.txt", "hello");
17
+ * writeFile("a.txt", "world");
18
+ * ```
19
+ */
20
+ export declare function sequential<T extends unknown[], R>(fn: (...args: T) => Promise<R>): (...args: T) => Promise<R>;
21
+ //# sourceMappingURL=sequential.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sequential.d.ts","sourceRoot":"","sources":["../src/sequential.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,OAAO,EAAE,EAAE,CAAC,EAC/C,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GAC7B,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAiC5B"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Serialize concurrent async calls into FIFO sequential execution.
3
+ *
4
+ * Wraps an async function so concurrent callers queue behind the
5
+ * in-flight invocation instead of racing.
6
+ *
7
+ * Inspired by Claude Code's `src/utils/sequential.ts`.
8
+ */
9
+ /**
10
+ * Create a sequential execution wrapper for an async function.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * const writeFile = sequential(fs.writeFile);
15
+ * // These execute one at a time, in order:
16
+ * writeFile("a.txt", "hello");
17
+ * writeFile("a.txt", "world");
18
+ * ```
19
+ */
20
+ export function sequential(fn) {
21
+ const queue = [];
22
+ let processing = false;
23
+ async function processQueue() {
24
+ if (processing || queue.length === 0)
25
+ return;
26
+ processing = true;
27
+ while (queue.length > 0) {
28
+ const { args, resolve, reject, context } = queue.shift();
29
+ try {
30
+ const result = await fn.apply(context, args);
31
+ resolve(result);
32
+ }
33
+ catch (error) {
34
+ reject(error);
35
+ }
36
+ }
37
+ processing = false;
38
+ // Check if new items were added while we were processing
39
+ if (queue.length > 0) {
40
+ void processQueue();
41
+ }
42
+ }
43
+ return function (...args) {
44
+ return new Promise((resolve, reject) => {
45
+ queue.push({ args, resolve, reject, context: this });
46
+ void processQueue();
47
+ });
48
+ };
49
+ }