[mod] A live forecast of the context window above the prompt: weather icon, fill, tokens, a chart of the last turns and how much the last turn added. Based on…

japan-da-man の Claude Code プラグイン(mods を含む)を管理するマーケットプレイス。
| 名前 | 内容 | | :- | :- | | japan-da-man-mods | まとめてインストール用。下のプラグインを全部入れる | | todo-mod | /todo で TODO パネルを開く。チェックを入れたタスクを Claude に依頼する | | token-weather | コンテキストの埋まり具合を天気でプロンプトの上に表示する(☀ Clear → ☁ Cloudy → ☂ Showers → ☇ Storm → ↯ Compact soon)。直近12ターンのグラフと、直前のターンの増減(▲ +98.3k last turn)付き。/weather で表示切り替え | | usage-stats | /stats で利用統計のパネルを開く。セッション数・メッセージ数・トークン数・利用日数・連続日数・よく使うモデル・日ごとのヒートマップ | | blast-radius | 危険なシェルコマンドを実行前に止め、何が消えるか・変わるかをペインに出して Proceed / Cancel で選ばせる(10分答えがなければ止める)。rm -r/-f、git reset --hard、force push、git clean、変更の破棄、git branch -D、git stash drop/clear、マイグレーション、find -delete、xargs rm。bash -c / eval の中も調べる。/blast-radius で履歴 | | replay-theater | ターンの中で Claude が行ったファイル編集を記録する。ターンが終わるとプロンプトの上に ▶ Replay: N edits が出て、r か /replay でペインを開き、編集を 1 件ずつ差分で見られる(Prev / Next / Close) | | spec-flow | 「〇〇な機能が欲しい」と話しかけるか /spec-flow:spec <要望> で、要求整理 → 影響画面確認 → 要件定義 → 機能案・UI案 を 1 段階ずつ承認しながら進める。曖昧な点はヒアリングし、影響調査と案出しはサブエージェントが行う。成果物は docs/specs/<id>/(UI 案の HTML モックは Desktop なら Artifact にも公開。--local で公開しない)。/specs でチェックリストを開き、チェックで承認・修正依頼もできる | | dev-flow | 汎用の開発フロー。skills plan(小さなタスクに分けて承認をもらってから着手)・tdd(RED → GREEN → REFACTOR)・debug(再現 → 仮説 → 検証で原因を確かめてから直す)・review(重要度つきの差分レビュー)。サブエージェント code-explorer(横断調査)・test-runner(テスト結果の要約)・reviewer(別コンテキストでレビュー、修正はしない)が長い出力をメインに持ち込まない | | dev-extras | 他の OSS から選んで取り込んだ skill(すべて MIT、出典は各 README と licenses/)。ponytail(最小の実装に絞る)・ponytail-review(作り込みすぎだけを探す)・grill-me(質問攻めで計画を詰める)・handoff(バックグラウンドエージェントに引き継ぐ)・verification-before-completion(検証してから完了と言う)・security-audit(Cloudflare 製のセキュリティ監査) | | mod-dev | skill add-mod。「〇〇する mod を作って」で雛形・テスト・登録まで行う。marketplace リポジトリでは marketplace.json / bundle / README も更新し、それ以外では単体の mod を作る |
claude plugin marketplace add japan-da-man/claude-code
claude plugin install japan-da-man-mods@japan-da-man
1つずつ入れる場合は claude plugin install <名前>@japan-da-man。
更新:
claude plugin marketplace update japan-da-man
claude plugin update <名前>@japan-da-man
bundle に増えたプラグインを入れるときは、update → install の順で実行する(update だけだと増えた分は入らず、bundle が failed to load になる):
claude plugin marketplace update japan-da-man
claude plugin update japan-da-man-mods@japan-da-man
claude plugin install japan-da-man-mods@japan-da-man
セッション内なら update のあと /reload-plugins でもよい。
インストールせずに作業中のディレクトリを読み込む(保存するとホットリロードされる):
claude --plugin-dir ./plugins/todo-mod
チェック:
claude plugin validate .
claude plugin validate ./plugins/todo-mod
テスト(tests/*.test.ts があるプラグイン):
cd plugins/<name> && claude plugin test
mod-dev を入れた状態でこのリポジトリを開き「〇〇する mod を追加して」と頼むと、skill add-mod が下の手順(雛形・テスト・marketplace / bundle / README 更新・validate)をまとめてやる。手でやる場合:
plugins/<name>/ に .claude-plugin/plugin.json と中身を置く.claude-plugin/marketplace.json の plugins にエントリを追加する(name は plugin.json と同じにする)plugins/japan-da-man-mods/.claude-plugin/plugin.json の dependencies にも名前を足すplugin.json に version を書いていないので、コミットごとに新しいバージョンとして扱われる。
mods は Claude Code v2.1.287 以降が必要。
token-weather・blast-radius・replay-theater は、Anthropic の claude-code-playground にある同名の mod(Apache-2.0)をもとに手を加えたもの。各プラグインに LICENSE を同梱し、各 hooks/register.js の先頭に元のコードの著作権表示と、こちらで変えた点を書いている。
hooks/register.js 131 lines1// Copyright 2026 Anthropic PBC
2// SPDX-License-Identifier: Apache-2.0
3//
4// Token Weather: a live forecast of the context window, above the prompt.
5// Based on mods/token-weather in anthropics/claude-code-playground (Apache-2.0, see LICENSE).
6//
7// japan-da-man による変更:
8// - 計測値を $.state に置く(プラグインを読み込み直しても履歴が消えない。/clear などでは初期化される)
9// - 前回と同じ計測値は追加しない(読み込み直した直後に同じ値が届いても二重に数えない)
10// - 帯に他の mod が描くものを残す(Replay Theater などと共存する)
11// - /weather で表示を切り替える
12// - 描画サイトの値は e.props から読む
13
14import { atom, read, update } from 'claude-code'
15
16const HISTORY = 12
17const BARS = '▁▂▃▄▅▆▇█'
18
19// 使用率ごとの天気。絵文字ではなく 1 文字幅の記号を使う(どのターミナルのフォントでも揃う)
20export const FORECAST = [
21 { upTo: 25, icon: '☀', word: 'Clear', color: 'yellow' },
22 { upTo: 50, icon: '☁', word: 'Cloudy', color: 'cyan' },
23 { upTo: 75, icon: '☂', word: 'Showers', color: 'blue' },
24 { upTo: 90, icon: '☇', word: 'Storm', color: 'magenta' },
25 { upTo: Infinity, icon: '↯', word: 'Compact soon', color: 'red' },
26]
27
28// 計測値 { tokens, window, percent } の並び(古い順)
29const readingsAtom = atom({ plugin: 'token-weather', key: 'readings' }, [])
30// /weather で表示を切り替える
31let hidden = false
32
33// 計測値を 1 つ足した次の並びを返す。足すものがなければ同じ配列を返す
34export function addReading(readings, context) {
35 if (!context || !context.window) return readings
36 const tokens = context.tokens ?? 0
37 const percent = Math.round(context.percent ?? (tokens / context.window) * 100)
38 // 最初の応答の前の 0 の計測は、本物の計測が来たら外す
39 const kept = readings.filter((r) => r.tokens > 0)
40 const last = kept[kept.length - 1]
41 if (last && last.tokens === tokens && last.window === context.window) return readings
42 if (tokens === 0 && readings.length) return readings
43 return [...kept, { tokens, window: context.window, percent }].slice(-HISTORY)
44}
45
46export function forecastFor(percent) {
47 return FORECAST.find((f) => percent < f.upTo) ?? FORECAST[FORECAST.length - 1]
48}
49
50// バーの高さは表示中で一番多いターンを基準にする。使用率が低くても増え方が見える
51export function chart(readings) {
52 const top = Math.max(...readings.map((r) => r.tokens), 1)
53 return readings.map((r) => BARS[Math.min(BARS.length - 1, Math.floor((r.tokens / top) * (BARS.length - 1)))]).join('')
54}
55
56export function trendWord(readings) {
57 if (readings.length < 2) return ''
58 const delta = readings[readings.length - 1].tokens - readings[readings.length - 2].tokens
59 if (delta > 0) return `▲ +${short(delta)} last turn`
60 if (delta < 0) return `▼ ${short(-delta)} last turn`
61 return 'steady'
62}
63
64export function short(n) {
65 if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(n % 1_000_000 === 0 ? 0 : 1)}M`
66 if (n >= 1_000) return `${(n / 1_000).toFixed(n % 1_000 === 0 ? 0 : 1)}k`
67 return String(n)
68}
69
70async function takeReading($) {
71 try {
72 const { context } = await $.session.usage()
73 // $.state に書くと、それを読んでいる帯は自動で描き直される
74 await update($, readingsAtom, (rs) => addReading(rs, context))
75 } catch {
76 // このターンは計測なし。帯は前回の値のまま
77 }
78}
79
80export function register(on) {
81 on('session.start', async ($, e, next) => {
82 const result = await next(e)
83 hidden = (await $.store.get('hidden')) === true
84 await takeReading($)
85 await $.command.register({ name: 'weather', description: 'Token Weather の表示を切り替える', immediate: true })
86 return result
87 })
88
89 // メインのターンが終わるたびに計測する。サブエージェントのターンは数えない
90 on('turn.complete', async ($, e, next) => {
91 const result = await next(e)
92 if (!e.agentId) await takeReading($)
93 return result
94 })
95
96 on('command.run', { command: 'weather' }, async ($) => {
97 hidden = !hidden
98 $.ui.invalidate('ui.render')
99 await $.store.set('hidden', hidden)
100 return { text: hidden ? 'Token Weather を非表示にしました' : 'Token Weather を表示しました' }
101 })
102
103 on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
104 const readings = await read($, readingsAtom)
105 if (hidden || e.props.hasSurvey || readings.length === 0) return next(e)
106 const { Box, Text } = $.ui.resolve(e)
107 const line = band(Box, Text, readings, e.props.bodyColumns ?? 80)
108 // 他の mod が帯に描くものも残す
109 const rest = await next(e)
110 return rest ? Box({ flexDirection: 'column', children: [line, rest] }) : line
111 })
112}
113
114function band(Box, Text, readings, columns) {
115 const now = readings[readings.length - 1]
116 const f = forecastFor(now.percent)
117 const trend = trendWord(readings)
118 const parts = [
119 Text({ color: f.color, bold: true, children: `${f.icon} ${f.word}` }),
120 Text({ children: ` ${now.percent}% of context` }),
121 Text({ dimColor: true, children: ` ${short(now.tokens)} / ${short(now.window)}` }),
122 ]
123 // 狭い画面ではグラフと増減を省く
124 if (columns >= 60) {
125 parts.push(Text({ dimColor: true, children: ' last turns ' }))
126 parts.push(Text({ color: f.color, children: chart(readings) }))
127 if (trend) parts.push(Text({ dimColor: true, children: ` ${trend}` }))
128 }
129 return Box({ flexDirection: 'row', paddingX: 1, children: parts })
130}
131types/index.d.ts 9 lines1declare module 'claude-code' {
2 interface PluginState {
3 'token-weather': {
4 // 直近のターンの計測値(古い順)
5 readings: Array<{ tokens: number; window: number; percent: number }>
6 }
7 }
8}
9