@kaydash9999/banker-plugins 0.17.1 → 0.19.0

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 (38) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +72 -0
  4. package/README.md +26 -8
  5. package/codex/manifest.json +3 -1
  6. package/codex/transform-matrix.md +5 -2
  7. package/commands/front-qa.md +3 -3
  8. package/hooks/graceful-pause.mjs +4 -2
  9. package/hooks/obsidize-hook.mjs +38 -28
  10. package/hooks/progress-plan.mjs +14 -8
  11. package/hooks/progress.mjs +174 -47
  12. package/hooks/register.mjs +14 -7
  13. package/hooks/update-checkin.mjs +29 -27
  14. package/package.json +1 -1
  15. package/skills/3d-intro-build/SKILL.md +1 -1
  16. package/skills/3d-intro-build/references/assemble.mjs +3 -3
  17. package/skills/3d-intro-setup/SKILL.md +3 -3
  18. package/skills/anti-drm/SKILL.md +254 -0
  19. package/skills/anti-drm/scripts/anti-drm.mjs +643 -0
  20. package/skills/anti-drm/scripts/instruction-toggle.mjs +733 -0
  21. package/skills/lineage/SKILL.md +3 -3
  22. package/skills/lineage/lineage.py +43 -7
  23. package/skills/omc-patch/SKILL.md +18 -6
  24. package/skills/omc-patch/scripts/omc-patch.mjs +400 -87
  25. package/skills/omc-reference/SKILL.md +1 -1
  26. package/skills/ralph-qa/SKILL.md +19 -19
  27. package/skills/theme-selection/SKILL.md +165 -0
  28. package/skills/theme-selection/assets/LICENSE +21 -0
  29. package/skills/theme-selection/assets/NOTICE.md +30 -0
  30. package/skills/theme-selection/assets/palettes.json +81 -0
  31. package/skills/theme-selection/references/contrast.md +138 -0
  32. package/skills/theme-selection/references/integrate.md +161 -0
  33. package/skills/theme-selection/scripts/themes.mjs +1067 -0
  34. package/skills/tone-compact/SKILL.md +8 -4
  35. package/skills/tone-compact/scripts/instruction-toggle.mjs +733 -0
  36. package/skills/tone-compact/scripts/tone-compact.mjs +48 -397
  37. package/skills/ultra-chain/SKILL.md +7 -6
  38. package/skills/update-banker/SKILL.md +1 -1
@@ -2,7 +2,7 @@
2
2
  name: lineage
3
3
  description: "현재 세션 대화를 카카오톡 스타일의 단일 HTML 로 내보냄. Claude 답변은 한 줄 요약 아래에 원문을 접어 두고, 펼치면 마크다운으로 렌더해 보여 줌. 기본은 세션 모델이 요약을 쓰고 노이즈 턴을 걸러 내며, `--rulebase` 는 모델 없이 규칙만 씀. 여러 세션을 합칠 수 있음. 'lineage'/'대화 export'/'카톡 스타일 html' 시 사용."
4
4
  invocation: /lineage
5
- version: 3.0.2
5
+ version: 3.0.5
6
6
  schema_version: 1
7
7
  ---
8
8
 
