dsh-ci-diet 0.1.1 → 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.
Files changed (163) hide show
  1. package/README.ko.md +64 -15
  2. package/README.md +77 -20
  3. package/client/index.d.ts +3 -0
  4. package/client/index.js +1035 -0
  5. package/dist/adapters/github/budget.d.ts +1 -1
  6. package/dist/adapters/github/budget.js +4 -2
  7. package/dist/adapters/github/budget.js.map +1 -1
  8. package/dist/adapters/github/client.d.ts +2 -0
  9. package/dist/adapters/github/client.js.map +1 -1
  10. package/dist/adapters/github/errors.d.ts +3 -1
  11. package/dist/adapters/github/errors.js +12 -3
  12. package/dist/adapters/github/errors.js.map +1 -1
  13. package/dist/adapters/github/transport.d.ts +13 -3
  14. package/dist/adapters/github/transport.js +151 -25
  15. package/dist/adapters/github/transport.js.map +1 -1
  16. package/dist/cli/index.d.ts +25 -0
  17. package/dist/cli/index.js +522 -211
  18. package/dist/cli/index.js.map +1 -1
  19. package/dist/core/analysis/coverage.d.ts +2 -1
  20. package/dist/core/analysis/coverage.js +12 -8
  21. package/dist/core/analysis/coverage.js.map +1 -1
  22. package/dist/core/analysis/diagnostics.d.ts +57 -0
  23. package/dist/core/analysis/diagnostics.js +166 -0
  24. package/dist/core/analysis/diagnostics.js.map +1 -0
  25. package/dist/core/analysis/report.js +1 -1
  26. package/dist/core/analysis/report.js.map +1 -1
  27. package/dist/core/config/load.d.ts +13 -0
  28. package/dist/core/config/load.js +71 -0
  29. package/dist/core/config/load.js.map +1 -0
  30. package/dist/core/config/plugin-settings.d.ts +37 -0
  31. package/dist/core/config/plugin-settings.js +75 -0
  32. package/dist/core/config/plugin-settings.js.map +1 -0
  33. package/dist/core/contracts/schema-json.generated.d.ts +1 -1
  34. package/dist/core/contracts/schema-json.generated.js +1 -1
  35. package/dist/core/contracts/schema-json.generated.js.map +1 -1
  36. package/dist/core/contracts/schema.d.ts +12 -1
  37. package/dist/core/data/index.d.ts +7 -0
  38. package/dist/core/data/index.js +28 -0
  39. package/dist/core/data/index.js.map +1 -1
  40. package/dist/core/history/sync.d.ts +8 -3
  41. package/dist/core/history/sync.js +198 -47
  42. package/dist/core/history/sync.js.map +1 -1
  43. package/dist/core/patch/apply.d.ts +34 -1
  44. package/dist/core/patch/apply.js +486 -159
  45. package/dist/core/patch/apply.js.map +1 -1
  46. package/dist/core/patch/approval.d.ts +6 -0
  47. package/dist/core/patch/approval.js +29 -3
  48. package/dist/core/patch/approval.js.map +1 -1
  49. package/dist/core/patch/attestation.js +7 -3
  50. package/dist/core/patch/attestation.js.map +1 -1
  51. package/dist/core/patch/dependencies.d.ts +1 -0
  52. package/dist/core/patch/dependencies.js +176 -132
  53. package/dist/core/patch/dependencies.js.map +1 -1
  54. package/dist/core/patch/diff.d.ts +11 -0
  55. package/dist/core/patch/diff.js +76 -0
  56. package/dist/core/patch/diff.js.map +1 -0
  57. package/dist/core/patch/edits.d.ts +1 -1
  58. package/dist/core/patch/edits.js +27 -5
  59. package/dist/core/patch/edits.js.map +1 -1
  60. package/dist/core/patch/eligibility.d.ts +3 -2
  61. package/dist/core/patch/eligibility.js +22 -19
  62. package/dist/core/patch/eligibility.js.map +1 -1
  63. package/dist/core/patch/locks.d.ts +50 -0
  64. package/dist/core/patch/locks.js +196 -0
  65. package/dist/core/patch/locks.js.map +1 -0
  66. package/dist/core/patch/plan.d.ts +1 -2
  67. package/dist/core/patch/plan.js +4 -3
  68. package/dist/core/patch/plan.js.map +1 -1
  69. package/dist/core/patch/request-plan.d.ts +51 -0
  70. package/dist/core/patch/request-plan.js +122 -0
  71. package/dist/core/patch/request-plan.js.map +1 -0
  72. package/dist/core/patch/store.d.ts +182 -5
  73. package/dist/core/patch/store.js +909 -76
  74. package/dist/core/patch/store.js.map +1 -1
  75. package/dist/core/patch/verify.d.ts +4 -3
  76. package/dist/core/patch/verify.js +6 -4
  77. package/dist/core/patch/verify.js.map +1 -1
  78. package/dist/core/policy/constants.d.ts +34 -0
  79. package/dist/core/policy/constants.js +35 -0
  80. package/dist/core/policy/constants.js.map +1 -0
  81. package/dist/core/report/html.d.ts +2 -0
  82. package/dist/core/report/html.js +51 -32
  83. package/dist/core/report/html.js.map +1 -1
  84. package/dist/core/report/localize.d.ts +13 -0
  85. package/dist/core/report/localize.js +19 -0
  86. package/dist/core/report/localize.js.map +1 -0
  87. package/dist/core/rules/cd001.js +108 -32
  88. package/dist/core/rules/cd001.js.map +1 -1
  89. package/dist/core/rules/cd002.js +5 -0
  90. package/dist/core/rules/cd002.js.map +1 -1
  91. package/dist/core/rules/cd003.js +52 -13
  92. package/dist/core/rules/cd003.js.map +1 -1
  93. package/dist/core/rules/cd004.js +13 -0
  94. package/dist/core/rules/cd004.js.map +1 -1
  95. package/dist/core/rules/cd005.d.ts +0 -5
  96. package/dist/core/rules/cd005.js +182 -60
  97. package/dist/core/rules/cd005.js.map +1 -1
  98. package/dist/core/rules/cd008.d.ts +1 -2
  99. package/dist/core/rules/cd008.js +22 -4
  100. package/dist/core/rules/cd008.js.map +1 -1
  101. package/dist/core/rules/types.d.ts +6 -0
  102. package/dist/core/rules/types.js +9 -0
  103. package/dist/core/rules/types.js.map +1 -1
  104. package/dist/core/savings/report-metrics.d.ts +8 -0
  105. package/dist/core/savings/report-metrics.js +24 -1
  106. package/dist/core/savings/report-metrics.js.map +1 -1
  107. package/dist/core/scan/binding.d.ts +34 -2
  108. package/dist/core/scan/binding.js +58 -17
  109. package/dist/core/scan/binding.js.map +1 -1
  110. package/dist/core/scan/discover.d.ts +2 -0
  111. package/dist/core/scan/discover.js +13 -8
  112. package/dist/core/scan/discover.js.map +1 -1
  113. package/dist/core/scan/scan.d.ts +4 -0
  114. package/dist/core/scan/scan.js +10 -4
  115. package/dist/core/scan/scan.js.map +1 -1
  116. package/dist/core/support/clock.d.ts +34 -0
  117. package/dist/core/support/clock.js +34 -0
  118. package/dist/core/support/clock.js.map +1 -0
  119. package/dist/core/support/concurrency.d.ts +11 -0
  120. package/dist/core/support/concurrency.js +47 -0
  121. package/dist/core/support/concurrency.js.map +1 -0
  122. package/dist/core/support/deadline.d.ts +17 -0
  123. package/dist/core/support/deadline.js +45 -0
  124. package/dist/core/support/deadline.js.map +1 -0
  125. package/dist/core/support/filesystem.d.ts +19 -0
  126. package/dist/core/support/filesystem.js +8 -0
  127. package/dist/core/support/filesystem.js.map +1 -0
  128. package/dist/core/version.d.ts +1 -1
  129. package/dist/core/version.js +1 -1
  130. package/dist/core/workflow/jobkey.js +106 -31
  131. package/dist/core/workflow/jobkey.js.map +1 -1
  132. package/dist/core/workflow/matrix.d.ts +4 -2
  133. package/dist/core/workflow/matrix.js +90 -25
  134. package/dist/core/workflow/matrix.js.map +1 -1
  135. package/dist/core/workflow/parse.js +14 -11
  136. package/dist/core/workflow/parse.js.map +1 -1
  137. package/dist/dsh/host/plugin.d.ts +125 -5
  138. package/dist/dsh/host/plugin.js +240 -167
  139. package/dist/dsh/host/plugin.js.map +1 -1
  140. package/dist/shared/i18n/en.d.ts +113 -4
  141. package/dist/shared/i18n/en.js +113 -4
  142. package/dist/shared/i18n/en.js.map +1 -1
  143. package/dist/shared/i18n/es.d.ts +2 -0
  144. package/dist/shared/i18n/es.js +226 -0
  145. package/dist/shared/i18n/es.js.map +1 -0
  146. package/dist/shared/i18n/fr.d.ts +2 -0
  147. package/dist/shared/i18n/fr.js +226 -0
  148. package/dist/shared/i18n/fr.js.map +1 -0
  149. package/dist/shared/i18n/hi.d.ts +2 -0
  150. package/dist/shared/i18n/hi.js +226 -0
  151. package/dist/shared/i18n/hi.js.map +1 -0
  152. package/dist/shared/i18n/host.d.ts +14 -0
  153. package/dist/shared/i18n/host.js +118 -0
  154. package/dist/shared/i18n/host.js.map +1 -0
  155. package/dist/shared/i18n/index.d.ts +3 -1
  156. package/dist/shared/i18n/index.js +37 -14
  157. package/dist/shared/i18n/index.js.map +1 -1
  158. package/dist/shared/i18n/ko.js +113 -4
  159. package/dist/shared/i18n/ko.js.map +1 -1
  160. package/dist/shared/i18n/zh-Hans.d.ts +1 -1
  161. package/dist/shared/i18n/zh-Hans.js +225 -3
  162. package/dist/shared/i18n/zh-Hans.js.map +1 -1
  163. package/package.json +19 -6
