@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.
Files changed (98) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +5 -0
  3. package/THIRD_PARTY_NOTICES.md +11 -0
  4. package/bin/apply_patch +4 -0
  5. package/bootstrap.mjs +21 -0
  6. package/cordis.patch.yml +756 -0
  7. package/package.json +327 -0
  8. package/plugins/auto-review/audit.mjs +20 -0
  9. package/plugins/auto-review/index.mjs +181 -0
  10. package/plugins/auto-review/policy.mjs +59 -0
  11. package/plugins/dscode/index.mjs +35 -0
  12. package/plugins/session-metrics/index.mjs +44 -0
  13. package/plugins/session-metrics/pricing.mjs +18 -0
  14. package/plugins/session-metrics/store.mjs +24 -0
  15. package/plugins/session-metrics/view.mjs +58 -0
  16. package/plugins/tui-tools/hooks.mjs +23 -0
  17. package/plugins/tui-tools/index.mjs +164 -0
  18. package/plugins/ultra/policy.mjs +11 -0
  19. package/presets/dscode/agent.cordis.yml +288 -0
  20. package/presets/dscode/preset.yml +3 -0
  21. package/vendor/bash/LICENSE +21 -0
  22. package/vendor/bash/index.js +449 -0
  23. package/vendor/bash/types/background.d.ts +19 -0
  24. package/vendor/bash/types/index.d.ts +22 -0
  25. package/vendor/bash/types/render.d.ts +38 -0
  26. package/vendor/deepseek/LICENSE +21 -0
  27. package/vendor/deepseek/index.js +2102 -0
  28. package/vendor/deepseek/types/adapter.d.ts +163 -0
  29. package/vendor/deepseek/types/file-id.d.ts +19 -0
  30. package/vendor/deepseek/types/file-store.d.ts +83 -0
  31. package/vendor/deepseek/types/files-api.d.ts +103 -0
  32. package/vendor/deepseek/types/image-tokens.d.ts +19 -0
  33. package/vendor/deepseek/types/index.d.ts +106 -0
  34. package/vendor/deepseek/types/request-pricing.d.ts +48 -0
  35. package/vendor/deepseek/types/serialize.d.ts +85 -0
  36. package/vendor/deepseek/types/sse.d.ts +24 -0
  37. package/vendor/deepseek/types/translate.d.ts +37 -0
  38. package/vendor/deepseek/types/types.d.ts +178 -0
  39. package/vendor/deepseek/types/upload-index.d.ts +68 -0
  40. package/vendor/persistent/LICENSE +21 -0
  41. package/vendor/persistent/index.js +386 -0
  42. package/vendor/persistent/types/index.d.ts +24 -0
  43. package/vendor/tui/LICENSE +21 -0
  44. package/vendor/tui/devtools-CdTl3MNy.mjs +3643 -0
  45. package/vendor/tui/index.mjs +39105 -0
  46. package/vendor/tui/invariant.mjs +21 -0
  47. package/vendor/tui/rolldown-runtime-CMFfr-1z.mjs +26 -0
  48. package/vendor/tui/startup.mjs +109 -0
  49. package/vendor/tui/theme-DCT8Y2xf.mjs +628 -0
  50. package/vendor/tui/types/app.d.ts +304 -0
  51. package/vendor/tui/types/approval.d.ts +59 -0
  52. package/vendor/tui/types/attachments.d.ts +52 -0
  53. package/vendor/tui/types/authorization-panel.d.ts +22 -0
  54. package/vendor/tui/types/authorization.d.ts +36 -0
  55. package/vendor/tui/types/commands.d.ts +52 -0
  56. package/vendor/tui/types/editor-keys.d.ts +105 -0
  57. package/vendor/tui/types/editor.d.ts +6 -0
  58. package/vendor/tui/types/fork.d.ts +8 -0
  59. package/vendor/tui/types/git-workflow.d.ts +32 -0
  60. package/vendor/tui/types/history.d.ts +97 -0
  61. package/vendor/tui/types/index.d.ts +124 -0
  62. package/vendor/tui/types/input-split.d.ts +54 -0
  63. package/vendor/tui/types/internals.d.ts +26 -0
  64. package/vendor/tui/types/invariant.d.ts +15 -0
  65. package/vendor/tui/types/kernel-panels.d.ts +167 -0
  66. package/vendor/tui/types/keyboard.d.ts +80 -0
  67. package/vendor/tui/types/mentions.d.ts +81 -0
  68. package/vendor/tui/types/model-capabilities.d.ts +82 -0
  69. package/vendor/tui/types/models.d.ts +119 -0
  70. package/vendor/tui/types/permissions.d.ts +27 -0
  71. package/vendor/tui/types/plugin-inventory.d.ts +11 -0
  72. package/vendor/tui/types/presets.d.ts +22 -0
  73. package/vendor/tui/types/provider-settings.d.ts +239 -0
  74. package/vendor/tui/types/questions.d.ts +54 -0
  75. package/vendor/tui/types/render/animations.d.ts +265 -0
  76. package/vendor/tui/types/render/editor.d.ts +162 -0
  77. package/vendor/tui/types/render/export.d.ts +9 -0
  78. package/vendor/tui/types/render/fuzzy.d.ts +21 -0
  79. package/vendor/tui/types/render/inspector.d.ts +36 -0
  80. package/vendor/tui/types/render/lines.d.ts +66 -0
  81. package/vendor/tui/types/render/markdown.d.ts +29 -0
  82. package/vendor/tui/types/render/projection.d.ts +461 -0
  83. package/vendor/tui/types/render/status.d.ts +196 -0
  84. package/vendor/tui/types/render/text.d.ts +58 -0
  85. package/vendor/tui/types/render/tool-detail.d.ts +94 -0
  86. package/vendor/tui/types/render/tool-preview.d.ts +28 -0
  87. package/vendor/tui/types/render/width.d.ts +29 -0
  88. package/vendor/tui/types/session-directory.d.ts +173 -0
  89. package/vendor/tui/types/session-switch.d.ts +17 -0
  90. package/vendor/tui/types/settings-file.d.ts +41 -0
  91. package/vendor/tui/types/skills.d.ts +47 -0
  92. package/vendor/tui/types/startup.d.ts +65 -0
  93. package/vendor/tui/types/store.d.ts +58 -0
  94. package/vendor/tui/types/subagents.d.ts +70 -0
  95. package/vendor/tui/types/theme-panel.d.ts +24 -0
  96. package/vendor/tui/types/theme.d.ts +215 -0
  97. package/vendor/tui/types/version.d.ts +18 -0
  98. package/vendor/tui/types/whale-glyph.d.ts +6 -0
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Read-only Git inspection used by /diff and /review. Every diff
3
+ * invocation carries --no-ext-diff and --no-textconv, so configured
4
+ * external diff drivers and text converters can never execute as a
5
+ * side effect of reading a diff.
6
+ */
7
+ export interface GitDiffSpec {
8
+ readonly label: string;
9
+ readonly args: readonly string[];
10
+ }
11
+ /** One file section from a unified diff, retained in source order. */
12
+ export interface GitDiffFile {
13
+ readonly path: string;
14
+ readonly lines: readonly string[];
15
+ }
16
+ /** A parsed diff ready for a file-oriented terminal viewport. */
17
+ export interface GitDiffView {
18
+ readonly title: string;
19
+ readonly files: readonly GitDiffFile[];
20
+ }
21
+ /** Split Git's stable `diff --git` framing without interpreting patch content. */
22
+ export declare function parseGitDiffFiles(text: string): readonly GitDiffFile[];
23
+ /** Parse the intentionally small, option-safe /diff argument vocabulary. */
24
+ export declare function parseGitDiffSpec(argument: string): GitDiffSpec;
25
+ /**
26
+ * Load one complete textual diff without invoking external programs.
27
+ * @param signal - aborted by the caller on session switches/quit, killing the
28
+ * git subprocess instead of letting a stale repository's diff land later.
29
+ */
30
+ export declare function loadGitDiff(cwd: string, argument: string, signal?: AbortSignal): Promise<GitDiffView>;
31
+ /** Review prompt capped before it reaches a provider context window. */
32
+ export declare function buildReviewPrompt(diff: string, label: string, maxChars?: number): string;
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Global input recall: persistent cross-session entries plus this process's
3
+ * submissions, with Codex `ChatComposerHistory` semantics — empty submissions
4
+ * are ignored, adjacent duplicates collapse, the recall space skips
5
+ * persistent entries that duplicate a local one (local wins), and Up/Down
6
+ * navigation is gated so interior cursor movement never hijacks the draft.
7
+ *
8
+ * @module @deepseek-ai/dsh-tui/history
9
+ */
10
+ /** Maximum entries retained in the persistent history file and the local recall pool. */
11
+ export declare const HISTORY_MAX_ENTRIES = 100;
12
+ /** Encode one entry for the history file (JSON keeps multi-line drafts intact). */
13
+ export declare function serializeHistoryEntry(text: string): string;
14
+ /**
15
+ * Parse a persisted history file (one JSON entry per line): invalid lines
16
+ * drop out, empty entries are ignored, adjacent duplicates collapse, and the
17
+ * result keeps only the newest `max` entries.
18
+ * @param raw - file content, empty for a missing file.
19
+ * @param max - entry cap.
20
+ * @returns persistent entries, oldest first.
21
+ */
22
+ export declare function parseHistoryFile(raw: string, max?: number): readonly string[];
23
+ /**
24
+ * The append unit for the persistent file: one JSON line, so a multi-line
25
+ * draft still occupies exactly one physical line. Each submission appends
26
+ * this unit at the end of the file, so concurrent terminals add entries
27
+ * after each other. Node chunks one append at 512 KiB: a pasted entry
28
+ * beyond that size could interleave mid-line with another writer's
29
+ * chunks, and the damaged line then drops out at the next parse —
30
+ * recall tolerates the loss by design.
31
+ */
32
+ export declare function historyLine(text: string): string;
33
+ /**
34
+ * Whether the file on disk differs from its canonical form (deduped and
35
+ * capped). True means stale lines have accumulated and the next boot
36
+ * should rewrite it once, atomically.
37
+ */
38
+ export declare function needsCompaction(raw: string, max?: number): boolean;
39
+ /**
40
+ * Record one in-session submission: empty text is ignored and an adjacent
41
+ * duplicate collapses (Codex `record_local_submission` semantics). The local
42
+ * pool shares the persistent pool's cap so the recall space stays bounded.
43
+ * @param local - current in-session entries, oldest first.
44
+ * @param text - the submitted prompt.
45
+ * @param max - the local pool cap.
46
+ * @returns the updated local list.
47
+ */
48
+ export declare function recordLocalEntry(local: readonly string[], text: string, max?: number): readonly string[];
49
+ /**
50
+ * Serialize a capped entry list to the history file format (one JSON line
51
+ * per entry, trailing newline). The boot-time compaction writes this
52
+ * canonical form once when stale lines have accumulated; submissions
53
+ * themselves only ever append a single line.
54
+ * @param entries - the entries to persist, oldest first.
55
+ * @returns the file content, '' for an empty list.
56
+ */
57
+ export declare function serializeHistoryList(entries: readonly string[]): string;
58
+ /**
59
+ * Build the recall space, newest first: local entries, then persistent
60
+ * entries whose text is not duplicated locally (the local copy wins and the
61
+ * persistent twin is skipped — Codex's replay-seed dedup, applied to the
62
+ * whole local set).
63
+ * @param persistent - cross-session entries, oldest first.
64
+ * @param local - this process's submissions, oldest first.
65
+ * @returns recall entries, newest first.
66
+ */
67
+ export declare function recallEntries(persistent: readonly string[], local: readonly string[]): readonly string[];
68
+ /** Shell-style recall navigation over a fixed recall space. */
69
+ export interface RecallState {
70
+ /** Recall entries, newest first (frozen at navigation start). */
71
+ entries: readonly string[];
72
+ /** Current recall index; null when not browsing. */
73
+ index: number | null;
74
+ /** Draft saved when browsing started; restored on Down past the newest. */
75
+ savedDraft: string;
76
+ /** The recalled text currently in the composer (the boundary gate's anchor). */
77
+ lastRecalled: string | null;
78
+ }
79
+ /** Fresh navigation state over one recall space. */
80
+ export declare function beginRecall(entries: readonly string[], draft: string): RecallState;
81
+ /** The outcome of one recall step. */
82
+ export interface RecallStep {
83
+ state: RecallState;
84
+ /** The text to place in the composer; undefined means "no movement". */
85
+ entry: string | undefined;
86
+ }
87
+ /**
88
+ * Move one entry older (Up, toward index +1 in the newest-first space). The
89
+ * first Up saves the current draft so Down past the newest can restore it
90
+ * (Claude-Code shell recall — the draft is never lost); the oldest entry
91
+ * stays put.
92
+ * @param state - current navigation state.
93
+ * @param draft - the composer text to preserve when browsing starts.
94
+ */
95
+ export declare function recallOlder(state: RecallState, draft: string): RecallStep;
96
+ /** Move one entry newer (Down, toward index 0); past the newest, browsing ends and the saved draft returns. */
97
+ export declare function recallNewer(state: RecallState): RecallStep;
@@ -0,0 +1,124 @@
1
+ /**
2
+ * @deepseek-ai/dsh-code — the interactive terminal driver. The bundle patch
3
+ * rides over dsh-base without Host, HTTP, or browser plugins; this runner
4
+ * creates or resumes preset-composed Agents through the core registry, keeps
5
+ * one Ink owner while the active session changes, folds submitted prompts
6
+ * into the selected durable session, answers approval asks with a y/n bar,
7
+ * dispatches slash commands, and on quit flushes and requests process exit.
8
+ *
9
+ * @module @deepseek-ai/dsh-code
10
+ */
11
+ import type { Context } from '@deepseek-ai/cordis';
12
+ import z from '@deepseek-ai/schemastery';
13
+ import { type ContentBlock } from '@deepseek-ai/dsh-llm';
14
+ import { SessionId, type SessionEvent } from '@deepseek-ai/dsh-session';
15
+ import type { SessionPersistence } from '@deepseek-ai/dsh-session-persistence';
16
+ import type { TuiStartup } from './startup.ts';
17
+ /** Stable Cordis plugin name. */
18
+ export declare const name = "tui-runner";
19
+ /** Core services required before the interactive session can start. */
20
+ export declare const inject: string[];
21
+ /** Plugin config: the startup resolved from this app's injected provider service. */
22
+ export interface Config {
23
+ /** How this invocation obtains its session identity (validated loosely; narrowed in {@link apply}). */
24
+ startup: {
25
+ kind: string;
26
+ sessionId?: string;
27
+ mode?: string;
28
+ theme?: string;
29
+ prompt?: string;
30
+ images?: string[];
31
+ };
32
+ }
33
+ export declare const Config: z<Config>;
34
+ /** The session identity this invocation will run, plus whether it is resumed. */
35
+ interface Target {
36
+ sessionId: string;
37
+ resume: boolean;
38
+ mode?: string;
39
+ cwd?: string;
40
+ seed?: readonly SessionEvent[];
41
+ parentSession?: SessionId;
42
+ seedLength?: number;
43
+ }
44
+ /**
45
+ * Reduce a session id to a filename-safe /export default-name suffix. Session
46
+ * ids are normally minted `session-<uuid>`, but `--session` accepts arbitrary
47
+ * user text: path separators must never leak into the default export filename
48
+ * (which would escape the session cwd).
49
+ * @param id - the session id.
50
+ * @returns at most the last 8 filename-safe characters.
51
+ */
52
+ export declare function exportSessionIdSuffix(id: string): string;
53
+ /** One ordered step of the terminal quit cleanup. */
54
+ export interface QuitCleanupStep {
55
+ /** Step label used in diagnostics and tests. */
56
+ readonly name: string;
57
+ /** The step's async work; a rejection is contained by the sequence. */
58
+ readonly run: () => Promise<void>;
59
+ }
60
+ /**
61
+ * Run the ordered quit cleanup, then request exit. Every step rejection is
62
+ * contained (reported through `onError`) so a failed flush or dispose never
63
+ * skips the remaining cleanup; the exit request is always reached exactly
64
+ * once.
65
+ * @param steps - the cleanup steps in dependency order (settle the visible
66
+ * session, await the final in-flight composition, await durable recall).
67
+ * @param exit - the terminal exit request (code 0).
68
+ * @param onError - optional failure sink; called once per failing step and
69
+ * itself contained, so a throwing sink cannot abort the sequence.
70
+ * @returns the names of the steps that started, in order (for tests).
71
+ */
72
+ export declare function runQuitSequence(steps: readonly QuitCleanupStep[], exit: (code: number) => void, onError?: (name: string, error: unknown) => void): Promise<readonly string[]>;
73
+ /** One composer submission waiting behind the startup delivery. */
74
+ export interface QueuedSubmission {
75
+ readonly text: string;
76
+ readonly mode: 'followup' | 'steer';
77
+ readonly images: readonly ContentBlock[];
78
+ }
79
+ /**
80
+ * Whether a tagged submission still belongs to the active session. Attachment
81
+ * prepares resolve on the microtask timeline, while a queued session switch
82
+ * remounts the app asynchronously — the composing instance's unmount cleanup
83
+ * runs too late to abort, so the delivery itself carries the composing
84
+ * session's full id and the runner drops it here when the world moved on.
85
+ * An untagged (synchronous) or pending-session ('') submission always passes.
86
+ */
87
+ export declare function submissionBelongsToSession(origin: string | undefined, activeSessionId: string | undefined): boolean;
88
+ /**
89
+ * Order-preserving gate for composer input while the startup prompt/images
90
+ * are still preparing. Anything submitted before the startup delivery settles
91
+ * queues and flushes afterwards in submit order, so the initial request can
92
+ * never be overtaken by typing that raced a slow image preparation. The flush
93
+ * also runs when the startup delivery fails: user input is never stranded.
94
+ */
95
+ export declare class StartupInputGate {
96
+ private readonly deliver;
97
+ private readonly queued;
98
+ private pending;
99
+ constructor(deliver: (submission: QueuedSubmission) => void);
100
+ /** Submit one line: delivered now while idle, queued behind the startup delivery otherwise. */
101
+ submit(submission: QueuedSubmission): void;
102
+ /**
103
+ * Run the startup delivery — the callback receives the direct-delivery sink
104
+ * for the startup prompt itself — then flush everything that queued behind
105
+ * it, in order, even when the callback rejects.
106
+ */
107
+ run(startup: (deliver: (submission: QueuedSubmission) => void) => Promise<void>): Promise<void>;
108
+ }
109
+ /**
110
+ * Resolve the invocation's target session against the persisted headers.
111
+ * @param startup - the parsed startup flags.
112
+ * @param persistence - the persistence service; required for resume/latest.
113
+ * @param cwd - the working directory `--continue` filters by.
114
+ * @returns the target identity.
115
+ * @throws with a user-facing message when the flags name nothing resolvable.
116
+ */
117
+ export declare function resolveTarget(startup: TuiStartup, persistence: SessionPersistence | undefined, cwd: string): Promise<Target>;
118
+ /**
119
+ * Mount the interactive terminal driver.
120
+ * @param ctx - plugin context carrying core services and the launcher-provided exit request.
121
+ * @param config - validated startup config resolved from the tuiStartup provider.
122
+ */
123
+ export declare function apply(ctx: Context, config: Config): void;
124
+ export {};
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Terminal input arrives as byte chunks, and one chunk can carry several
3
+ * keypresses: a fast space-then-enter, a bridged stdin that batches reads, a
4
+ * middle-click paste. Ink parses each chunk as exactly one keypress —
5
+ * `parseKeypress(' \r')` matches neither member, so both keys silently
6
+ * vanish (a multi-select question answered with an empty set). The splitter
7
+ * below cuts every chunk into the individual keypress units Ink's parser
8
+ * expects, keeping escape sequences and bracketed-paste blocks intact, and
9
+ * the stdin proxy feeds the split stream to the Ink mount.
10
+ *
11
+ * @module @deepseek-ai/dsh-tui/input-split
12
+ */
13
+ import { PassThrough } from 'node:stream';
14
+ /** One keypress cut from the input stream. */
15
+ export interface KeypressSplitter {
16
+ /** Feed one chunk; returns every keypress unit this chunk completed. */
17
+ push(chunk: string): string[];
18
+ /** Whether an unterminated bracketed-paste block is currently held. */
19
+ openPaste(): boolean;
20
+ /**
21
+ * Last-resort escape hatch for a paste whose end marker never arrived:
22
+ * drop the start marker and emit the held bytes as plain keypress units so
23
+ * nothing (Esc and Ctrl+C included) stays hostage. Inert when no paste is
24
+ * open.
25
+ */
26
+ releaseStalePaste(): string[];
27
+ }
28
+ /**
29
+ * Build a stateful chunk splitter. A partial unit at the end of one chunk
30
+ * (a cut CSI sequence, an open paste block) waits in the buffer for the
31
+ * rest. A chunk-trailing lone ESC emits as the Escape key right away:
32
+ * terminals send Escape as its own chunk, and holding it hostage for a
33
+ * sequence that may never continue would break every Esc cancel.
34
+ */
35
+ export declare function createKeypressSplitter(): KeypressSplitter;
36
+ /** The stdin-shaped stream the Ink mount renders through. */
37
+ export interface TuiStdin extends PassThrough {
38
+ /** Mirrors the real stdin so Ink's raw-mode gate passes. */
39
+ isTTY: boolean;
40
+ /** Forwarded to the real stdin; Ink toggles it around focus. */
41
+ setRawMode(value: boolean): unknown;
42
+ ref(): void;
43
+ unref(): void;
44
+ }
45
+ /**
46
+ * Wrap one real stdin in the splitting proxy: keypress units flow into a
47
+ * PassThrough Ink reads, while raw-mode/ref calls forward to the source.
48
+ * @param source - the process (or harness) input stream in raw mode.
49
+ * @returns the proxy stream plus a dispose that detaches the tap.
50
+ */
51
+ export declare function createSplitStdin(source: NodeJS.ReadStream): {
52
+ stdin: TuiStdin;
53
+ dispose(): void;
54
+ };
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Injectable process-facing effects for the TUI runner. Tests substitute the
3
+ * Ink mount with a capturing fake and the streams with string sinks, keeping
4
+ * the runner's lifecycle testable without a terminal.
5
+ *
6
+ * @module @deepseek-ai/dsh-tui/internals
7
+ */
8
+ import type { ReactElement } from 'react';
9
+ /** A mounted terminal app instance; the runner owns unmount ordering. */
10
+ export interface TuiMount {
11
+ /** Replace the root element while preserving Ink's single terminal owner. */
12
+ rerender(element: ReactElement): void;
13
+ /** Tear the terminal app down before flush and exit. */
14
+ unmount(): void;
15
+ }
16
+ /** The Ink mount seam: renders the app element and returns its handle. */
17
+ export type Mount = (element: ReactElement) => TuiMount;
18
+ /** Substitutable runner effects; production values write to the real terminal. */
19
+ export declare const internals: {
20
+ /** Ink renderer mount; tests substitute a fake that captures the element. */
21
+ mount: Mount;
22
+ /** Diagnostics stream for direct-driver failures. */
23
+ stderr: {
24
+ write(chunk: string): unknown;
25
+ };
26
+ };
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Package-owned invariant companion for `dsh-code`.
3
+ * @module dsh-code/invariant
4
+ */
5
+ import type { Context } from '@deepseek-ai/cordis';
6
+ /** Cordis companion plugin name. */
7
+ export declare const name = "tui-invariant";
8
+ /** Service required before the companion can register. */
9
+ export declare const inject: string[];
10
+ /**
11
+ * Register this package's invariant companion.
12
+ * @param ctx - Cordis context carrying the invariant service.
13
+ * @returns the installed registration's disposer after setup succeeds.
14
+ */
15
+ export declare const apply: (ctx: Context) => Promise<() => void>;
@@ -0,0 +1,167 @@
1
+ /** Bounded, composer-safe panels for preset, session, and plugin kernel views. */
2
+ import { type ReactElement } from 'react';
3
+ import type { ModelDirectory, ModelRow } from './models.ts';
4
+ import type { SubagentRow } from './subagents.ts';
5
+ import type { PermissionRow } from './permissions.ts';
6
+ import type { PresetRow } from './presets.ts';
7
+ import type { PluginRow } from './plugin-inventory.ts';
8
+ import type { SessionDirectoryOptions, SessionRow } from './session-directory.ts';
9
+ import { type StatusItemId } from './render/status.ts';
10
+ /**
11
+ * Apply one keystroke to a panel search query. IME commits arrive as one
12
+ * multi-character chunk, so the whole printable run is appended; paste
13
+ * markers are stripped and control-laden chunks are ignored.
14
+ */
15
+ export declare function editQuery(query: string, input: string, key: {
16
+ backspace?: boolean;
17
+ delete?: boolean;
18
+ }): string | undefined;
19
+ export declare function ModePanel({ current, load, select, close }: {
20
+ current: string;
21
+ load(): Promise<readonly PresetRow[]>;
22
+ select(id: string): void;
23
+ close(): void;
24
+ }): ReactElement;
25
+ export declare function PermissionPanel({ current, load, select, close }: {
26
+ current: string;
27
+ load(): Promise<readonly PermissionRow[]>;
28
+ select(id: string): void;
29
+ close(): void;
30
+ }): ReactElement;
31
+ export declare function PluginPanel({ load, close, initialQuery }: {
32
+ load(): readonly PluginRow[];
33
+ close(): void;
34
+ initialQuery?: string;
35
+ }): ReactElement;
36
+ /** One background job snapshot for the /jobs panel (the registry's read-only view). */
37
+ export interface JobRow {
38
+ /** The registry-issued id (`<kind>-N`). */
39
+ readonly id: string;
40
+ /** Producer kind (bash, subagent, …). */
41
+ readonly kind: string;
42
+ /** One-line model-facing label (the command; the delegation description). */
43
+ readonly label: string;
44
+ /** Lifecycle state. */
45
+ readonly status: 'running' | 'stopping' | 'completed' | 'killed' | 'failed';
46
+ /** Kind-specific status detail once the producer supplied one. */
47
+ readonly detail?: string;
48
+ /** Epoch ms when the job was registered. */
49
+ readonly startedAt: number;
50
+ /** Epoch ms when the job settled; absent while running/stopping. */
51
+ readonly finishedAt?: number;
52
+ }
53
+ /** Web TurnStatus elapsed format: `45s` under a minute, `2m03s` beyond. */
54
+ export declare function runClock(ms: number): string;
55
+ /**
56
+ * The read-only background-job panel: caller-owned and unowned jobs from the
57
+ * host `jobs` registry in registration order, with a local second-hand while
58
+ * the panel is open (elapsed clocks advance and the snapshot re-reads; the
59
+ * interval dies with the panel). Cancel stays upstream-only; an absent
60
+ * registry renders as the plain empty state (a harmless missing service).
61
+ */
62
+ export declare function JobsPanel({ load, close }: {
63
+ load(): readonly JobRow[];
64
+ close(): void;
65
+ }): ReactElement;
66
+ export declare function ResumePanel({ currentCwd, load, readTranscript, select, requestDelete, deleteConfirmId, reloadToken, deleteMode, close }: {
67
+ currentCwd: string;
68
+ load(options: SessionDirectoryOptions, signal?: AbortSignal): Promise<readonly SessionRow[]>;
69
+ readTranscript(id: string, signal?: AbortSignal): Promise<string>;
70
+ select(row: SessionRow): void;
71
+ /** Arm the composer-based delete confirm for one row (App owns the keys). */
72
+ requestDelete?(row: SessionRow): void;
73
+ /** The row id awaiting y/n in the composer, when any (App-owned). */
74
+ deleteConfirmId?: string;
75
+ /** Bump to reload the listing (e.g. after a deletion). */
76
+ reloadToken?: number;
77
+ /** Opened via /delete: hint-first delete mode. */
78
+ deleteMode?: boolean;
79
+ close(): void;
80
+ }): ReactElement;
81
+ /**
82
+ * The /history recall panel (Codex composer-history search, bounded): one
83
+ * query line over the newest-first recall space, filtered by substring, with
84
+ * arrow selection and enter to fill the composer. Editing the query restarts
85
+ * from the newest match; Esc closes without touching the draft.
86
+ */
87
+ export declare function HistoryPanel({ entries, fill, close }: {
88
+ /** Newest-first recall entries (persistent + in-session, deduped). */
89
+ entries: readonly string[];
90
+ /** Accept one entry: its text plus its recall-space index (browsing resumes there). */
91
+ fill(text: string, index: number): void;
92
+ close(): void;
93
+ }): ReactElement;
94
+ /**
95
+ * The /statusline picker (the Codex setup-view contract): one bounded list
96
+ * of every status item with its enabled mark, arrow reordering, and a
97
+ * live preview — the real status line under the composer updates as you
98
+ * edit, so the panel itself carries no duplicate preview row.
99
+ */
100
+ export declare function StatuslinePanel({ enabled, change, close }: {
101
+ enabled: readonly StatusItemId[];
102
+ change(items: readonly StatusItemId[]): void;
103
+ close(): void;
104
+ }): ReactElement;
105
+ /**
106
+ * The `/model` reasoning-effort stage (the Codex model → reasoning popup
107
+ * contract): one bounded list over the selected model's adapter-advertised
108
+ * effort levels — in the adapter's own display order, ids verbatim (the
109
+ * kernel treats them as opaque and rejects anything else) — with the
110
+ * effective effort and the model default marked. A model WITHOUT an
111
+ * adapter-declared default leads with a "Default" (provider-default) row —
112
+ * the web effort pane's first entry — so the user can clear a picked level
113
+ * back to provider behavior. A model advertising no levels opens the same
114
+ * stage with an explicit empty state (the web pane's "no levels" copy)
115
+ * instead of a bare failure notice. Enter applies one level; Esc returns to
116
+ * the model list without applying.
117
+ */
118
+ export declare function EffortPanel({ row, current, select, back, onExit }: {
119
+ /** The model row whose advertised levels this stage lists. */
120
+ row: ModelRow;
121
+ /** Effective effort currently in force ('' when none), for the ● mark. */
122
+ current: string | undefined;
123
+ /** Accept one advertised effort id, or '' for the provider default. */
124
+ select(effortId: string): void;
125
+ /** Return to the model list without applying. */
126
+ back(): void;
127
+ /** Leave the whole /model flow (Ctrl+C). */
128
+ onExit(): void;
129
+ }): ReactElement;
130
+ /**
131
+ * The /agents panel (the Codex agent-picker contract, read-only): this
132
+ * conversation's subagent conversations — live rows from the activity feed
133
+ * first, persisted children the feed has not seen this process after — with
134
+ * Enter/t opening the child's full transcript in the shared read-only
135
+ * document view (the same projection the exporter uses).
136
+ */
137
+ export declare function AgentsPanel({ live, load, readTranscript, close }: {
138
+ /** Live feed rows (child sessions observed this process). */
139
+ live: readonly SubagentRow[];
140
+ /** Load this session's persisted child sessions by lineage. */
141
+ load(): Promise<readonly SessionRow[]>;
142
+ /** Read one child session's full transcript as markdown. */
143
+ readTranscript(id: string, signal?: AbortSignal): Promise<string>;
144
+ close(): void;
145
+ }): ReactElement;
146
+ /**
147
+ * The /subagent model panel: which model configuration delegated subagents
148
+ * run on. The kernel seeds child agents from the parent's CREATE-TIME
149
+ * AgentOptions, so a mid-session /model switch would otherwise leave them on
150
+ * the launch-time route; the TUI mirrors the selection onto subagent-origin
151
+ * requests (or an explicit override picked here) via an agent/request
152
+ * listener. The leading "inherit" row restores follow-the-current-model
153
+ * behavior; picking a model with several advertised efforts opens the same
154
+ * effort stage /model uses. Effort overrides are not offered separately —
155
+ * the kernel's AgentOptions has no effort channel for children, so the level
156
+ * rides the selected model exactly as /model applies it.
157
+ */
158
+ export declare function SubagentPanel({ current, load, pick, inherit, close }: {
159
+ /** Display label of the override in force, '' when following the current model. */
160
+ current: string;
161
+ load(): Promise<ModelDirectory>;
162
+ /** Apply one model (with an advertised effort, when picked) as the override. */
163
+ pick(row: ModelRow, effortId?: string): void;
164
+ /** Drop the override: subagents follow the current model again. */
165
+ inherit(): void;
166
+ close(): void;
167
+ }): ReactElement;
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Keyboard enhancement protocol (Codex `keyboard_modes` parity) and the
3
+ * kitty CSI-u normalization layer.
4
+ *
5
+ * The TUI pushes the kitty keyboard protocol with DISAMBIGUATE_ESCAPE_CODES
6
+ * and REPORT_ALTERNATE_KEYS (flags 1|4 = `\x1b[>5u`). Event types are
7
+ * deliberately NOT requested: Ink 5's parser cannot decode the
8
+ * `:event-type` suffix, and repeat/release reporting buys this surface
9
+ * nothing.
10
+ *
11
+ * Ink 5 also cannot parse most CSI-u forms at all — they fall through its
12
+ * regex as unnamed sequences and get INSERTED AS DRAFT TEXT. The composer's
13
+ * stdin read patch therefore rewrites every CSI-u form it can decode back
14
+ * to the legacy byte or canonical sequence the existing key handling
15
+ * already understands, before Ink ever parses the chunk.
16
+ * @module @deepseek-ai/dsh-code/keyboard
17
+ */
18
+ /** Push keyboard enhancement (modifyOtherKeys off, kitty flags 1|4). */
19
+ export declare const KEYBOARD_ENHANCE_ENABLE = "\u001B[>4;0m\u001B[>5u";
20
+ /** Pop the enhancement stack and reset modifyOtherKeys (exit path). */
21
+ export declare const KEYBOARD_ENHANCE_DISABLE = "\u001B[<u\u001B[>4;0m";
22
+ /** Explicit environment overrides for terminal keyboard enhancement. */
23
+ export declare const DSH_DISABLE_KEYBOARD_ENHANCEMENT = "DSH_DISABLE_KEYBOARD_ENHANCEMENT";
24
+ export declare const DSH_ENABLE_KEYBOARD_ENHANCEMENT = "DSH_ENABLE_KEYBOARD_ENHANCEMENT";
25
+ /** True when the process is running inside the VS Code integrated terminal. */
26
+ export declare function isVsCodeTerminalEnv(env?: NodeJS.ProcessEnv): boolean;
27
+ /** Whether to push Kitty keyboard enhancement for the current terminal. */
28
+ export declare function shouldEnableKeyboardEnhancement(env?: NodeJS.ProcessEnv): boolean;
29
+ /** Enable bracketed paste reporting. */
30
+ export declare const BRACKETED_PASTE_ENABLE = "\u001B[?2004h";
31
+ /** Disable bracketed paste reporting. */
32
+ export declare const BRACKETED_PASTE_DISABLE = "\u001B[?2004l";
33
+ /** Enable terminal focus-in/focus-out reporting (xterm focus protocol). */
34
+ export declare const TERMINAL_FOCUS_REPORT_ENABLE = "\u001B[?1004h";
35
+ /** Disable terminal focus-in/focus-out reporting. */
36
+ export declare const TERMINAL_FOCUS_REPORT_DISABLE = "\u001B[?1004l";
37
+ /**
38
+ * Remove xterm focus reports from one input chunk and update the caller's
39
+ * focus state. Focus reports are terminal protocol, not composer text.
40
+ */
41
+ export declare function stripTerminalFocusEvents(chunk: string, onFocus: (focused: boolean) => void): string;
42
+ /** Bracketed paste markers as Ink delivers them (it strips the leading ESC). */
43
+ export declare const PASTE_START_MARKER = "[200~";
44
+ export declare const PASTE_END_MARKER = "[201~";
45
+ /**
46
+ * How long an unterminated bracketed-paste block may hold buffered bytes
47
+ * before the input splitter strips its start marker and releases them: a
48
+ * terminal that loses the end marker must never take the whole keyboard
49
+ * hostage (Esc/Ctrl+C included). Shared by the splitter and the composer's
50
+ * lost-paste safety net so both use one window.
51
+ */
52
+ export declare const PASTE_BRACKET_TIMEOUT_MS = 1000;
53
+ /**
54
+ * Remove bracketed paste markers from one input chunk. Panel drafts accept raw
55
+ * `input` text, where an unhandled paste would otherwise persist the literal
56
+ * "[200~"/"[201~" markers Ink leaves after stripping the ESC byte.
57
+ */
58
+ export declare function stripPasteMarkers(text: string): string;
59
+ /**
60
+ * Rewrite every decodable kitty CSI-u sequence in one stdin chunk to the
61
+ * legacy form the input layer already handles. Undecodable or non-key
62
+ * sequences pass through untouched, so terminals without the protocol are
63
+ * unaffected.
64
+ */
65
+ export declare function normalizeKeyboardChunk(chunk: string): string;
66
+ /** Editor actions Ink cannot distinguish reliably when terminal bytes batch. */
67
+ export type RawEditorToken = {
68
+ readonly kind: 'text';
69
+ readonly text: string;
70
+ } | {
71
+ readonly kind: 'home' | 'end' | 'delete-backward' | 'delete-word-backward' | 'delete-forward' | 'delete-word-forward';
72
+ };
73
+ /**
74
+ * Tokenize a stdin chunk containing at least one editor-only key. Ink calls
75
+ * `useInput` once for a pasted/batched chunk, so preserving each action here
76
+ * prevents repeated Backspace/Home/End/Delete presses from collapsing into
77
+ * one blurred key event. Unknown escape sequences return undefined and stay
78
+ * under Ink's ownership.
79
+ */
80
+ export declare function tokenizeRawEditorChunk(chunk: string): readonly RawEditorToken[] | undefined;