dsh-console-utf8 0.1.1 → 0.1.3

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,15 @@ All notable changes to this project are documented in this file.
4
4
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## 0.1.3 (2026-09-16)
8
+
9
+ - **A hook file this plugin does not own is never overwritten.** `BASH_ENV` ownership is now decided *before* anything is written — it used to stand down only after `writeShimIfChanged` had already run — and `writeShimIfChanged` refuses to replace a file that exists but does not carry this plugin's marker, raising `ForeignShimError` instead. Following the old warning's advice ("set this plugin's `shimPath` to adopt it") replaced that user's script with no backup. The warning no longer suggests it, and a foreign hook path stands the plugin down with reason `hook path holds a foreign file`.
10
+ - `SHIM_MARKER` and `ForeignShimError` are exported, and five unit tests pin the behaviour: a free path is written, this plugin's own hook follows a code-page change, a foreign file is refused and left byte-identical, ownership is decided before any write, and the marker is exactly what `shimScript()` emits.
11
+
12
+ ## 0.1.2 (2026-09-13)
13
+
14
+ - Documentation only, no code change. The READMEs gain a CI badge, the release section records that publishing goes through npm trusted publishing (OIDC) with no stored token, and the duplicated publishing heading is merged into one section.
15
+
7
16
  ## 0.1.1 (2026-09-13)
8
17
 
9
18
  - Documentation only, no code change. The "host switch" limitation now records what a restarted dsh-tui session measured: the Windows launcher starts the host without a console of its own, so every `chcp.com` child gets a fresh console, the host half logs its warning, and the `BASH_ENV` hook carries the whole fix. The warning is expected on every start, not a fault.
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # dsh-console-utf8
2
2
 
