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.
Files changed (86) hide show
  1. package/README.en.md +123 -26
  2. package/README.md +124 -27
  3. package/bin/deepseek.mjs +283 -35
  4. package/cordis.patch.yml +97 -0
  5. package/lib/index.mjs +5008 -881
  6. package/lib/session-query.mjs +150 -0
  7. package/lib/startup.mjs +4 -4
  8. package/lib/{theme-DCT8Y2xf.mjs → theme-7u5Qo3dF.mjs} +657 -20
  9. package/lib/types/app.d.ts +106 -62
  10. package/lib/types/authorization-panel.d.ts +3 -3
  11. package/lib/types/git-workflow.d.ts +91 -2
  12. package/lib/types/i18n.d.ts +39 -0
  13. package/lib/types/index.d.ts +100 -1
  14. package/lib/types/input-split.d.ts +1 -1
  15. package/lib/types/kernel-panels.d.ts +107 -29
  16. package/lib/types/language-panel.d.ts +12 -0
  17. package/lib/types/locales/en.d.ts +450 -0
  18. package/lib/types/locales/zh.d.ts +9 -0
  19. package/lib/types/mentions.d.ts +7 -3
  20. package/lib/types/models.d.ts +14 -0
  21. package/lib/types/panel-accent.d.ts +28 -0
  22. package/lib/types/rainbow.d.ts +69 -0
  23. package/lib/types/render/animations.d.ts +42 -0
  24. package/lib/types/render/editor.d.ts +4 -3
  25. package/lib/types/render/ime-cursor.d.ts +60 -0
  26. package/lib/types/render/inspector.d.ts +26 -0
  27. package/lib/types/render/lines.d.ts +21 -1
  28. package/lib/types/render/markdown.d.ts +1 -1
  29. package/lib/types/render/projection.d.ts +130 -4
  30. package/lib/types/render/status.d.ts +9 -9
  31. package/lib/types/render/text.d.ts +6 -0
  32. package/lib/types/render/usage.d.ts +113 -0
  33. package/lib/types/session-directory.d.ts +17 -0
  34. package/lib/types/session-query.d.ts +92 -0
  35. package/lib/types/startup.d.ts +1 -1
  36. package/lib/types/terminal-title.d.ts +66 -0
  37. package/lib/types/theme-panel.d.ts +2 -2
  38. package/lib/types/theme.d.ts +271 -52
  39. package/lib/types/update-panel.d.ts +49 -0
  40. package/lib/types/update.d.ts +75 -0
  41. package/lib/types/version.d.ts +4 -3
  42. package/package.json +246 -90
  43. package/src/app.ts +1369 -509
  44. package/src/approval.ts +166 -166
  45. package/src/authorization-panel.ts +19 -16
  46. package/src/editor-keys.ts +371 -371
  47. package/src/git-workflow.ts +229 -3
  48. package/src/i18n.ts +68 -0
  49. package/src/index.ts +534 -80
  50. package/src/input-split.ts +3 -3
  51. package/src/internals.ts +5 -0
  52. package/src/kernel-panels.ts +554 -86
  53. package/src/keyboard.ts +5 -4
  54. package/src/language-panel.ts +53 -0
  55. package/src/locales/en.ts +489 -0
  56. package/src/locales/zh.ts +488 -0
  57. package/src/mentions.ts +8 -4
  58. package/src/models.ts +264 -212
  59. package/src/panel-accent.ts +41 -0
  60. package/src/presets.ts +1 -1
  61. package/src/provider-settings.ts +1 -1
  62. package/src/rainbow.ts +208 -0
  63. package/src/render/animations.ts +104 -6
  64. package/src/render/editor.ts +25 -24
  65. package/src/render/export.ts +116 -95
  66. package/src/render/ime-cursor.ts +147 -0
  67. package/src/render/inspector.ts +42 -0
  68. package/src/render/lines.ts +628 -415
  69. package/src/render/markdown.ts +15 -3
  70. package/src/render/projection.ts +572 -21
  71. package/src/render/status.ts +59 -39
  72. package/src/render/text.ts +14 -0
  73. package/src/render/tool-preview.ts +77 -77
  74. package/src/render/usage.ts +430 -0
  75. package/src/render/width.ts +2 -2
  76. package/src/session-directory.ts +8 -6
  77. package/src/session-query.ts +239 -0
  78. package/src/startup.ts +3 -3
  79. package/src/subagents.ts +229 -229
  80. package/src/terminal-title.ts +190 -0
  81. package/src/theme-panel.ts +17 -21
  82. package/src/theme.ts +281 -33
  83. package/src/update-panel.ts +256 -0
  84. package/src/update.ts +126 -0
  85. package/src/version.ts +58 -20
  86. 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 { t as THEME_NAMES } from "./theme-DCT8Y2xf.mjs";
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("--theme must be dark, light, or auto");
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