dsh-output-styles 0.2.0 → 0.3.1

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 ADDED
@@ -0,0 +1,74 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file. The format
4
+ follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the
5
+ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [0.3.1] - 2026-08-15
8
+
9
+ ### Added
10
+
11
+ - **Publish workflow** (`.github/workflows/publish.yml`): pushing a `v*` tag
12
+ whose suffix matches the `package.json` version runs the full verification
13
+ suite and publishes the tarball to npm with provenance, so a GitHub release
14
+ can never again leave npm behind.
15
+ - **`prepublishOnly` verification gate**: every `npm publish` runs typecheck,
16
+ the full test suite, and the self-contained check before packing — a local
17
+ safety net outside CI.
18
+ - Package metadata: `author`, `bugs`, and `publishConfig.access: public`.
19
+
20
+ ### Changed
21
+
22
+ - `pnpm run verify` aggregates typecheck, tests, and the self-contained check.
23
+ - The unknown-style error says `available: none` instead of a trailing empty
24
+ list when the library is empty.
25
+ - The development sections of all five READMEs document the release flow.
26
+
27
+ ## [0.3.0] - 2026-08-14
28
+
29
+ ### Added
30
+
31
+ - **Claude Code `force-for-plugin` support**: the official Claude Code field
32
+ is now accepted verbatim in both frontmatter and `outputStyles` JSON
33
+ entries. The original `force` field remains as an alias; when both appear
34
+ they must agree, and a disagreement skips the file with a warning.
35
+ - **Built-in styles `proactive` and `learning`**: bundled-library parity with
36
+ Claude Code's built-in output styles (Default/Proactive/Explanatory/
37
+ Learning). The bundled library now ships six styles:
38
+ `concise`, `explanatory`, `formal`, `learning`, `proactive`, `step-by-step`.
39
+
40
+ ### Changed
41
+
42
+ - `package.json` declares `packageManager` (`pnpm@11.7.0`, aligned with CI)
43
+ and `sideEffects: false` for bundler friendliness.
44
+
45
+ ## [0.2.0] - 2026-08-14
46
+
47
+ ### Added
48
+
49
+ - Claude Code parity: layered `stylesDir` directories (later wins),
50
+ `keep-coding-instructions`, forced styles, `outputStyles` JSON compatibility
51
+ (`compatJson`), style-body budget (`maxStyleChars`/`truncationMarker`),
52
+ `sectionOrder`, hot reload (`watchStyles`), built-ins opt-out
53
+ (`includeBuiltins`).
54
+ - Project-level default over the DSH settings seam (`output-style.style`).
55
+ - Web picker (`dsh-output-styles/client`) decorating the host `/style`
56
+ command with a projection-backed popup picker.
57
+ - `style` session projection (`{ options, currentValue }`) folded from
58
+ settled commands in the session log.
59
+ - Bundle install: `dsh.bundle.patch` manifest (`cordis.patch.yml`) composes
60
+ storage rows + the plugin through a single `dsh plugin add`.
61
+ - Invariant companion (`dsh-output-styles/invariant`).
62
+
63
+ ## [0.1.0] - 2026-08-12
64
+
65
+ ### Added
66
+
67
+ - Initial release: `/style` command, `output_style` storage domain
68
+ persistence, `systemPrompt.section()` injection, four bundled styles
69
+ (`concise`, `explanatory`, `formal`, `step-by-step`).
70
+
71
+ [0.3.1]: https://github.com/PerryLink/dsh-output-styles/releases/tag/v0.3.1
72
+ [0.3.0]: https://github.com/PerryLink/dsh-output-styles/releases/tag/v0.3.0
73
+ [0.2.0]: https://github.com/PerryLink/dsh-output-styles/releases/tag/v0.2.0
74
+ [0.1.0]: https://github.com/PerryLink/dsh-output-styles/releases/tag/v0.1.0
package/README.es.md CHANGED
@@ -22,12 +22,12 @@
22
22
 
23
23
  | | |
24
24
  |---|---|
25
- | 🗂️ **Biblioteca de estilos** | Un archivo Markdown por estilo (`styles/*.md`); frontmatter para los metadatos, cuerpo = la directiva del modelo. `name` toma por defecto el nombre del archivo y puede contener espacios (`Diagrams first`). |
25
+ | 🗂️ **Biblioteca de estilos** | Un archivo Markdown por estilo (`styles/*.md`); frontmatter para los metadatos, cuerpo = la directiva del modelo. `name` toma por defecto el nombre del archivo y puede contener espacios (`Diagrams first`). Se incluyen seis estilos integrados, entre ellos `proactive` y `learning`, en paridad con Claude Code. |
26
26
  | ⌨️ **Comando `/style`** | Sin argumentos lista los estilos (con descripciones) + la selección actual; `/style <name>` cambia; `/style off` restaura el valor por defecto del proyecto. Todo el resto tras `/style` es el nombre del estilo. |
27
27
  | 💾 **Persistencia por sesión** | La elección vive en el dominio de almacenamiento `output_style`, con clave sessionId: dos sesiones nunca interfieren y la elección sobrevive a los reinicios. |
28
28
  | 🧩 **Inyección en el system prompt** | Una contribución `systemPrompt.section()` (orden 90) inyecta el cuerpo del estilo de la sesión actual en cada ensamblado; los cuerpos se truncan según un presupuesto configurable. |
29
29
  | 🎭 **`keep-coding-instructions` de Claude Code** | Los estilos con `keep-coding-instructions: false` (el valor por defecto, como Claude Code) reemplazan todo el system prompt — para estilos que dejan atrás la ingeniería de software. |
30
- | 📌 **Estilos forzados** | `force: true` aplica un estilo incondicionalmente, anulando cualquier selección de sesión; dos estilos forzados hacen fallar la carga. |
30
+ | 📌 **Estilos forzados** | El campo `force-for-plugin` de Claude Code (alias `force`) aplica un estilo incondicionalmente, anulando cualquier selección de sesión; dos estilos forzados hacen fallar la carga. |
31
31
  | 🔁 **Compatibilidad con Claude Code** | Carga colecciones JSON `outputStyles` (`{ name, description, prompt }`), entradas individuales o matrices estilo `settings.json`; las entradas no analizables se omiten con un aviso. |
32
32
  | 📚 **Directorios en capas** | `stylesDir` es una lista; los directorios posteriores anulan los anteriores (el `styles/` incluido es la capa más baja; desactívalo con `includeBuiltins: false`). |
33
33
  | 🔄 **Recarga en caliente** | Los cambios en los archivos de estilo se detectan sin reiniciar (`watchStyles: false` para desactivarlo). |
@@ -67,6 +67,8 @@ You > /style
67
67
  concise — Terse, direct answers — minimal prose, no preamble. (Daily coding work, tool-heavy sessions, or when prompt length matters.)
68
68
  explanatory — Educational answers with short "Insights" that teach as you work. (Learning a codebase, onboarding, …)
69
69
  formal — Formal, precise prose with complete sentences and defined terms. (Reports, documentation, release notes, …)
70
+ learning — Collaborative learn-by-doing mode with short "Insights" and small hands-on steps for the user. (Pairing, onboarding, …)
71
+ proactive — Execute immediately, assume reasonable defaults, and prefer action over planning. (Routine multi-step work, …)
70
72
  step-by-step — Numbered reasoning steps with explicit intermediate results. (Debugging, design decisions, …)
71
73
 
72
74
  You > /style concise
@@ -134,7 +136,7 @@ Campos del frontmatter:
134
136
  | `description` | — (obligatorio) | Una frase mostrada en los listados y en el selector. |
135
137
  | `whenToUse` | — | Guía opcional añadida a los listados. |
136
138
  | `keep-coding-instructions` | `false` | Conserva el prompt del harness (identidad, persona, guía de herramientas) cuando es `true`; lo reemplaza por completo cuando es `false` (semántica de Claude Code). |
137
- | `force` | `false` | Se aplica incondicionalmente, anulando cualquier selección de sesión; como máximo un estilo puede activarlo. |
139
+ | `force-for-plugin` | `false` | Campo oficial de Claude Code: se aplica incondicionalmente, anulando cualquier selección de sesión; `force` es un alias y como máximo un estilo puede activarlo. |
138
140
 
139
141
  <details>
140
142
  <summary>JSON de Claude Code <code>outputStyles</code> (<code>compatJson: true</code>)</summary>
@@ -143,7 +145,7 @@ Campos del frontmatter:
143
145
  { "name": "explain", "description": "Explain like a teacher.", "prompt": "Teach in small steps." }
