SLOPSHOPPER

accent

My Dotfiles!

newrowsprompt
v?MITupdated 2026-10-080ta2/dots/dot_claude/mods/accent
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · accent
⟨Claude Code's own drawing⟩ ⏺ Read(src/auth.ts) ⎿ Read 6 lines ⏺ Update(src/auth.ts) ⎿ Added 2 lines, removed 1 line ⏺ Bash(bun test) ⎿ 3 pass, 1 fail ● Done. refresh now rejects expired claims and logs an audit event. ✻ Worked for 42s · done 4:20 PM ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts

Draws

Your message
⟨Claude Code's own drawing⟩
README

dots

セットアップ (初回のみ、2段階)

1. chezmoi を導入し dots を取得する (反映はしない)

sh -c "$(curl -fsLS get.chezmoi.io)" -- -b $HOME/.local/bin init --source=~/ghq/github.com/0ta2/dots git@github.com:0ta2/dots.git

2. Homebrew と mise を用意して初回セットアップする

~/ghq/github.com/0ta2/dots/bootstrap.sh

Homebrew・mise を導入した後 mise run install (ドットファイル反映・不足ツール・skill・plugin の 導入・Codex 設定同期) を実行する。

日常のコマンド

mise run sync    # ドットファイル反映 + Codex設定マージ (副作用なし、何度実行しても収束する)
mise run update  # brew/mise/skill/uv tool の更新、最後に sync

直接 chezmoi コマンドを実行する場合は下記の通り:

~/.local/bin/chezmoi --source=~/ghq/github.com/0ta2/dots apply

mac セットアップ

  • 一般
  • 情報 
  • コンピュータ名 を変更
  • 自動入力とパスワード
  • パスワードやパスキーを自動入力 をOFF
  • アクセシビリティ
  • ポインタコントロール
  • トラックパッドオプション
  • ドラッグにトラックパッドを使用 をON
  • デスクトップとDock
  • Dock のサイズ小さく好みのサイズへ変更
  • Dock の拡大を好みの大きさへ変更
  • Dock を自動的に表示/非表示をOFF
  • 起動中のアプリケーションをアニメーションで表示をOFF
  • 起動済みのアプリケーションにインジケータを表示をOFF
  • アプリの提案と最近使用したアプリをDockに表示をOFF
  • アプリの提案と最近使用したアプリをDockに表示をOFF
  • 外観
  • 外観モードをダークに変更
  • キーボード
  • キーボードショートカット
  • Spotlight検索を表示 のショートカットのチェックを外す
  • 入力ソース
  • 前の入力ソースを選択 を Cmd + スペース に変更
  • 入力メニューの次のソースを選択 を Cmd + shift + スペース に変更
  • 装飾キー
  • CapsLock を Ctrl に変更する
  • 入力ソース
  • USキー と ひらがな(Google)
  • トラックパッド
  • ポイントとクリック
  • 軌跡の速さを一番早く
  • タップでクリック にチェック

Neovim ローカル開発プラグインのリンク作成

iwano.nvim / amanoukihashi.nvim をローカルのリポジトリから読み込むため、下記のシンボリックリンクを作成する:

