dsh-code 1.2.0 → 1.3.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/lib/startup.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { r as THEME_NAMES } from "./theme-7u5Qo3dF.mjs";
1
+ import { r as THEME_NAMES } from "./theme-B3orFUYz.mjs";
2
2
  import { Command } from "commander";
3
3
  import { parseCmdline } from "@deepseek-ai/dsh-cmdline";
4
4
  //#region src/startup.ts
@@ -538,6 +538,10 @@ function hueOf([r, g, b]) {
538
538
  if (max === g) return (60 * (b - r) / span + 120) % 360;
539
539
  return (60 * (r - g) / span + 240) % 360;
540
540
  }
541
+ /** Strict RGB equality for the wrap-collision repair. */
542
+ function sameRgb(left, right) {
543
+ return left[0] === right[0] && left[1] === right[1] && left[2] === right[2];
544
+ }
541
545
  /** A dark row tint for diff backgrounds: the hue at 22% strength over black. */
542
546
  function darkTint(hue) {
543
547
  return [
@@ -603,6 +607,10 @@ function rollRainbow(seed) {
603
607
  TONE_ORDER.forEach((tone, index) => {
604
608
  toneColors[tone] = pool[(offset + index) % pool.length];
605
609
  });
610
+ if (sameRgb(toneColors.live, toneColors.error)) {
611
+ const replacement = pool.find((hue) => !sameRgb(hue, toneColors.live) && !sameRgb(hue, toneColors.warn));
612
+ if (replacement !== void 0) toneColors.error = replacement;
613
+ }
606
614
  return {
607
615
  seed,
608
616
  palette,
@@ -234,6 +234,20 @@ export interface AppProps {
234
234
  /** Apply the Ctrl+R terminal passthrough to the detected editor (/vscode-keys); resolves to a one-line summary. */
235
235
  applyEditorKeys: () => Promise<string>;
236
236
  }
237
+ /**
238
+ * The streaming buffer rendered with a hard size cap: the live region must
239
+ * ALWAYS fit the terminal, or Ink's erase/rewrite of a dynamic tree taller
240
+ * than the screen freezes (cursor-up past the top, garbage, no scroll). The
241
+ * cap counts explicit newlines and terminal wrapping, slicing from the END so
242
+ * the freshest tokens stay visible while a long reply streams; the complete
243
+ * text lands in the flushed scrollback once the turn assembles it.
244
+ *
245
+ * Body wrap width for a streaming tail. `rowColumns` is the same width
246
+ * passed to `transcriptEntryLines` (terminal minus the last-column safety);
247
+ * the hanging prefix then shrinks the body so streamed text and settled
248
+ * markdown wrap on the same column.
249
+ */
250
+ export declare function streamTailBodyColumns(rowColumns: number, prefix: string, continuationPrefix?: string): number;
237
251
  /** Rows in the exact next-turn inbox order, never transcript append order. */
238
252
  export declare function queuedInboxRows(entries: readonly TranscriptEntry[], ids: readonly string[]): readonly Extract<TranscriptEntry, {
239
253
  kind: 'pending';
@@ -247,6 +261,12 @@ interface CompletionCandidate {
247
261
  /** Candidate origin; skills land the same literal text but route through the prompt. */
248
262
  origin: 'command' | 'skill' | 'mention';
249
263
  }
264
+ /**
265
+ * Wrap one completion-menu cursor step. An empty menu keeps the index at 0:
266
+ * `% 0` is NaN, and a NaN index silently disables the highlight, the accept
267
+ * key, and any later Enter that runs through the menu.
268
+ */
269
+ export declare function stepCompletionIndex(index: number, delta: number, count: number): number;
250
270
  /**
251
271
  * Resolve completion candidates for the current input: TUI-local commands,
252
272
  * the live registry descriptors, and user-invocable skills, filtered by the
@@ -26,17 +26,26 @@ export declare const MAX_FILES_PER_MESSAGE = 8;
26
26
  export declare function detectImageMediaType(data: Uint8Array): ImageMediaType | undefined;
27
27
  /** Whether a path-like token is worth probing as an image attachment. */
28
28
  export declare function looksLikeImagePath(path: string): boolean;
29
+ /** Strip one layer of ASCII or Unicode quotes and shell-escaped spaces. */
30
+ export declare function unwrapDroppedPath(token: string): string;
31
+ /** Absolute/relative drop with a dotted leaf — including unquoted spaces. */
32
+ export declare function looksLikeFilesystemDrop(path: string): boolean;
29
33
  /**
30
- * Parse a paste/drop into its image and file paths: image-suffixed tokens
31
- * stay images, other path-shaped tokens ride as file attachments (0.1.5
32
- * file blocks), and anything that is neither leaves both empty — the caller
33
- * then treats the paste as plain text.
34
+ * A composer draft that is a filesystem path, not a slash command.
35
+ * `/usage` stays a command; `/Users/foo.png` and `C:\temp\a.png` are drops.
36
+ */
37
+ export declare function looksLikePathDraft(value: string): boolean;
38
+ /**
39
+ * Parse a paste or file-drop into image and file paths: image-suffixed
40
+ * tokens stay images, other path-shaped tokens ride as file attachments
41
+ * (0.1.5 file blocks), and anything that is neither leaves both empty —
42
+ * the caller then treats the paste as plain text.
34
43
  *
35
44
  * File tokens are held to an absolute-path-with-shape bar (drive/backslash
36
- * or a dot-suffixed leaf after a separator): a dropped terminal path always
45
+ * or a dotted leaf after a separator): a dropped terminal path always
37
46
  * carries one of those, while prose, slash commands, and option flags never
38
- * do. A POSIX absolute path without any dot-suffixed leaf falls through as
39
- * text — the @ mention route still attaches such files deliberately.
47
+ * do. A POSIX absolute path without a dotted leaf falls through as text —
48
+ * the @ mention route still attaches such files deliberately.
40
49
  */
41
50
  export declare function parsePastedAttachmentPaths(input: string): {
42
51
  readonly images: readonly string[];
@@ -78,6 +78,16 @@ export interface RecallState {
78
78
  }
79
79
  /** Fresh navigation state over one recall space. */
80
80
  export declare function beginRecall(entries: readonly string[], draft: string): RecallState;
81
+ /**
82
+ * Join a panel-recalled entry onto the draft already in the composer: the
83
+ * draft is extended, never replaced, so picking a history row cannot discard
84
+ * work in progress. An empty draft takes the entry as-is; otherwise the entry
85
+ * starts on its own line unless the draft already ends one.
86
+ * @param draft - the composer text before the recall.
87
+ * @param entry - the sanitized text of the accepted row.
88
+ * @returns the text to place in the composer.
89
+ */
90
+ export declare function appendRecall(draft: string, entry: string): string;
81
91
  /** The outcome of one recall step. */
82
92
  export interface RecallStep {
83
93
  state: RecallState;
@@ -13,7 +13,7 @@ import z from '@deepseek-ai/schemastery';
13
13
  import type { Agent, AgentStatus, Inbox } from '@deepseek-ai/dsh-agent';
14
14
  import { type ContentBlock } from '@deepseek-ai/dsh-llm';
15
15
  import { SessionId, type SessionEvent, type SessionHeader, type UserMessage } from '@deepseek-ai/dsh-session';
16
- import type { SessionPersistence } from '@deepseek-ai/dsh-session-persistence';
16
+ import { type SessionPersistence } from '@deepseek-ai/dsh-session-persistence';
17
17
  import { type QueueMutation } from './app.ts';
18
18
  import type { TuiStartup } from './startup.ts';
19
19
  import type { SearchRow } from './kernel-panels.ts';
@@ -66,7 +66,7 @@ export declare function JobsPanel({ load, close }: {
66
66
  load: () => readonly JobRow[];
67
67
  close: () => void;
68
68
  }): ReactElement;
69
- export declare function ResumePanel({ currentCwd, load, readTranscript, select, requestDelete, deleteConfirmId, reloadToken, deleteMode, close }: {
69
+ export declare function ResumePanel({ currentCwd, load, readTranscript, select, requestDelete, deleteConfirmId, reloadToken, deleteMode, presetId, close }: {
70
70
  currentCwd: string;
71
71
  load: (options: SessionDirectoryOptions, signal?: AbortSignal) => Promise<readonly SessionRow[]>;
72
72
  readTranscript: (id: string, signal?: AbortSignal) => Promise<string>;
@@ -79,6 +79,8 @@ export declare function ResumePanel({ currentCwd, load, readTranscript, select,
79
79
  reloadToken?: number;
80
80
  /** Opened via /delete: hint-first delete mode. */
81
81
  deleteMode?: boolean;
82
+ /** `/delete <id>` argument to resolve after the listing loads. */
83
+ presetId?: string;
82
84
  close: () => void;
83
85
  }): ReactElement;
84
86
  /**
@@ -51,7 +51,37 @@ export declare const en: {
51
51
  readonly 'search.compact.searching': "searching…";
52
52
  readonly 'search.compact.error': "error: {message}";
53
53
  readonly 'search.footer': "↑↓ move · enter search/resume · esc close";
54
+ readonly 'header.hint': "/help · Esc interrupt · Ctrl+C quit";
55
+ readonly 'header.hintResumed': "resumed · /help · Esc interrupt";
54
56
  readonly 'statusline.title': "/statusline · items apply to the live status line below";
57
+ readonly 'statusline.item.model': "model";
58
+ readonly 'statusline.item.model.desc': "provider/model serving this session";
59
+ readonly 'statusline.item.cwd': "cwd";
60
+ readonly 'statusline.item.cwd.desc': "working-directory basename";
61
+ readonly 'statusline.item.mode': "mode";
62
+ readonly 'statusline.item.mode.desc': "agent preset composing the session";
63
+ readonly 'statusline.item.branch': "branch";
64
+ readonly 'statusline.item.branch.desc': "git branch inside a repository";
65
+ readonly 'statusline.item.context': "context";
66
+ readonly 'statusline.item.context.desc': "context-window occupancy meter";
67
+ readonly 'statusline.item.permission': "permission";
68
+ readonly 'statusline.item.permission.desc': "permission preset badge with cycle hint";
69
+ readonly 'statusline.item.plan': "plan";
70
+ readonly 'statusline.item.plan.desc': "plan-mode state mark";
71
+ readonly 'statusline.item.turns': "turns";
72
+ readonly 'statusline.item.turns.desc': "turn and step counters";
73
+ readonly 'statusline.item.durations': "durations";
74
+ readonly 'statusline.item.durations.desc': "llm/ttft/decode/tool wall time";
75
+ readonly 'statusline.item.cache': "cache";
76
+ readonly 'statusline.item.cache.desc': "cache-hit share of billed input";
77
+ readonly 'statusline.item.tokens': "tokens";
78
+ readonly 'statusline.item.tokens.desc': "cumulative input/output tokens";
79
+ readonly 'statusline.item.title': "title";
80
+ readonly 'statusline.item.title.desc': "session title or short id";
81
+ readonly 'statusline.item.goal': "goal";
82
+ readonly 'statusline.item.goal.desc': "live goal phase and round progress";
83
+ readonly 'statusline.item.sandbox': "sandbox";
84
+ readonly 'statusline.item.sandbox.desc': "divergent sandbox-mode override";
55
85
  readonly 'schedule.title': "/schedule · {count} active reminder";
56
86
  readonly 'schedule.titlePlural': "/schedule · {count} active reminders";
57
87
  readonly 'schedule.empty': "no active reminders — the model creates them with schedule_create";
@@ -197,10 +227,16 @@ export declare const en: {
197
227
  readonly 'status.label.out': "out";
198
228
  readonly 'status.label.mode': "/mode";
199
229
  readonly 'status.label.context': "context";
230
+ readonly 'status.label.sandbox': "sandbox";
231
+ readonly 'status.plan.on': "plan on";
232
+ readonly 'status.plan.mark': "⧉ plan";
233
+ readonly 'status.goal.round': "◎ round {current}/{max}";
234
+ readonly 'status.goal.phase': "◎ {phase}";
200
235
  readonly 'frozen.keysGoTo': "keys go to {owner} · esc {action}";
201
236
  readonly 'frozen.action.rejects': "rejects";
202
237
  readonly 'frozen.action.cancels': "cancels";
203
238
  readonly 'frozen.action.closes': "closes";
239
+ readonly 'frozen.action.waits': "waits";
204
240
  readonly 'time.justNow': "now";
205
241
  readonly 'time.minutesAgo': "{n}m ago";
206
242
  readonly 'time.hoursAgo': "{n}h ago";
@@ -212,6 +248,7 @@ export declare const en: {
212
248
  readonly 'notice.themeSaveFailed': "theme save failed: {message}";
213
249
  readonly 'notice.languageSaveFailed': "language save failed: {message}";
214
250
  readonly 'notice.alreadyActive': "that session is already active";
251
+ readonly 'notice.permissionPresetsUnmounted': "permission presets are not mounted in this composition";
215
252
  readonly 'notice.queueCancelled': "queued message cancelled";
216
253
  readonly 'notice.queueActionFailed': "queue action failed: {message}";
217
254
  readonly 'notice.queueUnavailable': "queued message is no longer pending";
@@ -226,6 +263,8 @@ export declare const en: {
226
263
  readonly 'notice.usage.animation': "usage: /animation [on|off]";
227
264
  readonly 'notice.usage.language': "usage: /language [en|zh]";
228
265
  readonly 'notice.usage.rainbow': "usage: /rainbow [seed]";
266
+ readonly 'notice.usage.bareCommand': "usage: /{name}";
267
+ readonly 'notice.switchInProgress': "switching sessions — send again once the new session is up, or /resume cancel";
229
268
  readonly 'notice.imageCancelled': "image submission cancelled";
230
269
  readonly 'notice.themeConfigUnreadable': "theme config unreadable, using dark: {message}";
231
270
  readonly 'notice.languageConfigUnreadable': "language config unreadable, using english: {message}";
@@ -256,6 +295,13 @@ export declare const en: {
256
295
  readonly 'notice.resumeFailed': "resume failed: {message}";
257
296
  readonly 'notice.forkFailed': "fork failed: {message}";
258
297
  readonly 'notice.sessionSwitchFailed': "session switch failed: {message}";
298
+ readonly 'notice.sessionCreated': "created {id} · mode {mode}";
299
+ readonly 'notice.sessionResumed': "resumed {id} · mode {mode}";
300
+ readonly 'notice.sessionSwitchedDirty': "switched to {id}, but {detail}";
301
+ readonly 'notice.flushFailed': "previous session flush failed: {message}";
302
+ readonly 'notice.agentReleaseFailed': "previous agent release failed: {message}";
303
+ readonly 'notice.copyEmpty': "nothing to copy yet";
304
+ readonly 'notice.copied': "copied latest response";
259
305
  readonly 'notice.switchQueued': "will switch to {label} when the current turn finishes · /resume cancel to abort";
260
306
  readonly 'notice.reviewStarted': "review started under read-only permissions";
261
307
  readonly 'notice.reviewFailed': "review failed: {message}";
@@ -307,7 +353,8 @@ export declare const en: {
307
353
  readonly 'panel.footer.chooseSelect': "↑↓ choose · enter select · r refresh · esc close";
308
354
  readonly 'panel.footer.inspectDetails': "↑↓ inspect · enter details · r refresh · esc close";
309
355
  readonly 'panel.footer.inspectRefresh': "↑↓ inspect · r refresh · esc close";
310
- readonly 'panel.footer.resume': "tab/←→ filters · ↑↓/pg navigate · ctrl+f search · e details · t transcript · d delete · enter resume";
356
+ readonly 'panel.footer.resume': "tab/←→ filters · ↑↓/pg navigate · ctrl+f search · e details · t transcript · enter resume";
357
+ readonly 'panel.footer.delete': "tab/←→ filters · ↑↓/pg navigate · ctrl+f search · e details · t transcript · enter delete · esc close";
311
358
  readonly 'panel.footer.transcript': "lines {from}-{to}/{total} · ↑↓/pg/g/G · t/esc close";
312
359
  readonly 'panel.footer.history': "↑↓ move · g/G ends · enter fill · esc close";
313
360
  readonly 'panel.footer.review': "↑↓ move · enter select · esc back · q close";
@@ -319,6 +366,7 @@ export declare const en: {
319
366
  readonly 'panel.jobs.title': "/jobs · background tasks · {count}";
320
367
  readonly 'panel.resume.deleteTitle': "permanently delete {target}? this cannot be undone · subagent threads go too";
321
368
  readonly 'panel.resume.title': "/resume{mode}{search} · {toolbar}";
369
+ readonly 'panel.delete.title': "/delete{search} · {toolbar}";
322
370
  readonly 'panel.noActiveReminders': "no active reminders — the model schedules via schedule_create";
323
371
  readonly 'panel.notMounted': "not mounted";
324
372
  readonly 'panel.broken': "broken: {message}";
@@ -119,6 +119,8 @@ export interface StatusItemInfo {
119
119
  }
120
120
  /** The full item catalog in canonical order (the /statusline default). */
121
121
  export declare const STATUS_ITEMS: readonly StatusItemInfo[];
122
+ /** Picker rows with labels/descriptions in the active interface language. */
123
+ export declare function localizedStatusItems(): readonly StatusItemInfo[];
122
124
  /**
123
125
  * Default order: the whole catalog (matches the pre-customization bar).
124
126
  * The busy dot is not an item — it always leads the identity cluster.
@@ -178,7 +180,8 @@ export declare function permissionTone(permission: string): StatusTone;
178
180
  /**
179
181
  * Compose the two-row footer layout under a column budget. Row 1 keeps model,
180
182
  * cwd, mode, branch, context, then the right-pinned permission badge and cycle
181
- * hint. It drops hint, context, and permission before ellipsizing identity.
183
+ * hint. It shrinks the context bar, drops the hint, and peels trailing
184
+ * identity facts before removing the context group or the permission badge.
182
185
  * Row 2 fits all secondary figures and state within its own budget.
183
186
  * @param facts - identity facts resolved by the runner.
184
187
  * @param stats - session figures folded from the durable log.
@@ -1,10 +1,26 @@
1
1
  /** Lightweight session-directory projection for the /resume picker. */
2
- import { type SessionEvent, type SessionHeader } from '@deepseek-ai/dsh-session';
2
+ import { SessionId, type SessionEvent, type SessionHeader } from '@deepseek-ai/dsh-session';
3
3
  export interface SessionRecord {
4
4
  readonly header: SessionHeader;
5
5
  readonly live: boolean;
6
6
  readonly persisted: boolean;
7
7
  }
8
+ /** Minimal write handle retained while a planned deletion touches artifacts. */
9
+ export interface SessionDeletionLease {
10
+ close(): Promise<void>;
11
+ }
12
+ /** Public persistence operation used to acquire the backend's write lease. */
13
+ export interface SessionDeletionPersistence {
14
+ open(id: SessionId, access: 'write'): Promise<SessionDeletionLease>;
15
+ }
16
+ /**
17
+ * Acquire every subtree member's cross-process write lease before deleting
18
+ * any artifact. A partial acquisition is rolled back, so callers either hold
19
+ * the whole deletion boundary or touch nothing.
20
+ */
21
+ export declare function acquireSessionDeletionLeases(persistence: SessionDeletionPersistence, ids: readonly string[]): Promise<readonly SessionDeletionLease[]>;
22
+ /** Release deletion leases in reverse acquisition order. */
23
+ export declare function releaseSessionDeletionLeases(leases: readonly SessionDeletionLease[]): Promise<void>;
8
24
  export interface TitleObservationResult {
9
25
  readonly sessionId: string;
10
26
  readonly status: 'fulfilled' | 'rejected';
@@ -78,6 +94,12 @@ export declare function isSubagentSession(header: SessionHeader): boolean;
78
94
  * @throws when nothing matches or the prefix is ambiguous.
79
95
  */
80
96
  export declare function matchSessionId(headers: readonly SessionHeader[], wanted: string): SessionHeader;
97
+ /**
98
+ * Unique picker-row match by exact id, unique prefix, or unique suffix.
99
+ * The resume list shows `id.slice(-12)`, so `/delete` arguments are often
100
+ * that tail rather than a leading prefix.
101
+ */
102
+ export declare function matchSessionRow(rows: readonly SessionRow[], wanted: string): SessionRow;
81
103
  /** The newest persisted ROOT session pinned to this cwd, or undefined. */
82
104
  export declare function newestRootForCwd(headers: readonly SessionHeader[], cwd: string): SessionHeader | undefined;
83
105
  /**
@@ -90,6 +112,8 @@ export declare function newestRootForCwd(headers: readonly SessionHeader[], cwd:
90
112
  * @param updated - per-session last-activity timestamps, when resolved.
91
113
  */
92
114
  export declare function projectSessionRows(records: readonly SessionRecord[], options: SessionDirectoryOptions, updated?: ReadonlyMap<string, number>): SessionRow[];
115
+ /** True when the picker query hits id, path, preset, or the displayed title. */
116
+ export declare function sessionRowMatchesQuery(row: Pick<SessionRow, 'id' | 'cwd' | 'workspace' | 'preset' | 'title'>, query: string): boolean;
93
117
  /** Merge page-local title observations without disturbing directory order. */
94
118
  export declare function mergeSessionTitles(rows: readonly SessionRow[], observations: readonly TitleObservationResult[]): SessionRow[];
95
119
  /**
@@ -8,10 +8,18 @@ export declare class SessionSwitchQueue<T> {
8
8
  private readonly failed;
9
9
  private pending;
10
10
  private pumping;
11
+ private running;
11
12
  constructor(execute: (value: T) => Promise<void>, failed: (error: unknown) => void);
12
13
  /** Queue a request; a later request replaces any request still waiting. */
13
14
  request(activity: IdleActivity, value: T): 'queued' | 'started';
14
15
  /** Cancel only work that has not begun activation. */
15
16
  cancel(): boolean;
17
+ /**
18
+ * Whether a queued change is being activated right now. Between the idle
19
+ * wait and the handoff the old session is still installed, so a submission
20
+ * made in that window would start a turn the handoff then discards; callers
21
+ * use this to refuse one instead of losing it.
22
+ */
23
+ get activating(): boolean;
16
24
  private pump;
17
25
  }
@@ -9,11 +9,31 @@
9
9
  * here.
10
10
  */
11
11
  import { type ReactElement } from 'react';
12
- import type { LauncherUpdateStatus } from './update.ts';
12
+ import type { LauncherUpdatePlan, LauncherUpdateStatus } from './update.ts';
13
13
  /** Retained apply-progress lines (ring tail; npm output is ephemeral). */
14
14
  export declare const UPDATE_OUTPUT_CAP = 800;
15
15
  /** Keep the newest UPDATE_OUTPUT_CAP lines of streamed update output. */
16
16
  export declare function clipUpdateLines(lines: readonly string[]): readonly string[];
17
+ /** One in-flight `update --apply`. Closing the panel must not start a second. */
18
+ interface UpdateApplyJob {
19
+ readonly promise: Promise<number>;
20
+ readonly lines: string[];
21
+ readonly lineListeners: Set<(line: string) => void>;
22
+ }
23
+ /** True while an apply child is alive, even if the /update panel is closed. */
24
+ export declare function isUpdateApplyRunning(): boolean;
25
+ /** Subscribe to apply-running changes (frozen-hint "esc waits"). */
26
+ export declare function subscribeUpdateApplyRunning(listener: (running: boolean) => void): () => void;
27
+ /** The live apply job, if any: lines already streamed plus the shared promise. */
28
+ export declare function currentUpdateApply(): UpdateApplyJob | undefined;
29
+ /**
30
+ * Run `apply` once. A second call while the child is alive reuses the same
31
+ * promise and replays buffered lines — closing /update and opening it again
32
+ * must not spawn a second `npm install`.
33
+ */
34
+ export declare function runUpdateApply(apply: (onLine: (line: string) => void, plan: LauncherUpdatePlan) => Promise<number>, plan: LauncherUpdatePlan, onLine?: (line: string) => void): Promise<number>;
35
+ /** Drop a leftover job between tests. */
36
+ export declare function resetUpdateApply(): void;
17
37
  /** One display row of the update surface. */
18
38
  export interface UpdateRow {
19
39
  readonly key: string;
@@ -47,3 +67,4 @@ export declare function UpdatePanel({ probe, apply, close, notify }: {
47
67
  /** One bounded cross-surface notice (phase completions). */
48
68
  notify: (text: string, tone?: 'info' | 'warning' | 'error') => void;
49
69
  }): ReactElement;
70
+ export {};
@@ -1,6 +1,8 @@
1
1
  /** Installed dsh-code version exposed by the terminal header. */
2
2
  /** Version of the installed dsh-code package. */
3
3
  export declare const DSH_CODE_VERSION: string;
4
+ /** Header brand line: hide a missing-manifest fallback so we never paint v0.0.0. */
5
+ export declare function headerBrandTitle(version?: string): string;
4
6
  /**
5
7
  * Resolve the running dsh CLI host's version from its entry file
6
8
  * (`process.argv[1]`, e.g. `.../@deepseek-ai/dsh/lib/bin.js` or a PATH
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "dsh-code",
3
3
  "description": "DeepSeek Harness CLI core bundle: interactive coding terminal, durable sessions, and model management for dsh --profile cli",
4
- "version": "1.2.0",
4
+ "version": "1.3.0",
5
+ "packageManager": "pnpm@12.4.1",
5
6
  "type": "module",
6
7
  "bin": {
7
8
  "deepseek": "./bin/deepseek.mjs",
@@ -57,16 +58,17 @@
57
58
  },
58
59
  "scripts": {
59
60
  "build": "tsdown && tsc -p tsconfig.json",
61
+ "audit:prod": "pnpm audit --prod --audit-level moderate",
60
62
  "test": "vitest run",
61
63
  "test:coverage": "vitest run --coverage",
62
64
  "typecheck": "tsc -p tsconfig.json --noEmit",
63
65
  "typecheck:tests": "tsc -p tsconfig.test.json --noEmit",
64
- "lint": "eslint .",
65
- "lint:fix": "eslint . --fix",
66
+ "lint": "eslint . --max-warnings 0",
67
+ "lint:fix": "eslint . --fix --max-warnings 0",
66
68
  "verify": "pnpm lint && pnpm typecheck && pnpm typecheck:tests && pnpm test",
67
69
  "gen:whale": "tsx scripts/gen-whale-glyph.ts",
68
70
  "prepare": "pnpm build",
69
- "prepublishOnly": "pnpm typecheck && pnpm typecheck:tests && pnpm test && pnpm build"
71
+ "prepublishOnly": "pnpm audit:prod && pnpm exec tsx scripts/check-release.ts --package-version && pnpm verify && pnpm build"
70
72
  },
71
73
  "engines": {
72
74
  "node": "^22.19 || >=24"
@@ -314,7 +316,7 @@
314
316
  "@vitest/coverage-v8": "^3.2.7",
315
317
  "eslint": "^10.10.0",
316
318
  "eslint-plugin-react-hooks": "^7.1.1",
317
- "js-yaml": "^4.3.1",
319
+ "js-yaml": "^4.3.2",
318
320
  "tsdown": "^0.22.2",
319
321
  "tsx": "^4.22.4",
320
322
  "typescript": "^5.9.0",