144
146
  ```
145
147
 
146
- Las matrices heredadas de `settings.json` (`[{ … }, { … }]`) se cargan tal cual; las entradas incorrectas se omiten con un aviso.
148
+ Las entradas aceptan `keep-coding-instructions` y `force-for-plugin` exactamente como los escribe Claude Code. Las matrices heredadas de `settings.json` (`[{ … }, { … }]`) se cargan tal cual; las entradas incorrectas se omiten con un aviso.
147
149
 
148
150
  </details>
149
151
 
@@ -159,7 +161,7 @@ Las matrices heredadas de `settings.json` (`[{ … }, { … }]`) se cargan tal c
159
161
 
160
162
  ## 🖱️ Selector web
161
163
 
162
- La entrada `dsh.client` decora la invocación sin argumentos del comando `/style` del host con un selector emergente: una fila «off» más una fila por estilo de la biblioteca (`description · whenToUse`), con la fila activa marcada. Al elegir se envía `/style <name>` a través del Remote de comandos, de modo que cada cambio conserva el ciclo de vida duradero de comandos del host y la proyección `style` sigue siendo el único dato mostrado.
164
+ La entrada `dsh.client` decora la invocación sin argumentos del comando `/style` del host con un selector emergente: una fila «off» más una fila por estilo de la biblioteca (`description · whenToUse`), con la fila activa marcada. Al elegir se envía `/style <name>` a través del Remote de comandos, de modo que cada cambio conserva el ciclo de vida duradero de comandos del host y la proyección `style` sigue siendo el único dato mostrado. Los textos del selector siguen el par de idiomas `zh`/`en` que incluye la Web UI.
163
165
 
164
166
  ## 🔍 Verificación de conflictos
165
167
 
@@ -170,7 +172,7 @@ Se contrastó con el ecosistema DSH antes del desarrollo (instantánea 2026-08):
170
172
  | | Claude Code | dsh-output-styles |
171
173
  |---|---|---|
172
174
  | Archivos de estilo | `.claude/output-styles` en los niveles usuario/proyecto/gestionado | Directorios `stylesDir` + `styles/` incluido, gana el directorio posterior |
173
- | Estilos personalizados | Markdown, frontmatter `name`/`description`/`keep-coding-instructions`/`force-for-plugin` | Los mismos campos (`force` = `force-for-plugin`) + `whenToUse` |
175
+ | Estilos personalizados | Markdown, frontmatter `name`/`description`/`keep-coding-instructions`/`force-for-plugin` | Los mismos campos (`force-for-plugin` aceptado literalmente, `force` como alias) + `whenToUse` |
174
176
  | JSON heredado | Matriz `outputStyles` en `settings.json` | Se carga tal cual (`compatJson: true`) |
175
177
  | Entrada en vigor | Tras `/clear` o una sesión nueva | Inmediatamente — el system prompt se reensambla en cada petición |
176
178
  | Subagentes | Los estilos no se aplican | Igual — las sesiones de los subagentes mantienen sus propios prompts |
@@ -181,11 +183,14 @@ Se contrastó con el ecosistema DSH antes del desarrollo (instantánea 2026-08):
181
183
  ```sh
182
184
  pnpm install
183
185
  pnpm run typecheck # ambos proyectos tsc
184
- pnpm test # vitest — 87 pruebas
186
+ pnpm test # vitest — 92 pruebas
187
+ pnpm run verify # typecheck + pruebas + verificación autocontenida (puerta de prepublishOnly)
185
188
  pnpm run build # artefactos lib/ (bundles de host + cliente)
186
189
  pnpm pack # tarball para dsh plugin add
