@toddzheng024/dscode-bundle 0.1.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/LICENSE +21 -0
- package/README.md +5 -0
- package/THIRD_PARTY_NOTICES.md +11 -0
- package/bin/apply_patch +4 -0
- package/bootstrap.mjs +21 -0
- package/cordis.patch.yml +756 -0
- package/package.json +327 -0
- package/plugins/auto-review/audit.mjs +20 -0
- package/plugins/auto-review/index.mjs +181 -0
- package/plugins/auto-review/policy.mjs +59 -0
- package/plugins/dscode/index.mjs +35 -0
- package/plugins/session-metrics/index.mjs +44 -0
- package/plugins/session-metrics/pricing.mjs +18 -0
- package/plugins/session-metrics/store.mjs +24 -0
- package/plugins/session-metrics/view.mjs +58 -0
- package/plugins/tui-tools/hooks.mjs +23 -0
- package/plugins/tui-tools/index.mjs +164 -0
- package/plugins/ultra/policy.mjs +11 -0
- package/presets/dscode/agent.cordis.yml +288 -0
- package/presets/dscode/preset.yml +3 -0
- package/vendor/bash/LICENSE +21 -0
- package/vendor/bash/index.js +449 -0
- package/vendor/bash/types/background.d.ts +19 -0
- package/vendor/bash/types/index.d.ts +22 -0
- package/vendor/bash/types/render.d.ts +38 -0
- package/vendor/deepseek/LICENSE +21 -0
- package/vendor/deepseek/index.js +2102 -0
- package/vendor/deepseek/types/adapter.d.ts +163 -0
- package/vendor/deepseek/types/file-id.d.ts +19 -0
- package/vendor/deepseek/types/file-store.d.ts +83 -0
- package/vendor/deepseek/types/files-api.d.ts +103 -0
- package/vendor/deepseek/types/image-tokens.d.ts +19 -0
- package/vendor/deepseek/types/index.d.ts +106 -0
- package/vendor/deepseek/types/request-pricing.d.ts +48 -0
- package/vendor/deepseek/types/serialize.d.ts +85 -0
- package/vendor/deepseek/types/sse.d.ts +24 -0
- package/vendor/deepseek/types/translate.d.ts +37 -0
- package/vendor/deepseek/types/types.d.ts +178 -0
- package/vendor/deepseek/types/upload-index.d.ts +68 -0
- package/vendor/persistent/LICENSE +21 -0
- package/vendor/persistent/index.js +386 -0
- package/vendor/persistent/types/index.d.ts +24 -0
- package/vendor/tui/LICENSE +21 -0
- package/vendor/tui/devtools-CdTl3MNy.mjs +3643 -0
- package/vendor/tui/index.mjs +39105 -0
- package/vendor/tui/invariant.mjs +21 -0
- package/vendor/tui/rolldown-runtime-CMFfr-1z.mjs +26 -0
- package/vendor/tui/startup.mjs +109 -0
- package/vendor/tui/theme-DCT8Y2xf.mjs +628 -0
- package/vendor/tui/types/app.d.ts +304 -0
- package/vendor/tui/types/approval.d.ts +59 -0
- package/vendor/tui/types/attachments.d.ts +52 -0
- package/vendor/tui/types/authorization-panel.d.ts +22 -0
- package/vendor/tui/types/authorization.d.ts +36 -0
- package/vendor/tui/types/commands.d.ts +52 -0
- package/vendor/tui/types/editor-keys.d.ts +105 -0
- package/vendor/tui/types/editor.d.ts +6 -0
- package/vendor/tui/types/fork.d.ts +8 -0
- package/vendor/tui/types/git-workflow.d.ts +32 -0
- package/vendor/tui/types/history.d.ts +97 -0
- package/vendor/tui/types/index.d.ts +124 -0
- package/vendor/tui/types/input-split.d.ts +54 -0
- package/vendor/tui/types/internals.d.ts +26 -0
- package/vendor/tui/types/invariant.d.ts +15 -0
- package/vendor/tui/types/kernel-panels.d.ts +167 -0
- package/vendor/tui/types/keyboard.d.ts +80 -0
- package/vendor/tui/types/mentions.d.ts +81 -0
- package/vendor/tui/types/model-capabilities.d.ts +82 -0
- package/vendor/tui/types/models.d.ts +119 -0
- package/vendor/tui/types/permissions.d.ts +27 -0
- package/vendor/tui/types/plugin-inventory.d.ts +11 -0
- package/vendor/tui/types/presets.d.ts +22 -0
- package/vendor/tui/types/provider-settings.d.ts +239 -0
- package/vendor/tui/types/questions.d.ts +54 -0
- package/vendor/tui/types/render/animations.d.ts +265 -0
- package/vendor/tui/types/render/editor.d.ts +162 -0
- package/vendor/tui/types/render/export.d.ts +9 -0
- package/vendor/tui/types/render/fuzzy.d.ts +21 -0
- package/vendor/tui/types/render/inspector.d.ts +36 -0
- package/vendor/tui/types/render/lines.d.ts +66 -0
- package/vendor/tui/types/render/markdown.d.ts +29 -0
- package/vendor/tui/types/render/projection.d.ts +461 -0
- package/vendor/tui/types/render/status.d.ts +196 -0
- package/vendor/tui/types/render/text.d.ts +58 -0
- package/vendor/tui/types/render/tool-detail.d.ts +94 -0
- package/vendor/tui/types/render/tool-preview.d.ts +28 -0
- package/vendor/tui/types/render/width.d.ts +29 -0
- package/vendor/tui/types/session-directory.d.ts +173 -0
- package/vendor/tui/types/session-switch.d.ts +17 -0
- package/vendor/tui/types/settings-file.d.ts +41 -0
- package/vendor/tui/types/skills.d.ts +47 -0
- package/vendor/tui/types/startup.d.ts +65 -0
- package/vendor/tui/types/store.d.ts +58 -0
- package/vendor/tui/types/subagents.d.ts +70 -0
- package/vendor/tui/types/theme-panel.d.ts +24 -0
- package/vendor/tui/types/theme.d.ts +215 -0
- package/vendor/tui/types/version.d.ts +18 -0
- package/vendor/tui/types/whale-glyph.d.ts +6 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Display-boundary sanitization for externally sourced text (model output,
|
|
3
|
+
* tool payloads, skill descriptions). Control characters — including ANSI
|
|
4
|
+
* CSI/OSC escape sequences — would otherwise pass through Ink into the
|
|
5
|
+
* terminal, letting output rewrite the screen or inject prompts. Newlines
|
|
6
|
+
* survive; everything else in C0/C1 plus DEL becomes a visible `\xNN`
|
|
7
|
+
* escape, and bidi overrides / invisible format controls / Unicode line and
|
|
8
|
+
* paragraph separators become a visible `\uXXXX` escape (terminal emulators
|
|
9
|
+
* that render bidirectional text would otherwise reorder the displayed
|
|
10
|
+
* glyphs and let a command read as something it is not).
|
|
11
|
+
*
|
|
12
|
+
* @module @deepseek-ai/dsh-code/render/text
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Escape control and deceptive characters so externally sourced text cannot
|
|
16
|
+
* drive the terminal. C0/C1/DEL render as a literal `\xNN` escape; bidi,
|
|
17
|
+
* invisible-format, and separator controls render as a literal `\uXXXX`
|
|
18
|
+
* escape. Newlines and tabs survive (budgeted callers normalize tabs).
|
|
19
|
+
* @param text - raw text from a session event, tool payload, or catalog.
|
|
20
|
+
* @returns display-safe text with every injectable character made visible.
|
|
21
|
+
*/
|
|
22
|
+
export declare function displayText(text: string): string;
|
|
23
|
+
/** Collapse external text to one terminal-safe logical row. */
|
|
24
|
+
export declare function singleLineText(text: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Truncate one display-safe row without ever exceeding its physical-column
|
|
27
|
+
* budget. The ellipsis is included inside the budget, matching Codex's popup
|
|
28
|
+
* truncation contract; the cut walks grapheme clusters so emoji and
|
|
29
|
+
* combining sequences never split mid-cluster.
|
|
30
|
+
*/
|
|
31
|
+
export declare function truncateColumns(text: string, columns: number): string;
|
|
32
|
+
/** A display-safe suffix bounded by terminal rows and columns. */
|
|
33
|
+
export interface DisplayTail {
|
|
34
|
+
/** Sanitized suffix suitable for direct terminal rendering. */
|
|
35
|
+
text: string;
|
|
36
|
+
/** Whether content before the returned suffix was omitted. */
|
|
37
|
+
truncated: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Keep the newest display-safe text that fits a terminal rectangle, wrapping
|
|
41
|
+
* FORWARD from the start of the text and slicing the tail rows.
|
|
42
|
+
*
|
|
43
|
+
* Forward wrapping is what keeps a streaming tail calm: rows already produced
|
|
44
|
+
* never re-wrap as tokens append (a backward scan recomputes every wrap point
|
|
45
|
+
* per chunk and the whole visible block jumps), and the wrap rules match the
|
|
46
|
+
* settled text's renderer so the flush at turn end does not reflow the block
|
|
47
|
+
* a second time. CJK kinsoku applies at both edges: closing punctuation
|
|
48
|
+
* overhangs up to two cells onto the filled row instead of starting the next
|
|
49
|
+
* one (within the caret column the caller reserves), and opening punctuation
|
|
50
|
+
* moves down instead of dangling at a row end. Tabs expand to two spaces so
|
|
51
|
+
* terminal tab stops cannot inflate the physical row count; clusters carry
|
|
52
|
+
* emoji presentation and combining marks whole.
|
|
53
|
+
* @param text - raw externally sourced text.
|
|
54
|
+
* @param columns - available terminal columns.
|
|
55
|
+
* @param rows - available terminal rows.
|
|
56
|
+
* @returns a sanitized bounded suffix and whether an earlier prefix was cut.
|
|
57
|
+
*/
|
|
58
|
+
export declare function displayTail(text: string, columns: number, rows: number): DisplayTail;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Expansion payloads for tool cards (the Ctrl+O verbose transcript): the
|
|
3
|
+
* TUI-side consumption of the harness presentation contract. Mutation and
|
|
4
|
+
* read tools persist a structured `tool/result.meta` (`diffs`, read
|
|
5
|
+
* windows, web sources) exactly so a capable UI can replay richer cards than
|
|
6
|
+
* the model-facing text; this module narrows that opaque JSON defensively —
|
|
7
|
+
* mirroring the upstream validators — and pre-formats bounded, render-ready
|
|
8
|
+
* rows. Malformed or absent metadata always degrades to the bounded raw
|
|
9
|
+
* result text, never throws during replay.
|
|
10
|
+
*
|
|
11
|
+
* @module @deepseek-ai/dsh-code/render/tool-detail
|
|
12
|
+
*/
|
|
13
|
+
/** One rendered diff row: removed, added, or shared context. */
|
|
14
|
+
export interface DiffLine {
|
|
15
|
+
/** '-' removed, '+' added, ' ' context. */
|
|
16
|
+
mark: '-' | '+' | ' ';
|
|
17
|
+
/** The line text, truncated to the column budget. */
|
|
18
|
+
text: string;
|
|
19
|
+
}
|
|
20
|
+
/** One file's bounded inline diff. */
|
|
21
|
+
export interface ToolDiff {
|
|
22
|
+
/** File path the change belongs to. */
|
|
23
|
+
path: string;
|
|
24
|
+
/** Rendered rows in order; '-' block before the '+' block. */
|
|
25
|
+
lines: readonly DiffLine[];
|
|
26
|
+
/** True when the line budget cut the hunk. */
|
|
27
|
+
truncated: boolean;
|
|
28
|
+
}
|
|
29
|
+
/** One numbered line of a read window. */
|
|
30
|
+
export interface ToolReadLine {
|
|
31
|
+
/** 1-based file line number. */
|
|
32
|
+
number: number;
|
|
33
|
+
/** The line text, truncated to the column budget. */
|
|
34
|
+
text: string;
|
|
35
|
+
}
|
|
36
|
+
/** One web-search source row. */
|
|
37
|
+
export interface ToolWebSource {
|
|
38
|
+
/** Source URL. */
|
|
39
|
+
url: string;
|
|
40
|
+
/** Source title, when the provider returned one. */
|
|
41
|
+
title: string | undefined;
|
|
42
|
+
/** Short excerpt, truncated to the column budget. */
|
|
43
|
+
snippet: string;
|
|
44
|
+
}
|
|
45
|
+
/** The expansion payload a verbose tool card renders; a discriminated union. */
|
|
46
|
+
export type ToolDetail = {
|
|
47
|
+
kind: 'diff';
|
|
48
|
+
diffs: readonly ToolDiff[];
|
|
49
|
+
} | {
|
|
50
|
+
kind: 'read';
|
|
51
|
+
path: string;
|
|
52
|
+
offset: number;
|
|
53
|
+
lines: readonly ToolReadLine[];
|
|
54
|
+
totalLines: number;
|
|
55
|
+
truncated: boolean;
|
|
56
|
+
} | {
|
|
57
|
+
kind: 'web-search';
|
|
58
|
+
sources: readonly ToolWebSource[];
|
|
59
|
+
truncated: boolean;
|
|
60
|
+
} | {
|
|
61
|
+
kind: 'web-fetch';
|
|
62
|
+
url: string;
|
|
63
|
+
statusCode: number;
|
|
64
|
+
} | {
|
|
65
|
+
kind: 'raw';
|
|
66
|
+
text: string;
|
|
67
|
+
truncated: boolean;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Render one change as removed-then-added rows, hunked by common prefix and
|
|
71
|
+
* suffix. A null before-image (file create) renders as pure additions. The
|
|
72
|
+
* budget caps emitted rows and reports the cut, so a whole-file overwrite
|
|
73
|
+
* never floods the transcript. Inputs are hard-capped before line splitting
|
|
74
|
+
* and the row list is built incrementally up to the budget — a crafted or
|
|
75
|
+
* replayed giant diff cannot force a full intermediate rows array.
|
|
76
|
+
* @param oldText - prior content, or null for a create.
|
|
77
|
+
* @param newText - content after the change.
|
|
78
|
+
* @param budget - maximum rows to emit.
|
|
79
|
+
* @returns the bounded rows and whether they were cut.
|
|
80
|
+
*/
|
|
81
|
+
export declare function diffRows(oldText: string | null, newText: string, budget: number): {
|
|
82
|
+
lines: readonly DiffLine[];
|
|
83
|
+
truncated: boolean;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Narrow the opaque `tool/result.meta` into one bounded expansion payload,
|
|
87
|
+
* mirroring the upstream presenters' degradation ladder: diffs (write/edit),
|
|
88
|
+
* read windows (read), sources (web_search), fetch summaries (web_fetch), and
|
|
89
|
+
* the bounded raw result text as the universal fallback.
|
|
90
|
+
* @param meta - the persisted presentation metadata, when the tool attached one.
|
|
91
|
+
* @param rawText - the joined text blocks of the result message.
|
|
92
|
+
* @returns the expansion payload, or undefined when nothing renderable exists.
|
|
93
|
+
*/
|
|
94
|
+
export declare function toolResultDetail(meta: unknown, rawText: string): ToolDetail | undefined;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded preview line for a tool invocation's raw JSON arguments: the first
|
|
3
|
+
* human-meaningful string among the well-known keys (command, path, query, …)
|
|
4
|
+
* with a fallback to the bounded raw JSON. Shared by the tool card in the
|
|
5
|
+
* transcript and the approval bar's command preview. Arguments longer than
|
|
6
|
+
* {@link MAX_PARSE_CHARS} are never parsed: the preview is a display concern,
|
|
7
|
+
* and a synchronous `JSON.parse` plus string copies of an unbounded model
|
|
8
|
+
* payload must not run on the approval or projection paths.
|
|
9
|
+
*
|
|
10
|
+
* @module @deepseek-ai/dsh-code/render/tool-preview
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Resolve one bounded preview for raw tool arguments.
|
|
14
|
+
* @param args - raw JSON arguments string as the model produced it.
|
|
15
|
+
* @param toolName - the tool the arguments belong to (fallback label).
|
|
16
|
+
* @returns the preview line; empty when nothing useful resolves.
|
|
17
|
+
*/
|
|
18
|
+
export declare function toolArgumentsPreview(args: string, toolName: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Bounded prompt preview for delegation-style tools (`subagent`): the
|
|
21
|
+
* `prompt` argument rendered as the card's second row, so the transcript
|
|
22
|
+
* shows what the child agent was asked — not just its description label —
|
|
23
|
+
* while it runs (Codex's SpawnAgent card preview). Anything else returns ''.
|
|
24
|
+
* @param toolName - the tool the arguments belong to.
|
|
25
|
+
* @param args - raw JSON arguments string as the model produced it.
|
|
26
|
+
* @returns the one-line prompt preview, or '' when none applies.
|
|
27
|
+
*/
|
|
28
|
+
export declare function toolPromptPreview(toolName: string, args: string): string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Precise terminal-cell width measurement — the single authority every
|
|
3
|
+
* budget, wrap, and truncation path shares. The previous heuristic
|
|
4
|
+
* (`codePoint > 0x2e7f ? 2 : 1)) mis-sized Hangul Jamo (narrow), high
|
|
5
|
+
* non-CJK code points (wide), and emoji: text-default glyphs like ✳ ⚠ ❤
|
|
6
|
+
* counted 2 while terminals draw 1, and VS16 sequences counted 1 while
|
|
7
|
+
* terminals draw 2 — the exact drift class the community dsh-TUI string
|
|
8
|
+
* engine documents (a spinner glyph drifting one column per frame). This
|
|
9
|
+
* module adapts that engine's rules without its Ink-fork renderer: an ASCII
|
|
10
|
+
* fast path, grapheme-cluster iteration via Intl.Segmenter (code-point
|
|
11
|
+
* fallback), a merged East-Asian-Wide/Fullwidth + Emoji_Presentation range
|
|
12
|
+
* table, text-default emoji = 1, VS16 = 2, marks/selectors/ZWJ = 0.
|
|
13
|
+
* @module @deepseek-ai/dsh-code/render/width
|
|
14
|
+
*/
|
|
15
|
+
/** Split text into grapheme clusters (code points when Segmenter is absent). */
|
|
16
|
+
export declare function splitGraphemes(text: string): string[];
|
|
17
|
+
/** Terminal-cell width of one grapheme cluster. */
|
|
18
|
+
export declare function graphemeWidth(cluster: string): number;
|
|
19
|
+
/** Terminal-cell width of one code point (surrogate pairs must stay paired). */
|
|
20
|
+
export declare function codePointWidth(char: string): number;
|
|
21
|
+
/**
|
|
22
|
+
* Terminal-cell width of a string: an ASCII fast path avoids the segmenter
|
|
23
|
+
* for the overwhelmingly common case; everything else sums grapheme clusters.
|
|
24
|
+
* Control characters occupy no cells (display sanitization makes them
|
|
25
|
+
* visible escapes before they ever reach a budget).
|
|
26
|
+
* @param text - display-safe or raw text to measure.
|
|
27
|
+
* @returns the column count the terminal will draw.
|
|
28
|
+
*/
|
|
29
|
+
export declare function stringWidth(text: string): number;
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/** Lightweight session-directory projection for the /resume picker. */
|
|
2
|
+
import { type SessionEvent, type SessionHeader } from '@deepseek-ai/dsh-session';
|
|
3
|
+
export interface SessionRecord {
|
|
4
|
+
readonly header: SessionHeader;
|
|
5
|
+
readonly live: boolean;
|
|
6
|
+
readonly persisted: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface TitleObservationResult {
|
|
9
|
+
readonly sessionId: string;
|
|
10
|
+
readonly status: 'fulfilled' | 'rejected';
|
|
11
|
+
readonly value?: {
|
|
12
|
+
readonly title?: {
|
|
13
|
+
readonly title?: string;
|
|
14
|
+
readonly text?: string;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export interface SessionLogSnapshot {
|
|
19
|
+
readonly session: SessionHeader;
|
|
20
|
+
readonly events: SessionEvent[];
|
|
21
|
+
}
|
|
22
|
+
/** Structural upstream SessionQuery surface used by the TUI. */
|
|
23
|
+
export interface SessionQueryService {
|
|
24
|
+
listSessions(signal?: AbortSignal): Promise<SessionRecord[]>;
|
|
25
|
+
readTitleSnapshots(ids: readonly string[], signal?: AbortSignal): Promise<TitleObservationResult[]>;
|
|
26
|
+
readSession(id: string, signal?: AbortSignal): Promise<SessionLogSnapshot>;
|
|
27
|
+
}
|
|
28
|
+
export type SessionScope = 'roots' | 'all';
|
|
29
|
+
export type CwdScope = 'all' | 'current';
|
|
30
|
+
export type SessionSort = 'newest' | 'oldest';
|
|
31
|
+
export interface SessionDirectoryOptions {
|
|
32
|
+
readonly sessions: SessionScope;
|
|
33
|
+
readonly cwd: CwdScope;
|
|
34
|
+
readonly sort: SessionSort;
|
|
35
|
+
readonly currentCwd: string;
|
|
36
|
+
readonly query: string;
|
|
37
|
+
}
|
|
38
|
+
export interface SessionRow {
|
|
39
|
+
readonly id: string;
|
|
40
|
+
readonly createdAt: number;
|
|
41
|
+
/** Last-activity timestamp: artifact mtime when known, else createdAt. */
|
|
42
|
+
readonly updatedAt: number;
|
|
43
|
+
readonly cwd: string;
|
|
44
|
+
readonly workspace: string;
|
|
45
|
+
readonly parent?: string;
|
|
46
|
+
readonly subagent: boolean;
|
|
47
|
+
readonly resumable: boolean;
|
|
48
|
+
readonly live: boolean;
|
|
49
|
+
readonly persisted: boolean;
|
|
50
|
+
readonly preset: string;
|
|
51
|
+
readonly title?: string;
|
|
52
|
+
}
|
|
53
|
+
/** True only for delegated subagents; ordinary forks also carry lineage. */
|
|
54
|
+
export declare function isSubagentSession(header: SessionHeader): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Unique header match by exact id or unique id prefix (root and subagent
|
|
57
|
+
* headers alike); the caller applies any lineage gate.
|
|
58
|
+
* @param headers - the persisted headers.
|
|
59
|
+
* @param wanted - the id or id prefix.
|
|
60
|
+
* @returns the uniquely matched header.
|
|
61
|
+
* @throws when nothing matches or the prefix is ambiguous.
|
|
62
|
+
*/
|
|
63
|
+
export declare function matchSessionId(headers: readonly SessionHeader[], wanted: string): SessionHeader;
|
|
64
|
+
/** The newest persisted ROOT session pinned to this cwd, or undefined. */
|
|
65
|
+
export declare function newestRootForCwd(headers: readonly SessionHeader[], cwd: string): SessionHeader | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* Filter/sort header-only records. No session log is loaded here. Sorting is
|
|
68
|
+
* by LAST ACTIVITY (`updated` — artifact mtime when the caller resolved one,
|
|
69
|
+
* else createdAt), matching the codex resume picker's default UpdatedAt
|
|
70
|
+
* ordering: a session you kept talking in outranks one created later but idle.
|
|
71
|
+
* @param records - the header-only records.
|
|
72
|
+
* @param options - filter/sort options.
|
|
73
|
+
* @param updated - per-session last-activity timestamps, when resolved.
|
|
74
|
+
*/
|
|
75
|
+
export declare function projectSessionRows(records: readonly SessionRecord[], options: SessionDirectoryOptions, updated?: ReadonlyMap<string, number>): SessionRow[];
|
|
76
|
+
/** Merge page-local title observations without disturbing directory order. */
|
|
77
|
+
export declare function mergeSessionTitles(rows: readonly SessionRow[], observations: readonly TitleObservationResult[]): SessionRow[];
|
|
78
|
+
/**
|
|
79
|
+
* Encode a session id the way the JSONL backend does for its on-disk layout
|
|
80
|
+
* (`encodeSegment`: safe units literal, everything else `~XXXX`). Used to
|
|
81
|
+
* validate and derive session directories — a local copy of the pure upstream
|
|
82
|
+
* contract, kept in sync with `session-persistence-jsonl/src/format.ts`.
|
|
83
|
+
*/
|
|
84
|
+
export declare function encodeSessionSegment(raw: string): string;
|
|
85
|
+
/**
|
|
86
|
+
* Encode a project cwd the way the JSONL backend groups sessions on disk
|
|
87
|
+
* (`projectKey`: separators collapse to one `-`, everything else mirrors
|
|
88
|
+
* `encodeSegment`, bounded to 251 chars). A local copy of the pure upstream
|
|
89
|
+
* contract, kept in sync with `session-persistence-jsonl/src/format.ts`.
|
|
90
|
+
*/
|
|
91
|
+
export declare function encodeProjectKey(cwd: string): string;
|
|
92
|
+
/**
|
|
93
|
+
* Derive one session's artifact directory under the JSONL backend root,
|
|
94
|
+
* mirroring the upstream `<root>/<projectKey(cwd)>/<encodeSegment(id)>/`
|
|
95
|
+
* layout (0.1.5 `sessionDir`/`projectDir`).
|
|
96
|
+
* @param root - the JSONL backend's configured session root.
|
|
97
|
+
* @param cwd - the session's pinned working directory, when the header has one.
|
|
98
|
+
* @param id - the session id.
|
|
99
|
+
* @returns the absolute session directory path.
|
|
100
|
+
*/
|
|
101
|
+
export declare function sessionDirectoryFor(root: string, cwd: string | undefined, id: string): string;
|
|
102
|
+
/**
|
|
103
|
+
* The canonical session-log artifact filenames the JSONL backend may create:
|
|
104
|
+
* format v0 writes the bare `session.jsonl` name; v1+ write
|
|
105
|
+
* `session.vN.jsonl`, each generation optionally zstd-compressed. Multiple
|
|
106
|
+
* immutable generations may coexist in one session directory (0.1.5). The
|
|
107
|
+
* range follows the installed session package's `SESSION_FORMAT_VERSION`, so
|
|
108
|
+
* a future generation joins the enumeration with the dependency bump.
|
|
109
|
+
*/
|
|
110
|
+
export declare function sessionArtifactNames(): readonly string[];
|
|
111
|
+
/** True for one canonical session-log artifact filename the backend may own. */
|
|
112
|
+
export declare function isSessionArtifactName(name: string): boolean;
|
|
113
|
+
/**
|
|
114
|
+
* Guard a derived session directory before deletion (codex's scoped-path
|
|
115
|
+
* check, adapted to the JSONL layout): the directory's base name must be
|
|
116
|
+
* exactly `encodeSegment(id)` beneath its project grouping.
|
|
117
|
+
* @param dir - the derived session artifact directory.
|
|
118
|
+
* @param id - the session id the directory claims to belong to.
|
|
119
|
+
* @returns the guarded directory, or undefined when the layout is unexpected.
|
|
120
|
+
*/
|
|
121
|
+
export declare function sessionArtifactDirectory(dir: string, id: string): string | undefined;
|
|
122
|
+
/**
|
|
123
|
+
* The JSONL backend's configured session root, when the mounted backend
|
|
124
|
+
* exposes one. The upstream service contract dropped `locate()` in 0.1.5
|
|
125
|
+
* (artifact paths are backend-private; only refusal diagnostics carry them),
|
|
126
|
+
* so the TUI derives artifact paths from the backend's public plugin config.
|
|
127
|
+
* Backends without a JSONL-style config (or a foreign shape) yield undefined
|
|
128
|
+
* and callers degrade: mtime sorting falls back to createdAt and /delete
|
|
129
|
+
* refuses, exactly as before.
|
|
130
|
+
*/
|
|
131
|
+
export declare function jsonlSessionRoot(persistence: unknown): string | undefined;
|
|
132
|
+
/**
|
|
133
|
+
* Collect one session's deletion subtree: the id plus every record whose
|
|
134
|
+
* parent chain leads to it (codex deletes subagent threads with their root).
|
|
135
|
+
* @param records - the full directory listing.
|
|
136
|
+
* @param id - the root session id to delete.
|
|
137
|
+
* @returns the ids to delete, root first.
|
|
138
|
+
*/
|
|
139
|
+
export declare function collectDeletionSubtree(records: readonly SessionRecord[], id: string): string[];
|
|
140
|
+
/** One validated node of a deletion plan. */
|
|
141
|
+
export interface DeletionPlanNode {
|
|
142
|
+
/** Session id to remove. */
|
|
143
|
+
readonly id: string;
|
|
144
|
+
/** Distance from the deletion root (0 for the root itself). */
|
|
145
|
+
readonly depth: number;
|
|
146
|
+
}
|
|
147
|
+
/** A fully preflighted subtree deletion, or the refusal that produced none. */
|
|
148
|
+
export type SessionDeletionPlan = {
|
|
149
|
+
readonly ok: true;
|
|
150
|
+
readonly nodes: readonly DeletionPlanNode[];
|
|
151
|
+
} | {
|
|
152
|
+
readonly ok: false;
|
|
153
|
+
readonly reason: string;
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* Plan one session-subtree deletion with NO filesystem side effects: collect
|
|
157
|
+
* the doomed lineage, refuse when the root or ANY member is live (a live
|
|
158
|
+
* child would outlive its deleted parent) or missing from the listing, and
|
|
159
|
+
* order the result children-first so the executor can never leave a deleted
|
|
160
|
+
* parent behind surviving children. Artifact-location guards stay at the
|
|
161
|
+
* call site; this is the pure preflight they complete.
|
|
162
|
+
* @param records - the full directory listing.
|
|
163
|
+
* @param id - the root session id to delete.
|
|
164
|
+
* @returns the ordered plan, or a user-facing refusal reason.
|
|
165
|
+
*/
|
|
166
|
+
export declare function planSessionDeletion(records: readonly SessionRecord[], id: string): SessionDeletionPlan;
|
|
167
|
+
/**
|
|
168
|
+
* Codex-style relative time for session rows ("now", "5m ago", "3h ago",
|
|
169
|
+
* "2d ago"; older than a week falls back to the local date).
|
|
170
|
+
* @param timestamp - epoch milliseconds of the last activity.
|
|
171
|
+
* @param now - the pinned reference clock (one value per list render).
|
|
172
|
+
*/
|
|
173
|
+
export declare function formatRelativeTime(timestamp: number, now: number): string;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Latest-wins, idle-bound queue for safe Agent session changes. */
|
|
2
|
+
export interface IdleActivity {
|
|
3
|
+
readonly status: 'idle' | 'running';
|
|
4
|
+
whenIdle(): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
export declare class SessionSwitchQueue<T> {
|
|
7
|
+
private readonly execute;
|
|
8
|
+
private readonly failed;
|
|
9
|
+
private pending;
|
|
10
|
+
private pumping;
|
|
11
|
+
constructor(execute: (value: T) => Promise<void>, failed: (error: unknown) => void);
|
|
12
|
+
/** Queue a request; a later request replaces any request still waiting. */
|
|
13
|
+
request(activity: IdleActivity, value: T): 'queued' | 'started';
|
|
14
|
+
/** Cancel only work that has not begun activation. */
|
|
15
|
+
cancel(): boolean;
|
|
16
|
+
private pump;
|
|
17
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serialized, crash-atomic persistence for the small user-level JSON files
|
|
3
|
+
* under the DSH home (statusline.json, theme.json). Two guarantees the bare
|
|
4
|
+
* floating `writeFile` path could not give:
|
|
5
|
+
*
|
|
6
|
+
* 1. Every save is appended to ONE chain, so rapid consecutive edits land
|
|
7
|
+
* in submission order and the last snapshot is the one on disk (parallel
|
|
8
|
+
* floating writes let an older snapshot finish last and win).
|
|
9
|
+
* 2. Each write goes to a sibling temp file first and is renamed into
|
|
10
|
+
* place, so a crash mid-write can never leave a half-written JSON
|
|
11
|
+
* document behind.
|
|
12
|
+
*
|
|
13
|
+
* The chain itself never rejects: a failed write is reported to that
|
|
14
|
+
* save's caller while later saves keep their turn.
|
|
15
|
+
*
|
|
16
|
+
* @module @deepseek-ai/dsh-code/settings-file
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Write one file atomically: create the parent directory, write to a
|
|
20
|
+
* uniquely named temp file, and rename it into place. A crash midway
|
|
21
|
+
* can never leave a half-written document behind. Unique temp names
|
|
22
|
+
* keep concurrent writers (two terminals, two chains in one process)
|
|
23
|
+
* from sharing one temp path.
|
|
24
|
+
*/
|
|
25
|
+
export declare function writeFileAtomically(path: string, text: string): Promise<void>;
|
|
26
|
+
/** The serialized persistence surface; flush() is handed to the quit sequence. */
|
|
27
|
+
export interface UserSettingsPersistence {
|
|
28
|
+
/**
|
|
29
|
+
* Queue one file snapshot. Resolves when the chain reaches (and renames)
|
|
30
|
+
* it; rejects only to THIS caller when its own write failed.
|
|
31
|
+
*/
|
|
32
|
+
save(path: string, text: string): Promise<void>;
|
|
33
|
+
/** Wait for every queued write; safe to call repeatedly. */
|
|
34
|
+
flush(): Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Create the shared settings-write chain. One instance per process keeps
|
|
38
|
+
* every user-level JSON file mutually serialized.
|
|
39
|
+
* @returns the persistence handle.
|
|
40
|
+
*/
|
|
41
|
+
export declare function createUserSettingsPersistence(): UserSettingsPersistence;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User-invocable skill watch for the `/` completion menu: the in-process
|
|
3
|
+
* equivalent of the web ui-skill trigger source. Skills are NOT commands —
|
|
4
|
+
* picking one lands the literal `/name ` text in the input, and submitting
|
|
5
|
+
* it as a normal prompt lets the host's tool-skill pre-step inject the body
|
|
6
|
+
* (the only entry point for model-disabled skills). Command descriptors win
|
|
7
|
+
* on a name collision; see the runner's dispatch.
|
|
8
|
+
*
|
|
9
|
+
* @module @deepseek-ai/dsh-code/skills
|
|
10
|
+
*/
|
|
11
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
12
|
+
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
13
|
+
/** One completion-menu row derived from a user-invocable skill. */
|
|
14
|
+
export interface SkillRow {
|
|
15
|
+
/** Skill name; the literal `/name` text is what a pick lands. */
|
|
16
|
+
name: string;
|
|
17
|
+
/** Human-readable description (suffixed when model-invocation is off). */
|
|
18
|
+
description: string;
|
|
19
|
+
/** Whether the model may also invoke this skill by name. */
|
|
20
|
+
modelInvocable: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** The skill-catalog snapshot the completion menu subscribes to. */
|
|
23
|
+
export interface SkillsView {
|
|
24
|
+
/** Name-sorted user-invocable rows; empty until the first load lands. */
|
|
25
|
+
readonly rows: readonly SkillRow[];
|
|
26
|
+
/** Latest catalog-read failure; the help panel exposes it in place. */
|
|
27
|
+
readonly error?: string;
|
|
28
|
+
/** Subscribe to catalog changes; returns the unsubscribe function. */
|
|
29
|
+
subscribe(listener: () => void): () => void;
|
|
30
|
+
/** Retarget the agent whose workspace the catalog is read for. */
|
|
31
|
+
setAgent(agent: Agent): void;
|
|
32
|
+
}
|
|
33
|
+
/** Internal shape shared by {@link watchSkills} and its test doubles. */
|
|
34
|
+
interface SkillsWatch extends SkillsView {
|
|
35
|
+
setAgent(agent: Agent): void;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Watch the user-invocable skill catalog for one agent's workspace. The first
|
|
39
|
+
* load starts when the owning agent is known (`setAgent`); `skills/change`
|
|
40
|
+
* and agent retargets re-read. Read failures keep the last good rows (the
|
|
41
|
+
* next change notification is the retry surface) — a missing `skills`
|
|
42
|
+
* service leaves the view permanently empty.
|
|
43
|
+
* @param ctx - context carrying the `skills` service (optional).
|
|
44
|
+
* @returns the view the completion menu subscribes to.
|
|
45
|
+
*/
|
|
46
|
+
export declare function watchSkills(ctx: Context, fallbackCwd?: string): SkillsWatch;
|
|
47
|
+
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The interactive terminal app's command-line provider: parses `--resume`,
|
|
3
|
+
* `--continue`, `--session`, `--mode`, `--theme`, `--image`, an optional
|
|
4
|
+
* initial prompt, and `--help`, then
|
|
5
|
+
* publishes {@link TUI_STARTUP_SERVICE} for the runner to consume lazily.
|
|
6
|
+
* Follows the headless bundle's startup shape (a commander action publishing
|
|
7
|
+
* a service through {@link parseCmdline}).
|
|
8
|
+
*
|
|
9
|
+
* Semantics:
|
|
10
|
+
* - `--resume <id|prefix>` — continue the persisted session whose id or unique
|
|
11
|
+
* id-prefix matches; the TUI replays its transcript and appends to the same
|
|
12
|
+
* durable log.
|
|
13
|
+
* - `--continue` / `-c` — resume the most recently modified persisted session
|
|
14
|
+
* whose project directory matches the current working directory.
|
|
15
|
+
* - `--session <id>` — create a new session under an explicit identity (the
|
|
16
|
+
* id must not exist yet).
|
|
17
|
+
* - `--theme <dark|light|auto>` — the color palette; auto follows the
|
|
18
|
+
* terminal (dark fallback until OSC-11 detection lands).
|
|
19
|
+
* - no flags — a fresh session with a minted id.
|
|
20
|
+
*
|
|
21
|
+
* @module @deepseek-ai/dsh-tui/startup
|
|
22
|
+
*/
|
|
23
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
24
|
+
import { type ThemeName } from './theme.ts';
|
|
25
|
+
/** Stable Cordis plugin name. */
|
|
26
|
+
export declare const name = "tui-startup";
|
|
27
|
+
/** Services required before the invocation can be resolved. */
|
|
28
|
+
export declare const inject: string[];
|
|
29
|
+
/** How the runner obtains its session identity. */
|
|
30
|
+
export type TuiStartup = ({
|
|
31
|
+
readonly kind: 'fresh';
|
|
32
|
+
readonly mode?: string;
|
|
33
|
+
} & TuiStartupInput) | ({
|
|
34
|
+
readonly kind: 'named';
|
|
35
|
+
readonly sessionId: string;
|
|
36
|
+
readonly mode?: string;
|
|
37
|
+
} & TuiStartupInput) | ({
|
|
38
|
+
readonly kind: 'resume';
|
|
39
|
+
readonly sessionId: string;
|
|
40
|
+
} & TuiStartupInput) | ({
|
|
41
|
+
readonly kind: 'latest';
|
|
42
|
+
} & TuiStartupInput);
|
|
43
|
+
interface TuiStartupInput {
|
|
44
|
+
readonly theme?: ThemeName;
|
|
45
|
+
readonly prompt?: string;
|
|
46
|
+
readonly images?: readonly string[];
|
|
47
|
+
}
|
|
48
|
+
export interface TuiStartupOptions {
|
|
49
|
+
readonly resume?: string;
|
|
50
|
+
readonly continue?: boolean;
|
|
51
|
+
readonly session?: string;
|
|
52
|
+
readonly mode?: string;
|
|
53
|
+
readonly theme?: ThemeName;
|
|
54
|
+
readonly prompt?: string;
|
|
55
|
+
readonly images?: readonly string[];
|
|
56
|
+
}
|
|
57
|
+
/** Pure option policy shared by Commander and tests. */
|
|
58
|
+
export declare function resolveTuiStartup(options: TuiStartupOptions): TuiStartup;
|
|
59
|
+
/**
|
|
60
|
+
* Parse the invocation and publish the startup service. Mutual exclusions are
|
|
61
|
+
* usage errors rejected from the action before anything is provided.
|
|
62
|
+
* @param ctx - plugin context carrying the command line and exit request.
|
|
63
|
+
*/
|
|
64
|
+
export declare function apply(ctx: Context): void;
|
|
65
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observable transcript store: folds session events into the projection view
|
|
3
|
+
* and notifies subscribers. The renderer subscribes through
|
|
4
|
+
* `useSyncExternalStore`; the runner owns event feeding.
|
|
5
|
+
*
|
|
6
|
+
* Folding runs on the same mutable replay accumulator the persisted-log
|
|
7
|
+
* path uses (`replayProjectEvent`: id-indexed row updates, in-place
|
|
8
|
+
* appends), so a live structural event costs O(1) entry work regardless of
|
|
9
|
+
* transcript length — the copy-on-write fold rebuilt the whole entries
|
|
10
|
+
* array per event, making a growing session quadratic. An immutable
|
|
11
|
+
* `TranscriptView` snapshot is materialized only when a changed view is
|
|
12
|
+
* READ (once per rendered frame under the notification throttle, never per
|
|
13
|
+
* event), and every snapshot copies its arrays, so a view already handed
|
|
14
|
+
* out never observes later folds.
|
|
15
|
+
*
|
|
16
|
+
* Notification coalescing: the fold stays synchronous — `getView()` always
|
|
17
|
+
* returns the latest state the moment `apply` returns — but listener
|
|
18
|
+
* notification is frame-throttled (~16ms) and deduplicated. The zai/GLM
|
|
19
|
+
* adapter delivers tokens as a sustained stream of sub-millisecond,
|
|
20
|
+
* microtask-spaced bursts: per-burst notification renders at microtask
|
|
21
|
+
* cadence, which chained SyncLane `useSyncExternalStore` rerenders past
|
|
22
|
+
* React's nested-update limit ("Maximum update depth exceeded"), while a
|
|
23
|
+
* bare `setImmediate` merges a whole macrotask turn's bursts into one
|
|
24
|
+
* chunky repaint (streaming text visibly staggers). The frame budget gives
|
|
25
|
+
* both: an event ≥16ms after the last paint notifies via `setImmediate`
|
|
26
|
+
* (sub-millisecond latency for sparse/first tokens), and anything denser
|
|
27
|
+
* defers to the next 16ms boundary — a 60fps render cap that also breaks
|
|
28
|
+
* the nesting chain by construction.
|
|
29
|
+
*
|
|
30
|
+
* @module @deepseek-ai/dsh-tui/store
|
|
31
|
+
*/
|
|
32
|
+
import type { AssistantStreamFrame } from '@deepseek-ai/dsh-agent';
|
|
33
|
+
import type { SessionEvent } from '@deepseek-ai/dsh-session';
|
|
34
|
+
import { type TranscriptView } from './render/projection.ts';
|
|
35
|
+
/** The externally readable, event-fed transcript store for one session. */
|
|
36
|
+
export interface TranscriptStore {
|
|
37
|
+
/** The current view; the same object identity until an event changes it. */
|
|
38
|
+
getView(): TranscriptView;
|
|
39
|
+
/** Subscribe to view changes; returns the unsubscribe function. */
|
|
40
|
+
subscribe(listener: () => void): () => void;
|
|
41
|
+
/** Fold one session event; ignored events change nothing and notify nobody. */
|
|
42
|
+
apply(event: SessionEvent): void;
|
|
43
|
+
/** Fold one live assistant-stream frame; frames without visible deltas stay silent. */
|
|
44
|
+
applyStreamFrame(frame: AssistantStreamFrame): void;
|
|
45
|
+
/** Drop the folded view entirely (/clear): the next event starts a fresh one. */
|
|
46
|
+
reset(): void;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Create one transcript store, optionally seeded with replayed history. The
|
|
50
|
+
* seed folds synchronously BEFORE the first render, so a resumed session
|
|
51
|
+
* paints its full transcript on mount (no live `session/event` fires for
|
|
52
|
+
* constructor seeds — the store's `session/event` feed only carries new
|
|
53
|
+
* appends).
|
|
54
|
+
* @param replay - persisted events in `seq` order (e.g. a resumed session's
|
|
55
|
+
* constructor seed); folded once and never re-notified.
|
|
56
|
+
* @returns the store the runner feeds and the renderer subscribes to.
|
|
57
|
+
*/
|
|
58
|
+
export declare function createTranscriptStore(replay?: readonly SessionEvent[]): TranscriptStore;
|