mkdir -p ~/.local/share/nvim/site/pack/mine/opt
ln -s ~/ghq/github.com/0ta2/iwano.nvim ~/.local/share/nvim/site/pack/mine/opt/iwano.nvim-local
ln -s ~/ghq/github.com/0ta2/amanoukihashi.nvim ~/.local/share/nvim/site/pack/mine/opt/amanoukihashi.nvim-local
Source 2 files
hooks/register.tsx 105 lines
1import type { Register } from 'claude-code'
2
3import { isDangerous, linkRefs, segmentsOf, type Callout } from './segments'
4
5const HEADING_COLORS = ['#ff9e64', '#7aa2f7', '#9ece6a'] as const
6const CALLOUTS: Record<Callout, { label: string; color: string }> = {
7  important: { label: '重要', color: '#f7768e' },
8  warning: { label: '注意', color: '#e0af68' },
9  note: { label: 'メモ', color: '#565f89' },
10}
11const DANGER_COLOR = '#f7768e'
12const ASK_COLOR = '#e0af68'
13const MINE_BACKGROUND = '#24283b'
14const FORMAT = [
15  '# Highlighting in replies',
16  'The transcript draws these markers in color, so the user notices them:',
17  '- `> [!IMPORTANT]` on its own line, the block below it quoted with `> `: the answer to what the user asked, and anything the user has to decide or do. At most one or two per reply.',
18  '- `> [!WARNING]`: a risk or a side effect the user should know before acting.',
19  '- `> [!NOTE]`: an aside that can be skipped.',
20  '- `##` headings split a long reply into parts; a short reply needs none.',
21  '- Write a pull request or issue as `owner/repo#123` so it becomes a link.',
22].join('\n')
23
24export const register: Register = on => {
25  on('prompt.compose', async (_$, e, next) => {
26    const composed = await next(e)
27    if (e.surfaces.length === 0) return composed
28    return { sections: [...composed.sections, { id: 'accent:format', text: FORMAT, scope: 'session' as const }] }
29  })
30
31  on('ui.render', { component: 'AssistantMessage' }, async ($, e, next) => {
32    if (e.props.isSummary) return next(e)
33    const segments = segmentsOf(e.props.text)
34    const hasRefs = linkRefs(e.props.text) !== e.props.text
35    if (!hasRefs && segments.every(one => one.kind === 'markdown')) return next(e)
36    const { Box, Markdown, Text } = $.ui.resolve(e)
37
38    return (
39      <Box flexDirection="column">
40        {segments.map((one, index) =>
41          one.kind === 'heading' ? (
42            <Text key={`h:${index}`} bold underline={one.level === 1} color={HEADING_COLORS[one.level - 1]}>
43              {`${one.level === 1 ? '■' : one.level === 2 ? '▍' : '・'} ${one.text}`}
44            </Text>
45          ) : one.kind === 'callout' ? (
46            <Box key={`c:${index}`} flexDirection="column" borderStyle="round" borderColor={CALLOUTS[one.callout].color} paddingX={1}>
47              <Text bold color={CALLOUTS[one.callout].color}>{CALLOUTS[one.callout].label}</Text>
48              <Markdown text={linkRefs(one.text)} dimColor={one.callout === 'note'} />
49            </Box>
50          ) : (
51            <Markdown key={`m:${index}`} text={linkRefs(one.text)} />
52          ),
53        )}
54      </Box>
55    )
56  })
57
58  on('ui.render', { component: 'ToolUse' }, async ($, e, next) => {
59    const command = e.props.tool === 'Bash' && typeof (e.props.input as { command?: unknown })?.command === 'string' ? (e.props.input as { command: string }).command : ''
60    if (!isDangerous(command)) return next(e)
61    const drawn = await next(e)
62    const { Box, Text } = $.ui.resolve(e)
63
64    return (
65      <Box flexDirection="column" borderStyle="round" borderColor={DANGER_COLOR} paddingX={1}>
66        <Text bold color={DANGER_COLOR}>⚠ 取り消しにくい操作</Text>
67        {drawn}
68      </Box>
69    )
70  })
71
72  on('ui.render', { component: 'AskUserQuestion' }, async ($, e, next) => {
73    const drawn = await next(e)
74    const { Box, Text } = $.ui.resolve(e)
75
76    return (
77      <Box flexDirection="column" borderStyle="double" borderColor={ASK_COLOR} paddingX={1}>
78        <Text bold color={ASK_COLOR}>🙋 あなたの判断待ち</Text>
79        {drawn}
80      </Box>
81    )
82  })
83
84  on('ui.render', { component: 'UserMessage' }, async ($, e, next) => {
85    const { origin, from } = e.props
86    const isMine = origin.kind === 'composer'
87    const sender = from?.name ?? (origin.kind === 'channel' ? origin.server : undefined)
88    // A collapsed row from someone else already names its sender in one line.
89    if (!isMine && (sender === undefined || !e.props.isExpanded)) return next(e)
90    const drawn = await next(e)
91    const { Box, Text } = $.ui.resolve(e)
92
93    return isMine ? (
94      <Box flexDirection="column" backgroundColor={MINE_BACKGROUND}>
95        {drawn}
96      </Box>
97    ) : (
98      <Box flexDirection="column">
99        <Text bold color="#7dcfff">{`📨 ${sender}`}</Text>
100        {drawn}
101      </Box>
102    )
103  })
104}
105
hooks/segments.ts 97 lines
1export type Callout = 'important' | 'warning' | 'note'
2export type Segment = { kind: 'markdown'; text: string } | { kind: 'heading'; level: number; text: string } | { kind: 'callout'; callout: Callout; text: string }
3
4const CALLOUT = /^>\s*\[!(IMPORTANT|WARNING|NOTE)\]\s*$/i
5const HEADING = /^(#{1,3})\s+(.+?)(?:\s+#+)?\s*$/
6const REPO_REF = /(?<![\w/.-])([\w.-]+\/[\w.-]+)#(\d+)\b/g
7const DANGER = /(^|[\s;&|(])(rm\s+-\w*[rf]|sudo\b|git\s+(push|reset\s+--hard|clean\s+-\w*f|branch\s+-D|checkout\s+--|restore\b)|gh\s+(pr\s+merge|repo\s+delete|release\s+delete)|chezmoi\s+apply|mise\s+run\s+chezmoi:apply|brew\s+(bundle|uninstall)|kill(all)?\b|chmod\b|chown\b|dd\s+if=|truncate\b)/
8
9export const isDangerous = (command: string): boolean => DANGER.test(command)
10
11/** What a reference inside stays as written: an inline code span of any backtick count, or a Markdown link. */
12const KEPT = /(?<!`)(`+)(?!`)[\s\S]*?(?<!`)\1(?!`)|\[[^\]\n]*\]\([^)\n]*\)/g
13const link = (text: string) => text.replace(REPO_REF, (all, repo, number) => `[${all}](https://github.com/${repo}/issues/${number})`)
14
15const fenceOf = (line: string): string | undefined => /^\s*(`{3,}|~{3,})/.exec(line)?.[1]
16/** Whether `line` closes a block opened by `fence`: the same character, at least as many, nothing after. */
17const closes = (line: string, fence: string): boolean => {
18  const marker = fenceOf(line)
19  return marker !== undefined && marker[0] === fence[0] && marker.length >= fence.length && line.trim() === marker
20}
21
22const linkOutsideKept = (text: string): string => {
23  let out = ''
24  let last = 0
25  for (const span of text.matchAll(KEPT)) {
26    out += link(text.slice(last, span.index)) + span[0]
27    last = span.index + span[0].length
28  }
29  return out + link(text.slice(last))
30}
31
32/** `owner/repo#123` becomes a link to it on GitHub, outside fenced blocks, inline code and existing links. */
33export const linkRefs = (text: string): string => {
34  const out: string[] = []
35  let prose: string[] = []
36  let fence: string | undefined
37  const flush = () => {
38    if (prose.length > 0) out.push(linkOutsideKept(prose.join('\n')))
39    prose = []
40  }
41  for (const line of text.split('\n')) {
42    if (fence !== undefined) {
43      out.push(line)
44      if (closes(line, fence)) fence = undefined
45    } else if (fenceOf(line) !== undefined) {
46      flush()
47      fence = fenceOf(line)
48      out.push(line)
49    } else {
50      prose.push(line)
51    }
52  }
53  flush()
54  return out.join('\n')
55}
56
57export const segmentsOf = (text: string): Segment[] => {
58  const out: Segment[] = []
59  let markdown: string[] = []
60  let callout: { callout: Callout; lines: string[] } | undefined
61  let fence: string | undefined
62  const flush = () => {
63    if (markdown.join('').trim()) out.push({ kind: 'markdown', text: markdown.join('\n') })
64    markdown = []
65  }
66  const close = () => {
67    if (callout) out.push({ kind: 'callout', callout: callout.callout, text: callout.lines.join('\n') })
68    callout = undefined
69  }
70
71  for (const line of text.split('\n')) {
72    if (callout && line.startsWith('>') && !CALLOUT.test(line)) {
73      callout.lines.push(line.replace(/^>\s?/, ''))
74      continue
75    }
76    close()
77    const marker = fenceOf(line)
78    const isFenced = fence !== undefined || marker !== undefined
79    if (fence === undefined) fence = marker
80    else if (closes(line, fence)) fence = undefined
81    const heading = isFenced ? null : HEADING.exec(line)
82    const opened = isFenced ? null : CALLOUT.exec(line)
83    if (opened) {
84      flush()
85      callout = { callout: opened[1]!.toLowerCase() as Callout, lines: [] }
86    } else if (heading) {
87      flush()
88      out.push({ kind: 'heading', level: heading[1]!.length, text: heading[2]! })
89    } else {
90      markdown.push(line)
91    }
92  }
93  close()
94  flush()
95  return out
96}
97