3
+ [![ci](https://github.com/VviLliAm-qwq/dsh-console-utf8/actions/workflows/ci.yml/badge.svg)](https://github.com/VviLliAm-qwq/dsh-console-utf8/actions/workflows/ci.yml)
4
+
3
5
  **English** · [中文](README.zh.md)
4
6
 
5
7
  Keeps the Windows console on code page **65001 (UTF-8)** for the dsh host and for the commands the bash tool runs, so output from Windows-native child processes stops arriving as mojibake.
@@ -79,11 +81,8 @@ The unit tests never touch the real console or the user's files: the code-page c
79
81
 
80
82
  ## Publishing
81
83
 
82
- Version tags drive the release (`vX.Y.Z`, tag = `package.json` version). The repository ships a GitHub Actions workflow that runs the verification chain and publishes to npm with provenance.
83
-
84
- ## Publishing
85
-
86
84
  - **Repository**: <https://github.com/VviLliAm-qwq/dsh-console-utf8> (public)
85
+ - **Release**: version tags (`vX.Y.Z`, tag = `package.json` version) drive `.github/workflows/release.yml`, which runs the verification chain and publishes to npm through **trusted publishing (OIDC)** with provenance — no token is stored in the repository.
87
86
 
88
87
  ## License
89
88
 
package/README.zh.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # dsh-console-utf8
2
2
 
3
+ [![ci](https://github.com/VviLliAm-qwq/dsh-console-utf8/actions/workflows/ci.yml/badge.svg)](https://github.com/VviLliAm-qwq/dsh-console-utf8/actions/workflows/ci.yml)
4
+
3
5
  [English](README.md) · **中文**
4
6
 
5
7
  把 **dsh 宿主**和 **bash 工具命令**所用的 Windows 控制台固定在代码页 **65001(UTF-8)**,让 Windows 原生子进程的输出不再变成乱码。
@@ -79,11 +81,8 @@ npm run pack:verify # 发布文件清单,以及「有没有模块漏进清
79
81
 
80
82
  ## 发布
81
83
 
82
- 版本由 tag 驱动(`vX.Y.Z`,tag 必须等于 `package.json` 的 version)。仓库自带 GitHub Actions 工作流:先跑完整校验链,再带 provenance 发布到 npm。
83
-
84
- ## 发布
85
-
86
84
  - **仓库**:<https://github.com/VviLliAm-qwq/dsh-console-utf8>(公开)
85
+ - **发布方式**:`vX.Y.Z` tag(tag 必须等于 `package.json` 的 version)驱动 `.github/workflows/release.yml`,先跑完整校验链,再经 npm **可信发布(OIDC)**带 provenance 上传——仓库内不存放任何令牌。
87
86
 
88
87
  ## 许可
89
88
 
package/dsh-plugin.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "manifestVersion": "0.15",
4
4
  "id": "com.dsh-tui-ecosystem.dsh-console-utf8",
5
5
  "name": "dsh-console-utf8",
6
- "version": "0.1.1",
6
+ "version": "0.1.3",
7
7
  "facets": {
8
8
  "host": {
9
9
  "entry": "lib/index.js",
package/lib/plugin.js CHANGED
@@ -120,6 +120,24 @@ export function restoreBashEnv(env, owned) {
120
120
  return 'restored'
121
121
  }
122
122
 
123
+ /**
124
+ * Substring that identifies a hook file as THIS plugin's own. Any file at the
125
+ * configured `shimPath` that does not carry it belongs to somebody else and is
126
+ * never overwritten.
127
+ */
128
+ export const SHIM_MARKER = 'dsh-console-utf8'
129
+
130
+ /** Raised instead of replacing a hook file this plugin does not own. */
131
+ export class ForeignShimError extends Error {
132
+ /**
133
+ * @param {string} path - The offending hook path.
134
+ */
135
+ constructor(path) {
136
+ super(`refusing to overwrite ${path}: the file exists and is not this plugin's hook (move it aside, or point shimPath at a free path)`)
137
+ this.name = 'ForeignShimError'
138
+ }
139
+ }
140
+
123
141
  /**
124
142
  * Write the hook when its content differs, creating the directory if needed.
125
143
  *
@@ -127,9 +145,16 @@ export function restoreBashEnv(env, owned) {
127
145
  * the fix silently do the wrong thing, so the file is compared rather than
128
146
  * assumed.
129
147
  *
148
+ * The file is only ever replaced when it is missing, already identical, or
149
+ * recognisably this plugin's own (it carries {@link SHIM_MARKER}). Following
150
+ * the old warning's advice — "set shimPath to adopt an existing BASH_ENV" —
151
+ * used to overwrite that user's script with no backup; a foreign file now
152
+ * raises {@link ForeignShimError} instead, and the plugin stands down.
153
+ *
130
154
  * @param {string} path - Hook path.
131
155
  * @param {string} content - Desired content.
132
156
  * @returns {boolean} True when the file was (re)written.
157
+ * @throws {ForeignShimError} When `path` holds a file this plugin does not own.
133
158
  */
134
159
  export function writeShimIfChanged(path, content) {
135
160
  let current
@@ -139,6 +164,7 @@ export function writeShimIfChanged(path, content) {
139
164
  current = undefined
140
165
  }
141
166
  if (current === content) return false
167
+ if (current !== undefined && !current.includes(SHIM_MARKER)) throw new ForeignShimError(path)
142
168
  mkdirSync(dirname(path), { recursive: true })
143
169
  // No BOM, LF endings: the file is sourced by `sh`, never parsed as JSON.
144
170
  writeFileSync(path, content, 'utf8')
@@ -190,24 +216,29 @@ export function setup(deps, config) {
190
216
  if (config.shellHook) {
191
217
  const shimPath = config.shimPath === '' ? defaultShimPath(deps.home) : config.shimPath
192
218
  const value = toPosixPath(shimPath)
193
- let written = false
194
- try {
195
- written = deps.ensureShim(shimPath, shimScript(config.codePage))
196
- } catch (error) {
197
- deps.log.warn(`could not write the shell hook: ${error instanceof Error ? error.message : String(error)}`)
198
- result.shim = { path: shimPath, applied: false, reason: 'hook not writable' }
199
- return result
200
- }
201
219
 
220
+ // Ownership is decided BEFORE anything is written. Standing down after a
221
+ // write would already have replaced a file this plugin does not own, so
222
+ // pointing `shimPath` at somebody else's hook must never destroy it.
202
223
  const existing = typeof deps.env.BASH_ENV === 'string' && deps.env.BASH_ENV !== '' ? deps.env.BASH_ENV : undefined
203
224
  if (existing !== undefined && existing !== value) {
204
225
  // Someone else owns BASH_ENV. Clobbering it would break their hook, so
205
- // this plugin stands down and says why; the config can point elsewhere.
206
- deps.log.warn(`BASH_ENV is already ${existing}; left untouched (set this plugin's shimPath to adopt it)`)
226
+ // this plugin stands down and says why.
227
+ deps.log.warn(`BASH_ENV is already ${existing}; left untouched. This plugin only maintains its own hook file (shimPath), so that hook wins — remove it first if this plugin should own BASH_ENV`)
207
228
  result.shim = { path: shimPath, applied: false, reason: 'BASH_ENV owned by someone else' }
208
229
  return result
209
230
  }
210
231
 
232
+ let written = false
233
+ try {
234
+ written = deps.ensureShim(shimPath, shimScript(config.codePage))
235
+ } catch (error) {
236
+ const reason = error instanceof ForeignShimError ? 'hook path holds a foreign file' : 'hook not writable'
237
+ deps.log.warn(`could not write the shell hook: ${error instanceof Error ? error.message : String(error)}`)
238
+ result.shim = { path: shimPath, applied: false, reason }
239
+ return result
240
+ }
241
+
211
242
  deps.env.BASH_ENV = value
212
243
  result.shim = {
213
244
  path: shimPath,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-console-utf8",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Keep the Windows console on code page 65001 (UTF-8) for the dsh host and its bash tool commands, so output from Windows-native child processes stops being decoded as mojibake",
5
5
  "packageManager": "pnpm@11.22.0",
6
6
  "license": "MIT",