dsh-output-styles 0.6.2 → 0.6.4

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/CHANGELOG.md CHANGED
@@ -4,6 +4,18 @@ All notable changes to this project are documented in this file. The format
4
4
  follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the
5
5
  project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.6.4] - 2026-09-02
8
+
9
+ ### Changed
10
+
11
+ - Align the devDependency pins to the published dsh 0.1.2-alpha.5 line and re-verify the adaptation claims; no behavior change.
12
+
13
+ ## [0.6.3] - 2026-09-01
14
+
15
+ ### Changed
16
+
17
+ - Align the devDependency pins to the published dsh `0.1.2-alpha.3` line (21 `@deepseek-ai/dsh-*` packages), widen the `dsh-commands`/`dsh-system-prompt` peers to `>=0.1.0-rc.8 <0.2.0`, and raise `dshWorkshop.compatibility.dshVersions` to `0.1.2-alpha.3`. No behavior change; the five-language READMEs record the alpha.3 fact.
18
+
7
19
  ## [0.6.2] - 2026-08-30
8
20
 
9
21
  ### Fixed
package/README.es.md CHANGED
@@ -25,7 +25,7 @@
25
25
 
26
26
  | Surface | Status |
27
27
  |---|---|
28
- | Harness | DeepSeek Harness `0.1.1-rc.2` |
28
+ | Harness | DeepSeek Harness `0.1.1-rc.2` 0.1.2-alpha.5 (adaptado el 2026-09-02): el sobre de sesión conserva su campo ignorable solo para compatibilidad de lectura de logs almacenados - Session.append aún no puede estamparlo, por lo que el comportamiento de la puerta no cambia. |
29
29
  | Node | `^22.19.0 || >=24.0.0` |
30
30
  | Platforms | Todas (host + cliente web) |
31
31
  | Model | Cualquiera (inyección en el prompt del sistema) |
package/README.hi.md CHANGED
@@ -25,7 +25,7 @@
25
25
 
26
26
  | Surface | Status |
27
27
  |---|---|
28
- | Harness | DeepSeek Harness `0.1.1-rc.2` |
28
+ | Harness | DeepSeek Harness `0.1.1-rc.2` 0.1.2-alpha.5 (2026-09-02 को अनुकूलित): सत्र लिफ़ाफ़ा अपना ignorable फ़ील्ड केवल संग्रहीत-लॉग पठन संगतता के लिए रखता है - Session.append अभी भी इसे स्टैम्प नहीं कर सकता, इसलिए गेट व्यवहार अपरिवर्तित है। |
29
29
  | Node | `^22.19.0 || >=24.0.0` |
30
30
  | Platforms | सभी (host + वेब क्लाइंट) |
31
31
  | Model | कोई भी (सिस्टम-प्रॉम्प्ट इंजेक्शन) |
package/README.md CHANGED
@@ -28,7 +28,7 @@
28
28
 
29
29
  | Surface | Status |
30
30
  |---|---|
31
- | Harness | DeepSeek Harness `0.1.1-rc.2` |
31
+ | Harness | DeepSeek Harness `0.1.1-rc.2` 0.1.2-alpha.5 (adapted 2026-09-02): the session envelope keeps its ignorable field for stored-log read compatibility only - Session.append still cannot stamp it, so audit-gate behavior is unchanged. |
32
32
  | Node | `^22.19.0 || >=24.0.0` |
33
33
  | Platforms | All (host + web client) |
34
34
  | Model | Any (system-prompt injection) |
package/README.pt.md CHANGED
@@ -25,7 +25,7 @@
25
25
 
26
26
  | Surface | Status |
27
27
  |---|---|
28
- | Harness | DeepSeek Harness `0.1.1-rc.2` |
28
+ | Harness | DeepSeek Harness `0.1.1-rc.2` 0.1.2-alpha.5 (adaptado em 2026-09-02): o envelope de sessão mantém seu campo ignorable apenas para compatibilidade de leitura de logs armazenados - o Session.append ainda não consegue estampá-lo, então o comportamento da porta não muda. |
29
29
  | Node | `^22.19.0 || >=24.0.0` |
30
30
  | Platforms | Todas (host + cliente web) |
31
31
  | Model | Qualquer (injeção no prompt do sistema) |
package/README.zh.md CHANGED
@@ -27,7 +27,7 @@
27
27
 
28
28
  | Surface | Status |