package/README.ko.md CHANGED
@@ -2,9 +2,10 @@
2
2
 
3
3
  낭비된 GitHub Actions 러너 시간을 찾고, 작고 검토 가능한 패치를 제안합니다.
4
4
 
5
- 상태: **알파, npm에 `dsh-ci-diet@0.1.1`로 배포됨**. 계약, 명세, 분석 엔진,
5
+ 상태: **알파, `dsh-ci-diet@0.3.1` npm 게시됨**. 계약, 명세, 분석 엔진,
6
6
  패치 엔진, CLI, DSH 플러그인 도구, 자체 완결형 HTML 보고서는 구현과 테스트를
7
- 마쳤습니다. DSH Web 클라이언트 화면은 아직 남아 있습니다.
7
+ 마쳤습니다. DSH Web 클라이언트는 설정 화면을 제공하고, 보고서·적용 화면은 아직
8
+ 남아 있습니다.
8
9
 
9
10
  ## 하는 일
10
11
 
@@ -58,15 +59,43 @@ CI Diet는 두 가지를 읽고 비교합니다.
58
59
 
59
60
  ## 설치
60
61
 
62
+ CLI는 Node `^22.19.0 || >=24.0.0`이 필요합니다. DSH 플러그인은 DSH
63
+ `>=0.2.1-rc.2 <0.3.0-0` 또는 `>=0.2.2-rc.1 <0.3.0-0`이 필요합니다. `0.3.1`
64
+ 릴리스는 DSH `0.2.1-rc.2`에서 검증했으며 DSH `0.3.0`은 아직 지원하지 않습니다.
65
+
66
+ CLI 설치:
67
+
68
+ ```
69
+ npm install --global dsh-ci-diet@0.3.1
70
+ ci-diet --version
71
+ ```
72
+
73
+ 전역 설치를 원하지 않으면 `npx dsh-ci-diet@0.3.1`으로 같은 CLI를 실행할 수
74
+ 있습니다.
75
+
76
+ DSH 플러그인 설치:
77
+
61
78
  ```
62
- npm install --global dsh-ci-diet
63
- dsh plugin --profile web add dsh-ci-diet
79
+ dsh plugin --profile web add dsh-ci-diet@0.3.1
80
+ dsh --profile web
64
81
  ```
