@kaydash9999/banker-plugins 0.19.0 → 0.19.2
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +63 -0
- package/bin/lib/telemetry-config.mjs +25 -0
- package/hooks/obsidize-hook.mjs +23 -4
- package/hooks/progress.mjs +24 -12
- package/hooks/register.mjs +1 -0
- package/hooks/telemetry-count-skill.mjs +4 -6
- package/hooks/telemetry-count.mjs +4 -6
- package/hooks/update-checkin.mjs +18 -17
- package/hooks/update-fetch.mjs +8 -7
- package/package.json +1 -1
- package/skills/anti-drm/SKILL.md +14 -7
- package/skills/anti-drm/scripts/anti-drm.mjs +92 -31
- package/skills/anti-drm/scripts/instruction-toggle.mjs +45 -14
- package/skills/lineage/SKILL.md +4 -1
- package/skills/lineage/lineage.py +230 -82
- package/skills/omc-patch/SKILL.md +30 -16
- package/skills/omc-patch/scripts/omc-patch.mjs +291 -72
- package/skills/tone-compact/SKILL.md +7 -2
- package/skills/tone-compact/scripts/instruction-toggle.mjs +45 -14
- package/skills/tone-compact/scripts/tone-compact.mjs +2 -1
|
@@ -39,7 +39,7 @@ argument-hint: "on | off | status"
|
|
|
39
39
|
| 코드 | 뜻 | 처리 |
|
|
40
40
|
|---|---|---|
|
|
41
41
|
| 0 | 완료. 이미 그 상태였던 경우 포함 | 결과 전달 |
|
|
42
|
-
| 1 | 거부 또는 사용법 오류. 아무것도 바꾸지
|
|
42
|
+
| 1 | 거부 또는 사용법 오류. 아무것도 바꾸지 않음. 단 메시지에 `앞서 바꾼 파일:` 이 있으면 그 파일은 이미 바뀜 | 메시지 그대로 전달 |
|
|
43
43
|
| 2 | 예기치 못한 오류 | 메시지 전달 후 `status` 로 확인 |
|
|
44
44
|
|
|
45
45
|
- 출력이 비어 있으면 실행 실패. 성공으로 보고하지 않음
|
|
@@ -191,9 +191,12 @@ argument-hint: "on | off | status"
|
|
|
191
191
|
|
|
192
192
|
## 문제 해결
|
|
193
193
|
|
|
194
|
+
- 아래 표에서 파일을 보인다는 것은 `ls -l` 로 그 이름의 종류와 링크 대상 경로를 보이는 것이다. 링크가 아닌 일반 파일임을 본 뒤에만 내용을 연다. 심어 둔 링크가 가리키는 파일(키 등)이 세션에 오르지 않게 한다.
|
|
195
|
+
- `<파일>.tone-compact.bak` 은 내용을 열지 않고 경로만 알린다. 지침 파일이 링크였으면 가리키던 파일(키 등)의 사본일 수 있다.
|
|
196
|
+
|
|
194
197
|
| 메시지 | 조치 |
|
|
195
198
|
|---|---|
|
|
196
|
-
| 같은 이름의 다른 파일이 있음 | `rules/banker-tone-compact.md` 가 banker 파일이 아님. 지우거나 이름을 바꾸지 않음. 내용을 보이고 어떻게 할지 물은 뒤 다시 실행 |
|
|
199
|
+
| 같은 이름의 다른 파일이 있음 | `rules/banker-tone-compact.md` 가 banker 파일이 아님. 지우거나 이름을 바꾸지 않음. 내용을 보이고(링크면 `ls -l` 로 링크와 대상 경로만 보이고 대상 내용은 열지 않음) 어떻게 할지 물은 뒤 다시 실행 |
|
|
197
200
|
| 표시의 짝이 맞지 않음 | 지침 파일에 tone-compact 표시 줄이 한쪽만 있거나 문장 속에 들어 있음. 또는 블록 안에 다른 표시 줄이 있음. 짝을 새로 맞추지 않음. 남은 표시 줄을 보이고 지울지 물은 뒤 다시 실행 |
|
|
198
201
|
| 설정 폴더가 없음 | 해당 런타임 미설치. 또는 설정 폴더 환경 변수 값 확인 |
|
|
199
202
|
| 규칙이 이 버전과 다름 | `on` 한 번 실행 |
|
|
@@ -202,6 +205,8 @@ argument-hint: "on | off | status"
|
|
|
202
205
|
| 다른 banker 블록만 있어 Codex 가 AGENTS.md 를 읽지 않음 | 메시지가 말한 스킬에서 `on` 실행 |
|
|
203
206
|
| UTF-8 이 아닌 파일 | 지침 파일을 바꾸지 않음. 인코딩을 보이고, 백업을 만든 뒤 UTF-8 로 바꿀지 물은 뒤 다시 실행 |
|
|
204
207
|
| 끊어진 링크라 그대로 두었습니다 | AGENTS.md 가 가리키는 파일이 없음. 링크를 지우거나 바꾸지 않음. 링크와 대상을 보이고 어떻게 할지 물은 뒤 다시 실행 |
|
|
208
|
+
| AGENTS.md 가 끊어진 링크라 on 이 블록을 옮기지 못함 | AGENTS.override.md 에 블록만 남았고 AGENTS.md 가 가리키는 파일이 없음. 링크를 지우거나 바꾸지 않음. 링크와 대상을 보이고 어떻게 할지 물은 뒤 `on` 실행 |
|
|
209
|
+
| 쓰는 사이에 같은 이름이 생겨 그대로 두었습니다 | 다른 프로그램이 그 사이에 같은 이름을 만들었음(링크일 수 있음). 지우거나 바꾸지 않음. 무엇인지 보이고(링크면 `ls -l` 로 링크와 대상 경로만 보이고 대상 내용은 열지 않음) 어떻게 할지 물은 뒤 다시 실행 |
|
|
205
210
|
| 일반 파일이 아님 | 지침 파일 자리(AGENTS.md, AGENTS.override.md)의 폴더나 특수 파일은 지우지 않음. 무엇인지 사용자에게 보이고, 옮기거나 이름을 바꿀지 물은 뒤 다시 실행 |
|
|
206
211
|
| 다른 banker 지침 작업이 끝나지 않아 그대로 두었습니다 | 다른 banker 스킬의 `on`, `off` 가 도는 중. 잠시 뒤 다시 실행. 끝나지 않은 작업이 남긴 잠금은 1분 뒤 저절로 넘어감. 1분이 지나도 같거나 잠금 자리가 폴더면 잠금 경로를 보이고 어떻게 할지 물은 뒤 다시 실행. 잠금을 임의로 지우지 않음 |
|
|
207
212
|
| 쓸 권한이 없음 | 해당 파일과 폴더 권한 확인 |
|
|
@@ -42,7 +42,9 @@
|
|
|
42
42
|
* the Codex folder), so both skills turned on at once keep both blocks; a lock
|
|
43
43
|
* older than a minute is taken over.
|
|
44
44
|
*
|
|
45
|
-
* Results are { ok, message }; ok false means refused with nothing changed
|
|
45
|
+
* Results are { ok, message }; ok false means refused with nothing changed, or,
|
|
46
|
+
* when a change of two files was refused at the second, with the first changed
|
|
47
|
+
* and named in the message ("앞서 바꾼 파일").
|
|
46
48
|
* Anything else that goes wrong throws.
|
|
47
49
|
*/
|
|
48
50
|
import {
|
|
@@ -95,7 +97,7 @@ const isLink = (path) => {
|
|
|
95
97
|
|
|
96
98
|
const UTF8 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
|
|
97
99
|
|
|
98
|
-
// What sits at a name that is not a regular file: a folder, a FIFO or a
|
|
100
|
+
// What sits at a name that is not a regular file: a folder, a FIFO, a socket, a device or a link loop.
|
|
99
101
|
// It is never read; reading a FIFO waits for a writer.
|
|
100
102
|
const SPECIAL = Object.freeze({ bytes: null, text: null, special: true });
|
|
101
103
|
// What sits at a name that is a link to nothing: Codex finds no file there, and writing would follow the link.
|
|
@@ -148,7 +150,7 @@ function readFile(path) {
|
|
|
148
150
|
|
|
149
151
|
/** A result that did, or found already done, what was asked. */
|
|
150
152
|
export const done = (message) => ({ ok: true, message });
|
|
151
|
-
/** A result that refused and changed nothing. */
|
|
153
|
+
/** A result that refused and changed nothing, unless its message names a file changed before (applied). */
|
|
152
154
|
export const refuse = (message) => ({ ok: false, message });
|
|
153
155
|
|
|
154
156
|
/** A skill's marks: the first line of its rules file, and the lines around its Codex block. */
|
|
@@ -226,6 +228,7 @@ function claudeOn(t, o, getRules) {
|
|
|
226
228
|
const state = claudeState(t, readFile(file), rules);
|
|
227
229
|
if (state === "foreign") return refuse(`같은 이름의 다른 파일이 있어 그대로 두었습니다: ${shown}`);
|
|
228
230
|
if (state === "on") return done(`Claude Code: 이미 켜져 있습니다 (변경 없음). ${shown}`);
|
|
231
|
+
const wasLink = isLink(file);
|
|
229
232
|
try {
|
|
230
233
|
mkdirSync(dirname(file), { recursive: true, mode: 0o755 });
|
|
231
234
|
writeFresh(file, claudeText(t, rules));
|
|
@@ -233,13 +236,13 @@ function claudeOn(t, o, getRules) {
|
|
|
233
236
|
if (denied(e)) return refuse(`쓸 권한이 없어 켜지 못했습니다 (${e.code}): ${shown}`);
|
|
234
237
|
throw e;
|
|
235
238
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
? `Claude Code: ${t.updatedText}. ${shown}`
|
|
239
|
-
: `Claude Code: 켰습니다. 다음 세션부터 자동 적용됩니다. ${shown}`,
|
|
240
|
-
);
|
|
239
|
+
const words = state === "stale" ? `Claude Code: ${t.updatedText}. ${shown}` : `Claude Code: 켰습니다. 다음 세션부터 자동 적용됩니다. ${shown}`;
|
|
240
|
+
return done(wasLink ? `${words}\n${LINK_REPLACED}` : words);
|
|
241
241
|
}
|
|
242
242
|
|
|
243
|
+
/** The note for a name that was a link (to nothing, or to an older copy) and is now a regular file. */
|
|
244
|
+
export const LINK_REPLACED = "참고: 링크였던 자리를 일반 파일로 바꿨습니다. 링크가 가리키던 곳은 건드리지 않았습니다.";
|
|
245
|
+
|
|
243
246
|
function claudeOff(t, o) {
|
|
244
247
|
const file = claudeFile(t, o);
|
|
245
248
|
const state = claudeState(t, readFile(file));
|
|
@@ -435,10 +438,14 @@ function withBlock(t, text, rules) {
|
|
|
435
438
|
}
|
|
436
439
|
|
|
437
440
|
// The state when the block is not in its place: "hidden" (only in an override with no text of its own),
|
|
438
|
-
// "
|
|
439
|
-
// nothing that on must not write
|
|
441
|
+
// "hiddenbroken" (the same, with AGENTS.md a link to nothing, so on cannot move it), "misplaced" (only in AGENTS.md
|
|
442
|
+
// while Codex reads the override), "dangling" (nowhere, and AGENTS.md is a link to nothing that on must not write
|
|
443
|
+
// through) or "off".
|
|
440
444
|
function placeState(files) {
|
|
441
|
-
if (hasBlock(files.other))
|
|
445
|
+
if (hasBlock(files.other)) {
|
|
446
|
+
if (files.other !== files.all[0]) return "misplaced";
|
|
447
|
+
return files.target.dangling ? "hiddenbroken" : "hidden";
|
|
448
|
+
}
|
|
442
449
|
return files.target.dangling ? "dangling" : "off";
|
|
443
450
|
}
|
|
444
451
|
|
|
@@ -477,12 +484,32 @@ function writeBlocked(changes) {
|
|
|
477
484
|
// whatever the umask allows more. A file left empty is removed, unless it is a
|
|
478
485
|
// link or has other names (a hard link), whose other names would keep the old
|
|
479
486
|
// text: it is emptied instead. Codex skips an empty file anyway.
|
|
487
|
+
// A file that was not there when it was read is created only if it still is not ("wx"): a name that appeared in
|
|
488
|
+
// between, a link planted there among them, is not written through.
|
|
480
489
|
function apply(t, changes) {
|
|
481
490
|
for (const { file, after } of changes) {
|
|
482
491
|
if (file.bytes !== null) writeFresh(`${file.path}.${t.slug}.bak`, file.bytes, 0o600);
|
|
483
492
|
if (after === "" && !isLink(file.path) && !hasOtherNames(file.path)) rmSync(file.path, { force: true });
|
|
484
|
-
else writeFileSync(file.path, after, { mode: 0o644 });
|
|
493
|
+
else writeFileSync(file.path, after, { mode: 0o644, flag: file.bytes === null ? "wx" : "w" });
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// Applies the changes, or the refusal for a write that failed with nothing of the file changed: a name that
|
|
498
|
+
// appeared in between (EEXIST), or a write a sandbox refused after access() allowed it. The refusal names the place
|
|
499
|
+
// the system refused (a rename's target, as the backup, or the file it was about), and a file changed before the
|
|
500
|
+
// failing one. Other errors propagate.
|
|
501
|
+
function applied(t, changes) {
|
|
502
|
+
let i = 0;
|
|
503
|
+
try {
|
|
504
|
+
for (; i < changes.length; i++) apply(t, [changes[i]]);
|
|
505
|
+
} catch (e) {
|
|
506
|
+
if (e.code !== "EEXIST" && !denied(e)) throw e;
|
|
507
|
+
const why = e.code === "EEXIST" ? "쓰는 사이에 같은 이름이 생겨 그대로 두었습니다" : `쓸 권한이 없어 그대로 두었습니다 (${where(e.code)})`;
|
|
508
|
+
const at = [e.dest, e.path].find((p) => typeof p === "string") ?? changes[i].file.path;
|
|
509
|
+
const before = i === 0 ? "" : `\n앞서 바꾼 파일: ${changes.slice(0, i).map((c) => where(c.file.path)).join(", ")}`;
|
|
510
|
+
return refuse(`${why}: ${where(at)}${before}`);
|
|
485
511
|
}
|
|
512
|
+
return null;
|
|
486
513
|
}
|
|
487
514
|
|
|
488
515
|
// Whether the file at path is also reachable under another name: a hard link.
|
|
@@ -523,6 +550,7 @@ function dropStale(path) {
|
|
|
523
550
|
st = lstatSync(path);
|
|
524
551
|
} catch (e) {
|
|
525
552
|
if (e.code === "ENOENT") return true; /* gone in between */
|
|
553
|
+
if (e.code === "ESTALE") return false; /* a network share's stale handle: rest and look again, not spin */
|
|
526
554
|
throw e;
|
|
527
555
|
}
|
|
528
556
|
if (st.isDirectory() || Math.abs(Date.now() - st.mtimeMs) <= LOCK_STALE_MS) return false;
|
|
@@ -628,7 +656,8 @@ function codexOnHeld(t, o, getRules) {
|
|
|
628
656
|
if (hasBlock(files.other)) changes.push({ file: files.other, after: stripped(files.other) });
|
|
629
657
|
const why = writeBlocked(changes);
|
|
630
658
|
if (why) return refuse(why);
|
|
631
|
-
|
|
659
|
+
const failed = applied(t, changes);
|
|
660
|
+
if (failed) return failed;
|
|
632
661
|
const note = files.target === files.all[1] ? `\n${OMX_NOTE}` : "";
|
|
633
662
|
return done(`Codex: ${words}. ${tail}${note}`);
|
|
634
663
|
}
|
|
@@ -646,7 +675,8 @@ function codexOffHeld(t, o) {
|
|
|
646
675
|
if (changes.length === 0) return done("Codex: 이미 꺼져 있습니다 (변경 없음).");
|
|
647
676
|
const why = writeBlocked(changes);
|
|
648
677
|
if (why) return refuse(why);
|
|
649
|
-
|
|
678
|
+
const failed = applied(t, changes);
|
|
679
|
+
if (failed) return failed;
|
|
650
680
|
const paths = changes.map((c) => where(c.file.path)).join(", ");
|
|
651
681
|
const baks = changes.map((c) => where(`${c.file.path}.${t.slug}.bak`)).join(", ");
|
|
652
682
|
return done(`Codex: 껐습니다. 다음 세션부터 적용되지 않습니다. ${paths}\n지우기 전 파일: ${baks}`);
|
|
@@ -661,6 +691,7 @@ const STATE_TEXT = {
|
|
|
661
691
|
foreign: "꺼짐, 같은 이름의 다른 파일이 있음 (손대지 않음)",
|
|
662
692
|
misplaced: "꺼짐, 단 블록이 Codex 가 읽지 않는 AGENTS.md 에 있음 (on 으로 옮김)",
|
|
663
693
|
hidden: "켜짐, 단 AGENTS.override.md 에 블록만 있어 AGENTS.md 가 가려짐 (on 으로 옮김)",
|
|
694
|
+
hiddenbroken: "켜짐, 단 AGENTS.override.md 에 블록만 있고 AGENTS.md 가 끊어진 링크라 on 이 블록을 옮기지 못함 (링크 확인 필요)",
|
|
664
695
|
notutf8: "UTF-8 이 아닌 지침 파일이 있어 손대지 않음 (on, off 모두 거부)",
|
|
665
696
|
notregular: "일반 파일이 아닌 지침 파일이 있어 손대지 않음 (on, off 모두 거부)",
|
|
666
697
|
unpaired: "표시의 짝이 맞지 않음 (on, off 모두 거부. 남은 표시 줄 정리 필요)",
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
*
|
|
16
16
|
* `off` never needs the rules, so it works even when SKILL.md cannot be read.
|
|
17
17
|
* Exit status 0 means done or already so; 1 means refused or a usage error, with
|
|
18
|
-
* nothing changed
|
|
18
|
+
* nothing changed (a refusal at the second of two files names the first, which
|
|
19
|
+
* it changed); 2 means an unexpected error stopped the command partway, so
|
|
19
20
|
* check `status`.
|
|
20
21
|
*/
|
|
21
22
|
import { readFileSync, realpathSync } from "node:fs";
|