@@ -212,7 +212,7 @@ Schema-tolerant 파서: 미지 record type → stderr WARN + 다음 line. `v1`/`
212
212
 
213
213
  기본 흐름에서는 검토자 요약이 우선이고, 검토자가 `null` 로 둔 턴만 아래 규칙 요약을 쓴다. `--rulebase` 는 규칙 요약만 쓴다.
214
214
 
215
- - 캐시 hit(`~/.cache/lineage/<schema>/<sid>/<uuid>-<digest>.txt`) → 그대로. digest 는 본문+요약기버전
215
+ - 캐시 hit(`~/.cache/lineage/<schema>/<sid>/<uuid>-<digest>.md`, 3.0.2 까지 쓴 `.txt` 도 읽음) → 그대로. digest 는 본문+요약기버전
216
216
  해시라 **요약기를 고치면 자동 무효화**된다.
217
217
  - miss → head+tail 추출(도입이 순수 의도문이면 결론절을 끝에서 읽어 승격) + 0600 캐시 쓰기.
218
218
  - 요약 저장은 항상 **redact 적용 후**(평문 secret 이 디스크에 남지 않음).
@@ -344,7 +344,7 @@ pip install 'detect-secrets>=1.5' # (선택) 강한 redaction
344
344
 
345
345
  ~/.cache/lineage/
346
346
  ├── stdin-id.key (stdin 턴 id 의 HMAC 키, 0600. --purge-cache 로 지우면 stdin id 가 바뀐다)
347
- └── <schema_version>/<session_id>/<turn_uuid>-<digest>.txt (규칙 요약, 0700/0600)
347
+ └── <schema_version>/<session_id>/<turn_uuid>-<digest>.md (규칙 요약, 0700/0600)
348
348
  <turn_uuid>-<digest>-llm.json (검토자 결정)
349
349
 
350
350
  work/.lineage-review.json, .lineage-review.part-K.json (검토 중에만, 0600)
@@ -20,6 +20,7 @@ import pathlib
20
20
  import re
21
21
  import sys
22
22
  import tempfile
23
+ import unicodedata
23
24
  from html.parser import HTMLParser
24
25
 
25
26
  if sys.version_info < (3, 7):
@@ -189,7 +190,7 @@ def redact(text: str, extra: "str | None" = None, mode: str = "full"):
189
190
  from detect_secrets import SecretsCollection
190
191
  from detect_secrets.settings import default_settings
191
192
  import tempfile
192
- with tempfile.NamedTemporaryFile("w", suffix=".txt", delete=False,
193
+ with tempfile.NamedTemporaryFile("w", suffix=".md", delete=False,
193
194
  encoding="utf-8") as tf:
194
195
  tf.write(out)
195
196
  tmp = tf.name
@@ -734,6 +735,43 @@ def _page_clean_turn(t, extra, mode):
734
735
  return dict(t, text=clean(t["text"]), parts=[clean(p) for p in t.get("parts") or []])
735
736
 
736
737
 
738
+ # Letters that print as nothing: the Hangul fillers, the braille blank, and the combining marks Unicode ignores by
739
+ # default (the grapheme joiner, the Khmer inherent vowels, the Mongolian free variation selectors). With the control,
740
+ # format, private-use, unassigned and separator categories, a cache made only of them holds no summary a person can
741
+ # read (3.0.5).
742
+ _BLANK_LETTERS = frozenset(map(chr, (0x115F, 0x1160, 0x3164, 0xFFA0, 0x2800,
743
+ 0x034F, 0x17B4, 0x17B5, 0x180B, 0x180C, 0x180D, 0x180F)))
744
+ _BLANK_CATEGORIES = frozenset(("Cc", "Cf", "Co", "Cn", "Zs", "Zl", "Zp"))
745
+
746
+
747
+ def _blank(ch):
748
+ """Whether ch prints as nothing: whitespace, a blank-looking letter, or a variation selector."""
749
+ if ch.isspace() or ch in _BLANK_LETTERS or unicodedata.category(ch) in _BLANK_CATEGORIES:
750
+ return True
751
+ o = ord(ch)
752
+ return 0xFE00 <= o <= 0xFE0F or 0xE0100 <= o <= 0xE01EF
753
+
754
+
755
+ def _has_visible(text):
756
+ """Whether text holds a letter a person can see."""
757
+ return not all(_blank(ch) for ch in text)
758
+
759
+
760
+ def _read_cached(p):
761
+ """The summary cached at p, else at the same name with .txt, which 3.0.2 and earlier wrote.
762
+ None when neither holds one: missing, bytes that are not UTF-8 (a DRM encrypted them), or
763
+ nothing a person can see (a write that stopped early, or only blank-looking letters); the
764
+ turn is then summarized again (3.0.4, 3.0.5)."""
765
+ for cached in (p, p.with_name(p.stem + ".txt")):
766
+ try:
767
+ text = cached.read_text(encoding="utf-8").strip()
768
+ except (OSError, UnicodeDecodeError):
769
+ continue
770
+ if _has_visible(text):
771
+ return text
772
+ return None
773
+
774
+
737
775
  def read_or_summarize(turn: dict, session_id: str, rebuild: bool = False,
738
776
  redact_extra=None, redact_mode: str = "full"):
739
777
  """Return (summary, cache_hit). Cache key includes the content hash AND the
@@ -745,15 +783,13 @@ def read_or_summarize(turn: dict, session_id: str, rebuild: bool = False,
745
783
  ).hexdigest()[:8]
746
784
  try: # ids come from the transcript: keep them in the cache
747
785
  p = (cache_dir(_safe_name(turn.get("session") or session_id))
748
- / f"{_safe_name(turn['uuid'])}-{digest}.txt")
786
+ / f"{_safe_name(turn['uuid'])}-{digest}.md")
749
787
  except OSError as e: # no writable cache: summarize anyway
750
788
  _warn_once("_no_cache", f"cache unavailable ({e}); summaries are not cached")
751
789
  p = None
752
- if p is not None and p.exists() and not rebuild:
753
- try:
754
- return p.read_text(encoding="utf-8").strip(), True
755
- except (OSError, UnicodeDecodeError):
756
- pass
790
+ cached = None if p is None or rebuild else _read_cached(p)
791
+ if cached is not None:
792
+ return cached, True
757
793
  redacted = summarize_turn(_page_clean_turn(turn, redact_extra, redact_mode))
758
794
  if p is not None:
759
795
  try:
@@ -41,11 +41,11 @@ OMC(oh-my-claudecode)가 새 버전으로 자동 업데이트되면 로컬 훅
41
41
  - `--root` 는 폴더의 이름표가 OMC 가 아니면 `OMC 플러그인 폴더가 아님` 으로 멈춘다. `.claude-plugin/plugin.json` 의 name 이 있으면 그것으로, 없으면 `package.json` 의 name 으로 정한다. 다른 폴더를 잘못 준 실수를 막는 확인이고, 이름표가 없는 폴더는 통과한다.
42
42
  - 쓸 파일이 링크로 플러그인 폴더 밖을 가리키거나 백업 자리(`.omcbak`)가 링크면 도구는 쓰지 않고 실패로 센다. 문구는 적용 때 `쓰지 않음`, 되돌리기 때 `되돌리지 않음`, hooks.json 은 `hooks.json 을 건드리지 않음` 이다.
43
43
  - 패치 규칙은 OMC 훅 코드의 모양에 맞춰져 있다. 처음 보는 OMC 버전이면 반드시 `check` 를 먼저 실행한다.
44
- - `실패 N건` 이 1건 이상이면 멈추고 출력을 그대로 보고한다. 문법 오류가 난 파일은 도구가 원본으로 자동 롤백한다.
44
+ - `실패 N건` 이 1건 이상이면 멈추고 출력을 그대로 보고한다. 문법 오류가 난 파일은 도구가 원본으로 자동 롤백한다. 고친 hooks.json 이 다시 읽어 JSON 이 아니어도 원본으로 되돌리고(`hooks.json 손상으로 롤백`) 실패로 센다.
45
45
  - 판정은 출력 문구로 한다. 종료 코드 0 만으로 완료라고 보고하지 않는다.
46
46
  - 캐시에는 정션이나 심볼릭 링크로 이어진 버전 폴더가 있을 수 있다(예: 옛 버전 폴더가 새 버전을 가리킴). 이때 한 번의 변경이 두 버전 폴더에 함께 보인다. 정상이다.
47
47
  - 도구는 `os.homedir()/.claude` 를 쓴다. `CLAUDE_CONFIG_DIR` 로 설정 폴더를 옮겼다면 이 도구는 그 폴더를 보지 않는다.
48
- - 출력의 origin 에 `https://사용자:토큰@...` 처럼 자격증명이 들어 있으면, 보고할 때 `//***@` 로 가린다. 출력을 그대로 보고하라는 단계에서도 이 가림은 지킨다. 그 URL 은 `PINNED` 에도 평문으로 남으니 사용자에게 알린다.
48
+ - 출력의 origin 에 `https://사용자:토큰@...` 처럼 자격증명이 들어 있으면, 보고할 때 `//***@` 로 가린다. 출력을 그대로 보고하라는 단계에서도 이 가림은 지킨다. 옛 판의 도구가 만든 `PINNED` 에는 그 URL 이 남아 있을 수 있다. `--check` 는 그 칸을 `[!] 고정 기록(PINNED)에 옛 URL 칸이 남아 있음 (적용하면 지움)` 으로 알리고 모두 적용된 상태로 보지 않는다. 적용(`--check` 가 아닌 실행)은 그 칸을 지우고 권한을 0600 으로 맞춘다. 이 도구가 지우지 못하면(기록이 링크, JSON 이 아님, 쓰기 실패, 읽지 못함) `[!] 고정 기록(PINNED)의 옛 URL 칸을 ...` 줄로 알리고, 적용과 되돌리기는 실패로 센다(종료 1). 링크는 따라가 쓰지 않는다. 이때는 그 줄의 경로를 사용자에게 보이고 그 파일을 지울지 묻는다. `PINNED` 는 기록일 뿐이라 지워도 고정과 되돌리기에 영향이 없다. 링크면 URL 칸은 링크가 가리키는 파일에 있으니 그 파일도 보이고 함께 묻는다. 지운 뒤 다시 실행한다. 기록 파일의 내용은 읽어 보이지 않는다(인증 정보가 들 수 있음).
49
49
 
