reasonix 0.27.2 → 0.28.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/cli/{chunk-R2L5YEEF.js → chunk-COFBA5FV.js} +7 -2
- package/dist/cli/chunk-COFBA5FV.js.map +1 -0
- package/dist/cli/index.js +1871 -1234
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/{prompt-YUL7CYKY.js → prompt-VF7B6BWR.js} +2 -2
- package/dist/index.d.ts +166 -139
- package/dist/index.js +1097 -722
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/dist/cli/chunk-R2L5YEEF.js.map +0 -1
- /package/dist/cli/{prompt-YUL7CYKY.js.map → prompt-VF7B6BWR.js.map} +0 -0
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import {
|
|
3
3
|
CODE_SYSTEM_PROMPT,
|
|
4
4
|
codeSystemPrompt
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-COFBA5FV.js";
|
|
6
6
|
export {
|
|
7
7
|
CODE_SYSTEM_PROMPT,
|
|
8
8
|
codeSystemPrompt
|
|
9
9
|
};
|
|
10
|
-
//# sourceMappingURL=prompt-
|
|
10
|
+
//# sourceMappingURL=prompt-VF7B6BWR.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -259,6 +259,27 @@ type ChoiceVerdict = {
|
|
|
259
259
|
} | {
|
|
260
260
|
type: "cancel";
|
|
261
261
|
};
|
|
262
|
+
type ToolConfirmationAuditEvent = {
|
|
263
|
+
type: "tool.confirm.allow";
|
|
264
|
+
kind: "run_command" | "run_background";
|
|
265
|
+
payload: {
|
|
266
|
+
command: string;
|
|
267
|
+
};
|
|
268
|
+
} | {
|
|
269
|
+
type: "tool.confirm.deny";
|
|
270
|
+
kind: "run_command" | "run_background";
|
|
271
|
+
payload: {
|
|
272
|
+
command: string;
|
|
273
|
+
};
|
|
274
|
+
denyContext?: string;
|
|
275
|
+
} | {
|
|
276
|
+
type: "tool.confirm.always_allow";
|
|
277
|
+
kind: "run_command" | "run_background";
|
|
278
|
+
payload: {
|
|
279
|
+
command: string;
|
|
280
|
+
};
|
|
281
|
+
prefix: string;
|
|
282
|
+
};
|
|
262
283
|
interface PauseResponseMap {
|
|
263
284
|
run_command: ConfirmationChoice;
|
|
264
285
|
run_background: ConfirmationChoice;
|
|
@@ -303,6 +324,7 @@ type PauseRequest = {
|
|
|
303
324
|
payload: unknown;
|
|
304
325
|
};
|
|
305
326
|
type GateListener = (request: PauseRequest) => void;
|
|
327
|
+
type AuditListener = (event: ToolConfirmationAuditEvent) => void;
|
|
306
328
|
/** Named options for PauseGate.ask() — makes it obvious which field is kind vs payload. */
|
|
307
329
|
interface PauseAskOpts<K extends PauseKind = PauseKind> {
|
|
308
330
|
kind: K;
|
|
@@ -312,15 +334,18 @@ declare class PauseGate {
|
|
|
312
334
|
private _nextId;
|
|
313
335
|
private _pending;
|
|
314
336
|
private _listeners;
|
|
337
|
+
private _auditListener;
|
|
315
338
|
/** Block until the user responds. Takes a named options object so the
|
|
316
339
|
* kind and payload fields don't get confused at the call site. */
|
|
317
340
|
ask<K extends PauseKind>(opts: PauseAskOpts<K>): Promise<PauseResponseMap[K]>;
|
|
318
341
|
/** Resolve a pending request. Called by the App's modal callback. */
|
|
319
342
|
resolve(id: number, data: unknown): void;
|
|
343
|
+
setAuditListener(fn: AuditListener | null): void;
|
|
320
344
|
/** Subscribe to new pause requests. Returns an unsubscribe function. */
|
|
321
345
|
on(fn: GateListener): () => void;
|
|
322
346
|
/** Current pending request, if any (polling fallback). */
|
|
323
347
|
get current(): PauseRequest | null;
|
|
348
|
+
private emitAuditEvent;
|
|
324
349
|
}
|
|
325
350
|
|
|
326
351
|
/** Shell-command hooks; project scope first, then global. Exit 0=pass, 2=block on Pre*, other=warn. */
|
|
@@ -429,46 +454,30 @@ interface RunHooksOptions {
|
|
|
429
454
|
/** Stops at first `block` so a gating hook can prevent later hooks running against a phantom success. */
|
|
430
455
|
declare function runHooks(opts: RunHooksOptions): Promise<HookReport>;
|
|
431
456
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
declare class AppendOnlyLog {
|
|
457
|
-
private _entries;
|
|
458
|
-
append(message: ChatMessage): void;
|
|
459
|
-
extend(messages: ChatMessage[]): void;
|
|
460
|
-
/** The one append-only-breaking path — reserved for `/compact` + recovery. Use `append()` otherwise. */
|
|
461
|
-
compactInPlace(replacement: ChatMessage[]): void;
|
|
462
|
-
get entries(): readonly ChatMessage[];
|
|
463
|
-
toMessages(): ChatMessage[];
|
|
464
|
-
get length(): number;
|
|
465
|
-
}
|
|
466
|
-
declare class VolatileScratch {
|
|
467
|
-
reasoning: string | null;
|
|
468
|
-
planState: Record<string, unknown> | null;
|
|
469
|
-
notes: string[];
|
|
470
|
-
reset(): void;
|
|
471
|
-
}
|
|
457
|
+
/** Single text-layer DeepSeek-error formatter — 429/5xx never reach here (retry.ts swallows). */
|
|
458
|
+
declare function formatLoopError(err: Error): string;
|
|
459
|
+
|
|
460
|
+
/** Drops both unpaired assistant.tool_calls and stray tool messages — DeepSeek 400s on either. */
|
|
461
|
+
declare function fixToolCallPairing(messages: ChatMessage[]): {
|
|
462
|
+
messages: ChatMessage[];
|
|
463
|
+
droppedAssistantCalls: number;
|
|
464
|
+
droppedStrayTools: number;
|
|
465
|
+
};
|
|
466
|
+
declare function healLoadedMessages(messages: ChatMessage[], maxChars: number): {
|
|
467
|
+
messages: ChatMessage[];
|
|
468
|
+
healedCount: number;
|
|
469
|
+
healedFrom: number;
|
|
470
|
+
};
|
|
471
|
+
/** Token-cap variant — char cap would let CJK slip past at 2× the intended token cost. */
|
|
472
|
+
declare function healLoadedMessagesByTokens(messages: ChatMessage[], maxTokens: number): {
|
|
473
|
+
messages: ChatMessage[];
|
|
474
|
+
healedCount: number;
|
|
475
|
+
tokensSaved: number;
|
|
476
|
+
charsSaved: number;
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
/** Strip hallucinated tool-call envelopes — `tools: undefined` doesn't always force prose. */
|
|
480
|
+
declare function stripHallucinatedToolMarkup(s: string): string;
|
|
472
481
|
|
|
473
482
|
/** Mutating calls clear prior read-only entries so a post-edit re-read isn't flagged as repeat. */
|
|
474
483
|
type IsMutating = (call: ToolCall) => boolean;
|
|
@@ -587,6 +596,91 @@ declare class SessionStats {
|
|
|
587
596
|
summary(): SessionSummary;
|
|
588
597
|
}
|
|
589
598
|
|
|
599
|
+
type EventRole = "assistant_delta" | "assistant_final"
|
|
600
|
+
/** Only liveness signal during a large-args tool call (no content/reasoning bytes). */
|
|
601
|
+
| "tool_call_delta"
|
|
602
|
+
/** Pre-dispatch ping so the TUI can show a spinner during long tool awaits. */
|
|
603
|
+
| "tool_start" | "tool" | "done" | "error" | "warning"
|
|
604
|
+
/** Transient indicator for silent phases; UI clears on next primary event. */
|
|
605
|
+
| "status" | "branch_start" | "branch_progress" | "branch_done";
|
|
606
|
+
interface BranchSummary {
|
|
607
|
+
budget: number;
|
|
608
|
+
chosenIndex: number;
|
|
609
|
+
uncertainties: number[];
|
|
610
|
+
temperatures: number[];
|
|
611
|
+
}
|
|
612
|
+
interface BranchProgress {
|
|
613
|
+
completed: number;
|
|
614
|
+
total: number;
|
|
615
|
+
latestIndex: number;
|
|
616
|
+
latestTemperature: number;
|
|
617
|
+
latestUncertainties: number;
|
|
618
|
+
}
|
|
619
|
+
interface LoopEvent {
|
|
620
|
+
turn: number;
|
|
621
|
+
role: EventRole;
|
|
622
|
+
content: string;
|
|
623
|
+
reasoningDelta?: string;
|
|
624
|
+
toolName?: string;
|
|
625
|
+
/** Raw args JSON — needed by `reasonix diff` to explain why a tool was called. */
|
|
626
|
+
toolArgs?: string;
|
|
627
|
+
/** Cumulative arguments-string length for `role === "tool_call_delta"`. */
|
|
628
|
+
toolCallArgsChars?: number;
|
|
629
|
+
/** Zero-based index of the tool call this delta belongs to (multi-tool progress). */
|
|
630
|
+
toolCallIndex?: number;
|
|
631
|
+
/** Count of tool calls whose args have parsed as valid JSON (UI progress, not dispatch gate). */
|
|
632
|
+
toolCallReadyCount?: number;
|
|
633
|
+
stats?: TurnStats;
|
|
634
|
+
planState?: TypedPlanState;
|
|
635
|
+
repair?: RepairReport;
|
|
636
|
+
branch?: BranchSummary;
|
|
637
|
+
branchProgress?: BranchProgress;
|
|
638
|
+
error?: string;
|
|
639
|
+
/** Display-only — code-mode applier MUST skip SEARCH/REPLACE in forced-summary text. */
|
|
640
|
+
forcedSummary?: boolean;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
interface ImmutablePrefixOptions {
|
|
644
|
+
system: string;
|
|
645
|
+
toolSpecs?: readonly ToolSpec[];
|
|
646
|
+
fewShots?: readonly ChatMessage[];
|
|
647
|
+
}
|
|
648
|
+
declare class ImmutablePrefix {
|
|
649
|
+
readonly system: string;
|
|
650
|
+
/** Each `addTool` costs one cache-miss turn — DeepSeek's prefix cache is keyed by full tool list. */
|
|
651
|
+
private _toolSpecs;
|
|
652
|
+
readonly fewShots: readonly ChatMessage[];
|
|
653
|
+
/** Invalidated only via `addTool`; bypassing it leaves cache stale → fingerprint diverges from sent prefix. */
|
|
654
|
+
private _fingerprintCache;
|
|
655
|
+
constructor(opts: ImmutablePrefixOptions);
|
|
656
|
+
get toolSpecs(): readonly ToolSpec[];
|
|
657
|
+
toMessages(): ChatMessage[];
|
|
658
|
+
tools(): ToolSpec[];
|
|
659
|
+
addTool(spec: ToolSpec): boolean;
|
|
660
|
+
/** Mirror of addTool for MCP hot-unbridge. Same cache-miss cost — prefix changes shape. */
|
|
661
|
+
removeTool(name: string): boolean;
|
|
662
|
+
get fingerprint(): string;
|
|
663
|
+
/** Dev/test only — throws on cache drift, which always means a non-`addTool` mutation slipped in. */
|
|
664
|
+
verifyFingerprint(): string;
|
|
665
|
+
private computeFingerprint;
|
|
666
|
+
}
|
|
667
|
+
declare class AppendOnlyLog {
|
|
668
|
+
private _entries;
|
|
669
|
+
append(message: ChatMessage): void;
|
|
670
|
+
extend(messages: ChatMessage[]): void;
|
|
671
|
+
/** The one append-only-breaking path — reserved for `/compact` + recovery. Use `append()` otherwise. */
|
|
672
|
+
compactInPlace(replacement: ChatMessage[]): void;
|
|
673
|
+
get entries(): readonly ChatMessage[];
|
|
674
|
+
toMessages(): ChatMessage[];
|
|
675
|
+
get length(): number;
|
|
676
|
+
}
|
|
677
|
+
declare class VolatileScratch {
|
|
678
|
+
reasoning: string | null;
|
|
679
|
+
planState: Record<string, unknown> | null;
|
|
680
|
+
notes: string[];
|
|
681
|
+
reset(): void;
|
|
682
|
+
}
|
|
683
|
+
|
|
590
684
|
interface ToolCallContext {
|
|
591
685
|
signal?: AbortSignal;
|
|
592
686
|
/** Inject a mock PauseGate for tests. When absent, tools use the singleton. */
|
|
@@ -606,6 +700,11 @@ interface ToolRegistryOptions {
|
|
|
606
700
|
/** Auto-flatten + re-nest at dispatch; default true. */
|
|
607
701
|
autoFlatten?: boolean;
|
|
608
702
|
}
|
|
703
|
+
type ToolCallAuditEvent = {
|
|
704
|
+
name: string;
|
|
705
|
+
args: Record<string, unknown>;
|
|
706
|
+
};
|
|
707
|
+
type ToolCallAuditListener = (event: ToolCallAuditEvent) => void;
|
|
609
708
|
/** String return short-circuits dispatch; null/undefined falls through to the tool fn. */
|
|
610
709
|
type ToolInterceptor = (name: string, args: Record<string, unknown>) => string | null | undefined | Promise<string | null | undefined>;
|
|
611
710
|
declare class ToolRegistry {
|
|
@@ -613,6 +712,7 @@ declare class ToolRegistry {
|
|
|
613
712
|
private readonly _autoFlatten;
|
|
614
713
|
private _planMode;
|
|
615
714
|
private _interceptor;
|
|
715
|
+
private _auditListener;
|
|
616
716
|
constructor(opts?: ToolRegistryOptions);
|
|
617
717
|
/** Enable / disable plan-mode enforcement at dispatch. */
|
|
618
718
|
setPlanMode(on: boolean): void;
|
|
@@ -620,6 +720,7 @@ declare class ToolRegistry {
|
|
|
620
720
|
get planMode(): boolean;
|
|
621
721
|
/** At most one interceptor active; calling twice replaces. */
|
|
622
722
|
setToolInterceptor(fn: ToolInterceptor | null): void;
|
|
723
|
+
setAuditListener(fn: ToolCallAuditListener | null): void;
|
|
623
724
|
register<A, R>(def: ToolDefinition<A, R>): this;
|
|
624
725
|
/** Drop a registered tool. Returns true if the name was present. Used by MCP hot-unbridge. */
|
|
625
726
|
unregister(name: string): boolean;
|
|
@@ -638,49 +739,6 @@ declare class ToolRegistry {
|
|
|
638
739
|
}): Promise<string>;
|
|
639
740
|
}
|
|
640
741
|
|
|
641
|
-
type EventRole = "assistant_delta" | "assistant_final"
|
|
642
|
-
/** Only liveness signal during a large-args tool call (no content/reasoning bytes). */
|
|
643
|
-
| "tool_call_delta"
|
|
644
|
-
/** Pre-dispatch ping so the TUI can show a spinner during long tool awaits. */
|
|
645
|
-
| "tool_start" | "tool" | "done" | "error" | "warning"
|
|
646
|
-
/** Transient indicator for silent phases; UI clears on next primary event. */
|
|
647
|
-
| "status" | "branch_start" | "branch_progress" | "branch_done";
|
|
648
|
-
interface BranchSummary {
|
|
649
|
-
budget: number;
|
|
650
|
-
chosenIndex: number;
|
|
651
|
-
uncertainties: number[];
|
|
652
|
-
temperatures: number[];
|
|
653
|
-
}
|
|
654
|
-
interface BranchProgress {
|
|
655
|
-
completed: number;
|
|
656
|
-
total: number;
|
|
657
|
-
latestIndex: number;
|
|
658
|
-
latestTemperature: number;
|
|
659
|
-
latestUncertainties: number;
|
|
660
|
-
}
|
|
661
|
-
interface LoopEvent {
|
|
662
|
-
turn: number;
|
|
663
|
-
role: EventRole;
|
|
664
|
-
content: string;
|
|
665
|
-
reasoningDelta?: string;
|
|
666
|
-
toolName?: string;
|
|
667
|
-
/** Raw args JSON — needed by `reasonix diff` to explain why a tool was called. */
|
|
668
|
-
toolArgs?: string;
|
|
669
|
-
/** Cumulative arguments-string length for `role === "tool_call_delta"`. */
|
|
670
|
-
toolCallArgsChars?: number;
|
|
671
|
-
/** Zero-based index of the tool call this delta belongs to (multi-tool progress). */
|
|
672
|
-
toolCallIndex?: number;
|
|
673
|
-
/** Count of tool calls whose args have parsed as valid JSON (UI progress, not dispatch gate). */
|
|
674
|
-
toolCallReadyCount?: number;
|
|
675
|
-
stats?: TurnStats;
|
|
676
|
-
planState?: TypedPlanState;
|
|
677
|
-
repair?: RepairReport;
|
|
678
|
-
branch?: BranchSummary;
|
|
679
|
-
branchProgress?: BranchProgress;
|
|
680
|
-
error?: string;
|
|
681
|
-
/** Display-only — code-mode applier MUST skip SEARCH/REPLACE in forced-summary text. */
|
|
682
|
-
forcedSummary?: boolean;
|
|
683
|
-
}
|
|
684
742
|
interface CacheFirstLoopOptions {
|
|
685
743
|
client: DeepSeekClient;
|
|
686
744
|
prefix: ImmutablePrefix;
|
|
@@ -746,11 +804,11 @@ declare class CacheFirstLoop {
|
|
|
746
804
|
private _turnAbort;
|
|
747
805
|
private _proArmedForNextTurn;
|
|
748
806
|
private _escalateThisTurn;
|
|
749
|
-
private
|
|
750
|
-
private _turnFailureTypes;
|
|
807
|
+
private readonly _turnFailures;
|
|
751
808
|
private _turnSelfCorrected;
|
|
752
809
|
private _foldedThisTurn;
|
|
753
810
|
private context;
|
|
811
|
+
get currentTurn(): number;
|
|
754
812
|
constructor(opts: CacheFirstLoopOptions);
|
|
755
813
|
/** Replace older turns with one summary message; keep tail within keepRecentTokens budget. */
|
|
756
814
|
compactHistory(opts?: {
|
|
@@ -780,49 +838,16 @@ declare class CacheFirstLoop {
|
|
|
780
838
|
/** UI surface — true while the current turn is running on pro (armed or auto-escalated). */
|
|
781
839
|
get escalatedThisTurn(): boolean;
|
|
782
840
|
private modelForCurrentCall;
|
|
783
|
-
/** Anchored to lead — mid-text matches are normal content (user asking about the marker). */
|
|
784
|
-
private parseEscalationMarker;
|
|
785
|
-
/** Convenience boolean — same gate the streaming path used to call. */
|
|
786
|
-
private isEscalationRequest;
|
|
787
|
-
/** Drives streaming flush — while plausibly partial, keep accumulating; else flush. */
|
|
788
|
-
private looksLikePartialEscalationMarker;
|
|
789
841
|
/** Returns true ONLY on the tipping call — caller surfaces a one-shot warning. */
|
|
790
842
|
private noteToolFailureSignal;
|
|
791
|
-
private formatFailureBreakdown;
|
|
792
843
|
private buildMessages;
|
|
793
844
|
abort(): void;
|
|
794
845
|
/** Drop the last user message + everything after; caller re-sends. Persists to session file. */
|
|
795
846
|
retryLastUser(): string | null;
|
|
796
847
|
step(userInput: string): AsyncGenerator<LoopEvent>;
|
|
797
|
-
private
|
|
848
|
+
private summaryContext;
|
|
798
849
|
run(userInput: string, onEvent?: (ev: LoopEvent) => void): Promise<string>;
|
|
799
|
-
/** Thinking-mode producer ⇒ reasoning_content MUST be set (even ""), or next call 400s. */
|
|
800
|
-
private assistantMessage;
|
|
801
|
-
/** Abort notices etc — uses this.model as stand-in producer for the thinking-mode stamp. */
|
|
802
|
-
private syntheticAssistantMessage;
|
|
803
850
|
}
|
|
804
|
-
/** Strip hallucinated tool-call envelopes — `tools: undefined` doesn't always force prose. */
|
|
805
|
-
declare function stripHallucinatedToolMarkup(s: string): string;
|
|
806
|
-
/** Drops both unpaired assistant.tool_calls and stray tool messages — DeepSeek 400s on either. */
|
|
807
|
-
declare function fixToolCallPairing(messages: ChatMessage[]): {
|
|
808
|
-
messages: ChatMessage[];
|
|
809
|
-
droppedAssistantCalls: number;
|
|
810
|
-
droppedStrayTools: number;
|
|
811
|
-
};
|
|
812
|
-
declare function healLoadedMessages(messages: ChatMessage[], maxChars: number): {
|
|
813
|
-
messages: ChatMessage[];
|
|
814
|
-
healedCount: number;
|
|
815
|
-
healedFrom: number;
|
|
816
|
-
};
|
|
817
|
-
/** Token-cap variant — char cap would let CJK slip past at 2× the intended token cost. */
|
|
818
|
-
declare function healLoadedMessagesByTokens(messages: ChatMessage[], maxTokens: number): {
|
|
819
|
-
messages: ChatMessage[];
|
|
820
|
-
healedCount: number;
|
|
821
|
-
tokensSaved: number;
|
|
822
|
-
charsSaved: number;
|
|
823
|
-
};
|
|
824
|
-
/** Single text-layer DeepSeek-error formatter — 429/5xx never reach here (retry.ts swallows). */
|
|
825
|
-
declare function formatLoopError(err: Error): string;
|
|
826
851
|
|
|
827
852
|
/** Expand `@path` mentions inline. Paths must resolve inside rootDir; escapes / oversize get a skip note, not content. */
|
|
828
853
|
/** Caps match tool-result dispatch truncation (0.5.2). */
|
|
@@ -1177,26 +1202,6 @@ interface JobReadResult {
|
|
|
1177
1202
|
spawnError?: string;
|
|
1178
1203
|
}
|
|
1179
1204
|
|
|
1180
|
-
/** cwd pinned to root; non-allowlisted commands throw to a UI confirm gate; spawn is `shell: false`, tokenized argv only. */
|
|
1181
|
-
|
|
1182
|
-
interface ShellToolsOptions {
|
|
1183
|
-
/** Directory to run commands in. Must be an absolute path. */
|
|
1184
|
-
rootDir: string;
|
|
1185
|
-
/** Seconds before an individual command is killed. Default: 60. */
|
|
1186
|
-
timeoutSec?: number;
|
|
1187
|
-
maxOutputChars?: number;
|
|
1188
|
-
/** Getter form is load-bearing — newly-persisted "always allow" prefixes MUST take effect mid-session. */
|
|
1189
|
-
extraAllowed?: readonly string[] | (() => readonly string[]);
|
|
1190
|
-
/** Getter form lets `editMode === "yolo"` flip mid-session without re-registering tools. */
|
|
1191
|
-
allowAll?: boolean | (() => boolean);
|
|
1192
|
-
jobs?: JobRegistry;
|
|
1193
|
-
}
|
|
1194
|
-
/** No env / glob / backtick / `$(…)` expansion — prevents bypass of allowlist via concatenation. */
|
|
1195
|
-
declare function tokenizeCommand(cmd: string): string[];
|
|
1196
|
-
/** Up-front detection — without it, `dir | findstr foo` quotes `|` literal and pipe silently fails. */
|
|
1197
|
-
declare function detectShellOperator(cmd: string): string | null;
|
|
1198
|
-
/** Allowlist match on leading argv tokens; demoted by `RISKY_ARGS` when a destructive flag appears in the tail. */
|
|
1199
|
-
declare function isAllowed(cmd: string, extra?: readonly string[]): boolean;
|
|
1200
1205
|
interface RunCommandResult {
|
|
1201
1206
|
exitCode: number | null;
|
|
1202
1207
|
/** Combined stdout+stderr, truncated to `maxOutputChars` with a marker. */
|
|
@@ -1233,6 +1238,28 @@ declare function injectPowerShellUtf8(args: readonly string[]): string[] | null;
|
|
|
1233
1238
|
declare function withUtf8Codepage(cmdline: string): string;
|
|
1234
1239
|
/** Doubles embedded quotes per cmd.exe's `""` escape rule; bare alnum passes through unquoted. */
|
|
1235
1240
|
declare function quoteForCmdExe(arg: string): string;
|
|
1241
|
+
|
|
1242
|
+
/** No env / glob / backtick / `$(…)` expansion — prevents bypass of allowlist via concatenation. */
|
|
1243
|
+
declare function tokenizeCommand(cmd: string): string[];
|
|
1244
|
+
/** Up-front detection — without it, `dir | findstr foo` quotes `|` literal and pipe silently fails. */
|
|
1245
|
+
declare function detectShellOperator(cmd: string): string | null;
|
|
1246
|
+
/** Allowlist match on leading argv tokens; demoted by `RISKY_ARGS` when a destructive flag appears in the tail. */
|
|
1247
|
+
declare function isAllowed(cmd: string, extra?: readonly string[]): boolean;
|
|
1248
|
+
|
|
1249
|
+
/** cwd pinned to root; non-allowlisted commands throw to a UI confirm gate; spawn is `shell: false`, tokenized argv only. */
|
|
1250
|
+
|
|
1251
|
+
interface ShellToolsOptions {
|
|
1252
|
+
/** Directory to run commands in. Must be an absolute path. */
|
|
1253
|
+
rootDir: string;
|
|
1254
|
+
/** Seconds before an individual command is killed. Default: 60. */
|
|
1255
|
+
timeoutSec?: number;
|
|
1256
|
+
maxOutputChars?: number;
|
|
1257
|
+
/** Getter form is load-bearing — newly-persisted "always allow" prefixes MUST take effect mid-session. */
|
|
1258
|
+
extraAllowed?: readonly string[] | (() => readonly string[]);
|
|
1259
|
+
/** Getter form lets `editMode === "yolo"` flip mid-session without re-registering tools. */
|
|
1260
|
+
allowAll?: boolean | (() => boolean);
|
|
1261
|
+
jobs?: JobRegistry;
|
|
1262
|
+
}
|
|
1236
1263
|
/** Error thrown by `run_command` when the command isn't allowlisted. */
|
|
1237
1264
|
declare class NeedsConfirmationError extends Error {
|
|
1238
1265
|
readonly command: string;
|