@wrongstack/core 0.309.0 → 0.310.0
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/chronicle/index.js +113 -41
- package/dist/chronicle/metrics-ingest.d.ts +7 -0
- package/dist/chronicle/metrics-schema.d.ts +4 -1
- package/dist/chronicle/project-server.js +94 -38
- package/dist/chronicle/query.d.ts +1 -0
- package/dist/chronicle/sqlite-journal-schema.d.ts +2 -1
- package/dist/chronicle/types.d.ts +2 -0
- package/dist/{agent-status-helpers.d.ts → coordination/agent-status-helpers.d.ts} +1 -1
- package/dist/{agent-status-tracker.d.ts → coordination/agent-status-tracker.d.ts} +2 -2
- package/dist/{middleware → coordination}/collab-pause.d.ts +1 -1
- package/dist/coordination/director-kanban-queue-helpers.d.ts +1 -1
- package/dist/coordination/director.d.ts +7 -0
- package/dist/coordination/explore-companion.d.ts +9 -6
- package/dist/coordination/fleet-status-tool.d.ts +1 -1
- package/dist/coordination/index.d.ts +5 -1
- package/dist/coordination/index.js +2392 -405
- package/dist/coordination/kanban-dispatch-port.d.ts +30 -0
- package/dist/coordination/kanban-ops-port.d.ts +21 -0
- package/dist/coordination/mailbox-hooks.d.ts +1 -1
- package/dist/coordination/mailbox-project-server.js +14 -9
- package/dist/coordination/mutation-engine.d.ts +5 -3
- package/dist/core/context.d.ts +35 -44
- package/dist/core/conversation-state.d.ts +16 -52
- package/dist/core/index.js +92 -25
- package/dist/core/provider-runner.d.ts +2 -2
- package/dist/core/run-env.d.ts +7 -28
- package/dist/core/streaming-response-builder.d.ts +2 -2
- package/dist/execution/index.js +138 -162
- package/dist/goal/index.js +100 -22
- package/dist/hq/auth-store.d.ts +9 -0
- package/dist/hq/cost-bridge.d.ts +1 -1
- package/dist/hq/index.js +69 -7
- package/dist/index.d.ts +12 -5
- package/dist/index.js +21185 -26807
- package/dist/infrastructure/index.js +232 -135
- package/dist/infrastructure/provider-cache-ledger.d.ts +1 -1
- package/dist/infrastructure/token-counter.d.ts +5 -1
- package/dist/kernel/events/file-events.d.ts +6 -0
- package/dist/kernel/events/provider-events.d.ts +10 -7
- package/dist/kernel/events/session-events.d.ts +4 -4
- package/dist/kernel/events/tool-events.d.ts +12 -2
- package/dist/observability/index.js +1 -1
- package/dist/plugin/index.js +218 -47
- package/dist/prompts/index.js +360 -3
- package/dist/security/auto-approve-policy.d.ts +2 -2
- package/dist/security/index.d.ts +1 -0
- package/dist/security/index.js +224 -68
- package/dist/security/kanban-boundary.d.ts +1 -1
- package/dist/security/kanban-governance-port.d.ts +28 -0
- package/dist/security/permission-helpers.d.ts +11 -0
- package/dist/security/permission-policy.d.ts +10 -1
- package/dist/security/yolo-risk.d.ts +17 -0
- package/dist/session-catalog/index.js +34 -5
- package/dist/session-catalog/project-server.js +34 -5
- package/dist/session-catalog/protocol.d.ts +1 -1
- package/dist/session-catalog/registry.d.ts +1 -1
- package/dist/session-catalog/store-schema.d.ts +1 -1
- package/dist/session-catalog/store.d.ts +1 -1
- package/dist/skills/index.js +39 -6
- package/dist/storage/annotations-store.d.ts +1 -1
- package/dist/storage/board-store-port.d.ts +45 -0
- package/dist/storage/completed-work-checkpoint.d.ts +1 -1
- package/dist/storage/config-loader/types.d.ts +1 -1
- package/dist/storage/event-bus-port.d.ts +27 -0
- package/dist/storage/file-session-writer.d.ts +47 -5
- package/dist/storage/goal-coordination.d.ts +1 -1
- package/dist/storage/goal-store.d.ts +1 -1
- package/dist/storage/index.d.ts +3 -4
- package/dist/storage/index.js +1107 -1462
- package/dist/storage/plan-store.d.ts +1 -1
- package/dist/storage/queue-store.d.ts +1 -1
- package/dist/storage/replay-log-store.d.ts +1 -1
- package/dist/storage/session-recovery.d.ts +10 -0
- package/dist/storage/session-resume-validation.d.ts +13 -1
- package/dist/storage/session-store/events.d.ts +1 -1
- package/dist/storage/session-store/load-session-data.d.ts +1 -1
- package/dist/storage/session-store/rename-session.d.ts +1 -1
- package/dist/storage/session-store/resume-session.d.ts +3 -1
- package/dist/storage/session-store/session-store-index.d.ts +2 -1
- package/dist/storage/session-store/types.d.ts +1 -1
- package/dist/storage/session-store.d.ts +70 -0
- package/dist/storage/session-summary-tracker.d.ts +8 -0
- package/dist/storage/session-write-buffer.d.ts +31 -2
- package/dist/storage/task-store.d.ts +1 -1
- package/dist/storage/todos-checkpoint.d.ts +1 -1
- package/dist/storage/tool-audit-log.d.ts +1 -1
- package/dist/tasking/index.js +100 -22
- package/dist/tasking/task-tracker.d.ts +24 -1
- package/dist/types/compactor.d.ts +2 -2
- package/dist/types/context.d.ts +212 -0
- package/dist/types/conversation-state.d.ts +109 -0
- package/dist/types/error-handler.d.ts +2 -2
- package/dist/types/file-event-record.d.ts +6 -0
- package/dist/types/index.d.ts +3 -3
- package/dist/types/index.js +17 -1
- package/dist/types/permission.d.ts +3 -3
- package/dist/types/plugin.d.ts +3 -3
- package/dist/types/provider-runner.d.ts +2 -2
- package/dist/types/provider.d.ts +10 -0
- package/dist/types/run-env.d.ts +32 -0
- package/dist/types/session.d.ts +3 -0
- package/dist/types/slash-command.d.ts +2 -2
- package/dist/types/token-counter.d.ts +30 -1
- package/dist/types/tool-executor.d.ts +2 -2
- package/dist/types/tool.d.ts +20 -5
- package/dist/utils/context-breakdown.d.ts +2 -2
- package/dist/utils/context-evidence.d.ts +12 -12
- package/dist/utils/crash-shield.d.ts +9 -0
- package/dist/utils/heap-watchdog.js +11 -3
- package/dist/utils/index.d.ts +2 -1
- package/dist/utils/index.js +126 -160
- package/dist/utils/regex-guard.d.ts +7 -30
- package/dist/utils/terminal-sanitize.d.ts +41 -0
- package/dist/utils/todos-format.d.ts +1 -1
- package/dist/utils/tool-subject.d.ts +1 -1
- package/dist/utils/tree-kill.d.ts +2 -0
- package/dist/utils/tree-kill.js +1 -0
- package/instructions/agents/chaos-monkey.md +5 -1
- package/instructions/coordination/subagent-baseline.md +10 -0
- package/instructions/system-lite.md +2 -0
- package/instructions/system-pro.md +40 -0
- package/instructions/system.md +15 -0
- package/package.json +7 -10
- package/dist/defaults/index.d.ts +0 -69
- package/dist/defaults/index.js +0 -37755
- /package/dist/{fleet-notifier.d.ts → coordination/fleet-notifier.d.ts} +0 -0
- /package/dist/{session-registry-atomic-file.d.ts → session-catalog/session-registry-atomic-file.d.ts} +0 -0
- /package/dist/{session-registry-types.d.ts → session-catalog/session-registry-types.d.ts} +0 -0
- /package/dist/{session-registry.d.ts → session-catalog/session-registry.d.ts} +0 -0
package/dist/types/tool.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AgentContext } from './context.js';
|
|
2
2
|
export type Permission = 'auto' | 'confirm' | 'deny';
|
|
3
3
|
/**
|
|
4
4
|
* Risk tier for tools in UI/audit surfaces. YOLO auto-approves non-denied
|
|
@@ -101,6 +101,21 @@ export interface Tool<I = unknown, O = unknown> {
|
|
|
101
101
|
* fall back to the heuristic.
|
|
102
102
|
*/
|
|
103
103
|
subjectKey?: string | undefined;
|
|
104
|
+
/**
|
|
105
|
+
* Extra input fields folded into the permission subject, after `subjectKey`.
|
|
106
|
+
*
|
|
107
|
+
* For a shell-style tool the subject is the whole command line, so the trust
|
|
108
|
+
* rule is as specific as the invocation. A tool whose parameters are NAMED
|
|
109
|
+
* FIELDS rather than an argv array has no such luck: `git` sets
|
|
110
|
+
* `subjectKey: 'command'`, whose value is an enum subcommand, so every
|
|
111
|
+
* `git push` — any branch, `force` or not — rendered to the subject `"push"`
|
|
112
|
+
* and one "always allow" covered them all (audit 2026-08-20).
|
|
113
|
+
*
|
|
114
|
+
* List the fields that change what the call actually does. Absent fields are
|
|
115
|
+
* skipped, so adding a field only narrows existing rules (they degrade to a
|
|
116
|
+
* confirm prompt) and never silently widens one.
|
|
117
|
+
*/
|
|
118
|
+
subjectFields?: readonly string[] | undefined;
|
|
104
119
|
maxOutputBytes?: number | undefined;
|
|
105
120
|
timeoutMs?: number | undefined;
|
|
106
121
|
/**
|
|
@@ -135,7 +150,7 @@ export interface Tool<I = unknown, O = unknown> {
|
|
|
135
150
|
* Each UI maps this id to its own icon library.
|
|
136
151
|
*/
|
|
137
152
|
icon?: ToolIconId | undefined;
|
|
138
|
-
execute(input: I, ctx:
|
|
153
|
+
execute(input: I, ctx: AgentContext, opts: {
|
|
139
154
|
signal: AbortSignal;
|
|
140
155
|
}): Promise<O>;
|
|
141
156
|
/**
|
|
@@ -161,7 +176,7 @@ export interface Tool<I = unknown, O = unknown> {
|
|
|
161
176
|
* have intermediate state shouldn't implement this; the default `execute`
|
|
162
177
|
* path is more efficient.
|
|
163
178
|
*/
|
|
164
|
-
executeStream?(input: I, ctx:
|
|
179
|
+
executeStream?(input: I, ctx: AgentContext, opts: {
|
|
165
180
|
signal: AbortSignal;
|
|
166
181
|
}): AsyncIterable<ToolStreamEvent<O>>;
|
|
167
182
|
/**
|
|
@@ -207,7 +222,7 @@ export interface Tool<I = unknown, O = unknown> {
|
|
|
207
222
|
* Avoid double-free by gating one on the other's effect, or pick a single
|
|
208
223
|
* teardown channel per resource.
|
|
209
224
|
*/
|
|
210
|
-
cleanup?(input: I, ctx:
|
|
225
|
+
cleanup?(input: I, ctx: AgentContext): Promise<void>;
|
|
211
226
|
/**
|
|
212
227
|
* Optional custom output serializer. When present, the executor's output
|
|
213
228
|
* serializer calls this INSTEAD of the central `renderToolObject()` switch
|
|
@@ -228,7 +243,7 @@ export interface ToolCallContext {
|
|
|
228
243
|
tool: Tool;
|
|
229
244
|
input: unknown;
|
|
230
245
|
callId: string;
|
|
231
|
-
ctx:
|
|
246
|
+
ctx: AgentContext;
|
|
232
247
|
signal: AbortSignal;
|
|
233
248
|
}
|
|
234
249
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AgentContext } from '../types/context.js';
|
|
2
2
|
import { type SystemBlockSource } from '../core/system-prompt-builder.js';
|
|
3
3
|
/**
|
|
4
4
|
* Real, per-category token accounting for the live context window — the data
|
|
@@ -61,5 +61,5 @@ export interface ContextBreakdown {
|
|
|
61
61
|
* interactively (e.g. from `/context`): it walks the full message array once, so
|
|
62
62
|
* it is O(messages·blocks), not the O(1) cached path the per-turn bar uses.
|
|
63
63
|
*/
|
|
64
|
-
export declare function getContextBreakdown(ctx:
|
|
64
|
+
export declare function getContextBreakdown(ctx: AgentContext): ContextBreakdown;
|
|
65
65
|
//# sourceMappingURL=context-breakdown.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AgentContext } from '../types/context.js';
|
|
2
2
|
import { type TextBlock } from '../types/blocks.js';
|
|
3
3
|
import type { CompactReport } from '../types/compactor.js';
|
|
4
4
|
import type { CompletedWorkEvidence, CompletedWorkSource, ContextEvidenceState, ToolOutputMetadata } from '../types/context-evidence.js';
|
|
@@ -13,7 +13,7 @@ export interface RecordToolOutputEvidenceInput {
|
|
|
13
13
|
outputTokens?: number | undefined;
|
|
14
14
|
outputLines?: number | undefined;
|
|
15
15
|
}
|
|
16
|
-
export declare function recordUserIntentEvidence(ctx:
|
|
16
|
+
export declare function recordUserIntentEvidence(ctx: AgentContext, text: string): void;
|
|
17
17
|
/** Runtime steering/status blocks must not displace real conversation turns. */
|
|
18
18
|
export declare function isRuntimeContextInput(text: string): boolean;
|
|
19
19
|
/**
|
|
@@ -25,11 +25,11 @@ export declare function isRuntimeContextInput(text: string): boolean;
|
|
|
25
25
|
* It is volatile provider evidence, so it never grows the durable chat log or
|
|
26
26
|
* invalidates the cached base prompt.
|
|
27
27
|
*/
|
|
28
|
-
export declare function buildConversationContinuityBlock(ctx: Pick<
|
|
29
|
-
export declare function recordToolOutputEvidence(ctx:
|
|
30
|
-
export declare function markAssistantReferencedEvidence(ctx:
|
|
31
|
-
export declare function buildContextEvidenceDigest(ctx:
|
|
32
|
-
export declare function repeatedReadPressure(ctx:
|
|
28
|
+
export declare function buildConversationContinuityBlock(ctx: Pick<AgentContext, 'contextEvidence' | 'messages'>): TextBlock | undefined;
|
|
29
|
+
export declare function recordToolOutputEvidence(ctx: AgentContext, input: RecordToolOutputEvidenceInput): ToolOutputMetadata;
|
|
30
|
+
export declare function markAssistantReferencedEvidence(ctx: AgentContext, text: string): void;
|
|
31
|
+
export declare function buildContextEvidenceDigest(ctx: AgentContext): string;
|
|
32
|
+
export declare function repeatedReadPressure(ctx: AgentContext): number;
|
|
33
33
|
/**
|
|
34
34
|
* Deterministic post-compaction sanity check. Cheap and local: records whether
|
|
35
35
|
* the compacted context still carries an intent anchor and a tool/path trail.
|
|
@@ -37,7 +37,7 @@ export declare function repeatedReadPressure(ctx: Context): number;
|
|
|
37
37
|
* only HybridCompactor did). Advisory on its own — pair with
|
|
38
38
|
* `injectEvidenceFloor` to actually repair a flagged loss.
|
|
39
39
|
*/
|
|
40
|
-
export declare function checkCompactionQuality(ctx:
|
|
40
|
+
export declare function checkCompactionQuality(ctx: AgentContext, opts: {
|
|
41
41
|
collapsedDigest?: string | undefined;
|
|
42
42
|
evidenceDigest?: string | undefined;
|
|
43
43
|
reduced: boolean;
|
|
@@ -50,7 +50,7 @@ export declare function checkCompactionQuality(ctx: Context, opts: {
|
|
|
50
50
|
* no-op when quality is fine or there is no evidence to inject. Returns true
|
|
51
51
|
* when it injected a block (so the caller re-estimates tokens).
|
|
52
52
|
*/
|
|
53
|
-
export declare function injectEvidenceFloor(ctx:
|
|
53
|
+
export declare function injectEvidenceFloor(ctx: AgentContext, quality: CompactReport['quality'] | undefined): boolean;
|
|
54
54
|
/** Marker prefixing the ledger's system-prompt block (also used to find/replace it). */
|
|
55
55
|
export declare const COMPLETED_WORK_LEDGER_MARKER = "[completed_work_ledger]";
|
|
56
56
|
export interface RecordCompletedWorkInput {
|
|
@@ -68,14 +68,14 @@ export interface RecordCompletedWorkInput {
|
|
|
68
68
|
* composer renders this state as a volatile tail block; the stable system-prompt
|
|
69
69
|
* prefix is never mutated here.
|
|
70
70
|
*/
|
|
71
|
-
export declare function recordCompletedWorkEvidence(ctx:
|
|
71
|
+
export declare function recordCompletedWorkEvidence(ctx: AgentContext, input: RecordCompletedWorkInput): CompletedWorkEvidence;
|
|
72
72
|
/** Render the ledger's system-prompt block text (marker + newest entries). */
|
|
73
73
|
export declare function formatCompletedWorkLedger(items: readonly CompletedWorkEvidence[]): string;
|
|
74
74
|
/** Build the current volatile completed-work block without mutating the prompt. */
|
|
75
|
-
export declare function buildCompletedWorkLedgerBlock(ctx:
|
|
75
|
+
export declare function buildCompletedWorkLedgerBlock(ctx: AgentContext): TextBlock | undefined;
|
|
76
76
|
/**
|
|
77
77
|
* @deprecated Volatile state must be composed at request time. Kept as a
|
|
78
78
|
* compatibility no-op for embedders importing the old helper.
|
|
79
79
|
*/
|
|
80
|
-
export declare function syncCompletedWorkLedgerBlock(_ctx:
|
|
80
|
+
export declare function syncCompletedWorkLedgerBlock(_ctx: AgentContext): void;
|
|
81
81
|
//# sourceMappingURL=context-evidence.d.ts.map
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/** Register a synchronous salvage hook. Returns an unregister function. */
|
|
2
|
+
export declare function addFatalSalvageHook(hook: () => void): () => void;
|
|
3
|
+
/**
|
|
4
|
+
* Run every registered salvage hook once. Swallows individual hook failures
|
|
5
|
+
* so one broken hook cannot skip the remaining ones. Safe to call multiple
|
|
6
|
+
* times — hooks are expected to be idempotent (a drained buffer stays
|
|
7
|
+
* drained).
|
|
8
|
+
*/
|
|
9
|
+
export declare function runFatalSalvageSync(): void;
|
|
1
10
|
interface CrashShieldTarget {
|
|
2
11
|
on(event: 'unhandledRejection' | 'uncaughtException', listener: (reason: unknown) => void): unknown;
|
|
3
12
|
off(event: 'unhandledRejection' | 'uncaughtException', listener: (reason: unknown) => void): unknown;
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as fsp2 from "node:fs/promises";
|
|
4
4
|
import * as path3 from "node:path";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
PerformanceObserver,
|
|
7
|
+
constants as performanceConstants
|
|
8
|
+
} from "node:perf_hooks";
|
|
6
9
|
import * as v8 from "node:v8";
|
|
7
10
|
|
|
8
11
|
// src/utils/memory-flight-recorder.ts
|
|
@@ -308,7 +311,8 @@ function createMemoryFlightRecorder(options = {}) {
|
|
|
308
311
|
const now = options.now ?? Date.now;
|
|
309
312
|
const startedAt = now();
|
|
310
313
|
const root = options.diagnosticsRoot ?? path2.join(wstackGlobalRoot(), "diagnostics", "memory");
|
|
311
|
-
const
|
|
314
|
+
const isBunRuntime = typeof globalThis.Bun !== "undefined";
|
|
315
|
+
const enabled = options.enabled ?? (!isBunRuntime && process.env["WRONGSTACK_MEMORY_FLIGHT_RECORDER"] !== "0" && process.env["NODE_ENV"] !== "test");
|
|
312
316
|
const writer = options.captureWriter ?? (enabled ? new ContinuousMemoryCaptureWriter(root) : disabledWriter(path2.join(root, `${timestampSlug()}-pid-${process.pid}`)));
|
|
313
317
|
const observations = [];
|
|
314
318
|
const windowMs = options.windowMs ?? DEFAULT_WINDOW_MS;
|
|
@@ -418,7 +422,11 @@ function defaultHeapLogPath() {
|
|
|
418
422
|
function takeHeapSample() {
|
|
419
423
|
const m = process.memoryUsage();
|
|
420
424
|
const heap = v8.getHeapStatistics();
|
|
421
|
-
|
|
425
|
+
let spaces = [];
|
|
426
|
+
try {
|
|
427
|
+
spaces = v8.getHeapSpaceStatistics();
|
|
428
|
+
} catch {
|
|
429
|
+
}
|
|
422
430
|
const spaceUsed = (name) => spaces.find((space) => space.space_name === name)?.space_used_size ?? 0;
|
|
423
431
|
const limit = heap.heap_size_limit || 0;
|
|
424
432
|
let activeResources = 0;
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export * from './config-backup.js';
|
|
|
7
7
|
export * from './config-json.js';
|
|
8
8
|
export { checkConnectivity, resetConnectivityCache } from './connectivity.js';
|
|
9
9
|
export { type ContextBreakdown, getContextBreakdown } from './context-breakdown.js';
|
|
10
|
-
export { type CrashShieldOptions, installCrashShield } from './crash-shield.js';
|
|
10
|
+
export { addFatalSalvageHook, runFatalSalvageSync, type CrashShieldOptions, installCrashShield, } from './crash-shield.js';
|
|
11
11
|
export { buildCompletedWorkLedgerBlock, buildContextEvidenceDigest, COMPLETED_WORK_LEDGER_MARKER, createContextEvidenceState, formatCompletedWorkLedger, markAssistantReferencedEvidence, type RecordCompletedWorkInput, type RecordToolOutputEvidenceInput, recordCompletedWorkEvidence, recordToolOutputEvidence, recordUserIntentEvidence, repeatedReadPressure, syncCompletedWorkLedgerBlock, } from './context-evidence.js';
|
|
12
12
|
export { type DeepMergeOptions, deepMerge, FORBIDDEN_PROTO_KEYS, isPrimitiveArray, } from './deep-merge.js';
|
|
13
13
|
export * from './diff.js';
|
|
@@ -44,6 +44,7 @@ export { withSqliteExperimentalWarningSuppressed } from './sqlite-warning.js';
|
|
|
44
44
|
export * from './string.js';
|
|
45
45
|
export * from './task-format.js';
|
|
46
46
|
export { buildSgrSequence, buildTitleSequence, type ColorDepth, detectTerminal, ESCAPE_TERMINATOR, type EscapeEmitResult, type EscapeSequence, isStdinTTY, type MouseProtocol, onResize, safeEmit, setOutputLineGuard, setRawMode, setTitle, type TerminalCapability, TerminalLifecycle, writeErr, writeOut, } from './term.js';
|
|
47
|
+
export { sanitizeTerminalPreview, sanitizeTerminalText } from './terminal-sanitize.js';
|
|
47
48
|
export * from './todos-format.js';
|
|
48
49
|
export { computeMessageTokens, estimateMessageTokens, estimateRequestTokens, estimateRequestTokensCalibrated, estimateTextTokens, estimateToolDefTokens, estimateToolInputTokens, estimateToolResultTokens, getCalibrationState, type RequestTokenBreakdown, recordActualUsage, resetCalibration, } from './token-estimate.js';
|
|
49
50
|
export { applyToolDescriptionModes, applyToolDescriptionModeToTool, DEFAULT_TOOL_DESCRIPTION_MODE, getToolDescriptionMode, normalizeToolDescriptionMode, resolveToolDescriptionMode, setToolDescriptionMode, simplifyToolDescription, type ToolDescriptionRegistryLike, } from './tool-description-mode.js';
|
package/dist/utils/index.js
CHANGED
|
@@ -1915,6 +1915,22 @@ function getContextBreakdown(ctx) {
|
|
|
1915
1915
|
// src/utils/crash-shield.ts
|
|
1916
1916
|
var CRASH_STORM_WINDOW_MS = 6e4;
|
|
1917
1917
|
var CRASH_STORM_LIMIT = 20;
|
|
1918
|
+
var fatalSalvageHooks = [];
|
|
1919
|
+
function addFatalSalvageHook(hook) {
|
|
1920
|
+
fatalSalvageHooks.push(hook);
|
|
1921
|
+
return () => {
|
|
1922
|
+
const idx = fatalSalvageHooks.indexOf(hook);
|
|
1923
|
+
if (idx >= 0) fatalSalvageHooks.splice(idx, 1);
|
|
1924
|
+
};
|
|
1925
|
+
}
|
|
1926
|
+
function runFatalSalvageSync() {
|
|
1927
|
+
for (const hook of [...fatalSalvageHooks]) {
|
|
1928
|
+
try {
|
|
1929
|
+
hook();
|
|
1930
|
+
} catch {
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1918
1934
|
function isBrokenOutputConsumer(error) {
|
|
1919
1935
|
if (typeof error !== "object" || error === null || !("code" in error)) return false;
|
|
1920
1936
|
return error.code === "EPIPE" || error.code === "ECONNRESET" || error.code === "ECONNABORTED";
|
|
@@ -1950,6 +1966,7 @@ function installCrashShield(options = {}) {
|
|
|
1950
1966
|
`error storm: >${CRASH_STORM_LIMIT} in ${CRASH_STORM_WINDOW_MS / 1e3}s \u2014 exiting`
|
|
1951
1967
|
)
|
|
1952
1968
|
);
|
|
1969
|
+
runFatalSalvageSync();
|
|
1953
1970
|
exit(1);
|
|
1954
1971
|
}
|
|
1955
1972
|
};
|
|
@@ -2232,49 +2249,57 @@ async function expandGlob(pattern) {
|
|
|
2232
2249
|
async function walk2(dir, pat) {
|
|
2233
2250
|
let entries;
|
|
2234
2251
|
try {
|
|
2235
|
-
entries = await fsp.readdir(dir);
|
|
2252
|
+
entries = await fsp.readdir(dir, { withFileTypes: true });
|
|
2236
2253
|
} catch {
|
|
2237
2254
|
return;
|
|
2238
2255
|
}
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2256
|
+
if (pat.startsWith("**/")) {
|
|
2257
|
+
const rest = pat.slice(3);
|
|
2258
|
+
await walk2(dir, rest);
|
|
2242
2259
|
for (const e of entries) {
|
|
2243
|
-
if (
|
|
2244
|
-
const
|
|
2245
|
-
|
|
2260
|
+
if (e.isDirectory()) {
|
|
2261
|
+
const subDir = `${dir}${SEP}${e.name}`;
|
|
2262
|
+
await walk2(subDir, pat);
|
|
2246
2263
|
}
|
|
2247
2264
|
}
|
|
2248
2265
|
return;
|
|
2249
2266
|
}
|
|
2250
|
-
|
|
2251
|
-
const rest = pat.slice(firstGlob);
|
|
2252
|
-
if (before.endsWith("**")) {
|
|
2253
|
-
await walk2(dir, rest);
|
|
2267
|
+
if (pat === "**") {
|
|
2254
2268
|
for (const e of entries) {
|
|
2255
|
-
const full = `${dir}${SEP}${e}`;
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
} catch {
|
|
2269
|
+
const full = `${dir}${SEP}${e.name}`;
|
|
2270
|
+
results.add(abs ? resolve2(full) : full);
|
|
2271
|
+
if (e.isDirectory()) {
|
|
2272
|
+
await walk2(full, "**");
|
|
2260
2273
|
}
|
|
2261
2274
|
}
|
|
2262
|
-
|
|
2263
|
-
|
|
2275
|
+
return;
|
|
2276
|
+
}
|
|
2277
|
+
const firstSlash = pat.indexOf("/");
|
|
2278
|
+
if (firstSlash < 0) {
|
|
2279
|
+
const re = globToRegex(pat);
|
|
2264
2280
|
for (const e of entries) {
|
|
2265
|
-
if (re.test(e)) {
|
|
2266
|
-
const full = `${dir}${SEP}${e}`;
|
|
2281
|
+
if (re.test(e.name)) {
|
|
2282
|
+
const full = `${dir}${SEP}${e.name}`;
|
|
2267
2283
|
results.add(abs ? resolve2(full) : full);
|
|
2268
2284
|
}
|
|
2269
2285
|
}
|
|
2286
|
+
return;
|
|
2287
|
+
}
|
|
2288
|
+
const currentSeg = pat.slice(0, firstSlash);
|
|
2289
|
+
const remainingPat = pat.slice(firstSlash + 1);
|
|
2290
|
+
if (isGlob(currentSeg)) {
|
|
2291
|
+
const re = globToRegex(currentSeg);
|
|
2292
|
+
for (const e of entries) {
|
|
2293
|
+
if (e.isDirectory() && re.test(e.name)) {
|
|
2294
|
+
const subDir = `${dir}${SEP}${e.name}`;
|
|
2295
|
+
await walk2(subDir, remainingPat);
|
|
2296
|
+
}
|
|
2297
|
+
}
|
|
2270
2298
|
} else {
|
|
2271
|
-
const
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
const stat4 = await fsp.stat(full);
|
|
2276
|
-
if (stat4.isDirectory()) await walk2(full, rest);
|
|
2277
|
-
} catch {
|
|
2299
|
+
for (const e of entries) {
|
|
2300
|
+
if (e.isDirectory() && e.name === currentSeg) {
|
|
2301
|
+
const subDir = `${dir}${SEP}${e.name}`;
|
|
2302
|
+
await walk2(subDir, remainingPat);
|
|
2278
2303
|
}
|
|
2279
2304
|
}
|
|
2280
2305
|
}
|
|
@@ -2379,7 +2404,10 @@ function matchAnyCommand(patterns, input) {
|
|
|
2379
2404
|
import * as fs4 from "node:fs";
|
|
2380
2405
|
import * as fsp3 from "node:fs/promises";
|
|
2381
2406
|
import * as path5 from "node:path";
|
|
2382
|
-
import {
|
|
2407
|
+
import {
|
|
2408
|
+
PerformanceObserver,
|
|
2409
|
+
constants as performanceConstants
|
|
2410
|
+
} from "node:perf_hooks";
|
|
2383
2411
|
import * as v8 from "node:v8";
|
|
2384
2412
|
|
|
2385
2413
|
// src/utils/memory-flight-recorder.ts
|
|
@@ -2696,8 +2724,8 @@ async function pruneOldSessions(root, currentDir) {
|
|
|
2696
2724
|
const sessions = await Promise.all(
|
|
2697
2725
|
entries.filter((entry) => entry.isDirectory() && entry.name !== path4.basename(currentDir)).map(async (entry) => {
|
|
2698
2726
|
const fullPath = path4.join(root, entry.name);
|
|
2699
|
-
const
|
|
2700
|
-
return { fullPath, mtimeMs:
|
|
2727
|
+
const stat3 = await fsp2.stat(fullPath);
|
|
2728
|
+
return { fullPath, mtimeMs: stat3.mtimeMs };
|
|
2701
2729
|
})
|
|
2702
2730
|
);
|
|
2703
2731
|
sessions.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
@@ -2815,7 +2843,8 @@ function createMemoryFlightRecorder(options = {}) {
|
|
|
2815
2843
|
const now = options.now ?? Date.now;
|
|
2816
2844
|
const startedAt = now();
|
|
2817
2845
|
const root = options.diagnosticsRoot ?? path4.join(wstackGlobalRoot(), "diagnostics", "memory");
|
|
2818
|
-
const
|
|
2846
|
+
const isBunRuntime = typeof globalThis.Bun !== "undefined";
|
|
2847
|
+
const enabled = options.enabled ?? (!isBunRuntime && process.env["WRONGSTACK_MEMORY_FLIGHT_RECORDER"] !== "0" && process.env["NODE_ENV"] !== "test");
|
|
2819
2848
|
const writer = options.captureWriter ?? (enabled ? new ContinuousMemoryCaptureWriter(root) : disabledWriter(path4.join(root, `${timestampSlug()}-pid-${process.pid}`)));
|
|
2820
2849
|
const observations = [];
|
|
2821
2850
|
const windowMs = options.windowMs ?? DEFAULT_WINDOW_MS;
|
|
@@ -2925,7 +2954,11 @@ function defaultHeapLogPath() {
|
|
|
2925
2954
|
function takeHeapSample() {
|
|
2926
2955
|
const m = process.memoryUsage();
|
|
2927
2956
|
const heap = v8.getHeapStatistics();
|
|
2928
|
-
|
|
2957
|
+
let spaces = [];
|
|
2958
|
+
try {
|
|
2959
|
+
spaces = v8.getHeapSpaceStatistics();
|
|
2960
|
+
} catch {
|
|
2961
|
+
}
|
|
2929
2962
|
const spaceUsed = (name) => spaces.find((space) => space.space_name === name)?.space_used_size ?? 0;
|
|
2930
2963
|
const limit = heap.heap_size_limit || 0;
|
|
2931
2964
|
let activeResources = 0;
|
|
@@ -4270,130 +4303,11 @@ function watchProjectTree(root, listener, opts) {
|
|
|
4270
4303
|
}
|
|
4271
4304
|
|
|
4272
4305
|
// src/utils/regex-guard.ts
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
// Adjacent quantifiers: a++ a*+
|
|
4279
|
-
/[+*]{2,}/,
|
|
4280
|
-
// Quantifier on alternation with length 2+
|
|
4281
|
-
/\([^|)]+\|[^)]+\)[+*][+*]/,
|
|
4282
|
-
// Greedy quantifier inside lookahead/lookbehind — (?!.*a+)
|
|
4283
|
-
/[([][^)\]]*[+*][^)\]]*[)\]][^)]*\?\??/
|
|
4284
|
-
];
|
|
4285
|
-
function hasAmbiguousQuantifiedAlternation(pattern) {
|
|
4286
|
-
for (let i = 0; i < pattern.length; i++) {
|
|
4287
|
-
if (pattern[i] !== "(") continue;
|
|
4288
|
-
if (i > 0 && pattern[i - 1] === "\\") continue;
|
|
4289
|
-
let depth = 0;
|
|
4290
|
-
let inClass = false;
|
|
4291
|
-
let j = i;
|
|
4292
|
-
for (; j < pattern.length; j++) {
|
|
4293
|
-
const ch = pattern[j];
|
|
4294
|
-
if (ch === "\\") {
|
|
4295
|
-
j++;
|
|
4296
|
-
continue;
|
|
4297
|
-
}
|
|
4298
|
-
if (inClass) {
|
|
4299
|
-
if (ch === "]") inClass = false;
|
|
4300
|
-
continue;
|
|
4301
|
-
}
|
|
4302
|
-
if (ch === "[") {
|
|
4303
|
-
inClass = true;
|
|
4304
|
-
continue;
|
|
4305
|
-
}
|
|
4306
|
-
if (ch === "(") depth++;
|
|
4307
|
-
else if (ch === ")") {
|
|
4308
|
-
depth--;
|
|
4309
|
-
if (depth === 0) break;
|
|
4310
|
-
}
|
|
4311
|
-
}
|
|
4312
|
-
if (j >= pattern.length) return false;
|
|
4313
|
-
const next = pattern[j + 1];
|
|
4314
|
-
if (next !== "+" && next !== "*" && next !== "{") continue;
|
|
4315
|
-
let inner = pattern.slice(i + 1, j);
|
|
4316
|
-
inner = inner.replace(/^\?(?::|<?[=!])/u, "");
|
|
4317
|
-
const branches = [];
|
|
4318
|
-
let current = "";
|
|
4319
|
-
let d = 0;
|
|
4320
|
-
let cls = false;
|
|
4321
|
-
for (let k = 0; k < inner.length; k++) {
|
|
4322
|
-
const ch = inner[k];
|
|
4323
|
-
if (ch === "\\") {
|
|
4324
|
-
current += ch + (inner[k + 1] ?? "");
|
|
4325
|
-
k++;
|
|
4326
|
-
continue;
|
|
4327
|
-
}
|
|
4328
|
-
if (cls) {
|
|
4329
|
-
if (ch === "]") cls = false;
|
|
4330
|
-
current += ch;
|
|
4331
|
-
continue;
|
|
4332
|
-
}
|
|
4333
|
-
if (ch === "[") {
|
|
4334
|
-
cls = true;
|
|
4335
|
-
current += ch;
|
|
4336
|
-
continue;
|
|
4337
|
-
}
|
|
4338
|
-
if (ch === "(") d++;
|
|
4339
|
-
if (ch === ")") d--;
|
|
4340
|
-
if (ch === "|" && d === 0) {
|
|
4341
|
-
branches.push(current);
|
|
4342
|
-
current = "";
|
|
4343
|
-
continue;
|
|
4344
|
-
}
|
|
4345
|
-
current += ch;
|
|
4346
|
-
}
|
|
4347
|
-
branches.push(current);
|
|
4348
|
-
if (branches.length < 2) continue;
|
|
4349
|
-
for (let a = 0; a < branches.length; a++) {
|
|
4350
|
-
for (let b = a + 1; b < branches.length; b++) {
|
|
4351
|
-
const x = branches[a];
|
|
4352
|
-
const y = branches[b];
|
|
4353
|
-
if (x === "" || y === "") return true;
|
|
4354
|
-
if (x === y || x.startsWith(y) || y.startsWith(x)) return true;
|
|
4355
|
-
}
|
|
4356
|
-
}
|
|
4357
|
-
}
|
|
4358
|
-
return false;
|
|
4359
|
-
}
|
|
4360
|
-
function compileUserRegex(pattern, flags) {
|
|
4361
|
-
if (typeof pattern !== "string") {
|
|
4362
|
-
return { ok: false, reason: "pattern must be a string" };
|
|
4363
|
-
}
|
|
4364
|
-
if (pattern.length === 0) {
|
|
4365
|
-
return { ok: false, reason: "pattern is empty" };
|
|
4366
|
-
}
|
|
4367
|
-
if (pattern.length > MAX_PATTERN_LEN) {
|
|
4368
|
-
return { ok: false, reason: `pattern exceeds ${MAX_PATTERN_LEN} characters` };
|
|
4369
|
-
}
|
|
4370
|
-
for (const rx of DANGEROUS_PATTERNS) {
|
|
4371
|
-
if (rx.test(pattern)) {
|
|
4372
|
-
return {
|
|
4373
|
-
ok: false,
|
|
4374
|
-
reason: "pattern looks vulnerable to catastrophic backtracking \u2014 rewrite without nested quantifiers"
|
|
4375
|
-
};
|
|
4376
|
-
}
|
|
4377
|
-
}
|
|
4378
|
-
if (hasAmbiguousQuantifiedAlternation(pattern)) {
|
|
4379
|
-
return {
|
|
4380
|
-
ok: false,
|
|
4381
|
-
reason: "pattern quantifies an alternation with overlapping branches \u2014 rewrite so no two branches can match the same text"
|
|
4382
|
-
};
|
|
4383
|
-
}
|
|
4384
|
-
try {
|
|
4385
|
-
return { ok: true, regex: new RegExp(pattern, flags) };
|
|
4386
|
-
} catch (err) {
|
|
4387
|
-
return {
|
|
4388
|
-
ok: false,
|
|
4389
|
-
reason: err instanceof Error ? err.message : "invalid regex"
|
|
4390
|
-
};
|
|
4391
|
-
}
|
|
4392
|
-
}
|
|
4393
|
-
var MAX_SUBJECT_LEN = 64 * 1024;
|
|
4394
|
-
function capSubject(line) {
|
|
4395
|
-
return line.length > MAX_SUBJECT_LEN ? line.slice(0, MAX_SUBJECT_LEN) : line;
|
|
4396
|
-
}
|
|
4306
|
+
import {
|
|
4307
|
+
capSubject,
|
|
4308
|
+
compileUserRegex,
|
|
4309
|
+
MAX_SUBJECT_LEN
|
|
4310
|
+
} from "@wrongstack/primitives";
|
|
4397
4311
|
|
|
4398
4312
|
// src/utils/safe-json.ts
|
|
4399
4313
|
function safeParse(input, maxBytes = 5e6) {
|
|
@@ -4710,6 +4624,42 @@ function formatTaskList(tasks) {
|
|
|
4710
4624
|
return lines.join("\n");
|
|
4711
4625
|
}
|
|
4712
4626
|
|
|
4627
|
+
// src/utils/terminal-sanitize.ts
|
|
4628
|
+
var ANSI_RE = /\x1b\[[0-?]*[ -/]*[@-~]/g;
|
|
4629
|
+
var ANSI_OSC_RE = /\x1b\][\s\S]*?(?:\x07|\x1b\\)/g;
|
|
4630
|
+
var ANSI_CONTROL_STRING_RE = /\x1b[P^_X][\s\S]*?\x1b\\/g;
|
|
4631
|
+
var ANSI_ESCAPE_RE = /\x1b[ -/]*[@-~]/g;
|
|
4632
|
+
var BIDI_AND_ZERO_WIDTH_RE = /[---]/g;
|
|
4633
|
+
function sanitizeTerminalText(value, tabWidth = 2) {
|
|
4634
|
+
const tab = " ".repeat(Math.max(1, Math.min(8, Math.floor(tabWidth))));
|
|
4635
|
+
const withoutEscapes = value.replace(ANSI_OSC_RE, "").replace(ANSI_CONTROL_STRING_RE, "").replace(ANSI_RE, "").replace(ANSI_ESCAPE_RE, "").replace(BIDI_AND_ZERO_WIDTH_RE, "").replace(/\t/g, tab).replace(/\r/g, "");
|
|
4636
|
+
let safe = "";
|
|
4637
|
+
for (const char of withoutEscapes) {
|
|
4638
|
+
const code = char.codePointAt(0) ?? 0;
|
|
4639
|
+
if (char === "\n" || code >= 32 && code !== 127 && !(code >= 128 && code <= 159)) {
|
|
4640
|
+
safe += char;
|
|
4641
|
+
}
|
|
4642
|
+
}
|
|
4643
|
+
return safe;
|
|
4644
|
+
}
|
|
4645
|
+
function sanitizeTerminalPreview(value, opts = {}) {
|
|
4646
|
+
const maxLines = opts.maxLines ?? 40;
|
|
4647
|
+
const maxChars = opts.maxChars ?? 8e3;
|
|
4648
|
+
const safe = sanitizeTerminalText(value, opts.tabWidth);
|
|
4649
|
+
let truncated = false;
|
|
4650
|
+
let clipped = safe;
|
|
4651
|
+
if (clipped.length > maxChars) {
|
|
4652
|
+
clipped = clipped.slice(0, maxChars);
|
|
4653
|
+
truncated = true;
|
|
4654
|
+
}
|
|
4655
|
+
const lines = clipped.split("\n");
|
|
4656
|
+
if (lines.length > maxLines) {
|
|
4657
|
+
clipped = lines.slice(0, maxLines).join("\n");
|
|
4658
|
+
truncated = true;
|
|
4659
|
+
}
|
|
4660
|
+
return { text: clipped, truncated };
|
|
4661
|
+
}
|
|
4662
|
+
|
|
4713
4663
|
// src/utils/tool-description-mode.ts
|
|
4714
4664
|
var DEFAULT_TOOL_DESCRIPTION_MODE = "extend";
|
|
4715
4665
|
var ORIGINAL_TOOL_DESCRIPTION = /* @__PURE__ */ Symbol.for("wrongstack.tool.originalDescription");
|
|
@@ -5589,9 +5539,21 @@ function renderCommandLine(command, args) {
|
|
|
5589
5539
|
});
|
|
5590
5540
|
return [command, ...rendered].join(" ");
|
|
5591
5541
|
}
|
|
5592
|
-
function
|
|
5542
|
+
function renderSubjectFields(obj, fields) {
|
|
5543
|
+
const parts = [];
|
|
5544
|
+
for (const field of fields) {
|
|
5545
|
+
const value = obj[field];
|
|
5546
|
+
if (value === void 0 || value === null || value === "" || value === false) continue;
|
|
5547
|
+
const str = String(value);
|
|
5548
|
+
parts.push(`${field}=${/\s/.test(str) ? `"${str.replace(/"/g, '\\"')}"` : str}`);
|
|
5549
|
+
}
|
|
5550
|
+
return parts.join(" ");
|
|
5551
|
+
}
|
|
5552
|
+
function subjectForToolInput(toolName, input, subjectKey, subjectFields) {
|
|
5593
5553
|
if (!input || typeof input !== "object") return void 0;
|
|
5594
5554
|
const obj = input;
|
|
5555
|
+
const extra = subjectFields && subjectFields.length > 0 ? renderSubjectFields(obj, subjectFields) : "";
|
|
5556
|
+
const withExtra = (base) => extra ? `${base} ${extra}` : base;
|
|
5595
5557
|
if (subjectKey) {
|
|
5596
5558
|
const value = obj[subjectKey];
|
|
5597
5559
|
if (Array.isArray(value)) {
|
|
@@ -5607,9 +5569,9 @@ function subjectForToolInput(toolName, input, subjectKey) {
|
|
|
5607
5569
|
if (subjectKey === "command") {
|
|
5608
5570
|
const rendered = renderCommandLine(value, obj["args"]);
|
|
5609
5571
|
if (value === "commit" && obj["dry_run"] === true) {
|
|
5610
|
-
return `${escapeGlobSubject(rendered)}:dry-run`;
|
|
5572
|
+
return `${escapeGlobSubject(withExtra(rendered))}:dry-run`;
|
|
5611
5573
|
}
|
|
5612
|
-
return escapeGlobSubject(rendered);
|
|
5574
|
+
return escapeGlobSubject(withExtra(rendered));
|
|
5613
5575
|
}
|
|
5614
5576
|
if (subjectKey === "directory" && obj["dry_run"] === true) {
|
|
5615
5577
|
return `${escapeGlobSubject(value)}:dry-run`;
|
|
@@ -5662,7 +5624,7 @@ var DEFAULT_WALK_IGNORE_DIRS = Object.freeze([
|
|
|
5662
5624
|
var DEFAULT_WALK_IGNORE_SET = new Set(DEFAULT_WALK_IGNORE_DIRS);
|
|
5663
5625
|
|
|
5664
5626
|
// src/utils/win32-cmd.ts
|
|
5665
|
-
var WIN32_CMD_META = /[&|<>"
|
|
5627
|
+
var WIN32_CMD_META = /[&|<>"%\r\n\0]/;
|
|
5666
5628
|
function buildWin32CmdShimInvocation(command, args = []) {
|
|
5667
5629
|
assertSafeWin32CmdArgs([command, ...args]);
|
|
5668
5630
|
const line = ["call", quoteWin32CmdArg(command), ...args.map(quoteWin32CmdArg)].join(" ");
|
|
@@ -5751,6 +5713,7 @@ export {
|
|
|
5751
5713
|
WIRE_TOOL_NAME_MAX_LENGTH,
|
|
5752
5714
|
WIRE_TOOL_NAME_PATTERN,
|
|
5753
5715
|
activateProjectStateGuard,
|
|
5716
|
+
addFatalSalvageHook,
|
|
5754
5717
|
applyToolDescriptionModeToTool,
|
|
5755
5718
|
applyToolDescriptionModes,
|
|
5756
5719
|
applyToolResultRenderModes,
|
|
@@ -5885,6 +5848,7 @@ export {
|
|
|
5885
5848
|
resolveToolDescriptionMode,
|
|
5886
5849
|
resolveToolResultRenderMode,
|
|
5887
5850
|
resolveWstackPaths,
|
|
5851
|
+
runFatalSalvageSync,
|
|
5888
5852
|
safeEmit,
|
|
5889
5853
|
safeParse,
|
|
5890
5854
|
safeProfileName,
|
|
@@ -5893,6 +5857,8 @@ export {
|
|
|
5893
5857
|
sanitizeMemoryEvidenceBody,
|
|
5894
5858
|
sanitizeMemoryEvidenceSource,
|
|
5895
5859
|
sanitizeNodeOptions,
|
|
5860
|
+
sanitizeTerminalPreview,
|
|
5861
|
+
sanitizeTerminalText,
|
|
5896
5862
|
sanitizeWireToolName,
|
|
5897
5863
|
sessionScopedPath,
|
|
5898
5864
|
setJsonPath,
|
|
@@ -1,35 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Compile a user-supplied regex with conservative bounds against ReDoS.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* subject cap at all. `packages/tools/tests/regex-guard-parity.test.ts` now
|
|
11
|
-
* holds all three to the same verdicts — change one, change all three.
|
|
12
|
-
*
|
|
13
|
-
* V8's regex engine is backtracking-based and cannot interrupt a
|
|
14
|
-
* synchronous match — a pattern like `(a+)+$` against a sufficiently
|
|
15
|
-
* long line will pin a worker for seconds.
|
|
16
|
-
*/
|
|
17
|
-
export interface CompileResult {
|
|
18
|
-
ok: true;
|
|
19
|
-
regex: RegExp;
|
|
20
|
-
}
|
|
21
|
-
export interface CompileFail {
|
|
22
|
-
ok: false;
|
|
23
|
-
reason: string;
|
|
24
|
-
}
|
|
25
|
-
export declare function compileUserRegex(pattern: string, flags: string): CompileResult | CompileFail;
|
|
26
|
-
/**
|
|
27
|
-
* Truncate a subject line to a safe length for synchronous regex eval.
|
|
28
|
-
*
|
|
29
|
-
* The canonical copy has always shipped this; this one did not, so callers
|
|
30
|
-
* here bounded the pattern but never the SUBJECT — and a linear-time pattern
|
|
31
|
-
* over a multi-megabyte line is still a stall.
|
|
4
|
+
* Canonical home since card #5: `@wrongstack/primitives/src/regex-guard.ts`
|
|
5
|
+
* (a dependency leaf, so every workspace tier — including kanban, which sits
|
|
6
|
+
* below core and tools — can share one implementation). This module is now a
|
|
7
|
+
* re-export shim: importers of `@wrongstack/core/utils` keep working, and
|
|
8
|
+
* `tools/tests/regex-guard-parity.test.ts` still pins all three historical
|
|
9
|
+
* entry points to identical verdicts (now trivially true — one code path).
|
|
32
10
|
*/
|
|
33
|
-
export
|
|
34
|
-
export declare function capSubject(line: string): string;
|
|
11
|
+
export { type CompileFail, type CompileResult, capSubject, compileUserRegex, MAX_SUBJECT_LEN, } from '@wrongstack/primitives';
|
|
35
12
|
//# sourceMappingURL=regex-guard.d.ts.map
|