dsh-ssh-tui 0.5.1 → 0.5.3
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/README.en.md +13 -4
- package/README.md +9 -6
- package/lib/approval-reviewer.js +56 -12
- package/lib/approval-reviewer.js.map +1 -1
- package/lib/auto-approval.js +75 -8
- package/lib/auto-approval.js.map +1 -1
- package/lib/i18n/en.js +36 -7
- package/lib/i18n/en.js.map +1 -1
- package/lib/i18n/index.js +1 -0
- package/lib/i18n/index.js.map +1 -1
- package/lib/i18n/zh.js +36 -7
- package/lib/i18n/zh.js.map +1 -1
- package/lib/tui.js +512 -61
- package/lib/tui.js.map +1 -1
- package/lib/types/approval-reviewer.d.ts +12 -4
- package/lib/types/auto-approval.d.ts +25 -2
- package/lib/types/i18n/index.d.ts +2 -0
- package/lib/types/tui.d.ts +77 -3
- package/package.json +4 -4
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI reviewer for /approval auto mode: commands whose shape the rule table
|
|
3
|
+
* cannot classify are judged by the subagent-configured model with compact
|
|
4
|
+
* context (latest user message, recent model output, the pending tool call)
|
|
5
|
+
* instead of paging the human.
|
|
6
|
+
*
|
|
7
|
+
* Injection hardening: everything inside the marked data regions is review
|
|
8
|
+
* MATERIAL, never instructions — the system prompt says so, and material that
|
|
9
|
+
* tries to instruct is treated as an injection attempt and rejected. The
|
|
10
|
+
* caller also enforces its own floor: `high` risk or `authorization: no`
|
|
11
|
+
* is never approved, whatever the model claims.
|
|
12
|
+
*/
|
|
1
13
|
export interface ReviewInput {
|
|
2
14
|
userText: string;
|
|
3
15
|
segments: string[];
|
|
@@ -13,8 +25,4 @@ export interface ReviewVerdict {
|
|
|
13
25
|
export declare const REVIEW_SYSTEM_PROMPT: string;
|
|
14
26
|
/** Assemble the compact, fence-marked user message for the reviewer. */
|
|
15
27
|
export declare function buildReviewUserMessage(input: ReviewInput): string;
|
|
16
|
-
/**
|
|
17
|
-
* Parse the reviewer's one-line JSON verdict. Anything unreadable, missing
|
|
18
|
-
* fields, or with invalid enum values returns undefined (fail-safe).
|
|
19
|
-
*/
|
|
20
28
|
export declare function parseReviewOutput(text: string): ReviewVerdict | undefined;
|
|
@@ -12,8 +12,9 @@
|
|
|
12
12
|
export type AutoApprovalMode = 'off' | 'auto';
|
|
13
13
|
export type ApprovalDecision = 'allow' | 'deny' | 'ask';
|
|
14
14
|
/**
|
|
15
|
-
* Whole-command danger patterns, checked before anything else. A match
|
|
16
|
-
*
|
|
15
|
+
* Whole-command danger patterns, checked before anything else. A match
|
|
16
|
+
* auto-rejects. This is a UX heuristic, not a security boundary: obfuscated
|
|
17
|
+
* or interpreter-wrapped damage still has to be contained by the sandbox.
|
|
17
18
|
*/
|
|
18
19
|
export declare const DANGER_PATTERNS: RegExp[];
|
|
19
20
|
/**
|
|
@@ -38,5 +39,27 @@ export declare function classifyApproval(toolName: string, command: string | und
|
|
|
38
39
|
* Returns undefined for non-shell tools or unparseable args.
|
|
39
40
|
*/
|
|
40
41
|
export declare function commandFromArgs(toolName: string, args: string): string | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* Pull a shell command out of an approval-request `reason` when the
|
|
44
|
+
* classifier never saw the tool-call JSON (sandbox escalation, missing
|
|
45
|
+
* callId, or a card whose args were not recorded).
|
|
46
|
+
*/
|
|
47
|
+
export declare function commandFromApprovalReason(reason: string | undefined): string | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* Resolve the command the classifier should see for one approval request.
|
|
50
|
+
* Prefer the streamed bash/pwsh card, then a command already decoded on the
|
|
51
|
+
* card, then the request's reason text.
|
|
52
|
+
*/
|
|
53
|
+
export declare function commandForApprovalRequest(input: {
|
|
54
|
+
toolName: string;
|
|
55
|
+
reason?: string;
|
|
56
|
+
row?: {
|
|
57
|
+
name: string;
|
|
58
|
+
args: string;
|
|
59
|
+
command?: string;
|
|
60
|
+
};
|
|
61
|
+
}): string | undefined;
|
|
41
62
|
/** Parse the /approval argument into a mode. */
|
|
42
63
|
export declare function parseAutoApprovalMode(raw: string): AutoApprovalMode | undefined;
|
|
64
|
+
/** True when `/approval <arg>` should print the current mode and counters. */
|
|
65
|
+
export declare function isApprovalStatusArg(raw: string): boolean;
|
|
@@ -15,11 +15,13 @@ export declare const UI_LOCALE_SCHEMA: z<Schemastery.ObjectS<{
|
|
|
15
15
|
skipUpdate: z<string, string>;
|
|
16
16
|
view: z<string, string>;
|
|
17
17
|
disconnect: z<string, string>;
|
|
18
|
+
autoApproval: z<string, string>;
|
|
18
19
|
}>, Schemastery.ObjectT<{
|
|
19
20
|
language: z<string, string>;
|
|
20
21
|
skipUpdate: z<string, string>;
|
|
21
22
|
view: z<string, string>;
|
|
22
23
|
disconnect: z<string, string>;
|
|
24
|
+
autoApproval: z<string, string>;
|
|
23
25
|
}>>;
|
|
24
26
|
export declare function localeFromTag(tag: string): Locale | undefined;
|
|
25
27
|
/** Pick zh/en from env, optionally after a saved settings value. */
|
package/lib/types/tui.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ import { SessionId, type SessionEvent } from '@deepseek-ai/dsh-session';
|
|
|
17
17
|
import type { SubagentRunEndInfo, SubagentRunInfo } from '@deepseek-ai/dsh-subagent';
|
|
18
18
|
import { type SubagentSelectionRef } from './subagent-model.js';
|
|
19
19
|
import { type AskUserQuestionAnswer, type AskUserQuestionRequest } from '@deepseek-ai/dsh-user-questions';
|
|
20
|
+
import type { ApprovalOutcome, ApprovalRequest } from '@deepseek-ai/dsh-user-approval';
|
|
20
21
|
export type DisconnectPolicyName = 'pause' | 'continue';
|
|
21
22
|
/** Presentation configuration for the terminal channel. */
|
|
22
23
|
export interface TuiConfig {
|
|
@@ -112,6 +113,8 @@ type Row = {
|
|
|
112
113
|
expanded: boolean;
|
|
113
114
|
/** Consecutive same-path reads/edits folded into this card. */
|
|
114
115
|
repeats?: number;
|
|
116
|
+
/** Call ids folded into this card; results still match after merge. */
|
|
117
|
+
mergedCallIds?: string[];
|
|
115
118
|
/** Sum of output characters across folded reads. */
|
|
116
119
|
totalChars?: number;
|
|
117
120
|
/** Sum of output lines across folded reads. */
|
|
@@ -223,6 +226,50 @@ export interface TuiController {
|
|
|
223
226
|
export type PaintLinkKind = 'local' | 'ssh';
|
|
224
227
|
/** Compact token count, matching the web stats line (517 / 12.2K / 1.2M). */
|
|
225
228
|
export declare function formatTokens(n: number): string;
|
|
229
|
+
/**
|
|
230
|
+
* Prompt occupancy of the next request, from DSH `contextPressure`.
|
|
231
|
+
* Provider-agnostic: uses the routed model's advertised window, not a
|
|
232
|
+
* hardcoded xAI size. Compaction-basic still owns in-turn pressure at 80%.
|
|
233
|
+
*/
|
|
234
|
+
export declare const CONTEXT_PRESSURE_WARN_RATIO = 0.8;
|
|
235
|
+
export declare const CONTEXT_PRESSURE_DANGER_RATIO = 0.95;
|
|
236
|
+
/** Idle auto-compact starts here so recovery finishes before the 80% in-turn trigger. */
|
|
237
|
+
export declare const CONTEXT_IDLE_COMPACT_RATIO = 0.72;
|
|
238
|
+
export interface ContextPressureSample {
|
|
239
|
+
usedTokens: number;
|
|
240
|
+
contextWindow: number;
|
|
241
|
+
}
|
|
242
|
+
export interface ContextPressureView {
|
|
243
|
+
usedTokens: number;
|
|
244
|
+
contextWindow: number;
|
|
245
|
+
percent: number;
|
|
246
|
+
level: 'ok' | 'warn' | 'danger';
|
|
247
|
+
}
|
|
248
|
+
/** Prompt-side occupancy of one usage sample: uncached input plus cache traffic. */
|
|
249
|
+
export declare function promptPressureTokens(usage: {
|
|
250
|
+
inputTokens: number;
|
|
251
|
+
cacheReadTokens?: number;
|
|
252
|
+
cacheWriteTokens?: number;
|
|
253
|
+
}): number;
|
|
254
|
+
/** Prefer the next-request projection; fall back to last-request pressure. */
|
|
255
|
+
export declare function contextPressureUsedTokens(pressure: {
|
|
256
|
+
projectedTokens?: number;
|
|
257
|
+
pressureTokens?: number;
|
|
258
|
+
} | undefined): number | undefined;
|
|
259
|
+
export declare function parseContextPressure(value: unknown): ContextPressureSample | undefined;
|
|
260
|
+
export declare function contextPressureView(sample: ContextPressureSample): ContextPressureView;
|
|
261
|
+
/**
|
|
262
|
+
* 8-segment Braille ring. Empty `⣀`; full `⣿`. Width is always 1 cell.
|
|
263
|
+
* Index is `ceil(percent / 12.5)` clamped to 0..8.
|
|
264
|
+
*/
|
|
265
|
+
export declare const CONTEXT_RING_EMPTY = "\u28C0";
|
|
266
|
+
export declare const CONTEXT_RING_SEGMENTS: readonly ["⣀", "⠉", "⠋", "⠛", "⠞", "⠟", "⠿", "⡿", "⣿"];
|
|
267
|
+
export declare function formatContextPressureRing(percent: number): string;
|
|
268
|
+
export declare function contextPressureRingColor(level: ContextPressureView['level']): string;
|
|
269
|
+
export declare function formatContextPressureChip(view: ContextPressureView, color?: boolean): string;
|
|
270
|
+
export declare function formatContextPressureStatusLine(view: ContextPressureView | undefined): string;
|
|
271
|
+
export declare function contextPressureAlertText(view: ContextPressureView): string;
|
|
272
|
+
export declare function shouldIdleAutoCompact(view: ContextPressureView | undefined): boolean;
|
|
226
273
|
/** Compact duration, matching the web stats line (45.2s / 2m42s). */
|
|
227
274
|
export declare function formatDuration(ms: number): string;
|
|
228
275
|
export declare function formatTokensPerSecond(tokensPerSecond: number): string;
|
|
@@ -306,6 +353,7 @@ export interface FooterStatusInput {
|
|
|
306
353
|
subDiffers: boolean;
|
|
307
354
|
quotaCode?: string;
|
|
308
355
|
quotaPercent?: number;
|
|
356
|
+
contextChip?: string;
|
|
309
357
|
balanceText?: string;
|
|
310
358
|
search?: {
|
|
311
359
|
index: number;
|
|
@@ -359,6 +407,7 @@ export interface StatusReportInput {
|
|
|
359
407
|
disconnect?: DisconnectPolicyName;
|
|
360
408
|
waitingQuestions: number;
|
|
361
409
|
quota?: QuotaSnapshot;
|
|
410
|
+
context?: ContextPressureView;
|
|
362
411
|
parentModel?: string;
|
|
363
412
|
subProvider?: string;
|
|
364
413
|
subModel: string;
|
|
@@ -573,6 +622,15 @@ export declare function countDiffAddDel(hunks: readonly ToolDiffHunk[] | undefin
|
|
|
573
622
|
*/
|
|
574
623
|
export declare function diffStatToken(add: number, del: number): string;
|
|
575
624
|
export declare function toolTargetPath(name: string, args: string, fallback?: string): string;
|
|
625
|
+
/** Path shown on a compact single-file edit summary. */
|
|
626
|
+
export declare function compactEditPath(item: {
|
|
627
|
+
name: string;
|
|
628
|
+
args: string;
|
|
629
|
+
summary?: string;
|
|
630
|
+
diff?: readonly {
|
|
631
|
+
path?: string;
|
|
632
|
+
}[];
|
|
633
|
+
}): string;
|
|
576
634
|
export declare function countOutputLines(text: string): number;
|
|
577
635
|
/**
|
|
578
636
|
* Consecutive same-path reads (or edits) collapse onto one card.
|
|
@@ -642,6 +700,8 @@ export declare function parseFindQuery(raw: string): {
|
|
|
642
700
|
export declare function promptInjectionSources(text: string, plugin?: string): string[];
|
|
643
701
|
export declare function promptInjectionTitle(sources: readonly string[]): string;
|
|
644
702
|
export declare function isPromptInjectionMessage(sourceKind: string, text: string, plugin?: string): boolean;
|
|
703
|
+
/** Official `/compact` idle-only failures, mapped to a local sentence. */
|
|
704
|
+
export declare function formatCompactCommandError(text: string): string;
|
|
645
705
|
export declare function compactionHeaderText(row: {
|
|
646
706
|
status: 'running' | 'ok' | 'error';
|
|
647
707
|
pruneCount: number;
|
|
@@ -822,6 +882,8 @@ export declare class SshTui {
|
|
|
822
882
|
private activeSubagents;
|
|
823
883
|
private subagentSessions;
|
|
824
884
|
private openToolCalls;
|
|
885
|
+
/** Survives result settlement so a card-less result can still be labelled. */
|
|
886
|
+
private toolCallNames;
|
|
825
887
|
private readonly stats;
|
|
826
888
|
private openStepStats;
|
|
827
889
|
private readonly pendingToolTimes;
|
|
@@ -859,6 +921,10 @@ export declare class SshTui {
|
|
|
859
921
|
private quotaAlerted;
|
|
860
922
|
private quotaStepsSinceRefresh;
|
|
861
923
|
private quotaRefreshInFlight;
|
|
924
|
+
private contextPressure;
|
|
925
|
+
private contextAlertLevel;
|
|
926
|
+
private idleCompactInFlight;
|
|
927
|
+
private lastIdleCompactAt;
|
|
862
928
|
private searchHits;
|
|
863
929
|
private searchIndex;
|
|
864
930
|
private searchQuery;
|
|
@@ -936,6 +1002,8 @@ export declare class SshTui {
|
|
|
936
1002
|
private markDirty;
|
|
937
1003
|
private toolCardSummary;
|
|
938
1004
|
private mergeIntoToolCard;
|
|
1005
|
+
private findToolRowByCallId;
|
|
1006
|
+
private findMergeableToolRow;
|
|
939
1007
|
/** Append one transcript row, bounding memory on long sessions. */
|
|
940
1008
|
private pushRow;
|
|
941
1009
|
/** The transcript rows that support per-row expand/collapse. */
|
|
@@ -959,8 +1027,8 @@ export declare class SshTui {
|
|
|
959
1027
|
private upsertPlanRow;
|
|
960
1028
|
/** Whether the live plan strip should occupy the workspace footer. */
|
|
961
1029
|
private shouldDockPlan;
|
|
962
|
-
/**
|
|
963
|
-
private
|
|
1030
|
+
/** Send the leftover-todo nudge only from true idle, so /compact is not blocked. */
|
|
1031
|
+
private flushPlanCloseNudge;
|
|
964
1032
|
/** Compact web-style plan strip pinned above the input, not in the transcript. */
|
|
965
1033
|
private paintPlanDock;
|
|
966
1034
|
private paintToolBodyLine;
|
|
@@ -1022,6 +1090,11 @@ export declare class SshTui {
|
|
|
1022
1090
|
private handleExtensionEvent;
|
|
1023
1091
|
private findCompactionRow;
|
|
1024
1092
|
private handleCompactionEvent;
|
|
1093
|
+
private readContextPressure;
|
|
1094
|
+
private refreshContextPressure;
|
|
1095
|
+
private canRunCompactCommand;
|
|
1096
|
+
private maybeIdleAutoCompact;
|
|
1097
|
+
private dispatchCompactCommand;
|
|
1025
1098
|
private handleCommandRun;
|
|
1026
1099
|
private formatCommandText;
|
|
1027
1100
|
private handleCommandDone;
|
|
@@ -1047,7 +1120,8 @@ export declare class SshTui {
|
|
|
1047
1120
|
* output was unusable (caller falls back to prompt/reject).
|
|
1048
1121
|
*/
|
|
1049
1122
|
private reviewUnknownWithModel;
|
|
1050
|
-
private
|
|
1123
|
+
private recordAutoApproval;
|
|
1124
|
+
readonly handleApproval: (request: ApprovalRequest, _next: () => Promise<ApprovalOutcome>) => Promise<ApprovalOutcome>;
|
|
1051
1125
|
readonly handleUserQuestions: (request: AskUserQuestionRequest) => Promise<AskUserQuestionAnswer>;
|
|
1052
1126
|
/** Queue one dialog behind an already-open one instead of overwriting it. */
|
|
1053
1127
|
private openDialog;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-ssh-tui",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
4
4
|
"description": "SSH-friendly interactive terminal TUI plugin for DeepSeek Harness",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|
|
@@ -56,12 +56,12 @@
|
|
|
56
56
|
"patch": "./cordis.patch.yml"
|
|
57
57
|
},
|
|
58
58
|
"compatibility": {
|
|
59
|
-
"dsh": ">=0.1.1-rc.2 <0.
|
|
59
|
+
"dsh": ">=0.1.1-rc.2 <0.1.3",
|
|
60
60
|
"dshReleases": {
|
|
61
61
|
"0.1.2-rc.1": "compatible",
|
|
62
62
|
"0.1.3-alpha.1": "unknown",
|
|
63
|
-
"0.1.3-alpha.2": "
|
|
64
|
-
"0.1.5-alpha.1": "
|
|
63
|
+
"0.1.3-alpha.2": "incompatible",
|
|
64
|
+
"0.1.5-alpha.1": "incompatible"
|
|
65
65
|
},
|
|
66
66
|
"profiles": ["tui"]
|
|
67
67
|
}
|