29
29
  |---|---|
30
- | Harness | DeepSeek Harness `0.1.1-rc.2` |
30
+ | Harness | DeepSeek Harness `0.1.1-rc.2` 0.1.2-alpha.5(2026-09-02 已适配):会话信封保留 ignorable 字段但仅用于存量日志读取兼容——Session.append 仍无法盖章,门控行为不变。 |
31
31
  | Node | `^22.19.0 || >=24.0.0` |
32
32
  | Platforms | 全部(host + Web 客户端) |
33
33
  | Model | 任意(系统提示注入) |
package/lib/index.js CHANGED
@@ -3,7 +3,6 @@ import z from "@deepseek-ai/schemastery";
3
3
  import { resolve } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { watch } from "node:fs";
6
- import { installSettingsSection, settingsNamespace } from "@deepseek-ai/dsh-settings";
7
6
  import { deriveEventMessage, foldSurface } from "@deepseek-ai/dsh-session/surface";
8
7
  //#region lib/types/config.js
9
8
  /**
@@ -302,7 +301,8 @@ const BUILTIN_RENDERERS = [{
302
301
  /**
303
302
  * Session export: a pure projection of the current session's message surface
304
303
  * into Markdown or sanitized HTML, with renderer application on top. The
305
- * extraction reads only the public `session.events` log through the official
304
+ * extraction reads only the public session event log (`Session.events` up to
305
+ * 0.1.2-alpha.3, `Session.snapshotEvents()` from 0.1.2-alpha.5) through the official
306
306
  * `deriveEventMessage` projection — the same rule the harness uses to build
307
307
  * model requests — so the exported document is reconstructable from the log.
308
308
  * Every render application preserves the original text beside the rendered
@@ -472,12 +472,21 @@ function renderExport(registry, lines, format, rules, now = /* @__PURE__ */ new
472
472
  * configuration hot-reload replaces the whole plugin without residue.
473
473
  * @module dsh-output-styles/runtime
474
474
  */
475
+ /**
476
+ * Session events with an old-host fallback: 0.1.2-alpha.5 renamed the
477
+ * `Session.events` getter to `snapshotEvents()` while the peer floor
478
+ * (>=0.1.0-rc.8) still exposes `.events`.
479
+ */
480
+ function readSessionEvents(session) {
481
+ if (typeof session.snapshotEvents === "function") return session.snapshotEvents();
482
+ return session.events;
483
+ }
475
484
  /** Bundled style-library directory (package `styles/`), the lowest-priority `stylesDir` entry. */
476
485
  const DEFAULT_STYLES_DIR = fileURLToPath(new URL("../styles/", import.meta.url));
477
486
  /** Prompt-section name; a fixed registry key a scoped composition could shadow. */
478
487
  const STYLE_SECTION_NAME = "output-style:selection";
479
488
  /** Settings namespace owning the project-level default (`outputStyle`). */
480
- const SETTINGS_NS = settingsNamespace("output-style");
489
+ const SETTINGS_NS = "output-style";
481
490
  /** Coalescing delay for style-file change events; an internal implementation constant, not a deployment knob. */
482
491
  const WATCH_DEBOUNCE_MS = 250;