65
82
 
66
- 플러그인은 기본으로 꺼진 로더 항목 하나를 추가합니다. 이력 동기화를 쓸 때만
67
- `networkEnabled`를 켜십시오. 전역 설치는 선택 사항입니다. `npx dsh-ci-diet`로
68
- 같은 CLI를 실행할 수 있고, DSH 플러그인은 프로필에 패키지가 있으면 됩니다.
69
- 릴리스 태그는 GitHub에, 같은 버전은 npm `0.1.1`에 있습니다.
83
+ 플러그인은 기본으로 꺼진 로더 항목 하나와 **설정 → CI Diet** 페이지를 추가합니다.
84
+ 이 페이지에서 분석 규칙, 이력 상한, 저장 공간 한도, 비용 추정, 네트워크 접근,
85
+ 상태 디렉터리를 모두 바꿀 수 있습니다. 값은 `ci-diet --config`와 같은 계약 검증과
86
+ 기본값을 쓰며, 재시작 없이 다음 도구 호출부터 적용되고 CLI의 설정 파일은 건드리지
87
+ 않습니다. 적용 도구가 아직 없어 `localApplyEnabled`는 노출하지 않습니다.
88
+
89
+ 기존 설치 업데이트:
90
+
91
+ ```
92
+ npm install --global dsh-ci-diet@latest
93
+ dsh plugin --profile web add dsh-ci-diet@latest
94
+ ```
95
+
96
+ 플러그인을 업데이트한 뒤 DSH를 재시작합니다. `dsh plugin --profile web list`로
97
+ 설치된 플러그인 버전을, `ci-diet --version`(또는
98
+ `npx dsh-ci-diet@latest --version`)으로 CLI 버전을 확인할 수 있습니다.
70
99
 
