@nolit/dsh-notify 0.0.0-stage → 0.0.1-rc.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 +445 -0
- package/LICENSE +21 -0
- package/PROVENANCE.md +96 -0
- package/README.md +331 -2
- package/cordis.patch.yml +19 -0
- package/docs/2026-10-20-dsh-notify-design.md +335 -0
- package/docs/2026-10-20-final-status.md +125 -0
- package/docs/2026-10-23-asset-policy.md +170 -0
- package/docs/2026-10-23-deployment-strategy-review.md +530 -0
- package/docs/2026-10-23-headless-nonintrusive-ui-architecture.md +579 -0
- package/docs/2026-10-23-hybrid-dual-mode-design.md +955 -0
- package/docs/2026-10-23-timezone-global-report.md +204 -0
- package/docs/2026-10-23-web-notify-plugin-spec.md +454 -0
- package/docs/2026-10-23-web-plugin-mount.md +111 -0
- package/docs/2026-10-23-windows-widget-poc-report.md +312 -0
- package/docs/2026-10-24-linux-desktop-verification.md +134 -0
- package/docs/BOOT-CARD.md +176 -0
- package/docs/RECOVERY-NOTES.md +111 -0
- package/docs/WORK-PROTOCOL.md +155 -0
- package/docs/deepseek-peak-spec.md +370 -0
- package/docs/dsh-harness-notify-spec.md +149 -0
- package/icon.svg +6 -0
- package/lib/client.js +2175 -0
- package/lib/client.src.js +1966 -0
- package/lib/index.js +13 -0
- package/lib/locale-table.js +215 -0
- package/locale/en.json +104 -0
- package/locale/ko.json +104 -0
- package/market/icons/dsh-notify.svg +6 -0
- package/market/index.json +77 -0
- package/package.json +80 -4
- package/scripts/build-client.mjs +41 -0
- package/scripts/gen-locale.mjs +36 -0
- package/test/client.test.mjs +601 -0
- package/test/locale.test.mjs +114 -0
- package/test/manifest.test.mjs +115 -0
- package/test/peak.test.mjs +370 -0
- package/test/typography.test.mjs +85 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
# DSH Notify — 설계 문서
|
|
2
|
+
|
|
3
|
+
<!-- skeleton:
|
|
4
|
+
version: 1.0
|
|
5
|
+
kind: design
|
|
6
|
+
status: historical
|
|
7
|
+
updated: 2026-10-20
|
|
8
|
+
summary: Original DSH Notify design: goal, scope, and the plugin shape chosen before implementation started.
|
|
9
|
+
-->
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
> 상태: active · 최종 갱신: 2026-10-20 · git: main @ milestone-1 · 상위: [BOOT-CARD.md](BOOT-CARD.md)
|
|
13
|
+
|
|
14
|
+
- 작성일: 2026-10-20
|
|
15
|
+
- 상태: 승인됨 (판정 코어 구현 완료, UI 미착수)
|
|
16
|
+
- 프로젝트 루트: `C:\Users\nolit\Workspace\projects\DSH Notify`
|
|
17
|
+
- 첫 기능: DeepSeek 과금 구간 인디케이터
|
|
18
|
+
|
|
19
|
+
## 인덱스
|
|
20
|
+
|
|
21
|
+
| § | 섹션 | 이동 | 한 줄 요약 |
|
|
22
|
+
|---|---|---|---|
|
|
23
|
+
| 1 | 목적 | [§1](#1-목적) | 왜 만드는가, 성공과 안티골 |
|
|
24
|
+
| 2 | 구조 | [§2](#2-구조) | 계층, provider 계약, severity, 갱신 주기 |
|
|
25
|
+
| 3 | UI | [§3](#3-ui) | 인디케이터 창, 트레이, 알림 |
|
|
26
|
+
| 4 | 설정 | [§4](#4-설정) | config.json 기본값 |
|
|
27
|
+
| 5 | 오류 처리 원칙 | [§5](#5-오류-처리-원칙) | 안전 강등 표 |
|
|
28
|
+
| 6 | 파일 구성 | [§6](#6-파일-구성) | 최종 디렉터리 배치 |
|
|
29
|
+
| 7 | 확장 방법 | [§7](#7-확장-방법-미래) | provider 추가 4단계 |
|
|
30
|
+
| 8 | 확인된 기술 사실 | [§8](#8-확인된-기술-사실) | 재확인 불필요 항목 |
|
|
31
|
+
| 9 | 미결 사항 | [§9](#9-미결-사항) | 구현 중 결정 |
|
|
32
|
+
| 10 | 하지 않는 것 | [§10](#10-하지-않는-것) | 범위 밖 명시 |
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 1. 목적
|
|
37
|
+
|
|
38
|
+
DSH(DeepSeek Harness) 작업 중에 알아야 하는 외부 상태가 여러 개 있다. 지금은 그때그때 사람이 확인해야 하고, 확인을 잊으면 비용이나 시간이 낭비된다.
|
|
39
|
+
|
|
40
|
+
`DSH Notify`는 그 상태들을 한 곳에서 상시 보여주는 **로컬 알림 플랫폼**이다.
|
|
41
|
+
|
|
42
|
+
### 왜 지금인가
|
|
43
|
+
|
|
44
|
+
DeepSeek API는 피크 시간에 2배, 그 외 시간에 1배의 요금을 매긴다(오프피크가 피크의 0.5배). 실측 기준 주간 시간의 약 79%가 오프피크인데, 그 사실을 모르면 비용이 큰 작업을 피크에 시작하게 된다. 이 하나만으로도 알림 인프라를 만들 값이 있다고 판단했다.
|
|
45
|
+
|
|
46
|
+
### 성공의 정의
|
|
47
|
+
|
|
48
|
+
- 작업을 시작하기 전에 과금 구간을 확인하는 습관이 생긴다.
|
|
49
|
+
- 알림 소스를 추가할 때 UI를 다시 만들지 않는다.
|
|
50
|
+
|
|
51
|
+
### 안티골: 이렇게 되면 실패다
|
|
52
|
+
|
|
53
|
+
- 인디케이터가 화면을 방해해서 꺼버리게 된다.
|
|
54
|
+
- 알림이 너무 잦아서 무시하게 된다.
|
|
55
|
+
- 판정이 틀려서 잘못된 구간을 알려준다.
|
|
56
|
+
- 프로세스가 죽어도 사용자가 알아채지 못한다.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 2. 구조
|
|
61
|
+
|
|
62
|
+
### 2.1 계층
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
DSH Notify (단일 상주 프로세스)
|
|
66
|
+
│
|
|
67
|
+
├── core.ps1 provider 로딩, 상태 집계, 설정 관리, 단일 인스턴스 보장
|
|
68
|
+
│
|
|
69
|
+
├── providers/ 알림 소스 (각각 독립)
|
|
70
|
+
│ ├── deepseek-peak.ps1 DeepSeek 과금 구간 ◀ 첫 기능
|
|
71
|
+
│ ├── (비어 있음) 세션 길이·토큰 소모
|
|
72
|
+
│ ├── (비어 있음) 백그라운드 작업 완료
|
|
73
|
+
│ └── (비어 있음) 예약 작업 도래
|
|
74
|
+
│
|
|
75
|
+
├── ui/
|
|
76
|
+
│ ├── indicator.ps1 반투명 인디케이터 창
|
|
77
|
+
│ └── tray.ps1 트레이 아이콘 + 풍선 알림
|
|
78
|
+
│
|
|
79
|
+
└── cache/ provider가 쓰는 캐시
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 2.2 Provider 계약
|
|
83
|
+
|
|
84
|
+
모든 provider 스크립트는 **하나의 함수**를 내보낸다.
|
|
85
|
+
|
|
86
|
+
```powershell
|
|
87
|
+
function Get-State {
|
|
88
|
+
param(
|
|
89
|
+
[datetime] $Now, # 로컬 시각 (provider가 필요 시 내부에서 UTC 변환)
|
|
90
|
+
[hashtable] $Config, # config.json 의 providers.<id> 섹션
|
|
91
|
+
[string] $CacheDir # 캐시 디렉터리 절대 경로
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
return [pscustomobject]@{
|
|
95
|
+
Id = 'deepseek-peak' # 고유 식별자
|
|
96
|
+
Label = 'DeepSeek 과금' # 화면 표시명
|
|
97
|
+
Severity = 'warn' # ok | warn | alert
|
|
98
|
+
Headline = 'PEAK · 100%' # 1줄 요약
|
|
99
|
+
Detail = '→ 다음 구간까지 2h 14m'
|
|
100
|
+
NextChangeAt = [datetime] # 다음 상태 변화 시각 (없으면 $null)
|
|
101
|
+
NotifyText = '대량 작업은 50% 구간까지 미루는 것을 검토하세요.'
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 2.3 Severity 체계
|
|
107
|
+
|
|
108
|
+
| severity | 창 색 | 트레이 아이콘 | 풍선 알림 |
|
|
109
|
+
|---|---|---|---|
|
|
110
|
+
| `ok` | 녹색 `#1E7B3C` | 녹색 | 없음 |
|
|
111
|
+
| `warn` | 주황 `#B26A00` | 주황 | 전환 시 1회 |
|
|
112
|
+
| `alert` | 적색 `#B3261E` | 적색 | 전환 시 1회 |
|
|
113
|
+
|
|
114
|
+
여러 provider가 동시에 활성이면 **가장 높은 severity**가 창 색을 결정한다. 나머지는 창을 클릭했을 때 목록으로 보인다.
|
|
115
|
+
|
|
116
|
+
**DeepSeek 첫 기능의 매핑**
|
|
117
|
+
- 피크(100%) → `alert` (적색)
|
|
118
|
+
- 오프피크(50%) → `ok` (녹색)
|
|
119
|
+
- 판정 불가(데이터 없음) → `ok` + detail에 "추정" 표시
|
|
120
|
+
|
|
121
|
+
### 2.4 갱신 주기
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
60초마다: 모든 provider의 Get-State 호출 → 상태 집계 → UI 반영
|
|
125
|
+
캐시 만료 시(기본 240시간 = 10일): 기존 캐시로 즉시 응답 + 백그라운드 갱신
|
|
126
|
+
— 갱신은 스레드 작업 1개, 실패 시 1시간 쿨다운. 미공고 파일(papers: [])은 24시간 TTL
|
|
127
|
+
하루 1회: 접속 지역(공인 IP) 확인 — 표시용. 판정은 UTC 고정이라 영향 없음
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
요일 규칙(평일 UTC 01–04, 06–10)은 고정이므로 매번 계산하고, 변하는 것은 공휴일 데이터뿐이다.
|
|
131
|
+
중국 공휴일 달력은 연간 공고가 11월에 확정되고 연중 임시휴일이 드물게 추가되므로 10일 주기면
|
|
132
|
+
충분하다. 갱신은 타이머가 아니라 "만료 후 첫 호출"에서 시작되며, 폴링을 막지 않는다(lazy + async).
|
|
133
|
+
|
|
134
|
+
기기 시간대는 해외에서도 KST 로 남아 있을 수 있다(노트북은 모바일처럼 자동 변경을 기대하기 어렵다).
|
|
135
|
+
그래서 하루 1회 IP 로 접속 지역 시간대를 확인해 두고, 기기 시간대와 다르면 UI 가 두 시간대를 병기한다.
|
|
136
|
+
IP 는 VPN 으로 바뀔 수 있으므로 표시 힌트로만 쓰고 판정에는 쓰지 않는다(§4.4 in spec).
|
|
137
|
+
|
|
138
|
+
provider가 실패하면 그 provider만 건너뛰고 나머지는 계속 돈다. 전체가 죽지 않는다.
|
|
139
|
+
|
|
140
|
+
**시작 경량화**: 창은 즉시 `00:00:00` 자리 상태로 뜨고, 5초 뒤 백그라운드 스레드에서 공휴일·지역
|
|
141
|
+
동기화를 수행한다. 동기화가 끝나면 값이 채워지고, 이후 60초 폴링으로 이어진다.
|
|
142
|
+
시작·동기화·폴링 오류는 `cache\core.log` 에 남긴다(진단용, git 제외).
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## 3. UI
|
|
147
|
+
|
|
148
|
+
### 3.1 인디케이터 창
|
|
149
|
+
|
|
150
|
+
| 항목 | 값 |
|
|
151
|
+
|---|---|
|
|
152
|
+
| 크기 | 210 × 92 px |
|
|
153
|
+
| 배경 | 짙은 무채색 `#121212`, 알파 0.6, 모서리 10px, 테두리 없음 |
|
|
154
|
+
| 최상위 | 예 |
|
|
155
|
+
| 작업표시줄 | 미표시 |
|
|
156
|
+
| 이동 | 창 전체 드래그 |
|
|
157
|
+
| 위치 저장 | `config.json` |
|
|
158
|
+
|
|
159
|
+
**표시 내용** — 강조는 하나만: digital-7 타이머. 모두 영어, 가운데 정렬.
|
|
160
|
+
```
|
|
161
|
+
┌──────────────────────────────┐
|
|
162
|
+
│ DeepSeek Peak (100%) ← Pretendard 10, CI 블루 #4D6BFE, 중앙
|
|
163
|
+
│ 02:14:30 ← digital-7 46px, 중앙
|
|
164
|
+
│ 본문(HH:MM) 피크 #E5534B / 오프 #4ADE80
|
|
165
|
+
│ 콜론·초(:SS)는 배경색 #2C2C2C (존재감 최소)
|
|
166
|
+
│ Local 18:00–21:00 (UTC-7) ← 기기/현지 불일치일 때만, 9px, 중앙
|
|
167
|
+
└──────────────────────────────┘
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
- 아이콘(점) 없음. 상태는 **제목 문구** + **타이머 색**으로 전달
|
|
171
|
+
- 제목: `DeepSeek Peak (100%)` / `DeepSeek Off-Peak (50% discount)`. 50%는 사용량이 아니라 **피크 대비 가격 할인율**임을 명시한다
|
|
172
|
+
- 타이머는 `HH:MM:SS`. 앞의 `HH:MM` 만 색을 주고 **콜론과 초**는 배경과 같은 회색으로 죽인다
|
|
173
|
+
- 시작 시 동기화(공휴일/지역)를 기다리지 않는다: 카드는 즉시 `00:00:00` 으로 뜨고, 5초 뒤 백그라운드 스레드에서 동기화해 값이 채워진다
|
|
174
|
+
- 타이머 글꼴: `ui\assets\digital-7.ttf` 임베드, `file://…digital-7.ttf#Digital-7` 로드(없으면 Consolas 폴백)
|
|
175
|
+
- digital-7 은 개인용 무료 폰트. 라이선스 원문: `ui\assets\digital-7-license.txt`
|
|
176
|
+
- 제목·현지 줄은 **시스템 설치 Pretendard**(`C:\WINDOWS\FONTS\PRETENDARD-REGULAR.OTF`). 임베드 폰트는 타이머 하나뿐
|
|
177
|
+
- `tests\font.ps1` F4 가 WPF 가 실제로 Pretendard 파일을 해석하는지 확인한다
|
|
178
|
+
- 레이아웃 Grid: 제목 Top, 타이머 Center, 현지 줄 Bottom — 타이머가 카드 정중앙
|
|
179
|
+
- 타이머는 1초마다 재계산하지만 표시는 분 단위, 서버 호출 없음
|
|
180
|
+
|
|
181
|
+
실제 렌더(2배 확대, 어두운 배경 합성):
|
|
182
|
+
|
|
183
|
+
*[이미지: PEAK 카드 — `previews/indicator-alert.png`, 이 저장소에 포함되지 않음]*
|
|
184
|
+
*[이미지: OFF-PEAK 카드 — `previews/indicator-ok.png`, 이 저장소에 포함되지 않음]*
|
|
185
|
+
|
|
186
|
+
- 표시 모델: `ui\presenter.ps1` (순수) / 카드: `ui\indicator.ps1`
|
|
187
|
+
- 창 없이 렌더 검증: `pwsh -Sta -File ui\render-indicator.ps1 -Severity alert -Out out.png`
|
|
188
|
+
|
|
189
|
+
**표시 모드** (`config.displayMode`)
|
|
190
|
+
|
|
191
|
+
| 값 | 동작 |
|
|
192
|
+
|---|---|
|
|
193
|
+
| `always` | 항상 표시, 색만 바뀜 (기본값) |
|
|
194
|
+
| `peakOnly` | `alert` 또는 `warn` 일 때만 창 표시 |
|
|
195
|
+
|
|
196
|
+
### 3.2 트레이
|
|
197
|
+
|
|
198
|
+
- `NotifyIcon` 상주, 아이콘 색도 severity에 맞춰 교체
|
|
199
|
+
- 아이콘 자산: `ui\assets\deepseek-logo-source.png`(워드마크 포함 원본)
|
|
200
|
+
→ `ui\prepare-logo.ps1`(연결요소로 심볼만 크롭 → `ui\assets\deepseek-logo.png` 222px 마스터)
|
|
201
|
+
→ `ui\build-icons.ps1` → `ui\icons\deepseek-{green,red,amber,gray}.ico`
|
|
202
|
+
- 현재 아이콘은 **green(ok) / red(alert) 2종**. provider 가 내는 상태가 둘뿐이라 warn·unknown 자산은 만들지 않는다
|
|
203
|
+
- `warn`(amber `#B26A00`)·`unknown`(gray `#6B7280`) 은 생산자가 생길 때 `ui\icons.ps1` 의 Colors 에 한 줄 추가 후 재생성
|
|
204
|
+
- 16/20/24/32/48/256 멀티 사이즈 PNG-in-ICO. 테스트: `tests\icons.ps1`, `tests\logo-mask.ps1`
|
|
205
|
+
- 워드마크가 섞인 원본에서 심볼만 잘라야 16px 에서 깨끗하다. 크롭은 알파 연결요소 최대값 기준
|
|
206
|
+
- 원본 로고는 DeepSeek 상표다. 로컬 트레이 표시에만 쓰고 배포물에 재배포하지 않는다
|
|
207
|
+
- 우클릭 메뉴: `지금 갱신` / **`알림`(체크)** / **`OLED 보호`(체크)** / `항상 표시`(체크) / `피크일 때만`(체크) / `위치 초기화` / **`카드 보이기`(체크)** / `종료`
|
|
208
|
+
- 체크 표시로 현재 상태를 바로 알 수 있다. `알림` 을 끄면 피크 전환 토스트와 DSH 완료/승인 팝업이 모두 멈춘다(config `notifications`)
|
|
209
|
+
- `OLED 보호` 를 켜면 `oledIntervalSeconds`(기본 60초)마다 카드를 **5px 씩 네 방향으로 순환**시킨다(번인 완화). 저장되는 기준 위치는 그대로 두고 표시 오프셋만 움직인다
|
|
210
|
+
- `카드 보이기` 체크는 실제 창 표시 상태(`IsVisible`)를 반영한다. 끄면 숨김, 켜면 표시
|
|
211
|
+
- 툴팁에 전체 provider 상태 요약
|
|
212
|
+
|
|
213
|
+
### 3.3 알림
|
|
214
|
+
|
|
215
|
+
- severity가 **바뀔 때만** 1회 풍선 알림
|
|
216
|
+
- 같은 severity가 유지되는 동안 재알림 없음
|
|
217
|
+
- 상태 파일(`cache/notify-state.json`)에 마지막 severity 기록
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## 4. 설정
|
|
222
|
+
|
|
223
|
+
`config.json` (프로젝트 루트)
|
|
224
|
+
|
|
225
|
+
```json
|
|
226
|
+
{
|
|
227
|
+
"displayMode": "always",
|
|
228
|
+
"opacity": 0.6,
|
|
229
|
+
"position": { "x": 40, "y": 40 },
|
|
230
|
+
"notifyOnChange": true,
|
|
231
|
+
"notifications": true,
|
|
232
|
+
"oledProtection": false,
|
|
233
|
+
"oledIntervalSeconds": 60,
|
|
234
|
+
"pollSeconds": 60,
|
|
235
|
+
"providers": {
|
|
236
|
+
"deepseek-peak": {
|
|
237
|
+
"enabled": true,
|
|
238
|
+
"treatMakeupAsPeak": true,
|
|
239
|
+
"refreshHours": 240
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
설정 파일이 없으면 기본값으로 생성한다. 잘못된 JSON이면 기본값으로 되돌리고 트레이 툴팁에 경고를 남긴다.
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## 5. 오류 처리 원칙
|
|
250
|
+
|
|
251
|
+
핵심 원칙: **정보가 부족하면 안전한 쪽으로 강등하고, 강등 사실을 숨기지 않는다.**
|
|
252
|
+
|
|
253
|
+
| 상황 | 동작 |
|
|
254
|
+
|---|---|
|
|
255
|
+
| 네트워크 없음 | 캐시 사용 → 캐시도 없으면 주말 규칙만 |
|
|
256
|
+
| 공휴일 JSON 파싱 실패 | 해당 파일 무시, 캐시 사용, 주말 규칙 |
|
|
257
|
+
| 해당 연도 데이터 미공고 | `papers: []` 감지 → 주말 규칙, detail에 "공고 전" 표시 |
|
|
258
|
+
| provider 스크립트 오류 | 해당 provider만 제외, 나머지 계속 |
|
|
259
|
+
| 트레이 아이콘 생성 실패 | 창만으로 동작 계속 |
|
|
260
|
+
| 이미 실행 중 | 뮤텍스로 중복 차단, 기존 인스턴스에 신호 |
|
|
261
|
+
| config 손상 | 기본값 사용 + 경고 표시 |
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## 6. 파일 구성
|
|
266
|
+
|
|
267
|
+
```
|
|
268
|
+
DSH Notify\
|
|
269
|
+
docs\
|
|
270
|
+
2026-10-20-dsh-notify-design.md 이 문서
|
|
271
|
+
deepseek-peak-spec.md 첫 기능 상세
|
|
272
|
+
BOOT-CARD.md 새 창 진입 카드
|
|
273
|
+
providers\
|
|
274
|
+
deepseek-peak.ps1
|
|
275
|
+
_template.ps1 새 provider 작성용 빈 틀
|
|
276
|
+
ui\
|
|
277
|
+
indicator.ps1
|
|
278
|
+
tray.ps1
|
|
279
|
+
cache\ 런타임 생성 (git 제외)
|
|
280
|
+
tests\
|
|
281
|
+
peak-decisions.ps1 판정 단위 테스트
|
|
282
|
+
core.ps1
|
|
283
|
+
config.json 런타임 생성
|
|
284
|
+
start.vbs 콘솔 없이 실행
|
|
285
|
+
README.md
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## 7. 확장 방법 (미래)
|
|
291
|
+
|
|
292
|
+
새 provider를 추가하는 절차:
|
|
293
|
+
|
|
294
|
+
1. `providers/_template.ps1`를 복사해 이름 변경
|
|
295
|
+
2. `Get-State` 구현
|
|
296
|
+
3. `config.json`의 `providers.<id>`에 `enabled: true` 추가
|
|
297
|
+
4. UI는 손대지 않음
|
|
298
|
+
|
|
299
|
+
이 절차가 4단계를 넘으면 구조가 잘못된 것이므로 계획을 다시 세운다.
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## 8. 확인된 기술 사실
|
|
304
|
+
|
|
305
|
+
조사 시점(2026-10-20) 기준 실제 확인한 것:
|
|
306
|
+
|
|
307
|
+
- PowerShell 7.6.7
|
|
308
|
+
- `System.Windows.Forms` 로드 성공
|
|
309
|
+
- `PresentationFramework` (WPF) 로드 성공
|
|
310
|
+
- `schtasks.exe` 존재
|
|
311
|
+
- 프로젝트 디렉터리는 원래 비어 있었음
|
|
312
|
+
|
|
313
|
+
이 사실들은 구현 시 전제로 삼는다. 재확인이 필요한 항목은 아니다.
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## 9. 미결 사항
|
|
318
|
+
|
|
319
|
+
구현 단계에서 결정할 것:
|
|
320
|
+
|
|
321
|
+
| 항목 | 선택지 | 결정 시점 |
|
|
322
|
+
|---|---|---|
|
|
323
|
+
| 자동 시작 등록 | `HKCU\...\Run` 등록 여부 | 구현 후 사용자 확인 |
|
|
324
|
+
| 대체근무일 해석 | 피크로 볼지 오프피크로 볼지 | 설정 플래그로 양쪽 지원 |
|
|
325
|
+
| 향후 provider 우선순위 | 세션/작업/예약 중 무엇 먼저 | 첫 기능 검증 후 |
|
|
326
|
+
| DSH 플러그인 초안 처리 | `C:\Users\nolit\deepseek-peak-dsh` 삭제 여부 | 구현 후 |
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## 10. 하지 않는 것
|
|
331
|
+
|
|
332
|
+
- **DSH 프로필 변경** — 이 플랫폼은 DSH 외부에서 독립 동작한다
|
|
333
|
+
- **하네스 실행 감지** — GUI 앱의 실행 시점을 외부에서 안정적으로 잡기 어렵다. 대신 구간 전환 알림으로 같은 목적을 달성한다
|
|
334
|
+
- **요금 조작** — 불가능하며 시도하지 않는다
|
|
335
|
+
- **클라우드 동기화** — 로컬 전용. 설정은 파일로 관리한다
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# DSH Notify — 최종 상태와 알려진 문제
|
|
2
|
+
|
|
3
|
+
<!-- skeleton:
|
|
4
|
+
version: 1.0
|
|
5
|
+
kind: report
|
|
6
|
+
status: historical
|
|
7
|
+
updated: 2026-10-20
|
|
8
|
+
summary: Final state of the first DSH Notify round and the known problems left open at that point.
|
|
9
|
+
-->
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
> 상태: final · 최종 갱신: 2026-10-20 · git: main @ milestone-3 · 상위: [WORK-PROTOCOL.md](WORK-PROTOCOL.md)
|
|
13
|
+
|
|
14
|
+
이 문서는 "지금 이 버전을 그대로 두고 멈춘다"는 결정에 따라, 현재 동작·구조·한계를 한곳에 정리한 마감 문서다.
|
|
15
|
+
|
|
16
|
+
## 인덱스
|
|
17
|
+
|
|
18
|
+
| § | 섹션 | 한 줄 요약 |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| 1 | 현재 버전 | 마지막 커밋·태그·실행 방법 |
|
|
21
|
+
| 2 | 동작하는 기능 | 카드·트레이·DSH 팝업·동기화 |
|
|
22
|
+
| 3 | 구조 | 파일 맵과 이벤트 경로 |
|
|
23
|
+
| 4 | 설정 | config.json 키 |
|
|
24
|
+
| 5 | **알려진 문제** | 반드시 읽을 것 — 소리/토스트/SAC |
|
|
25
|
+
| 6 | 진단 로그 | core.log·bridge.log·popup 로그 |
|
|
26
|
+
| 7 | 테스트 | 실행 명령과 현재 결과 |
|
|
27
|
+
| 8 | 다음 후보 (미착수) | 클라이언트 오디오 등 |
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 1. 현재 버전
|
|
32
|
+
|
|
33
|
+
| 항목 | 값 |
|
|
34
|
+
|---|---|
|
|
35
|
+
| 브랜치 | `main` |
|
|
36
|
+
| 태그 | `milestone-3` (문서·팝업 마감) |
|
|
37
|
+
| 실행 | 시작 메뉴 `DSH Notify` 바로가기 또는 `pwsh -NoProfile -File start.ps1` |
|
|
38
|
+
| 종료 | 트레이 고래 아이콘 우클릭 → `종료` |
|
|
39
|
+
| 요구 | PowerShell 7, Windows 10/11, DSH 프로필에 브리지 플러그인 등록됨 |
|
|
40
|
+
|
|
41
|
+
## 2. 동작하는 기능
|
|
42
|
+
|
|
43
|
+
- **피크/오프피크 카드**: 제목 `DeepSeek Peak (100%)` / `DeepSeek Off-Peak (50% discount)`. digital-7 타이머 `HH:MM:SS`, 초와 콜론은 배경색(`#2C2C2C`), 본문 색 피크 `#E5534B` / 오프피크 `#4ADE80`, 제목 CI 블루, 투명도 0.6
|
|
44
|
+
- **트레이 메뉴**: 지금 갱신 / 알림(체크) / OLED 보호(체크) / 항상 표시(체크) / 피크일 때만 / 위치 초기화 / 카드 보이기(체크) / 종료
|
|
45
|
+
- **OLED 보호**: 켜면 `oledIntervalSeconds`(기본 60초)마다 카드를 5px씩 네 방향 순환. 저장 기준 위치는 유지
|
|
46
|
+
- **시작 경량화**: 창은 즉시 `00:00:00` 으로 뜨고 5초 뒤 백그라운드 스레드에서 공휴일·지역 동기화
|
|
47
|
+
- **DSH 완료/승인 팝업**: 브리지가 `cache\popup-request.json` 을 남기면 코어가 팝업 표시 (소리 없음)
|
|
48
|
+
- **서브에이전트 완료 필터**: 완료 알림은 루트 세션만. 승인/질문은 서브에이전트 것도 알림
|
|
49
|
+
- **알림 전체 스위치**: 트레이 `알림` 체크 = `config.notifications`. 코어 전환 토스트와 DSH 팝업을 함께 끔
|
|
50
|
+
|
|
51
|
+
## 3. 구조
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
DSH host plugin bridge\index.js (@local/dsh-notify-bridge)
|
|
55
|
+
├─ 턴 완료/승인/질문/오류 이벤트 구독 ({global:true})
|
|
56
|
+
└─ cache\popup-request.json 기록
|
|
57
|
+
↓ (1초 tick 폴링)
|
|
58
|
+
core.ps1 (상주 WPF) ── 카드·트레이·팝업
|
|
59
|
+
├─ providers\deepseek-peak.ps1 판정·공휴일 캐시
|
|
60
|
+
├─ ui\presenter.ps1 표시 모델
|
|
61
|
+
├─ ui\indicator.ps1 카드
|
|
62
|
+
├─ ui\tray.ps1 트레이
|
|
63
|
+
└─ ui\popup.ps1 우하단 팝업
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
- 포트·웹서버·데몬 없음. 파일 큐 + 프로세스 내부 타이머만 사용
|
|
67
|
+
- DSH 프로필 등록: `~\.dsh\profiles\desktop\node_modules\@local\dsh-notify-bridge` junction + `cordis.patch.yml` 의 insert 엔트리 (백업 `cordis.patch.yml.bak`)
|
|
68
|
+
- 브리지는 로더 핫 리로드로 재시작 없이 반영된다. 적용 증거: `cache\bridge.log` 의 `bridge x.y.z applied: ...`
|
|
69
|
+
|
|
70
|
+
## 4. 설정
|
|
71
|
+
|
|
72
|
+
`config.json` (프로젝트 루트). 트레이 메뉴가 일부 값을 직접 바꾼다.
|
|
73
|
+
|
|
74
|
+
| 키 | 기본 | 의미 |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| `displayMode` | `always` | `peakOnly` 면 피크일 때만 카드 |
|
|
77
|
+
| `opacity` | 0.6 | 카드 불투명도 (0.2–1.0) |
|
|
78
|
+
| `position` | 저장값 | 카드 기준 위치 (OLED 오프셋 제외) |
|
|
79
|
+
| `notifyOnChange` | true | 구간 전환 시 토스트 1회 |
|
|
80
|
+
| `notifications` | true | 전체 알림 스위치 |
|
|
81
|
+
| `oledProtection` | false | OLED 번인 완화 이동 |
|
|
82
|
+
| `oledIntervalSeconds` | 60 | 이동 간격(최소 5초) |
|
|
83
|
+
| `pollSeconds` | 60 | provider 폴링 주기 |
|
|
84
|
+
| `providers.deepseek-peak` | enabled/treatMakeupAsPeak/refreshHours(240) | 공휴일·판정 옵션 |
|
|
85
|
+
|
|
86
|
+
## 5. 알려진 문제
|
|
87
|
+
|
|
88
|
+
| 심각도 | 문제 | 원인/현상 | 현재 대응 |
|
|
89
|
+
|---|---|---|---|
|
|
90
|
+
| **높음** | **DSH 팝업 소리 없음** | 이 PC에서 WinMM(`SoundPlayer`/`PlaySound`)은 스피커 앰프까지 도달하지 않고 "뽁"만 났다(피크 0 실측). 5.1 WinRT MediaPlayer 자식도 무음, 미디어 플레이어 경유는 창이 떠서 UX 훼손 | **소리 제거 결정**. 팝업만 표시 |
|
|
91
|
+
| **높음** | 윈도 토스트 배너 미표시 | PushNotification 로그에는 `delivered` 로 찍히지만 배너가 억제됨(집중 지원/알림 설정). 앱은 표시 여부를 알 수 없음 | 토스트는 수동 확인용(`notify\send-toast.ps1`). 정식 알림은 자체 팝업 |
|
|
92
|
+
| **높음** | `DSH-Notify.exe` 실행 차단 | Smart App Control 이 서명 없는 exe 차단 (CodeIntegrity 3073/3077) | 시작 메뉴 바로가기/스크립트 사용. exe 는 서명·SAC 해제 환경용 |
|
|
93
|
+
| 중간 | 완료 팝업은 코어 상주가 전제 | 코어가 꺼져 있으면 요청 파일이 소비되지 않고 남음 | 트레이 앱 실행 상태 유지. 다음 실행 시 첫 tick 에서 소비됨 |
|
|
94
|
+
| 중간 | 로그 무한 증가 | `cache\core.log`, `cache\bridge.log` 로테이션 없음 | 수동 삭제. 필요 시 로테이션 추가 |
|
|
95
|
+
| 낮음 | OLED 이동폭 고정 | 5px 4방향만 지원 | `ui\popup`/`core.ps1` 상수 수정 |
|
|
96
|
+
| 낮음 | digital-7 폰트 라이선스 | 개인용 무료 | 배포 금지. 로컬 사용만 |
|
|
97
|
+
| 낮음 | WMP 11 설치해도 WPF MediaPlayer 실패 | 새 Store 앱은 레거시 WMP 구성 요소가 아님 | 사용 안 함 (소리 제거) |
|
|
98
|
+
|
|
99
|
+
## 6. 진단 로그
|
|
100
|
+
|
|
101
|
+
| 파일 | 내용 |
|
|
102
|
+
|---|---|
|
|
103
|
+
| `cache\core.log` | 시작·동기화·UI 반영·팝업 소비·디스패처 예외 |
|
|
104
|
+
| `cache\bridge.log` | 플러그인 적용 버전, 수신 이벤트, 완료 판정 |
|
|
105
|
+
| `cache\popup-sound.log` | 과거 음향 실험 기록(현재 미사용) |
|
|
106
|
+
| `cache\region.json` / `cache\deepseek-peak\holidays.json` | 지역·공휴일 캐시 |
|
|
107
|
+
| `cache\audio-policy-backup.reg` | 실험 중 삭제한 PowerShell 앱 오디오 라우팅 백업 |
|
|
108
|
+
|
|
109
|
+
## 7. 테스트
|
|
110
|
+
|
|
111
|
+
```powershell
|
|
112
|
+
pwsh -NoProfile -File tests\run-all.ps1 # 19 files
|
|
113
|
+
pwsh -NoProfile -File tests\docs-contract.ps1 # 헤더/인덱스 검사
|
|
114
|
+
node .\bridge\test.mjs # 브리지 단위 테스트
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
마지막 결과: **19 files, 19 passed / 0 failed**, docs-contract 47 files PASS.
|
|
118
|
+
|
|
119
|
+
## 8. 다음 후보 (미착수)
|
|
120
|
+
|
|
121
|
+
- **클라이언트(브라우저) 오디오**: DSH 웹 GUI에서 `<audio>` 로 재생. spawn 프로세스 오디오 문제를 우회하는 유일한 검증된 경로
|
|
122
|
+
- 토스트 AUMID 브랜딩(시작 메뉴 AUMID 등록) — 배너 억제 문제와는 별개
|
|
123
|
+
- 코드 서명으로 SAC 통과
|
|
124
|
+
- 로그 로테이션, OLED 이동폭/패턴 설정화
|
|
125
|
+
- 자동 시작 토글
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# 에셋·상표 라이선스 정책 — BYO(Bring Your Own) 방식
|
|
2
|
+
|
|
3
|
+
<!-- skeleton:
|
|
4
|
+
version: 1.0
|
|
5
|
+
kind: policy
|
|
6
|
+
status: reference
|
|
7
|
+
updated: 2026-10-23
|
|
8
|
+
summary: Asset and trademark licence policy: bring-your-own assets, what may ship, and what must never be redistributed.
|
|
9
|
+
-->
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
> 상태: active · 최종 갱신: 2026-10-23 · git: main @ 8129b54 · 상위: [README.md](../README.md)
|
|
13
|
+
|
|
14
|
+
- 목적: 오픈소스 재배포 시 폰트·로고·사운드 라이선스 분쟁을 원천 차단한다.
|
|
15
|
+
- 원칙: **패키지는 에셋을 배포하지 않는다.** 사용자가 직접 주입한 에셋만 로컬에서 사용한다.
|
|
16
|
+
- 적용 대상: `@nolit/dsh-notify`(웹 플러그인), 윈도우 오프피크 위젯(포터블 패키지).
|
|
17
|
+
- 코드 라이선스: MIT ([LICENSE](../LICENSE)).
|
|
18
|
+
|
|
19
|
+
## 인덱스
|
|
20
|
+
|
|
21
|
+
| § | 섹션 | 한 줄 요약 |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| 1 | 기본 원칙 | 기본은 시스템 폰트/중립 아이콘/합성음, 에셋 번들 없음 |
|
|
24
|
+
| 2 | 폰트 | 시스템 폰트 기본, `fonts/digital-7.ttf` 사용자 주입 시 우선 |
|
|
25
|
+
| 3 | 아이콘·상표 | DeepSeek 로고 제외, 중립 시계 아이콘, `icons/custom.ico` 지원 |
|
|
26
|
+
| 4 | 사운드 | `ding.wav` 제거, Web Audio 합성/시스템 소리 |
|
|
27
|
+
| 5 | 라이선스·면책 | MIT + 사용자 주입 에셋 책임은 사용자 |
|
|
28
|
+
| 6 | 패키징 검사 | 배포물에 금지 에셋이 없어야 함 |
|
|
29
|
+
| 7 | 사용자 안내 | 다운로드/배치/적용/제거 방법 |
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 1. 기본 원칙
|
|
34
|
+
|
|
35
|
+
1. **기본값은 라이선스가 명확한 시스템 자산**을 쓴다.
|
|
36
|
+
2. ** Digital-7, DeepSeek 로고, `ding.wav`는 저장소/배포물에서 제외**한다. 로컬 개발 편의를 위해 남아 있더라도 공개 아티팩트에는 포함하지 않는다.
|
|
37
|
+
3. 사용자 주입 에셋은 앱이 **감지하면 우선 적용**하고, 없으면 기본값으로 조용히 폴백한다.
|
|
38
|
+
4. 사용자 주입 에셋의 라이선스/재배포 권리는 **사용자 책임**이며, 프로젝트는 이를 배포하지 않는다.
|
|
39
|
+
5. 기본 아이콘/코드 외에 제3자 에셋을 포함할 경우 `THIRD-PARTY-NOTICES.md`에 출처/라이선스를 기록한다.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 2. 폰트
|
|
44
|
+
|
|
45
|
+
### 2.1 기본값
|
|
46
|
+
|
|
47
|
+
- 타이머: `Consolas, "Cascadia Mono", "Segoe UI", monospace` 순서의 시스템 폰트.
|
|
48
|
+
- 일반 UI: `"Segoe UI", system-ui, sans-serif`.
|
|
49
|
+
- 별도 TTF/OTF를 패키지에 넣지 않는다. OS 기본 폰트로 렌더링한다.
|
|
50
|
+
|
|
51
|
+
### 2.2 사용자 주입(BYO)
|
|
52
|
+
|
|
53
|
+
- 경로: `<widget-data>\fonts\digital-7.ttf` (권장) 또는 `fonts\*.ttf`.
|
|
54
|
+
- 앱은 시작 시 `fonts\digital-7.ttf` 존재 여부를 확인하고, 로드에 성공하면 타이머 폰트로 우선 사용한다.
|
|
55
|
+
- 파일이 없거나 로드에 실패하면 시스템 폰트로 폴백한다. 오류를 띄우지 않는다.
|
|
56
|
+
- README에는 폰트 배포 페이지 링크만 안내한다. 패키지에 폰트 파일을 포함하지 않는다.
|
|
57
|
+
- Digital-7 제작사: <https://www.styleseven.com/>
|
|
58
|
+
- 사용자는 다운로드한 폰트의 라이선스를 직접 확인해야 한다. Digital-7은 제작사 EULA상 가정용/프리웨어 조건이므로, 상업적 사용자는 별도 라이선스를 구매해야 한다.
|
|
59
|
+
|
|
60
|
+
### 2.3 웹 플러그인
|
|
61
|
+
|
|
62
|
+
- 웹 플러그인은 폰트를 번들하지 않으며, DSH/브라우저의 시스템 폰트를 그대로 쓴다.
|
|
63
|
+
- 웹 알림에는 커스텀 폰트를 적용하지 않는다.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 3. 아이콘·상표
|
|
68
|
+
|
|
69
|
+
### 3.1 기본 아이콘
|
|
70
|
+
|
|
71
|
+
- 웹 플러그인: `plugin/icon.svg` — 자체 제작한 중립 알람시계 SVG(MIT).
|
|
72
|
+
- 윈도우 위젯: 동일 계열의 중립 시계/타이머 `.ico`. 기본 배포물에 DeepSeek 로고를 넣지 않는다.
|
|
73
|
+
- 트레이/창 아이콘은 중립 아이콘을 기본으로 하고, 사용자가 교체할 수 있다.
|
|
74
|
+
|
|
75
|
+
### 3.2 DeepSeek 로고
|
|
76
|
+
|
|
77
|
+
- DeepSeek 공식 로고/워드마크/브랜드 자산은 **배포 패키지에서 완전히 제외**한다.
|
|
78
|
+
- 저장소에 남아 있는 로컬 개발용 로고 파일은 공개 아티팩트 빌드에서 제외한다.
|
|
79
|
+
- 사용자가 로컬에서 직접 넣는 경우에도 상표 사용 권한은 사용자 책임이다.
|
|
80
|
+
|
|
81
|
+
### 3.3 사용자 커스텀 아이콘
|
|
82
|
+
|
|
83
|
+
- 경로: `<widget-data>\icons\custom.ico` (트레이/앱 아이콘), 선택적으로 `icons\custom.png`.
|
|
84
|
+
- 앱은 `custom.ico`가 있으면 우선 사용하고, 없으면 중립 기본 아이콘을 쓴다.
|
|
85
|
+
- 잘못된 ICO/크기 불일치는 무시하고 기본 아이콘으로 폴백한다.
|
|
86
|
+
- 웹 플러그인은 알림 아이콘을 지정하지 않는다(브라우저 기본 표시). 커스텀 아이콘 주입은 위젯 전용이다.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 4. 사운드
|
|
91
|
+
|
|
92
|
+
### 4.1 웹 플러그인
|
|
93
|
+
|
|
94
|
+
- `ding.wav`를 번들하지 않는다.
|
|
95
|
+
- Web Audio API로 짧은 2음 차임을 합성한다(예: 880Hz/1175Hz, 120ms).
|
|
96
|
+
- 사용자 제스처 전에는 `AudioContext`가 잠겨 있을 수 있으며, 패널의 “소리 켜기”로 활성화한다.
|
|
97
|
+
|
|
98
|
+
### 4.2 윈도우 위젯
|
|
99
|
+
|
|
100
|
+
- `notify/ding.wav`를 배포물에서 제거한다.
|
|
101
|
+
- 시스템 기본 알림음(`[System.Media.SystemSounds]::Asterisk` 등) 또는 무음 정책을 사용한다.
|
|
102
|
+
- 별도 오디오 파일을 패키지에 넣지 않는다.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 5. 라이선스·면책
|
|
107
|
+
|
|
108
|
+
- 코드는 MIT 라이선스다. [LICENSE](../LICENSE) 참조.
|
|
109
|
+
- **사용자 주입 에셋 면책:** 사용자가 `fonts/`, `icons/`, 사운드 등으로 주입한 제3자 자산의 저작권/상표권/라이선스 준수 책임은 전적으로 사용자에게 있다. 프로젝트 저자와 기여자는 이에 대해 책임지지 않는다.
|
|
110
|
+
- 프로젝트는 사용자 주입 에셋을 수집·배포·호스팅하지 않는다.
|
|
111
|
+
- 소프트웨어는 “있는 그대로(AS IS)” 제공되며, 상품성/특정 목적 적합성/비침해에 대한 보증을 하지 않는다.
|
|
112
|
+
- 기본 패키지에 포함된 자체 제작 아이콘/SVG는 MIT로 배포한다.
|
|
113
|
+
- 향후 OFL 폰트를 기본 포함할 경우, 해당 폰트의 OFL 고지와 저작권을 `THIRD-PARTY-NOTICES.md`에 포함한다.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 6. 패키징 검사
|
|
118
|
+
|
|
119
|
+
공개 아티팩트(`npm pack`, 위젯 zip)에 다음이 없어야 한다.
|
|
120
|
+
|
|
121
|
+
- [ ] `digital-7.ttf`, 기타 Digital-7 폰트 파일
|
|
122
|
+
- [ ] `deepseek-logo*.png`, `deepseek-*.ico` 등 DeepSeek 브랜드 자산
|
|
123
|
+
- [ ] `ding.wav`, 기타 출처 불명 오디오 파일
|
|
124
|
+
- [ ] `DSH-Notify.exe`, `start.vbs` (SAC/VBScript 문제)
|
|
125
|
+
- [ ] 사용자 `config.json`, 로그, 캐시, 개인 경로
|
|
126
|
+
|
|
127
|
+
검사 예:
|
|
128
|
+
|
|
129
|
+
```powershell
|
|
130
|
+
# 저장소에서 금지 에셋이 있는지 확인
|
|
131
|
+
Get-ChildItem -Recurse -File |
|
|
132
|
+
Where-Object { $_.Name -match 'digital-7|deepseek-logo|ding\.wav|DSH-Notify\.exe|start\.vbs' } |
|
|
133
|
+
Select-Object FullName
|
|
134
|
+
|
|
135
|
+
# npm 패키지 내용 확인
|
|
136
|
+
npm pack --dry-run --json
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
> 로컬 개발용 `ui/assets`에 기존 에셋이 남아 있을 수 있다. 이는 공개 빌드 입력에서 제외하며, 위젯 패키징 단계에서 정리한다.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## 7. 사용자 안내(README용)
|
|
144
|
+
|
|
145
|
+
### 폰트
|
|
146
|
+
|
|
147
|
+
1. <https://www.styleseven.com/>에서 Digital-7 폰트를 내려받는다.
|
|
148
|
+
2. 앱 데이터 폴더에 `fonts\digital-7.ttf`로 저장한다.
|
|
149
|
+
3. 앱을 재시작하면 타이머에 적용된다. 파일이 없으면 Consolas/Segoe UI로 표시된다.
|
|
150
|
+
4. 폰트 라이선스는 사용자가 직접 확인한다.
|
|
151
|
+
|
|
152
|
+
### 아이콘
|
|
153
|
+
|
|
154
|
+
1. 사용할 `.ico` 파일을 준비한다.
|
|
155
|
+
2. 앱 데이터 폴더에 `icons\custom.ico`로 저장한다.
|
|
156
|
+
3. 앱을 재시작하면 트레이/창 아이콘에 적용된다.
|
|
157
|
+
4. 없으면 중립 기본 아이콘이 사용된다.
|
|
158
|
+
|
|
159
|
+
### 사운드
|
|
160
|
+
|
|
161
|
+
- 웹 플러그인: 패널에서 “소리 켜기” 후 Web Audio 차임 사용.
|
|
162
|
+
- 윈도우 위젯: 시스템 기본 알림음 사용. 별도 파일 없음.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## 8. 관련 문서
|
|
167
|
+
|
|
168
|
+
- 웹 플러그인 사양: [2026-10-23-web-notify-plugin-spec.md](2026-10-23-web-notify-plugin-spec.md)
|
|
169
|
+
- 배포 전략 검증: [2026-10-23-deployment-strategy-review.md](2026-10-23-deployment-strategy-review.md)
|
|
170
|
+
- 코드 라이선스: [LICENSE](../LICENSE)
|