483
492
  /**
@@ -719,14 +728,14 @@ async function apply(ctx, config) {
719
728
  };
720
729
  });
721
730
  }
722
- installSettingsSection(ctx, SETTINGS_NS, z.object({ style: z.string().default("") }), { style: resolved.defaultStyle }, {
723
- setSource: (current) => {
724
- runtime.setProjectDefault(() => current().style);
725
- },
726
- onChange: () => {},
727
- validate: (value) => {
728
- if (value.style !== "" && !runtime.styles.has(value.style)) throw new Error(`dsh-output-styles: settings outputStyle "${value.style}" names no style (available: ${[...runtime.styles.keys()].join(", ") || "none"})`);
729
- }
731
+ ctx.inject(["settings"], (settingsCtx) => {
732
+ const scope = settingsCtx.settings.register(SETTINGS_NS, z.object({ style: z.string().default("") }), {
733
+ base: { style: resolved.defaultStyle },
734
+ validate: (value) => {
735
+ if (value.style !== "" && !runtime.styles.has(value.style)) throw new Error(`dsh-output-styles: settings outputStyle "${value.style}" names no style (available: ${[...runtime.styles.keys()].join(", ") || "none"})`);
736
+ }
737
+ });
738
+ runtime.setProjectDefault(() => scope.get().style);
730
739
  });
731
740
  if (!coreActive) {
732
741
  ctx.systemPrompt.section({
@@ -822,30 +831,32 @@ async function apply(ctx, config) {
822
831
  renderText
823
832
  };
824
833
  ctx.provide("outputRenderers", renderService);
825
- installSettingsSection(ctx, settingsNamespace("output-style-rules"), z.object({ rules: z.array(z.object({
826
- match: z.object({
827
- tool: z.string().required(false),
828
- contentType: z.union([
829
- z.const("text"),
830
- z.const("markdown"),
831
- z.const("html")
832
- ]).required(false),
833
- session: z.string().required(false)
834
- }).required(false),
835
- style: z.string().min(1),
836
- priority: z.number().required(false)
837
- })).default([]) }), { rules: resolved.rules }, {
838
- setSource: (current) => {
839
- effectiveRules = current().rules.map((rule) => ({
840
- match: rule.match ?? {},
841
- style: rule.style,
842
- priority: rule.priority ?? 0
843
- }));
844
- },
845
- onChange: () => {},
846
- validate: (value) => {
847
- for (const rule of value.rules) if (rule.style === "" || /[^a-z0-9-]/.test(rule.style)) throw new Error(`dsh-output-styles: rule style ${JSON.stringify(rule.style)} must be a kebab-case renderer id`);
848
- }
834
+ ctx.inject(["settings"], (settingsCtx) => {
835
+ const rulesScope = settingsCtx.settings.register("output-style-rules", z.object({ rules: z.array(z.object({
836
+ match: z.object({
837
+ tool: z.string().required(false),
838
+ contentType: z.union([
839
+ z.const("text"),
840
+ z.const("markdown"),
841
+ z.const("html")
842
+ ]).required(false),
843
+ session: z.string().required(false)
844
+ }).required(false),
845
+ style: z.string().min(1),
846
+ priority: z.number().required(false)
847
+ })).default([]) }), {
848
+ base: { rules: resolved.rules },
849
+ validate: (value) => {
850
+ for (const rule of value.rules) if (rule.style === "" || /[^a-z0-9-]/.test(rule.style)) throw new Error(`dsh-output-styles: rule style ${JSON.stringify(rule.style)} must be a kebab-case renderer id`);
851
+ }
852
+ });
853
+ const adoptRules = (next) => {
854
+ effectiveRules = next.rules;
855
+ };
856
+ adoptRules(rulesScope.get());
857
+ rulesScope.watch((next) => {
858
+ adoptRules(next);
859
+ });
849
860
  });
850
861
  if (resolved.enableExport) ctx.inject(["commands"], (commandCtx) => {
851
862
  commandCtx.commands.register({
@@ -858,7 +869,7 @@ async function apply(ctx, config) {
858
869
  kind: "error",
859
870
  text: "usage: /export [markdown|html] [--renderer=<id>] [--save <path>]"
860
871
  };
861
- const lines = conversationLines(agent.session.events);
872
+ const lines = conversationLines(readSessionEvents(agent.session));
862
873
  const rules = input.renderer === void 0 ? [...effectiveRules] : [{
863
874
  match: {},
864
875
  style: input.renderer,
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Session export: a pure projection of the current session's message surface
3
3
  * into Markdown or sanitized HTML, with renderer application on top. The
4
- * extraction reads only the public `session.events` log through the official
4
+ * extraction reads only the public session event log (`Session.events` up to
5
+ * 0.1.2-alpha.3, `Session.snapshotEvents()` from 0.1.2-alpha.5) through the official
5
6
  * `deriveEventMessage` projection — the same rule the harness uses to build
6
7
  * model requests — so the exported document is reconstructable from the log.
7
8
  * Every render application preserves the original text beside the rendered
@@ -1 +1 @@
1
- {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/export.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAEpE,sCAAsC;AACtC,MAAM,WAAW,UAAU;IACzB,oDAAoD;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAAA;IAC5C,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,qDAAqD;IACrD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,mEAAmE;AACnE,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAA;IACpC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAA;IACnC,QAAQ,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAAA;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAA;IACrC,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAA;CAC3C;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,GAAG,UAAU,EAAE,CAa/E;AAiDD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQjD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAMvD;AAED,+DAA+D;AAC/D,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,MAAM,CAG/D;AAED,qEAAqE;AACrE,wBAAgB,MAAM,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,MAAM,CAW3D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,SAAS,UAAU,EAAE,EAC5B,MAAM,EAAE,UAAU,GAAG,MAAM,EAC3B,KAAK,EAAE,SAAS,OAAO,gBAAgB,EAAE,SAAS,EAAE,EACpD,GAAG,GAAE,IAAiB,GACrB,cAAc,CAoBhB"}
1
+ {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/export.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAEpE,sCAAsC;AACtC,MAAM,WAAW,UAAU;IACzB,oDAAoD;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAAA;IAC5C,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,qDAAqD;IACrD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,mEAAmE;AACnE,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAA;IACpC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAA;IACnC,QAAQ,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAAA;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAA;IACrC,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAA;CAC3C;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,GAAG,UAAU,EAAE,CAa/E;AAiDD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQjD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAMvD;AAED,+DAA+D;AAC/D,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,MAAM,CAG/D;AAED,qEAAqE;AACrE,wBAAgB,MAAM,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,MAAM,CAW3D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,SAAS,UAAU,EAAE,EAC5B,MAAM,EAAE,UAAU,GAAG,MAAM,EAC3B,KAAK,EAAE,SAAS,OAAO,gBAAgB,EAAE,SAAS,EAAE,EACpD,GAAG,GAAE,IAAiB,GACrB,cAAc,CAoBhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-output-styles",
3
- "version": "0.6.2",
3
+ "version": "0.6.4",
4
4
  "description": "Claude Code outputStyles-equivalent runtime output-style switching for DeepSeek Harness",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -107,7 +107,7 @@
107
107
  ],
108
108
  "compatibility": {
109
109
  "dshVersions": [
110
- "0.1.1-rc.2"
110
+ "0.1.2-alpha.5"
111
111
  ]
112
112
  },
113
113
  "capability": {
@@ -132,13 +132,13 @@
132
132
  },
133
133
  "peerDependencies": {
134
134
  "@deepseek-ai/cordis": "^4.0.1",
135
- "@deepseek-ai/dsh-commands": "0.1.1-rc.2",
135
+ "@deepseek-ai/dsh-commands": ">=0.1.0-rc.8 <0.2.0",
136
136
  "@deepseek-ai/dsh-fs": ">=0.1.0-rc.8 <0.2.0",
137
137
  "@deepseek-ai/dsh-session": ">=0.1.0-rc.8 <0.2.0",
138
138
  "@deepseek-ai/dsh-session-projection": ">=0.1.1-rc.2 <0.2.0",
139
139
  "@deepseek-ai/dsh-settings": ">=0.1.0-rc.8 <0.2.0",
140
140
  "@deepseek-ai/dsh-storage-domain": ">=0.1.0-rc.8 <0.2.0",
141
- "@deepseek-ai/dsh-system-prompt": "0.1.1-rc.2",
141
+ "@deepseek-ai/dsh-system-prompt": ">=0.1.0-rc.8 <0.2.0",
142
142
  "@deepseek-ai/dsh-user-approval": ">=0.1.0-rc.8 <0.2.0",
143
143
  "@deepseek-ai/schemastery": "^3.18.1",
144
144
  "@deepseek-ai/dsh-api-remotes": ">=0.1.1-rc.2 <0.2.0",
@@ -175,32 +175,32 @@
175
175
  }
176
176
  },
177
177
  "devDependencies": {
178
- "@deepseek-ai/cordis": "4.0.1",
178
+ "@deepseek-ai/cordis": "^4.0.2",
179
179
  "@deepseek-ai/cordis-plugin-include": "1.0.6",
180
180
  "@deepseek-ai/cordis-plugin-loader": "1.0.2",
181
- "@deepseek-ai/dsh-agent": "0.1.1-rc.2",
182
- "@deepseek-ai/dsh-api-remotes": "0.1.1-rc.2",
183
- "@deepseek-ai/dsh-attachment": "0.1.1-rc.2",
184
- "@deepseek-ai/dsh-brand": "0.1.1-rc.2",
185
- "@deepseek-ai/dsh-client-locale": "0.1.1-rc.2",
186
- "@deepseek-ai/dsh-client-ui-commands": "0.1.1-rc.2",
187
- "@deepseek-ai/dsh-client-ui-input-trigger": "0.1.1-rc.2",
188
- "@deepseek-ai/dsh-client-ui-slots": "0.1.1-rc.2",
189
- "@deepseek-ai/dsh-commands": "0.1.1-rc.2",
190
- "@deepseek-ai/dsh-llm": "0.1.1-rc.2",
191
- "@deepseek-ai/dsh-scope": "0.1.1-rc.2",
192
- "@deepseek-ai/dsh-session": "0.1.1-rc.2",
193
- "@deepseek-ai/dsh-session-persistence": "0.1.1-rc.2",
194
- "@deepseek-ai/dsh-session-persistence-jsonl": "0.1.1-rc.2",
195
- "@deepseek-ai/dsh-session-projection": "0.1.1-rc.2",
196
- "@deepseek-ai/dsh-settings": "0.1.1-rc.2",
197
- "@deepseek-ai/dsh-storage": "0.1.1-rc.2",
198
- "@deepseek-ai/dsh-storage-domain": "0.1.1-rc.2",
199
- "@deepseek-ai/dsh-storage-json": "0.1.1-rc.2",
200
- "@deepseek-ai/dsh-system-prompt": "0.1.1-rc.2",
201
- "@deepseek-ai/dsh-timeout": "0.1.1-rc.2",
202
- "@deepseek-ai/dsh-typert-protocol": "0.1.1-rc.2",
203
- "@deepseek-ai/schemastery": "3.18.1",
181
+ "@deepseek-ai/dsh-agent": "0.1.2-alpha.5",
182
+ "@deepseek-ai/dsh-api-remotes": "0.1.2-alpha.5",
183
+ "@deepseek-ai/dsh-attachment": "0.1.2-alpha.5",
184
+ "@deepseek-ai/dsh-brand": "0.1.2-alpha.5",
185
+ "@deepseek-ai/dsh-client-locale": "0.1.2-alpha.5",
186
+ "@deepseek-ai/dsh-client-ui-commands": "0.1.2-alpha.5",
187
+ "@deepseek-ai/dsh-client-ui-input-trigger": "0.1.2-alpha.5",
188
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.2-alpha.5",
189
+ "@deepseek-ai/dsh-commands": "0.1.2-alpha.5",
190
+ "@deepseek-ai/dsh-llm": "0.1.2-alpha.5",
191
+ "@deepseek-ai/dsh-scope": "0.1.2-alpha.5",
192
+ "@deepseek-ai/dsh-session": "0.1.2-alpha.5",
193
+ "@deepseek-ai/dsh-session-persistence": "0.1.2-alpha.5",
194
+ "@deepseek-ai/dsh-session-persistence-jsonl": "0.1.2-alpha.5",
195
+ "@deepseek-ai/dsh-session-projection": "0.1.2-alpha.5",
196
+ "@deepseek-ai/dsh-settings": "0.1.2-alpha.5",
197
+ "@deepseek-ai/dsh-storage": "0.1.2-alpha.5",
198
+ "@deepseek-ai/dsh-storage-domain": "0.1.2-alpha.5",
199
+ "@deepseek-ai/dsh-storage-json": "0.1.2-alpha.5",
200
+ "@deepseek-ai/dsh-system-prompt": "0.1.2-alpha.5",
201
+ "@deepseek-ai/dsh-timeout": "0.1.2-alpha.5",
202
+ "@deepseek-ai/dsh-typert-protocol": "0.1.2-alpha.5",
203
+ "@deepseek-ai/schemastery": "^3.18.2",
204
204
  "@types/node": "^22.20.0",
205
205
  "@vitest/coverage-v8": "4.1.10",
206
206
  "oxlint": "0.18.1",
package/src/export.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Session export: a pure projection of the current session's message surface
3
3
  * into Markdown or sanitized HTML, with renderer application on top. The
4
- * extraction reads only the public `session.events` log through the official
4
+ * extraction reads only the public session event log (`Session.events` up to
5
+ * 0.1.2-alpha.3, `Session.snapshotEvents()` from 0.1.2-alpha.5) through the official
5
6
  * `deriveEventMessage` projection — the same rule the harness uses to build
6
7
  * model requests — so the exported document is reconstructable from the log.
7
8
  * Every render application preserves the original text beside the rendered
package/src/runtime.ts CHANGED
@@ -11,14 +11,14 @@
11
11
  import { fileURLToPath } from 'node:url'
12
12
  import { watch, type FSWatcher } from 'node:fs'
13
13
  import type { Context } from '@deepseek-ai/cordis'
14
- import type { Session, SessionId } from '@deepseek-ai/dsh-session'
14
+ import type { Session, SessionEvent, SessionId } from '@deepseek-ai/dsh-session'
15
15
  import type {} from '@deepseek-ai/dsh-agent'
16
16
  import type {} from '@deepseek-ai/dsh-commands'
17
17
  import type {} from '@deepseek-ai/dsh-session-projection'
18
18
  import type { AssembleContext, PromptAssembly } from '@deepseek-ai/dsh-system-prompt'
19
19
  import type { Domain, DomainFacility, KvTable } from '@deepseek-ai/dsh-storage-domain'
20
20
  import z from '@deepseek-ai/schemastery'
21
- import { installSettingsSection, settingsNamespace } from '@deepseek-ai/dsh-settings'
21
+ import type { SettingsNamespace } from '@deepseek-ai/dsh-settings'
22
22
  import { resolveConfig, type Config } from './config.ts'
23
23
  import { detectCoreOutputStyles } from './coexist.ts'
24
24
  import { installInvariant, PACKAGE_NAME, type InvariantFacts, type InvariantRegistry } from './invariant.ts'
@@ -28,6 +28,16 @@ import { OUTPUT_STYLE_DOMAIN, STYLE_SOURCE, styleFoldStateSchema, styleSelection
28
28
  import { BUILTIN_RENDERERS, RendererRegistry, type OutputRenderer, type RenderContext, type RenderedText, type StyleRule } from './renderers.ts'
29
29
  import { conversationLines, renderExport, sanitizeText } from './export.ts'
30
30
 
31
+ /**
32
+ * Session events with an old-host fallback: 0.1.2-alpha.5 renamed the
33
+ * `Session.events` getter to `snapshotEvents()` while the peer floor
34
+ * (>=0.1.0-rc.8) still exposes `.events`.
35
+ */
36
+ function readSessionEvents(session: Session): readonly SessionEvent[] {
37
+ if (typeof session.snapshotEvents === 'function') return session.snapshotEvents()
38
+ return (session as unknown as { events: readonly SessionEvent[] }).events
39
+ }
40
+
31
41
  /** Bundled style-library directory (package `styles/`), the lowest-priority `stylesDir` entry. */