71
100
  ## 실행
72
101
 
@@ -91,20 +120,31 @@ ci-diet revert --change <changeId> # 백업한 바이트를 복원
91
120
  ```
92
121
  ci-diet report # 저장된 최신 보고서의 텍스트 요약
93
122
  ci-diet report --format html --out report.html
123
+ ci-diet diagnose # Job 이름 매칭과 수집 커버리지 설명
94
124
  ci-diet prune # 만료된 보고서, 계획, 캐시 정리
95
125
  ```
96
126
 
97
127
  HTML 파일은 자체 완결형입니다. 인라인 CSS만 쓰고 스크립트와 외부 요청이 없습니다.
98
128
  읽기 전용이므로 승인은 digest와 nonce 검사가 있는 CLI에 남습니다.
99
129
 
130
+ `diagnose`는 저장된 최신 이력을 읽어 GitHub Job 이름이 워크플로 키로 얼마나
131
+ 해석됐는지, 어떤 matrix Job이 몇 개 레그로 확장됐는지, 어느 수집 상한 때문에
132
+ 커버리지 축이 불완전한지 보여줍니다. 오프라인에서도 동작하며 `--require-complete`를
133
+ 쓰면 축이 불완전할 때 종료 코드 `3`으로 끝납니다.
134
+
135
+ 점검용 캐시 힌트도 함께 보여줍니다. 캐시 없이 의존성을 설치하는 Job이나
136
+ lockfile 변경을 따라가지 못하는 리터럴 캐시 키가 대상입니다. 동결된 계약에는
137
+ 캐시 규칙 ID가 없으므로 힌트는 발견 항목이나 패치로 이어지지 않습니다.
138
+
139
+
100
140
  ## 릴리스