50
50
  ## 절차
51
51
 
@@ -77,6 +77,8 @@ node "<이 스킬 디렉터리 절대경로>/scripts/omc-patch.mjs" --check --no
77
77
  | `모두 적용된 상태입니다.` | 4단계 검증으로 건너뜀 |
78
78
  | `헬퍼 자리 결함 N건이 있습니다.` | 2단계 확인 뒤 3단계에서 활성 폴더부터 되돌림 |
79
79
  | `적용되지 않은 항목이 있습니다.` | 2단계 확인 뒤 3단계 적용 |
80
+ | `hooks.json 을 확인하지 못했습니다.` | 적용하지 않고 위의 `[!]` 줄을 그대로 보고 |
81
+ | `고정 기록(PINNED)의 옛 URL 칸은 이 도구로 지울 수 없습니다.` | 적용하지 않고, 위 `규칙` 절의 `PINNED` 처리대로 사용자에게 묻는다. 지운 뒤 1단계부터 다시 |
80
82
 
81
83
  - `참고: 비활성 버전 ...` 은 지금 쓰지 않는 버전이라 판정에 들어가지 않는다.
82
84
  - 인자가 `check` 이면 여기서 결과만 보고하고 끝낸다.
@@ -184,13 +186,17 @@ node "<이 스킬 디렉터리 절대경로>/scripts/omc-patch.mjs" --check --no
184
186
  | 그 밖의 `probe-pm:` 줄(종료 코드 2) | 명령 오류다. 경로를 다시 구해 한 번만 다시 실행한다. 같으면 출력을 보고하고 멈춘다 |
