dsh-code 1.0.6 → 1.2.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/README.en.md +123 -26
- package/README.md +124 -27
- package/bin/deepseek.mjs +283 -35
- package/cordis.patch.yml +97 -0
- package/lib/index.mjs +5008 -881
- package/lib/session-query.mjs +150 -0
- package/lib/startup.mjs +4 -4
- package/lib/{theme-DCT8Y2xf.mjs → theme-7u5Qo3dF.mjs} +657 -20
- package/lib/types/app.d.ts +106 -62
- package/lib/types/authorization-panel.d.ts +3 -3
- package/lib/types/git-workflow.d.ts +91 -2
- package/lib/types/i18n.d.ts +39 -0
- package/lib/types/index.d.ts +100 -1
- package/lib/types/input-split.d.ts +1 -1
- package/lib/types/kernel-panels.d.ts +107 -29
- package/lib/types/language-panel.d.ts +12 -0
- package/lib/types/locales/en.d.ts +450 -0
- package/lib/types/locales/zh.d.ts +9 -0
- package/lib/types/mentions.d.ts +7 -3
- package/lib/types/models.d.ts +14 -0
- package/lib/types/panel-accent.d.ts +28 -0
- package/lib/types/rainbow.d.ts +69 -0
- package/lib/types/render/animations.d.ts +42 -0
- package/lib/types/render/editor.d.ts +4 -3
- package/lib/types/render/ime-cursor.d.ts +60 -0
- package/lib/types/render/inspector.d.ts +26 -0
- package/lib/types/render/lines.d.ts +21 -1
- package/lib/types/render/markdown.d.ts +1 -1
- package/lib/types/render/projection.d.ts +130 -4
- package/lib/types/render/status.d.ts +9 -9
- package/lib/types/render/text.d.ts +6 -0
- package/lib/types/render/usage.d.ts +113 -0
- package/lib/types/session-directory.d.ts +17 -0
- package/lib/types/session-query.d.ts +92 -0
- package/lib/types/startup.d.ts +1 -1
- package/lib/types/terminal-title.d.ts +66 -0
- package/lib/types/theme-panel.d.ts +2 -2
- package/lib/types/theme.d.ts +271 -52
- package/lib/types/update-panel.d.ts +49 -0
- package/lib/types/update.d.ts +75 -0
- package/lib/types/version.d.ts +4 -3
- package/package.json +246 -90
- package/src/app.ts +1369 -509
- package/src/approval.ts +166 -166
- package/src/authorization-panel.ts +19 -16
- package/src/editor-keys.ts +371 -371
- package/src/git-workflow.ts +229 -3
- package/src/i18n.ts +68 -0
- package/src/index.ts +534 -80
- package/src/input-split.ts +3 -3
- package/src/internals.ts +5 -0
- package/src/kernel-panels.ts +554 -86
- package/src/keyboard.ts +5 -4
- package/src/language-panel.ts +53 -0
- package/src/locales/en.ts +489 -0
- package/src/locales/zh.ts +488 -0
- package/src/mentions.ts +8 -4
- package/src/models.ts +264 -212
- package/src/panel-accent.ts +41 -0
- package/src/presets.ts +1 -1
- package/src/provider-settings.ts +1 -1
- package/src/rainbow.ts +208 -0
- package/src/render/animations.ts +104 -6
- package/src/render/editor.ts +25 -24
- package/src/render/export.ts +116 -95
- package/src/render/ime-cursor.ts +147 -0
- package/src/render/inspector.ts +42 -0
- package/src/render/lines.ts +628 -415
- package/src/render/markdown.ts +15 -3
- package/src/render/projection.ts +572 -21
- package/src/render/status.ts +59 -39
- package/src/render/text.ts +14 -0
- package/src/render/tool-preview.ts +77 -77
- package/src/render/usage.ts +430 -0
- package/src/render/width.ts +2 -2
- package/src/session-directory.ts +8 -6
- package/src/session-query.ts +239 -0
- package/src/startup.ts +3 -3
- package/src/subagents.ts +229 -229
- package/src/terminal-title.ts +190 -0
- package/src/theme-panel.ts +17 -21
- package/src/theme.ts +281 -33
- package/src/update-panel.ts +256 -0
- package/src/update.ts +126 -0
- package/src/version.ts +58 -20
- package/src/whale-glyph.ts +23 -23
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import SqliteSessionQueryEngine from "@deepseek-ai/dsh-session-query-sqlite";
|
|
3
|
+
import { SessionQueryError, assertSessionHeadersCompatible, buildSessionEventSearchDocuments, readColdSessionLog } from "@deepseek-ai/dsh-session-query";
|
|
4
|
+
//#region src/session-query.ts
|
|
5
|
+
/**
|
|
6
|
+
* Skip-tolerant session-query engine for this terminal.
|
|
7
|
+
*
|
|
8
|
+
* The upstream SqliteSessionQueryEngine reconciliation observes EVERY
|
|
9
|
+
* persisted session before each search, and ONE unreadable source (for
|
|
10
|
+
* example a pre-release session artifact the frozen format codecs reject)
|
|
11
|
+
* fails the whole pass with SESSION_QUERY_PERSISTENCE_FAILED — every
|
|
12
|
+
* cross-session search dies because of a single old file nobody opened
|
|
13
|
+
* otherwise. This subclass overrides only the observation loop so an
|
|
14
|
+
* unreadable source is skipped with a warning and the rest of the corpus
|
|
15
|
+
* indexes normally; skipped sessions are retried on later reconciliations
|
|
16
|
+
* and rejoin automatically once a host that can read them is installed.
|
|
17
|
+
*
|
|
18
|
+
* Vendored surface note: `_observeStable` and its module-local helpers are
|
|
19
|
+
* private upstream; this file re-declares the observation loop against the
|
|
20
|
+
* pinned @deepseek-ai line (see package.json peers) and must be re-checked
|
|
21
|
+
* whenever that line moves. The engine class and the tool boundary also
|
|
22
|
+
* share ONE physical parent-package instance through this bundle, which
|
|
23
|
+
* restores instanceof-based typed error messages on the search path.
|
|
24
|
+
*/
|
|
25
|
+
const STABLE_OBSERVATION_ATTEMPTS = 2;
|
|
26
|
+
function assertNotAborted(signal) {
|
|
27
|
+
if (signal?.aborted) throw new SessionQueryError("session-search aborted", "SESSION_QUERY_ABORTED");
|
|
28
|
+
}
|
|
29
|
+
function isAbort(error) {
|
|
30
|
+
return error instanceof SessionQueryError && error.code === "SESSION_QUERY_ABORTED";
|
|
31
|
+
}
|
|
32
|
+
function errorMessage(error) {
|
|
33
|
+
return error instanceof Error ? error.message : "unknown error";
|
|
34
|
+
}
|
|
35
|
+
function observeSession(header, inheritedEventCount, events) {
|
|
36
|
+
const detachedHeader = structuredClone(header);
|
|
37
|
+
const detachedEvents = events.map((event) => structuredClone(event));
|
|
38
|
+
return {
|
|
39
|
+
header: detachedHeader,
|
|
40
|
+
inheritedEventCount,
|
|
41
|
+
documents: buildSessionEventSearchDocuments(detachedHeader.id, detachedEvents),
|
|
42
|
+
fingerprint: createHash("sha256").update(JSON.stringify({
|
|
43
|
+
header: detachedHeader,
|
|
44
|
+
inheritedEventCount,
|
|
45
|
+
events: detachedEvents
|
|
46
|
+
})).digest("base64url")
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function sameHeader(a, b) {
|
|
50
|
+
return a.id === b.id && a.createdAt === b.createdAt && a.cwd === b.cwd && a.parentSession === b.parentSession && a.isSeeded === b.isSeeded && (a.delegationDepth ?? 0) === (b.delegationDepth ?? 0) && a.agentPreset === b.agentPreset;
|
|
51
|
+
}
|
|
52
|
+
function materializePersistenceSnapshots(snapshots) {
|
|
53
|
+
const candidate = snapshots;
|
|
54
|
+
if (!Array.isArray(candidate)) throw new Error("persistence snapshots must be an array");
|
|
55
|
+
const result = /* @__PURE__ */ new Map();
|
|
56
|
+
for (const snapshot of candidate) {
|
|
57
|
+
if (typeof snapshot.revision !== "string") throw new Error("persistence snapshot revision must be a string");
|
|
58
|
+
const header = structuredClone(snapshot.header);
|
|
59
|
+
if (result.has(header.id)) throw new Error(`persistence listed duplicate session "${header.id}"`);
|
|
60
|
+
result.set(header.id, {
|
|
61
|
+
header,
|
|
62
|
+
revision: snapshot.revision
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
function samePersistenceSnapshots(before, after) {
|
|
68
|
+
if (before.size !== after.size) return false;
|
|
69
|
+
for (const [id, first] of before) {
|
|
70
|
+
const second = after.get(id);
|
|
71
|
+
if (second === void 0 || first.revision !== second.revision || !sameHeader(first.header, second.header)) return false;
|
|
72
|
+
}
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The skip-tolerant observation pass: structurally the upstream loop, with
|
|
77
|
+
* the per-source cold read wrapped so one unreadable session degrades to a
|
|
78
|
+
* warning instead of failing every search. Exported for unit tests with an
|
|
79
|
+
* injectable cold reader.
|
|
80
|
+
*/
|
|
81
|
+
async function observeStableWithSkip(engine, indexed, signal, readCold = readColdSessionLog) {
|
|
82
|
+
for (let attempt = 0; attempt < STABLE_OBSERVATION_ATTEMPTS; attempt += 1) {
|
|
83
|
+
assertNotAborted(signal);
|
|
84
|
+
const persistenceBinding = engine._persistenceBinding;
|
|
85
|
+
const persistence = persistenceBinding.service;
|
|
86
|
+
const initiallyLive = new Set(engine.ctx.sessions.list().map((session) => session.id));
|
|
87
|
+
let persisted = /* @__PURE__ */ new Map();
|
|
88
|
+
if (persistence !== void 0) try {
|
|
89
|
+
const canReuseIndexed = engine._lastPersistenceIdentity === void 0 || engine._lastPersistenceIdentity === persistenceBinding.identity;
|
|
90
|
+
const listOptions = signal === void 0 ? void 0 : { signal };
|
|
91
|
+
const before = await persistence.list(listOptions);
|
|
92
|
+
assertNotAborted(signal);
|
|
93
|
+
persisted = materializePersistenceSnapshots(before);
|
|
94
|
+
for (const entry of persisted.values()) {
|
|
95
|
+
if (canReuseIndexed && indexed.get(entry.header.id)?.revision === entry.revision) continue;
|
|
96
|
+
if (initiallyLive.has(entry.header.id) || engine.ctx.sessions.get(entry.header.id) !== void 0) continue;
|
|
97
|
+
assertNotAborted(signal);
|
|
98
|
+
try {
|
|
99
|
+
const loaded = await readCold(persistence, entry.header.id, signal);
|
|
100
|
+
assertNotAborted(signal);
|
|
101
|
+
assertSessionHeadersCompatible(entry.header, loaded.header);
|
|
102
|
+
entry.loaded = observeSession(loaded.header, loaded.inheritedEventCount, loaded.events);
|
|
103
|
+
} catch (error) {
|
|
104
|
+
if (isAbort(error) || signal?.aborted) throw error;
|
|
105
|
+
if (engine._persistenceBinding !== persistenceBinding) break;
|
|
106
|
+
entry.unreadable = errorMessage(error);
|
|
107
|
+
engine.ctx.logger?.warn("session-search skipped unreadable session %s: %s", entry.header.id, entry.unreadable);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
assertNotAborted(signal);
|
|
111
|
+
const afterSnapshots = await persistence.list(listOptions);
|
|
112
|
+
assertNotAborted(signal);
|
|
113
|
+
const after = materializePersistenceSnapshots(afterSnapshots);
|
|
114
|
+
if (!samePersistenceSnapshots(persisted, after)) continue;
|
|
115
|
+
if (engine._persistenceBinding !== persistenceBinding) continue;
|
|
116
|
+
} catch (error) {
|
|
117
|
+
if (isAbort(error) || signal?.aborted) throw new SessionQueryError("session-search aborted", "SESSION_QUERY_ABORTED", { cause: error });
|
|
118
|
+
if (engine._persistenceBinding !== persistenceBinding) continue;
|
|
119
|
+
if (error instanceof SessionQueryError) throw error;
|
|
120
|
+
throw new SessionQueryError(`session-search persistence observation failed: ${errorMessage(error)}`, "SESSION_QUERY_PERSISTENCE_FAILED", { cause: error });
|
|
121
|
+
}
|
|
122
|
+
const live = /* @__PURE__ */ new Map();
|
|
123
|
+
for (const session of engine.ctx.sessions.list()) {
|
|
124
|
+
const observed = observeSession(session.header, session.inheritedEventCount, session.snapshotEvents());
|
|
125
|
+
const durable = persisted.get(session.id);
|
|
126
|
+
if (durable !== void 0 && durable.loaded === void 0) {
|
|
127
|
+
live.set(session.id, observed);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (durable !== void 0) assertSessionHeadersCompatible(observed.header, durable.header);
|
|
131
|
+
live.set(session.id, observed);
|
|
132
|
+
}
|
|
133
|
+
if (!(initiallyLive.size === live.size && [...initiallyLive].every((id) => live.has(id)))) continue;
|
|
134
|
+
return {
|
|
135
|
+
persistenceBinding,
|
|
136
|
+
persisted,
|
|
137
|
+
live
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
throw new SessionQueryError("session-search persistence observation did not stabilize after one retry", "SESSION_QUERY_PERSISTENCE_FAILED");
|
|
141
|
+
}
|
|
142
|
+
const EngineBase = SqliteSessionQueryEngine;
|
|
143
|
+
/** The engine this bundle mounts in place of the base `session-query-sqlite` row. */
|
|
144
|
+
var SkipTolerantSessionQueryEngine = class extends EngineBase {
|
|
145
|
+
async _observeStable(indexed, signal) {
|
|
146
|
+
return await observeStableWithSkip(this, indexed, signal);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
//#endregion
|
|
150
|
+
export { SkipTolerantSessionQueryEngine, SkipTolerantSessionQueryEngine as default, observeStableWithSkip };
|
package/lib/startup.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { r as THEME_NAMES } from "./theme-7u5Qo3dF.mjs";
|
|
2
2
|
import { Command } from "commander";
|
|
3
3
|
import { parseCmdline } from "@deepseek-ai/dsh-cmdline";
|
|
4
4
|
//#region src/startup.ts
|
|
@@ -18,7 +18,7 @@ import { parseCmdline } from "@deepseek-ai/dsh-cmdline";
|
|
|
18
18
|
* whose project directory matches the current working directory.
|
|
19
19
|
* - `--session <id>` — create a new session under an explicit identity (the
|
|
20
20
|
* id must not exist yet).
|
|
21
|
-
* - `--theme <dark|light|auto>` — the color palette; auto follows the
|
|
21
|
+
* - `--theme <dark|light|prismatic|rainbow|auto>` — the color palette; auto follows the
|
|
22
22
|
* terminal (dark fallback until OSC-11 detection lands).
|
|
23
23
|
* - no flags — a fresh session with a minted id.
|
|
24
24
|
*
|
|
@@ -41,7 +41,7 @@ function resolveTuiStartup(options) {
|
|
|
41
41
|
if (options.resume === "") throw new Error("--resume needs a session id or id prefix");
|
|
42
42
|
if (options.mode === "") throw new Error("--mode needs a preset id");
|
|
43
43
|
if (options.mode !== void 0 && (options.resume !== void 0 || options.continue === true)) throw new Error("--mode applies only to a new session; it cannot be combined with --resume or --continue");
|
|
44
|
-
if (options.theme !== void 0 && !THEME_NAMES.includes(options.theme)) throw new Error(
|
|
44
|
+
if (options.theme !== void 0 && !THEME_NAMES.includes(options.theme)) throw new Error(`--theme must be one of: ${THEME_NAMES.join(", ")}`);
|
|
45
45
|
const input = {
|
|
46
46
|
...options.theme === void 0 ? {} : { theme: options.theme },
|
|
47
47
|
...options.prompt === void 0 || options.prompt.trim() === "" ? {} : { prompt: options.prompt.trim() },
|
|
@@ -71,7 +71,7 @@ function resolveTuiStartup(options) {
|
|
|
71
71
|
* @returns a fresh program, so one process can parse more than once (tests).
|
|
72
72
|
*/
|
|
73
73
|
function tuiCommand() {
|
|
74
|
-
return new Command().name("dsh --profile cli").description("DeepSeek Harness CLI core: the interactive coding terminal.").helpOption("-h, --help", "show this help").option("-r, --resume <session>", "resume the persisted session with this id (or unique id prefix)").option("-c, --continue", "resume the most recent persisted session for this working directory").option("--session <id>", "create a new session under this explicit id").option("--mode <preset>", "agent preset for a newly created session").option("--theme <name>", "color theme: dark (default), light, or auto").option("-i, --image <path>", "attach an image to the initial prompt (repeatable)", (path, paths) => [...paths, path], []).argument("[prompt...]", "initial prompt; sends immediately after startup").addHelpText("after", `
|
|
74
|
+
return new Command().name("dsh --profile cli").description("DeepSeek Harness CLI core: the interactive coding terminal.").helpOption("-h, --help", "show this help").option("-r, --resume <session>", "resume the persisted session with this id (or unique id prefix)").option("-c, --continue", "resume the most recent persisted session for this working directory").option("--session <id>", "create a new session under this explicit id").option("--mode <preset>", "agent preset for a newly created session").option("--theme <name>", "color theme: dark (default), light, prismatic, rainbow, or auto").option("-i, --image <path>", "attach an image to the initial prompt (repeatable)", (path, paths) => [...paths, path], []).argument("[prompt...]", "initial prompt; sends immediately after startup").addHelpText("after", `
|
|
75
75
|
Examples:
|
|
76
76
|
dsh --profile cli fresh session, minted id
|
|
77
77
|
dsh --profile cli --resume abc123 resume session by id prefix
|