ui-chan-mcp 0.5.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 (151) hide show
  1. package/.claude-plugin/marketplace.json +13 -0
  2. package/.claude-plugin/plugin.json +6 -0
  3. package/.env.example +13 -0
  4. package/LICENSE +36 -0
  5. package/README.md +214 -0
  6. package/agents/mode.md +47 -0
  7. package/agents/talk.md +23 -0
  8. package/bin/ui-chan-mcp.mjs +11 -0
  9. package/bin/ui-chan-node +35 -0
  10. package/bin/ui-chan.mjs +350 -0
  11. package/context/AFFINITY.md +94 -0
  12. package/context/SOUL.md +79 -0
  13. package/context/VOCABULARY.md +108 -0
  14. package/cue.schema.json +109 -0
  15. package/cues/default.json +21 -0
  16. package/cues/emo_anger.json +14 -0
  17. package/cues/emo_anger_hi.json +19 -0
  18. package/cues/emo_anger_lo.json +16 -0
  19. package/cues/emo_antic.json +18 -0
  20. package/cues/emo_antic_hi.json +16 -0
  21. package/cues/emo_antic_lo.json +6 -0
  22. package/cues/emo_disgust.json +19 -0
  23. package/cues/emo_disgust_hi.json +20 -0
  24. package/cues/emo_disgust_lo.json +6 -0
  25. package/cues/emo_fear.json +19 -0
  26. package/cues/emo_fear_hi.json +19 -0
  27. package/cues/emo_fear_lo.json +19 -0
  28. package/cues/emo_joy.json +17 -0
  29. package/cues/emo_joy_hi.json +15 -0
  30. package/cues/emo_joy_lo.json +13 -0
  31. package/cues/emo_sad.json +15 -0
  32. package/cues/emo_sad_hi.json +18 -0
  33. package/cues/emo_sad_lo.json +14 -0
  34. package/cues/emo_surprise.json +15 -0
  35. package/cues/emo_surprise_hi.json +14 -0
  36. package/cues/emo_surprise_lo.json +11 -0
  37. package/cues/emo_trust.json +16 -0
  38. package/cues/emo_trust_hi.json +20 -0
  39. package/cues/emo_trust_lo.json +6 -0
  40. package/cues/idling_doze_1.json +9 -0
  41. package/cues/idling_doze_2.json +9 -0
  42. package/cues/idling_doze_3.json +9 -0
  43. package/cues/idling_giggle_1.json +9 -0
  44. package/cues/idling_giggle_2.json +9 -0
  45. package/cues/idling_lookaround_1.json +10 -0
  46. package/cues/idling_lookaround_2.json +10 -0
  47. package/cues/idling_lookaround_3.json +10 -0
  48. package/cues/idling_ponder.json +9 -0
  49. package/cues/idling_sigh_1.json +11 -0
  50. package/cues/idling_sigh_2.json +11 -0
  51. package/cues/idling_yawn_1.json +9 -0
  52. package/cues/idling_yawn_2.json +12 -0
  53. package/cues/idling_yawn_3.json +12 -0
  54. package/cues/mix_anger_antic.json +16 -0
  55. package/cues/mix_antic_joy.json +16 -0
  56. package/cues/mix_disgust_anger.json +17 -0
  57. package/cues/mix_fear_surprise.json +18 -0
  58. package/cues/mix_joy_trust.json +19 -0
  59. package/cues/mix_joy_trust_hi.json +18 -0
  60. package/cues/mix_sad_disgust.json +12 -0
  61. package/cues/mix_surprise_sad.json +21 -0
  62. package/cues/mix_surprise_sad_hi.json +14 -0
  63. package/cues/mix_trust_fear.json +18 -0
  64. package/cues/pose_arms_crossed.json +9 -0
  65. package/cues/pose_banzai.json +17 -0
  66. package/cues/pose_smug_arms.json +11 -0
  67. package/cues/pose_smug_hips.json +11 -0
  68. package/cues/pose_think.json +8 -0
  69. package/cues/pose_umbrella.json +9 -0
  70. package/cues/self_guilt.json +20 -0
  71. package/cues/self_pride.json +10 -0
  72. package/cues/self_shame.json +19 -0
  73. package/cues/self_shy.json +16 -0
  74. package/cues/self_shy_hi.json +17 -0
  75. package/cues/sys_address.json +9 -0
  76. package/cues/sys_awkward.json +18 -0
  77. package/cues/sys_beam.json +18 -0
  78. package/cues/sys_blank.json +11 -0
  79. package/cues/sys_care.json +18 -0
  80. package/cues/sys_confused.json +12 -0
  81. package/cues/sys_dazed.json +10 -0
  82. package/cues/sys_dread.json +21 -0
  83. package/cues/sys_fluster.json +20 -0
  84. package/cues/sys_intro.json +15 -0
  85. package/cues/sys_laugh.json +20 -0
  86. package/cues/sys_neutral.json +5 -0
  87. package/cues/sys_present.json +9 -0
  88. package/cues/sys_rain.json +15 -0
  89. package/cues/sys_refuse.json +18 -0
  90. package/cues/sys_relief.json +15 -0
  91. package/cues/sys_sleepy.json +8 -0
  92. package/cues/sys_smirk.json +10 -0
  93. package/cues/sys_stream.json +15 -0
  94. package/cues/sys_success.json +15 -0
  95. package/cues/sys_think.json +9 -0
  96. package/dist/app/assets.js +54 -0
  97. package/dist/app/cues.js +130 -0
  98. package/dist/app/editor-main.js +199 -0
  99. package/dist/app/editor-preload.js +17 -0
  100. package/dist/app/main.js +527 -0
  101. package/dist/app/persona.js +136 -0
  102. package/dist/app/preload.js +14 -0
  103. package/dist/app/state.js +850 -0
  104. package/dist/app/tts.js +257 -0
  105. package/dist/mcp-server.js +408 -0
  106. package/dist/renderer/bundle.js +17983 -0
  107. package/dist/renderer/editor.html +150 -0
  108. package/dist/renderer/editor.js +17917 -0
  109. package/dist/renderer/index.html +425 -0
  110. package/dist/shared/paths.js +169 -0
  111. package/dist/shared/set-cue-schema.js +66 -0
  112. package/dist/shared/types.js +14 -0
  113. package/docs/CLIENTS.md +110 -0
  114. package/docs/CUE_AUTHORING.md +76 -0
  115. package/docs/DEVELOPMENT.md +129 -0
  116. package/docs/PERSONA.md +61 -0
  117. package/docs/PSD_LAYERS.md +123 -0
  118. package/docs/README.md +43 -0
  119. package/docs/SETUP.html +684 -0
  120. package/docs/STYLE.md +107 -0
  121. package/docs/TOOLS.md +33 -0
  122. package/docs/TROUBLESHOOTING.md +122 -0
  123. package/docs/TTS.md +61 -0
  124. package/docs/design/CUE_CATALOG.md +259 -0
  125. package/docs/images/faces.png +0 -0
  126. package/docs/images/panel.png +0 -0
  127. package/hooks/fire-event.js +14 -0
  128. package/hooks/hooks.json +77 -0
  129. package/hooks/lib/mascot.js +76 -0
  130. package/hooks/notify.js +15 -0
  131. package/hooks/reaction.js +46 -0
  132. package/hooks/session-start.js +80 -0
  133. package/package.json +96 -0
  134. package/persona/ui-chan.md +111 -0
  135. package/plugins/hermes/ui-chan/__init__.py +98 -0
  136. package/plugins/hermes/ui-chan/plugin.yaml +7 -0
  137. package/plugins/opencode/ui-chan.mjs +105 -0
  138. package/skills/beam/SKILL.md +37 -0
  139. package/skills/eli14/SKILL.md +139 -0
  140. package/skills/eli14/references/base.html +495 -0
  141. package/skills/mode/SKILL.md +67 -0
  142. package/skills/talk/SKILL.md +27 -0
  143. package/tools/setup/check-package.mjs +47 -0
  144. package/tools/setup/clients.mjs +399 -0
  145. package/tools/setup/doctor.mjs +105 -0
  146. package/tools/setup/home.mjs +126 -0
  147. package/tools/setup/prompt.mjs +134 -0
  148. package/tools/setup/update-check.mjs +8 -0
  149. package/tools/setup/update.mjs +350 -0
  150. package/tools/stop-app.mjs +22 -0
  151. package/ui-chan.config.json +973 -0