185
187
  | 판정 줄 뒤의 `probe-pm: 임시 폴더를 지우지 못함` | 판정은 그대로 쓴다. 남은 임시 폴더 경로를 보고에 적어 사용자가 지우게 한다 |
186
188
 
187
- 5. 마켓플레이스 고정을 확인한다. `omc-pinned://` 로 시작하면 고정된 것이다.
189
+ 5. 마켓플레이스 고정을 확인한다. `omc-pinned://` 로 시작하면 고정된 것이다. 명령은 origin 의 사용자 정보를 `//***@` 로 가려서 낸다.
188
190
 
189
191
  ```bash
190
- git -C "$HOME/.claude/plugins/marketplaces/omc" remote get-url origin
192
+ git -C "$HOME/.claude/plugins/marketplaces/omc" config --get remote.origin.url | sed -E 's#(//)[^/]*@#\1***@#'
191
193
  ```
192
194
 
193
- PowerShell 에서는 `$HOME` 대신 `$env:USERPROFILE` 을 쓴다.
195
+ PowerShell:
196
+
197
+ ```powershell
198
+ (git -C "$env:USERPROFILE/.claude/plugins/marketplaces/omc" config --get remote.origin.url) -replace '(//)[^/]*@', '$1***@'
199
+ ```
194
200
 
195
201
  ### 5. 보고
196
202
 
@@ -209,6 +215,7 @@ node "<이 스킬 디렉터리 절대경로>/scripts/omc-patch.mjs" --revert
209
215
  - `.omcbak` 백업으로 설치된 모든 버전의 훅 스크립트와 `hooks.json` 을 되돌리고 마켓플레이스 `origin` 을 원래 URL 로 복구한다.
210
216
  - 되돌린 뒤 Claude Code 를 다시 시작해야 반영된다.
211
217
  - `되돌리기를 끝내지 못했습니다.` 가 나오면 위의 `[!]` 줄을 그대로 보고한다. 종료 코드는 1 이다. 백업이 없어 남은 파일과 hooks.json 도 이 끝 줄로 끝난다.
218
+ - 고정 기록(`PINNED`)을 지우지 못하면(읽기 전용 폴더, 폴더인 `PINNED`) `[!] 고정 기록(PINNED)을 지우지 못함` 으로 알리고 실패로 센다. 링크인 `PINNED` 너머에 옛 URL 칸이 있으면 링크를 두고 `[!]` 로 알린다. 둘 다 origin 은 그대로 되돌린다. 위 `규칙` 절의 `PINNED` 처리대로 사용자에게 묻는다.
212
219
  - `이 도구가 만들지 않은 수정이 남아 있습니다` 가 나오면 백업이 없는 손 수정이다. 출력에 적힌 복구 명령을 그대로 보고하고, 사용자 승인 없이 실행하지 않는다.