32
42
  export const DEFAULT_STYLES_DIR = fileURLToPath(new URL('../styles/', import.meta.url))
33
43
 
@@ -35,7 +45,7 @@ export const DEFAULT_STYLES_DIR = fileURLToPath(new URL('../styles/', import.met
35
45
  export const STYLE_SECTION_NAME = 'output-style:selection'
36
46
 
37
47
  /** Settings namespace owning the project-level default (`outputStyle`). */
38
- const SETTINGS_NS = settingsNamespace('output-style')
48
+ const SETTINGS_NS = 'output-style' as SettingsNamespace
39
49
 
40
50
  /** Coalescing delay for style-file change events; an internal implementation constant, not a deployment knob. */
41
51
  const WATCH_DEBOUNCE_MS = 250
@@ -337,25 +347,27 @@ export async function apply(ctx: Context, config: Config): Promise<void> {
337
347
  // selected a style fall back to `output-style.style` (user settings layer,
338
348
  // then the composition defaultStyle). Stays inactive until a settings
339
349
  // provider is composed; the settings namespace validates names against the
340
- // live library at write time.
341
- installSettingsSection(
342
- ctx,
343
- SETTINGS_NS,
344
- z.object({ style: z.string().default('') }),
345
- { style: resolved.defaultStyle },
346
- {
347
- setSource: current => { runtime.setProjectDefault(() => current().style) },
348
- onChange: () => {},
349
- validate: value => {
350
- if (value.style !== '' && !runtime.styles.has(value.style)) {
351
- throw new Error(
352
- `dsh-output-styles: settings outputStyle "${value.style}" names no style `
353
- + `(available: ${[...runtime.styles.keys()].join(', ') || 'none'})`,
354
- )
355
- }
350
+ // live library at write time. The 0.1.2-alpha.2 settings seam registers a
351
+ // namespace schema and returns an owner scope (`get`/`watch`); the removed
352
+ // `installSettingsSection` helper no longer exists.
353
+ ctx.inject(['settings'], (settingsCtx) => {
354
+ const scope = settingsCtx.settings.register(
355
+ SETTINGS_NS,
356
+ z.object({ style: z.string().default('') }),
357
+ {
358
+ base: { style: resolved.defaultStyle },
359
+ validate: (value: { style: string }): void => {
360
+ if (value.style !== '' && !runtime.styles.has(value.style)) {
361
+ throw new Error(
362
+ `dsh-output-styles: settings outputStyle "${value.style}" names no style `
363
+ + `(available: ${[...runtime.styles.keys()].join(', ') || 'none'})`,
364
+ )
365
+ }
366
+ },
356
367
  },
357
- },
358
- )
368
+ )
369
+ runtime.setProjectDefault(() => scope.get().style)
370
+ })
359
371
 
360
372
  if (!coreActive) {
361
373
  ctx.systemPrompt.section({
@@ -484,35 +496,37 @@ export async function apply(ctx: Context, config: Config): Promise<void> {
484
496
  // namespace carries the rule table (composition `base` + user overrides);
485
497
  // rules referencing an unknown renderer fail at write time, and rendering
486
498
  // fails loudly at call time if a renderer left the registry.
487
- installSettingsSection(
488
- ctx,
489
- settingsNamespace('output-style-rules'),
490
- z.object({
491
- rules: z.array(z.object({
492
- match: z.object({
493
- tool: z.string().required(false),
494
- contentType: z.union([z.const('text'), z.const('markdown'), z.const('html')]).required(false),
495
- session: z.string().required(false),
496
- }).required(false),
497
- style: z.string().min(1),
498
- priority: z.number().required(false),
499
- })).default([]),
500
- }),
501
- { rules: resolved.rules },
502
- {
503
- setSource: current => {
504
- effectiveRules = current().rules.map(rule => ({ match: rule.match ?? {}, style: rule.style, priority: rule.priority ?? 0 }))
505
- },
506
- onChange: () => {},
507
- validate: value => {
508
- for (const rule of value.rules) {
509
- if (rule.style === '' || /[^a-z0-9-]/.test(rule.style)) {
510
- throw new Error(`dsh-output-styles: rule style ${JSON.stringify(rule.style)} must be a kebab-case renderer id`)
499
+ ctx.inject(['settings'], (settingsCtx) => {
500
+ const rulesScope = settingsCtx.settings.register(
501
+ 'output-style-rules' as SettingsNamespace,
502
+ z.object({
503
+ rules: z.array(z.object({
504
+ match: z.object({
505
+ tool: z.string().required(false),
506
+ contentType: z.union([z.const('text'), z.const('markdown'), z.const('html')]).required(false),
507
+ session: z.string().required(false),
508
+ }).required(false),
509
+ style: z.string().min(1),
510
+ priority: z.number().required(false),
511
+ })).default([]),
512
+ }),
513
+ {
514
+ base: { rules: resolved.rules } as never,
515
+ validate: (value: { rules: ReadonlyArray<{ style: string }> }): void => {
516
+ for (const rule of value.rules) {
517
+ if (rule.style === '' || /[^a-z0-9-]/.test(rule.style)) {
518
+ throw new Error(`dsh-output-styles: rule style ${JSON.stringify(rule.style)} must be a kebab-case renderer id`)
519
+ }
511
520
  }
512
- }
521
+ },
513
522
  },
514
- },
515
- )
523
+ )
524
+ const adoptRules = (next: { rules: readonly StyleRule[] }): void => {
525
+ effectiveRules = next.rules
526
+ }
527
+ adoptRules(rulesScope.get() as unknown as { rules: readonly StyleRule[] })
528
+ rulesScope.watch(next => { adoptRules(next as unknown as { rules: readonly StyleRule[] }) })
529
+ })
516
530
 
517
531
  // The /export command: renders the current session's message surface to
518
532
  // Markdown or sanitized HTML through the renderer pipeline. The document
@@ -533,7 +547,7 @@ export async function apply(ctx: Context, config: Config): Promise<void> {
533
547
  if (input.kind === 'error') {
534
548
  return { kind: 'error', text: 'usage: /export [markdown|html] [--renderer=<id>] [--save <path>]' }
535
549
  }
536
- const lines = conversationLines(agent.session.events)
550
+ const lines = conversationLines(readSessionEvents(agent.session))
537
551
  const rules: StyleRule[] = input.renderer === undefined
538
552
  ? [...effectiveRules]
539
553
  : [{ match: {}, style: input.renderer, priority: 0 }]