101
141
 
102
142
  `package.json`의 버전과 일치하는 태그를 푸시하면
103
143
  `.github/workflows/publish.yml`이 실행됩니다.
104
144
 
105
145
  ```
106
- git tag v0.1.1
107
- git push origin v0.1.1
146
+ git tag v0.3.1
147
+ git push origin v0.3.1
108
148
  ```
109
149
 
110
150
  워크플로는 태그와 `package.json` 버전을 대조하고(`node
@@ -117,13 +157,14 @@ trusted publisher에 이 저장소의 `publish.yml`이 등록되어 있어야
117
157
 
118
158
  - Node `^22.19.0 || >=24.0.0`
119
159
  - `gh` CLI(선택): 실행 이력 조회에만 사용
120
- - DSH `>=0.2.1-rc.2 <0.3.0`(선택): 플러그인 도구에만 사용
160
+ - DSH `>=0.2.1-rc.2 <0.3.0-0 || >=0.2.2-rc.1 <0.3.0-0`(선택): 플러그인 도구에만
161
+ 사용
121
162
 
122
163
  ## 개발
123
164
 
124
165
  ```
125
166
  bun install
126
- node --test "tests/unit/*.test.ts"
167
+ node scripts/test-core.mjs
127
168
  node scripts/gen-types.mjs --check
128
169
  node scripts/sync-contracts.mjs --check
129
170
  bun run typecheck
@@ -151,9 +192,17 @@ tests/unit 네트워크가 필요 없는 빠른 검사
151
192
 
152
193
  ## 언어
153
194
 
154
- 영어가 기본이며 메시지 키의 단일 소스입니다. 한국어는 전체 번역되어 있고, 중국어
155
- 간체는 번역 슬롯으로만 두며 관리자가 생기기 전까지 영어로 대체됩니다. 공개 문서는
156
- 영어이고 README만 한국어로 미러링합니다.
195
+ 영어가 기본이며 메시지 키의 단일 소스입니다. CLI, HTML 보고서, DSH 도구 문구는
196
+ 영어·한국어·중국어 간체·힌디어·스페인어·프랑스어로 제공하며, 모든 사전이 완역이라
197
+ 키가 빠지면 타입 오류가 납니다. 지역 태그는 언어로 해석하고(`hi-IN`, `es-MX`,
198
+ `fr-CA`), 간체가 아닌 중국어 변형은 영어로 대체합니다.
199
+
200
+ 언어 선택 순서는 `--lang`, DSH 언어 설정, `LC_ALL`/`LC_MESSAGES`/`LANG`,
201
+ 영어입니다. 보고서는 영어로 저장하고 표시할 때만 번역합니다. 규칙 ID, 오류 코드,
202
+ 열거값, 경로, 다이제스트, 수치는 번역하지 않으며 HTML 보고서의 `lang` 속성은
203
+ 선택한 언어를 따릅니다. DSH 도구 설명은 플러그인 로드 시점에 고정되므로 DSH
204
+ 언어 설정을 바꾸면 다시 로드해야 합니다. 공개 문서는 영어이고 README만 한국어로
205
+ 미러링합니다.
157
206
 
158
207
  ## 문서
159
208
 
package/README.md CHANGED
@@ -2,10 +2,10 @@
2
2
 
3
3
  Find wasted GitHub Actions runner time and propose small, reviewable patches.
4
4
 
5
- Status: **alpha, published on npm** as `dsh-ci-diet@0.1.1`. The contracts,
5
+ Status: **alpha**, `dsh-ci-diet@0.3.1` is released on npm. The contracts,
6
6
  specification, analysis engine, patch engine, CLI, DSH plugin tools, and a
7
- self-contained HTML report are implemented and tested. The DSH Web client
8
- screens are still open.
7
+ self-contained HTML report are implemented and tested. The DSH Web client has a
8
+ Settings screen; the report and apply screens are still open.
9
9
 
10
10
  ## What it does
11
11
 
@@ -60,15 +60,43 @@ is not shipped.
60
60
 
61
61
  ## Install
62
62
 
63
+ The CLI needs Node `^22.19.0 || >=24.0.0`. The DSH plugin needs DSH
64
+ `>=0.2.1-rc.2 <0.3.0-0` or `>=0.2.2-rc.1 <0.3.0-0`. Release `0.3.1` was tested
65
+ against DSH `0.2.1-rc.2`; DSH `0.3.0` is not supported yet.
66
+
67
+ Install the CLI:
68
+
69
+ ```
70
+ npm install --global dsh-ci-diet@0.3.1
71
+ ci-diet --version
72
+ ```
73
+
74
+ If you do not want a global install, `npx dsh-ci-diet@0.3.1` runs the same CLI.
75
+
76
+ Install the DSH plugin into a profile:
77
+
78
+ ```
79
+ dsh plugin --profile web add dsh-ci-diet@0.3.1
80
+ dsh --profile web
63
81
  ```
64
- npm install --global dsh-ci-diet
65
- dsh plugin --profile web add dsh-ci-diet
82
+
83
+ The plugin adds one disabled loader entry and a **Settings → CI Diet** page.
84
+ The page edits every engine setting used by the DSH tools: analysis rules, history
85
+ caps, storage limits, the cost estimate, network access, and the state directory.
86
+ Values use the same contract validation and defaults as `ci-diet --config`, apply
87
+ to the next tool call without a restart, and never rewrite the CLI's own config.
88
+ `localApplyEnabled` is not exposed because there is no apply tool yet.
89
+
90
+ Update an existing install:
91
+
92
+ ```
93
+ npm install --global dsh-ci-diet@latest
94
+ dsh plugin --profile web add dsh-ci-diet@latest
66
95
  ```
67
96
 
68
- The plugin adds one disabled loader entry; enable `networkEnabled` only if you
69
- want history sync. Installing the package globally is optional: `npx dsh-ci-diet`
70
- runs the same CLI, and the DSH plugin only needs the package in the profile.
71
- Release tags are on GitHub; the matching npm version is `0.1.1`.
97
+ Restart DSH after updating the plugin. `dsh plugin --profile web list` shows the
98
+ installed plugin version, and `ci-diet --version` (or
99
+ `npx dsh-ci-diet@latest --version`) shows the CLI version.
72
100
 
73
101
  ## Run it
74
102
 
@@ -85,14 +113,23 @@ ci-diet revert --change <changeId> # restores the backed-up bytes
85
113
  `plan` refuses to write when the finding is not patch-eligible, when coverage
86
114
  does not allow a write, or when the policy snapshot a rule depends on is stale.
87
115
  CD005 needs `--job` and `--minutes`; CD008 needs `--job` and `--step`, plus
88
- `--claims artifact-purpose:temporary,consumer-min-days:7`. Nothing is committed,
89
- pushed, or applied without the explicit `approve` step.
116
+ `--claims artifact-purpose:temporary,consumer-min-days:7`. The command prints the
117
+ proposed lines as a diff, and `ci-diet plans --plan <planId>` shows a saved plan
118
+ again. Nothing is committed, pushed, or applied without the explicit `approve`
119
+ step.
120
+
121
+ `--config <file>` merges a partial JSON configuration over the built-in defaults
122
+ for any command, so a repository can lower the workflow size limit or the
123
+ storage quota without code changes. The merged document is validated against
124
+ the frozen contract before the command runs; an unreadable or invalid file
125
+ exits `2`. Relative paths resolve against the effective `--cwd`.
90
126
 
91
127
  ## Read a report
92
128
 
93
129
  ```
94
- ci-diet report # text summary of the latest stored report
130
+ ci-diet report # text summary for this repository
95
131
  ci-diet report --format html --out report.html
132
+ ci-diet diagnose # explain job-name attribution and collection coverage
96
133
  ci-diet prune # drop expired reports, plans, and cache entries
97
134
  ```
98
135
 
@@ -100,14 +137,24 @@ The HTML file is self-contained: inline CSS, no scripts, no external requests.
100
137
  It is read-only, so approvals stay in the CLI where the digest and nonce checks
101
138
  live.
102
139
 
140
+ `diagnose` reads the latest stored history and reports how many GitHub job
141
+ names resolved to workflow keys, which matrix jobs expanded, and which
142
+ collection caps left a coverage axis incomplete. It is read-only and works
143
+ offline; `--require-complete` exits `3` when any axis is incomplete.
144
+
145
+ It also lists advisory cache hygiene hints: a dependency install with no cache,
146
+ and a literal cache key that cannot follow the lockfile. The frozen contract has
147
+ no cache rule id, so hints never become findings or patches.
148
+
149
+
103
150
  ## Releasing
104
151
 
105
152
  Pushing a tag that matches the version in `package.json` triggers
106
153
  `.github/workflows/publish.yml`:
107
154
 
108
155
  ```
109
- git tag v0.1.1
110
- git push origin v0.1.1
156
+ git tag v0.3.1
157
+ git push origin v0.3.1
111
158
  ```
112
159
 
113
160
  The workflow compares the tag with `package.json` (`node
@@ -120,13 +167,14 @@ package's trusted publisher must name `publish.yml` for this repository.
120
167
 
121
168
  - Node `^22.19.0 || >=24.0.0`
122
169
  - `gh` CLI, optional, only for execution history
123
- - DSH `>=0.2.1-rc.2 <0.3.0`, optional, only for the plugin tools
170
+ - DSH `>=0.2.1-rc.2 <0.3.0-0 || >=0.2.2-rc.1 <0.3.0-0`, optional, only for
171
+ the plugin tools
124
172
 
125
173
  ## Development
126
174
 
127
175
  ```
128
176
  bun install
129
- node --test "tests/unit/*.test.ts"
177
+ node scripts/test-core.mjs
130
178
  node scripts/gen-types.mjs --check
131
179
  node scripts/sync-contracts.mjs --check
132
180
  bun run typecheck
@@ -154,10 +202,19 @@ tests/unit fast checks that need no network
154
202
 
155
203
  ## Languages
156
204
 
157
- English is the default and the source of truth for message keys. Korean is
158
- fully translated. Simplified Chinese is a translation slot that falls back to
159
- English until someone maintains it. Public documentation is English, with a
160
- Korean README mirror.
205
+ English is the default and the source of truth for message keys. The CLI, the
206
+ HTML report, and DSH tool text ship in English, Korean, Simplified Chinese,
207
+ Hindi, Spanish, and French; every dictionary is complete, so a missing key is a
208
+ type error. Regional tags resolve by language (`hi-IN`, `es-MX`, `fr-CA`), and
209
+ Chinese variants that are not Simplified fall back to English.
210
+
211
+ Language selection is an explicit `--lang`, then the DSH locale preference,
212
+ then `LC_ALL`/`LC_MESSAGES`/`LANG`, then English. Reports are stored in
213
+ English and translated only when displayed: rule ids, error codes, enum values,
214
+ paths, digests, and numbers stay untranslated, and the HTML report sets its
215
+ `lang` attribute to the selected locale. DSH tool descriptions are captured at
216
+ plugin load, so changing the DSH language preference needs a reload. Public
217
+ documentation is English, with a Korean README mirror.
161
218
 
162
219
  ## Documentation
163
220
 
@@ -0,0 +1,3 @@
1
+ /** DSH Web client half for the CI Diet settings section. */
2
+ declare const plugin: { readonly inject: readonly string[]; apply(ctx: unknown): void };
3
+ export default plugin;