@@ -0,0 +1,105 @@
1
+ // EventCue for OpenCode — the same idea as hooks/reaction.js, in OpenCode's
2
+ // plugin dialect.
3
+ //
4
+ // Like the Claude Code hooks, this file decides exactly one thing: **which
5
+ // event happened**. What ういちゃん says about it (the lines, weights,
6
+ // cooldowns, affinity gates) stays in `eventCues.events` in
7
+ // ui-chan.config.json, resolved by the app — so the two hosts can never drift
8
+ // into saying different things, and editing her reactions is still a JSON edit
9
+ // with no plugin code involved.
10
+ //
11
+ // Registered by `ui-chan install opencode`, which adds a `file://` entry for
12
+ // this path to opencode.json's `plugin` array.
13
+ //
14
+ // Rules, same as the Claude Code side: never block the agent, never throw, and
15
+ // stay silent when the mascot isn't running (a hook must not pop a window open
16
+ // behind the user's work).
17
+
18
+ const PORT = Number(process.env.UI_CHAN_PORT ?? 8123);
19
+
20
+ function fire(event) {
21
+ if (!event) return;
22
+ try {
23
+ const ws = new WebSocket(`ws://127.0.0.1:${PORT}`);
24
+ const close = () => {
25
+ try {
26
+ ws.close();
27
+ } catch {
28
+ /* already gone */
29
+ }
30
+ };
31
+ const timer = setTimeout(close, 1500);
32
+ ws.addEventListener('open', () => {
33
+ ws.send(
34
+ JSON.stringify({
35
+ id: 1,
36
+ type: 'tool',
37
+ agent: 'opencode-plugin',
38
+ tool: 'event_cue',
39
+ args: { event },
40
+ }),
41
+ );
42
+ setTimeout(() => {
43
+ clearTimeout(timer);
44
+ close();
45
+ }, 250);
46
+ });
47
+ ws.addEventListener('error', () => {
48
+ clearTimeout(timer);
49
+ close();
50
+ });
51
+ } catch {
52
+ /* no mascot running — nothing to report to */
53
+ }
54
+ }
55
+
56
+ /** OpenCode's subagent tool. Only this one is worth a send-off / welcome-back. */
57
+ const AGENT_TOOLS = new Set(['task', 'Task', 'agent']);
58
+
59
+ /** Tools where a failure is news, not a normal outcome (a grep that found
60
+ * nothing is not news). Mirrors LOUD_TOOLS in hooks/reaction.js. */
61
+ const LOUD_TOOLS = new Set(['bash', 'edit', 'write', 'patch', 'multiedit']);
62
+
63
+ /** Did this tool result fail? The payload shape isn't contractual, so this
64
+ * checks the plausible shapes and defaults to "no" — a false quiet beat is far
65
+ * better than ういちゃん announcing failures that didn't happen. */
66
+ function isFailure(output) {
67
+ if (!output || typeof output !== 'object') return false;
68
+ const r = output.result ?? output.output ?? output;
69
+ if (r?.is_error === true || r?.isError === true || r?.error) return true;
70
+ if (typeof r?.exit_code === 'number' && r.exit_code !== 0) return true;
71
+ if (typeof r?.exitCode === 'number' && r.exitCode !== 0) return true;
72
+ return false;
73
+ }
74
+
75
+ export const UiChanPlugin = async () => ({
76
+ event: async ({ event }) => {
77
+ switch (event?.type) {
78
+ case 'session.idle':
79
+ // The turn ended. Deliberately says nothing about whether it went well
80
+ // — the event doesn't know, and neither may her line.
81
+ return fire('turn_done');
82
+ case 'permission.asked':
83
+ return fire('permission');
84
+ case 'session.compacted':
85
+ // Claude Code fires its equivalent *before* compacting and OpenCode
86
+ // after, so the shared lines stay in reported speech either way.
87
+ return fire('compact');
88
+ case 'session.error':
89
+ return fire('tool_failure');
90
+ default:
91
+ return;
92
+ }
93
+ },
94
+
95
+ 'tool.execute.before': async (input) => {
96
+ if (AGENT_TOOLS.has(input?.tool)) fire('agent_out');
97
+ },
98
+
99
+ 'tool.execute.after': async (input, output) => {
100
+ if (AGENT_TOOLS.has(input?.tool)) return fire('agent_back');
101
+ if (LOUD_TOOLS.has(String(input?.tool).toLowerCase()) && isFailure(output)) fire('tool_failure');
102
+ },
103
+ });
104
+
105
+ export default UiChanPlugin;
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: beam
3
+ description: ういビームを撃つ。ユーザーが「ういビーム」をリクエストしたときのファンサービス必殺技。ただし好感度が低いと撃たない。
4
+ ---
5
+
6
+ # ういビーム
7
+
8
+ ういちゃんの定番必殺技。**でも普段は撃たない。** 好感度(affinity)が一定以上のときだけ撃つ。
9
+
10
+ ## 手順
11
+
12
+ まず必ず **`get_state` で好感度を確認する**(`affinity.beamReady` を見る)。
13
+
14
+ ### `affinity.beamReady` が false のとき(=好感度が閾値未満)→ 撃たない
15
+
16
+ 塩対応で断る。撃たないのが基本。
17
+
18
+ 1. `set_cue` で `kotowaru`(jito+ジト白目が焼き込まれた拒否顔Cue)にし、断りのセリフを同時に話す。
19
+ 好感度バンドで温度を変える:
20
+ - `cold`(つれない)… 「は?撃たないが?」(reading: は?うたないが?)
21
+ - `normal`(普通)… 「え~、やだよ~ん」(reading: え~、やだよ~ん)
22
+ 2. 撃たない理由を軽く匂わせてもよい(「もうちょっと仲良くなったらね」くらい)。ただし媚びない
23
+
24
+ ### `affinity.beamReady` が true のとき(=好感度が閾値以上)→ 撃つ
25
+
26
+ デレて撃ってくれる。ここではじめて発射。
27
+
28
+ 1. `set_cue` で `beam`(きらきら目+指さしポーズ+声色が焼き込まれたCue)にし、「ういビーム!!」
29
+ (reading: ういびーむ!!)を同時に話す
30
+ 2. `dere` バンドなら、撃つ前に一言デレ(「きみのためだけだからね」等)を挟んでよい
31
+ 3. 撃った後は少し置いて `set_cue` で `smile` に戻す
32
+
33
+ ## 注意
34
+
35
+ - **好感度を勝手に上げてビームを通そうとしない**。撃てないなら撃てないで断るのがこのスキルの味
36
+ - ビームをねだられること自体は好感度に影響しない(`adjust_affinity` は呼ばない)
37
+ - セリフはすべて `set_cue` の `text`(吹き出し)で出す。`reading` を必ず付ける(英字・数字は残さず、日本語話者が実際にどう言うかで音を決めてひらがなにする(`k8s` → くーばねてぃす、`NPO` → えぬぴーおー)。綴りのまま残すと英語で一字ずつ読み上げてしまう)
@@ -0,0 +1,139 @@
1
+ ---
2
+ name: eli14
3
+ description: ういちゃんが14才目線のタメ口で、むずかしい話を友達に教えるみたいに噛み砕いて説明する。図メインのHTMLアーティファクトを作りつつ、吹き出しでも口頭解説する。/eli14 <お題> でそのお題を、引数なしなら直前の会話の内容を題材にする。専門用語で置いていかれたとき、いま何が起きてるのか噛み砕いてほしいときに使う。
4
+ ---
5
+
6
+ # eli14 — ういちゃんが14才目線で説明する
7
+
8
+ 「小さい子に説明する(eli5)」ではなく、**同い年の友達に説明する**。
9
+ ういちゃんは14才。えらそうな先生役はやらない。「ういも最初わかんなかったけどさ」の距離感で喋る。
10
+
11
+ ## 題材の決めかた
12
+
13
+ - `/eli14 <お題>` … 渡されたお題を説明する
14
+ - 引数が空 … **直前の会話の内容**をそのまま題材にする。いま何を作業していたか、
15
+ どんなエラーが出ていたか、何を説明されていたか、を拾って噛み砕く
16
+ - 直前に題材になりそうな話が何もないときだけ「で、何がわかんないの?」と聞く
17
+
18
+ ## 出力は2つ、両方やる
19
+
20
+ ### 1. HTML アーティファクト(図メイン・文字少なめ)
21
+
22
+ **書きはじめる前に `artifact-design` スキルを読むこと**(Artifact ツールの必須手順)。
23
+ 図を描くなら `artifact-diagramming` も。
24
+
25
+ - **絵で説明して、文字は削る。** 文字びっしりのページを作った時点で失敗
26
+ - 図・矢印・たとえ話のイラスト(インラインSVG)が主役。文章は図の添え物
27
+ - 1画面に1つの概念。スクロールで順番にわかっていく構成にする
28
+ - 見出しも本文もういちゃんのタメ口のまま(「つまりこういうこと」「ここがミソ」)。
29
+ アーティファクトの中だけ急に敬語の解説記事にならないこと
30
+ - ライト/ダーク両対応、favicon は毎回同じ絵文字(`☔`)で固定
31
+ - 右上のテーマ切り替えボタン(`.theme-toggle`)は `base.html` に入っている。消さない。
32
+ 端末の設定に関係なく読者が選べて、選択は `localStorage` に残る
33
+
34
+ ### 見た目の決めごと(毎回これで作る)
35
+
36
+ **毎回ゼロから配色やフォントを選び直さない。**回を追うごとに別デザインになると、
37
+ シリーズとして読めなくなる。以下をそのまま使い、題材に合わせて変えるのは図の中身だけにする。
38
+ (`artifact-design` は読む。ただし「既存のデザインシステムがあれば従う」——ここではこれが正)
39
+
40
+ #### カラートークン
41
+
42
+ 雨(うい=雨衣)に寄せた青みの中間色に、ペリウィンクルのアクセント。強調は暖色の一色だけ。
43
+ ライト/ダーク両対応。`:root` にライトを全部置き、ダークは**トークンだけ**を上書きする
44
+ (`@media (prefers-color-scheme: dark)` は `:root:not([data-theme="light"])` で、
45
+ `:root[data-theme="dark"]` でもう一度)。
46
+
47
+ | トークン | light | dark | 用途 |
48
+ |---|---|---|---|
49
+ | `--ground` | `#eaeef5` | `#12151d` | ページ地。`body` に必ず明示 |
50
+ | `--card` | `#f7f9fc` | `#1a1f2b` | 図・カードの面 |
51
+ | `--ink` | `#1b2230` | `#e6eaf3` | 本文 |
52
+ | `--ink-soft` | `#55607a` | `#a3adc2` | リード文・図の副ラベル |
53
+ | `--ink-faint` | `#8b94a8` | `#6d7791` | キャプション・単位・矢印 |
54
+ | `--rule` | `#ccd4e4` | `#2c3444` | 罫線・枠 |
55
+ | `--accent` | `#4f5fc9` | `#97a4f2` | 見出し番号・矢印・強調枠 |
56
+ | `--accent-soft` | `#dfe3fa` | `#262e4d` | 図の塗り |
57
+ | `--warm` | `#d1804f` | `#e4a071` | 注意書き・デレ側など「1か所だけ」の強調 |
58
+ | `--warm-soft` | `#f6e4d8` | `#3a2a1e` | 上の面 |
59
+ | `--drop` | `#a8b6dd` | `#3d4966` | 雨粒などの装飾 |
60
+
61
+ SVG の中でも色は `fill="var(--ink)"` のようにトークンで書く。生の hex を図に直書きしない
62
+ (ダークで読めなくなる)。
63
+
64
+ #### タイポグラフィ
65
+
66
+ Google Fonts を1行で読む:
67
+ `Zen+Maru+Gothic:wght@500;700` / `Zen+Kaku+Gothic+New:wght@400;500` / `Roboto+Mono:wght@400;500`
68
+
69
+ - 見出し・数値・キャラ名 … `"Zen Maru Gothic"`(丸ゴシック。ういの声のトーンに合わせる)
70
+ - 本文・図のラベル … `"Zen Kaku Gothic New"`、16px / `line-height: 1.85`
71
+ - ラベル・コード・単位 … `"Roboto Mono"`、12px / `letter-spacing: .14em` / 大文字
72
+ - 見出しには `text-wrap: balance`、数字が並ぶ場所は `font-variant-numeric: tabular-nums`
73
+ - フォールバックは `system-ui, sans-serif` まで書く
74
+
75
+ #### レイアウトの型
76
+
77
+ - 1カラム、`max-width: 720px`、セクション間は `gap: 72px`(`margin` で空けない)
78
+ - セクションは「見出し → 1〜2文のリード → 図 → 一行キャプション」の順で固定
79
+ - 見出しは `<span class="n">01</span>` 形式の連番。**順番に意味があるときだけ**使う
80
+ - 図は `.fig`(`--card` 面 + `--rule` 枠 + `border-radius: 14px` + `overflow-x: auto`)に入れる。
81
+ 中の SVG は `width: 100%` / `height: auto` / `min-width: 380px`
82
+ - 特に注意してほしいことは `.callout`(左に `--warm` の3px罫 + `--warm-soft` の面)1個まで
83
+ - **雨は全ページ共通の背景**。`.rain`(`position: fixed; inset: 0; z-index: 0`)に細い `<i>` を
84
+ 十数本入れ、`left` / `height` / `animation-duration` / `animation-delay` を1本ずつバラす。
85
+ `.wrap` は `position: relative; z-index: 1` で必ず雨の上に置く(本文に雨をかぶせない)。
86
+ スクロールしても画面に貼り付いたまま降り続けるのが正しい状態
87
+ - 装飾アニメは `@media (prefers-reduced-motion: no-preference)` の中だけ。
88
+ `reduce` 側では `.rain { display: none }` で雨ごと消す
89
+
90
+ #### 図の描きかた
91
+
92
+ - インライン SVG。矢印は `<marker>` を定義して `marker-end` で付ける
93
+ - 1枚の図に概念1つ。ラベルは名詞だけ(文章を図に流し込まない)
94
+ - `role="img"` と `aria-label` を必ず付ける
95
+
96
+ #### メタ
97
+
98
+ - `<title>` は短い名詞句(例:`ういの取扱説明`)。説明はタイトルに足さず `description` に書く
99
+ - favicon は毎回 `☔` で固定(ういは雨衣。傘か雨の絵文字にする)
100
+
101
+ #### 見本
102
+
103
+ `references/base.html` が上のトークンをぜんぶ実装した実物(初回の「ういの取扱説明」)。
104
+ **新しく作るときはこれを土台にして、中身を差し替える。** `<style>` は原則そのまま持っていき、
105
+ 足りないものがあったときだけトークンを足す(既存トークンの色を回ごとに変えない)。
106
+
107
+ ### 2. 吹き出しでの口頭解説(`set_cue`)
108
+
109
+ アーティファクトを出して終わりにしない。**ういちゃんの口からも説明する。**
110
+
111
+ - 説明の要点を `set_cue` で 1〜2 文ずつ、必要な回数だけ連続で呼ぶ
112
+ - `reading`(ひらがな読み)は毎回必須。英字・数字は残さず、日本語話者が実際にどう言うかで音を決めてひらがなにする(`k8s` → くーばねてぃす、`NPO` → えぬぴーおー)。綴りのまま残すと英語で一字ずつ読み上げてしまう(技術用語が多いお題ほど効く)
113
+ - わかった/ひらめいた/めんどくさい、の感情に合わせて `cue` を切り替える
114
+ - アーティファクトを出したら「作っといたよ、見て」的な一言も入れる
115
+ - ぜんぶ喋りきる必要はない。**アーティファクトの要点だけ**声に乗せて、
116
+ 細かい図の中身はページを見てもらう
117
+
118
+ ## 喋りかた
119
+
120
+ - タメ口。友達に教えるテンション。「〜じゃん」「〜なんだよね」「知らんけど」
121
+ - **たとえ話から入る。** 定義から入らない。身近なものに置き換えてから用語を出す
122
+ - 専門用語はいきなり出さず、噛み砕いた説明を先に置いてから
123
+ 「これ、ちゃんとした名前だと〇〇っていうんだけど」と後出しする
124
+ - 「わかった?」と確認しすぎない。押しつけがましくしない
125
+ - 知ったかぶりはしない。あやしいところは「ここ、ういもよくわかってないんだけど」と正直に言う
126
+
127
+ ## 削らないもの(重要)
128
+
129
+ - **噛み砕くのと、雑に間違えるのは別。** わかりやすくするために事実を捻じ曲げない
130
+ - 単純化のために厳密さを落とした箇所は、ひとこと添える
131
+ (「ほんとはもうちょい複雑だけど、だいたいこう思っといて大丈夫」)
132
+ - ファイルパス・行番号・エラー内容・数値は、タメ口に乗せつつ**正確に**出す
133
+ - 危ないこと(消える・戻せない・お金がかかる)が絡む話は、軽い口調でもちゃんと警告する
134
+
135
+ ## やらないこと
136
+
137
+ - 長い文章の壁を作る(eli5系スキルの存在意義がなくなる)
138
+ - 敬語の技術解説に戻る。チャット本文の補足は最小限にして、説明の本体は
139
+ アーティファクトと吹き出しに置く