187
190
  ```
188
191
 
192
+ Lanzamientos: hacer push de una etiqueta `v*` cuyo sufijo coincida con la versión de `package.json` dispara el flujo Publish — verificación completa y publicación en npm (con provenance). Cualquier `npm publish` también pasa la puerta `verify` vía `prepublishOnly`.
193
+
189
194
  La estructura sigue [omdsh-dev/plugin-template](https://github.com/omdsh-dev/plugin-template): `src/index.ts` (metadatos del plugin), `src/config.ts` (esquema), `src/runtime.ts` (servicio de runtime + activación), `src/invariant.ts` (invariantes), `src/client/` (selector web), `styles/` (estilos integrados).
190
195
 
191
196
  ## 📄 Licencia
package/README.ja.md CHANGED
@@ -22,12 +22,12 @@
22
22
 
23
23
  | | |
24
24
  |---|---|
25
- | 🗂️ **スタイルライブラリ** | スタイルごとに 1 つの Markdown ファイル(`styles/*.md`)。frontmatter にメタデータ、本文がモデルへの指示です。`name` は既定でファイル名になり、空白を含めます(`Diagrams first`)。 |
25
+ | 🗂️ **スタイルライブラリ** | スタイルごとに 1 つの Markdown ファイル(`styles/*.md`)。frontmatter にメタデータ、本文がモデルへの指示です。`name` は既定でファイル名になり、空白を含めます(`Diagrams first`)。同梱の組み込みスタイルは 6 種で、Claude Code と同等の `proactive` と `learning` を含みます。 |
26
26
  | ⌨️ **`/style` コマンド** | 引数なしでスタイル一覧(説明付き)と現在の選択を表示。`/style <name>` で切り替え、`/style off` でプロジェクトのデフォルトを復元します。`/style` より後の残り全体がスタイル名です。 |
27
27
  | 💾 **セッション単位の永続化** | 選択は `output_style` ストレージドメインに sessionId をキーとして保持され、2 つのセッションが干渉することはなく、選択は再起動後も残ります。 |
28
28
  | 🧩 **システムプロンプト注入** | `systemPrompt.section()` の貢献(order 90)が、毎回の組み立てで現在のセッションのスタイル本文を注入します。本文は設定可能なバジェットで切り詰められます。 |
29
29
  | 🎭 **Claude Code `keep-coding-instructions`** | `keep-coding-instructions: false`(Claude Code と同じ既定)のスタイルはシステムプロンプト全体を置き換えます——ソフトウェアエンジニアリングから離れるスタイル向けです。 |
30
- | 📌 **強制スタイル** | `force: true` はセッションの選択を無視して無条件にスタイルを適用します。強制スタイルが 2 つあると読み込みに失敗します。 |
30
+ | 📌 **強制スタイル** | Claude Code の `force-for-plugin`(エイリアス `force`)はセッションの選択を無視して無条件にスタイルを適用します。強制スタイルが 2 つあると読み込みに失敗します。 |
31
31
  | 🔁 **Claude Code 互換性** | `outputStyles` JSON コレクション(`{ name, description, prompt }`)を読み込みます。単一エントリまたは `settings.json` 形式の配列に対応し、解析不能なエントリは警告付きでスキップします。 |
32
32
  | 📚 **ディレクトリの階層化** | `stylesDir` はリストで、後方のディレクトリが前方のものを上書きします(同梱の `styles/` が最下層で、`includeBuiltins: false` で無効化)。 |
33
33
  | 🔄 **ホットリロード** | スタイルファイルの変更は再起動なしで反映されます(`watchStyles: false` で無効化)。 |
@@ -67,6 +67,8 @@ You > /style
67
67
  concise — Terse, direct answers — minimal prose, no preamble. (Daily coding work, tool-heavy sessions, or when prompt length matters.)
68
68
  explanatory — Educational answers with short "Insights" that teach as you work. (Learning a codebase, onboarding, …)
69
69
  formal — Formal, precise prose with complete sentences and defined terms. (Reports, documentation, release notes, …)
70
+ learning — Collaborative learn-by-doing mode with short "Insights" and small hands-on steps for the user. (Pairing, onboarding, …)
71
+ proactive — Execute immediately, assume reasonable defaults, and prefer action over planning. (Routine multi-step work, …)
70
72
  step-by-step — Numbered reasoning steps with explicit intermediate results. (Debugging, design decisions, …)
71
73
 
72
74
  You > /style concise
@@ -134,7 +136,7 @@ frontmatter フィールド:
134
136
  | `description` | —(必須) | 一覧とピッカーに表示される 1 文。 |
135
137
  | `whenToUse` | — | 一覧に追記される任意の利用ガイダンス。 |
136
138
  | `keep-coding-instructions` | `false` | `true` のときハーネスのプロンプト(アイデンティティ、persona、ツールガイダンス)を保持し、`false` のとき完全に置き換えます(Claude Code のセマンティクス)。 |
137
- | `force` | `false` | セッションの選択を無視して無条件に適用します。設定できるのは最大 1 つのスタイルです。 |
139
+ | `force-for-plugin` | `false` | Claude Code 公式フィールド:セッションの選択を無視して無条件に適用します。`force` はエイリアスで、設定できるのは最大 1 つのスタイルです。 |
138
140
 
139
141
  <details>
140
142
  <summary>Claude Code <code>outputStyles</code> JSON(<code>compatJson: true</code>)</summary>
@@ -143,7 +145,7 @@ frontmatter フィールド:
143
145
  { "name": "explain", "description": "Explain like a teacher.", "prompt": "Teach in small steps." }
144
146
  ```
145
147
 
146
- レガシーの `settings.json` 配列(`[{ … }, { … }]`)はそのまま読み込まれ、不正なエントリは警告付きでスキップされます。
148
+ エントリは Claude Code が書き込むとおりに `keep-coding-instructions` と `force-for-plugin` を受け付けます。レガシーの `settings.json` 配列(`[{ … }, { … }]`)はそのまま読み込まれ、不正なエントリは警告付きでスキップされます。
147
149
 
148
150
  </details>
149
151
 
@@ -159,7 +161,7 @@ frontmatter フィールド:
159
161
 
160
162
  ## 🖱️ Web ピッカー
161
163
 
162
- `dsh.client` エントリは、ホストの `/style` コマンドの引数なし呼び出しをポップアップピッカーで装飾します:「off」行 + ライブラリのスタイルごとに 1 行(`description · whenToUse`)で、アクティブな行がマークされます。選択するとコマンド Remote を通じて `/style <name>` が送信されるため、どの切り替えもホストの永続的なコマンドライフサイクルを経由し、`style` 投影が唯一の表示事実であり続けます。
164
+ `dsh.client` エントリは、ホストの `/style` コマンドの引数なし呼び出しをポップアップピッカーで装飾します:「off」行 + ライブラリのスタイルごとに 1 行(`description · whenToUse`)で、アクティブな行がマークされます。選択するとコマンド Remote を通じて `/style <name>` が送信されるため、どの切り替えもホストの永続的なコマンドライフサイクルを経由し、`style` 投影が唯一の表示事実であり続けます。ピッカーの文言は Web UI が同梱する `zh`/`en` の言語ペアに従います。
163
165
 
164
166
  ## 🔍 競合チェック
165
167
 
@@ -170,7 +172,7 @@ frontmatter フィールド:
170
172
  | | Claude Code | dsh-output-styles |
171
173
  |---|---|---|
172
174
  | スタイルファイル | ユーザー/プロジェクト/マネージド階層の `.claude/output-styles` | `stylesDir` ディレクトリ + 同梱の `styles/`。後方のディレクトリが優先 |
173
- | カスタムスタイル | Markdown、frontmatter `name`/`description`/`keep-coding-instructions`/`force-for-plugin` | 同じフィールド(`force` = `force-for-plugin`)+ `whenToUse` |
175
+ | カスタムスタイル | Markdown、frontmatter `name`/`description`/`keep-coding-instructions`/`force-for-plugin` | 同じフィールド(`force-for-plugin` をそのまま受け付け、`force` はエイリアス)+ `whenToUse` |
174
176
  | レガシー JSON | `settings.json` 内の `outputStyles` 配列 | そのまま読み込み(`compatJson: true`) |
175
177
  | 反映タイミング | `/clear` 後または新しいセッション | 即時——システムプロンプトはリクエストごとに再構築 |
176
178
  | サブエージェント | スタイルは適用されない | 同じ——サブエージェントのセッションは独自のプロンプトを保持 |
@@ -181,11 +183,14 @@ frontmatter フィールド:
181
183
  ```sh
182
184
  pnpm install
183
185
  pnpm run typecheck # 両方の tsc プロジェクト
184
- pnpm test # vitest — 87 テスト
186
+ pnpm test # vitest — 92 テスト
187
+ pnpm run verify # typecheck + テスト + 自己完結チェック(prepublishOnly ゲート)
185
188
  pnpm run build # lib/ 成果物(ホスト + クライアント bundle)
186
189
  pnpm pack # dsh plugin add 用の tarball
187
190
  ```
188
191
 
192
+ リリース:`package.json` のバージョンと一致する接尾辞を持つ `v*` タグを push すると Publish ワークフローが起動します——完全検証の後に npm へ公開(provenance 付き)。あらゆる `npm publish` も `prepublishOnly` 経由で `verify` ゲートを通過します。
193
+
189
194
  構成は [omdsh-dev/plugin-template](https://github.com/omdsh-dev/plugin-template) に従います:`src/index.ts`(プラグインメタデータ)、`src/config.ts`(スキーマ)、`src/runtime.ts`(ランタイムサービス + アクティベーション)、`src/invariant.ts`(不変条件)、`src/client/`(Web ピッカー)、`styles/`(組み込みスタイル)。
190
195
 
191
196
  ## 📄 ライセンス
package/README.ko.md CHANGED
@@ -22,12 +22,12 @@
22
22
 
23
23
  | | |
24
24
  |---|---|
25
- | 🗂️ **스타일 라이브러리** | 스타일당 Markdown 파일 하나(`styles/*.md`). frontmatter에 메타데이터를, 본문은 모델 지시문입니다. `name`은 기본값이 파일명이며 공백을 포함할 수 있습니다(`Diagrams first`). |
25
+ | 🗂️ **스타일 라이브러리** | 스타일당 Markdown 파일 하나(`styles/*.md`). frontmatter에 메타데이터를, 본문은 모델 지시문입니다. `name`은 기본값이 파일명이며 공백을 포함할 수 있습니다(`Diagrams first`). 내장 스타일 6종이 함께 제공되며, Claude Code와 동등한 `proactive`와 `learning`을 포함합니다. |
26
26
  | ⌨️ **`/style` 명령** | 인자 없이 실행하면 스타일 목록(설명 포함) + 현재 선택을 표시합니다. `/style <name>`으로 전환하고 `/style off`로 프로젝트 기본값을 복원합니다. `/style` 뒤의 나머지 전체가 스타일 이름입니다. |
27
27
  | 💾 **세션 범위 영속화** | 선택은 `output_style` 저장소 도메인에 sessionId를 키로 저장되어, 두 세션이 서로 간섭하지 않고 선택은 재시작 후에도 유지됩니다. |
28
28
  | 🧩 **시스템 프롬프트 주입** | `systemPrompt.section()` 기여(order 90)가 매 조립마다 현재 세션의 스타일 본문을 주입합니다. 본문은 설정 가능한 예산으로 잘립니다. |
29
29
  | 🎭 **Claude Code `keep-coding-instructions`** | `keep-coding-instructions: false`(Claude Code와 같은 기본값)인 스타일은 시스템 프롬프트 전체를 교체합니다 —— 소프트웨어 엔지니어링에서 벗어나는 스타일용입니다. |
30
- | 📌 **강제 스타일** | `force: true`는 세션 선택을 무시하고 무조건 스타일을 적용합니다. 강제 스타일이 둘이면 로드가 실패합니다. |
30
+ | 📌 **강제 스타일** | Claude Code의 `force-for-plugin`(별칭 `force`)이 세션 선택을 무시하고 무조건 스타일을 적용합니다. 강제 스타일이 둘이면 로드가 실패합니다. |
31
31
  | 🔁 **Claude Code 호환성** | `outputStyles` JSON 컬렉션(`{ name, description, prompt }`)을 로드하며, 단일 항목 또는 `settings.json` 스타일 배열을 지원합니다. 해석 불가 항목은 경고와 함께 건너뜁니다. |
32
32
  | 📚 **계층화된 디렉터리** | `stylesDir`은 목록이며 뒤쪽 디렉터리가 앞쪽을 재정의합니다(내장 `styles/`가 최하위 계층, `includeBuiltins: false`로 비활성화). |
33
33
  | 🔄 **핫 리로드** | 스타일 파일 변경이 재시작 없이 반영됩니다(`watchStyles: false`로 해제). |
@@ -67,6 +67,8 @@ You > /style
67
67
  concise — Terse, direct answers — minimal prose, no preamble. (Daily coding work, tool-heavy sessions, or when prompt length matters.)
68
68
  explanatory — Educational answers with short "Insights" that teach as you work. (Learning a codebase, onboarding, …)
69
69
  formal — Formal, precise prose with complete sentences and defined terms. (Reports, documentation, release notes, …)
70
+ learning — Collaborative learn-by-doing mode with short "Insights" and small hands-on steps for the user. (Pairing, onboarding, …)
71
+ proactive — Execute immediately, assume reasonable defaults, and prefer action over planning. (Routine multi-step work, …)
70
72
  step-by-step — Numbered reasoning steps with explicit intermediate results. (Debugging, design decisions, …)
71
73
 
72
74
  You > /style concise
@@ -134,7 +136,7 @@ frontmatter 필드:
134
136
  | `description` | —(필수) | 목록과 피커에 표시되는 한 문장. |
135
137
  | `whenToUse` | — | 목록에 덧붙이는 선택적 안내. |
136
138
  | `keep-coding-instructions` | `false` | `true`면 하네스 프롬프트(정체성, persona, 도구 지침)를 유지하고, `false`면 완전히 교체합니다(Claude Code 의미론). |
137
- | `force` | `false` | 세션 선택을 무시하고 무조건 적용합니다. 최대 한 스타일만 설정할 수 있습니다. |
139
+ | `force-for-plugin` | `false` | Claude Code 공식 필드: 세션 선택을 무시하고 무조건 적용합니다. `force`는 별칭이며 최대 한 스타일만 설정할 수 있습니다. |
138
140
 
139
141
  <details>
140
142
  <summary>Claude Code <code>outputStyles</code> JSON(<code>compatJson: true</code>)</summary>
@@ -143,7 +145,7 @@ frontmatter 필드:
143
145
  { "name": "explain", "description": "Explain like a teacher.", "prompt": "Teach in small steps." }
144
146
  ```
145
147
 
146
- 레거시 `settings.json` 배열(`[{ … }, { … }]`)은 그대로 로드되고, 잘못된 항목은 경고와 함께 건너뜁니다.
148
+ 항목은 Claude Code가 쓰는 그대로 `keep-coding-instructions`와 `force-for-plugin` 필드를 받습니다. 레거시 `settings.json` 배열(`[{ … }, { … }]`)은 그대로 로드되고, 잘못된 항목은 경고와 함께 건너뜁니다.
147
149
 
148
150
  </details>
149
151
 
@@ -159,7 +161,7 @@ frontmatter 필드:
159
161
 
160
162
  ## 🖱️ 웹 피커
161
163
 
162
- `dsh.client` 항목은 호스트 `/style` 명령의 인자 없는 호출을 팝업 피커로 꾸밉니다: 「off」 행 + 라이브러리 스타일별 한 행(`description · whenToUse`), 활성 행이 표시됩니다. 선택하면 명령 Remote를 통해 `/style <name>`을 제출하므로, 모든 전환이 호스트의 영구적인 명령 수명 주기를 유지하고 `style` 프로젝션이 유일하게 표시되는 사실로 남습니다.
164
+ `dsh.client` 항목은 호스트 `/style` 명령의 인자 없는 호출을 팝업 피커로 꾸밉니다: 「off」 행 + 라이브러리 스타일별 한 행(`description · whenToUse`), 활성 행이 표시됩니다. 선택하면 명령 Remote를 통해 `/style <name>`을 제출하므로, 모든 전환이 호스트의 영구적인 명령 수명 주기를 유지하고 `style` 프로젝션이 유일하게 표시되는 사실로 남습니다. 피커 문구는 Web UI에 내장된 `zh`/`en` 언어 쌍을 따릅니다.
163
165
 
164
166
  ## 🔍 충돌 검사
165
167
 
@@ -170,7 +172,7 @@ frontmatter 필드:
170
172
  | | Claude Code | dsh-output-styles |
171
173
  |---|---|---|
172
174
  | 스타일 파일 | 사용자/프로젝트/관리 계층의 `.claude/output-styles` | `stylesDir` 디렉터리 + 내장 `styles/`, 뒤쪽 디렉터리가 우선 |
173
- | 사용자 정의 스타일 | Markdown, frontmatter `name`/`description`/`keep-coding-instructions`/`force-for-plugin` | 동일 필드(`force` = `force-for-plugin`) + `whenToUse` |
175
+ | 사용자 정의 스타일 | Markdown, frontmatter `name`/`description`/`keep-coding-instructions`/`force-for-plugin` | 동일 필드(`force-for-plugin` 그대로 수용, `force`는 별칭) + `whenToUse` |
174
176
  | 레거시 JSON | `settings.json`의 `outputStyles` 배열 | 그대로 로드(`compatJson: true`) |
175
177
  | 적용 시점 | `/clear` 후 또는 새 세션 | 즉시 — 시스템 프롬프트가 요청마다 재조립 |
176
178
  | 하위 에이전트 | 스타일 미적용 | 동일 — 하위 에이전트 세션은 자체 프롬프트 유지 |
@@ -181,11 +183,14 @@ frontmatter 필드:
181
183
  ```sh
182
184
  pnpm install
183
185
  pnpm run typecheck # 두 tsc 프로젝트
184
- pnpm test # vitest — 87 테스트
186
+ pnpm test # vitest — 92 테스트
187
+ pnpm run verify # typecheck + 테스트 + 자체 포함 검사(prepublishOnly 게이트)
185
188
  pnpm run build # lib/ 산출물(호스트 + 클라이언트 번들)
186
189
  pnpm pack # dsh plugin add용 tarball
187
190
  ```
188
191
 
192
+ 릴리스: `package.json` 버전과 일치하는 접미사를 가진 `v*` 태그를 push하면 Publish 워크플로가 실행됩니다 — 전체 검증 후 npm 게시(provenance 포함). 모든 `npm publish`도 `prepublishOnly`를 통해 `verify` 게이트를 통과합니다.
193
+
189
194
  구조는 [omdsh-dev/plugin-template](https://github.com/omdsh-dev/plugin-template)를 따릅니다: `src/index.ts`(플러그인 메타데이터), `src/config.ts`(스키마), `src/runtime.ts`(런타임 서비스 + 활성화), `src/invariant.ts`(불변식), `src/client/`(웹 피커), `styles/`(내장 스타일).
190
195
 
191
196
  ## 📄 라이선스
package/README.md CHANGED
@@ -22,12 +22,12 @@
22
22
 
23
23
  | | |
24
24
  |---|---|
25
- | 🗂️ **Style library** | One Markdown file per style (`styles/*.md`); frontmatter for metadata, body = the model directive. `name` defaults to the file name and may contain spaces (`Diagrams first`). |
25
+ | 🗂️ **Style library** | One Markdown file per style (`styles/*.md`); frontmatter for metadata, body = the model directive. `name` defaults to the file name and may contain spaces (`Diagrams first`). Six built-ins ship in the box, including Claude Code-parity `proactive` and `learning`. |
26
26
  | ⌨️ **`/style` command** | No argument lists styles (with descriptions) + current selection; `/style <name>` switches; `/style off` restores the project default. The whole remainder after `/style` is the style name. |
27
27
  | 💾 **Session-scoped persistence** | The choice lives in the `output_style` storage domain, keyed by sessionId — two sessions never interfere, and the choice survives restarts. |
28
28
  | 🧩 **System-prompt injection** | A `systemPrompt.section()` contribution (order 90) injects the current session's style body at every assembly; bodies are truncated at a configurable budget. |
29
29
  | 🎭 **Claude Code `keep-coding-instructions`** | Styles with `keep-coding-instructions: false` (the default, like Claude Code) replace the whole system prompt — for styles that leave software engineering behind. |
30
- | 📌 **Forced styles** | `force: true` applies a style unconditionally, overriding any session selection; two forced styles fail the load. |
30
+ | 📌 **Forced styles** | Claude Code's `force-for-plugin` (alias `force`) applies a style unconditionally, overriding any session selection; two forced styles fail the load. |
31
31
  | 🔁 **Claude Code compatibility** | Loads `outputStyles` JSON collections (`{ name, description, prompt }`), single entries or `settings.json`-style arrays; unparseable entries are skipped with a warning. |
32
32
  | 📚 **Layered directories** | `stylesDir` is a list; later directories override earlier ones (bundled `styles/` is the lowest layer, disable with `includeBuiltins: false`). |
33
33
  | 🔄 **Hot reload** | Style-file changes are picked up without restarting (`watchStyles: false` to opt out). |
@@ -67,6 +67,8 @@ You > /style
67
67
  concise — Terse, direct answers — minimal prose, no preamble. (Daily coding work, tool-heavy sessions, or when prompt length matters.)
68
68
  explanatory — Educational answers with short "Insights" that teach as you work. (Learning a codebase, onboarding, …)
69
69
  formal — Formal, precise prose with complete sentences and defined terms. (Reports, documentation, release notes, …)
70
+ learning — Collaborative learn-by-doing mode with short "Insights" and small hands-on steps for the user. (Pairing, onboarding, …)
71
+ proactive — Execute immediately, assume reasonable defaults, and prefer action over planning. (Routine multi-step work, …)
70
72
  step-by-step — Numbered reasoning steps with explicit intermediate results. (Debugging, design decisions, …)
71
73
 
72
74
  You > /style concise
@@ -134,7 +136,7 @@ Frontmatter fields:
134
136
  | `description` | — (required) | One sentence shown in listings and the picker. |
135
137
  | `whenToUse` | — | Optional guidance appended to listings. |
136
138
  | `keep-coding-instructions` | `false` | Keep the harness prompt (identity, persona, tool guidance) when `true`; replace it entirely when `false` (Claude Code semantics). |
137
- | `force` | `false` | Apply unconditionally, overriding any session selection; at most one style may set it. |
139
+ | `force-for-plugin` | `false` | Claude Code's field: apply unconditionally, overriding any session selection; `force` is accepted as an alias, and at most one style may set it. |
138
140
 
139
141
  <details>
140
142
  <summary>Claude Code <code>outputStyles</code> JSON (<code>compatJson: true</code>)</summary>
@@ -143,7 +145,7 @@ Frontmatter fields:
143
145
  { "name": "explain", "description": "Explain like a teacher.", "prompt": "Teach in small steps." }
144
146
  ```
145
147
 
146
- Legacy `settings.json` arrays (`[{ … }, { … }]`) load as-is; bad entries are skipped with a warning.
148
+ Entries accept `keep-coding-instructions` and `force-for-plugin` exactly as Claude Code writes them. Legacy `settings.json` arrays (`[{ … }, { … }]`) load as-is; bad entries are skipped with a warning.
147
149
 
148
150
  </details>
149
151
 
@@ -159,7 +161,7 @@ Legacy `settings.json` arrays (`[{ … }, { … }]`) load as-is; bad entries are
159
161
 
160
162
  ## 🖱️ Web picker
161
163
 
162
- The `dsh.client` entry decorates the host `/style` command's bare invocation with a popup picker: an "off" row plus one row per library style (`description · whenToUse`), the active row marked. Picking submits `/style <name>` through the command Remote, so every switch keeps the host's durable command lifecycle and the `style` projection stays the single displayed fact.
164
+ The `dsh.client` entry decorates the host `/style` command's bare invocation with a popup picker: an "off" row plus one row per library style (`description · whenToUse`), the active row marked. Picking submits `/style <name>` through the command Remote, so every switch keeps the host's durable command lifecycle and the `style` projection stays the single displayed fact. The picker follows the Web UI's shipped `zh`/`en` locale pair.
163
165
 
164
166
  ## 🔍 Conflict check
165
167
 
@@ -170,7 +172,7 @@ Screened against the DSH ecosystem before development (2026-08 snapshot): no `st
170
172
  | | Claude Code | dsh-output-styles |
171
173
  |---|---|---|
172
174
  | Style files | `.claude/output-styles` at user/project/managed levels | `stylesDir` directories + bundled `styles/`, later directory wins |
173
- | Custom styles | Markdown, frontmatter `name`/`description`/`keep-coding-instructions`/`force-for-plugin` | Same fields (`force` = `force-for-plugin`) + `whenToUse` |
175
+ | Custom styles | Markdown, frontmatter `name`/`description`/`keep-coding-instructions`/`force-for-plugin` | Same fields (`force-for-plugin` accepted verbatim, `force` as alias) + `whenToUse` |
174
176
  | Legacy JSON | `outputStyles` array in `settings.json` | Loaded verbatim (`compatJson: true`) |
175
177
  | Taking effect | After `/clear` or a new session | Immediately — the system prompt re-assembles per request |
176
178
  | Subagents | Styles do not apply | Same — subagent sessions keep their own prompts |
@@ -181,11 +183,14 @@ Screened against the DSH ecosystem before development (2026-08 snapshot): no `st
181
183
  ```sh
182
184
  pnpm install
183
185
  pnpm run typecheck # both tsc projects
184
- pnpm test # vitest — 87 tests
186
+ pnpm test # vitest — 92 tests
187
+ pnpm run verify # typecheck + tests + self-contained (the prepublishOnly gate)
185
188
  pnpm run build # lib/ artifacts (host + client bundles)
186
189
  pnpm pack # tarball for dsh plugin add
187
190
  ```
188
191
 
192
+ Releases: pushing a `v*` tag whose suffix matches the `package.json` version triggers the Publish workflow — full verification, then an npm publish with provenance. Any `npm publish` also passes the `verify` gate through `prepublishOnly`.
193
+
189
194
  Structure follows the [omdsh-dev/plugin-template](https://github.com/omdsh-dev/plugin-template): `src/index.ts` (plugin metadata), `src/config.ts` (schema), `src/runtime.ts` (runtime service + activation), `src/invariant.ts` (invariants), `src/client/` (Web picker), `styles/` (built-ins).
190
195
 
191
196
  ## 📄 License
package/README.zh.md CHANGED
@@ -22,12 +22,12 @@
22
22
 
23
23
  | | |
24
24
  |---|---|
25
- | 🗂️ **风格库** | 每个风格一个 Markdown 文件(`styles/*.md`);frontmatter 存元数据,正文即模型指令。`name` 缺省继承文件名,且可含空格(如 `Diagrams first`)。 |
25
+ | 🗂️ **风格库** | 每个风格一个 Markdown 文件(`styles/*.md`);frontmatter 存元数据,正文即模型指令。`name` 缺省继承文件名,且可含空格(如 `Diagrams first`)。内置六种风格,含与 Claude Code 对齐的 `proactive` 与 `learning`。 |
26
26
  | ⌨️ **`/style` 命令** | 无参列出全部风格(含描述)与当前选择;`/style <name>` 切换;`/style off` 恢复项目默认。`/style` 之后的整段文本即风格名。 |
27
27
  | 💾 **会话级持久化** | 选择保存在 `output_style` 存储域,按 sessionId 隔离——会话互不干扰,重启后保留。 |
28
28
  | 🧩 **系统提示注入** | `systemPrompt.section()` 贡献(order 90)在每次组装时注入当前会话的风格正文;正文按可配置预算截断。 |
29
29
  | 🎭 **Claude Code `keep-coding-instructions`** | `keep-coding-instructions: false`(缺省,与 Claude Code 一致)的风格**替换整个系统提示**——适合彻底离开软件工程的风格。 |
30
- | 📌 **强制风格** | `force: true` 无条件生效,覆盖任何会话选择;两个强制风格会在加载期报错。 |
30
+ | 📌 **强制风格** | Claude Code 的 `force-for-plugin`(别名 `force`)无条件生效,覆盖任何会话选择;两个强制风格会在加载期报错。 |
31
31
  | 🔁 **Claude Code 兼容** | 加载 `outputStyles` JSON 集合(`{ name, description, prompt }`),支持单对象与 `settings.json` 式数组;坏条目逐个跳过并警告。 |
32
32
  | 📚 **目录分层** | `stylesDir` 是目录列表,后者覆盖前者(内置 `styles/` 是最低层,`includeBuiltins: false` 可排除)。 |
33
33
  | 🔄 **热加载** | 风格文件改动即时生效,无需重启(`watchStyles: false` 可关闭)。 |
@@ -67,6 +67,8 @@ You > /style
67
67
  concise — Terse, direct answers — minimal prose, no preamble. (Daily coding work, tool-heavy sessions, or when prompt length matters.)
68
68
  explanatory — Educational answers with short "Insights" that teach as you work. (Learning a codebase, onboarding, …)
69
69
  formal — Formal, precise prose with complete sentences and defined terms. (Reports, documentation, release notes, …)
70
+ learning — Collaborative learn-by-doing mode with short "Insights" and small hands-on steps for the user. (Pairing, onboarding, …)
71
+ proactive — Execute immediately, assume reasonable defaults, and prefer action over planning. (Routine multi-step work, …)
70
72
  step-by-step — Numbered reasoning steps with explicit intermediate results. (Debugging, design decisions, …)
71
73
 
72
74
  You > /style concise
@@ -134,7 +136,7 @@ frontmatter 字段:
134
136
  | `description` | ——(必填) | 列表与选择器里展示的一句话。 |
135
137
  | `whenToUse` | —— | 可选适用场景说明,追加到列表。 |
136
138
  | `keep-coding-instructions` | `false` | `true` 保留宿主提示(身份、persona、工具指引);`false` 整体替换(Claude Code 语义)。 |
137
- | `force` | `false` | 无条件生效,覆盖会话选择;最多一个风格可设置。 |
139
+ | `force-for-plugin` | `false` | Claude Code 官方字段:无条件生效,覆盖会话选择;`force` 为其别名,最多一个风格可设置。 |
138
140
 
139
141
  <details>
140
142
  <summary>Claude Code <code>outputStyles</code> JSON(<code>compatJson: true</code>)</summary>
@@ -143,7 +145,7 @@ frontmatter 字段:
143
145
  { "name": "explain", "description": "Explain like a teacher.", "prompt": "Teach in small steps." }
144
146
  ```
145
147
 
146
- 旧版 `settings.json` 的数组形式(`[{ … }, { … }]`)原样加载;坏条目逐个跳过并警告。
148
+ 条目按 Claude Code 原样接受 `keep-coding-instructions` 与 `force-for-plugin` 字段。旧版 `settings.json` 的数组形式(`[{ … }, { … }]`)原样加载;坏条目逐个跳过并警告。
147
149
 
148
150
  </details>
149
151
 
@@ -159,7 +161,7 @@ frontmatter 字段:
159
161
 
160
162
  ## 🖱️ Web 选择器
161
163
 
162
- `dsh.client` 入口把宿主 `/style` 命令的裸调用装饰成弹窗选择器:「off」行 + 每风格一行(`描述 · 适用场景`),当前行高亮。选中即通过命令 Remote 提交 `/style <name>`,因此每次切换都保留宿主的持久命令生命周期,`style` 投影始终是唯一展示事实。
164
+ `dsh.client` 入口把宿主 `/style` 命令的裸调用装饰成弹窗选择器:「off」行 + 每风格一行(`描述 · 适用场景`),当前行高亮。选中即通过命令 Remote 提交 `/style <name>`,因此每次切换都保留宿主的持久命令生命周期,`style` 投影始终是唯一展示事实。选择器文案跟随 Web UI 内置的 `zh`/`en` 语言对。
163
165
 
164
166
  ## 🔍 生态冲突检查
165
167
 
@@ -170,7 +172,7 @@ frontmatter 字段:
170
172
  | | Claude Code | dsh-output-styles |
171
173
  |---|---|---|
172
174
  | 风格文件 | 用户/项目/托管层级的 `.claude/output-styles` | `stylesDir` 目录 + 内置 `styles/`,后目录胜出 |
173
- | 自定义风格 | Markdown,frontmatter `name`/`description`/`keep-coding-instructions`/`force-for-plugin` | 同字段(`force` 对应 `force-for-plugin`)+ `whenToUse` |
175
+ | 自定义风格 | Markdown,frontmatter `name`/`description`/`keep-coding-instructions`/`force-for-plugin` | 同字段(`force-for-plugin` 原样接受,`force` 为别名)+ `whenToUse` |
174
176
  | 旧版 JSON | `settings.json` 里的 `outputStyles` 数组 | 原样加载(`compatJson: true`) |
175
177
  | 生效时机 | `/clear` 或新会话后 | 立即生效——系统提示每次请求重组 |
176
178
  | 子代理 | 风格不适用 | 一致——子代理会话保持各自提示 |
@@ -181,11 +183,14 @@ frontmatter 字段:
181
183
  ```sh
182
184
  pnpm install
183
185
  pnpm run typecheck # 两个 tsc 工程
184
- pnpm test # vitest —— 87 个测试
186
+ pnpm test # vitest —— 92 个测试
187
+ pnpm run verify # typecheck + 测试 + 自包含检查(prepublishOnly 闸门)
185
188
  pnpm run build # lib/ 产物(宿主 + 客户端两个 bundle)
186
189
  pnpm pack # 供 dsh plugin add 使用的 tarball
187
190
  ```
188
191
 
192
+ 发布:推送后缀与 `package.json` 版本一致的 `v*` tag 会触发 Publish 工作流——完整验证后发布到 npm(含 provenance)。任何 `npm publish` 也会通过 `prepublishOnly` 执行 `verify` 闸门。
193
+
189
194
  结构遵循 [omdsh-dev/plugin-template](https://github.com/omdsh-dev/plugin-template):`src/index.ts`(插件元数据)、`src/config.ts`(schema)、`src/runtime.ts`(运行时服务与激活)、`src/invariant.ts`(不变量)、`src/client/`(Web 选择器)、`styles/`(内置风格)。
190
195
 
191
196
  ## 📄 License
@@ -1,6 +1,6 @@
1
1
  # 验证记录(dsh-output-styles)
2
2
 
3
- > 本文档记录交付验证的实测命令与输出。运行环境:Windows + Node 22 + pnpm 11;宿主为已安装的 `@deepseek-ai/dsh` CLI `0.1.0-rc.6`(`dsh --version` 输出 `0.1.0-rc.6`)。版本:0.2.0
3
+ > 本文档记录交付验证的实测命令与输出。运行环境:Windows + Node 22 + pnpm 11;宿主为已安装的 `@deepseek-ai/dsh` CLI `0.1.0-rc.6`(`dsh --version` 输出 `0.1.0-rc.6`)。版本:0.3.0(第 7 节为 0.3.0 增量验证;第 1–6 节为 0.2.0 基线记录)。
4
4
 
5
5
  ## 1. 单元与集成测试
6
6
 
@@ -91,3 +91,81 @@ harness identity alongside style: true
91
91
  - 真实 API 复测(第 4 节)需要 `DEEPSEEK_API_KEY`;无 key 时组装级集成测试是模型可见路径的回归保障,真实 API 手动复测步骤不变。
92
92
  - 风格不作用于子代理会话(与 Claude Code 语义一致,README「与 Claude Code 的差异」表明确记录)。
93
93
  - settings 提供方未配置时项目默认回落 `defaultStyle`;settings 值在风格热加载后变为悬空名时静默降级为无风格(与悬空会话选择同策略)。
94
+
95
+ ## 7. 0.3.0 增量验证
96
+
97
+ ### 7.1 单元与集成测试
98
+
99
+ ```text
100
+ $ pnpm test
101
+ ✓ tests/config.spec.ts (8 tests)
102
+ ✓ tests/style-command.spec.ts (10 tests)
103
+ ✓ tests/invariant.spec.ts (9 tests)
104
+ ✓ tests/style-library.spec.ts (28 tests)
105
+ ✓ tests/commands-projections.spec.ts (7 tests)
106
+ ✓ tests/runtime.spec.ts (24 tests)
107
+ ✓ tests/client.spec.ts (6 tests)
108
+ Test Files 7 passed (7)
109
+ Tests 92 passed (92)
110
+ ```
111
+
112
+ `pnpm run typecheck`(两个 tsc 工程)、`pnpm run build`、`pnpm run verify:self-contained` 均通过。
113
+
114
+ ### 7.2 Claude Code `force-for-plugin` 兼容
115
+
116
+ 对照 [Claude Code 官方 output-styles 文档](https://code.claude.com/docs/en/output-styles.md)(frontmatter 表确认 `force-for-plugin` 为官方字段)补齐 0.2.0 文档已声称但实现缺失的字段:
117
+
118
+ - frontmatter 与 `outputStyles` JSON 两条路径均原样接受 `force-for-plugin`(新测试:`reads Claude Code force-for-plugin in frontmatter and outputStyles JSON`)。
119
+ - `force` 保留为别名;两者同时出现且一致时正常加载,冲突时整文件跳过并警告(`force and force-for-plugin disagree`)。
120
+ - 非布尔 `force-for-plugin` 跳过并警告;两个强制风格(无论用哪个字段)加载期抛错(复用既有双 force 检查)。
121
+ - `FRONTMATTER_KEYS` 收录 `force-for-plugin`,未知键告警不再误报。
122
+
123
+ ### 7.3 内置风格对齐 Claude Code
124
+
125
+ 官方内置为 Default/Proactive/Explanatory/Learning;新增 `styles/proactive.md` 与 `styles/learning.md`,内置库现为六风格(`concise`, `explanatory`, `formal`, `learning`, `proactive`, `step-by-step`,按文件名字典序):
126
+
127
+ - 列表、错误提示 `available:`、`style` 投影 options 均同步为六风格(runtime/commands-projections 断言已更新)。
128
+ - 新增切换用例:`/style proactive` → `switched to proactive` 且注入正文含 `Prefer action over planning`。
129
+
130
+ ### 7.4 客户端选择器本地化结论(研究后否决)
131
+
132
+ 曾计划为选择器补 ja/ko/es 字典。研读宿主 `dsh-client-locale`(rc.6)后否决:其 `LocaleId` 联合类型与设置行为仅 `zh`/`en`(`LOCALE_IDS = ['zh','en']`),语言行只暴露这两个选项,注册更多字典是永远无法被选中的死代码。选择器保持 `zh`/`en`,`src/client/locales.ts` 记录该决策供后续宿主版本扩展;README 五语承诺限定为文档。
133
+
134
+ ### 7.5 工程元数据
135
+
136
+ - `package.json`:版本 0.3.0;新增 `packageManager: pnpm@11.7.0`(与 CI 一致)、`sideEffects: false`(供打包器摇树)。
137
+ - 新增 `CHANGELOG.md`(Keep a Changelog 格式,0.1.0/0.2.0/0.3.0 三节)。
138
+ - 五份 README 同步:`force-for-plugin` 字段表与差异表、六内置风格、演示列表、测试数(92)。
139
+
140
+ ### 7.6 真实 CLI bundle 装载复测
141
+
142
+ ```text
143
+ $ pnpm pack # dsh-output-styles-0.3.0.tgz
144
+ $ env:DSH_HOME = <临时目录>
145
+ $ dsh plugin --profile scratch add ./dsh-output-styles-0.3.0.tgz
146
+ Packages: +9 ... Done # bundle 补丁层随包安装
147
+ $ dsh --profile scratch --dump-config
148
+ # == dsh-output-styles
149
+ - id: storage
150
+ name: '@deepseek-ai/dsh-storage'
151
+ - id: storage-json
152
+ name: '@deepseek-ai/dsh-storage-json'
153
+ - id: storage-domain
154
+ name: '@deepseek-ai/dsh-storage-domain'
155
+ - id: output-styles
156
+ name: dsh-output-styles
157
+ ```
158
+
159
+ 补丁层装载与 0.2.0 行为一致。进一步做了 0.2.0 未做的宿主启动级验证:
160
+
161
+ ```text
162
+ $ dsh --profile scratch --help # 无 storage 配置时快速失败:
163
+ Error: ... entry storage-json ... invalid config: $.root missing required value
164
+ $ (profile cordis.patch.yml 补 storage-json.root 与 storage-domain.backend: json)
165
+ $ dsh --profile scratch --help # 加载器阶段全部通过,进入应用空闲(无 FAILED)
166
+ $ (把插件行改为非法 config: maxStyleChars: 0,验证 schema 在真实组合中生效)
167
+ Error: dsh: plugin tree failed to load: ... entry output-styles (dsh-output-styles): invalid config:
168
+ - $.maxStyleChars expected number >= 1 but got 0 (at maxStyleChars)
169
+ ```
170
+
171
+ 即:0.3.0 tarball 经真实 rc.6 CLI 安装、补丁层组合、启动加载器逐行应用全部通过;插件的 Schemastery schema 在真实组合中生效(非法配置按插件自身的校验信息拒绝启动)。模型可见注入路径(systemPrompt 组装)由第 7.1 节组装级集成测试覆盖,真实 API 复测边界与第 6 节一致。
package/lib/client.js CHANGED
@@ -1,5 +1,12 @@
1
1
  //#region src/client/locales.ts
2
- /** Simplified Chinese dictionary (the key-set source of truth). */
2
+ /**
3
+ * Simplified Chinese dictionary (the key-set source of truth).
4
+ *
5
+ * Only `zh` and `en` are shipped: the DSH Web locale system (dsh-client-locale
6
+ * rc.6) exposes exactly the `zh`/`en` locale pair in its settings row, so
7
+ * further dictionaries would be dead weight the framework can never select.
8
+ * When a future harness release ships more locales, extend this pair.
9
+ */
3
10
  const zh = {
4
11
  "option.off": "关闭(默认)",
5
12
  "option.offDetail": "恢复项目默认输出风格"
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { _ as styleSelectionSchema, c as loadStyleLibrary, d as STYLE_COMMAND, f as applyStyleEvent, g as STYLE_SOURCE, h as OUTPUT_STYLE_DOMAIN, i as installInvariant, l as truncateStyle, m as OFF, o as STYLE_NAME_RE, p as parseStyleInput, s as isValidStyleName, t as PACKAGE_NAME, u as EMPTY_STYLE_STATE, v as styleSelectionViewSchema } from "./invariant-LV6hQX5s.js";
1
+ import { _ as styleSelectionSchema, c as loadStyleLibrary, d as STYLE_COMMAND, f as applyStyleEvent, g as STYLE_SOURCE, h as OUTPUT_STYLE_DOMAIN, i as installInvariant, l as truncateStyle, m as OFF, o as STYLE_NAME_RE, p as parseStyleInput, s as isValidStyleName, t as PACKAGE_NAME, u as EMPTY_STYLE_STATE, v as styleSelectionViewSchema } from "./invariant-B9LpUViP.js";
2
2
  import z from "@deepseek-ai/schemastery";
3
3
  import { resolve } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
@@ -203,7 +203,7 @@ var OutputStyleRuntime = class {
203
203
  * @returns the error text listing every switchable name.
204
204
  */
205
205
  unknownStyleLine(name) {
206
- return `unknown output style "${name}" (available: ${this.names.join(", ")})`;
206
+ return `unknown output style "${name}" (available: ${this.names.join(", ") || "none"})`;
207
207
  }
208
208
  /**
209
209
  * Durably select a style for a session. The write resolves only after the
@@ -252,7 +252,8 @@ const FRONTMATTER_KEYS = /* @__PURE__ */ new Set([
252
252
  "description",
253
253
  "whenToUse",
254
254
  "keep-coding-instructions",
255
- "force"
255
+ "force",
256
+ "force-for-plugin"
256
257
  ]);
257
258
  /** Validate one frontmatter block into {@link StyleFields}. */
258
259
  function parseFrontmatter(file, frontmatter) {
@@ -281,7 +282,13 @@ function parseFrontmatter(file, frontmatter) {
281
282
  force: booleans.force
282
283
  } }, oddity);
283
284
  }
