@k2works/claude-code-booster 4.5.0 → 4.7.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 (43) hide show
  1. package/lib/assets/.claude/skills/creating-slides/SKILL.md +86 -0
  2. package/lib/assets/.claude/skills/creating-slides/agents/openai.yaml +4 -0
  3. package/lib/assets/.claude/skills/creating-slides/references/manga-css.md +45 -0
  4. package/lib/assets/.claude/skills/creating-slides/scripts/slide_tools.py +239 -0
  5. package/lib/assets/docs/article/getting-start-docker-kubernetes/01-container-and-docker-basics.md +332 -0
  6. package/lib/assets/docs/article/getting-start-docker-kubernetes/02-container-deployment.md +776 -0
  7. package/lib/assets/docs/article/getting-start-docker-kubernetes/03-practical-container-build-deploy.md +457 -0
  8. package/lib/assets/docs/article/getting-start-docker-kubernetes/04-multi-container-application.md +869 -0
  9. package/lib/assets/docs/article/getting-start-docker-kubernetes/05-kubernetes-introduction.md +576 -0
  10. package/lib/assets/docs/article/getting-start-docker-kubernetes/06-kubernetes-deploy-cluster.md +611 -0
  11. package/lib/assets/docs/article/getting-start-docker-kubernetes/07-kubernetes-advanced.md +612 -0
  12. package/lib/assets/docs/article/getting-start-docker-kubernetes/08-kubernetes-packaging.md +509 -0
  13. package/lib/assets/docs/article/getting-start-docker-kubernetes/09-container-operations.md +537 -0
  14. package/lib/assets/docs/article/getting-start-docker-kubernetes/10-optimal-container-image.md +631 -0
  15. package/lib/assets/docs/article/getting-start-docker-kubernetes/11-continuous-delivery.md +598 -0
  16. package/lib/assets/docs/article/getting-start-docker-kubernetes/12-container-use-cases.md +454 -0
  17. package/lib/assets/docs/article/getting-start-docker-kubernetes/13-case-monolith-compose-vs-kustomize.md +337 -0
  18. package/lib/assets/docs/article/getting-start-docker-kubernetes/14-case-event-driven-kustomize-vs-helm.md +315 -0
  19. package/lib/assets/docs/article/getting-start-docker-kubernetes/15-case-escqrs-axon-kustomize-vs-helm.md +288 -0
  20. package/lib/assets/docs/article/getting-start-docker-kubernetes/16-case-escqrs-kafka-kustomize-vs-helm.md +247 -0
  21. package/lib/assets/docs/article/getting-start-docker-kubernetes/17-case-comparison-summary.md +132 -0
  22. package/lib/assets/docs/article/getting-start-docker-kubernetes/18-case-load-testing.md +294 -0
  23. package/lib/assets/docs/article/getting-start-docker-kubernetes/appendix-a-dev-tools-setup.md +265 -0
  24. package/lib/assets/docs/article/getting-start-docker-kubernetes/appendix-b-orchestration-environments.md +521 -0
  25. package/lib/assets/docs/article/getting-start-docker-kubernetes/appendix-c-tips.md +510 -0
  26. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-01-comic.png +0 -0
  27. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-02-comic.png +0 -0
  28. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-03-comic.png +0 -0
  29. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-04-comic.png +0 -0
  30. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-05-comic.png +0 -0
  31. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-06-comic.png +0 -0
  32. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-07-comic.png +0 -0
  33. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-08-comic.png +0 -0
  34. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-09-comic.png +0 -0
  35. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-10-comic.png +0 -0
  36. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-11-comic.png +0 -0
  37. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-12-comic.png +0 -0
  38. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/overview-comic.png +0 -0
  39. package/lib/assets/docs/article/getting-start-docker-kubernetes/index.md +82 -0
  40. package/lib/assets/docs/article/getting-start-docker-kubernetes/outline.md +211 -0
  41. package/lib/assets/docs/article/index.md +3 -1
  42. package/lib/assets/mkdocs.yml +1 -0
  43. package/package.json +1 -1
