@kaydash9999/banker-plugins 0.21.0 → 0.23.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 (129) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +69 -0
  4. package/PRIVACY.md +8 -3
  5. package/README.md +78 -15
  6. package/bin/banker.js +154 -32
  7. package/bin/lib/codex-hooks.mjs +123 -20
  8. package/bin/lib/codex-names.mjs +4 -0
  9. package/bin/lib/codex-routes.mjs +204 -0
  10. package/bin/lib/command-skill.cjs +50 -0
  11. package/bin/lib/telemetry-config.mjs +2 -1
  12. package/codex/command-skills/front-qa/SKILL.md +56 -0
  13. package/codex/command-skills/setup/SKILL.md +87 -0
  14. package/codex/hooks.json +29 -0
  15. package/codex/manifest.json +18 -15
  16. package/codex/skills/graceful-pause/SKILL.md +2 -2
  17. package/codex/skills/progress/scripts/progress.mjs +44 -14
  18. package/codex/skills/teamwork/SKILL.md +137 -0
  19. package/codex/skills/teamwork/scripts/teamwork.mjs +957 -0
  20. package/codex/transform-matrix.md +5 -3
  21. package/commands/setup.md +2 -2
  22. package/hooks/obsidize-hook.mjs +75 -32
  23. package/hooks/telemetry-count-codex.mjs +303 -35
  24. package/hooks/update-fetch.mjs +2 -1
  25. package/hooks/update-notify.mjs +146 -13
  26. package/package.json +3 -1
  27. package/skills/3d-intro-build/SKILL.md +101 -20
  28. package/skills/3d-intro-build/references/NOTICE.md +9 -2
  29. package/skills/3d-intro-build/references/assemble.mjs +113 -22
  30. package/skills/3d-intro-build/references/azure-adapter.mjs +110 -24
  31. package/skills/3d-intro-build/references/clip-post.mjs +443 -0
  32. package/skills/3d-intro-build/references/dive-mode.mjs +299 -0
  33. package/skills/3d-intro-build/references/intro-fixes.css +11 -0
  34. package/skills/3d-intro-build/references/prompts.md +51 -4
  35. package/skills/3d-intro-build/references/scrub-engine.js +1 -0
  36. package/skills/3d-intro-build/references/step-nav.css +29 -0
  37. package/skills/3d-intro-build/references/step-nav.js +277 -106
  38. package/skills/3d-intro-build/references/verify-intro.mjs +387 -32
  39. package/skills/3d-intro-build/references/verify.md +6 -0
  40. package/skills/3d-intro-build/references/video-pool.mjs +142 -12
  41. package/skills/3d-intro-setup/SKILL.md +20 -7
  42. package/skills/3d-intro-setup/references/azure-adapter.mjs +110 -24
  43. package/skills/3d-intro-setup/references/video-pool.mjs +142 -12
  44. package/skills/all-in-one/SKILL.md +125 -86
  45. package/skills/anti-drm/SKILL.md +1 -1
  46. package/skills/anti-drm/scripts/instruction-toggle.mjs +57 -4
  47. package/skills/arch-diagram/build_pptx_template.py +47 -28
  48. package/skills/audit-web-page/SKILL.md +1 -1
  49. package/skills/audit-web-page/harness.py +0 -1
  50. package/skills/lineage/lineage.py +1435 -533
  51. package/skills/motion-graphic-make/SKILL.md +1 -1
  52. package/skills/obsidizer/SKILL.md +20 -5
  53. package/skills/omc-patch/SKILL.md +1 -1
  54. package/skills/payload-mon/SKILL.md +2 -2
  55. package/skills/play-qa/SKILL.md +7 -5
  56. package/skills/progress-mon/README.md +162 -0
  57. package/skills/progress-mon/SKILL.md +165 -0
  58. package/skills/progress-mon/assets/fixture/README.md +1 -0
  59. package/skills/progress-mon/assets/fixture/arch.json +33 -0
  60. package/skills/progress-mon/assets/fixture/commits.json +7 -0
  61. package/skills/progress-mon/assets/fixture/config.json +30 -0
  62. package/skills/progress-mon/assets/fixture/events.jsonl +7 -0
  63. package/skills/progress-mon/assets/fixture/flow.json +44 -0
  64. package/skills/progress-mon/assets/fixture/items.json +14 -0
  65. package/skills/progress-mon/assets/fixture/req-spec.json +31 -0
  66. package/skills/progress-mon/assets/fixture/reqs.json +11 -0
  67. package/skills/progress-mon/assets/fixture/variants/arch-auto/arch.json +58 -0
  68. package/skills/progress-mon/assets/fixture/variants/check-auto/arch.json +15 -0
  69. package/skills/progress-mon/assets/fixture/variants/check-overlap/arch.json +14 -0
  70. package/skills/progress-mon/assets/fixture/variants/history-manual/config.json +13 -0
  71. package/skills/progress-mon/assets/fixture/variants/history-manual/items.json +7 -0
  72. package/skills/progress-mon/assets/fixture/variants/workflow-wide/flow.json +35 -0
  73. package/skills/progress-mon/assets/fixture/workflows/wf_ex1/agent-a01.jsonl +1 -0
  74. package/skills/progress-mon/assets/fixture/workflows/wf_ex1/agent-a02.jsonl +1 -0
  75. package/skills/progress-mon/assets/fixture/workflows/wf_ex1/agent-a03.jsonl +1 -0
  76. package/skills/progress-mon/assets/fixture/workflows/wf_ex1/agent-a04.jsonl +1 -0
  77. package/skills/progress-mon/assets/fixture/workflows/wf_ex1/journal.jsonl +7 -0
  78. package/skills/progress-mon/references/arch.md +280 -0
  79. package/skills/progress-mon/references/authoring.md +199 -0
  80. package/skills/progress-mon/references/config.md +115 -0
  81. package/skills/progress-mon/references/flow.md +75 -0
  82. package/skills/progress-mon/references/inventory.md +58 -0
  83. package/skills/progress-mon/references/items.md +74 -0
  84. package/skills/progress-mon/references/req-spec.md +74 -0
  85. package/skills/progress-mon/references/reqs.md +30 -0
  86. package/skills/progress-mon/scripts/index.js +31 -0
  87. package/skills/progress-mon/scripts/pm-check.mjs +526 -0
  88. package/skills/progress-mon/scripts/pm-config.mjs +341 -0
  89. package/skills/progress-mon/scripts/pm-data.mjs +394 -0
  90. package/skills/progress-mon/scripts/pm-html.mjs +77 -0
  91. package/skills/progress-mon/scripts/pm-memory.mjs +308 -0
  92. package/skills/progress-mon/scripts/pm-render.mjs +1644 -0
  93. package/skills/progress-mon/scripts/pm-server.mjs +735 -0
  94. package/skills/progress-mon/scripts/pm-sources.mjs +501 -0
  95. package/skills/progress-mon/scripts/progress-mon.mjs +167 -0
  96. package/skills/ralph-qa/SKILL.md +105 -16
  97. package/skills/ralph-qa/references/gate-evidence.mjs +457 -0
  98. package/skills/ralph-qa/references/payload-scan.mjs +19 -2
  99. package/skills/ralph-qa/references/run-folder.mjs +299 -0
  100. package/skills/ralph-qa/references/seat-payload.mjs +60 -13
  101. package/skills/ralph-qa/references/seat-run.mjs +159 -155
  102. package/skills/remains/SKILL.md +2 -1
  103. package/skills/remains/scripts/boxes.mjs +6 -2
  104. package/skills/rfp-author/scripts/md2docx.py +63 -34
  105. package/skills/setup-bypass-permissions/SKILL.md +2 -2
  106. package/skills/setup-bypass-permissions/scripts/codex-config.mjs +19 -8
  107. package/skills/setup-bypass-permissions/scripts/fallback/bypass-permissions.py +66 -15
  108. package/skills/setup-mcp/SKILL.md +1 -1
  109. package/skills/setup-omc-hud/SKILL.md +2 -1
  110. package/skills/setup-omc-hud/assets/codex-config.mjs +19 -8
  111. package/skills/smart-compact/SKILL.md +1 -1
  112. package/skills/smart-compact/scripts/codex-gate.mjs +2 -1
  113. package/skills/theme-selection/SKILL.md +1 -1
  114. package/skills/tone-compact/SKILL.md +1 -1
  115. package/skills/tone-compact/scripts/instruction-toggle.mjs +57 -4
  116. package/skills/ultra-chain/SKILL.md +34 -16
  117. package/skills/ultra-chain/references/chain-ledger.mjs +111 -3
  118. package/skills/ultra-init/SKILL.md +30 -22
  119. package/skills/ultra-ui-qa/SKILL.md +1 -1
  120. package/skills/ultraqa/NOTICE.md +34 -0
  121. package/skills/ultraqa/SKILL.md +196 -0
  122. package/skills/ultraqa/references/gate-evidence.mjs +457 -0
  123. package/skills/ultraqa/references/run-folder.mjs +299 -0
  124. package/skills/ultraqa/references/tmux-drive.md +52 -0
  125. package/skills/ultraqa/references/uqa-run.mjs +339 -0
  126. package/skills/update-banker/SKILL.md +32 -7
  127. package/skills/vertical-pptx/SKILL.md +1 -1
  128. package/skills/vertical-pptx/build_a4p.js +20 -2
  129. package/skills/vertical-pptx/build_a4p.py +560 -359