213
220
 
214
221
  ## 함정
@@ -218,9 +225,14 @@ node "<이 스킬 디렉터리 절대경로>/scripts/omc-patch.mjs" --revert
218
225
  - 헬퍼 자리 결함이 남은 채 `revert` 없이 적용을 다시 돌려도 바뀌는 것이 없다. 이미 감싼 파일은 건너뛰기 때문이다.
219
226
  - `--root` 와 `--revert --root` 는 그 폴더만 다룬다. 고정 해제까지 하려면 인자 없는 `--revert` 를 쓴다.
220
227
  - 고정을 풀지 않고 OMC 를 올리려면 먼저 `revert` 한다. 그렇지 않으면 마켓플레이스 fetch 가 계속 실패한다.
221
- - 고정 기록(`PINNED`)은 `~/.claude/omc-local-patches/PINNED` 에 생긴다. 기록일 뿐이라 지워도 고정은 풀리지 않고, 이미 고정된 상태에서는 다시 만들어지지 않는다. `revert` 는 origin 값에서만 원래 URL 을 되찾고, `PINNED` 의 값으로 origin 을 쓰지 않는다. 다른 기기의 기록이면 알리기만 한다.
228
+ - 고정 기록(`PINNED`)은 `~/.claude/omc-local-patches/PINNED` 에 생긴다. 고정한 시각, 판, 기기 이름만 담고 URL 은 담지 않는다. 옛 판의 기록에 URL 칸이 있으면 `--check` 가 알리고 다음 적용 때 지운다. 지우지 못하면 `[!]` 로 알리고 실패로 센다(링크는 따라가 쓰지 않음). 이 계정만 읽을 수 있다(0600). 기록일 뿐이라 지워도 고정은 풀리지 않고, 이미 고정된 상태에서는 다시 만들어지지 않는다. `revert` 는 origin 값에서만 원래 URL 을 되찾는다. 다른 기기의 기록이면 알리기만 한다.
222
229
  - `--check` 와 `--revert` 를 함께 주면 도구는 아무것도 하지 않고 종료 코드 1 로 멈춘다. 진단만 하려면 `--check` 만 준다.
223
230
  - 도구는 git 을 부를 때 저장소를 고르는 변수(`GIT_DIR`, `GIT_WORK_TREE` 등 `git rev-parse --local-env-vars` 목록)를 지운다. git 훅 안에서 불러도 마켓플레이스 저장소만 다룬다.
224
231
  - 마켓플레이스의 `.git` 이 깨졌으면(중단된 clone 등) git 이 위쪽 저장소로 올라가지 못하게 막는다. 그때 `[4/4]` 는 `origin remote 없음` 으로 끝나고 고정하지 않는다.
225
232
  - `--scan` 은 읽기만 한다. 플러그인 캐시도 `installed_plugins.json` 도 읽지 않고 준 파일만 본다.
233
+ - 도구는 모르는 인자를 받지 않는다. `--check`, `--revert`, `--no-update`, `--root <폴더>`, `--scan <파일>...`, `--help` 밖의 인자나 `--root=<폴더>` 꼴을 주면 아무것도 하지 않고 사용법과 함께 종료 1 로 멈춘다.
234
+ - 출력의 origin URL 에 사용자 이름과 비밀번호가 있으면 `//***@` 로 가린다. 도구는 origin 을 설정 값 그대로 읽어 고정하고 되돌린다(전역 `insteadOf` 를 펼치지 않음).
235
+ - origin 을 바꾸지 못하면(`.git` 쓰기 권한 등) `[!] 고정 실패` 나 `[!] 고정 해제 실패` 와 종료 1 로 끝난다. 그 줄을 그대로 보고한다. 고정 해제에 실패해도 원래 URL 은 `git config --get remote.origin.url` 결과의 `omc-pinned://` 뒤에 남는다.
236
+ - `--check` 는 쓸 수 없는 파일을 `패치 필요, 쓸 수 없음` 으로 미리 알린다. 폴더 밖 링크 때문에 되돌리지 못한 파일은 손 복구 방법을 함께 낸다. 사용자 승인 없이 그 방법을 실행하지 않는다.
237
+ - 파일은 새 임시 파일과 rename 으로 바꾼다. 하드 링크로 이어진 폴더 밖 파일은 바뀌지 않는다. 쓰지 못한 파일은 `쓰지 못함` 으로 이름을 대고 실패로 센다.
226
238
  - 도구의 주석과 출력 문구는 한글이다.