284
- /** Read the two shared boolean flags, defaulting each to false. */
285
+ /**
286
+ * Read the shared boolean flags, defaulting each to false. `force-for-plugin`
287
+ * is the Claude Code field name (both in frontmatter and in `outputStyles`
288
+ * JSON); `force` is this package's alias for it, kept so styles written
289
+ * against the original plugin keep loading. When both appear they must
290
+ * agree — a disagreement is ambiguous, so the file is skipped.
291
+ */
285
292
  function booleanFields(record, source) {
286
293
  const keep = record["keep-coding-instructions"];
287
294
  if (keep !== void 0 && typeof keep !== "boolean") return {
@@ -289,15 +296,26 @@ function booleanFields(record, source) {
289
296
  force: false,
290
297
  problem: `${source} keep-coding-instructions must be a boolean when present`
291
298
  };
292
- const force = record["force"];
293
- if (force !== void 0 && typeof force !== "boolean") return {
299
+ const forceAlias = record["force"];
300
+ if (forceAlias !== void 0 && typeof forceAlias !== "boolean") return {
294
301
  keepCodingInstructions: false,
295
302
  force: false,
296
303
  problem: `${source} force must be a boolean when present`
297
304
  };
305
+ const forceForPlugin = record["force-for-plugin"];
306
+ if (forceForPlugin !== void 0 && typeof forceForPlugin !== "boolean") return {
307
+ keepCodingInstructions: false,
308
+ force: false,
309
+ problem: `${source} force-for-plugin must be a boolean when present`
310
+ };
311
+ if (forceAlias !== void 0 && forceForPlugin !== void 0 && forceAlias !== forceForPlugin) return {
312
+ keepCodingInstructions: false,
313
+ force: false,
314
+ problem: `${source} force and force-for-plugin disagree; drop one of them`
315
+ };
298
316
  return {
299
317
  keepCodingInstructions: keep ?? false,
300
- force: force ?? false
318
+ force: forceForPlugin ?? forceAlias ?? false
301
319
  };
302
320
  }
303
321
  /**
package/lib/invariant.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as name, i as installInvariant, n as apply, r as inject, t as PACKAGE_NAME } from "./invariant-LV6hQX5s.js";
1
+ import { a as name, i as installInvariant, n as apply, r as inject, t as PACKAGE_NAME } from "./invariant-B9LpUViP.js";
2
2
  export { PACKAGE_NAME, apply, inject, installInvariant, name };
@@ -1,4 +1,11 @@
1
- /** Simplified Chinese dictionary (the key-set source of truth). */
1
+ /**
2
+ * Simplified Chinese dictionary (the key-set source of truth).
3
+ *
4
+ * Only `zh` and `en` are shipped: the DSH Web locale system (dsh-client-locale
5
+ * rc.6) exposes exactly the `zh`/`en` locale pair in its settings row, so
6
+ * further dictionaries would be dead weight the framework can never select.
7
+ * When a future harness release ships more locales, extend this pair.
8
+ */
2
9
  export declare const zh: {
3
10
  'option.off': string;
4
11
  'option.offDetail': string;
@@ -1 +1 @@
1
- {"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,eAAO,MAAM,EAAE;;;CAGmB,CAAA;AAElC,4CAA4C;AAC5C,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,EAAE,CAAA;AAEtC,mEAAmE;AACnE,eAAO,MAAM,EAAE;;;CAGqB,CAAA"}
1
+ {"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,EAAE;;;CAGmB,CAAA;AAElC,4CAA4C;AAC5C,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,EAAE,CAAA;AAEtC,mEAAmE;AACnE,eAAO,MAAM,EAAE;;;CAGqB,CAAA"}
@@ -42,7 +42,11 @@ export interface OutputStyle {
42
42
  * Claude Code.
43
43
  */
44
44
  readonly keepCodingInstructions: boolean;
45
- /** Apply this style unconditionally, overriding any session selection. */
45
+ /**
46
+ * Apply this style unconditionally, overriding any session selection.
47
+ * Declared through Claude Code's `force-for-plugin` field (`force` is
48
+ * accepted as an alias).
49
+ */
46
50
  readonly force: boolean;
47
51
  }
48
52
  /** Report a style file the loader skipped or a tolerated oddity. */
@@ -1 +1 @@
1
- {"version":3,"file":"style-library.d.ts","sourceRoot":"","sources":["../../src/style-library.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,gFAAgF;AAChF,eAAO,MAAM,aAAa,QAAuB,CAAA;AAEjD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAItD;AAED,uEAAuE;AACvE,MAAM,WAAW,WAAW;IAC1B,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,uDAAuD;IACvD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,wEAAwE;IACxE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,4EAA4E;IAC5E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,sEAAsE;IACtE,QAAQ,CAAC,MAAM,EAAE,IAAI,GAAG,MAAM,CAAA;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,sBAAsB,EAAE,OAAO,CAAA;IACxC,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CACxB;AAED,oEAAoE;AACpE,KAAK,IAAI,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;AAErC;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,OAAO,EAAE;IAAE,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;CAAE,EACzC,IAAI,EAAE,IAAI,GACT,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,CAclC;AA8OD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAIpF"}
1
+ {"version":3,"file":"style-library.d.ts","sourceRoot":"","sources":["../../src/style-library.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,gFAAgF;AAChF,eAAO,MAAM,aAAa,QAAuB,CAAA;AAEjD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAItD;AAED,uEAAuE;AACvE,MAAM,WAAW,WAAW;IAC1B,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,uDAAuD;IACvD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,wEAAwE;IACxE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,4EAA4E;IAC5E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,sEAAsE;IACtE,QAAQ,CAAC,MAAM,EAAE,IAAI,GAAG,MAAM,CAAA;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,sBAAsB,EAAE,OAAO,CAAA;IACxC;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CACxB;AAED,oEAAoE;AACpE,KAAK,IAAI,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;AAErC;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,OAAO,EAAE;IAAE,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;CAAE,EACzC,IAAI,EAAE,IAAI,GACT,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,CAclC;AA4PD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAIpF"}
package/package.json CHANGED
@@ -1,14 +1,23 @@
1
1
  {
2
2
  "name": "dsh-output-styles",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "Claude Code outputStyles-equivalent runtime output-style switching for DeepSeek Harness",
5
5
  "type": "module",
6
+ "sideEffects": false,
7
+ "packageManager": "pnpm@11.7.0",
6
8
  "license": "Apache-2.0",
9
+ "author": "PerryLink",
7
10
  "repository": {
8
11
  "type": "git",
9
12
  "url": "git+https://github.com/PerryLink/dsh-output-styles.git"
10
13
  },
11
14
  "homepage": "https://github.com/PerryLink/dsh-output-styles#readme",
15
+ "bugs": {
16
+ "url": "https://github.com/PerryLink/dsh-output-styles/issues"
17
+ },
18
+ "publishConfig": {
19
+ "access": "public"
20
+ },
12
21
  "engines": {
13
22
  "node": "^22.19.0 || >=24.0.0"
14
23
  },
@@ -16,7 +25,9 @@
16
25
  "build": "node -e \"require('node:fs').rmSync('lib',{recursive:true,force:true})\" && tsc -p tsconfig.json --noEmitOnError --pretty false && tsdown && tsdown -c tsdown.client.config.ts",
17
26
  "test": "vitest run",
18
27
  "typecheck": "tsc -p tsconfig.json --noEmitOnError --pretty false && tsc -p tsconfig.vitest.json --pretty false",
28
+ "verify": "pnpm run typecheck && pnpm test && pnpm run verify:self-contained",
19
29
  "verify:self-contained": "node scripts/verify-self-contained.mjs",
30
+ "prepublishOnly": "pnpm run verify",
20
31
  "prepare": "node scripts/prepare.mjs"
21
32
  },
22
33
  "main": "lib/index.js",
@@ -48,6 +59,7 @@
48
59
  "src",
49
60
  "styles",
50
61
  "cordis.patch.yml",
62
+ "CHANGELOG.md",
51
63
  "LICENSE",
52
64
  "README.md",
53
65
  "README.zh.md",
@@ -1,4 +1,11 @@
1
- /** Simplified Chinese dictionary (the key-set source of truth). */
1
+ /**
2
+ * Simplified Chinese dictionary (the key-set source of truth).
3
+ *
4
+ * Only `zh` and `en` are shipped: the DSH Web locale system (dsh-client-locale
5
+ * rc.6) exposes exactly the `zh`/`en` locale pair in its settings row, so
6
+ * further dictionaries would be dead weight the framework can never select.
7
+ * When a future harness release ships more locales, extend this pair.
8
+ */
2
9
  export const zh = {
3
10
  'option.off': '关闭(默认)',
4
11
  'option.offDetail': '恢复项目默认输出风格',
package/src/runtime.ts CHANGED
@@ -190,7 +190,7 @@ export class OutputStyleRuntime {
190
190
  * @returns the error text listing every switchable name.
191
191
  */
192
192
  unknownStyleLine(name: string): string {
193
- return `unknown output style "${name}" (available: ${this.names.join(', ')})`
193
+ return `unknown output style "${name}" (available: ${this.names.join(', ') || 'none'})`
194
194
  }
195
195
 
196
196
  /**
@@ -55,7 +55,11 @@ export interface OutputStyle {
55
55
  * Claude Code.
56
56
  */
57
57
  readonly keepCodingInstructions: boolean
58
- /** Apply this style unconditionally, overriding any session selection. */
58
+ /**
59
+ * Apply this style unconditionally, overriding any session selection.
60
+ * Declared through Claude Code's `force-for-plugin` field (`force` is
61
+ * accepted as an alias).
62
+ */
59
63
  readonly force: boolean
60
64
  }
61
65
 
@@ -212,6 +216,7 @@ const FRONTMATTER_KEYS = new Set([
212
216
  'whenToUse',
213
217
  'keep-coding-instructions',
214
218
  'force',
219
+ 'force-for-plugin',
215
220
  ])
216
221
 
217
222
  /** Validate one frontmatter block into {@link StyleFields}. */
@@ -252,17 +257,30 @@ function parseFrontmatter(file: string, frontmatter: string): { fields?: StyleFi
252
257
  }, oddity)
253
258
  }
254
259
 
255
- /** Read the two shared boolean flags, defaulting each to false. */
260
+ /**
261
+ * Read the shared boolean flags, defaulting each to false. `force-for-plugin`
262
+ * is the Claude Code field name (both in frontmatter and in `outputStyles`
263
+ * JSON); `force` is this package's alias for it, kept so styles written
264
+ * against the original plugin keep loading. When both appear they must
265
+ * agree — a disagreement is ambiguous, so the file is skipped.
266
+ */
256
267
  function booleanFields(record: Record<string, unknown>, source: string): { keepCodingInstructions: boolean; force: boolean; problem?: string } {
257
268
  const keep = record['keep-coding-instructions']
258
269
  if (keep !== undefined && typeof keep !== 'boolean') {
259
270
  return { keepCodingInstructions: false, force: false, problem: `${source} keep-coding-instructions must be a boolean when present` }
260
271
  }
261
- const force = record['force']
262
- if (force !== undefined && typeof force !== 'boolean') {
272
+ const forceAlias = record['force']
273
+ if (forceAlias !== undefined && typeof forceAlias !== 'boolean') {
263
274
  return { keepCodingInstructions: false, force: false, problem: `${source} force must be a boolean when present` }
264
275
  }
265
- return { keepCodingInstructions: keep ?? false, force: force ?? false }
276
+ const forceForPlugin = record['force-for-plugin']
277
+ if (forceForPlugin !== undefined && typeof forceForPlugin !== 'boolean') {
278
+ return { keepCodingInstructions: false, force: false, problem: `${source} force-for-plugin must be a boolean when present` }
279
+ }
280
+ if (forceAlias !== undefined && forceForPlugin !== undefined && forceAlias !== forceForPlugin) {
281
+ return { keepCodingInstructions: false, force: false, problem: `${source} force and force-for-plugin disagree; drop one of them` }
282
+ }
283
+ return { keepCodingInstructions: keep ?? false, force: forceForPlugin ?? forceAlias ?? false }
266
284
  }
267
285
 
268
286
  /**
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: learning
3
+ description: Collaborative learn-by-doing mode with short "Insights" and small hands-on steps for the user.
4
+ whenToUse: Pairing, onboarding, or when the user wants to learn the codebase and not just watch.
5
+ keep-coding-instructions: true
6
+ ---
7
+
8
+ You are in the learning output style for this conversation.
9
+
10
+ - Share a short "Insight" with each significant action: the why behind the what, framed to teach the mechanism or decision in plain language.
11
+ - Ask the user to contribute small, strategic pieces of the work: hand back focused micro-tasks (one function, one test, one rename) instead of doing everything yourself.
12
+ - Mark the pieces you deliberately leave for the user with `TODO(human)` comments so they are easy to find, and state clearly what the marker asks for.
13
+ - Alternate between showing and letting them try; when they contribute, acknowledge the change and build the next step on it.
14
+ - 回答语言跟随用户语言:中文提问用中文回答,英文提问用英文回答。
15
+
16
+ 边做边学:关键动作配一段简短「Insight」讲清原理;把小而关键的任务以 `TODO(human)` 标记留给用户动手,再在其成果上继续。
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: proactive
3
+ description: Execute immediately, assume reasonable defaults, and prefer action over planning.
4
+ whenToUse: Routine multi-step work where pausing for confirmation slows you down.
5
+ keep-coding-instructions: true
6
+ ---
7
+
8
+ You are in the proactive output style for this conversation.
9
+
10
+ - Execute immediately instead of waiting for confirmation; make reasonable assumptions for routine decisions and say what you assumed.
11
+ - Prefer action over planning: start with the most likely correct step, correct course from results, and only plan up front when the cost of a wrong step is high.
12
+ - Do not pause for permission on reversible, low-risk actions; do pause (and explain) for destructive or irreversible ones.
13
+ - Report what you did and what remains in short progress notes; avoid asking questions you can answer yourself.
14
+ - 回答语言跟随用户语言:中文提问用中文回答,英文提问用英文回答。
15
+
16
+ 主动执行:可逆且低风险的步骤直接做、边做边修正;只对不可逆或有破坏性的动作停下来说明并等待确认。