@@ -0,0 +1,86 @@
1
+ ---
2
+ name: creating-slides
3
+ description: Marp Markdown スライドデッキの作成・拡張・再生成を支援。PlantUML 図表、AI 画像バリアント、漫画画像バリアント、PPTX/HTML 出力に対応。`tmp/k2works-wiki/スライド/YYYYMMDD` などの日本語技術スライドフォルダの構築・更新、コードサンプル追加、ビジュアル要約スライド追加、`スライド.images.md` / `スライド.images.ai.md` / `スライド.images.ai.manga.md` の生成、Marp HTML/PPTX デッキの再生成時に使用。
4
+ ---
5
+
6
+ # Creating Slides
7
+
8
+ ## Core Workflow
9
+
10
+ 1. Read the target slide folder and the reference slide Markdown first.
11
+ - Check `スライド.md`, `スライド.images.md`, `スライド.images.ai.md`, and any manga variant if present.
12
+ - Use `rg` for headings, image references, code sample lists, and reference links.
13
+ 2. Gather source material before editing.
14
+ - Prefer `docs/article` for conceptual content.
15
+ - Use `apps` or language-specific app folders for concrete code samples.
16
+ - Browse only when the user requests current external references or a live website.
17
+ 3. Edit `スライド.md` as the canonical source.
18
+ - Keep Japanese prose concise.
19
+ - Keep Japanese and ASCII terms separated by a half-width space.
20
+ - Add code slides near related language groups.
21
+ - Update structure, comparison tables, and references when adding samples.
22
+ 4. Regenerate derived Markdown and outputs.
23
+ - Run `scripts/slide_tools.py build <slide-dir>`.
24
+ - For AI image variants, ensure generated Markdown references `images-ai/diagram-ai-NN.png`.
25
+ - For manga variants, ensure generated Markdown references `images-manga/*.png`.
26
+ 5. Verify outputs.
27
+ - Count PPTX slides with `unzip -Z1 '<deck>.pptx' 'ppt/slides/slide*.xml' | wc -l`.
28
+ - Open rendered HTML with Playwright when visual layout matters.
29
+ - Check representative slide screenshots, especially image-heavy and code-heavy slides.
30
+ - Remove temporary `render-check-*.png` files before finishing.
31
+
32
+ ## Commands
33
+
34
+ Use the bundled script from this skill directory:
35
+
36
+ ```bash
37
+ python ~/.codex/skills/creating-slides/scripts/slide_tools.py build tmp/k2works-wiki/スライド/20260602
38
+ ```
39
+
40
+ Useful subcommands:
41
+
42
+ ```bash
43
+ python ~/.codex/skills/creating-slides/scripts/slide_tools.py extract <slide-dir>
44
+ python ~/.codex/skills/creating-slides/scripts/slide_tools.py make-ai <slide-dir>
45
+ python ~/.codex/skills/creating-slides/scripts/slide_tools.py make-manga <slide-dir>
46
+ python ~/.codex/skills/creating-slides/scripts/slide_tools.py marp <slide-dir>
47
+ python ~/.codex/skills/creating-slides/scripts/slide_tools.py count <slide-dir>
48
+ python ~/.codex/skills/creating-slides/scripts/slide_tools.py split-summary <slide-dir> images-manga/summary-manga.png
49
+ ```
50
+
51
+ ## Image Variants
52
+
53
+ Use the `imagegen` skill when creating new AI or manga bitmap assets.
54
+
55
+ Project-bound generated images must be copied into the slide folder, normally:
56
+
57
+ - `images-ai/diagram-ai-NN.png` for AI diagram replacements.
58
+ - `images-manga/manga-*.png` for manga story panels.
59
+ - `images-manga/summary-manga.png` and split files for tall summary comics.
60
+
61
+ For tall manga summaries, do not place the full vertical image on one 16:9 slide. Split it into section images and use multiple slides so text remains readable:
62
+
63
+ ```bash
64
+ python ~/.codex/skills/creating-slides/scripts/slide_tools.py split-summary <slide-dir> images-manga/summary-manga.png --parts 5
65
+ ```
66
+
67
+ Then replace a single summary image slide with numbered slides that reference the split files.
68
+
69
+ ## Manga Markdown Pattern
70
+
71
+ When converting AI Markdown to a manga variant, preserve prose and replace only diagram image references with `figure.diagram` blocks:
72
+
73
+ ```html
74
+ <figure class="diagram wide">
75
+ <img src="images-manga/manga-01-overview.png" alt="...">
76
+ </figure>
77
+ ```
78
+
79
+ Read `references/manga-css.md` when a manga variant needs CSS or layout tuning.
80
+
81
+ ## Validation Notes
82
+
83
+ - Marp PPTX generation needs `--allow-local-files` when local images are referenced.
84
+ - `npx --yes @marp-team/marp-cli` is the expected renderer unless the project has a local renderer.
85
+ - PlantUML must be available for diagram rendering; if missing, report that diagram PNG generation could not be completed.
86
+ - If HTML keyboard navigation jumps unexpectedly during Playwright checks, inspect the DOM for `section` elements and image sizes directly.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Create Slides"
3
+ short_description: "Create Marp slide decks with visual variants"
4
+ default_prompt: "Use $creating-slides to create a Marp slide deck with image and manga variants."
@@ -0,0 +1,45 @@
1
+ # Manga Slide CSS
2
+
3
+ Use this CSS pattern in Marp decks that mix text slides and manga images:
4
+
5
+ ```css
6
+ section img {
7
+ display: block;
8
+ max-width: 100%;
9
+ height: auto;
10
+ }
11
+ section .diagram {
12
+ margin: 10px auto 14px;
13
+ text-align: center;
14
+ }
15
+ section .diagram img {
16
+ width: 100%;
17
+ max-width: 980px;
18
+ max-height: 420px;
19
+ object-fit: contain;
20
+ margin: 0 auto;
21
+ }
22
+ section .diagram.wide img {
23
+ max-width: 1040px;
24
+ max-height: 470px;
25
+ }
26
+ section .diagram.compact img {
27
+ max-width: 760px;
28
+ max-height: 320px;
29
+ }
30
+ section.manga-summary {
31
+ padding: 24px 60px;
32
+ }
33
+ section.manga-summary h3 {
34
+ margin: 0 0 0.2em;
35
+ }
36
+ section.manga-summary img {
37
+ max-width: 100%;
38
+ max-height: 600px;
39
+ display: block;
40
+ margin: 0 auto;
41
+ object-fit: contain;
42
+ }
43
+ ```
44
+
45
+ For tall summary comics, prefer 4-6 cropped slides over one full-height image. Verify each crop renders at roughly 800 px or wider on a 1280 px viewport.
@@ -0,0 +1,239 @@
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+ import re
6
+ import shutil
7
+ import subprocess
8
+ import sys
9
+ from pathlib import Path
10
+
11
+
12
+ START_RE = re.compile(r"^@(startuml|startmindmap)\b.*$", re.MULTILINE)
13
+ END_RE = re.compile(r"^@(enduml|endmindmap)\b.*$", re.MULTILINE)
14
+
15
+
16
+ def run(cmd: list[str], cwd: Path) -> None:
17
+ print("+", " ".join(cmd), f"(cwd={cwd})")
18
+ subprocess.run(cmd, cwd=cwd, check=True)
19
+
20
+
21
+ def extract(slide_dir: Path) -> None:
22
+ src = slide_dir / "スライド.md"
23
+ dst = slide_dir / "スライド.images.md"
24
+ img_dir = slide_dir / "images"
25
+ if not src.exists():
26
+ raise SystemExit(f"missing canonical markdown: {src}")
27
+ img_dir.mkdir(exist_ok=True)
28
+ text = src.read_text(encoding="utf-8")
29
+ out: list[str] = []
30
+ cursor = 0
31
+ index = 0
32
+ fence_open_re = re.compile(r"```[a-zA-Z]*\s*\n")
33
+ fence_close_re = re.compile(r"\n```")
34
+ while True:
35
+ start = START_RE.search(text, cursor)
36
+ if not start:
37
+ out.append(text[cursor:])
38
+ break
39
+ end = END_RE.search(text, start.end())
40
+ if not end:
41
+ raise SystemExit(f"missing @enduml/@endmindmap after offset {start.start()}")
42
+ index += 1
43
+ block = text[start.start() : end.end()]
44
+ (img_dir / f"diagram-{index:02d}.puml").write_text(block + "\n", encoding="utf-8")
45
+ before = text[cursor : start.start()]
46
+ m_open = None
47
+ for match in fence_open_re.finditer(before):
48
+ m_open = match
49
+ m_close = fence_close_re.search(text, end.end())
50
+ if m_open and m_close:
51
+ replace_start = cursor + m_open.start()
52
+ replace_end = m_close.end()
53
+ out.append(text[cursor:replace_start])
54
+ out.append(f"![](images/diagram-{index:02d}.png)")
55
+ cursor = replace_end
56
+ else:
57
+ out.append(text[cursor : start.start()])
58
+ out.append(f"![](images/diagram-{index:02d}.png)")
59
+ cursor = end.end()
60
+ dst.write_text("".join(out), encoding="utf-8")
61
+ print(f"Extracted {index} diagrams -> {img_dir}")
62
+ print(f"Wrote {dst}")
63
+
64
+
65
+ def render_plantuml(slide_dir: Path) -> None:
66
+ puml_files = sorted((slide_dir / "images").glob("*.puml"))
67
+ if puml_files:
68
+ run(["plantuml", "-tpng", *[str(p.relative_to(slide_dir)) for p in puml_files]], slide_dir)
69
+
70
+
71
+ def make_ai(slide_dir: Path) -> None:
72
+ src = slide_dir / "スライド.images.md"
73
+ dst = slide_dir / "スライド.images.ai.md"
74
+ if not src.exists():
75
+ extract(slide_dir)
76
+ text = src.read_text(encoding="utf-8")
77
+ text = re.sub(r"images/diagram-(\d\d)\.png", r"images-ai/diagram-ai-\1.png", text)
78
+ text = text.replace(
79
+ "section img {\n max-height: 420px;\n }",
80
+ "section img {\n display: block;\n max-width: 100%;\n max-height: 420px;\n height: auto;\n object-fit: contain;\n margin: 0 auto;\n }",
81
+ )
82
+ dst.write_text(text, encoding="utf-8")
83
+ print(f"Wrote {dst}")
84
+
85
+
86
+ MANGA_REPLACEMENTS = {
87
+ "01": ("manga-01-overview.png", "diagram wide", "概要を描いた漫画"),
88
+ "02": ("manga-02-side-effect.png", "diagram", "副作用を描いた漫画"),
89
+ "03": ("manga-03-hard-to-test.png", "diagram", "テスト困難性を描いた漫画"),
90
+ "04": ("manga-04-core-shell.png", "diagram", "純粋なコアと不純なシェルを描いた漫画"),
91
+ "05": ("manga-05-io-plan.png", "diagram", "IO の実行計画を描いた漫画"),
92
+ "06": ("manga-06-execution-order.png", "diagram wide", "実行順序を描いた漫画"),
93
+ "07": ("manga-07-resource-safety.png", "diagram", "Resource の安全性を描いた漫画"),
94
+ }
95
+
96
+
97
+ def manga_css(text: str) -> str:
98
+ text = text.replace("font-size: 0.82em;", "font-size: 0.85em;")
99
+ text = text.replace("font-size: 0.68em;", "font-size: 0.7em;")
100
+ needle = "section img {\n max-height: 420px;\n }"
101
+ repl = """section img {
102
+ display: block;
103
+ max-width: 100%;
104
+ height: auto;
105
+ }
106
+ section .diagram {
107
+ margin: 10px auto 14px;
108
+ text-align: center;
109
+ }
110
+ section .diagram img {
111
+ width: 100%;
112
+ max-width: 980px;
113
+ max-height: 420px;
114
+ object-fit: contain;
115
+ margin: 0 auto;
116
+ }
117
+ section .diagram.wide img {
118
+ max-width: 1040px;
119
+ max-height: 470px;
120
+ }
121
+ section .diagram.compact img {
122
+ max-width: 760px;
123
+ max-height: 320px;
124
+ }
125
+ section .columns .diagram {
126
+ margin-top: 0;
127
+ }
128
+ section .columns .diagram img {
129
+ max-height: 330px;
130
+ }"""
131
+ return text.replace(needle, repl)
132
+
133
+
134
+ def make_manga(slide_dir: Path) -> None:
135
+ src = slide_dir / "スライド.images.ai.md"
136
+ dst = slide_dir / "スライド.images.ai.manga.md"
137
+ if not src.exists():
138
+ make_ai(slide_dir)
139
+ text = manga_css(src.read_text(encoding="utf-8"))
140
+ for num, (filename, klass, alt) in MANGA_REPLACEMENTS.items():
141
+ image = slide_dir / "images-manga" / filename
142
+ if not image.exists():
143
+ continue
144
+ block = f'<figure class="{klass}">\n <img src="images-manga/{filename}" alt="{alt}">\n</figure>'
145
+ text = text.replace(f"![](images-ai/diagram-ai-{num}.png)", block)
146
+ dst.write_text(text, encoding="utf-8")
147
+ print(f"Wrote {dst}")
148
+
149
+
150
+ def marp(slide_dir: Path) -> None:
151
+ targets = [
152
+ ("スライド.images.md", "スライド.html", ["--html"]),
153
+ ("スライド.images.md", "スライド.pptx", ["--pptx", "--allow-local-files"]),
154
+ ("スライド.images.ai.md", "スライド.images.ai.html", ["--html"]),
155
+ ("スライド.images.ai.md", "スライド.images.ai.pptx", ["--pptx", "--allow-local-files"]),
156
+ ("スライド.images.ai.manga.md", "スライド.images.ai.manga.html", ["--html"]),
157
+ ("スライド.images.ai.manga.md", "スライド.images.ai.manga.pptx", ["--pptx", "--allow-local-files"]),
158
+ ]
159
+ for src, dst, flags in targets:
160
+ if (slide_dir / src).exists():
161
+ run(["npx", "--yes", "@marp-team/marp-cli", src, "-o", dst, *flags], slide_dir)
162
+
163
+
164
+ def count(slide_dir: Path) -> None:
165
+ for pptx in sorted(slide_dir.glob("*.pptx")):
166
+ proc = subprocess.run(
167
+ ["unzip", "-Z1", str(pptx), "ppt/slides/slide*.xml"],
168
+ check=True,
169
+ text=True,
170
+ capture_output=True,
171
+ )
172
+ print(f"{pptx.name}: {len(proc.stdout.splitlines())}")
173
+
174
+
175
+ def split_summary(slide_dir: Path, image_rel: str, parts: int) -> None:
176
+ src = slide_dir / image_rel
177
+ if not src.exists():
178
+ raise SystemExit(f"missing image: {src}")
179
+ try:
180
+ proc = subprocess.run(
181
+ ["sips", "-g", "pixelWidth", "-g", "pixelHeight", str(src)],
182
+ check=True,
183
+ text=True,
184
+ capture_output=True,
185
+ )
186
+ except FileNotFoundError as exc:
187
+ raise SystemExit("split-summary requires macOS sips") from exc
188
+ nums = [int(x) for x in re.findall(r"pixel(?:Width|Height):\s+(\d+)", proc.stdout)]
189
+ if len(nums) < 2:
190
+ raise SystemExit(f"could not read image size from sips output: {proc.stdout}")
191
+ width, height = nums[0], nums[1]
192
+ stem = src.stem
193
+ chunk = height // parts
194
+ for idx in range(parts):
195
+ offset = idx * chunk if idx else 1
196
+ crop_h = chunk if idx < parts - 1 else height - idx * chunk - 1
197
+ out = src.with_name(f"{stem}-{idx + 1:02d}.png")
198
+ shutil.copy2(src, out)
199
+ run(["sips", "-c", str(crop_h), str(width), "--cropOffset", str(offset), "0", str(out)], slide_dir)
200
+ print(f"Wrote {out.relative_to(slide_dir)}")
201
+
202
+
203
+ def build(slide_dir: Path) -> None:
204
+ extract(slide_dir)
205
+ render_plantuml(slide_dir)
206
+ make_ai(slide_dir)
207
+ make_manga(slide_dir)
208
+ marp(slide_dir)
209
+ count(slide_dir)
210
+
211
+
212
+ def main() -> None:
213
+ parser = argparse.ArgumentParser()
214
+ parser.add_argument("command", choices=["extract", "make-ai", "make-manga", "marp", "count", "build", "split-summary"])
215
+ parser.add_argument("slide_dir")
216
+ parser.add_argument("image", nargs="?")
217
+ parser.add_argument("--parts", type=int, default=5)
218
+ args = parser.parse_args()
219
+ slide_dir = Path(args.slide_dir).expanduser().resolve()
220
+ if args.command == "extract":
221
+ extract(slide_dir)
222
+ elif args.command == "make-ai":
223
+ make_ai(slide_dir)
224
+ elif args.command == "make-manga":
225
+ make_manga(slide_dir)
226
+ elif args.command == "marp":
227
+ marp(slide_dir)
228
+ elif args.command == "count":
229
+ count(slide_dir)
230
+ elif args.command == "build":
231
+ build(slide_dir)
232
+ elif args.command == "split-summary":
233
+ if not args.image:
234
+ raise SystemExit("split-summary requires an image path relative to slide-dir")
235
+ split_summary(slide_dir, args.image, args.parts)
236
+
237
+
238
+ if __name__ == "__main__":
239
+ main()