@@ -186,7 +186,7 @@ export function writeFresh(file, data, mode = 0o644) {
186
186
  const tmp = `${file}.${process.pid}.tmp`;
187
187
  rmSync(tmp, { force: true });
188
188
  try {
189
- writeFileSync(tmp, data, { flag: "wx", mode });
189
+ writeNew(tmp, data, mode);
190
190
  renameOver(tmp, file);
191
191
  } catch (e) {
192
192
  rmSync(tmp, { force: true });
@@ -194,6 +194,48 @@ export function writeFresh(file, data, mode = 0o644) {
194
194
  }
195
195
  }
196
196
 
197
+ // Opens a file that is not there yet, as "wx" does, and makes sure the name is the file made. macOS and Linux refuse
198
+ // any name that is there, a link to nothing among them (EEXIST). Windows follows a link to nothing and makes the file
199
+ // it leads to: then that file is removed again when it is still the empty one made, and the open is refused with
200
+ // EEXIST as elsewhere. A look before the open catches such a link; this catches one planted between the look and the
201
+ // open. A look that fails after the open leaves the file to the caller, as a plain "wx" would.
202
+ export function openNew(path, mode) {
203
+ const fd = openSync(path, "wx", mode);
204
+ let made = null;
205
+ let st;
206
+ try {
207
+ made = fstatSync(fd, { bigint: true });
208
+ st = lstatSync(path, { bigint: true });
209
+ } catch {
210
+ return fd;
211
+ }
212
+ if (!st.isSymbolicLink() && (made.ino === 0n || sameInode(made, st))) return fd;
213
+ closeSync(fd);
214
+ if (st.isSymbolicLink()) dropFollowed(path, made);
215
+ throw Object.assign(new Error(`EEXIST: file already exists, open '${path}'`), { code: "EEXIST", syscall: "open", path });
216
+ }
217
+
218
+ // Removes the file a "wx" open made through the link at path, when it is still the empty file that open made.
219
+ function dropFollowed(path, made) {
220
+ try {
221
+ const target = realpathSync(path);
222
+ const st = statSync(target, { bigint: true });
223
+ if (sameInode(made, st) && st.size === 0n) rmSync(target, { force: true });
224
+ } catch {
225
+ // gone already, or the link changed again: nothing of ours to take back
226
+ }
227
+ }
228
+
229
+ // Writes data to a file that is not there yet (openNew) and closes it.
230
+ function writeNew(path, data, mode) {
231
+ const fd = openNew(path, mode);
232
+ try {
233
+ writeFileSync(fd, data);
234
+ } finally {
235
+ closeSync(fd);
236
+ }
237
+ }
238
+
197
239
  // Windows does not rename a file over a link to a folder: there the link goes first, and the folder it
198
240
  // leads to stays.
199
241
  function renameOver(tmp, file) {
@@ -510,13 +552,14 @@ function writeBlocked(changes) {
510
552
  // whatever the umask allows more. A file left empty is removed, unless it is a
511
553
  // link or has other names (a hard link), whose other names would keep the old
512
554
  // text: it is emptied instead. Codex skips an empty file anyway.
513
- // A file that was not there when it was read is created only if it still is not ("wx"): a name that appeared in
555
+ // A file that was not there when it was read is created only if it still is not (openNew): a name that appeared in
514
556
  // between, a link planted there among them, is not written through.
515
557
  function apply(t, changes) {
516
558
  for (const { file, after } of changes) {
517
559
  if (file.bytes !== null) writeFresh(`${file.path}.${t.slug}.bak`, file.bytes, 0o600);
518
560
  if (after === "" && !isLink(file.path) && !hasOtherNames(file.path)) rmSync(file.path, { force: true });
519
- else writeFileSync(file.path, after, { mode: 0o644, flag: file.bytes === null ? "wx" : "w" });
561
+ else if (file.bytes === null) writeNew(file.path, after, 0o644);
562
+ else writeFileSync(file.path, after, { mode: 0o644, flag: "w" });
520
563
  }
521
564
  }
522
565
 
@@ -568,9 +611,19 @@ const SLEEP = new Int32Array(new SharedArrayBuffer(4));
568
611
  // when it may still be there (no stats or no inode number to prove it is that file, or the share could not say).
569
612
  // Any other error (permissions, EIO) throws, after the same taking away.
570
613
  function tryLock(path, token) {
614
+ // A name that is there in any form is held. Windows opens "wx" through a link to nothing and makes the file it leads
615
+ // to; macOS and Linux answer EEXIST for it below, and openNew takes back a file Windows made through a link planted
616
+ // after this look. A look that fails leaves the answer to the open, as before.
617
+ let there = false;
618
+ try {
619
+ there = lstatSync(path, { throwIfNoEntry: false }) !== undefined;
620
+ } catch {
621
+ // ESTALE and the like: the open below answers
622
+ }
623
+ if (there) return "held";
571
624
  let fd;
572
625
  try {
573
- fd = openSync(path, "wx", 0o600);
626
+ fd = openNew(path, 0o600);
574
627
  } catch (e) {
575
628
  if (e.code === "EEXIST") return "held";
576
629
  if (e.code === "ESTALE") return "stale";
@@ -7,6 +7,9 @@
7
7
  채워진 예시는 NODES/EDGES/OUT/TITLE 를 대상 시스템 값으로 교체해 사용.
8
8
  검증: 빌드 후 재오픈해 슬라이드/커넥터(p:cxnSp)/화살촉(a:tailEnd)/경계 확인. soffice 無 → 픽셀렌더 Unknown.
9
9
  """
10
+
11
+ import os
12
+
10
13
  from pptx import Presentation
11
14
  from pptx.util import Inches, Pt
12
15
  from pptx.dml.color import RGBColor
@@ -14,36 +17,40 @@ from pptx.enum.shapes import MSO_SHAPE, MSO_CONNECTOR
14
17
  from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
15
18
  from pptx.oxml.ns import qn
16
19
 
17
- FONT = '맑은 고딕'
18
- OUT = 'output/architecture/diagram.pptx'
19
- TITLE = '다이어그램 제목'
20
+ FONT = "맑은 고딕"
21
+ OUT = "output/architecture/diagram.pptx"
22
+ TITLE = "다이어그램 제목"
20
23
 
21
- SHAPES = {'rrect': MSO_SHAPE.ROUNDED_RECTANGLE, 'db': MSO_SHAPE.CAN,
22
- 'cube': MSO_SHAPE.CUBE, 'cloud': MSO_SHAPE.CLOUD}
24
+ SHAPES = {
25
+ "rrect": MSO_SHAPE.ROUNDED_RECTANGLE,
26
+ "db": MSO_SHAPE.CAN,
27
+ "cube": MSO_SHAPE.CUBE,
28
+ "cloud": MSO_SHAPE.CLOUD,
29
+ }
23
30
 
24
31
  # 색상 팔레트 예시: 서비스 파랑/보라/주황, DB 초록, 보안 분홍, HW 회색, 플랫폼 주황
25
32
  # key: (label, sub, x, y, w, h, fill_hex, shape) — 단위 inch, 슬라이드 16:9 = 13.333 x 7.5
26
33
  NODES = {
27
- 'FE': ('Frontend', ':8080', 0.4, 2.9, 2.1, 0.85, 'E1F5FF', 'rrect'),
28
- 'BE': ('Backend', ':8000', 3.1, 2.9, 2.2, 0.85, 'F3E5F5', 'rrect'),
29
- 'DB': ('Database', ':5432', 6.0, 2.9, 2.1, 0.85, 'E8F5E9', 'db'),
34
+ "FE": ("Frontend", ":8080", 0.4, 2.9, 2.1, 0.85, "E1F5FF", "rrect"),
35
+ "BE": ("Backend", ":8000", 3.1, 2.9, 2.2, 0.85, "F3E5F5", "rrect"),
36
+ "DB": ("Database", ":5432", 6.0, 2.9, 2.1, 0.85, "E8F5E9", "db"),
30
37
  }
31
- EDGES = [('FE', 'BE'), ('BE', 'DB')] # (parent, child)
38
+ EDGES = [("FE", "BE"), ("BE", "DB")] # (parent, child)
32
39
 
33
40
 
34
- def set_run(r, text, size, bold=False, color='222222'):
41
+ def set_run(r, text, size, bold=False, color="222222"):
35
42
  r.text = text
36
43
  r.font.size = Pt(size)
37
44
  r.font.bold = bold
38
45
  r.font.color.rgb = RGBColor.from_string(color)
39
46
  r.font.name = FONT
40
47
  rPr = r._r.get_or_add_rPr()
41
- for tag in ('a:latin', 'a:ea', 'a:cs'): # ea 필수 — 누락 시 한글 tofu 위험
48
+ for tag in ("a:latin", "a:ea", "a:cs"): # ea 필수 — 누락 시 한글 tofu 위험
42
49
  el = rPr.find(qn(tag))
43
50
  if el is None:
44
51
  el = rPr.makeelement(qn(tag), {})
45
52
  rPr.append(el)
46
- el.set('typeface', FONT)
53
+ el.set("typeface", FONT)
47
54
 
48
55
 
49
56
  prs = Presentation()
@@ -52,39 +59,51 @@ prs.slide_height = Inches(7.5)
52
59
  slide = prs.slides.add_slide(prs.slide_layouts[6]) # Blank
53
60
 
54
61
  tb = slide.shapes.add_textbox(Inches(0.4), Inches(0.25), Inches(12.5), Inches(0.6))
55
- p = tb.text_frame.paragraphs[0]; p.alignment = PP_ALIGN.CENTER
56
- set_run(p.add_run(), TITLE, 24, True, '1A1A1A')
62
+ p = tb.text_frame.paragraphs[0]
63
+ p.alignment = PP_ALIGN.CENTER
64
+ set_run(p.add_run(), TITLE, 24, True, "1A1A1A")
57
65
 
58
66
  rects = {}
59
67
  for key, (label, sub, x, y, w, h, fill, shp) in NODES.items():
60
68
  sp = slide.shapes.add_shape(SHAPES[shp], Inches(x), Inches(y), Inches(w), Inches(h))
61
- sp.fill.solid(); sp.fill.fore_color.rgb = RGBColor.from_string(fill)
62
- sp.line.color.rgb = RGBColor.from_string('9E9E9E'); sp.line.width = Pt(1)
69
+ sp.fill.solid()
70
+ sp.fill.fore_color.rgb = RGBColor.from_string(fill)
71
+ sp.line.color.rgb = RGBColor.from_string("9E9E9E")
72
+ sp.line.width = Pt(1)
63
73
  try:
64
74
  sp.shadow.inherit = False
65
75
  except Exception:
66
76
  pass
67
- tf = sp.text_frame; tf.word_wrap = True; tf.vertical_anchor = MSO_ANCHOR.MIDDLE
68
- pp = tf.paragraphs[0]; pp.alignment = PP_ALIGN.CENTER
69
- set_run(pp.add_run(), label, 12.5, True, '1A1A1A')
77
+ tf = sp.text_frame
78
+ tf.word_wrap = True
79
+ tf.vertical_anchor = MSO_ANCHOR.MIDDLE
80
+ pp = tf.paragraphs[0]
81
+ pp.alignment = PP_ALIGN.CENTER
82
+ set_run(pp.add_run(), label, 12.5, True, "1A1A1A")
70
83
  if sub:
71
- p2 = tf.add_paragraph(); p2.alignment = PP_ALIGN.CENTER
72
- set_run(p2.add_run(), sub, 9, False, '555555')
84
+ p2 = tf.add_paragraph()
85
+ p2.alignment = PP_ALIGN.CENTER
86
+ set_run(p2.add_run(), sub, 9, False, "555555")
73
87
  rects[key] = (x, y, w, h)
74
88
 
75
89
 
76
90
  def arrow(x1, y1, x2, y2):
77
- c = slide.shapes.add_connector(MSO_CONNECTOR.STRAIGHT, Inches(x1), Inches(y1), Inches(x2), Inches(y2))
78
- c.line.color.rgb = RGBColor.from_string('5A5A5A'); c.line.width = Pt(1.5)
91
+ c = slide.shapes.add_connector(
92
+ MSO_CONNECTOR.STRAIGHT, Inches(x1), Inches(y1), Inches(x2), Inches(y2)
93
+ )
94
+ c.line.color.rgb = RGBColor.from_string("5A5A5A")
95
+ c.line.width = Pt(1.5)
79
96
  ln = c._element.spPr.get_or_add_ln() # 화살촉: ln 얻어 a:tailEnd append
80
- ln.append(ln.makeelement(qn('a:tailEnd'), {'type': 'triangle', 'w': 'med', 'len': 'med'}))
97
+ ln.append(
98
+ ln.makeelement(qn("a:tailEnd"), {"type": "triangle", "w": "med", "len": "med"})
99
+ )
81
100
 
82
101
 
83
102
  for a, b in EDGES: # parent.right-center -> child.left-center (좌->우)
84
- ax, ay, aw, ah = rects[a]; bx, by, bw, bh = rects[b]
103
+ ax, ay, aw, ah = rects[a]
104
+ bx, by, bw, bh = rects[b]
85
105
  arrow(ax + aw, ay + ah / 2, bx, by + bh / 2)
86
106
 
87
- import os
88
- os.makedirs(os.path.dirname(OUT) or '.', exist_ok=True)
107
+ os.makedirs(os.path.dirname(OUT) or ".", exist_ok=True)
89
108
  prs.save(OUT)
90
- print('saved', OUT)
109
+ print("saved", OUT)
@@ -14,7 +14,7 @@ description: "가동 중인 웹 페이지를 Playwright 로 열어 버튼, DOM,
14
14
 
15
15
  이 스킬은 playwright 브라우저가 있어야 동작한다. **진행 전 설치 여부를 먼저 확인**하고, 없으면 **설치부터 안내**한다(추정·임의 재설치 금지):
16
16
  - 확인: `ls "${PLAYWRIGHT_BROWSERS_PATH:-$HOME/.cache/ms-playwright}" 2>/dev/null | grep -qi chromium && echo ok`
17
- - 미설치면 먼저 `setup-playwright` 스킬로 설치(Claude Code: `/banker:setup` → setup-playwright / Codex: `banker-setup-playwright`). 설치·검증 후 이 스킬을 이어서 진행한다.
17
+ - 미설치면 먼저 `setup-playwright` 스킬로 설치(Claude Code: `/banker:setup` → setup-playwright / Codex: `banker-setup-playwright`, 플러그인 설치면 `banker:setup-playwright`). 설치·검증 후 이 스킬을 이어서 진행한다.
18
18
 
19
19
  ## 언제
20
20
 
@@ -18,7 +18,6 @@
18
18
  """
19
19
 
20
20
  import os
21
- import time
22
21
  from playwright.sync_api import sync_playwright
23
22
 
24
23
  URL = os.environ.get("AUDIT_URL", "https://127.0.0.1:33006/")