@oka-core/reason 0.2.15 → 0.2.17
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.
- package/dist/abort-controller.d.ts +19 -0
- package/dist/abort-controller.d.ts.map +1 -0
- package/dist/abort-controller.js +53 -0
- package/dist/activity-tracker.d.ts +48 -0
- package/dist/activity-tracker.d.ts.map +1 -0
- package/dist/activity-tracker.js +80 -0
- package/dist/analytics.d.ts +49 -0
- package/dist/analytics.d.ts.map +1 -0
- package/dist/analytics.js +88 -0
- package/dist/array.d.ts +12 -0
- package/dist/array.d.ts.map +1 -0
- package/dist/array.js +20 -0
- package/dist/async-context.d.ts +20 -0
- package/dist/async-context.d.ts.map +1 -0
- package/dist/async-context.js +25 -0
- package/dist/binary-check.d.ts +16 -0
- package/dist/binary-check.d.ts.map +1 -0
- package/dist/binary-check.js +43 -0
- package/dist/buffered-writer.d.ts +30 -0
- package/dist/buffered-writer.d.ts.map +1 -0
- package/dist/buffered-writer.js +87 -0
- package/dist/circular-buffer.d.ts +28 -0
- package/dist/circular-buffer.d.ts.map +1 -0
- package/dist/circular-buffer.js +61 -0
- package/dist/cleanup-registry.d.ts +23 -0
- package/dist/cleanup-registry.d.ts.map +1 -0
- package/dist/cleanup-registry.js +34 -0
- package/dist/client.d.ts +4 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +32 -10
- package/dist/combined-abort-signal.d.ts +25 -0
- package/dist/combined-abort-signal.d.ts.map +1 -0
- package/dist/combined-abort-signal.js +47 -0
- package/dist/cron-lock.d.ts +29 -0
- package/dist/cron-lock.d.ts.map +1 -0
- package/dist/cron-lock.js +127 -0
- package/dist/cron-scheduler.d.ts +41 -0
- package/dist/cron-scheduler.d.ts.map +1 -0
- package/dist/cron-scheduler.js +189 -0
- package/dist/cron-tasks.d.ts +86 -0
- package/dist/cron-tasks.d.ts.map +1 -0
- package/dist/cron-tasks.js +205 -0
- package/dist/cron.d.ts +35 -0
- package/dist/cron.d.ts.map +1 -0
- package/dist/cron.js +215 -0
- package/dist/env.d.ts +26 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +50 -0
- package/dist/errors.d.ts +99 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +214 -0
- package/dist/format.d.ts +21 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +48 -0
- package/dist/fps-tracker.d.ts +22 -0
- package/dist/fps-tracker.d.ts.map +1 -0
- package/dist/fps-tracker.js +44 -0
- package/dist/graceful-shutdown.d.ts +35 -0
- package/dist/graceful-shutdown.d.ts.map +1 -0
- package/dist/graceful-shutdown.js +89 -0
- package/dist/hash.d.ts +21 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +31 -0
- package/dist/heap-diagnostics.d.ts +68 -0
- package/dist/heap-diagnostics.d.ts.map +1 -0
- package/dist/heap-diagnostics.js +110 -0
- package/dist/idle-timeout.d.ts +21 -0
- package/dist/idle-timeout.d.ts.map +1 -0
- package/dist/idle-timeout.js +42 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -0
- package/dist/intl.d.ts +18 -0
- package/dist/intl.d.ts.map +1 -0
- package/dist/intl.js +75 -0
- package/dist/jsonl.d.ts +16 -0
- package/dist/jsonl.d.ts.map +1 -0
- package/dist/jsonl.js +60 -0
- package/dist/lazy-schema.d.ts +6 -0
- package/dist/lazy-schema.d.ts.map +1 -0
- package/dist/lazy-schema.js +8 -0
- package/dist/memo.d.ts +64 -0
- package/dist/memo.d.ts.map +1 -0
- package/dist/memo.js +162 -0
- package/dist/pkce.d.ts +13 -0
- package/dist/pkce.d.ts.map +1 -0
- package/dist/pkce.js +28 -0
- package/dist/priority-queue.d.ts +36 -0
- package/dist/priority-queue.d.ts.map +1 -0
- package/dist/priority-queue.js +97 -0
- package/dist/process-utils.d.ts +20 -0
- package/dist/process-utils.d.ts.map +1 -0
- package/dist/process-utils.js +54 -0
- package/dist/query-guard.d.ts +34 -0
- package/dist/query-guard.d.ts.map +1 -0
- package/dist/query-guard.js +74 -0
- package/dist/retry.d.ts +60 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +89 -0
- package/dist/schemas.d.ts +6 -6
- package/dist/secrets.d.ts +44 -0
- package/dist/secrets.d.ts.map +1 -0
- package/dist/secrets.js +115 -0
- package/dist/semantic-types.d.ts +39 -0
- package/dist/semantic-types.d.ts.map +1 -0
- package/dist/semantic-types.js +49 -0
- package/dist/sequential.d.ts +21 -0
- package/dist/sequential.d.ts.map +1 -0
- package/dist/sequential.js +49 -0
- package/dist/signal.d.ts +29 -0
- package/dist/signal.d.ts.map +1 -0
- package/dist/signal.js +39 -0
- package/dist/sleep.d.ts +21 -0
- package/dist/sleep.d.ts.map +1 -0
- package/dist/sleep.js +58 -0
- package/dist/slow-ops.d.ts +41 -0
- package/dist/slow-ops.d.ts.map +1 -0
- package/dist/slow-ops.js +133 -0
- package/dist/store.d.ts +20 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +34 -0
- package/dist/stream.d.ts +29 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +92 -0
- package/dist/string-utils.d.ts +46 -0
- package/dist/string-utils.d.ts.map +1 -0
- package/dist/string-utils.js +69 -0
- package/dist/strip-bom.d.ts +8 -0
- package/dist/strip-bom.d.ts.map +1 -0
- package/dist/strip-bom.js +10 -0
- package/dist/subprocess-env.d.ts +25 -0
- package/dist/subprocess-env.d.ts.map +1 -0
- package/dist/subprocess-env.js +55 -0
- package/dist/telemetry.d.ts +16 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +61 -0
- package/dist/temp-file.d.ts +18 -0
- package/dist/temp-file.d.ts.map +1 -0
- package/dist/temp-file.js +26 -0
- package/dist/tool-contract.d.ts +85 -0
- package/dist/tool-contract.d.ts.map +1 -0
- package/dist/tool-contract.js +101 -0
- package/dist/tools/read.d.ts +2 -10
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +662 -537
- package/dist/tools/write.d.ts +3 -2
- package/dist/tools/write.d.ts.map +1 -1
- package/dist/tools/write.js +329 -177
- package/dist/uuid.d.ts +20 -0
- package/dist/uuid.d.ts.map +1 -0
- package/dist/uuid.js +28 -0
- package/dist/validation.d.ts +64 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +236 -0
- package/dist/with-resolvers.d.ts +12 -0
- package/dist/with-resolvers.d.ts.map +1 -0
- package/dist/with-resolvers.js +14 -0
- package/dist/xml-escape.d.ts +12 -0
- package/dist/xml-escape.d.ts.map +1 -0
- package/dist/xml-escape.js +15 -0
- package/package.json +8 -1
|
@@ -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
|
+
}
|
package/dist/retry.d.ts
ADDED
|
@@ -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: "
|
|
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: "
|
|
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" | "
|
|
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" | "
|
|
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"}
|
package/dist/secrets.js
ADDED
|
@@ -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
|
+
}
|
package/dist/signal.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed event signal primitive — zero external dependencies.
|
|
3
|
+
*
|
|
4
|
+
* Collapses the ~8-line `new Set(); subscribe/notify` boilerplate into a
|
|
5
|
+
* reusable, typed primitive. Compatible with React's `useSyncExternalStore`.
|
|
6
|
+
*
|
|
7
|
+
* Inspired by Claude Code's `src/utils/signal.ts`.
|
|
8
|
+
*/
|
|
9
|
+
export type Signal<Args extends unknown[] = []> = {
|
|
10
|
+
/** Subscribe a listener. Returns an unsubscribe function. */
|
|
11
|
+
subscribe: (listener: (...args: Args) => void) => () => void;
|
|
12
|
+
/** Emit to all subscribed listeners synchronously. */
|
|
13
|
+
emit: (...args: Args) => void;
|
|
14
|
+
/** Remove all listeners. */
|
|
15
|
+
clear: () => void;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Create a typed event signal.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* const changed = createSignal<[newValue: number]>();
|
|
23
|
+
* const unsub = changed.subscribe((v) => console.log(v));
|
|
24
|
+
* changed.emit(42); // logs 42
|
|
25
|
+
* unsub();
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare function createSignal<Args extends unknown[] = []>(): Signal<Args>;
|
|
29
|
+
//# sourceMappingURL=signal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signal.d.ts","sourceRoot":"","sources":["../src/signal.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,MAAM,MAAM,CAAC,IAAI,SAAS,OAAO,EAAE,GAAG,EAAE,IAAI;IAChD,6DAA6D;IAC7D,SAAS,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IAC7D,sDAAsD;IACtD,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC9B,4BAA4B;IAC5B,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AAIF;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,IAAI,SAAS,OAAO,EAAE,GAAG,EAAE,KAAK,MAAM,CAAC,IAAI,CAAC,CAmBxE"}
|